@oxyhq/core 4.0.1 → 5.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/HttpService.js +6 -18
- package/dist/cjs/OxyServices.base.js +0 -21
- package/dist/cjs/crypto/keyManager.js +7 -7
- package/dist/cjs/crypto/polyfill.js +6 -5
- package/dist/cjs/crypto/signatureService.js +44 -220
- package/dist/cjs/index.js +4 -8
- package/dist/cjs/mixins/OxyServices.accounts.js +54 -0
- package/dist/cjs/mixins/OxyServices.assets.js +2 -2
- package/dist/cjs/mixins/OxyServices.auth.js +3 -3
- package/dist/cjs/mixins/OxyServices.civic.js +3 -3
- package/dist/cjs/mixins/OxyServices.language.js +2 -2
- package/dist/cjs/mixins/OxyServices.utility.js +7 -95
- package/dist/cjs/utils/cacheKey.js +17 -19
- package/dist/cjs/utils/deviceManager.js +2 -2
- package/dist/cjs/utils/platform.js +0 -14
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/HttpService.js +6 -18
- package/dist/esm/OxyServices.base.js +0 -21
- package/dist/esm/crypto/keyManager.js +4 -4
- package/dist/esm/crypto/polyfill.js +5 -4
- package/dist/esm/crypto/signatureService.js +39 -214
- package/dist/esm/index.js +1 -2
- package/dist/esm/mixins/OxyServices.accounts.js +54 -0
- package/dist/esm/mixins/OxyServices.assets.js +1 -1
- package/dist/esm/mixins/OxyServices.auth.js +1 -1
- package/dist/esm/mixins/OxyServices.civic.js +3 -3
- package/dist/esm/mixins/OxyServices.language.js +1 -1
- package/dist/esm/mixins/OxyServices.utility.js +6 -94
- package/dist/esm/utils/cacheKey.js +17 -19
- package/dist/esm/utils/deviceManager.js +1 -1
- package/dist/esm/utils/platform.js +0 -12
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/HttpService.d.ts +3 -6
- package/dist/types/OxyServices.base.d.ts +0 -17
- package/dist/types/crypto/polyfill.d.ts +2 -2
- package/dist/types/crypto/signatureService.d.ts +18 -84
- package/dist/types/index.d.ts +3 -4
- package/dist/types/mixins/OxyServices.accounts.d.ts +57 -5
- package/dist/types/mixins/OxyServices.analytics.d.ts +0 -2
- package/dist/types/mixins/OxyServices.appData.d.ts +0 -2
- package/dist/types/mixins/OxyServices.assets.d.ts +0 -2
- package/dist/types/mixins/OxyServices.auth.d.ts +0 -2
- package/dist/types/mixins/OxyServices.civic.d.ts +3 -5
- package/dist/types/mixins/OxyServices.connectedApps.d.ts +0 -2
- package/dist/types/mixins/OxyServices.contacts.d.ts +0 -2
- package/dist/types/mixins/OxyServices.devices.d.ts +0 -2
- package/dist/types/mixins/OxyServices.features.d.ts +0 -2
- package/dist/types/mixins/OxyServices.fedcm.d.ts +0 -2
- package/dist/types/mixins/OxyServices.identity.d.ts +8 -5
- package/dist/types/mixins/OxyServices.language.d.ts +0 -2
- package/dist/types/mixins/OxyServices.links.d.ts +0 -2
- package/dist/types/mixins/OxyServices.location.d.ts +0 -2
- package/dist/types/mixins/OxyServices.nodes.d.ts +0 -44
- package/dist/types/mixins/OxyServices.payment.d.ts +0 -2
- package/dist/types/mixins/OxyServices.privacy.d.ts +0 -2
- package/dist/types/mixins/OxyServices.redirect.d.ts +0 -2
- package/dist/types/mixins/OxyServices.reputation.d.ts +0 -2
- package/dist/types/mixins/OxyServices.security.d.ts +0 -2
- package/dist/types/mixins/OxyServices.silent.d.ts +0 -2
- package/dist/types/mixins/OxyServices.sso.d.ts +0 -2
- package/dist/types/mixins/OxyServices.topics.d.ts +0 -2
- package/dist/types/mixins/OxyServices.user.d.ts +0 -2
- package/dist/types/mixins/OxyServices.utility.d.ts +0 -32
- package/dist/types/server/auth.d.ts +0 -6
- package/dist/types/server/index.d.ts +1 -1
- package/dist/types/utils/cacheKey.d.ts +6 -7
- package/dist/types/utils/platform.d.ts +0 -8
- package/package.json +4 -7
- package/src/HttpService.ts +6 -22
- package/src/OxyServices.base.ts +0 -23
- package/src/__tests__/httpServiceCache.test.ts +0 -19
- package/src/crypto/__tests__/keyManager.atomicity.test.ts +2 -1
- package/src/crypto/__tests__/keyManager.test.ts +9 -7
- package/src/crypto/__tests__/signChallengeShared.test.ts +2 -1
- package/src/crypto/__tests__/signedRecord.test.ts +37 -150
- package/src/crypto/keyManager.ts +28 -17
- package/src/crypto/polyfill.ts +5 -4
- package/src/crypto/signatureService.ts +67 -255
- package/src/index.ts +3 -3
- package/src/mixins/OxyServices.accounts.ts +91 -3
- package/src/mixins/OxyServices.assets.ts +1 -1
- package/src/mixins/OxyServices.auth.ts +1 -1
- package/src/mixins/OxyServices.civic.ts +6 -17
- package/src/mixins/OxyServices.identity.ts +8 -2
- package/src/mixins/OxyServices.language.ts +1 -1
- package/src/mixins/OxyServices.nodes.ts +1 -12
- package/src/mixins/OxyServices.utility.ts +6 -119
- package/src/mixins/__tests__/OxyServices.civic.test.ts +2 -2
- package/src/mixins/__tests__/accounts.test.ts +70 -0
- package/src/server/auth.ts +0 -7
- package/src/server/index.ts +0 -1
- package/src/utils/__tests__/cacheKey.test.ts +0 -0
- package/src/utils/cacheKey.ts +16 -21
- package/src/utils/deviceManager.ts +1 -1
- package/src/utils/platform.ts +0 -14
- package/dist/cjs/crypto/canonicalJson.js +0 -107
- package/dist/cjs/utils/platformCrypto.js +0 -165
- package/dist/cjs/utils/platformCrypto.native.js +0 -123
- package/dist/esm/crypto/canonicalJson.js +0 -104
- package/dist/esm/utils/platformCrypto.js +0 -125
- package/dist/esm/utils/platformCrypto.native.js +0 -80
- package/dist/types/crypto/canonicalJson.d.ts +0 -44
- package/dist/types/utils/platformCrypto.d.ts +0 -87
- package/dist/types/utils/platformCrypto.native.d.ts +0 -54
- package/src/crypto/__tests__/canonicalJson.test.ts +0 -116
- package/src/crypto/canonicalJson.ts +0 -120
- package/src/utils/platformCrypto.native.ts +0 -101
- package/src/utils/platformCrypto.ts +0 -145
|
@@ -95,8 +95,6 @@ export declare function OxyServicesSsoMixin<T extends typeof OxyServicesBase>(Ba
|
|
|
95
95
|
hasValidToken(): boolean;
|
|
96
96
|
getAccessToken(): string | null;
|
|
97
97
|
getAccessTokenExpiry(): number | null;
|
|
98
|
-
setActingAs(userId: string | null): void;
|
|
99
|
-
getActingAs(): string | null;
|
|
100
98
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
101
99
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
102
100
|
maxRetries?: number;
|
|
@@ -93,8 +93,6 @@ export declare function OxyServicesTopicsMixin<T extends typeof OxyServicesBase>
|
|
|
93
93
|
hasValidToken(): boolean;
|
|
94
94
|
getAccessToken(): string | null;
|
|
95
95
|
getAccessTokenExpiry(): number | null;
|
|
96
|
-
setActingAs(userId: string | null): void;
|
|
97
|
-
getActingAs(): string | null;
|
|
98
96
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
99
97
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
100
98
|
maxRetries?: number;
|
|
@@ -364,8 +364,6 @@ export declare function OxyServicesUserMixin<T extends typeof OxyServicesBase>(B
|
|
|
364
364
|
hasValidToken(): boolean;
|
|
365
365
|
getAccessToken(): string | null;
|
|
366
366
|
getAccessTokenExpiry(): number | null;
|
|
367
|
-
setActingAs(userId: string | null): void;
|
|
368
|
-
getActingAs(): string | null;
|
|
369
367
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
370
368
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
371
369
|
maxRetries?: number;
|
|
@@ -1,15 +1,5 @@
|
|
|
1
1
|
import type { ApiError, User } from '../models/interfaces';
|
|
2
2
|
import type { OxyServicesBase } from '../OxyServices.base';
|
|
3
|
-
/**
|
|
4
|
-
* Result from the account acting-as verification endpoint
|
|
5
|
-
* (`GET /accounts/verify-acting-as`). Indicates whether a user is authorized to
|
|
6
|
-
* act as a given account. The `account:act_as` capability is granted only to the
|
|
7
|
-
* `owner`, `admin`, and `editor` account roles.
|
|
8
|
-
*/
|
|
9
|
-
interface ActingAsVerification {
|
|
10
|
-
authorized: boolean;
|
|
11
|
-
role: 'owner' | 'admin' | 'editor';
|
|
12
|
-
}
|
|
13
3
|
/**
|
|
14
4
|
* Result from the service-acting-as verification endpoint.
|
|
15
5
|
* Confirms that a given service app holds an active delegation grant for
|
|
@@ -76,11 +66,6 @@ interface AuthMiddlewareOptions {
|
|
|
76
66
|
}
|
|
77
67
|
export declare function OxyServicesUtilityMixin<T extends typeof OxyServicesBase>(Base: T): {
|
|
78
68
|
new (...args: any[]): {
|
|
79
|
-
/** @internal In-memory cache for acting-as verification results (TTL: 5 min) */
|
|
80
|
-
_actingAsCache: Map<string, {
|
|
81
|
-
result: ActingAsVerification | null;
|
|
82
|
-
expiresAt: number;
|
|
83
|
-
}>;
|
|
84
69
|
/**
|
|
85
70
|
* In-memory cache for service-acting-as verification.
|
|
86
71
|
* Negative results are cached for 1min to avoid hammering the verify
|
|
@@ -92,14 +77,6 @@ export declare function OxyServicesUtilityMixin<T extends typeof OxyServicesBase
|
|
|
92
77
|
result: ServiceActingAsVerification | null;
|
|
93
78
|
expiresAt: number;
|
|
94
79
|
}>;
|
|
95
|
-
/**
|
|
96
|
-
* Verify that a user is authorized to act as an account (direct membership
|
|
97
|
-
* or inherited via an ancestor). Backed by `GET /accounts/verify-acting-as`.
|
|
98
|
-
* Results are cached in-memory for 5 minutes to avoid repeated API calls.
|
|
99
|
-
*
|
|
100
|
-
* @internal Used by the auth() middleware — not part of the public API
|
|
101
|
-
*/
|
|
102
|
-
verifyActingAs(userId: string, accountId: string): Promise<ActingAsVerification | null>;
|
|
103
80
|
/**
|
|
104
81
|
* Verify that a service app holds an active delegation grant authorising
|
|
105
82
|
* it to act on behalf of `userId`. Returns the grant (with allowed scopes)
|
|
@@ -281,8 +258,6 @@ export declare function OxyServicesUtilityMixin<T extends typeof OxyServicesBase
|
|
|
281
258
|
hasValidToken(): boolean;
|
|
282
259
|
getAccessToken(): string | null;
|
|
283
260
|
getAccessTokenExpiry(): number | null;
|
|
284
|
-
setActingAs(userId: string | null): void;
|
|
285
|
-
getActingAs(): string | null;
|
|
286
261
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
287
262
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
288
263
|
maxRetries?: number;
|
|
@@ -313,13 +288,6 @@ interface AuthReq {
|
|
|
313
288
|
userId: string;
|
|
314
289
|
scopes: string[];
|
|
315
290
|
};
|
|
316
|
-
actingAs?: {
|
|
317
|
-
userId: string;
|
|
318
|
-
role: string;
|
|
319
|
-
};
|
|
320
|
-
originalUser?: {
|
|
321
|
-
id: string;
|
|
322
|
-
} & Partial<User>;
|
|
323
291
|
}
|
|
324
292
|
interface AuthRes {
|
|
325
293
|
status(code: number): AuthRes;
|
|
@@ -8,10 +8,6 @@ export interface OxyRequestUser {
|
|
|
8
8
|
avatar?: string;
|
|
9
9
|
[key: string]: unknown;
|
|
10
10
|
}
|
|
11
|
-
export interface OxyActingAsContext {
|
|
12
|
-
userId: string;
|
|
13
|
-
role: 'owner' | 'admin' | 'editor';
|
|
14
|
-
}
|
|
15
11
|
export interface OxyServiceAppContext {
|
|
16
12
|
appId: string;
|
|
17
13
|
appName: string;
|
|
@@ -25,8 +21,6 @@ export interface OxyServiceActingAsContext {
|
|
|
25
21
|
export interface OxyAuthRequest extends Request {
|
|
26
22
|
userId?: string | null;
|
|
27
23
|
user?: OxyRequestUser | null;
|
|
28
|
-
originalUser?: OxyRequestUser | null;
|
|
29
|
-
actingAs?: OxyActingAsContext;
|
|
30
24
|
accessToken?: string;
|
|
31
25
|
sessionId?: string | null;
|
|
32
26
|
serviceApp?: OxyServiceAppContext;
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
17
|
export { createOptionalOxyAuth, createOxyAuthMiddleware, getOxyUserId, getRequiredOxyUserId, isOxyAuthenticated, requireOxyAuth, } from './auth';
|
|
18
|
-
export type {
|
|
18
|
+
export type { OxyAuthenticatedRequest, OxyAuthMiddlewareOptions, OxyAuthRequest, OxyRequestUser, OxyServiceActingAsContext, OxyServiceAppContext, } from './auth';
|
|
19
19
|
export { createOxyRateLimit } from './rateLimit';
|
|
20
20
|
export type { OxyRateLimitOptions } from './rateLimit';
|
|
21
21
|
export { assertSafePublicUrl, isBlockedIp, safeFetch, SsrfRejection, UpstreamError, ALLOWED_PORTS, ALLOWED_PROTOCOLS, BLOCKED_HOSTNAMES, DEFAULT_USER_AGENT, MAX_REDIRECTS, MAX_URL_LENGTH, UPSTREAM_HEADERS_TIMEOUT_MS, } from './safeFetch';
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Extracted from {@link HttpService} so the identity-tag derivation is a pure,
|
|
5
5
|
* independently testable function with no dependency on instance/token state.
|
|
6
|
-
* The HTTP service injects the live access token
|
|
7
|
-
*
|
|
6
|
+
* The HTTP service injects the live access token; everything here is
|
|
7
|
+
* referentially transparent given that input.
|
|
8
8
|
*/
|
|
9
9
|
/**
|
|
10
10
|
* Minimal JWT payload shape we read for cache scoping. The identity discriminator
|
|
@@ -57,11 +57,10 @@ export declare function fnv1a32(str: string): string;
|
|
|
57
57
|
*
|
|
58
58
|
* We use the decoded user id rather than the raw JWT so the token never lands
|
|
59
59
|
* in a cache key (no token leakage through any cache-key logging, no key bloat).
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
60
|
+
* Switching into a managed account mints a REAL new session whose access token
|
|
61
|
+
* carries the target account's id, so the identity tag changes naturally on a
|
|
62
|
+
* switch — there is no separate acting-as discriminator to fold in.
|
|
63
63
|
*
|
|
64
64
|
* @param accessToken The current bearer access token, or `null` when anonymous.
|
|
65
|
-
* @param actingAsUserId The active managed-account id, or `null`.
|
|
66
65
|
*/
|
|
67
|
-
export declare function computeIdentityTag(accessToken: string | null
|
|
66
|
+
export declare function computeIdentityTag(accessToken: string | null): string;
|
|
@@ -27,14 +27,6 @@ export declare function isIOS(): boolean;
|
|
|
27
27
|
* Check if running on Android
|
|
28
28
|
*/
|
|
29
29
|
export declare function isAndroid(): boolean;
|
|
30
|
-
/**
|
|
31
|
-
* Check if running in React Native
|
|
32
|
-
*/
|
|
33
|
-
export declare function isReactNative(): boolean;
|
|
34
|
-
/**
|
|
35
|
-
* Check if running in Node.js
|
|
36
|
-
*/
|
|
37
|
-
export declare function isNodeJS(): boolean;
|
|
38
30
|
/**
|
|
39
31
|
* Set the platform OS explicitly
|
|
40
32
|
* Called by React Native entry point to register the platform
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxyhq/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.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",
|
|
@@ -43,10 +43,6 @@
|
|
|
43
43
|
},
|
|
44
44
|
"./package.json": "./package.json"
|
|
45
45
|
},
|
|
46
|
-
"react-native": {
|
|
47
|
-
"./dist/esm/utils/platformCrypto.js": "./dist/esm/utils/platformCrypto.native.js",
|
|
48
|
-
"./dist/cjs/utils/platformCrypto.js": "./dist/cjs/utils/platformCrypto.native.js"
|
|
49
|
-
},
|
|
50
46
|
"files": [
|
|
51
47
|
"dist",
|
|
52
48
|
"src"
|
|
@@ -98,14 +94,15 @@
|
|
|
98
94
|
}
|
|
99
95
|
},
|
|
100
96
|
"dependencies": {
|
|
101
|
-
"@oxyhq/contracts": "^0.
|
|
97
|
+
"@oxyhq/contracts": "^0.7.0",
|
|
98
|
+
"@oxyhq/protocol": "^0.1.0",
|
|
102
99
|
"bip39": "^3.1.0",
|
|
103
100
|
"buffer": "^6.0.3",
|
|
104
101
|
"elliptic": "^6.6.1",
|
|
105
102
|
"invariant": "^2.2.4",
|
|
106
103
|
"jwt-decode": "^4.0.0",
|
|
107
104
|
"socket.io-client": "^4.8.1",
|
|
108
|
-
"tldts": "^7.
|
|
105
|
+
"tldts": "^7.4.5",
|
|
109
106
|
"zod": "^3.25.64"
|
|
110
107
|
},
|
|
111
108
|
"peerDependencies": {
|
package/src/HttpService.ts
CHANGED
|
@@ -18,7 +18,8 @@ import { RequestDeduplicator, RequestQueue, SimpleLogger } from './utils/request
|
|
|
18
18
|
import { retryAsync } from './utils/asyncUtils';
|
|
19
19
|
import { handleHttpError } from './utils/errorUtils';
|
|
20
20
|
import { jwtDecode } from 'jwt-decode';
|
|
21
|
-
import { isNative,
|
|
21
|
+
import { isNative, getPlatformOS } from './utils/platform';
|
|
22
|
+
import { isReactNative } from '@oxyhq/protocol';
|
|
22
23
|
import { computeIdentityTag, fnv1a32 } from './utils/cacheKey';
|
|
23
24
|
import type { OxyConfig } from './models/interfaces';
|
|
24
25
|
|
|
@@ -238,9 +239,6 @@ export class HttpService {
|
|
|
238
239
|
*/
|
|
239
240
|
private _tokenChangeListeners = new Set<(accessToken: string | null) => void>();
|
|
240
241
|
|
|
241
|
-
// Acting-as identity for managed accounts
|
|
242
|
-
private _actingAsUserId: string | null = null;
|
|
243
|
-
|
|
244
242
|
// Performance monitoring
|
|
245
243
|
private requestMetrics = {
|
|
246
244
|
totalRequests: 0,
|
|
@@ -466,11 +464,6 @@ export class HttpService {
|
|
|
466
464
|
});
|
|
467
465
|
}
|
|
468
466
|
|
|
469
|
-
// Add X-Acting-As header for managed account identity delegation
|
|
470
|
-
if (this._actingAsUserId) {
|
|
471
|
-
headers['X-Acting-As'] = this._actingAsUserId;
|
|
472
|
-
}
|
|
473
|
-
|
|
474
467
|
// Merge custom headers if provided
|
|
475
468
|
if (config.headers) {
|
|
476
469
|
Object.entries(config.headers).forEach(([key, value]) => {
|
|
@@ -820,12 +813,12 @@ export class HttpService {
|
|
|
820
813
|
* Derive a stable, non-sensitive identity discriminator for cache scoping.
|
|
821
814
|
*
|
|
822
815
|
* Thin instance wrapper over the pure {@link computeIdentityTag} helper —
|
|
823
|
-
* binds it to this instance's live access token
|
|
824
|
-
*
|
|
825
|
-
*
|
|
816
|
+
* binds it to this instance's live access token. See that function's docs for
|
|
817
|
+
* the full resolution contract (anon fallback, decoded `userId || id`,
|
|
818
|
+
* token-hash fallback for undecodable tokens).
|
|
826
819
|
*/
|
|
827
820
|
private computeIdentityTag(): string {
|
|
828
|
-
return computeIdentityTag(this.tokenStore.getAccessToken()
|
|
821
|
+
return computeIdentityTag(this.tokenStore.getAccessToken());
|
|
829
822
|
}
|
|
830
823
|
|
|
831
824
|
/**
|
|
@@ -1107,15 +1100,6 @@ export class HttpService {
|
|
|
1107
1100
|
return this.request<T>({ method: 'DELETE', url, ...config });
|
|
1108
1101
|
}
|
|
1109
1102
|
|
|
1110
|
-
// Acting-as identity management (managed accounts)
|
|
1111
|
-
setActingAs(userId: string | null): void {
|
|
1112
|
-
this._actingAsUserId = userId;
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
getActingAs(): string | null {
|
|
1116
|
-
return this._actingAsUserId;
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
1103
|
// Token management
|
|
1120
1104
|
setTokens(accessToken: string): void {
|
|
1121
1105
|
this.tokenStore.setTokens(accessToken);
|
package/src/OxyServices.base.ts
CHANGED
|
@@ -335,29 +335,6 @@ export class OxyServicesBase {
|
|
|
335
335
|
}
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
-
/**
|
|
339
|
-
* Set the acting-as identity for managed accounts.
|
|
340
|
-
*
|
|
341
|
-
* When set, all subsequent API requests will include the `X-Acting-As` header,
|
|
342
|
-
* causing the server to attribute actions to the managed account. The
|
|
343
|
-
* authenticated user must be an authorized manager of the target account.
|
|
344
|
-
*
|
|
345
|
-
* Pass `null` to clear and revert to the authenticated user's own identity.
|
|
346
|
-
*
|
|
347
|
-
* @param userId - The managed account user ID, or null to clear
|
|
348
|
-
*/
|
|
349
|
-
public setActingAs(userId: string | null): void {
|
|
350
|
-
this.httpService.setActingAs(userId);
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Get the current acting-as identity (managed account user ID), or null
|
|
355
|
-
* if operating as the authenticated user's own identity.
|
|
356
|
-
*/
|
|
357
|
-
public getActingAs(): string | null {
|
|
358
|
-
return this.httpService.getActingAs();
|
|
359
|
-
}
|
|
360
|
-
|
|
361
338
|
/**
|
|
362
339
|
* Wait for authentication to be ready
|
|
363
340
|
*
|
|
@@ -112,25 +112,6 @@ describe('HttpService identity-scoped response cache', () => {
|
|
|
112
112
|
expect(u2.profiles).toEqual(['for-user-2']);
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
-
it('partitions the cache by acting-as identity for the same bearer token', async () => {
|
|
116
|
-
const http = newService();
|
|
117
|
-
http.setTokens(makeJwt({ userId: 'owner-1' }));
|
|
118
|
-
|
|
119
|
-
// Acting as managed account A.
|
|
120
|
-
http.setActingAs('managed-a');
|
|
121
|
-
fetchMock.mockResolvedValueOnce(jsonResponse({ items: ['a-only'] }));
|
|
122
|
-
const a = await http.get<{ items: string[] }>('/some/managed-resource', { cache: true });
|
|
123
|
-
expect(a.items).toEqual(['a-only']);
|
|
124
|
-
|
|
125
|
-
// Acting as managed account B — different content, must miss the cache.
|
|
126
|
-
http.setActingAs('managed-b');
|
|
127
|
-
fetchMock.mockResolvedValueOnce(jsonResponse({ items: ['b-only'] }));
|
|
128
|
-
const b = await http.get<{ items: string[] }>('/some/managed-resource', { cache: true });
|
|
129
|
-
|
|
130
|
-
expect(fetchMock).toHaveBeenCalledTimes(2);
|
|
131
|
-
expect(b.items).toEqual(['b-only']);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
115
|
it('does NOT serve an authenticated cached response to an anonymous caller after clearTokens()', async () => {
|
|
135
116
|
const http = newService();
|
|
136
117
|
http.setTokens(makeJwt({ userId: 'user-1' }));
|
|
@@ -83,8 +83,9 @@ jest.mock(
|
|
|
83
83
|
{ virtual: true },
|
|
84
84
|
);
|
|
85
85
|
|
|
86
|
-
jest.mock('
|
|
86
|
+
jest.mock('@oxyhq/protocol', () => ({
|
|
87
87
|
__esModule: true,
|
|
88
|
+
...jest.requireActual('@oxyhq/protocol'),
|
|
88
89
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
89
90
|
loadExpoCrypto: async () => require('expo-crypto'),
|
|
90
91
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
@@ -66,14 +66,16 @@ jest.mock(
|
|
|
66
66
|
);
|
|
67
67
|
|
|
68
68
|
// Production code routes platform-specific module loads through
|
|
69
|
-
// `
|
|
70
|
-
// (`
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
|
|
69
|
+
// `@oxyhq/protocol`'s `platform/crypto`, which ships in two physical variants
|
|
70
|
+
// on disk (`crypto.ts` / `crypto.native.ts`) selected by the consumer's
|
|
71
|
+
// bundler. Jest runs on Node — it picks the default variant, which references
|
|
72
|
+
// Node's built-in `crypto`, not `expo-*`. For the test suite to exercise the
|
|
73
|
+
// RN code paths, we override only the platform loaders to delegate to the
|
|
74
|
+
// virtual `expo-*` modules registered above, keeping every other protocol
|
|
75
|
+
// export (canonical bytes, signing, the platform predicates) real.
|
|
76
|
+
jest.mock('@oxyhq/protocol', () => ({
|
|
76
77
|
__esModule: true,
|
|
78
|
+
...jest.requireActual('@oxyhq/protocol'),
|
|
77
79
|
loadExpoCrypto: async () => {
|
|
78
80
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
79
81
|
return require('expo-crypto');
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { ec as EC } from 'elliptic';
|
|
12
|
+
import { verifySignature } from '@oxyhq/protocol';
|
|
12
13
|
import { KeyManager } from '../keyManager';
|
|
13
14
|
import { SignatureService } from '../signatureService';
|
|
14
15
|
|
|
@@ -40,7 +41,7 @@ describe('SignatureService.signChallengeWithSharedKey', () => {
|
|
|
40
41
|
// uses, proving the format is unchanged and the shared key signed it.
|
|
41
42
|
const message = `auth:${sharedPublicKey}:chal-123:${result.timestamp}`;
|
|
42
43
|
await expect(
|
|
43
|
-
|
|
44
|
+
verifySignature(message, result.challenge, sharedPublicKey),
|
|
44
45
|
).resolves.toBe(true);
|
|
45
46
|
});
|
|
46
47
|
|