@oxyhq/services 5.16.33 → 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.
Files changed (190) hide show
  1. package/README.md +26 -8
  2. package/lib/commonjs/core/OxyServices.base.js.map +1 -1
  3. package/lib/commonjs/core/mixins/OxyServices.user.js.map +1 -1
  4. package/lib/commonjs/core/mixins/OxyServices.utility.js.map +1 -1
  5. package/lib/commonjs/core/services/AuthService.js +156 -0
  6. package/lib/commonjs/core/services/AuthService.js.map +1 -0
  7. package/lib/commonjs/core/services/SessionService.js +1 -2
  8. package/lib/commonjs/core/services/SessionService.js.map +1 -1
  9. package/lib/commonjs/core/services/SessionTransportService.js +64 -0
  10. package/lib/commonjs/core/services/SessionTransportService.js.map +1 -0
  11. package/lib/commonjs/core/services/TokenService.js +9 -17
  12. package/lib/commonjs/core/services/TokenService.js.map +1 -1
  13. package/lib/commonjs/core/services/UserService.js +123 -0
  14. package/lib/commonjs/core/services/UserService.js.map +1 -0
  15. package/lib/commonjs/core/services/index.js +34 -0
  16. package/lib/commonjs/core/services/index.js.map +1 -0
  17. package/lib/commonjs/crypto/index.js.map +1 -1
  18. package/lib/commonjs/crypto/keyManager.js +5 -2
  19. package/lib/commonjs/crypto/keyManager.js.map +1 -1
  20. package/lib/commonjs/crypto/signatureService.js +36 -121
  21. package/lib/commonjs/crypto/signatureService.js.map +1 -1
  22. package/lib/commonjs/index.js.map +1 -1
  23. package/lib/commonjs/models/interfaces.js +11 -11
  24. package/lib/commonjs/models/interfaces.js.map +1 -1
  25. package/lib/commonjs/ui/context/OxyContext.js +4 -40
  26. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  27. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +23 -61
  28. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  29. package/lib/commonjs/ui/context/hooks/useLanguageManagement.js.map +1 -1
  30. package/lib/commonjs/ui/hooks/queries/useServicesQueries.js +4 -12
  31. package/lib/commonjs/ui/hooks/queries/useServicesQueries.js.map +1 -1
  32. package/lib/commonjs/ui/hooks/useLanguageManagement.js.map +1 -1
  33. package/lib/commonjs/ui/hooks/useSessionManagement.js +0 -8
  34. package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
  35. package/lib/commonjs/ui/index.js +2 -0
  36. package/lib/commonjs/ui/index.js.map +1 -1
  37. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  38. package/lib/commonjs/ui/screens/OxyAuthScreen.js +9 -13
  39. package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +1 -1
  40. package/lib/commonjs/ui/utils/sessionHelpers.js +11 -26
  41. package/lib/commonjs/ui/utils/sessionHelpers.js.map +1 -1
  42. package/lib/commonjs/utils/sessionUtils.js +1 -8
  43. package/lib/commonjs/utils/sessionUtils.js.map +1 -1
  44. package/lib/module/core/OxyServices.base.js.map +1 -1
  45. package/lib/module/core/mixins/OxyServices.user.js.map +1 -1
  46. package/lib/module/core/mixins/OxyServices.utility.js.map +1 -1
  47. package/lib/module/core/services/AuthService.js +151 -0
  48. package/lib/module/core/services/AuthService.js.map +1 -0
  49. package/lib/module/core/services/SessionService.js +1 -2
  50. package/lib/module/core/services/SessionService.js.map +1 -1
  51. package/lib/module/core/services/SessionTransportService.js +59 -0
  52. package/lib/module/core/services/SessionTransportService.js.map +1 -0
  53. package/lib/module/core/services/TokenService.js +9 -17
  54. package/lib/module/core/services/TokenService.js.map +1 -1
  55. package/lib/module/core/services/UserService.js +118 -0
  56. package/lib/module/core/services/UserService.js.map +1 -0
  57. package/lib/module/core/services/index.js +16 -0
  58. package/lib/module/core/services/index.js.map +1 -0
  59. package/lib/module/crypto/index.js +9 -0
  60. package/lib/module/crypto/index.js.map +1 -1
  61. package/lib/module/crypto/keyManager.js +5 -2
  62. package/lib/module/crypto/keyManager.js.map +1 -1
  63. package/lib/module/crypto/signatureService.js +36 -122
  64. package/lib/module/crypto/signatureService.js.map +1 -1
  65. package/lib/module/index.js +1 -0
  66. package/lib/module/index.js.map +1 -1
  67. package/lib/module/models/interfaces.js +11 -11
  68. package/lib/module/models/interfaces.js.map +1 -1
  69. package/lib/module/ui/context/OxyContext.js +4 -40
  70. package/lib/module/ui/context/OxyContext.js.map +1 -1
  71. package/lib/module/ui/context/hooks/useAuthOperations.js +23 -61
  72. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  73. package/lib/module/ui/context/hooks/useLanguageManagement.js.map +1 -1
  74. package/lib/module/ui/hooks/queries/useServicesQueries.js +5 -13
  75. package/lib/module/ui/hooks/queries/useServicesQueries.js.map +1 -1
  76. package/lib/module/ui/hooks/useLanguageManagement.js.map +1 -1
  77. package/lib/module/ui/hooks/useSessionManagement.js +0 -8
  78. package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
  79. package/lib/module/ui/index.js +1 -0
  80. package/lib/module/ui/index.js.map +1 -1
  81. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  82. package/lib/module/ui/screens/OxyAuthScreen.js +7 -9
  83. package/lib/module/ui/screens/OxyAuthScreen.js.map +1 -1
  84. package/lib/module/ui/utils/sessionHelpers.js +11 -26
  85. package/lib/module/ui/utils/sessionHelpers.js.map +1 -1
  86. package/lib/module/utils/sessionUtils.js +1 -8
  87. package/lib/module/utils/sessionUtils.js.map +1 -1
  88. package/lib/typescript/core/OxyServices.base.d.ts.map +1 -1
  89. package/lib/typescript/core/mixins/OxyServices.analytics.d.ts.map +1 -1
  90. package/lib/typescript/core/mixins/OxyServices.assets.d.ts.map +1 -1
  91. package/lib/typescript/core/mixins/OxyServices.auth.d.ts +1 -1
  92. package/lib/typescript/core/mixins/OxyServices.auth.d.ts.map +1 -1
  93. package/lib/typescript/core/mixins/OxyServices.developer.d.ts.map +1 -1
  94. package/lib/typescript/core/mixins/OxyServices.devices.d.ts.map +1 -1
  95. package/lib/typescript/core/mixins/OxyServices.karma.d.ts.map +1 -1
  96. package/lib/typescript/core/mixins/OxyServices.language.d.ts.map +1 -1
  97. package/lib/typescript/core/mixins/OxyServices.location.d.ts.map +1 -1
  98. package/lib/typescript/core/mixins/OxyServices.payment.d.ts.map +1 -1
  99. package/lib/typescript/core/mixins/OxyServices.privacy.d.ts.map +1 -1
  100. package/lib/typescript/core/mixins/OxyServices.security.d.ts.map +1 -1
  101. package/lib/typescript/core/mixins/OxyServices.user.d.ts +2 -1
  102. package/lib/typescript/core/mixins/OxyServices.user.d.ts.map +1 -1
  103. package/lib/typescript/core/mixins/OxyServices.utility.d.ts.map +1 -1
  104. package/lib/typescript/core/mixins/index.d.ts +13 -13
  105. package/lib/typescript/core/mixins/index.d.ts.map +1 -1
  106. package/lib/typescript/core/services/AuthService.d.ts +50 -0
  107. package/lib/typescript/core/services/AuthService.d.ts.map +1 -0
  108. package/lib/typescript/core/services/SessionService.d.ts +3 -5
  109. package/lib/typescript/core/services/SessionService.d.ts.map +1 -1
  110. package/lib/typescript/core/services/SessionTransportService.d.ts +31 -0
  111. package/lib/typescript/core/services/SessionTransportService.d.ts.map +1 -0
  112. package/lib/typescript/core/services/TokenService.d.ts +3 -8
  113. package/lib/typescript/core/services/TokenService.d.ts.map +1 -1
  114. package/lib/typescript/core/services/UserService.d.ts +39 -0
  115. package/lib/typescript/core/services/UserService.d.ts.map +1 -0
  116. package/lib/typescript/core/services/index.d.ts +13 -0
  117. package/lib/typescript/core/services/index.d.ts.map +1 -0
  118. package/lib/typescript/crypto/index.d.ts +9 -0
  119. package/lib/typescript/crypto/index.d.ts.map +1 -1
  120. package/lib/typescript/crypto/keyManager.d.ts.map +1 -1
  121. package/lib/typescript/crypto/signatureService.d.ts +10 -13
  122. package/lib/typescript/crypto/signatureService.d.ts.map +1 -1
  123. package/lib/typescript/index.d.ts +1 -1
  124. package/lib/typescript/index.d.ts.map +1 -1
  125. package/lib/typescript/models/interfaces.d.ts +15 -69
  126. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  127. package/lib/typescript/models/session.d.ts +2 -4
  128. package/lib/typescript/models/session.d.ts.map +1 -1
  129. package/lib/typescript/ui/context/OxyContext.d.ts +2 -1
  130. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  131. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts +2 -1
  132. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  133. package/lib/typescript/ui/context/hooks/useLanguageManagement.d.ts +2 -1
  134. package/lib/typescript/ui/context/hooks/useLanguageManagement.d.ts.map +1 -1
  135. package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts +1 -1
  136. package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  137. package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts +1 -1
  138. package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
  139. package/lib/typescript/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
  140. package/lib/typescript/ui/hooks/useLanguageManagement.d.ts +2 -1
  141. package/lib/typescript/ui/hooks/useLanguageManagement.d.ts.map +1 -1
  142. package/lib/typescript/ui/hooks/useSessionManagement.d.ts +2 -1
  143. package/lib/typescript/ui/hooks/useSessionManagement.d.ts.map +1 -1
  144. package/lib/typescript/ui/index.d.ts +1 -1
  145. package/lib/typescript/ui/index.d.ts.map +1 -1
  146. package/lib/typescript/ui/screens/OxyAuthScreen.d.ts.map +1 -1
  147. package/lib/typescript/ui/stores/authStore.d.ts +1 -1
  148. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
  149. package/lib/typescript/ui/utils/avatarUtils.d.ts +1 -1
  150. package/lib/typescript/ui/utils/avatarUtils.d.ts.map +1 -1
  151. package/lib/typescript/ui/utils/sessionHelpers.d.ts +2 -6
  152. package/lib/typescript/ui/utils/sessionHelpers.d.ts.map +1 -1
  153. package/lib/typescript/utils/sessionUtils.d.ts.map +1 -1
  154. package/package.json +2 -1
  155. package/src/core/OxyServices.base.ts +2 -1
  156. package/src/core/mixins/OxyServices.auth.ts +1 -1
  157. package/src/core/mixins/OxyServices.user.ts +2 -1
  158. package/src/core/mixins/OxyServices.utility.ts +2 -1
  159. package/src/core/services/AuthService.ts +153 -0
  160. package/src/core/services/SessionService.ts +3 -5
  161. package/src/core/services/SessionTransportService.ts +69 -0
  162. package/src/core/services/TokenService.ts +10 -18
  163. package/src/core/services/UserService.ts +125 -0
  164. package/src/core/services/index.ts +14 -0
  165. package/src/crypto/index.ts +9 -0
  166. package/src/crypto/keyManager.ts +3 -2
  167. package/src/crypto/signatureService.ts +44 -142
  168. package/src/index.ts +1 -2
  169. package/src/models/interfaces.ts +21 -74
  170. package/src/models/session.ts +3 -5
  171. package/src/ui/context/OxyContext.tsx +22 -57
  172. package/src/ui/context/hooks/useAuthOperations.ts +33 -65
  173. package/src/ui/context/hooks/useLanguageManagement.ts +2 -1
  174. package/src/ui/hooks/auth/index.ts +0 -2
  175. package/src/ui/hooks/mutations/useAccountMutations.ts +1 -1
  176. package/src/ui/hooks/mutations/useServicesMutations.ts +1 -1
  177. package/src/ui/hooks/queries/useAccountQueries.ts +1 -1
  178. package/src/ui/hooks/queries/useServicesQueries.ts +3 -8
  179. package/src/ui/hooks/useLanguageManagement.ts +2 -1
  180. package/src/ui/hooks/useSessionManagement.ts +3 -9
  181. package/src/ui/index.ts +2 -1
  182. package/src/ui/screens/AccountSettingsScreen.tsx +6 -6
  183. package/src/ui/screens/AccountSwitcherScreen.tsx +1 -1
  184. package/src/ui/screens/OxyAuthScreen.tsx +5 -9
  185. package/src/ui/screens/ProfileScreen.tsx +1 -1
  186. package/src/ui/stores/authStore.ts +1 -1
  187. package/src/ui/types/navigation.ts +1 -1
  188. package/src/ui/utils/avatarUtils.ts +1 -1
  189. package/src/ui/utils/sessionHelpers.ts +15 -32
  190. 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
- // Lazy import for expo-crypto
12
- let ExpoCrypto: typeof import('expo-crypto') | null = null;
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
- * Check if we're in a React Native environment
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 expo-crypto in React Native, crypto.randomBytes in Node.js
35
+ * Uses shared crypto adapter
88
36
  */
89
37
  static async generateChallenge(): Promise<string> {
90
- if (isReactNative() || !isNodeJS()) {
91
- // Use expo-crypto for React Native (expo-random is deprecated)
92
- const Crypto = await initExpoCrypto();
93
- const randomBytes = await Crypto.getRandomBytesAsync(32);
94
- return Array.from(randomBytes)
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
- return sha256(message);
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 messageHash = await sha256(message);
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 messageHash = await sha256(message);
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
- try {
153
- const key = ec.keyFromPublic(publicKey, 'hex');
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
- const now = Date.now();
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 SignatureService.verify(messageWithTimestamp, signature, publicKey);
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 = `auth:${publicKey}:${challenge}:${timestamp}`;
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
- // Check timestamp freshness
258
- const now = Date.now();
259
- if (now - timestamp > maxAgeMs) {
260
- return false;
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 = `oxy:register:${publicKey}:${timestamp}`;
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,
@@ -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
- * User Model
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
- export interface PaginationInfo {
157
- total: number;
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?: 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
 
@@ -2,17 +2,15 @@
2
2
  * Client Session Model
3
3
  *
4
4
  * IMPORTANT:
5
- * - publicKey: Canonical user identity (ECDSA secp256k1 public key) - PRIMARY IDENTIFIER
6
- * - userId: MongoDB ObjectId (kept for backward compatibility, but publicKey is canonical)
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
- publicKey: string; // Canonical user identity - PRIMARY IDENTIFIER
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 { User, ApiError } from '../../models/interfaces';
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
- publicKey: sessionPublicKey, // Canonical user identity
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
- // Note: JWT token may contain MongoDB ObjectId internally, but user.id is publicKey (canonical identity)
767
- // Socket rooms may need internal mapping from publicKey to MongoDB ObjectId if backend requires it
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) {