2020-11-29 19:15:42 +02:00
const fs = require ( 'fs' ) ;
const path = require ( 'path' ) ;
const electron _notarize = require ( 'electron-notarize' ) ;
2020-12-05 13:06:20 +02:00
function execCommand ( command ) {
const exec = require ( 'child_process' ) . exec ;
return new Promise ( ( resolve , reject ) => {
exec ( command , ( error , stdout , stderr ) => {
if ( error ) {
2022-07-23 11:33:12 +02:00
if ( error . signal === 'SIGTERM' ) {
2020-12-05 13:06:20 +02:00
resolve ( 'Process was killed' ) ;
} else {
reject ( new Error ( [ stdout . trim ( ) , stderr . trim ( ) ] . join ( '\n' ) ) ) ;
}
} else {
resolve ( [ stdout . trim ( ) , stderr . trim ( ) ] . join ( '\n' ) ) ;
}
} ) ;
} ) ;
}
2021-06-15 17:05:26 +02:00
function isDesktopAppTag ( tagName ) {
if ( ! tagName ) return false ;
return tagName [ 0 ] === 'v' ;
}
2020-11-29 19:15:42 +02:00
module . exports = async function ( params ) {
if ( process . platform !== 'darwin' ) return ;
console . info ( 'Checking if notarization should be done...' ) ;
2021-06-15 17:05:26 +02:00
if ( ! process . env . IS _CONTINUOUS _INTEGRATION || ! isDesktopAppTag ( process . env . GIT _TAG _NAME ) ) {
console . info ( ` Either not running in CI or not processing a desktop app tag - skipping notarization. process.env.IS_CONTINUOUS_INTEGRATION = ${ process . env . IS _CONTINUOUS _INTEGRATION } ; process.env.GIT_TAG_NAME = ${ process . env . GIT _TAG _NAME } ` ) ;
2020-11-29 19:15:42 +02:00
return ;
}
if ( ! process . env . APPLE _ID || ! process . env . APPLE _ID _PASSWORD ) {
console . warn ( 'Environment variables APPLE_ID and APPLE_ID_PASSWORD not found - notarization will NOT be done.' ) ;
return ;
}
// Same appId in electron-builder.
const appId = 'net.cozic.joplin-desktop' ;
const appPath = path . join ( params . appOutDir , ` ${ params . packager . appInfo . productFilename } .app ` ) ;
if ( ! fs . existsSync ( appPath ) ) {
throw new Error ( ` Cannot find application at: ${ appPath } ` ) ;
}
console . log ( ` Notarizing ${ appId } found at ${ appPath } ` ) ;
2021-06-10 17:02:52 +02:00
// Every x seconds we print something to stdout, otherwise CI may timeout
// the task after 10 minutes, and Apple notarization can take more time.
2021-01-28 00:11:40 +02:00
const waitingIntervalId = setInterval ( ( ) => {
console . log ( '.' ) ;
} , 60000 ) ;
2021-06-23 16:27:06 +02:00
try {
await electron _notarize . notarize ( {
appBundleId : appId ,
appPath : appPath ,
// Apple Developer email address
appleId : process . env . APPLE _ID ,
// App-specific password: https://support.apple.com/en-us/HT204397
appleIdPassword : process . env . APPLE _ID _PASSWORD ,
// When Apple ID is attached to multiple providers (eg if the
// account has been used to build multiple apps for different
// companies), in that case the provider "Team Short Name" (also
// known as "ProviderShortname") must be provided.
//
// Use this to get it:
//
// xcrun altool --list-providers -u APPLE_ID -p APPLE_ID_PASSWORD
ascProvider : process . env . APPLE _ASC _PROVIDER ,
} ) ;
} catch ( error ) {
console . error ( error ) ;
process . exit ( 1 ) ;
}
2020-11-29 19:15:42 +02:00
2021-01-28 00:11:40 +02:00
clearInterval ( waitingIntervalId ) ;
2020-12-05 14:18:31 +02:00
// It appears that electron-notarize doesn't staple the app, but without
// this we were still getting the malware warning when launching the app.
// Stapling the app means attaching the notarization ticket to it, so that
// if the user is offline, macOS can still check if the app was notarized.
// So it seems to be more or less optional, but at least in our case it
// wasn't.
2020-12-05 13:06:20 +02:00
console . log ( 'Staple notarization ticket to the app...' ) ;
const staplerCmd = ` xcrun stapler staple " ${ appPath } " ` ;
console . log ( ` > ${ staplerCmd } ` ) ;
console . log ( await execCommand ( staplerCmd ) ) ;
2020-11-29 19:15:42 +02:00
console . log ( ` Done notarizing ${ appId } ` ) ;
} ;