You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

417 lines
16 KiB

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.UseExistingProvisioningProfile = exports.RemoveProvisioningProfile = exports.CreateProvisioningProfile = exports.CreateOrReuseProvisioningProfile = void 0;
exports.configureAndUpdateProvisioningProfile = configureAndUpdateProvisioningProfile;
exports.getAppleInfo = getAppleInfo;
exports.getProvisioningProfileFromParams = getProvisioningProfileFromParams;
exports.useProvisioningProfileFromParams = useProvisioningProfileFromParams;
exports.validateProfileWithoutApple = validateProfileWithoutApple;
function _plist() {
const data = _interopRequireDefault(require("@expo/plist"));
_plist = function () {
return data;
};
return data;
}
function _assert() {
const data = _interopRequireDefault(require("assert"));
_assert = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require("chalk"));
_chalk = function () {
return data;
};
return data;
}
function _fsExtra() {
const data = _interopRequireDefault(require("fs-extra"));
_fsExtra = 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 provisioningProfileUtils() {
const data = _interopRequireWildcard(require("../utils/provisioningProfile"));
provisioningProfileUtils = 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 }; }
class RemoveProvisioningProfile {
constructor(accountName, shouldRevoke = false) {
this.accountName = accountName;
this.shouldRevoke = shouldRevoke;
}
async open(ctx) {
const credentials = await ctx.ios.getAllCredentials(this.accountName);
const selected = await selectProfileFromExpo(credentials);
if (selected) {
const app = (0, _IosApi().getAppLookupParams)(selected.experienceName, selected.bundleIdentifier);
await this.removeSpecific(ctx, app);
_log().default.log(_chalk().default.green(`Successfully removed Provisioning Profile for ${selected.experienceName} (${selected.bundleIdentifier})`));
}
return null;
}
async removeSpecific(ctx, app) {
_log().default.log('Removing Provisioning Profile...\n');
await ctx.ios.deleteProvisioningProfile(app);
let shouldRevoke = this.shouldRevoke;
if (!shouldRevoke && !ctx.nonInteractive) {
const revoke = await (0, _prompts().confirmAsync)({
message: 'Do you also want to revoke this Provisioning Profile on Apple Developer Portal?'
});
shouldRevoke = revoke;
}
if (shouldRevoke) {
await ctx.ensureAppleCtx();
const ppManager = new (_appleApi().ProvisioningProfileManager)(ctx.appleCtx);
await ppManager.revoke(app.bundleIdentifier);
}
}
}
exports.RemoveProvisioningProfile = RemoveProvisioningProfile;
class CreateProvisioningProfile {
constructor(app) {
this.app = app;
}
async create(ctx) {
const provisioningProfile = await this.provideOrGenerate(ctx);
return await ctx.ios.updateProvisioningProfile(this.app, provisioningProfile);
}
async open(ctx) {
await this.create(ctx);
_log().default.log(_chalk().default.green('Successfully created Provisioning Profile\n'));
const appCredentials = await ctx.ios.getAppCredentials(this.app);
(0, _list().displayIosAppCredentials)(appCredentials);
_log().default.log();
return null;
}
async provideOrGenerate(ctx) {
if (!ctx.nonInteractive) {
const userProvided = await (0, _promptForCredentials().askForUserProvided)(_credentials().provisioningProfileSchema);
if (userProvided) {
// userProvided profiles don't come with ProvisioningProfileId's (only accessible from Apple Portal API)
_log().default.log(_chalk().default.yellow('Provisioning profile: Unable to validate specified profile.'));
return {
...userProvided,
...provisioningProfileUtils().readAppleTeam(userProvided.provisioningProfile)
};
}
}
const distCert = await ctx.ios.getDistCert(this.app);
(0, _assert().default)(distCert, 'missing distribution certificate');
return await generateProvisioningProfile(ctx, this.app.bundleIdentifier, distCert);
}
}
exports.CreateProvisioningProfile = CreateProvisioningProfile;
class UseExistingProvisioningProfile {
constructor(app) {
this.app = app;
}
async open(ctx) {
await ctx.ensureAppleCtx();
if (ctx.nonInteractive) {
throw new (_CommandError().default)('NON_INTERACTIVE', "Start the CLI without the '--non-interactive' flag to select a distribution certificate.");
}
const selected = await selectProfileFromApple(ctx.appleCtx, this.app.bundleIdentifier);
if (selected) {
const distCert = await ctx.ios.getDistCert(this.app);
(0, _assert().default)(distCert, 'missing distribution certificate');
await configureAndUpdateProvisioningProfile(ctx, this.app, distCert, selected);
}
return null;
}
}
exports.UseExistingProvisioningProfile = UseExistingProvisioningProfile;
class CreateOrReuseProvisioningProfile {
constructor(app) {
this.app = app;
}
choosePreferred(profiles, distCert) {
// prefer the profile that already has the same dist cert associated with it
const profileWithSameCert = profiles.find(profile => profile.certificates.some(cert => cert.id === distCert.certId));
// if not, just get an arbitrary profile
return profileWithSameCert || profiles[0];
}
async open(ctx) {
if (!ctx.user) {
throw new Error(`This workflow requires you to be logged in.`);
}
if (!ctx.hasAppleCtx()) {
return new CreateProvisioningProfile(this.app);
}
const ppManager = new (_appleApi().ProvisioningProfileManager)(ctx.appleCtx);
const existingProfiles = await ppManager.list(this.app.bundleIdentifier);
if (existingProfiles.length === 0) {
return new CreateProvisioningProfile(this.app);
}
const distCert = await ctx.ios.getDistCert(this.app);
(0, _assert().default)(distCert, 'missing distribution certificate');
const autoselectedProfile = this.choosePreferred(existingProfiles, distCert);
// autoselect creds if we find valid certs
if (!ctx.nonInteractive) {
const confirm = await (0, _prompts().confirmAsync)({
message: `${formatProvisioningProfileFromApple(autoselectedProfile)} \n Would you like to use this profile?`,
limit: Infinity
});
if (!confirm) {
return await this._createOrReuse(ctx);
}
}
_log().default.log(`Using Provisioning Profile: ${autoselectedProfile.provisioningProfileId}`);
await configureAndUpdateProvisioningProfile(ctx, this.app, distCert, autoselectedProfile);
return null;
}
async _createOrReuse(ctx) {
const choices = [{
title: '[Choose existing provisioning profile] (Recommended)',
value: 'CHOOSE_EXISTING'
}, {
title: '[Add a new provisioning profile]',
value: 'GENERATE'
}];
const question = {
type: 'select',
name: 'action',
message: 'Select a Provisioning Profile:',
choices,
optionsPerPage: 20
};
const {
action
} = await (0, _prompts().default)(question);
if (action === 'GENERATE') {
return new CreateProvisioningProfile(this.app);
} else if (action === 'CHOOSE_EXISTING') {
return new UseExistingProvisioningProfile(this.app);
}
throw new Error('unsupported action');
}
}
exports.CreateOrReuseProvisioningProfile = CreateOrReuseProvisioningProfile;
async function selectProfileFromApple(appleCtx, bundleIdentifier) {
const ppManager = new (_appleApi().ProvisioningProfileManager)(appleCtx);
const profiles = await ppManager.list(bundleIdentifier);
if (profiles.length === 0) {
_log().default.warn(`There are no Provisioning Profiles available in your apple account for bundleIdentifier: ${bundleIdentifier}`);
return null;
}
const question = {
type: 'select',
name: 'credentialsIndex',
message: 'Select Provisioning Profile from the list.',
choices: profiles.map((entry, index) => ({
title: formatProvisioningProfileFromApple(entry),
value: index
}))
};
const {
credentialsIndex
} = await (0, _prompts().default)(question);
return profiles[credentialsIndex];
}
async function selectProfileFromExpo(iosCredentials) {
const profiles = iosCredentials.appCredentials.filter(({
credentials
}) => !!credentials.provisioningProfile && !!credentials.provisioningProfileId);
if (profiles.length === 0) {
_log().default.warn('There are no Provisioning Profiles available in your account');
return null;
}
const getName = profile => {
const id = _chalk().default.green(profile.credentials.provisioningProfileId || '-----');
const teamId = profile.credentials.teamId || '------';
return `Provisioning Profile (ID: ${id}, Team ID: ${teamId})`;
};
const question = {
type: 'select',
name: 'credentialsIndex',
message: 'Select Provisioning Profile from the list.',
choices: profiles.map((entry, index) => ({
title: getName(entry),
value: index
}))
};
const {
credentialsIndex
} = await (0, _prompts().default)(question);
return profiles[credentialsIndex];
}
async function generateProvisioningProfile(ctx, bundleIdentifier, distCert) {
await ctx.ensureAppleCtx();
const manager = new (_appleApi().ProvisioningProfileManager)(ctx.appleCtx);
const type = ctx.appleCtx.team.inHouse ? 'Enterprise ' : 'AppStore';
const profileName = `*[expo] ${bundleIdentifier} ${type} ${new Date().toISOString()}`; // Apple drops [ if its the first char (!!)
return await manager.create(bundleIdentifier, distCert, profileName);
}
// Best effort validation without Apple credentials
async function validateProfileWithoutApple(provisioningProfile, distCert, bundleIdentifier) {
const spinner = (0, _ora().ora)(`Performing best effort validation of Provisioning Profile...\n`).start();
const base64EncodedProfile = provisioningProfile.provisioningProfile;
if (!base64EncodedProfile) {
spinner.fail('No profile on file');
return false;
}
const buffer = Buffer.from(base64EncodedProfile, 'base64');
const profile = buffer.toString('utf-8');
const profilePlist = _plist().default.parse(profile);
try {
const distCertFingerprint = await _xdl().PKCS12Utils.getP12CertFingerprint(distCert.certP12, distCert.certPassword);
_xdl().IosCodeSigning.validateProvisioningProfile(profilePlist, {
distCertFingerprint,
bundleIdentifier
});
} catch (e) {
spinner.fail(`Provisioning profile is invalid: ${e.toString()}`);
return false;
}
const isExpired = new Date(profilePlist['ExpirationDate']) <= new Date();
if (isExpired) {
spinner.fail('Provisioning profile is expired');
return false;
}
spinner.succeed('Successfully performed best effort validation of Provisioning Profile.');
return true;
}
async function getAppleInfo(appleCtx, bundleIdentifier, profile) {
if (!profile.provisioningProfileId) {
_log().default.log(_chalk().default.yellow('Provisioning Profile: cannot look up profile on Apple Servers - there is no id'));
return null;
}
const spinner = (0, _ora().ora)(`Getting Provisioning Profile info from Apple's Servers...\n`).start();
const ppManager = new (_appleApi().ProvisioningProfileManager)(appleCtx);
const profilesFromApple = await ppManager.list(bundleIdentifier);
const configuredProfileFromApple = profilesFromApple.find(appleProfile => appleProfile.provisioningProfileId === profile.provisioningProfileId);
if (!configuredProfileFromApple) {
spinner.fail(`Provisioning Profile: ${profile.provisioningProfileId} does not exist on Apple Servers`);
return null;
}
spinner.succeed(`Successfully fetched Provisioning Profile ${profile.provisioningProfileId} from Apple Servers`);
return configuredProfileFromApple;
}
async function configureAndUpdateProvisioningProfile(ctx, app, distCert, profileFromApple) {
// configure profile on Apple's Server to use our distCert
const ppManager = new (_appleApi().ProvisioningProfileManager)(ctx.appleCtx);
const updatedProfile = await ppManager.useExisting(app.bundleIdentifier, profileFromApple, distCert);
_log().default.log(_chalk().default.green(`Successfully configured Provisioning Profile ${profileFromApple.provisioningProfileId} on Apple Servers with Distribution Certificate ${distCert.certId || ''}`));
// Update profile on expo servers
await ctx.ios.updateProvisioningProfile(app, updatedProfile);
_log().default.log(_chalk().default.green(`Successfully assigned Provisioning Profile to @${app.accountName}/${app.projectName} (${app.bundleIdentifier})`));
}
function formatProvisioningProfileFromApple(appleInfo) {
var _appleInfo$name;
const {
expires,
provisioningProfileId
} = appleInfo;
const id = provisioningProfileId !== null && provisioningProfileId !== void 0 ? provisioningProfileId : '-----';
const name = (_appleInfo$name = appleInfo.name) !== null && _appleInfo$name !== void 0 ? _appleInfo$name : '-----';
const expireString = expires ? new Date(expires * 1000).toDateString() : 'unknown';
const details = _chalk().default.green(`\n Name: ${name}\n Expiry: ${expireString}`);
return `Provisioning Profile - ID: ${id}${details}`;
}
async function getProvisioningProfileFromParams(provisioningProfilePath) {
if (!provisioningProfilePath) {
return null;
}
const provisioningProfile = await _fsExtra().default.readFile(provisioningProfilePath, 'base64');
const team = provisioningProfileUtils().readAppleTeam(provisioningProfile);
return {
provisioningProfile,
...team
};
}
async function useProvisioningProfileFromParams(ctx, app, provisioningProfile) {
const distCert = await ctx.ios.getDistCert(app);
(0, _assert().default)(distCert, 'missing distribution certificate');
const isValid = await validateProfileWithoutApple(provisioningProfile, distCert, app.bundleIdentifier);
if (!isValid) {
throw new Error('Specified invalid Provisioning Profile');
}
return await ctx.ios.updateProvisioningProfile(app, provisioningProfile);
}
//# sourceMappingURL=IosProvisioningProfile.js.map