Is there a way to determine the hash value of an incoming attachment to SN? In general, trying to avoid attaching signature images to created incidents.

crob
Kilo Explorer

Is there a way to determine the hash value of an incoming attachment to SN? In general, trying to avoid attaching signature images to created incidents. The signature images come in with a random name of 'image001.png' through 'image011.png' depending on how many you have.

I've considered trying to compare sys_attachment_doc records, but the attachments names are not always the same so if 'image001' came in I would need to compare it to 11 different attachments to be sure it's not a match on them and am concerned that would be a performance issue.

9 REPLIES 9

Matt Saxton - G
Kilo Guru

Cody,



it might be possible with GlideChecksum however this is undocumented and about an hour of playing around got me no where with validating binary's.



SORTED PROPERTIES OF CLASS: GlideChecksum



*** Script: MD5


*** Script: class


*** Script: dataBytes


*** Script: dataLength


*** Script: equals


*** Script: get


*** Script: getClass


*** Script: getDataBytes


*** Script: getDataLength


*** Script: getMD5


*** Script: hashCode


*** Script: notify


*** Script: notifyAll


*** Script: toString


*** Script: wait


*** Script:



var a = new GlideChecksum('CheckSomeTHis');


gs.print(a.MD5)



Script: 484ab8565f1c80212aa112322c9769a3



Online MD5 Hash Generator & SHA1 Hash Generator



validated it here that the CheckSum Generated properly.



-Matt


Alright, Matt Saxton pointed us in the right direction.



What I'll be doing in my instance is setting up a table that contains a list of hashes for signature images to ignore, and then query that table for matches against inbound email attachment file hashes.



To get those attachment hashes, I get getBytes on the attachment and convert it to base 64, and then get a md5 of that. Set up a Before Insert business rule on the sys_attachment table and set the Conditions for name matches pattern img\d{3} and type is image/whatever:



function onBefore (current, previous) {


var StringUtil = GlideStringUtil;


var gsa = new GlideSysAttachment();


var b64 = StringUtil.base64Encode(gsa.getBytes(current));


var imgHash = (new GlideChecksum(b64)).getMD5();



var gr = new GlideRecord("CUSTOM_HASH_TABLE_HERE");


if (gr.get("u_hashcode", imgHash)) {


current.setAbortAction(true);


gs.log("Ignoring blah blah blah");


}


}



Edit: fixed capitalization issue.


You could also just compare the base 64 string but that's a pretty big text string. Alternatively you can flag a 'prototype' attachment record via a custom column, and check any new attachments' encoded base 64 string against all the flagged attachments (so you don't have to maintain a separate table), and use some basic conditions to limit the attachments being checked (since I guess this could get processor intensive).



I'd say with specific enough conditions the chance of an important attachment having a hash collision with a signature file is low enough for the md5 method to be OK.


Well, I went a little overboard on this and wound up creating a mini-application.



New table - contains string field for hash codes and set that field as a unique index. The name of the table is u_hashcodes (accidentally pluralized it, hate it when I do that). The relevant field is u_code to contain the hash. Additional fields are highlighted below in green.



Note: uLibrary is a script include that we have some custom utility scripts inside, the code for getting the hash is based on my earlier post above.



New UI Action - right-click context menu to block the attachment from the related list of attachments on (e.g.) the incident record. The condition excludes the hashcode table for the reason colorized in the script below it.



UI Action Table:


sys_attachment


Condition:


gs.hasRole("admin") && current.file_name.match(/image\d{3}\.\w{3}/i) && current.content_type.indexOf("image") == 0 && current.table_name != "u_hashcodes"


Script:


blockSignatureImage();


function blockSignatureImage() {


var md5 = uLibrary.getAttachmentMD5(current);


var hc = new GlideRecord("u_hashcodes");


hc.addQuery("u_code", md5);


hc.query();


if (hc.next()) {


if (!hc.u_active) {


hc.u_active = true;


hc.update();


}


current.deleteRecord();


} else {


hc = new GlideRecord("u_hashcodes");


hc.initialize();


hc.u_code = md5;


hc.u_description = current.table_name + ":" + current.table_sys_id;


hc.u_name = current.content_type + ": " + current.file_name;


var hcID = hc.insert();


if (hcID) {


current.table_name = "u_hashcodes";


current.table_sys_id = hcID;


current.update();


}


}


}



Blue part -- If you're defining a blocked signature image for the first time using this action, it is re-associated with the image block definition record, so you can check and see what each hashcode record is supposed to be blocking (if it's flagged as active).



Preventing new attachments from being created that match those hashcodes is done with a business rule. This needs to be corrected by someone who knows better, I wound up using an After business rule; tried onAsynch but it took too long to fire, and onBefore generates an error message.



Business Rule Table:


sys_attachment


Condition:


current.content_type.indexOf("image") == 0 && current.table_name.indexOf("ZZ_YY") < 0 && current.file_name.match(/image\d{3}\.\w{3}/i) && current.table_name != "u_hashcodes"


Script:


function onAfter(current, previous) {


var md5 = uLibrary.getAttachmentMD5(current);


var hc = new GlideRecord("u_hashcodes");


hc.addQuery("u_code", md5);


hc.addQuery("u_active", true);


hc.query();


if (hc.hasNext()) {


current.deleteRecord();


}


}



Lastly, the scariest one: clearing all this garbage out of your attachment table. Go to any newly created hashcode record and hit this UI action.



UI Action Table:


u_hashcodes


Condition:


current.u_active && gs.hasRole("admin")


Script:


deleteMatchingAttachments();


function deleteMatchingAttachments() {


var sa = new GlideRecord("sys_attachment");


sa.addQuery("file_name", "STARTSWITH", "image");


sa.addQuery("content_type", "STARTSWITH", "image");


sa.addQuery("table_name", "DOES NOT CONTAIN", "ZZ_YY");


sa.addQuery("table_name", "!=", "u_hashcodes");


sa.query();


while (sa.next()) {


if (!sa.file_name.match(/image\d{3}\.\w{3}/i)) continue;


var md5 = uLibrary.getAttachmentMD5(sa);


if (md5 == current.u_code) {


sa.deleteRecord();


}


}


}



I'd have posted an update XML of this but it's mixed in with the other work I'm actually supposed to be doing right now.


For your business rule I made a slight adjustment and it works great:



OnBefore an Insert



Business Rule Table:


sys_attachment


Condition:


current.content_type.indexOf("image") == 0 && current.table_name.indexOf("ZZ_YY") < 0 && current.table_name != "u_hashcodes"


Script:


var md5 = uLibrary.getAttachmentMD5(current);


var hc = new GlideRecord("u_hashcodes");


hc.addQuery("u_code", md5);


hc.addQuery("u_active", true);


hc.query();


if (hc.hasNext()) {


current.setAbortAction(true);


}






Thanks for your posts!