@oatscenter/trellis 0.100.0-rc.3 → 0.100.0-rc.4
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/auth/authority.js +37 -23
- package/auth/authorization/transport_state.d.ts +0 -80
- package/auth/authorization/transport_state.js +0 -136
- package/auth/browser/oauth.d.ts +3 -28
- package/auth/browser/oauth.js +81 -185
- package/auth/connection.js +9 -1
- package/auth/issuer_trust.js +3 -5
- package/auth/message_digests.d.ts +36 -0
- package/auth/message_digests.js +236 -0
- package/auth/oauth_core.d.ts +58 -0
- package/auth/oauth_core.js +123 -0
- package/auth/proof.js +5 -4
- package/auth/protocol_wasm/client/trellis_protocol_wasm.d.ts +400 -0
- package/auth/protocol_wasm/client/trellis_protocol_wasm.js +1954 -0
- package/auth/protocol_wasm/client/trellis_protocol_wasm_bg.wasm +0 -0
- package/auth/protocol_wasm/{trellis_protocol_wasm.d.ts → provider/trellis_protocol_wasm.d.ts} +134 -96
- package/auth/protocol_wasm/provider/trellis_protocol_wasm.js +2220 -0
- package/auth/protocol_wasm/provider/trellis_protocol_wasm_bg.wasm +0 -0
- package/auth/protocol_wasm.d.ts +107 -31
- package/auth/protocol_wasm.js +176 -73
- package/auth/protocol_wasm_provider.d.ts +1 -0
- package/auth/protocol_wasm_provider.js +11 -0
- package/auth/session_auth.js +1 -1
- package/auth/session_proof.js +5 -7
- package/caller.js +8 -1
- package/client_connect.d.ts +0 -3
- package/client_connect.js +10 -3
- package/connection.d.ts +0 -2
- package/connection.js +0 -6
- package/data_plane/budget.d.ts +16 -0
- package/data_plane/budget.js +36 -0
- package/device.d.ts +1 -0
- package/device.js +7 -19
- package/errors/index.js +1 -1
- package/generated_support.js +3 -1
- package/internal_sdk/generated/apis/auth/mod.d.ts +25 -109
- package/internal_sdk/generated/apis/auth/mod.js +33 -131
- package/internal_sdk/generated/apis/core/mod.d.ts +1 -1
- package/internal_sdk/generated/apis/core/mod.js +5 -5
- package/internal_sdk/generated/apis/events/mod.d.ts +1 -1
- package/internal_sdk/generated/apis/events/mod.js +5 -5
- package/internal_sdk/generated/apis/health/mod.d.ts +1 -1
- package/internal_sdk/generated/apis/health/mod.js +5 -5
- package/internal_sdk/generated/apis/jobs/mod.d.ts +1 -1
- package/internal_sdk/generated/apis/jobs/mod.js +5 -5
- package/internal_sdk/generated/apis/state/mod.d.ts +1 -1
- package/internal_sdk/generated/apis/state/mod.js +5 -5
- package/internal_sdk/generated/apps/cli/mod.d.ts +108 -128
- package/internal_sdk/generated/apps/cli/mod.js +155 -285
- package/internal_sdk/generated/apps/console/mod.d.ts +136 -156
- package/internal_sdk/generated/apps/console/mod.js +226 -356
- package/internal_sdk/generated/package.json +2 -2
- package/internal_sdk/generated/participants/eventsRuntime/mod.d.ts +3 -10
- package/internal_sdk/generated/participants/eventsRuntime/mod.js +9 -16
- package/internal_sdk/generated/participants/healthRuntime/mod.d.ts +1 -1
- package/internal_sdk/generated/participants/healthRuntime/mod.js +6 -6
- package/internal_sdk/generated/participants/jobsRuntime/mod.d.ts +3 -10
- package/internal_sdk/generated/participants/jobsRuntime/mod.js +9 -16
- package/internal_sdk/generated/participants/platform/mod.d.ts +3 -10
- package/internal_sdk/generated/participants/platform/mod.js +8 -15
- package/internal_sdk/generated/types/_internal/p0.d.ts +3336 -3556
- package/internal_sdk/generated/types/_internal/p0.js +1420 -1531
- package/internal_sdk/generated/types/index.d.ts +916 -940
- package/internal_sdk/generated/types/index.js +458 -470
- package/live/client_open.js +3 -3
- package/live/protocol.d.ts +2 -1
- package/live/protocol.js +2 -1
- package/live/provider.js +6 -2
- package/live/telemetry.d.ts +1 -1
- package/live/telemetry.js +2 -1
- package/native/discovery.d.ts +0 -1
- package/native/discovery.js +6 -29
- package/native/oauth.d.ts +6 -6
- package/native/oauth.js +71 -104
- package/native.d.ts +0 -1
- package/operations.d.ts +3 -4
- package/operations.js +0 -3
- package/own_authority.d.ts +0 -1
- package/own_authority.js +0 -1
- package/package.json +2 -2
- package/participant_runtime/api.d.ts +2 -6
- package/participant_runtime/participant.d.ts +3 -0
- package/participant_runtime/participant.js +8 -1
- package/service/runtime/core.d.ts +8 -5
- package/service/runtime/core.js +65 -84
- package/service/runtime/service.d.ts +7 -3
- package/service/runtime/service.js +12 -6
- package/service/runtime/transfer/queue.js +12 -1
- package/service/runtime/transfer.d.ts +33 -5
- package/service/runtime/transfer.js +333 -89
- package/session/contract_types.d.ts +201 -0
- package/session/contract_types.js +7 -0
- package/session/durable_events.d.ts +63 -0
- package/session/durable_events.js +561 -0
- package/session/events.d.ts +77 -0
- package/session/events.js +54 -0
- package/session/facades.d.ts +133 -0
- package/session/facades.js +50 -0
- package/session/handler_errors.d.ts +32 -0
- package/session/handler_errors.js +64 -0
- package/session/helpers.d.ts +20 -0
- package/session/helpers.js +71 -0
- package/session/local_authorization.d.ts +61 -0
- package/session/local_authorization.js +156 -0
- package/session/operations.d.ts +265 -0
- package/session/operations.js +75 -0
- package/session/state.d.ts +120 -0
- package/session/state.js +333 -0
- package/session/types.d.ts +168 -0
- package/session/types.js +13 -0
- package/session/wire.d.ts +67 -0
- package/session/wire.js +227 -0
- package/session.d.ts +28 -861
- package/session.js +76 -1536
- package/sha256.d.ts +9 -0
- package/sha256.js +33 -0
- package/store.js +7 -1
- package/store_reader.js +40 -40
- package/telemetry/metrics.d.ts +2 -2
- package/telemetry/metrics.js +3 -0
- package/transfer/frames.d.ts +11 -0
- package/transfer/frames.js +156 -0
- package/transfer/session.d.ts +8 -0
- package/transfer/session.js +38 -7
- package/transfer.d.ts +18 -9
- package/transfer.js +127 -107
- package/transport/generations.d.ts +2 -40
- package/transport/generations.js +22 -331
- package/auth/protocol_wasm/trellis_protocol_wasm.js +0 -1750
- package/auth/protocol_wasm/trellis_protocol_wasm_bg.wasm +0 -0
- package/auth/protocol_wasm/trellis_protocol_wasm_bytes.d.ts +0 -1
- package/auth/protocol_wasm/trellis_protocol_wasm_bytes.js +0 -2
package/auth/authority.js
CHANGED
|
@@ -2,9 +2,9 @@ import { Kvm } from "@nats-io/kv";
|
|
|
2
2
|
import { createInbox } from "@nats-io/nats-core";
|
|
3
3
|
import { QueuedIteratorImpl } from "@nats-io/nats-core/internal";
|
|
4
4
|
import { AckPolicy, DeliverPolicy, jetstream, } from "@nats-io/jetstream";
|
|
5
|
-
import { assertSessionAuthorityHandleCurrentWasm, verifyAdmissionContextWasm, authorizeCatalogActionWasm, createSessionAuthorityHandleWasm, verifyAuthorityMetadataWasm, verifySessionEventWasm, verifySessionRequestWasm, verifySessionResponseWasm, } from "./protocol_wasm.js";
|
|
5
|
+
import { assertSessionAuthorityHandleCurrentWasm, verifyAdmissionContextWasm, authenticateCatalogWasm, authenticateProviderCertificateWasm, authorizeCatalogActionWasm, authorizeProviderEventPublicationWasm, createSessionAuthorityHandleWasm, verifyAuthorityMetadataWasm, verifySessionEventWasm, verifySessionRequestWasm, verifySessionResponseWasm, authorizationSessionStatusSchema, signedBytes, } from "./protocol_wasm.js";
|
|
6
|
+
import { payloadSha256 } from "./message_digests.js";
|
|
6
7
|
import {} from "./utils.js";
|
|
7
|
-
import { AuthAuthorityStatusResponseCodec } from "../internal_sdk/generated/types/_internal/p0.js";
|
|
8
8
|
import { requestIssuerMetadata } from "./issuer_metadata.js";
|
|
9
9
|
const authorityLeaseToken = Symbol("verified authority lease");
|
|
10
10
|
/** Short-lived typed identity lease; cannot be constructed from unverified JSON. */
|
|
@@ -57,7 +57,6 @@ export class VerifiedAuthority {
|
|
|
57
57
|
oauthGrantId: authority.oauthGrantId,
|
|
58
58
|
capabilities: authority.capabilities,
|
|
59
59
|
apis: authority.apis,
|
|
60
|
-
platformPrivileges: authority.platformPrivileges,
|
|
61
60
|
};
|
|
62
61
|
}
|
|
63
62
|
/** Time and observed retirement are checked again immediately before authorized work. */
|
|
@@ -624,7 +623,7 @@ export class SessionAuthorityOwner {
|
|
|
624
623
|
const verified = await verifySessionRequestWasm({
|
|
625
624
|
authorityHandle: entry.handle,
|
|
626
625
|
request,
|
|
627
|
-
payload,
|
|
626
|
+
payloadSha256: await payloadSha256(payload),
|
|
628
627
|
proof,
|
|
629
628
|
policy: this.policy(),
|
|
630
629
|
knownRevoked: this.#revocations.has(entry.authority.authorizationSessionId),
|
|
@@ -649,9 +648,9 @@ export class SessionAuthorityOwner {
|
|
|
649
648
|
const verified = await verifySessionResponseWasm({
|
|
650
649
|
providerHandle: provider.entry(authorityLeaseToken).handle,
|
|
651
650
|
response,
|
|
652
|
-
payload,
|
|
651
|
+
payloadSha256: await payloadSha256(payload),
|
|
653
652
|
proof,
|
|
654
|
-
certificate: certificate.
|
|
653
|
+
certificate: certificate.handle,
|
|
655
654
|
certificateIssuer: issuer,
|
|
656
655
|
pendingRequest: pending.request,
|
|
657
656
|
pendingRequestDigest: pending.proofDigest,
|
|
@@ -700,11 +699,11 @@ export class SessionAuthorityOwner {
|
|
|
700
699
|
});
|
|
701
700
|
if (metadata.result.kind !== "value")
|
|
702
701
|
throw new Error("historical revocation resolution unavailable");
|
|
703
|
-
const status =
|
|
702
|
+
const status = authorizationSessionStatusSchema.parse(JSON.parse(metadata.result.payload));
|
|
704
703
|
if (status.authorizationSessionId !== hints.authorizationSessionId)
|
|
705
704
|
throw new Error("historical status mismatch");
|
|
706
705
|
if (status.revocation) {
|
|
707
|
-
const revocation = await this.#verifyMetadata("revocation", status.revocation);
|
|
706
|
+
const revocation = await this.#verifyMetadata("revocation", signedBytes(status.revocation));
|
|
708
707
|
if (revocation.record.authorizationSessionId !==
|
|
709
708
|
hints.authorizationSessionId ||
|
|
710
709
|
typeof revocation.record.effectiveCutoff !== "number")
|
|
@@ -734,7 +733,7 @@ export class SessionAuthorityOwner {
|
|
|
734
733
|
const verified = await verifySessionEventWasm({
|
|
735
734
|
authorityHandle: entry.handle,
|
|
736
735
|
event,
|
|
737
|
-
payload,
|
|
736
|
+
payloadSha256: await payloadSha256(payload),
|
|
738
737
|
proof,
|
|
739
738
|
policy: this.policy(),
|
|
740
739
|
originalPublication,
|
|
@@ -835,7 +834,7 @@ export class SessionAuthorityOwner {
|
|
|
835
834
|
return false;
|
|
836
835
|
const catalog = await this.#metadata("catalog", api.catalogSnapshotDigest);
|
|
837
836
|
const issuer = await this.#issuer(String(catalog.record.issuerKeyId));
|
|
838
|
-
let allowed = await authorizeCatalogActionWasm(entry.handle, catalog.
|
|
837
|
+
let allowed = await authorizeCatalogActionWasm(entry.handle, catalog.handle, this.#metadataPolicy(issuer), action);
|
|
839
838
|
if (!allowed && action.kind === "event" && action.direction === "publish") {
|
|
840
839
|
const binding = entry.authority.providerBindings.find((binding) => binding.apiId === apiId);
|
|
841
840
|
if (binding &&
|
|
@@ -844,16 +843,15 @@ export class SessionAuthorityOwner {
|
|
|
844
843
|
const at = publication?.at ?? this.#now();
|
|
845
844
|
const certificate = await this.#metadata("provider", binding.providerCertificateDigest, at);
|
|
846
845
|
const providerIssuer = await this.#issuer(String(certificate.record.issuerKeyId));
|
|
847
|
-
allowed = await
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
},
|
|
846
|
+
allowed = await authorizeProviderEventPublicationWasm(entry.handle, catalog.handle, certificate.handle, {
|
|
847
|
+
catalogIssuer: issuer,
|
|
848
|
+
certificateIssuer: providerIssuer,
|
|
849
|
+
trellisInstanceId: this.instanceId,
|
|
850
|
+
audienceNatsAccount: this.account,
|
|
851
|
+
at,
|
|
852
|
+
...(publication?.publishedAt !== undefined
|
|
853
|
+
? { publishedAt: publication.publishedAt }
|
|
854
|
+
: {}),
|
|
857
855
|
}, action);
|
|
858
856
|
}
|
|
859
857
|
}
|
|
@@ -994,11 +992,11 @@ export class SessionAuthorityOwner {
|
|
|
994
992
|
}
|
|
995
993
|
if (query.kind === "authorityStatus" &&
|
|
996
994
|
response.result.kind === "value") {
|
|
997
|
-
const status =
|
|
995
|
+
const status = authorizationSessionStatusSchema.parse(JSON.parse(response.result.payload));
|
|
998
996
|
if (status.authorizationSessionId !== query.authorizationSessionId)
|
|
999
997
|
throw new Error("issuer metadata status identity mismatch");
|
|
1000
998
|
if (status.revocation)
|
|
1001
|
-
await this.observeRevocation(status.revocation, query.authorizationSessionId, () => epoch === this.#mirrorEpoch &&
|
|
999
|
+
await this.observeRevocation(signedBytes(status.revocation), query.authorizationSessionId, () => epoch === this.#mirrorEpoch &&
|
|
1002
1000
|
this.#mirrorCovered &&
|
|
1003
1001
|
!this.#stopped);
|
|
1004
1002
|
assertCurrent();
|
|
@@ -1193,8 +1191,24 @@ export class SessionAuthorityOwner {
|
|
|
1193
1191
|
bytes: bytes.slice(),
|
|
1194
1192
|
digest: verified.digest,
|
|
1195
1193
|
record: verified.record,
|
|
1194
|
+
handle: undefined,
|
|
1196
1195
|
};
|
|
1197
1196
|
}
|
|
1197
|
+
/** Authenticate fetched catalog or certificate bytes once into a handle. */
|
|
1198
|
+
async #authenticateMaterial(kind, bytes, at) {
|
|
1199
|
+
const hints = this.#hints(bytes);
|
|
1200
|
+
if (typeof hints.issuerKeyId !== "string")
|
|
1201
|
+
throw new Error("missing issuer lookup identity");
|
|
1202
|
+
const issuer = await this.#issuer(hints.issuerKeyId);
|
|
1203
|
+
const policy = {
|
|
1204
|
+
...this.#metadataPolicy(issuer),
|
|
1205
|
+
...(at !== undefined ? { nowUnixSeconds: at } : {}),
|
|
1206
|
+
};
|
|
1207
|
+
const authenticated = kind === "catalog"
|
|
1208
|
+
? await authenticateCatalogWasm(bytes, policy)
|
|
1209
|
+
: await authenticateProviderCertificateWasm(bytes, policy);
|
|
1210
|
+
return { bytes: bytes.slice(), ...authenticated };
|
|
1211
|
+
}
|
|
1198
1212
|
async #metadata(kind, digest, at) {
|
|
1199
1213
|
const key = `${kind}.${digest}`;
|
|
1200
1214
|
const cached = this.#materials.get(key);
|
|
@@ -1208,7 +1222,7 @@ export class SessionAuthorityOwner {
|
|
|
1208
1222
|
if (this.#coldMaterials.size >= 32)
|
|
1209
1223
|
throw new Error("metadata resolution budget exceeded");
|
|
1210
1224
|
pending = (async () => {
|
|
1211
|
-
const verified = await this.#
|
|
1225
|
+
const verified = await this.#authenticateMaterial(kind, await this.#read(kind, digest), at);
|
|
1212
1226
|
if (verified.digest !== digest)
|
|
1213
1227
|
throw new Error("metadata digest mismatch");
|
|
1214
1228
|
if (this.#stopped)
|
|
@@ -1,84 +1,4 @@
|
|
|
1
1
|
import { type TransportAuthorizationV1 } from "../protocol_wasm.ts";
|
|
2
|
-
/**
|
|
3
|
-
* Retained transport-authorization status for one logical connection.
|
|
4
|
-
*
|
|
5
|
-
* `unavailable` covers a real disconnect and a socket whose own authority no
|
|
6
|
-
* longer covers its admitted policy; it never means "application authorization
|
|
7
|
-
* is revoked", which is a separate observation.
|
|
8
|
-
*/
|
|
9
|
-
export type TransportAuthorizationStatus = "unavailable" | "current" | "upgrade_available";
|
|
10
|
-
/**
|
|
11
|
-
* Parse the signed-context digest out of an authenticated admission name.
|
|
12
|
-
*
|
|
13
|
-
* Returns `undefined` for any name that is not a well-formed Trellis admission
|
|
14
|
-
* marker, so a foreign or malformed name is never mistaken for admitted
|
|
15
|
-
* authority.
|
|
16
|
-
* The complete marker requires nonempty opaque digest and server fields,
|
|
17
|
-
* no whitespace, and a canonical positive decimal u64 client ID.
|
|
18
|
-
*/
|
|
19
|
-
export declare function admissionContextDigest(authenticatedUser: string): string | undefined;
|
|
20
|
-
/** Result of one bounded own-user-information read. */
|
|
21
|
-
export type OwnAdmission = {
|
|
22
|
-
authenticatedUser: string;
|
|
23
|
-
contextDigest?: string;
|
|
24
|
-
};
|
|
25
|
-
/** Minimal NATS request surface used for the own-user-information read. */
|
|
26
|
-
export type OwnUserInfoRequester = {
|
|
27
|
-
request(subject: string, payload?: Uint8Array, opts?: {
|
|
28
|
-
timeout?: number;
|
|
29
|
-
}): Promise<{
|
|
30
|
-
json<T>(): T;
|
|
31
|
-
}>;
|
|
32
|
-
};
|
|
33
|
-
/**
|
|
34
|
-
* Read this attachment's authenticated identity from the broker.
|
|
35
|
-
*
|
|
36
|
-
* Best effort by design: notification is triggered by a hint or a refresh, and
|
|
37
|
-
* a missing or malformed reply must never install authority or lose
|
|
38
|
-
* enforcement, so any failure yields `undefined` instead of throwing.
|
|
39
|
-
*/
|
|
40
|
-
export declare function readOwnAdmission(nc: OwnUserInfoRequester, timeoutMs: number): Promise<OwnAdmission | undefined>;
|
|
41
|
-
/**
|
|
42
|
-
* Retained admitted-transport state for one logical connection.
|
|
43
|
-
*
|
|
44
|
-
* Holds the exact signed policy actually admitted on the current physical
|
|
45
|
-
* attachment (`A`) and recomputes the retained upgrade status against the
|
|
46
|
-
* newest valid application policy (`D`). It installs no authority: a change
|
|
47
|
-
* here only records a passive upgrade notice or marks transport unavailable.
|
|
48
|
-
*/
|
|
49
|
-
export declare class TransportAuthorizationState {
|
|
50
|
-
#private;
|
|
51
|
-
/** Register the retained status observer; it receives semantic changes and the current value. */
|
|
52
|
-
onStatusChanged(callback: (status: TransportAuthorizationStatus) => void): void;
|
|
53
|
-
status(): TransportAuthorizationStatus;
|
|
54
|
-
admittedDigest(): string | undefined;
|
|
55
|
-
admittedPolicy(): TransportAuthorizationV1 | undefined;
|
|
56
|
-
/** Newest valid application policy D used for the last comparison. */
|
|
57
|
-
allowedPolicy(): TransportAuthorizationV1 | undefined;
|
|
58
|
-
/**
|
|
59
|
-
* Record the policy actually admitted on the current physical generation and
|
|
60
|
-
* recompute the status against the newest valid application policy.
|
|
61
|
-
*
|
|
62
|
-
* Called only after an actual admission read, never as a side effect of an
|
|
63
|
-
* ordinary context promotion, so an in-place renewal does not pretend the
|
|
64
|
-
* socket adopted the newer policy.
|
|
65
|
-
*/
|
|
66
|
-
recordAdmission(args: {
|
|
67
|
-
contextDigest: string;
|
|
68
|
-
policy: TransportAuthorizationV1;
|
|
69
|
-
allowed?: TransportAuthorizationV1;
|
|
70
|
-
nowUnixSeconds: number;
|
|
71
|
-
}): Promise<void>;
|
|
72
|
-
/**
|
|
73
|
-
* Recompute against the newest valid application policy without a new read.
|
|
74
|
-
*
|
|
75
|
-
* A duplicate renewal that changes only the context digest does not change
|
|
76
|
-
* the semantic status, so no repeated transition is published.
|
|
77
|
-
*/
|
|
78
|
-
recompute(allowed: TransportAuthorizationV1 | undefined, nowUnixSeconds: number): Promise<void>;
|
|
79
|
-
/** Record a real physical loss; the next admission recomputes from scratch. */
|
|
80
|
-
markDisconnected(): void;
|
|
81
|
-
}
|
|
82
2
|
/**
|
|
83
3
|
* Whether the admitted policy covers the exact subjects an operation needs.
|
|
84
4
|
*
|
|
@@ -1,140 +1,4 @@
|
|
|
1
1
|
import { classifyTransportAuthorizationWasm, TRANSPORT_AUTHORIZATION_FORMAT_V1, } from "../protocol_wasm.js";
|
|
2
|
-
/**
|
|
3
|
-
* Prefix the runtime sets on every callout-owned attachment's authenticated
|
|
4
|
-
* name: `trellis.auth.v1:<contextDigest>:<serverId>:<clientId>`.
|
|
5
|
-
*/
|
|
6
|
-
const ADMISSION_NAME_PREFIX = "trellis.auth.v1:";
|
|
7
|
-
/**
|
|
8
|
-
* Parse the signed-context digest out of an authenticated admission name.
|
|
9
|
-
*
|
|
10
|
-
* Returns `undefined` for any name that is not a well-formed Trellis admission
|
|
11
|
-
* marker, so a foreign or malformed name is never mistaken for admitted
|
|
12
|
-
* authority.
|
|
13
|
-
* The complete marker requires nonempty opaque digest and server fields,
|
|
14
|
-
* no whitespace, and a canonical positive decimal u64 client ID.
|
|
15
|
-
*/
|
|
16
|
-
export function admissionContextDigest(authenticatedUser) {
|
|
17
|
-
if (!authenticatedUser.startsWith(ADMISSION_NAME_PREFIX))
|
|
18
|
-
return undefined;
|
|
19
|
-
const remainder = authenticatedUser.slice(ADMISSION_NAME_PREFIX.length);
|
|
20
|
-
const fields = remainder.split(":");
|
|
21
|
-
const [digest, serverId, clientId] = fields;
|
|
22
|
-
if (fields.length !== 3 ||
|
|
23
|
-
!digest ||
|
|
24
|
-
!serverId ||
|
|
25
|
-
/[\p{White_Space}\uFEFF]/u.test(remainder) ||
|
|
26
|
-
!/^[1-9][0-9]*$/u.test(clientId) ||
|
|
27
|
-
BigInt(clientId) > 18446744073709551615n)
|
|
28
|
-
return undefined;
|
|
29
|
-
return digest;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Read this attachment's authenticated identity from the broker.
|
|
33
|
-
*
|
|
34
|
-
* Best effort by design: notification is triggered by a hint or a refresh, and
|
|
35
|
-
* a missing or malformed reply must never install authority or lose
|
|
36
|
-
* enforcement, so any failure yields `undefined` instead of throwing.
|
|
37
|
-
*/
|
|
38
|
-
export async function readOwnAdmission(nc, timeoutMs) {
|
|
39
|
-
try {
|
|
40
|
-
const reply = await nc.request("$SYS.REQ.USER.INFO", undefined, {
|
|
41
|
-
timeout: timeoutMs,
|
|
42
|
-
});
|
|
43
|
-
const info = reply.json();
|
|
44
|
-
const user = info?.data?.user;
|
|
45
|
-
if (typeof user !== "string" || user.length === 0)
|
|
46
|
-
return undefined;
|
|
47
|
-
return {
|
|
48
|
-
authenticatedUser: user,
|
|
49
|
-
contextDigest: admissionContextDigest(user),
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
53
|
-
return undefined;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Retained admitted-transport state for one logical connection.
|
|
58
|
-
*
|
|
59
|
-
* Holds the exact signed policy actually admitted on the current physical
|
|
60
|
-
* attachment (`A`) and recomputes the retained upgrade status against the
|
|
61
|
-
* newest valid application policy (`D`). It installs no authority: a change
|
|
62
|
-
* here only records a passive upgrade notice or marks transport unavailable.
|
|
63
|
-
*/
|
|
64
|
-
export class TransportAuthorizationState {
|
|
65
|
-
#admittedDigest;
|
|
66
|
-
#admitted;
|
|
67
|
-
#allowed;
|
|
68
|
-
#status = "unavailable";
|
|
69
|
-
#onStatusChanged;
|
|
70
|
-
/** Register the retained status observer; it receives semantic changes and the current value. */
|
|
71
|
-
onStatusChanged(callback) {
|
|
72
|
-
this.#onStatusChanged = callback;
|
|
73
|
-
callback(this.#status);
|
|
74
|
-
}
|
|
75
|
-
status() {
|
|
76
|
-
return this.#status;
|
|
77
|
-
}
|
|
78
|
-
admittedDigest() {
|
|
79
|
-
return this.#admittedDigest;
|
|
80
|
-
}
|
|
81
|
-
admittedPolicy() {
|
|
82
|
-
return this.#admitted;
|
|
83
|
-
}
|
|
84
|
-
/** Newest valid application policy D used for the last comparison. */
|
|
85
|
-
allowedPolicy() {
|
|
86
|
-
return this.#allowed;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Record the policy actually admitted on the current physical generation and
|
|
90
|
-
* recompute the status against the newest valid application policy.
|
|
91
|
-
*
|
|
92
|
-
* Called only after an actual admission read, never as a side effect of an
|
|
93
|
-
* ordinary context promotion, so an in-place renewal does not pretend the
|
|
94
|
-
* socket adopted the newer policy.
|
|
95
|
-
*/
|
|
96
|
-
async recordAdmission(args) {
|
|
97
|
-
this.#admittedDigest = args.contextDigest;
|
|
98
|
-
this.#admitted = args.policy;
|
|
99
|
-
await this.recompute(args.allowed, args.nowUnixSeconds);
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Recompute against the newest valid application policy without a new read.
|
|
103
|
-
*
|
|
104
|
-
* A duplicate renewal that changes only the context digest does not change
|
|
105
|
-
* the semantic status, so no repeated transition is published.
|
|
106
|
-
*/
|
|
107
|
-
async recompute(allowed, nowUnixSeconds) {
|
|
108
|
-
this.#allowed = allowed;
|
|
109
|
-
const admitted = this.#admitted;
|
|
110
|
-
if (!admitted) {
|
|
111
|
-
this.#setStatus("unavailable");
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
if (!allowed) {
|
|
115
|
-
this.#setStatus("current");
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
const relation = await classifyTransportAuthorizationWasm(admitted, allowed, nowUnixSeconds);
|
|
119
|
-
this.#setStatus(relation === "current"
|
|
120
|
-
? "current"
|
|
121
|
-
: relation === "upgrade_available"
|
|
122
|
-
? "upgrade_available"
|
|
123
|
-
: "unavailable");
|
|
124
|
-
}
|
|
125
|
-
/** Record a real physical loss; the next admission recomputes from scratch. */
|
|
126
|
-
markDisconnected() {
|
|
127
|
-
this.#admittedDigest = undefined;
|
|
128
|
-
this.#admitted = undefined;
|
|
129
|
-
this.#setStatus("unavailable");
|
|
130
|
-
}
|
|
131
|
-
#setStatus(next) {
|
|
132
|
-
if (next === this.#status)
|
|
133
|
-
return;
|
|
134
|
-
this.#status = next;
|
|
135
|
-
this.#onStatusChanged?.(next);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
2
|
/**
|
|
139
3
|
* Whether the admitted policy covers the exact subjects an operation needs.
|
|
140
4
|
*
|
package/auth/browser/oauth.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
import { AuthError } from "../../errors/AuthError.ts";
|
|
4
4
|
import { type TrellisAuth } from "../session_auth.ts";
|
|
5
5
|
import { BrowserSessionStore, type BrowserOAuthScope } from "./storage.ts";
|
|
6
|
-
import { type
|
|
6
|
+
import { type SignedOAuthAdmission } from "../protocol_wasm.ts";
|
|
7
7
|
import { SessionAuthorityOwner, type RuntimeAuthorizationTrust } from "../authority.ts";
|
|
8
8
|
declare const metadataSchema: z.ZodObject<{
|
|
9
9
|
issuer: z.ZodString;
|
|
@@ -33,29 +33,11 @@ declare const tokenSchema: z.ZodObject<{
|
|
|
33
33
|
refresh_token: z.ZodString;
|
|
34
34
|
expires_in: z.ZodNumber;
|
|
35
35
|
trellis_admission: z.ZodString;
|
|
36
|
-
authorization_details: z.ZodOptional<z.ZodArray<z.
|
|
36
|
+
authorization_details: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
37
37
|
type: z.ZodLiteral<"trellis_capabilities">;
|
|
38
38
|
required: z.ZodArray<z.ZodString>;
|
|
39
39
|
optional: z.ZodArray<z.ZodString>;
|
|
40
|
-
}, z.core.$strip
|
|
41
|
-
type: z.ZodLiteral<"trellis_platform_privileges">;
|
|
42
|
-
required: z.ZodArray<z.ZodEnum<{
|
|
43
|
-
"principals.manage": "principals.manage";
|
|
44
|
-
"roles.manage": "roles.manage";
|
|
45
|
-
"apis.accept": "apis.accept";
|
|
46
|
-
"apis.forceReplace": "apis.forceReplace";
|
|
47
|
-
"clients.manage": "clients.manage";
|
|
48
|
-
"privileges.manage": "privileges.manage";
|
|
49
|
-
}>>;
|
|
50
|
-
optional: z.ZodArray<z.ZodEnum<{
|
|
51
|
-
"principals.manage": "principals.manage";
|
|
52
|
-
"roles.manage": "roles.manage";
|
|
53
|
-
"apis.accept": "apis.accept";
|
|
54
|
-
"apis.forceReplace": "apis.forceReplace";
|
|
55
|
-
"clients.manage": "clients.manage";
|
|
56
|
-
"privileges.manage": "privileges.manage";
|
|
57
|
-
}>>;
|
|
58
|
-
}, z.core.$strip>], "type">>>;
|
|
40
|
+
}, z.core.$strip>>>;
|
|
59
41
|
}, z.core.$strip>;
|
|
60
42
|
/** HTTPS-authenticated discovery scoped to the user's selected server. */
|
|
61
43
|
export type BrowserOAuthMetadata = z.infer<typeof metadataSchema>;
|
|
@@ -75,11 +57,6 @@ export type BrowserOAuthAdmission = {
|
|
|
75
57
|
export type BrowserCapabilityRequest = {
|
|
76
58
|
readonly required: readonly string[];
|
|
77
59
|
readonly optional: readonly string[];
|
|
78
|
-
/** Finite RAR requests; the server still enforces client eligibility, administrator authority, and consent. */
|
|
79
|
-
readonly platformPrivileges?: {
|
|
80
|
-
readonly required: readonly PlatformPrivilege[];
|
|
81
|
-
readonly optional: readonly PlatformPrivilege[];
|
|
82
|
-
};
|
|
83
60
|
};
|
|
84
61
|
/** Registered and CIMD public OAuth clients share this flow and durable custody. */
|
|
85
62
|
export declare class BrowserOAuthClient {
|
|
@@ -109,6 +86,4 @@ export declare class BrowserOAuthClient {
|
|
|
109
86
|
/** Bind the authenticated connection to the retained credential trust root. */
|
|
110
87
|
bindOwner(owner: SessionAuthorityOwner): Promise<void>;
|
|
111
88
|
}
|
|
112
|
-
/** RFC 9449 proof and the authenticated Trellis runtime/NKey extension, signed without exporting the private key. */
|
|
113
|
-
export declare function createBrowserDpopProof(key: Readonly<CryptoKeyPair>, tokenEndpoint: string, runtimeId: string, sessionPublicKey: string, nonce?: string): Promise<string>;
|
|
114
89
|
export {};
|