@mdbase-dev/sdk 0.1.0-beta.169 → 0.1.0-beta.175
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 +91 -3
- package/dist/app-host/account-key-host.d.ts +128 -0
- package/dist/app-host/account-key-host.js +449 -0
- package/dist/app-host/account-key-host.js.map +1 -0
- package/dist/app-host/app-environment.d.ts +3 -4
- package/dist/app-host/app-environment.js +6 -6
- package/dist/app-host/app-environment.js.map +1 -1
- package/dist/app-host/app-origin.d.ts +5 -2
- package/dist/app-host/app-origin.js +10 -6
- package/dist/app-host/app-origin.js.map +1 -1
- package/dist/app-host/cloud-copy-bootstrap.js +2 -2
- package/dist/app-host/cloud-copy-bootstrap.js.map +1 -1
- package/dist/app-host/cloud-copy-host.d.ts +69 -5
- package/dist/app-host/cloud-copy-host.js +289 -20
- package/dist/app-host/cloud-copy-host.js.map +1 -1
- package/dist/app-host/cloud-copy-persistence-idb.d.ts +0 -2
- package/dist/app-host/cloud-copy-persistence-idb.js +2 -2
- package/dist/app-host/cloud-copy-persistence-idb.js.map +1 -1
- package/dist/app-host/cp-authority.js +2 -2
- package/dist/app-host/cp-authority.js.map +1 -1
- package/dist/app-host/cp-people.js +2 -2
- package/dist/app-host/cp-people.js.map +1 -1
- package/dist/app-host/cp-problem.d.ts +1 -1
- package/dist/app-host/cp-problem.js +4 -0
- package/dist/app-host/cp-problem.js.map +1 -1
- package/dist/app-host/device-key-idb.d.ts +0 -2
- package/dist/app-host/device-key-idb.js +1 -1
- package/dist/app-host/device-key-idb.js.map +1 -1
- package/dist/app-host/device-key-provider.d.ts +0 -3
- package/dist/app-host/device-key-provider.js +1 -1
- package/dist/app-host/device-key-provider.js.map +1 -1
- package/dist/app-host/device-registration.js +2 -2
- package/dist/app-host/device-registration.js.map +1 -1
- package/dist/app-host/http-log.d.ts +2 -6
- package/dist/app-host/http-log.js +12 -45
- package/dist/app-host/http-log.js.map +1 -1
- package/dist/app-host/index.d.ts +4 -2
- package/dist/app-host/index.js +2 -1
- package/dist/app-host/index.js.map +1 -1
- package/dist/app-host/installation-sign-in.d.ts +19 -1
- package/dist/app-host/installation-sign-in.js +149 -30
- package/dist/app-host/installation-sign-in.js.map +1 -1
- package/dist/app-host/installation-store.d.ts +0 -2
- package/dist/app-host/installation-store.js +4 -4
- package/dist/app-host/installation-store.js.map +1 -1
- package/dist/app-host/log-push.js +2 -2
- package/dist/app-host/log-push.js.map +1 -1
- package/dist/app-host/noise-idb.d.ts +0 -3
- package/dist/app-host/noise-idb.js +1 -1
- package/dist/app-host/noise-idb.js.map +1 -1
- package/dist/app-host/private-bootstrap.js +2 -2
- package/dist/app-host/private-bootstrap.js.map +1 -1
- package/dist/app-host/private-persistence-idb.d.ts +0 -2
- package/dist/app-host/private-persistence-idb.js +1 -1
- package/dist/app-host/private-persistence-idb.js.map +1 -1
- package/dist/app-host/private-persistence.js +2 -2
- package/dist/app-host/private-persistence.js.map +1 -1
- package/dist/app-host/scoped-sign-in-session.d.ts +4 -0
- package/dist/app-host/scoped-sign-in-session.js +13 -1
- package/dist/app-host/scoped-sign-in-session.js.map +1 -1
- package/dist/app-host/spare-nonces.d.ts +27 -0
- package/dist/app-host/spare-nonces.js +58 -0
- package/dist/app-host/spare-nonces.js.map +1 -0
- package/dist/app-host/unsynced-collection.js +8 -3
- package/dist/app-host/unsynced-collection.js.map +1 -1
- package/dist/app-host/wasm-runtime.d.ts +14 -0
- package/dist/app-host/wasm-runtime.js +45 -0
- package/dist/app-host/wasm-runtime.js.map +1 -1
- package/dist/app-host/web-collection.d.ts +4 -1
- package/dist/app-host/web-collection.js +214 -125
- package/dist/app-host/web-collection.js.map +1 -1
- package/dist/app-host/web-sign-in-problem.js +6 -1
- package/dist/app-host/web-sign-in-problem.js.map +1 -1
- package/dist/app-host/web-sign-in-session.d.ts +46 -4
- package/dist/app-host/web-sign-in-session.js +88 -15
- package/dist/app-host/web-sign-in-session.js.map +1 -1
- package/dist/application/asset-loader.d.ts +0 -1
- package/dist/application/asset-loader.js +2 -2
- package/dist/application/asset-loader.js.map +1 -1
- package/dist/application/asset-pins.json +4 -4
- package/dist/application/browser-selection.js +1 -1
- package/dist/application/browser-selection.js.map +1 -1
- package/dist/application/collection-selection.d.ts +10 -0
- package/dist/application/collection-selection.js +58 -11
- package/dist/application/collection-selection.js.map +1 -1
- package/dist/application/declaration.js +2 -2
- package/dist/application/declaration.js.map +1 -1
- package/dist/application/entry.d.ts +19 -0
- package/dist/application/entry.js +81 -38
- package/dist/application/entry.js.map +1 -1
- package/dist/application/front-door.d.ts +6 -1
- package/dist/application/front-door.js +5 -0
- package/dist/application/front-door.js.map +1 -1
- package/dist/application/local-build.d.ts +4 -2
- package/dist/application/local-build.js +4 -2
- package/dist/application/local-build.js.map +1 -1
- package/dist/application/manifest.d.ts +1 -0
- package/dist/application/manifest.js +8 -3
- package/dist/application/manifest.js.map +1 -1
- package/dist/application/native-assets.js +3 -4
- package/dist/application/native-assets.js.map +1 -1
- package/dist/application/packaged-assets.d.ts +1 -1
- package/dist/application/packaged-assets.js +6 -3
- package/dist/application/packaged-assets.js.map +1 -1
- package/dist/application/phase.d.ts +21 -1
- package/dist/application/phase.js +12 -1
- package/dist/application/phase.js.map +1 -1
- package/dist/application/portal-reservation.js +2 -2
- package/dist/application/portal-reservation.js.map +1 -1
- package/dist/application/registration.d.ts +3 -0
- package/dist/application/registration.js +7 -4
- package/dist/application/registration.js.map +1 -1
- package/dist/application/return-url.d.ts +1 -1
- package/dist/application/return-url.js +6 -7
- package/dist/application/return-url.js.map +1 -1
- package/dist/application/runtime.d.ts +7 -1
- package/dist/application/runtime.js +53 -4
- package/dist/application/runtime.js.map +1 -1
- package/dist/application/startup-timing.d.ts +20 -0
- package/dist/application/startup-timing.js +58 -0
- package/dist/application/startup-timing.js.map +1 -0
- package/dist/application/ui-connections.js +17 -4
- package/dist/application/ui-connections.js.map +1 -1
- package/dist/application/worker-client.d.ts +3 -0
- package/dist/application/worker-client.js +27 -2
- package/dist/application/worker-client.js.map +1 -1
- package/dist/application/worker-host.js +51 -3
- package/dist/application/worker-host.js.map +1 -1
- package/dist/application/worker-protocol.d.ts +7 -2
- package/dist/application/worker-protocol.js +10 -1
- package/dist/application/worker-protocol.js.map +1 -1
- package/dist/application/worker-session.d.ts +1 -1
- package/dist/application/worker-session.js +5 -1
- package/dist/application/worker-session.js.map +1 -1
- package/dist/application/worker.js +8969 -2561
- package/dist/application/worker.js.map +1 -1
- package/dist/browser/mdbase-sdk.js +8174 -3680
- package/dist/browser/mdbase-sdk.min.js +78 -78
- package/dist/describe-error.d.ts +2 -2
- package/dist/describe-error.js +11 -2
- package/dist/describe-error.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/local-build.d.ts +7 -4
- package/dist/local-build.js +7 -4
- package/dist/local-build.js.map +1 -1
- package/dist/native/provenance.json +5 -5
- package/dist/native/runtime.wasm +0 -0
- package/dist/private-account.js +13 -18
- package/dist/private-account.js.map +1 -1
- package/dist/testing/application.d.ts +3 -1
- package/dist/testing/application.js +8 -1
- package/dist/testing/application.js.map +1 -1
- package/dist/testing/test-app.d.ts +9 -0
- package/dist/testing/test-app.js +13 -0
- package/dist/testing/test-app.js.map +1 -1
- package/dist/transport/control-route.d.ts +2 -1
- package/dist/transport/control-route.js +4 -1
- package/dist/transport/control-route.js.map +1 -1
- package/dist/transport/relay.d.ts +7 -0
- package/dist/transport/relay.js +3 -1
- package/dist/transport/relay.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
/** Account-key (AK1) unlock of ONE adopted Private collection on a first-party
|
|
2
|
+
* installation device. Runs in the owned Worker. Reaches only the fixed status,
|
|
3
|
+
* challenge and fetch routes over the installation bearer; the fetch proof is
|
|
4
|
+
* signed by the native device. Setup, password change, strict mode and
|
|
5
|
+
* recovery-device enrolment are refused here, not routed.
|
|
6
|
+
* `R` and the password are never stored and never returned: `R` lives in a
|
|
7
|
+
* RAM-only store for this one call and is wiped when it settles. The sealed
|
|
8
|
+
* bundle is never persisted or returned either; the owner of a locked
|
|
9
|
+
* collection may keep that ciphertext in RAM between attempts
|
|
10
|
+
* ({@link AppAccountKeySealedBundle}), so a mistyped secret does not spend the
|
|
11
|
+
* account's fetch budget again. */
|
|
12
|
+
import { loopbackHttpOrigin } from "../application/local-build.js";
|
|
13
|
+
import { AccountKeyError, checkPassword, parseRecoveryKey, wipe } from "../account-key.js";
|
|
14
|
+
import { uuidToBytes } from "../codec.js";
|
|
15
|
+
import { PrivateAccount, mapPortError, memorySecretStore, } from "../private-account.js";
|
|
16
|
+
import { appServerBody, appServerProblem } from "./cp-problem.js";
|
|
17
|
+
import { waitForOpenRetry } from "./open-wait.js";
|
|
18
|
+
import { AppAccountKeyProofUnavailableError, AppStrictDeviceApprovalError } from "./wasm-runtime.js";
|
|
19
|
+
export class AppAccountKeyUnlockError extends Error {
|
|
20
|
+
reason;
|
|
21
|
+
detail;
|
|
22
|
+
retryAfterMs;
|
|
23
|
+
constructor(reason, detail, retryAfterMs) {
|
|
24
|
+
super(`app account key unlock: ${reason}`);
|
|
25
|
+
this.reason = reason;
|
|
26
|
+
this.detail = detail;
|
|
27
|
+
this.retryAfterMs = retryAfterMs;
|
|
28
|
+
this.name = "AppAccountKeyUnlockError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** The sealed account-key bundle that ONE locked Private collection keeps
|
|
32
|
+
* between unlock attempts, so a mistyped password or a recovery key of another
|
|
33
|
+
* account key does not spend the account-wide fetch budget (10 per hour, shared
|
|
34
|
+
* with the person's other devices) again. It is the ciphertext Connect already
|
|
35
|
+
* gave this device, held in RAM only: never persisted, published or returned
|
|
36
|
+
* to the app. A held answer is used only while the budget-free status route,
|
|
37
|
+
* which applies the same account and installation scope checks on every
|
|
38
|
+
* attempt, still reports the same account-key version and key id for the same
|
|
39
|
+
* account, connector and device. Anything else drops it and fetches afresh.
|
|
40
|
+
* `unlockPrivateDevice` drops it on every outcome but a wrong secret; the
|
|
41
|
+
* owner clears it when the collection closes (which is also sign-out). */
|
|
42
|
+
export class AppAccountKeySealedBundle {
|
|
43
|
+
held = null;
|
|
44
|
+
/** True while a sealed bundle is held. */
|
|
45
|
+
get holding() { return this.held !== null; }
|
|
46
|
+
/** The held fetch answer for exactly this account-key state, else nothing
|
|
47
|
+
* (and whatever was held is dropped). An unknown version or key id never matches.
|
|
48
|
+
* @internal */
|
|
49
|
+
take(session, version, keyId) {
|
|
50
|
+
const h = this.held;
|
|
51
|
+
if (h && version !== null && keyId !== null && h.accountId === session.accountId && h.connectorId === session.connectorId && h.deviceId === session.deviceId
|
|
52
|
+
&& h.version === version && h.keyId === keyId)
|
|
53
|
+
return { mode: "password", version: h.version, key_id: h.keyId, bundle: h.bundle };
|
|
54
|
+
this.held = null;
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
/** Replaces what is held with this fetch answer when it is a well-formed
|
|
58
|
+
* password bundle, and with nothing otherwise.
|
|
59
|
+
* @internal */
|
|
60
|
+
keep(session, answer) {
|
|
61
|
+
this.held = null;
|
|
62
|
+
const r = answer && typeof answer === "object" && !Array.isArray(answer) ? answer : {};
|
|
63
|
+
if (r.mode !== "password" || !Number.isSafeInteger(r.version) || r.version < 1 || typeof r.key_id !== "string" || !HEX32.test(r.key_id)
|
|
64
|
+
|| typeof r.bundle !== "string" || !/^([0-9a-f]{2}){1,512}$/.test(r.bundle))
|
|
65
|
+
return;
|
|
66
|
+
this.held = Object.freeze({ accountId: session.accountId, connectorId: session.connectorId, deviceId: session.deviceId, version: r.version, keyId: r.key_id, bundle: r.bundle });
|
|
67
|
+
}
|
|
68
|
+
clear() { this.held = null; }
|
|
69
|
+
}
|
|
70
|
+
const MAX_BODY = 64 * 1024, REQUEST_MS = 15_000, SETTLE_MS = 45_000;
|
|
71
|
+
const unavailable = (reason) => new AccountKeyError("unavailable", "The account key service refused or was unreachable.", { reason });
|
|
72
|
+
const cancelled = () => new AccountKeyError("cancelled", "Account key request cancelled.");
|
|
73
|
+
const unsupported = () => unavailable("not_supported");
|
|
74
|
+
const hex = (b) => Array.from(b, v => v.toString(16).padStart(2, "0")).join("");
|
|
75
|
+
const HEX32 = /^[0-9a-f]{64}$/;
|
|
76
|
+
/** `AccountKeyControlPort` over the installation bearer: status, challenge and
|
|
77
|
+
* fetch only. One fixed request each, no retry, bounded decoded bodies. */
|
|
78
|
+
export class AppCpAccountKeyControl {
|
|
79
|
+
session;
|
|
80
|
+
sign;
|
|
81
|
+
accountId;
|
|
82
|
+
lifetime = new AbortController();
|
|
83
|
+
origin;
|
|
84
|
+
deviceId;
|
|
85
|
+
fetchImpl;
|
|
86
|
+
now;
|
|
87
|
+
constructor(session, sign, options = {}) {
|
|
88
|
+
this.session = session;
|
|
89
|
+
this.sign = sign;
|
|
90
|
+
for (const id of [session.accountId, session.connectorId, session.deviceId, session.collection])
|
|
91
|
+
if (uuidToBytes(id).every(v => v === 0))
|
|
92
|
+
throw unavailable("binding");
|
|
93
|
+
const u = new URL(session.cpOrigin);
|
|
94
|
+
if (u.origin !== session.cpOrigin || u.username || u.password || (u.protocol !== "https:" && !(options.allowLoopbackHttp === true && loopbackHttpOrigin(session.cpOrigin))))
|
|
95
|
+
throw unavailable("binding");
|
|
96
|
+
this.accountId = session.accountId;
|
|
97
|
+
this.deviceId = session.deviceId;
|
|
98
|
+
this.origin = u.origin;
|
|
99
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
100
|
+
this.now = options.now ?? Date.now;
|
|
101
|
+
if (session.isCurrent() !== true)
|
|
102
|
+
throw unavailable("fenced");
|
|
103
|
+
}
|
|
104
|
+
check(signal) {
|
|
105
|
+
if (signal.aborted || this.lifetime.signal.aborted)
|
|
106
|
+
throw cancelled();
|
|
107
|
+
let current = false;
|
|
108
|
+
try {
|
|
109
|
+
current = this.session.isCurrent() === true && this.session.accountId === this.accountId && this.session.deviceId === this.deviceId && this.session.cpOrigin === this.origin;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
current = false;
|
|
113
|
+
}
|
|
114
|
+
if (!current)
|
|
115
|
+
throw unavailable("fenced");
|
|
116
|
+
}
|
|
117
|
+
async request(method, path, headers, options) {
|
|
118
|
+
const parent = options.signal ?? this.lifetime.signal;
|
|
119
|
+
this.check(parent);
|
|
120
|
+
const bearer = await this.session.connectorBearer({ signal: parent });
|
|
121
|
+
this.check(parent);
|
|
122
|
+
if (typeof bearer !== "string" || !bearer || bearer.length > 16384 || /[^\x21-\x7e]/.test(bearer))
|
|
123
|
+
throw unavailable("binding");
|
|
124
|
+
const ctrl = new AbortController(), abort = () => ctrl.abort(), timer = setTimeout(abort, REQUEST_MS);
|
|
125
|
+
timer.unref?.();
|
|
126
|
+
parent.addEventListener("abort", abort, { once: true });
|
|
127
|
+
this.lifetime.signal.addEventListener("abort", abort, { once: true });
|
|
128
|
+
const buffer = new Uint8Array(MAX_BODY);
|
|
129
|
+
let count = 0, response = null, reader = null;
|
|
130
|
+
try {
|
|
131
|
+
const request = this.fetchImpl;
|
|
132
|
+
try {
|
|
133
|
+
response = await request(`${this.origin}${path}`, { method, headers: { authorization: `Bearer ${bearer}`, ...headers }, signal: ctrl.signal, redirect: "error", credentials: "omit", cache: "no-store", referrerPolicy: "no-referrer" });
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
this.check(parent);
|
|
137
|
+
throw unavailable("network");
|
|
138
|
+
}
|
|
139
|
+
this.check(parent);
|
|
140
|
+
if (ctrl.signal.aborted)
|
|
141
|
+
throw unavailable("timeout");
|
|
142
|
+
if (response.body) {
|
|
143
|
+
reader = response.body.getReader();
|
|
144
|
+
for (;;) {
|
|
145
|
+
let part;
|
|
146
|
+
try {
|
|
147
|
+
part = await reader.read();
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
this.check(parent);
|
|
151
|
+
throw unavailable("network");
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
this.check(parent);
|
|
155
|
+
if (ctrl.signal.aborted)
|
|
156
|
+
throw unavailable("timeout");
|
|
157
|
+
if (part.done)
|
|
158
|
+
break;
|
|
159
|
+
if (count + part.value.length > buffer.length) {
|
|
160
|
+
ctrl.abort();
|
|
161
|
+
throw unavailable("response");
|
|
162
|
+
}
|
|
163
|
+
buffer.set(part.value, count);
|
|
164
|
+
count += part.value.length;
|
|
165
|
+
}
|
|
166
|
+
finally {
|
|
167
|
+
part.value?.fill(0);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const body = appServerBody(buffer.subarray(0, count));
|
|
172
|
+
// The typed refusal object (status, code, retry delay) is read by PrivateAccount.
|
|
173
|
+
if (!response.ok)
|
|
174
|
+
throw appServerProblem(response.status, body, response.headers);
|
|
175
|
+
if (!body || typeof body !== "object" || Array.isArray(body))
|
|
176
|
+
throw unavailable("response");
|
|
177
|
+
return body;
|
|
178
|
+
}
|
|
179
|
+
finally {
|
|
180
|
+
buffer.fill(0);
|
|
181
|
+
void (reader?.cancel() ?? response?.body?.cancel())?.catch(() => { });
|
|
182
|
+
try {
|
|
183
|
+
reader?.releaseLock();
|
|
184
|
+
}
|
|
185
|
+
catch { /* cancelled */ }
|
|
186
|
+
clearTimeout(timer);
|
|
187
|
+
parent.removeEventListener("abort", abort);
|
|
188
|
+
this.lifetime.signal.removeEventListener("abort", abort);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
status(options) { return this.request("GET", "/v1/next/account-key/status", {}, options); }
|
|
192
|
+
challenge(options) { return this.request("POST", "/v1/next/devices/challenge", {}, options); }
|
|
193
|
+
/** A fresh single-use challenge, the native fetch proof over it, then the
|
|
194
|
+
* bundle. The challenge and signature are wiped here; the bundle is returned
|
|
195
|
+
* to PrivateAccount only. */
|
|
196
|
+
async fetch(options) {
|
|
197
|
+
let nonce = null, signature = null;
|
|
198
|
+
try {
|
|
199
|
+
const issued = await this.request("POST", "/v1/next/devices/challenge", {}, options);
|
|
200
|
+
const text = issued.challenge, expires = issued.expires_at;
|
|
201
|
+
if (typeof text !== "string" || !/^[0-9a-f]{64}$/.test(text) || typeof expires !== "number" || !Number.isSafeInteger(expires) || expires - this.now() <= 5_000 || expires - this.now() > 16 * 60_000)
|
|
202
|
+
throw unavailable("response");
|
|
203
|
+
nonce = Uint8Array.from(text.match(/../g).map(v => parseInt(v, 16)));
|
|
204
|
+
try {
|
|
205
|
+
signature = this.sign(nonce);
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
if (error instanceof AppAccountKeyProofUnavailableError)
|
|
209
|
+
throw unavailable(error.reason);
|
|
210
|
+
if (error instanceof AppStrictDeviceApprovalError)
|
|
211
|
+
throw new AccountKeyError("strict_mode", "The account is in strict mode.");
|
|
212
|
+
throw unavailable("proof");
|
|
213
|
+
}
|
|
214
|
+
if (!(signature instanceof Uint8Array) || signature.length !== 64)
|
|
215
|
+
throw unavailable("proof");
|
|
216
|
+
return await this.request("GET", "/v1/next/account-key", { "x-mdbase-device-id": this.deviceId, "x-mdbase-challenge": text, "x-mdbase-signature": hex(signature) }, options);
|
|
217
|
+
}
|
|
218
|
+
finally {
|
|
219
|
+
nonce?.fill(0);
|
|
220
|
+
signature?.fill(0);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
put() { return Promise.reject(unsupported()); }
|
|
224
|
+
strict() { return Promise.reject(unsupported()); }
|
|
225
|
+
enrolRecoveryDevice() { return Promise.reject(unsupported()); }
|
|
226
|
+
close() { this.lifetime.abort(); }
|
|
227
|
+
}
|
|
228
|
+
function problem(error) {
|
|
229
|
+
if (error instanceof AppAccountKeyUnlockError)
|
|
230
|
+
return error;
|
|
231
|
+
if (error instanceof AppStrictDeviceApprovalError)
|
|
232
|
+
return new AppAccountKeyUnlockError("unlock_strict");
|
|
233
|
+
if (error instanceof AppAccountKeyProofUnavailableError)
|
|
234
|
+
return new AppAccountKeyUnlockError("unlock_unavailable");
|
|
235
|
+
if (!(error instanceof AccountKeyError))
|
|
236
|
+
return null;
|
|
237
|
+
switch (error.code) {
|
|
238
|
+
case "wrong_secret": return new AppAccountKeyUnlockError("wrong_secret");
|
|
239
|
+
case "invalid_recovery_key": return new AppAccountKeyUnlockError("invalid_recovery_key", error.reason);
|
|
240
|
+
case "no_account_key": return new AppAccountKeyUnlockError("no_account_key");
|
|
241
|
+
case "strict_mode": return new AppAccountKeyUnlockError("unlock_strict");
|
|
242
|
+
case "rate_limited": return new AppAccountKeyUnlockError("rate_limited", undefined, error.retryAfterMs);
|
|
243
|
+
case "cancelled": return null;
|
|
244
|
+
default: return error.reason === "account_key_proof_unavailable" ? new AppAccountKeyUnlockError("unlock_unavailable")
|
|
245
|
+
: new AppAccountKeyUnlockError("unavailable", error.reason ?? error.code, error.retryAfterMs);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/** Which of the three states the account key is in: a password is set, strict,
|
|
249
|
+
* or none. Only `mode` is read. Connect answers an installation with less than
|
|
250
|
+
* it answers the account's own devices (no strict `complete`/`pending`
|
|
251
|
+
* witnesses, which are the account's inventory), so nothing else in the body
|
|
252
|
+
* is required or trusted here. An unknown mode is a refusal, never a guess. */
|
|
253
|
+
async function accountKeyMode(control, signal) {
|
|
254
|
+
return (await accountKeyStatus(control, signal)).mode;
|
|
255
|
+
}
|
|
256
|
+
/** The mode, with the account-key version and key id when the answer carries
|
|
257
|
+
* them well formed. Those two decide only whether a held sealed bundle is still
|
|
258
|
+
* the current one: absent or malformed is "not known" (fetch afresh), never a
|
|
259
|
+
* refusal and never a grant. */
|
|
260
|
+
async function accountKeyStatus(control, signal) {
|
|
261
|
+
let raw;
|
|
262
|
+
try {
|
|
263
|
+
raw = await control.status({ signal });
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
throw mapPortError(error);
|
|
267
|
+
}
|
|
268
|
+
if (signal.aborted)
|
|
269
|
+
throw cancelled();
|
|
270
|
+
const r = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {}, mode = r.mode;
|
|
271
|
+
if (mode !== "password" && mode !== "strict" && mode !== "none")
|
|
272
|
+
throw unavailable("response");
|
|
273
|
+
return { mode, version: Number.isSafeInteger(r.version) && r.version >= 1 ? r.version : null,
|
|
274
|
+
keyId: typeof r.key_id === "string" && HEX32.test(r.key_id) ? r.key_id : null };
|
|
275
|
+
}
|
|
276
|
+
/** The account-key mode from the status route (no bundle, no proof, not on the
|
|
277
|
+
* fetch budget). A failed read rejects: the mode is never guessed. */
|
|
278
|
+
export async function readAccountKeyMode(session, options) {
|
|
279
|
+
const control = new AppCpAccountKeyControl(session, () => { throw unavailable("proof"); }, options);
|
|
280
|
+
try {
|
|
281
|
+
return await accountKeyMode(control, options.signal);
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
if (options.signal.aborted)
|
|
285
|
+
throw error;
|
|
286
|
+
throw problem(error) ?? error;
|
|
287
|
+
}
|
|
288
|
+
finally {
|
|
289
|
+
control.close();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/** Unlock this device's ONE adopted Private collection with the account key.
|
|
293
|
+
* Resolves only once the native applied policy has this device keyed and
|
|
294
|
+
* trusted. A typed `AppAccountKeyUnlockError` leaves the collection locked and
|
|
295
|
+
* open for another attempt; anything else is a lost owner or cancelled call. */
|
|
296
|
+
export async function unlockPrivateDevice(session, native, secret, options) {
|
|
297
|
+
const signal = options.signal, settleMs = options.settleMs ?? SETTLE_MS, sealed = options.sealed;
|
|
298
|
+
const password = "password" in secret, recovery = "recoveryKey" in secret;
|
|
299
|
+
if (password === recovery || typeof (password ? secret.password : secret.recoveryKey) !== "string" || !Number.isSafeInteger(settleMs) || settleMs < 1)
|
|
300
|
+
throw new AppAccountKeyUnlockError("unavailable", "binding");
|
|
301
|
+
const current = () => { if (signal.aborted)
|
|
302
|
+
throw cancelled(); if (session.isCurrent() !== true)
|
|
303
|
+
throw unavailable("fenced"); };
|
|
304
|
+
current();
|
|
305
|
+
// Keyed already (an earlier grant applied): nothing to fetch or derive.
|
|
306
|
+
if (native.status().state === "keyed") {
|
|
307
|
+
sealed?.clear();
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
// What can be told from the typed secret alone is refused here, before any
|
|
311
|
+
// request: it costs no status read and no bundle fetch, and leaves a held
|
|
312
|
+
// bundle as it was. A mistyped recovery key is not a recovery key. A password
|
|
313
|
+
// outside the length policy every sealed bundle was made under opens none.
|
|
314
|
+
if (recovery) {
|
|
315
|
+
try {
|
|
316
|
+
wipe(parseRecoveryKey(secret.recoveryKey));
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
throw problem(error) ?? error;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
try {
|
|
324
|
+
checkPassword(secret.password);
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
throw new AppAccountKeyUnlockError("wrong_secret");
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
let refusal, lost = null;
|
|
331
|
+
const replica = {
|
|
332
|
+
privateCollections: async () => [session.collection],
|
|
333
|
+
keyAccountKeyDevice: () => Promise.reject(unsupported()),
|
|
334
|
+
async selfGrantWithAccountKey(collectionId, r, request) {
|
|
335
|
+
const turn = request.signal ?? signal;
|
|
336
|
+
try {
|
|
337
|
+
current();
|
|
338
|
+
if (collectionId !== session.collection || !(r instanceof Uint8Array) || r.length !== 32)
|
|
339
|
+
throw unavailable("binding");
|
|
340
|
+
// The native call consumes its own copy; PrivateAccount wipes `r`.
|
|
341
|
+
const loan = new Uint8Array(r);
|
|
342
|
+
let state;
|
|
343
|
+
try {
|
|
344
|
+
state = native.unlockConsuming(loan);
|
|
345
|
+
}
|
|
346
|
+
finally {
|
|
347
|
+
loan.fill(0);
|
|
348
|
+
}
|
|
349
|
+
const until = Date.now() + settleMs;
|
|
350
|
+
let delay = 100;
|
|
351
|
+
while (state.state === "pending") {
|
|
352
|
+
if (Date.now() >= until) {
|
|
353
|
+
refusal = "grant_pending";
|
|
354
|
+
throw unavailable("grant_pending");
|
|
355
|
+
}
|
|
356
|
+
await native.drive({ signal: turn });
|
|
357
|
+
current();
|
|
358
|
+
state = native.status();
|
|
359
|
+
if (state.state !== "pending")
|
|
360
|
+
break;
|
|
361
|
+
await waitForOpenRetry(delay, turn);
|
|
362
|
+
current();
|
|
363
|
+
delay = Math.min(1_000, delay * 2);
|
|
364
|
+
}
|
|
365
|
+
if (state.state === "refused") {
|
|
366
|
+
refusal = state.reason;
|
|
367
|
+
throw unavailable(state.reason);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
catch (error) {
|
|
371
|
+
// PrivateAccount folds a failed collection into `incomplete`; keep what
|
|
372
|
+
// actually happened. Only a typed native refusal or a pending grant is
|
|
373
|
+
// a problem the person can retry: the rest ended this owner.
|
|
374
|
+
if (refusal === undefined)
|
|
375
|
+
lost = { error };
|
|
376
|
+
throw error;
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
const control = new AppCpAccountKeyControl(session, challenge => native.signFetch(challenge), options);
|
|
381
|
+
let known = null;
|
|
382
|
+
// The bundle route is asked only when this collection holds no sealed bundle
|
|
383
|
+
// for the account-key version and key id the status read of THIS attempt reported.
|
|
384
|
+
const port = !sealed ? control : {
|
|
385
|
+
accountId: control.accountId,
|
|
386
|
+
status: request => control.status(request), challenge: request => control.challenge(request),
|
|
387
|
+
async fetch(request) {
|
|
388
|
+
const held = sealed.take(session, known?.version ?? null, known?.keyId ?? null);
|
|
389
|
+
if (held)
|
|
390
|
+
return held;
|
|
391
|
+
const answer = await control.fetch(request);
|
|
392
|
+
sealed.keep(session, answer);
|
|
393
|
+
return answer;
|
|
394
|
+
},
|
|
395
|
+
put: () => control.put(), strict: () => control.strict(), enrolRecoveryDevice: () => control.enrolRecoveryDevice(), close: () => control.close(),
|
|
396
|
+
};
|
|
397
|
+
const secrets = memorySecretStore();
|
|
398
|
+
const account = new PrivateAccount({ control: port, replica, secrets, ...(options.argon2id ? { argon2id: options.argon2id } : {}) });
|
|
399
|
+
try {
|
|
400
|
+
known = await accountKeyStatus(control, signal);
|
|
401
|
+
current();
|
|
402
|
+
const mode = known.mode;
|
|
403
|
+
try {
|
|
404
|
+
options.onMode?.(mode);
|
|
405
|
+
}
|
|
406
|
+
catch { /* display observer does not own the unlock */ }
|
|
407
|
+
if (mode === "none")
|
|
408
|
+
throw new AppAccountKeyUnlockError("no_account_key");
|
|
409
|
+
if (mode === "strict")
|
|
410
|
+
throw new AppAccountKeyUnlockError("unlock_strict");
|
|
411
|
+
if (!native.supportsFetchProof())
|
|
412
|
+
throw new AppAccountKeyUnlockError("unlock_unavailable");
|
|
413
|
+
// The native unlock reads control items up to the head it knows.
|
|
414
|
+
if (native.headKnown() <= 0) {
|
|
415
|
+
await native.drive({ signal });
|
|
416
|
+
current();
|
|
417
|
+
}
|
|
418
|
+
if (native.headKnown() <= 0)
|
|
419
|
+
throw new AppAccountKeyUnlockError("unavailable", "log_head_unknown");
|
|
420
|
+
const result = await account.unlock(secret, signal);
|
|
421
|
+
const ended = lost;
|
|
422
|
+
if (ended)
|
|
423
|
+
throw ended.error;
|
|
424
|
+
current();
|
|
425
|
+
if (result.incomplete?.length)
|
|
426
|
+
throw new AppAccountKeyUnlockError(refusal === "grant_pending" ? "unavailable" : "unlock_failed", refusal ?? "incomplete");
|
|
427
|
+
if (native.status().state !== "keyed")
|
|
428
|
+
throw new AppAccountKeyUnlockError("unlock_failed", "not_keyed");
|
|
429
|
+
sealed?.clear();
|
|
430
|
+
}
|
|
431
|
+
catch (error) {
|
|
432
|
+
// Only a wrong secret leaves the sealed bundle for the next attempt.
|
|
433
|
+
if (!(error instanceof AccountKeyError && error.code === "wrong_secret") || signal.aborted || session.isCurrent() !== true)
|
|
434
|
+
sealed?.clear();
|
|
435
|
+
if (signal.aborted || session.isCurrent() !== true)
|
|
436
|
+
throw error;
|
|
437
|
+
throw problem(error) ?? error;
|
|
438
|
+
}
|
|
439
|
+
finally {
|
|
440
|
+
// RAM-only `R` is wiped on every path; the facade keeps nothing else.
|
|
441
|
+
try {
|
|
442
|
+
await secrets.clear();
|
|
443
|
+
}
|
|
444
|
+
finally {
|
|
445
|
+
account.close();
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
//# sourceMappingURL=account-key-host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-key-host.js","sourceRoot":"","sources":["../../src/app-host/account-key-host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;mCAUmC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,gBAAgB,EAAE,IAAI,EAAuB,MAAM,mBAAmB,CAAC;AAChH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EACL,cAAc,EAAE,YAAY,EAAE,iBAAiB,GAEhD,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,kCAAkC,EAAE,4BAA4B,EAA2B,MAAM,mBAAmB,CAAC;AAuB9H,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAC5B;IAA6C;IAA0B;IAA5F,YAAqB,MAAkC,EAAW,MAAe,EAAW,YAAqB;QAC/G,KAAK,CAAC,2BAA2B,MAAM,EAAE,CAAC,CAAC;QADxB,WAAM,GAAN,MAAM,CAA4B;QAAW,WAAM,GAAN,MAAM,CAAS;QAAW,iBAAY,GAAZ,YAAY,CAAS;QACnE,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACrF,CAAC;CACF;AAoCD;;;;;;;;;;0EAU0E;AAC1E,MAAM,OAAO,yBAAyB;IAC5B,IAAI,GAAoF,IAAI,CAAC;IACrG,0CAA0C;IAC1C,IAAI,OAAO,KAAc,OAAO,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC;IACrD;;mBAEe;IACf,IAAI,CAAC,OAAoB,EAAE,OAAsB,EAAE,KAAoB;QACrE,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;QACpB,IAAI,CAAC,IAAI,OAAO,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS,IAAI,CAAC,CAAC,WAAW,KAAK,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,QAAQ;eACvJ,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK;YAAE,OAAO,EAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAC,CAAC;QAClI,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAAC,OAAO,IAAI,CAAC;IAChC,CAAC;IACD;;mBAEe;IACf,IAAI,CAAC,OAAoB,EAAE,MAAe;QACxC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,MAAM,CAAC,GAAG,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAiC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClH,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,IAAK,CAAC,CAAC,OAAkB,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;eAC9I,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;YAAE,OAAO;QACtF,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,EAAC,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,OAAiB,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAC,CAAC,CAAC;IAC3L,CAAC;IACD,KAAK,KAAW,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC;CACpC;AAED,MAAM,QAAQ,GAAG,EAAE,GAAG,IAAI,EAAE,UAAU,GAAG,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;AACpE,MAAM,WAAW,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,IAAI,eAAe,CAAC,aAAa,EAAE,qDAAqD,EAAE,EAAC,MAAM,EAAC,CAAC,CAAC;AAC5I,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,IAAI,eAAe,CAAC,WAAW,EAAE,gCAAgC,CAAC,CAAC;AAC3F,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;AACvD,MAAM,GAAG,GAAG,CAAC,CAAa,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC5F,MAAM,KAAK,GAAG,gBAAgB,CAAC;AAE/B;2EAC2E;AAC3E,MAAM,OAAO,sBAAsB;IAOJ;IAAgD;IANpE,SAAS,CAAS;IACV,QAAQ,GAAG,IAAI,eAAe,EAAE,CAAC;IACjC,MAAM,CAAS;IACf,QAAQ,CAAS;IACjB,SAAS,CAAe;IACxB,GAAG,CAAe;IACnC,YAA6B,OAA6B,EAAmB,IAA2C,EAAE,UAAoC,EAAE;QAAnI,YAAO,GAAP,OAAO,CAAsB;QAAmB,SAAI,GAAJ,IAAI,CAAuC;QACtH,KAAK,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC;YAAE,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;gBAAE,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC;QACvK,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC,iBAAiB,KAAK,IAAI,IAAI,kBAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC;QAC1M,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QAAC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;QAC7F,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;QAAC,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;QACvF,IAAI,OAAO,CAAC,SAAS,EAAE,KAAK,IAAI;YAAE,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;IAChE,CAAC;IACO,KAAK,CAAC,MAAmB;QAC/B,IAAI,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO;YAAE,MAAM,SAAS,EAAE,CAAC;QACtE,IAAI,OAAO,GAAG,KAAK,CAAC;QAAC,IAAI,CAAC;YAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,KAAK,IAAI,CAAC,MAAM,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,GAAG,KAAK,CAAC;QAAC,CAAC;QACrO,IAAI,CAAC,OAAO;YAAE,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IACO,KAAK,CAAC,OAAO,CAAC,MAAsB,EAAE,IAA2F,EACvI,OAAyC,EAAE,OAAqC;QAChF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC1E,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,EAAC,MAAM,EAAE,MAAM,EAAC,CAAC,CAAC;QAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACxF,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,KAAK,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC;QAChI,MAAM,IAAI,GAAG,IAAI,eAAe,EAAE,EAAE,KAAK,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QAAE,KAA8B,CAAC,KAAK,EAAE,EAAE,CAAC;QACjJ,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;QAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAC,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;QAC3H,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC;QAAC,IAAI,KAAK,GAAG,CAAC,EAAE,QAAQ,GAAoB,IAAI,EAAE,MAAM,GAAmD,IAAI,CAAC;QACxJ,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;YAC/B,IAAI,CAAC;gBACH,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,EAAE,EAAC,MAAM,EAAE,OAAO,EAAE,EAAC,aAAa,EAAE,UAAU,MAAM,EAAE,EAAE,GAAG,OAAO,EAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAC,CAAC,CAAC;YACvO,CAAC;YAAC,MAAM,CAAC;gBAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAAC,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC;YAAC,CAAC;YAC7D,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAAC,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO;gBAAE,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC;YAC1E,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAClB,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACnC,SAAS,CAAC;oBACR,IAAI,IAA0C,CAAC;oBAC/C,IAAI,CAAC;wBAAC,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;oBAAC,CAAC;oBAAC,MAAM,CAAC;wBAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;wBAAC,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC;oBAAC,CAAC;oBAC/F,IAAI,CAAC;wBAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;wBAAC,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO;4BAAE,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC;wBAAC,IAAI,IAAI,CAAC,IAAI;4BAAE,MAAM;wBACpG,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;4BAAC,IAAI,CAAC,KAAK,EAAE,CAAC;4BAAC,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC;wBAAC,CAAC;wBAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;wBAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;oBAAC,CAAC;4BACtJ,CAAC;wBAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;oBAAC,CAAC;gBAClC,CAAC;YACH,CAAC;YACD,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;YACtD,kFAAkF;YAClF,IAAI,CAAC,QAAQ,CAAC,EAAE;gBAAE,MAAM,gBAAgB,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;YAClF,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;gBAAE,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC;YAC5F,OAAO,IAA+B,CAAC;QACzC,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAAC,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAAC,IAAI,CAAC;gBAAC,MAAM,EAAE,WAAW,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;YAC9I,YAAY,CAAC,KAAK,CAAC,CAAC;YAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC5H,CAAC;IACH,CAAC;IACD,MAAM,CAAC,OAAqC,IAAsB,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,6BAA6B,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3I,SAAS,CAAC,OAAqC,IAAsB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,4BAA4B,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9I;;iCAE6B;IAC7B,KAAK,CAAC,KAAK,CAAC,OAAqC;QAC/C,IAAI,KAAK,GAAsB,IAAI,EAAE,SAAS,GAAsB,IAAI,CAAC;QACzE,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,4BAA4B,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;YACrF,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC;YAC3D,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,KAAK,IAAI,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,MAAM;gBAAE,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC;YACpO,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;YACtE,IAAI,CAAC;gBAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAAC,CAAC;YACrC,OAAO,KAAK,EAAE,CAAC;gBACb,IAAI,KAAK,YAAY,kCAAkC;oBAAE,MAAM,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBACzF,IAAI,KAAK,YAAY,4BAA4B;oBAAE,MAAM,IAAI,eAAe,CAAC,aAAa,EAAE,gCAAgC,CAAC,CAAC;gBAC9H,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;YAC7B,CAAC;YACD,IAAI,CAAC,CAAC,SAAS,YAAY,UAAU,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,EAAE;gBAAE,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;YAC9F,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,sBAAsB,EAAE,EAAC,oBAAoB,EAAE,IAAI,CAAC,QAAQ,EAAE,oBAAoB,EAAE,IAAI,EAAE,oBAAoB,EAAE,GAAG,CAAC,SAAS,CAAC,EAAC,EAAE,OAAO,CAAC,CAAC;QAC7K,CAAC;gBAAS,CAAC;YAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;YAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAAC,CAAC;IACnD,CAAC;IACD,GAAG,KAAuB,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;IACjE,MAAM,KAAuB,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;IACpE,mBAAmB,KAAuB,OAAO,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;IACjF,KAAK,KAAW,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;CACzC;AAED,SAAS,OAAO,CAAC,KAAc;IAC7B,IAAI,KAAK,YAAY,wBAAwB;QAAE,OAAO,KAAK,CAAC;IAC5D,IAAI,KAAK,YAAY,4BAA4B;QAAE,OAAO,IAAI,wBAAwB,CAAC,eAAe,CAAC,CAAC;IACxG,IAAI,KAAK,YAAY,kCAAkC;QAAE,OAAO,IAAI,wBAAwB,CAAC,oBAAoB,CAAC,CAAC;IACnH,IAAI,CAAC,CAAC,KAAK,YAAY,eAAe,CAAC;QAAE,OAAO,IAAI,CAAC;IACrD,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,cAAc,CAAC,CAAC,OAAO,IAAI,wBAAwB,CAAC,cAAc,CAAC,CAAC;QACzE,KAAK,sBAAsB,CAAC,CAAC,OAAO,IAAI,wBAAwB,CAAC,sBAAsB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACvG,KAAK,gBAAgB,CAAC,CAAC,OAAO,IAAI,wBAAwB,CAAC,gBAAgB,CAAC,CAAC;QAC7E,KAAK,aAAa,CAAC,CAAC,OAAO,IAAI,wBAAwB,CAAC,eAAe,CAAC,CAAC;QACzE,KAAK,cAAc,CAAC,CAAC,OAAO,IAAI,wBAAwB,CAAC,cAAc,EAAE,SAAS,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;QACxG,KAAK,WAAW,CAAC,CAAC,OAAO,IAAI,CAAC;QAC9B,OAAO,CAAC,CAAC,OAAO,KAAK,CAAC,MAAM,KAAK,+BAA+B,CAAC,CAAC,CAAC,IAAI,wBAAwB,CAAC,oBAAoB,CAAC;YACnH,CAAC,CAAC,IAAI,wBAAwB,CAAC,aAAa,EAAE,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAClG,CAAC;AACH,CAAC;AAED;;;;+EAI+E;AAC/E,KAAK,UAAU,cAAc,CAAC,OAA+B,EAAE,MAAmB;IAChF,OAAO,CAAC,MAAM,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACxD,CAAC;AACD;;;gCAGgC;AAChC,KAAK,UAAU,gBAAgB,CAAC,OAA+B,EAAE,MAAmB;IAClF,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QAAC,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,EAAC,MAAM,EAAC,CAAC,CAAC;IAAC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAAC,MAAM,YAAY,CAAC,KAAK,CAAC,CAAC;IAAC,CAAC;IAC1F,IAAI,MAAM,CAAC,OAAO;QAAE,MAAM,SAAS,EAAE,CAAC;IACtC,MAAM,CAAC,GAAG,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAA8B,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;IACrH,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,MAAM;QAAE,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC;IAC/F,OAAO,EAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,IAAK,CAAC,CAAC,OAAkB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAiB,CAAC,CAAC,CAAC,IAAI;QAC/G,KAAK,EAAE,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAC,CAAC;AACnF,CAAC;AAED;sEACsE;AACtE,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAA6B,EAAE,OAAyD;IAC/H,MAAM,OAAO,GAAG,IAAI,sBAAsB,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACpG,IAAI,CAAC;QAAC,OAAO,MAAM,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAAC,CAAC;IAC7D,OAAO,KAAK,EAAE,CAAC;QAAC,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO;YAAE,MAAM,KAAK,CAAC;QAAC,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;IAAC,CAAC;YACjF,CAAC;QAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;AAC9B,CAAC;AAED;;;gFAGgF;AAChF,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAA6B,EAAE,MAA2B,EAAE,MAA2B,EAC/H,OAEqC;IACrC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACjG,MAAM,QAAQ,GAAG,UAAU,IAAI,MAAM,EAAE,QAAQ,GAAG,aAAa,IAAI,MAAM,CAAC;IAC1E,IAAI,QAAQ,KAAK,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAE,MAAgC,CAAC,WAAW,CAAC,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC;QAC9K,MAAM,IAAI,wBAAwB,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,GAAG,EAAE,GAAG,IAAI,MAAM,CAAC,OAAO;QAAE,MAAM,SAAS,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,SAAS,EAAE,KAAK,IAAI;QAAE,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAChI,OAAO,EAAE,CAAC;IACV,wEAAwE;IACxE,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;QAAC,MAAM,EAAE,KAAK,EAAE,CAAC;QAAC,OAAO;IAAC,CAAC;IACnE,2EAA2E;IAC3E,0EAA0E;IAC1E,8EAA8E;IAC9E,2EAA2E;IAC3E,IAAI,QAAQ,EAAE,CAAC;QAAC,IAAI,CAAC;YAAC,IAAI,CAAC,gBAAgB,CAAE,MAAgC,CAAC,WAAW,CAAC,CAAC,CAAC;QAAC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAAC,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;QAAC,CAAC;IAAC,CAAC;SAC5I,CAAC;QAAC,IAAI,CAAC;YAAC,aAAa,CAAE,MAA6B,CAAC,QAAQ,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,MAAM,IAAI,wBAAwB,CAAC,cAAc,CAAC,CAAC;QAAC,CAAC;IAAC,CAAC;IACtI,IAAI,OAA2B,EAAE,IAAI,GAA4B,IAAI,CAAC;IACtE,MAAM,OAAO,GAA0B;QACrC,kBAAkB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;QACpD,mBAAmB,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACxD,KAAK,CAAC,uBAAuB,CAAC,YAAY,EAAE,CAAC,EAAE,OAAO;YACpD,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC;YACtC,IAAI,CAAC;gBACH,OAAO,EAAE,CAAC;gBAAC,IAAI,YAAY,KAAK,OAAO,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,YAAY,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,EAAE;oBAAE,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC;gBAClI,mEAAmE;gBACnE,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;gBAAC,IAAI,KAAyB,CAAC;gBAC9D,IAAI,CAAC;oBAAC,KAAK,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;gBAAC,CAAC;wBAAS,CAAC;oBAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAAC,CAAC;gBACvE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC;gBAAC,IAAI,KAAK,GAAG,GAAG,CAAC;gBACrD,OAAO,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;oBACjC,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,KAAK,EAAE,CAAC;wBAAC,OAAO,GAAG,eAAe,CAAC;wBAAC,MAAM,WAAW,CAAC,eAAe,CAAC,CAAC;oBAAC,CAAC;oBAC3F,MAAM,MAAM,CAAC,KAAK,CAAC,EAAC,MAAM,EAAE,IAAI,EAAC,CAAC,CAAC;oBAAC,OAAO,EAAE,CAAC;oBAC9C,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;oBACxB,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;wBAAE,MAAM;oBACrC,MAAM,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;oBAAC,OAAO,EAAE,CAAC;oBAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;gBACrF,CAAC;gBACD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;oBAAC,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC;oBAAC,MAAM,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAAC,CAAC;YAC7F,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,wEAAwE;gBACxE,uEAAuE;gBACvE,6DAA6D;gBAC7D,IAAI,OAAO,KAAK,SAAS;oBAAE,IAAI,GAAG,EAAC,KAAK,EAAC,CAAC;gBAC1C,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;KACF,CAAC;IACF,MAAM,OAAO,GAAG,IAAI,sBAAsB,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC;IACvG,IAAI,KAAK,GAAwD,IAAI,CAAC;IACtE,6EAA6E;IAC7E,mFAAmF;IACnF,MAAM,IAAI,GAA0B,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACtD,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC;QAC5F,KAAK,CAAC,KAAK,CAAC,OAAO;YACjB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,IAAI,IAAI,EAAE,KAAK,EAAE,KAAK,IAAI,IAAI,CAAC,CAAC;YAChF,IAAI,IAAI;gBAAE,OAAO,IAAI,CAAC;YACtB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAAC,OAAO,MAAM,CAAC;QAC3F,CAAC;QACD,GAAG,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,mBAAmB,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE;KACjJ,CAAC;IACF,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;IACpC,MAAM,OAAO,GAAG,IAAI,cAAc,CAAC,EAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAC,CAAC,CAAC;IACjI,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAAC,OAAO,EAAE,CAAC;QAC3D,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC;YAAC,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,8CAA8C,CAAC,CAAC;QACxF,IAAI,IAAI,KAAK,MAAM;YAAE,MAAM,IAAI,wBAAwB,CAAC,gBAAgB,CAAC,CAAC;QAC1E,IAAI,IAAI,KAAK,QAAQ;YAAE,MAAM,IAAI,wBAAwB,CAAC,eAAe,CAAC,CAAC;QAC3E,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE;YAAE,MAAM,IAAI,wBAAwB,CAAC,oBAAoB,CAAC,CAAC;QAC3F,iEAAiE;QACjE,IAAI,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC;YAAC,MAAM,MAAM,CAAC,KAAK,CAAC,EAAC,MAAM,EAAC,CAAC,CAAC;YAAC,OAAO,EAAE,CAAC;QAAC,CAAC;QACzE,IAAI,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC;YAAE,MAAM,IAAI,wBAAwB,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAAC;QACnG,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACpD,MAAM,KAAK,GAAG,IAA+B,CAAC;QAC9C,IAAI,KAAK;YAAE,MAAM,KAAK,CAAC,KAAK,CAAC;QAC7B,OAAO,EAAE,CAAC;QACV,IAAI,MAAM,CAAC,UAAU,EAAE,MAAM;YAAE,MAAM,IAAI,wBAAwB,CAAC,OAAO,KAAK,eAAe,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,eAAe,EAAE,OAAO,IAAI,YAAY,CAAC,CAAC;QAC1J,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,KAAK,OAAO;YAAE,MAAM,IAAI,wBAAwB,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;QACxG,MAAM,EAAE,KAAK,EAAE,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,qEAAqE;QACrE,IAAI,CAAC,CAAC,KAAK,YAAY,eAAe,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC,IAAI,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,SAAS,EAAE,KAAK,IAAI;YAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QAC5I,IAAI,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,SAAS,EAAE,KAAK,IAAI;YAAE,MAAM,KAAK,CAAC;QAChE,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;IAChC,CAAC;YAAS,CAAC;QACT,sEAAsE;QACtE,IAAI,CAAC;YAAC,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QAAC,CAAC;gBAAS,CAAC;YAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAAC,CAAC;IAC7D,CAAC;AACH,CAAC"}
|
|
@@ -8,18 +8,17 @@ export interface AppEnvironmentSelection {
|
|
|
8
8
|
readonly cpOrigin: string;
|
|
9
9
|
readonly logOrigin: string;
|
|
10
10
|
readonly assetSha256: string;
|
|
11
|
+
/** mdbase's own origins (CP, log) may be loopback HTTP: LAB and local builds only. */
|
|
11
12
|
readonly allowLoopbackHttp: boolean;
|
|
12
|
-
/** Native app-origin storage only; never CP/log HTTP or test trust. */
|
|
13
|
-
readonly allowNativeLoopbackHttp: boolean;
|
|
14
13
|
}
|
|
15
14
|
/** No environment or app-origin default. CP/log origins come only from the
|
|
16
15
|
* preauthenticated build release, whose environment must match exactly.
|
|
17
|
-
*
|
|
16
|
+
* A loopback app origin is an application under development (or a native one);
|
|
17
|
+
* it never relaxes HTTPS for the CP or log outside LAB.
|
|
18
18
|
* Same-origin storage preservation is an app gate, not a runtime fallback. */
|
|
19
19
|
export declare function selectAppEnvironment(input: {
|
|
20
20
|
environment: "lab" | "staging" | "production" | "local";
|
|
21
21
|
appOrigin: string;
|
|
22
|
-
platform?: "native";
|
|
23
22
|
release: AppBundledReleaseTrust;
|
|
24
23
|
}): AppEnvironmentSelection;
|
|
25
24
|
/** Only a previously validated immutable selection, not a copied/redirect object.
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { isAppOrigin } from "./app-origin.js";
|
|
2
|
-
import { applicationEnvironmentAllowed,
|
|
2
|
+
import { applicationEnvironmentAllowed, serviceLoopbackAllowed, loopbackHttpOrigin, localApplicationEnvironment, localApplicationOrigin } from "../application/local-build.js";
|
|
3
3
|
const selections = new WeakSet();
|
|
4
4
|
const invalid = () => new Error("app environment: explicit authenticated build context required");
|
|
5
5
|
function origin(value, loopbackAllowed) {
|
|
6
6
|
if (typeof value !== "string" || !value.length)
|
|
7
7
|
throw invalid();
|
|
8
8
|
const u = new URL(value);
|
|
9
|
-
const loopback = loopbackAllowed &&
|
|
9
|
+
const loopback = loopbackAllowed && loopbackHttpOrigin(value);
|
|
10
10
|
if (u.origin !== value || u.username || u.password || (u.protocol !== "https:" && !loopback))
|
|
11
11
|
throw invalid();
|
|
12
12
|
return value;
|
|
13
13
|
}
|
|
14
14
|
/** No environment or app-origin default. CP/log origins come only from the
|
|
15
15
|
* preauthenticated build release, whose environment must match exactly.
|
|
16
|
-
*
|
|
16
|
+
* A loopback app origin is an application under development (or a native one);
|
|
17
|
+
* it never relaxes HTTPS for the CP or log outside LAB.
|
|
17
18
|
* Same-origin storage preservation is an app gate, not a runtime fallback. */
|
|
18
19
|
export function selectAppEnvironment(input) {
|
|
19
20
|
const { environment, release } = input;
|
|
@@ -32,11 +33,10 @@ export function selectAppEnvironment(input) {
|
|
|
32
33
|
const appOrigin = input.appOrigin;
|
|
33
34
|
if (local && ![cpOrigin, logOrigin, appOrigin].every(localApplicationOrigin))
|
|
34
35
|
throw invalid();
|
|
35
|
-
if (!isAppOrigin(appOrigin
|
|
36
|
+
if (!isAppOrigin(appOrigin))
|
|
36
37
|
throw invalid();
|
|
37
38
|
const selected = Object.freeze({ environment, appOrigin, cpOrigin, logOrigin, assetSha256: release.assetSha256,
|
|
38
|
-
allowLoopbackHttp:
|
|
39
|
-
allowNativeLoopbackHttp: input.platform === "native" && isAppOrigin(appOrigin, false, "native") && new URL(appOrigin).protocol === "http:" });
|
|
39
|
+
allowLoopbackHttp: serviceLoopbackAllowed(environment) && new URL(appOrigin).protocol === "http:" });
|
|
40
40
|
selections.add(selected);
|
|
41
41
|
return selected;
|
|
42
42
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-environment.js","sourceRoot":"","sources":["../../src/app-host/app-environment.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,6BAA6B,EAAE,
|
|
1
|
+
{"version":3,"file":"app-environment.js","sourceRoot":"","sources":["../../src/app-host/app-environment.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export type AppOriginPlatform = "web" | "mobile" | "extension" | "native";
|
|
2
2
|
/** Origin of a URL, including app schemes whose WHATWG origin is opaque. */
|
|
3
3
|
export declare function urlOrigin(url: URL): string;
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
/** The platform an app origin runs on, or null when it is not an app origin.
|
|
5
|
+
* A manifest that declares `platform: "native"` is held to the canonical IPv4
|
|
6
|
+
* loopback origin its manifest rule requires. */
|
|
7
|
+
export declare function appOriginPlatform(value: unknown, declared?: "native"): AppOriginPlatform | null;
|
|
8
|
+
export declare const isAppOrigin: (value: unknown) => boolean;
|
|
6
9
|
/** This document's or Worker's own app origin, or null outside a browser. */
|
|
7
10
|
export declare function currentAppOrigin(): string | null;
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { isNativeLoopbackOrigin } from "@mdbase-dev/connect-protocol/manifest";
|
|
2
|
-
/** App origins the SDK can run under: https
|
|
3
|
-
*
|
|
2
|
+
/** App origins the SDK can run under: https web origins, loopback http (an
|
|
3
|
+
* application under development, or a native one), Capacitor's iOS
|
|
4
|
+
* `capacitor://<host>` and browser-extension pages.
|
|
4
5
|
* Browsers may report custom app schemes as an opaque "null" origin, so the
|
|
5
6
|
* canonical form is always `<scheme>//<host>`. Exact match, no wildcards. */
|
|
6
|
-
import {
|
|
7
|
+
import { loopbackHttpOrigin } from "../application/local-build.js";
|
|
7
8
|
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
8
9
|
/** Origin of a URL, including app schemes whose WHATWG origin is opaque. */
|
|
9
10
|
export function urlOrigin(url) {
|
|
10
11
|
return url.protocol === "https:" || url.protocol === "http:" ? url.origin : `${url.protocol}//${url.host}`;
|
|
11
12
|
}
|
|
12
|
-
|
|
13
|
+
/** The platform an app origin runs on, or null when it is not an app origin.
|
|
14
|
+
* A manifest that declares `platform: "native"` is held to the canonical IPv4
|
|
15
|
+
* loopback origin its manifest rule requires. */
|
|
16
|
+
export function appOriginPlatform(value, declared) {
|
|
13
17
|
if (typeof value !== "string" || value.length > 512)
|
|
14
18
|
return null;
|
|
15
19
|
let u;
|
|
@@ -23,14 +27,14 @@ export function appOriginPlatform(value, loopbackHttp = false, platform) {
|
|
|
23
27
|
return null;
|
|
24
28
|
switch (u.protocol) {
|
|
25
29
|
case "https:": return "web";
|
|
26
|
-
case "http:": return
|
|
30
|
+
case "http:": return declared === "native" ? (isNativeLoopbackOrigin(value) ? "native" : null) : loopbackHttpOrigin(value) ? "web" : null;
|
|
27
31
|
case "capacitor:": return !u.port && /^[a-z0-9.-]{1,253}$/.test(u.hostname) ? "mobile" : null;
|
|
28
32
|
case "chrome-extension:": return /^[a-p]{32}$/.test(u.host) ? "extension" : null;
|
|
29
33
|
case "moz-extension:": return UUID.test(u.host) ? "extension" : null;
|
|
30
34
|
default: return null;
|
|
31
35
|
}
|
|
32
36
|
}
|
|
33
|
-
export const isAppOrigin = (value
|
|
37
|
+
export const isAppOrigin = (value) => appOriginPlatform(value) !== null;
|
|
34
38
|
/** This document's or Worker's own app origin, or null outside a browser. */
|
|
35
39
|
export function currentAppOrigin() {
|
|
36
40
|
const location = globalThis.location;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-origin.js","sourceRoot":"","sources":["../../src/app-host/app-origin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,sBAAsB,EAAC,MAAM,uCAAuC,CAAC;AAC7E
|
|
1
|
+
{"version":3,"file":"app-origin.js","sourceRoot":"","sources":["../../src/app-host/app-origin.ts"],"names":[],"mappings":"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"}
|