@@ -751,15 +751,16 @@ let signCount = 0;
751751/**
752752 * @typedef {{
753753 * SignFileRecordList: {
754- * SignFileList: { SrcPath: string; DstPath: string | null; }[];
754+ * SignFileList: { SrcPath: string; DstPath: string | null }[];
755755 * Certs: Cert;
756+ * MacAppName: string | undefined
756757 * }[]
757758 * }} DDSignFileList
758759 *
759760 * @param {DDSignFileList } filelist
760761 */
761- async function sign ( filelist ) {
762- const data = JSON . stringify ( filelist , undefined , 4 ) ;
762+ async function sign ( filelist , unchangedOutputOkay = false ) {
763+ let data = JSON . stringify ( filelist , undefined , 4 ) ;
763764 console . log ( "filelist:" , data ) ;
764765
765766 if ( ! process . env . MBSIGN_APPFOLDER ) {
@@ -802,6 +803,71 @@ async function sign(filelist) {
802803 return ;
803804 }
804805
806+ const signingWorkaround = true ;
807+
808+ /** @type {{ source: string; target: string }[] } */
809+ const signingWorkaroundFiles = [ ] ;
810+
811+ if ( signingWorkaround ) {
812+ // DstPath is currently broken in the signing tool.
813+ // Copy all of the files to a new tempdir and then leave DstPath unset
814+ // so that it's overwritten, then move the file to the destination.
815+ console . log ( "Working around DstPath bug" ) ;
816+
817+ /** @type {DDSignFileList } */
818+ const newFileList = {
819+ SignFileRecordList : filelist . SignFileRecordList . map ( list => {
820+ return {
821+ Certs : list . Certs ,
822+ SignFileList : list . SignFileList . map ( file => {
823+ const dstPath = file . DstPath ;
824+ if ( dstPath === null ) {
825+ return file ;
826+ }
827+
828+ const src = file . SrcPath ;
829+ // File extensions must be preserved; use a prefix.
830+ const dstPathTemp = `${ path . dirname ( src ) } /signing-temp-${ path . basename ( src ) } ` ;
831+
832+ console . log ( `Copying: ${ src } -> ${ dstPathTemp } ` ) ;
833+ fs . cpSync ( src , dstPathTemp ) ;
834+
835+ signingWorkaroundFiles . push ( { source : dstPathTemp , target : dstPath } ) ;
836+
837+ return {
838+ SrcPath : dstPathTemp ,
839+ DstPath : null ,
840+ } ;
841+ } ) ,
842+ MacAppName : list . MacAppName ,
843+ } ;
844+ } ) ,
845+ } ;
846+
847+ data = JSON . stringify ( newFileList , undefined , 4 ) ;
848+ console . log ( "new filelist:" , data ) ;
849+ }
850+
851+ /** @type {Map<string, string> } */
852+ const srcHashes = new Map ( ) ;
853+
854+ for ( const record of filelist . SignFileRecordList ) {
855+ for ( const file of record . SignFileList ) {
856+ const src = file . SrcPath ;
857+ const dst = file . DstPath ?? src ;
858+
859+ if ( ! fs . existsSync ( src ) ) {
860+ throw new Error ( `Source file does not exist: ${ src } ` ) ;
861+ }
862+
863+ const hash = crypto . createHash ( "sha256" ) . update ( fs . readFileSync ( src ) ) . digest ( "hex" ) ;
864+ srcHashes . set ( src , hash ) ;
865+
866+ console . log ( `Will sign ${ src } -> ${ dst } ` ) ;
867+ console . log ( ` sha256: ${ hash } ` ) ;
868+ }
869+ }
870+
805871 const tmp = await getSignTempDir ( ) ;
806872 const filelistPath = path . resolve ( tmp , `signing-filelist-${ signCount ++ } .json` ) ;
807873 await fs . promises . writeFile ( filelistPath , data ) ;
@@ -814,6 +880,61 @@ async function sign(filelist) {
814880 finally {
815881 await fs . promises . unlink ( filelistPath ) ;
816882 }
883+
884+ if ( signingWorkaround ) {
885+ // Now, copy the files back.
886+ for ( const { source, target } of signingWorkaroundFiles ) {
887+ console . log ( `Moving signed file: ${ source } -> ${ target } ` ) ;
888+ await fs . promises . rename ( source , target ) ;
889+ }
890+ }
891+
892+ /** @type {string[] } */
893+ let failures = [ ] ;
894+
895+ for ( const record of filelist . SignFileRecordList ) {
896+ for ( const file of record . SignFileList ) {
897+ const src = file . SrcPath ;
898+ const dst = file . DstPath ?? src ;
899+
900+ if ( ! fs . existsSync ( dst ) ) {
901+ failures . push ( `Signed file does not exist: ${ dst } ` ) ;
902+ const newSrcHash = crypto . createHash ( "sha256" ) . update ( fs . readFileSync ( src ) ) . digest ( "hex" ) ;
903+ const oldSrcHash = srcHashes . get ( src ) ;
904+ assert ( oldSrcHash ) ;
905+ if ( oldSrcHash !== newSrcHash ) {
906+ failures . push ( ` Source file changed during signing: ${ src } \n before: ${ oldSrcHash } \n after: ${ newSrcHash } ` ) ;
907+ }
908+ continue ;
909+ }
910+
911+ const srcHash = srcHashes . get ( src ) ;
912+ assert ( srcHash ) ;
913+ const dstHash = crypto . createHash ( "sha256" ) . update ( fs . readFileSync ( dst ) ) . digest ( "hex" ) ;
914+ if ( srcHash === dstHash ) {
915+ const message = `Signed file is identical to source file (not signed?): ${ src } -> ${ dst } \n sha256: ${ dstHash } ` ;
916+ if ( unchangedOutputOkay ) {
917+ console . log ( message ) ;
918+ }
919+ else {
920+ failures . push ( message ) ;
921+ continue ;
922+ }
923+ }
924+
925+ if ( src === dst ) {
926+ console . log ( `Signed ${ src } ` ) ;
927+ }
928+ else {
929+ console . log ( `Signed ${ src } -> ${ dst } ` ) ;
930+ }
931+ console . log ( ` sha256: ${ dstHash } ` ) ;
932+ }
933+ }
934+
935+ if ( failures . length ) {
936+ throw new Error ( "Some files failed to sign:\n" + failures . map ( f => " - " + f ) . join ( "\n" ) ) ;
937+ }
817938}
818939
819940/**
@@ -1065,12 +1186,14 @@ export const signNativePreviewPackages = task({
10651186 filelist . SignFileRecordList . push ( {
10661187 SignFileList : filelistPaths . map ( p => ( { SrcPath : p . path , DstPath : null } ) ) ,
10671188 Certs : cert ,
1189+ MacAppName : undefined ,
10681190 } ) ;
10691191 break ;
10701192 case "LinuxSign" :
10711193 filelist . SignFileRecordList . push ( {
10721194 SignFileList : filelistPaths . map ( p => ( { SrcPath : p . path , DstPath : p . path + ".sig" } ) ) ,
10731195 Certs : cert ,
1196+ MacAppName : undefined ,
10741197 } ) ;
10751198 break ;
10761199 case "MacDeveloperHarden" :
@@ -1095,6 +1218,7 @@ export const signNativePreviewPackages = task({
10951218 filelist . SignFileRecordList . push ( {
10961219 SignFileList : macZips . map ( p => ( { SrcPath : p . unsignedZipPath , DstPath : p . signedZipPath } ) ) ,
10971220 Certs : cert ,
1221+ MacAppName : undefined , // MacAppName is only for notarization
10981222 } ) ;
10991223 break ;
11001224 default :
@@ -1115,11 +1239,14 @@ export const signNativePreviewPackages = task({
11151239 {
11161240 SignFileList : macZips . map ( p => ( { SrcPath : p . signedZipPath , DstPath : p . notarizedZipPath } ) ) ,
11171241 Certs : "8020" , // "MacNotarize" (friendly name not supported by the tooling)
1242+ MacAppName : "MicrosoftTypeScript" ,
11181243 } ,
11191244 ] ,
11201245 } ;
11211246
1122- await sign ( notarizeFilelist ) ;
1247+ // Notarizing does not change the file, it just sends it to Apple, so ignore the case
1248+ // where the input files are the same as the output files.
1249+ await sign ( notarizeFilelist , /*unchangedOutputOkay*/ true ) ;
11231250
11241251 // Finally, unzip the notarized files and move them back to their original locations.
11251252
@@ -1234,6 +1361,7 @@ export const signNativePreviewExtensions = task({
12341361 {
12351362 SignFileList : extensions . map ( ( { vsixSignaturePath } ) => ( { SrcPath : vsixSignaturePath , DstPath : null } ) ) ,
12361363 Certs : "VSCodePublisher" ,
1364+ MacAppName : undefined ,
12371365 } ,
12381366 ] ,
12391367 } ) ;
0 commit comments