@oxy.so/core 4.5.0-oxy-one.1 → 4.5.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/README.md +1 -1
- package/dist/cjs/HttpService.js +63 -19
- package/dist/cjs/api/accounts.js +10 -3
- package/dist/cjs/api/agency.js +3 -1
- package/dist/cjs/api/apps.js +15 -4
- package/dist/cjs/api/assets.js +39 -11
- package/dist/cjs/api/auth.js +28 -8
- package/dist/cjs/api/billing.js +24 -7
- package/dist/cjs/api/civic.js +14 -4
- package/dist/cjs/api/follows.js +9 -2
- package/dist/cjs/api/identity.js +31 -9
- package/dist/cjs/api/nodes.js +3 -1
- package/dist/cjs/api/privacy.js +8 -2
- package/dist/cjs/api/session.js +15 -4
- package/dist/cjs/api/store.js +15 -5
- package/dist/cjs/api/topics.js +10 -3
- package/dist/cjs/api/users.js +16 -4
- package/dist/cjs/boot/sessionColdBoot.js +40 -13
- package/dist/cjs/constants/version.js +6 -6
- package/dist/cjs/crypto/identityMarker.js +3 -1
- package/dist/cjs/crypto/identityProof.js +6 -1
- package/dist/cjs/crypto/keyManager.js +87 -32
- package/dist/cjs/crypto/recoveryPhrase.js +2 -2
- package/dist/cjs/crypto/signatureService.js +3 -4
- package/dist/cjs/i18n/index.js +16 -3
- package/dist/cjs/i18n/locales/ar-SA.js +366 -366
- package/dist/cjs/i18n/locales/ca-ES.js +366 -366
- package/dist/cjs/i18n/locales/de-DE.js +366 -366
- package/dist/cjs/i18n/locales/en-US.js +1994 -1994
- package/dist/cjs/i18n/locales/es-ES.js +1994 -1994
- package/dist/cjs/i18n/locales/fr-FR.js +366 -366
- package/dist/cjs/i18n/locales/it-IT.js +366 -366
- package/dist/cjs/i18n/locales/ja-JP.js +366 -366
- package/dist/cjs/i18n/locales/ko-KR.js +366 -366
- package/dist/cjs/i18n/locales/pt-PT.js +366 -366
- package/dist/cjs/i18n/locales/zh-CN.js +366 -366
- package/dist/cjs/inference/OxyInferenceClient.js +12 -18
- package/dist/cjs/models/interfaces.js +11 -11
- package/dist/cjs/server/OxyServer.js +86 -28
- package/dist/cjs/server/agentAccount.js +6 -2
- package/dist/cjs/server/aliaMachineCredential.js +39 -14
- package/dist/cjs/server/auth.js +5 -4
- package/dist/cjs/server/capabilityTicket.js +5 -5
- package/dist/cjs/server/index.js +2 -1
- package/dist/cjs/server/liveCapabilityTicket.js +4 -1
- package/dist/cjs/server/middleware.js +61 -42
- package/dist/cjs/server/namespaces.js +28 -7
- package/dist/cjs/server/requesterAssertion.js +36 -30
- package/dist/cjs/server/serviceTokenLifetime.js +7 -4
- package/dist/cjs/server/traffic.js +53 -14
- package/dist/cjs/server/trafficNodeHttp.js +33 -8
- package/dist/cjs/server/workloadIdentity.client.js +4 -0
- package/dist/cjs/server/workloadIdentity.js +28 -1
- package/dist/cjs/session/SessionClient.js +54 -17
- package/dist/cjs/session/accountDelegationAccess.js +4 -6
- package/dist/cjs/session/accountDialogController.js +1 -1
- package/dist/cjs/session/authStateStore.js +18 -9
- package/dist/cjs/session/identityPin.js +6 -2
- package/dist/cjs/session/refresh.js +81 -23
- package/dist/cjs/session/sharedDeviceCredential.js +28 -15
- package/dist/cjs/shared/utils/errorUtils.js +1 -1
- package/dist/cjs/shared/utils/networkUtils.js +1 -1
- package/dist/cjs/shared/utils/themeUtils.js +1 -1
- package/dist/cjs/utils/accountCacheSweep.js +3 -1
- package/dist/cjs/utils/accountUtils.js +1 -3
- package/dist/cjs/utils/asyncUtils.js +1 -1
- package/dist/cjs/utils/authHelpers.js +2 -1
- package/dist/cjs/utils/avatarUtils.js +4 -2
- package/dist/cjs/utils/cache.js +1 -1
- package/dist/cjs/utils/cacheKey.js +3 -1
- package/dist/cjs/utils/deviceManager.js +4 -4
- package/dist/cjs/utils/errorUtils.js +6 -4
- package/dist/cjs/utils/languageUtils.js +404 -57
- package/dist/cjs/utils/profileLinks.js +1 -3
- package/dist/cjs/utils/requestUtils.js +7 -1
- package/dist/cjs/utils/userIdentity.js +1 -1
- package/dist/cjs/utils/validationUtils.js +5 -6
- package/dist/esm/HttpService.js +64 -20
- package/dist/esm/api/accounts.js +11 -4
- package/dist/esm/api/agency.js +3 -1
- package/dist/esm/api/apps.js +15 -4
- package/dist/esm/api/assets.js +39 -11
- package/dist/esm/api/auth.js +28 -8
- package/dist/esm/api/billing.js +25 -8
- package/dist/esm/api/civic.js +14 -4
- package/dist/esm/api/follows.js +9 -2
- package/dist/esm/api/identity.js +31 -9
- package/dist/esm/api/nodes.js +3 -1
- package/dist/esm/api/privacy.js +8 -2
- package/dist/esm/api/session.js +15 -4
- package/dist/esm/api/store.js +15 -5
- package/dist/esm/api/topics.js +10 -3
- package/dist/esm/api/users.js +16 -4
- package/dist/esm/boot/sessionColdBoot.js +41 -14
- package/dist/esm/constants/version.js +6 -6
- package/dist/esm/crypto/identityMarker.js +3 -1
- package/dist/esm/crypto/identityProof.js +6 -1
- package/dist/esm/crypto/internal.js +1 -1
- package/dist/esm/crypto/keyManager.js +87 -32
- package/dist/esm/crypto/recoveryPhrase.js +2 -2
- package/dist/esm/crypto/signatureService.js +3 -4
- package/dist/esm/i18n/index.js +16 -3
- package/dist/esm/i18n/locales/ar-SA.js +366 -366
- package/dist/esm/i18n/locales/ca-ES.js +366 -366
- package/dist/esm/i18n/locales/de-DE.js +366 -366
- package/dist/esm/i18n/locales/en-US.js +1994 -1994
- package/dist/esm/i18n/locales/es-ES.js +1994 -1994
- package/dist/esm/i18n/locales/fr-FR.js +366 -366
- package/dist/esm/i18n/locales/it-IT.js +366 -366
- package/dist/esm/i18n/locales/ja-JP.js +366 -366
- package/dist/esm/i18n/locales/ko-KR.js +366 -366
- package/dist/esm/i18n/locales/pt-PT.js +366 -366
- package/dist/esm/i18n/locales/zh-CN.js +366 -366
- package/dist/esm/index.js +1 -1
- package/dist/esm/inference/OxyInferenceClient.js +13 -19
- package/dist/esm/models/interfaces.js +11 -11
- package/dist/esm/server/OxyServer.js +87 -29
- package/dist/esm/server/agentAccount.js +6 -2
- package/dist/esm/server/aliaMachineCredential.js +39 -14
- package/dist/esm/server/auth.js +6 -5
- package/dist/esm/server/capabilityTicket.js +6 -6
- package/dist/esm/server/index.js +5 -5
- package/dist/esm/server/liveCapabilityTicket.js +6 -3
- package/dist/esm/server/middleware.js +62 -43
- package/dist/esm/server/namespaces.js +31 -10
- package/dist/esm/server/requesterAssertion.js +36 -30
- package/dist/esm/server/serviceTokenLifetime.js +7 -4
- package/dist/esm/server/traffic.js +55 -16
- package/dist/esm/server/trafficNodeHttp.js +34 -9
- package/dist/esm/server/userInvalidation.js +1 -1
- package/dist/esm/server/workloadIdentity.client.js +3 -0
- package/dist/esm/server/workloadIdentity.js +27 -1
- package/dist/esm/session/SessionClient.js +54 -17
- package/dist/esm/session/accountDelegationAccess.js +5 -7
- package/dist/esm/session/accountDialogController.js +1 -1
- package/dist/esm/session/authStateStore.js +18 -9
- package/dist/esm/session/identityPin.js +6 -2
- package/dist/esm/session/refresh.js +82 -24
- package/dist/esm/session/sharedDeviceCredential.js +28 -15
- package/dist/esm/shared/utils/errorUtils.js +1 -1
- package/dist/esm/shared/utils/networkUtils.js +1 -1
- package/dist/esm/shared/utils/themeUtils.js +1 -1
- package/dist/esm/utils/accountCacheSweep.js +3 -1
- package/dist/esm/utils/accountUtils.js +1 -3
- package/dist/esm/utils/asyncUtils.js +1 -1
- package/dist/esm/utils/authHelpers.js +2 -1
- package/dist/esm/utils/avatarUtils.js +4 -2
- package/dist/esm/utils/cache.js +1 -1
- package/dist/esm/utils/cacheKey.js +3 -1
- package/dist/esm/utils/deviceManager.js +4 -4
- package/dist/esm/utils/errorUtils.js +6 -4
- package/dist/esm/utils/languageUtils.js +404 -57
- package/dist/esm/utils/profileLinks.js +1 -3
- package/dist/esm/utils/requestUtils.js +7 -1
- package/dist/esm/utils/userIdentity.js +1 -1
- package/dist/esm/utils/validationUtils.js +5 -6
- package/dist/types/HttpService.d.ts +1 -1
- package/dist/types/api/accounts.d.ts +1 -1
- package/dist/types/api/apps.d.ts +4 -4
- package/dist/types/crypto/internal.d.ts +1 -1
- package/dist/types/index.d.ts +4 -4
- package/dist/types/server/index.d.ts +6 -6
- package/dist/types/server/workloadIdentity.client.d.ts +5 -1
- package/dist/types/server/workloadIdentity.d.ts +26 -0
- package/dist/types/session/accountDelegationAccess.d.ts +1 -1
- package/dist/types/session/index.d.ts +1 -1
- package/dist/types/utils/userIdentity.d.ts +1 -1
- package/dist/types/utils/validationUtils.d.ts +4 -5
- package/package.json +2 -3
- package/src/HttpService.ts +183 -53
- package/src/OxyServices.errors.ts +7 -3
- package/src/OxyServices.ts +6 -2
- package/src/api/accounts.ts +76 -26
- package/src/api/agency.ts +24 -9
- package/src/api/appData.ts +12 -2
- package/src/api/apps.ts +81 -31
- package/src/api/assets.ts +113 -43
- package/src/api/auth.ts +145 -77
- package/src/api/billing.ts +112 -65
- package/src/api/civic.ts +61 -19
- package/src/api/contacts.ts +4 -1
- package/src/api/devices.ts +54 -21
- package/src/api/follows.ts +88 -31
- package/src/api/identity.ts +101 -33
- package/src/api/linkedAccounts.ts +26 -8
- package/src/api/nodes.ts +18 -6
- package/src/api/notifications.ts +26 -6
- package/src/api/privacy.ts +42 -8
- package/src/api/reputation.ts +18 -7
- package/src/api/session.ts +23 -5
- package/src/api/store.ts +81 -31
- package/src/api/topics.ts +18 -6
- package/src/api/users.ts +98 -35
- package/src/boot/sessionColdBoot.ts +60 -19
- package/src/civic/payloads.ts +1 -4
- package/src/client/context.ts +6 -1
- package/src/constants/version.ts +7 -6
- package/src/crypto/aead.ts +1 -5
- package/src/crypto/ecdh.ts +1 -4
- package/src/crypto/identityDerivations.ts +5 -1
- package/src/crypto/identityMarker.ts +3 -1
- package/src/crypto/identityProof.ts +6 -1
- package/src/crypto/index.ts +11 -11
- package/src/crypto/internal.ts +6 -1
- package/src/crypto/keyManager.ts +348 -98
- package/src/crypto/recoveryPhrase.ts +14 -9
- package/src/crypto/registrationPow.ts +1 -1
- package/src/crypto/signatureService.ts +14 -6
- package/src/i18n/accountCategoryLabels.ts +1 -4
- package/src/i18n/accountRoleLabels.ts +1 -4
- package/src/i18n/index.ts +25 -7
- package/src/i18n/locales/ar-SA.ts +375 -366
- package/src/i18n/locales/ca-ES.ts +382 -366
- package/src/i18n/locales/de-DE.ts +387 -366
- package/src/i18n/locales/en-US.ts +2034 -1994
- package/src/i18n/locales/es-ES.ts +2043 -1994
- package/src/i18n/locales/fr-FR.ts +387 -366
- package/src/i18n/locales/it-IT.ts +380 -366
- package/src/i18n/locales/ja-JP.ts +380 -366
- package/src/i18n/locales/ko-KR.ts +377 -366
- package/src/i18n/locales/pt-PT.ts +383 -366
- package/src/i18n/locales/zh-CN.ts +373 -366
- package/src/i18n/trustTierLabels.ts +1 -4
- package/src/index.ts +371 -349
- package/src/inference/OxyInferenceClient.ts +784 -780
- package/src/models/interfaces.ts +30 -27
- package/src/server/OxyServer.ts +227 -68
- package/src/server/agentAccount.ts +8 -2
- package/src/server/aliaMachineCredential.ts +57 -16
- package/src/server/auth.ts +9 -5
- package/src/server/capabilityTicket.ts +30 -21
- package/src/server/index.ts +29 -6
- package/src/server/liveCapabilityTicket.ts +31 -9
- package/src/server/middleware.ts +212 -121
- package/src/server/namespaces.ts +247 -94
- package/src/server/rateLimit.ts +2 -4
- package/src/server/requesterAssertion.ts +93 -54
- package/src/server/serviceTokenLifetime.ts +9 -4
- package/src/server/traffic.ts +117 -23
- package/src/server/trafficNodeHttp.ts +61 -14
- package/src/server/userInvalidation.ts +1 -4
- package/src/server/workloadIdentity.client.ts +12 -1
- package/src/server/workloadIdentity.ts +52 -5
- package/src/session/SessionClient.ts +170 -49
- package/src/session/accountDelegationAccess.ts +24 -31
- package/src/session/accountDialogController.ts +59 -14
- package/src/session/accountSwitchTargets.ts +10 -15
- package/src/session/authStateStore.ts +121 -81
- package/src/session/deviceDirectory.ts +1 -3
- package/src/session/identityPin.ts +10 -11
- package/src/session/identitySession.ts +3 -1
- package/src/session/index.ts +87 -82
- package/src/session/refresh.ts +138 -44
- package/src/session/sessionClientHost.ts +1 -3
- package/src/session/sharedDeviceCredential.ts +35 -14
- package/src/session/socketLoader.ts +9 -2
- package/src/shared/utils/errorUtils.ts +5 -2
- package/src/shared/utils/networkUtils.ts +5 -8
- package/src/shared/utils/themeUtils.ts +2 -6
- package/src/types/buffer.d.ts +66 -21
- package/src/types/expo-secure-store.d.ts +5 -1
- package/src/utils/accountCacheSweep.ts +4 -5
- package/src/utils/accountUtils.ts +107 -108
- package/src/utils/apiUtils.ts +3 -3
- package/src/utils/asyncUtils.ts +2 -2
- package/src/utils/authHelpers.ts +10 -5
- package/src/utils/avatarUtils.ts +11 -6
- package/src/utils/cache.ts +9 -10
- package/src/utils/cacheKey.ts +5 -1
- package/src/utils/coldBoot.ts +1 -3
- package/src/utils/commonsDelivery.ts +1 -4
- package/src/utils/deviceManager.ts +15 -14
- package/src/utils/errorUtils.ts +68 -86
- package/src/utils/languageUtils.ts +407 -58
- package/src/utils/oauthPkce.ts +1 -4
- package/src/utils/platform.ts +0 -1
- package/src/utils/profileLinks.ts +2 -5
- package/src/utils/requestUtils.ts +18 -14
- package/src/utils/sessionUtils.ts +34 -33
- package/src/utils/userHandle.ts +3 -1
- package/src/utils/userIdentity.ts +1 -1
- package/src/utils/validationUtils.ts +11 -9
package/dist/esm/index.js
CHANGED
|
@@ -42,7 +42,7 @@ export { OxyAppDataIdentifierError } from './api/appData.js';
|
|
|
42
42
|
export { getCommonsApprovalBlockingReason, parseCommonsApprovalExpiresAt, } from './utils/commonsApproval.js';
|
|
43
43
|
// Automatic "Sign in with Oxy" delivery selection — ONE pure decision that maps
|
|
44
44
|
// the caller's facts onto exactly one primary route (open Commons / await push / QR).
|
|
45
|
-
export { selectCommonsDelivery, pushTargetsFromDelivery, commonsDeliveryPlatform } from './utils/commonsDelivery.js';
|
|
45
|
+
export { selectCommonsDelivery, pushTargetsFromDelivery, commonsDeliveryPlatform, } from './utils/commonsDelivery.js';
|
|
46
46
|
// ---------------------------------------------------------------------------
|
|
47
47
|
// User identity and handles
|
|
48
48
|
// ---------------------------------------------------------------------------
|
|
@@ -61,7 +61,7 @@ var _OxyInferenceClient_instances, _OxyInferenceClient_baseURL, _OxyInferenceCli
|
|
|
61
61
|
* schema, so a rename on either side fails a build rather than a customer's
|
|
62
62
|
* request.
|
|
63
63
|
*/
|
|
64
|
-
import { decisionRequestSchema, decisionSuccessSchema, decisionAnswersMatch } from '@oxy.so/contracts';
|
|
64
|
+
import { decisionRequestSchema, decisionSuccessSchema, decisionAnswersMatch, } from '@oxy.so/contracts';
|
|
65
65
|
import { INFERENCE_ERROR_CODES, MAX_INFERENCE_AUDIO_BYTES, inferenceAudioMediaTypeSchema, inferenceStreamEventSchema, modelIdSchema, } from '@oxy.so/contracts';
|
|
66
66
|
/** The base URL of the Oxy API, when a caller names none. */
|
|
67
67
|
export const OXY_INFERENCE_BASE_URL = 'https://api.oxy.so';
|
|
@@ -200,9 +200,7 @@ export class OxyInferenceClient {
|
|
|
200
200
|
return __classPrivateFieldGet(this, _OxyInferenceClient_instances, "m", _OxyInferenceClient_request).call(this, 'POST', '/v1/responses', {
|
|
201
201
|
body: request,
|
|
202
202
|
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
203
|
-
...(options.idempotencyKey === undefined
|
|
204
|
-
? {}
|
|
205
|
-
: { idempotencyKey: options.idempotencyKey }),
|
|
203
|
+
...(options.idempotencyKey === undefined ? {} : { idempotencyKey: options.idempotencyKey }),
|
|
206
204
|
...(options.delegatedUserId === undefined
|
|
207
205
|
? {}
|
|
208
206
|
: { delegatedUserId: options.delegatedUserId }),
|
|
@@ -219,7 +217,8 @@ export class OxyInferenceClient {
|
|
|
219
217
|
delegatedUserId: options.delegatedUserId,
|
|
220
218
|
});
|
|
221
219
|
const parsed = decisionSuccessSchema.safeParse(payload);
|
|
222
|
-
if (!parsed.success ||
|
|
220
|
+
if (!parsed.success ||
|
|
221
|
+
parsed.data.model !== input.model ||
|
|
223
222
|
!decisionAnswersMatch(input, parsed.data.data)) {
|
|
224
223
|
throw new OxyInferenceProtocolError('Invalid or mismatched decisions response.');
|
|
225
224
|
}
|
|
@@ -231,9 +230,7 @@ export class OxyInferenceClient {
|
|
|
231
230
|
method: 'POST',
|
|
232
231
|
headers: await __classPrivateFieldGet(this, _OxyInferenceClient_instances, "m", _OxyInferenceClient_headers).call(this, 'audio/*', {
|
|
233
232
|
hasBody: true,
|
|
234
|
-
...(options.idempotencyKey === undefined
|
|
235
|
-
? {}
|
|
236
|
-
: { idempotencyKey: options.idempotencyKey }),
|
|
233
|
+
...(options.idempotencyKey === undefined ? {} : { idempotencyKey: options.idempotencyKey }),
|
|
237
234
|
...(options.delegatedUserId === undefined
|
|
238
235
|
? {}
|
|
239
236
|
: { delegatedUserId: options.delegatedUserId }),
|
|
@@ -305,9 +302,7 @@ export class OxyInferenceClient {
|
|
|
305
302
|
method: 'POST',
|
|
306
303
|
headers: await __classPrivateFieldGet(this, _OxyInferenceClient_instances, "m", _OxyInferenceClient_headers).call(this, 'text/event-stream', {
|
|
307
304
|
hasBody: true,
|
|
308
|
-
...(options.idempotencyKey === undefined
|
|
309
|
-
? {}
|
|
310
|
-
: { idempotencyKey: options.idempotencyKey }),
|
|
305
|
+
...(options.idempotencyKey === undefined ? {} : { idempotencyKey: options.idempotencyKey }),
|
|
311
306
|
...(options.delegatedUserId === undefined
|
|
312
307
|
? {}
|
|
313
308
|
: { delegatedUserId: options.delegatedUserId }),
|
|
@@ -405,9 +400,7 @@ export class OxyInferenceClient {
|
|
|
405
400
|
_OxyInferenceClient_baseURL = new WeakMap(), _OxyInferenceClient_credential = new WeakMap(), _OxyInferenceClient_fetch = new WeakMap(), _OxyInferenceClient_instances = new WeakSet(), _OxyInferenceClient_bearer =
|
|
406
401
|
/** The bearer for this request, from whichever lane was configured. */
|
|
407
402
|
async function _OxyInferenceClient_bearer() {
|
|
408
|
-
const value = typeof __classPrivateFieldGet(this, _OxyInferenceClient_credential, "f") === 'string'
|
|
409
|
-
? __classPrivateFieldGet(this, _OxyInferenceClient_credential, "f")
|
|
410
|
-
: await __classPrivateFieldGet(this, _OxyInferenceClient_credential, "f").call(this);
|
|
403
|
+
const value = typeof __classPrivateFieldGet(this, _OxyInferenceClient_credential, "f") === 'string' ? __classPrivateFieldGet(this, _OxyInferenceClient_credential, "f") : await __classPrivateFieldGet(this, _OxyInferenceClient_credential, "f").call(this);
|
|
411
404
|
if (value === null || value === undefined || value.length === 0) {
|
|
412
405
|
throw new Error('OxyInferenceClient has no bearer: the configured credential resolved to nothing. On the Oxy auth lane this usually means the session is not restored yet.');
|
|
413
406
|
}
|
|
@@ -445,9 +438,7 @@ async function _OxyInferenceClient_request(method, path, options) {
|
|
|
445
438
|
method,
|
|
446
439
|
headers: await __classPrivateFieldGet(this, _OxyInferenceClient_instances, "m", _OxyInferenceClient_headers).call(this, 'application/json', {
|
|
447
440
|
hasBody: options.body !== undefined,
|
|
448
|
-
...(options.idempotencyKey === undefined
|
|
449
|
-
? {}
|
|
450
|
-
: { idempotencyKey: options.idempotencyKey }),
|
|
441
|
+
...(options.idempotencyKey === undefined ? {} : { idempotencyKey: options.idempotencyKey }),
|
|
451
442
|
...(options.delegatedUserId === undefined
|
|
452
443
|
? {}
|
|
453
444
|
: { delegatedUserId: options.delegatedUserId }),
|
|
@@ -461,8 +452,11 @@ async function _OxyInferenceClient_request(method, path, options) {
|
|
|
461
452
|
}
|
|
462
453
|
if (options.bindRequestId) {
|
|
463
454
|
const requestId = response.headers.get('X-Oxy-Request-Id');
|
|
464
|
-
if (!requestId ||
|
|
465
|
-
|
|
455
|
+
if (!requestId ||
|
|
456
|
+
typeof payload !== 'object' ||
|
|
457
|
+
payload === null ||
|
|
458
|
+
!('requestId' in payload) ||
|
|
459
|
+
payload.requestId !== requestId) {
|
|
466
460
|
throw new OxyInferenceProtocolError('Decisions response request ID does not match its header.', requestId ?? undefined);
|
|
467
461
|
}
|
|
468
462
|
}
|
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
* Maps each event type to its default severity level
|
|
4
4
|
*/
|
|
5
5
|
export const SECURITY_EVENT_SEVERITY_MAP = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
sign_in: 'low',
|
|
7
|
+
sign_out: 'low',
|
|
8
|
+
profile_updated: 'low',
|
|
9
|
+
email_changed: 'medium',
|
|
10
|
+
device_added: 'medium',
|
|
11
|
+
device_removed: 'medium',
|
|
12
|
+
security_settings_changed: 'medium',
|
|
13
|
+
account_recovery: 'high',
|
|
14
|
+
private_key_exported: 'high',
|
|
15
|
+
backup_created: 'high',
|
|
16
|
+
suspicious_activity: 'critical',
|
|
17
17
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { subjectProductAccessQuerySchema, subjectProductGrantSnapshotSchema } from '@oxy.so/contracts';
|
|
1
|
+
import { subjectProductAccessQuerySchema, subjectProductGrantSnapshotSchema, } from '@oxy.so/contracts';
|
|
2
2
|
/**
|
|
3
3
|
* `OxyServer` — the Oxy client for a backend.
|
|
4
4
|
*
|
|
@@ -32,8 +32,9 @@ import { hasBoundedServiceTokenLifetime } from './serviceTokenLifetime.js';
|
|
|
32
32
|
function reusableServiceToken(token) {
|
|
33
33
|
try {
|
|
34
34
|
const claims = jwtDecode(token);
|
|
35
|
-
return hasBoundedServiceTokenLifetime(claims) &&
|
|
36
|
-
|
|
35
|
+
return (hasBoundedServiceTokenLifetime(claims) &&
|
|
36
|
+
typeof claims.exp === 'number' &&
|
|
37
|
+
claims.exp > Math.floor(Date.now() / 1000));
|
|
37
38
|
}
|
|
38
39
|
catch {
|
|
39
40
|
return false;
|
|
@@ -80,7 +81,11 @@ export class OxyServer extends OxyServices {
|
|
|
80
81
|
this.actingAsPending = new Map();
|
|
81
82
|
this.actingAsGenerations = new Map();
|
|
82
83
|
/** Public keys only; never private material. */
|
|
83
|
-
this.jwksCache = {
|
|
84
|
+
this.jwksCache = {
|
|
85
|
+
keys: new Map(),
|
|
86
|
+
expiresAt: 0,
|
|
87
|
+
lastAttemptAt: 0,
|
|
88
|
+
};
|
|
84
89
|
/**
|
|
85
90
|
* Before this instant a request without a user session does not try to mint
|
|
86
91
|
* a service token and goes out anonymous. Set after a failed mint.
|
|
@@ -224,7 +229,9 @@ export class OxyServer extends OxyServices {
|
|
|
224
229
|
});
|
|
225
230
|
throw new ServiceCredentialMismatchError();
|
|
226
231
|
}
|
|
227
|
-
if (entry.token &&
|
|
232
|
+
if (entry.token &&
|
|
233
|
+
reusableServiceToken(entry.token) &&
|
|
234
|
+
entry.expiresAt > now + TOKEN_REUSE_MARGIN_MS) {
|
|
228
235
|
return entry.token;
|
|
229
236
|
}
|
|
230
237
|
if (entry.pending) {
|
|
@@ -283,7 +290,8 @@ export class OxyServer extends OxyServices {
|
|
|
283
290
|
throw new Error('A user session is required');
|
|
284
291
|
const answer = await this.request('GET', `/v1/products/${encodeURIComponent(parsed.productId)}/access/${encodeURIComponent(parsed.subjectAccountId)}/grants`, undefined, { cache: false, retry: false, headers: { Authorization: `Bearer ${accessToken}` } });
|
|
285
292
|
const snapshot = subjectProductGrantSnapshotSchema.parse(answer);
|
|
286
|
-
if (snapshot.access.subjectAccountId !== parsed.subjectAccountId ||
|
|
293
|
+
if (snapshot.access.subjectAccountId !== parsed.subjectAccountId ||
|
|
294
|
+
snapshot.access.productId !== parsed.productId)
|
|
287
295
|
throw new Error('Product grant response attribution differs');
|
|
288
296
|
return snapshot;
|
|
289
297
|
}
|
|
@@ -292,7 +300,8 @@ export class OxyServer extends OxyServices {
|
|
|
292
300
|
const parsed = subjectProductAccessQuerySchema.parse(query);
|
|
293
301
|
const answer = await this.serviceRequest('GET', `/v1/products/${encodeURIComponent(parsed.productId)}/access/${encodeURIComponent(parsed.subjectAccountId)}/service-grants`, undefined, { cache: false, retry: false });
|
|
294
302
|
const snapshot = subjectProductGrantSnapshotSchema.parse(answer);
|
|
295
|
-
if (snapshot.access.subjectAccountId !== parsed.subjectAccountId ||
|
|
303
|
+
if (snapshot.access.subjectAccountId !== parsed.subjectAccountId ||
|
|
304
|
+
snapshot.access.productId !== parsed.productId)
|
|
296
305
|
throw new Error('Product grant response attribution differs');
|
|
297
306
|
return snapshot;
|
|
298
307
|
}
|
|
@@ -314,7 +323,13 @@ export class OxyServer extends OxyServices {
|
|
|
314
323
|
*/
|
|
315
324
|
async verifyActingAs(appId, userId, options = {}) {
|
|
316
325
|
const pair = JSON.stringify([appId, userId]);
|
|
317
|
-
const cacheKey = JSON.stringify([
|
|
326
|
+
const cacheKey = JSON.stringify([
|
|
327
|
+
appId,
|
|
328
|
+
userId,
|
|
329
|
+
options.credentialId,
|
|
330
|
+
options.ownerAccountId,
|
|
331
|
+
options.environment,
|
|
332
|
+
]);
|
|
318
333
|
if (options.cache === true) {
|
|
319
334
|
const cached = this.actingAs.get(cacheKey);
|
|
320
335
|
if (cached && cached.expiresAt > Date.now()) {
|
|
@@ -397,18 +412,32 @@ export class OxyServer extends OxyServices {
|
|
|
397
412
|
entry.secretBuf = secretBuf;
|
|
398
413
|
}
|
|
399
414
|
else {
|
|
400
|
-
this.serviceTokens.set(cacheKey, {
|
|
415
|
+
this.serviceTokens.set(cacheKey, {
|
|
416
|
+
token: response.token,
|
|
417
|
+
expiresAt,
|
|
418
|
+
secretBuf,
|
|
419
|
+
pending: null,
|
|
420
|
+
apiKey: key,
|
|
421
|
+
});
|
|
401
422
|
}
|
|
402
423
|
return response.token;
|
|
403
424
|
}
|
|
404
425
|
/** A token obtained by attestation, cached like a credential's (one identity per process). */
|
|
405
426
|
async workloadServiceToken() {
|
|
406
427
|
const entry = this.serviceTokens.get(WORKLOAD_CACHE_KEY);
|
|
407
|
-
if (entry?.token &&
|
|
428
|
+
if (entry?.token &&
|
|
429
|
+
reusableServiceToken(entry.token) &&
|
|
430
|
+
entry.expiresAt > Date.now() + TOKEN_REUSE_MARGIN_MS)
|
|
408
431
|
return entry.token;
|
|
409
432
|
if (entry?.pending)
|
|
410
433
|
return entry.pending;
|
|
411
|
-
const seeded = entry ?? {
|
|
434
|
+
const seeded = entry ?? {
|
|
435
|
+
token: '',
|
|
436
|
+
expiresAt: 0,
|
|
437
|
+
secretBuf: Buffer.alloc(0),
|
|
438
|
+
pending: null,
|
|
439
|
+
apiKey: WORKLOAD_CACHE_KEY,
|
|
440
|
+
};
|
|
412
441
|
this.serviceTokens.set(WORKLOAD_CACHE_KEY, seeded);
|
|
413
442
|
const pending = (async () => {
|
|
414
443
|
const granted = await requestWorkloadServiceToken({ baseUrl: this.baseURL });
|
|
@@ -438,8 +467,22 @@ export class OxyServer extends OxyServices {
|
|
|
438
467
|
async lookupActingAs(appId, userId, options, pair, cacheKey, generation, serial, startedAt) {
|
|
439
468
|
try {
|
|
440
469
|
const serviceToken = await this.serviceToken();
|
|
441
|
-
const result = await this.request('GET', '/internal/service-acting-as/verify', {
|
|
442
|
-
|
|
470
|
+
const result = await this.request('GET', '/internal/service-acting-as/verify', {
|
|
471
|
+
appId,
|
|
472
|
+
userId,
|
|
473
|
+
...(options.credentialId
|
|
474
|
+
? {
|
|
475
|
+
credentialId: options.credentialId,
|
|
476
|
+
ownerAccountId: options.ownerAccountId,
|
|
477
|
+
environment: options.environment,
|
|
478
|
+
}
|
|
479
|
+
: {}),
|
|
480
|
+
}, {
|
|
481
|
+
cache: false,
|
|
482
|
+
retry: false,
|
|
483
|
+
timeout: 5000,
|
|
484
|
+
headers: { Authorization: `Bearer ${serviceToken}` },
|
|
485
|
+
});
|
|
443
486
|
// A deadline bounds how long an already old response can authorize. It
|
|
444
487
|
// is not by itself a measurement of end-to-end revocation latency.
|
|
445
488
|
if (this.actingAsGenerations.get(pair) !== generation || serial < generation.completed)
|
|
@@ -454,10 +497,11 @@ export class OxyServer extends OxyServices {
|
|
|
454
497
|
const epoch = BigInt(rawEpoch);
|
|
455
498
|
if (epoch > 9223372036854775807n)
|
|
456
499
|
return null;
|
|
457
|
-
if (typeof result.authorized !== 'boolean' ||
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
500
|
+
if (typeof result.authorized !== 'boolean' ||
|
|
501
|
+
!Array.isArray(result.scopes) ||
|
|
502
|
+
!result.scopes.every((scope) => typeof scope === 'string' && scope.length > 0 && scope.trim() === scope) ||
|
|
503
|
+
new Set(result.scopes).size !== result.scopes.length ||
|
|
504
|
+
(!result.authorized && result.scopes.length !== 0))
|
|
461
505
|
return null;
|
|
462
506
|
const older = epoch < generation.epoch;
|
|
463
507
|
if (epoch > generation.epoch)
|
|
@@ -465,7 +509,8 @@ export class OxyServer extends OxyServices {
|
|
|
465
509
|
if (result.authorized && older)
|
|
466
510
|
return null;
|
|
467
511
|
const verified = result.authorized === true
|
|
468
|
-
? { authorized: true, scopes: result.scopes, epoch: rawEpoch }
|
|
512
|
+
? { authorized: true, scopes: result.scopes, epoch: rawEpoch }
|
|
513
|
+
: null;
|
|
469
514
|
if (options.cache === true)
|
|
470
515
|
this.rememberActingAs(cacheKey, verified, startedAt + (verified ? ACTING_AS_GRANT_TTL_MS : ACTING_AS_DENIAL_TTL_MS));
|
|
471
516
|
return verified;
|
|
@@ -476,7 +521,10 @@ export class OxyServer extends OxyServices {
|
|
|
476
521
|
this.clearActingAsPair(appId, userId);
|
|
477
522
|
}
|
|
478
523
|
logger.warn('[oxy.auth] verifyActingAs lookup failed — not cached', {
|
|
479
|
-
component: 'auth',
|
|
524
|
+
component: 'auth',
|
|
525
|
+
method: 'verifyActingAs',
|
|
526
|
+
appId,
|
|
527
|
+
userId,
|
|
480
528
|
}, error);
|
|
481
529
|
return null;
|
|
482
530
|
}
|
|
@@ -515,11 +563,11 @@ export class OxyServer extends OxyServices {
|
|
|
515
563
|
catch {
|
|
516
564
|
throw new OxyAccountEventError('Account event token is malformed');
|
|
517
565
|
}
|
|
518
|
-
if (Object.keys(header).length !== 3
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
566
|
+
if (Object.keys(header).length !== 3 ||
|
|
567
|
+
header.alg !== 'EdDSA' ||
|
|
568
|
+
header.typ !== 'secevent+jwt' ||
|
|
569
|
+
typeof header.kid !== 'string' ||
|
|
570
|
+
!/^[A-Za-z0-9._-]{1,128}$/.test(header.kid)) {
|
|
523
571
|
throw new OxyAccountEventError('Account event token header is not supported');
|
|
524
572
|
}
|
|
525
573
|
const nodeCrypto = await loadNodeCrypto();
|
|
@@ -528,7 +576,9 @@ export class OxyServer extends OxyServices {
|
|
|
528
576
|
jwk = await resolveServiceTokenPublicKey(header.kid, options.jwksUrl ?? new URL('/.well-known/jwks.json', this.baseURL).toString(), this.jwksCache);
|
|
529
577
|
}
|
|
530
578
|
catch (error) {
|
|
531
|
-
throw new OxyAccountEventError(error instanceof Error
|
|
579
|
+
throw new OxyAccountEventError(error instanceof Error
|
|
580
|
+
? error.message.replace('Service token', 'Account event')
|
|
581
|
+
: 'Signing key is unavailable');
|
|
532
582
|
}
|
|
533
583
|
const signature = Buffer.from(signatureB64, 'base64url');
|
|
534
584
|
if (signature.toString('base64url') !== signatureB64 || signature.length !== 64) {
|
|
@@ -536,7 +586,10 @@ export class OxyServer extends OxyServices {
|
|
|
536
586
|
}
|
|
537
587
|
let verified = false;
|
|
538
588
|
try {
|
|
539
|
-
const publicKey = nodeCrypto.createPublicKey({
|
|
589
|
+
const publicKey = nodeCrypto.createPublicKey({
|
|
590
|
+
key: jwk,
|
|
591
|
+
format: 'jwk',
|
|
592
|
+
});
|
|
540
593
|
verified = nodeCrypto.verify(null, Buffer.from(`${headerB64}.${payloadB64}`), publicKey, signature);
|
|
541
594
|
}
|
|
542
595
|
catch {
|
|
@@ -547,7 +600,7 @@ export class OxyServer extends OxyServices {
|
|
|
547
600
|
if (payload.iss !== OXY_JWT_ISSUER) {
|
|
548
601
|
throw new OxyAccountEventError('Account event token issuer is not Oxy');
|
|
549
602
|
}
|
|
550
|
-
const audience = options.audience ?? await this.configuredServiceAppId();
|
|
603
|
+
const audience = options.audience ?? (await this.configuredServiceAppId());
|
|
551
604
|
if (typeof payload.aud !== 'string' || payload.aud !== audience) {
|
|
552
605
|
throw new OxyAccountEventError('Account event token is addressed to another application');
|
|
553
606
|
}
|
|
@@ -563,7 +616,10 @@ export class OxyServer extends OxyServices {
|
|
|
563
616
|
}
|
|
564
617
|
const entries = Object.entries(events);
|
|
565
618
|
const deleted = events[OXY_ACCOUNT_DELETED_EVENT_URI];
|
|
566
|
-
if (entries.length !== 1 ||
|
|
619
|
+
if (entries.length !== 1 ||
|
|
620
|
+
typeof deleted !== 'object' ||
|
|
621
|
+
deleted === null ||
|
|
622
|
+
Array.isArray(deleted)) {
|
|
567
623
|
throw new OxyAccountEventError('Account event token carries an unknown event');
|
|
568
624
|
}
|
|
569
625
|
const body = deleted;
|
|
@@ -573,7 +629,9 @@ export class OxyServer extends OxyServices {
|
|
|
573
629
|
if (typeof body.occurredAt !== 'string' || Number.isNaN(Date.parse(body.occurredAt))) {
|
|
574
630
|
throw new OxyAccountEventError('Account event has no occurrence time');
|
|
575
631
|
}
|
|
576
|
-
if (body.username !== undefined &&
|
|
632
|
+
if (body.username !== undefined &&
|
|
633
|
+
body.username !== null &&
|
|
634
|
+
typeof body.username !== 'string') {
|
|
577
635
|
throw new OxyAccountEventError('Account event username is malformed');
|
|
578
636
|
}
|
|
579
637
|
return {
|
|
@@ -7,8 +7,12 @@ export async function signInAgentAccount(options) {
|
|
|
7
7
|
const publicKey = normalizeSecp256k1PublicKey(signer.publicKey.trim());
|
|
8
8
|
const claims = await client.auth.agent.requestChallenge(publicKey);
|
|
9
9
|
const timestamp = Date.now();
|
|
10
|
-
if (claims.action !== 'agent_signin' ||
|
|
11
|
-
|
|
10
|
+
if (claims.action !== 'agent_signin' ||
|
|
11
|
+
claims.accountId !== accountId ||
|
|
12
|
+
claims.actorId !== accountId ||
|
|
13
|
+
normalizeSecp256k1PublicKey(claims.publicKey) !== publicKey ||
|
|
14
|
+
!claims.authMethodId ||
|
|
15
|
+
claims.expiresAt <= timestamp) {
|
|
12
16
|
throw new Error('Agent challenge does not match this account and signer');
|
|
13
17
|
}
|
|
14
18
|
const signature = await signer.signMessage(buildAgentProofMessage(claims, timestamp));
|
|
@@ -2,20 +2,34 @@
|
|
|
2
2
|
export const OXY_ALIA_RESOURCE_APPLICATION_ID = '6a2f851751b784a86fd0e934';
|
|
3
3
|
export const OXY_ALIA_MACHINE_SCOPES = ['alia:chat', 'inference:invoke'];
|
|
4
4
|
function id(value) {
|
|
5
|
-
return typeof value === 'string' && value.length > 0 && value.length <= 128 && value.trim() === value;
|
|
5
|
+
return (typeof value === 'string' && value.length > 0 && value.length <= 128 && value.trim() === value);
|
|
6
6
|
}
|
|
7
7
|
/** Strict response boundary: extra user/tier fields cannot smuggle authority. */
|
|
8
8
|
export function isOxyAliaMachinePrincipal(value) {
|
|
9
9
|
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
10
10
|
return false;
|
|
11
11
|
const p = value;
|
|
12
|
-
const keys = [
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
const keys = [
|
|
13
|
+
'kind',
|
|
14
|
+
'audience',
|
|
15
|
+
'applicationId',
|
|
16
|
+
'credentialId',
|
|
17
|
+
'ownerAccountId',
|
|
18
|
+
'environment',
|
|
19
|
+
'scopes',
|
|
20
|
+
];
|
|
21
|
+
return (Object.keys(p).length === keys.length &&
|
|
22
|
+
keys.every((key) => Object.prototype.hasOwnProperty.call(p, key)) &&
|
|
23
|
+
p.kind === 'machine' &&
|
|
24
|
+
p.audience === OXY_ALIA_RESOURCE_APPLICATION_ID &&
|
|
25
|
+
id(p.applicationId) &&
|
|
26
|
+
id(p.credentialId) &&
|
|
27
|
+
id(p.ownerAccountId) &&
|
|
28
|
+
typeof p.environment === 'string' &&
|
|
29
|
+
['production', 'staging', 'development'].includes(p.environment) &&
|
|
30
|
+
Array.isArray(p.scopes) &&
|
|
31
|
+
p.scopes.length === 2 &&
|
|
32
|
+
OXY_ALIA_MACHINE_SCOPES.every((scope) => p.scopes.includes(scope)));
|
|
19
33
|
}
|
|
20
34
|
// Keep the forwarding credential out of enumerable request/principal objects,
|
|
21
35
|
// logs, response serialization and persistent SDK/session state. No cache.
|
|
@@ -23,7 +37,9 @@ const forwardingCredentials = new WeakMap();
|
|
|
23
37
|
/** Only for the request-scoped Oxy inference client; never for a user API. */
|
|
24
38
|
export function getOxyAliaMachineCredentialBearer(req) {
|
|
25
39
|
const bound = forwardingCredentials.get(req);
|
|
26
|
-
return bound && req.machineCredential === bound.principal
|
|
40
|
+
return bound && req.machineCredential === bound.principal
|
|
41
|
+
? bound.bearer
|
|
42
|
+
: null;
|
|
27
43
|
}
|
|
28
44
|
/** Opt into Alia's app-only chat lane on its two chat routes, never globally. */
|
|
29
45
|
export function createOxyAliaMachineCredentialAuth(server, options) {
|
|
@@ -35,19 +51,28 @@ export function createOxyAliaMachineCredentialAuth(server, options) {
|
|
|
35
51
|
return;
|
|
36
52
|
}
|
|
37
53
|
const existing = req;
|
|
38
|
-
if (existing.user ||
|
|
39
|
-
||
|
|
40
|
-
|
|
54
|
+
if (existing.user ||
|
|
55
|
+
existing.userId ||
|
|
56
|
+
existing.serviceApp ||
|
|
57
|
+
existing.oxyRequester ||
|
|
58
|
+
req.machineCredential ||
|
|
59
|
+
req.headers['x-oxy-user-id'] !== undefined ||
|
|
60
|
+
req.headers['x-oxy-requester-assertion'] !== undefined) {
|
|
41
61
|
res.status(403).json({ error: 'MACHINE_USER_DELEGATION_UNSUPPORTED' });
|
|
42
62
|
return;
|
|
43
63
|
}
|
|
44
64
|
try {
|
|
45
65
|
const answer = await server.apps.introspectAliaMachineCredential(token);
|
|
46
|
-
if (!answer.active ||
|
|
66
|
+
if (!answer.active ||
|
|
67
|
+
!isOxyAliaMachinePrincipal(answer.principal) ||
|
|
68
|
+
answer.principal.environment !== options.environment) {
|
|
47
69
|
res.status(401).json({ error: 'MACHINE_CREDENTIAL_INVALID' });
|
|
48
70
|
return;
|
|
49
71
|
}
|
|
50
|
-
const principal = Object.freeze({
|
|
72
|
+
const principal = Object.freeze({
|
|
73
|
+
...answer.principal,
|
|
74
|
+
scopes: Object.freeze(['alia:chat', 'inference:invoke']),
|
|
75
|
+
});
|
|
51
76
|
req.machineCredential = principal;
|
|
52
77
|
forwardingCredentials.set(req, { principal, bearer: token });
|
|
53
78
|
next();
|
package/dist/esm/server/auth.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { logger } from '../logger/index.js';
|
|
2
|
-
import { OXY_SERVICE_ENVIRONMENTS } from '../utils/oxyServiceEnvironment.js';
|
|
2
|
+
import { OXY_SERVICE_ENVIRONMENTS, } from '../utils/oxyServiceEnvironment.js';
|
|
3
3
|
export { OXY_SERVICE_ENVIRONMENTS };
|
|
4
4
|
function normalizeId(value) {
|
|
5
5
|
const normalized = value?.trim();
|
|
@@ -21,9 +21,7 @@ function ensureUser(req, userId) {
|
|
|
21
21
|
}
|
|
22
22
|
export function getOxyUserId(req) {
|
|
23
23
|
const authReq = req;
|
|
24
|
-
return (normalizeId(authReq.userId) ??
|
|
25
|
-
normalizeId(authReq.user?.id) ??
|
|
26
|
-
normalizeId(authReq.user?._id));
|
|
24
|
+
return (normalizeId(authReq.userId) ?? normalizeId(authReq.user?.id) ?? normalizeId(authReq.user?._id));
|
|
27
25
|
}
|
|
28
26
|
/**
|
|
29
27
|
* Who acted, and as whom, on this user session (issue #1520), or `null` when
|
|
@@ -167,7 +165,10 @@ export function requireOxyAuth(req, res, next) {
|
|
|
167
165
|
next();
|
|
168
166
|
}
|
|
169
167
|
export function createOptionalOxyAuth(oxy, options = {}) {
|
|
170
|
-
const resolveSession = oxy.middleware.auth({
|
|
168
|
+
const resolveSession = oxy.middleware.auth({
|
|
169
|
+
...options.auth,
|
|
170
|
+
optional: true,
|
|
171
|
+
});
|
|
171
172
|
return (req, res, next) => {
|
|
172
173
|
if (getOxyUserId(req)) {
|
|
173
174
|
next();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { randomUUID, sign as signBytes, verify as verifyBytes
|
|
1
|
+
import { randomUUID, sign as signBytes, verify as verifyBytes } from 'node:crypto';
|
|
2
2
|
import { capabilityTicketClaimsSchema, } from '@oxy.so/contracts';
|
|
3
3
|
const ALGORITHM = 'EdDSA';
|
|
4
4
|
const TOKEN_TYPE = 'OXY-CAPABILITY+JWT';
|
|
@@ -55,11 +55,11 @@ export function verifyCapabilityTicket(token, options) {
|
|
|
55
55
|
throw new CapabilityTicketError('malformed', 'Capability ticket header is not supported');
|
|
56
56
|
}
|
|
57
57
|
const headerRecord = header;
|
|
58
|
-
if (Object.keys(headerRecord).length !== 3
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
if (Object.keys(headerRecord).length !== 3 ||
|
|
59
|
+
headerRecord.alg !== ALGORITHM ||
|
|
60
|
+
headerRecord.typ !== TOKEN_TYPE ||
|
|
61
|
+
typeof headerRecord.kid !== 'string' ||
|
|
62
|
+
headerRecord.kid.length === 0) {
|
|
63
63
|
throw new CapabilityTicketError('malformed', 'Capability ticket header is not supported');
|
|
64
64
|
}
|
|
65
65
|
const publicKey = options.resolvePublicKey(headerRecord.kid);
|
package/dist/esm/server/index.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
// The backend client: OxyServices plus the service-token lane, middleware,
|
|
18
18
|
// account events and the service-only namespace methods.
|
|
19
|
-
export { OxyServer, ServiceCredentialMismatchError, ANONYMOUS_SERVICE_TOKEN_RETRY_MS } from './OxyServer.js';
|
|
19
|
+
export { OxyServer, ServiceCredentialMismatchError, ANONYMOUS_SERVICE_TOKEN_RETRY_MS, } from './OxyServer.js';
|
|
20
20
|
export { ServerAppsApi, ServerAgencyApi, ServerAssetsApi, ServerLinkedAccountsApi, ServerNotificationsApi, ServerReputationApi, } from './namespaces.js';
|
|
21
21
|
export { createOxyAliaMachineCredentialAuth, getOxyAliaMachineCredentialBearer, isOxyAliaMachinePrincipal, OXY_ALIA_RESOURCE_APPLICATION_ID, OXY_ALIA_MACHINE_SCOPES, } from './aliaMachineCredential.js';
|
|
22
22
|
export { OxyAccountEventError, OXY_ACCOUNT_DELETED_EVENT_URI } from './middleware.js';
|
|
@@ -48,13 +48,13 @@ export { createOxyUserInvalidationHandler, publishOxyUserInvalidation, } from '.
|
|
|
48
48
|
// The identity-key enumeration itself is platform-neutral (`src/utils/`) so the
|
|
49
49
|
// client namespaces and this Node-only subscriber sweep the SAME list — a second
|
|
50
50
|
// copy is what let `updateAccount` and `updateProfile` drift apart.
|
|
51
|
-
export { evictOxyIdentityCache, oxyUserByIdCacheKey, OXY_IDENTITY_CACHE_PREFIXES } from '../utils/identityCacheSweep.js';
|
|
51
|
+
export { evictOxyIdentityCache, oxyUserByIdCacheKey, OXY_IDENTITY_CACHE_PREFIXES, } from '../utils/identityCacheSweep.js';
|
|
52
52
|
// Registrable-apex (eTLD+1) derivation via the Public Suffix List — the SINGLE
|
|
53
53
|
// SOURCE OF TRUTH shared with the IdP worker and the client FAPI auto-detect.
|
|
54
54
|
// Pure host handling (no browser deps), so it is safe on the server subpath and
|
|
55
55
|
// lets `@oxy.so/api` derive `auth.<apex>` without duplicating PSL logic.
|
|
56
56
|
export { registrableApex } from '../utils/registrableApex.js';
|
|
57
|
-
export { isLoopbackOrigin, isOfficialWebOrigin, isAllowedDeviceJoinOrigin } from '../utils/officialOrigins.js';
|
|
57
|
+
export { isLoopbackOrigin, isOfficialWebOrigin, isAllowedDeviceJoinOrigin, } from '../utils/officialOrigins.js';
|
|
58
58
|
export { createEcosystemTraffic } from './traffic.js';
|
|
59
59
|
export { observeNodeHttp, withoutNodeHttpObservation } from './trafficNodeHttp.js';
|
|
60
60
|
/**
|
|
@@ -63,6 +63,6 @@ export { observeNodeHttp, withoutNodeHttpObservation } from './trafficNodeHttp.j
|
|
|
63
63
|
* exported from this subpath rather than the root barrel because it reaches the
|
|
64
64
|
* container credentials endpoint.
|
|
65
65
|
*/
|
|
66
|
-
export { canAttestWorkloadIdentity, requestWorkloadServiceToken } from './workloadIdentity.js';
|
|
67
|
-
export { OXY_SERVICE_TOKEN_MAX_LIFETIME_SECONDS, hasBoundedServiceTokenLifetime } from './serviceTokenLifetime.js';
|
|
66
|
+
export { attestWorkloadIdentity, canAttestWorkloadIdentity, requestWorkloadServiceToken, } from './workloadIdentity.js';
|
|
67
|
+
export { OXY_SERVICE_TOKEN_MAX_LIFETIME_SECONDS, hasBoundedServiceTokenLifetime, } from './serviceTokenLifetime.js';
|
|
68
68
|
export { signInAgentAccount } from './agentAccount.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { canonicalCapabilityJson, capabilityTicketClaimsSchema } from '@oxy.so/contracts';
|
|
2
|
-
import { verifyCapabilityTicket } from './capabilityTicket.js';
|
|
1
|
+
import { canonicalCapabilityJson, capabilityTicketClaimsSchema, } from '@oxy.so/contracts';
|
|
2
|
+
import { verifyCapabilityTicket, } from './capabilityTicket.js';
|
|
3
3
|
/** Local signature + live receiving-service introspection; no cache or retry. */
|
|
4
4
|
export function createLiveCapabilityTicketVerifier(options) {
|
|
5
5
|
if (typeof options.issuer !== 'string' || options.issuer.trim() === '')
|
|
@@ -25,7 +25,10 @@ export function createLiveCapabilityTicketVerifier(options) {
|
|
|
25
25
|
if (controller.signal.aborted)
|
|
26
26
|
rejectAbort();
|
|
27
27
|
});
|
|
28
|
-
const result = await Promise.race([
|
|
28
|
+
const result = await Promise.race([
|
|
29
|
+
options.introspect(ticket, { signal: controller.signal }),
|
|
30
|
+
interrupted,
|
|
31
|
+
]);
|
|
29
32
|
controller.signal.throwIfAborted();
|
|
30
33
|
if (result.active !== true)
|
|
31
34
|
throw new Error('Capability ticket is inactive');
|