@tinycloud/node-sdk 3.10.0-beta.3 → 3.11.0-beta.0
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/dist/{TinyCloudNode-BjJJIifr.d.ts → TinyCloudNode-BpolXzu5.d.ts} +59 -2
- package/dist/{TinyCloudNode-BhWBbCay.d.cts → TinyCloudNode-wAQN1Ndh.d.cts} +59 -2
- package/dist/{authority-WCJA3phs.d.cts → authority-C0JKqTwY.d.cts} +1 -1
- package/dist/{authority-BzqKNzOr.d.ts → authority-Cj8MLCkr.d.ts} +1 -1
- package/dist/core.cjs +100 -24
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +2 -2
- package/dist/core.d.ts +2 -2
- package/dist/core.js +101 -24
- package/dist/core.js.map +1 -1
- package/dist/encryption-keys.d.cts +1 -1
- package/dist/encryption-keys.d.ts +1 -1
- package/dist/index.cjs +99 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +100 -23
- package/dist/index.js.map +1 -1
- package/dist/replication/authority.d.cts +2 -2
- package/dist/replication/authority.d.ts +2 -2
- package/package.json +6 -6
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NamedKeyClient } from '@tinycloud/sdk-services/encryption/named-keys';
|
|
2
2
|
export { DecryptManyResult, KeyCallOptions, KeyDescriptor, KeyEncryptOptions, NamedKeyClient, NamedKeyEnvelope, NamedKeyError, NamedKeyErrorCode, PublicKeyDescriptor, buildKeyAdminFacts, buildKeyDescribeFacts } from '@tinycloud/sdk-services/encryption/named-keys';
|
|
3
|
-
import { T as TinyCloudNode } from './TinyCloudNode-
|
|
3
|
+
import { T as TinyCloudNode } from './TinyCloudNode-wAQN1Ndh.cjs';
|
|
4
4
|
import '@tinycloud/sdk-core';
|
|
5
5
|
import '@tinycloud/sdk-services/kv/replication';
|
|
6
6
|
import '@tinycloud/sdk-services';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NamedKeyClient } from '@tinycloud/sdk-services/encryption/named-keys';
|
|
2
2
|
export { DecryptManyResult, KeyCallOptions, KeyDescriptor, KeyEncryptOptions, NamedKeyClient, NamedKeyEnvelope, NamedKeyError, NamedKeyErrorCode, PublicKeyDescriptor, buildKeyAdminFacts, buildKeyDescribeFacts } from '@tinycloud/sdk-services/encryption/named-keys';
|
|
3
|
-
import { T as TinyCloudNode } from './TinyCloudNode-
|
|
3
|
+
import { T as TinyCloudNode } from './TinyCloudNode-BpolXzu5.js';
|
|
4
4
|
import '@tinycloud/sdk-core';
|
|
5
5
|
import '@tinycloud/sdk-services/kv/replication';
|
|
6
6
|
import '@tinycloud/sdk-services';
|
package/dist/index.cjs
CHANGED
|
@@ -18969,6 +18969,16 @@ var MemorySessionStorage = class {
|
|
|
18969
18969
|
};
|
|
18970
18970
|
|
|
18971
18971
|
// src/authorization/NodeUserAuthorization.ts
|
|
18972
|
+
function assertMaxExpiresAt(value) {
|
|
18973
|
+
if (value === void 0 || typeof value === "function") return;
|
|
18974
|
+
const ms = value instanceof Date ? value.getTime() : value;
|
|
18975
|
+
if (typeof ms !== "number" || !Number.isFinite(new Date(ms).getTime())) {
|
|
18976
|
+
throw new Error("maxExpiresAt must be a finite number of epoch milliseconds, a valid Date, or a function returning one");
|
|
18977
|
+
}
|
|
18978
|
+
}
|
|
18979
|
+
function lastAnchoredLine(siwe, pattern) {
|
|
18980
|
+
return [...siwe.matchAll(pattern)].at(-1)?.[1];
|
|
18981
|
+
}
|
|
18972
18982
|
function pkhSpaceIdentity(spaceId) {
|
|
18973
18983
|
const match = /^(tinycloud:pkh:eip155:\d+:)(0x[0-9a-fA-F]{40})(:.+)$/.exec(spaceId);
|
|
18974
18984
|
return match === null ? spaceId : `${match[1]}${match[2].toLowerCase()}${match[3]}`;
|
|
@@ -20261,10 +20271,8 @@ var NodeUserAuthorization = class {
|
|
|
20261
20271
|
siwe: prepared.siwe,
|
|
20262
20272
|
signature: signature2
|
|
20263
20273
|
};
|
|
20264
|
-
const
|
|
20265
|
-
const
|
|
20266
|
-
const expiresAt = expirationMatch?.[1] ?? new Date(Date.now() + this.sessionExpirationMs).toISOString();
|
|
20267
|
-
const createdAt = issuedAtMatch?.[1] ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
20274
|
+
const expiresAt = lastAnchoredLine(prepared.siwe ?? "", /^Expiration Time: (.+)$/gm) ?? new Date(Date.now() + this.sessionExpirationMs).toISOString();
|
|
20275
|
+
const createdAt = lastAnchoredLine(prepared.siwe ?? "", /^Issued At: (.+)$/gm) ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
20268
20276
|
const replicaStamp = await this.establishReplicaStamp?.(tinyCloudSession);
|
|
20269
20277
|
const persistedData = this.persistedData(tinyCloudSession, expiresAt, createdAt, replicaStamp);
|
|
20270
20278
|
await this.sessionStorage.save(address, persistedData);
|
|
@@ -20323,6 +20331,7 @@ var NodeUserAuthorization = class {
|
|
|
20323
20331
|
/** Finish address, host and SIWE preparation before an approval click. */
|
|
20324
20332
|
async prepareOpenKeySignIn(options) {
|
|
20325
20333
|
refuseCaveated(this.getCapabilityRequest()?.manifests);
|
|
20334
|
+
assertMaxExpiresAt(options?.maxExpiresAt);
|
|
20326
20335
|
if (options?.host !== void 0) {
|
|
20327
20336
|
const overrideHost = options.host.trim();
|
|
20328
20337
|
if (!overrideHost) {
|
|
@@ -20343,7 +20352,9 @@ var NodeUserAuthorization = class {
|
|
|
20343
20352
|
verificationMethod: prepared.verificationMethod,
|
|
20344
20353
|
host: hostHint,
|
|
20345
20354
|
keyId: options?.openkeyKeyId,
|
|
20346
|
-
presentation
|
|
20355
|
+
presentation,
|
|
20356
|
+
// Present only when set, so the default request shape is unchanged.
|
|
20357
|
+
...options?.expiryChangeable === true ? { expiryChangeable: true } : {}
|
|
20347
20358
|
};
|
|
20348
20359
|
return {
|
|
20349
20360
|
request: originalRequest,
|
|
@@ -20353,7 +20364,10 @@ var NodeUserAuthorization = class {
|
|
|
20353
20364
|
address,
|
|
20354
20365
|
chainId,
|
|
20355
20366
|
generation: this.sessionGeneration,
|
|
20356
|
-
createdAt: Date.now()
|
|
20367
|
+
createdAt: Date.now(),
|
|
20368
|
+
// Kept in memory with the pending request. It is not part of `request`, so it is never sent to OpenKey, and
|
|
20369
|
+
// nothing here is persisted.
|
|
20370
|
+
...options?.maxExpiresAt === void 0 ? {} : { maxExpiresAt: options.maxExpiresAt }
|
|
20357
20371
|
};
|
|
20358
20372
|
}
|
|
20359
20373
|
/** Complete a prepared approval. The caller starts authorization before awaiting this method. */
|
|
@@ -20371,7 +20385,11 @@ var NodeUserAuthorization = class {
|
|
|
20371
20385
|
for (let attempt = 0; ; ) {
|
|
20372
20386
|
try {
|
|
20373
20387
|
result ?? (result = await authorization);
|
|
20374
|
-
signed2 = await this.verifyOpenKeyResult(result, prepared
|
|
20388
|
+
signed2 = await this.verifyOpenKeyResult(result, prepared, {
|
|
20389
|
+
// Relax only for a request that actually carried the opt-in.
|
|
20390
|
+
allowExpirationChange: originalRequest.expiryChangeable === true,
|
|
20391
|
+
maxExpiresAt: pending.maxExpiresAt
|
|
20392
|
+
});
|
|
20375
20393
|
signature2 = result.signature;
|
|
20376
20394
|
break;
|
|
20377
20395
|
} catch (error) {
|
|
@@ -20463,13 +20481,23 @@ var NodeUserAuthorization = class {
|
|
|
20463
20481
|
* in the original prepared SIWE — narrowing OK, broadening rejected.
|
|
20464
20482
|
* 5. Every `result.selectedActionKeys` entry corresponds to a
|
|
20465
20483
|
* (resource, action) pair in the returned SIWE.
|
|
20484
|
+
*
|
|
20485
|
+
* `options.expiryChangeable` is true only when the request sent to OpenKey
|
|
20486
|
+
* carried `expiryChangeable: true`. Then (and only then) the signed
|
|
20487
|
+
* `Expiration Time` may differ from the prepared one and is the expiry the
|
|
20488
|
+
* session is built with; the changed expiry must pass
|
|
20489
|
+
* `checkChangedExpiration` and every other field in (3) must still match.
|
|
20490
|
+
* Without it, any expiry difference is refused as in (3).
|
|
20466
20491
|
*/
|
|
20467
|
-
async signInWithOpenKeyResult(result, prepared, keyId, jwk) {
|
|
20468
|
-
const signed2 = await this.verifyOpenKeyResult(result, prepared
|
|
20492
|
+
async signInWithOpenKeyResult(result, prepared, keyId, jwk, options) {
|
|
20493
|
+
const signed2 = await this.verifyOpenKeyResult(result, prepared, {
|
|
20494
|
+
allowExpirationChange: options?.expiryChangeable === true,
|
|
20495
|
+
maxExpiresAt: options?.maxExpiresAt
|
|
20496
|
+
});
|
|
20469
20497
|
return this.signInWithPreparedSession(signed2, result.signature, keyId, jwk);
|
|
20470
20498
|
}
|
|
20471
20499
|
/** Validate a candidate without activating a network session, so paste retries reuse one preparation. */
|
|
20472
|
-
async verifyOpenKeyResult(result, prepared) {
|
|
20500
|
+
async verifyOpenKeyResult(result, prepared, options) {
|
|
20473
20501
|
if (result.protocolVersion !== 1) {
|
|
20474
20502
|
throw new Error(`Unsupported OpenKey protocol version ${result.protocolVersion}`);
|
|
20475
20503
|
}
|
|
@@ -20512,16 +20540,39 @@ var NodeUserAuthorization = class {
|
|
|
20512
20540
|
`OpenKey signedMessage.address (${parsedSignedSiwe.address}) does not match local signer address (${expectedAddress})`
|
|
20513
20541
|
);
|
|
20514
20542
|
}
|
|
20543
|
+
const parsedExpiry = parsedSignedSiwe.expirationTime;
|
|
20544
|
+
const lineExpiry = lastAnchoredLine(result.signedMessage, /^Expiration Time: (.+)$/gm);
|
|
20545
|
+
if (parsedExpiry === void 0 || parsedExpiry === null || lineExpiry === void 0) {
|
|
20546
|
+
throw new Error("OpenKey signedMessage has no Expiration Time line of its own");
|
|
20547
|
+
}
|
|
20548
|
+
const parsedExpiryMs = Date.parse(parsedExpiry);
|
|
20549
|
+
if (!Number.isFinite(parsedExpiryMs) || parsedExpiryMs !== Date.parse(lineExpiry)) {
|
|
20550
|
+
throw new Error("OpenKey signedMessage Expiration Time line does not match the message's own expiry");
|
|
20551
|
+
}
|
|
20515
20552
|
const originalHasRecap = /(?:^|\n)-\s+urn:recap:/i.test(prepared.siwe);
|
|
20516
20553
|
const originalFields = (0, import_sdk_core5.extractImmutableSiweFields)(prepared.siwe);
|
|
20517
20554
|
const signedFields = (0, import_sdk_core5.extractImmutableSiweFields)(result.signedMessage);
|
|
20518
|
-
|
|
20519
|
-
|
|
20520
|
-
|
|
20521
|
-
|
|
20522
|
-
|
|
20523
|
-
|
|
20524
|
-
|
|
20555
|
+
if (options?.allowExpirationChange === true) {
|
|
20556
|
+
const maxExpiresAt = typeof options.maxExpiresAt === "function" ? options.maxExpiresAt() : options.maxExpiresAt;
|
|
20557
|
+
const refusal = (0, import_sdk_core5.checkChangedExpiration)({
|
|
20558
|
+
preparedSiwe: prepared.siwe,
|
|
20559
|
+
signedSiwe: result.signedMessage,
|
|
20560
|
+
now: Date.now(),
|
|
20561
|
+
originalHasRecap,
|
|
20562
|
+
...maxExpiresAt === void 0 ? {} : { maxExpiresAt }
|
|
20563
|
+
});
|
|
20564
|
+
if (refusal !== null) {
|
|
20565
|
+
throw new Error(`OpenKey signedMessage ${refusal}`);
|
|
20566
|
+
}
|
|
20567
|
+
} else {
|
|
20568
|
+
const changedFields = (0, import_sdk_core5.diffImmutableSiweFields)(originalFields, signedFields, {
|
|
20569
|
+
originalHasRecap
|
|
20570
|
+
});
|
|
20571
|
+
if (changedFields.length > 0) {
|
|
20572
|
+
throw new Error(
|
|
20573
|
+
`OpenKey signedMessage altered immutable SIWE fields: ${changedFields.join(", ")}`
|
|
20574
|
+
);
|
|
20575
|
+
}
|
|
20525
20576
|
}
|
|
20526
20577
|
let originalCaps;
|
|
20527
20578
|
let signedCaps;
|
|
@@ -22706,14 +22757,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22706
22757
|
await this.signInWith(() => this.auth.signInWithOpenKey(authorizeFn, options));
|
|
22707
22758
|
}
|
|
22708
22759
|
/** Prepare the OpenKey request before the approval click. */
|
|
22709
|
-
async prepareOpenKeySignIn() {
|
|
22760
|
+
async prepareOpenKeySignIn(options) {
|
|
22710
22761
|
if (!this.signer || !this.tc || !this.auth) {
|
|
22711
22762
|
throw new Error("Cannot prepare OpenKey sign-in in session-only mode. Provide a signer in config.");
|
|
22712
22763
|
}
|
|
22713
22764
|
await this.signOutInFlight;
|
|
22714
22765
|
await this.accountRegistryTail;
|
|
22715
22766
|
await this.wasmBindings.ensureInitialized?.();
|
|
22716
|
-
return this.auth.prepareOpenKeySignIn();
|
|
22767
|
+
return this.auth.prepareOpenKeySignIn(options);
|
|
22717
22768
|
}
|
|
22718
22769
|
/** Start OpenKey authorization synchronously, then complete normal session setup. */
|
|
22719
22770
|
signInWithPreparedOpenKey(pending, authorizeFn) {
|
|
@@ -25297,7 +25348,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25297
25348
|
path: "",
|
|
25298
25349
|
// Root access
|
|
25299
25350
|
actions: [...ROOT_DELEGATION_ACTIONS],
|
|
25300
|
-
expiry: this.
|
|
25351
|
+
expiry: this.getSignedSessionExpiry(),
|
|
25301
25352
|
isRevoked: false,
|
|
25302
25353
|
allowSubDelegation: true
|
|
25303
25354
|
};
|
|
@@ -25310,7 +25361,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25310
25361
|
spaceId,
|
|
25311
25362
|
path: "",
|
|
25312
25363
|
actions: [...ROOT_DELEGATION_ACTIONS],
|
|
25313
|
-
expiry: this.
|
|
25364
|
+
expiry: this.getSignedSessionExpiry(),
|
|
25314
25365
|
isRevoked: false,
|
|
25315
25366
|
allowSubDelegation: true
|
|
25316
25367
|
});
|
|
@@ -25402,7 +25453,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25402
25453
|
assertActive: () => graph.assertActive(),
|
|
25403
25454
|
keyProvider: this._keyProvider,
|
|
25404
25455
|
registry: this._capabilityRegistry,
|
|
25405
|
-
sessionExpiry: this.
|
|
25456
|
+
sessionExpiry: this.getSignedSessionExpiry(),
|
|
25406
25457
|
createDelegationWasm: (params) => {
|
|
25407
25458
|
graph.assertActive();
|
|
25408
25459
|
return this.createDelegationWrapper(params);
|
|
@@ -25449,6 +25500,29 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25449
25500
|
const expirationMs = this.config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS;
|
|
25450
25501
|
return new Date(Date.now() + expirationMs);
|
|
25451
25502
|
}
|
|
25503
|
+
/**
|
|
25504
|
+
* The expiry of the session that was actually signed, so the registry root
|
|
25505
|
+
* and the sharing service never outlive or undercut what the SIWE grants
|
|
25506
|
+
* (a user may change the expiry in the OpenKey approval).
|
|
25507
|
+
*
|
|
25508
|
+
* Any expiry the SIWE parses to is used exactly as signed, however near or
|
|
25509
|
+
* far. The configured lifetime is used only when the SIWE cannot be parsed
|
|
25510
|
+
* (the session is already established, so failing sign-in here would be
|
|
25511
|
+
* worse; real sign-ins verify the SIWE first) or when a valid SIWE carries
|
|
25512
|
+
* no `Expiration Time` line, as the other `extractSiweExpiration` callers do.
|
|
25513
|
+
* @internal
|
|
25514
|
+
*/
|
|
25515
|
+
getSignedSessionExpiry() {
|
|
25516
|
+
const siwe = this.auth?.tinyCloudSession?.siwe;
|
|
25517
|
+
if (!siwe) return this.getSessionExpiry();
|
|
25518
|
+
let signed2;
|
|
25519
|
+
try {
|
|
25520
|
+
signed2 = extractSiweExpiration(siwe);
|
|
25521
|
+
} catch {
|
|
25522
|
+
return this.getSessionExpiry();
|
|
25523
|
+
}
|
|
25524
|
+
return signed2 ?? this.getSessionExpiry();
|
|
25525
|
+
}
|
|
25452
25526
|
/**
|
|
25453
25527
|
* Wrapper for the WASM createDelegation function.
|
|
25454
25528
|
*
|
|
@@ -28335,7 +28409,9 @@ function wireOpenKeyAuthorize(openkey, opts) {
|
|
|
28335
28409
|
host: input.host,
|
|
28336
28410
|
// Forward the presentation envelope verbatim — the OpenKey SDK
|
|
28337
28411
|
// validates and size-bounds it before use.
|
|
28338
|
-
presentation: input.presentation
|
|
28412
|
+
presentation: input.presentation,
|
|
28413
|
+
// Sent only when true, so a request without it keeps its prior shape.
|
|
28414
|
+
...input.expiryChangeable === true ? { expiryChangeable: true } : {}
|
|
28339
28415
|
}, opts);
|
|
28340
28416
|
if (result.protocolVersion !== 1) {
|
|
28341
28417
|
throw new Error(
|