1import { 2 convertKeyPairPEMToKeyPair, 3 convertCertificatePEMToCertificate, 4 validateSelfSignedCertificate, 5} from '@expo/code-signing-certificates'; 6import { getConfig } from '@expo/config'; 7import assert from 'assert'; 8import { promises as fs } from 'fs'; 9import path from 'path'; 10 11import { log } from './utils/log'; 12import { attemptModification } from './utils/modifyConfigAsync'; 13 14type Options = { input?: string }; 15 16export async function configureCodeSigningAsync(projectRoot: string, { input }: Options) { 17 assert(typeof input === 'string', '--input must be a string'); 18 19 const inputDir = path.resolve(projectRoot, input); 20 21 const [certificatePEM, privateKeyPEM, publicKeyPEM] = await Promise.all( 22 ['certificate.pem', 'private-key.pem', 'public-key.pem'].map((fname) => 23 fs.readFile(path.join(inputDir, fname), 'utf8') 24 ) 25 ); 26 27 const certificate = convertCertificatePEMToCertificate(certificatePEM); 28 const keyPair = convertKeyPairPEMToKeyPair({ privateKeyPEM, publicKeyPEM }); 29 validateSelfSignedCertificate(certificate, keyPair); 30 31 const { exp } = getConfig(projectRoot, { skipSDKVersionRequirement: true }); 32 33 // TODO(wschurman) type as ExpoConfig['updates'] when typedefs are updated 34 const fields: any = { 35 codeSigningCertificate: `./${path.relative(projectRoot, inputDir)}/certificate.pem`, 36 codeSigningMetadata: { 37 keyid: 'main', 38 alg: 'rsa-v1_5-sha256', 39 }, 40 }; 41 await attemptModification( 42 projectRoot, 43 { 44 updates: { 45 ...exp.updates, 46 ...fields, 47 }, 48 }, 49 { 50 updates: { 51 ...fields, 52 }, 53 } 54 ); 55 56 log(`Code signing configured for expo-updates (configuration written to app.json)`); 57} 58