· 5 years ago · Jun 30, 2020, 12:54 PM
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.validateProfileWithoutApple = validateProfileWithoutApple;
7exports.getAppleInfo = getAppleInfo;
8exports.configureAndUpdateProvisioningProfile = configureAndUpdateProvisioningProfile;
9exports.getProvisioningProfileFromParams = getProvisioningProfileFromParams;
10exports.useProvisioningProfileFromParams = useProvisioningProfileFromParams;
11exports.CreateOrReuseProvisioningProfile = exports.UseExistingProvisioningProfile = exports.CreateProvisioningProfile = exports.RemoveProvisioningProfile = void 0;
12
13function _chalk() {
14 const data = _interopRequireDefault(require("chalk"));
15
16 _chalk = function () {
17 return data;
18 };
19
20 return data;
21}
22
23function _fsExtra() {
24 const data = _interopRequireDefault(require("fs-extra"));
25
26 _fsExtra = function () {
27 return data;
28 };
29
30 return data;
31}
32
33function _ora() {
34 const data = _interopRequireDefault(require("ora"));
35
36 _ora = function () {
37 return data;
38 };
39
40 return data;
41}
42
43function _plist() {
44 const data = _interopRequireDefault(require("@expo/plist"));
45
46 _plist = function () {
47 return data;
48 };
49
50 return data;
51}
52
53function _xdl() {
54 const data = require("@expo/xdl");
55
56 _xdl = function () {
57 return data;
58 };
59
60 return data;
61}
62
63function _prompt() {
64 const data = _interopRequireDefault(require("../../prompt"));
65
66 _prompt = function () {
67 return data;
68 };
69
70 return data;
71}
72
73function _log() {
74 const data = _interopRequireDefault(require("../../log"));
75
76 _log = function () {
77 return data;
78 };
79
80 return data;
81}
82
83function _credentials() {
84 const data = require("../credentials");
85
86 _credentials = function () {
87 return data;
88 };
89
90 return data;
91}
92
93function _promptForCredentials() {
94 const data = require("../actions/promptForCredentials");
95
96 _promptForCredentials = function () {
97 return data;
98 };
99
100 return data;
101}
102
103function _list() {
104 const data = require("../actions/list");
105
106 _list = function () {
107 return data;
108 };
109
110 return data;
111}
112
113function _appleApi() {
114 const data = require("../../appleApi");
115
116 _appleApi = function () {
117 return data;
118 };
119
120 return data;
121}
122
123function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
124
125function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
126
127class RemoveProvisioningProfile {
128 constructor(shouldRevoke = false, nonInteractive = false) {
129 _defineProperty(this, "shouldRevoke", void 0);
130
131 _defineProperty(this, "nonInteractive", void 0);
132
133 this.shouldRevoke = shouldRevoke;
134 this.nonInteractive = nonInteractive;
135 }
136
137 async open(ctx) {
138 const selected = await selectProfileFromExpo(ctx.ios.credentials);
139
140 if (selected) {
141 await this.removeSpecific(ctx, selected);
142 (0, _log().default)(_chalk().default.green(`Successfully removed Provisioning Profile for ${selected.experienceName} (${selected.bundleIdentifier})`));
143 }
144
145 return null;
146 }
147
148 async removeSpecific(ctx, selected) {
149 (0, _log().default)('Removing Provisioning Profile...\n');
150 await ctx.ios.deleteProvisioningProfile(selected.experienceName, selected.bundleIdentifier);
151 let shouldRevoke = this.shouldRevoke;
152
153 if (!shouldRevoke && !this.nonInteractive) {
154 const {
155 revoke
156 } = await (0, _prompt().default)([{
157 type: 'confirm',
158 name: 'revoke',
159 message: 'Do you also want to revoke it on Apple Developer Portal?'
160 }]);
161 shouldRevoke = revoke;
162 }
163
164 if (shouldRevoke) {
165 await ctx.ensureAppleCtx();
166 const ppManager = new (_appleApi().ProvisioningProfileManager)(ctx.appleCtx);
167 await ppManager.revoke(selected.bundleIdentifier);
168 }
169 }
170
171}
172
173exports.RemoveProvisioningProfile = RemoveProvisioningProfile;
174
175class CreateProvisioningProfile {
176 constructor(options) {
177 var _options$nonInteracti;
178
179 _defineProperty(this, "_experienceName", void 0);
180
181 _defineProperty(this, "_bundleIdentifier", void 0);
182
183 _defineProperty(this, "_distCert", void 0);
184
185 _defineProperty(this, "_nonInteractive", void 0);
186
187 const {
188 experienceName,
189 bundleIdentifier,
190 distCert
191 } = options;
192 this._experienceName = experienceName;
193 this._bundleIdentifier = bundleIdentifier;
194 this._distCert = distCert;
195 this._nonInteractive = (_options$nonInteracti = options.nonInteractive) !== null && _options$nonInteracti !== void 0 ? _options$nonInteracti : false;
196 }
197
198 async create(ctx) {
199 const provisioningProfile = await this.provideOrGenerate(ctx);
200 const appleTeam = ctx.hasAppleCtx() ? ctx.appleCtx.team : await (0, _promptForCredentials().getCredentialsFromUser)(_credentials().appleTeamSchema);
201
202 if (!appleTeam) {
203 throw new Error('Must provide a valid Apple Team Id');
204 }
205
206 return await ctx.ios.updateProvisioningProfile(this._experienceName, this._bundleIdentifier, provisioningProfile, appleTeam);
207 }
208
209 async open(ctx) {
210 await this.create(ctx);
211 (0, _log().default)(_chalk().default.green('Successfully created Provisioning Profile\n'));
212 const appCredentials = ctx.ios.credentials.appCredentials.find(app => app.experienceName === this._experienceName && app.bundleIdentifier === this._bundleIdentifier);
213 (0, _list().displayIosAppCredentials)(appCredentials);
214 (0, _log().default)();
215 return null;
216 }
217
218 async provideOrGenerate(ctx) {
219 if (!this._nonInteractive) {
220 // const userProvided = await (0, _promptForCredentials().askForUserProvided)(_credentials().provisioningProfileSchema);
221
222 //if (userProvided) {
223 //# userProvided profiles don't come with ProvisioningProfileId's (only accessible from Apple Portal API)
224 // (0, _log().default)(_chalk().default.yellow('Provisioning profile: Unable to validate uploaded profile.'));
225 // return userProvided;
226 // }
227 }
228
229 return await generateProvisioningProfile(ctx, this._bundleIdentifier, this._distCert);
230 }
231
232}
233
234exports.CreateProvisioningProfile = CreateProvisioningProfile;
235
236class UseExistingProvisioningProfile {
237 constructor(options) {
238 _defineProperty(this, "_experienceName", void 0);
239
240 _defineProperty(this, "_bundleIdentifier", void 0);
241
242 _defineProperty(this, "_distCert", void 0);
243
244 const {
245 experienceName,
246 bundleIdentifier,
247 distCert
248 } = options;
249 this._experienceName = experienceName;
250 this._bundleIdentifier = bundleIdentifier;
251 this._distCert = distCert;
252 }
253
254 async open(ctx) {
255 await ctx.ensureAppleCtx();
256 const selected = await selectProfileFromApple(ctx.appleCtx, this._bundleIdentifier);
257
258 if (selected) {
259 await configureAndUpdateProvisioningProfile(ctx, this._experienceName, this._bundleIdentifier, this._distCert, selected);
260 }
261
262 return null;
263 }
264
265}
266
267exports.UseExistingProvisioningProfile = UseExistingProvisioningProfile;
268
269class CreateOrReuseProvisioningProfile {
270 constructor(options) {
271 var _options$nonInteracti2;
272
273 _defineProperty(this, "_experienceName", void 0);
274
275 _defineProperty(this, "_bundleIdentifier", void 0);
276
277 _defineProperty(this, "_distCert", void 0);
278
279 _defineProperty(this, "_nonInteractive", void 0);
280
281 const {
282 experienceName,
283 bundleIdentifier,
284 distCert
285 } = options;
286 this._experienceName = experienceName;
287 this._bundleIdentifier = bundleIdentifier;
288 this._distCert = distCert;
289 this._nonInteractive = (_options$nonInteracti2 = options.nonInteractive) !== null && _options$nonInteracti2 !== void 0 ? _options$nonInteracti2 : false;
290 }
291
292 choosePreferred(profiles) {
293 // prefer the profile that already has the same dist cert associated with it
294 const profileWithSameCert = profiles.find(profile => profile.certificates.some(cert => cert.id === this._distCert.certId)); // if not, just get an arbitrary profile
295
296 return profileWithSameCert || profiles[0];
297 }
298
299 async open(ctx) {
300 if (!ctx.user) {
301 throw new Error(`This workflow requires you to be logged in.`);
302 }
303
304 if (!ctx.hasAppleCtx()) {
305 return new CreateProvisioningProfile({
306 experienceName: this._experienceName,
307 bundleIdentifier: this._bundleIdentifier,
308 distCert: this._distCert,
309 nonInteractive: this._nonInteractive
310 });
311 }
312
313 const ppManager = new (_appleApi().ProvisioningProfileManager)(ctx.appleCtx);
314 const existingProfiles = await ppManager.list(this._bundleIdentifier);
315
316 if (existingProfiles.length === 0) {
317 return new CreateProvisioningProfile({
318 experienceName: this._experienceName,
319 bundleIdentifier: this._bundleIdentifier,
320 distCert: this._distCert,
321 nonInteractive: this._nonInteractive
322 });
323 }
324
325 const autoselectedProfile = this.choosePreferred(existingProfiles); // autoselect creds if we find valid certs
326
327 const confirmQuestion = {
328 type: 'confirm',
329 name: 'confirm',
330 message: `${formatProvisioningProfileFromApple(autoselectedProfile)} \n Would you like to use this profile?`,
331 pageSize: Infinity
332 };
333
334 if (!this._nonInteractive) {
335 const {
336 confirm
337 } = await (0, _prompt().default)(confirmQuestion);
338
339 if (!confirm) {
340 return await this._createOrReuse(ctx);
341 }
342 }
343
344 (0, _log().default)(`Using Provisioning Profile: ${autoselectedProfile.provisioningProfileId}`);
345 await configureAndUpdateProvisioningProfile(ctx, this._experienceName, this._bundleIdentifier, this._distCert, autoselectedProfile);
346 return null;
347 }
348
349 async _createOrReuse(ctx) {
350 const choices = [{
351 name: '[Choose existing provisioning profile] (Recommended)',
352 value: 'CHOOSE_EXISTING'
353 }, {
354 name: '[Add a new provisioning profile]',
355 value: 'GENERATE'
356 }];
357 const question = {
358 type: 'list',
359 name: 'action',
360 message: 'Select a Provisioning Profile:',
361 choices,
362 pageSize: Infinity
363 };
364 const {
365 action
366 } = await (0, _prompt().default)(question);
367
368 if (action === 'GENERATE') {
369 return new CreateProvisioningProfile({
370 experienceName: this._experienceName,
371 bundleIdentifier: this._bundleIdentifier,
372 distCert: this._distCert,
373 nonInteractive: this._nonInteractive
374 });
375 } else if (action === 'CHOOSE_EXISTING') {
376 return new UseExistingProvisioningProfile({
377 experienceName: this._experienceName,
378 bundleIdentifier: this._bundleIdentifier,
379 distCert: this._distCert
380 });
381 }
382
383 throw new Error('unsupported action');
384 }
385
386}
387
388exports.CreateOrReuseProvisioningProfile = CreateOrReuseProvisioningProfile;
389
390async function selectProfileFromApple(appleCtx, bundleIdentifier) {
391 const ppManager = new (_appleApi().ProvisioningProfileManager)(appleCtx);
392 const profiles = await ppManager.list(bundleIdentifier);
393
394 if (profiles.length === 0) {
395 _log().default.warn(`There are no Provisioning Profiles available in your apple account for bundleIdentifier: ${bundleIdentifier}`);
396
397 return null;
398 }
399
400 const question = {
401 type: 'list',
402 name: 'credentialsIndex',
403 message: 'Select Provisioning Profile from the list.',
404 choices: profiles.map((entry, index) => ({
405 name: formatProvisioningProfileFromApple(entry),
406 value: index
407 }))
408 };
409 const {
410 credentialsIndex
411 } = await (0, _prompt().default)(question);
412 return profiles[credentialsIndex];
413}
414
415async function selectProfileFromExpo(iosCredentials) {
416 const profiles = iosCredentials.appCredentials.filter(({
417 credentials
418 }) => !!credentials.provisioningProfile && !!credentials.provisioningProfileId);
419
420 if (profiles.length === 0) {
421 _log().default.warn('There are no Provisioning Profiles available in your account');
422
423 return null;
424 }
425
426 const getName = profile => {
427 const id = _chalk().default.green(profile.credentials.provisioningProfileId || '-----');
428
429 const teamId = profile.credentials.teamId || '------';
430 return `Provisioning Profile (ID: ${id}, Team ID: ${teamId})`;
431 };
432
433 const question = {
434 type: 'list',
435 name: 'credentialsIndex',
436 message: 'Select Provisioning Profile from the list.',
437 choices: profiles.map((entry, index) => ({
438 name: getName(entry),
439 value: index
440 }))
441 };
442 const {
443 credentialsIndex
444 } = await (0, _prompt().default)(question);
445 return profiles[credentialsIndex];
446}
447
448async function generateProvisioningProfile(ctx, bundleIdentifier, distCert) {
449 await ctx.ensureAppleCtx();
450 const manager = new (_appleApi().ProvisioningProfileManager)(ctx.appleCtx);
451 const type = ctx.appleCtx.team.inHouse ? 'Enterprise ' : 'AppStore';
452 const profileName = `*[expo] ${bundleIdentifier} ${type} ${new Date().toISOString()}`; // Apple drops [ if its the first char (!!)
453
454 return await manager.create(bundleIdentifier, distCert, profileName);
455} // Best effort validation without Apple credentials
456
457
458async function validateProfileWithoutApple(provisioningProfile, distCert, bundleIdentifier) {
459 const spinner = (0, _ora().default)(`Performing best effort validation of Provisioning Profile...\n`).start();
460 const base64EncodedProfile = provisioningProfile.provisioningProfile;
461
462 if (!base64EncodedProfile) {
463 spinner.fail('No profile on file');
464 return false;
465 }
466
467 const buffer = Buffer.from(base64EncodedProfile, 'base64');
468 const profile = buffer.toString('utf-8');
469
470 const profilePlist = _plist().default.parse(profile);
471
472 try {
473 const distCertFingerprint = await _xdl().PKCS12Utils.getP12CertFingerprint(distCert.certP12, distCert.certPassword);
474
475 _xdl().IosCodeSigning.validateProvisioningProfile(profilePlist, {
476 distCertFingerprint,
477 bundleIdentifier
478 });
479 } catch (e) {
480 spinner.fail(`Provisioning profile is invalid: ${e.toString()}`);
481 return false;
482 }
483
484 const isExpired = new Date(profilePlist['ExpirationDate']) <= new Date();
485
486 if (isExpired) {
487 spinner.fail('Provisioning profile is expired');
488 return false;
489 }
490
491 spinner.succeed('Successfully performed best effort validation of Provisioning Profile.');
492 return true;
493}
494
495async function getAppleInfo(appleCtx, bundleIdentifier, profile) {
496 if (!profile.provisioningProfileId) {
497 (0, _log().default)(_chalk().default.yellow('Provisioning Profile: cannot look up profile on Apple Servers - there is no id'));
498 return null;
499 }
500
501 const spinner = (0, _ora().default)(`Getting Provisioning Profile info from Apple's Servers...\n`).start();
502 const ppManager = new (_appleApi().ProvisioningProfileManager)(appleCtx);
503 const profilesFromApple = await ppManager.list(bundleIdentifier);
504 const configuredProfileFromApple = profilesFromApple.find(appleProfile => appleProfile.provisioningProfileId === profile.provisioningProfileId);
505
506 if (!configuredProfileFromApple) {
507 spinner.fail(`Provisioning Profile: ${profile.provisioningProfileId} does not exist on Apple Servers`);
508 return null;
509 }
510
511 spinner.succeed(`Successfully fetched Provisioning Profile ${profile.provisioningProfileId} from Apple Servers`);
512 return configuredProfileFromApple;
513}
514
515async function configureAndUpdateProvisioningProfile(ctx, experienceName, bundleIdentifier, distCert, profileFromApple) {
516 // configure profile on Apple's Server to use our distCert
517 const ppManager = new (_appleApi().ProvisioningProfileManager)(ctx.appleCtx);
518 const updatedProfile = await ppManager.useExisting(bundleIdentifier, profileFromApple, distCert);
519 (0, _log().default)(_chalk().default.green(`Successfully configured Provisioning Profile ${profileFromApple.provisioningProfileId} on Apple Servers with Distribution Certificate ${distCert.certId || ''}`)); // Update profile on expo servers
520
521 await ctx.ios.updateProvisioningProfile(experienceName, bundleIdentifier, updatedProfile, ctx.appleCtx.team);
522 (0, _log().default)(_chalk().default.green(`Successfully assigned Provisioning Profile to ${experienceName} (${bundleIdentifier})`));
523}
524
525function formatProvisioningProfileFromApple(appleInfo) {
526 var _appleInfo$name;
527
528 const {
529 expires,
530 provisioningProfileId
531 } = appleInfo;
532 const id = provisioningProfileId !== null && provisioningProfileId !== void 0 ? provisioningProfileId : '-----';
533 const name = (_appleInfo$name = appleInfo.name) !== null && _appleInfo$name !== void 0 ? _appleInfo$name : '-----';
534 const expireString = expires ? new Date(expires * 1000).toDateString() : 'unknown';
535
536 const details = _chalk().default.green(`\n Name: ${name}\n Expiry: ${expireString}`);
537
538 return `Provisioning Profile - ID: ${id}${details}`;
539}
540
541async function getProvisioningProfileFromParams(builderOptions) {
542 const {
543 provisioningProfilePath,
544 teamId
545 } = builderOptions; // none of the provisioningProfile params were set, assume user has no intention of passing it in
546
547 if (!provisioningProfilePath && !teamId) {
548 return null;
549 } // partial provisioningProfile params were set, assume user has intention of passing it in
550
551
552 if (!(provisioningProfilePath && teamId)) {
553 throw new Error('In order to provide a Provisioning Profile through the CLI parameters, you have to pass --provisioning-profile-path and --team-id parameters.');
554 }
555
556 return {
557 provisioningProfile: await _fsExtra().default.readFile(provisioningProfilePath, 'base64')
558 };
559}
560
561async function useProvisioningProfileFromParams(ctx, appCredentials, teamId, provisioningProfile, distCert) {
562 const {
563 experienceName,
564 bundleIdentifier
565 } = appCredentials;
566 const isValid = await validateProfileWithoutApple(provisioningProfile, distCert, appCredentials.bundleIdentifier);
567
568 if (!isValid) {
569 throw new Error('Uploaded invalid Provisioning Profile');
570 }
571
572 return await ctx.ios.updateProvisioningProfile(experienceName, bundleIdentifier, provisioningProfile, {
573 id: teamId
574 });
575}
576//# sourceMappingURL=IosProvisioningProfile.js.map