@oxyhq/services 5.16.34 → 5.16.36

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 (178) hide show
  1. package/README.md +8 -26
  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/crypto/README.md +142 -0
  6. package/lib/commonjs/crypto/core.js +147 -0
  7. package/lib/commonjs/crypto/core.js.map +1 -0
  8. package/lib/commonjs/crypto/index.js +16 -0
  9. package/lib/commonjs/crypto/index.js.map +1 -1
  10. package/lib/commonjs/crypto/keyManager.js +19 -24
  11. package/lib/commonjs/crypto/keyManager.js.map +1 -1
  12. package/lib/commonjs/crypto/signatureService.js +116 -37
  13. package/lib/commonjs/crypto/signatureService.js.map +1 -1
  14. package/lib/commonjs/index.js.map +1 -1
  15. package/lib/commonjs/models/interfaces.js +10 -11
  16. package/lib/commonjs/models/interfaces.js.map +1 -1
  17. package/lib/commonjs/node/index.js +10 -1
  18. package/lib/commonjs/node/index.js.map +1 -1
  19. package/lib/commonjs/node/signatureService.js +107 -0
  20. package/lib/commonjs/node/signatureService.js.map +1 -0
  21. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  22. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  23. package/lib/commonjs/ui/context/hooks/useLanguageManagement.js.map +1 -1
  24. package/lib/commonjs/ui/hooks/useLanguageManagement.js.map +1 -1
  25. package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
  26. package/lib/commonjs/ui/index.js +0 -2
  27. package/lib/commonjs/ui/index.js.map +1 -1
  28. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  29. package/lib/commonjs/ui/screens/OxyAuthScreen.js +13 -9
  30. package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +1 -1
  31. package/lib/module/core/OxyServices.base.js.map +1 -1
  32. package/lib/module/core/mixins/OxyServices.user.js.map +1 -1
  33. package/lib/module/core/mixins/OxyServices.utility.js.map +1 -1
  34. package/lib/module/crypto/README.md +142 -0
  35. package/lib/module/crypto/core.js +133 -0
  36. package/lib/module/crypto/core.js.map +1 -0
  37. package/lib/module/crypto/index.js +3 -9
  38. package/lib/module/crypto/index.js.map +1 -1
  39. package/lib/module/crypto/keyManager.js +19 -24
  40. package/lib/module/crypto/keyManager.js.map +1 -1
  41. package/lib/module/crypto/signatureService.js +113 -33
  42. package/lib/module/crypto/signatureService.js.map +1 -1
  43. package/lib/module/index.js +0 -1
  44. package/lib/module/index.js.map +1 -1
  45. package/lib/module/models/interfaces.js +10 -11
  46. package/lib/module/models/interfaces.js.map +1 -1
  47. package/lib/module/node/index.js +3 -0
  48. package/lib/module/node/index.js.map +1 -1
  49. package/lib/module/node/signatureService.js +101 -0
  50. package/lib/module/node/signatureService.js.map +1 -0
  51. package/lib/module/ui/context/OxyContext.js.map +1 -1
  52. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  53. package/lib/module/ui/context/hooks/useLanguageManagement.js.map +1 -1
  54. package/lib/module/ui/hooks/useLanguageManagement.js.map +1 -1
  55. package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
  56. package/lib/module/ui/index.js +0 -1
  57. package/lib/module/ui/index.js.map +1 -1
  58. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  59. package/lib/module/ui/screens/OxyAuthScreen.js +9 -7
  60. package/lib/module/ui/screens/OxyAuthScreen.js.map +1 -1
  61. package/lib/typescript/core/OxyServices.base.d.ts.map +1 -1
  62. package/lib/typescript/core/mixins/OxyServices.analytics.d.ts.map +1 -1
  63. package/lib/typescript/core/mixins/OxyServices.assets.d.ts.map +1 -1
  64. package/lib/typescript/core/mixins/OxyServices.auth.d.ts +1 -1
  65. package/lib/typescript/core/mixins/OxyServices.auth.d.ts.map +1 -1
  66. package/lib/typescript/core/mixins/OxyServices.developer.d.ts.map +1 -1
  67. package/lib/typescript/core/mixins/OxyServices.devices.d.ts.map +1 -1
  68. package/lib/typescript/core/mixins/OxyServices.karma.d.ts.map +1 -1
  69. package/lib/typescript/core/mixins/OxyServices.language.d.ts.map +1 -1
  70. package/lib/typescript/core/mixins/OxyServices.location.d.ts.map +1 -1
  71. package/lib/typescript/core/mixins/OxyServices.payment.d.ts.map +1 -1
  72. package/lib/typescript/core/mixins/OxyServices.privacy.d.ts.map +1 -1
  73. package/lib/typescript/core/mixins/OxyServices.security.d.ts.map +1 -1
  74. package/lib/typescript/core/mixins/OxyServices.user.d.ts +1 -2
  75. package/lib/typescript/core/mixins/OxyServices.user.d.ts.map +1 -1
  76. package/lib/typescript/core/mixins/OxyServices.utility.d.ts.map +1 -1
  77. package/lib/typescript/core/mixins/index.d.ts +13 -13
  78. package/lib/typescript/core/mixins/index.d.ts.map +1 -1
  79. package/lib/typescript/core/services/SessionService.d.ts +1 -1
  80. package/lib/typescript/core/services/SessionService.d.ts.map +1 -1
  81. package/lib/typescript/crypto/core.d.ts +56 -0
  82. package/lib/typescript/crypto/core.d.ts.map +1 -0
  83. package/lib/typescript/crypto/index.d.ts +1 -9
  84. package/lib/typescript/crypto/index.d.ts.map +1 -1
  85. package/lib/typescript/crypto/keyManager.d.ts +13 -1
  86. package/lib/typescript/crypto/keyManager.d.ts.map +1 -1
  87. package/lib/typescript/crypto/signatureService.d.ts +15 -9
  88. package/lib/typescript/crypto/signatureService.d.ts.map +1 -1
  89. package/lib/typescript/index.d.ts +1 -1
  90. package/lib/typescript/index.d.ts.map +1 -1
  91. package/lib/typescript/models/interfaces.d.ts +68 -15
  92. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  93. package/lib/typescript/node/index.d.ts +1 -0
  94. package/lib/typescript/node/index.d.ts.map +1 -1
  95. package/lib/typescript/node/signatureService.d.ts +55 -0
  96. package/lib/typescript/node/signatureService.d.ts.map +1 -0
  97. package/lib/typescript/ui/context/OxyContext.d.ts +1 -2
  98. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  99. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts +1 -2
  100. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  101. package/lib/typescript/ui/context/hooks/useLanguageManagement.d.ts +1 -2
  102. package/lib/typescript/ui/context/hooks/useLanguageManagement.d.ts.map +1 -1
  103. package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts +1 -1
  104. package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  105. package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts +1 -1
  106. package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
  107. package/lib/typescript/ui/hooks/useLanguageManagement.d.ts +1 -2
  108. package/lib/typescript/ui/hooks/useLanguageManagement.d.ts.map +1 -1
  109. package/lib/typescript/ui/hooks/useSessionManagement.d.ts +1 -2
  110. package/lib/typescript/ui/hooks/useSessionManagement.d.ts.map +1 -1
  111. package/lib/typescript/ui/index.d.ts +1 -1
  112. package/lib/typescript/ui/index.d.ts.map +1 -1
  113. package/lib/typescript/ui/screens/OxyAuthScreen.d.ts.map +1 -1
  114. package/lib/typescript/ui/stores/authStore.d.ts +1 -1
  115. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
  116. package/lib/typescript/ui/utils/avatarUtils.d.ts +1 -1
  117. package/lib/typescript/ui/utils/avatarUtils.d.ts.map +1 -1
  118. package/package.json +6 -2
  119. package/src/core/OxyServices.base.ts +1 -2
  120. package/src/core/mixins/OxyServices.auth.ts +1 -1
  121. package/src/core/mixins/OxyServices.user.ts +1 -2
  122. package/src/core/mixins/OxyServices.utility.ts +1 -2
  123. package/src/core/services/SessionService.ts +1 -1
  124. package/src/crypto/README.md +142 -0
  125. package/src/crypto/__tests__/core.test.ts +203 -0
  126. package/src/crypto/core.ts +142 -0
  127. package/src/crypto/index.ts +3 -10
  128. package/src/crypto/keyManager.ts +25 -21
  129. package/src/crypto/signatureService.ts +137 -37
  130. package/src/index.ts +2 -1
  131. package/src/models/interfaces.ts +73 -21
  132. package/src/node/index.ts +3 -0
  133. package/src/node/signatureService.ts +126 -0
  134. package/src/ui/context/OxyContext.tsx +1 -2
  135. package/src/ui/context/hooks/useAuthOperations.ts +1 -2
  136. package/src/ui/context/hooks/useLanguageManagement.ts +1 -2
  137. package/src/ui/hooks/auth/index.ts +2 -0
  138. package/src/ui/hooks/mutations/useAccountMutations.ts +1 -1
  139. package/src/ui/hooks/mutations/useServicesMutations.ts +1 -1
  140. package/src/ui/hooks/queries/useAccountQueries.ts +1 -1
  141. package/src/ui/hooks/useLanguageManagement.ts +1 -2
  142. package/src/ui/hooks/useSessionManagement.ts +1 -2
  143. package/src/ui/index.ts +1 -2
  144. package/src/ui/screens/AccountSettingsScreen.tsx +6 -6
  145. package/src/ui/screens/AccountSwitcherScreen.tsx +1 -1
  146. package/src/ui/screens/OxyAuthScreen.tsx +9 -5
  147. package/src/ui/screens/ProfileScreen.tsx +1 -1
  148. package/src/ui/stores/authStore.ts +1 -1
  149. package/src/ui/types/navigation.ts +1 -1
  150. package/src/ui/utils/avatarUtils.ts +1 -1
  151. package/lib/commonjs/core/services/AuthService.js +0 -156
  152. package/lib/commonjs/core/services/AuthService.js.map +0 -1
  153. package/lib/commonjs/core/services/SessionTransportService.js +0 -64
  154. package/lib/commonjs/core/services/SessionTransportService.js.map +0 -1
  155. package/lib/commonjs/core/services/UserService.js +0 -123
  156. package/lib/commonjs/core/services/UserService.js.map +0 -1
  157. package/lib/commonjs/core/services/index.js +0 -34
  158. package/lib/commonjs/core/services/index.js.map +0 -1
  159. package/lib/module/core/services/AuthService.js +0 -151
  160. package/lib/module/core/services/AuthService.js.map +0 -1
  161. package/lib/module/core/services/SessionTransportService.js +0 -59
  162. package/lib/module/core/services/SessionTransportService.js.map +0 -1
  163. package/lib/module/core/services/UserService.js +0 -118
  164. package/lib/module/core/services/UserService.js.map +0 -1
  165. package/lib/module/core/services/index.js +0 -16
  166. package/lib/module/core/services/index.js.map +0 -1
  167. package/lib/typescript/core/services/AuthService.d.ts +0 -50
  168. package/lib/typescript/core/services/AuthService.d.ts.map +0 -1
  169. package/lib/typescript/core/services/SessionTransportService.d.ts +0 -31
  170. package/lib/typescript/core/services/SessionTransportService.d.ts.map +0 -1
  171. package/lib/typescript/core/services/UserService.d.ts +0 -39
  172. package/lib/typescript/core/services/UserService.d.ts.map +0 -1
  173. package/lib/typescript/core/services/index.d.ts +0 -13
  174. package/lib/typescript/core/services/index.d.ts.map +0 -1
  175. package/src/core/services/AuthService.ts +0 -153
  176. package/src/core/services/SessionTransportService.ts +0 -69
  177. package/src/core/services/UserService.ts +0 -125
  178. package/src/core/services/index.ts +0 -14
@@ -4,24 +4,88 @@
4
4
  * Handles signing and verification of messages using ECDSA secp256k1.
5
5
  * Used for authenticating requests and proving identity ownership.
6
6
  *
7
- * Note: This service handles SIGNING (requires private key access via KeyManager).
8
- * For VERIFICATION, use @oxyhq/shared SignatureService instead.
7
+ * This service provides async methods for cross-platform compatibility (React Native + Node).
8
+ * For Node.js-only synchronous operations, use the node/signatureService module.
9
9
  */
10
10
 
11
- import { ec as EC } from 'elliptic';
12
11
  import { KeyManager } from './keyManager';
13
12
  import {
13
+ verifySignatureCore,
14
+ isValidPublicKey as validatePublicKey,
15
+ isTimestampFresh,
14
16
  buildAuthMessage,
15
17
  buildRegistrationMessage,
16
18
  buildRequestMessage,
17
- getCryptoAdapter,
18
- type SignedMessage,
19
- } from '@oxyhq/shared';
19
+ shortenPublicKey as shortenKey,
20
+ getEllipticCurve,
21
+ } from './core';
20
22
 
21
- const ec = new EC('secp256k1');
23
+ // Lazy import for expo-crypto
24
+ let ExpoCrypto: typeof import('expo-crypto') | null = null;
22
25
 
23
- // Re-export shared types
24
- export type { SignedMessage } from '@oxyhq/shared';
26
+ const ec = getEllipticCurve();
27
+
28
+ /**
29
+ * Check if we're in a React Native environment
30
+ */
31
+ function isReactNative(): boolean {
32
+ return typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
33
+ }
34
+
35
+ /**
36
+ * Check if we're in a Node.js environment
37
+ */
38
+ function isNodeJS(): boolean {
39
+ return typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
40
+ }
41
+
42
+ /**
43
+ * Initialize expo-crypto module
44
+ */
45
+ async function initExpoCrypto(): Promise<typeof import('expo-crypto')> {
46
+ if (!ExpoCrypto) {
47
+ ExpoCrypto = await import('expo-crypto');
48
+ }
49
+ return ExpoCrypto;
50
+ }
51
+
52
+ /**
53
+ * Compute SHA-256 hash of a string
54
+ */
55
+ async function sha256(message: string): Promise<string> {
56
+ // In React Native, always use expo-crypto
57
+ if (isReactNative() || !isNodeJS()) {
58
+ const Crypto = await initExpoCrypto();
59
+ return Crypto.digestStringAsync(
60
+ Crypto.CryptoDigestAlgorithm.SHA256,
61
+ message
62
+ );
63
+ }
64
+
65
+ // In Node.js, use Node's crypto module
66
+ // Use Function constructor to prevent Metro bundler from statically analyzing this require
67
+ // This ensures the require is only evaluated in Node.js runtime, not during Metro bundling
68
+ try {
69
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
70
+ const getCrypto = new Function('return require("crypto")');
71
+ const crypto = getCrypto();
72
+ return crypto.createHash('sha256').update(message).digest('hex');
73
+ } catch (error) {
74
+ // Fallback to expo-crypto if Node crypto fails
75
+ const Crypto = await initExpoCrypto();
76
+ return Crypto.digestStringAsync(
77
+ Crypto.CryptoDigestAlgorithm.SHA256,
78
+ message
79
+ );
80
+ }
81
+ }
82
+
83
+ export interface SignedMessage {
84
+ message: string;
85
+ signature: string;
86
+ publicKey: string;
87
+ timestamp: number;
88
+ }
25
89
 
26
90
  export interface AuthChallenge {
27
91
  challenge: string;
@@ -32,23 +96,39 @@ export interface AuthChallenge {
32
96
  export class SignatureService {
33
97
  /**
34
98
  * Generate a random challenge string (for offline use)
35
- * Uses shared crypto adapter
99
+ * Uses expo-crypto in React Native, crypto.randomBytes in Node.js
36
100
  */
37
101
  static async generateChallenge(): Promise<string> {
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('');
102
+ if (isReactNative() || !isNodeJS()) {
103
+ // Use expo-crypto for React Native (expo-random is deprecated)
104
+ const Crypto = await initExpoCrypto();
105
+ const randomBytes = await Crypto.getRandomBytesAsync(32);
106
+ return Array.from(randomBytes)
107
+ .map((b: number) => b.toString(16).padStart(2, '0'))
108
+ .join('');
109
+ }
110
+
111
+ // Node.js fallback
112
+ try {
113
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
114
+ const getCrypto = new Function('return require("crypto")');
115
+ const crypto = getCrypto();
116
+ return crypto.randomBytes(32).toString('hex');
117
+ } catch (error) {
118
+ // Fallback to expo-crypto if Node crypto fails
119
+ const Crypto = await initExpoCrypto();
120
+ const randomBytes = await Crypto.getRandomBytesAsync(32);
121
+ return Array.from(randomBytes)
122
+ .map((b: number) => b.toString(16).padStart(2, '0'))
123
+ .join('');
124
+ }
43
125
  }
44
126
 
45
127
  /**
46
128
  * Hash a message using SHA-256
47
- * Uses shared crypto adapter
48
129
  */
49
130
  static async hashMessage(message: string): Promise<string> {
50
- const adapter = await getCryptoAdapter();
51
- return adapter.sha256(message);
131
+ return sha256(message);
52
132
  }
53
133
 
54
134
  /**
@@ -61,8 +141,7 @@ export class SignatureService {
61
141
  throw new Error('No identity found. Please create or import an identity first.');
62
142
  }
63
143
 
64
- const adapter = await getCryptoAdapter();
65
- const messageHash = await adapter.sha256(message);
144
+ const messageHash = await sha256(message);
66
145
  const signature = keyPair.sign(messageHash);
67
146
  return signature.toDER('hex');
68
147
  }
@@ -73,19 +152,43 @@ export class SignatureService {
73
152
  */
74
153
  static async signWithKey(message: string, privateKey: string): Promise<string> {
75
154
  const keyPair = ec.keyFromPrivate(privateKey);
76
- const adapter = await getCryptoAdapter();
77
- const messageHash = await adapter.sha256(message);
155
+ const messageHash = await sha256(message);
78
156
  const signature = keyPair.sign(messageHash);
79
157
  return signature.toDER('hex');
80
158
  }
81
159
 
82
160
  /**
83
161
  * Verify a signature against a message and public key
84
- * Uses shared SignatureService for verification
85
162
  */
86
163
  static async verify(message: string, signature: string, publicKey: string): Promise<boolean> {
87
- const { SignatureService: SharedSignatureService } = await import('@oxyhq/shared');
88
- return SharedSignatureService.verify(message, signature, publicKey);
164
+ try {
165
+ const messageHash = await sha256(message);
166
+ return verifySignatureCore(messageHash, signature, publicKey);
167
+ } catch {
168
+ return false;
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Synchronous verification (for Node.js backend)
174
+ * Uses crypto module directly for hashing
175
+ * Note: This method should only be used in Node.js environments
176
+ */
177
+ static verifySync(message: string, signature: string, publicKey: string): boolean {
178
+ try {
179
+ if (!isNodeJS()) {
180
+ // In React Native, use async verify instead
181
+ throw new Error('verifySync should only be used in Node.js. Use verify() in React Native.');
182
+ }
183
+ // Use Function constructor to prevent Metro bundler from statically analyzing this require
184
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
185
+ const getCrypto = new Function('return require("crypto")');
186
+ const crypto = getCrypto();
187
+ const messageHash = crypto.createHash('sha256').update(message).digest('hex');
188
+ return verifySignatureCore(messageHash, signature, publicKey);
189
+ } catch {
190
+ return false;
191
+ }
89
192
  }
90
193
 
91
194
  /**
@@ -112,13 +215,11 @@ export class SignatureService {
112
215
  /**
113
216
  * Verify a signed message object
114
217
  * Checks both signature validity and timestamp freshness
115
- * Uses shared SignatureService for verification
116
218
  */
117
219
  static async verifySignedMessage(
118
220
  signedMessage: SignedMessage,
119
221
  maxAgeMs: number = 5 * 60 * 1000 // 5 minutes default
120
222
  ): Promise<boolean> {
121
- const { SignatureService: SharedSignatureService, isTimestampFresh } = await import('@oxyhq/shared');
122
223
  const { message, signature, publicKey, timestamp } = signedMessage;
123
224
 
124
225
  // Check timestamp freshness
@@ -128,7 +229,7 @@ export class SignatureService {
128
229
 
129
230
  // Verify signature
130
231
  const messageWithTimestamp = `${message}:${timestamp}`;
131
- return SharedSignatureService.verify(messageWithTimestamp, signature, publicKey);
232
+ return SignatureService.verify(messageWithTimestamp, signature, publicKey);
132
233
  }
133
234
 
134
235
  /**
@@ -154,22 +255,21 @@ export class SignatureService {
154
255
 
155
256
  /**
156
257
  * Verify a challenge response
157
- * Uses shared SignatureService for verification
158
258
  */
159
259
  static async verifyChallengeResponse(
160
260
  originalChallenge: string,
161
261
  response: AuthChallenge,
162
262
  maxAgeMs: number = 5 * 60 * 1000
163
263
  ): Promise<boolean> {
164
- const { SignatureService: SharedSignatureService } = await import('@oxyhq/shared');
165
264
  const { challenge: signature, publicKey, timestamp } = response;
166
- return SharedSignatureService.verifyChallengeResponse(
167
- publicKey,
168
- originalChallenge,
169
- signature,
170
- timestamp,
171
- maxAgeMs
172
- );
265
+
266
+ // Check timestamp freshness
267
+ if (!isTimestampFresh(timestamp, maxAgeMs)) {
268
+ return false;
269
+ }
270
+
271
+ const message = buildAuthMessage(publicKey, originalChallenge, timestamp);
272
+ return SignatureService.verify(message, signature, publicKey);
173
273
  }
174
274
 
175
275
  /**
package/src/index.ts CHANGED
@@ -49,9 +49,10 @@ 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
53
52
  export type {
54
53
  OxyConfig,
54
+ User,
55
+ LoginResponse,
55
56
  Notification,
56
57
  Wallet,
57
58
  Transaction,
@@ -1,12 +1,3 @@
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
-
10
1
  export interface OxyConfig {
11
2
  baseURL: string;
12
3
  cloudURL?: string;
@@ -30,8 +21,65 @@ export interface OxyConfig {
30
21
  onRequestError?: (url: string, method: string, error: Error) => void;
31
22
  }
32
23
 
33
- // Note: User and LoginResponse are in @oxyhq/shared
34
- // Import them directly: import { User, LoginResponse } from '@oxyhq/shared';
24
+ /**
25
+ * User Model
26
+ *
27
+ * IMPORTANT:
28
+ * - id: MongoDB ObjectId (24 hex characters) - PRIMARY IDENTIFIER for all internal operations
29
+ * - publicKey: Cryptographic public key (130 hex characters) - LOOKUP KEY for authentication and identity operations
30
+ *
31
+ * Never use publicKey as an ID. Always use id (ObjectId) for:
32
+ * - Database queries
33
+ * - Session userId
34
+ * - Token userId
35
+ * - Socket room names
36
+ * - API route parameters (unless explicitly doing publicKey lookup)
37
+ */
38
+ export interface User {
39
+ id: string; // MongoDB ObjectId - PRIMARY IDENTIFIER (always 24 hex chars)
40
+ publicKey: string; // Cryptographic public key - LOOKUP KEY (130 hex chars for secp256k1)
41
+ username: string;
42
+ email?: string;
43
+ // Avatar file id (asset id)
44
+ avatar?: string;
45
+ // Privacy and security settings
46
+ privacySettings?: {
47
+ [key: string]: unknown;
48
+ };
49
+ name?: {
50
+ first?: string;
51
+ last?: string;
52
+ full?: string; // virtual, not stored in DB, returned by API
53
+ [key: string]: unknown;
54
+ };
55
+ bio?: string;
56
+ karma?: number;
57
+ location?: string;
58
+ website?: string;
59
+ createdAt?: string;
60
+ updatedAt?: string;
61
+ links?: Array<{
62
+ title?: string;
63
+ description?: string;
64
+ image?: string;
65
+ link: string;
66
+ }>;
67
+ // Social counts
68
+ _count?: {
69
+ followers?: number;
70
+ following?: number;
71
+ };
72
+ accountExpiresAfterInactivityDays?: number | null; // Days of inactivity before account expires (null = never expire)
73
+ [key: string]: unknown;
74
+ }
75
+
76
+ export interface LoginResponse {
77
+ accessToken?: string;
78
+ refreshToken?: string;
79
+ token?: string; // For backwards compatibility
80
+ user: User;
81
+ message?: string;
82
+ }
35
83
 
36
84
  export interface Notification {
37
85
  id: string;
@@ -104,8 +152,17 @@ export interface TransactionResponse {
104
152
  transaction: Transaction;
105
153
  }
106
154
 
107
- // Note: PaginationInfo and SearchProfilesResponse are in @oxyhq/shared
108
- // Import them directly: import { PaginationInfo, SearchProfilesResponse } from '@oxyhq/shared';
155
+ export interface PaginationInfo {
156
+ total: number;
157
+ limit: number;
158
+ offset: number;
159
+ hasMore: boolean;
160
+ }
161
+
162
+ export interface SearchProfilesResponse {
163
+ data: User[];
164
+ pagination: PaginationInfo;
165
+ }
109
166
 
110
167
  export interface KarmaRule {
111
168
  id: string;
@@ -318,6 +375,8 @@ export interface AssetUrlResponse {
318
375
 
319
376
  export interface AssetDeleteSummary {
320
377
  fileId: string;
378
+ wouldDelete: boolean;
379
+ affectedApps: string[];
321
380
  remainingLinks: number;
322
381
  variants: string[];
323
382
  }
@@ -435,7 +494,6 @@ export interface AssetUploadProgress {
435
494
  }
436
495
 
437
496
  // Device Session interfaces
438
- // Note: User type should be imported from @oxyhq/shared
439
497
  export interface DeviceSession {
440
498
  sessionId: string;
441
499
  deviceId: string;
@@ -444,13 +502,7 @@ export interface DeviceSession {
444
502
  lastActive: string;
445
503
  expiresAt: string;
446
504
  isCurrent: boolean;
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
505
+ user?: User;
454
506
  createdAt?: string;
455
507
  }
456
508
 
package/src/node/index.ts CHANGED
@@ -13,5 +13,8 @@ export { OxyServices, OXY_CLOUD_URL, oxyClient };
13
13
  export { Models }; // Export all models as a namespace
14
14
  export * from '../models/interfaces'; // Export all models directly
15
15
 
16
+ // ------------- Node-Specific Crypto Exports -------------
17
+ export { SignatureService } from './signatureService';
18
+
16
19
  // Default export for consistency or specific use cases if needed
17
20
  export default OxyServices;
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Node.js Signature Service
3
+ *
4
+ * Provides synchronous signature operations for Node.js backend.
5
+ * Uses Node's crypto module for hashing and the shared core for verification.
6
+ */
7
+
8
+ import crypto from 'crypto';
9
+ import {
10
+ verifySignatureCore,
11
+ isValidPublicKey,
12
+ isTimestampFresh,
13
+ buildAuthMessage,
14
+ buildRegistrationMessage,
15
+ buildRequestMessage,
16
+ shortenPublicKey,
17
+ CHALLENGE_TTL_MS,
18
+ MAX_SIGNATURE_AGE_MS,
19
+ } from '../crypto/core';
20
+
21
+ export class SignatureService {
22
+ /**
23
+ * Generate a random challenge string
24
+ */
25
+ static generateChallenge(): string {
26
+ return crypto.randomBytes(32).toString('hex');
27
+ }
28
+
29
+ /**
30
+ * Compute SHA-256 hash of a message (synchronous)
31
+ */
32
+ static hashMessage(message: string): string {
33
+ return crypto.createHash('sha256').update(message).digest('hex');
34
+ }
35
+
36
+ /**
37
+ * Verify an ECDSA signature (synchronous)
38
+ *
39
+ * @param message - The original message that was signed
40
+ * @param signature - The signature in DER format (hex encoded)
41
+ * @param publicKey - The public key (hex encoded, uncompressed)
42
+ * @returns true if the signature is valid
43
+ */
44
+ static verifySignature(message: string, signature: string, publicKey: string): boolean {
45
+ const messageHash = SignatureService.hashMessage(message);
46
+ return verifySignatureCore(messageHash, signature, publicKey);
47
+ }
48
+
49
+ /**
50
+ * Verify an authentication challenge response
51
+ *
52
+ * @param publicKey - The user's public key
53
+ * @param challenge - The original challenge string
54
+ * @param signature - The signature of the auth message
55
+ * @param timestamp - The timestamp when the signature was created
56
+ * @returns true if the challenge response is valid
57
+ */
58
+ static verifyChallengeResponse(
59
+ publicKey: string,
60
+ challenge: string,
61
+ signature: string,
62
+ timestamp: number
63
+ ): boolean {
64
+ // Check timestamp is not too old
65
+ if (!isTimestampFresh(timestamp, CHALLENGE_TTL_MS)) {
66
+ return false;
67
+ }
68
+
69
+ // Build the message and verify signature
70
+ const message = buildAuthMessage(publicKey, challenge, timestamp);
71
+ return SignatureService.verifySignature(message, signature, publicKey);
72
+ }
73
+
74
+ /**
75
+ * Verify a registration signature
76
+ * Signature format: oxy:register:{publicKey}:{timestamp}
77
+ */
78
+ static verifyRegistrationSignature(
79
+ publicKey: string,
80
+ signature: string,
81
+ timestamp: number
82
+ ): boolean {
83
+ // Check timestamp freshness
84
+ if (!isTimestampFresh(timestamp, MAX_SIGNATURE_AGE_MS)) {
85
+ return false;
86
+ }
87
+
88
+ const message = buildRegistrationMessage(publicKey, timestamp);
89
+ return SignatureService.verifySignature(message, signature, publicKey);
90
+ }
91
+
92
+ /**
93
+ * Verify a signed request
94
+ * Used for authenticated API operations
95
+ */
96
+ static verifyRequestSignature(
97
+ publicKey: string,
98
+ data: Record<string, unknown>,
99
+ signature: string,
100
+ timestamp: number
101
+ ): boolean {
102
+ // Check timestamp freshness
103
+ if (!isTimestampFresh(timestamp, MAX_SIGNATURE_AGE_MS)) {
104
+ return false;
105
+ }
106
+
107
+ const message = buildRequestMessage(publicKey, timestamp, data);
108
+ return SignatureService.verifySignature(message, signature, publicKey);
109
+ }
110
+
111
+ /**
112
+ * Validate that a string is a valid public key
113
+ */
114
+ static isValidPublicKey(publicKey: string): boolean {
115
+ return isValidPublicKey(publicKey);
116
+ }
117
+
118
+ /**
119
+ * Get a shortened display version of a public key
120
+ */
121
+ static shortenPublicKey(publicKey: string): string {
122
+ return shortenPublicKey(publicKey);
123
+ }
124
+ }
125
+
126
+ export default SignatureService;
@@ -11,8 +11,7 @@ import {
11
11
  } from 'react';
12
12
  import { Platform } from 'react-native';
13
13
  import { OxyServices } from '../../core';
14
- import type { ApiError } from '../../models/interfaces';
15
- import type { User } from '@oxyhq/shared';
14
+ import type { User, ApiError } from '../../models/interfaces';
16
15
  import type { ClientSession } from '../../models/session';
17
16
  import { toast } from '../../lib/sonner';
18
17
  import { useAuthStore, type AuthState } from '../stores/authStore';
@@ -1,6 +1,5 @@
1
1
  import { useCallback } from 'react';
2
- import type { ApiError } from '../../../models/interfaces';
3
- import type { User } from '@oxyhq/shared';
2
+ import type { ApiError, User } from '../../../models/interfaces';
4
3
  import type { AuthState } from '../../stores/authStore';
5
4
  import type { ClientSession, SessionLoginResponse } from '../../../models/session';
6
5
  import { DeviceManager } from '../../../utils/deviceManager';
@@ -1,6 +1,5 @@
1
1
  import { useCallback, useEffect, useMemo, useState } from 'react';
2
- import type { ApiError } from '../../../models/interfaces';
3
- import type { User } from '@oxyhq/shared';
2
+ import type { ApiError, User } from '../../../models/interfaces';
4
3
  import {
5
4
  getLanguageMetadata,
6
5
  getLanguageName,
@@ -4,3 +4,5 @@
4
4
  export { useUsernameValidation, USERNAME_MIN_LENGTH, USERNAME_REGEX, USERNAME_FORMAT_ERROR, USERNAME_DEBOUNCE_MS } from './useUsernameValidation';
5
5
  export type { UsernameValidationResult } from './useUsernameValidation';
6
6
 
7
+
8
+
@@ -1,5 +1,5 @@
1
1
  import { useMutation, useQueryClient } from '@tanstack/react-query';
2
- import type { User } from '@oxyhq/shared';
2
+ import type { User } from '../../../models/interfaces';
3
3
  import { queryKeys, invalidateAccountQueries, invalidateUserQueries } from '../queries/queryKeys';
4
4
  import { useOxy } from '../../context/OxyContext';
5
5
  import { toast } from '../../../lib/sonner';
@@ -1,5 +1,5 @@
1
1
  import { useMutation, useQueryClient } from '@tanstack/react-query';
2
- import type { User } from '@oxyhq/shared';
2
+ import type { User } from '../../../models/interfaces';
3
3
  import { queryKeys, invalidateSessionQueries } from '../queries/queryKeys';
4
4
  import { useOxy } from '../../context/OxyContext';
5
5
  import { toast } from '../../../lib/sonner';
@@ -1,5 +1,5 @@
1
1
  import { useQuery, useQueries } from '@tanstack/react-query';
2
- import type { User } from '@oxyhq/shared';
2
+ import type { User } from '../../../models/interfaces';
3
3
  import type { OxyServices } from '../../../core';
4
4
  import { queryKeys } from './queryKeys';
5
5
  import { useOxy } from '../../context/OxyContext';
@@ -1,6 +1,5 @@
1
1
  import { useCallback, useEffect, useMemo, useState } from 'react';
2
- import type { ApiError } from '../../models/interfaces';
3
- import type { User } from '@oxyhq/shared';
2
+ import type { ApiError, User } from '../../models/interfaces';
4
3
  import {
5
4
  getLanguageMetadata,
6
5
  getLanguageName,
@@ -1,6 +1,5 @@
1
1
  import { useCallback, useMemo, useRef, useState } from 'react';
2
- import type { ApiError } from '../../models/interfaces';
3
- import type { User } from '@oxyhq/shared';
2
+ import type { ApiError, User } from '../../models/interfaces';
4
3
  import type { ClientSession } from '../../models/session';
5
4
  import { mergeSessions, normalizeAndSortSessions, sessionsArraysEqual } from '../../utils/sessionUtils';
6
5
  import { fetchSessionsWithFallback, mapSessionsToClient, validateSessionBatch } from '../utils/sessionHelpers';
package/src/ui/index.ts CHANGED
@@ -81,5 +81,4 @@ export {
81
81
 
82
82
  // Re-export core services for convenience in UI context
83
83
  export { OxyServices } from '../core';
84
- // Note: User and LoginResponse should be imported from @oxyhq/shared
85
- export type { ApiError } from '../models/interfaces';
84
+ export type { User, LoginResponse, ApiError } from '../models/interfaces';
@@ -233,7 +233,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
233
233
 
234
234
  // Handle locations - convert single location to array format
235
235
  if (finalUser.locations && Array.isArray(finalUser.locations)) {
236
- setLocations(finalUser.locations.map((loc: any, index: number) => ({
236
+ setLocations(finalUser.locations.map((loc, index) => ({
237
237
  id: loc.id || `existing-${index}`,
238
238
  name: loc.name,
239
239
  label: loc.label,
@@ -252,17 +252,17 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
252
252
 
253
253
  // Handle links - simple and direct like other fields
254
254
  if (finalUser.linksMetadata && Array.isArray(finalUser.linksMetadata)) {
255
- const urls = finalUser.linksMetadata.map((l: any) => l.url);
255
+ const urls = finalUser.linksMetadata.map(l => l.url);
256
256
  setLinks(urls);
257
- const metadataWithIds = finalUser.linksMetadata.map((link: any, index: number) => ({
257
+ const metadataWithIds = finalUser.linksMetadata.map((link, index) => ({
258
258
  ...link,
259
259
  id: link.id || `existing-${index}`
260
260
  }));
261
261
  setLinksMetadata(metadataWithIds);
262
262
  } else if (Array.isArray(finalUser.links)) {
263
- const simpleLinks = finalUser.links.map((l: any) => typeof l === 'string' ? l : l.link).filter(Boolean);
263
+ const simpleLinks = finalUser.links.map(l => typeof l === 'string' ? l : l.link).filter(Boolean);
264
264
  setLinks(simpleLinks);
265
- const linksWithMetadata = simpleLinks.map((url: string, index: number) => ({
265
+ const linksWithMetadata = simpleLinks.map((url, index) => ({
266
266
  url,
267
267
  title: url.replace(/^https?:\/\//, '').replace(/\/$/, ''),
268
268
  description: `Link to ${url}`,
@@ -553,7 +553,7 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
553
553
  }
554
554
 
555
555
  if (currentUser.linksMetadata && Array.isArray(currentUser.linksMetadata)) {
556
- setLinksMetadata(currentUser.linksMetadata.map((link: any, index: number) => ({
556
+ setLinksMetadata(currentUser.linksMetadata.map((link, index) => ({
557
557
  ...link,
558
558
  id: link.id || `existing-${index}`
559
559
  })));
@@ -15,7 +15,7 @@ import {
15
15
  import type { BaseScreenProps } from '../types/navigation';
16
16
  import type { ClientSession } from '../../models/session';
17
17
  import { fontFamilies } from '../styles/fonts';
18
- import type { User } from '@oxyhq/shared';
18
+ import type { User } from '../../models/interfaces';
19
19
  import { toast } from '../../lib/sonner';
20
20
  import { confirmAction } from '../utils/confirmAction';
21
21
  import OxyIcon from '../components/icon/OxyIcon';