Checksum
This document explains how to use a checksum in lucee.
Many servers provide a checksum for the files they provide for download. We use the checksum to validate a download file in order to avoid a corrupted file.
If you download a file in your application, you can automatically check if the download is valid or not if the necessary info was provided in the response header.
Example 1 :
<cfscript>
_url="http://central.maven.org/maven2/org/lucee/esapi/2.1.0.1/esapi-2.1.0.1.jar";
http url=_url result="res";
if(res.status_code!=200) throw "wtf";
dump(res.responseheader);
// store the file
localFile="esapi-2.1.0.1.jar";
fileWrite(localFile,res.fileContent);
// get a hash
dump(fileInfo(localFile));
dump(hash(fileReadBinary(localFile),"md5"));
dump(hash(fileReadBinary(localFile),"SHA1"));
// validate file
if(!isEmpty(res.responseheader["X-Checksum-MD5"]?:"")) {
fi=fileInfo("esapi-2.1.0.1.jar");
if(res.responseheader["X-Checksum-MD5"]==fi.checksum) {
dump("we have a match!");
}
else {
fileDelete("esapi-2.1.0.1.jar");
dump("something went wrong! give it an other try?");
}
}
</cfscript>
- Download the jar file by using cfhttp.
- Dump the file response header. You can see the "X-Checksum-MD5" "X-Checksum-SHA1" keys from the file itself.
- Save the file, and dump(fileInfo(localFile.checksum)). Check to see if the dump matches the value of the downloaded file response["X-Checksum-MD5"] header.
Checksum values are hashed from the binaryfile itself.
dump(hash(fileReadBinary(localFile),"md5"));
dump(hash(fileReadBinary(localFile),"SHA1"));
You can validate the checksum as shown below:
// validate file
if(!isEmpty(res.responseheader["X-Checksum-MD5"]?:"")) {
fi=fileInfo("esapi-2.1.0.1.jar");
if(res.responseheader["X-Checksum-MD5"]==fi.checksum) {
dump("we have a match!");
}
else {
fileDelete("esapi-2.1.0.1.jar");
dump("something went wrong! give it an other try?");
}
}
If the checksum is provided, we can check it. However, the checksum may not always be provided. The following example shows how to provide a checksum for all downloads.
Example 2
//download.cfm
<cfscript>
fi=fileInfo("esapi-2.1.0.1.jar");
header name="Content-MD5" value=fi.checksum;
content file="esapi-2.1.0.1.jar" type="application/x-zip-compressed";
</cfscript>
This code allow a downloading application to check if the download was successful or not. Adding the file with header content "Content-MD5" is not required.
Download the file using the below example code:
<cfscript>
// possible MD5 headers
HEADER_NAMES.SHA1=["Content-SHA1","X-Checksum-SHA1"];
HEADER_NAMES.MD5=["Content-MD5","X-Checksum-MD5"]; // ETag
_url=getDirectoryFromPath(cgi.request_url)&"/_download.cfm";
<span class="nv">http</span> <span class="nv">url</span><span class="o">=</span><span class="nv">_url</span> <span class="nv">result</span><span class="o">=</span><span class="s2">"res"</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="nv">res.status_code</span><span class="o">!=</span><span class="m">200</span><span class="p">)</span> <span class="nv">throw</span> <span class="s2">"wtf"</span><span class="p">;</span>
<span class="c">// store the file</span>
<span class="nf">fileWrite</span><span class="p">(</span><span class="s2">"clone.jar"</span><span class="p">,</span><span class="nv">res.fileContent</span><span class="p">);</span>
<span class="c">// see if we have one of the MD5 headers</span>
<span class="nv">checksum</span><span class="o">=</span><span class="p">{</span><span class="nv">type</span><span class="p">:</span><span class="s2">""</span><span class="p">,</span><span class="nv">name</span><span class="p">:</span><span class="s2">""</span><span class="p">};</span>
<span class="nv">loop</span> <span class="nv">label</span><span class="o">=</span><span class="s2">"outer"</span> <span class="nv">struct</span><span class="o">=</span><span class="nv">HEADER_NAMES</span> <span class="nv">index</span><span class="o">=</span><span class="s2">"type"</span> <span class="nv">item</span><span class="o">=</span><span class="s2">"names"</span> <span class="p">{</span>
<span class="nv">loop</span> <span class="nv">array</span><span class="o">=</span><span class="nv">names</span> <span class="nv">item</span><span class="o">=</span><span class="s2">"name"</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="nf">structKeyExists</span><span class="p">(</span><span class="nv">res.responseheader</span><span class="p">,</span><span class="nv">name</span><span class="p">))</span> <span class="p">{</span>
<span class="nv">checksum.type</span><span class="o">=</span><span class="nv">type</span><span class="p">;</span>
<span class="nv">checksum.name</span><span class="o">=</span><span class="nv">name</span><span class="p">;</span>
<span class="nv">checksum.value</span><span class="o">=</span><span class="nv">res.responseheader</span><span class="p">[</span><span class="nv">name</span><span class="p">];</span>
<span class="k">break</span> <span class="nv">outer</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nf">dump</span><span class="p">(</span><span class="nv">checksum</span><span class="p">);</span>
<span class="c">// validate file</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nf">isEmpty</span><span class="p">(</span><span class="nv">checksum.name</span><span class="p">))</span> <span class="p">{</span>
<span class="nv">cs</span><span class="o">=</span><span class="nf">hash</span><span class="p">(</span><span class="nf">fileReadBinary</span><span class="p">(</span><span class="s2">"clone.jar"</span><span class="p">),</span><span class="nv">checksum.type</span><span class="p">);</span>
<span class="c">//dump(checksum);</span>
<span class="k">if</span><span class="p">(</span><span class="nv">checksum.value</span><span class="o">==</span><span class="nv">cs</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">dump</span><span class="p">(</span><span class="s2">"we have a match!"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
<span class="nf">fileDelete</span><span class="p">(</span><span class="s2">"clone.jar"</span><span class="p">);</span>
<span class="nf">dump</span><span class="p">(</span><span class="s2">"something went wrong! give it an other try?"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</cfscript>
Above code checks and validates the downloaded file.
Footnotes
You can see the details in this video: Checksum