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