|
|
"use strict";
|
|
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
|
value: true
|
|
|
});
|
|
|
exports.UseExistingDistributionCert = exports.UpdateIosDist = exports.RemoveIosDist = exports.CreateOrReuseDistributionCert = exports.CreateIosDist = void 0;
|
|
|
exports.getDistCertFromParams = getDistCertFromParams;
|
|
|
exports.useDistCertFromParams = useDistCertFromParams;
|
|
|
exports.validateDistributionCertificate = validateDistributionCertificate;
|
|
|
function _chalk() {
|
|
|
const data = _interopRequireDefault(require("chalk"));
|
|
|
_chalk = function () {
|
|
|
return data;
|
|
|
};
|
|
|
return data;
|
|
|
}
|
|
|
function _dateformat() {
|
|
|
const data = _interopRequireDefault(require("dateformat"));
|
|
|
_dateformat = function () {
|
|
|
return data;
|
|
|
};
|
|
|
return data;
|
|
|
}
|
|
|
function _fsExtra() {
|
|
|
const data = _interopRequireDefault(require("fs-extra"));
|
|
|
_fsExtra = function () {
|
|
|
return data;
|
|
|
};
|
|
|
return data;
|
|
|
}
|
|
|
function _terminalLink() {
|
|
|
const data = _interopRequireDefault(require("terminal-link"));
|
|
|
_terminalLink = function () {
|
|
|
return data;
|
|
|
};
|
|
|
return data;
|
|
|
}
|
|
|
function _xdl() {
|
|
|
const data = require("xdl");
|
|
|
_xdl = function () {
|
|
|
return data;
|
|
|
};
|
|
|
return data;
|
|
|
}
|
|
|
function _CommandError() {
|
|
|
const data = _interopRequireDefault(require("../../CommandError"));
|
|
|
_CommandError = function () {
|
|
|
return data;
|
|
|
};
|
|
|
return data;
|
|
|
}
|
|
|
function _appleApi() {
|
|
|
const data = require("../../appleApi");
|
|
|
_appleApi = function () {
|
|
|
return data;
|
|
|
};
|
|
|
return data;
|
|
|
}
|
|
|
function _log() {
|
|
|
const data = _interopRequireDefault(require("../../log"));
|
|
|
_log = function () {
|
|
|
return data;
|
|
|
};
|
|
|
return data;
|
|
|
}
|
|
|
function _ora() {
|
|
|
const data = require("../../utils/ora");
|
|
|
_ora = function () {
|
|
|
return data;
|
|
|
};
|
|
|
return data;
|
|
|
}
|
|
|
function _prompts() {
|
|
|
const data = _interopRequireWildcard(require("../../utils/prompts"));
|
|
|
_prompts = function () {
|
|
|
return data;
|
|
|
};
|
|
|
return data;
|
|
|
}
|
|
|
function _list() {
|
|
|
const data = require("../actions/list");
|
|
|
_list = function () {
|
|
|
return data;
|
|
|
};
|
|
|
return data;
|
|
|
}
|
|
|
function _promptForCredentials() {
|
|
|
const data = require("../actions/promptForCredentials");
|
|
|
_promptForCredentials = function () {
|
|
|
return data;
|
|
|
};
|
|
|
return data;
|
|
|
}
|
|
|
function _IosApi() {
|
|
|
const data = require("../api/IosApi");
|
|
|
_IosApi = function () {
|
|
|
return data;
|
|
|
};
|
|
|
return data;
|
|
|
}
|
|
|
function _credentials() {
|
|
|
const data = require("../credentials");
|
|
|
_credentials = function () {
|
|
|
return data;
|
|
|
};
|
|
|
return data;
|
|
|
}
|
|
|
function _IosProvisioningProfile() {
|
|
|
const data = require("./IosProvisioningProfile");
|
|
|
_IosProvisioningProfile = function () {
|
|
|
return data;
|
|
|
};
|
|
|
return data;
|
|
|
}
|
|
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
const APPLE_DIST_CERTS_TOO_MANY_GENERATED_ERROR = `
|
|
|
You can have only ${_chalk().default.underline('three')} Apple Distribution Certificates generated on your Apple Developer account.
|
|
|
Please revoke the old ones or reuse existing from your other apps.
|
|
|
Please remember that Apple Distribution Certificates are not application specific!
|
|
|
`;
|
|
|
class CreateIosDist {
|
|
|
constructor(accountName) {
|
|
|
this.accountName = accountName;
|
|
|
}
|
|
|
async create(ctx) {
|
|
|
const newDistCert = await this.provideOrGenerate(ctx);
|
|
|
return await ctx.ios.createDistCert(this.accountName, newDistCert);
|
|
|
}
|
|
|
async open(ctx) {
|
|
|
const distCert = await this.create(ctx);
|
|
|
_log().default.log(_chalk().default.green('Successfully created Distribution Certificate\n'));
|
|
|
(0, _list().displayIosUserCredentials)(distCert);
|
|
|
_log().default.log();
|
|
|
return null;
|
|
|
}
|
|
|
async provideOrGenerate(ctx) {
|
|
|
if (!ctx.nonInteractive) {
|
|
|
const userProvided = await promptForDistCert(ctx);
|
|
|
if (userProvided) {
|
|
|
const isValid = await validateDistributionCertificate(ctx, userProvided);
|
|
|
return isValid ? userProvided : await this.provideOrGenerate(ctx);
|
|
|
}
|
|
|
}
|
|
|
return await generateDistCert(ctx, this.accountName);
|
|
|
}
|
|
|
}
|
|
|
exports.CreateIosDist = CreateIosDist;
|
|
|
class RemoveIosDist {
|
|
|
constructor(accountName, shouldRevoke = false) {
|
|
|
this.accountName = accountName;
|
|
|
this.shouldRevoke = shouldRevoke;
|
|
|
}
|
|
|
async open(ctx) {
|
|
|
const selected = await selectDistCertFromList(ctx, this.accountName);
|
|
|
if (selected) {
|
|
|
await this.removeSpecific(ctx, selected);
|
|
|
_log().default.log(_chalk().default.green('Successfully removed Distribution Certificate\n'));
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
async removeSpecific(ctx, selected) {
|
|
|
const credentials = await ctx.ios.getAllCredentials(this.accountName);
|
|
|
const apps = credentials.appCredentials.filter(cred => cred.distCredentialsId === selected.id);
|
|
|
const appsList = apps.map(appCred => _chalk().default.green(appCred.experienceName)).join(', ');
|
|
|
if (appsList && !ctx.nonInteractive) {
|
|
|
_log().default.log('Removing Distribution Certificate');
|
|
|
const confirm = await (0, _prompts().confirmAsync)({
|
|
|
message: `You are removing certificate used by ${appsList}. Do you want to continue?`
|
|
|
});
|
|
|
if (!confirm) {
|
|
|
_log().default.log('Aborting');
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
_log().default.log('Removing Distribution Certificate...\n');
|
|
|
await ctx.ios.deleteDistCert(selected.id, this.accountName);
|
|
|
let shouldRevoke = this.shouldRevoke;
|
|
|
if (selected.certId) {
|
|
|
if (!shouldRevoke && !ctx.nonInteractive) {
|
|
|
const revoke = await (0, _prompts().confirmAsync)({
|
|
|
message: `Do you also want to revoke it on Apple Developer Portal?`
|
|
|
});
|
|
|
shouldRevoke = revoke;
|
|
|
}
|
|
|
if (shouldRevoke) {
|
|
|
await ctx.ensureAppleCtx();
|
|
|
await new (_appleApi().DistCertManager)(ctx.appleCtx).revoke([selected.certId]);
|
|
|
}
|
|
|
}
|
|
|
for (const appCredentials of apps) {
|
|
|
const appLookupParams = (0, _IosApi().getAppLookupParams)(appCredentials.experienceName, appCredentials.bundleIdentifier);
|
|
|
if (!(await ctx.ios.getProvisioningProfile(appLookupParams))) {
|
|
|
continue;
|
|
|
}
|
|
|
_log().default.log(`Removing Provisioning Profile for ${appCredentials.experienceName} (${appCredentials.bundleIdentifier})`);
|
|
|
const view = new (_IosProvisioningProfile().RemoveProvisioningProfile)(this.accountName, shouldRevoke);
|
|
|
await view.removeSpecific(ctx, appLookupParams);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
exports.RemoveIosDist = RemoveIosDist;
|
|
|
class UpdateIosDist {
|
|
|
constructor(accountName) {
|
|
|
this.accountName = accountName;
|
|
|
}
|
|
|
async open(ctx) {
|
|
|
const selected = await selectDistCertFromList(ctx, this.accountName);
|
|
|
if (selected) {
|
|
|
await this.updateSpecific(ctx, selected);
|
|
|
_log().default.log(_chalk().default.green('Successfully updated Distribution Certificate\n'));
|
|
|
const credentials = await ctx.ios.getAllCredentials(this.accountName);
|
|
|
const updated = credentials.userCredentials.find(i => i.id === selected.id);
|
|
|
if (updated) {
|
|
|
(0, _list().displayIosUserCredentials)(updated);
|
|
|
}
|
|
|
_log().default.log();
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
async updateSpecific(ctx, selected) {
|
|
|
const credentials = await ctx.ios.getAllCredentials(this.accountName);
|
|
|
const apps = credentials.appCredentials.filter(cred => cred.distCredentialsId === selected.id);
|
|
|
const appsList = apps.map(appCred => _chalk().default.green(appCred.experienceName)).join(', ');
|
|
|
if (apps.length > 1) {
|
|
|
if (ctx.nonInteractive) {
|
|
|
throw new (_CommandError().default)('NON_INTERACTIVE', `Start the CLI without the '--non-interactive' flag to update the certificate used by ${appsList}.`);
|
|
|
}
|
|
|
const confirm = await (0, _prompts().confirmAsync)({
|
|
|
message: `You are updating certificate used by ${appsList}. Do you want to continue?`
|
|
|
});
|
|
|
if (!confirm) {
|
|
|
_log().default.log('Aborting update process');
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
const newDistCert = await this.provideOrGenerate(ctx);
|
|
|
await ctx.ios.updateDistCert(selected.id, this.accountName, newDistCert);
|
|
|
for (const appCredentials of apps) {
|
|
|
_log().default.log(`Removing Provisioning Profile for ${appCredentials.experienceName} (${appCredentials.bundleIdentifier})`);
|
|
|
const appLookupParams = (0, _IosApi().getAppLookupParams)(appCredentials.experienceName, appCredentials.bundleIdentifier);
|
|
|
await new (_IosProvisioningProfile().RemoveProvisioningProfile)(this.accountName, true).removeSpecific(ctx, appLookupParams);
|
|
|
}
|
|
|
}
|
|
|
async provideOrGenerate(ctx) {
|
|
|
const userProvided = await promptForDistCert(ctx);
|
|
|
if (userProvided) {
|
|
|
const isValid = await validateDistributionCertificate(ctx, userProvided);
|
|
|
return isValid ? userProvided : await this.provideOrGenerate(ctx);
|
|
|
}
|
|
|
return await generateDistCert(ctx, this.accountName);
|
|
|
}
|
|
|
}
|
|
|
exports.UpdateIosDist = UpdateIosDist;
|
|
|
class UseExistingDistributionCert {
|
|
|
constructor(app) {
|
|
|
this.app = app;
|
|
|
}
|
|
|
async open(ctx) {
|
|
|
const selected = await selectDistCertFromList(ctx, this.app.accountName, {
|
|
|
filterInvalid: true
|
|
|
});
|
|
|
if (selected) {
|
|
|
await ctx.ios.useDistCert(this.app, selected.id);
|
|
|
_log().default.log(_chalk().default.green(`Successfully assigned Distribution Certificate to @${this.app.accountName}/${this.app.projectName} (${this.app.bundleIdentifier})`));
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
}
|
|
|
exports.UseExistingDistributionCert = UseExistingDistributionCert;
|
|
|
class CreateOrReuseDistributionCert {
|
|
|
constructor(app) {
|
|
|
this.app = app;
|
|
|
}
|
|
|
async assignDistCert(ctx, userCredentialsId) {
|
|
|
await ctx.ios.useDistCert(this.app, userCredentialsId);
|
|
|
_log().default.log(_chalk().default.green(`Successfully assigned Distribution Certificate to @${this.app.accountName}/${this.app.projectName} (${this.app.bundleIdentifier})`));
|
|
|
}
|
|
|
async open(ctx) {
|
|
|
if (!ctx.user) {
|
|
|
throw new Error(`This workflow requires you to be logged in.`);
|
|
|
}
|
|
|
const existingCertificates = await getValidDistCerts(await ctx.ios.getAllCredentials(this.app.accountName), ctx);
|
|
|
if (existingCertificates.length === 0) {
|
|
|
const distCert = await new CreateIosDist(this.app.accountName).create(ctx);
|
|
|
await this.assignDistCert(ctx, distCert.id);
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
// autoselect creds if we find valid certs
|
|
|
const autoselectedCertificate = existingCertificates[0];
|
|
|
if (!ctx.nonInteractive) {
|
|
|
const confirm = await (0, _prompts().confirmAsync)({
|
|
|
message: `${formatDistCert(autoselectedCertificate, await ctx.ios.getAllCredentials(this.app.accountName), 'VALID')} \n Would you like to use this certificate?`,
|
|
|
limit: Infinity
|
|
|
});
|
|
|
if (!confirm) {
|
|
|
return await this._createOrReuse(ctx);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Use autosuggested push key
|
|
|
_log().default.log(`Using Distribution Certificate: ${autoselectedCertificate.certId || '-----'}`);
|
|
|
await this.assignDistCert(ctx, autoselectedCertificate.id);
|
|
|
return null;
|
|
|
}
|
|
|
async _createOrReuse(ctx) {
|
|
|
const choices = [{
|
|
|
title: '[Choose existing certificate] (Recommended)',
|
|
|
value: 'CHOOSE_EXISTING'
|
|
|
}, {
|
|
|
title: '[Add a new certificate]',
|
|
|
value: 'GENERATE'
|
|
|
}];
|
|
|
const question = {
|
|
|
type: 'select',
|
|
|
name: 'action',
|
|
|
message: 'Select an iOS distribution certificate to use for code signing:',
|
|
|
choices,
|
|
|
optionsPerPage: 20
|
|
|
};
|
|
|
const {
|
|
|
action
|
|
|
} = await (0, _prompts().default)(question);
|
|
|
if (action === 'GENERATE') {
|
|
|
const distCert = await new CreateIosDist(this.app.accountName).create(ctx);
|
|
|
await this.assignDistCert(ctx, distCert.id);
|
|
|
return null;
|
|
|
} else if (action === 'CHOOSE_EXISTING') {
|
|
|
return new UseExistingDistributionCert(this.app);
|
|
|
}
|
|
|
throw new Error('unsupported action');
|
|
|
}
|
|
|
}
|
|
|
exports.CreateOrReuseDistributionCert = CreateOrReuseDistributionCert;
|
|
|
async function getValidDistCerts(iosCredentials, ctx) {
|
|
|
const distCerts = iosCredentials.userCredentials.filter(cred => cred.type === 'dist-cert');
|
|
|
if (!ctx.hasAppleCtx()) {
|
|
|
_log().default.log(_chalk().default.yellow(`Unable to determine validity of Distribution Certificates.`));
|
|
|
return distCerts;
|
|
|
}
|
|
|
const distCertManager = new (_appleApi().DistCertManager)(ctx.appleCtx);
|
|
|
const certInfoFromApple = await distCertManager.list();
|
|
|
const validCerts = await filterRevokedDistributionCerts(certInfoFromApple, distCerts);
|
|
|
return sortByExpiryDesc(certInfoFromApple, validCerts);
|
|
|
}
|
|
|
function getValidityStatus(distCert, validDistCerts) {
|
|
|
if (!validDistCerts) {
|
|
|
return 'UNKNOWN';
|
|
|
}
|
|
|
return validDistCerts.includes(distCert) ? 'VALID' : 'INVALID';
|
|
|
}
|
|
|
async function selectDistCertFromList(ctx, accountName, options = {}) {
|
|
|
const iosCredentials = await ctx.ios.getAllCredentials(accountName);
|
|
|
let distCerts = iosCredentials.userCredentials.filter(cred => cred.type === 'dist-cert');
|
|
|
let validDistCerts = null;
|
|
|
if (ctx.hasAppleCtx()) {
|
|
|
const distCertManager = new (_appleApi().DistCertManager)(ctx.appleCtx);
|
|
|
const certInfoFromApple = await distCertManager.list();
|
|
|
validDistCerts = await filterRevokedDistributionCerts(certInfoFromApple, distCerts);
|
|
|
}
|
|
|
distCerts = options.filterInvalid && validDistCerts ? validDistCerts : distCerts;
|
|
|
if (distCerts.length === 0) {
|
|
|
_log().default.warn('There are no Distribution Certificates available in your expo account');
|
|
|
return null;
|
|
|
}
|
|
|
const question = {
|
|
|
type: 'select',
|
|
|
name: 'credentialsIndex',
|
|
|
message: 'Select certificate from the list.',
|
|
|
choices: distCerts.map((entry, index) => ({
|
|
|
title: formatDistCert(entry, iosCredentials, getValidityStatus(entry, validDistCerts)),
|
|
|
value: index
|
|
|
}))
|
|
|
};
|
|
|
const {
|
|
|
credentialsIndex
|
|
|
} = await (0, _prompts().default)(question);
|
|
|
return distCerts[credentialsIndex];
|
|
|
}
|
|
|
function formatDistCertFromApple(appleInfo, credentials) {
|
|
|
const userCredentials = credentials.userCredentials.filter(cred => cred.type === 'dist-cert' && cred.certId === appleInfo.id);
|
|
|
const appCredentials = userCredentials.length !== 0 ? credentials.appCredentials.filter(cred => cred.distCredentialsId === userCredentials[0].id) : [];
|
|
|
const joinApps = appCredentials.map(i => ` ${i.experienceName} (${i.bundleIdentifier})`).join('\n');
|
|
|
const usedByString = joinApps ? ` ${_chalk().default.gray(`used by\n${joinApps}`)}` : ` ${_chalk().default.gray(`not used by any apps`)}`;
|
|
|
const {
|
|
|
name,
|
|
|
status,
|
|
|
id,
|
|
|
expires,
|
|
|
created,
|
|
|
ownerName,
|
|
|
serialNumber
|
|
|
} = appleInfo;
|
|
|
const expiresDate = (0, _dateformat().default)(new Date(expires * 1000));
|
|
|
const createdDate = (0, _dateformat().default)(new Date(created * 1000));
|
|
|
return `${name} (${status}) - Cert ID: ${id}, Serial number: ${serialNumber}, Team ID: ${appleInfo.ownerId}, Team name: ${ownerName}
|
|
|
expires: ${expiresDate}, created: ${createdDate}
|
|
|
${usedByString}`;
|
|
|
}
|
|
|
function formatDistCert(distCert, credentials, validityStatus = 'UNKNOWN') {
|
|
|
const appCredentials = credentials.appCredentials.filter(cred => cred.distCredentialsId === distCert.id);
|
|
|
const joinApps = appCredentials.map(i => `${i.experienceName} (${i.bundleIdentifier})`).join(', ');
|
|
|
const usedByString = joinApps ? `\n ${_chalk().default.gray(`used by ${joinApps}`)}` : `\n ${_chalk().default.gray(`not used by any apps`)}`;
|
|
|
let serialNumber = distCert.distCertSerialNumber;
|
|
|
try {
|
|
|
if (!serialNumber) {
|
|
|
var _PKCS12Utils$findP12C;
|
|
|
serialNumber = (_PKCS12Utils$findP12C = _xdl().PKCS12Utils.findP12CertSerialNumber(distCert.certP12, distCert.certPassword)) !== null && _PKCS12Utils$findP12C !== void 0 ? _PKCS12Utils$findP12C : undefined;
|
|
|
}
|
|
|
} catch {
|
|
|
serialNumber = _chalk().default.red('invalid serial number');
|
|
|
}
|
|
|
let validityText;
|
|
|
if (validityStatus === 'VALID') {
|
|
|
validityText = _chalk().default.gray("\n ✅ Currently valid on Apple's servers.");
|
|
|
} else if (validityStatus === 'INVALID') {
|
|
|
validityText = _chalk().default.gray("\n ❌ No longer valid on Apple's servers.");
|
|
|
} else {
|
|
|
validityText = _chalk().default.gray("\n ❓ Validity of this certificate on Apple's servers is unknown.");
|
|
|
}
|
|
|
return `Distribution Certificate (Cert ID: ${distCert.certId || '-----'}, Serial number: ${serialNumber}, Team ID: ${distCert.teamId})${usedByString}${validityText}`;
|
|
|
}
|
|
|
async function generateDistCert(ctx, accountName) {
|
|
|
await ctx.ensureAppleCtx();
|
|
|
const manager = new (_appleApi().DistCertManager)(ctx.appleCtx);
|
|
|
try {
|
|
|
return await manager.create();
|
|
|
} catch (e) {
|
|
|
if (e.code === 'APPLE_DIST_CERTS_TOO_MANY_GENERATED_ERROR') {
|
|
|
const certs = await manager.list();
|
|
|
_log().default.warn('Maximum number of Distribution Certificates generated on Apple Developer Portal.');
|
|
|
_log().default.warn(APPLE_DIST_CERTS_TOO_MANY_GENERATED_ERROR);
|
|
|
if (ctx.nonInteractive) {
|
|
|
throw new (_CommandError().default)('NON_INTERACTIVE', "Start the CLI without the '--non-interactive' flag to revoke existing certificates.");
|
|
|
}
|
|
|
const credentials = await ctx.ios.getAllCredentials(accountName);
|
|
|
const usedByExpo = credentials.userCredentials.filter(cert => cert.type === 'dist-cert' && !!cert.certId).reduce((acc, cert) => ({
|
|
|
...acc,
|
|
|
[cert.certId || '']: cert
|
|
|
}), {});
|
|
|
|
|
|
// https://docs.expo.dev/distribution/app-signing/#summary
|
|
|
const here = (0, _terminalLink().default)('here', 'https://bit.ly/3cfJJkQ');
|
|
|
_log().default.log(_chalk().default.grey(`✅ Distribution Certificates can be revoked with no production side effects`));
|
|
|
_log().default.log(_chalk().default.grey(`ℹ️ Learn more ${here}`));
|
|
|
_log().default.log();
|
|
|
const {
|
|
|
revoke
|
|
|
} = await (0, _prompts().default)([{
|
|
|
type: 'multiselect',
|
|
|
name: 'revoke',
|
|
|
message: 'Select certificates to revoke.',
|
|
|
optionsPerPage: 20,
|
|
|
choices: certs.map((cert, index) => ({
|
|
|
value: index,
|
|
|
title: formatDistCertFromApple(cert, credentials)
|
|
|
}))
|
|
|
}]);
|
|
|
for (const index of revoke) {
|
|
|
const certInfo = certs[index];
|
|
|
if (certInfo && usedByExpo[certInfo.id]) {
|
|
|
await new RemoveIosDist(accountName, true).removeSpecific(ctx, usedByExpo[certInfo.id]);
|
|
|
} else {
|
|
|
await manager.revoke([certInfo.id]);
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
throw e;
|
|
|
}
|
|
|
}
|
|
|
return await generateDistCert(ctx, accountName);
|
|
|
}
|
|
|
function _getRequiredQuestions(ctx) {
|
|
|
const requiredQuestions = {
|
|
|
..._credentials().distCertSchema
|
|
|
};
|
|
|
if (ctx.hasAppleCtx() && requiredQuestions.required) {
|
|
|
requiredQuestions.required = requiredQuestions.required.filter(q => q !== 'teamId');
|
|
|
}
|
|
|
return requiredQuestions;
|
|
|
}
|
|
|
function _ensureDistCert(ctx, partialCert) {
|
|
|
if (ctx.hasAppleCtx()) {
|
|
|
partialCert.teamId = ctx.appleCtx.team.id;
|
|
|
}
|
|
|
if (!(0, _appleApi().isDistCert)(partialCert)) {
|
|
|
throw new Error(`Not of type DistCert: ${partialCert}`);
|
|
|
}
|
|
|
return partialCert;
|
|
|
}
|
|
|
async function promptForDistCert(ctx) {
|
|
|
const requiredQuestions = _getRequiredQuestions(ctx);
|
|
|
const userProvided = await (0, _promptForCredentials().askForUserProvided)(requiredQuestions);
|
|
|
if (userProvided) {
|
|
|
const distCert = _ensureDistCert(ctx, userProvided);
|
|
|
return await _getDistCertWithSerial(distCert);
|
|
|
} else {
|
|
|
return null;
|
|
|
}
|
|
|
}
|
|
|
async function _getDistCertWithSerial(distCert) {
|
|
|
try {
|
|
|
var _PKCS12Utils$findP12C2;
|
|
|
distCert.distCertSerialNumber = (_PKCS12Utils$findP12C2 = _xdl().PKCS12Utils.findP12CertSerialNumber(distCert.certP12, distCert.certPassword)) !== null && _PKCS12Utils$findP12C2 !== void 0 ? _PKCS12Utils$findP12C2 : undefined;
|
|
|
} catch (error) {
|
|
|
_log().default.warn('Unable to access certificate serial number.');
|
|
|
_log().default.warn('Make sure that certificate and password are correct.');
|
|
|
_log().default.warn(error);
|
|
|
}
|
|
|
return distCert;
|
|
|
}
|
|
|
async function validateDistributionCertificate(ctx, distributionCert) {
|
|
|
if (!ctx.hasAppleCtx()) {
|
|
|
_log().default.warn('Unable to validate distribution certificate due to insufficient Apple Credentials');
|
|
|
return true;
|
|
|
}
|
|
|
const spinner = (0, _ora().ora)(`Checking validity of distribution certificate on Apple Developer Portal...`).start();
|
|
|
const distCertManager = new (_appleApi().DistCertManager)(ctx.appleCtx);
|
|
|
const certInfoFromApple = await distCertManager.list();
|
|
|
const validDistributionCerts = await filterRevokedDistributionCerts(certInfoFromApple, [distributionCert]);
|
|
|
const isValidCert = validDistributionCerts.length > 0;
|
|
|
if (isValidCert) {
|
|
|
const successMsg = `Successfully validated Distribution Certificate against Apple Servers`;
|
|
|
spinner.succeed(successMsg);
|
|
|
} else {
|
|
|
const failureMsg = `The Distribution Certificate is no longer valid on the Apple Developer Portal`;
|
|
|
spinner.fail(failureMsg);
|
|
|
}
|
|
|
return isValidCert;
|
|
|
}
|
|
|
async function filterRevokedDistributionCerts(certInfoFromApple, distributionCerts) {
|
|
|
if (distributionCerts.length === 0) {
|
|
|
return [];
|
|
|
}
|
|
|
|
|
|
// if the credentials are valid, check it against apple to make sure it hasnt been revoked
|
|
|
const validCertSerialsOnAppleServer = certInfoFromApple.filter(
|
|
|
// remove expired certs
|
|
|
cert => cert.expires > Math.floor(Date.now() / 1000)).map(cert => cert.serialNumber);
|
|
|
const validDistributionCerts = distributionCerts.filter(cert => {
|
|
|
const serialNumber = cert.distCertSerialNumber;
|
|
|
if (!serialNumber) {
|
|
|
return false;
|
|
|
}
|
|
|
return validCertSerialsOnAppleServer.includes(serialNumber);
|
|
|
});
|
|
|
return validDistributionCerts;
|
|
|
}
|
|
|
function sortByExpiryDesc(certInfoFromApple, distributionCerts) {
|
|
|
return distributionCerts.sort((certA, certB) => {
|
|
|
const certAInfo = certInfoFromApple.find(cert => cert.id === certA.certId);
|
|
|
const certAExpiry = certAInfo ? certAInfo.expires : Number.NEGATIVE_INFINITY;
|
|
|
const certBInfo = certInfoFromApple.find(cert => cert.id === certB.certId);
|
|
|
const certBExpiry = certBInfo ? certBInfo.expires : Number.NEGATIVE_INFINITY;
|
|
|
return certBExpiry - certAExpiry;
|
|
|
});
|
|
|
}
|
|
|
async function getDistCertFromParams(builderOptions) {
|
|
|
const {
|
|
|
distP12Path,
|
|
|
teamId
|
|
|
} = builderOptions;
|
|
|
const certPassword = process.env.EXPO_IOS_DIST_P12_PASSWORD;
|
|
|
|
|
|
// none of the distCert params were set, assume user has no intention of passing it in
|
|
|
if (!distP12Path && !certPassword) {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
// partial distCert params were set, assume user has intention of passing it in
|
|
|
if (!(distP12Path && certPassword && teamId)) {
|
|
|
throw new Error('In order to provide a Distribution Certificate through the CLI parameters, you have to pass --dist-p12-path parameter, --team-id parameter and set EXPO_IOS_DIST_P12_PASSWORD environment variable.');
|
|
|
}
|
|
|
const distCert = {
|
|
|
certP12: await _fsExtra().default.readFile(distP12Path, 'base64'),
|
|
|
teamId,
|
|
|
certPassword
|
|
|
};
|
|
|
return await _getDistCertWithSerial(distCert);
|
|
|
}
|
|
|
async function useDistCertFromParams(ctx, app, distCert) {
|
|
|
const isValid = await validateDistributionCertificate(ctx, distCert);
|
|
|
if (!isValid) {
|
|
|
throw new Error('Cannot validate uploaded Distribution Certificate');
|
|
|
}
|
|
|
const iosDistCredentials = await ctx.ios.createDistCert(app.accountName, distCert);
|
|
|
await ctx.ios.useDistCert(app, iosDistCredentials.id);
|
|
|
_log().default.log(_chalk().default.green(`Successfully assigned Distribution Certificate to @${app.accountName}/${app.projectName} (${app.bundleIdentifier})`));
|
|
|
return iosDistCredentials;
|
|
|
}
|
|
|
//# sourceMappingURL=IosDistCert.js.map
|