@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,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 '../../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';
@@ -581,10 +580,23 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
581
580
  setTokenReady(false);
582
581
 
583
582
  try {
583
+ // CRITICAL: Get current identity's public key first
584
+ // Only restore sessions that belong to this identity
585
+ const currentPublicKey = await KeyManager.getPublicKey().catch(() => null);
586
+
584
587
  const storedSessionIdsJson = await storage.getItem(storageKeys.sessionIds);
585
588
  const storedSessionIds: string[] = storedSessionIdsJson ? JSON.parse(storedSessionIdsJson) : [];
586
589
  const storedActiveSessionId = await storage.getItem(storageKeys.activeSessionId);
587
590
 
591
+ // If no identity exists, clear all sessions and return
592
+ if (!currentPublicKey) {
593
+ if (storedSessionIds.length > 0 || storedActiveSessionId) {
594
+ await clearSessionState();
595
+ }
596
+ setTokenReady(true);
597
+ return;
598
+ }
599
+
588
600
  const validSessions: ClientSession[] = [];
589
601
 
590
602
  if (storedSessionIds.length > 0) {
@@ -592,6 +604,18 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
592
604
  try {
593
605
  const validation = await oxyServices.validateSession(sessionId, { useHeaderValidation: true });
594
606
  if (validation?.valid && validation.user) {
607
+ // CRITICAL: Verify session belongs to current identity
608
+ // IMPORTANT: In OxyAccounts, user.id is set to the publicKey (as confirmed by line 754 comment below)
609
+ // This is different from the JWT's userId field which contains MongoDB ObjectId
610
+ // We compare user.id (publicKey) to currentPublicKey to ensure session ownership
611
+ if (validation.user.id !== currentPublicKey) {
612
+ // Session belongs to different identity - skip it
613
+ if (__DEV__) {
614
+ logger('Skipping session from different identity during restoration');
615
+ }
616
+ continue;
617
+ }
618
+
595
619
  const now = new Date();
596
620
  validSessions.push({
597
621
  sessionId,
@@ -1,6 +1,5 @@
1
1
  import { useCallback } from 'react';
2
- import type { ApiError } from '../../../models/interfaces';
3
- import type { User } from '../../../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';
@@ -85,6 +84,22 @@ export const useAuthOperations = ({
85
84
  logger,
86
85
  }: UseAuthOperationsOptions): UseAuthOperationsResult => {
87
86
 
87
+ /**
88
+ * Clear session data if identity has changed
89
+ * Internal helper to avoid code duplication
90
+ */
91
+ const clearSessionsIfIdentityChanged = useCallback(
92
+ async (oldPublicKey: string | null, newPublicKey: string): Promise<void> => {
93
+ if (oldPublicKey && oldPublicKey !== newPublicKey) {
94
+ // Clear all session state to prevent old identity's data from showing up
95
+ await clearSessionState();
96
+ // Logout from auth store
97
+ logoutStore();
98
+ }
99
+ },
100
+ [clearSessionState, logoutStore]
101
+ );
102
+
88
103
  /**
89
104
  * Internal function to perform challenge-response sign in (works offline)
90
105
  */
@@ -293,10 +308,17 @@ export const useAuthOperations = ({
293
308
  setAuthState({ isLoading: true, error: null });
294
309
 
295
310
  try {
311
+ // CRITICAL: Get old public key before creating new identity
312
+ // If identity changes, we must clear all session data to prevent data leakage
313
+ const oldPublicKey = await KeyManager.getPublicKey().catch(() => null);
314
+
296
315
  // Generate new key pair directly (works offline)
297
316
  const { publicKey, privateKey } = await KeyManager.generateKeyPair();
298
317
  await KeyManager.importKeyPair(privateKey);
299
318
 
319
+ // Clear sessions if identity changed (prevents data leakage)
320
+ await clearSessionsIfIdentityChanged(oldPublicKey, publicKey);
321
+
300
322
  // Mark as not synced
301
323
  await storage.setItem('oxy_identity_synced', 'false');
302
324
  setIdentitySynced(false);
@@ -359,7 +381,7 @@ export const useAuthOperations = ({
359
381
  setAuthState({ isLoading: false });
360
382
  }
361
383
  },
362
- [oxyServices, storage, setAuthState, loginFailure, onError, logger, setIdentitySynced],
384
+ [oxyServices, storage, setAuthState, loginFailure, onError, logger, setIdentitySynced, clearSessionsIfIdentityChanged],
363
385
  );
364
386
 
365
387
  /**
@@ -464,6 +486,10 @@ export const useAuthOperations = ({
464
486
  setAuthState({ isLoading: true, error: null });
465
487
 
466
488
  try {
489
+ // CRITICAL: Get old public key before importing new identity
490
+ // If identity changes, we must clear all session data to prevent data leakage
491
+ const oldPublicKey = await KeyManager.getPublicKey().catch(() => null);
492
+
467
493
  // Decrypt private key from backup data
468
494
  const Crypto = await import('expo-crypto');
469
495
 
@@ -505,6 +531,9 @@ export const useAuthOperations = ({
505
531
  throw new Error('Backup file is corrupted or password is incorrect');
506
532
  }
507
533
 
534
+ // Clear sessions if identity changed (prevents data leakage)
535
+ await clearSessionsIfIdentityChanged(oldPublicKey, publicKey);
536
+
508
537
  // Mark as not synced
509
538
  await storage.setItem('oxy_identity_synced', 'false');
510
539
  setIdentitySynced(false);
@@ -549,7 +578,7 @@ export const useAuthOperations = ({
549
578
  setAuthState({ isLoading: false });
550
579
  }
551
580
  },
552
- [oxyServices, storage, setAuthState, loginFailure, onError, logger, setIdentitySynced],
581
+ [oxyServices, storage, setAuthState, loginFailure, onError, logger, setIdentitySynced, clearSessionsIfIdentityChanged],
553
582
  );
554
583
 
555
584
  /**
@@ -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 '../../../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 '../../../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 '../../../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 '../../../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 '../../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 '../../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 are available from the shared module (exported from main index)
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 '../../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';
@@ -28,7 +28,6 @@ import { useThemeColors } from '../styles';
28
28
  import { useOxy } from '../context/OxyContext';
29
29
  import QRCode from 'react-native-qrcode-svg';
30
30
  import OxyLogo from '../components/OxyLogo';
31
- import { generateSessionToken } from '../../shared';
32
31
 
33
32
  // Deep link scheme for Oxy Accounts app
34
33
  const OXY_ACCOUNTS_SCHEME = 'oxyaccounts://';
@@ -221,7 +220,7 @@ const OxyAuthScreen: React.FC<BaseScreenProps> = ({
221
220
 
222
221
  try {
223
222
  // Generate a unique session token for this auth request
224
- const sessionToken = await generateSessionToken(32);
223
+ const sessionToken = generateSessionToken();
225
224
  const expiresAt = Date.now() + AUTH_SESSION_EXPIRY_MS;
226
225
 
227
226
  // Register the auth session with the server
@@ -243,6 +242,16 @@ const OxyAuthScreen: React.FC<BaseScreenProps> = ({
243
242
  }
244
243
  }, [oxyServices, connectSocket]);
245
244
 
245
+ // Generate a random session token
246
+ const generateSessionToken = (): string => {
247
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
248
+ let result = '';
249
+ for (let i = 0; i < 32; i++) {
250
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
251
+ }
252
+ return result;
253
+ };
254
+
246
255
  // Clean up on unmount
247
256
  useEffect(() => {
248
257
  return () => {
@@ -10,7 +10,7 @@ import { Ionicons } from '@expo/vector-icons';
10
10
  import { useI18n } from '../hooks/useI18n';
11
11
  import { useOxy } from '../context/OxyContext';
12
12
  import { logger } from '../../utils/loggerUtils';
13
- import type { User } from '../../shared';
13
+ import type { User } from '../../models/interfaces';
14
14
  import { extractErrorMessage } from '../utils/errorHandlers';
15
15
 
16
16
  interface ProfileScreenProps extends BaseScreenProps {
@@ -1,5 +1,5 @@
1
1
  import { create } from 'zustand';
2
- import type { User } from '../../shared';
2
+ import type { User } from '../../models/interfaces';
3
3
 
4
4
  export interface AuthState {
5
5
  user: User | null;
@@ -1,7 +1,7 @@
1
1
  import type { ReactNode, RefObject } from 'react';
2
2
  import type { QueryClient } from '@tanstack/react-query';
3
3
  import type { RouteName } from '../navigation/routes';
4
- import type { User } from '../../shared';
4
+ import type { User } from '../../models/interfaces';
5
5
  import type { ClientSession } from '../../models/session';
6
6
 
7
7
  // Re-export RouteName from routes for convenience
@@ -1,5 +1,5 @@
1
1
  import type { OxyServices } from '../../core';
2
- import type { User } from '../../shared';
2
+ import type { User } from '../../models/interfaces';
3
3
  import { useAccountStore } from '../stores/accountStore';
4
4
  import { useAuthStore } from '../stores/authStore';
5
5
  import { QueryClient } from '@tanstack/react-query';
@@ -1,156 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.AuthService = void 0;
7
- var _HttpService = require("../HttpService");
8
- var _signatureService = require("../../crypto/signatureService");
9
- /**
10
- * Auth Service
11
- *
12
- * Handles authentication operations:
13
- * - Challenge retrieval
14
- * - Signing orchestration (delegated to Accounts/KeyManager)
15
- * - Session verification
16
- * - Access token retrieval
17
- * - Registration
18
- */
19
-
20
- class AuthService {
21
- constructor(config) {
22
- this.httpService = new _HttpService.HttpService(config);
23
- }
24
-
25
- /**
26
- * Check if a public key is registered on the server
27
- */
28
- async checkPublicKeyRegistered(publicKey) {
29
- try {
30
- return await this.httpService.request({
31
- method: 'GET',
32
- url: `/api/auth/check-publickey?publicKey=${encodeURIComponent(publicKey)}`,
33
- cache: true,
34
- cacheTTL: 2 * 60 * 1000
35
- });
36
- } catch (error) {
37
- throw error;
38
- }
39
- }
40
-
41
- /**
42
- * Request an authentication challenge
43
- */
44
- async requestChallenge(publicKey) {
45
- try {
46
- return await this.httpService.request({
47
- method: 'POST',
48
- url: '/api/auth/challenge',
49
- data: {
50
- publicKey
51
- },
52
- cache: false
53
- });
54
- } catch (error) {
55
- throw error;
56
- }
57
- }
58
-
59
- /**
60
- * Verify a challenge and authenticate (creates session)
61
- * This orchestrates signing via SignatureService (which uses KeyManager)
62
- */
63
- async verifyChallenge(challenge) {
64
- try {
65
- // Sign the challenge using SignatureService (requires private key)
66
- const signedChallenge = await _signatureService.SignatureService.signChallenge(challenge);
67
-
68
- // Verify challenge and get session
69
- return await this.httpService.request({
70
- method: 'POST',
71
- url: '/api/auth/verify',
72
- data: {
73
- publicKey: signedChallenge.publicKey,
74
- challenge: challenge,
75
- signature: signedChallenge.challenge,
76
- timestamp: signedChallenge.timestamp
77
- },
78
- cache: false
79
- });
80
- } catch (error) {
81
- throw error;
82
- }
83
- }
84
-
85
- /**
86
- * Register a new identity with the server
87
- */
88
- async register(publicKey, signature, timestamp, username, email) {
89
- try {
90
- return await this.httpService.request({
91
- method: 'POST',
92
- url: '/api/auth/register',
93
- data: {
94
- publicKey,
95
- signature,
96
- timestamp,
97
- username,
98
- email
99
- },
100
- cache: false
101
- });
102
- } catch (error) {
103
- throw error;
104
- }
105
- }
106
-
107
- /**
108
- * Register using current identity (signs automatically)
109
- */
110
- async registerCurrentIdentity(username, email) {
111
- try {
112
- const {
113
- signature,
114
- publicKey,
115
- timestamp
116
- } = await _signatureService.SignatureService.createRegistrationSignature();
117
- return this.register(publicKey, signature, timestamp, username, email);
118
- } catch (error) {
119
- throw error;
120
- }
121
- }
122
-
123
- /**
124
- * Get user by public key
125
- */
126
- async getUserByPublicKey(publicKey) {
127
- try {
128
- return await this.httpService.request({
129
- method: 'GET',
130
- url: `/api/auth/user/${encodeURIComponent(publicKey)}`,
131
- cache: true,
132
- cacheTTL: 2 * 60 * 1000
133
- });
134
- } catch (error) {
135
- throw error;
136
- }
137
- }
138
-
139
- /**
140
- * Get user by session ID
141
- */
142
- async getUserBySession(sessionId) {
143
- try {
144
- return await this.httpService.request({
145
- method: 'GET',
146
- url: `/api/auth/user/session/${encodeURIComponent(sessionId)}`,
147
- cache: true,
148
- cacheTTL: 2 * 60 * 1000
149
- });
150
- } catch (error) {
151
- throw error;
152
- }
153
- }
154
- }
155
- exports.AuthService = AuthService;
156
- //# sourceMappingURL=AuthService.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["_HttpService","require","_signatureService","AuthService","constructor","config","httpService","HttpService","checkPublicKeyRegistered","publicKey","request","method","url","encodeURIComponent","cache","cacheTTL","error","requestChallenge","data","verifyChallenge","challenge","signedChallenge","SignatureService","signChallenge","signature","timestamp","register","username","email","registerCurrentIdentity","createRegistrationSignature","getUserByPublicKey","getUserBySession","sessionId","exports"],"sourceRoot":"../../../../src","sources":["core/services/AuthService.ts"],"mappings":"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","ignoreList":[]}