nativescript 8.5.0-dev.0 → 8.5.0-dev.0-next-03-25-2023-4519382718

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,13 +37,12 @@ class PublishIOS {
37
37
  this.$projectData.initializeProjectData();
38
38
  }
39
39
  execute(args) {
40
+ var _a;
40
41
  return __awaiter(this, void 0, void 0, function* () {
41
- yield this.$itmsTransporterService.validate();
42
+ yield this.$itmsTransporterService.validate(this.$options.appleApplicationSpecificPassword);
42
43
  const username = args[0] ||
43
44
  (yield this.$prompter.getString("Apple ID", { allowEmpty: false }));
44
45
  const password = args[1] || (yield this.$prompter.getPassword("Apple ID password"));
45
- const mobileProvisionIdentifier = args[2];
46
- const codeSignIdentity = args[3];
47
46
  const user = yield this.$applePortalSessionService.createUserSession({ username, password }, {
48
47
  applicationSpecificPassword: this.$options
49
48
  .appleApplicationSpecificPassword,
@@ -54,21 +53,21 @@ class PublishIOS {
54
53
  if (!user.areCredentialsValid) {
55
54
  this.$errors.fail(`Invalid username and password combination. Used '${username}' as the username.`);
56
55
  }
56
+ const mobileProvisionIdentifier = (_a = this.$options.provision) !== null && _a !== void 0 ? _a : args[2];
57
57
  let ipaFilePath = this.$options.ipa
58
58
  ? path.resolve(this.$options.ipa)
59
59
  : null;
60
60
  if (!mobileProvisionIdentifier && !ipaFilePath) {
61
61
  this.$logger.warn("No mobile provision identifier set. A default mobile provision will be used. You can set one in app/App_Resources/iOS/build.xcconfig");
62
62
  }
63
- if (!codeSignIdentity && !ipaFilePath) {
64
- this.$logger.warn("No code sign identity set. A default code sign identity will be used. You can set one in app/App_Resources/iOS/build.xcconfig");
65
- }
66
63
  this.$options.release = true;
67
64
  if (!ipaFilePath) {
68
65
  const platform = this.$devicePlatformsConstants.iOS.toLowerCase();
69
- if (mobileProvisionIdentifier || codeSignIdentity) {
70
- this.$logger.info("Building .ipa with the selected mobile provision and/or certificate.");
66
+ if (mobileProvisionIdentifier) {
67
+ this.$logger.info("Building .ipa with the selected mobile provision and/or certificate. " +
68
+ mobileProvisionIdentifier);
71
69
  this.$options.forDevice = true;
70
+ this.$options.provision = mobileProvisionIdentifier;
72
71
  const buildData = new build_data_1.IOSBuildData(this.$projectData.projectDir, platform, Object.assign(Object.assign({}, this.$options.argv), { watch: false }));
73
72
  ipaFilePath = yield this.$buildController.prepareAndBuild(buildData);
74
73
  }
@@ -87,6 +86,7 @@ class PublishIOS {
87
86
  ipaFilePath,
88
87
  shouldExtractIpa: !!this.$options.ipa,
89
88
  verboseLogging: this.$logger.getLevel() === "TRACE",
89
+ teamId: this.$options.teamId,
90
90
  });
91
91
  });
92
92
  }
package/lib/constants.js CHANGED
@@ -157,6 +157,7 @@ ITMSConstants.VerboseLoggingLevels = {
157
157
  };
158
158
  ITMSConstants.iTMSExecutableName = "iTMSTransporter";
159
159
  ITMSConstants.iTMSDirectoryName = "itms";
160
+ ITMSConstants.altoolExecutableName = "altool";
160
161
  class ItunesConnectApplicationTypesClass {
161
162
  constructor() {
162
163
  this.iOS = "iOS App";
@@ -765,13 +765,18 @@ interface IITMSData {
765
765
  * @type {string}
766
766
  */
767
767
  verboseLogging?: boolean;
768
+ /**
769
+ * Specifies the team id
770
+ * @type {string}
771
+ */
772
+ teamId?: string;
768
773
  }
769
774
 
770
775
  /**
771
776
  * Used for communicating with Xcode iTMS Transporter tool.
772
777
  */
773
778
  interface IITMSTransporterService {
774
- validate(): Promise<void>;
779
+ validate(appSpecificPassword?: string): Promise<void>;
775
780
  /**
776
781
  * Uploads an .ipa package to iTunes Connect.
777
782
  * @param {IITMSData} data Data needed to upload the package
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.ApplePortalSessionService = void 0;
13
13
  const helpers_1 = require("../../common/helpers");
14
14
  const yok_1 = require("../../common/yok");
15
+ const crypto = require("crypto");
15
16
  class ApplePortalSessionService {
16
17
  constructor($applePortalCookieService, $errors, $httpClient, $logger, $prompter) {
17
18
  this.$applePortalCookieService = $applePortalCookieService;
@@ -31,7 +32,7 @@ class ApplePortalSessionService {
31
32
  if (!opts || !opts.sessionBase64) {
32
33
  if (loginResult.isTwoFactorAuthenticationEnabled) {
33
34
  const authServiceKey = (yield this.getLoginConfig()).authServiceKey;
34
- yield this.handleTwoFactorAuthentication(loginResult.scnt, loginResult.xAppleIdSessionId, authServiceKey);
35
+ yield this.handleTwoFactorAuthentication(loginResult.scnt, loginResult.xAppleIdSessionId, authServiceKey, loginResult.hashcash);
35
36
  }
36
37
  const sessionResponse = yield this.$httpClient.httpRequest({
37
38
  url: "https://appstoreconnect.apple.com/olympus/v1/session",
@@ -80,12 +81,14 @@ class ApplePortalSessionService {
80
81
  });
81
82
  }
82
83
  login(credentials, opts) {
84
+ var _a, _b;
83
85
  return __awaiter(this, void 0, void 0, function* () {
84
86
  const result = {
85
87
  scnt: null,
86
88
  xAppleIdSessionId: null,
87
89
  isTwoFactorAuthenticationEnabled: false,
88
90
  areCredentialsValid: true,
91
+ hashcash: null,
89
92
  };
90
93
  if (opts && opts.sessionBase64) {
91
94
  const decodedSession = Buffer.from(opts.sessionBase64, "base64").toString("utf8");
@@ -99,6 +102,10 @@ class ApplePortalSessionService {
99
102
  }
100
103
  catch (err) {
101
104
  const statusCode = err && err.response && err.response.status;
105
+ const bits = (_a = err === null || err === void 0 ? void 0 : err.response) === null || _a === void 0 ? void 0 : _a.headers["x-apple-hc-bits"];
106
+ const challenge = (_b = err === null || err === void 0 ? void 0 : err.response) === null || _b === void 0 ? void 0 : _b.headers["x-apple-hc-challenge"];
107
+ const hashcash = makeHashCash(bits, challenge);
108
+ result.hashcash = hashcash;
102
109
  result.areCredentialsValid = statusCode !== 401 && statusCode !== 403;
103
110
  result.isTwoFactorAuthenticationEnabled = statusCode === 409;
104
111
  if (result.isTwoFactorAuthenticationEnabled &&
@@ -166,12 +173,13 @@ For more details how to set up your environment, please execute "tns publish ios
166
173
  return config || this.defaultLoginConfig;
167
174
  });
168
175
  }
169
- handleTwoFactorAuthentication(scnt, xAppleIdSessionId, authServiceKey) {
176
+ handleTwoFactorAuthentication(scnt, xAppleIdSessionId, authServiceKey, hashcash) {
170
177
  return __awaiter(this, void 0, void 0, function* () {
171
178
  const headers = {
172
179
  scnt: scnt,
173
180
  "X-Apple-Id-Session-Id": xAppleIdSessionId,
174
181
  "X-Apple-Widget-Key": authServiceKey,
182
+ "X-Apple-HC": hashcash,
175
183
  Accept: "application/json",
176
184
  };
177
185
  const authResponse = yield this.$httpClient.httpRequest({
@@ -180,17 +188,35 @@ For more details how to set up your environment, please execute "tns publish ios
180
188
  headers,
181
189
  });
182
190
  const data = JSON.parse(authResponse.body);
183
- if (data.trustedPhoneNumbers && data.trustedPhoneNumbers.length) {
191
+ const isSMS = data.trustedPhoneNumbers &&
192
+ data.trustedPhoneNumbers.length === 1 &&
193
+ data.noTrustedDevices;
194
+ const multiSMS = data.trustedPhoneNumbers &&
195
+ data.trustedPhoneNumbers.length !== 1 &&
196
+ data.noTrustedDevices;
197
+ let token;
198
+ if (data.trustedPhoneNumbers &&
199
+ data.trustedPhoneNumbers.length &&
200
+ !multiSMS) {
184
201
  const parsedAuthResponse = JSON.parse(authResponse.body);
185
- const token = yield this.$prompter.getString(`Please enter the ${parsedAuthResponse.securityCode.length} digit code`, { allowEmpty: false });
202
+ token = yield this.$prompter.getString(`Please enter the ${parsedAuthResponse.securityCode.length} digit code`, { allowEmpty: false });
203
+ const body = {
204
+ securityCode: {
205
+ code: token.toString(),
206
+ },
207
+ };
208
+ let url = `https://idmsa.apple.com/appleauth/auth/verify/trusteddevice/securitycode`;
209
+ if (isSMS) {
210
+ body.mode = "sms";
211
+ body.phoneNumber = {
212
+ id: data.trustedPhoneNumbers[0].id,
213
+ };
214
+ url = `https://idmsa.apple.com/appleauth/auth/verify/phone/securitycode`;
215
+ }
186
216
  yield this.$httpClient.httpRequest({
187
- url: `https://idmsa.apple.com/appleauth/auth/verify/trusteddevice/securitycode`,
217
+ url,
188
218
  method: "POST",
189
- body: {
190
- securityCode: {
191
- code: token.toString(),
192
- },
193
- },
219
+ body,
194
220
  headers: Object.assign(Object.assign({}, headers), { "Content-Type": "application/json" }),
195
221
  });
196
222
  const authTrustResponse = yield this.$httpClient.httpRequest({
@@ -200,6 +226,9 @@ For more details how to set up your environment, please execute "tns publish ios
200
226
  });
201
227
  this.$applePortalCookieService.updateUserSessionCookie(authTrustResponse.headers["set-cookie"]);
202
228
  }
229
+ else if (multiSMS) {
230
+ this.$errors.fail(`The NativeScript CLI does not support SMS authenticaton with multiple registered phone numbers.`);
231
+ }
203
232
  else {
204
233
  this.$errors.fail(`Although response from Apple indicated activated Two-step Verification or Two-factor Authentication, NativeScript CLI don't know how to handle this response: ${data}`);
205
234
  }
@@ -208,3 +237,41 @@ For more details how to set up your environment, please execute "tns publish ios
208
237
  }
209
238
  exports.ApplePortalSessionService = ApplePortalSessionService;
210
239
  yok_1.injector.register("applePortalSessionService", ApplePortalSessionService);
240
+ function makeHashCash(bits, challenge) {
241
+ const version = 1;
242
+ const dateString = getHashCanDateString();
243
+ let result;
244
+ for (let counter = 0;; counter++) {
245
+ const hc = [version, bits, dateString, challenge, `:${counter}`].join(":");
246
+ const shasumData = crypto.createHash("sha1");
247
+ shasumData.update(hc);
248
+ const digest = shasumData.digest();
249
+ if (checkBits(+bits, digest)) {
250
+ result = hc;
251
+ break;
252
+ }
253
+ }
254
+ return result;
255
+ }
256
+ function getHashCanDateString() {
257
+ const now = new Date();
258
+ return `${now.getFullYear()}${padTo2Digits(now.getMonth() + 1)}${padTo2Digits(now.getDate())}${padTo2Digits(now.getHours())}${padTo2Digits(now.getMinutes())}${padTo2Digits(now.getSeconds())}`;
259
+ }
260
+ function padTo2Digits(num) {
261
+ return num.toString().padStart(2, "0");
262
+ }
263
+ function checkBits(bits, digest) {
264
+ let result = true;
265
+ for (let i = 0; i < bits; ++i) {
266
+ result = checkBit(i, digest);
267
+ if (!result)
268
+ break;
269
+ }
270
+ return result;
271
+ }
272
+ function checkBit(position, buffer) {
273
+ const bitOffset = position & 7;
274
+ const byteIndex = position >> 3;
275
+ const bit = (buffer[byteIndex] >> bitOffset) & 1;
276
+ return bit === 0;
277
+ }
@@ -39,6 +39,7 @@ interface IAppleLoginResult {
39
39
  xAppleIdSessionId: string;
40
40
  isTwoFactorAuthenticationEnabled: boolean;
41
41
  areCredentialsValid: boolean;
42
+ hashcash: string;
42
43
  }
43
44
 
44
45
  interface IApplePortalUserDetail extends IAppleLoginResult {
@@ -20,7 +20,7 @@ class SPMService {
20
20
  this.$xcodebuildArgsService = $xcodebuildArgsService;
21
21
  }
22
22
  getSPMPackages(projectData) {
23
- const spmPackages = this.$projectConfigService.getValue("ios.experimentalSPMPackages", []);
23
+ const spmPackages = this.$projectConfigService.getValue("ios.SPMPackages", []);
24
24
  return spmPackages;
25
25
  }
26
26
  hasSPMPackages(projectData) {
@@ -36,15 +36,38 @@ class ITMSTransporterService {
36
36
  get $projectData() {
37
37
  return this.$injector.resolve("projectData");
38
38
  }
39
- validate() {
39
+ validate(appSpecificPassword) {
40
40
  return __awaiter(this, void 0, void 0, function* () {
41
41
  const itmsTransporterPath = yield this.getITMSTransporterPath();
42
- if (!this.$fs.exists(itmsTransporterPath)) {
43
- this.$errors.fail("iTMS Transporter not found on this machine - make sure your Xcode installation is not damaged.");
42
+ const version = yield this.$xcodeSelectService.getXcodeVersion();
43
+ if (+version.major < 14) {
44
+ if (!this.$fs.exists(itmsTransporterPath)) {
45
+ this.$errors.fail("iTMS Transporter not found on this machine - make sure your Xcode installation is not damaged.");
46
+ }
47
+ }
48
+ else {
49
+ const altoolPath = yield this.getAltoolPath();
50
+ if (!this.$fs.exists(altoolPath)) {
51
+ this.$errors.fail("altool not found on this machine - make sure your Xcode installation is not damaged.");
52
+ }
53
+ if (!appSpecificPassword) {
54
+ this.$errors.fail("An app-specific password is required from xCode versions 14 and above, Use the --appleApplicationSpecificPassword to supply it.");
55
+ }
44
56
  }
45
57
  });
46
58
  }
47
59
  upload(data) {
60
+ return __awaiter(this, void 0, void 0, function* () {
61
+ const version = yield this.$xcodeSelectService.getXcodeVersion();
62
+ if (+version.major < 14) {
63
+ yield this.upload_iTMSTransporter(data);
64
+ }
65
+ else {
66
+ yield this.upload_altool(data);
67
+ }
68
+ });
69
+ }
70
+ upload_iTMSTransporter(data) {
48
71
  return __awaiter(this, void 0, void 0, function* () {
49
72
  const itmsTransporterPath = yield this.getITMSTransporterPath();
50
73
  const ipaFileName = "app.ipa";
@@ -81,6 +104,40 @@ class ITMSTransporterService {
81
104
  ], "close", { stdio: "inherit" });
82
105
  });
83
106
  }
107
+ upload_altool(data) {
108
+ return __awaiter(this, void 0, void 0, function* () {
109
+ const altoolPath = yield this.getAltoolPath();
110
+ const ipaFileName = "app.ipa";
111
+ const itmsDirectory = yield this.$tempService.mkdirSync("itms-");
112
+ const innerDirectory = path.join(itmsDirectory, "mybundle.itmsp");
113
+ const ipaFileLocation = path.join(innerDirectory, ipaFileName);
114
+ this.$fs.createDirectory(innerDirectory);
115
+ this.$fs.copyFile(data.ipaFilePath, ipaFileLocation);
116
+ const password = data.applicationSpecificPassword;
117
+ const args = [
118
+ "--upload-app",
119
+ "-t",
120
+ "ios",
121
+ "-f",
122
+ ipaFileLocation,
123
+ "-u",
124
+ data.credentials.username,
125
+ "-p",
126
+ password,
127
+ "-k 100000",
128
+ ];
129
+ if (data.teamId) {
130
+ args.push("--asc-provider");
131
+ args.push(data.teamId);
132
+ }
133
+ if (data.verboseLogging) {
134
+ args.push("--verbose");
135
+ }
136
+ yield this.$childProcess.spawnFromEvent(altoolPath, args, "close", {
137
+ stdio: "inherit",
138
+ });
139
+ });
140
+ }
84
141
  getBundleIdentifier(data) {
85
142
  return __awaiter(this, void 0, void 0, function* () {
86
143
  const { shouldExtractIpa, ipaFilePath } = data;
@@ -115,6 +172,13 @@ class ITMSTransporterService {
115
172
  return this.$projectData.projectIdentifiers.ios;
116
173
  });
117
174
  }
175
+ getAltoolPath() {
176
+ return __awaiter(this, void 0, void 0, function* () {
177
+ const xcodePath = yield this.$xcodeSelectService.getContentsDirectoryPath();
178
+ let itmsTransporterPath = path.join(xcodePath, "..", "Contents", "Developer", "usr", "bin", constants_1.ITMSConstants.altoolExecutableName);
179
+ return itmsTransporterPath;
180
+ });
181
+ }
118
182
  getITMSTransporterPath() {
119
183
  return __awaiter(this, void 0, void 0, function* () {
120
184
  const xcodePath = yield this.$xcodeSelectService.getContentsDirectoryPath();
@@ -142,6 +206,9 @@ class ITMSTransporterService {
142
206
  </package>`;
143
207
  }
144
208
  }
209
+ __decorate([
210
+ (0, decorators_1.cache)()
211
+ ], ITMSTransporterService.prototype, "getAltoolPath", null);
145
212
  __decorate([
146
213
  (0, decorators_1.cache)()
147
214
  ], ITMSTransporterService.prototype, "getITMSTransporterPath", null);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nativescript",
3
3
  "preferGlobal": true,
4
- "version": "8.5.0-dev.0",
4
+ "version": "8.5.0-dev.0-next-03-25-2023-4519382718",
5
5
  "author": "NativeScript <support@nativescript.org>",
6
6
  "description": "Command-line interface for building NativeScript projects",
7
7
  "bin": {