Robust Download Utility v. 1.5

Post your working scripts, libraries and tools for AHK v1.1 and older
MrBubbles
Posts: 87
Joined: 25 Nov 2015, 15:27

Robust Download Utility v. 1.5

29 Nov 2015, 23:32

There are lots of handy scripts on the forums to download stuff. Unfortunately, nothing posted every seemed to work out of the box for me, probably because of my own lack of knowledge. Anyway, on the old forums, I'd posted this robust little download script that you can use to download just about anything with an unsecured URL (and if the URL is secured with Windows Authentication, it will work there too).

I provide my end users a larger script (which includes this script) in order to automate the download, assembling and installation a massive 40GB data package ontheir system which they use with their GIS software.

The script will pop up a nice little progress bar and provide updates on how much has downloaded thus far, how large the file being downloaded is and percent complete. The "Downloaded " label will continually update to the largest whole metric unit of the file as it downloads, creating a nice, intuitive indicator of how much has downloaded. The percent complete also helps.
Image
Image

In addition, I added a function recently to validate the download using an MD5 Checksum. If you provide the file's hash to the download function, when the download completes it will generate an MD5 hash using CertUtil and compare that hash to the one provided as a parameter to the download function and raise an error if the values don't match. MD5 is the default hashing algorithm but the validation function is just calling CertUtil so it supports any algorithm that CertUtil can hash a file with.
Image

Once all is downloaded and the file integrity has been verified, it will raise a simple messagebox indicating the download is complete. Obviously, you can make it do additional things from there like I do, such as extract the download, run the installer, etc.

Anyway, it works for me and as far as I know, everything you need to run it is included in the source, except of course the windows dependencies that come from your specific environment. If for some reason you don't have CertUtil installed on your system, the code can be modified to use Microsoft's File Checksum Integrity Verifier which you can download and ship with a compiled version of the script.

I documented everything as meticulously as I could. Enjoy and please let me know if you find bugs!

Source:

Code: Select all

ProductName := "AutoHotKey"
AHKURL = https://www.autohotkey.com/download/ahk-install.exe
AHKDest = %A_TEMP%\ahk-install.exe
AHKMD5 = e9459f111cc184777ad34c7eb02ce710
 
IF Download(AHKURL, AHKDest, ProductName, AHKMD5)
{
	MSGBOX 64, SUCCESS, Download Complete
}
ELSE
{
	MSGBOX 16, AWW SNAP!, Something bad happened. 
}
 
iAccess() 
/* DESCRIPTION:
	Returns a Boolean Integer of 1 if the local machine has an active internet connection
	Raises an error dialog and exits if the local machine does not have an active internet connection
 
   PARAMETERS: NONE
 
   DEPENDENCIES:
	Wininet.dll
*/
{ ; LOGIC
    Status := DllCall("Wininet.dll\InternetGetConnectedState", "Str", 0x40, "Int", 0)
	IF Status = 1
	{
		RETURN 1
	}
	ELSE
	{
		MSGBOX 16, ERROR, An internet connection is required.`nPlease establish an internet connection and try again.
		EXITAPP
	}
}
 
validateURL(URL)
/* DESCRIPTION:
	Returns a value of 1 if the HTTP Response code is "200 OK"
	Raises an error message for HTTP Response codes 400, 401, 403 and 404. 
	For all other HTTP Response codes, raises an error dialog containing full HTTP Header Response.
 
   PARAMETERS:									OPTIONS:								DESCRIPTION:
	URL	(Text)									None									URL of resource to validate
 
   DEPENDENCIES:
	httpQuery()
*/
{ ; LOGIC
	ReturnHeader := httpQuery(URL)
	IF InStr(ReturnHeader, "200 OK")
	{
		RETURN 1
	}
	IF InStr(ReturnHeader, "400 Bad Request")
	{
		MSGBOX 16, ERROR: 400 - BAD REQUEST, The Server could not interpret the request. `n`nPlease contact your administrator for assistance.
		EXITAPP
	}
	IF InStr(ReturnHeader, "401 Unauthorized")
	{
		MSGBOX 16, ERROR: 401 - UNAUTHORIZED, The Administrator has not granted you access to this resource. `n`nPlease contact your administrator.com for assistance.
		EXITAPP
	}
	IF InStr(ReturnHeader, "403 Forbidden")
	{
		MSGBOX 16, ERROR: 403 - FORBIDDEN, The Administrator has blocked access to the requested resource. `n`nPlease contact your Administrator for assistance.
		EXITAPP
	}
	IF InStr(ReturnHeader, "404 Not Found")
	{
		MSGBOX 16, ERROR: 404 - NOT FOUND, The requested resource: `n"%URL%" could not be found. `n`nPlease contact your Administrator for assistance.
		EXITAPP
	}
	ELSE
	{
		MSGBOX 16, UNHANDLED EXCEPTION,  An unexpected error was encountered.`nPlease provide your Administrator with the following information:`n`nRequested Resource: %URL% `n`nResponse:`n%ReturnHeader%
		;EXITAPP
	}
}
 
httpQuery(URL, QueryInfoFlag=21, Proxy="", ProxyBypass="")
/* DESCRIPTION:
	Queries a URL and returns the HTTP Header information - Automatically detects and uses internet proxy if configured in internet settings
 
   PARAMETERS:									OPTIONS:								DESCRIPTION:
	URL	(Text)									None									URL of resource to query
 
	QueryInfoFlag								21 (Default)							Returns all headers from URL - Each header is terminated by "\0"
												5										Retrieves the size of the resource in bytes
												1										Retrieves the content-type of the resource (ex. text/html)
 
	Proxy										None									Proxy Alternative Address
 
	ProxyBypass									None									Proxy Alternative Credentials
 
   DEPENDENCIES:
	Wininet.dll
*/
{ ; LOGIC
	hModule := DllCall("LoadLibrary", "str", "wininet.dll") 
 
	If (Proxy != "")
	AccessType=3
	Else
	AccessType=1
 
	io_hInternet := DllCall("wininet\InternetOpenA"
	, "str", "" ;lpszAgent
	, "uint", AccessType
	, "str", Proxy
	, "str", ProxyBypass
	, "uint", 0) ;dwFlags
	If (ErrorLevel != 0 or io_hInternet = 0) {
	DllCall("FreeLibrary", "uint", hModule)
	return, -1
	}
 
	iou_hInternet := DllCall("wininet\InternetOpenUrlA"
	, "uint", io_hInternet
	, "str", url
	, "str", "" ;lpszHeaders
	, "uint", 0 ;dwHeadersLength
	, "uint", 0x80000000 ;dwFlags: INTERNET_FLAG_RELOAD = 0x80000000 // retrieve the original item
	, "uint", 0) ;dwContext
	If (ErrorLevel != 0 or iou_hInternet = 0) {
	DllCall("FreeLibrary", "uint", hModule)
	return, -1
	}
 
	VarSetCapacity(buffer, 1024, 0)
	VarSetCapacity(buffer_len, 4, 0)
 
	Loop, 5
	{
	  hqi := DllCall("wininet\HttpQueryInfoA"
	  , "uint", iou_hInternet
	  , "uint", QueryInfoFlag ;dwInfoLevel
	  , "uint", &buffer
	  , "uint", &buffer_len
	  , "uint", 0) ;lpdwIndex
	  If (hqi = 1) {
		hqi=success
		break
	  }
	}
 
	IfNotEqual, hqi, success, SetEnv, res, timeout
 
	If (hqi = "success") {
	p := &buffer
	Loop
	{
	  l := DllCall("lstrlen", "UInt", p)
	  VarSetCapacity(tmp_var, l+1, 0)
	  DllCall("lstrcpy", "Str", tmp_var, "UInt", p)
	  p += l + 1  
	  res := res  . "`n" . tmp_var
	  If (*p = 0)
	  Break
	}
	StringTrimLeft, res, res, 1
	}
 
	DllCall("wininet\InternetCloseHandle",  "uint", iou_hInternet)
	DllCall("wininet\InternetCloseHandle",  "uint", io_hInternet)
	DllCall("FreeLibrary", "uint", hModule)
 
	return, res	
}
 
getResourceSize(URL)
/* DESCRIPTION:
	Returns the size in bytes of a URL
 
   PARAMETERS:									OPTIONS:								DESCRIPTION:
	URL											None									URL of resource to query
 
   DEPENDENCIES:
	httpQuery()
*/
{ ; LOGIC
	; Query the URL and get the size os the resource in Bytes
	fSize := httpQuery(URL, 5)
	; Reference the Byte-size as the return value of the Query
	Bytes := fSize
	RETURN Bytes
}
 
getDownloadedSize(File)
/* DESCRIPTION:
	Returns the current size of the resource downloaded to the local machine in bytes
 
   PARAMETERS:									OPTIONS:								DESCRIPTION:
	File										None									Location and Name of file to query
 
   DEPENDENCIES:
	None
*/
{ ; LOGIC
	; If the given File does not exist
	IFNOTEXIST %File%
	{
		; Return None
		size = 0
		RETURN size
	}
	; Otherwise
	ELSE
	{
		; Read the first line of the file into a Temporary variable which will update any cached integer variables representing the size of the file
		FILEREADLINE TempVar, %File%, 1
		; Get the size of the file in Bytes
		FILEGETSIZE fSize, %File%
		; Reference the Byte-size as the return value of the Query
		Bytes = %fSize%
		RETURN Bytes
	}
}
 
convertSize(Bytes, Metric="Automatic", base="2")
/* DESCRIPTION:
	Converts the input size (which must be given in Bytes) to same size in the given file size Metric in Base 2 (Default) or Base 10 format returning the  
	resulting values as an array wherein the value at index 0 is the number of items in the array, the value at index 1 is the resource size and the value 
	at index 2 is the associated size metric of the value at index 1
 
	NOTE: Windows versions 8.1 and prior report file sizes formatted to Base 2. Windows 10 reports file sizes formatted to Base 10.
 
   PARAMETERS:									OPTIONS:								DESCRIPTION:
	Bytes										None									Integer representing Bytes to convert to another metric
 
	Metric										Automatic (Default)						Returns resource size in largest metric where the resource size is greater than or equal to 1 metric unit
												B										Returns resource size in Bytes
												KB										Returns resource size in Kilobytes
												MB										Returns resource size in Megabytes
												GB										Returns resource size in Gigabytes
												TB										Returns resource size in Terabytes
												PB										Returns resource size in Petabytes
												EB										Returns resource size in Exabytes
												ZB										Returns resource size in Zetabytes
												YB										Returns resource size in Yottabytes
 
	base									2 (Default)									Returns resource size in Base 2 format (1024)
											10											Returns resource size in Base 10 format (1000)
   DEPENDENCIES:
	None
*/
{ ; LOGIC
	; If the base parameter is 2
	IF base = 2
	{
		; Establish the conversionFactor as 1024
		conversionFactor = 1024
	}
	; If the base parameter is 10
	IF base = 10
	{
		; Establish the conversion factor as 1000
		conversionFactor = 1000
	}
	; Calculate the resource size for each metric
	B := Bytes
	KB := Bytes / conversionFactor
	MB := Bytes / conversionFactor**2
	GB := Bytes / conversionFactor**3
	TB := Bytes / conversionFactor**4
	PB := Bytes / conversionFactor**5
	EB := Bytes / conversionFactor**6
	ZB := Bytes / conversionFactor**7
	YB := Bytes / conversionFactor**8
	; If the Metric parameter is Automatic
	IF Metric = Automatic
	{
		; If the KB value is less than 1
		IF KB < 1
		{
			; Return the resource size in Bytes
			sizeArray = %B%, B
			RETURN sizeArray
		}
		; If the KB value is greater than or equal to 1 -AND- the MB value less than 1
		IF (KB >= 1 AND MB < 1)
		{
			; Return the resource size in KB
			sizeArray = %KB%, KB
			RETURN sizeArray
		}
		; If the MB value is greater than or equal to 1 -AND- the GB value less than 1
		IF (MB >= 1 AND GB < 1)
		{
			; Return the resource size in MB
			sizeArray = %MB%, MB
			RETURN sizeArray
		}
		; If the GB value is greater than or equal to 1 -AND- the TB value less than 1
		IF (GB >= 1 AND TB < 1)
		{
			; Return the resource size in GB
			sizeArray = %GB%, GB
			RETURN sizeArray
		}
		; If the TB value is greater than or equal to 1 -AND- the PB value less than 1
		IF (TB >= 1 AND PB < 1)
		{
			; Return the resource size in TB
			sizeArray = %TB%, TB
			RETURN sizeArray
		}
		; If the PB value is greater than or equal to 1 -AND- the EB value less than 1
		IF (PB >= 1 AND EB < 1)
		{
			; Return the resource size in PB
			sizeArray = %PB%, PB
			RETURN sizeArray
		}
		; If the EB value is greater than or equal to 1 -AND- the ZB value less than 1
		IF (EB >= 1 AND ZB < 1)
		{
			; Return the resource size in EB
			sizeArray = %EB%, EB
			RETURN sizeArray
		}
		; If the ZB value is greater than or equal to 1 -AND- the YB value less than 1
		IF (ZB >=1 AND YB < 1)
		{
			; Return the resource size in ZB
			sizeArray = %ZB%, ZB
			RETURN sizeArray
		}
		; If the YB value is greater than or equal to 1
		IF YB >=1
		{
			; Return the resource size in YB
			sizeArray = %YB%, YB
			RETURN sizeArray
		}
	}
	; If the Metric parameter is B
	IF Metric = B
	{
		; Return the resource size in B
		sizeArray = %B%, B
		RETURN sizeArray
	}
	; If the Metric parameter is KB
	IF Metric = KB
	{
		; Return the resource size in KB
		sizeArray = %KB%, KB
		RETURN sizeArray
	}
	; If the Metric parameter is MB
	IF Metric = MB
	{
		; Return the resource size in MB
		sizeArray = %MB%, MB
		RETURN sizeArray
	}
	; If the Metric parameter is GB
	IF Metric = GB
	{
		; Return the resource size in GB
		sizeArray = %GB%, GB
		RETURN sizeArray
	}
	; If the Metric parameter is TB
	IF Metric = TB
	{
		; Return the resource size in TB
		sizeArray = %TB%, TB
		RETURN sizeArray
	}
	; If the Metric parameter is EB
	IF Metric = EB
	{
		; Return the resource size in EB
		sizeArray = %EB%, EB
		RETURN sizeArray
	}
	; If the Metric Parameter is ZB
	IF Metric = ZB
	{
		; Return the resource size in ZB
		sizeArray = %ZB%, ZB
		RETURN sizeArray
	}
	; If the Metric Parameter is YB
	IF Metric = YB
	{
		; Return the resource size in YB
		sizeArray = %YB%, YB
		RETURN sizeArray
	}
}
 
Download(URL, SaveAsFile, ProductName, Hash=0, HashAlgorithm="MD5") 
/* DESCRIPTION:
	Downloads a given web resource to the local system displaying a Progressbar GUI during download.
 
   PARAMETERS:									OPTIONS:								DESCRIPTION:
	URL											None									URL of resource to query			
	SaveAsFile									None									Location and name of file in which to Save Resource being downloaded
	ProductName									None									Label for Progressbar main text
	Hash (Text - Optional)						None									A hash value used to validate the integrity of the download
	HashAlgorithm (Text - Optional)				See validateHash function				If omitted, the Hash value will be assumed MD5.
																						Otherwise, see options for validateHash() function's algorithm parameter
   DEPENDENCIES:
	iAccess(), validateURL(), httpQuery(), getResourceSize(), getDownloadedSize(), convertSize()
*/
{ ; LOGIC
	; If the system has internet access
	IF iAccess()
	{
		; If the given URL is valid
		IF validateURL(URL)
		{
			; Declare GLOBAL scope for the following variables
			GLOBAL totalSizeArray
			GLOBAL totalSize
			GLOBAL totalSizeUnit
			GLOBAL finalSize
			; Get the size of the requested resource in Bytes
			totalSize := getResourceSize(URL)
			; Execute the dlProgrssMonitor subroutine every 500 milliseconds (half-second)
			SETTIMER dlProgressMonitor, 500
			; Raise the Progress Bar
			PROGRESS M h80 w500 fm8 fs8, Initializing..., Downloading %ProductName%`nPlease wait...
			; Download the resource
			URLDOWNLOADTOFILE %URL%, %SaveAsFile%
			IF %ERRORLEVEL%
			{
				PROGRESS OFF
				SETTIMER dlProgressMonitor, OFF
				MSGBOX 16, ERROR, An error occurred while attempting download
				EXITAPP
			}
			; Turn off the Progress Bar
			PROGRESS OFF
			; Turn off the dlProgressMonitor subroutine
			SETTIMER dlProgressMonitor, OFF
 
			; If a hash value was provided
			IF Hash
			{
				; Validate the Hash
				IF validateHash(Hash, SaveAsFile, HashAlgorithm)
				{
					; Return a Boolean True indicating the File was downloaded successfully
					RETURN 1
				}
				; Otherwise - The file did not download successfully
				ELSE
				{
					; Raise an error and exit
					MSGBOX 16, FILE INTEGRITY ERROR, The file did not download completely or was updated during download.`n`nPlease restart the program to begin the download again. If this error message persists, please contact your Administrator for assistance.
					EXITAPP
				}
			}
 
			; Define the 'dlProgressMonitor' subroutine
			dlProgressMonitor:
			{
				; Declare GLOBAL scope for the following variables 
				GLOBAL totalSizeDisplayArray1
				GLOBAL totalSizeDisplayArray2
				GLOBAL currentSizeDisplayArray1
				GLOBAL currentSizeDisplayArray2
				GLOBAL currentSize
 
				; Perform the conversions for the total size to be displayed in the Progressbar
				totalSizeDisplayArray := convertSize(totalSize)
				STRINGSPLIT totalSizeDisplayArray, totalSizeDisplayArray, `,
				totalSizeDisplay := ROUND(totalSizeDisplayArray1, 2)
				totalSizeUnit = %totalSizeDisplayArray2%
 
				; Get the current size of the file being downloaded in bytes
				currentSize := getDownloadedSize(SaveAsFile)
				; Calculate the fractional percentage of the file downloaded
				fractionalProgress := currentSize / totalSize
				; Convert the fractionalProgress to a whole number rounding down to the nearest integer
				percentProgress := FLOOR(fractionalProgress * 100)
 
				; Perform the conversions for the local file being downloaded to be displayed in the Progressbar
				convertedSize := convertSize(currentSize)
				STRINGSPLIT currentSizeDisplayArray, convertedSize, `,
				currentSizeDisplay := ROUND(currentSizeDisplayArray1, 2)
				currentSizeUnit = %currentSizeDisplayArray2%
 
				;MSGBOX Percent Progress: %percentProgress%
				PROGRESS %percentProgress%, Downloaded %currentSizeDisplay% %currentSizeUnit% of %totalSizeDisplay% %totalSizeUnit% (%percentProgress%`%)
				;%
				RETURN
			}
		}
		ELSE
		{
			MSGBOX 16, ERROR, The requested resource is not available
			EXITAPP
		}
	}
	ELSE
	{
		MSGBOX 16, ERROR, An internet connection is required.`nPlease establish an internet connection and try again.
		EXITAPP
	}
}
 
validateHash(HASH, FILE, ALGORITHM="MD5")
/* DESCRIPTION:
	Executes the given file against Microsoft CertUtil command-line utility to generate a hash value for the given file.
	Compares the generated hash value against the given hash value to validate file integrity.
 
   PARAMETERS:							OPTIONS:										DESCRIPTION:
	HASH (Required)					None							The hash value expected to be returned for the given file
 
	FILE (Required)					None							The full path to the file to generate an hash for 
 
	ALGORITHM (Optional)			MD2 							Generates the file hash based on the MD2 algorithm					
									MD4								Generates the file hash based on the MD4 algorithm
									MD5 (Default)					Generates the file hash based on the MD5 algorithm. This is the default.
									SHA1							Generates the file hash based on the SHA1 algorithm
									SHA256							Generates the file hash based on the SHA256 algorithm
									SHA384 							Generates the file hash based on the SHA384 algorithm
									SHA512							Generates the file hash based on the SHA512 algorithm
   DEPENDENCIES:
	CertUtil
*/
{ ; LOGIC
	; 
	IF (ALGORITHM = "MD2" OR ALGORITHM = "MD4" OR ALGORITHM = "MD5")
	{
		reqLEN = 32
	}
	IF (ALGORITHM = "SHA1")
	{
		reqLEN = 40
	}
	IF (ALGORITHM = "SHA256")
	{
		reqLEN = 64
	}
	IF (ALGORITHM = "SHA384")
	{
		reqLEN = 96
	}
	IF (ALGORITHM = "SHA512")
	{
		reqLEN = 128
	}
	hashLEN := STRLEN(HASH)
	IF (hashLEN = reqLEN)
	{
		; If the given file exists on the system
		IFEXIST %FILE%
		{
			; Reference the command to be executed as 'CMD'
			CMD = CertUtil -hashfile %FILE% %ALGORITHM% > %A_TEMP%\fHash.txt
 
			; NOTE - FOR THE INDETERMINATE PROGRESSBAR, YOU WILL NEED TO GET THE GRAB THE SOURCE POSTED BY 'LEARNING ONE' AT https://autohotkey.com/board/topic/63662-indeterminate-progress-bar/, THEN COMPILE IT AND REFERENCE IT IN THE FILEINSTALL COMMAND
			; Extract the Indeterminate Progressbar GUI executable to the user's temp directory
			FILEINSTALL ...\iPB.exe, %A_TEMP%\iPB.exe, 1 
 
			; Initialize the Indeterminate Progressbar executable to provide a UI indicator of ongoing events
			RUN %A_TEMP%\iPB.exe
			; Execute the command, writing the result to a temporary file
			RUNWAIT %COMSPEC% /C %CMD%,, HIDE
			; Read the second line of the temporary file and store it as 'fHASH'
			FILEREADLINE fHASH, %A_TEMP%\fHash.txt, 2
			; Delete the temporary file from the system
			FILEDELETE %A_TEMP%\fHash.txt
			; Strip all of the spaces from the 'fHASH' value
			STRINGREPLACE fHASH, fHASH, %A_SPACE%,, All
			; Close the Indeterminate Progressbar process
			PROCESS Close, iPB.exe
			; Delete the 'iPB.exe' from the system
			FILEDELETE %A_TEMP%\iPB.exe
 
			; If the 'fHASH' value is identical to the given 'HASH'
			IF (fHASH = HASH)
			{
				; The hash values match, return a boolean True
				RETURN 1
			}
			; Otherwise - the 'fHASH' is identical to the given 'HASH'
			ELSE
			{
				; The hash values do not match, return a boolean False
				RETURN 0
			}
		}
		; Otherwise - The File does not exist on the system
		ELSE
		{
			; Raise an error and exit
			MSGBOX 16, ERROR, The file %File% could not be found.`n`nThe program is unable to continue.`nPlease contact your Administrator for assistance.
			EXITAPP
		}
	}
	; Otherwise - the length of the given hash is not valid for the selected algorithm
	ELSE
	{
		; Raise an error and exit
		MSGBOX, 16, INVALID %ALGORITHM% HASH,  The hash value given is not a valid %ALGORITHM% hash. `n%ALGORITHM% hashes must be %reqLEN%-characters long and cannot contain spaces or other delimeters.
		EXITAPP
	}
}
Attachments
RobustDownloadUtility.ahk
(18.96 KiB) Downloaded 273 times
iPB.ahk
(356 Bytes) Downloaded 257 times
SlowPoster[1H+]

Re: Robust Download Utility v. 1.5

30 Nov 2015, 21:15

I think you earned some bubbles for this mister ;) :thumbup:
I'm sure this will come in really handy for many people.

Your country thanks you for your service :salute:
User avatar
Soft
Posts: 174
Joined: 07 Jan 2015, 13:18
Location: Seoul
Contact:

Re: Robust Download Utility v. 1.5

01 Dec 2015, 09:29

awesome code!
I'm a bit inspired by the way it handles the percentage
AutoHotkey & AutoHotkey_H v1.1.22.07
User avatar
SnowFlake
Posts: 368
Joined: 28 Apr 2015, 05:41
Contact:

Re: Robust Download Utility v. 1.5

04 Dec 2015, 08:01

Nice :D

also how do you add Attachments to the post?
:yawn:
daorc
Posts: 8
Joined: 27 Mar 2015, 10:51

Re: Robust Download Utility v. 1.5

01 Feb 2016, 07:11

MrBubbles, this is great! Thanks for sharing. I'm trying to extend this to check if the downloaded file is signed, but I'm getting confused by the CertUtil documentation.

I've tried the following command line text but with no luck ...

Code: Select all

CertUtil -verify "%FILE%" > %A_TEMP%\fVerify.txt
The CertUtil documentation is here:
https://technet.microsoft.com/en-us/lib ... 32443.aspx

Any ideas?

Thank you!!
MrBubbles
Posts: 87
Joined: 25 Nov 2015, 15:27

Re: Robust Download Utility v. 1.5

07 Apr 2016, 10:45

Hey daorc,
Sorry I didn't see this until last night. CertUtils is mostly meant for management of Certificate Store and Certificates on a machine, not actually verifying whether or not a file is signed. I just used it in this case to generate the checksum because it's is loaded on most windows 7 systems by default and it has that functionality.

Verifying the validity of a file's signature however is not a capability that I believe CertUtil has. Standard practice is to use SignTool.exe from Microsoft. Unfortunately, that's a developed tool that comes with the Windows SDK and is not usually installed on a Windows system by default.

Good news though, SignTool.exe is a standalone command-line utility. So you can download the Windows SDK installer, install only the part of it that contains SignTool.exe and then just include that in your application and extract it and run it whenever your download completes. The Windows SDK installer can be downloaded Microsoft for free, you'll just need to use the Google machine to determine where the SDK is located for your OS. Google something like "Windows 7 SDK .NET 4.5" or whatever is appropriate for your setup.

Fire up that installer, accept the terms and conditions, then when you get to the part where you select the portions of the SDK you want to download and install, select only Windows Native Code Development > Tools, then run the installer. This will download and install only the portion of the Windows SDK which contains SignTool.exe (and some other sweet tools that you may find helpful for doing all kinds of nerdy things).

Once it finishes installing, signtool.exe should be located in C:\Program Files\Microsoft SDKs\Windows\v<your windows version>\bin. Now just use a fileinstall command to include signtool.exe in your app.

Code: Select all

FILEINSTALL C:\Program Files\Microsoft SDKs\Windows\v<your windows version>\bin, %A_TEMP%\signtool.exe, 1
RUNWAIT %A_TEMP%\signtool.exe verify %FILE% > %A_TEMP%\fVerify.txt
As per the signtool docs, if the above fails then its possible that the signature used a code-signing certificate. Windows defaults to the Digital Authentication Verification policy. To verify a signature that was signed with a code-signing certificate, use:

Code: Select all

RUNWAIT %A_TEMP%\signtool.exe verify /pa %FILE% > %A_TEMP%\fVerify.txt
Hope that helps.
MrBubbles
Posts: 87
Joined: 25 Nov 2015, 15:27

Re: Robust Download Utility v. 1.5

07 Apr 2016, 10:47

SnowFlake wrote:Nice :D

also how do you add Attachments to the post?
When drafting a response, click on the 'Full Editor and Preview' button. Under the text editor window, you should see a box with two tabs, Options and Attachments. Click the Attachments Tab, then Add Files and voila!
MrBubbles
Posts: 87
Joined: 25 Nov 2015, 15:27

Re: Robust Download Utility v. 1.5

20 Apr 2016, 09:08

After finally upgrading to AHK_L last week, I tested this tool today and found that the version of HTTPQUERY it is using is not compatible with AHK_L. As a result, the source posted above is only known to work with AHK Basic.

To get it to work with AHK_L, you simply need to replace the HTTPQUERY function with the AHK_L version of that function, posted below.

Kudos and much thanks to Olphen who developed the original HttpQueryInfo function (.../board/topic/9569-dllcall-httpqueryinfo-get-http-headers/)
and 0x150--ISO who made the necessary changes to get it working with AHK_L.

AHK_L compatible HTTPQUERY function:

Code: Select all

httpQuery(URL, QueryInfoFlag=21, Proxy="", ProxyBypass="")
/* DESCRIPTION:
	Queries a URL and returns information from the response header
	NOTE:	Function auto-detects and uses internet proxy if configured in 
			internet settings

   PARAMETERS:						OPTIONS:			DESCRIPTION:
	URL	(Required)					None				URL of resource to query
		
	QueryInfoFlag (Optional)		21 (Default)		Returns full resource header
									5					Retrieves the size of the resource in bytes
									1					Retrieves the resource content-type
													
	Proxy (Optional)				None (Default)		Proxy Alternative Address
		
	ProxyBypass	(Optional)			None (Default)		Proxy Alternative Credentials

   DEPENDENCIES:
	Wininet.dll
	
   CREDITS:	
	Original Version: User "Olfen" @ 
	https://autohotkey.com/board/topic/9569-dllcall-httpqueryinfo-get-http-headers/#id=entry60438
	AHK_L Version: User "0x150--ISO" @ 
	https://autohotkey.com/board/topic/9569-dllcall-httpqueryinfo-get-http-headers/page-2#id=entry508053
*/
{ ; LOGIC
	hModule := DllCall("LoadLibrary", "str", dll := "wininet.dll")

	ver := ( A_IsUnicode && !RegExMatch( A_AhkVersion, "\d+\.\d+\.4" ) ? "W" : "A" )
	InternetOpen := dll "\InternetOpen" ver
	HttpQueryInfo := dll "\HttpQueryInfo" ver
	InternetOpenUrl := dll "\InternetOpenUrl" ver

	If (Proxy != "")
	{
		AccessType=3
	}
	Else
	{
		AccessType=1
	}
	
	io_hInternet := DllCall( InternetOpen
	, "str", "" 
	, "uint", AccessType
	, "str", Proxy
	, "str", ProxyBypass
	, "uint", 0) ;dwFlags
	If (ErrorLevel != 0 or io_hInternet = 0) 
	{
	DllCall("FreeLibrary", "uint", hModule)
	return, -1
	}

	iou_hInternet := DllCall( InternetOpenUrl
	, "uint", io_hInternet
	, "str", url
	, "str", ""
	, "uint", 0
	, "uint", 0x80000000
	, "uint", 0)
	If (ErrorLevel != 0 or iou_hInternet = 0) {
	DllCall("FreeLibrary", "uint", hModule)
	return, -1
	}

	VarSetCapacity(buffer, 1024, 0)
	VarSetCapacity(buffer_len, 4, 0)

	Loop, 5
	{
		hqi := DllCall( HttpQueryInfo
		, "uint", iou_hInternet
		, "uint", QueryInfoFlag
		, "uint", &buffer
		, "uint", &buffer_len
		, "uint", 0)
		If (hqi = 1)
		{
			hqi=success
			break
		}
	}

	IfNotEqual, hqi, success, SetEnv, res, timeout

	If (hqi = "success")
	{
		p := &buffer
		Loop
		{
			l := DllCall("lstrlen", "UInt", p)
			VarSetCapacity(tmp_var, l+1, 0)
			DllCall("lstrcpy", "Str", tmp_var, "UInt", p)
			p += l + 1 
			res := res . tmp_var
			If (*p = 0)
			{
				Break
			}
		}
	}

	DllCall("wininet\InternetCloseHandle",  "uint", iou_hInternet)
	DllCall("wininet\InternetCloseHandle",  "uint", io_hInternet)
	DllCall("FreeLibrary", "uint", hModule)

	return, res
}
daorc
Posts: 8
Joined: 27 Mar 2015, 10:51

Re: Robust Download Utility v. 1.5

21 Sep 2016, 01:32

Sorry MrBubbles, my turn - I only saw your reply just now! Thanks for all that detail! In the end I just decided to check another server for an md5 and compare it, but I will look back into that with what you suggested.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: gwarble and 145 guests