@oxyhq/services 5.16.35 → 5.16.37

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 (232) 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 -22
  11. package/lib/commonjs/crypto/keyManager.js.map +1 -1
  12. package/lib/commonjs/crypto/signatureService.js +116 -28
  13. package/lib/commonjs/crypto/signatureService.js.map +1 -1
  14. package/lib/commonjs/index.js +0 -12
  15. package/lib/commonjs/index.js.map +1 -1
  16. package/lib/commonjs/models/interfaces.js +10 -11
  17. package/lib/commonjs/models/interfaces.js.map +1 -1
  18. package/lib/commonjs/node/index.js +10 -1
  19. package/lib/commonjs/node/index.js.map +1 -1
  20. package/lib/commonjs/node/signatureService.js +107 -0
  21. package/lib/commonjs/node/signatureService.js.map +1 -0
  22. package/lib/commonjs/ui/context/OxyContext.js +23 -0
  23. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  24. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +29 -2
  25. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  26. package/lib/commonjs/ui/context/hooks/useLanguageManagement.js.map +1 -1
  27. package/lib/commonjs/ui/hooks/useLanguageManagement.js.map +1 -1
  28. package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
  29. package/lib/commonjs/ui/index.js +0 -2
  30. package/lib/commonjs/ui/index.js.map +1 -1
  31. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  32. package/lib/commonjs/ui/screens/OxyAuthScreen.js +11 -2
  33. package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +1 -1
  34. package/lib/module/core/OxyServices.base.js.map +1 -1
  35. package/lib/module/core/mixins/OxyServices.user.js.map +1 -1
  36. package/lib/module/core/mixins/OxyServices.utility.js.map +1 -1
  37. package/lib/module/crypto/README.md +142 -0
  38. package/lib/module/crypto/core.js +133 -0
  39. package/lib/module/crypto/core.js.map +1 -0
  40. package/lib/module/crypto/index.js +3 -9
  41. package/lib/module/crypto/index.js.map +1 -1
  42. package/lib/module/crypto/keyManager.js +19 -22
  43. package/lib/module/crypto/keyManager.js.map +1 -1
  44. package/lib/module/crypto/signatureService.js +113 -23
  45. package/lib/module/crypto/signatureService.js.map +1 -1
  46. package/lib/module/index.js +0 -2
  47. package/lib/module/index.js.map +1 -1
  48. package/lib/module/models/interfaces.js +10 -11
  49. package/lib/module/models/interfaces.js.map +1 -1
  50. package/lib/module/node/index.js +3 -0
  51. package/lib/module/node/index.js.map +1 -1
  52. package/lib/module/node/signatureService.js +101 -0
  53. package/lib/module/node/signatureService.js.map +1 -0
  54. package/lib/module/ui/context/OxyContext.js +23 -0
  55. package/lib/module/ui/context/OxyContext.js.map +1 -1
  56. package/lib/module/ui/context/hooks/useAuthOperations.js +29 -2
  57. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  58. package/lib/module/ui/context/hooks/useLanguageManagement.js.map +1 -1
  59. package/lib/module/ui/hooks/useLanguageManagement.js.map +1 -1
  60. package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
  61. package/lib/module/ui/index.js +0 -1
  62. package/lib/module/ui/index.js.map +1 -1
  63. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  64. package/lib/module/ui/screens/OxyAuthScreen.js +11 -2
  65. package/lib/module/ui/screens/OxyAuthScreen.js.map +1 -1
  66. package/lib/typescript/core/OxyServices.base.d.ts.map +1 -1
  67. package/lib/typescript/core/mixins/OxyServices.analytics.d.ts.map +1 -1
  68. package/lib/typescript/core/mixins/OxyServices.assets.d.ts.map +1 -1
  69. package/lib/typescript/core/mixins/OxyServices.auth.d.ts +1 -1
  70. package/lib/typescript/core/mixins/OxyServices.auth.d.ts.map +1 -1
  71. package/lib/typescript/core/mixins/OxyServices.developer.d.ts.map +1 -1
  72. package/lib/typescript/core/mixins/OxyServices.devices.d.ts.map +1 -1
  73. package/lib/typescript/core/mixins/OxyServices.karma.d.ts.map +1 -1
  74. package/lib/typescript/core/mixins/OxyServices.language.d.ts.map +1 -1
  75. package/lib/typescript/core/mixins/OxyServices.location.d.ts.map +1 -1
  76. package/lib/typescript/core/mixins/OxyServices.payment.d.ts.map +1 -1
  77. package/lib/typescript/core/mixins/OxyServices.privacy.d.ts.map +1 -1
  78. package/lib/typescript/core/mixins/OxyServices.security.d.ts.map +1 -1
  79. package/lib/typescript/core/mixins/OxyServices.user.d.ts +1 -2
  80. package/lib/typescript/core/mixins/OxyServices.user.d.ts.map +1 -1
  81. package/lib/typescript/core/mixins/OxyServices.utility.d.ts.map +1 -1
  82. package/lib/typescript/core/mixins/index.d.ts +13 -13
  83. package/lib/typescript/core/mixins/index.d.ts.map +1 -1
  84. package/lib/typescript/core/services/SessionService.d.ts +1 -1
  85. package/lib/typescript/core/services/SessionService.d.ts.map +1 -1
  86. package/lib/typescript/crypto/core.d.ts +56 -0
  87. package/lib/typescript/crypto/core.d.ts.map +1 -0
  88. package/lib/typescript/crypto/index.d.ts +1 -9
  89. package/lib/typescript/crypto/index.d.ts.map +1 -1
  90. package/lib/typescript/crypto/keyManager.d.ts +13 -1
  91. package/lib/typescript/crypto/keyManager.d.ts.map +1 -1
  92. package/lib/typescript/crypto/signatureService.d.ts +15 -9
  93. package/lib/typescript/crypto/signatureService.d.ts.map +1 -1
  94. package/lib/typescript/index.d.ts +1 -2
  95. package/lib/typescript/index.d.ts.map +1 -1
  96. package/lib/typescript/models/interfaces.d.ts +68 -15
  97. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  98. package/lib/typescript/node/index.d.ts +1 -0
  99. package/lib/typescript/node/index.d.ts.map +1 -1
  100. package/lib/typescript/node/signatureService.d.ts +55 -0
  101. package/lib/typescript/node/signatureService.d.ts.map +1 -0
  102. package/lib/typescript/ui/context/OxyContext.d.ts +1 -2
  103. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  104. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts +1 -2
  105. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  106. package/lib/typescript/ui/context/hooks/useLanguageManagement.d.ts +1 -2
  107. package/lib/typescript/ui/context/hooks/useLanguageManagement.d.ts.map +1 -1
  108. package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts +1 -1
  109. package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  110. package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts +1 -1
  111. package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
  112. package/lib/typescript/ui/hooks/useLanguageManagement.d.ts +1 -2
  113. package/lib/typescript/ui/hooks/useLanguageManagement.d.ts.map +1 -1
  114. package/lib/typescript/ui/hooks/useSessionManagement.d.ts +1 -2
  115. package/lib/typescript/ui/hooks/useSessionManagement.d.ts.map +1 -1
  116. package/lib/typescript/ui/index.d.ts +1 -1
  117. package/lib/typescript/ui/index.d.ts.map +1 -1
  118. package/lib/typescript/ui/screens/OxyAuthScreen.d.ts.map +1 -1
  119. package/lib/typescript/ui/stores/authStore.d.ts +1 -1
  120. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
  121. package/lib/typescript/ui/utils/avatarUtils.d.ts +1 -1
  122. package/lib/typescript/ui/utils/avatarUtils.d.ts.map +1 -1
  123. package/package.json +6 -1
  124. package/src/core/OxyServices.base.ts +1 -2
  125. package/src/core/mixins/OxyServices.auth.ts +1 -1
  126. package/src/core/mixins/OxyServices.user.ts +1 -2
  127. package/src/core/mixins/OxyServices.utility.ts +1 -2
  128. package/src/core/services/SessionService.ts +1 -1
  129. package/src/crypto/README.md +142 -0
  130. package/src/crypto/__tests__/core.test.ts +203 -0
  131. package/src/crypto/core.ts +142 -0
  132. package/src/crypto/index.ts +3 -10
  133. package/src/crypto/keyManager.ts +25 -21
  134. package/src/crypto/signatureService.ts +137 -36
  135. package/src/index.ts +2 -3
  136. package/src/models/interfaces.ts +73 -21
  137. package/src/node/index.ts +3 -0
  138. package/src/node/signatureService.ts +126 -0
  139. package/src/ui/context/OxyContext.tsx +26 -2
  140. package/src/ui/context/hooks/useAuthOperations.ts +33 -4
  141. package/src/ui/context/hooks/useLanguageManagement.ts +1 -2
  142. package/src/ui/hooks/auth/index.ts +2 -0
  143. package/src/ui/hooks/mutations/useAccountMutations.ts +1 -1
  144. package/src/ui/hooks/mutations/useServicesMutations.ts +1 -1
  145. package/src/ui/hooks/queries/useAccountQueries.ts +1 -1
  146. package/src/ui/hooks/useLanguageManagement.ts +1 -2
  147. package/src/ui/hooks/useSessionManagement.ts +1 -2
  148. package/src/ui/index.ts +1 -2
  149. package/src/ui/screens/AccountSettingsScreen.tsx +6 -6
  150. package/src/ui/screens/AccountSwitcherScreen.tsx +1 -1
  151. package/src/ui/screens/OxyAuthScreen.tsx +11 -2
  152. package/src/ui/screens/ProfileScreen.tsx +1 -1
  153. package/src/ui/stores/authStore.ts +1 -1
  154. package/src/ui/types/navigation.ts +1 -1
  155. package/src/ui/utils/avatarUtils.ts +1 -1
  156. package/lib/commonjs/core/services/AuthService.js +0 -156
  157. package/lib/commonjs/core/services/AuthService.js.map +0 -1
  158. package/lib/commonjs/core/services/SessionTransportService.js +0 -64
  159. package/lib/commonjs/core/services/SessionTransportService.js.map +0 -1
  160. package/lib/commonjs/core/services/UserService.js +0 -123
  161. package/lib/commonjs/core/services/UserService.js.map +0 -1
  162. package/lib/commonjs/core/services/index.js +0 -34
  163. package/lib/commonjs/core/services/index.js.map +0 -1
  164. package/lib/commonjs/shared/crypto/messageBuilders.js +0 -79
  165. package/lib/commonjs/shared/crypto/messageBuilders.js.map +0 -1
  166. package/lib/commonjs/shared/crypto/platform.js +0 -118
  167. package/lib/commonjs/shared/crypto/platform.js.map +0 -1
  168. package/lib/commonjs/shared/crypto/signature.js +0 -191
  169. package/lib/commonjs/shared/crypto/signature.js.map +0 -1
  170. package/lib/commonjs/shared/index.js +0 -94
  171. package/lib/commonjs/shared/index.js.map +0 -1
  172. package/lib/commonjs/shared/models/index.js +0 -2
  173. package/lib/commonjs/shared/models/index.js.map +0 -1
  174. package/lib/commonjs/shared/transport/index.js +0 -260
  175. package/lib/commonjs/shared/transport/index.js.map +0 -1
  176. package/lib/commonjs/shared/utils/index.js +0 -82
  177. package/lib/commonjs/shared/utils/index.js.map +0 -1
  178. package/lib/module/core/services/AuthService.js +0 -151
  179. package/lib/module/core/services/AuthService.js.map +0 -1
  180. package/lib/module/core/services/SessionTransportService.js +0 -59
  181. package/lib/module/core/services/SessionTransportService.js.map +0 -1
  182. package/lib/module/core/services/UserService.js +0 -118
  183. package/lib/module/core/services/UserService.js.map +0 -1
  184. package/lib/module/core/services/index.js +0 -16
  185. package/lib/module/core/services/index.js.map +0 -1
  186. package/lib/module/shared/crypto/messageBuilders.js +0 -70
  187. package/lib/module/shared/crypto/messageBuilders.js.map +0 -1
  188. package/lib/module/shared/crypto/platform.js +0 -112
  189. package/lib/module/shared/crypto/platform.js.map +0 -1
  190. package/lib/module/shared/crypto/signature.js +0 -186
  191. package/lib/module/shared/crypto/signature.js.map +0 -1
  192. package/lib/module/shared/index.js +0 -30
  193. package/lib/module/shared/index.js.map +0 -1
  194. package/lib/module/shared/models/index.js +0 -2
  195. package/lib/module/shared/models/index.js.map +0 -1
  196. package/lib/module/shared/transport/index.js +0 -254
  197. package/lib/module/shared/transport/index.js.map +0 -1
  198. package/lib/module/shared/utils/index.js +0 -74
  199. package/lib/module/shared/utils/index.js.map +0 -1
  200. package/lib/typescript/core/services/AuthService.d.ts +0 -50
  201. package/lib/typescript/core/services/AuthService.d.ts.map +0 -1
  202. package/lib/typescript/core/services/SessionTransportService.d.ts +0 -31
  203. package/lib/typescript/core/services/SessionTransportService.d.ts.map +0 -1
  204. package/lib/typescript/core/services/UserService.d.ts +0 -39
  205. package/lib/typescript/core/services/UserService.d.ts.map +0 -1
  206. package/lib/typescript/core/services/index.d.ts +0 -13
  207. package/lib/typescript/core/services/index.d.ts.map +0 -1
  208. package/lib/typescript/shared/crypto/messageBuilders.d.ts +0 -38
  209. package/lib/typescript/shared/crypto/messageBuilders.d.ts.map +0 -1
  210. package/lib/typescript/shared/crypto/platform.d.ts +0 -54
  211. package/lib/typescript/shared/crypto/platform.d.ts.map +0 -1
  212. package/lib/typescript/shared/crypto/signature.d.ts +0 -72
  213. package/lib/typescript/shared/crypto/signature.d.ts.map +0 -1
  214. package/lib/typescript/shared/index.d.ts +0 -20
  215. package/lib/typescript/shared/index.d.ts.map +0 -1
  216. package/lib/typescript/shared/models/index.d.ts +0 -163
  217. package/lib/typescript/shared/models/index.d.ts.map +0 -1
  218. package/lib/typescript/shared/transport/index.d.ts +0 -73
  219. package/lib/typescript/shared/transport/index.d.ts.map +0 -1
  220. package/lib/typescript/shared/utils/index.d.ts +0 -28
  221. package/lib/typescript/shared/utils/index.d.ts.map +0 -1
  222. package/src/core/services/AuthService.ts +0 -153
  223. package/src/core/services/SessionTransportService.ts +0 -69
  224. package/src/core/services/UserService.ts +0 -125
  225. package/src/core/services/index.ts +0 -14
  226. package/src/shared/crypto/messageBuilders.ts +0 -89
  227. package/src/shared/crypto/platform.ts +0 -140
  228. package/src/shared/crypto/signature.ts +0 -235
  229. package/src/shared/index.ts +0 -28
  230. package/src/shared/models/index.ts +0 -173
  231. package/src/shared/transport/index.ts +0 -349
  232. package/src/shared/utils/index.ts +0 -73
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Core Cryptographic Functions - Platform Agnostic
3
+ *
4
+ * This module contains the core signature verification logic
5
+ * that is shared between all platforms (React Native, Node.js, Web).
6
+ * Platform-specific implementations (hashing, random generation) are injected.
7
+ */
8
+
9
+ import { ec as EC } from 'elliptic';
10
+ import type { EC as ECType } from 'elliptic';
11
+
12
+ const ec = new EC('secp256k1');
13
+
14
+ // Constants for signature validation
15
+ export const CHALLENGE_TTL_MS = 5 * 60 * 1000; // 5 minutes
16
+ export const MAX_SIGNATURE_AGE_MS = 5 * 60 * 1000; // 5 minutes
17
+
18
+ /**
19
+ * Core signature verification using elliptic curve
20
+ * This is platform-agnostic and works everywhere
21
+ */
22
+ export function verifySignatureCore(
23
+ messageHash: string,
24
+ signature: string,
25
+ publicKey: string
26
+ ): boolean {
27
+ try {
28
+ const key = ec.keyFromPublic(publicKey, 'hex');
29
+ return key.verify(messageHash, signature);
30
+ } catch {
31
+ return false;
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Validate that a string is a valid public key
37
+ */
38
+ export function isValidPublicKey(publicKey: string): boolean {
39
+ // Reject empty strings
40
+ if (!publicKey || publicKey.trim().length === 0) {
41
+ return false;
42
+ }
43
+
44
+ try {
45
+ ec.keyFromPublic(publicKey, 'hex');
46
+ return true;
47
+ } catch {
48
+ return false;
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Validate that a string is a valid private key
54
+ */
55
+ export function isValidPrivateKey(privateKey: string): boolean {
56
+ // Reject empty strings
57
+ if (!privateKey || privateKey.trim().length === 0) {
58
+ return false;
59
+ }
60
+
61
+ // Private keys must be 64 hex characters (32 bytes)
62
+ if (!/^[0-9a-fA-F]{64}$/.test(privateKey)) {
63
+ return false;
64
+ }
65
+
66
+ try {
67
+ const keyPair = ec.keyFromPrivate(privateKey);
68
+ // Verify it can derive a public key and the key is valid
69
+ keyPair.getPublic('hex');
70
+ // Check that the private key is not zero (which would be invalid)
71
+ const priv = keyPair.getPrivate();
72
+ if (!priv || priv.isZero()) {
73
+ return false;
74
+ }
75
+ return true;
76
+ } catch {
77
+ return false;
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Get a shortened display version of a public key
83
+ * Format: first 8 chars...last 8 chars
84
+ */
85
+ export function shortenPublicKey(publicKey: string): string {
86
+ if (publicKey.length <= 20) return publicKey;
87
+ return `${publicKey.slice(0, 8)}...${publicKey.slice(-8)}`;
88
+ }
89
+
90
+ /**
91
+ * Derive public key from a private key (without storing)
92
+ */
93
+ export function derivePublicKey(privateKey: string): string {
94
+ const keyPair = ec.keyFromPrivate(privateKey);
95
+ return keyPair.getPublic('hex');
96
+ }
97
+
98
+ /**
99
+ * Check timestamp freshness
100
+ */
101
+ export function isTimestampFresh(timestamp: number, maxAgeMs: number = MAX_SIGNATURE_AGE_MS): boolean {
102
+ const now = Date.now();
103
+ return (now - timestamp) <= maxAgeMs;
104
+ }
105
+
106
+ /**
107
+ * Build authentication challenge message
108
+ * Format: auth:{publicKey}:{challenge}:{timestamp}
109
+ */
110
+ export function buildAuthMessage(publicKey: string, challenge: string, timestamp: number): string {
111
+ return `auth:${publicKey}:${challenge}:${timestamp}`;
112
+ }
113
+
114
+ /**
115
+ * Build registration message
116
+ * Format: oxy:register:{publicKey}:{timestamp}
117
+ */
118
+ export function buildRegistrationMessage(publicKey: string, timestamp: number): string {
119
+ return `oxy:register:${publicKey}:${timestamp}`;
120
+ }
121
+
122
+ /**
123
+ * Build request signature message
124
+ * Format: request:{publicKey}:{timestamp}:{canonicalString}
125
+ */
126
+ export function buildRequestMessage(
127
+ publicKey: string,
128
+ timestamp: number,
129
+ data: Record<string, unknown>
130
+ ): string {
131
+ const sortedKeys = Object.keys(data).sort();
132
+ const canonicalParts = sortedKeys.map(key => `${key}:${JSON.stringify(data[key])}`);
133
+ const canonicalString = canonicalParts.join('|');
134
+ return `request:${publicKey}:${timestamp}:${canonicalString}`;
135
+ }
136
+
137
+ /**
138
+ * Get the elliptic curve instance (for key generation)
139
+ */
140
+ export function getEllipticCurve(): ECType {
141
+ return ec;
142
+ }
@@ -3,15 +3,6 @@
3
3
  *
4
4
  * Provides cryptographic identity management for the Oxy ecosystem.
5
5
  * Handles key generation, secure storage, and digital signatures.
6
- *
7
- * ⚠️ IMPORTANT: KeyManager is primarily intended for use in the Oxy Accounts app.
8
- * While it's exported here for convenience, third-party applications should NOT
9
- * generate or store user identities. The Accounts app is the identity wallet.
10
- *
11
- * For third-party apps:
12
- * - Use SignatureService for signing operations (but keys come from Accounts app)
13
- * - Do NOT call KeyManager.createIdentity() or KeyManager.importKeyPair()
14
- * - The Oxy Accounts app handles all identity generation and key storage
15
6
  */
16
7
 
17
8
  // Import polyfills first - this ensures Buffer is available for crypto libraries
@@ -25,7 +16,9 @@ export {
25
16
  } from './signatureService';
26
17
  export { type BackupData } from './types';
27
18
 
19
+ // Export core crypto utilities (shared across platforms)
20
+ export * from './core';
21
+
28
22
  // Re-export for convenience
29
23
  export { KeyManager as default } from './keyManager';
30
24
 
31
-
@@ -1,20 +1,38 @@
1
1
  /**
2
2
  * Key Manager - ECDSA secp256k1 Key Generation and Storage
3
3
  *
4
- * Handles secure generation, storage, and retrieval of cryptographic keys.
4
+ * ⚠️ **FOR OXY ACCOUNTS APP ONLY**
5
+ *
6
+ * This module handles secure generation, storage, and retrieval of cryptographic keys.
5
7
  * Private keys are stored securely using expo-secure-store and never leave the device.
8
+ *
9
+ * **IMPORTANT**: Third-party apps should NOT use KeyManager directly.
10
+ * Instead, use the OxyServices authentication flows which communicate with the
11
+ * Oxy Accounts app via deep links/QR codes to obtain user authorization.
12
+ *
13
+ * The Oxy Accounts app is the sole owner of the user's private key and identity.
14
+ * Other apps request authentication from the Accounts app, which signs challenges
15
+ * and returns authorization to the requesting app via the API.
16
+ *
17
+ * @see {@link https://github.com/OxyHQ/OxyHQServices/blob/main/packages/services/src/crypto/README.md|Crypto Module Documentation}
6
18
  */
7
19
 
8
20
  import { ec as EC } from 'elliptic';
9
21
  import type { ECKeyPair } from 'elliptic';
10
22
  import { Platform } from 'react-native';
11
- import { shortenPublicKey as sharedShortenPublicKey } from '../shared';
23
+ import {
24
+ isValidPublicKey as validatePublicKey,
25
+ isValidPrivateKey as validatePrivateKey,
26
+ derivePublicKey as derivePublicKeyFromPrivate,
27
+ shortenPublicKey as shortenKey,
28
+ getEllipticCurve,
29
+ } from './core';
12
30
 
13
31
  // Lazy imports for React Native specific modules
14
32
  let SecureStore: typeof import('expo-secure-store') | null = null;
15
33
  let ExpoCrypto: typeof import('expo-crypto') | null = null;
16
34
 
17
- const ec = new EC('secp256k1');
35
+ const ec = getEllipticCurve();
18
36
 
19
37
  const STORAGE_KEYS = {
20
38
  PRIVATE_KEY: 'oxy_identity_private_key',
@@ -505,34 +523,21 @@ export class KeyManager {
505
523
  * Derive public key from a private key (without storing)
506
524
  */
507
525
  static derivePublicKey(privateKey: string): string {
508
- const keyPair = ec.keyFromPrivate(privateKey);
509
- return keyPair.getPublic('hex');
526
+ return derivePublicKeyFromPrivate(privateKey);
510
527
  }
511
528
 
512
529
  /**
513
530
  * Validate that a string is a valid public key
514
531
  */
515
532
  static isValidPublicKey(publicKey: string): boolean {
516
- try {
517
- ec.keyFromPublic(publicKey, 'hex');
518
- return true;
519
- } catch {
520
- return false;
521
- }
533
+ return validatePublicKey(publicKey);
522
534
  }
523
535
 
524
536
  /**
525
537
  * Validate that a string is a valid private key
526
538
  */
527
539
  static isValidPrivateKey(privateKey: string): boolean {
528
- try {
529
- const keyPair = ec.keyFromPrivate(privateKey);
530
- // Verify it can derive a public key
531
- keyPair.getPublic('hex');
532
- return true;
533
- } catch {
534
- return false;
535
- }
540
+ return validatePrivateKey(privateKey);
536
541
  }
537
542
 
538
543
  /**
@@ -540,8 +545,7 @@ export class KeyManager {
540
545
  * Format: first 8 chars...last 8 chars
541
546
  */
542
547
  static shortenPublicKey(publicKey: string): string {
543
- // Use shared utility
544
- return sharedShortenPublicKey(publicKey);
548
+ return shortenKey(publicKey);
545
549
  }
546
550
  }
547
551
 
@@ -4,26 +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 the shared SignatureService from '../shared' 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
- SignatureService as SharedSignatureService,
19
- isTimestampFresh,
20
- type SignedMessage,
21
- } from '../shared';
19
+ shortenPublicKey as shortenKey,
20
+ getEllipticCurve,
21
+ } from './core';
22
+
23
+ // Lazy import for expo-crypto
24
+ let ExpoCrypto: typeof import('expo-crypto') | null = null;
25
+
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
+ }
22
41
 
23
- const ec = new EC('secp256k1');
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
+ }
24
51
 
25
- // Re-export shared types
26
- export type { SignedMessage } from '../shared';
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
+ }
27
89
 
28
90
  export interface AuthChallenge {
29
91
  challenge: string;
@@ -34,23 +96,39 @@ export interface AuthChallenge {
34
96
  export class SignatureService {
35
97
  /**
36
98
  * Generate a random challenge string (for offline use)
37
- * Uses shared crypto adapter
99
+ * Uses expo-crypto in React Native, crypto.randomBytes in Node.js
38
100
  */
39
101
  static async generateChallenge(): Promise<string> {
40
- const adapter = await getCryptoAdapter();
41
- const randomBytes = await adapter.randomBytes(32);
42
- return Array.from(randomBytes)
43
- .map((b: number) => b.toString(16).padStart(2, '0'))
44
- .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
+ }
45
125
  }
46
126
 
47
127
  /**
48
128
  * Hash a message using SHA-256
49
- * Uses shared crypto adapter
50
129
  */
51
130
  static async hashMessage(message: string): Promise<string> {
52
- const adapter = await getCryptoAdapter();
53
- return adapter.sha256(message);
131
+ return sha256(message);
54
132
  }
55
133
 
56
134
  /**
@@ -63,8 +141,7 @@ export class SignatureService {
63
141
  throw new Error('No identity found. Please create or import an identity first.');
64
142
  }
65
143
 
66
- const adapter = await getCryptoAdapter();
67
- const messageHash = await adapter.sha256(message);
144
+ const messageHash = await sha256(message);
68
145
  const signature = keyPair.sign(messageHash);
69
146
  return signature.toDER('hex');
70
147
  }
@@ -75,18 +152,43 @@ export class SignatureService {
75
152
  */
76
153
  static async signWithKey(message: string, privateKey: string): Promise<string> {
77
154
  const keyPair = ec.keyFromPrivate(privateKey);
78
- const adapter = await getCryptoAdapter();
79
- const messageHash = await adapter.sha256(message);
155
+ const messageHash = await sha256(message);
80
156
  const signature = keyPair.sign(messageHash);
81
157
  return signature.toDER('hex');
82
158
  }
83
159
 
84
160
  /**
85
161
  * Verify a signature against a message and public key
86
- * Uses shared SignatureService for verification
87
162
  */
88
163
  static async verify(message: string, signature: string, publicKey: string): Promise<boolean> {
89
- 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
+ }
90
192
  }
91
193
 
92
194
  /**
@@ -113,7 +215,6 @@ export class SignatureService {
113
215
  /**
114
216
  * Verify a signed message object
115
217
  * Checks both signature validity and timestamp freshness
116
- * Uses shared SignatureService for verification
117
218
  */
118
219
  static async verifySignedMessage(
119
220
  signedMessage: SignedMessage,
@@ -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,7 +255,6 @@ 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,
@@ -162,13 +262,14 @@ export class SignatureService {
162
262
  maxAgeMs: number = 5 * 60 * 1000
163
263
  ): Promise<boolean> {
164
264
  const { challenge: signature, publicKey, timestamp } = response;
165
- return SharedSignatureService.verifyChallengeResponse(
166
- publicKey,
167
- originalChallenge,
168
- signature,
169
- timestamp,
170
- maxAgeMs
171
- );
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);
172
273
  }
173
274
 
174
275
  /**
package/src/index.ts CHANGED
@@ -48,12 +48,11 @@ export {
48
48
  } from './utils/languageUtils';
49
49
  export type { LanguageMetadata } from './utils/languageUtils';
50
50
 
51
- // Shared models and utilities (bundled for external consumers)
52
- export * from './shared';
53
-
54
51
  // Type exports
55
52
  export type {
56
53
  OxyConfig,
54
+ User,
55
+ LoginResponse,
57
56
  Notification,
58
57
  Wallet,
59
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 the shared module:
6
- *
7
- * import { User, LoginResponse, Session } from '../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 the shared module
34
- // Import them directly: import { User, LoginResponse } from '../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 the shared module
108
- // Import them directly: import { PaginationInfo, SearchProfilesResponse } from '../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 the shared module
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 '../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;