@oxyhq/core 12.11.1 → 13.0.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/index.js +2 -12
- package/dist/cjs/mixins/OxyServices.deviceBoot.js +0 -31
- package/dist/cjs/server/index.js +1 -6
- package/dist/cjs/server/rateLimit.js +3 -0
- package/dist/cjs/session/accountDialogController.js +6 -8
- package/dist/cjs/utils/oauthPkce.js +1 -5
- package/dist/cjs/utils/officialOrigins.js +3 -73
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/index.js +2 -3
- package/dist/esm/mixins/OxyServices.deviceBoot.js +1 -32
- package/dist/esm/server/index.js +1 -1
- package/dist/esm/server/rateLimit.js +3 -0
- package/dist/esm/session/accountDialogController.js +6 -8
- package/dist/esm/utils/oauthPkce.js +0 -4
- package/dist/esm/utils/officialOrigins.js +3 -68
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/index.d.ts +3 -5
- package/dist/types/mixins/OxyServices.auth.d.ts +1 -12
- package/dist/types/mixins/OxyServices.deviceBoot.d.ts +1 -5
- package/dist/types/server/index.d.ts +1 -1
- package/dist/types/session/accountDialogController.d.ts +9 -15
- package/dist/types/utils/oauthPkce.d.ts +11 -7
- package/dist/types/utils/officialOrigins.d.ts +3 -13
- package/package.json +3 -3
- package/src/index.ts +6 -14
- package/src/mixins/OxyServices.auth.ts +6 -13
- package/src/mixins/OxyServices.deviceBoot.ts +0 -47
- package/src/mixins/__tests__/commonsSignIn.test.ts +9 -2
- package/src/server/index.ts +1 -8
- package/src/server/rateLimit.ts +3 -0
- package/src/session/__tests__/accountDialogController.test.ts +3 -5
- package/src/session/accountDialogController.ts +12 -18
- package/src/utils/__tests__/officialOrigins.test.ts +0 -57
- package/src/utils/oauthPkce.ts +11 -9
- package/src/utils/officialOrigins.ts +3 -70
- package/dist/cjs/session/hubSync.js +0 -55
- package/dist/esm/session/hubSync.js +0 -51
- package/dist/types/session/hubSync.d.ts +0 -20
- package/src/session/__tests__/hubSync.test.ts +0 -51
- package/src/session/hubSync.ts +0 -79
package/dist/esm/index.js
CHANGED
|
@@ -148,9 +148,8 @@ export { runColdBoot } from './utils/coldBoot.js';
|
|
|
148
148
|
// OAuth 2.0 Authorization Code + PKCE helpers ("Sign in with Oxy" third party).
|
|
149
149
|
// Standard OAuth against auth.oxy.so/authorize — no FedCM/cookies/SSO bounce.
|
|
150
150
|
// ---------------------------------------------------------------------------
|
|
151
|
-
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,
|
|
152
|
-
export {
|
|
153
|
-
export { syncHubAfterSignIn, redeemHubTicketOnHub, } from './session/hubSync.js';
|
|
151
|
+
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.js';
|
|
152
|
+
export { isLoopbackOrigin, isOfficialWebOrigin, isAllowedDeviceJoinOrigin, } from './utils/officialOrigins.js';
|
|
154
153
|
// ---------------------------------------------------------------------------
|
|
155
154
|
// Session sync (device-scoped multi-account session client)
|
|
156
155
|
// ---------------------------------------------------------------------------
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* the cold boot / re-mint handler own persistence and `setTokens`, so the same
|
|
14
14
|
* primitive can be reused from either without double-planting.
|
|
15
15
|
*/
|
|
16
|
-
import { deviceTokenMintResponseSchema,
|
|
16
|
+
import { deviceTokenMintResponseSchema, safeParseContract, } from '@oxyhq/contracts';
|
|
17
17
|
/**
|
|
18
18
|
* The server's `401 account_not_on_device` for a PINNED mint: the requested
|
|
19
19
|
* `accountId` is not (or is no longer) a live account of this device session.
|
|
@@ -105,36 +105,5 @@ export function OxyServicesDeviceBootMixin(Base) {
|
|
|
105
105
|
throw normalized;
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
-
/** Mint a one-time hub sync ticket (bearer required). */
|
|
109
|
-
async issueHubTicket(returnOrigin) {
|
|
110
|
-
try {
|
|
111
|
-
const res = await this.makeRequest('POST', '/session/device/hub-ticket', { returnOrigin }, { cache: false });
|
|
112
|
-
const parsed = safeParseContract(deviceHubTicketIssueResponseSchema, res);
|
|
113
|
-
if (!parsed) {
|
|
114
|
-
throw new Error('session/device/hub-ticket returned an unexpected response shape');
|
|
115
|
-
}
|
|
116
|
-
return parsed;
|
|
117
|
-
}
|
|
118
|
-
catch (error) {
|
|
119
|
-
throw this.handleError(error);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
/** Redeem a hub sync ticket for a fresh device secret (public). */
|
|
123
|
-
async redeemHubTicket(ticket, returnOrigin) {
|
|
124
|
-
try {
|
|
125
|
-
const res = await this.makeRequest('POST', '/session/device/redeem-ticket', { ticket, returnOrigin },
|
|
126
|
-
// Public device-hub sync mint (bearer-less). Same control-plane class as
|
|
127
|
-
// the device-secret mint — bypassQueue so it never waits for a slot.
|
|
128
|
-
{ cache: false, skipAuth: true, bypassQueue: true });
|
|
129
|
-
const parsed = safeParseContract(deviceHubTicketRedeemResponseSchema, res);
|
|
130
|
-
if (!parsed) {
|
|
131
|
-
throw new Error('session/device/redeem-ticket returned an unexpected response shape');
|
|
132
|
-
}
|
|
133
|
-
return parsed;
|
|
134
|
-
}
|
|
135
|
-
catch (error) {
|
|
136
|
-
throw this.handleError(error);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
108
|
};
|
|
140
109
|
}
|
package/dist/esm/server/index.js
CHANGED
|
@@ -27,4 +27,4 @@ export { verifySecret } from './verifySecret.js';
|
|
|
27
27
|
// Pure host handling (no browser deps), so it is safe on the server subpath and
|
|
28
28
|
// lets `@oxyhq/api` derive `auth.<apex>` without duplicating PSL logic.
|
|
29
29
|
export { registrableApex } from '../utils/registrableApex.js';
|
|
30
|
-
export {
|
|
30
|
+
export { isOfficialWebOrigin } from '../utils/officialOrigins.js';
|
|
@@ -168,6 +168,9 @@ export function createOxyRateLimit(oxy, options = {}) {
|
|
|
168
168
|
standardHeaders: true,
|
|
169
169
|
legacyHeaders: false,
|
|
170
170
|
skip,
|
|
171
|
+
// hashAnonymousIp already buckets IPv6 to /56 before HMAC; disable the v8
|
|
172
|
+
// static source scan that false-positives on req.ip (ERR_ERL_KEY_GEN_IPV6).
|
|
173
|
+
validate: { keyGeneratorIpFallback: false },
|
|
171
174
|
});
|
|
172
175
|
return (req, res, next) => {
|
|
173
176
|
// Skipped paths bypass BOTH session resolution and limiting — cheap and
|
|
@@ -477,9 +477,9 @@ export class AccountDialogController {
|
|
|
477
477
|
user: result.user,
|
|
478
478
|
accessToken: result.accessToken,
|
|
479
479
|
}, result.user,
|
|
480
|
-
// A switch is IN-PLACE:
|
|
481
|
-
//
|
|
482
|
-
//
|
|
480
|
+
// A switch is IN-PLACE: use the switch commit funnel (not sign-in).
|
|
481
|
+
// Cross-tab/app propagation rides the server's `session_state` socket
|
|
482
|
+
// broadcast, not a navigation.
|
|
483
483
|
{ fromSwitch: true });
|
|
484
484
|
}
|
|
485
485
|
// Re-project + refetch immediately; the subscription also fires.
|
|
@@ -982,11 +982,9 @@ export class AccountDialogController {
|
|
|
982
982
|
* consumer's commit funnel (durable persist + hydration); falls back to
|
|
983
983
|
* `SessionClient.registerAndActivate` (registration + activation only).
|
|
984
984
|
*
|
|
985
|
-
* A SWITCH (`opts.fromSwitch`) uses the IN-PLACE `commitSwitchedSession` funnel
|
|
986
|
-
*
|
|
987
|
-
*
|
|
988
|
-
* switch funnel is not wired it falls back to the sign-in funnel, then to
|
|
989
|
-
* `registerAndActivate`.
|
|
985
|
+
* A SWITCH (`opts.fromSwitch`) uses the IN-PLACE `commitSwitchedSession` funnel;
|
|
986
|
+
* a SIGN-IN uses `commitSession`. When the switch funnel is not wired it falls
|
|
987
|
+
* back to the sign-in funnel, then to `registerAndActivate`.
|
|
990
988
|
*/
|
|
991
989
|
async commitAuthorizedSession(session, user, opts) {
|
|
992
990
|
const commit = opts?.fromSwitch
|
|
@@ -145,10 +145,6 @@ export const OXY_OAUTH_STATE_STORAGE_KEY = 'oxy_oauth_state';
|
|
|
145
145
|
export const OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY = 'oxy_oauth_code_verifier';
|
|
146
146
|
/** `sessionStorage` key — the exact `redirect_uri` sent on the authorize request. */
|
|
147
147
|
export const OXY_OAUTH_REDIRECT_URI_STORAGE_KEY = 'oxy.oauth_redirect_uri';
|
|
148
|
-
/** `sessionStorage` key — at most one silent OAuth attempt per navigation. */
|
|
149
|
-
export const OXY_SILENT_OAUTH_ATTEMPTED_KEY = 'oxy.silent_oauth_attempted';
|
|
150
|
-
/** `sessionStorage` key — blocks further cross-origin auto-restore in this tab. */
|
|
151
|
-
export const OXY_CROSS_ORIGIN_RESTORE_ATTEMPTED_KEY = 'oxy.cross_origin_restore_attempted';
|
|
152
148
|
/**
|
|
153
149
|
* `sessionStorage` key for the in-app path to return to after an authorize
|
|
154
150
|
* round trip. See {@link persistOAuthReturnPath}.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Official first-party web origin allowlist — shared by
|
|
3
|
-
*
|
|
2
|
+
* Official first-party web origin allowlist — shared by OAuth redirect
|
|
3
|
+
* validation and the server-side trusted-origin checks.
|
|
4
4
|
*/
|
|
5
5
|
import { CENTRAL_IDP_APEX } from './authWebUrl.js';
|
|
6
6
|
import { registrableApex } from './registrableApex.js';
|
|
@@ -17,30 +17,9 @@ const OFFICIAL_APEXES = new Set([
|
|
|
17
17
|
'moovo.now',
|
|
18
18
|
'mercaria.co',
|
|
19
19
|
]);
|
|
20
|
-
export function buildIdpHubOrigin() {
|
|
21
|
-
return `https://auth.${CENTRAL_IDP_APEX}`;
|
|
22
|
-
}
|
|
23
|
-
/** Whether the current web origin is the central IdP hub (`auth.oxy.so`). */
|
|
24
|
-
export function isIdpHubOrigin() {
|
|
25
|
-
if (typeof globalThis === 'undefined') {
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
const location = globalThis.location;
|
|
29
|
-
if (!location) {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
try {
|
|
33
|
-
const { hostname } = new URL(location.href);
|
|
34
|
-
return hostname === `auth.${CENTRAL_IDP_APEX}`;
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
20
|
/**
|
|
41
21
|
* Whether an origin is a loopback / local-dev origin (`localhost`, `127.0.0.1`,
|
|
42
|
-
* or `[::1]` on any port, http or https).
|
|
43
|
-
* hosted IdP for cross-origin session restore.
|
|
22
|
+
* or `[::1]` on any port, http or https).
|
|
44
23
|
*/
|
|
45
24
|
export function isLoopbackOrigin(origin) {
|
|
46
25
|
try {
|
|
@@ -76,49 +55,5 @@ export function isOfficialWebOrigin(origin) {
|
|
|
76
55
|
return false;
|
|
77
56
|
}
|
|
78
57
|
}
|
|
79
|
-
/** Normalize and validate a return URL against official origins. Returns origin only. */
|
|
80
|
-
export function normalizeOfficialReturnOrigin(raw) {
|
|
81
|
-
try {
|
|
82
|
-
const parsed = new URL(raw);
|
|
83
|
-
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
if (!isOfficialWebOrigin(parsed.origin)) {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
return parsed.origin;
|
|
90
|
-
}
|
|
91
|
-
catch {
|
|
92
|
-
return null;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
/** Validate a hub-sync return URL; returns the full normalized URL string. */
|
|
96
|
-
export function parseHubSyncReturnUrl(raw) {
|
|
97
|
-
if (!raw) {
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
try {
|
|
101
|
-
const parsed = new URL(raw);
|
|
102
|
-
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
if (!isOfficialWebOrigin(parsed.origin)) {
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
return parsed.toString();
|
|
109
|
-
}
|
|
110
|
-
catch {
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
/** Build auth.oxy.so/sync redirect URL with a one-time hub ticket. */
|
|
115
|
-
export function buildHubSyncUrl(ticket, returnUrl) {
|
|
116
|
-
const url = new URL('/sync', buildIdpHubOrigin());
|
|
117
|
-
url.searchParams.set('ticket', ticket);
|
|
118
|
-
if (returnUrl) {
|
|
119
|
-
url.searchParams.set('return', returnUrl);
|
|
120
|
-
}
|
|
121
|
-
return url.toString();
|
|
122
|
-
}
|
|
123
58
|
/** @deprecated Use {@link isOfficialWebOrigin}. */
|
|
124
59
|
export const isAllowedDeviceJoinOrigin = isOfficialWebOrigin;
|