@oxy.so/core 1.12.1 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/crypto/webIdentityCarrier.js +1 -1
- package/dist/cjs/i18n/locales/ar-SA.json +33 -88
- package/dist/cjs/i18n/locales/ca-ES.json +35 -90
- package/dist/cjs/i18n/locales/de-DE.json +33 -88
- package/dist/cjs/i18n/locales/en-US.json +45 -141
- package/dist/cjs/i18n/locales/es-ES.json +44 -140
- package/dist/cjs/i18n/locales/fr-FR.json +33 -88
- package/dist/cjs/i18n/locales/it-IT.json +33 -88
- package/dist/cjs/i18n/locales/ja-JP.json +33 -88
- package/dist/cjs/i18n/locales/ko-KR.json +33 -88
- package/dist/cjs/i18n/locales/locales/ar-SA.json +33 -88
- package/dist/cjs/i18n/locales/locales/ca-ES.json +35 -90
- package/dist/cjs/i18n/locales/locales/de-DE.json +33 -88
- package/dist/cjs/i18n/locales/locales/en-US.json +45 -141
- package/dist/cjs/i18n/locales/locales/es-ES.json +44 -140
- package/dist/cjs/i18n/locales/locales/fr-FR.json +33 -88
- package/dist/cjs/i18n/locales/locales/it-IT.json +33 -88
- package/dist/cjs/i18n/locales/locales/ja-JP.json +33 -88
- package/dist/cjs/i18n/locales/locales/ko-KR.json +33 -88
- package/dist/cjs/i18n/locales/locales/pt-PT.json +33 -88
- package/dist/cjs/i18n/locales/locales/zh-CN.json +34 -89
- package/dist/cjs/i18n/locales/pt-PT.json +33 -88
- package/dist/cjs/i18n/locales/zh-CN.json +34 -89
- package/dist/cjs/index.js +10 -7
- package/dist/cjs/mixins/OxyServices.utility.js +140 -0
- package/dist/cjs/server/securityHeaders.js +19 -1
- package/dist/cjs/session/accountDialogController.js +37 -142
- package/dist/cjs/utils/authWebUrl.js +7 -6
- package/dist/cjs/utils/oauthPkce.js +5 -1
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/crypto/webIdentityCarrier.js +1 -1
- package/dist/esm/i18n/locales/ar-SA.json +33 -88
- package/dist/esm/i18n/locales/ca-ES.json +35 -90
- package/dist/esm/i18n/locales/de-DE.json +33 -88
- package/dist/esm/i18n/locales/en-US.json +45 -141
- package/dist/esm/i18n/locales/es-ES.json +44 -140
- package/dist/esm/i18n/locales/fr-FR.json +33 -88
- package/dist/esm/i18n/locales/it-IT.json +33 -88
- package/dist/esm/i18n/locales/ja-JP.json +33 -88
- package/dist/esm/i18n/locales/ko-KR.json +33 -88
- package/dist/esm/i18n/locales/locales/ar-SA.json +33 -88
- package/dist/esm/i18n/locales/locales/ca-ES.json +35 -90
- package/dist/esm/i18n/locales/locales/de-DE.json +33 -88
- package/dist/esm/i18n/locales/locales/en-US.json +45 -141
- package/dist/esm/i18n/locales/locales/es-ES.json +44 -140
- package/dist/esm/i18n/locales/locales/fr-FR.json +33 -88
- package/dist/esm/i18n/locales/locales/it-IT.json +33 -88
- package/dist/esm/i18n/locales/locales/ja-JP.json +33 -88
- package/dist/esm/i18n/locales/locales/ko-KR.json +33 -88
- package/dist/esm/i18n/locales/locales/pt-PT.json +33 -88
- package/dist/esm/i18n/locales/locales/zh-CN.json +34 -89
- package/dist/esm/i18n/locales/pt-PT.json +33 -88
- package/dist/esm/i18n/locales/zh-CN.json +34 -89
- package/dist/esm/index.js +2 -1
- package/dist/esm/mixins/OxyServices.utility.js +138 -0
- package/dist/esm/server/securityHeaders.js +19 -1
- package/dist/esm/session/accountDialogController.js +37 -142
- package/dist/esm/utils/authWebUrl.js +6 -5
- package/dist/esm/utils/oauthPkce.js +5 -1
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/crypto/webIdentityCarrier.d.ts +1 -1
- package/dist/types/index.d.ts +5 -3
- package/dist/types/mixins/OxyServices.utility.d.ts +84 -1
- package/dist/types/server/requesterAssertion.d.ts +2 -2
- package/dist/types/server/securityHeaders.d.ts +9 -12
- package/dist/types/session/accountDialogController.d.ts +29 -98
- package/dist/types/utils/authWebUrl.d.ts +6 -5
- package/dist/types/utils/oauthPkce.d.ts +10 -0
- package/package.json +2 -2
- package/src/crypto/webIdentityCarrier.ts +1 -1
- package/src/i18n/locales/ar-SA.json +33 -88
- package/src/i18n/locales/ca-ES.json +35 -90
- package/src/i18n/locales/de-DE.json +33 -88
- package/src/i18n/locales/en-US.json +45 -141
- package/src/i18n/locales/es-ES.json +44 -140
- package/src/i18n/locales/fr-FR.json +33 -88
- package/src/i18n/locales/it-IT.json +33 -88
- package/src/i18n/locales/ja-JP.json +33 -88
- package/src/i18n/locales/ko-KR.json +33 -88
- package/src/i18n/locales/pt-PT.json +33 -88
- package/src/i18n/locales/zh-CN.json +34 -89
- package/src/index.ts +9 -3
- package/src/mixins/OxyServices.utility.ts +208 -0
- package/src/mixins/__tests__/accountEvents.test.ts +158 -0
- package/src/server/__tests__/securityHeaders.test.ts +17 -0
- package/src/server/securityHeaders.ts +29 -1
- package/src/session/__tests__/accountDialogController.test.ts +42 -184
- package/src/session/accountDialogController.ts +50 -185
- package/src/utils/__tests__/oauthPkce.test.ts +7 -0
- package/src/utils/authWebUrl.ts +6 -5
- package/src/utils/oauthPkce.ts +16 -1
|
@@ -11,7 +11,7 @@
|
|
|
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 —
|
|
14
|
+
* therefore safe to store anywhere — auth.oxy.so's IndexedDB and the server
|
|
15
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
|
package/dist/types/index.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ export type { ServiceTokenResponse, OAuthUserInfoResponse, OAuthTokenExchangeRes
|
|
|
29
29
|
export type { CommonsSignInHandle, CommonsSignInStatus, CommonsSignInPurpose, CommonsOAuthContext, CommonsApprovalInfo, CommonsApprovalSubjectAccount, CommonsSignInActionResult, CommonsOAuthFinalizeResult, CommonsDeliveryResult, } from './mixins/OxyServices.auth';
|
|
30
30
|
export type { PushTokenPlatform, RegisterPushTokenInput, } from './mixins/OxyServices.notifications';
|
|
31
31
|
export type { ServiceApp, ServiceActingAsVerification, OxyAuthRefusal } from './mixins/OxyServices.utility';
|
|
32
|
+
export type { OxyAccountEvent, OxyAccountEventFeedItem, OxyAccountEventFeedPage, VerifyAccountEventOptions, } from './mixins/OxyServices.utility';
|
|
33
|
+
export { OxyAccountEventError, OXY_ACCOUNT_DELETED_EVENT_URI } from './mixins/OxyServices.utility';
|
|
32
34
|
export type { ContactDiscoveryMatch, ContactDiscoveryResponse, } from './mixins/OxyServices.contacts';
|
|
33
35
|
export type { BulkFollowEntry, BulkFollowResult, BulkUnfollowEntry, BulkUnfollowResult, FollowMutationResult, ViewerGraph, } from './mixins/OxyServices.user';
|
|
34
36
|
export { OxyAppDataIdentifierError } from './mixins/OxyServices.appData';
|
|
@@ -109,12 +111,12 @@ export { updateAvatarVisibility } from './utils/avatarUtils';
|
|
|
109
111
|
export { buildAccountsArray, createQuickAccount, getAccountDisplayName, getAccountFallbackHandle, formatPublicKeyHandle, getAccountColor, } from './utils/accountUtils';
|
|
110
112
|
export type { QuickAccount, DisplayNameUserShape } from './utils/accountUtils';
|
|
111
113
|
export { registrableApex } from './utils/registrableApex';
|
|
112
|
-
export {
|
|
114
|
+
export { AUTH_WEB_ORIGIN, CENTRAL_IDP_APEX } from './utils/authWebUrl';
|
|
113
115
|
export { isOxyRpOrigin } from './utils/webauthnOrigin';
|
|
114
116
|
export { runColdBoot } from './utils/coldBoot';
|
|
115
117
|
export type { ColdBootStep, ColdBootStepResult, ColdBootSession, ColdBootSkip, ColdBootOutcome, RunColdBootOptions, } from './utils/coldBoot';
|
|
116
118
|
export { buildOAuthAuthorizeUrl, computeCodeChallenge, generateOAuthState, generatePkcePair, DEFAULT_OAUTH_SCOPE, OXY_AUTHORIZE_URL, OXY_OAUTH_STATE_STORAGE_KEY, OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY, OXY_OAUTH_REDIRECT_URI_STORAGE_KEY, OXY_OAUTH_RETURN_PATH_STORAGE_KEY, normalizeOAuthRedirectUri, canonicalizeOAuthRedirectUri, persistOAuthHandshake, readOAuthHandshake, clearOAuthHandshake, persistOAuthReturnPath, consumeOAuthReturnPath, } from './utils/oauthPkce';
|
|
117
|
-
export type { PkcePair, BuildOAuthAuthorizeUrlParams } from './utils/oauthPkce';
|
|
119
|
+
export type { PkcePair, BuildOAuthAuthorizeUrlParams, OxyAuthScreen } from './utils/oauthPkce';
|
|
118
120
|
export { isLoopbackOrigin, isOfficialWebOrigin, isAllowedDeviceJoinOrigin, } from './utils/officialOrigins';
|
|
119
121
|
export { SessionClient } from './session/SessionClient';
|
|
120
122
|
export type { TokenTransport, SessionClientHost, SessionClientOptions, DeviceCredential, SessionStateOrigin } from './session/SessionClient';
|
|
@@ -130,7 +132,7 @@ export { isSwitchTargetAccount, canSwitchIntoAccount, } from './session/accountS
|
|
|
130
132
|
export { resolveAccountDelegationAccess } from './session/accountDelegationAccess';
|
|
131
133
|
export type { AccountDelegationAccess, AccountDelegationNode, } from './session/accountDelegationAccess';
|
|
132
134
|
export { AccountDialogController, createAccountDialogController, } from './session/accountDialogController';
|
|
133
|
-
export type { AccountDialogControllerOptions, AccountDialogSnapshot, AccountDialogView, CommonsAvailability, ContextChoiceOutcome,
|
|
135
|
+
export type { AccountDialogControllerOptions, AccountDialogSnapshot, AccountDialogView, CommonsAvailability, ContextChoiceOutcome, SignInFailureReason, SignInFlowPhase, SignInFlowState, SignInProgress, } from './session/accountDialogController';
|
|
134
136
|
export { createWebAuthStateStore, createNativeAuthStateStore, createMemoryAuthStateStore, AUTH_STATE_STORAGE_KEY, } from './session/authStateStore';
|
|
135
137
|
export type { PersistedAuthState, AuthStateStore, NativeKeyValueStorage, } from './session/authStateStore';
|
|
136
138
|
export { createSharedMirroringAuthStateStore, decideSharedDeviceJoin, decideSharedDevicePublish, normalizeSharedDeviceSessionRead, publishProvenDeviceCredential, readLocalDeviceCredential, } from './session/sharedDeviceCredential';
|
|
@@ -25,6 +25,64 @@ export interface ServiceActingAsVerification {
|
|
|
25
25
|
authorized: boolean;
|
|
26
26
|
scopes: string[];
|
|
27
27
|
}
|
|
28
|
+
/** The SET `events` member Oxy uses for an account deletion. */
|
|
29
|
+
export declare const OXY_ACCOUNT_DELETED_EVENT_URI = "https://oxy.so/events/account.deleted";
|
|
30
|
+
/**
|
|
31
|
+
* A verified account event from Oxy (OxyHQ/Mention#1169): a person deleted
|
|
32
|
+
* their Oxy account and every relying application must erase what it holds
|
|
33
|
+
* for them. Returned by `verifyAccountEvent` only after the signature, `typ`,
|
|
34
|
+
* issuer and audience all check out.
|
|
35
|
+
*/
|
|
36
|
+
export interface OxyAccountEvent {
|
|
37
|
+
/** The event id (`jti`). Stable across webhook retries and the pull feed: dedupe on it. */
|
|
38
|
+
eventId: string;
|
|
39
|
+
type: 'account.deleted';
|
|
40
|
+
/** The deleted Oxy account. */
|
|
41
|
+
userId: string;
|
|
42
|
+
/**
|
|
43
|
+
* The account's handle at deletion time, for relying parties that address
|
|
44
|
+
* the person by handle (an ActivityPub actor URI). `null` when the account had
|
|
45
|
+
* none, or when the token predates the field.
|
|
46
|
+
*/
|
|
47
|
+
username: string | null;
|
|
48
|
+
/** ISO-8601 time the deletion committed. */
|
|
49
|
+
occurredAt: string;
|
|
50
|
+
/** `true` when Oxy archived the row to keep financial records. Erase either way. */
|
|
51
|
+
retained: boolean;
|
|
52
|
+
/** The application the event was addressed to (`aud`). */
|
|
53
|
+
applicationId: string;
|
|
54
|
+
/** Seconds since the epoch the token was issued at (`iat`). */
|
|
55
|
+
issuedAt: number;
|
|
56
|
+
}
|
|
57
|
+
/** One entry of the account-event pull feed (`GET /account-events`). */
|
|
58
|
+
export interface OxyAccountEventFeedItem {
|
|
59
|
+
eventId: string;
|
|
60
|
+
type: 'account.deleted';
|
|
61
|
+
userId: string;
|
|
62
|
+
username: string | null;
|
|
63
|
+
occurredAt: string;
|
|
64
|
+
retained: boolean;
|
|
65
|
+
/** The same signed token the webhook carries. Verify it with `verifyAccountEvent`. */
|
|
66
|
+
token: string;
|
|
67
|
+
}
|
|
68
|
+
export interface OxyAccountEventFeedPage {
|
|
69
|
+
events: OxyAccountEventFeedItem[];
|
|
70
|
+
/** Pass back as `after` to continue; unchanged when the page is empty. */
|
|
71
|
+
nextCursor: string | null;
|
|
72
|
+
}
|
|
73
|
+
export interface VerifyAccountEventOptions {
|
|
74
|
+
/**
|
|
75
|
+
* The application id the token must be addressed to. Defaults to the `appId`
|
|
76
|
+
* of this client's configured service credential.
|
|
77
|
+
*/
|
|
78
|
+
audience?: string;
|
|
79
|
+
/** Defaults to `/.well-known/jwks.json` on this client's API origin. */
|
|
80
|
+
jwksUrl?: string;
|
|
81
|
+
}
|
|
82
|
+
/** Why an account event token was refused. `message` never contains the token. */
|
|
83
|
+
export declare class OxyAccountEventError extends Error {
|
|
84
|
+
constructor(message: string);
|
|
85
|
+
}
|
|
28
86
|
/**
|
|
29
87
|
* Service app metadata attached to requests authenticated with service tokens.
|
|
30
88
|
*
|
|
@@ -177,6 +235,31 @@ export declare function OxyServicesUtilityMixin<T extends typeof OxyServicesBase
|
|
|
177
235
|
* @internal Used by the auth() middleware — not part of the public API
|
|
178
236
|
*/
|
|
179
237
|
verifyServiceActingAs(appId: string, userId: string): Promise<ServiceActingAsVerification | null>;
|
|
238
|
+
/**
|
|
239
|
+
* Verify an account event token from Oxy — the body of an account-event
|
|
240
|
+
* webhook, or an entry's `token` from `listAccountEvents` — and return the
|
|
241
|
+
* event. Throws {@link OxyAccountEventError} unless the token is an
|
|
242
|
+
* EdDSA-signed `secevent+jwt` from Oxy's published key set, issued by
|
|
243
|
+
* `oxy-auth`, addressed to this application, carrying exactly one known
|
|
244
|
+
* event. A service token (`typ: JWT`) is refused here, as this token is
|
|
245
|
+
* refused as a service token.
|
|
246
|
+
*
|
|
247
|
+
* Node only (it needs `node:crypto`). The caller must still be idempotent on
|
|
248
|
+
* `eventId`: Oxy delivers at least once, by push and by pull.
|
|
249
|
+
*/
|
|
250
|
+
verifyAccountEvent(token: string, options?: VerifyAccountEventOptions): Promise<OxyAccountEvent>;
|
|
251
|
+
/**
|
|
252
|
+
* One page of account events addressed to this application, oldest first,
|
|
253
|
+
* from Oxy's pull feed — the reconciliation path behind the webhook. Needs
|
|
254
|
+
* the service credential (`configureServiceAuth`). Verify each entry's
|
|
255
|
+
* `token` with {@link verifyAccountEvent} before acting on it.
|
|
256
|
+
*/
|
|
257
|
+
listAccountEvents(options?: {
|
|
258
|
+
after?: string;
|
|
259
|
+
limit?: number;
|
|
260
|
+
}): Promise<OxyAccountEventFeedPage>;
|
|
261
|
+
/** @internal The `appId` claim of this client's own service token. */
|
|
262
|
+
_configuredServiceAppId(): Promise<string>;
|
|
180
263
|
/**
|
|
181
264
|
* Express.js authentication middleware
|
|
182
265
|
*
|
|
@@ -380,7 +463,7 @@ export declare function OxyServicesUtilityMixin<T extends typeof OxyServicesBase
|
|
|
380
463
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
381
464
|
maxRetries?: number;
|
|
382
465
|
retryDelay?: number;
|
|
383
|
-
authTimeoutMs
|
|
466
|
+
authTimeoutMs? /** @internal Per-client public-key cache; never contains private material. */: number;
|
|
384
467
|
}): Promise<T_1>;
|
|
385
468
|
validate(): Promise<boolean>;
|
|
386
469
|
handleError(error: unknown): Error;
|
|
@@ -40,8 +40,8 @@ export declare const oxyRequesterAssertionClaimsSchema: z.ZodObject<{
|
|
|
40
40
|
sub: string;
|
|
41
41
|
aud: string;
|
|
42
42
|
iss: string;
|
|
43
|
-
iat: number;
|
|
44
43
|
jti: string;
|
|
44
|
+
iat: number;
|
|
45
45
|
azp: string;
|
|
46
46
|
cid: string;
|
|
47
47
|
agentId: string;
|
|
@@ -50,8 +50,8 @@ export declare const oxyRequesterAssertionClaimsSchema: z.ZodObject<{
|
|
|
50
50
|
sub: string;
|
|
51
51
|
aud: string;
|
|
52
52
|
iss: string;
|
|
53
|
-
iat: number;
|
|
54
53
|
jti: string;
|
|
54
|
+
iat: number;
|
|
55
55
|
azp: string;
|
|
56
56
|
cid: string;
|
|
57
57
|
agentId: string;
|
|
@@ -166,6 +166,15 @@ export interface OxyPagesHeadersOptions {
|
|
|
166
166
|
* injecting the beacon at all — otherwise every page load logs a CSP
|
|
167
167
|
* violation for a script we never asked for. The rest of the value is Pages'
|
|
168
168
|
* own default, so caching is unchanged.
|
|
169
|
+
*
|
|
170
|
+
* And, because this origin is the web identity carrier — where a person's
|
|
171
|
+
* self-custody root is created, opened, recovered and moved (ADR 0028) — the
|
|
172
|
+
* rest of the holder policy: no `<base>` and no form posts (`base-uri` /
|
|
173
|
+
* `form-action 'none'`), no Referer to anyone, passkeys for this origin only
|
|
174
|
+
* with every other powerful feature off (`Permissions-Policy`), and its
|
|
175
|
+
* responses readable by no other origin (`Cross-Origin-Resource-Policy`).
|
|
176
|
+
* Never `Cross-Origin-Opener-Policy`: the third-party OAuth popup reports
|
|
177
|
+
* its code to the app that opened it, and COOP severs `window.opener`.
|
|
169
178
|
*/
|
|
170
179
|
sensitive?: boolean;
|
|
171
180
|
/**
|
|
@@ -184,18 +193,6 @@ export interface OxyPagesHeadersOptions {
|
|
|
184
193
|
*/
|
|
185
194
|
html?: readonly string[];
|
|
186
195
|
}
|
|
187
|
-
/**
|
|
188
|
-
* Build a Cloudflare Pages `_headers` block for an Oxy HTML origin. Uses the
|
|
189
|
-
* same CSP resolution as {@link createOxySecurityHeaders} plus the non-CSP
|
|
190
|
-
* hardening headers Helmet would add on an Express HTML backend.
|
|
191
|
-
*
|
|
192
|
-
* Adding a hash to `script-src` does not narrow it: per CSP Level 3 a hash is
|
|
193
|
-
* an additional source, so `'self'` and the beacon host keep matching external
|
|
194
|
-
* scripts. (It WOULD neutralize `'unsafe-inline'` in the same directive — which
|
|
195
|
-
* is why this hashes scripts only. `style-src` keeps `'unsafe-inline'` for
|
|
196
|
-
* react-native-web's runtime stylesheet, and a style hash would silently switch
|
|
197
|
-
* that off and render every Oxy web app unstyled.)
|
|
198
|
-
*/
|
|
199
196
|
export declare function buildOxyPagesHeaders(options?: OxyPagesHeadersOptions): string;
|
|
200
197
|
export interface OxySecurityHeadersOptions {
|
|
201
198
|
/**
|
|
@@ -36,12 +36,6 @@
|
|
|
36
36
|
* - `commonsAvailability` — whether Commons is installed on this device
|
|
37
37
|
* (native only, via the injected `canOpenApp` probe), so the QR view can
|
|
38
38
|
* offer a "Get Commons" fallback instead of a same-device dead end.
|
|
39
|
-
* - `startPasskeyHubSignIn` — on a non-Oxy web origin (where a WebAuthn
|
|
40
|
-
* ceremony can't run locally, the RP-ID is bound to oxy.so), open a popup
|
|
41
|
-
* at the auth.oxy.so passkey hub instead, scoped to the SAME device-flow
|
|
42
|
-
* session `showQr` creates, and complete it via the SAME poll/socket/claim
|
|
43
|
-
* engine. Falls back to `showQr`'s plain QR rendering if the popup is
|
|
44
|
-
* blocked.
|
|
45
39
|
*
|
|
46
40
|
* Sign-in is passkey (WebAuthn) or the Commons QR / shared-keychain handoff —
|
|
47
41
|
* password, social login, and 2FA were removed ecosystem-wide. Account
|
|
@@ -114,8 +108,6 @@ export type SignInProgress = 'idle' | 'preparing' | 'awaiting-approval' | 'deliv
|
|
|
114
108
|
* WHY a sign-in attempt ended in `'error'` — a machine-readable reason the UI
|
|
115
109
|
* turns into localized copy (the controller ships no user-facing prose).
|
|
116
110
|
*
|
|
117
|
-
* - `'cancelled'` — the USER walked away (closed the passkey hub popup). A
|
|
118
|
-
* voluntary outcome, not a failure to report.
|
|
119
111
|
* - `'denied'` — the approver declined the request in Commons.
|
|
120
112
|
* - `'expired'` — the request outlived its server-authoritative expiry.
|
|
121
113
|
* - `'network'` — Oxy could not be reached (no response, timeout).
|
|
@@ -124,22 +116,7 @@ export type SignInProgress = 'idle' | 'preparing' | 'awaiting-approval' | 'deliv
|
|
|
124
116
|
* - `'claim-failed'` — the request WAS approved, but the session could not be claimed.
|
|
125
117
|
* - `'unknown'` — anything else; the raw message stays on `error` for logs.
|
|
126
118
|
*/
|
|
127
|
-
export type SignInFailureReason = '
|
|
128
|
-
/**
|
|
129
|
-
* Minimal structural handle over a popup `Window` — just enough for the
|
|
130
|
-
* cross-origin passkey hub flow ({@link AccountDialogController.startPasskeyHubSignIn}):
|
|
131
|
-
* navigate it once the device-flow session's `authorizeCode` is known, detect
|
|
132
|
-
* the user closing it early (`closed`), and close it programmatically on
|
|
133
|
-
* completion/failure. Satisfied directly by `window.open()`'s return value on
|
|
134
|
-
* web; native has no popup concept and never injects an opener.
|
|
135
|
-
*/
|
|
136
|
-
export interface PopupWindowHandle {
|
|
137
|
-
readonly closed: boolean;
|
|
138
|
-
close(): void;
|
|
139
|
-
location: {
|
|
140
|
-
href: string;
|
|
141
|
-
};
|
|
142
|
-
}
|
|
119
|
+
export type SignInFailureReason = 'denied' | 'expired' | 'network' | 'not-configured' | 'unsupported-flow' | 'claim-failed' | 'unknown';
|
|
143
120
|
/**
|
|
144
121
|
* State of the "Sign in with Oxy" (shared-key / QR) device flow.
|
|
145
122
|
*
|
|
@@ -217,6 +194,14 @@ export interface SignInFlowState {
|
|
|
217
194
|
* attempt failing with the same message is).
|
|
218
195
|
*/
|
|
219
196
|
attempt: number;
|
|
197
|
+
/**
|
|
198
|
+
* `true` when this attempt is the sign-in entry's EMBEDDED QR
|
|
199
|
+
* ({@link AccountDialogController.startInlineQr}): a request the surface
|
|
200
|
+
* started on its own, not one the person asked for. Its failures (an expired
|
|
201
|
+
* code, above all) belong to that QR, which renews itself, and are not news
|
|
202
|
+
* to report.
|
|
203
|
+
*/
|
|
204
|
+
inline: boolean;
|
|
220
205
|
}
|
|
221
206
|
/** Immutable snapshot consumed by `useSyncExternalStore`. */
|
|
222
207
|
export interface AccountDialogSnapshot {
|
|
@@ -343,28 +328,6 @@ export interface AccountDialogControllerOptions {
|
|
|
343
328
|
* `showQr` behaves exactly as before (render QR only).
|
|
344
329
|
*/
|
|
345
330
|
canOpenApp?: (url: string) => Promise<boolean>;
|
|
346
|
-
/**
|
|
347
|
-
* Open a new, empty popup window SYNCHRONOUSLY (before any `await`) so the
|
|
348
|
-
* browser attributes it to the click gesture that triggered it, returning a
|
|
349
|
-
* handle to navigate once the device-flow session is known — or `null` if
|
|
350
|
-
* the popup was blocked. Injected by the provider (web only:
|
|
351
|
-
* `window.open('', ...)`; absent on native, where the hub-popup flow does
|
|
352
|
-
* not apply). Used by {@link AccountDialogController.startPasskeyHubSignIn}.
|
|
353
|
-
*/
|
|
354
|
-
openPopup?: () => PopupWindowHandle | null;
|
|
355
|
-
/**
|
|
356
|
-
* Origin of the web identity carrier (default `IDENTITY_WEB_ORIGIN`,
|
|
357
|
-
* `https://id.oxy.so`) — where a passkey sign-in or sign-up runs
|
|
358
|
-
* and the account's identity is kept sealed under the passkey. The popup opens
|
|
359
|
-
* `<identityOrigin>/continue?code=…`. Overridable for local/staging testing.
|
|
360
|
-
*/
|
|
361
|
-
identityOrigin?: string;
|
|
362
|
-
/**
|
|
363
|
-
* @deprecated Alias of {@link identityOrigin}, kept for existing
|
|
364
|
-
* configuration. The popup used to open `auth.oxy.so/hub-passkey`; it now opens
|
|
365
|
-
* the identity origin's `/continue`, so a value here must be that origin.
|
|
366
|
-
*/
|
|
367
|
-
hubBaseUrl?: string;
|
|
368
331
|
/**
|
|
369
332
|
* Which surface the sign-in is initiated from — a FACT supplied by the
|
|
370
333
|
* consumer, because only the consumer can classify its own environment
|
|
@@ -389,8 +352,6 @@ export declare class AccountDialogController {
|
|
|
389
352
|
private readonly openUrl?;
|
|
390
353
|
private readonly canOpenApp?;
|
|
391
354
|
private readonly socketFactory?;
|
|
392
|
-
private readonly openPopup?;
|
|
393
|
-
private readonly identityOrigin;
|
|
394
355
|
private readonly platform;
|
|
395
356
|
private readonly listeners;
|
|
396
357
|
private view;
|
|
@@ -433,10 +394,6 @@ export declare class AccountDialogController {
|
|
|
433
394
|
* ABANDONED request never blocks the next request's first poll.
|
|
434
395
|
*/
|
|
435
396
|
private pollInFlightToken;
|
|
436
|
-
/** The popup opened by {@link startPasskeyHubSignIn}, or `null`. */
|
|
437
|
-
private activePopup;
|
|
438
|
-
/** Watches {@link activePopup}'s `closed` state; see {@link watchPopup}. */
|
|
439
|
-
private popupWatchTimer;
|
|
440
397
|
private unsubscribeSession;
|
|
441
398
|
private unsubscribeTokens;
|
|
442
399
|
/** Last-observed SDK auth readiness (a planted bearer). Drives the fetch edge. */
|
|
@@ -642,38 +599,21 @@ export declare class AccountDialogController {
|
|
|
642
599
|
*/
|
|
643
600
|
showQr(): Promise<void>;
|
|
644
601
|
/**
|
|
645
|
-
*
|
|
646
|
-
*
|
|
647
|
-
* passkey-hub attempt reopens the hub popup; a failed "Sign in with Oxy"
|
|
648
|
-
* retries that; an explicit QR request shows the QR.
|
|
602
|
+
* The sign-in entry's EMBEDDED QR: a request whose only route is the QR,
|
|
603
|
+
* started without leaving the current view.
|
|
649
604
|
*
|
|
650
|
-
*
|
|
651
|
-
*
|
|
652
|
-
*
|
|
605
|
+
* Unlike {@link showQr} it runs no delivery selection. The surface starts it
|
|
606
|
+
* by itself, on mount, so it must not push to the person's phone or open
|
|
607
|
+
* Commons — nobody asked for either. Any other sign-in the person then
|
|
608
|
+
* chooses supersedes it (and withdraws its request) like any new attempt.
|
|
653
609
|
*/
|
|
654
|
-
|
|
610
|
+
startInlineQr(): Promise<void>;
|
|
655
611
|
/**
|
|
656
|
-
*
|
|
657
|
-
*
|
|
658
|
-
*
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
* (one identity, two carriers). Opens a popup at `<identityOrigin>/continue`,
|
|
662
|
-
* scoped to the SAME device-flow
|
|
663
|
-
* session {@link showQr} would create (same `authorizeCode`/`sessionToken`
|
|
664
|
-
* pair), and let the SAME poll/socket/claim engine complete it once the hub
|
|
665
|
-
* authorizes the session (`POST /auth/session/authorize-code/:authorizeCode`,
|
|
666
|
-
* bearer-authed, server-side — this method never sees or transmits the
|
|
667
|
-
* secret `sessionToken`).
|
|
668
|
-
*
|
|
669
|
-
* The popup MUST be opened synchronously, before any `await`, or the
|
|
670
|
-
* browser's popup blocker loses the click-gesture attribution and silently
|
|
671
|
-
* blocks it — so {@link openPopup} is invoked as the very first step, before
|
|
672
|
-
* the device-flow session (which needs an async call) even exists. If the
|
|
673
|
-
* popup is blocked (or no `openPopup` was injected), this falls back to
|
|
674
|
-
* `showQr`'s plain QR rendering — no dead end.
|
|
675
|
-
*/
|
|
676
|
-
startPasskeyHubSignIn(): Promise<void>;
|
|
612
|
+
* Start a NEW attempt the same way the last one was started — "Try again"
|
|
613
|
+
* repeats the user's choice rather than silently switching method: a failed
|
|
614
|
+
* "Sign in with Oxy" retries that; an explicit QR request shows the QR.
|
|
615
|
+
*/
|
|
616
|
+
retrySignIn(): Promise<void>;
|
|
677
617
|
/**
|
|
678
618
|
* End whatever attempt is running (withdrawing its request) and begin a new
|
|
679
619
|
* one. Returns the new attempt's identity for the caller to re-check after
|
|
@@ -683,9 +623,9 @@ export declare class AccountDialogController {
|
|
|
683
623
|
/** Whether `attempt` is still the one the surface is waiting on. */
|
|
684
624
|
private isCurrentAttempt;
|
|
685
625
|
/**
|
|
686
|
-
* Shared device-flow session creation for
|
|
687
|
-
*
|
|
688
|
-
*
|
|
626
|
+
* Shared device-flow session creation for {@link signInWithOxy},
|
|
627
|
+
* {@link showQr} and {@link startInlineQr} — the same `startCommonsSignIn` →
|
|
628
|
+
* poll/socket wiring every time. Returns the
|
|
689
629
|
* handle on success (already reflected in `signIn`), or `null` when the
|
|
690
630
|
* attempt failed (already set as `signIn.failure`) or was abandoned while the
|
|
691
631
|
* request was being created.
|
|
@@ -696,8 +636,8 @@ export declare class AccountDialogController {
|
|
|
696
636
|
* request, a socket, and a poll behind it.
|
|
697
637
|
* @param opts.deliver - Whether to run automatic Commons delivery selection
|
|
698
638
|
* ({@link resolveDeliveryRoute}). `true` for the normal one-primary-action
|
|
699
|
-
* entry; `false`
|
|
700
|
-
*
|
|
639
|
+
* entry; `false` for the embedded QR, which the screen starts by itself,
|
|
640
|
+
* where the request's Commons route is simply the QR.
|
|
701
641
|
*/
|
|
702
642
|
private startDeviceFlowSession;
|
|
703
643
|
/**
|
|
@@ -744,17 +684,6 @@ export declare class AccountDialogController {
|
|
|
744
684
|
* end the user stares at.
|
|
745
685
|
*/
|
|
746
686
|
private openCommonsLink;
|
|
747
|
-
/**
|
|
748
|
-
* Poll {@link PopupWindowHandle.closed} so a user who dismisses the hub
|
|
749
|
-
* popup without completing sign-in gets prompt feedback (there is no DOM
|
|
750
|
-
* event for a cross-origin popup closing — polling is the only mechanism).
|
|
751
|
-
* Cleared by {@link closeActivePopup}, which every sign-in exit path already
|
|
752
|
-
* calls.
|
|
753
|
-
*/
|
|
754
|
-
private watchPopup;
|
|
755
|
-
private clearPopupWatchTimer;
|
|
756
|
-
/** Tear down the popup watch timer and close the popup, if any. Idempotent. */
|
|
757
|
-
private closeActivePopup;
|
|
758
687
|
/**
|
|
759
688
|
* Resolve whether Commons is installed on this device via the injected
|
|
760
689
|
* `canOpenApp` probe, updating {@link commonsAvailability} as durable,
|
|
@@ -769,7 +698,7 @@ export declare class AccountDialogController {
|
|
|
769
698
|
*/
|
|
770
699
|
private resolveCommonsAvailability;
|
|
771
700
|
/**
|
|
772
|
-
* Tear down the active sign-in device flow (timers + socket +
|
|
701
|
+
* Tear down the active sign-in device flow (timers + socket + token),
|
|
773
702
|
* WITHDRAW the request server-side, and reset to idle.
|
|
774
703
|
*
|
|
775
704
|
* Cancellation has to converge in both directions: the surface closing must
|
|
@@ -869,6 +798,8 @@ export declare class AccountDialogController {
|
|
|
869
798
|
* to advance without a fact behind it.
|
|
870
799
|
*/
|
|
871
800
|
private setSignIn;
|
|
801
|
+
/** `facts` as the current attempt's state. */
|
|
802
|
+
private stampSignIn;
|
|
872
803
|
/** Update a subset of the device-flow facts, re-deriving `progress`. */
|
|
873
804
|
private patchSignIn;
|
|
874
805
|
private computeSnapshot;
|
|
@@ -15,9 +15,10 @@
|
|
|
15
15
|
*/
|
|
16
16
|
export declare const CENTRAL_IDP_APEX = "oxy.so";
|
|
17
17
|
/**
|
|
18
|
-
* The
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* The IdP's origin, `auth.oxy.so` — the OAuth authorize/consent surface AND the
|
|
19
|
+
* web identity carrier: where a person signs in or creates an account with a
|
|
20
|
+
* passkey from another origin's popup, and the one origin that may create,
|
|
21
|
+
* open, recover or move their self-custody identity (one identity, two
|
|
22
|
+
* carriers). Apps open it; they never handle the identity themselves.
|
|
22
23
|
*/
|
|
23
|
-
export declare const
|
|
24
|
+
export declare const AUTH_WEB_ORIGIN = "https://auth.oxy.so";
|
|
@@ -67,7 +67,17 @@ export interface BuildOAuthAuthorizeUrlParams {
|
|
|
67
67
|
* a token, device secret, or the PKCE verifier, which the opener keeps.
|
|
68
68
|
*/
|
|
69
69
|
responseMode?: 'web_message';
|
|
70
|
+
/**
|
|
71
|
+
* Which of the IdP's screens a person with no session there lands on:
|
|
72
|
+
* `signin` (sign in with a passkey), `signup` (create an account with its
|
|
73
|
+
* root), `recover` (recover it from the recovery phrase). Omitted, the IdP
|
|
74
|
+
* offers its Commons request first. An Oxy app sends this when it sends the
|
|
75
|
+
* person to auth.oxy.so for what only that origin can do, in the same tab.
|
|
76
|
+
*/
|
|
77
|
+
screen?: OxyAuthScreen;
|
|
70
78
|
}
|
|
79
|
+
/** The IdP screens {@link BuildOAuthAuthorizeUrlParams.screen} can open. */
|
|
80
|
+
export type OxyAuthScreen = 'signin' | 'signup' | 'recover';
|
|
71
81
|
/**
|
|
72
82
|
* Compute the PKCE S256 `code_challenge` for a given verifier:
|
|
73
83
|
* `BASE64URL(SHA-256(ASCII(codeVerifier)))` (RFC 7636 §4.2). The verifier is
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxy.so/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.0",
|
|
4
4
|
"description": "OxyHQ SDK Foundation — API client, authentication, cryptographic identity, and shared utilities",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"@oxy.so/telemetry": "^1.1.1",
|
|
119
119
|
"@noble/ciphers": "^1.3.0",
|
|
120
120
|
"@noble/hashes": "^1.8.0",
|
|
121
|
-
"@oxy.so/contracts": "^
|
|
121
|
+
"@oxy.so/contracts": "^2.0.0",
|
|
122
122
|
"@oxy.so/protocol": "^1.1.1",
|
|
123
123
|
"@scure/bip39": "^1.6.0",
|
|
124
124
|
"buffer": "^6.0.3",
|
|
@@ -11,7 +11,7 @@
|
|
|
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 —
|
|
14
|
+
* therefore safe to store anywhere — auth.oxy.so's IndexedDB and the server
|
|
15
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
|
|
@@ -1,53 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"signin": {
|
|
3
3
|
"title": "تسجيل الدخول",
|
|
4
|
-
"subtitle": "
|
|
4
|
+
"subtitle": "استخدم حسابك في Oxy",
|
|
5
5
|
"addAccountTitle": "إضافة حساب آخر",
|
|
6
6
|
"addAccountSubtitle": "تسجيل الدخول بحساب آخر",
|
|
7
7
|
"username": {
|
|
8
8
|
"label": "اسم المستخدم",
|
|
9
|
-
"placeholder": "
|
|
10
|
-
"
|
|
11
|
-
"required": "يرجى إدخال اسم المستخدم.",
|
|
12
|
-
"minLength": "يجب أن يكون اسم المستخدم 3 أحرف على الأقل."
|
|
13
|
-
},
|
|
14
|
-
"password": {
|
|
15
|
-
"label": "كلمة المرور",
|
|
16
|
-
"placeholder": "أدخل كلمة المرور",
|
|
17
|
-
"required": "يرجى إدخال كلمة المرور.",
|
|
18
|
-
"hint": "أدخل كلمة المرور لتسجيل الدخول"
|
|
9
|
+
"placeholder": "yourname",
|
|
10
|
+
"required": "يرجى إدخال اسم المستخدم."
|
|
19
11
|
},
|
|
20
12
|
"actions": {
|
|
21
13
|
"continue": "متابعة",
|
|
22
|
-
"back": "رجوع"
|
|
23
|
-
"signIn": "تسجيل الدخول",
|
|
24
|
-
"verify": "التحقق",
|
|
25
|
-
"openAccountSwitcher": "التبديل إلى حساب آخر",
|
|
26
|
-
"openAccountSwitcherSubtitle": "{{count}} حسابات أخرى متاحة",
|
|
27
|
-
"openAccountSwitcherSubtitle_singular": "حساب آخر واحد متاح",
|
|
28
|
-
"openAccountSwitcherSubtitle_zero": "راجع حساباتك المحفوظة",
|
|
29
|
-
"manageAccounts": "إدارة الحسابات المحفوظة",
|
|
30
|
-
"manageAccountsSubtitle": "مراجعة الجلسات أو إزالتها أو تسجيل الخروج",
|
|
31
|
-
"loadingOtherAccounts": "جاري تحميل الحسابات الأخرى…",
|
|
32
|
-
"switchAccountFailed": "لم نتمكن من التبديل بين الحسابات. يرجى المحاولة مرة أخرى."
|
|
14
|
+
"back": "رجوع"
|
|
33
15
|
},
|
|
34
|
-
"forgotPrompt": "نسيت كلمة المرور؟",
|
|
35
|
-
"security": {
|
|
36
|
-
"dataSecure": "بياناتك مشفرة وآمنة"
|
|
37
|
-
},
|
|
38
|
-
"currentlySignedInAs": "مسجل الدخول حاليًا كـ",
|
|
39
|
-
"alreadySignedInWith": "مسجل الدخول بالفعل بـ",
|
|
40
|
-
"alreadySignedIn": "مسجل الدخول بالفعل",
|
|
41
|
-
"alreadySignedInMessage": "هذا الحساب مسجل الدخول بالفعل. المتابعة بهذا الحساب؟",
|
|
42
|
-
"continueWithAccount": "متابعة",
|
|
43
|
-
"currentAccount": "الحالي",
|
|
44
|
-
"or": "أو",
|
|
45
|
-
"viewAllAccounts": "عرض {{count}} المزيد",
|
|
46
16
|
"createAccountLink": "جديد على Oxy؟ أنشئ حسابًا",
|
|
47
17
|
"status": {
|
|
48
|
-
"accountSwitched": "استخدام {{name}} الآن",
|
|
49
18
|
"signingIn": "جارٍ تسجيل الدخول…"
|
|
50
|
-
}
|
|
19
|
+
},
|
|
20
|
+
"subtitleToApp": "للمتابعة إلى {{app}}",
|
|
21
|
+
"orContinueWith": "أو تابع باستخدام",
|
|
22
|
+
"qr": {
|
|
23
|
+
"caption": "امسح باستخدام Commons لتسجيل الدخول",
|
|
24
|
+
"renew": "عرض رمز جديد"
|
|
25
|
+
},
|
|
26
|
+
"methods": {
|
|
27
|
+
"passkey": "تسجيل الدخول بمفتاح المرور"
|
|
28
|
+
},
|
|
29
|
+
"errors": {
|
|
30
|
+
"rateLimited": "محاولات كثيرة جدًا. حاول مرة أخرى بعد {{seconds}} ث.",
|
|
31
|
+
"passkeyCancelled": "تم إغلاق طلب مفتاح المرور. حاول مرة أخرى عندما تكون مستعدًا.",
|
|
32
|
+
"passkeyFailed": "تعذر إكمال مفتاح المرور. حاول مرة أخرى."
|
|
33
|
+
},
|
|
34
|
+
"chooser": {
|
|
35
|
+
"subtitleToApp": "للمتابعة إلى {{app}}"
|
|
36
|
+
},
|
|
37
|
+
"terms": {
|
|
38
|
+
"before": "بالمتابعة، أنت توافق على",
|
|
39
|
+
"termsLink": "شروط الخدمة",
|
|
40
|
+
"and": "و",
|
|
41
|
+
"privacyLink": "سياسة الخصوصية"
|
|
42
|
+
},
|
|
43
|
+
"noAccount": "ليس لديك حساب؟",
|
|
44
|
+
"createAccount": "إنشاء حساب",
|
|
45
|
+
"recoverLink": "فقدت مفتاح المرور؟ استرد حسابك"
|
|
51
46
|
},
|
|
52
47
|
"signup": {
|
|
53
48
|
"title": "أنشئ حسابك",
|
|
@@ -55,56 +50,9 @@
|
|
|
55
50
|
"createInCommons": "أنشئ هويتك في Commons",
|
|
56
51
|
"createAccount": "إنشاء حساب",
|
|
57
52
|
"backToSignInLink": "لديك حساب بالفعل؟ سجّل الدخول",
|
|
58
|
-
"
|
|
59
|
-
"title": "مرحبًا بك في Oxy!",
|
|
60
|
-
"subtitle": "أنشئ حسابك في خطوات قليلة",
|
|
61
|
-
"haveAccount": "لديك حساب بالفعل؟",
|
|
62
|
-
"signInCta": "تسجيل الدخول"
|
|
63
|
-
},
|
|
64
|
-
"identity": {
|
|
65
|
-
"title": "من أنت؟",
|
|
66
|
-
"subtitle": "اختر اسم المستخدم وأدخل بريدك الإلكتروني"
|
|
67
|
-
},
|
|
68
|
-
"username": {
|
|
69
|
-
"helper": "3-30 حرفًا، أحرف وأرقام فقط",
|
|
70
|
-
"required": "يرجى إدخال اسم مستخدم",
|
|
71
|
-
"minLength": "يجب أن يكون اسم المستخدم 3 أحرف على الأقل"
|
|
72
|
-
},
|
|
73
|
-
"email": {
|
|
74
|
-
"required": "يرجى إدخال عنوان بريد إلكتروني",
|
|
75
|
-
"invalid": "يرجى إدخال عنوان بريد إلكتروني صالح",
|
|
76
|
-
"helper": "لن نشارك بريدك الإلكتروني أبدًا"
|
|
77
|
-
},
|
|
78
|
-
"security": {
|
|
79
|
-
"title": "أمّن حسابك",
|
|
80
|
-
"subtitle": "أنشئ كلمة مرور قوية لحماية حسابك"
|
|
81
|
-
},
|
|
82
|
-
"password": {
|
|
83
|
-
"helper": "8 أحرف على الأقل",
|
|
84
|
-
"required": "يرجى إدخال كلمة مرور",
|
|
85
|
-
"minLength": "يجب أن تكون كلمة المرور 8 أحرف على الأقل",
|
|
86
|
-
"confirmRequired": "يرجى تأكيد كلمة المرور",
|
|
87
|
-
"mismatch": "كلمات المرور غير متطابقة",
|
|
88
|
-
"confirmHint": "أعد إدخال كلمة المرور للتأكيد"
|
|
89
|
-
},
|
|
90
|
-
"summary": {
|
|
91
|
-
"title": "أوشكت على الانتهاء!",
|
|
92
|
-
"subtitle": "راجع معلوماتك وأنشئ حسابك",
|
|
93
|
-
"sectionTitle": "معلومات الحساب",
|
|
94
|
-
"fields": {
|
|
95
|
-
"username": "اسم المستخدم",
|
|
96
|
-
"email": "البريد الإلكتروني",
|
|
97
|
-
"password": "كلمة المرور"
|
|
98
|
-
},
|
|
99
|
-
"notSet": "غير محدد",
|
|
100
|
-
"securityTip": "لمزيد من الأمان، قم بتمكين المصادقة الحيوية من إعدادات الحساب بعد إنشاء حسابك.",
|
|
101
|
-
"legalReminder": "بإنشاء حساب، فإنك توافق على شروط الخدمة وسياسة الخصوصية الخاصة بنا."
|
|
102
|
-
}
|
|
53
|
+
"webSubtitle": "بلا كلمة مرور. ينشئ جهازك مفتاح مرور، ويحصل حسابك على عبارة استرداد تحتفظ بها أنت وحدك."
|
|
103
54
|
},
|
|
104
55
|
"accountSwitcher": {
|
|
105
|
-
"sections": {
|
|
106
|
-
"yourAccounts": "حساباتك"
|
|
107
|
-
},
|
|
108
56
|
"loading": "جارٍ تحميل الحسابات...",
|
|
109
57
|
"qrHeadline": "سجّل الدخول بهوية Oxy الخاصة بك",
|
|
110
58
|
"signInWithOxy": "تسجيل الدخول باستخدام Oxy",
|
|
@@ -136,10 +84,7 @@
|
|
|
136
84
|
"claimFailed": "تمت الموافقة على تسجيل الدخول، لكن تعذّر إكماله. يُرجى المحاولة مرة أخرى.",
|
|
137
85
|
"generic": "تعذّر تسجيل الدخول. يُرجى المحاولة مرة أخرى."
|
|
138
86
|
},
|
|
139
|
-
"linkOpenFailed": "تعذّر فتح الرابط. يُرجى المحاولة مرة أخرى."
|
|
140
|
-
"continueWithPasskey": "متابعة",
|
|
141
|
-
"passkeyHint": "استخدم بصمتك أو وجهك أو رمز PIN للجهاز.",
|
|
142
|
-
"otherDeviceCommons": "حسابك على جهاز آخر؟ امسح الرمز باستخدام Commons"
|
|
87
|
+
"linkOpenFailed": "تعذّر فتح الرابط. يُرجى المحاولة مرة أخرى."
|
|
143
88
|
},
|
|
144
89
|
"common": {
|
|
145
90
|
"actions": {
|