@swipt/cli 0.1.0-nightly.43 → 0.1.0-nightly.45
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/client.mjs +103 -30
- package/connection.mjs +86 -26
- package/coredevice.mjs +68 -0
- package/device.mjs +274 -90
- package/ignore.mjs +17 -5
- package/metro.mjs +235 -65
- package/output.mjs +32 -7
- package/package.json +8 -3
- package/project.mjs +394 -106
- package/proto/system_pb.js +1 -1
- package/sideload/trust.js +235 -0
- package/sideload.mjs +649 -0
- package/swipt.mjs +374 -52
package/proto/system_pb.js
CHANGED
|
@@ -10,7 +10,7 @@ import { file_common } from "./common_pb.js";
|
|
|
10
10
|
* Describes the file system.proto.
|
|
11
11
|
*/
|
|
12
12
|
export const file_system = /*@__PURE__*/
|
|
13
|
-
fileDesc("
|
|
13
|
+
fileDesc("CgxzeXN0ZW0ucHJvdG8SBXN3aXB0IqgBCg9HZXRJbmZvUmVzcG9uc2USFgoOc2VydmVyX3ZlcnNpb24YASABKAkSEwoLZGV2aWNlX25hbWUYAiABKAkSDAoEdWRpZBgDIAEoCRIyChFkZXZpY2VfY29ubmVjdGlvbhgEIAEoCzIXLnN3aXB0LkRldmljZUNvbm5lY3Rpb24SEwoLYXBwX3ZlcnNpb24YBSABKAkSEQoJYXBwX2J1aWxkGAYgASgJMoYBCg1TeXN0ZW1TZXJ2aWNlEjkKB0dldEluZm8SFi5nb29nbGUucHJvdG9idWYuRW1wdHkaFi5zd2lwdC5HZXRJbmZvUmVzcG9uc2USOgoIU2h1dGRvd24SFi5nb29nbGUucHJvdG9idWYuRW1wdHkaFi5nb29nbGUucHJvdG9idWYuRW1wdHlCMlowZ2l0aHViLmNvbS9zd2lwdC1hdXRvbWF0aW9uL3N3aXB0L2ludGVybmFsL3Byb3RvYgZwcm90bzM", [file_google_protobuf_empty, file_common]);
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Describes the message swipt.GetInfoResponse.
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
const [id] = args;
|
|
2
|
+
const settings = "com.apple.Preferences";
|
|
3
|
+
const developerPattern =
|
|
4
|
+
/(?:Apple Development|iPhone Developer): .+?\([A-Z0-9]{10}\)/;
|
|
5
|
+
const tapTimeoutMs = 3_000;
|
|
6
|
+
|
|
7
|
+
const sheet = async () => {
|
|
8
|
+
const screen = await accessibility.snapshot({ scope: "screen" });
|
|
9
|
+
return screen.find({ role: "sheet" });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const alertPresentMs = 600;
|
|
13
|
+
|
|
14
|
+
async function dismiss(alert, buttons, index) {
|
|
15
|
+
await sleep(alertPresentMs);
|
|
16
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
17
|
+
await input.tap(buttons[index].point);
|
|
18
|
+
await sleep(alertPresentMs);
|
|
19
|
+
const shown = await sheet();
|
|
20
|
+
if (shown === null || shown.label !== alert.label) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
throw new Error(`the alert stays: ${alert.label}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function allowPrompts(name, waitMs) {
|
|
28
|
+
const until = Date.now() + waitMs;
|
|
29
|
+
do {
|
|
30
|
+
const alert = await sheet();
|
|
31
|
+
const buttons = alert?.findAll({ role: "button" }) ?? [];
|
|
32
|
+
if (buttons.length === 2 && alert.label?.includes(name)) {
|
|
33
|
+
await dismiss(alert, buttons, 1);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
await sleep(300);
|
|
37
|
+
} while (Date.now() < until);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function launch(name) {
|
|
41
|
+
try {
|
|
42
|
+
await device.launchApplication(id, { restart: true });
|
|
43
|
+
await allowPrompts(name, 3_000);
|
|
44
|
+
return null;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
47
|
+
const alert = await sheet();
|
|
48
|
+
const buttons = alert?.findAll({ role: "button" }) ?? [];
|
|
49
|
+
if (buttons.length === 1) {
|
|
50
|
+
const developer = alert
|
|
51
|
+
.findAll({ role: "text" })
|
|
52
|
+
.map((text) => developerPattern.exec(text.label ?? "")?.[0])
|
|
53
|
+
.find((found) => found !== undefined);
|
|
54
|
+
await dismiss(alert, buttons, 0);
|
|
55
|
+
if (developer === undefined) {
|
|
56
|
+
throw new Error(`the alert names no developer: ${alert.label}`);
|
|
57
|
+
}
|
|
58
|
+
return developer;
|
|
59
|
+
}
|
|
60
|
+
await sleep(300);
|
|
61
|
+
}
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function findScrolling(selector, bounds) {
|
|
67
|
+
for (let attempt = 0; attempt < 12; attempt++) {
|
|
68
|
+
const found = await accessibility.find(
|
|
69
|
+
{ app: settings, ...selector },
|
|
70
|
+
{ timeoutMs: 1_500, poll: true },
|
|
71
|
+
);
|
|
72
|
+
if (found !== null && !found.partial && !found.offScreen) {
|
|
73
|
+
return found;
|
|
74
|
+
}
|
|
75
|
+
const distance = found === null ? 0.5 : 0.25;
|
|
76
|
+
await input.swipe(
|
|
77
|
+
[bounds.width * 0.6, bounds.height * (0.3 + distance)],
|
|
78
|
+
[bounds.width * 0.6, bounds.height * 0.3],
|
|
79
|
+
{ durationMs: 300 },
|
|
80
|
+
);
|
|
81
|
+
await sleep(500);
|
|
82
|
+
}
|
|
83
|
+
throw new Error(`Settings did not show ${JSON.stringify(selector)}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function openRow(selector, bounds, loaded) {
|
|
87
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
88
|
+
try {
|
|
89
|
+
await accessibility.tap(await findScrolling(selector, bounds), {
|
|
90
|
+
timeoutMs: tapTimeoutMs,
|
|
91
|
+
});
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (error.name !== "TimeoutError") {
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
await input.pressHome();
|
|
97
|
+
await sleep(800);
|
|
98
|
+
await device.launchApplication(settings);
|
|
99
|
+
await sleep(1_000);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
for (let wait = 0; wait < 10; wait++) {
|
|
103
|
+
await sleep(300);
|
|
104
|
+
if (loaded(await accessibility.snapshot({ scope: "frontApp" }))) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
throw new Error(`Settings did not open ${JSON.stringify(selector)}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function back() {
|
|
113
|
+
const button = await accessibility.find(
|
|
114
|
+
{ app: settings, identifier: "BackButton" },
|
|
115
|
+
{ timeoutMs: 3_000, poll: true },
|
|
116
|
+
);
|
|
117
|
+
if (button === null) {
|
|
118
|
+
throw new Error("Settings shows no back button");
|
|
119
|
+
}
|
|
120
|
+
await accessibility.tap(button, { timeoutMs: tapTimeoutMs });
|
|
121
|
+
await sleep(600);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function trust(developer, bounds) {
|
|
125
|
+
await device.launchApplication(settings, { restart: true });
|
|
126
|
+
await openRow(
|
|
127
|
+
{ identifier: "com.apple.settings.general" },
|
|
128
|
+
bounds,
|
|
129
|
+
(opened) =>
|
|
130
|
+
opened.findAll({ identifier: /^com\.apple\.settings\.general\./ })
|
|
131
|
+
.length > 0,
|
|
132
|
+
);
|
|
133
|
+
await openRow(
|
|
134
|
+
{ identifier: "com.apple.settings.general.vpnAndDeviceManagement" },
|
|
135
|
+
bounds,
|
|
136
|
+
(opened) =>
|
|
137
|
+
opened.findAll({ role: "button", identifier: "VPN" }).length > 0,
|
|
138
|
+
);
|
|
139
|
+
const candidates = (list) => {
|
|
140
|
+
const elsewhere = new Set(
|
|
141
|
+
list
|
|
142
|
+
.findAll({
|
|
143
|
+
role: "button",
|
|
144
|
+
within: {
|
|
145
|
+
identifier: "com.apple.settings.sidebar.collectionView",
|
|
146
|
+
},
|
|
147
|
+
})
|
|
148
|
+
.concat(
|
|
149
|
+
list.findAll({
|
|
150
|
+
role: "button",
|
|
151
|
+
within: { role: /^(navigationBar|searchField)$/ },
|
|
152
|
+
}),
|
|
153
|
+
)
|
|
154
|
+
.map((row) => row.identifier),
|
|
155
|
+
);
|
|
156
|
+
return list
|
|
157
|
+
.findAll({ role: "button" })
|
|
158
|
+
.filter(
|
|
159
|
+
(row) =>
|
|
160
|
+
row.identifier !== undefined &&
|
|
161
|
+
row.identifier !== "BackButton" &&
|
|
162
|
+
row.identifier !== "VPN" &&
|
|
163
|
+
row.identifier !== row.label &&
|
|
164
|
+
!elsewhere.has(row.identifier),
|
|
165
|
+
)
|
|
166
|
+
.map((row) => row.identifier);
|
|
167
|
+
};
|
|
168
|
+
let rows = [];
|
|
169
|
+
for (let attempt = 0; attempt < 15 && rows.length === 0; attempt++) {
|
|
170
|
+
await sleep(400);
|
|
171
|
+
rows = candidates(await accessibility.snapshot({ scope: "frontApp" }));
|
|
172
|
+
}
|
|
173
|
+
for (const row of rows) {
|
|
174
|
+
const button = await accessibility.find(
|
|
175
|
+
{ app: settings, role: "button", identifier: row },
|
|
176
|
+
{ timeoutMs: 3_000, poll: true },
|
|
177
|
+
);
|
|
178
|
+
if (button === null) {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
await accessibility.tap(button, { timeoutMs: tapTimeoutMs });
|
|
182
|
+
let control = null;
|
|
183
|
+
for (let attempt = 0; attempt < 10 && control === null; attempt++) {
|
|
184
|
+
await sleep(300);
|
|
185
|
+
const opened = await accessibility.snapshot({ scope: "frontApp" });
|
|
186
|
+
if (
|
|
187
|
+
opened.findAll((it) => (it.label ?? "").includes(developer)).length > 0
|
|
188
|
+
) {
|
|
189
|
+
control =
|
|
190
|
+
opened
|
|
191
|
+
.findAll({ role: "text" })
|
|
192
|
+
.find((it) => it.label !== row && it.label?.includes(row)) ?? null;
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (control === null) {
|
|
197
|
+
await back();
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
await input.tap(control.point);
|
|
201
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
202
|
+
const alert = await sheet();
|
|
203
|
+
const buttons = alert?.findAll({ role: "button" }) ?? [];
|
|
204
|
+
if (buttons.length === 2) {
|
|
205
|
+
await dismiss(alert, buttons, 0);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
await sleep(300);
|
|
209
|
+
}
|
|
210
|
+
throw new Error("Settings did not ask to allow the developer");
|
|
211
|
+
}
|
|
212
|
+
throw new Error(`Settings lists no app from ${developer}`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async function main() {
|
|
216
|
+
await device.unlock().catch(() => {});
|
|
217
|
+
const name =
|
|
218
|
+
(await device.installedApplications()).find((app) => app.bundleId === id)
|
|
219
|
+
?.name ?? "Swipt";
|
|
220
|
+
await allowPrompts(name, 0);
|
|
221
|
+
const developer = await launch(name);
|
|
222
|
+
if (developer === null) {
|
|
223
|
+
console.log(`${name} is running`);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const { screen: bounds } = await device.info();
|
|
227
|
+
await trust(developer, bounds);
|
|
228
|
+
await sleep(1_000);
|
|
229
|
+
if ((await launch(name)) !== null) {
|
|
230
|
+
throw new Error(`${name} does not open after trusting ${developer}`);
|
|
231
|
+
}
|
|
232
|
+
console.log(`${name} is running; ${developer} is trusted`);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
await main();
|