@swipt/cli 0.1.0-nightly.45 → 0.1.0-nightly.46
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.
- package/connection.mjs +2 -2
- package/coredevice.mjs +12 -6
- package/package.json +4 -4
- package/sideload.mjs +71 -24
- package/swipt.mjs +19 -23
package/connection.mjs
CHANGED
|
@@ -155,7 +155,7 @@ const requiresToken = (found) =>
|
|
|
155
155
|
`${found.name} requires a token: swipt device add ${withToken(found.url)}`;
|
|
156
156
|
|
|
157
157
|
export async function attach(context) {
|
|
158
|
-
const given = context.options.device
|
|
158
|
+
const given = context.options.device;
|
|
159
159
|
const stored = load();
|
|
160
160
|
let device;
|
|
161
161
|
if (given && /[:/]/.test(given)) {
|
|
@@ -197,7 +197,7 @@ export async function attach(context) {
|
|
|
197
197
|
}
|
|
198
198
|
if (names.length > 1) {
|
|
199
199
|
throw new Error(
|
|
200
|
-
`there is more than one device: ${names.join(", ")}; choose one with -d
|
|
200
|
+
`there is more than one device: ${names.join(", ")}; choose one with -d`,
|
|
201
201
|
);
|
|
202
202
|
}
|
|
203
203
|
device = parseURL(stored[names[0]]);
|
package/coredevice.mjs
CHANGED
|
@@ -34,7 +34,7 @@ export function devicectl(args, { parse = false } = {}) {
|
|
|
34
34
|
return parsed;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export function coreDevice(given) {
|
|
37
|
+
export function coreDevice(given, { required = false } = {}) {
|
|
38
38
|
const devices = devicectl(["list", "devices"], { parse: true })
|
|
39
39
|
.result.devices.filter(
|
|
40
40
|
(device) =>
|
|
@@ -51,13 +51,19 @@ export function coreDevice(given) {
|
|
|
51
51
|
sameName(device.udid, given) ||
|
|
52
52
|
sameName(label(device.name), label(given)),
|
|
53
53
|
)
|
|
54
|
-
:
|
|
54
|
+
: required
|
|
55
|
+
? []
|
|
56
|
+
: devices;
|
|
55
57
|
if (matches.length !== 1) {
|
|
56
|
-
const
|
|
58
|
+
const reason = !given
|
|
59
|
+
? "choose a device with -d NAME|UDID"
|
|
60
|
+
: matches.length === 0
|
|
61
|
+
? `no iOS device is named ${given}`
|
|
62
|
+
: `more than one iOS device is named ${given}; choose one by UDID`;
|
|
57
63
|
throw new Error(
|
|
58
|
-
|
|
59
|
-
? `${
|
|
60
|
-
: `${
|
|
64
|
+
devices.length === 0
|
|
65
|
+
? `${reason}; no iOS device is paired with this Mac`
|
|
66
|
+
: `${reason}; paired iOS devices:\n${devices.map((device) => ` ${device.name} ${device.udid}`).join("\n")}`,
|
|
61
67
|
);
|
|
62
68
|
}
|
|
63
69
|
return matches[0];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swipt/cli",
|
|
3
|
-
"version": "0.1.0-nightly.
|
|
3
|
+
"version": "0.1.0-nightly.46",
|
|
4
4
|
"license": "GPL-3.0-or-later",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
"react-native-worklets": "0.13.0"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@swipt/api": "0.1.0-nightly.
|
|
35
|
+
"@swipt/api": "0.1.0-nightly.46"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
|
-
"@swipt/server-darwin-arm64": "0.1.0-nightly.
|
|
39
|
-
"@swipt/server-darwin-x64": "0.1.0-nightly.
|
|
38
|
+
"@swipt/server-darwin-arm64": "0.1.0-nightly.46",
|
|
39
|
+
"@swipt/server-darwin-x64": "0.1.0-nightly.46"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@bufbuild/protoc-gen-es": "^2.16.0"
|
package/sideload.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
2
|
-
import { createHash } from "node:crypto";
|
|
2
|
+
import { X509Certificate, createHash } from "node:crypto";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import os from "node:os";
|
|
@@ -31,7 +31,7 @@ function passcodeOf(options) {
|
|
|
31
31
|
`invalid argument ${JSON.stringify(type)} for --passcode-type: it is ${passcodeTypes.join(", ")}`,
|
|
32
32
|
);
|
|
33
33
|
}
|
|
34
|
-
const passcode = options.passcode
|
|
34
|
+
const passcode = options.passcode;
|
|
35
35
|
if (!passcode) {
|
|
36
36
|
return undefined;
|
|
37
37
|
}
|
|
@@ -51,7 +51,7 @@ function passcodeOf(options) {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
function headers(accept) {
|
|
54
|
-
const token = process.env.GITHUB_TOKEN
|
|
54
|
+
const token = process.env.GITHUB_TOKEN;
|
|
55
55
|
return {
|
|
56
56
|
Accept: accept,
|
|
57
57
|
"X-GitHub-Api-Version": "2022-11-28",
|
|
@@ -72,7 +72,7 @@ async function github(url, accept, signal) {
|
|
|
72
72
|
if (!response.ok) {
|
|
73
73
|
let message = `GitHub answered ${response.status} for ${url}`;
|
|
74
74
|
if ([401, 403, 404, 429].includes(response.status)) {
|
|
75
|
-
message += `; ${process.env.GITHUB_TOKEN
|
|
75
|
+
message += `; ${process.env.GITHUB_TOKEN ? "GITHUB_TOKEN" : "set GITHUB_TOKEN to a token that"} must read the repository and stay under the rate limit`;
|
|
76
76
|
}
|
|
77
77
|
throw new Error(message);
|
|
78
78
|
}
|
|
@@ -317,7 +317,45 @@ function resign(app, id, signing) {
|
|
|
317
317
|
]);
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
-
function
|
|
320
|
+
function xcodeTeams() {
|
|
321
|
+
const valid = new Set(
|
|
322
|
+
[
|
|
323
|
+
...execFileSync(
|
|
324
|
+
"security",
|
|
325
|
+
["find-identity", "-v", "-p", "codesigning"],
|
|
326
|
+
{
|
|
327
|
+
encoding: "utf8",
|
|
328
|
+
},
|
|
329
|
+
).matchAll(/\) ([0-9A-F]{40}) "Apple Development: /g),
|
|
330
|
+
].map((match) => match[1]),
|
|
331
|
+
);
|
|
332
|
+
const certificates = execFileSync(
|
|
333
|
+
"security",
|
|
334
|
+
["find-certificate", "-a", "-Z", "-p", "-c", "Apple Development"],
|
|
335
|
+
{ encoding: "utf8" },
|
|
336
|
+
).matchAll(
|
|
337
|
+
/SHA-1 hash: ([0-9A-F]{40})[\s\S]*?(-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----)/g,
|
|
338
|
+
);
|
|
339
|
+
const teams = new Map();
|
|
340
|
+
for (const [, hash, pem] of certificates) {
|
|
341
|
+
if (!valid.has(hash)) {
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
const subject = new X509Certificate(pem).subject;
|
|
345
|
+
const id = /^OU=(.+)$/m.exec(subject)?.[1];
|
|
346
|
+
if (id !== undefined && teamPattern.test(id)) {
|
|
347
|
+
teams.set(id, /^O=(.+)$/m.exec(subject)?.[1].replaceAll("\\", ""));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return [...teams].map(([id, name]) => ({ id, name }));
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const teamList = (teams) =>
|
|
354
|
+
teams
|
|
355
|
+
.map((team) => ` ${team.id}${team.name ? ` ${team.name}` : ""}`)
|
|
356
|
+
.join("\n");
|
|
357
|
+
|
|
358
|
+
function locate(options, device, fresh = false) {
|
|
321
359
|
const found = apps(device.udid)
|
|
322
360
|
.map((app) => ({
|
|
323
361
|
...app,
|
|
@@ -337,25 +375,35 @@ function locate(options, device) {
|
|
|
337
375
|
}
|
|
338
376
|
if (found.length > 1) {
|
|
339
377
|
throw new Error(
|
|
340
|
-
`Swipt is sideloaded on ${device.name} by more than one team
|
|
378
|
+
`Swipt is sideloaded on ${device.name} by more than one team; choose one with --team ID:\n${teamList(found.map((app) => ({ id: app.team })))}`,
|
|
341
379
|
);
|
|
342
380
|
}
|
|
381
|
+
if (found.length === 0 && fresh) {
|
|
382
|
+
const teams = xcodeTeams();
|
|
383
|
+
if (teams.length !== 1) {
|
|
384
|
+
throw new Error(
|
|
385
|
+
teams.length === 0
|
|
386
|
+
? `Xcode has no development certificate; sign in at ${accountsHint}, or choose a team with --team ID`
|
|
387
|
+
: `choose a team with --team ID:\n${teamList(teams)}`,
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
return { team: teams[0].id, current: undefined };
|
|
391
|
+
}
|
|
343
392
|
return { team: found[0]?.team, current: found[0] };
|
|
344
393
|
}
|
|
345
394
|
|
|
346
395
|
const buildText = (app) => `Swipt ${app.version} (${app.bundleVersion})`;
|
|
347
396
|
|
|
348
397
|
async function deploy(context, onlyNewer) {
|
|
349
|
-
const
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
if (team === undefined) {
|
|
398
|
+
const device = coreDevice(context.options.device, { required: true });
|
|
399
|
+
const { team, current } = locate(context.options, device, !onlyNewer);
|
|
400
|
+
if (current === undefined && onlyNewer) {
|
|
353
401
|
throw new Error(
|
|
354
|
-
|
|
355
|
-
? `Swipt is not sideloaded on ${device.name}; install it with "swipt sideload install"`
|
|
356
|
-
: `Swipt is not sideloaded on ${device.name} yet; choose the team with --team ID, as shown in ${accountsHint}`,
|
|
402
|
+
`Swipt is not sideloaded on ${device.name}${team === undefined ? "" : ` by team ${team}`}; install it with "swipt sideload install"`,
|
|
357
403
|
);
|
|
358
404
|
}
|
|
405
|
+
const passcode =
|
|
406
|
+
current === undefined ? passcodeOf(context.options) : undefined;
|
|
359
407
|
const release = await findRelease(context.options.nightly, context.signal);
|
|
360
408
|
if (current !== undefined) {
|
|
361
409
|
const installed = Number(current.bundleVersion);
|
|
@@ -432,12 +480,9 @@ export const install = (context) => deploy(context, false);
|
|
|
432
480
|
export const update = (context) => deploy(context, true);
|
|
433
481
|
|
|
434
482
|
const serverHint =
|
|
435
|
-
"swipt-server is missing; install @swipt/cli with its optional dependencies
|
|
483
|
+
"swipt-server is missing; install @swipt/cli with its optional dependencies";
|
|
436
484
|
|
|
437
485
|
function serverPath() {
|
|
438
|
-
if (process.env.SWIPT_SERVER_PATH) {
|
|
439
|
-
return process.env.SWIPT_SERVER_PATH;
|
|
440
|
-
}
|
|
441
486
|
let packaged;
|
|
442
487
|
try {
|
|
443
488
|
packaged = path.join(
|
|
@@ -540,12 +585,14 @@ function pair(device, id, work) {
|
|
|
540
585
|
function serve(udid, passcode, signal) {
|
|
541
586
|
const server = spawn(
|
|
542
587
|
serverPath(),
|
|
543
|
-
[
|
|
588
|
+
[
|
|
589
|
+
"-d",
|
|
590
|
+
udid,
|
|
591
|
+
...(passcode
|
|
592
|
+
? ["--passcode", passcode.passcode, "--passcode-type", passcode.type]
|
|
593
|
+
: []),
|
|
594
|
+
],
|
|
544
595
|
{
|
|
545
|
-
env: {
|
|
546
|
-
...process.env,
|
|
547
|
-
...(passcode ? { SWIPT_PASSCODE: passcode.passcode } : {}),
|
|
548
|
-
},
|
|
549
596
|
stdio: ["ignore", "pipe", "pipe"],
|
|
550
597
|
signal,
|
|
551
598
|
},
|
|
@@ -586,7 +633,7 @@ function serve(udid, passcode, signal) {
|
|
|
586
633
|
|
|
587
634
|
export async function start(context) {
|
|
588
635
|
const passcode = passcodeOf(context.options);
|
|
589
|
-
const device = coreDevice(context.options.device
|
|
636
|
+
const device = coreDevice(context.options.device, { required: true });
|
|
590
637
|
const { team, current } = locate(context.options, device);
|
|
591
638
|
if (current === undefined) {
|
|
592
639
|
throw new Error(
|
|
@@ -630,7 +677,7 @@ export async function start(context) {
|
|
|
630
677
|
}
|
|
631
678
|
|
|
632
679
|
export function uninstall(context) {
|
|
633
|
-
const device = coreDevice(context.options.device
|
|
680
|
+
const device = coreDevice(context.options.device, { required: true });
|
|
634
681
|
const { team, current } = locate(context.options, device);
|
|
635
682
|
if (current === undefined) {
|
|
636
683
|
throw new Error(
|
package/swipt.mjs
CHANGED
|
@@ -18,7 +18,7 @@ const deviceOption = {
|
|
|
18
18
|
type: "string",
|
|
19
19
|
short: "d",
|
|
20
20
|
value: "NAME|URL",
|
|
21
|
-
help: "the device to use
|
|
21
|
+
help: "the device to use",
|
|
22
22
|
},
|
|
23
23
|
};
|
|
24
24
|
|
|
@@ -27,33 +27,26 @@ const sideloadOptions = {
|
|
|
27
27
|
type: "string",
|
|
28
28
|
short: "d",
|
|
29
29
|
value: "NAME|UDID",
|
|
30
|
-
help: "
|
|
30
|
+
help: "device paired with this Mac",
|
|
31
31
|
},
|
|
32
32
|
team: {
|
|
33
33
|
type: "string",
|
|
34
34
|
value: "ID",
|
|
35
|
-
help: "
|
|
35
|
+
help: "team ID, required if more than one",
|
|
36
36
|
},
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
const passcodeOptions = {
|
|
40
|
-
passcode: {
|
|
41
|
-
type: "string",
|
|
42
|
-
value: "CODE",
|
|
43
|
-
help: "the device passcode, for unlocking it (SWIPT_PASSCODE)",
|
|
44
|
-
},
|
|
39
|
+
const passcodeOptions = (help) => ({
|
|
40
|
+
passcode: { type: "string", value: "CODE", help },
|
|
45
41
|
"passcode-type": {
|
|
46
42
|
type: "string",
|
|
47
43
|
value: "TYPE",
|
|
48
|
-
help: "pin
|
|
44
|
+
help: "pin (4 or 6 digits, default), numeric or alphanumeric",
|
|
49
45
|
},
|
|
50
|
-
};
|
|
46
|
+
});
|
|
51
47
|
|
|
52
48
|
const nightlyOption = {
|
|
53
|
-
nightly: {
|
|
54
|
-
type: "boolean",
|
|
55
|
-
help: "the nightly build",
|
|
56
|
-
},
|
|
49
|
+
nightly: { type: "boolean", help: "use nightly build" },
|
|
57
50
|
};
|
|
58
51
|
|
|
59
52
|
const durationUnits = {
|
|
@@ -391,33 +384,36 @@ const commands = [
|
|
|
391
384
|
},
|
|
392
385
|
{
|
|
393
386
|
name: "sideload",
|
|
394
|
-
short: "
|
|
387
|
+
short: "Sideload Swipt, signed by Xcode",
|
|
395
388
|
options: sideloadOptions,
|
|
396
389
|
commands: [
|
|
397
390
|
{
|
|
398
391
|
name: "install",
|
|
399
|
-
short: "Install
|
|
392
|
+
short: "Install latest release",
|
|
400
393
|
args: [0, 0],
|
|
401
|
-
options: {
|
|
394
|
+
options: {
|
|
395
|
+
...passcodeOptions("set up auto-unlock with this passcode"),
|
|
396
|
+
...nightlyOption,
|
|
397
|
+
},
|
|
402
398
|
run: sideload.install,
|
|
403
399
|
},
|
|
404
400
|
{
|
|
405
401
|
name: "update",
|
|
406
|
-
short: "
|
|
402
|
+
short: "Update to latest release",
|
|
407
403
|
args: [0, 0],
|
|
408
|
-
options:
|
|
404
|
+
options: nightlyOption,
|
|
409
405
|
run: sideload.update,
|
|
410
406
|
},
|
|
411
407
|
{
|
|
412
408
|
name: "start",
|
|
413
|
-
short: "
|
|
409
|
+
short: "Trust developer if needed and open Swipt",
|
|
414
410
|
args: [0, 0],
|
|
415
|
-
options: passcodeOptions,
|
|
411
|
+
options: passcodeOptions("unlock device with this passcode"),
|
|
416
412
|
run: sideload.start,
|
|
417
413
|
},
|
|
418
414
|
{
|
|
419
415
|
name: "uninstall",
|
|
420
|
-
short: "Remove
|
|
416
|
+
short: "Remove Swipt",
|
|
421
417
|
args: [0, 0],
|
|
422
418
|
run: sideload.uninstall,
|
|
423
419
|
},
|