velocious 1.0.473 → 1.0.475
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 +7 -2
- package/build/authorization/base-resource.js +99 -0
- package/build/configuration-types.js +41 -3
- package/build/configuration.js +41 -1
- package/build/database/drivers/base.js +51 -3
- package/build/database/drivers/mysql/index.js +74 -7
- package/build/database/drivers/sqlite/connection-sql-js.js +16 -5
- package/build/database/drivers/sqlite/index.web.js +29 -15
- package/build/database/drivers/sqlite/web-persistence.js +521 -0
- package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +64 -1
- package/build/frontend-model-controller.js +139 -16
- package/build/frontend-model-resource/base-resource.js +258 -46
- package/build/frontend-model-resource/velocious-attachment-resource.js +0 -3
- package/build/frontend-models/base.js +146 -2
- package/build/frontend-models/query.js +3 -3
- package/build/frontend-models/resource-definition.js +400 -23
- package/build/routes/hooks/frontend-model-command-route-hook.js +8 -0
- package/build/src/authorization/base-resource.d.ts +41 -0
- package/build/src/authorization/base-resource.d.ts.map +1 -1
- package/build/src/authorization/base-resource.js +88 -1
- package/build/src/configuration-types.d.ts +128 -5
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +38 -4
- package/build/src/configuration.d.ts +18 -1
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +37 -2
- package/build/src/database/drivers/base.d.ts +30 -0
- package/build/src/database/drivers/base.d.ts.map +1 -1
- package/build/src/database/drivers/base.js +47 -4
- package/build/src/database/drivers/mysql/index.d.ts +32 -3
- package/build/src/database/drivers/mysql/index.d.ts.map +1 -1
- package/build/src/database/drivers/mysql/index.js +65 -7
- package/build/src/database/drivers/sqlite/connection-sql-js.d.ts +8 -1
- package/build/src/database/drivers/sqlite/connection-sql-js.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/connection-sql-js.js +15 -6
- package/build/src/database/drivers/sqlite/index.web.d.ts +5 -5
- package/build/src/database/drivers/sqlite/index.web.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/index.web.js +27 -13
- package/build/src/database/drivers/sqlite/web-persistence.d.ts +77 -0
- package/build/src/database/drivers/sqlite/web-persistence.d.ts.map +1 -0
- package/build/src/database/drivers/sqlite/web-persistence.js +464 -0
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts +30 -0
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +54 -2
- package/build/src/frontend-model-controller.d.ts +34 -0
- package/build/src/frontend-model-controller.d.ts.map +1 -1
- package/build/src/frontend-model-controller.js +125 -17
- package/build/src/frontend-model-resource/base-resource.d.ts +69 -0
- package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
- package/build/src/frontend-model-resource/base-resource.js +247 -54
- package/build/src/frontend-model-resource/velocious-attachment-resource.d.ts +0 -2
- package/build/src/frontend-model-resource/velocious-attachment-resource.d.ts.map +1 -1
- package/build/src/frontend-model-resource/velocious-attachment-resource.js +1 -3
- package/build/src/frontend-models/base.d.ts +29 -0
- package/build/src/frontend-models/base.d.ts.map +1 -1
- package/build/src/frontend-models/base.js +131 -3
- package/build/src/frontend-models/query.js +4 -4
- package/build/src/frontend-models/resource-definition.d.ts +6 -0
- package/build/src/frontend-models/resource-definition.d.ts.map +1 -1
- package/build/src/frontend-models/resource-definition.js +355 -28
- package/build/src/routes/hooks/frontend-model-command-route-hook.d.ts.map +1 -1
- package/build/src/routes/hooks/frontend-model-command-route-hook.js +8 -1
- package/build/src/sync/device-identity.d.ts +240 -0
- package/build/src/sync/device-identity.d.ts.map +1 -0
- package/build/src/sync/device-identity.js +454 -0
- package/build/src/sync/local-mutation-log.d.ts +212 -0
- package/build/src/sync/local-mutation-log.d.ts.map +1 -0
- package/build/src/sync/local-mutation-log.js +404 -0
- package/build/src/sync/offline-grant.d.ts +157 -0
- package/build/src/sync/offline-grant.d.ts.map +1 -0
- package/build/src/sync/offline-grant.js +292 -0
- package/build/sync/device-identity.js +503 -0
- package/build/sync/local-mutation-log.js +448 -0
- package/build/sync/offline-grant.js +327 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/scripts/tensorbuzz-retry +21 -0
- package/src/authorization/base-resource.js +99 -0
- package/src/configuration-types.js +41 -3
- package/src/configuration.js +41 -1
- package/src/database/drivers/base.js +51 -3
- package/src/database/drivers/mysql/index.js +74 -7
- package/src/database/drivers/sqlite/connection-sql-js.js +16 -5
- package/src/database/drivers/sqlite/index.web.js +29 -15
- package/src/database/drivers/sqlite/web-persistence.js +521 -0
- package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +64 -1
- package/src/frontend-model-controller.js +139 -16
- package/src/frontend-model-resource/base-resource.js +258 -46
- package/src/frontend-model-resource/velocious-attachment-resource.js +0 -3
- package/src/frontend-models/base.js +146 -2
- package/src/frontend-models/query.js +3 -3
- package/src/frontend-models/resource-definition.js +400 -23
- package/src/routes/hooks/frontend-model-command-route-hook.js +8 -0
- package/src/sync/device-identity.js +503 -0
- package/src/sync/local-mutation-log.js +448 -0
- package/src/sync/offline-grant.js +327 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
const OFFLINE_GRANT_SIGNATURE_ALGORITHM = "HS256";
|
|
3
|
+
const OFFLINE_GRANT_SIGNATURE_PREFIX = "hmac-sha256-";
|
|
4
|
+
/**
|
|
5
|
+
* Signed offline grant envelope.
|
|
6
|
+
* @typedef {object} SignedOfflineGrant
|
|
7
|
+
* @property {"HS256"} algorithm - Signature algorithm.
|
|
8
|
+
* @property {OfflineGrant} grant - Signed grant payload.
|
|
9
|
+
* @property {string} keyId - Signing key id.
|
|
10
|
+
* @property {string} signature - Hex HMAC signature with a hmac-sha256 prefix.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Backend-issued offline grant payload.
|
|
14
|
+
* @typedef {object} OfflineGrant
|
|
15
|
+
* @property {string} deviceId - Device id allowed to use the grant.
|
|
16
|
+
* @property {string} expiresAt - ISO timestamp after which replay must reject the grant.
|
|
17
|
+
* @property {string} grantId - Stable grant id.
|
|
18
|
+
* @property {string} issuedAt - ISO timestamp when the backend issued the grant.
|
|
19
|
+
* @property {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} resources - Sync manifest/materialized resource metadata.
|
|
20
|
+
* @property {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} scopes - Materialized grant scopes.
|
|
21
|
+
* @property {string} userId - Actor user id allowed to use the grant.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Offline grant signing key.
|
|
25
|
+
* @typedef {object} OfflineGrantSigningKey
|
|
26
|
+
* @property {boolean} [current] - Whether this is the active key for new grants.
|
|
27
|
+
* @property {string} id - Public key id included in signed grant envelopes.
|
|
28
|
+
* @property {string} secret - Private HMAC secret. Never expose this to clients.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Creates a signed offline grant envelope.
|
|
32
|
+
* @param {object} args - Arguments.
|
|
33
|
+
* @param {OfflineGrant} args.grant - Grant payload.
|
|
34
|
+
* @param {OfflineGrantSigningKey} args.signingKey - Current signing key.
|
|
35
|
+
* @returns {Promise<SignedOfflineGrant>} - Signed grant envelope.
|
|
36
|
+
*/
|
|
37
|
+
export async function createOfflineGrant({ grant, signingKey }) {
|
|
38
|
+
const normalizedGrant = normalizeOfflineGrant(grant);
|
|
39
|
+
const normalizedSigningKey = normalizeOfflineGrantSigningKey(signingKey);
|
|
40
|
+
const signatureInput = offlineGrantSignatureInput({
|
|
41
|
+
algorithm: OFFLINE_GRANT_SIGNATURE_ALGORITHM,
|
|
42
|
+
grant: normalizedGrant,
|
|
43
|
+
keyId: normalizedSigningKey.id
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
algorithm: OFFLINE_GRANT_SIGNATURE_ALGORITHM,
|
|
47
|
+
grant: normalizedGrant,
|
|
48
|
+
keyId: normalizedSigningKey.id,
|
|
49
|
+
signature: await hmacSha256Hex({ message: signatureInput, secret: normalizedSigningKey.secret })
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Verifies a signed offline grant and returns the trusted grant payload.
|
|
54
|
+
* @param {object} args - Arguments.
|
|
55
|
+
* @param {Date} [args.now] - Verification time. Defaults to current time.
|
|
56
|
+
* @param {SignedOfflineGrant} args.signedGrant - Signed grant envelope.
|
|
57
|
+
* @param {OfflineGrantSigningKey[]} args.signingKeys - Candidate verification keys.
|
|
58
|
+
* @returns {Promise<OfflineGrant>} - Verified grant payload.
|
|
59
|
+
*/
|
|
60
|
+
export async function verifyOfflineGrant({ now = new Date(), signedGrant, signingKeys }) {
|
|
61
|
+
const normalizedSignedGrant = normalizeSignedOfflineGrant(signedGrant);
|
|
62
|
+
if (normalizedSignedGrant.algorithm !== OFFLINE_GRANT_SIGNATURE_ALGORITHM) {
|
|
63
|
+
throw new Error(`Unsupported offline grant signature algorithm '${normalizedSignedGrant.algorithm}'`);
|
|
64
|
+
}
|
|
65
|
+
const signingKey = signingKeys
|
|
66
|
+
.map((key) => normalizeOfflineGrantSigningKey(key))
|
|
67
|
+
.find((key) => key.id === normalizedSignedGrant.keyId);
|
|
68
|
+
if (!signingKey)
|
|
69
|
+
throw new Error(`No offline grant signing key for key id '${normalizedSignedGrant.keyId}'`);
|
|
70
|
+
const expectedSignature = await hmacSha256Hex({
|
|
71
|
+
message: offlineGrantSignatureInput(normalizedSignedGrant),
|
|
72
|
+
secret: signingKey.secret
|
|
73
|
+
});
|
|
74
|
+
if (expectedSignature !== normalizedSignedGrant.signature) {
|
|
75
|
+
throw new Error("Offline grant signature did not match");
|
|
76
|
+
}
|
|
77
|
+
if (Number.isNaN(now.getTime()))
|
|
78
|
+
throw new Error("Invalid offline grant verification time");
|
|
79
|
+
if (new Date(normalizedSignedGrant.grant.expiresAt).getTime() <= now.getTime())
|
|
80
|
+
throw new Error("Offline grant expired");
|
|
81
|
+
return normalizedSignedGrant.grant;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Builds a signed grant from bootstrap request inputs.
|
|
85
|
+
* @param {object} args - Arguments.
|
|
86
|
+
* @param {string} args.deviceId - Device id.
|
|
87
|
+
* @param {string | undefined} [args.grantId] - Optional deterministic grant id for tests/custom callers.
|
|
88
|
+
* @param {number | undefined} [args.grantTtlMs] - Grant TTL in milliseconds.
|
|
89
|
+
* @param {Date} args.now - Issue time.
|
|
90
|
+
* @param {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} args.resources - Resource sync manifest.
|
|
91
|
+
* @param {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} args.scopes - Grant scopes.
|
|
92
|
+
* @param {OfflineGrantSigningKey} args.signingKey - Current signing key.
|
|
93
|
+
* @param {string} args.userId - Actor user id.
|
|
94
|
+
* @returns {Promise<SignedOfflineGrant>} - Signed grant.
|
|
95
|
+
*/
|
|
96
|
+
export async function createOfflineGrantFromBootstrap({ deviceId, grantId, grantTtlMs, now, resources, scopes, signingKey, userId }) {
|
|
97
|
+
const issuedAt = isoDateString(now, "issuedAt");
|
|
98
|
+
const ttlMs = grantTtlMs === undefined ? 24 * 60 * 60 * 1000 : grantTtlMs;
|
|
99
|
+
if (!Number.isInteger(ttlMs) || ttlMs <= 0)
|
|
100
|
+
throw new Error("Offline grant TTL must be a positive integer number of milliseconds");
|
|
101
|
+
return await createOfflineGrant({
|
|
102
|
+
grant: {
|
|
103
|
+
deviceId,
|
|
104
|
+
expiresAt: new Date(now.getTime() + ttlMs).toISOString(),
|
|
105
|
+
grantId: grantId || randomGrantId(),
|
|
106
|
+
issuedAt,
|
|
107
|
+
resources,
|
|
108
|
+
scopes,
|
|
109
|
+
userId
|
|
110
|
+
},
|
|
111
|
+
signingKey
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Normalizes signed grant signature input.
|
|
116
|
+
* @param {{algorithm: "HS256", grant: OfflineGrant, keyId: string}} signedGrant - Grant signature fields.
|
|
117
|
+
* @returns {string} - Stable signature input.
|
|
118
|
+
*/
|
|
119
|
+
function offlineGrantSignatureInput(signedGrant) {
|
|
120
|
+
return stableJsonStringify({
|
|
121
|
+
algorithm: signedGrant.algorithm,
|
|
122
|
+
grant: signedGrant.grant,
|
|
123
|
+
keyId: signedGrant.keyId
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Normalizes a signed offline grant envelope.
|
|
128
|
+
* @param {SignedOfflineGrant} signedGrant - Signed grant.
|
|
129
|
+
* @returns {SignedOfflineGrant} - Normalized signed grant.
|
|
130
|
+
*/
|
|
131
|
+
function normalizeSignedOfflineGrant(signedGrant) {
|
|
132
|
+
if (!signedGrant || typeof signedGrant !== "object" || Array.isArray(signedGrant))
|
|
133
|
+
throw new Error("Expected signed offline grant object");
|
|
134
|
+
if (signedGrant.algorithm !== OFFLINE_GRANT_SIGNATURE_ALGORITHM)
|
|
135
|
+
throw new Error(`Unsupported offline grant signature algorithm '${String(signedGrant.algorithm)}'`);
|
|
136
|
+
if (typeof signedGrant.keyId !== "string" || signedGrant.keyId.length < 1)
|
|
137
|
+
throw new Error("Expected offline grant key id");
|
|
138
|
+
if (typeof signedGrant.signature !== "string" || !signedGrant.signature.match(/^hmac-sha256-[a-f0-9]{64}$/))
|
|
139
|
+
throw new Error("Expected offline grant signature");
|
|
140
|
+
return {
|
|
141
|
+
algorithm: signedGrant.algorithm,
|
|
142
|
+
grant: normalizeOfflineGrant(signedGrant.grant),
|
|
143
|
+
keyId: signedGrant.keyId,
|
|
144
|
+
signature: signedGrant.signature
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Normalizes an offline grant payload.
|
|
149
|
+
* @param {OfflineGrant} grant - Grant payload.
|
|
150
|
+
* @returns {OfflineGrant} - Normalized grant payload.
|
|
151
|
+
*/
|
|
152
|
+
function normalizeOfflineGrant(grant) {
|
|
153
|
+
if (!grant || typeof grant !== "object" || Array.isArray(grant))
|
|
154
|
+
throw new Error("Expected offline grant object");
|
|
155
|
+
return {
|
|
156
|
+
deviceId: requiredString(grant.deviceId, "deviceId"),
|
|
157
|
+
expiresAt: isoDateString(new Date(requiredString(grant.expiresAt, "expiresAt")), "expiresAt"),
|
|
158
|
+
grantId: requiredString(grant.grantId, "grantId"),
|
|
159
|
+
issuedAt: isoDateString(new Date(requiredString(grant.issuedAt, "issuedAt")), "issuedAt"),
|
|
160
|
+
resources: deterministicJsonObject({ label: "resources", value: grant.resources }),
|
|
161
|
+
scopes: deterministicJsonObject({ label: "scopes", value: grant.scopes }),
|
|
162
|
+
userId: requiredString(grant.userId, "userId")
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Normalizes an offline grant signing key.
|
|
167
|
+
* @param {OfflineGrantSigningKey} signingKey - Signing key.
|
|
168
|
+
* @returns {OfflineGrantSigningKey} - Normalized signing key.
|
|
169
|
+
*/
|
|
170
|
+
export function normalizeOfflineGrantSigningKey(signingKey) {
|
|
171
|
+
if (!signingKey || typeof signingKey !== "object" || Array.isArray(signingKey))
|
|
172
|
+
throw new Error("Expected offline grant signing key object");
|
|
173
|
+
return {
|
|
174
|
+
current: signingKey.current === true,
|
|
175
|
+
id: requiredString(signingKey.id, "signingKey.id"),
|
|
176
|
+
secret: requiredString(signingKey.secret, "signingKey.secret")
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Returns the current key used to sign new grants.
|
|
181
|
+
* @param {OfflineGrantSigningKey[]} signingKeys - Configured signing keys.
|
|
182
|
+
* @returns {OfflineGrantSigningKey} - Current signing key.
|
|
183
|
+
*/
|
|
184
|
+
export function currentOfflineGrantSigningKey(signingKeys) {
|
|
185
|
+
const normalizedKeys = signingKeys.map((key) => normalizeOfflineGrantSigningKey(key));
|
|
186
|
+
const currentKeys = normalizedKeys.filter((key) => key.current === true);
|
|
187
|
+
if (normalizedKeys.length < 1)
|
|
188
|
+
throw new Error("At least one offline grant signing key is required");
|
|
189
|
+
if (currentKeys.length > 1)
|
|
190
|
+
throw new Error("Only one offline grant signing key can be current");
|
|
191
|
+
return currentKeys[0] || normalizedKeys[0];
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Signs a message using HMAC-SHA256 and returns a prefixed hex signature.
|
|
195
|
+
* @param {object} args - Arguments.
|
|
196
|
+
* @param {string} args.message - Message to sign.
|
|
197
|
+
* @param {string} args.secret - HMAC secret.
|
|
198
|
+
* @returns {Promise<string>} - Prefixed hex signature.
|
|
199
|
+
*/
|
|
200
|
+
async function hmacSha256Hex({ message, secret }) {
|
|
201
|
+
const cryptoProvider = globalThis.crypto;
|
|
202
|
+
if (!cryptoProvider?.subtle)
|
|
203
|
+
throw new Error("WebCrypto subtle API is required for offline grant signing");
|
|
204
|
+
const key = await cryptoProvider.subtle.importKey("raw", new TextEncoder().encode(secret), { hash: "SHA-256", name: "HMAC" }, false, ["sign"]);
|
|
205
|
+
const signature = await cryptoProvider.subtle.sign("HMAC", key, new TextEncoder().encode(message));
|
|
206
|
+
return `${OFFLINE_GRANT_SIGNATURE_PREFIX}${hex(new Uint8Array(signature))}`;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Converts bytes to lower-case hex.
|
|
210
|
+
* @param {Uint8Array} bytes - Bytes.
|
|
211
|
+
* @returns {string} - Hex string.
|
|
212
|
+
*/
|
|
213
|
+
function hex(bytes) {
|
|
214
|
+
return Array.from(bytes).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Requires a non-empty string field.
|
|
218
|
+
* @param {unknown} value - Value.
|
|
219
|
+
* @param {string} name - Field name.
|
|
220
|
+
* @returns {string} - String value.
|
|
221
|
+
*/
|
|
222
|
+
function requiredString(value, name) {
|
|
223
|
+
if (typeof value !== "string" || value.length < 1)
|
|
224
|
+
throw new Error(`Expected offline grant ${name}`);
|
|
225
|
+
return value;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Normalizes a Date to an ISO timestamp.
|
|
229
|
+
* @param {Date} date - Date value.
|
|
230
|
+
* @param {string} label - Field label.
|
|
231
|
+
* @returns {string} - ISO timestamp.
|
|
232
|
+
*/
|
|
233
|
+
function isoDateString(date, label) {
|
|
234
|
+
if (Number.isNaN(date.getTime()))
|
|
235
|
+
throw new Error(`Invalid offline grant ${label}`);
|
|
236
|
+
return date.toISOString();
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Generates a fallback random grant id.
|
|
240
|
+
* @returns {string} - Grant id.
|
|
241
|
+
*/
|
|
242
|
+
function randomGrantId() {
|
|
243
|
+
return globalThis.crypto?.randomUUID ? globalThis.crypto.randomUUID() : `grant-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Stable JSON stringifier with sorted object keys.
|
|
247
|
+
* @param {unknown} value - Value.
|
|
248
|
+
* @returns {string} - JSON string.
|
|
249
|
+
*/
|
|
250
|
+
function stableJsonStringify(value) {
|
|
251
|
+
return JSON.stringify(deterministicJson({ label: "root", value }));
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Normalizes a value as a JSON object.
|
|
255
|
+
* @param {object} args - Arguments.
|
|
256
|
+
* @param {string} args.label - Diagnostic label.
|
|
257
|
+
* @param {unknown} args.value - Value.
|
|
258
|
+
* @returns {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} - JSON object.
|
|
259
|
+
*/
|
|
260
|
+
function deterministicJsonObject({ label, value }) {
|
|
261
|
+
const normalized = deterministicJson({ label, value });
|
|
262
|
+
if (!normalized || typeof normalized !== "object" || Array.isArray(normalized))
|
|
263
|
+
throw new Error(`Expected offline grant ${label} object`);
|
|
264
|
+
return /** @type {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} */ (normalized);
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Normalizes deterministic JSON with sorted object keys.
|
|
268
|
+
* @param {object} args - Arguments.
|
|
269
|
+
* @param {string} args.label - Diagnostic label.
|
|
270
|
+
* @param {unknown} args.value - Value.
|
|
271
|
+
* @returns {import("../configuration-types.js").FrontendModelSyncJsonValue} - Normalized JSON value.
|
|
272
|
+
*/
|
|
273
|
+
function deterministicJson({ label, value }) {
|
|
274
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean")
|
|
275
|
+
return value;
|
|
276
|
+
if (Array.isArray(value)) {
|
|
277
|
+
return value.map((entry, index) => deterministicJson({ label: `${label}/${index}`, value: entry }));
|
|
278
|
+
}
|
|
279
|
+
if (value && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
|
|
280
|
+
/** @type {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} */
|
|
281
|
+
const normalized = {};
|
|
282
|
+
for (const key of Object.keys(value).sort()) {
|
|
283
|
+
const childValue = /** @type {Record<string, unknown>} */ (value)[key];
|
|
284
|
+
if (childValue === undefined)
|
|
285
|
+
continue;
|
|
286
|
+
normalized[key] = deterministicJson({ label: `${label}/${key}`, value: childValue });
|
|
287
|
+
}
|
|
288
|
+
return normalized;
|
|
289
|
+
}
|
|
290
|
+
throw new Error(`Offline grant ${label} must be deterministic JSON`);
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib2ZmbGluZS1ncmFudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zeW5jL29mZmxpbmUtZ3JhbnQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE1BQU0saUNBQWlDLEdBQUcsT0FBTyxDQUFBO0FBQ2pELE1BQU0sOEJBQThCLEdBQUcsY0FBYyxDQUFBO0FBRXJEOzs7Ozs7O0dBT0c7QUFFSDs7Ozs7Ozs7OztHQVVHO0FBRUg7Ozs7OztHQU1HO0FBRUg7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxrQkFBa0IsQ0FBQyxFQUFDLEtBQUssRUFBRSxVQUFVLEVBQUM7SUFDMUQsTUFBTSxlQUFlLEdBQUcscUJBQXFCLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDcEQsTUFBTSxvQkFBb0IsR0FBRywrQkFBK0IsQ0FBQyxVQUFVLENBQUMsQ0FBQTtJQUN4RSxNQUFNLGNBQWMsR0FBRywwQkFBMEIsQ0FBQztRQUNoRCxTQUFTLEVBQUUsaUNBQWlDO1FBQzVDLEtBQUssRUFBRSxlQUFlO1FBQ3RCLEtBQUssRUFBRSxvQkFBb0IsQ0FBQyxFQUFFO0tBQy9CLENBQUMsQ0FBQTtJQUVGLE9BQU87UUFDTCxTQUFTLEVBQUUsaUNBQWlDO1FBQzVDLEtBQUssRUFBRSxlQUFlO1FBQ3RCLEtBQUssRUFBRSxvQkFBb0IsQ0FBQyxFQUFFO1FBQzlCLFNBQVMsRUFBRSxNQUFNLGFBQWEsQ0FBQyxFQUFDLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLG9CQUFvQixDQUFDLE1BQU0sRUFBQyxDQUFDO0tBQy9GLENBQUE7QUFDSCxDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsa0JBQWtCLENBQUMsRUFBQyxHQUFHLEdBQUcsSUFBSSxJQUFJLEVBQUUsRUFBRSxXQUFXLEVBQUUsV0FBVyxFQUFDO0lBQ25GLE1BQU0scUJBQXFCLEdBQUcsMkJBQTJCLENBQUMsV0FB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QUFJLEtBQUssRUFBRSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUMsQ0FBQyxDQUFDLENBQUE7SUFDbkcsQ0FBQztJQUVELElBQUksS0FBSyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxNQUFNLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxLQUFLLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUM1Riw2RkFBNkY7UUFDN0YsTUFBTSxVQUFVLEdBQUcsRUFBRSxDQUFBO1FBRXJCLEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDO1lBQzVDLE1BQU0sVUFBVSxHQUFHLHNDQUFzQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUE7WUFFdEUsSUFBSSxVQUFVLEtBQUssU0FBUztnQkFBRSxTQUFRO1lBQ3RDLFVBQVUsQ0FBQyxHQUFHLENBQUMsR0FBRyxpQkFBaUIsQ0FBQyxFQUFDLEtBQUssRUFBRSxHQUFHLEtBQUssSUFBSSxHQUFHLEVBQUUsRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFDLENBQUMsQ0FBQTtRQUNwRixDQUFDO1FBRUQsT0FBTyxVQUFVLENBQUE7SUFDbkIsQ0FBQztJQUVELE1BQU0sSUFBSSxLQUFLLENBQUMsaUJBQWlCLEtBQUssNkJBQTZCLENBQUMsQ0FBQTtBQUN0RSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmNvbnN0IE9GRkxJTkVfR1JBTlRfU0lHTkFUVVJFX0FMR09SSVRITSA9IFwiSFMyNTZcIlxuY29uc3QgT0ZGTElORV9HUkFOVF9TSUdOQVRVUkVfUFJFRklYID0gXCJobWFjLXNoYTI1Ni1cIlxuXG4vKipcbiAqIFNpZ25lZCBvZmZsaW5lIGdyYW50IGVudmVsb3BlLlxuICogQHR5cGVkZWYge29iamVjdH0gU2lnbmVkT2ZmbGluZUdyYW50XG4gKiBAcHJvcGVydHkge1wiSFMyNTZcIn0gYWxnb3JpdGhtIC0gU2lnbmF0dXJlIGFsZ29yaXRobS5cbiAqIEBwcm9wZXJ0eSB7T2ZmbGluZUdyYW50fSBncmFudCAtIFNpZ25lZCBncmFudCBwYXlsb2FkLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IGtleUlkIC0gU2lnbmluZyBrZXkgaWQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gc2lnbmF0dXJlIC0gSGV4IEhNQUMgc2lnbmF0dXJlIHdpdGggYSBobWFjLXNoYTI1NiBwcmVmaXguXG4gKi9cblxuLyoqXG4gKiBCYWNrZW5kLWlzc3VlZCBvZmZsaW5lIGdyYW50IHBheWxvYWQuXG4gKiBAdHlwZWRlZiB7b2JqZWN0fSBPZmZsaW5lR3JhbnRcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBkZXZpY2VJZCAtIERldmljZSBpZCBhbGxvd2VkIHRvIHVzZSB0aGUgZ3JhbnQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gZXhwaXJlc0F0IC0gSVNPIHRpbWVzdGFtcCBhZnRlciB3aGljaCByZXBsYXkgbXVzdCByZWplY3QgdGhlIGdyYW50LlxuICogQHByb3BlcnR5IHtzdHJpbmd9IGdyYW50SWQgLSBTdGFibGUgZ3JhbnQgaWQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gaXNzdWVkQXQgLSBJU08gdGltZXN0YW1wIHdoZW4gdGhlIGJhY2tlbmQgaXNzdWVkIHRoZSBncmFudC5cbiAqIEBwcm9wZXJ0eSB7UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5Gcm9udGVuZE1vZGVsU3luY0pzb25WYWx1ZT59IHJlc291cmNlcyAtIFN5bmMgbWFuaWZlc3QvbWF0ZXJpYWxpemVkIHJlc291cmNlIG1ldGFkYXRhLlxuICogQHByb3BlcnR5IHtSZWNvcmQ8c3RyaW5nLCBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkZyb250ZW5kTW9kZWxTeW5jSnNvblZhbHVlPn0gc2NvcGVzIC0gTWF0ZXJpYWxpemVkIGdyYW50IHNjb3Blcy5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSB1c2VySWQgLSBBY3RvciB1c2VyIGlkIGFsbG93ZWQgdG8gdXNlIHRoZSBncmFudC5cbiAqL1xuXG4vKipcbiAqIE9mZmxpbmUgZ3JhbnQgc2lnbmluZyBrZXkuXG4gKiBAdHlwZWRlZiB7b2JqZWN0fSBPZmZsaW5lR3JhbnRTaWduaW5nS2V5XG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IFtjdXJyZW50XSAtIFdoZXRoZXIgdGhpcyBpcyB0aGUgYWN0aXZlIGtleSBmb3IgbmV3IGdyYW50cy5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBpZCAtIFB1YmxpYyBrZXkgaWQgaW5jbHVkZWQgaW4gc2lnbmVkIGdyYW50IGVudmVsb3Blcy5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBzZWNyZXQgLSBQcml2YXRlIEhNQUMgc2VjcmV0LiBOZXZlciBleHBvc2UgdGhpcyB0byBjbGllbnRzLlxuICovXG5cbi8qKlxuICogQ3JlYXRlcyBhIHNpZ25lZCBvZmZsaW5lIGdyYW50IGVudmVsb3BlLlxuICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBBcmd1bWVudHMuXG4gKiBAcGFyYW0ge09mZmxpbmVHcmFudH0gYXJncy5ncmFudCAtIEdyYW50IHBheWxvYWQuXG4gKiBAcGFyYW0ge09mZmxpbmVHcmFudFNpZ25pbmdLZXl9IGFyZ3Muc2lnbmluZ0tleSAtIEN1cnJlbnQgc2lnbmluZyBrZXkuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxTaWduZWRPZmZsaW5lR3JhbnQ+fSAtIFNpZ25lZCBncmFudCBlbnZlbG9wZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZU9mZmxpbmVHcmFudCh7Z3JhbnQsIHNpZ25pbmdLZXl9KSB7XG4gIGNvbnN0IG5vcm1hbGl6ZWRHcmFudCA9IG5vcm1hbGl6ZU9mZmxpbmVHcmFudChncmFudClcbiAgY29uc3Qgbm9ybWFsaXplZFNpZ25pbmdLZXkgPSBub3JtYWxpemVPZmZsaW5lR3JhbnRTaWduaW5nS2V5KHNpZ25pbmdLZXkpXG4gIGNvbnN0IHNpZ25hdHVyZUlucHV0ID0gb2ZmbGluZUdyYW50U2lnbmF0dXJlSW5wdXQoe1xuICAgIGFsZ29yaXRobTogT0ZGTElORV9HUkFOVF9TSUdOQVRVUkVfQUxHT1JJVEhNLFxuICAgIGdyYW50OiBub3JtYWxpemVkR3JhbnQsXG4gICAga2V5SWQ6IG5vcm1hbGl6ZWRTaWduaW5nS2V5LmlkXG4gIH0pXG5cbiAgcmV0dXJuIHtcbiAgICBhbGdvcml0aG06IE9GRkxJTkVfR1JBTlRfU0lHTkFUVVJFX0FMR09SSVRITSxcbiAgICBncmFudDogbm9ybWFsaXplZEdyYW50LFxuICAgIGtleUlkOiBub3JtYWxpemVkU2lnbmluZ0tleS5pZCxcbiAgICBzaWduYXR1cmU6IGF3YWl0IGhtYWNTaGEyNTZIZXgoe21lc3NhZ2U6IHNpZ25hdHVyZUlucHV0LCBzZWNyZXQ6IG5vcm1hbGl6ZWRTaWduaW5nS2V5LnNlY3JldH0pXG4gIH1cbn1cblxuLyoqXG4gKiBWZXJpZmllcyBhIHNpZ25lZCBvZmZsaW5lIGdyYW50IGFuZCByZXR1cm5zIHRoZSB0cnVzdGVkIGdyYW50IHBheWxvYWQuXG4gKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIEFyZ3VtZW50cy5cbiAqIEBwYXJhbSB7RGF0ZX0gW2FyZ3Mubm93XSAtIFZlcmlmaWNhdGlvbiB0aW1lLiBEZWZhdWx0cyB0byBjdXJyZW50IHRpbWUuXG4gKiBAcGFyYW0ge1NpZ25lZE9mZmxpbmVHcmFudH0gYXJncy5zaWduZWRHcmFudCAtIFNpZ25lZCBncmFudCBlbnZlbG9wZS5cbiAqIEBwYXJhbSB7T2ZmbGluZUdyYW50U2lnbmluZ0tleVtdfSBhcmdzLnNpZ25pbmdLZXlzIC0gQ2FuZGlkYXRlIHZlcmlmaWNhdGlvbiBrZXlzLlxuICogQHJldHVybnMge1Byb21pc2U8T2ZmbGluZUdyYW50Pn0gLSBWZXJpZmllZCBncmFudCBwYXlsb2FkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdmVyaWZ5T2ZmbGluZUdyYW50KHtub3cgPSBuZXcgRGF0ZSgpLCBzaWduZWRHcmFudCwgc2lnbmluZ0tleXN9KSB7XG4gIGNvbnN0IG5vcm1hbGl6ZWRTaWduZWRHcmFudCA9IG5vcm1hbGl6ZVNpZ25lZE9mZmxpbmVHcmFudChzaWduZWRHcmFudClcblxuICBpZiAobm9ybWFsaXplZFNpZ25lZEdyYW50LmFsZ29yaXRobSAhPT0gT0ZGTElORV9HUkFOVF9TSUdOQVRVUkVfQUxHT1JJVEhNKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBvZmZsaW5lIGdyYW50IHNpZ25hdHVyZSBhbGdvcml0aG0gJyR7bm9ybWFsaXplZFNpZ25lZEdyYW50LmFsZ29yaXRobX0nYClcbiAgfVxuXG4gIGNvbnN0IHNpZ25pbmdLZXkgPSBzaWduaW5nS2V5c1xuICAgIC5tYXAoKGtleSkgPT4gbm9ybWFsaXplT2ZmbGluZUdyYW50U2lnbmluZ0tleShrZXkpKVxuICAgIC5maW5kKChrZXkpID0+IGtleS5pZCA9PT0gbm9ybWFsaXplZFNpZ25lZEdyYW50LmtleUlkKVxuXG4gIGlmICghc2lnbmluZ0tleSkgdGhyb3cgbmV3IEVycm9yKGBObyBvZmZsaW5lIGdyYW50IHNpZ25pbmcga2V5IGZvciBrZXkgaWQgJyR7bm9ybWFsaXplZFNpZ25lZEdyYW50LmtleUlkfSdgKVxuXG4gIGNvbnN0IGV4cGVjdGVkU2lnbmF0dXJlID0gYXdhaXQgaG1hY1NoYTI1NkhleCh7XG4gICAgbWVzc2FnZTogb2ZmbGluZUdyYW50U2lnbmF0dXJlSW5wdXQobm9ybWFsaXplZFNpZ25lZEdyYW50KSxcbiAgICBzZWNyZXQ6IHNpZ25pbmdLZXkuc2VjcmV0XG4gIH0pXG5cbiAgaWYgKGV4cGVjdGVkU2lnbmF0dXJlICE9PSBub3JtYWxpemVkU2lnbmVkR3JhbnQuc2lnbmF0dXJlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiT2ZmbGluZSBncmFudCBzaWduYXR1cmUgZGlkIG5vdCBtYXRjaFwiKVxuICB9XG5cbiAgaWYgKE51bWJlci5pc05hTihub3cuZ2V0VGltZSgpKSkgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBvZmZsaW5lIGdyYW50IHZlcmlmaWNhdGlvbiB0aW1lXCIpXG4gIGlmIChuZXcgRGF0ZShub3JtYWxpemVkU2lnbmVkR3JhbnQuZ3JhbnQuZXhwaXJlc0F0KS5nZXRUaW1lKCkgPD0gbm93LmdldFRpbWUoKSkgdGhyb3cgbmV3IEVycm9yKFwiT2ZmbGluZSBncmFudCBleHBpcmVkXCIpXG5cbiAgcmV0dXJuIG5vcm1hbGl6ZWRTaWduZWRHcmFudC5ncmFudFxufVxuXG4vKipcbiAqIEJ1aWxkcyBhIHNpZ25lZCBncmFudCBmcm9tIGJvb3RzdHJhcCByZXF1ZXN0IGlucHV0cy5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gQXJndW1lbnRzLlxuICogQHBhcmFtIHtzdHJpbmd9IGFyZ3MuZGV2aWNlSWQgLSBEZXZpY2UgaWQuXG4gKiBAcGFyYW0ge3N0cmluZyB8IHVuZGVmaW5lZH0gW2FyZ3MuZ3JhbnRJZF0gLSBPcHRpb25hbCBkZXRlcm1pbmlzdGljIGdyYW50IGlkIGZvciB0ZXN0cy9jdXN0b20gY2FsbGVycy5cbiAqIEBwYXJhbSB7bnVtYmVyIHwgdW5kZWZpbmVkfSBbYXJncy5ncmFudFR0bE1zXSAtIEdyYW50IFRUTCBpbiBtaWxsaXNlY29uZHMuXG4gKiBAcGFyYW0ge0RhdGV9IGFyZ3Mubm93IC0gSXNzdWUgdGltZS5cbiAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5Gcm9udGVuZE1vZGVsU3luY0pzb25WYWx1ZT59IGFyZ3MucmVzb3VyY2VzIC0gUmVzb3VyY2Ugc3luYyBtYW5pZmVzdC5cbiAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5Gcm9udGVuZE1vZGVsU3luY0pzb25WYWx1ZT59IGFyZ3Muc2NvcGVzIC0gR3JhbnQgc2NvcGVzLlxuICogQHBhcmFtIHtPZmZsaW5lR3JhbnRTaWduaW5nS2V5fSBhcmdzLnNpZ25pbmdLZXkgLSBDdXJyZW50IHNpZ25pbmcga2V5LlxuICogQHBhcmFtIHtzdHJpbmd9IGFyZ3MudXNlcklkIC0gQWN0b3IgdXNlciBpZC5cbiAqIEByZXR1cm5zIHtQcm9taXNlPFNpZ25lZE9mZmxpbmVHcmFudD59IC0gU2lnbmVkIGdyYW50LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlT2ZmbGluZUdyYW50RnJvbUJvb3RzdHJhcCh7ZGV2aWNlSWQsIGdyYW50SWQsIGdyYW50VHRsTXMsIG5vdywgcmVzb3VyY2VzLCBzY29wZXMsIHNpZ25pbmdLZXksIHVzZXJJZH0pIHtcbiAgY29uc3QgaXNzdWVkQXQgPSBpc29EYXRlU3RyaW5nKG5vdywgXCJpc3N1ZWRBdFwiKVxuICBjb25zdCB0dGxNcyA9IGdyYW50VHRsTXMgPT09IHVuZGVmaW5lZCA/IDI0ICogNjAgKiA2MCAqIDEwMDAgOiBncmFudFR0bE1zXG5cbiAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHR0bE1zKSB8fCB0dGxNcyA8PSAwKSB0aHJvdyBuZXcgRXJyb3IoXCJPZmZsaW5lIGdyYW50IFRUTCBtdXN0IGJlIGEgcG9zaXRpdmUgaW50ZWdlciBudW1iZXIgb2YgbWlsbGlzZWNvbmRzXCIpXG5cbiAgcmV0dXJuIGF3YWl0IGNyZWF0ZU9mZmxpbmVHcmFudCh7XG4gICAgZ3JhbnQ6IHtcbiAgICAgIGRldmljZUlkLFxuICAgICAgZXhwaXJlc0F0OiBuZXcgRGF0ZShub3cuZ2V0VGltZSgpICsgdHRsTXMpLnRvSVNPU3RyaW5nKCksXG4gICAgICBncmFudElkOiBncmFudElkIHx8IHJhbmRvbUdyYW50SWQoKSxcbiAgICAgIGlzc3VlZEF0LFxuICAgICAgcmVzb3VyY2VzLFxuICAgICAgc2NvcGVzLFxuICAgICAgdXNlcklkXG4gICAgfSxcbiAgICBzaWduaW5nS2V5XG4gIH0pXG59XG5cbi8qKlxuICogTm9ybWFsaXplcyBzaWduZWQgZ3JhbnQgc2lnbmF0dXJlIGlucHV0LlxuICogQHBhcmFtIHt7YWxnb3JpdGhtOiBcIkhTMjU2XCIsIGdyYW50OiBPZmZsaW5lR3JhbnQsIGtleUlkOiBzdHJpbmd9fSBzaWduZWRHcmFudCAtIEdyYW50IHNpZ25hdHVyZSBmaWVsZHMuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFN0YWJsZSBzaWduYXR1cmUgaW5wdXQuXG4gKi9cbmZ1bmN0aW9uIG9mZmxpbmVHcmFudFNpZ25hdHVyZUlucHV0KHNpZ25lZEdyYW50KSB7XG4gIHJldHVybiBzdGFibGVKc29uU3RyaW5naWZ5KHtcbiAgICBhbGdvcml0aG06IHNpZ25lZEdyYW50LmFsZ29yaXRobSxcbiAgICBncmFudDogc2lnbmVkR3JhbnQuZ3JhbnQsXG4gICAga2V5SWQ6IHNpZ25lZEdyYW50LmtleUlkXG4gIH0pXG59XG5cbi8qKlxuICogTm9ybWFsaXplcyBhIHNpZ25lZCBvZmZsaW5lIGdyYW50IGVudmVsb3BlLlxuICogQHBhcmFtIHtTaWduZWRPZmZsaW5lR3JhbnR9IHNpZ25lZEdyYW50IC0gU2lnbmVkIGdyYW50LlxuICogQHJldHVybnMge1NpZ25lZE9mZmxpbmVHcmFudH0gLSBOb3JtYWxpemVkIHNpZ25lZCBncmFudC5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplU2lnbmVkT2ZmbGluZUdyYW50KHNpZ25lZEdyYW50KSB7XG4gIGlmICghc2lnbmVkR3JhbnQgfHwgdHlwZW9mIHNpZ25lZEdyYW50ICE9PSBcIm9iamVjdFwiIHx8IEFycmF5LmlzQXJyYXkoc2lnbmVkR3JhbnQpKSB0aHJvdyBuZXcgRXJyb3IoXCJFeHBlY3RlZCBzaWduZWQgb2ZmbGluZSBncmFudCBvYmplY3RcIilcbiAgaWYgKHNpZ25lZEdyYW50LmFsZ29yaXRobSAhPT0gT0ZGTElORV9HUkFOVF9TSUdOQVRVUkVfQUxHT1JJVEhNKSB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIG9mZmxpbmUgZ3JhbnQgc2lnbmF0dXJlIGFsZ29yaXRobSAnJHtTdHJpbmcoc2lnbmVkR3JhbnQuYWxnb3JpdGhtKX0nYClcbiAgaWYgKHR5cGVvZiBzaWduZWRHcmFudC5rZXlJZCAhPT0gXCJzdHJpbmdcIiB8fCBzaWduZWRHcmFudC5rZXlJZC5sZW5ndGggPCAxKSB0aHJvdyBuZXcgRXJyb3IoXCJFeHBlY3RlZCBvZmZsaW5lIGdyYW50IGtleSBpZFwiKVxuICBpZiAodHlwZW9mIHNpZ25lZEdyYW50LnNpZ25hdHVyZSAhPT0gXCJzdHJpbmdcIiB8fCAhc2lnbmVkR3JhbnQuc2lnbmF0dXJlLm1hdGNoKC9eaG1hYy1zaGEyNTYtW2EtZjAtOV17NjR9JC8pKSB0aHJvdyBuZXcgRXJyb3IoXCJFeHBlY3RlZCBvZmZsaW5lIGdyYW50IHNpZ25hdHVyZVwiKVxuXG4gIHJldHVybiB7XG4gICAgYWxnb3JpdGhtOiBzaWduZWRHcmFudC5hbGdvcml0aG0sXG4gICAgZ3JhbnQ6IG5vcm1hbGl6ZU9mZmxpbmVHcmFudChzaWduZWRHcmFudC5ncmFudCksXG4gICAga2V5SWQ6IHNpZ25lZEdyYW50LmtleUlkLFxuICAgIHNpZ25hdHVyZTogc2lnbmVkR3JhbnQuc2lnbmF0dXJlXG4gIH1cbn1cblxuLyoqXG4gKiBOb3JtYWxpemVzIGFuIG9mZmxpbmUgZ3JhbnQgcGF5bG9hZC5cbiAqIEBwYXJhbSB7T2ZmbGluZUdyYW50fSBncmFudCAtIEdyYW50IHBheWxvYWQuXG4gKiBAcmV0dXJucyB7T2ZmbGluZUdyYW50fSAtIE5vcm1hbGl6ZWQgZ3JhbnQgcGF5bG9hZC5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplT2ZmbGluZUdyYW50KGdyYW50KSB7XG4gIGlmICghZ3JhbnQgfHwgdHlwZW9mIGdyYW50ICE9PSBcIm9iamVjdFwiIHx8IEFycmF5LmlzQXJyYXkoZ3JhbnQpKSB0aHJvdyBuZXcgRXJyb3IoXCJFeHBlY3RlZCBvZmZsaW5lIGdyYW50IG9iamVjdFwiKVxuXG4gIHJldHVybiB7XG4gICAgZGV2aWNlSWQ6IHJlcXVpcmVkU3RyaW5nKGdyYW50LmRldmljZUlkLCBcImRldmljZUlkXCIpLFxuICAgIGV4cGlyZXNBdDogaXNvRGF0ZVN0cmluZyhuZXcgRGF0ZShyZXF1aXJlZFN0cmluZyhncmFudC5leHBpcmVzQXQsIFwiZXhwaXJlc0F0XCIpKSwgXCJleHBpcmVzQXRcIiksXG4gICAgZ3JhbnRJZDogcmVxdWlyZWRTdHJpbmcoZ3JhbnQuZ3JhbnRJZCwgXCJncmFudElkXCIpLFxuICAgIGlzc3VlZEF0OiBpc29EYXRlU3RyaW5nKG5ldyBEYXRlKHJlcXVpcmVkU3RyaW5nKGdyYW50Lmlzc3VlZEF0LCBcImlzc3VlZEF0XCIpKSwgXCJpc3N1ZWRBdFwiKSxcbiAgICByZXNvdXJjZXM6IGRldGVybWluaXN0aWNKc29uT2JqZWN0KHtsYWJlbDogXCJyZXNvdXJjZXNcIiwgdmFsdWU6IGdyYW50LnJlc291cmNlc30pLFxuICAgIHNjb3BlczogZGV0ZXJtaW5pc3RpY0pzb25PYmplY3Qoe2xhYmVsOiBcInNjb3Blc1wiLCB2YWx1ZTogZ3JhbnQuc2NvcGVzfSksXG4gICAgdXNlcklkOiByZXF1aXJlZFN0cmluZyhncmFudC51c2VySWQsIFwidXNlcklkXCIpXG4gIH1cbn1cblxuLyoqXG4gKiBOb3JtYWxpemVzIGFuIG9mZmxpbmUgZ3JhbnQgc2lnbmluZyBrZXkuXG4gKiBAcGFyYW0ge09mZmxpbmVHcmFudFNpZ25pbmdLZXl9IHNpZ25pbmdLZXkgLSBTaWduaW5nIGtleS5cbiAqIEByZXR1cm5zIHtPZmZsaW5lR3JhbnRTaWduaW5nS2V5fSAtIE5vcm1hbGl6ZWQgc2lnbmluZyBrZXkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVPZmZsaW5lR3JhbnRTaWduaW5nS2V5KHNpZ25pbmdLZXkpIHtcbiAgaWYgKCFzaWduaW5nS2V5IHx8IHR5cGVvZiBzaWduaW5nS2V5ICE9PSBcIm9iamVjdFwiIHx8IEFycmF5LmlzQXJyYXkoc2lnbmluZ0tleSkpIHRocm93IG5ldyBFcnJvcihcIkV4cGVjdGVkIG9mZmxpbmUgZ3JhbnQgc2lnbmluZyBrZXkgb2JqZWN0XCIpXG5cbiAgcmV0dXJuIHtcbiAgICBjdXJyZW50OiBzaWduaW5nS2V5LmN1cnJlbnQgPT09IHRydWUsXG4gICAgaWQ6IHJlcXVpcmVkU3RyaW5nKHNpZ25pbmdLZXkuaWQsIFwic2lnbmluZ0tleS5pZFwiKSxcbiAgICBzZWNyZXQ6IHJlcXVpcmVkU3RyaW5nKHNpZ25pbmdLZXkuc2VjcmV0LCBcInNpZ25pbmdLZXkuc2VjcmV0XCIpXG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBjdXJyZW50IGtleSB1c2VkIHRvIHNpZ24gbmV3IGdyYW50cy5cbiAqIEBwYXJhbSB7T2ZmbGluZUdyYW50U2lnbmluZ0tleVtdfSBzaWduaW5nS2V5cyAtIENvbmZpZ3VyZWQgc2lnbmluZyBrZXlzLlxuICogQHJldHVybnMge09mZmxpbmVHcmFudFNpZ25pbmdLZXl9IC0gQ3VycmVudCBzaWduaW5nIGtleS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGN1cnJlbnRPZmZsaW5lR3JhbnRTaWduaW5nS2V5KHNpZ25pbmdLZXlzKSB7XG4gIGNvbnN0IG5vcm1hbGl6ZWRLZXlzID0gc2lnbmluZ0tleXMubWFwKChrZXkpID0+IG5vcm1hbGl6ZU9mZmxpbmVHcmFudFNpZ25pbmdLZXkoa2V5KSlcbiAgY29uc3QgY3VycmVudEtleXMgPSBub3JtYWxpemVkS2V5cy5maWx0ZXIoKGtleSkgPT4ga2V5LmN1cnJlbnQgPT09IHRydWUpXG5cbiAgaWYgKG5vcm1hbGl6ZWRLZXlzLmxlbmd0aCA8IDEpIHRocm93IG5ldyBFcnJvcihcIkF0IGxlYXN0IG9uZSBvZmZsaW5lIGdyYW50IHNpZ25pbmcga2V5IGlzIHJlcXVpcmVkXCIpXG4gIGlmIChjdXJyZW50S2V5cy5sZW5ndGggPiAxKSB0aHJvdyBuZXcgRXJyb3IoXCJPbmx5IG9uZSBvZmZsaW5lIGdyYW50IHNpZ25pbmcga2V5IGNhbiBiZSBjdXJyZW50XCIpXG5cbiAgcmV0dXJuIGN1cnJlbnRLZXlzWzBdIHx8IG5vcm1hbGl6ZWRLZXlzWzBdXG59XG5cbi8qKlxuICogU2lnbnMgYSBtZXNzYWdlIHVzaW5nIEhNQUMtU0hBMjU2IGFuZCByZXR1cm5zIGEgcHJlZml4ZWQgaGV4IHNpZ25hdHVyZS5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gQXJndW1lbnRzLlxuICogQHBhcmFtIHtzdHJpbmd9IGFyZ3MubWVzc2FnZSAtIE1lc3NhZ2UgdG8gc2lnbi5cbiAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLnNlY3JldCAtIEhNQUMgc2VjcmV0LlxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gLSBQcmVmaXhlZCBoZXggc2lnbmF0dXJlLlxuICovXG5hc3luYyBmdW5jdGlvbiBobWFjU2hhMjU2SGV4KHttZXNzYWdlLCBzZWNyZXR9KSB7XG4gIGNvbnN0IGNyeXB0b1Byb3ZpZGVyID0gZ2xvYmFsVGhpcy5jcnlwdG9cblxuICBpZiAoIWNyeXB0b1Byb3ZpZGVyPy5zdWJ0bGUpIHRocm93IG5ldyBFcnJvcihcIldlYkNyeXB0byBzdWJ0bGUgQVBJIGlzIHJlcXVpcmVkIGZvciBvZmZsaW5lIGdyYW50IHNpZ25pbmdcIilcblxuICBjb25zdCBrZXkgPSBhd2FpdCBjcnlwdG9Qcm92aWRlci5zdWJ0bGUuaW1wb3J0S2V5KFxuICAgIFwicmF3XCIsXG4gICAgbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKHNlY3JldCksXG4gICAge2hhc2g6IFwiU0hBLTI1NlwiLCBuYW1lOiBcIkhNQUNcIn0sXG4gICAgZmFsc2UsXG4gICAgW1wic2lnblwiXVxuICApXG4gIGNvbnN0IHNpZ25hdHVyZSA9IGF3YWl0IGNyeXB0b1Byb3ZpZGVyLnN1YnRsZS5zaWduKFwiSE1BQ1wiLCBrZXksIG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShtZXNzYWdlKSlcblxuICByZXR1cm4gYCR7T0ZGTElORV9HUkFOVF9TSUdOQVRVUkVfUFJFRklYfSR7aGV4KG5ldyBVaW50OEFycmF5KHNpZ25hdHVyZSkpfWBcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBieXRlcyB0byBsb3dlci1jYXNlIGhleC5cbiAqIEBwYXJhbSB7VWludDhBcnJheX0gYnl0ZXMgLSBCeXRlcy5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gSGV4IHN0cmluZy5cbiAqL1xuZnVuY3Rpb24gaGV4KGJ5dGVzKSB7XG4gIHJldHVybiBBcnJheS5mcm9tKGJ5dGVzKS5tYXAoKGJ5dGUpID0+IGJ5dGUudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDIsIFwiMFwiKSkuam9pbihcIlwiKVxufVxuXG4vKipcbiAqIFJlcXVpcmVzIGEgbm9uLWVtcHR5IHN0cmluZyBmaWVsZC5cbiAqIEBwYXJhbSB7dW5rbm93bn0gdmFsdWUgLSBWYWx1ZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gRmllbGQgbmFtZS5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gU3RyaW5nIHZhbHVlLlxuICovXG5mdW5jdGlvbiByZXF1aXJlZFN0cmluZyh2YWx1ZSwgbmFtZSkge1xuICBpZiAodHlwZW9mIHZhbHVlICE9PSBcInN0cmluZ1wiIHx8IHZhbHVlLmxlbmd0aCA8IDEpIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgb2ZmbGluZSBncmFudCAke25hbWV9YClcblxuICByZXR1cm4gdmFsdWVcbn1cblxuLyoqXG4gKiBOb3JtYWxpemVzIGEgRGF0ZSB0byBhbiBJU08gdGltZXN0YW1wLlxuICogQHBhcmFtIHtEYXRlfSBkYXRlIC0gRGF0ZSB2YWx1ZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBsYWJlbCAtIEZpZWxkIGxhYmVsLlxuICogQHJldHVybnMge3N0cmluZ30gLSBJU08gdGltZXN0YW1wLlxuICovXG5mdW5jdGlvbiBpc29EYXRlU3RyaW5nKGRhdGUsIGxhYmVsKSB7XG4gIGlmIChOdW1iZXIuaXNOYU4oZGF0ZS5nZXRUaW1lKCkpKSB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgb2ZmbGluZSBncmFudCAke2xhYmVsfWApXG5cbiAgcmV0dXJuIGRhdGUudG9JU09TdHJpbmcoKVxufVxuXG4vKipcbiAqIEdlbmVyYXRlcyBhIGZhbGxiYWNrIHJhbmRvbSBncmFudCBpZC5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gR3JhbnQgaWQuXG4gKi9cbmZ1bmN0aW9uIHJhbmRvbUdyYW50SWQoKSB7XG4gIHJldHVybiBnbG9iYWxUaGlzLmNyeXB0bz8ucmFuZG9tVVVJRCA/IGdsb2JhbFRoaXMuY3J5cHRvLnJhbmRvbVVVSUQoKSA6IGBncmFudC0ke0RhdGUubm93KCl9LSR7TWF0aC5yYW5kb20oKS50b1N0cmluZygxNikuc2xpY2UoMil9YFxufVxuXG4vKipcbiAqIFN0YWJsZSBKU09OIHN0cmluZ2lmaWVyIHdpdGggc29ydGVkIG9iamVjdCBrZXlzLlxuICogQHBhcmFtIHt1bmtub3dufSB2YWx1ZSAtIFZhbHVlLlxuICogQHJldHVybnMge3N0cmluZ30gLSBKU09OIHN0cmluZy5cbiAqL1xuZnVuY3Rpb24gc3RhYmxlSnNvblN0cmluZ2lmeSh2YWx1ZSkge1xuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoZGV0ZXJtaW5pc3RpY0pzb24oe2xhYmVsOiBcInJvb3RcIiwgdmFsdWV9KSlcbn1cblxuLyoqXG4gKiBOb3JtYWxpemVzIGEgdmFsdWUgYXMgYSBKU09OIG9iamVjdC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gQXJndW1lbnRzLlxuICogQHBhcmFtIHtzdHJpbmd9IGFyZ3MubGFiZWwgLSBEaWFnbm9zdGljIGxhYmVsLlxuICogQHBhcmFtIHt1bmtub3dufSBhcmdzLnZhbHVlIC0gVmFsdWUuXG4gKiBAcmV0dXJucyB7UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5Gcm9udGVuZE1vZGVsU3luY0pzb25WYWx1ZT59IC0gSlNPTiBvYmplY3QuXG4gKi9cbmZ1bmN0aW9uIGRldGVybWluaXN0aWNKc29uT2JqZWN0KHtsYWJlbCwgdmFsdWV9KSB7XG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSBkZXRlcm1pbmlzdGljSnNvbih7bGFiZWwsIHZhbHVlfSlcblxuICBpZiAoIW5vcm1hbGl6ZWQgfHwgdHlwZW9mIG5vcm1hbGl6ZWQgIT09IFwib2JqZWN0XCIgfHwgQXJyYXkuaXNBcnJheShub3JtYWxpemVkKSkgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBvZmZsaW5lIGdyYW50ICR7bGFiZWx9IG9iamVjdGApXG5cbiAgcmV0dXJuIC8qKiBAdHlwZSB7UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5Gcm9udGVuZE1vZGVsU3luY0pzb25WYWx1ZT59ICovIChub3JtYWxpemVkKVxufVxuXG4vKipcbiAqIE5vcm1hbGl6ZXMgZGV0ZXJtaW5pc3RpYyBKU09OIHdpdGggc29ydGVkIG9iamVjdCBrZXlzLlxuICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBBcmd1bWVudHMuXG4gKiBAcGFyYW0ge3N0cmluZ30gYXJncy5sYWJlbCAtIERpYWdub3N0aWMgbGFiZWwuXG4gKiBAcGFyYW0ge3Vua25vd259IGFyZ3MudmFsdWUgLSBWYWx1ZS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkZyb250ZW5kTW9kZWxTeW5jSnNvblZhbHVlfSAtIE5vcm1hbGl6ZWQgSlNPTiB2YWx1ZS5cbiAqL1xuZnVuY3Rpb24gZGV0ZXJtaW5pc3RpY0pzb24oe2xhYmVsLCB2YWx1ZX0pIHtcbiAgaWYgKHZhbHVlID09PSBudWxsIHx8IHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiB8fCB0eXBlb2YgdmFsdWUgPT09IFwibnVtYmVyXCIgfHwgdHlwZW9mIHZhbHVlID09PSBcImJvb2xlYW5cIikgcmV0dXJuIHZhbHVlXG5cbiAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgcmV0dXJuIHZhbHVlLm1hcCgoZW50cnksIGluZGV4KSA9PiBkZXRlcm1pbmlzdGljSnNvbih7bGFiZWw6IGAke2xhYmVsfS8ke2luZGV4fWAsIHZhbHVlOiBlbnRyeX0pKVxuICB9XG5cbiAgaWYgKHZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIiAmJiBPYmplY3QuZ2V0UHJvdG90eXBlT2YodmFsdWUpID09PSBPYmplY3QucHJvdG90eXBlKSB7XG4gICAgLyoqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkZyb250ZW5kTW9kZWxTeW5jSnNvblZhbHVlPn0gKi9cbiAgICBjb25zdCBub3JtYWxpemVkID0ge31cblxuICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHZhbHVlKS5zb3J0KCkpIHtcbiAgICAgIGNvbnN0IGNoaWxkVmFsdWUgPSAvKiogQHR5cGUge1JlY29yZDxzdHJpbmcsIHVua25vd24+fSAqLyAodmFsdWUpW2tleV1cblxuICAgICAgaWYgKGNoaWxkVmFsdWUgPT09IHVuZGVmaW5lZCkgY29udGludWVcbiAgICAgIG5vcm1hbGl6ZWRba2V5XSA9IGRldGVybWluaXN0aWNKc29uKHtsYWJlbDogYCR7bGFiZWx9LyR7a2V5fWAsIHZhbHVlOiBjaGlsZFZhbHVlfSlcbiAgICB9XG5cbiAgICByZXR1cm4gbm9ybWFsaXplZFxuICB9XG5cbiAgdGhyb3cgbmV3IEVycm9yKGBPZmZsaW5lIGdyYW50ICR7bGFiZWx9IG11c3QgYmUgZGV0ZXJtaW5pc3RpYyBKU09OYClcbn1cbiJdfQ==
|