@oxyhq/services 5.16.32 → 5.16.34
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 +26 -8
- package/lib/commonjs/core/OxyServices.base.js.map +1 -1
- package/lib/commonjs/core/mixins/OxyServices.user.js.map +1 -1
- package/lib/commonjs/core/mixins/OxyServices.utility.js.map +1 -1
- package/lib/commonjs/core/services/AuthService.js +156 -0
- package/lib/commonjs/core/services/AuthService.js.map +1 -0
- package/lib/commonjs/core/services/SessionService.js +1 -2
- package/lib/commonjs/core/services/SessionService.js.map +1 -1
- package/lib/commonjs/core/services/SessionTransportService.js +64 -0
- package/lib/commonjs/core/services/SessionTransportService.js.map +1 -0
- package/lib/commonjs/core/services/TokenService.js +9 -17
- package/lib/commonjs/core/services/TokenService.js.map +1 -1
- package/lib/commonjs/core/services/UserService.js +123 -0
- package/lib/commonjs/core/services/UserService.js.map +1 -0
- package/lib/commonjs/core/services/index.js +34 -0
- package/lib/commonjs/core/services/index.js.map +1 -0
- package/lib/commonjs/crypto/index.js.map +1 -1
- package/lib/commonjs/crypto/keyManager.js +5 -2
- package/lib/commonjs/crypto/keyManager.js.map +1 -1
- package/lib/commonjs/crypto/signatureService.js +36 -121
- package/lib/commonjs/crypto/signatureService.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/models/interfaces.js +11 -11
- package/lib/commonjs/models/interfaces.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +4 -40
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +14 -25
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/commonjs/ui/context/hooks/useLanguageManagement.js.map +1 -1
- package/lib/commonjs/ui/hooks/queries/useServicesQueries.js +4 -12
- package/lib/commonjs/ui/hooks/queries/useServicesQueries.js.map +1 -1
- package/lib/commonjs/ui/hooks/useLanguageManagement.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSessionManagement.js +0 -8
- package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
- package/lib/commonjs/ui/index.js +2 -0
- package/lib/commonjs/ui/index.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/OxyAuthScreen.js +9 -13
- package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +1 -1
- package/lib/commonjs/ui/utils/sessionHelpers.js +11 -26
- package/lib/commonjs/ui/utils/sessionHelpers.js.map +1 -1
- package/lib/commonjs/utils/sessionUtils.js +1 -8
- package/lib/commonjs/utils/sessionUtils.js.map +1 -1
- package/lib/module/core/OxyServices.base.js.map +1 -1
- package/lib/module/core/mixins/OxyServices.user.js.map +1 -1
- package/lib/module/core/mixins/OxyServices.utility.js.map +1 -1
- package/lib/module/core/services/AuthService.js +151 -0
- package/lib/module/core/services/AuthService.js.map +1 -0
- package/lib/module/core/services/SessionService.js +1 -2
- package/lib/module/core/services/SessionService.js.map +1 -1
- package/lib/module/core/services/SessionTransportService.js +59 -0
- package/lib/module/core/services/SessionTransportService.js.map +1 -0
- package/lib/module/core/services/TokenService.js +9 -17
- package/lib/module/core/services/TokenService.js.map +1 -1
- package/lib/module/core/services/UserService.js +118 -0
- package/lib/module/core/services/UserService.js.map +1 -0
- package/lib/module/core/services/index.js +16 -0
- package/lib/module/core/services/index.js.map +1 -0
- package/lib/module/crypto/index.js +9 -0
- package/lib/module/crypto/index.js.map +1 -1
- package/lib/module/crypto/keyManager.js +5 -2
- package/lib/module/crypto/keyManager.js.map +1 -1
- package/lib/module/crypto/signatureService.js +36 -122
- package/lib/module/crypto/signatureService.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/models/interfaces.js +11 -11
- package/lib/module/models/interfaces.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +4 -40
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/hooks/useAuthOperations.js +14 -25
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/module/ui/context/hooks/useLanguageManagement.js.map +1 -1
- package/lib/module/ui/hooks/queries/useServicesQueries.js +5 -13
- package/lib/module/ui/hooks/queries/useServicesQueries.js.map +1 -1
- package/lib/module/ui/hooks/useLanguageManagement.js.map +1 -1
- package/lib/module/ui/hooks/useSessionManagement.js +0 -8
- package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
- package/lib/module/ui/index.js +1 -0
- package/lib/module/ui/index.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/OxyAuthScreen.js +7 -9
- package/lib/module/ui/screens/OxyAuthScreen.js.map +1 -1
- package/lib/module/ui/utils/sessionHelpers.js +11 -26
- package/lib/module/ui/utils/sessionHelpers.js.map +1 -1
- package/lib/module/utils/sessionUtils.js +1 -8
- package/lib/module/utils/sessionUtils.js.map +1 -1
- package/lib/typescript/core/OxyServices.base.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.analytics.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.assets.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.auth.d.ts +1 -1
- package/lib/typescript/core/mixins/OxyServices.auth.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.developer.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.devices.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.karma.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.language.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.location.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.payment.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.privacy.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.security.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.user.d.ts +2 -1
- package/lib/typescript/core/mixins/OxyServices.user.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.utility.d.ts.map +1 -1
- package/lib/typescript/core/mixins/index.d.ts +13 -13
- package/lib/typescript/core/mixins/index.d.ts.map +1 -1
- package/lib/typescript/core/services/AuthService.d.ts +50 -0
- package/lib/typescript/core/services/AuthService.d.ts.map +1 -0
- package/lib/typescript/core/services/SessionService.d.ts +3 -5
- package/lib/typescript/core/services/SessionService.d.ts.map +1 -1
- package/lib/typescript/core/services/SessionTransportService.d.ts +31 -0
- package/lib/typescript/core/services/SessionTransportService.d.ts.map +1 -0
- package/lib/typescript/core/services/TokenService.d.ts +3 -8
- package/lib/typescript/core/services/TokenService.d.ts.map +1 -1
- package/lib/typescript/core/services/UserService.d.ts +39 -0
- package/lib/typescript/core/services/UserService.d.ts.map +1 -0
- package/lib/typescript/core/services/index.d.ts +13 -0
- package/lib/typescript/core/services/index.d.ts.map +1 -0
- package/lib/typescript/crypto/index.d.ts +9 -0
- package/lib/typescript/crypto/index.d.ts.map +1 -1
- package/lib/typescript/crypto/keyManager.d.ts.map +1 -1
- package/lib/typescript/crypto/signatureService.d.ts +10 -13
- package/lib/typescript/crypto/signatureService.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +1 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/models/interfaces.d.ts +15 -69
- package/lib/typescript/models/interfaces.d.ts.map +1 -1
- package/lib/typescript/models/session.d.ts +2 -4
- package/lib/typescript/models/session.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts +2 -1
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts +2 -1
- package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/ui/context/hooks/useLanguageManagement.d.ts +2 -1
- package/lib/typescript/ui/context/hooks/useLanguageManagement.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts +1 -1
- package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts +1 -1
- package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useLanguageManagement.d.ts +2 -1
- package/lib/typescript/ui/hooks/useLanguageManagement.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useSessionManagement.d.ts +2 -1
- package/lib/typescript/ui/hooks/useSessionManagement.d.ts.map +1 -1
- package/lib/typescript/ui/index.d.ts +1 -1
- package/lib/typescript/ui/index.d.ts.map +1 -1
- package/lib/typescript/ui/screens/OxyAuthScreen.d.ts.map +1 -1
- package/lib/typescript/ui/stores/authStore.d.ts +1 -1
- package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
- package/lib/typescript/ui/utils/avatarUtils.d.ts +1 -1
- package/lib/typescript/ui/utils/avatarUtils.d.ts.map +1 -1
- package/lib/typescript/ui/utils/sessionHelpers.d.ts +2 -6
- package/lib/typescript/ui/utils/sessionHelpers.d.ts.map +1 -1
- package/lib/typescript/utils/sessionUtils.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/core/OxyServices.base.ts +2 -1
- package/src/core/mixins/OxyServices.auth.ts +1 -1
- package/src/core/mixins/OxyServices.user.ts +2 -1
- package/src/core/mixins/OxyServices.utility.ts +2 -1
- package/src/core/services/AuthService.ts +153 -0
- package/src/core/services/SessionService.ts +3 -5
- package/src/core/services/SessionTransportService.ts +69 -0
- package/src/core/services/TokenService.ts +10 -18
- package/src/core/services/UserService.ts +125 -0
- package/src/core/services/index.ts +14 -0
- package/src/crypto/index.ts +9 -0
- package/src/crypto/keyManager.ts +3 -2
- package/src/crypto/signatureService.ts +44 -142
- package/src/index.ts +1 -2
- package/src/models/interfaces.ts +21 -74
- package/src/models/session.ts +3 -5
- package/src/ui/context/OxyContext.tsx +22 -57
- package/src/ui/context/hooks/useAuthOperations.ts +17 -24
- package/src/ui/context/hooks/useLanguageManagement.ts +2 -1
- package/src/ui/hooks/auth/index.ts +0 -1
- package/src/ui/hooks/mutations/useAccountMutations.ts +1 -1
- package/src/ui/hooks/mutations/useServicesMutations.ts +1 -1
- package/src/ui/hooks/queries/useAccountQueries.ts +1 -1
- package/src/ui/hooks/queries/useServicesQueries.ts +3 -8
- package/src/ui/hooks/useLanguageManagement.ts +2 -1
- package/src/ui/hooks/useSessionManagement.ts +3 -9
- package/src/ui/index.ts +2 -1
- package/src/ui/screens/AccountSettingsScreen.tsx +6 -6
- package/src/ui/screens/AccountSwitcherScreen.tsx +1 -1
- package/src/ui/screens/OxyAuthScreen.tsx +5 -9
- package/src/ui/screens/ProfileScreen.tsx +1 -1
- package/src/ui/stores/authStore.ts +1 -1
- package/src/ui/types/navigation.ts +1 -1
- package/src/ui/utils/avatarUtils.ts +1 -1
- package/src/ui/utils/sessionHelpers.ts +15 -32
- package/src/utils/sessionUtils.ts +1 -8
|
@@ -3,77 +3,25 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Handles signing and verification of messages using ECDSA secp256k1.
|
|
5
5
|
* Used for authenticating requests and proving identity ownership.
|
|
6
|
+
*
|
|
7
|
+
* Note: This service handles SIGNING (requires private key access via KeyManager).
|
|
8
|
+
* For VERIFICATION, use @oxyhq/shared SignatureService instead.
|
|
6
9
|
*/
|
|
7
10
|
|
|
8
11
|
import { ec as EC } from 'elliptic';
|
|
9
12
|
import { KeyManager } from './keyManager';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
import {
|
|
14
|
+
buildAuthMessage,
|
|
15
|
+
buildRegistrationMessage,
|
|
16
|
+
buildRequestMessage,
|
|
17
|
+
getCryptoAdapter,
|
|
18
|
+
type SignedMessage,
|
|
19
|
+
} from '@oxyhq/shared';
|
|
13
20
|
|
|
14
21
|
const ec = new EC('secp256k1');
|
|
15
22
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
*/
|
|
19
|
-
function isReactNative(): boolean {
|
|
20
|
-
return typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Check if we're in a Node.js environment
|
|
25
|
-
*/
|
|
26
|
-
function isNodeJS(): boolean {
|
|
27
|
-
return typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Initialize expo-crypto module
|
|
32
|
-
*/
|
|
33
|
-
async function initExpoCrypto(): Promise<typeof import('expo-crypto')> {
|
|
34
|
-
if (!ExpoCrypto) {
|
|
35
|
-
ExpoCrypto = await import('expo-crypto');
|
|
36
|
-
}
|
|
37
|
-
return ExpoCrypto;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Compute SHA-256 hash of a string
|
|
42
|
-
*/
|
|
43
|
-
async function sha256(message: string): Promise<string> {
|
|
44
|
-
// In React Native, always use expo-crypto
|
|
45
|
-
if (isReactNative() || !isNodeJS()) {
|
|
46
|
-
const Crypto = await initExpoCrypto();
|
|
47
|
-
return Crypto.digestStringAsync(
|
|
48
|
-
Crypto.CryptoDigestAlgorithm.SHA256,
|
|
49
|
-
message
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// In Node.js, use Node's crypto module
|
|
54
|
-
// Use Function constructor to prevent Metro bundler from statically analyzing this require
|
|
55
|
-
// This ensures the require is only evaluated in Node.js runtime, not during Metro bundling
|
|
56
|
-
try {
|
|
57
|
-
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
58
|
-
const getCrypto = new Function('return require("crypto")');
|
|
59
|
-
const crypto = getCrypto();
|
|
60
|
-
return crypto.createHash('sha256').update(message).digest('hex');
|
|
61
|
-
} catch (error) {
|
|
62
|
-
// Fallback to expo-crypto if Node crypto fails
|
|
63
|
-
const Crypto = await initExpoCrypto();
|
|
64
|
-
return Crypto.digestStringAsync(
|
|
65
|
-
Crypto.CryptoDigestAlgorithm.SHA256,
|
|
66
|
-
message
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export interface SignedMessage {
|
|
72
|
-
message: string;
|
|
73
|
-
signature: string;
|
|
74
|
-
publicKey: string;
|
|
75
|
-
timestamp: number;
|
|
76
|
-
}
|
|
23
|
+
// Re-export shared types
|
|
24
|
+
export type { SignedMessage } from '@oxyhq/shared';
|
|
77
25
|
|
|
78
26
|
export interface AuthChallenge {
|
|
79
27
|
challenge: string;
|
|
@@ -84,39 +32,23 @@ export interface AuthChallenge {
|
|
|
84
32
|
export class SignatureService {
|
|
85
33
|
/**
|
|
86
34
|
* Generate a random challenge string (for offline use)
|
|
87
|
-
* Uses
|
|
35
|
+
* Uses shared crypto adapter
|
|
88
36
|
*/
|
|
89
37
|
static async generateChallenge(): Promise<string> {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
.map((b: number) => b.toString(16).padStart(2, '0'))
|
|
96
|
-
.join('');
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Node.js fallback
|
|
100
|
-
try {
|
|
101
|
-
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
102
|
-
const getCrypto = new Function('return require("crypto")');
|
|
103
|
-
const crypto = getCrypto();
|
|
104
|
-
return crypto.randomBytes(32).toString('hex');
|
|
105
|
-
} catch (error) {
|
|
106
|
-
// Fallback to expo-crypto if Node crypto fails
|
|
107
|
-
const Crypto = await initExpoCrypto();
|
|
108
|
-
const randomBytes = await Crypto.getRandomBytesAsync(32);
|
|
109
|
-
return Array.from(randomBytes)
|
|
110
|
-
.map((b: number) => b.toString(16).padStart(2, '0'))
|
|
111
|
-
.join('');
|
|
112
|
-
}
|
|
38
|
+
const adapter = await getCryptoAdapter();
|
|
39
|
+
const randomBytes = await adapter.randomBytes(32);
|
|
40
|
+
return Array.from(randomBytes)
|
|
41
|
+
.map((b: number) => b.toString(16).padStart(2, '0'))
|
|
42
|
+
.join('');
|
|
113
43
|
}
|
|
114
44
|
|
|
115
45
|
/**
|
|
116
46
|
* Hash a message using SHA-256
|
|
47
|
+
* Uses shared crypto adapter
|
|
117
48
|
*/
|
|
118
49
|
static async hashMessage(message: string): Promise<string> {
|
|
119
|
-
|
|
50
|
+
const adapter = await getCryptoAdapter();
|
|
51
|
+
return adapter.sha256(message);
|
|
120
52
|
}
|
|
121
53
|
|
|
122
54
|
/**
|
|
@@ -129,7 +61,8 @@ export class SignatureService {
|
|
|
129
61
|
throw new Error('No identity found. Please create or import an identity first.');
|
|
130
62
|
}
|
|
131
63
|
|
|
132
|
-
const
|
|
64
|
+
const adapter = await getCryptoAdapter();
|
|
65
|
+
const messageHash = await adapter.sha256(message);
|
|
133
66
|
const signature = keyPair.sign(messageHash);
|
|
134
67
|
return signature.toDER('hex');
|
|
135
68
|
}
|
|
@@ -140,45 +73,19 @@ export class SignatureService {
|
|
|
140
73
|
*/
|
|
141
74
|
static async signWithKey(message: string, privateKey: string): Promise<string> {
|
|
142
75
|
const keyPair = ec.keyFromPrivate(privateKey);
|
|
143
|
-
const
|
|
76
|
+
const adapter = await getCryptoAdapter();
|
|
77
|
+
const messageHash = await adapter.sha256(message);
|
|
144
78
|
const signature = keyPair.sign(messageHash);
|
|
145
79
|
return signature.toDER('hex');
|
|
146
80
|
}
|
|
147
81
|
|
|
148
82
|
/**
|
|
149
83
|
* Verify a signature against a message and public key
|
|
84
|
+
* Uses shared SignatureService for verification
|
|
150
85
|
*/
|
|
151
86
|
static async verify(message: string, signature: string, publicKey: string): Promise<boolean> {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const messageHash = await sha256(message);
|
|
155
|
-
return key.verify(messageHash, signature);
|
|
156
|
-
} catch {
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Synchronous verification (for Node.js backend)
|
|
163
|
-
* Uses crypto module directly for hashing
|
|
164
|
-
* Note: This method should only be used in Node.js environments
|
|
165
|
-
*/
|
|
166
|
-
static verifySync(message: string, signature: string, publicKey: string): boolean {
|
|
167
|
-
try {
|
|
168
|
-
if (!isNodeJS()) {
|
|
169
|
-
// In React Native, use async verify instead
|
|
170
|
-
throw new Error('verifySync should only be used in Node.js. Use verify() in React Native.');
|
|
171
|
-
}
|
|
172
|
-
// Use Function constructor to prevent Metro bundler from statically analyzing this require
|
|
173
|
-
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
174
|
-
const getCrypto = new Function('return require("crypto")');
|
|
175
|
-
const crypto = getCrypto();
|
|
176
|
-
const key = ec.keyFromPublic(publicKey, 'hex');
|
|
177
|
-
const messageHash = crypto.createHash('sha256').update(message).digest('hex');
|
|
178
|
-
return key.verify(messageHash, signature);
|
|
179
|
-
} catch {
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
87
|
+
const { SignatureService: SharedSignatureService } = await import('@oxyhq/shared');
|
|
88
|
+
return SharedSignatureService.verify(message, signature, publicKey);
|
|
182
89
|
}
|
|
183
90
|
|
|
184
91
|
/**
|
|
@@ -205,22 +112,23 @@ export class SignatureService {
|
|
|
205
112
|
/**
|
|
206
113
|
* Verify a signed message object
|
|
207
114
|
* Checks both signature validity and timestamp freshness
|
|
115
|
+
* Uses shared SignatureService for verification
|
|
208
116
|
*/
|
|
209
117
|
static async verifySignedMessage(
|
|
210
118
|
signedMessage: SignedMessage,
|
|
211
119
|
maxAgeMs: number = 5 * 60 * 1000 // 5 minutes default
|
|
212
120
|
): Promise<boolean> {
|
|
121
|
+
const { SignatureService: SharedSignatureService, isTimestampFresh } = await import('@oxyhq/shared');
|
|
213
122
|
const { message, signature, publicKey, timestamp } = signedMessage;
|
|
214
123
|
|
|
215
124
|
// Check timestamp freshness
|
|
216
|
-
|
|
217
|
-
if (now - timestamp > maxAgeMs) {
|
|
125
|
+
if (!isTimestampFresh(timestamp, maxAgeMs)) {
|
|
218
126
|
return false;
|
|
219
127
|
}
|
|
220
128
|
|
|
221
129
|
// Verify signature
|
|
222
130
|
const messageWithTimestamp = `${message}:${timestamp}`;
|
|
223
|
-
return
|
|
131
|
+
return SharedSignatureService.verify(messageWithTimestamp, signature, publicKey);
|
|
224
132
|
}
|
|
225
133
|
|
|
226
134
|
/**
|
|
@@ -234,7 +142,7 @@ export class SignatureService {
|
|
|
234
142
|
}
|
|
235
143
|
|
|
236
144
|
const timestamp = Date.now();
|
|
237
|
-
const message =
|
|
145
|
+
const message = buildAuthMessage(publicKey, challenge, timestamp);
|
|
238
146
|
const signature = await SignatureService.sign(message);
|
|
239
147
|
|
|
240
148
|
return {
|
|
@@ -246,22 +154,22 @@ export class SignatureService {
|
|
|
246
154
|
|
|
247
155
|
/**
|
|
248
156
|
* Verify a challenge response
|
|
157
|
+
* Uses shared SignatureService for verification
|
|
249
158
|
*/
|
|
250
159
|
static async verifyChallengeResponse(
|
|
251
160
|
originalChallenge: string,
|
|
252
161
|
response: AuthChallenge,
|
|
253
162
|
maxAgeMs: number = 5 * 60 * 1000
|
|
254
163
|
): Promise<boolean> {
|
|
164
|
+
const { SignatureService: SharedSignatureService } = await import('@oxyhq/shared');
|
|
255
165
|
const { challenge: signature, publicKey, timestamp } = response;
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const message = `auth:${publicKey}:${originalChallenge}:${timestamp}`;
|
|
264
|
-
return SignatureService.verify(message, signature, publicKey);
|
|
166
|
+
return SharedSignatureService.verifyChallengeResponse(
|
|
167
|
+
publicKey,
|
|
168
|
+
originalChallenge,
|
|
169
|
+
signature,
|
|
170
|
+
timestamp,
|
|
171
|
+
maxAgeMs
|
|
172
|
+
);
|
|
265
173
|
}
|
|
266
174
|
|
|
267
175
|
/**
|
|
@@ -276,7 +184,7 @@ export class SignatureService {
|
|
|
276
184
|
}
|
|
277
185
|
|
|
278
186
|
const timestamp = Date.now();
|
|
279
|
-
const message =
|
|
187
|
+
const message = buildRegistrationMessage(publicKey, timestamp);
|
|
280
188
|
const signature = await SignatureService.sign(message);
|
|
281
189
|
|
|
282
190
|
return {
|
|
@@ -301,13 +209,7 @@ export class SignatureService {
|
|
|
301
209
|
}
|
|
302
210
|
|
|
303
211
|
const timestamp = Date.now();
|
|
304
|
-
|
|
305
|
-
// Create canonical string representation
|
|
306
|
-
const sortedKeys = Object.keys(data).sort();
|
|
307
|
-
const canonicalParts = sortedKeys.map(key => `${key}:${JSON.stringify(data[key])}`);
|
|
308
|
-
const canonicalString = canonicalParts.join('|');
|
|
309
|
-
|
|
310
|
-
const message = `request:${publicKey}:${timestamp}:${canonicalString}`;
|
|
212
|
+
const message = buildRequestMessage(publicKey, timestamp, data);
|
|
311
213
|
const signature = await SignatureService.sign(message);
|
|
312
214
|
|
|
313
215
|
return {
|
package/src/index.ts
CHANGED
|
@@ -49,10 +49,9 @@ export {
|
|
|
49
49
|
export type { LanguageMetadata } from './utils/languageUtils';
|
|
50
50
|
|
|
51
51
|
// Type exports
|
|
52
|
+
// Note: User and LoginResponse should be imported from @oxyhq/shared
|
|
52
53
|
export type {
|
|
53
54
|
OxyConfig,
|
|
54
|
-
User,
|
|
55
|
-
LoginResponse,
|
|
56
55
|
Notification,
|
|
57
56
|
Wallet,
|
|
58
57
|
Transaction,
|
package/src/models/interfaces.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Services Package Interfaces
|
|
3
|
+
*
|
|
4
|
+
* Package-specific interfaces. For shared models (User, Session, etc.),
|
|
5
|
+
* import directly from @oxyhq/shared:
|
|
6
|
+
*
|
|
7
|
+
* import { User, LoginResponse, Session } from '@oxyhq/shared';
|
|
8
|
+
*/
|
|
9
|
+
|
|
1
10
|
export interface OxyConfig {
|
|
2
11
|
baseURL: string;
|
|
3
12
|
cloudURL?: string;
|
|
@@ -21,66 +30,8 @@ export interface OxyConfig {
|
|
|
21
30
|
onRequestError?: (url: string, method: string, error: Error) => void;
|
|
22
31
|
}
|
|
23
32
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
*
|
|
27
|
-
* IMPORTANT:
|
|
28
|
-
* - id: Public key (ECDSA secp256k1 public key, 130 hex characters) - CANONICAL USER IDENTITY
|
|
29
|
-
* - publicKey: Same as id (kept for backward compatibility and explicit clarity)
|
|
30
|
-
*
|
|
31
|
-
* publicKey is the canonical user identity across the ecosystem because it's:
|
|
32
|
-
* - Globally unique
|
|
33
|
-
* - Local-first (stored in Accounts app)
|
|
34
|
-
* - Avoids device-bound artifacts
|
|
35
|
-
*
|
|
36
|
-
* MongoDB _id remains internal to backend only and is not exposed in the User interface.
|
|
37
|
-
* Backend may use MongoDB ObjectId internally for database operations, but client always uses publicKey.
|
|
38
|
-
*/
|
|
39
|
-
export interface User {
|
|
40
|
-
id: string; // Public key - CANONICAL USER IDENTITY (130 hex chars for secp256k1)
|
|
41
|
-
publicKey: string; // Same as id (kept for backward compatibility)
|
|
42
|
-
username: string;
|
|
43
|
-
email?: string;
|
|
44
|
-
// Avatar file id (asset id)
|
|
45
|
-
avatar?: string;
|
|
46
|
-
// Privacy and security settings
|
|
47
|
-
privacySettings?: {
|
|
48
|
-
[key: string]: unknown;
|
|
49
|
-
};
|
|
50
|
-
name?: {
|
|
51
|
-
first?: string;
|
|
52
|
-
last?: string;
|
|
53
|
-
full?: string; // virtual, not stored in DB, returned by API
|
|
54
|
-
[key: string]: unknown;
|
|
55
|
-
};
|
|
56
|
-
bio?: string;
|
|
57
|
-
karma?: number;
|
|
58
|
-
location?: string;
|
|
59
|
-
website?: string;
|
|
60
|
-
createdAt?: string;
|
|
61
|
-
updatedAt?: string;
|
|
62
|
-
links?: Array<{
|
|
63
|
-
title?: string;
|
|
64
|
-
description?: string;
|
|
65
|
-
image?: string;
|
|
66
|
-
link: string;
|
|
67
|
-
}>;
|
|
68
|
-
// Social counts
|
|
69
|
-
_count?: {
|
|
70
|
-
followers?: number;
|
|
71
|
-
following?: number;
|
|
72
|
-
};
|
|
73
|
-
accountExpiresAfterInactivityDays?: number | null; // Days of inactivity before account expires (null = never expire)
|
|
74
|
-
[key: string]: unknown;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export interface LoginResponse {
|
|
78
|
-
accessToken?: string;
|
|
79
|
-
refreshToken?: string;
|
|
80
|
-
token?: string; // For backwards compatibility
|
|
81
|
-
user: User;
|
|
82
|
-
message?: string;
|
|
83
|
-
}
|
|
33
|
+
// Note: User and LoginResponse are in @oxyhq/shared
|
|
34
|
+
// Import them directly: import { User, LoginResponse } from '@oxyhq/shared';
|
|
84
35
|
|
|
85
36
|
export interface Notification {
|
|
86
37
|
id: string;
|
|
@@ -153,17 +104,8 @@ export interface TransactionResponse {
|
|
|
153
104
|
transaction: Transaction;
|
|
154
105
|
}
|
|
155
106
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
limit: number;
|
|
159
|
-
offset: number;
|
|
160
|
-
hasMore: boolean;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export interface SearchProfilesResponse {
|
|
164
|
-
data: User[];
|
|
165
|
-
pagination: PaginationInfo;
|
|
166
|
-
}
|
|
107
|
+
// Note: PaginationInfo and SearchProfilesResponse are in @oxyhq/shared
|
|
108
|
+
// Import them directly: import { PaginationInfo, SearchProfilesResponse } from '@oxyhq/shared';
|
|
167
109
|
|
|
168
110
|
export interface KarmaRule {
|
|
169
111
|
id: string;
|
|
@@ -376,8 +318,6 @@ export interface AssetUrlResponse {
|
|
|
376
318
|
|
|
377
319
|
export interface AssetDeleteSummary {
|
|
378
320
|
fileId: string;
|
|
379
|
-
wouldDelete: boolean;
|
|
380
|
-
affectedApps: string[];
|
|
381
321
|
remainingLinks: number;
|
|
382
322
|
variants: string[];
|
|
383
323
|
}
|
|
@@ -495,6 +435,7 @@ export interface AssetUploadProgress {
|
|
|
495
435
|
}
|
|
496
436
|
|
|
497
437
|
// Device Session interfaces
|
|
438
|
+
// Note: User type should be imported from @oxyhq/shared
|
|
498
439
|
export interface DeviceSession {
|
|
499
440
|
sessionId: string;
|
|
500
441
|
deviceId: string;
|
|
@@ -503,7 +444,13 @@ export interface DeviceSession {
|
|
|
503
444
|
lastActive: string;
|
|
504
445
|
expiresAt: string;
|
|
505
446
|
isCurrent: boolean;
|
|
506
|
-
user?:
|
|
447
|
+
user?: {
|
|
448
|
+
id: string;
|
|
449
|
+
publicKey: string;
|
|
450
|
+
username: string;
|
|
451
|
+
avatar?: string;
|
|
452
|
+
[key: string]: unknown;
|
|
453
|
+
}; // Partial User - import full User type from @oxyhq/shared if needed
|
|
507
454
|
createdAt?: string;
|
|
508
455
|
}
|
|
509
456
|
|
package/src/models/session.ts
CHANGED
|
@@ -2,17 +2,15 @@
|
|
|
2
2
|
* Client Session Model
|
|
3
3
|
*
|
|
4
4
|
* IMPORTANT:
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
7
|
-
* - Sessions are bound to the local identity (publicKey) stored in Accounts app
|
|
5
|
+
* - userId: MongoDB ObjectId (24 hex characters), never publicKey
|
|
6
|
+
* - Used for session management and user identification
|
|
8
7
|
*/
|
|
9
8
|
export interface ClientSession {
|
|
10
9
|
sessionId: string;
|
|
11
10
|
deviceId: string;
|
|
12
11
|
expiresAt: string;
|
|
13
12
|
lastActive: string;
|
|
14
|
-
|
|
15
|
-
userId?: string; // MongoDB ObjectId (internal backend reference, optional for compatibility)
|
|
13
|
+
userId?: string; // MongoDB ObjectId - PRIMARY IDENTIFIER (never publicKey)
|
|
16
14
|
isCurrent?: boolean;
|
|
17
15
|
}
|
|
18
16
|
|
|
@@ -11,7 +11,8 @@ import {
|
|
|
11
11
|
} from 'react';
|
|
12
12
|
import { Platform } from 'react-native';
|
|
13
13
|
import { OxyServices } from '../../core';
|
|
14
|
-
import type {
|
|
14
|
+
import type { ApiError } from '../../models/interfaces';
|
|
15
|
+
import type { User } from '@oxyhq/shared';
|
|
15
16
|
import type { ClientSession } from '../../models/session';
|
|
16
17
|
import { toast } from '../../lib/sonner';
|
|
17
18
|
import { useAuthStore, type AuthState } from '../stores/authStore';
|
|
@@ -222,7 +223,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
222
223
|
// CRITICAL: Invalidate cache on app startup to ensure fresh state check
|
|
223
224
|
// This prevents stale cache from previous session from showing incorrect state
|
|
224
225
|
KeyManager.invalidateCache();
|
|
225
|
-
|
|
226
|
+
|
|
226
227
|
// Check if identity exists and verify integrity
|
|
227
228
|
const hasIdentity = await KeyManager.hasIdentity();
|
|
228
229
|
if (hasIdentity) {
|
|
@@ -421,7 +422,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
421
422
|
if (pendingTransfers.length > 0) {
|
|
422
423
|
const activeTransferId = getActiveTransferId();
|
|
423
424
|
const hasActiveTransfer = activeTransferId && pendingTransfers.some((t: { transferId: string; data: any }) => t.transferId === activeTransferId);
|
|
424
|
-
|
|
425
|
+
|
|
425
426
|
if (hasActiveTransfer) {
|
|
426
427
|
throw new Error(
|
|
427
428
|
'Cannot delete identity: An active identity transfer is in progress. ' +
|
|
@@ -485,11 +486,11 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
485
486
|
if (wasOffline) {
|
|
486
487
|
const now = Date.now();
|
|
487
488
|
const timeSinceLastLog = now - lastReconnectionLog;
|
|
488
|
-
|
|
489
|
+
|
|
489
490
|
if (timeSinceLastLog >= RECONNECTION_LOG_DEBOUNCE_MS) {
|
|
490
491
|
logger('Network reconnected, checking identity sync...');
|
|
491
492
|
lastReconnectionLog = now;
|
|
492
|
-
|
|
493
|
+
|
|
493
494
|
// Sync identity first (if not synced)
|
|
494
495
|
try {
|
|
495
496
|
const hasIdentityValue = await hasIdentity();
|
|
@@ -520,7 +521,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
520
521
|
// This is handled by useCheckPendingTransfers hook which runs automatically
|
|
521
522
|
// when authenticated and online
|
|
522
523
|
}
|
|
523
|
-
|
|
524
|
+
|
|
524
525
|
// TanStack Query will automatically retry pending mutations
|
|
525
526
|
// Reset flag immediately after processing (whether logged or not)
|
|
526
527
|
wasOffline = false;
|
|
@@ -580,22 +581,6 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
580
581
|
setTokenReady(false);
|
|
581
582
|
|
|
582
583
|
try {
|
|
583
|
-
// CRITICAL: Get current local identity (publicKey) before restoring sessions
|
|
584
|
-
// Sessions must belong to the current local identity stored in Accounts app
|
|
585
|
-
let currentPublicKey: string | null = null;
|
|
586
|
-
try {
|
|
587
|
-
if (Platform.OS !== 'web') {
|
|
588
|
-
// Only check identity on native platforms (web doesn't have local identity)
|
|
589
|
-
// KeyManager is already imported at the top of the file
|
|
590
|
-
currentPublicKey = await KeyManager.getPublicKey();
|
|
591
|
-
}
|
|
592
|
-
} catch (identityError) {
|
|
593
|
-
if (__DEV__) {
|
|
594
|
-
logger('Failed to get current local identity during session restoration', identityError);
|
|
595
|
-
}
|
|
596
|
-
// Continue without identity check if it fails (e.g., on web platform)
|
|
597
|
-
}
|
|
598
|
-
|
|
599
584
|
const storedSessionIdsJson = await storage.getItem(storageKeys.sessionIds);
|
|
600
585
|
const storedSessionIds: string[] = storedSessionIdsJson ? JSON.parse(storedSessionIdsJson) : [];
|
|
601
586
|
const storedActiveSessionId = await storage.getItem(storageKeys.activeSessionId);
|
|
@@ -608,25 +593,12 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
608
593
|
const validation = await oxyServices.validateSession(sessionId, { useHeaderValidation: true });
|
|
609
594
|
if (validation?.valid && validation.user) {
|
|
610
595
|
const now = new Date();
|
|
611
|
-
// user.id is now publicKey (canonical identity)
|
|
612
|
-
const sessionPublicKey = validation.user.publicKey || validation.user.id || '';
|
|
613
|
-
|
|
614
|
-
// IDENTITY BINDING: Only restore sessions that match current local identity
|
|
615
|
-
// If we have a current local identity, filter out sessions that don't match
|
|
616
|
-
if (currentPublicKey && sessionPublicKey !== currentPublicKey) {
|
|
617
|
-
if (__DEV__) {
|
|
618
|
-
logger(`Skipping session ${sessionId.substring(0, 8)}... - belongs to different identity (${sessionPublicKey.substring(0, 16)}... vs ${currentPublicKey.substring(0, 16)}...)`);
|
|
619
|
-
}
|
|
620
|
-
continue; // Skip this session - it belongs to a different identity
|
|
621
|
-
}
|
|
622
|
-
|
|
623
596
|
validSessions.push({
|
|
624
597
|
sessionId,
|
|
625
598
|
deviceId: '',
|
|
626
599
|
expiresAt: new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
627
600
|
lastActive: now.toISOString(),
|
|
628
|
-
|
|
629
|
-
userId: validation.user.id?.toString(), // Optional MongoDB ObjectId for backward compatibility
|
|
601
|
+
userId: validation.user.id?.toString() ?? '',
|
|
630
602
|
isCurrent: sessionId === storedActiveSessionId,
|
|
631
603
|
});
|
|
632
604
|
}
|
|
@@ -644,13 +616,6 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
644
616
|
|
|
645
617
|
if (validSessions.length > 0) {
|
|
646
618
|
updateSessions(validSessions, { merge: false });
|
|
647
|
-
} else if (currentPublicKey && storedSessionIds.length > 0) {
|
|
648
|
-
// All sessions were filtered out due to identity mismatch - clear stored sessions
|
|
649
|
-
if (__DEV__) {
|
|
650
|
-
logger('All stored sessions belong to different identity - clearing session storage');
|
|
651
|
-
}
|
|
652
|
-
await storage.removeItem(storageKeys.sessionIds);
|
|
653
|
-
await storage.removeItem(storageKeys.activeSessionId);
|
|
654
619
|
}
|
|
655
620
|
}
|
|
656
621
|
|
|
@@ -762,9 +727,9 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
762
727
|
return isAuthenticatedFromStore || isAuthenticatedFromSessions;
|
|
763
728
|
}, [isAuthenticatedFromStore, isAuthenticatedFromSessions]);
|
|
764
729
|
|
|
765
|
-
// Get userId from JWT token for socket room matching
|
|
766
|
-
//
|
|
767
|
-
//
|
|
730
|
+
// Get userId from JWT token (MongoDB ObjectId) for socket room matching
|
|
731
|
+
// user.id is set to publicKey for compatibility, but socket rooms use MongoDB ObjectId
|
|
732
|
+
// The JWT token's userId field contains the MongoDB ObjectId
|
|
768
733
|
const userId = oxyServices.getCurrentUserId() || user?.id;
|
|
769
734
|
|
|
770
735
|
// Use Zustand store for transfer state management
|
|
@@ -784,16 +749,16 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
784
749
|
// Load transfer codes
|
|
785
750
|
const storedCodes = await storage.getItem(TRANSFER_CODES_STORAGE_KEY);
|
|
786
751
|
const storedActiveTransferId = await storage.getItem(ACTIVE_TRANSFER_STORAGE_KEY);
|
|
787
|
-
|
|
752
|
+
|
|
788
753
|
const parsedCodes = storedCodes ? JSON.parse(storedCodes) : {};
|
|
789
754
|
const activeTransferId = storedActiveTransferId || null;
|
|
790
|
-
|
|
755
|
+
|
|
791
756
|
// Restore to Zustand store (store handles validation and expiration)
|
|
792
757
|
restoreFromStorage(parsedCodes, activeTransferId);
|
|
793
758
|
markRestored();
|
|
794
|
-
|
|
759
|
+
|
|
795
760
|
if (__DEV__ && Object.keys(parsedCodes).length > 0) {
|
|
796
|
-
logger('Restored transfer codes from storage', {
|
|
761
|
+
logger('Restored transfer codes from storage', {
|
|
797
762
|
count: Object.keys(parsedCodes).length,
|
|
798
763
|
hasActiveTransfer: !!activeTransferId,
|
|
799
764
|
});
|
|
@@ -818,7 +783,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
818
783
|
const persistTransferCodes = async () => {
|
|
819
784
|
try {
|
|
820
785
|
await storage.setItem(TRANSFER_CODES_STORAGE_KEY, JSON.stringify(transferCodes));
|
|
821
|
-
|
|
786
|
+
|
|
822
787
|
if (activeTransferId) {
|
|
823
788
|
await storage.setItem(ACTIVE_TRANSFER_STORAGE_KEY, activeTransferId);
|
|
824
789
|
} else {
|
|
@@ -846,7 +811,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
846
811
|
// Transfer code management functions using Zustand store
|
|
847
812
|
const storeTransferCode = useCallback(async (transferId: string, code: string, sourceDeviceId: string | null, publicKey: string) => {
|
|
848
813
|
storeTransferCodeStore(transferId, code, sourceDeviceId, publicKey);
|
|
849
|
-
|
|
814
|
+
|
|
850
815
|
if (__DEV__) {
|
|
851
816
|
logger('Stored transfer code', { transferId, sourceDeviceId, publicKey: publicKey.substring(0, 16) + '...' });
|
|
852
817
|
}
|
|
@@ -858,7 +823,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
858
823
|
|
|
859
824
|
const updateTransferState = useCallback(async (transferId: string, state: 'pending' | 'completed' | 'failed') => {
|
|
860
825
|
updateTransferStateStore(transferId, state);
|
|
861
|
-
|
|
826
|
+
|
|
862
827
|
if (__DEV__) {
|
|
863
828
|
logger('Updated transfer state', { transferId, state });
|
|
864
829
|
}
|
|
@@ -866,7 +831,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
866
831
|
|
|
867
832
|
const clearTransferCode = useCallback(async (transferId: string) => {
|
|
868
833
|
clearTransferCodeStore(transferId);
|
|
869
|
-
|
|
834
|
+
|
|
870
835
|
if (__DEV__) {
|
|
871
836
|
logger('Cleared transfer code', { transferId });
|
|
872
837
|
}
|
|
@@ -908,7 +873,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
908
873
|
const storedTransfer = getTransferCode(data.transferId);
|
|
909
874
|
|
|
910
875
|
if (!storedTransfer) {
|
|
911
|
-
logger('Transfer code not found for transferId', {
|
|
876
|
+
logger('Transfer code not found for transferId', {
|
|
912
877
|
transferId: data.transferId,
|
|
913
878
|
});
|
|
914
879
|
toast.error('Transfer verification failed: Code not found. Identity will not be deleted.');
|
|
@@ -930,7 +895,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
930
895
|
// Verify deviceId matches - very lenient since publicKey is the critical check
|
|
931
896
|
// If publicKey matches, we allow deletion even if deviceId doesn't match exactly
|
|
932
897
|
// This handles cases where deviceId might not be available or slightly different
|
|
933
|
-
const deviceIdMatches =
|
|
898
|
+
const deviceIdMatches =
|
|
934
899
|
// Exact match
|
|
935
900
|
(data.sourceDeviceId && data.sourceDeviceId === currentDeviceId) ||
|
|
936
901
|
// Stored sourceDeviceId matches current deviceId
|
|
@@ -1010,7 +975,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
1010
975
|
}
|
|
1011
976
|
|
|
1012
977
|
await deleteIdentityAndClearAccount(false, false, true);
|
|
1013
|
-
|
|
978
|
+
|
|
1014
979
|
// Verify identity was actually deleted
|
|
1015
980
|
const identityDeleted = !(await KeyManager.hasIdentity());
|
|
1016
981
|
if (!identityDeleted) {
|