@oxyhq/services 5.2.2 → 5.2.4
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.
- package/lib/commonjs/core/index.js +117 -0
- package/lib/commonjs/core/index.js.map +1 -1
- package/lib/commonjs/models/secureSession.js +2 -0
- package/lib/commonjs/models/secureSession.js.map +1 -0
- package/lib/commonjs/ui/context/LegacyOxyContext.js +643 -0
- package/lib/commonjs/ui/context/LegacyOxyContext.js.map +1 -0
- package/lib/commonjs/ui/context/OxyContext.js +215 -450
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/SecureOxyContext.js +408 -0
- package/lib/commonjs/ui/context/SecureOxyContext.js.map +1 -0
- package/lib/commonjs/ui/screens/AccountCenterScreen.js +3 -3
- package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +31 -30
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AppInfoScreen.js +4 -4
- package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SessionManagementScreen.js +34 -34
- package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignInScreen.js +2 -2
- package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
- package/lib/module/core/index.js +117 -0
- package/lib/module/core/index.js.map +1 -1
- package/lib/module/models/secureSession.js +2 -0
- package/lib/module/models/secureSession.js.map +1 -0
- package/lib/module/ui/context/LegacyOxyContext.js +639 -0
- package/lib/module/ui/context/LegacyOxyContext.js.map +1 -0
- package/lib/module/ui/context/OxyContext.js +214 -450
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/SecureOxyContext.js +403 -0
- package/lib/module/ui/context/SecureOxyContext.js.map +1 -0
- package/lib/module/ui/screens/AccountCenterScreen.js +3 -3
- package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +31 -30
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/module/ui/screens/AppInfoScreen.js +4 -4
- package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/module/ui/screens/SessionManagementScreen.js +34 -34
- package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/SignInScreen.js +2 -2
- package/lib/module/ui/screens/SignInScreen.js.map +1 -1
- package/lib/typescript/core/index.d.ts +51 -0
- package/lib/typescript/core/index.d.ts.map +1 -1
- package/lib/typescript/models/secureSession.d.ts +25 -0
- package/lib/typescript/models/secureSession.d.ts.map +1 -0
- package/lib/typescript/ui/context/LegacyOxyContext.d.ts +40 -0
- package/lib/typescript/ui/context/LegacyOxyContext.d.ts.map +1 -0
- package/lib/typescript/ui/context/OxyContext.d.ts +11 -12
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/context/SecureOxyContext.d.ts +39 -0
- package/lib/typescript/ui/context/SecureOxyContext.d.ts.map +1 -0
- package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/index.ts +117 -0
- package/src/index.ts +2 -2
- package/src/models/secureSession.ts +27 -0
- package/src/ui/context/LegacyOxyContext.tsx +735 -0
- package/src/ui/context/OxyContext.tsx +412 -674
- package/src/ui/context/SecureOxyContext.tsx +473 -0
- package/src/ui/screens/AccountCenterScreen.tsx +4 -4
- package/src/ui/screens/AccountSwitcherScreen.tsx +36 -34
- package/src/ui/screens/AppInfoScreen.tsx +3 -3
- package/src/ui/screens/SessionManagementScreen.tsx +31 -35
- package/src/ui/screens/SignInScreen.tsx +2 -2
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import React, { createContext, useContext, useState, useEffect, useCallback } from 'react';
|
|
4
|
-
|
|
5
|
-
// Define authenticated user with tokens
|
|
3
|
+
import React, { createContext, useContext, useState, useEffect, useCallback, useMemo } from 'react';
|
|
6
4
|
|
|
7
5
|
// Define the context shape
|
|
8
6
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
@@ -30,7 +28,6 @@ class WebStorage {
|
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
// React Native AsyncStorage implementation
|
|
33
|
-
// This will be dynamically imported only in React Native environment
|
|
34
31
|
let AsyncStorage;
|
|
35
32
|
|
|
36
33
|
// Determine the platform and set up storage
|
|
@@ -41,7 +38,6 @@ const isReactNative = () => {
|
|
|
41
38
|
// Get appropriate storage for the platform
|
|
42
39
|
const getStorage = async () => {
|
|
43
40
|
if (isReactNative()) {
|
|
44
|
-
// Dynamically import AsyncStorage only in React Native environment
|
|
45
41
|
if (!AsyncStorage) {
|
|
46
42
|
try {
|
|
47
43
|
const asyncStorageModule = await import('@react-native-async-storage/async-storage');
|
|
@@ -53,38 +49,33 @@ const getStorage = async () => {
|
|
|
53
49
|
}
|
|
54
50
|
return AsyncStorage;
|
|
55
51
|
}
|
|
56
|
-
|
|
57
|
-
// Default to web storage
|
|
58
52
|
return new WebStorage();
|
|
59
53
|
};
|
|
60
54
|
|
|
61
|
-
// Storage keys
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
// Array of
|
|
65
|
-
|
|
66
|
-
// ID of currently active user
|
|
67
|
-
// Legacy keys for migration
|
|
68
|
-
accessToken: `${prefix}_access_token`,
|
|
69
|
-
refreshToken: `${prefix}_refresh_token`,
|
|
70
|
-
user: `${prefix}_user`
|
|
55
|
+
// Storage keys for secure sessions
|
|
56
|
+
const getSecureStorageKeys = (prefix = 'oxy_secure') => ({
|
|
57
|
+
sessions: `${prefix}_sessions`,
|
|
58
|
+
// Array of SecureClientSession objects
|
|
59
|
+
activeSessionId: `${prefix}_active_session_id` // ID of currently active session
|
|
71
60
|
});
|
|
72
61
|
export const OxyContextProvider = ({
|
|
73
62
|
children,
|
|
74
63
|
oxyServices,
|
|
75
|
-
storageKeyPrefix = '
|
|
64
|
+
storageKeyPrefix = 'oxy_secure',
|
|
76
65
|
onAuthStateChange,
|
|
77
66
|
bottomSheetRef
|
|
78
67
|
}) => {
|
|
79
68
|
// Authentication state
|
|
80
69
|
const [user, setUser] = useState(null);
|
|
81
|
-
const [
|
|
70
|
+
const [minimalUser, setMinimalUser] = useState(null);
|
|
71
|
+
const [sessions, setSessions] = useState([]);
|
|
72
|
+
const [activeSessionId, setActiveSessionId] = useState(null);
|
|
82
73
|
const [isLoading, setIsLoading] = useState(true);
|
|
83
74
|
const [error, setError] = useState(null);
|
|
84
75
|
const [storage, setStorage] = useState(null);
|
|
85
76
|
|
|
86
|
-
// Storage keys
|
|
87
|
-
const keys =
|
|
77
|
+
// Storage keys (memoized to prevent infinite loops)
|
|
78
|
+
const keys = useMemo(() => getSecureStorageKeys(storageKeyPrefix), [storageKeyPrefix]);
|
|
88
79
|
|
|
89
80
|
// Initialize storage
|
|
90
81
|
useEffect(() => {
|
|
@@ -106,69 +97,54 @@ export const OxyContextProvider = ({
|
|
|
106
97
|
if (!storage) return;
|
|
107
98
|
setIsLoading(true);
|
|
108
99
|
try {
|
|
109
|
-
//
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
console.log('
|
|
113
|
-
console.log('
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
await saveActiveUserId(newActiveUser.id);
|
|
141
|
-
oxyServices.setTokens(newActiveUser.accessToken, newActiveUser.refreshToken || newActiveUser.accessToken);
|
|
100
|
+
// Load stored sessions
|
|
101
|
+
const sessionsData = await storage.getItem(keys.sessions);
|
|
102
|
+
const storedActiveSessionId = await storage.getItem(keys.activeSessionId);
|
|
103
|
+
console.log('SecureAuth - sessionsData:', sessionsData);
|
|
104
|
+
console.log('SecureAuth - activeSessionId:', storedActiveSessionId);
|
|
105
|
+
if (sessionsData) {
|
|
106
|
+
const parsedSessions = JSON.parse(sessionsData);
|
|
107
|
+
setSessions(parsedSessions);
|
|
108
|
+
if (storedActiveSessionId && parsedSessions.length > 0) {
|
|
109
|
+
const activeSession = parsedSessions.find(s => s.sessionId === storedActiveSessionId);
|
|
110
|
+
if (activeSession) {
|
|
111
|
+
console.log('SecureAuth - activeSession found:', activeSession);
|
|
112
|
+
|
|
113
|
+
// Validate session
|
|
114
|
+
try {
|
|
115
|
+
const validation = await oxyServices.validateSession(activeSession.sessionId);
|
|
116
|
+
if (validation.valid) {
|
|
117
|
+
console.log('SecureAuth - session validated successfully');
|
|
118
|
+
setActiveSessionId(activeSession.sessionId);
|
|
119
|
+
|
|
120
|
+
// Get access token for API calls
|
|
121
|
+
await oxyServices.getTokenBySession(activeSession.sessionId);
|
|
122
|
+
|
|
123
|
+
// Load full user data
|
|
124
|
+
const fullUser = await oxyServices.getUserBySession(activeSession.sessionId);
|
|
125
|
+
setUser(fullUser);
|
|
126
|
+
setMinimalUser({
|
|
127
|
+
id: fullUser.id,
|
|
128
|
+
username: fullUser.username,
|
|
129
|
+
avatar: fullUser.avatar
|
|
130
|
+
});
|
|
142
131
|
if (onAuthStateChange) {
|
|
143
|
-
onAuthStateChange(
|
|
132
|
+
onAuthStateChange(fullUser);
|
|
144
133
|
}
|
|
145
134
|
} else {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
await storage.removeItem(keys.activeUserId);
|
|
149
|
-
oxyServices.clearTokens();
|
|
150
|
-
if (onAuthStateChange) {
|
|
151
|
-
onAuthStateChange(null);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
} else {
|
|
155
|
-
console.log('InitAuth - user validated successfully, setting auth state');
|
|
156
|
-
// Notify about auth state change
|
|
157
|
-
if (onAuthStateChange) {
|
|
158
|
-
onAuthStateChange(activeUser);
|
|
135
|
+
console.log('SecureAuth - session invalid, removing');
|
|
136
|
+
await removeInvalidSession(activeSession.sessionId);
|
|
159
137
|
}
|
|
138
|
+
} catch (error) {
|
|
139
|
+
console.error('SecureAuth - session validation error:', error);
|
|
140
|
+
await removeInvalidSession(activeSession.sessionId);
|
|
160
141
|
}
|
|
161
142
|
}
|
|
162
143
|
}
|
|
163
|
-
} else {
|
|
164
|
-
console.log('InitAuth - no users data, checking legacy auth');
|
|
165
|
-
// Check for legacy single-user data and migrate
|
|
166
|
-
await migrateLegacyAuth();
|
|
167
144
|
}
|
|
168
145
|
} catch (err) {
|
|
169
|
-
console.error('
|
|
146
|
+
console.error('Secure auth initialization error:', err);
|
|
170
147
|
await clearAllStorage();
|
|
171
|
-
oxyServices.clearTokens();
|
|
172
148
|
} finally {
|
|
173
149
|
setIsLoading(false);
|
|
174
150
|
}
|
|
@@ -176,451 +152,238 @@ export const OxyContextProvider = ({
|
|
|
176
152
|
if (storage) {
|
|
177
153
|
initAuth();
|
|
178
154
|
}
|
|
179
|
-
}, [storage, oxyServices, keys
|
|
180
|
-
|
|
181
|
-
//
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
accessToken,
|
|
199
|
-
refreshToken: refreshToken || undefined
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
// Store in new multi-user format
|
|
203
|
-
await storage.setItem(keys.users, JSON.stringify([authenticatedUser]));
|
|
204
|
-
await storage.setItem(keys.activeUserId, authenticatedUser.id);
|
|
205
|
-
|
|
206
|
-
// Set state
|
|
207
|
-
setUsers([authenticatedUser]);
|
|
208
|
-
setUser(authenticatedUser);
|
|
209
|
-
|
|
210
|
-
// Notify about auth state change
|
|
211
|
-
if (onAuthStateChange) {
|
|
212
|
-
onAuthStateChange(authenticatedUser);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Clear legacy storage
|
|
217
|
-
await storage.removeItem(keys.accessToken);
|
|
218
|
-
await storage.removeItem(keys.refreshToken);
|
|
219
|
-
await storage.removeItem(keys.user);
|
|
155
|
+
}, [storage, oxyServices, keys, onAuthStateChange]);
|
|
156
|
+
|
|
157
|
+
// Remove invalid session
|
|
158
|
+
const removeInvalidSession = useCallback(async sessionId => {
|
|
159
|
+
const filteredSessions = sessions.filter(s => s.sessionId !== sessionId);
|
|
160
|
+
setSessions(filteredSessions);
|
|
161
|
+
await saveSessionsToStorage(filteredSessions);
|
|
162
|
+
|
|
163
|
+
// If there are other sessions, switch to the first one
|
|
164
|
+
if (filteredSessions.length > 0) {
|
|
165
|
+
await switchToSession(filteredSessions[0].sessionId);
|
|
166
|
+
} else {
|
|
167
|
+
// No valid sessions left
|
|
168
|
+
setActiveSessionId(null);
|
|
169
|
+
setUser(null);
|
|
170
|
+
setMinimalUser(null);
|
|
171
|
+
await storage?.removeItem(keys.activeSessionId);
|
|
172
|
+
if (onAuthStateChange) {
|
|
173
|
+
onAuthStateChange(null);
|
|
220
174
|
}
|
|
221
|
-
} catch (err) {
|
|
222
|
-
console.error('Migration error:', err);
|
|
223
175
|
}
|
|
224
|
-
};
|
|
176
|
+
}, [sessions, storage, keys, onAuthStateChange]);
|
|
225
177
|
|
|
226
|
-
//
|
|
227
|
-
const
|
|
178
|
+
// Save sessions to storage
|
|
179
|
+
const saveSessionsToStorage = useCallback(async sessionsList => {
|
|
228
180
|
if (!storage) return;
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
};
|
|
181
|
+
await storage.setItem(keys.sessions, JSON.stringify(sessionsList));
|
|
182
|
+
}, [storage, keys.sessions]);
|
|
183
|
+
|
|
184
|
+
// Save active session ID to storage
|
|
185
|
+
const saveActiveSessionId = useCallback(async sessionId => {
|
|
186
|
+
if (!storage) return;
|
|
187
|
+
await storage.setItem(keys.activeSessionId, sessionId);
|
|
188
|
+
}, [storage, keys.activeSessionId]);
|
|
237
189
|
|
|
238
|
-
//
|
|
239
|
-
const clearAllStorage = async () => {
|
|
190
|
+
// Clear all storage
|
|
191
|
+
const clearAllStorage = useCallback(async () => {
|
|
240
192
|
if (!storage) return;
|
|
241
193
|
try {
|
|
242
|
-
await storage.removeItem(keys.
|
|
243
|
-
await storage.removeItem(keys.
|
|
244
|
-
// Also clear legacy keys
|
|
245
|
-
await clearStorage();
|
|
194
|
+
await storage.removeItem(keys.sessions);
|
|
195
|
+
await storage.removeItem(keys.activeSessionId);
|
|
246
196
|
} catch (err) {
|
|
247
|
-
console.error('Clear
|
|
197
|
+
console.error('Clear secure storage error:', err);
|
|
248
198
|
}
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
// Save users to storage
|
|
252
|
-
const saveUsersToStorage = async usersList => {
|
|
253
|
-
if (!storage) return;
|
|
254
|
-
await storage.setItem(keys.users, JSON.stringify(usersList));
|
|
255
|
-
};
|
|
199
|
+
}, [storage, keys]);
|
|
256
200
|
|
|
257
|
-
//
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
};
|
|
201
|
+
// Switch to a different session
|
|
202
|
+
const switchToSession = useCallback(async sessionId => {
|
|
203
|
+
try {
|
|
204
|
+
setIsLoading(true);
|
|
262
205
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
await
|
|
268
|
-
|
|
269
|
-
|
|
206
|
+
// Get access token for this session
|
|
207
|
+
await oxyServices.getTokenBySession(sessionId);
|
|
208
|
+
|
|
209
|
+
// Load full user data
|
|
210
|
+
const fullUser = await oxyServices.getUserBySession(sessionId);
|
|
211
|
+
setActiveSessionId(sessionId);
|
|
212
|
+
setUser(fullUser);
|
|
213
|
+
setMinimalUser({
|
|
214
|
+
id: fullUser.id,
|
|
215
|
+
username: fullUser.username,
|
|
216
|
+
avatar: fullUser.avatar
|
|
217
|
+
});
|
|
218
|
+
await saveActiveSessionId(sessionId);
|
|
219
|
+
if (onAuthStateChange) {
|
|
220
|
+
onAuthStateChange(fullUser);
|
|
270
221
|
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
|
|
222
|
+
} catch (error) {
|
|
223
|
+
console.error('Switch session error:', error);
|
|
224
|
+
setError('Failed to switch session');
|
|
225
|
+
} finally {
|
|
226
|
+
setIsLoading(false);
|
|
274
227
|
}
|
|
275
|
-
|
|
276
|
-
};
|
|
228
|
+
}, [oxyServices, onAuthStateChange, saveActiveSessionId]);
|
|
277
229
|
|
|
278
|
-
//
|
|
279
|
-
const login = async (username, password) => {
|
|
230
|
+
// Secure login method
|
|
231
|
+
const login = async (username, password, deviceName) => {
|
|
280
232
|
if (!storage) throw new Error('Storage not initialized');
|
|
281
233
|
setIsLoading(true);
|
|
282
234
|
setError(null);
|
|
283
235
|
try {
|
|
284
|
-
const response = await oxyServices.
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
refreshToken: response.refreshToken
|
|
293
|
-
// sessionId will be set by backend, but we don't get it in response yet
|
|
236
|
+
const response = await oxyServices.secureLogin(username, password, deviceName);
|
|
237
|
+
|
|
238
|
+
// Create client session object
|
|
239
|
+
const clientSession = {
|
|
240
|
+
sessionId: response.sessionId,
|
|
241
|
+
deviceId: response.deviceId,
|
|
242
|
+
expiresAt: response.expiresAt,
|
|
243
|
+
lastActive: new Date().toISOString()
|
|
294
244
|
};
|
|
295
245
|
|
|
296
|
-
//
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
// Update existing user
|
|
301
|
-
updatedUsers = [...users];
|
|
302
|
-
updatedUsers[existingUserIndex] = newUser;
|
|
303
|
-
} else {
|
|
304
|
-
// Add new user
|
|
305
|
-
updatedUsers = [...users, newUser];
|
|
306
|
-
}
|
|
246
|
+
// Add to sessions list
|
|
247
|
+
const updatedSessions = [...sessions, clientSession];
|
|
248
|
+
setSessions(updatedSessions);
|
|
249
|
+
await saveSessionsToStorage(updatedSessions);
|
|
307
250
|
|
|
308
|
-
//
|
|
309
|
-
|
|
310
|
-
|
|
251
|
+
// Set as active session
|
|
252
|
+
setActiveSessionId(response.sessionId);
|
|
253
|
+
await saveActiveSessionId(response.sessionId);
|
|
311
254
|
|
|
312
|
-
//
|
|
313
|
-
await
|
|
314
|
-
await saveActiveUserId(newUser.id);
|
|
255
|
+
// Get access token for API calls
|
|
256
|
+
await oxyServices.getTokenBySession(response.sessionId);
|
|
315
257
|
|
|
316
|
-
//
|
|
258
|
+
// Load full user data
|
|
259
|
+
const fullUser = await oxyServices.getUserBySession(response.sessionId);
|
|
260
|
+
setUser(fullUser);
|
|
261
|
+
setMinimalUser(response.user);
|
|
317
262
|
if (onAuthStateChange) {
|
|
318
|
-
onAuthStateChange(
|
|
263
|
+
onAuthStateChange(fullUser);
|
|
319
264
|
}
|
|
320
|
-
return
|
|
321
|
-
} catch (
|
|
322
|
-
setError(
|
|
323
|
-
throw
|
|
265
|
+
return fullUser;
|
|
266
|
+
} catch (error) {
|
|
267
|
+
setError(error.message || 'Login failed');
|
|
268
|
+
throw error;
|
|
324
269
|
} finally {
|
|
325
270
|
setIsLoading(false);
|
|
326
271
|
}
|
|
327
272
|
};
|
|
328
273
|
|
|
329
|
-
// Logout method
|
|
330
|
-
const logout = async
|
|
331
|
-
if (!
|
|
332
|
-
setIsLoading(true);
|
|
333
|
-
setError(null);
|
|
274
|
+
// Logout method
|
|
275
|
+
const logout = async targetSessionId => {
|
|
276
|
+
if (!activeSessionId) return;
|
|
334
277
|
try {
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
setUser(nextUser);
|
|
357
|
-
oxyServices.setTokens(nextUser.accessToken, nextUser.refreshToken || nextUser.accessToken);
|
|
358
|
-
await saveActiveUserId(nextUser.id);
|
|
359
|
-
if (onAuthStateChange) {
|
|
360
|
-
onAuthStateChange(nextUser);
|
|
361
|
-
}
|
|
362
|
-
} else {
|
|
363
|
-
// No users left
|
|
364
|
-
setUser(null);
|
|
365
|
-
oxyServices.clearTokens();
|
|
366
|
-
await storage.removeItem(keys.activeUserId);
|
|
367
|
-
if (onAuthStateChange) {
|
|
368
|
-
onAuthStateChange(null);
|
|
369
|
-
}
|
|
278
|
+
const sessionToLogout = targetSessionId || activeSessionId;
|
|
279
|
+
await oxyServices.logoutSecureSession(activeSessionId, sessionToLogout);
|
|
280
|
+
|
|
281
|
+
// Remove session from local storage
|
|
282
|
+
const filteredSessions = sessions.filter(s => s.sessionId !== sessionToLogout);
|
|
283
|
+
setSessions(filteredSessions);
|
|
284
|
+
await saveSessionsToStorage(filteredSessions);
|
|
285
|
+
|
|
286
|
+
// If logging out active session
|
|
287
|
+
if (sessionToLogout === activeSessionId) {
|
|
288
|
+
if (filteredSessions.length > 0) {
|
|
289
|
+
// Switch to another session
|
|
290
|
+
await switchToSession(filteredSessions[0].sessionId);
|
|
291
|
+
} else {
|
|
292
|
+
// No sessions left
|
|
293
|
+
setActiveSessionId(null);
|
|
294
|
+
setUser(null);
|
|
295
|
+
setMinimalUser(null);
|
|
296
|
+
await storage?.removeItem(keys.activeSessionId);
|
|
297
|
+
if (onAuthStateChange) {
|
|
298
|
+
onAuthStateChange(null);
|
|
370
299
|
}
|
|
371
300
|
}
|
|
372
|
-
|
|
373
|
-
// Save updated users list
|
|
374
|
-
await saveUsersToStorage(updatedUsers);
|
|
375
301
|
}
|
|
376
|
-
} catch (
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
} finally {
|
|
380
|
-
setIsLoading(false);
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.error('Logout error:', error);
|
|
304
|
+
setError('Logout failed');
|
|
381
305
|
}
|
|
382
306
|
};
|
|
383
307
|
|
|
384
|
-
// Logout all
|
|
308
|
+
// Logout all sessions
|
|
385
309
|
const logoutAll = async () => {
|
|
386
|
-
if (!
|
|
387
|
-
setIsLoading(true);
|
|
388
|
-
setError(null);
|
|
310
|
+
if (!activeSessionId) return;
|
|
389
311
|
try {
|
|
390
|
-
|
|
391
|
-
for (const userItem of users) {
|
|
392
|
-
try {
|
|
393
|
-
oxyServices.setTokens(userItem.accessToken, userItem.refreshToken || userItem.accessToken);
|
|
394
|
-
await oxyServices.logout();
|
|
395
|
-
} catch (logoutError) {
|
|
396
|
-
console.warn(`Logout failed for user ${userItem.id}:`, logoutError);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
312
|
+
await oxyServices.logoutAllSecureSessions(activeSessionId);
|
|
399
313
|
|
|
400
|
-
// Clear all
|
|
401
|
-
|
|
314
|
+
// Clear all local data
|
|
315
|
+
setSessions([]);
|
|
316
|
+
setActiveSessionId(null);
|
|
402
317
|
setUser(null);
|
|
403
|
-
|
|
318
|
+
setMinimalUser(null);
|
|
404
319
|
await clearAllStorage();
|
|
405
|
-
|
|
406
|
-
// Notify about auth state change
|
|
407
320
|
if (onAuthStateChange) {
|
|
408
321
|
onAuthStateChange(null);
|
|
409
322
|
}
|
|
410
|
-
} catch (
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
} finally {
|
|
414
|
-
setIsLoading(false);
|
|
415
|
-
}
|
|
416
|
-
};
|
|
417
|
-
|
|
418
|
-
// Switch user
|
|
419
|
-
const switchUser = async userId => {
|
|
420
|
-
if (!storage) throw new Error('Storage not initialized');
|
|
421
|
-
setError(null);
|
|
422
|
-
try {
|
|
423
|
-
const targetUser = users.find(u => u.id === userId);
|
|
424
|
-
if (!targetUser) {
|
|
425
|
-
throw new Error('User not found');
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// Validate tokens before switching
|
|
429
|
-
oxyServices.setTokens(targetUser.accessToken, targetUser.refreshToken || targetUser.accessToken);
|
|
430
|
-
const isValid = await oxyServices.validate();
|
|
431
|
-
if (!isValid) {
|
|
432
|
-
// Remove invalid user
|
|
433
|
-
await removeUser(userId);
|
|
434
|
-
throw new Error('User session is invalid');
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// Switch to the user
|
|
438
|
-
setUser(targetUser);
|
|
439
|
-
await saveActiveUserId(userId);
|
|
440
|
-
|
|
441
|
-
// Notify about auth state change
|
|
442
|
-
if (onAuthStateChange) {
|
|
443
|
-
onAuthStateChange(targetUser);
|
|
444
|
-
}
|
|
445
|
-
} catch (err) {
|
|
446
|
-
setError(err.message || 'Switch user failed');
|
|
447
|
-
throw err;
|
|
323
|
+
} catch (error) {
|
|
324
|
+
console.error('Logout all error:', error);
|
|
325
|
+
setError('Logout all failed');
|
|
448
326
|
}
|
|
449
327
|
};
|
|
450
328
|
|
|
451
|
-
//
|
|
452
|
-
const
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
const updatedUsers = users.filter(u => u.id !== userId);
|
|
456
|
-
setUsers(updatedUsers);
|
|
457
|
-
|
|
458
|
-
// If removing current user, switch to another or clear
|
|
459
|
-
if (userId === user?.id) {
|
|
460
|
-
if (updatedUsers.length > 0) {
|
|
461
|
-
await switchUser(updatedUsers[0].id);
|
|
462
|
-
} else {
|
|
463
|
-
setUser(null);
|
|
464
|
-
oxyServices.clearTokens();
|
|
465
|
-
await storage.removeItem(keys.activeUserId);
|
|
466
|
-
if (onAuthStateChange) {
|
|
467
|
-
onAuthStateChange(null);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
// Save updated users list
|
|
473
|
-
await saveUsersToStorage(updatedUsers);
|
|
474
|
-
} catch (err) {
|
|
475
|
-
setError(err.message || 'Remove user failed');
|
|
476
|
-
throw err;
|
|
477
|
-
}
|
|
329
|
+
// Sign up method (placeholder - you can implement based on your needs)
|
|
330
|
+
const signUp = async (username, email, password) => {
|
|
331
|
+
// Implement sign up logic similar to secureLogin
|
|
332
|
+
throw new Error('Sign up not implemented yet');
|
|
478
333
|
};
|
|
479
334
|
|
|
480
|
-
//
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
const targetUserId = userId || user?.id;
|
|
484
|
-
if (!targetUserId) return [];
|
|
485
|
-
const targetUser = users.find(u => u.id === targetUserId);
|
|
486
|
-
if (!targetUser) return [];
|
|
487
|
-
|
|
488
|
-
// Store current tokens to restore later
|
|
489
|
-
const currentUser = user;
|
|
490
|
-
const wasCurrentUser = targetUserId === user?.id;
|
|
491
|
-
if (!wasCurrentUser) {
|
|
492
|
-
// Temporarily switch to target user's tokens
|
|
493
|
-
oxyServices.setTokens(targetUser.accessToken, targetUser.refreshToken || targetUser.accessToken);
|
|
494
|
-
}
|
|
495
|
-
try {
|
|
496
|
-
// Use the new OxyServices method
|
|
497
|
-
const sessions = await oxyServices.getUserSessions();
|
|
498
|
-
return sessions;
|
|
499
|
-
} finally {
|
|
500
|
-
if (!wasCurrentUser && currentUser) {
|
|
501
|
-
// Restore original tokens
|
|
502
|
-
oxyServices.setTokens(currentUser.accessToken, currentUser.refreshToken || currentUser.accessToken);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
} catch (err) {
|
|
506
|
-
console.error('Get user sessions failed:', err);
|
|
507
|
-
return [];
|
|
508
|
-
}
|
|
335
|
+
// Switch session method
|
|
336
|
+
const switchSession = async sessionId => {
|
|
337
|
+
await switchToSession(sessionId);
|
|
509
338
|
};
|
|
510
339
|
|
|
511
|
-
//
|
|
512
|
-
const
|
|
513
|
-
|
|
514
|
-
const targetUserId = userId || user?.id;
|
|
515
|
-
if (!targetUserId) return;
|
|
516
|
-
const targetUser = users.find(u => u.id === targetUserId);
|
|
517
|
-
if (!targetUser) return;
|
|
518
|
-
|
|
519
|
-
// Store current tokens to restore later
|
|
520
|
-
const currentUser = user;
|
|
521
|
-
const wasCurrentUser = targetUserId === user?.id;
|
|
522
|
-
if (!wasCurrentUser) {
|
|
523
|
-
// Temporarily switch to target user's tokens
|
|
524
|
-
oxyServices.setTokens(targetUser.accessToken, targetUser.refreshToken || targetUser.accessToken);
|
|
525
|
-
}
|
|
526
|
-
try {
|
|
527
|
-
// Use the new OxyServices method
|
|
528
|
-
await oxyServices.logoutSession(sessionId);
|
|
529
|
-
|
|
530
|
-
// If this is the current user's session, remove them from local state
|
|
531
|
-
if (wasCurrentUser && sessionId === targetUser.sessionId) {
|
|
532
|
-
await removeUser(targetUserId);
|
|
533
|
-
}
|
|
534
|
-
} finally {
|
|
535
|
-
if (!wasCurrentUser && currentUser) {
|
|
536
|
-
// Restore original tokens
|
|
537
|
-
oxyServices.setTokens(currentUser.accessToken, currentUser.refreshToken || currentUser.accessToken);
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
} catch (err) {
|
|
541
|
-
console.error('Logout session failed:', err);
|
|
542
|
-
throw err;
|
|
543
|
-
}
|
|
340
|
+
// Remove session method
|
|
341
|
+
const removeSession = async sessionId => {
|
|
342
|
+
await logout(sessionId);
|
|
544
343
|
};
|
|
545
344
|
|
|
546
|
-
//
|
|
547
|
-
const
|
|
548
|
-
if (!
|
|
549
|
-
setIsLoading(true);
|
|
550
|
-
setError(null);
|
|
345
|
+
// Refresh sessions method
|
|
346
|
+
const refreshSessions = async () => {
|
|
347
|
+
if (!activeSessionId) return;
|
|
551
348
|
try {
|
|
552
|
-
const
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
} finally {
|
|
567
|
-
setIsLoading(false);
|
|
349
|
+
const serverSessions = await oxyServices.getSessionsBySessionId(activeSessionId);
|
|
350
|
+
|
|
351
|
+
// Update local sessions with server data
|
|
352
|
+
const updatedSessions = serverSessions.map(serverSession => ({
|
|
353
|
+
sessionId: serverSession.sessionId,
|
|
354
|
+
deviceId: serverSession.deviceId,
|
|
355
|
+
expiresAt: new Date().toISOString(),
|
|
356
|
+
// You might want to get this from server
|
|
357
|
+
lastActive: new Date().toISOString()
|
|
358
|
+
}));
|
|
359
|
+
setSessions(updatedSessions);
|
|
360
|
+
await saveSessionsToStorage(updatedSessions);
|
|
361
|
+
} catch (error) {
|
|
362
|
+
console.error('Refresh sessions error:', error);
|
|
568
363
|
}
|
|
569
364
|
};
|
|
570
365
|
|
|
571
|
-
//
|
|
572
|
-
const showBottomSheet = useCallback(screenOrConfig => {
|
|
573
|
-
if (bottomSheetRef?.current) {
|
|
574
|
-
// Expand the bottom sheet
|
|
575
|
-
bottomSheetRef.current.expand();
|
|
576
|
-
if (typeof screenOrConfig === 'string') {
|
|
577
|
-
// If a screen is specified, navigate to it
|
|
578
|
-
if (screenOrConfig && bottomSheetRef.current._navigateToScreen) {
|
|
579
|
-
setTimeout(() => {
|
|
580
|
-
bottomSheetRef.current._navigateToScreen(screenOrConfig);
|
|
581
|
-
}, 100);
|
|
582
|
-
}
|
|
583
|
-
} else if (screenOrConfig && typeof screenOrConfig === 'object' && screenOrConfig.screen) {
|
|
584
|
-
// If an object is passed, navigate and pass props
|
|
585
|
-
if (bottomSheetRef.current._navigateToScreen) {
|
|
586
|
-
setTimeout(() => {
|
|
587
|
-
bottomSheetRef.current._navigateToScreen(screenOrConfig.screen, screenOrConfig.props || {});
|
|
588
|
-
}, 100);
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
}, [bottomSheetRef]);
|
|
593
|
-
const hideBottomSheet = useCallback(() => {
|
|
594
|
-
if (bottomSheetRef?.current) {
|
|
595
|
-
bottomSheetRef.current.close();
|
|
596
|
-
}
|
|
597
|
-
}, [bottomSheetRef]);
|
|
598
|
-
|
|
599
|
-
// Build context value
|
|
366
|
+
// Context value
|
|
600
367
|
const contextValue = {
|
|
601
|
-
// Single user state (current active user)
|
|
602
368
|
user,
|
|
369
|
+
minimalUser,
|
|
370
|
+
sessions,
|
|
371
|
+
activeSessionId,
|
|
603
372
|
isAuthenticated: !!user,
|
|
604
373
|
isLoading,
|
|
605
374
|
error,
|
|
606
|
-
// Multi-user state
|
|
607
|
-
users,
|
|
608
|
-
// Auth methods
|
|
609
375
|
login,
|
|
610
376
|
logout,
|
|
611
377
|
logoutAll,
|
|
612
378
|
signUp,
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
getUserSessions,
|
|
617
|
-
logoutSession,
|
|
618
|
-
// OxyServices instance
|
|
379
|
+
switchSession,
|
|
380
|
+
removeSession,
|
|
381
|
+
refreshSessions,
|
|
619
382
|
oxyServices,
|
|
620
|
-
// Bottom sheet methods
|
|
621
383
|
bottomSheetRef,
|
|
622
|
-
showBottomSheet,
|
|
623
|
-
|
|
384
|
+
showBottomSheet: undefined,
|
|
385
|
+
// Implement as needed
|
|
386
|
+
hideBottomSheet: undefined // Implement as needed
|
|
624
387
|
};
|
|
625
388
|
return /*#__PURE__*/_jsx(OxyContext.Provider, {
|
|
626
389
|
value: contextValue,
|
|
@@ -636,4 +399,5 @@ export const useOxy = () => {
|
|
|
636
399
|
}
|
|
637
400
|
return context;
|
|
638
401
|
};
|
|
402
|
+
export default OxyContext;
|
|
639
403
|
//# sourceMappingURL=OxyContext.js.map
|