UNPKG

applesign

Version:
301 lines (274 loc) 11.9 kB
'use strict'; const path = require('path'); const idprov = require('./idprov'); const shortHelpMessage = `Usage: applesign [--options ...] [target.ipa | Payload/Target.app] -a, --all Resign all binaries, even it unrelated to the app -b, --bundleid [BUNDLEID] Change the bundleid when repackaging -c, --clone-entitlements Clone the entitlements from the provisioning to the bin -D, --device-provision Automatically find the mobileprovision for the available device -f, --force-family Force UIDeviceFamily in Info.plist to be iPhone -h, --help Show verbose help message -H, --allow-http Add NSAppTransportSecurity.NSAllowsArbitraryLoads in plist -i, --identity [1C4D1A..] Specify hash-id of the identity to use -L, --identities List local codesign identities -m, --mobileprovision [FILE] Specify the mobileprovision file to use -o, --output [APP.IPA] Path to the output IPA filename -O, --osversion 9.0 Force specific OSVersion if any in Info.plist -p, --without-plugins Remove plugins (excluding XCTests) from the resigned IPA -w, --without-watchapp Remove the WatchApp from the IPA before resigning -x, --without-xctests Remove the XCTests from the resigned IPA Example: $ applesign -w -c -m embedded.mobileprovision target.ipa `; const helpMessage = `Usage: applesign [--options ...] [input-ipafile] Packaging: -7, --use-7zip Use 7zip instead of unzip -A, --all-dirs Archive all directories, not just Payload/ -I, --insert [frida.dylib] Insert a dynamic library to the main executable -l, --lipo [arm64|armv7] Lipo -thin all bins inside the IPA for the given architecture -n, --noclean keep temporary files when signing error happens -o, --output [APP.IPA] Path to the output IPA filename -P, --parallel Run layered signing dependencies in parallel (EXPERIMENTAL) -r, --replace Replace the input IPA file with the resigned one -u, --unfair Resign encrypted applications -z, --ignore-zip-errors Ignore unzip/7z uncompressing errors Stripping: -F, --without-signing-files Remove signing related files -p, --without-plugins Remove plugins (excluding XCTests) from the resigned IPA -w, --without-watchapp Remove the WatchApp from the IPA before resigning -x, --without-xctests Remove the XCTests from the resigned IPA Signing: --use-openssl Use OpenSSL cms instead of Apple's security tool (EXPERIMENTAL) -a, --all Resign all binaries, even it unrelated to the app -d, --debug [file] Create debug file with all the signing process -D, --device-provision Automatically find the mobileprovision for the available device -i, --identity [1C4D1A..] Specify hash-id of the identity to use -j, --json '{}' Set the alternative JSON for signing files with custom entitlements -k, --keychain [KEYCHAIN] Specify custom keychain file -K, --add-access-group [NAME] Add $(TeamIdentifier).NAME to keychain-access-groups -L, --identities List local codesign identities -m, --mobileprovision [FILE] Specify the mobileprovision file to use -s, --single Sign a single file instead of an IPA -S, --self-sign-provision Self-sign mobile provisioning (EXPERIMENTAL) -v, --verify Verify all the signed files at the end -V, --verify-twice Verify after signing every file and at the end -Z, --pseudo-sign Pseudo sign the binaries (EXPERIMENTAL) Info.plist -b, --bundleid [BUNDLEID] Change the bundleid when repackaging -B, --bundleid-access-group Add $(TeamIdentifier).bundleid to keychain-access-groups -f, --force-family Force UIDeviceFamily in Info.plist to be iPhone -H, --allow-http Add NSAppTransportSecurity.NSAllowsArbitraryLoads in plist -O, --osversion 9.0 Force specific OSVersion if any in Info.plist Entitlements: -c, --clone-entitlements Clone the entitlements from the provisioning to the bin -e, --entitlements [ENTITL] Specify entitlements file (EXPERIMENTAL) -E, --entry-entitlement Use generic entitlement (EXPERIMENTAL) -N, --add-entitlements [FILE] Append entitlements from file (EXPERIMENTAL) -M, --massage-entitlements Massage entitlements to remove privileged ones -t, --without-get-task-allow Do not set the get-task-allow entitlement (EXPERIMENTAL) -C, --no-entitlements-file Do not create .entitlements file in the IPA -h, --help Show this help message --version Show applesign version [input-ipafile] Path to the IPA file to resign Examples: $ applesign -L # enumerate codesign identities, grab one and use it with -i $ applesign -m embedded.mobileprovision target.ipa $ applesign -i AD71EB42BC289A2B9FD3C2D5C9F02D923495A23C target.ipa $ applesign -m a.mobileprovision -c --lipo arm64 -w target.ipa $ applesign -m a.mobileprovision -j '{"custom":[{"filematch":"ShareExtension$","entitlements":"/tmp/foo.ent"}]}' target.ipa Installing in the device: $ ideviceinstaller -i target-resigned.ipa $ ios-deploy -b target-resigned.ipa `; /* // Expected format: // ---------------- { "custom": [ { "filematch": "ShareExtension$", "entitlements": "/tmp/share.entitlements", "__identity": "83498489489X", } ] } */ const fromOptions = function (opt) { if (typeof opt !== 'object') { opt = {}; } if (opt.osversion !== undefined) { if (isNaN(+opt.osversion)) { throw new Error('Version passed to -O must be numeric'); } } if (opt.mobileprovision) { if (Array.isArray(opt.mobileprovision)) { opt.mobileprovisions = opt.mobileprovision; opt.mobileprovision = opt.mobileprovision[0]; // throw new Error('Multiple mobile provisionings not yet supported'); } const mp = opt.mobileprovision; opt.mobileprovisions = [mp]; if (opt.identity) { const id0 = idprov(mp); const id1 = opt.identity; if (id0 !== id1) { // throw new Error('MobileProvisioningVersion doesn\'t match the given identity (' + id0 + ' vs ' + id1 + ')'); } } else { opt.identity = idprov(mp); } } else { opt.mobileprovision = undefined; opt.mobileprovisions = []; } return { all: opt.all || false, allDirs: opt.allDirs || true, allowHttp: opt.allowHttp || false, addEntitlements: opt.addEntitlements || undefined, bundleIdKeychainGroup: opt.bundleIdKeychainGroup || false, bundleid: opt.bundleid || undefined, cloneEntitlements: opt.cloneEntitlements || false, customKeychainGroup: opt.customKeychainGroup || undefined, debug: opt.d || opt.debug || '', deviceProvision: opt.D || opt.deviceProvision || false, entitlement: opt.entitlement || undefined, entry: opt.entry || undefined, file: opt.file ? path.resolve(opt.file) : undefined, forceFamily: opt.forceFamily || false, identity: opt.identity || undefined, ignoreCodesignErrors: true, ignoreVerificationErrors: true, ignoreZipErrors: opt.ignoreZipErrors || false, insertLibrary: opt.insertLibrary || undefined, json: JSON.parse(opt.json || '{}'), keychain: opt.keychain, lipoArch: opt.lipoArch || undefined, massageEntitlements: opt.massageEntitlements || false, mobileprovision: opt.mobileprovision, mobileprovisions: opt.mobileprovisions, noEntitlementsFile: opt.noEntitlementsFile || false, noclean: opt.noclean || false, osversion: opt.osversion || undefined, outdir: undefined, outfile: opt.outfile, parallel: opt.parallel || false, pseudoSign: opt.pseudoSign || false, replaceipa: opt.replaceipa || false, run: opt.run, selfSignedProvision: opt.selfSignedProvision || false, unfairPlay: opt.unfairPlay || false, use7zip: opt.use7zip === true, useOpenSSL: opt.useOpenSSL === true, verify: opt.verify || false, verifyTwice: opt.verifyTwice || false, withGetTaskAllow: opt.withGetTaskAllow, withoutPlugins: opt.withoutPlugins || false, withoutSigningFiles: opt.withoutSigningFiles || false, withoutWatchapp: opt.withoutWatchapp || false, withoutXCTests: opt.withoutXCTests || false }; }; const fromState = function (state) { return JSON.parse(JSON.stringify(state)); }; function parse (argv) { return require('minimist')(argv.slice(2), { string: [ 'd', 'debug', 'j', 'json', 'i', 'identity', 'O', 'osversion', 'R', 'run' ], boolean: [ '7', 'use-7zip', 'A', 'all-dirs', 'B', 'bundleid-access-group', 'C', 'no-entitlements-file', 'D', 'device-provision', 'E', 'entry-entitlement', 'F', 'without-signing-files', 'H', 'allow-http', 'L', 'identities', 'M', 'massage-entitlements', 'P', 'parallel', 'S', 'self-signed-provision', 'V', 'verify-twice', 'Z', 'pseudo-sign', 'a', 'all', 'c', 'clone-entitlements', 'f', 'force-family', 'n', 'noclean', 'p', 'without-plugins', 'r', 'replace', 's', 'single', 't', 'without-get-task-allow', 'u', 'unfair', 'u', 'unsigned-provision', 'v', 'verify', 'w', 'without-watchapp', 'x', 'without-xctests', 'z', 'ignore-zip-errors' ] }); } function compile (conf) { const options = { all: conf.a || conf.all || false, allDirs: conf['all-dirs'] || conf.A, allowHttp: conf['allow-http'] || conf.H, addEntitlements: conf['add-entitlements'] || conf.N, bundleIdKeychainGroup: conf.B || conf['bundleid-access-group'], bundleid: conf.bundleid || conf.b, cloneEntitlements: conf.c || conf['clone-entitlements'], customKeychainGroup: conf.K || conf['add-access-group'], debug: conf.debug || conf.d || '', deviceProvision: conf.D || conf.deviceProvision || false, entitlement: conf.entitlement || conf.e, entry: conf['entry-entitlement'] || conf.E, file: conf._[0] || undefined, forceFamily: conf['force-family'] || conf.f, identity: conf.identity || conf.i, ignoreZipErrors: conf.z || conf['ignore-zip-errors'], insertLibrary: conf.I || conf.insert, json: conf.json || conf.j, keychain: conf.keychain || conf.k, lipoArch: conf.lipo || conf.l, massageEntitlements: conf['massage-entitlements'] || conf.M, mobileprovision: conf.mobileprovision || conf.m, noEntitlementsFile: conf.C || conf['no-entitlements-file'] || conf.noEntitlementsFile, noclean: conf.n || conf.noclean, osversion: conf.osversion || conf.O, outfile: (conf.output || conf.o) ? path.resolve(conf.output || conf.o) : '', parallel: conf.parallel || conf.P, pseudoSign: conf.Z || conf['pseudo-sign'], replaceipa: conf.replace || conf.r, run: conf.R || conf.run, selfSignedProvision: conf.S || conf['self-signed-provision'], single: conf.single || conf.s, unfairPlay: conf.unfair || conf.u, use7zip: conf['7'] || conf['use-7zip'], useOpenSSL: conf['use-openssl'], verify: conf.v || conf.V || conf.verify || conf['verify-twice'], verifyTwice: conf.V || conf['verify-twice'], withGetTaskAllow: !(conf['without-get-task-allow'] || conf.t), withoutPlugins: !!conf['without-plugins'] || !!conf.p, withoutSigningFiles: !!conf['without-signing-files'] || !!conf.F, withoutWatchapp: !!conf['without-watchapp'] || !!conf.w, withoutXCTests: !!conf['without-xctests'] || !!conf.x }; return options; } module.exports = { compile, fromOptions, fromState, helpMessage, parse, shortHelpMessage };