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
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
|