@oxyhq/services 5.16.33 → 5.16.35

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 (240) 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 +3 -2
  19. package/lib/commonjs/crypto/keyManager.js.map +1 -1
  20. package/lib/commonjs/crypto/signatureService.js +28 -122
  21. package/lib/commonjs/crypto/signatureService.js.map +1 -1
  22. package/lib/commonjs/index.js +12 -0
  23. package/lib/commonjs/index.js.map +1 -1
  24. package/lib/commonjs/models/interfaces.js +11 -11
  25. package/lib/commonjs/models/interfaces.js.map +1 -1
  26. package/lib/commonjs/shared/crypto/messageBuilders.js +79 -0
  27. package/lib/commonjs/shared/crypto/messageBuilders.js.map +1 -0
  28. package/lib/commonjs/shared/crypto/platform.js +118 -0
  29. package/lib/commonjs/shared/crypto/platform.js.map +1 -0
  30. package/lib/commonjs/shared/crypto/signature.js +191 -0
  31. package/lib/commonjs/shared/crypto/signature.js.map +1 -0
  32. package/lib/commonjs/shared/index.js +94 -0
  33. package/lib/commonjs/shared/index.js.map +1 -0
  34. package/lib/commonjs/shared/models/index.js +2 -0
  35. package/lib/commonjs/shared/models/index.js.map +1 -0
  36. package/lib/commonjs/shared/transport/index.js +260 -0
  37. package/lib/commonjs/shared/transport/index.js.map +1 -0
  38. package/lib/commonjs/shared/utils/index.js +82 -0
  39. package/lib/commonjs/shared/utils/index.js.map +1 -0
  40. package/lib/commonjs/ui/context/OxyContext.js +4 -40
  41. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  42. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +23 -61
  43. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  44. package/lib/commonjs/ui/context/hooks/useLanguageManagement.js.map +1 -1
  45. package/lib/commonjs/ui/hooks/queries/useServicesQueries.js +4 -12
  46. package/lib/commonjs/ui/hooks/queries/useServicesQueries.js.map +1 -1
  47. package/lib/commonjs/ui/hooks/useLanguageManagement.js.map +1 -1
  48. package/lib/commonjs/ui/hooks/useSessionManagement.js +0 -8
  49. package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
  50. package/lib/commonjs/ui/index.js +2 -0
  51. package/lib/commonjs/ui/index.js.map +1 -1
  52. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  53. package/lib/commonjs/ui/screens/OxyAuthScreen.js +2 -11
  54. package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +1 -1
  55. package/lib/commonjs/ui/utils/sessionHelpers.js +11 -26
  56. package/lib/commonjs/ui/utils/sessionHelpers.js.map +1 -1
  57. package/lib/commonjs/utils/sessionUtils.js +1 -8
  58. package/lib/commonjs/utils/sessionUtils.js.map +1 -1
  59. package/lib/module/core/OxyServices.base.js.map +1 -1
  60. package/lib/module/core/mixins/OxyServices.user.js.map +1 -1
  61. package/lib/module/core/mixins/OxyServices.utility.js.map +1 -1
  62. package/lib/module/core/services/AuthService.js +151 -0
  63. package/lib/module/core/services/AuthService.js.map +1 -0
  64. package/lib/module/core/services/SessionService.js +1 -2
  65. package/lib/module/core/services/SessionService.js.map +1 -1
  66. package/lib/module/core/services/SessionTransportService.js +59 -0
  67. package/lib/module/core/services/SessionTransportService.js.map +1 -0
  68. package/lib/module/core/services/TokenService.js +9 -17
  69. package/lib/module/core/services/TokenService.js.map +1 -1
  70. package/lib/module/core/services/UserService.js +118 -0
  71. package/lib/module/core/services/UserService.js.map +1 -0
  72. package/lib/module/core/services/index.js +16 -0
  73. package/lib/module/core/services/index.js.map +1 -0
  74. package/lib/module/crypto/index.js +9 -0
  75. package/lib/module/crypto/index.js.map +1 -1
  76. package/lib/module/crypto/keyManager.js +3 -2
  77. package/lib/module/crypto/keyManager.js.map +1 -1
  78. package/lib/module/crypto/signatureService.js +26 -122
  79. package/lib/module/crypto/signatureService.js.map +1 -1
  80. package/lib/module/index.js +2 -0
  81. package/lib/module/index.js.map +1 -1
  82. package/lib/module/models/interfaces.js +11 -11
  83. package/lib/module/models/interfaces.js.map +1 -1
  84. package/lib/module/shared/crypto/messageBuilders.js +70 -0
  85. package/lib/module/shared/crypto/messageBuilders.js.map +1 -0
  86. package/lib/module/shared/crypto/platform.js +112 -0
  87. package/lib/module/shared/crypto/platform.js.map +1 -0
  88. package/lib/module/shared/crypto/signature.js +186 -0
  89. package/lib/module/shared/crypto/signature.js.map +1 -0
  90. package/lib/module/shared/index.js +30 -0
  91. package/lib/module/shared/index.js.map +1 -0
  92. package/lib/module/shared/models/index.js +2 -0
  93. package/lib/module/shared/models/index.js.map +1 -0
  94. package/lib/module/shared/transport/index.js +254 -0
  95. package/lib/module/shared/transport/index.js.map +1 -0
  96. package/lib/module/shared/utils/index.js +74 -0
  97. package/lib/module/shared/utils/index.js.map +1 -0
  98. package/lib/module/ui/context/OxyContext.js +4 -40
  99. package/lib/module/ui/context/OxyContext.js.map +1 -1
  100. package/lib/module/ui/context/hooks/useAuthOperations.js +23 -61
  101. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  102. package/lib/module/ui/context/hooks/useLanguageManagement.js.map +1 -1
  103. package/lib/module/ui/hooks/queries/useServicesQueries.js +5 -13
  104. package/lib/module/ui/hooks/queries/useServicesQueries.js.map +1 -1
  105. package/lib/module/ui/hooks/useLanguageManagement.js.map +1 -1
  106. package/lib/module/ui/hooks/useSessionManagement.js +0 -8
  107. package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
  108. package/lib/module/ui/index.js +1 -0
  109. package/lib/module/ui/index.js.map +1 -1
  110. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  111. package/lib/module/ui/screens/OxyAuthScreen.js +2 -11
  112. package/lib/module/ui/screens/OxyAuthScreen.js.map +1 -1
  113. package/lib/module/ui/utils/sessionHelpers.js +11 -26
  114. package/lib/module/ui/utils/sessionHelpers.js.map +1 -1
  115. package/lib/module/utils/sessionUtils.js +1 -8
  116. package/lib/module/utils/sessionUtils.js.map +1 -1
  117. package/lib/typescript/core/OxyServices.base.d.ts.map +1 -1
  118. package/lib/typescript/core/mixins/OxyServices.analytics.d.ts.map +1 -1
  119. package/lib/typescript/core/mixins/OxyServices.assets.d.ts.map +1 -1
  120. package/lib/typescript/core/mixins/OxyServices.auth.d.ts +1 -1
  121. package/lib/typescript/core/mixins/OxyServices.auth.d.ts.map +1 -1
  122. package/lib/typescript/core/mixins/OxyServices.developer.d.ts.map +1 -1
  123. package/lib/typescript/core/mixins/OxyServices.devices.d.ts.map +1 -1
  124. package/lib/typescript/core/mixins/OxyServices.karma.d.ts.map +1 -1
  125. package/lib/typescript/core/mixins/OxyServices.language.d.ts.map +1 -1
  126. package/lib/typescript/core/mixins/OxyServices.location.d.ts.map +1 -1
  127. package/lib/typescript/core/mixins/OxyServices.payment.d.ts.map +1 -1
  128. package/lib/typescript/core/mixins/OxyServices.privacy.d.ts.map +1 -1
  129. package/lib/typescript/core/mixins/OxyServices.security.d.ts.map +1 -1
  130. package/lib/typescript/core/mixins/OxyServices.user.d.ts +2 -1
  131. package/lib/typescript/core/mixins/OxyServices.user.d.ts.map +1 -1
  132. package/lib/typescript/core/mixins/OxyServices.utility.d.ts.map +1 -1
  133. package/lib/typescript/core/mixins/index.d.ts +13 -13
  134. package/lib/typescript/core/mixins/index.d.ts.map +1 -1
  135. package/lib/typescript/core/services/AuthService.d.ts +50 -0
  136. package/lib/typescript/core/services/AuthService.d.ts.map +1 -0
  137. package/lib/typescript/core/services/SessionService.d.ts +3 -5
  138. package/lib/typescript/core/services/SessionService.d.ts.map +1 -1
  139. package/lib/typescript/core/services/SessionTransportService.d.ts +31 -0
  140. package/lib/typescript/core/services/SessionTransportService.d.ts.map +1 -0
  141. package/lib/typescript/core/services/TokenService.d.ts +3 -8
  142. package/lib/typescript/core/services/TokenService.d.ts.map +1 -1
  143. package/lib/typescript/core/services/UserService.d.ts +39 -0
  144. package/lib/typescript/core/services/UserService.d.ts.map +1 -0
  145. package/lib/typescript/core/services/index.d.ts +13 -0
  146. package/lib/typescript/core/services/index.d.ts.map +1 -0
  147. package/lib/typescript/crypto/index.d.ts +9 -0
  148. package/lib/typescript/crypto/index.d.ts.map +1 -1
  149. package/lib/typescript/crypto/keyManager.d.ts.map +1 -1
  150. package/lib/typescript/crypto/signatureService.d.ts +10 -13
  151. package/lib/typescript/crypto/signatureService.d.ts.map +1 -1
  152. package/lib/typescript/index.d.ts +2 -1
  153. package/lib/typescript/index.d.ts.map +1 -1
  154. package/lib/typescript/models/interfaces.d.ts +15 -69
  155. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  156. package/lib/typescript/models/session.d.ts +2 -4
  157. package/lib/typescript/models/session.d.ts.map +1 -1
  158. package/lib/typescript/shared/crypto/messageBuilders.d.ts +38 -0
  159. package/lib/typescript/shared/crypto/messageBuilders.d.ts.map +1 -0
  160. package/lib/typescript/shared/crypto/platform.d.ts +54 -0
  161. package/lib/typescript/shared/crypto/platform.d.ts.map +1 -0
  162. package/lib/typescript/shared/crypto/signature.d.ts +72 -0
  163. package/lib/typescript/shared/crypto/signature.d.ts.map +1 -0
  164. package/lib/typescript/shared/index.d.ts +20 -0
  165. package/lib/typescript/shared/index.d.ts.map +1 -0
  166. package/lib/typescript/shared/models/index.d.ts +163 -0
  167. package/lib/typescript/shared/models/index.d.ts.map +1 -0
  168. package/lib/typescript/shared/transport/index.d.ts +73 -0
  169. package/lib/typescript/shared/transport/index.d.ts.map +1 -0
  170. package/lib/typescript/shared/utils/index.d.ts +28 -0
  171. package/lib/typescript/shared/utils/index.d.ts.map +1 -0
  172. package/lib/typescript/ui/context/OxyContext.d.ts +2 -1
  173. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  174. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts +2 -1
  175. package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  176. package/lib/typescript/ui/context/hooks/useLanguageManagement.d.ts +2 -1
  177. package/lib/typescript/ui/context/hooks/useLanguageManagement.d.ts.map +1 -1
  178. package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts +1 -1
  179. package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  180. package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts +1 -1
  181. package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
  182. package/lib/typescript/ui/hooks/queries/useServicesQueries.d.ts.map +1 -1
  183. package/lib/typescript/ui/hooks/useLanguageManagement.d.ts +2 -1
  184. package/lib/typescript/ui/hooks/useLanguageManagement.d.ts.map +1 -1
  185. package/lib/typescript/ui/hooks/useSessionManagement.d.ts +2 -1
  186. package/lib/typescript/ui/hooks/useSessionManagement.d.ts.map +1 -1
  187. package/lib/typescript/ui/index.d.ts +1 -1
  188. package/lib/typescript/ui/index.d.ts.map +1 -1
  189. package/lib/typescript/ui/screens/OxyAuthScreen.d.ts.map +1 -1
  190. package/lib/typescript/ui/stores/authStore.d.ts +1 -1
  191. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
  192. package/lib/typescript/ui/utils/avatarUtils.d.ts +1 -1
  193. package/lib/typescript/ui/utils/avatarUtils.d.ts.map +1 -1
  194. package/lib/typescript/ui/utils/sessionHelpers.d.ts +2 -6
  195. package/lib/typescript/ui/utils/sessionHelpers.d.ts.map +1 -1
  196. package/lib/typescript/utils/sessionUtils.d.ts.map +1 -1
  197. package/package.json +1 -1
  198. package/src/core/OxyServices.base.ts +2 -1
  199. package/src/core/mixins/OxyServices.auth.ts +1 -1
  200. package/src/core/mixins/OxyServices.user.ts +2 -1
  201. package/src/core/mixins/OxyServices.utility.ts +2 -1
  202. package/src/core/services/AuthService.ts +153 -0
  203. package/src/core/services/SessionService.ts +3 -5
  204. package/src/core/services/SessionTransportService.ts +69 -0
  205. package/src/core/services/TokenService.ts +10 -18
  206. package/src/core/services/UserService.ts +125 -0
  207. package/src/core/services/index.ts +14 -0
  208. package/src/crypto/index.ts +9 -0
  209. package/src/crypto/keyManager.ts +3 -2
  210. package/src/crypto/signatureService.ts +43 -142
  211. package/src/index.ts +3 -2
  212. package/src/models/interfaces.ts +21 -74
  213. package/src/models/session.ts +3 -5
  214. package/src/shared/crypto/messageBuilders.ts +89 -0
  215. package/src/shared/crypto/platform.ts +140 -0
  216. package/src/shared/crypto/signature.ts +235 -0
  217. package/src/shared/index.ts +28 -0
  218. package/src/shared/models/index.ts +173 -0
  219. package/src/shared/transport/index.ts +349 -0
  220. package/src/shared/utils/index.ts +73 -0
  221. package/src/ui/context/OxyContext.tsx +22 -57
  222. package/src/ui/context/hooks/useAuthOperations.ts +33 -65
  223. package/src/ui/context/hooks/useLanguageManagement.ts +2 -1
  224. package/src/ui/hooks/auth/index.ts +0 -2
  225. package/src/ui/hooks/mutations/useAccountMutations.ts +1 -1
  226. package/src/ui/hooks/mutations/useServicesMutations.ts +1 -1
  227. package/src/ui/hooks/queries/useAccountQueries.ts +1 -1
  228. package/src/ui/hooks/queries/useServicesQueries.ts +3 -8
  229. package/src/ui/hooks/useLanguageManagement.ts +2 -1
  230. package/src/ui/hooks/useSessionManagement.ts +3 -9
  231. package/src/ui/index.ts +2 -1
  232. package/src/ui/screens/AccountSettingsScreen.tsx +6 -6
  233. package/src/ui/screens/AccountSwitcherScreen.tsx +1 -1
  234. package/src/ui/screens/OxyAuthScreen.tsx +2 -11
  235. package/src/ui/screens/ProfileScreen.tsx +1 -1
  236. package/src/ui/stores/authStore.ts +1 -1
  237. package/src/ui/types/navigation.ts +1 -1
  238. package/src/ui/utils/avatarUtils.ts +1 -1
  239. package/src/ui/utils/sessionHelpers.ts +15 -32
  240. package/src/utils/sessionUtils.ts +1 -8
@@ -3,77 +3,27 @@
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 the shared SignatureService from '../shared' 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
+ SignatureService as SharedSignatureService,
19
+ isTimestampFresh,
20
+ type SignedMessage,
21
+ } from '../shared';
13
22
 
14
23
  const ec = new EC('secp256k1');
15
24
 
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
- }
25
+ // Re-export shared types
26
+ export type { SignedMessage } from '../shared';
77
27
 
78
28
  export interface AuthChallenge {
79
29
  challenge: string;
@@ -84,39 +34,23 @@ export interface AuthChallenge {
84
34
  export class SignatureService {
85
35
  /**
86
36
  * Generate a random challenge string (for offline use)
87
- * Uses expo-crypto in React Native, crypto.randomBytes in Node.js
37
+ * Uses shared crypto adapter
88
38
  */
89
39
  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
- }
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('');
113
45
  }
114
46
 
115
47
  /**
116
48
  * Hash a message using SHA-256
49
+ * Uses shared crypto adapter
117
50
  */
118
51
  static async hashMessage(message: string): Promise<string> {
119
- return sha256(message);
52
+ const adapter = await getCryptoAdapter();
53
+ return adapter.sha256(message);
120
54
  }
121
55
 
122
56
  /**
@@ -129,7 +63,8 @@ export class SignatureService {
129
63
  throw new Error('No identity found. Please create or import an identity first.');
130
64
  }
131
65
 
132
- const messageHash = await sha256(message);
66
+ const adapter = await getCryptoAdapter();
67
+ const messageHash = await adapter.sha256(message);
133
68
  const signature = keyPair.sign(messageHash);
134
69
  return signature.toDER('hex');
135
70
  }
@@ -140,45 +75,18 @@ export class SignatureService {
140
75
  */
141
76
  static async signWithKey(message: string, privateKey: string): Promise<string> {
142
77
  const keyPair = ec.keyFromPrivate(privateKey);
143
- const messageHash = await sha256(message);
78
+ const adapter = await getCryptoAdapter();
79
+ const messageHash = await adapter.sha256(message);
144
80
  const signature = keyPair.sign(messageHash);
145
81
  return signature.toDER('hex');
146
82
  }
147
83
 
148
84
  /**
149
85
  * Verify a signature against a message and public key
86
+ * Uses shared SignatureService for verification
150
87
  */
151
88
  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
- }
89
+ return SharedSignatureService.verify(message, signature, publicKey);
182
90
  }
183
91
 
184
92
  /**
@@ -205,6 +113,7 @@ export class SignatureService {
205
113
  /**
206
114
  * Verify a signed message object
207
115
  * Checks both signature validity and timestamp freshness
116
+ * Uses shared SignatureService for verification
208
117
  */
209
118
  static async verifySignedMessage(
210
119
  signedMessage: SignedMessage,
@@ -213,14 +122,13 @@ export class SignatureService {
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,6 +154,7 @@ 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,
@@ -253,15 +162,13 @@ export class SignatureService {
253
162
  maxAgeMs: number = 5 * 60 * 1000
254
163
  ): Promise<boolean> {
255
164
  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);
165
+ return SharedSignatureService.verifyChallengeResponse(
166
+ publicKey,
167
+ originalChallenge,
168
+ signature,
169
+ timestamp,
170
+ maxAgeMs
171
+ );
265
172
  }
266
173
 
267
174
  /**
@@ -276,7 +183,7 @@ export class SignatureService {
276
183
  }
277
184
 
278
185
  const timestamp = Date.now();
279
- const message = `oxy:register:${publicKey}:${timestamp}`;
186
+ const message = buildRegistrationMessage(publicKey, timestamp);
280
187
  const signature = await SignatureService.sign(message);
281
188
 
282
189
  return {
@@ -301,13 +208,7 @@ export class SignatureService {
301
208
  }
302
209
 
303
210
  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}`;
211
+ const message = buildRequestMessage(publicKey, timestamp, data);
311
212
  const signature = await SignatureService.sign(message);
312
213
 
313
214
  return {
package/src/index.ts CHANGED
@@ -48,11 +48,12 @@ 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
+
51
54
  // Type exports
52
55
  export type {
53
56
  OxyConfig,
54
- User,
55
- LoginResponse,
56
57
  Notification,
57
58
  Wallet,
58
59
  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 the shared module:
6
+ *
7
+ * import { User, LoginResponse, Session } from '../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 the shared module
34
+ // Import them directly: import { User, LoginResponse } from '../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 the shared module
108
+ // Import them directly: import { PaginationInfo, SearchProfilesResponse } from '../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 the shared module
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 '../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
 
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Canonical Message Builders
3
+ *
4
+ * Creates standardized, canonical message formats for signing.
5
+ * These formats are used consistently across Accounts, Services SDK, and API.
6
+ */
7
+
8
+ import type { SignedMessage, AuthChallengeResponse } from '../models/index';
9
+
10
+ /**
11
+ * Build authentication message for challenge-response
12
+ * Format: auth:{publicKey}:{challenge}:{timestamp}
13
+ */
14
+ export function buildAuthMessage(
15
+ publicKey: string,
16
+ challenge: string,
17
+ timestamp: number
18
+ ): string {
19
+ return `auth:${publicKey}:${challenge}:${timestamp}`;
20
+ }
21
+
22
+ /**
23
+ * Build registration message
24
+ * Format: oxy:register:{publicKey}:{timestamp}
25
+ */
26
+ export function buildRegistrationMessage(
27
+ publicKey: string,
28
+ timestamp: number
29
+ ): string {
30
+ return `oxy:register:${publicKey}:${timestamp}`;
31
+ }
32
+
33
+ /**
34
+ * Build request signing message
35
+ * Format: request:{publicKey}:{timestamp}:{canonicalData}
36
+ */
37
+ export function buildRequestMessage(
38
+ publicKey: string,
39
+ timestamp: number,
40
+ data: Record<string, unknown>
41
+ ): string {
42
+ // Create canonical string representation
43
+ const sortedKeys = Object.keys(data).sort();
44
+ const canonicalParts = sortedKeys.map(key => `${key}:${JSON.stringify(data[key])}`);
45
+ const canonicalString = canonicalParts.join('|');
46
+
47
+ return `request:${publicKey}:${timestamp}:${canonicalString}`;
48
+ }
49
+
50
+ /**
51
+ * Create canonical data representation for signing
52
+ * Sorts keys and creates a consistent string representation
53
+ */
54
+ export function canonicalizeData(data: Record<string, unknown>): string {
55
+ const sortedKeys = Object.keys(data).sort();
56
+ const canonicalParts = sortedKeys.map(key => `${key}:${JSON.stringify(data[key])}`);
57
+ return canonicalParts.join('|');
58
+ }
59
+
60
+ /**
61
+ * Build auth challenge response payload
62
+ * Helper to construct the signed challenge response
63
+ */
64
+ export function buildAuthChallengeResponse(
65
+ publicKey: string,
66
+ challenge: string,
67
+ signature: string,
68
+ timestamp: number
69
+ ): AuthChallengeResponse {
70
+ return {
71
+ challenge,
72
+ publicKey,
73
+ signature,
74
+ timestamp,
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Validate timestamp freshness
80
+ * Ensures signed messages are not too old
81
+ */
82
+ export function isTimestampFresh(
83
+ timestamp: number,
84
+ maxAgeMs: number = 5 * 60 * 1000 // 5 minutes default
85
+ ): boolean {
86
+ const now = Date.now();
87
+ return (now - timestamp) <= maxAgeMs && timestamp <= now;
88
+ }
89
+
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Platform Detection and Adapters
3
+ *
4
+ * Provides environment detection and platform-specific crypto adapters
5
+ * to support Node.js, React Native, and Web environments.
6
+ */
7
+
8
+ /**
9
+ * Platform types
10
+ */
11
+ export type Platform = 'node' | 'react-native' | 'web';
12
+
13
+ /**
14
+ * Platform detection utilities
15
+ */
16
+ export const PlatformDetector = {
17
+ /**
18
+ * Detect current platform
19
+ */
20
+ detect(): Platform {
21
+ if (typeof window === 'undefined' && typeof process !== 'undefined' && process.versions?.node) {
22
+ return 'node';
23
+ }
24
+ if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
25
+ return 'react-native';
26
+ }
27
+ return 'web';
28
+ },
29
+
30
+ /**
31
+ * Check if running in Node.js
32
+ */
33
+ isNode(): boolean {
34
+ return this.detect() === 'node';
35
+ },
36
+
37
+ /**
38
+ * Check if running in React Native
39
+ */
40
+ isReactNative(): boolean {
41
+ return this.detect() === 'react-native';
42
+ },
43
+
44
+ /**
45
+ * Check if running in Web browser
46
+ */
47
+ isWeb(): boolean {
48
+ return this.detect() === 'web';
49
+ },
50
+ };
51
+
52
+ /**
53
+ * Crypto adapter interface
54
+ * Platform-specific implementations must implement this interface
55
+ */
56
+ export interface CryptoAdapter {
57
+ /**
58
+ * Generate random bytes
59
+ */
60
+ randomBytes(size: number): Promise<Uint8Array>;
61
+
62
+ /**
63
+ * Compute SHA-256 hash
64
+ */
65
+ sha256(message: string): Promise<string>;
66
+
67
+ /**
68
+ * Synchronous SHA-256 hash (Node.js only)
69
+ */
70
+ sha256Sync?(message: string): string;
71
+ }
72
+
73
+ /**
74
+ * Get the appropriate crypto adapter for the current platform
75
+ */
76
+ export async function getCryptoAdapter(): Promise<CryptoAdapter> {
77
+ const platform = PlatformDetector.detect();
78
+
79
+ if (platform === 'node') {
80
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
81
+ const getCrypto = new Function('return require("crypto")');
82
+ const crypto = getCrypto();
83
+
84
+ return {
85
+ async randomBytes(size: number): Promise<Uint8Array> {
86
+ return new Uint8Array(crypto.randomBytes(size));
87
+ },
88
+ async sha256(message: string): Promise<string> {
89
+ return crypto.createHash('sha256').update(message).digest('hex');
90
+ },
91
+ sha256Sync(message: string): string {
92
+ return crypto.createHash('sha256').update(message).digest('hex');
93
+ },
94
+ };
95
+ }
96
+
97
+ if (platform === 'react-native') {
98
+ // Lazy load expo-crypto (peer dependency)
99
+ try {
100
+ // @ts-ignore - expo-crypto is an optional peer dependency
101
+ const ExpoCrypto = await import('expo-crypto');
102
+
103
+ return {
104
+ async randomBytes(size: number): Promise<Uint8Array> {
105
+ const bytes = await ExpoCrypto.getRandomBytesAsync(size);
106
+ return new Uint8Array(bytes);
107
+ },
108
+ async sha256(message: string): Promise<string> {
109
+ return ExpoCrypto.digestStringAsync(
110
+ ExpoCrypto.CryptoDigestAlgorithm.SHA256,
111
+ message
112
+ );
113
+ },
114
+ };
115
+ } catch (error) {
116
+ throw new Error(
117
+ `expo-crypto is required in React Native environment: ${error instanceof Error ? error.message : String(error)}`
118
+ );
119
+ }
120
+ }
121
+
122
+ // Web platform - use Web Crypto API
123
+ if (typeof window !== 'undefined' && window.crypto) {
124
+ return {
125
+ async randomBytes(size: number): Promise<Uint8Array> {
126
+ return window.crypto.getRandomValues(new Uint8Array(size));
127
+ },
128
+ async sha256(message: string): Promise<string> {
129
+ const encoder = new TextEncoder();
130
+ const data = encoder.encode(message);
131
+ const hashBuffer = await window.crypto.subtle.digest('SHA-256', data);
132
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
133
+ return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
134
+ },
135
+ };
136
+ }
137
+
138
+ throw new Error('No suitable crypto implementation found for current platform');
139
+ }
140
+