@oxy.so/core 1.5.1 → 1.6.1
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/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/HttpService.js +72 -9
- package/dist/cjs/crypto/identityMove.js +53 -34
- package/dist/cjs/crypto/identityProof.js +28 -0
- package/dist/cjs/crypto/webIdentityCarrier.js +145 -82
- package/dist/cjs/i18n/locales/ar-SA.json +1 -0
- package/dist/cjs/i18n/locales/ca-ES.json +1 -0
- package/dist/cjs/i18n/locales/de-DE.json +1 -0
- package/dist/cjs/i18n/locales/en-US.json +1 -0
- package/dist/cjs/i18n/locales/es-ES.json +1 -0
- package/dist/cjs/i18n/locales/fr-FR.json +1 -0
- package/dist/cjs/i18n/locales/it-IT.json +1 -0
- package/dist/cjs/i18n/locales/ja-JP.json +1 -0
- package/dist/cjs/i18n/locales/ko-KR.json +1 -0
- package/dist/cjs/i18n/locales/locales/ar-SA.json +1 -0
- package/dist/cjs/i18n/locales/locales/ca-ES.json +1 -0
- package/dist/cjs/i18n/locales/locales/de-DE.json +1 -0
- package/dist/cjs/i18n/locales/locales/en-US.json +1 -0
- package/dist/cjs/i18n/locales/locales/es-ES.json +1 -0
- package/dist/cjs/i18n/locales/locales/fr-FR.json +1 -0
- package/dist/cjs/i18n/locales/locales/it-IT.json +1 -0
- package/dist/cjs/i18n/locales/locales/ja-JP.json +1 -0
- package/dist/cjs/i18n/locales/locales/ko-KR.json +1 -0
- package/dist/cjs/i18n/locales/locales/pt-PT.json +1 -0
- package/dist/cjs/i18n/locales/locales/zh-CN.json +1 -0
- package/dist/cjs/i18n/locales/pt-PT.json +1 -0
- package/dist/cjs/i18n/locales/zh-CN.json +1 -0
- package/dist/cjs/index.js +22 -14
- package/dist/cjs/inference/OxyInferenceClient.js +62 -5
- package/dist/cjs/mixins/OxyServices.auth.js +129 -0
- package/dist/cjs/mixins/OxyServices.identity.js +11 -44
- package/dist/cjs/mixins/index.js +0 -2
- package/dist/cjs/server/index.js +10 -1
- package/dist/cjs/server/securityHeaders.js +9 -2
- package/dist/cjs/server/traffic.js +29 -2
- package/dist/cjs/server/workloadIdentity.js +170 -0
- package/dist/cjs/session/refresh.js +12 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/HttpService.js +72 -9
- package/dist/esm/crypto/identityMove.js +51 -33
- package/dist/esm/crypto/identityProof.js +24 -0
- package/dist/esm/crypto/webIdentityCarrier.js +137 -77
- package/dist/esm/i18n/locales/ar-SA.json +1 -0
- package/dist/esm/i18n/locales/ca-ES.json +1 -0
- package/dist/esm/i18n/locales/de-DE.json +1 -0
- package/dist/esm/i18n/locales/en-US.json +1 -0
- package/dist/esm/i18n/locales/es-ES.json +1 -0
- package/dist/esm/i18n/locales/fr-FR.json +1 -0
- package/dist/esm/i18n/locales/it-IT.json +1 -0
- package/dist/esm/i18n/locales/ja-JP.json +1 -0
- package/dist/esm/i18n/locales/ko-KR.json +1 -0
- package/dist/esm/i18n/locales/locales/ar-SA.json +1 -0
- package/dist/esm/i18n/locales/locales/ca-ES.json +1 -0
- package/dist/esm/i18n/locales/locales/de-DE.json +1 -0
- package/dist/esm/i18n/locales/locales/en-US.json +1 -0
- package/dist/esm/i18n/locales/locales/es-ES.json +1 -0
- package/dist/esm/i18n/locales/locales/fr-FR.json +1 -0
- package/dist/esm/i18n/locales/locales/it-IT.json +1 -0
- package/dist/esm/i18n/locales/locales/ja-JP.json +1 -0
- package/dist/esm/i18n/locales/locales/ko-KR.json +1 -0
- package/dist/esm/i18n/locales/locales/pt-PT.json +1 -0
- package/dist/esm/i18n/locales/locales/zh-CN.json +1 -0
- package/dist/esm/i18n/locales/pt-PT.json +1 -0
- package/dist/esm/i18n/locales/zh-CN.json +1 -0
- package/dist/esm/index.js +5 -4
- package/dist/esm/inference/OxyInferenceClient.js +63 -6
- package/dist/esm/mixins/OxyServices.auth.js +96 -0
- package/dist/esm/mixins/OxyServices.identity.js +11 -44
- package/dist/esm/mixins/index.js +0 -2
- package/dist/esm/server/index.js +7 -0
- package/dist/esm/server/securityHeaders.js +9 -2
- package/dist/esm/server/traffic.js +29 -2
- package/dist/esm/server/workloadIdentity.js +166 -0
- package/dist/esm/session/refresh.js +12 -0
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/HttpService.d.ts +24 -0
- package/dist/types/crypto/identityMove.d.ts +48 -32
- package/dist/types/crypto/identityProof.d.ts +16 -0
- package/dist/types/crypto/webIdentityCarrier.d.ts +74 -47
- package/dist/types/index.d.ts +7 -6
- package/dist/types/inference/OxyInferenceClient.d.ts +21 -1
- package/dist/types/mixins/OxyServices.auth.d.ts +32 -0
- package/dist/types/mixins/OxyServices.identity.d.ts +16 -30
- package/dist/types/mixins/index.d.ts +1 -2
- package/dist/types/server/index.d.ts +8 -0
- package/dist/types/server/securityHeaders.d.ts +8 -0
- package/dist/types/server/workloadIdentity.d.ts +32 -0
- package/package.json +2 -2
- package/src/HttpService.ts +74 -9
- package/src/__tests__/httpServiceRateLimitedRefresh.test.ts +160 -0
- package/src/__tests__/serviceTokenWorkloadFallback.test.ts +85 -0
- package/src/crypto/__tests__/identityMove.test.ts +93 -51
- package/src/crypto/__tests__/identityProof.test.ts +81 -0
- package/src/crypto/__tests__/webIdentityCarrier.test.ts +21 -63
- package/src/crypto/__tests__/webIdentityRecoveryMaterial.test.ts +117 -0
- package/src/crypto/identityMove.ts +77 -43
- package/src/crypto/identityProof.ts +36 -0
- package/src/crypto/webIdentityCarrier.ts +185 -117
- package/src/i18n/locales/ar-SA.json +1 -0
- package/src/i18n/locales/ca-ES.json +1 -0
- package/src/i18n/locales/de-DE.json +1 -0
- package/src/i18n/locales/en-US.json +1 -0
- package/src/i18n/locales/es-ES.json +1 -0
- package/src/i18n/locales/fr-FR.json +1 -0
- package/src/i18n/locales/it-IT.json +1 -0
- package/src/i18n/locales/ja-JP.json +1 -0
- package/src/i18n/locales/ko-KR.json +1 -0
- package/src/i18n/locales/pt-PT.json +1 -0
- package/src/i18n/locales/zh-CN.json +1 -0
- package/src/index.ts +26 -15
- package/src/inference/OxyInferenceClient.ts +84 -7
- package/src/inference/__tests__/OxyInferenceClient.test.ts +48 -0
- package/src/mixins/OxyServices.auth.ts +100 -1
- package/src/mixins/OxyServices.identity.ts +17 -67
- package/src/mixins/__tests__/OxyServices.identity.test.ts +1 -76
- package/src/mixins/index.ts +0 -3
- package/src/server/__tests__/securityHeaders.test.ts +15 -0
- package/src/server/__tests__/traffic.test.ts +132 -1
- package/src/server/__tests__/workloadIdentity.test.ts +128 -0
- package/src/server/index.ts +9 -0
- package/src/server/securityHeaders.ts +19 -6
- package/src/server/traffic.ts +31 -1
- package/src/server/workloadIdentity.ts +207 -0
- package/src/session/__tests__/refresh.test.ts +53 -3
- package/src/session/refresh.ts +12 -0
- package/dist/cjs/mixins/OxyServices.deviceTransfer.js +0 -314
- package/dist/esm/mixins/OxyServices.deviceTransfer.js +0 -311
- package/dist/types/mixins/OxyServices.deviceTransfer.d.ts +0 -149
- package/src/mixins/OxyServices.deviceTransfer.ts +0 -393
- package/src/mixins/__tests__/OxyServices.deviceTransfer.test.ts +0 -271
|
@@ -111,6 +111,17 @@ export declare class HttpService {
|
|
|
111
111
|
* fixed deadline that could not shrink once the token expired mid-cooldown.
|
|
112
112
|
*/
|
|
113
113
|
private lastRefreshFailureAt;
|
|
114
|
+
/**
|
|
115
|
+
* Whether the last refresh failure was the server answering 429. Selects
|
|
116
|
+
* {@link RATE_LIMITED_REFRESH_COOLDOWN_MS} over the two token-state cooldowns
|
|
117
|
+
* for the NEXT attempt, and is cleared by any success or any other failure.
|
|
118
|
+
*
|
|
119
|
+
* A boolean beside {@link lastRefreshFailureAt} rather than a stored deadline,
|
|
120
|
+
* for the same reason that field gives: the cooldown stays a function of the
|
|
121
|
+
* current state, so it can still shorten if the situation changes underneath
|
|
122
|
+
* it, and there is exactly one timestamp to reason about.
|
|
123
|
+
*/
|
|
124
|
+
private lastRefreshWasRateLimited;
|
|
114
125
|
private authRefreshHandler;
|
|
115
126
|
private accessTokenProvider;
|
|
116
127
|
private deviceSecretMintInFlight;
|
|
@@ -266,6 +277,19 @@ export declare class HttpService {
|
|
|
266
277
|
*/
|
|
267
278
|
private getAuthHeader;
|
|
268
279
|
refreshAccessToken(reason: AuthRefreshReason): Promise<string | null>;
|
|
280
|
+
/**
|
|
281
|
+
* Report that the refresh/mint endpoint answered 429 Too Many Requests, so the
|
|
282
|
+
* next attempt waits {@link RATE_LIMITED_REFRESH_COOLDOWN_MS} instead of one of
|
|
283
|
+
* the token-state cooldowns.
|
|
284
|
+
*
|
|
285
|
+
* Called by the refresh handler (`refreshDeviceSecretArm`) from inside the
|
|
286
|
+
* `authRefreshHandler` call, because the handler's `Promise<string | null>`
|
|
287
|
+
* contract cannot carry WHY a refresh failed and 429 is the one failure whose
|
|
288
|
+
* correct retry interval is set by the server rather than by the token.
|
|
289
|
+
*
|
|
290
|
+
* Public because the handler lives in `session/refresh.ts`, not on this class.
|
|
291
|
+
*/
|
|
292
|
+
noteRefreshRateLimited(): void;
|
|
269
293
|
/**
|
|
270
294
|
* Whether the CURRENT stored access token is already past its `exp`. Drives
|
|
271
295
|
* the shorter post-failure refresh cooldown ({@link EXPIRED_TOKEN_REFRESH_COOLDOWN_MS}):
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Identity move — the crypto of
|
|
2
|
+
* Identity move — the crypto of giving a web root to Commons (ADR 0024 D6).
|
|
3
3
|
*
|
|
4
|
-
* Both
|
|
5
|
-
* Commons (the responder, receiving it). The relay in between sees
|
|
6
|
-
* public keys and ciphertext
|
|
7
|
-
*
|
|
4
|
+
* Both sides run this: the web holder (the initiator, holding the root) and
|
|
5
|
+
* Commons (the responder, receiving it). The relay in between sees a commitment,
|
|
6
|
+
* two ephemeral public keys and ciphertext. The initiator commits to its key
|
|
7
|
+
* before the responder chooses one and reveals it only afterwards, so the 6-digit
|
|
8
|
+
* code both screens show exposes a relay that substituted a key — it cannot grind
|
|
9
|
+
* one until the codes agree. The receipt binds the move, the root, both keys and
|
|
10
|
+
* the ciphertext actually relayed.
|
|
8
11
|
*
|
|
9
12
|
* PURE: no storage, no network. Contract: `@oxy.so/contracts` `identityMove`.
|
|
10
13
|
*/
|
|
11
14
|
import './polyfill';
|
|
12
|
-
import { type
|
|
13
|
-
/** Actions the identity key signs during a move. */
|
|
14
|
-
export declare const IDENTITY_MOVE_ACTIONS: {
|
|
15
|
-
readonly seal: "identity_move_seal";
|
|
16
|
-
readonly received: "identity_move_received";
|
|
17
|
-
};
|
|
15
|
+
import { type OpenedMnemonicIdentity } from './webIdentityCarrier';
|
|
18
16
|
/** A fresh ephemeral key pair for one move. Keep the private key in memory only. */
|
|
19
17
|
export declare function generateMoveEphemeralKeyPair(): {
|
|
20
18
|
privateKey: string;
|
|
@@ -22,10 +20,44 @@ export declare function generateMoveEphemeralKeyPair(): {
|
|
|
22
20
|
};
|
|
23
21
|
/** The symmetric key both sides derive: HKDF(ECDH, salt = moveId). */
|
|
24
22
|
export declare function deriveMoveKey(ownEphemeralPrivateKey: string, otherEphemeralPublicKey: string, moveId: string): Uint8Array;
|
|
25
|
-
/**
|
|
26
|
-
export declare function
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
/** Initiator: commit to the ephemeral key before anyone else's key is known. The nonce stays in memory until the reveal. */
|
|
24
|
+
export declare function createMoveCommitment(initiatorEphemeralPublicKey: string): {
|
|
25
|
+
commitment: string;
|
|
26
|
+
nonce: string;
|
|
27
|
+
};
|
|
28
|
+
/** Responder: does the revealed key match the commitment read before joining? */
|
|
29
|
+
export declare function verifyMoveCommitment(initiatorEphemeralPublicKey: string, nonce: string, commitment: string): boolean;
|
|
30
|
+
/** The 6-digit code, bound to the move, both keys in their roles, and the commitment. */
|
|
31
|
+
export declare function deriveMoveSas(input: {
|
|
32
|
+
moveId: string;
|
|
33
|
+
initiatorEphemeralPublicKey: string;
|
|
34
|
+
responderEphemeralPublicKey: string;
|
|
35
|
+
initiatorCommitment: string;
|
|
36
|
+
}): string;
|
|
37
|
+
/** The digest a receipt binds: what was actually relayed. */
|
|
38
|
+
export declare function digestMoveCiphertext(sealed: {
|
|
39
|
+
nonce: string;
|
|
40
|
+
ciphertext: string;
|
|
41
|
+
}): string;
|
|
42
|
+
export interface MoveReceiptClaims {
|
|
43
|
+
moveId: string;
|
|
44
|
+
rootPublicKey: string;
|
|
45
|
+
initiatorEphemeralPublicKey: string;
|
|
46
|
+
responderEphemeralPublicKey: string;
|
|
47
|
+
ciphertextDigest: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Responder: sign the receipt with a signer that reads the root back from durable
|
|
51
|
+
* storage (Commons passes its keychain signer), so a receipt exists only for a
|
|
52
|
+
* root that was actually stored.
|
|
53
|
+
*/
|
|
54
|
+
export declare function signMoveReceipt(sign: (message: string) => Promise<string>, claims: MoveReceiptClaims): Promise<{
|
|
55
|
+
signature: string;
|
|
56
|
+
}>;
|
|
57
|
+
/** Initiator: is this receipt the root's, for exactly this move and ciphertext? */
|
|
58
|
+
export declare function verifyMoveReceipt(claims: MoveReceiptClaims, signature: string): Promise<boolean>;
|
|
59
|
+
/** Initiator: seal the phrase entropy (12–24 words) for the responder. */
|
|
60
|
+
export declare function sealIdentityForMove(identity: Pick<OpenedMnemonicIdentity, 'mnemonic' | 'publicKey'>, moveKey: Uint8Array, moveId: string): {
|
|
29
61
|
nonce: string;
|
|
30
62
|
ciphertext: string;
|
|
31
63
|
};
|
|
@@ -36,23 +68,7 @@ export declare function sealIdentityForMove(identity: Pick<OpenedWebIdentity, 'm
|
|
|
36
68
|
export declare function openMovedIdentity(sealed: {
|
|
37
69
|
nonce: string;
|
|
38
70
|
ciphertext: string;
|
|
39
|
-
}, moveKey: Uint8Array, moveId: string, expectedPublicKey: string):
|
|
40
|
-
/** The exact bytes a move proof or receipt signs. */
|
|
41
|
-
export declare function buildMoveMessage(action: string, moveId: string, timestamp: number): string;
|
|
42
|
-
/** Sign a move action with the identity key. */
|
|
43
|
-
export declare function signMoveAction(identity: Pick<OpenedWebIdentity, 'privateKey'>, action: string, moveId: string, timestamp?: number): Promise<{
|
|
44
|
-
signature: string;
|
|
45
|
-
timestamp: number;
|
|
46
|
-
}>;
|
|
47
|
-
/**
|
|
48
|
-
* Initiator: is this receipt really from the identity? Checked locally with the
|
|
49
|
-
* identity's public key, so a server that claims "completed" without Commons
|
|
50
|
-
* having the key cannot make the web destroy its copy.
|
|
51
|
-
*/
|
|
52
|
-
export declare function verifyMoveReceipt(publicKey: string, moveId: string, receipt: {
|
|
53
|
-
signature: string;
|
|
54
|
-
timestamp: number;
|
|
55
|
-
}): Promise<boolean>;
|
|
71
|
+
}, moveKey: Uint8Array, moveId: string, expectedPublicKey: string): OpenedMnemonicIdentity;
|
|
56
72
|
/** The QR payload for a move. */
|
|
57
73
|
export declare function buildMoveQrPayload(moveId: string): string;
|
|
58
74
|
/** The move id in a scanned payload, or `null` when it is not a move QR. */
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signing the one identity-proof format (ADR 0024 D7).
|
|
3
|
+
*
|
|
4
|
+
* The bytes come from `@oxy.so/contracts` `buildIdentityProofMessage`, which the
|
|
5
|
+
* API verifies against; payload digests hash `canonicalJson`. Nothing here builds
|
|
6
|
+
* its own JSON.
|
|
7
|
+
*/
|
|
8
|
+
import './polyfill';
|
|
9
|
+
import { type IdentityProof, type IdentityProofClaims } from '@oxy.so/contracts';
|
|
10
|
+
/** SHA-256 hex of the canonical JSON of `payload` — the `payloadDigest` claim. */
|
|
11
|
+
export declare function digestIdentityPayload(payload: unknown): string;
|
|
12
|
+
/** Sign `claims` with the root, producing the proof as it travels. */
|
|
13
|
+
export declare function signIdentityProof(identity: {
|
|
14
|
+
privateKey: string;
|
|
15
|
+
publicKey: string;
|
|
16
|
+
}, claims: IdentityProofClaims): Promise<IdentityProof>;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Web identity
|
|
2
|
+
* Web identity holder — the crypto of a browser holding a personal root (ADR 0024).
|
|
3
3
|
*
|
|
4
|
-
* An Oxy
|
|
5
|
-
* secp256k1 key (`recoveryPhrase.ts`)
|
|
6
|
-
*
|
|
7
|
-
* being able to use it:
|
|
4
|
+
* An Oxy root is usually a BIP-39 mnemonic whose seed's first 32 bytes are the
|
|
5
|
+
* secp256k1 key (`recoveryPhrase.ts`), and for a few imported identities a raw
|
|
6
|
+
* private key with no phrase. Commons keeps it in the device keychain. This
|
|
7
|
+
* module lets a browser hold the SAME root without Oxy ever being able to use it:
|
|
8
8
|
*
|
|
9
|
-
|
|
9
|
+
secret ──AEAD(DEK)──▶ sealed secret (phrase entropy or raw key)
|
|
10
10
|
* DEK ──AEAD(KEK_i)─▶ wraps[i] KEK_i = HKDF(PRF output of passkey i)
|
|
11
11
|
*
|
|
12
12
|
* The PRF output is produced inside the user's authenticator, behind user
|
|
13
13
|
* verification, and never leaves the page that asked for it. The envelope is
|
|
14
|
-
* therefore safe to store anywhere — the
|
|
15
|
-
*
|
|
14
|
+
* therefore safe to store anywhere — the holder host's IndexedDB and the server
|
|
15
|
+
* copy alike — and opens only with a registered passkey or the recovery material.
|
|
16
16
|
*
|
|
17
17
|
* PURE: no storage, no network, no WebAuthn call, no platform globals beyond the
|
|
18
18
|
* CSPRNG the AEAD polyfill guarantees. The caller runs the ceremony and hands the
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* Contract: `WebIdentityEnvelope` in `@oxy.so/contracts`.
|
|
23
23
|
*/
|
|
24
24
|
import './polyfill';
|
|
25
|
-
import { type WebIdentityEnvelope
|
|
25
|
+
import { type WebIdentityEnvelope } from '@oxy.so/contracts';
|
|
26
26
|
/**
|
|
27
27
|
* The PRF input every identity-carrier ceremony evaluates (`prf.eval.first`).
|
|
28
28
|
*
|
|
@@ -31,6 +31,8 @@ import { type WebIdentityEnvelope, type WebIdentityWrap } from '@oxy.so/contract
|
|
|
31
31
|
* scheme change bumps the label — and with it every KEK — instead of mutating it.
|
|
32
32
|
*/
|
|
33
33
|
export declare const WEB_IDENTITY_PRF_INPUT: Uint8Array;
|
|
34
|
+
/** A WebAuthn PRF output is 32 bytes (HMAC-SHA-256). Nothing shorter or longer is usable. */
|
|
35
|
+
export declare const WEB_IDENTITY_PRF_OUTPUT_LENGTH = 32;
|
|
34
36
|
/** Why an envelope did not open. Every value is a normal outcome a UI can explain. */
|
|
35
37
|
export type WebIdentityUnlockFailure =
|
|
36
38
|
/** The passkey used is not one of the envelope's wraps. */
|
|
@@ -38,7 +40,7 @@ export type WebIdentityUnlockFailure =
|
|
|
38
40
|
/**
|
|
39
41
|
* The passkey IS listed but its PRF output does not open its wrap — a synced
|
|
40
42
|
* copy returning a different PRF value, or a provider that silently changed it.
|
|
41
|
-
* Recoverable with another passkey or the
|
|
43
|
+
* Recoverable with another passkey or the recovery material.
|
|
42
44
|
*/
|
|
43
45
|
| 'prf-mismatch'
|
|
44
46
|
/** The envelope itself is malformed or tampered with. */
|
|
@@ -47,39 +49,81 @@ export declare class WebIdentityUnlockError extends Error {
|
|
|
47
49
|
readonly failure: WebIdentityUnlockFailure;
|
|
48
50
|
constructor(failure: WebIdentityUnlockFailure, message: string);
|
|
49
51
|
}
|
|
50
|
-
/**
|
|
51
|
-
export interface
|
|
52
|
+
/** A root that came from a BIP-39 phrase (12–24 words). Hold it for one operation, then wipe. */
|
|
53
|
+
export interface OpenedMnemonicIdentity {
|
|
54
|
+
kind: 'mnemonic';
|
|
52
55
|
mnemonic: string;
|
|
53
|
-
/** 32-byte secp256k1 private key, lowercase hex. */
|
|
56
|
+
/** 32-byte secp256k1 private key, lowercase hex (`seed[0:32]`). */
|
|
54
57
|
privateKey: string;
|
|
55
58
|
/** Uncompressed SEC1 public key, lowercase hex (Oxy's canonical form). */
|
|
56
59
|
publicKey: string;
|
|
57
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* A root that was imported as a raw private key and never had a phrase. It has
|
|
63
|
+
* no mnemonic, and nothing may ever derive or display one for it (ADR 0024 D5).
|
|
64
|
+
*/
|
|
65
|
+
export interface OpenedRawKeyIdentity {
|
|
66
|
+
kind: 'raw-key';
|
|
67
|
+
mnemonic: null;
|
|
68
|
+
privateKey: string;
|
|
69
|
+
publicKey: string;
|
|
70
|
+
}
|
|
71
|
+
/** The identity in usable form. Hold it for one operation, then wipe it. */
|
|
72
|
+
export type OpenedWebIdentity = OpenedMnemonicIdentity | OpenedRawKeyIdentity;
|
|
73
|
+
/** Material a person can recover a root from. */
|
|
74
|
+
export type WebIdentityRecoveryMaterial = {
|
|
75
|
+
kind: 'mnemonic';
|
|
76
|
+
mnemonic: string;
|
|
77
|
+
} | {
|
|
78
|
+
kind: 'raw-key';
|
|
79
|
+
privateKey: string;
|
|
80
|
+
};
|
|
58
81
|
/** Overwrite a buffer holding secret material. Best effort — JS gives no stronger guarantee. */
|
|
59
82
|
export declare function wipeBytes(bytes: Uint8Array): void;
|
|
83
|
+
/** Best-effort removal of secret strings from an opened identity. */
|
|
84
|
+
export declare function wipeOpenedIdentity(identity: OpenedWebIdentity): void;
|
|
85
|
+
/** Normalize a typed phrase: trimmed, lowercase, single spaces. */
|
|
86
|
+
export declare function normalizeMnemonic(mnemonic: string): string;
|
|
60
87
|
/**
|
|
61
88
|
* Derive the identity from a mnemonic exactly as Commons does
|
|
62
|
-
* (`RecoveryPhraseService`): seed → first 32 bytes → secp256k1.
|
|
89
|
+
* (`RecoveryPhraseService`): seed → first 32 bytes → secp256k1. Any standard
|
|
90
|
+
* BIP-39 length (12, 15, 18, 21, 24 words) is accepted; the derivation does not
|
|
91
|
+
* depend on the length.
|
|
63
92
|
*/
|
|
64
|
-
export declare function deriveIdentityFromMnemonic(mnemonic: string):
|
|
93
|
+
export declare function deriveIdentityFromMnemonic(mnemonic: string): OpenedMnemonicIdentity;
|
|
94
|
+
/** A raw 32-byte private key (hex, optional `0x`) as an identity. Never gains a phrase. */
|
|
95
|
+
export declare function deriveIdentityFromPrivateKey(privateKey: string): OpenedRawKeyIdentity;
|
|
96
|
+
/**
|
|
97
|
+
* Read what a person typed as recovery material: a BIP-39 phrase, or a 64-hex
|
|
98
|
+
* private key. Throws `Invalid recovery material` for anything else.
|
|
99
|
+
*/
|
|
100
|
+
export declare function parseRecoveryMaterial(input: string): WebIdentityRecoveryMaterial;
|
|
101
|
+
/** Derive the identity recovery material names. */
|
|
102
|
+
export declare function deriveIdentityFromRecoveryMaterial(material: WebIdentityRecoveryMaterial): OpenedWebIdentity;
|
|
65
103
|
/** A brand-new 12-word identity. Nothing is persisted. */
|
|
66
|
-
export declare function generateWebIdentity():
|
|
104
|
+
export declare function generateWebIdentity(): OpenedMnemonicIdentity;
|
|
67
105
|
/** A fresh random data key for a new envelope. */
|
|
68
106
|
export declare function generateDataKey(): Uint8Array;
|
|
107
|
+
/** Whether `bytes` is a usable PRF output: exactly 32 bytes. */
|
|
108
|
+
export declare function isUsablePrfOutput(bytes: Uint8Array | null | undefined): bytes is Uint8Array;
|
|
69
109
|
/** The key-encryption key a passkey's PRF output yields for its own wrap. */
|
|
70
110
|
export declare function deriveKeyEncryptionKey(prfOutput: Uint8Array, credentialId: string): Uint8Array;
|
|
71
|
-
/**
|
|
72
|
-
export
|
|
111
|
+
/** One passkey's contribution to an envelope. */
|
|
112
|
+
export interface WrapInput {
|
|
113
|
+
prfOutput: Uint8Array;
|
|
114
|
+
credentialId: string;
|
|
115
|
+
/** The RP ID the passkey lives under; bound into the wrap. */
|
|
116
|
+
rpId: string;
|
|
117
|
+
/** Set when this PRF output came from a ceremony separate from the one that created the wrap. */
|
|
118
|
+
verifiedAt?: string;
|
|
119
|
+
}
|
|
73
120
|
/**
|
|
74
121
|
* Seal an identity into a new envelope that opens with the given passkey.
|
|
75
122
|
*
|
|
76
123
|
* Returns the data key too, so the caller can add further wraps in the same
|
|
77
124
|
* session; wipe it when done.
|
|
78
125
|
*/
|
|
79
|
-
export declare function sealWebIdentity(identity:
|
|
80
|
-
prfOutput: Uint8Array;
|
|
81
|
-
credentialId: string;
|
|
82
|
-
}, now?: Date): {
|
|
126
|
+
export declare function sealWebIdentity(identity: OpenedWebIdentity, firstWrap: WrapInput, now?: Date): {
|
|
83
127
|
envelope: WebIdentityEnvelope;
|
|
84
128
|
dataKey: Uint8Array;
|
|
85
129
|
};
|
|
@@ -88,36 +132,19 @@ export declare function unwrapDataKey(envelope: WebIdentityEnvelope, prfOutput:
|
|
|
88
132
|
/**
|
|
89
133
|
* Open an envelope with its data key.
|
|
90
134
|
*
|
|
91
|
-
* The derived public key is checked against the envelope's own: a sealed
|
|
135
|
+
* The derived public key is checked against the envelope's own: a sealed secret
|
|
92
136
|
* that decrypts into a different identity is treated as corruption, never used.
|
|
93
137
|
*/
|
|
94
138
|
export declare function openWebIdentity(envelope: WebIdentityEnvelope, dataKey: Uint8Array): OpenedWebIdentity;
|
|
95
139
|
/** Unwrap and open in one step. */
|
|
96
140
|
export declare function unlockWebIdentity(envelope: WebIdentityEnvelope, prfOutput: Uint8Array, credentialId: string): OpenedWebIdentity;
|
|
97
141
|
/** Add (or replace) one passkey's wrap. Requires the data key of an unlocked envelope. */
|
|
98
|
-
export declare function addWrap(envelope: WebIdentityEnvelope, dataKey: Uint8Array,
|
|
99
|
-
/** Remove one passkey's wrap. The last wrap can never be removed — an envelope nobody can open is a loss. */
|
|
100
|
-
export declare function removeWrap(envelope: WebIdentityEnvelope, credentialId: string): WebIdentityEnvelope;
|
|
142
|
+
export declare function addWrap(envelope: WebIdentityEnvelope, dataKey: Uint8Array, wrapInput: WrapInput, now?: Date): WebIdentityEnvelope;
|
|
101
143
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
144
|
+
* Record that a wrap's passkey opened the envelope in a ceremony of its own. The
|
|
145
|
+
* AEAD does not cover `verifiedAt`; it is holder metadata the owner writes with a
|
|
146
|
+
* root proof, not a cryptographic claim.
|
|
105
147
|
*/
|
|
106
|
-
export declare function
|
|
107
|
-
/**
|
|
108
|
-
export declare function
|
|
109
|
-
signature: string;
|
|
110
|
-
timestamp: number;
|
|
111
|
-
}>;
|
|
112
|
-
/**
|
|
113
|
-
* The 6-digit short authentication string both sides of an identity transfer show.
|
|
114
|
-
*
|
|
115
|
-
* Bound to the pairing and to BOTH ephemeral public keys in their roles, so a relay
|
|
116
|
-
* that substitutes either key produces a different code on each screen. The user
|
|
117
|
-
* comparing the two codes is what makes the transfer safe against the relay itself.
|
|
118
|
-
*/
|
|
119
|
-
export declare function deriveTransferSas(input: {
|
|
120
|
-
pairingId: string;
|
|
121
|
-
initiatorEphemeralPublicKey: string;
|
|
122
|
-
responderEphemeralPublicKey: string;
|
|
123
|
-
}): string;
|
|
148
|
+
export declare function markWrapVerified(envelope: WebIdentityEnvelope, credentialId: string, now?: Date): WebIdentityEnvelope;
|
|
149
|
+
/** Remove one passkey's wrap. The last wrap can never be removed — an envelope nobody can open is a loss. */
|
|
150
|
+
export declare function removeWrap(envelope: WebIdentityEnvelope, credentialId: string): WebIdentityEnvelope;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -30,7 +30,6 @@ export type { CommonsSignInHandle, CommonsSignInStatus, CommonsSignInPurpose, Co
|
|
|
30
30
|
export type { PushTokenPlatform, RegisterPushTokenInput, } from './mixins/OxyServices.notifications';
|
|
31
31
|
export type { ServiceApp, ServiceActingAsVerification, OxyAuthRefusal } from './mixins/OxyServices.utility';
|
|
32
32
|
export type { ContactDiscoveryMatch, ContactDiscoveryResponse, } from './mixins/OxyServices.contacts';
|
|
33
|
-
export type { InitDeviceTransferResult, DeviceTransferOutcome, } from './mixins/OxyServices.deviceTransfer';
|
|
34
33
|
export type { BulkFollowEntry, BulkFollowResult, BulkUnfollowEntry, BulkUnfollowResult, FollowMutationResult, ViewerGraph, } from './mixins/OxyServices.user';
|
|
35
34
|
export { OxyAppDataIdentifierError } from './mixins/OxyServices.appData';
|
|
36
35
|
export { getNormalizedUserId, normalizeUserIdentity, normalizeUserIdentityOrNull, } from './utils/userIdentity';
|
|
@@ -44,7 +43,7 @@ export type { StoreCategory, StoreRating, StoreListingSummary, StoreListingDetai
|
|
|
44
43
|
export type { AccountKind, AccountCategoryId, AccountRelationship, AccountRole, AccountMemberStatus, AccountMemberSource, AccountMember, AccountNode, ListAccountsOptions, CreateAccountInput, UpdateAccountInput, ProvisionChannelInput, ProvisionChannelMemberInput, ProvisionChannelResult, InviteAccountMemberInput, UpdateAccountMemberInput, TransferAccountOwnershipInput, AccountSuccessResult, SwitchAccountResult, Application, ApplicationType, ApplicationStatus, ApplicationCredential, ApplicationCredentialType, ApplicationCredentialStatus, ApplicationEnvironment, CreateApplicationInput, UpdateApplicationInput, CreateApplicationCredentialInput, RotateApplicationCredentialInput, ApplicationCredentialWithSecret, RotateApplicationCredentialResult, ApplicationUsagePeriod, ApplicationUsageSummary, ApplicationUsageByDay, ApplicationUsageByEndpoint, ApplicationUsageStats, } from './mixins/OxyServices.accounts';
|
|
45
44
|
export { ACCOUNT_CATEGORY_IDS, MAX_ACCOUNT_CATEGORIES, SELECTABLE_ACCOUNT_CATEGORY_IDS, isSelectableAccountCategoryId, kindAcceptsAccountCategories, } from './mixins/OxyServices.accounts';
|
|
46
45
|
export { buildUserDid } from './mixins/OxyServices.identity';
|
|
47
|
-
export type { IdentityRecordType,
|
|
46
|
+
export type { IdentityRecordType, LinkAuthMethodResult, PublishRecordResult, VerifyRecordResult, VerifyDomainResult, RemoveDomainResult, RotateKeyProof, RotateKeyOptions, RotateKeyResult, } from './mixins/OxyServices.identity';
|
|
48
47
|
export { parseIdPayload, parseAttestPayload, verifyPublicCardAttestation, } from './mixins/OxyServices.civic';
|
|
49
48
|
export type { CivicCardResult, IdCardRef, AttestQrPayload, ParsedAttestPayload, SubmitRealLifeAttestationInput, DenyValidationResult, VouchForPersonInput, WithdrawVouchResult, IssueCredentialInput, RevokeCredentialResult, } from './mixins/OxyServices.civic';
|
|
50
49
|
export type { UserNodeStatus, UserNodeMode, UserNodeController, UserNodeLivenessStatus, RegisterNodeInput, RemoveNodeResult } from './mixins/OxyServices.nodes';
|
|
@@ -70,9 +69,11 @@ export { hkdfSha256 } from './crypto/kdf';
|
|
|
70
69
|
export { encryptAead, decryptAead, AEAD_KEY_LENGTH, AEAD_NONCE_LENGTH, } from './crypto/aead';
|
|
71
70
|
export type { AeadResult } from './crypto/aead';
|
|
72
71
|
export { deriveSharedSecret } from './crypto/ecdh';
|
|
73
|
-
export { WEB_IDENTITY_PRF_INPUT, WebIdentityUnlockError,
|
|
74
|
-
export type { OpenedWebIdentity, WebIdentityUnlockFailure } from './crypto/webIdentityCarrier';
|
|
75
|
-
export {
|
|
72
|
+
export { WEB_IDENTITY_PRF_INPUT, WebIdentityUnlockError, WEB_IDENTITY_PRF_OUTPUT_LENGTH, addWrap, deriveIdentityFromMnemonic, deriveIdentityFromPrivateKey, deriveIdentityFromRecoveryMaterial, deriveKeyEncryptionKey, generateDataKey, generateWebIdentity, isUsablePrfOutput, markWrapVerified, normalizeMnemonic, openWebIdentity, parseRecoveryMaterial, removeWrap, sealWebIdentity, unlockWebIdentity, unwrapDataKey, wipeBytes, wipeOpenedIdentity, } from './crypto/webIdentityCarrier';
|
|
73
|
+
export type { OpenedMnemonicIdentity, OpenedRawKeyIdentity, OpenedWebIdentity, WebIdentityRecoveryMaterial, WebIdentityUnlockFailure, WrapInput, } from './crypto/webIdentityCarrier';
|
|
74
|
+
export { digestIdentityPayload, signIdentityProof } from './crypto/identityProof';
|
|
75
|
+
export { buildMoveQrPayload, createMoveCommitment, deriveMoveKey, deriveMoveSas, digestMoveCiphertext, generateMoveEphemeralKeyPair, openMovedIdentity, parseMoveQrPayload, sealIdentityForMove, signMoveReceipt, verifyMoveCommitment, verifyMoveReceipt, } from './crypto/identityMove';
|
|
76
|
+
export type { MoveReceiptClaims } from './crypto/identityMove';
|
|
76
77
|
export { DeviceManager } from './utils/deviceManager';
|
|
77
78
|
export type { DeviceFingerprint, StoredDeviceInfo } from './utils/deviceManager';
|
|
78
79
|
export type { OxyConfig, PrivacySettings, NotificationPreferences, UserPreferences, User, LoginResponse, Notification, Wallet, Transaction, BlockedUser, RestrictedUser, TransferFundsRequest, PurchaseRequest, WithdrawalRequest, TransactionResponse, PaginationInfo, SearchProfilesResponse, ApiError, PaymentMethod, PaymentRequest, PaymentResponse, AnalyticsData, FollowerDetails, ContentViewer, FileMetadata, FileUploadResponse, FileListResponse, FileUpdateRequest, FileDeleteResponse, RNFileDescriptor, AssetUploadInput, FileVisibility, AssetLink, AssetMetadata, AssetVariant, Asset, AssetInitRequest, AssetInitResponse, AssetCompleteRequest, AssetLinkRequest, AssetUnlinkRequest, AssetUrlResponse, BatchFileAccessEntry, BatchFileAccessResponse, AssetDeleteSummary, AssetUpdateVisibilityRequest, AssetUpdateVisibilityResponse, ServiceAssetMetadata, ServiceAssetMetadataBySha, AccountStorageCategoryUsage, AccountStorageUsageResponse, SecurityEventType, SecurityEventSeverity, SecurityActivity, SecurityActivityResponse, AssetUploadProgress, DeviceLinkedSession, DeviceLinkedSessionsResponse, DeviceLinkedSessionLogoutResponse, UpdateDeviceNameResponse, } from './models/interfaces';
|
|
@@ -141,7 +142,7 @@ export { AccountNotOnDeviceError } from './mixins/OxyServices.deviceBoot';
|
|
|
141
142
|
export { refreshPersistedSession, refreshDeviceSecretArm, createAuthRefreshHandler, installAuthRefreshHandler, startTokenRefreshScheduler, TOKEN_REFRESH_LEAD_MS, } from './session/refresh';
|
|
142
143
|
export type { RefreshDeps, TokenRefreshSchedulerHandle, DeviceSecretMintOutcome } from './session/refresh';
|
|
143
144
|
export { OxyInferenceClient, OxyInferenceError, OxyInferenceProtocolError, OXY_INFERENCE_BASE_URL, } from './inference/OxyInferenceClient';
|
|
144
|
-
export type { OxyInferenceClientOptions, OxyInferenceCredential, OxyInferenceFetch, OxyInferenceRequestOptions, OxyInferenceResponse, OxyGenerationReceipt, OxyResponsesRequest, } from './inference/OxyInferenceClient';
|
|
145
|
+
export type { OxyInferenceClientOptions, OxyInferenceCredential, OxyInferenceFetch, OxyInferenceRequestOptions, OxyInferenceResponse, OxyGenerationReceipt, OxyResponsesRequest, OxySpeechRequest, OxySpeechResponse, } from './inference/OxyInferenceClient';
|
|
145
146
|
export { runSessionColdBoot } from './boot/sessionColdBoot';
|
|
146
147
|
export type { RunSessionColdBootOptions, SessionMode, SignedOutReason, DeviceBootSession, } from './boot/sessionColdBoot';
|
|
147
148
|
export { packageInfo } from './constants/version';
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
* schema, so a rename on either side fails a build rather than a customer's
|
|
50
50
|
* request.
|
|
51
51
|
*/
|
|
52
|
-
import type { CurrencyCode, ExactDecimal, InferenceEnvironment, InferenceErrorCode, InferenceFinishReason, InferenceMessage, InferenceRequestOutcome, InferenceStreamEvent, ModelCatalogueEntry, ResponseFormat, RoutingPolicyReference, RoutingProfile, ToolChoice, ToolDefinition, UnitPrice, UsageQuantity, UsageSource } from '@oxy.so/contracts';
|
|
52
|
+
import type { CurrencyCode, ExactDecimal, InferenceEnvironment, InferenceErrorCode, InferenceFinishReason, InferenceMessage, InferenceRequestOutcome, InferenceAudioMediaType, InferenceStreamEvent, InferenceSpeechParameters, ModelCatalogueEntry, ResponseFormat, RoutingPolicyReference, RoutingProfile, ToolChoice, ToolDefinition, UnitPrice, UsageQuantity, UsageSource } from '@oxy.so/contracts';
|
|
53
53
|
/** The base URL of the Oxy API, when a caller names none. */
|
|
54
54
|
export declare const OXY_INFERENCE_BASE_URL = "https://api.oxy.so";
|
|
55
55
|
/**
|
|
@@ -110,6 +110,24 @@ export interface OxyResponsesRequest {
|
|
|
110
110
|
/** Your own correlation id, echoed on the response. */
|
|
111
111
|
readonly clientRequestId?: string;
|
|
112
112
|
}
|
|
113
|
+
/** Speech uses the same credential and delegation lane as responses. */
|
|
114
|
+
export type OxySpeechRequest = ({
|
|
115
|
+
readonly model: string;
|
|
116
|
+
readonly routingProfileId?: never;
|
|
117
|
+
} | {
|
|
118
|
+
readonly routingProfileId: string;
|
|
119
|
+
readonly model?: never;
|
|
120
|
+
}) & {
|
|
121
|
+
readonly input: string;
|
|
122
|
+
readonly voice: string;
|
|
123
|
+
readonly response_format?: InferenceSpeechParameters['responseFormat'];
|
|
124
|
+
readonly speed?: number;
|
|
125
|
+
};
|
|
126
|
+
export interface OxySpeechResponse {
|
|
127
|
+
readonly audio: Uint8Array;
|
|
128
|
+
readonly mediaType: InferenceAudioMediaType;
|
|
129
|
+
readonly requestId: string;
|
|
130
|
+
}
|
|
113
131
|
export interface OxyInferenceRequestOptions {
|
|
114
132
|
/**
|
|
115
133
|
* Abort the request. The edge treats a client disconnect as a cancellation:
|
|
@@ -307,6 +325,8 @@ export declare class OxyInferenceClient {
|
|
|
307
325
|
* `code`, `retryable` and `requestId`.
|
|
308
326
|
*/
|
|
309
327
|
respond(request: OxyResponsesRequest, options?: OxyInferenceRequestOptions): Promise<OxyInferenceResponse>;
|
|
328
|
+
/** Generate audio bytes through Oxy's authenticated inference edge. */
|
|
329
|
+
speech(request: OxySpeechRequest, options?: OxyInferenceRequestOptions): Promise<OxySpeechResponse>;
|
|
310
330
|
/**
|
|
311
331
|
* Stream one inference request from `POST /v1/responses`.
|
|
312
332
|
*
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { User } from '../models/interfaces';
|
|
7
7
|
import type { LoginResult, CommonsDenyReason } from '@oxy.so/contracts';
|
|
8
|
+
import { type IdentityProof, type WebIdentityEnvelope } from '@oxy.so/contracts';
|
|
8
9
|
import type { SessionLoginResponse } from '../models/session';
|
|
9
10
|
import type { OxyServicesBase } from '../OxyServices.base';
|
|
10
11
|
import type { PublicApplication } from './OxyServices.connectedApps';
|
|
@@ -387,6 +388,28 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
|
|
|
387
388
|
* @param apiSecret - Application credential secret (optional if configureServiceAuth was called)
|
|
388
389
|
*/
|
|
389
390
|
getServiceToken(apiKey?: string, apiSecret?: string): Promise<string>;
|
|
391
|
+
/**
|
|
392
|
+
* Whether this process can prove what it is (ADR 0026).
|
|
393
|
+
*
|
|
394
|
+
* The check and the module that performs it are loaded LAZILY and only on a
|
|
395
|
+
* Node host. `@oxy.so/core`'s root barrel reaches React Native and Expo, and
|
|
396
|
+
* `server/workloadIdentity` imports `node:crypto` — a static import here
|
|
397
|
+
* would pull it into every mobile bundle for a path a phone can never take.
|
|
398
|
+
*
|
|
399
|
+
* @internal
|
|
400
|
+
*/
|
|
401
|
+
_canUseWorkloadIdentity(): Promise<boolean>;
|
|
402
|
+
/**
|
|
403
|
+
* A service token obtained by attestation, cached like a credential's.
|
|
404
|
+
*
|
|
405
|
+
* The cache key is a constant, not a credential hash: a process has exactly
|
|
406
|
+
* one identity, so there is nothing to key on and nothing to keep separate.
|
|
407
|
+
* The secret-comparison guard the credential path applies has nothing to
|
|
408
|
+
* compare here, which is the point — there is no secret.
|
|
409
|
+
*
|
|
410
|
+
* @internal
|
|
411
|
+
*/
|
|
412
|
+
_getWorkloadServiceToken(): Promise<string>;
|
|
390
413
|
/**
|
|
391
414
|
* Perform the actual /auth/service-token request and cache the result.
|
|
392
415
|
* Separated so getServiceToken() can deduplicate concurrent calls.
|
|
@@ -799,6 +822,15 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
|
|
|
799
822
|
username?: string;
|
|
800
823
|
deviceName?: string;
|
|
801
824
|
deviceFingerprint?: string;
|
|
825
|
+
/**
|
|
826
|
+
* Sign-up only: the root created on the holder before this call, sealed
|
|
827
|
+
* under the passkey being registered, plus its `enroll_identity` proof
|
|
828
|
+
* (ADR 0024 D4). The account is created WITH it or not at all.
|
|
829
|
+
*/
|
|
830
|
+
identity?: {
|
|
831
|
+
envelope: WebIdentityEnvelope;
|
|
832
|
+
proof: IdentityProof;
|
|
833
|
+
};
|
|
802
834
|
}): Promise<{
|
|
803
835
|
success: true;
|
|
804
836
|
message: string;
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Provides typed access to Oxy's AtProto/Bluesky-flavoured identity &
|
|
5
5
|
* portability layer:
|
|
6
6
|
* - DID resolution (`did:web:oxy.so:u:<userId>`, derived on demand by the API).
|
|
7
|
-
* - The auth-method ↔ DID verification-method mapping
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* - The auth-method ↔ DID verification-method mapping (`GET /auth/methods`) and
|
|
8
|
+
* passkey removal. A root is linked by the holder flows (ADR 0024) and never
|
|
9
|
+
* unlinked; it is replaced by rotation.
|
|
10
10
|
* - Signed records: clients sign an envelope with their own cryptographic key
|
|
11
11
|
* (`SignatureService.signRecord` + the shared `canonicalize`) and publish it;
|
|
12
12
|
* anyone can fetch and verify it.
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
* the API validates its output against, so producer and consumer cannot drift.
|
|
20
20
|
*
|
|
21
21
|
* Identity signing is NATIVE-ONLY: the private key lives in native secure
|
|
22
|
-
* storage, so `
|
|
22
|
+
* storage, so `signRecord` and `publishRecord` require an
|
|
23
23
|
* on-device identity and throw on web (where `KeyManager.getPublicKey()` is
|
|
24
24
|
* always `null`).
|
|
25
25
|
*/
|
|
26
|
-
import type { AuthMethodsResponse, DidDocument, DomainVerificationInstructions, ExportBundle, OxySignedRecordType, SignedRecordEnvelope, VerifiedDomain } from '@oxy.so/contracts';
|
|
26
|
+
import type { AuthMethodsResponse, IdentityRootStatus, DidDocument, DomainVerificationInstructions, ExportBundle, OxySignedRecordType, SignedRecordEnvelope, VerifiedDomain } from '@oxy.so/contracts';
|
|
27
27
|
import type { OxyServicesBase } from '../OxyServices.base';
|
|
28
28
|
import { type PendingIdentityResult } from '../crypto/recoveryPhrase';
|
|
29
29
|
/**
|
|
@@ -33,12 +33,7 @@ import { type PendingIdentityResult } from '../crypto/recoveryPhrase';
|
|
|
33
33
|
* record set.
|
|
34
34
|
*/
|
|
35
35
|
export type IdentityRecordType = OxySignedRecordType;
|
|
36
|
-
/**
|
|
37
|
-
export type UnlinkableAuthMethodType = 'identity' | 'webauthn';
|
|
38
|
-
/**
|
|
39
|
-
* Result of a link/unlink auth-method mutation (`POST /auth/link`,
|
|
40
|
-
* `DELETE /auth/link/:type`).
|
|
41
|
-
*/
|
|
36
|
+
/** Result of an auth-method mutation (`DELETE /auth/link/webauthn/:id`). */
|
|
42
37
|
export interface LinkAuthMethodResult {
|
|
43
38
|
success: boolean;
|
|
44
39
|
message: string;
|
|
@@ -145,31 +140,22 @@ export declare function OxyServicesIdentityMixin<T extends typeof OxyServicesBas
|
|
|
145
140
|
*/
|
|
146
141
|
listAuthMethods(): Promise<AuthMethodsResponse>;
|
|
147
142
|
/**
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* or no user is authenticated). The signed payload is
|
|
154
|
-
* `JSON.stringify({ action: 'link_identity', userId, timestamp })` — the
|
|
155
|
-
* exact bytes the server reconstructs and verifies.
|
|
156
|
-
*/
|
|
157
|
-
linkIdentityKey(): Promise<LinkAuthMethodResult>;
|
|
158
|
-
/**
|
|
159
|
-
* Unlink an authentication method from the current account. The server
|
|
160
|
-
* refuses to remove the last remaining method (the account would become
|
|
161
|
-
* inaccessible). Unlinking `identity` downgrades the account to custodial.
|
|
162
|
-
*
|
|
163
|
-
* @param type - The auth-method type to remove.
|
|
143
|
+
* The signed-in account's root readiness (ADR 0024 D5): whether a root is
|
|
144
|
+
* linked, how many passkeys can open the web holder, whether the root has a
|
|
145
|
+
* phrase and whether it is saved and was shown to recover it. Metadata only —
|
|
146
|
+
* nothing here can open the root — so any first-party surface may show a
|
|
147
|
+
* "save your recovery phrase" reminder from it.
|
|
164
148
|
*/
|
|
165
|
-
|
|
149
|
+
getIdentityRootStatus(): Promise<IdentityRootStatus>;
|
|
166
150
|
/**
|
|
167
151
|
* Remove ONE passkey (WebAuthn credential) from the current account.
|
|
168
152
|
*
|
|
169
|
-
* Passkeys are per-credential, so
|
|
170
|
-
* removes an auth method by type) this targets a specific credential id.
|
|
153
|
+
* Passkeys are per-credential, so this targets a specific credential id.
|
|
171
154
|
* The server refuses to remove the last remaining auth method (the account
|
|
172
155
|
* would become inaccessible) and deletes the stored `WebauthnCredential`.
|
|
156
|
+
* A passkey that also opens the account's root on the web takes its wrap with
|
|
157
|
+
* it, and the ONLY such passkey is refused with
|
|
158
|
+
* `code: 'IDENTITY_LAST_WEB_HOLDER'` (ADR 0024 D6).
|
|
173
159
|
*
|
|
174
160
|
* @param credentialId - The passkey's public credential id
|
|
175
161
|
* (`AuthMethodEntry.credentialId`).
|
|
@@ -34,7 +34,6 @@ import { OxyServicesNodesMixin } from './OxyServices.nodes';
|
|
|
34
34
|
import { OxyServicesFollowGraphMixin } from './OxyServices.followGraph';
|
|
35
35
|
import { OxyServicesInferenceMixin } from './OxyServices.inference';
|
|
36
36
|
import { OxyServicesDeviceBootMixin } from './OxyServices.deviceBoot';
|
|
37
|
-
import { OxyServicesDeviceTransferMixin } from './OxyServices.deviceTransfer';
|
|
38
37
|
/**
|
|
39
38
|
* Instance shape of every mixin in the pipeline, intersected. The runtime
|
|
40
39
|
* `composeOxyServices()` produces a class whose instances expose all of
|
|
@@ -44,7 +43,7 @@ import { OxyServicesDeviceTransferMixin } from './OxyServices.deviceTransfer';
|
|
|
44
43
|
* If you add a new mixin to `MIXIN_PIPELINE`, add it here too so its methods
|
|
45
44
|
* are visible without a cast.
|
|
46
45
|
*/
|
|
47
|
-
type AllMixinInstances = InstanceType<ReturnType<typeof OxyServicesAuthMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesUserMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesIdentityMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesIdentityBackupMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesPrivacyMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesLanguageMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesPaymentMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesReputationMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAssetsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAccountsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesConnectedAppsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAgencyMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesStoreMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesLocationMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAnalyticsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesDevicesMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesSecurityMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesFeaturesMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesTopicsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesContactsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesNotificationsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAppDataMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesCivicMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesChainsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesNodesMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesFollowGraphMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesInferenceMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesDeviceBootMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof
|
|
46
|
+
type AllMixinInstances = InstanceType<ReturnType<typeof OxyServicesAuthMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesUserMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesIdentityMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesIdentityBackupMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesPrivacyMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesLanguageMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesPaymentMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesReputationMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAssetsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAccountsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesConnectedAppsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAgencyMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesStoreMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesLocationMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAnalyticsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesDevicesMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesSecurityMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesFeaturesMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesTopicsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesContactsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesNotificationsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesAppDataMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesCivicMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesChainsMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesNodesMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesFollowGraphMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesInferenceMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesDeviceBootMixin<typeof OxyServicesBase>>> & InstanceType<ReturnType<typeof OxyServicesUtilityMixin<typeof OxyServicesBase>>>;
|
|
48
47
|
/**
|
|
49
48
|
* Constructor type for the fully composed mixin pipeline. Each mixin returns
|
|
50
49
|
* a new constructor that augments its input; reducing across the pipeline
|
|
@@ -38,3 +38,11 @@ export { isOfficialWebOrigin } from '../utils/officialOrigins';
|
|
|
38
38
|
export { createEcosystemTraffic } from './traffic';
|
|
39
39
|
export type { EcosystemTrafficOptions } from './traffic';
|
|
40
40
|
export { observeNodeHttp, withoutNodeHttpObservation } from './trafficNodeHttp';
|
|
41
|
+
/**
|
|
42
|
+
* Workload identity (ADR 0026): a first-party service asks Oxy for a service
|
|
43
|
+
* token by proving what it IS, with no api key and no secret. Server-only, and
|
|
44
|
+
* exported from this subpath rather than the root barrel because it reaches the
|
|
45
|
+
* container credentials endpoint.
|
|
46
|
+
*/
|
|
47
|
+
export { canAttestWorkloadIdentity, requestWorkloadServiceToken } from './workloadIdentity';
|
|
48
|
+
export type { WorkloadServiceToken, WorkloadServiceTokenOptions } from './workloadIdentity';
|