From 896f11afab84961a52be8466aacf5052a29083a2 Mon Sep 17 00:00:00 2001 From: Javier Quintero Date: Mon, 19 Aug 2024 16:45:51 -0500 Subject: [PATCH 1/7] #COMMANDBOX-1638 Create a hash of the binary when storing the zip and return it to ForgeBox --- src/cfml/system/endpoints/ForgeBox.cfc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cfml/system/endpoints/ForgeBox.cfc b/src/cfml/system/endpoints/ForgeBox.cfc index 956c74fa..d30b54d4 100644 --- a/src/cfml/system/endpoints/ForgeBox.cfc +++ b/src/cfml/system/endpoints/ForgeBox.cfc @@ -250,6 +250,7 @@ component accessors="true" implements="IEndpointInteractive" { props.changeLogFormat = 'text'; props.APIToken = getAPIToken(); props.forceUpload = arguments.force; + props.binaryHash = ''; // start upload stuff here var upload = boxJSON.location == "forgeboxStorage"; @@ -353,6 +354,7 @@ component accessors="true" implements="IEndpointInteractive" { } consoleLogger.warn( "Uploading package zip [#readableSize#] to #getNamePrefixes()#..." ); var storeURL = forgebox.storeURL( props.slug, props.version, props.APIToken ); + var binary = fileReadBinary( zipPath ); http url="#storeURL#" @@ -364,9 +366,11 @@ component accessors="true" implements="IEndpointInteractive" { proxyPassword="#ConfigService.getSetting( 'proxy.password', '' )#" result="local.storeResult"{ httpparam type="header" name="Content-Type" value="application/zip"; - httpparam type="body" value="#fileReadBinary( zipPath )#"; + httpparam type="body" value="#binary#"; } + props.binaryHash = hash( binary, "MD5" ); + if( fileExists( zipPath ) ){ fileDelete( zipPath ); } From 2fd24ba49c6ba9be9af38deec5e08ffe9068cd50 Mon Sep 17 00:00:00 2001 From: Javier Quintero Date: Thu, 22 Aug 2024 11:28:21 -0500 Subject: [PATCH 2/7] Validate the binary hash --- src/cfml/system/endpoints/ForgeBox.cfc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cfml/system/endpoints/ForgeBox.cfc b/src/cfml/system/endpoints/ForgeBox.cfc index d30b54d4..0312d041 100644 --- a/src/cfml/system/endpoints/ForgeBox.cfc +++ b/src/cfml/system/endpoints/ForgeBox.cfc @@ -543,6 +543,11 @@ component accessors="true" implements="IEndpointInteractive" { throw( 'No download URL provided in #getNamePrefixes()#. Manual install only.', 'endpointException' ); } + // Validate the binary hash + if( len( satisfyingVersion.binaryHash ) && satisfyingVersion.binaryHash != hash( fileReadBinary( downloadURL ), "MD5" ) ) { + throw( 'The binary hash of the downloaded file does not match the expected hash.', 'endpointException' ); + } + job.addLog( "Installing version [#arguments.version#]." ); recordInstall( arguments.slug, arguments.version ); From c33929f758b1ba7b8075f7a6d0967ecc3410ba42 Mon Sep 17 00:00:00 2001 From: Javier Quintero Date: Thu, 22 Aug 2024 16:53:56 -0500 Subject: [PATCH 3/7] HTTP Endpoint update --- src/cfml/system/endpoints/ForgeBox.cfc | 9 ++++----- src/cfml/system/endpoints/HTTP.cfc | 12 ++++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/cfml/system/endpoints/ForgeBox.cfc b/src/cfml/system/endpoints/ForgeBox.cfc index 0312d041..3eeb42e0 100644 --- a/src/cfml/system/endpoints/ForgeBox.cfc +++ b/src/cfml/system/endpoints/ForgeBox.cfc @@ -543,11 +543,6 @@ component accessors="true" implements="IEndpointInteractive" { throw( 'No download URL provided in #getNamePrefixes()#. Manual install only.', 'endpointException' ); } - // Validate the binary hash - if( len( satisfyingVersion.binaryHash ) && satisfyingVersion.binaryHash != hash( fileReadBinary( downloadURL ), "MD5" ) ) { - throw( 'The binary hash of the downloaded file does not match the expected hash.', 'endpointException' ); - } - job.addLog( "Installing version [#arguments.version#]." ); recordInstall( arguments.slug, arguments.version ); @@ -584,6 +579,10 @@ component accessors="true" implements="IEndpointInteractive" { } else { job.addLog( "Deferring to [#endpointData.endpointName#] endpoint for #getNamePrefixes()# entry [#slug#]..." ); + + if( len( satisfyingVersion.binaryHash ) && isInstanceOf( endpointData.endpoint, 'HTTP' ) ) { + endpointData.package = endpointData.package & "##" & satisfyingVersion.binaryHash; + } var packagePath = endpointData.endpoint.resolvePackage( endpointData.package, currentWorkingDirectory, arguments.verbose ); // Cheat for people who set a version, slug, or type in ForgeBox, but didn't put it in their box.json diff --git a/src/cfml/system/endpoints/HTTP.cfc b/src/cfml/system/endpoints/HTTP.cfc index 776eccb1..ace59236 100644 --- a/src/cfml/system/endpoints/HTTP.cfc +++ b/src/cfml/system/endpoints/HTTP.cfc @@ -31,6 +31,18 @@ component accessors=true implements="IEndpoint" singleton { } public string function resolvePackage( required string package, string currentWorkingDirectory="", boolean verbose=false ) { + var binaryHash = ''; + // Check if a hash is in the URL and if so, strip it out + if( arguments.package contains '##' ) { + binaryHash = arguments.package.listLast( '##' ); + arguments.package = arguments.package.listFirst( '##' ); + } + + // Double check that the hash is not empty and return it if found + if( binaryHash.len() ) { + return hash( fileReadBinary( binaryHash ), "MD5" ); + } + // Defer to file endpoint return fileEndpoint.resolvePackage( resolvePackageZip( package, arguments.verbose ), From de657f9588c5915e4bc48a0ab28e0d45fe1b8649 Mon Sep 17 00:00:00 2001 From: Javier Quintero Date: Fri, 23 Aug 2024 10:15:36 -0500 Subject: [PATCH 4/7] Move logic to the right location and read the downloaded file instead instead of the hash --- src/cfml/system/endpoints/HTTP.cfc | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/cfml/system/endpoints/HTTP.cfc b/src/cfml/system/endpoints/HTTP.cfc index ace59236..ba94e9ef 100644 --- a/src/cfml/system/endpoints/HTTP.cfc +++ b/src/cfml/system/endpoints/HTTP.cfc @@ -31,18 +31,6 @@ component accessors=true implements="IEndpoint" singleton { } public string function resolvePackage( required string package, string currentWorkingDirectory="", boolean verbose=false ) { - var binaryHash = ''; - // Check if a hash is in the URL and if so, strip it out - if( arguments.package contains '##' ) { - binaryHash = arguments.package.listLast( '##' ); - arguments.package = arguments.package.listFirst( '##' ); - } - - // Double check that the hash is not empty and return it if found - if( binaryHash.len() ) { - return hash( fileReadBinary( binaryHash ), "MD5" ); - } - // Defer to file endpoint return fileEndpoint.resolvePackage( resolvePackageZip( package, arguments.verbose ), @@ -53,6 +41,12 @@ component accessors=true implements="IEndpoint" singleton { } public string function resolvePackageZip( required string package, boolean verbose=false ) { + var binaryHash = ''; + // Check if a hash is in the URL and if so, strip it out + if( package contains '##' ) { + package = package.listFirst( '##' ); + binaryHash = package.listLast( '##' ); + } if( configService.getSetting( 'offlineMode', false ) ) { throw( 'Can''t download [#getNamePrefixes()#:#package#], CommandBox is in offline mode. Go online with [config set offlineMode=false].', 'endpointException' ); @@ -77,6 +71,11 @@ component accessors=true implements="IEndpoint" singleton { job.addLog( "Redirecting to: '#arguments.newURL#'..." ); } ); + + // Validate the binary hash + if( len( binaryHash ) && binaryHash != hash( fileReadBinary( fullPath ), "MD5" ) ) { + throw( 'The binary hash of the downloaded file does not match the expected hash.', 'endpointException' ); + } } catch( UserInterruptException var e ) { if( fileExists( fullPath ) ) { fileDelete( fullPath ); } rethrow; From e490aea6219b8eb8e88a4e99ff49fa934fb6b253 Mon Sep 17 00:00:00 2001 From: Javier Quintero Date: Fri, 23 Aug 2024 15:45:36 -0500 Subject: [PATCH 5/7] Move the validation check outside the try-catch block --- src/cfml/system/endpoints/HTTP.cfc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cfml/system/endpoints/HTTP.cfc b/src/cfml/system/endpoints/HTTP.cfc index ba94e9ef..ad6874d3 100644 --- a/src/cfml/system/endpoints/HTTP.cfc +++ b/src/cfml/system/endpoints/HTTP.cfc @@ -71,11 +71,6 @@ component accessors=true implements="IEndpoint" singleton { job.addLog( "Redirecting to: '#arguments.newURL#'..." ); } ); - - // Validate the binary hash - if( len( binaryHash ) && binaryHash != hash( fileReadBinary( fullPath ), "MD5" ) ) { - throw( 'The binary hash of the downloaded file does not match the expected hash.', 'endpointException' ); - } } catch( UserInterruptException var e ) { if( fileExists( fullPath ) ) { fileDelete( fullPath ); } rethrow; @@ -84,6 +79,11 @@ component accessors=true implements="IEndpoint" singleton { throw( '#e.message##CR##e.detail#', 'endpointException' ); }; + // Validate the binary hash + if( len( binaryHash ) && binaryHash != hash( fileReadBinary( fullPath ), "MD5" ) ) { + throw( 'The binary hash of the downloaded file does not match the expected hash.', 'endpointException' ); + } + return fullPath; } From 69e701404cdaaee21e90f0c857dd3055485e37ab Mon Sep 17 00:00:00 2001 From: Javier Quintero Date: Tue, 3 Sep 2024 15:28:25 -0500 Subject: [PATCH 6/7] Read binaryHash from box.json file and pass the value to forgebox --- src/cfml/system/endpoints/ForgeBox.cfc | 2 +- src/cfml/system/endpoints/HTTP.cfc | 4 ++-- src/cfml/system/util/ForgeBox.cfc | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/cfml/system/endpoints/ForgeBox.cfc b/src/cfml/system/endpoints/ForgeBox.cfc index 3eeb42e0..26179927 100644 --- a/src/cfml/system/endpoints/ForgeBox.cfc +++ b/src/cfml/system/endpoints/ForgeBox.cfc @@ -250,7 +250,7 @@ component accessors="true" implements="IEndpointInteractive" { props.changeLogFormat = 'text'; props.APIToken = getAPIToken(); props.forceUpload = arguments.force; - props.binaryHash = ''; + props.binaryHash = boxJSON?.binaryHash ?: ''; // start upload stuff here var upload = boxJSON.location == "forgeboxStorage"; diff --git a/src/cfml/system/endpoints/HTTP.cfc b/src/cfml/system/endpoints/HTTP.cfc index ad6874d3..b8f36412 100644 --- a/src/cfml/system/endpoints/HTTP.cfc +++ b/src/cfml/system/endpoints/HTTP.cfc @@ -44,8 +44,8 @@ component accessors=true implements="IEndpoint" singleton { var binaryHash = ''; // Check if a hash is in the URL and if so, strip it out if( package contains '##' ) { - package = package.listFirst( '##' ); binaryHash = package.listLast( '##' ); + package = package.listFirst( '##' ); } if( configService.getSetting( 'offlineMode', false ) ) { @@ -81,7 +81,7 @@ component accessors=true implements="IEndpoint" singleton { // Validate the binary hash if( len( binaryHash ) && binaryHash != hash( fileReadBinary( fullPath ), "MD5" ) ) { - throw( 'The binary hash of the downloaded file does not match the expected hash.', 'endpointException' ); + throw( 'The hash of the downloaded file [#hash( fileReadBinary( fullPath ))#] doesn''t match the excepted hash [#binaryHash#] #fullPath#', 'endpointException' ); } return fullPath; diff --git a/src/cfml/system/util/ForgeBox.cfc b/src/cfml/system/util/ForgeBox.cfc index 4973b8e6..f537a4df 100644 --- a/src/cfml/system/util/ForgeBox.cfc +++ b/src/cfml/system/util/ForgeBox.cfc @@ -324,7 +324,8 @@ or just add DEBUG to the root logger string changeLogFormat='text', required string APIToken, string zipPath = "", - boolean forceUpload = false + boolean forceUpload = false, + string binaryHash = "" ) { var formFields = { @@ -339,7 +340,8 @@ or just add DEBUG to the root logger installInstructionsFormat = arguments.installInstructionsFormat, changeLog = arguments.changeLog, changeLogFormat = arguments.changeLogFormat, - forceUpload = arguments.forceUpload + forceUpload = arguments.forceUpload, + binaryHash = arguments.binaryHash }; var requestArguments = { From 124732c3d0e1e26373ea7ecfc8dd548b88952f57 Mon Sep 17 00:00:00 2001 From: Javier Quintero Date: Wed, 4 Sep 2024 09:55:13 -0500 Subject: [PATCH 7/7] Use a variable for the downloaded Binary Hash --- src/cfml/system/endpoints/HTTP.cfc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cfml/system/endpoints/HTTP.cfc b/src/cfml/system/endpoints/HTTP.cfc index b8f36412..33b615d1 100644 --- a/src/cfml/system/endpoints/HTTP.cfc +++ b/src/cfml/system/endpoints/HTTP.cfc @@ -80,8 +80,11 @@ component accessors=true implements="IEndpoint" singleton { }; // Validate the binary hash - if( len( binaryHash ) && binaryHash != hash( fileReadBinary( fullPath ), "MD5" ) ) { - throw( 'The hash of the downloaded file [#hash( fileReadBinary( fullPath ))#] doesn''t match the excepted hash [#binaryHash#] #fullPath#', 'endpointException' ); + if( len( binaryHash ) ) { + var downloadedBinaryHash = hash( fileReadBinary( fullPath ), "MD5" ); + if( binaryHash != downloadedBinaryHash ) { + throw( 'The hash of the downloaded file [#downloadedBinaryHash#] doesn''t match the excepted hash [#binaryHash#] #fullPath#', 'endpointException' ); + } } return fullPath;