"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ensureCertificateValid = ensureCertificateValid;
exports.validateProvisioningProfile = validateProvisioningProfile;
exports.writeExportOptionsPlistFile = writeExportOptionsPlistFile;
exports.buildIPA = buildIPA;
exports.createEntitlementsFile = createEntitlementsFile;
exports.resignIPA = resignIPA;
Object.defineProperty(exports, "findP12CertSerialNumber", {
enumerable: true,
get: function () {
return _PKCS12Utils().findP12CertSerialNumber;
}
});
exports.resolveExportMethod = void 0;
function _lodash() {
const data = _interopRequireDefault(require("lodash"));
_lodash = function () {
return data;
};
return data;
}
function _fsExtra() {
const data = _interopRequireDefault(require("fs-extra"));
_fsExtra = function () {
return data;
};
return data;
}
function _path() {
const data = _interopRequireDefault(require("path"));
_path = function () {
return data;
};
return data;
}
function _globPromise() {
const data = _interopRequireDefault(require("glob-promise"));
_globPromise = function () {
return data;
};
return data;
}
function _plist() {
const data = _interopRequireDefault(require("plist"));
_plist = function () {
return data;
};
return data;
}
function _crypto() {
const data = _interopRequireDefault(require("crypto"));
_crypto = function () {
return data;
};
return data;
}
function _PKCS12Utils() {
const data = require("./PKCS12Utils");
_PKCS12Utils = function () {
return data;
};
return data;
}
function _ExponentTools() {
const data = require("./ExponentTools");
_ExponentTools = function () {
return data;
};
return data;
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
async function ensureCertificateValid({
certPath,
certPassword,
teamID
}) {
const certData = await _fsExtra().default.readFile(certPath);
const fingerprint = (0, _PKCS12Utils().getP12CertFingerprint)(certData, certPassword);
const identities = await _findIdentitiesByTeamID(teamID);
const isValid = identities.indexOf(fingerprint) !== -1;
if (!isValid) {
throw new Error(`codesign ident not present in find-identity: ${fingerprint}\n${identities}`);
}
return fingerprint;
}
async function _findIdentitiesByTeamID(teamID) {
const {
output
} = await (0, _ExponentTools().spawnAsyncThrowError)('security', ['find-identity', '-v', '-s', `(${teamID})`], {
stdio: 'pipe'
});
return output.join('');
}
function validateProvisioningProfile(plistData, {
distCertFingerprint,
bundleIdentifier
}) {
_ensureDeveloperCertificateIsValid(plistData, distCertFingerprint);
_ensureBundleIdentifierIsValid(plistData, bundleIdentifier);
}
function _ensureDeveloperCertificateIsValid(plistData, distCertFingerprint) {
const devCertBase64 = plistData.DeveloperCertificates[0];
const devCertFingerprint = _genDerCertFingerprint(devCertBase64);
if (devCertFingerprint !== distCertFingerprint) {
throw new Error('validateProvisioningProfile: provisioning profile is not associated with uploaded distribution certificate');
}
}
function _genDerCertFingerprint(certBase64) {
const certBuffer = Buffer.from(certBase64, 'base64');
return _crypto().default.createHash('sha1').update(certBuffer).digest('hex').toUpperCase();
}
function _ensureBundleIdentifierIsValid(plistData, expectedBundleIdentifier) {
const actualApplicationIdentifier = plistData.Entitlements['application-identifier'];
const actualBundleIdentifier = /\.(.+)/.exec(actualApplicationIdentifier)[1];
if (expectedBundleIdentifier !== actualBundleIdentifier) {
throw new Error(`validateProvisioningProfile: wrong bundleIdentifier found in provisioning profile; expected: ${expectedBundleIdentifier}, found (in provisioning profile): ${actualBundleIdentifier}`);
}
}
async function writeExportOptionsPlistFile(plistPath, data) {
const toWrite = createExportOptionsPlist(data);
await _fsExtra().default.writeFile(plistPath, toWrite);
}
const createExportOptionsPlist = ({
bundleIdentifier,
provisioningProfileUUID,
exportMethod,
teamID
}) => {
const disableBitcodeCompiling = `<key>uploadBitcode</key>
<false/>
<key>compileBitcode</key>
<false/>
<key>uploadSymbols</key>
<false/>`;
return `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>${exportMethod}</string>
<key>teamID</key>
<string>${teamID}</string>
<key>provisioningProfiles</key>
<dict>
<key>${bundleIdentifier}</key>
<string>${provisioningProfileUUID}</string>
</dict>
${exportMethod === 'ad-hoc' || exportMethod === 'enterprise' ? disableBitcodeCompiling : ''}
</dict>
</plist>`;
};
async function buildIPA({
ipaPath,
workspacePath,
archivePath,
codeSignIdentity,
exportOptionsPlistPath,
plistData,
keychainPath,
exportMethod
}, credentials, client = false) {
if (client) {
await (0, _ExponentTools().spawnAsyncThrowError)('xcodebuild', ['-exportArchive', '-archivePath', archivePath, '-exportOptionsPlist', exportOptionsPlistPath, '-exportPath', _path().default.Dir(ipaPath), `OTHER_CODE_SIGN_FLAGS="--keychain ${keychainPath}"`], {
env: { ...process.env,
CI: 1
}
});
} else {
await runFastlane(credentials, ['gym', '-n', _path().default.basename(ipaPath), '--workspace', workspacePath, '--archive_path', archivePath, '--skip_build_archive', 'true', '-i', codeSignIdentity, '--export_options', exportOptionsPlistPath, '--export_method', exportMethod, '--export_xcargs', `OTHER_CODE_SIGN_FLAGS="--keychain ${keychainPath}"`, '-o', _path().default.dirname(ipaPath), '--verbose'], {
buildPhase: 'building and signing IPA'
});
}
}
const resolveExportMethod = plistData => {
if (plistData.ProvisionedDevices) {
return 'ad-hoc';
} else if (plistData.ProvisionsAllDevices === true) {
return 'enterprise';
} else {
return 'app-store';
}
};
exports.resolveExportMethod = resolveExportMethod;
const entitlementTransferRules = ['com.apple.developer.associated-domains', 'com.apple.developer.healthkit', 'com.apple.developer.homekit', 'com.apple.developer.icloud-container-identifiers', 'com.apple.developer.icloud-services', 'com.apple.developer.in-app-payments', 'com.apple.developer.networking.vpn.api', 'com.apple.developer.ubiquity-container-identifiers', 'com.apple.developer.ubiquity-kvstore-identifier', 'com.apple.external-accessory.wireless-configuration', 'com.apple.security.application-groups', 'inter-app-audio', 'keychain-access-groups'];
const blacklistedEntitlementKeysWithoutICloud = ['com.apple.developer.icloud-container-environment', 'com.apple.developer.icloud-container-identifiers', 'com.apple.developer.icloud-services', 'com.apple.developer.ubiquity-container-identifiers', 'com.apple.developer.ubiquity-kvstore-identifier'];
const blacklistedEntitlementKeys = ['com.apple.developer.icloud-container-development-container-identifiers', 'com.apple.developer.restricted-resource-mode', 'inter-app-audio', 'com.apple.developer.homekit', 'com.apple.developer.healthkit', 'com.apple.developer.in-app-payments', 'com.apple.developer.maps', 'com.apple.external-accessory.wireless-configuration'];
const icloudContainerEnvKey = 'com.apple.developer.icloud-container-environment';
async function createEntitlementsFile({
generatedEntitlementsPath,
plistData,
archivePath,
manifest
}) {
const decodedProvisioningProfileEntitlements = plistData.Entitlements;
const entitlementsPattern = _path().default.join(archivePath, 'Products/Applications/*.app/*.entitlements');
const entitlementsPaths = await (0, _globPromise().default)(entitlementsPattern);
if (entitlementsPaths.length === 0) {
throw new Error("Didn't find any generated entitlements file in archive.");
} else if (entitlementsPaths.length !== 1) {
throw new Error('Found more than one entitlements file.');
}
const archiveEntitlementsPath = entitlementsPaths[0];
const archiveEntitlementsRaw = await _fsExtra().default.readFile(archiveEntitlementsPath);
const archiveEntitlementsData = _lodash().default.attempt(_plist().default.parse, String(archiveEntitlementsRaw));
if (_lodash().default.isError(archiveEntitlementsData)) {
throw new Error(`Error when parsing plist: ${archiveEntitlementsData.message}`);
}
const entitlements = { ...decodedProvisioningProfileEntitlements
};
entitlementTransferRules.forEach(rule => {
if (rule in archiveEntitlementsData) {
entitlements[rule] = archiveEntitlementsData[rule];
}
});
let generatedEntitlements = _lodash().default.omit(entitlements, blacklistedEntitlementKeys);
if (!manifest.ios.usesIcloudStorage) {
generatedEntitlements = _lodash().default.omit(generatedEntitlements, blacklistedEntitlementKeysWithoutICloud);
} else {
const ubiquityKvKey = 'com.apple.developer.ubiquity-kvstore-identifier';
if (generatedEntitlements[ubiquityKvKey]) {
const teamId = generatedEntitlements[ubiquityKvKey].split('.')[0];
generatedEntitlements[ubiquityKvKey] = `${teamId}.${manifest.ios.bundleIdentifier}`;
}
generatedEntitlements['com.apple.developer.icloud-services'] = ['CloudDocuments'];
}
if (!manifest.ios.associatedDomains) {
generatedEntitlements = _lodash().default.omit(generatedEntitlements, 'com.apple.developer.associated-domains');
}
if (!manifest.ios.usesAppleSignIn) {
generatedEntitlements = _lodash().default.omit(generatedEntitlements, 'com.apple.developer.applesignin');
}
if (generatedEntitlements[icloudContainerEnvKey]) {
const envs = generatedEntitlements[icloudContainerEnvKey].filter(i => i === 'Production');
generatedEntitlements[icloudContainerEnvKey] = envs;
}
const generatedEntitlementsPlistData = _lodash().default.attempt(_plist().default.build, generatedEntitlements);
await _fsExtra().default.writeFile(generatedEntitlementsPath, generatedEntitlementsPlistData, {
mode: 0o755
});
const {
output
} = await (0, _ExponentTools().spawnAsyncThrowError)('/usr/libexec/PlistBuddy', ['-x', '-c', 'Print', generatedEntitlementsPath], {
stdio: 'pipe'
});
const plistDataReformatted = output.join('');
await _fsExtra().default.writeFile(generatedEntitlementsPath, plistDataReformatted, {
mode: 0o755
});
}
async function resignIPA({
codeSignIdentity,
entitlementsPath,
provisioningProfilePath,
sourceIpaPath,
destIpaPath,
keychainPath
}, credentials) {
await (0, _ExponentTools().spawnAsyncThrowError)('cp', ['-rf', sourceIpaPath, destIpaPath]);
await runFastlane(credentials, ['sigh', 'resign', '--verbose', '--entitlements', entitlementsPath, '--signing_identity', codeSignIdentity, '--keychain_path', keychainPath, '--provisioning_profile', provisioningProfilePath, destIpaPath], {
buildPhase: 'building and signing IPA'
});
}
async function runFastlane({
teamID
}, fastlaneArgs, loggerFields) {
const fastlaneEnvVars = {
FASTLANE_SKIP_UPDATE_CHECK: 1,
FASTLANE_DISABLE_COLORS: 1,
FASTLANE_TEAM_ID: teamID,
CI: 1,
LC_ALL: 'en_US.UTF-8'
};
await (0, _ExponentTools().spawnAsyncThrowError)('fastlane', fastlaneArgs, {
env: { ...process.env,
...fastlaneEnvVars
},
pipeToLogger: true,
dontShowStdout: false,
loggerFields
});
}
//# sourceMappingURL=../__sourcemaps__/detach/IosCodeSigning.js.map