@limrun/ui 0.9.0-rc.4 → 0.9.0-rc.5
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/README.md +0 -9
- package/dist/components/inspect-overlay.d.ts +33 -0
- package/dist/components/remote-control.d.ts +86 -0
- package/dist/core/ax-fetcher.d.ts +49 -0
- package/dist/core/ax-tree.d.ts +99 -0
- package/dist/index.cjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1491 -777
- package/package.json +8 -17
- package/src/components/inspect-overlay.css +223 -0
- package/src/components/inspect-overlay.tsx +437 -0
- package/src/components/remote-control.tsx +547 -9
- package/src/core/ax-fetcher.test.ts +418 -0
- package/src/core/ax-fetcher.ts +377 -0
- package/src/core/ax-tree.test.ts +491 -0
- package/src/core/ax-tree.ts +416 -0
- package/src/demo.tsx +93 -10
- package/src/index.ts +17 -2
- package/vite.config.ts +2 -6
- package/vitest.config.ts +23 -0
- package/dist/components/device-install/device-install-dialog.d.ts +0 -5
- package/dist/components/device-install/index.d.ts +0 -2
- package/dist/core/device-install/apple/client.d.ts +0 -17
- package/dist/core/device-install/apple/crypto.d.ts +0 -20
- package/dist/core/device-install/apple/gsa-srp.d.ts +0 -26
- package/dist/core/device-install/apple/index.d.ts +0 -5
- package/dist/core/device-install/apple/provisioning.d.ts +0 -161
- package/dist/core/device-install/apple/relay.d.ts +0 -29
- package/dist/core/device-install/index.d.ts +0 -4
- package/dist/core/device-install/operations/index.d.ts +0 -6
- package/dist/core/device-install/operations/limbuild-client.d.ts +0 -28
- package/dist/core/device-install/operations/operations.d.ts +0 -32
- package/dist/core/device-install/operations/relay-client.d.ts +0 -25
- package/dist/core/device-install/operations/relay-protocol.d.ts +0 -27
- package/dist/core/device-install/operations/usbmux.d.ts +0 -32
- package/dist/core/device-install/operations/webusb.d.ts +0 -21
- package/dist/core/device-install/storage/browser-storage.d.ts +0 -44
- package/dist/core/device-install/storage/index.d.ts +0 -1
- package/dist/core/device-install/types.d.ts +0 -48
- package/dist/device-install/index.cjs +0 -1
- package/dist/device-install/index.d.ts +0 -3
- package/dist/device-install/index.js +0 -78
- package/dist/device-install/react.cjs +0 -1
- package/dist/device-install/react.d.ts +0 -1
- package/dist/device-install/react.js +0 -4
- package/dist/device-install-dialog-86RDdoK9.js +0 -2
- package/dist/device-install-dialog-CnyDWf0q.mjs +0 -462
- package/dist/device-install-dialog.css +0 -1
- package/dist/hooks/index.d.ts +0 -1
- package/dist/hooks/use-device-install.d.ts +0 -73
- package/dist/use-device-install-CbGVvwPp.js +0 -31
- package/dist/use-device-install-j1Gekpl4.mjs +0 -13623
- package/src/components/device-install/device-install-dialog.css +0 -325
- package/src/components/device-install/device-install-dialog.tsx +0 -513
- package/src/components/device-install/index.ts +0 -2
- package/src/core/device-install/apple/client.ts +0 -152
- package/src/core/device-install/apple/crypto.ts +0 -202
- package/src/core/device-install/apple/gsa-srp.ts +0 -127
- package/src/core/device-install/apple/index.ts +0 -5
- package/src/core/device-install/apple/provisioning.ts +0 -298
- package/src/core/device-install/apple/relay.ts +0 -221
- package/src/core/device-install/index.ts +0 -4
- package/src/core/device-install/operations/index.ts +0 -6
- package/src/core/device-install/operations/limbuild-client.ts +0 -104
- package/src/core/device-install/operations/operations.ts +0 -217
- package/src/core/device-install/operations/relay-client.ts +0 -255
- package/src/core/device-install/operations/relay-protocol.ts +0 -71
- package/src/core/device-install/operations/usbmux.ts +0 -270
- package/src/core/device-install/operations/webusb-dom.d.ts +0 -54
- package/src/core/device-install/operations/webusb.ts +0 -105
- package/src/core/device-install/storage/browser-storage.ts +0 -263
- package/src/core/device-install/storage/index.ts +0 -1
- package/src/core/device-install/types.ts +0 -65
- package/src/device-install/index.ts +0 -3
- package/src/device-install/react.ts +0 -1
- package/src/hooks/index.ts +0 -1
- package/src/hooks/use-device-install.ts +0 -1210
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import forge from 'node-forge';
|
|
2
|
-
|
|
3
|
-
export type AppleSigningKeyMaterial = {
|
|
4
|
-
privateKey: CryptoKey;
|
|
5
|
-
privateKeyPKCS8Base64: string;
|
|
6
|
-
publicKeySPKIBase64: string;
|
|
7
|
-
csrPEM: string;
|
|
8
|
-
csrBase64: string;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export type AppleCSRInput = {
|
|
12
|
-
commonName: string;
|
|
13
|
-
emailAddress?: string;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export type ExportP12Input = {
|
|
17
|
-
privateKeyPKCS8Base64: string;
|
|
18
|
-
certificateBase64?: string;
|
|
19
|
-
certificatePEM?: string;
|
|
20
|
-
password: string;
|
|
21
|
-
friendlyName?: string;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const rsaAlgorithm: RsaHashedKeyGenParams = {
|
|
25
|
-
name: 'RSASSA-PKCS1-v1_5',
|
|
26
|
-
modulusLength: 2048,
|
|
27
|
-
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
|
28
|
-
hash: 'SHA-256',
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export async function generateAppleSigningKeyAndCSR(input: AppleCSRInput): Promise<AppleSigningKeyMaterial> {
|
|
32
|
-
if (!crypto.subtle) {
|
|
33
|
-
throw new Error('WebCrypto is not available in this browser.');
|
|
34
|
-
}
|
|
35
|
-
const keyPair = await crypto.subtle.generateKey(rsaAlgorithm, true, ['sign', 'verify']);
|
|
36
|
-
const publicKeySPKI = new Uint8Array(await crypto.subtle.exportKey('spki', keyPair.publicKey));
|
|
37
|
-
const certificationRequestInfo = derSequence(
|
|
38
|
-
derInteger(0),
|
|
39
|
-
derName(input),
|
|
40
|
-
publicKeySPKI,
|
|
41
|
-
derContext(0, new Uint8Array()),
|
|
42
|
-
);
|
|
43
|
-
const signature = new Uint8Array(
|
|
44
|
-
await crypto.subtle.sign('RSASSA-PKCS1-v1_5', keyPair.privateKey, toArrayBuffer(certificationRequestInfo)),
|
|
45
|
-
);
|
|
46
|
-
const csrDER = derSequence(
|
|
47
|
-
certificationRequestInfo,
|
|
48
|
-
derSequence(derOID('1.2.840.113549.1.1.11'), derNull()),
|
|
49
|
-
derBitString(signature),
|
|
50
|
-
);
|
|
51
|
-
const privateKeyPKCS8 = new Uint8Array(await crypto.subtle.exportKey('pkcs8', keyPair.privateKey));
|
|
52
|
-
return {
|
|
53
|
-
privateKey: keyPair.privateKey,
|
|
54
|
-
privateKeyPKCS8Base64: bytesToBase64(privateKeyPKCS8),
|
|
55
|
-
publicKeySPKIBase64: bytesToBase64(publicKeySPKI),
|
|
56
|
-
csrPEM: pemBlock('CERTIFICATE REQUEST', csrDER),
|
|
57
|
-
csrBase64: bytesToBase64(csrDER),
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function exportAppleCertificateP12(input: ExportP12Input) {
|
|
62
|
-
if (!input.certificateBase64 && !input.certificatePEM) {
|
|
63
|
-
throw new Error('certificateBase64 or certificatePEM is required.');
|
|
64
|
-
}
|
|
65
|
-
const privateKey = forge.pki.privateKeyFromPem(
|
|
66
|
-
pemFromBase64('PRIVATE KEY', input.privateKeyPKCS8Base64),
|
|
67
|
-
);
|
|
68
|
-
const certificate = input.certificatePEM
|
|
69
|
-
? forge.pki.certificateFromPem(input.certificatePEM)
|
|
70
|
-
: forge.pki.certificateFromAsn1(
|
|
71
|
-
forge.asn1.fromDer(forge.util.createBuffer(base64ToBinary(input.certificateBase64!))),
|
|
72
|
-
);
|
|
73
|
-
const p12 = forge.pkcs12.toPkcs12Asn1(privateKey, [certificate], input.password, {
|
|
74
|
-
algorithm: '3des',
|
|
75
|
-
friendlyName: input.friendlyName,
|
|
76
|
-
});
|
|
77
|
-
const der = forge.asn1.toDer(p12).getBytes();
|
|
78
|
-
return binaryToBase64(der);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function derName(input: AppleCSRInput) {
|
|
82
|
-
const attributes = [derAttribute('2.5.4.3', derUTF8String(input.commonName))];
|
|
83
|
-
if (input.emailAddress) {
|
|
84
|
-
attributes.push(derAttribute('1.2.840.113549.1.9.1', derIA5String(input.emailAddress)));
|
|
85
|
-
}
|
|
86
|
-
return derSequence(...attributes);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function derAttribute(oid: string, value: Uint8Array) {
|
|
90
|
-
return derSet(derSequence(derOID(oid), value));
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function derSequence(...values: Uint8Array[]) {
|
|
94
|
-
return derTLV(0x30, concatBytes(...values));
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function derSet(...values: Uint8Array[]) {
|
|
98
|
-
return derTLV(0x31, concatBytes(...values));
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function derContext(tag: number, value: Uint8Array) {
|
|
102
|
-
return derTLV(0xa0 + tag, value);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function derInteger(value: number) {
|
|
106
|
-
return derTLV(0x02, new Uint8Array([value]));
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function derNull() {
|
|
110
|
-
return new Uint8Array([0x05, 0x00]);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function derUTF8String(value: string) {
|
|
114
|
-
return derTLV(0x0c, new TextEncoder().encode(value));
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function derIA5String(value: string) {
|
|
118
|
-
return derTLV(0x16, new TextEncoder().encode(value));
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function derBitString(value: Uint8Array) {
|
|
122
|
-
return derTLV(0x03, concatBytes(new Uint8Array([0]), value));
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function derOID(oid: string) {
|
|
126
|
-
const parts = oid.split('.').map((part) => parseInt(part, 10));
|
|
127
|
-
if (parts.length < 2 || parts.some((part) => !Number.isFinite(part))) {
|
|
128
|
-
throw new Error(`Invalid OID: ${oid}`);
|
|
129
|
-
}
|
|
130
|
-
const encoded = [parts[0] * 40 + parts[1]];
|
|
131
|
-
for (const part of parts.slice(2)) {
|
|
132
|
-
const stack = [part & 0x7f];
|
|
133
|
-
let value = part >> 7;
|
|
134
|
-
while (value > 0) {
|
|
135
|
-
stack.unshift((value & 0x7f) | 0x80);
|
|
136
|
-
value >>= 7;
|
|
137
|
-
}
|
|
138
|
-
encoded.push(...stack);
|
|
139
|
-
}
|
|
140
|
-
return derTLV(0x06, new Uint8Array(encoded));
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function derTLV(tag: number, value: Uint8Array) {
|
|
144
|
-
return concatBytes(new Uint8Array([tag]), derLength(value.byteLength), value);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function derLength(length: number) {
|
|
148
|
-
if (length < 0x80) {
|
|
149
|
-
return new Uint8Array([length]);
|
|
150
|
-
}
|
|
151
|
-
const bytes: number[] = [];
|
|
152
|
-
let value = length;
|
|
153
|
-
while (value > 0) {
|
|
154
|
-
bytes.unshift(value & 0xff);
|
|
155
|
-
value >>= 8;
|
|
156
|
-
}
|
|
157
|
-
return new Uint8Array([0x80 | bytes.length, ...bytes]);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function concatBytes(...chunks: Uint8Array[]) {
|
|
161
|
-
const length = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);
|
|
162
|
-
const out = new Uint8Array(length);
|
|
163
|
-
let offset = 0;
|
|
164
|
-
for (const chunk of chunks) {
|
|
165
|
-
out.set(chunk, offset);
|
|
166
|
-
offset += chunk.byteLength;
|
|
167
|
-
}
|
|
168
|
-
return out;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function pemBlock(label: string, der: Uint8Array) {
|
|
172
|
-
const base64 = bytesToBase64(der);
|
|
173
|
-
const lines = base64.match(/.{1,64}/g) ?? [];
|
|
174
|
-
return `-----BEGIN ${label}-----\n${lines.join('\n')}\n-----END ${label}-----\n`;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function pemFromBase64(label: string, base64: string) {
|
|
178
|
-
const lines = base64.match(/.{1,64}/g) ?? [];
|
|
179
|
-
return `-----BEGIN ${label}-----\n${lines.join('\n')}\n-----END ${label}-----\n`;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function bytesToBase64(bytes: Uint8Array) {
|
|
183
|
-
let binary = '';
|
|
184
|
-
for (const byte of bytes) {
|
|
185
|
-
binary += String.fromCharCode(byte);
|
|
186
|
-
}
|
|
187
|
-
return btoa(binary);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function binaryToBase64(binary: string) {
|
|
191
|
-
return btoa(binary);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
function base64ToBinary(value: string) {
|
|
195
|
-
return atob(value);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function toArrayBuffer(bytes: Uint8Array): ArrayBuffer {
|
|
199
|
-
const copy = new Uint8Array(bytes.byteLength);
|
|
200
|
-
copy.set(bytes);
|
|
201
|
-
return copy.buffer;
|
|
202
|
-
}
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { Hash, Mode, Srp, util } from '@foxt/js-srp';
|
|
2
|
-
|
|
3
|
-
export type AppleSRPProtocol = 's2k' | 's2k_fo';
|
|
4
|
-
|
|
5
|
-
export type AppleSRPInitRequest = {
|
|
6
|
-
a: string;
|
|
7
|
-
accountName: string;
|
|
8
|
-
protocols: AppleSRPProtocol[];
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export type AppleSRPInitResponse = {
|
|
12
|
-
iteration: number;
|
|
13
|
-
salt: string;
|
|
14
|
-
protocol: AppleSRPProtocol;
|
|
15
|
-
b: string;
|
|
16
|
-
c: string;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export type AppleSRPCompleteProof = {
|
|
20
|
-
accountName: string;
|
|
21
|
-
m1: string;
|
|
22
|
-
m2: string;
|
|
23
|
-
c: string;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const srp = new Srp(Mode.GSA, Hash.SHA256, 2048);
|
|
27
|
-
|
|
28
|
-
export class AppleGsaSrpClient {
|
|
29
|
-
private srpClient?: Awaited<ReturnType<typeof srp.newClient>>;
|
|
30
|
-
|
|
31
|
-
constructor(private readonly accountName: string) {}
|
|
32
|
-
|
|
33
|
-
async init(): Promise<AppleSRPInitRequest> {
|
|
34
|
-
if (this.srpClient) {
|
|
35
|
-
throw new Error('SRP client is already initialized.');
|
|
36
|
-
}
|
|
37
|
-
this.srpClient = await srp.newClient(stringToBytes(this.accountName), new Uint8Array());
|
|
38
|
-
return {
|
|
39
|
-
accountName: this.accountName,
|
|
40
|
-
protocols: ['s2k', 's2k_fo'],
|
|
41
|
-
a: bytesToBase64(util.bytesFromBigint(this.srpClient.A)),
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async complete(password: string, serverData: AppleSRPInitResponse): Promise<AppleSRPCompleteProof> {
|
|
46
|
-
if (!this.srpClient) {
|
|
47
|
-
throw new Error('SRP client is not initialized.');
|
|
48
|
-
}
|
|
49
|
-
if (serverData.protocol !== 's2k' && serverData.protocol !== 's2k_fo') {
|
|
50
|
-
throw new Error(`Unsupported Apple SRP protocol ${serverData.protocol}.`);
|
|
51
|
-
}
|
|
52
|
-
const salt = base64ToBytes(serverData.salt);
|
|
53
|
-
const serverPublicKey = base64ToBytes(serverData.b);
|
|
54
|
-
const derivedPassword = await deriveApplePassword(
|
|
55
|
-
serverData.protocol,
|
|
56
|
-
password,
|
|
57
|
-
salt,
|
|
58
|
-
serverData.iteration,
|
|
59
|
-
);
|
|
60
|
-
this.srpClient.p = derivedPassword;
|
|
61
|
-
await this.srpClient.generate(salt, serverPublicKey);
|
|
62
|
-
const m2 = await this.srpClient.generateM2();
|
|
63
|
-
return {
|
|
64
|
-
accountName: this.accountName,
|
|
65
|
-
c: serverData.c,
|
|
66
|
-
m1: bytesToBase64(this.srpClient._M),
|
|
67
|
-
m2: bytesToBase64(m2),
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async function deriveApplePassword(
|
|
73
|
-
protocol: AppleSRPProtocol,
|
|
74
|
-
password: string,
|
|
75
|
-
salt: Uint8Array,
|
|
76
|
-
iterations: number,
|
|
77
|
-
) {
|
|
78
|
-
let passHash = new Uint8Array(await util.hash(srp.h, toArrayBuffer(stringToBytes(password))));
|
|
79
|
-
if (protocol === 's2k_fo') {
|
|
80
|
-
passHash = stringToBytes(util.toHex(passHash));
|
|
81
|
-
}
|
|
82
|
-
const imported = await crypto.subtle.importKey(
|
|
83
|
-
'raw',
|
|
84
|
-
toArrayBuffer(passHash),
|
|
85
|
-
{ name: 'PBKDF2' },
|
|
86
|
-
false,
|
|
87
|
-
['deriveBits'],
|
|
88
|
-
);
|
|
89
|
-
const derived = await crypto.subtle.deriveBits(
|
|
90
|
-
{
|
|
91
|
-
name: 'PBKDF2',
|
|
92
|
-
hash: { name: 'SHA-256' },
|
|
93
|
-
iterations,
|
|
94
|
-
salt: toArrayBuffer(salt),
|
|
95
|
-
},
|
|
96
|
-
imported,
|
|
97
|
-
256,
|
|
98
|
-
);
|
|
99
|
-
return new Uint8Array(derived);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function stringToBytes(value: string) {
|
|
103
|
-
return new TextEncoder().encode(value);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function bytesToBase64(bytes: Uint8Array) {
|
|
107
|
-
let binary = '';
|
|
108
|
-
for (const byte of bytes) {
|
|
109
|
-
binary += String.fromCharCode(byte);
|
|
110
|
-
}
|
|
111
|
-
return btoa(binary);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function base64ToBytes(value: string) {
|
|
115
|
-
const binary = atob(value);
|
|
116
|
-
const bytes = new Uint8Array(binary.length);
|
|
117
|
-
for (let index = 0; index < binary.length; index += 1) {
|
|
118
|
-
bytes[index] = binary.charCodeAt(index);
|
|
119
|
-
}
|
|
120
|
-
return bytes;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function toArrayBuffer(bytes: Uint8Array): ArrayBuffer {
|
|
124
|
-
const copy = new Uint8Array(bytes.byteLength);
|
|
125
|
-
copy.set(bytes);
|
|
126
|
-
return copy.buffer;
|
|
127
|
-
}
|
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
import type { ProvisioningProfileInfo, StoredSigningAssets } from '../types';
|
|
2
|
-
import {
|
|
3
|
-
getSigningAssets,
|
|
4
|
-
normalizeBundleID,
|
|
5
|
-
normalizeUDID,
|
|
6
|
-
profileContainsDevice,
|
|
7
|
-
profileMatchesBundleID,
|
|
8
|
-
putSigningAssets,
|
|
9
|
-
} from '../storage';
|
|
10
|
-
import type { AppleProvisioningRequest } from './relay';
|
|
11
|
-
|
|
12
|
-
export type AppleDeveloperPortalTeam = {
|
|
13
|
-
name?: string;
|
|
14
|
-
teamId?: string;
|
|
15
|
-
providerId?: string | number;
|
|
16
|
-
publicProviderId?: string;
|
|
17
|
-
type?: string;
|
|
18
|
-
subType?: string;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export type AppleDeveloperPortalDevice = {
|
|
22
|
-
deviceId?: string;
|
|
23
|
-
name?: string;
|
|
24
|
-
deviceNumber?: string;
|
|
25
|
-
deviceClass?: string;
|
|
26
|
-
model?: string;
|
|
27
|
-
status?: string;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export type AppleDeveloperPortalAppID = {
|
|
31
|
-
appId?: string;
|
|
32
|
-
appIdId?: string;
|
|
33
|
-
identifier?: string;
|
|
34
|
-
bundleId?: string;
|
|
35
|
-
name?: string;
|
|
36
|
-
prefix?: string;
|
|
37
|
-
platform?: string;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export type AppleDeveloperPortalResponse = {
|
|
41
|
-
resultCode?: number;
|
|
42
|
-
resultString?: string;
|
|
43
|
-
userString?: string;
|
|
44
|
-
teams?: AppleDeveloperPortalTeam[];
|
|
45
|
-
provider?: AppleDeveloperPortalTeam;
|
|
46
|
-
availableProviders?: AppleDeveloperPortalTeam[];
|
|
47
|
-
appIds?: AppleDeveloperPortalAppID[];
|
|
48
|
-
devices?: AppleDeveloperPortalDevice[];
|
|
49
|
-
certRequests?: Array<Record<string, unknown>>;
|
|
50
|
-
certRequest?: Record<string, unknown>;
|
|
51
|
-
appId?: Record<string, unknown>;
|
|
52
|
-
device?: Record<string, unknown>;
|
|
53
|
-
provisioningProfile?: Record<string, unknown>;
|
|
54
|
-
provisioningProfiles?: Array<Record<string, unknown>>;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export type AppleProvisioningContext = {
|
|
58
|
-
bundleID: string;
|
|
59
|
-
deviceUDID: string;
|
|
60
|
-
teamID?: string;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export type AppleSigningAssetCacheInput = {
|
|
64
|
-
bundleID: string;
|
|
65
|
-
deviceUDID?: string;
|
|
66
|
-
teamID?: string;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
export type PutAppleGeneratedSigningAssetsInput = {
|
|
70
|
-
bundleID: string;
|
|
71
|
-
deviceUDID?: string;
|
|
72
|
-
teamID?: string;
|
|
73
|
-
certificateID?: string;
|
|
74
|
-
certificateP12Base64: string;
|
|
75
|
-
certificatePassword: string;
|
|
76
|
-
provisioningProfileBase64: string;
|
|
77
|
-
profile: ProvisioningProfileInfo;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
export function listTeamsRequest(): AppleProvisioningRequest {
|
|
81
|
-
return {
|
|
82
|
-
method: 'POST',
|
|
83
|
-
path: '/account/listTeams.action',
|
|
84
|
-
payload: {},
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function findBundleIDRequest({ bundleID, teamID = '' }: Pick<AppleProvisioningContext, 'bundleID' | 'teamID'>) {
|
|
89
|
-
void bundleID;
|
|
90
|
-
return pagedRequest('/account/ios/identifiers/listAppIds.action', teamID, { sort: 'name=asc' });
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function findDeviceRequest({ deviceUDID, teamID = '' }: Pick<AppleProvisioningContext, 'deviceUDID' | 'teamID'>) {
|
|
94
|
-
void deviceUDID;
|
|
95
|
-
return pagedRequest('/account/ios/device/listDevices.action', teamID, {
|
|
96
|
-
sort: 'name=asc',
|
|
97
|
-
includeRemovedDevices: false,
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export function findDevelopmentCertificatesRequest(teamID = '') {
|
|
102
|
-
return pagedRequest('/account/ios/certificate/listCertRequests.action', teamID, {
|
|
103
|
-
sort: 'name=asc',
|
|
104
|
-
types: '83Q87W3TGH,5QPB9NHCEI',
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export function findDevelopmentProfilesRequest({
|
|
109
|
-
bundleID,
|
|
110
|
-
teamID = '',
|
|
111
|
-
}: Pick<AppleProvisioningContext, 'bundleID' | 'teamID'>) {
|
|
112
|
-
return pagedRequest('/account/ios/profile/listProvisioningProfiles.action', teamID, {
|
|
113
|
-
search: bundleID,
|
|
114
|
-
sort: 'name=asc',
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export function registerDeviceRequest({
|
|
119
|
-
deviceUDID,
|
|
120
|
-
teamID = '',
|
|
121
|
-
name = 'Limrun iPhone',
|
|
122
|
-
}: Pick<AppleProvisioningContext, 'deviceUDID' | 'teamID'> & { name?: string }) {
|
|
123
|
-
return {
|
|
124
|
-
method: 'POST',
|
|
125
|
-
path: '/account/ios/device/addDevices.action',
|
|
126
|
-
payload: {
|
|
127
|
-
teamId: teamID,
|
|
128
|
-
deviceNames: name,
|
|
129
|
-
deviceNumbers: normalizeUDID(deviceUDID),
|
|
130
|
-
deviceClasses: 'iphone',
|
|
131
|
-
register: 'single',
|
|
132
|
-
},
|
|
133
|
-
} satisfies AppleProvisioningRequest;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export function createBundleIDRequest({
|
|
137
|
-
bundleID,
|
|
138
|
-
teamID = '',
|
|
139
|
-
name,
|
|
140
|
-
}: Pick<AppleProvisioningContext, 'bundleID' | 'teamID'> & { name?: string }) {
|
|
141
|
-
return {
|
|
142
|
-
method: 'POST',
|
|
143
|
-
path: '/account/ios/identifiers/addAppId.action',
|
|
144
|
-
payload: {
|
|
145
|
-
teamId: teamID,
|
|
146
|
-
name: name ?? bundleID,
|
|
147
|
-
identifier: bundleID,
|
|
148
|
-
type: 'explicit',
|
|
149
|
-
},
|
|
150
|
-
} satisfies AppleProvisioningRequest;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export function submitDevelopmentCSRRequest({
|
|
154
|
-
csrPEM,
|
|
155
|
-
teamID = '',
|
|
156
|
-
}: {
|
|
157
|
-
csrPEM: string;
|
|
158
|
-
teamID?: string;
|
|
159
|
-
}) {
|
|
160
|
-
return {
|
|
161
|
-
method: 'POST',
|
|
162
|
-
path: '/account/ios/certificate/submitCertificateRequest.action',
|
|
163
|
-
payload: {
|
|
164
|
-
teamId: teamID,
|
|
165
|
-
type: '83Q87W3TGH',
|
|
166
|
-
csrContent: csrPEM,
|
|
167
|
-
},
|
|
168
|
-
} satisfies AppleProvisioningRequest;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export function downloadCertificateRequest(certificateID: string, teamID = '') {
|
|
172
|
-
return {
|
|
173
|
-
method: 'GET',
|
|
174
|
-
path: '/account/ios/certificate/downloadCertificateContent.action',
|
|
175
|
-
payload: {
|
|
176
|
-
teamId: teamID,
|
|
177
|
-
certificateId: certificateID,
|
|
178
|
-
type: '83Q87W3TGH',
|
|
179
|
-
},
|
|
180
|
-
} satisfies AppleProvisioningRequest;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
export function createDevelopmentProfileRequest({
|
|
184
|
-
bundleID,
|
|
185
|
-
teamID = '',
|
|
186
|
-
appIDID,
|
|
187
|
-
certificateID,
|
|
188
|
-
deviceIDs,
|
|
189
|
-
name,
|
|
190
|
-
}: Pick<AppleProvisioningContext, 'bundleID' | 'teamID'> & {
|
|
191
|
-
appIDID: string;
|
|
192
|
-
certificateID: string;
|
|
193
|
-
deviceIDs: string[];
|
|
194
|
-
name?: string;
|
|
195
|
-
}) {
|
|
196
|
-
return {
|
|
197
|
-
method: 'POST',
|
|
198
|
-
path: '/account/ios/profile/createProvisioningProfile.action',
|
|
199
|
-
payload: {
|
|
200
|
-
teamId: teamID,
|
|
201
|
-
provisioningProfileName: name ?? `Limrun ${bundleID}`,
|
|
202
|
-
certificateIds: [certificateID],
|
|
203
|
-
appIdId: appIDID,
|
|
204
|
-
deviceIds: deviceIDs,
|
|
205
|
-
distributionType: 'limited',
|
|
206
|
-
subPlatform: 'ios',
|
|
207
|
-
},
|
|
208
|
-
} satisfies AppleProvisioningRequest;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
export function downloadProfileRequest(profileID: string, teamID = '') {
|
|
212
|
-
return {
|
|
213
|
-
method: 'GET',
|
|
214
|
-
path: '/account/ios/profile/downloadProfileContent',
|
|
215
|
-
payload: {
|
|
216
|
-
teamId: teamID,
|
|
217
|
-
provisioningProfileId: profileID,
|
|
218
|
-
},
|
|
219
|
-
} satisfies AppleProvisioningRequest;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
export async function getReusableAppleSigningAssets({
|
|
223
|
-
bundleID,
|
|
224
|
-
deviceUDID,
|
|
225
|
-
teamID,
|
|
226
|
-
}: AppleSigningAssetCacheInput) {
|
|
227
|
-
const stored = await getSigningAssets({ bundleID, deviceUDID });
|
|
228
|
-
if (!stored || !storedSigningAssetsReusable(stored, { bundleID, deviceUDID, teamID })) {
|
|
229
|
-
return undefined;
|
|
230
|
-
}
|
|
231
|
-
return stored;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
export async function putAppleGeneratedSigningAssets(input: PutAppleGeneratedSigningAssetsInput) {
|
|
235
|
-
return putSigningAssets({
|
|
236
|
-
...input,
|
|
237
|
-
certificateFileName: input.certificateID ? `${input.certificateID}.p12` : 'apple-development.p12',
|
|
238
|
-
profileFileName: input.profile.uuid ? `${input.profile.uuid}.mobileprovision` : 'apple-development.mobileprovision',
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
export function storedSigningAssetsReusable(
|
|
243
|
-
stored: StoredSigningAssets,
|
|
244
|
-
{ bundleID, deviceUDID, teamID }: AppleSigningAssetCacheInput,
|
|
245
|
-
) {
|
|
246
|
-
if (!profileMatchesBundleID(stored.profile, bundleID)) {
|
|
247
|
-
return false;
|
|
248
|
-
}
|
|
249
|
-
if (teamID && stored.teamID && stored.teamID !== teamID) {
|
|
250
|
-
return false;
|
|
251
|
-
}
|
|
252
|
-
if (deviceUDID && !profileContainsDevice(stored.profile, deviceUDID)) {
|
|
253
|
-
return false;
|
|
254
|
-
}
|
|
255
|
-
if (stored.profile.expirationDate && new Date(stored.profile.expirationDate).getTime() <= Date.now()) {
|
|
256
|
-
return false;
|
|
257
|
-
}
|
|
258
|
-
return normalizeBundleID(stored.bundleID) === normalizeBundleID(bundleID);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
export function selectDeveloperPortalTeam(body: unknown): AppleDeveloperPortalTeam | undefined {
|
|
262
|
-
const response = body as AppleDeveloperPortalResponse | undefined;
|
|
263
|
-
return response?.teams?.[0] ?? response?.provider ?? response?.availableProviders?.[0];
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
export function teamIDCandidates(body: unknown): string[] {
|
|
267
|
-
const response = body as AppleDeveloperPortalResponse | undefined;
|
|
268
|
-
const teams = [
|
|
269
|
-
...(response?.teams ?? []),
|
|
270
|
-
...(response?.provider ? [response.provider] : []),
|
|
271
|
-
...(response?.availableProviders ?? []),
|
|
272
|
-
];
|
|
273
|
-
const ids = new Set<string>();
|
|
274
|
-
for (const team of teams) {
|
|
275
|
-
for (const value of [team.teamId, team.providerId, team.publicProviderId]) {
|
|
276
|
-
if (value !== undefined && value !== '') {
|
|
277
|
-
ids.add(String(value));
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
return [...ids];
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
function pagedRequest(path: string, teamID: string, payload: Record<string, unknown> = {}) {
|
|
285
|
-
const basePayload: Record<string, unknown> = {
|
|
286
|
-
pageNumber: 1,
|
|
287
|
-
pageSize: 200,
|
|
288
|
-
...payload,
|
|
289
|
-
};
|
|
290
|
-
if (teamID) {
|
|
291
|
-
basePayload.teamId = teamID;
|
|
292
|
-
}
|
|
293
|
-
return {
|
|
294
|
-
method: 'POST',
|
|
295
|
-
path,
|
|
296
|
-
payload: basePayload,
|
|
297
|
-
} satisfies AppleProvisioningRequest;
|
|
298
|
-
}
|