153b86b2cSWill Schurmanimport { 253b86b2cSWill Schurman generateKeyPair, 353b86b2cSWill Schurman generateSelfSignedCodeSigningCertificate, 453b86b2cSWill Schurman convertCertificateToCertificatePEM, 553b86b2cSWill Schurman convertKeyPairToPEM, 653b86b2cSWill Schurman} from '@expo/code-signing-certificates'; 753b86b2cSWill Schurmanimport assert from 'assert'; 853b86b2cSWill Schurmanimport { promises as fs } from 'fs'; 953b86b2cSWill Schurmanimport path from 'path'; 1053b86b2cSWill Schurman 11*283c4738SCedric van Puttenimport { ensureDirAsync } from './utils/dir'; 1253b86b2cSWill Schurmanimport { log } from './utils/log'; 1353b86b2cSWill Schurman 143425e61bSWill Schurmantype Options = { 153425e61bSWill Schurman certificateValidityDurationYears: number; 163425e61bSWill Schurman keyOutput: string; 173425e61bSWill Schurman certificateOutput: string; 183425e61bSWill Schurman certificateCommonName: string; 193425e61bSWill Schurman}; 2053b86b2cSWill Schurman 2153b86b2cSWill Schurmanexport async function generateCodeSigningAsync( 2253b86b2cSWill Schurman projectRoot: string, 233425e61bSWill Schurman { certificateValidityDurationYears, keyOutput, certificateOutput, certificateCommonName }: Options 2453b86b2cSWill Schurman) { 253425e61bSWill Schurman const validityDurationYears = Math.floor(certificateValidityDurationYears); 2653b86b2cSWill Schurman 273425e61bSWill Schurman const certificateOutputDir = path.resolve(projectRoot, certificateOutput); 283425e61bSWill Schurman const keyOutputDir = path.resolve(projectRoot, keyOutput); 29*283c4738SCedric van Putten await Promise.all([ensureDirAsync(certificateOutputDir), ensureDirAsync(keyOutputDir)]); 3053b86b2cSWill Schurman 313425e61bSWill Schurman const [certificateOutputDirContents, keyOutputDirContents] = await Promise.all([ 323425e61bSWill Schurman fs.readdir(certificateOutputDir), 333425e61bSWill Schurman fs.readdir(keyOutputDir), 343425e61bSWill Schurman ]); 353425e61bSWill Schurman assert(certificateOutputDirContents.length === 0, 'Certificate output directory must be empty'); 363425e61bSWill Schurman assert(keyOutputDirContents.length === 0, 'Key output directory must be empty'); 3753b86b2cSWill Schurman 3853b86b2cSWill Schurman const keyPair = generateKeyPair(); 3953b86b2cSWill Schurman const validityNotBefore = new Date(); 4053b86b2cSWill Schurman const validityNotAfter = new Date(); 4153b86b2cSWill Schurman validityNotAfter.setFullYear(validityNotAfter.getFullYear() + validityDurationYears); 4253b86b2cSWill Schurman const certificate = generateSelfSignedCodeSigningCertificate({ 4353b86b2cSWill Schurman keyPair, 4453b86b2cSWill Schurman validityNotBefore, 4553b86b2cSWill Schurman validityNotAfter, 463425e61bSWill Schurman commonName: certificateCommonName, 4753b86b2cSWill Schurman }); 4853b86b2cSWill Schurman 4953b86b2cSWill Schurman const keyPairPEM = convertKeyPairToPEM(keyPair); 5053b86b2cSWill Schurman const certificatePEM = convertCertificateToCertificatePEM(certificate); 5153b86b2cSWill Schurman 5253b86b2cSWill Schurman await Promise.all([ 533425e61bSWill Schurman fs.writeFile(path.join(keyOutputDir, 'public-key.pem'), keyPairPEM.publicKeyPEM), 543425e61bSWill Schurman fs.writeFile(path.join(keyOutputDir, 'private-key.pem'), keyPairPEM.privateKeyPEM), 553425e61bSWill Schurman fs.writeFile(path.join(certificateOutputDir, 'certificate.pem'), certificatePEM), 5653b86b2cSWill Schurman ]); 5753b86b2cSWill Schurman 583425e61bSWill Schurman log( 593425e61bSWill Schurman `Generated public and private keys output in ${keyOutputDir}. Remember to add them to .gitignore or to encrypt them. (e.g. with git-crypt)` 603425e61bSWill Schurman ); 613425e61bSWill Schurman log(`Generated code signing certificate output in ${certificateOutputDir}.`); 623425e61bSWill Schurman log( 633425e61bSWill Schurman `To automatically configure this project for code signing, run \`yarn expo-updates codesigning:configure --certificate-input-directory=${certificateOutput} --key-input-directory=${keyOutput}\`.` 643425e61bSWill Schurman ); 6553b86b2cSWill Schurman} 66