@digitaldefiance/express-suite-react-components 2.9.7 → 2.9.9

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 (257) hide show
  1. package/package.json +6 -5
  2. package/src/auth/Private.d.ts +6 -0
  3. package/src/auth/Private.d.ts.map +1 -0
  4. package/src/auth/Private.js +14 -0
  5. package/src/auth/PrivateRoute.d.ts +8 -0
  6. package/src/auth/PrivateRoute.d.ts.map +1 -0
  7. package/src/auth/PrivateRoute.js +23 -0
  8. package/src/auth/UnAuth.d.ts +6 -0
  9. package/src/auth/UnAuth.d.ts.map +1 -0
  10. package/src/auth/UnAuth.js +14 -0
  11. package/src/auth/UnAuthRoute.d.ts +8 -0
  12. package/src/auth/UnAuthRoute.d.ts.map +1 -0
  13. package/src/auth/UnAuthRoute.js +22 -0
  14. package/src/auth/{index.ts → index.d.ts} +2 -1
  15. package/src/auth/index.d.ts.map +1 -0
  16. package/src/auth/index.js +10 -0
  17. package/src/components/ApiAccess.d.ts +16 -0
  18. package/src/components/ApiAccess.d.ts.map +1 -0
  19. package/src/components/ApiAccess.js +70 -0
  20. package/src/components/BackupCodeLoginForm.d.ts +43 -0
  21. package/src/components/BackupCodeLoginForm.d.ts.map +1 -0
  22. package/src/components/BackupCodeLoginForm.js +106 -0
  23. package/src/components/BackupCodesForm.d.ts +26 -0
  24. package/src/components/BackupCodesForm.d.ts.map +1 -0
  25. package/src/components/BackupCodesForm.js +108 -0
  26. package/src/components/ChangePasswordForm.d.ts +26 -0
  27. package/src/components/ChangePasswordForm.d.ts.map +1 -0
  28. package/src/components/ChangePasswordForm.js +66 -0
  29. package/src/components/ConfirmationDialog.d.ts +13 -0
  30. package/src/components/ConfirmationDialog.d.ts.map +1 -0
  31. package/src/components/ConfirmationDialog.js +10 -0
  32. package/src/components/CurrencyCodeSelector.d.ts +9 -0
  33. package/src/components/CurrencyCodeSelector.d.ts.map +1 -0
  34. package/src/components/CurrencyCodeSelector.js +31 -0
  35. package/src/components/CurrencyInput.d.ts +13 -0
  36. package/src/components/CurrencyInput.d.ts.map +1 -0
  37. package/src/components/CurrencyInput.js +22 -0
  38. package/src/components/DashboardPage.d.ts +8 -0
  39. package/src/components/DashboardPage.d.ts.map +1 -0
  40. package/src/components/DashboardPage.js +10 -0
  41. package/src/components/DropdownMenu.d.ts +9 -0
  42. package/src/components/DropdownMenu.d.ts.map +1 -0
  43. package/src/components/DropdownMenu.js +56 -0
  44. package/src/components/ExpirationSecondsSelector.d.ts +13 -0
  45. package/src/components/ExpirationSecondsSelector.d.ts.map +1 -0
  46. package/src/components/ExpirationSecondsSelector.js +32 -0
  47. package/src/components/Flag.d.ts +20 -0
  48. package/src/components/Flag.d.ts.map +1 -0
  49. package/src/components/Flag.js +43 -0
  50. package/src/components/ForgotPasswordForm.d.ts +18 -0
  51. package/src/components/ForgotPasswordForm.d.ts.map +1 -0
  52. package/src/components/ForgotPasswordForm.js +54 -0
  53. package/src/components/LoginForm.d.ts +44 -0
  54. package/src/components/LoginForm.d.ts.map +1 -0
  55. package/src/components/LoginForm.js +99 -0
  56. package/src/components/LogoutPage.d.ts +8 -0
  57. package/src/components/LogoutPage.d.ts.map +1 -0
  58. package/src/components/LogoutPage.js +16 -0
  59. package/src/components/RegisterForm.d.ts +54 -0
  60. package/src/components/RegisterForm.d.ts.map +1 -0
  61. package/src/components/RegisterForm.js +105 -0
  62. package/src/components/ResetPasswordForm.d.ts +23 -0
  63. package/src/components/ResetPasswordForm.d.ts.map +1 -0
  64. package/src/components/ResetPasswordForm.js +68 -0
  65. package/src/components/SideMenu.d.ts +8 -0
  66. package/src/components/SideMenu.d.ts.map +1 -0
  67. package/src/components/SideMenu.js +25 -0
  68. package/src/components/SideMenuListItem.d.ts +13 -0
  69. package/src/components/SideMenuListItem.d.ts.map +1 -0
  70. package/src/components/SideMenuListItem.js +44 -0
  71. package/src/components/TopMenu.d.ts +24 -0
  72. package/src/components/TopMenu.d.ts.map +1 -0
  73. package/src/components/TopMenu.js +42 -0
  74. package/src/components/TranslatedTitle.d.ts +7 -0
  75. package/src/components/TranslatedTitle.d.ts.map +1 -0
  76. package/src/components/TranslatedTitle.js +15 -0
  77. package/src/components/UserLanguageSelector.d.ts +4 -0
  78. package/src/components/UserLanguageSelector.d.ts.map +1 -0
  79. package/src/components/UserLanguageSelector.js +31 -0
  80. package/src/components/UserMenu.d.ts +4 -0
  81. package/src/components/UserMenu.d.ts.map +1 -0
  82. package/src/components/UserMenu.js +12 -0
  83. package/src/components/UserSettingsForm.d.ts +56 -0
  84. package/src/components/UserSettingsForm.d.ts.map +1 -0
  85. package/src/components/UserSettingsForm.js +93 -0
  86. package/src/components/VerifyEmailPage.d.ts +23 -0
  87. package/src/components/VerifyEmailPage.d.ts.map +1 -0
  88. package/src/components/VerifyEmailPage.js +61 -0
  89. package/src/components/{index.ts → index.d.ts} +1 -1
  90. package/src/components/index.d.ts.map +1 -0
  91. package/src/components/index.js +28 -0
  92. package/src/contexts/AuthProvider.d.ts +152 -0
  93. package/src/contexts/AuthProvider.d.ts.map +1 -0
  94. package/src/contexts/AuthProvider.js +446 -0
  95. package/src/contexts/I18nProvider.d.ts +16 -0
  96. package/src/contexts/I18nProvider.d.ts.map +1 -0
  97. package/src/contexts/I18nProvider.js +46 -0
  98. package/src/contexts/MenuContext.d.ts +20 -0
  99. package/src/contexts/MenuContext.d.ts.map +1 -0
  100. package/src/contexts/MenuContext.js +244 -0
  101. package/src/contexts/SuiteConfigProvider.d.ts +44 -0
  102. package/src/contexts/SuiteConfigProvider.d.ts.map +1 -0
  103. package/src/contexts/SuiteConfigProvider.js +43 -0
  104. package/src/contexts/ThemeProvider.d.ts +15 -0
  105. package/src/contexts/ThemeProvider.d.ts.map +1 -0
  106. package/src/contexts/ThemeProvider.js +36 -0
  107. package/src/contexts/{index.ts → index.d.ts} +1 -0
  108. package/src/contexts/index.d.ts.map +1 -0
  109. package/src/contexts/index.js +8 -0
  110. package/src/hooks/{index.ts → index.d.ts} +1 -0
  111. package/src/hooks/index.d.ts.map +1 -0
  112. package/src/hooks/index.js +8 -0
  113. package/src/hooks/useBackupCodes.d.ts +15 -0
  114. package/src/hooks/useBackupCodes.d.ts.map +1 -0
  115. package/src/hooks/useBackupCodes.js +70 -0
  116. package/src/hooks/useEmailVerification.d.ts +10 -0
  117. package/src/hooks/useEmailVerification.d.ts.map +1 -0
  118. package/src/hooks/useEmailVerification.js +36 -0
  119. package/src/hooks/useExpiringValue.d.ts +14 -0
  120. package/src/hooks/useExpiringValue.d.ts.map +1 -0
  121. package/src/hooks/useExpiringValue.js +53 -0
  122. package/src/hooks/useLocalStorage.d.ts +2 -0
  123. package/src/hooks/useLocalStorage.d.ts.map +1 -0
  124. package/src/hooks/useLocalStorage.js +15 -0
  125. package/src/hooks/useUserSettings.d.ts +46 -0
  126. package/src/hooks/useUserSettings.d.ts.map +1 -0
  127. package/src/hooks/useUserSettings.js +152 -0
  128. package/src/{index.ts → index.d.ts} +1 -1
  129. package/src/index.d.ts.map +1 -0
  130. package/src/index.js +12 -0
  131. package/src/interfaces/IAppConfig.d.ts +6 -0
  132. package/src/interfaces/IAppConfig.d.ts.map +1 -0
  133. package/src/interfaces/IAppConfig.js +2 -0
  134. package/src/interfaces/IMenuConfig.d.ts +11 -0
  135. package/src/interfaces/IMenuConfig.d.ts.map +1 -0
  136. package/src/interfaces/IMenuConfig.js +2 -0
  137. package/src/interfaces/IMenuOption.d.ts +58 -0
  138. package/src/interfaces/IMenuOption.d.ts.map +1 -0
  139. package/src/interfaces/IMenuOption.js +2 -0
  140. package/src/interfaces/index.d.ts +4 -0
  141. package/src/interfaces/index.d.ts.map +1 -0
  142. package/src/interfaces/index.js +6 -0
  143. package/src/services/__mocks__/authService.d.ts +21 -0
  144. package/src/services/__mocks__/authService.d.ts.map +1 -0
  145. package/src/services/__mocks__/authService.js +15 -0
  146. package/src/services/api.d.ts +3 -0
  147. package/src/services/api.d.ts.map +1 -0
  148. package/src/services/api.js +14 -0
  149. package/src/services/authService.d.ts +72 -0
  150. package/src/services/authService.d.ts.map +1 -0
  151. package/src/services/authService.js +347 -0
  152. package/src/services/authenticatedApi.d.ts +3 -0
  153. package/src/services/authenticatedApi.d.ts.map +1 -0
  154. package/src/services/authenticatedApi.js +18 -0
  155. package/src/services/index.d.ts +4 -0
  156. package/src/services/index.d.ts.map +1 -0
  157. package/src/services/index.js +6 -0
  158. package/src/types/MenuType.d.ts +11 -0
  159. package/src/types/MenuType.d.ts.map +1 -0
  160. package/src/types/MenuType.js +12 -0
  161. package/src/types/expirationSeconds.d.ts +3 -0
  162. package/src/types/expirationSeconds.d.ts.map +1 -0
  163. package/src/types/expirationSeconds.js +17 -0
  164. package/src/types/index.d.ts +2 -0
  165. package/src/types/index.d.ts.map +1 -0
  166. package/src/types/index.js +4 -0
  167. package/src/types/translation.d.ts +10 -0
  168. package/src/types/translation.d.ts.map +1 -0
  169. package/src/types/translation.js +9 -0
  170. package/src/wrappers/BackupCodeLoginWrapper.d.ts +8 -0
  171. package/src/wrappers/BackupCodeLoginWrapper.d.ts.map +1 -0
  172. package/src/wrappers/BackupCodeLoginWrapper.js +21 -0
  173. package/src/wrappers/BackupCodesWrapper.d.ts +7 -0
  174. package/src/wrappers/BackupCodesWrapper.d.ts.map +1 -0
  175. package/src/wrappers/BackupCodesWrapper.js +17 -0
  176. package/src/wrappers/ChangePasswordFormWrapper.d.ts +8 -0
  177. package/src/wrappers/ChangePasswordFormWrapper.d.ts.map +1 -0
  178. package/src/wrappers/ChangePasswordFormWrapper.js +21 -0
  179. package/src/wrappers/LoginFormWrapper.d.ts +9 -0
  180. package/src/wrappers/LoginFormWrapper.d.ts.map +1 -0
  181. package/src/wrappers/LoginFormWrapper.js +43 -0
  182. package/src/wrappers/LogoutPageWrapper.d.ts +9 -0
  183. package/src/wrappers/LogoutPageWrapper.d.ts.map +1 -0
  184. package/src/wrappers/LogoutPageWrapper.js +21 -0
  185. package/src/wrappers/RegisterFormWrapper.d.ts +9 -0
  186. package/src/wrappers/RegisterFormWrapper.d.ts.map +1 -0
  187. package/src/wrappers/RegisterFormWrapper.js +26 -0
  188. package/src/wrappers/UserSettingsFormWrapper.d.ts +8 -0
  189. package/src/wrappers/UserSettingsFormWrapper.d.ts.map +1 -0
  190. package/src/wrappers/UserSettingsFormWrapper.js +24 -0
  191. package/src/wrappers/VerifyEmailPageWrapper.d.ts +8 -0
  192. package/src/wrappers/VerifyEmailPageWrapper.d.ts.map +1 -0
  193. package/src/wrappers/VerifyEmailPageWrapper.js +20 -0
  194. package/src/wrappers/{index.tsx → index.d.ts} +1 -8
  195. package/src/wrappers/index.d.ts.map +1 -0
  196. package/src/wrappers/index.js +20 -0
  197. package/LICENSE +0 -21
  198. package/src/auth/Private.tsx +0 -17
  199. package/src/auth/PrivateRoute.tsx +0 -28
  200. package/src/auth/UnAuth.tsx +0 -16
  201. package/src/auth/UnAuthRoute.tsx +0 -30
  202. package/src/components/ApiAccess.tsx +0 -134
  203. package/src/components/BackupCodeLoginForm.tsx +0 -314
  204. package/src/components/BackupCodesForm.tsx +0 -198
  205. package/src/components/ChangePasswordForm.tsx +0 -182
  206. package/src/components/ConfirmationDialog.tsx +0 -48
  207. package/src/components/CurrencyCodeSelector.tsx +0 -60
  208. package/src/components/CurrencyInput.tsx +0 -80
  209. package/src/components/DashboardPage.tsx +0 -24
  210. package/src/components/DropdownMenu.tsx +0 -92
  211. package/src/components/ExpirationSecondsSelector.tsx +0 -65
  212. package/src/components/Flag.tsx +0 -53
  213. package/src/components/ForgotPasswordForm.tsx +0 -120
  214. package/src/components/LoginForm.tsx +0 -307
  215. package/src/components/LogoutPage.tsx +0 -21
  216. package/src/components/RegisterForm.tsx +0 -354
  217. package/src/components/ResetPasswordForm.tsx +0 -164
  218. package/src/components/SideMenu.tsx +0 -46
  219. package/src/components/SideMenuListItem.tsx +0 -74
  220. package/src/components/TopMenu.tsx +0 -149
  221. package/src/components/TranslatedTitle.tsx +0 -22
  222. package/src/components/UserLanguageSelector.tsx +0 -45
  223. package/src/components/UserMenu.tsx +0 -15
  224. package/src/components/UserSettingsForm.tsx +0 -328
  225. package/src/components/VerifyEmailPage.tsx +0 -133
  226. package/src/contexts/AuthProvider.spec.tsx +0 -1060
  227. package/src/contexts/AuthProvider.tsx +0 -741
  228. package/src/contexts/I18nProvider.tsx +0 -85
  229. package/src/contexts/MenuContext.tsx +0 -310
  230. package/src/contexts/SuiteConfigProvider.tsx +0 -93
  231. package/src/contexts/ThemeProvider.tsx +0 -67
  232. package/src/hooks/useBackupCodes.ts +0 -85
  233. package/src/hooks/useEmailVerification.ts +0 -39
  234. package/src/hooks/useExpiringValue.ts +0 -78
  235. package/src/hooks/useLocalStorage.ts +0 -18
  236. package/src/hooks/useUserSettings.ts +0 -216
  237. package/src/interfaces/IAppConfig.ts +0 -5
  238. package/src/interfaces/IMenuConfig.ts +0 -11
  239. package/src/interfaces/IMenuOption.ts +0 -55
  240. package/src/interfaces/index.ts +0 -3
  241. package/src/services/__mocks__/authService.ts +0 -14
  242. package/src/services/api.ts +0 -13
  243. package/src/services/authService.ts +0 -422
  244. package/src/services/authenticatedApi.ts +0 -17
  245. package/src/services/index.ts +0 -3
  246. package/src/types/MenuType.ts +0 -15
  247. package/src/types/expirationSeconds.ts +0 -18
  248. package/src/types/index.ts +0 -1
  249. package/src/types/translation.ts +0 -20
  250. package/src/wrappers/BackupCodeLoginWrapper.tsx +0 -35
  251. package/src/wrappers/BackupCodesWrapper.tsx +0 -28
  252. package/src/wrappers/ChangePasswordFormWrapper.tsx +0 -31
  253. package/src/wrappers/LoginFormWrapper.tsx +0 -59
  254. package/src/wrappers/LogoutPageWrapper.tsx +0 -30
  255. package/src/wrappers/RegisterFormWrapper.tsx +0 -48
  256. package/src/wrappers/UserSettingsFormWrapper.tsx +0 -39
  257. package/src/wrappers/VerifyEmailPageWrapper.tsx +0 -27
@@ -1,741 +0,0 @@
1
- import { Member as FrontendMember,
2
- ECIESService,
3
- EmailString,
4
- IECIESConfig,
5
- SecureString,
6
- PasswordLoginService,
7
- Constants as AppConstants,
8
- Pbkdf2Service,
9
- } from '@digitaldefiance/ecies-lib';
10
- import {
11
- CoreLanguageCode,
12
- CurrencyCode,
13
- Timezone,
14
- } from '@digitaldefiance/i18n-lib';
15
- import { Wallet } from '@ethereumjs/wallet';
16
- import {
17
- createContext,
18
- ReactNode,
19
- useCallback,
20
- useContext,
21
- useEffect,
22
- useMemo,
23
- useState,
24
- } from 'react';
25
- import { useI18n } from './I18nProvider';
26
- import { useTheme } from './ThemeProvider';
27
- import { createAuthService } from '../services/authService';
28
- import { createAuthenticatedApiClient } from '../services/authenticatedApi';
29
- import { useExpiringValue } from '../hooks/useExpiringValue';
30
- import { useLocalStorage } from '../hooks/useLocalStorage';
31
- import { useUserSettings } from '../hooks/useUserSettings';
32
- import { ISuccessMessage, IRequestUserDTO, SuiteCoreComponentId, SuiteCoreStringKey, IConstants, IUserSettings } from '@digitaldefiance/suite-core-lib';
33
- import { PaletteMode } from '@mui/material';
34
-
35
- export interface AuthContextData {
36
- /**
37
- * True if the user has a global admin role
38
- */
39
- admin: boolean;
40
- /**
41
- * Counter that increments on login/logout to trigger effects in dependent components
42
- */
43
- authState: number;
44
- /**
45
- * Performs a server side backup-code login
46
- * @param identifier
47
- * @param code
48
- * @param isEmail
49
- * @param recoverMnemonic
50
- * @param newPassword
51
- * @returns
52
- */
53
- backupCodeLogin: (
54
- identifier: string,
55
- code: string,
56
- isEmail: boolean,
57
- recoverMnemonic: boolean,
58
- newPassword?: string,
59
- ) => Promise<
60
- | { token: string; codeCount: number; mnemonic?: string; message?: string }
61
- | { error: string; status?: number }
62
- >;
63
- /**
64
- * Verifies the stored token (if any) and updates auth state
65
- * @returns void
66
- */
67
- checkAuth: () => void;
68
- /**
69
- * Changes the stored browser password login mnemonic
70
- * @param currentPassword
71
- * @param newPassword
72
- * @returns
73
- */
74
- changePassword: (
75
- currentPassword: string,
76
- newPassword: string,
77
- ) => Promise<
78
- | ISuccessMessage
79
- | {
80
- error: string;
81
- errorType?: string | undefined;
82
- }
83
- >;
84
- clearMnemonic: () => void;
85
- clearWallet: () => void;
86
- colorMode?: PaletteMode;
87
- currencyCode?: CurrencyCode;
88
- directLogin: (
89
- mnemonic: SecureString,
90
- username?: string,
91
- email?: EmailString,
92
- expireMnemonicSeconds?: number,
93
- expireWalletSeconds?: number,
94
- ) => Promise<
95
- | { token: string; user: IRequestUserDTO; wallet: Wallet }
96
- | { error: string; errorType?: string }
97
- >;
98
- emailChallengeLogin: (
99
- mnemonic: SecureString,
100
- token: string,
101
- username?: string,
102
- email?: EmailString,
103
- expireMnemonicSeconds?: number,
104
- expireWalletSeconds?: number,
105
- ) => Promise<
106
- | { token: string; user: IRequestUserDTO; wallet: Wallet; message: string }
107
- | { error: string; errorType?: string }
108
- >;
109
- isAuthenticated: boolean;
110
- // True only while the app is determining initial auth state (e.g., on first load or refresh)
111
- isCheckingAuth: boolean;
112
- isBrowserPasswordLoginAvailable?: () => boolean;
113
- loading: boolean;
114
- logout: () => void;
115
- mnemonic?: SecureString;
116
- mnemonicExpirationSeconds: number;
117
- passwordLogin: (password: SecureString, username?: string, email?: EmailString) => Promise<{ token: string; user: IRequestUserDTO; wallet: Wallet } | { error: string; errorType?: string }>;
118
- requestEmailLogin: (
119
- username?: string,
120
- email?: EmailString,
121
- ) => Promise<string | { error: string; errorType?: string }>;
122
- refreshToken: () => Promise<{ token: string; user: IRequestUserDTO }>;
123
- register: (
124
- username: string,
125
- email: string,
126
- timezone: string,
127
- password?: string,
128
- ) => Promise<
129
- | {
130
- success: boolean;
131
- message: string;
132
- mnemonic: string;
133
- }
134
- | {
135
- error: string;
136
- errorType?: string;
137
- field?: string;
138
- errors?: Array<{ path: string; msg: string }>;
139
- }
140
- >;
141
- serverPublicKey: string | null;
142
- /**
143
- * Gets the remaining time in seconds for the mnemonic expiration
144
- * @returns Number of seconds remaining, or 0 if no mnemonic is set
145
- */
146
- getMnemonicRemainingTime: () => number;
147
- /**
148
- * Gets the remaining time in seconds for the wallet expiration
149
- * @returns Number of seconds remaining, or 0 if no wallet is set
150
- */
151
- getWalletRemainingTime: () => number;
152
- setMnemonic: (mnemonic: SecureString, durationSeconds?: number) => void;
153
- setMnemonicExpirationSeconds: (seconds: number) => void;
154
- setWalletExpirationSeconds: (seconds: number) => void;
155
- setUpBrowserPasswordLogin: (mnemonic: SecureString, password: SecureString, username?: string, email?: EmailString) => Promise<{ success: boolean; message: string } | { error: string; errorType?: string }>;
156
- setUser: (user: IRequestUserDTO | null) => Promise<void>;
157
- setUserSetting: (setting?: Partial<IUserSettings>) => Promise<void>;
158
- setWallet: (wallet: Wallet, durationSeconds?: number) => void;
159
- user: FrontendMember | null;
160
- userData: IRequestUserDTO | null;
161
- userSettings: IUserSettings | undefined;
162
- token: string | null;
163
- wallet?: Wallet;
164
- walletExpirationSeconds: number;
165
- verifyToken: (token: string) => Promise<boolean>;
166
- }
167
-
168
- export type AuthProviderProps = {
169
- children: ReactNode;
170
- baseUrl: string;
171
- constants: IConstants;
172
- eciesConfig: IECIESConfig;
173
- /**
174
- * Optional callback to handle navigation after logout
175
- * If not provided, logout will only clear auth state without navigation
176
- */
177
- onLogout?: () => void;
178
- };
179
-
180
- export const AuthContext = createContext<AuthContextData>(
181
- {} as AuthContextData,
182
- );
183
-
184
- const AuthProviderInner = ({ children, baseUrl, constants, eciesConfig, onLogout }: AuthProviderProps) => {
185
- const { t, tComponent } = useI18n();
186
- const { setColorMode: themeSetPaletteMode, mode: colorMode } = useTheme();
187
-
188
- const authService = useMemo(() => createAuthService(constants, baseUrl, eciesConfig), [constants, baseUrl, eciesConfig]);
189
- const authenticatedApi = useMemo(() => createAuthenticatedApiClient(baseUrl), [baseUrl]);
190
-
191
- // Use the custom hooks for expiring values
192
- const mnemonicManager = useExpiringValue<SecureString>(
193
- constants.DefaultExpireMemoryMnemonicSeconds,
194
- 'mnemonicExpirationSeconds'
195
- );
196
- const walletManager = useExpiringValue<Wallet>(
197
- constants.DefaultExpireMemoryWalletSeconds,
198
- 'walletExpirationSeconds'
199
- );
200
-
201
- // Use localStorage hook for expiration settings
202
- const [mnemonicExpirationSeconds, _setMnemonicExpirationSeconds] = useLocalStorage(
203
- 'mnemonicExpirationSeconds',
204
- constants.DefaultExpireMemoryMnemonicSeconds
205
- );
206
- const [walletExpirationSeconds, _setWalletExpirationSeconds] = useLocalStorage(
207
- 'walletExpirationSeconds',
208
- constants.DefaultExpireMemoryWalletSeconds
209
- );
210
- const [serverPublicKey, setServerPublicKey] = useState<string | null>(null);
211
- const [user, setUser] = useState<IRequestUserDTO | null>(null);
212
- const [frontendUser, setFrontendUser] =
213
- useState<FrontendMember | null>(null);
214
- const [isAuthenticated, setIsAuthenticated] = useState(false);
215
- const [isGlobalAdmin, setIsGlobalAdmin] = useState(false);
216
- const [loading, setLoading] = useState(true);
217
- // Separate flag so route guards don't unmount during actions (e.g., register/login)
218
- const [isCheckingAuth, setIsCheckingAuth] = useState(true);
219
- const [token, setToken] = useState<string | null>(null);
220
- const [authState, setAuthState] = useState(0);
221
-
222
- // Use the user settings hook for settings management
223
- const { userSettings, setUserSettingAndUpdateSettings } = useUserSettings({
224
- authenticatedApi,
225
- isAuthenticated,
226
- });
227
-
228
- // Helper functions to calculate remaining time (now provided by the hooks)
229
- const getMnemonicRemainingTime = mnemonicManager.getRemainingTime;
230
- const getWalletRemainingTime = walletManager.getRemainingTime;
231
-
232
- // Wrapper functions to match the interface (the localStorage hook handles storage automatically)
233
- const setMnemonicExpirationSeconds = _setMnemonicExpirationSeconds;
234
- const setWalletExpirationSeconds = _setWalletExpirationSeconds;
235
-
236
- // Sync user language with i18n provider when the user's saved language changes.
237
- // Important: do NOT depend on currentLanguage here, or we'll run when the UI
238
- // language changes and inadvertently revert to the older user.siteLanguage,
239
- // causing a second update request with English US.
240
- useEffect(() => {
241
- if (user?.siteLanguage) {
242
- (async () => {
243
- await setUserSettingAndUpdateSettings({ siteLanguage: user.siteLanguage });
244
- })();
245
- }
246
- // We intentionally only react to changes in the user's saved language.
247
- // eslint-disable-next-line react-hooks/exhaustive-deps
248
- }, [user?.siteLanguage]);
249
-
250
- const setMnemonic = useCallback((mnemonic: SecureString, durationSeconds?: number) => {
251
- const finalDurationSeconds = durationSeconds ?? mnemonicExpirationSeconds;
252
-
253
- // Store the duration to localStorage if provided
254
- if (durationSeconds !== undefined) {
255
- _setMnemonicExpirationSeconds(durationSeconds);
256
- }
257
-
258
- // Only save to storage if a custom duration was provided
259
- return mnemonicManager.setValue(mnemonic, finalDurationSeconds, durationSeconds !== undefined);
260
- }, [mnemonicExpirationSeconds, mnemonicManager.setValue, _setMnemonicExpirationSeconds]);
261
-
262
- const setWallet = useCallback((wallet: Wallet, durationSeconds?: number) => {
263
- const finalDurationSeconds = durationSeconds ?? walletExpirationSeconds;
264
-
265
- // Store the duration to localStorage if provided
266
- if (durationSeconds !== undefined) {
267
- _setWalletExpirationSeconds(durationSeconds);
268
- }
269
-
270
- // Only save to storage if a custom duration was provided
271
- return walletManager.setValue(wallet, finalDurationSeconds, durationSeconds !== undefined);
272
- }, [walletExpirationSeconds, walletManager.setValue, _setWalletExpirationSeconds]);
273
-
274
- const clearMnemonic = mnemonicManager.clearValue;
275
- const clearWallet = walletManager.clearValue;
276
-
277
- const checkAuth = useCallback(async () => {
278
- const token = localStorage.getItem('authToken');
279
- if (!token) {
280
- setUser(null);
281
- setIsAuthenticated(false);
282
- setLoading(false);
283
- setIsCheckingAuth(false);
284
- setToken(null);
285
- setFrontendUser(null);
286
- setServerPublicKey(null);
287
- await setUserSettingAndUpdateSettings(undefined);
288
- themeSetPaletteMode('light');
289
- clearMnemonic();
290
- clearWallet();
291
- return;
292
- }
293
-
294
- try {
295
- const userData = await authService.verifyToken(token);
296
- if ('error' in userData && typeof userData.error === 'string') {
297
- setIsAuthenticated(false);
298
- setToken(null);
299
- } else if ('id' in userData && 'email' in userData) {
300
- const userDataDTO: IRequestUserDTO = userData as IRequestUserDTO;
301
- setUser(userDataDTO);
302
- setIsGlobalAdmin(
303
- (userDataDTO).roles.some((r) => r.admin),
304
- );
305
- setIsAuthenticated(true);
306
- setToken(token);
307
- await setUserSettingAndUpdateSettings({
308
- darkMode: userDataDTO.darkMode,
309
- currency: new CurrencyCode(userDataDTO.currency),
310
- timezone: new Timezone(userDataDTO.timezone),
311
- siteLanguage: userDataDTO.siteLanguage as CoreLanguageCode,
312
- email: new EmailString(userDataDTO.email),
313
- directChallenge: userDataDTO.directChallenge,
314
- })
315
- }
316
- } catch (error) {
317
- console.error('Token verification failed:', error);
318
- setUser(null);
319
- setIsAuthenticated(false);
320
- await setUserSettingAndUpdateSettings(undefined);
321
- localStorage.removeItem('authToken');
322
- } finally {
323
- setLoading(false);
324
- setIsCheckingAuth(false);
325
- }
326
- }, [authService, clearMnemonic, clearWallet, setUserSettingAndUpdateSettings, themeSetPaletteMode]);
327
-
328
- useEffect(() => {
329
- const token = localStorage.getItem('authToken');
330
- if (token) {
331
- (async () => {
332
- await checkAuth();
333
- })();
334
- } else {
335
- setLoading(false);
336
- setIsCheckingAuth(false);
337
- }
338
- // eslint-disable-next-line react-hooks/exhaustive-deps
339
- }, [authState]); // Only run when authState changes (login/logout), not when checkAuth is recreated
340
-
341
- const directLogin: AuthContextData['directLogin'] = useCallback(
342
- async (mnemonic, username, email, expireMnemonicSeconds, expireWalletSeconds) => {
343
- setLoading(true);
344
- const loginResult = await authService.directLogin(
345
- mnemonic,
346
- username,
347
- email,
348
- );
349
- setLoading(false);
350
- if (
351
- typeof loginResult === 'object' &&
352
- 'token' in loginResult &&
353
- 'user' in loginResult &&
354
- 'wallet' in loginResult
355
- ) {
356
- setMnemonic(mnemonic, expireMnemonicSeconds);
357
- setUser(loginResult.user);
358
- setWallet(loginResult.wallet, expireWalletSeconds);
359
- setIsAuthenticated(true);
360
- setAuthState((prev) => prev + 1);
361
- localStorage.setItem('authToken', loginResult.token);
362
- localStorage.setItem('user', JSON.stringify(loginResult.user));
363
- await setUserSettingAndUpdateSettings({
364
- darkMode: loginResult.user.darkMode,
365
- currency: new CurrencyCode(loginResult.user.currency),
366
- timezone: new Timezone(loginResult.user.timezone),
367
- siteLanguage: loginResult.user.siteLanguage as CoreLanguageCode,
368
- email: new EmailString(loginResult.user.email),
369
- directChallenge: loginResult.user.directChallenge,
370
- });
371
- return loginResult;
372
- }
373
- return loginResult;
374
- },
375
- [authService, setMnemonic, setWallet, setUserSettingAndUpdateSettings],
376
- );
377
-
378
- const emailChallengeLogin: AuthContextData['emailChallengeLogin'] =
379
- useCallback(async (mnemonic, token, username, email, expireMnemonicSeconds, expireWalletSeconds) => {
380
- setLoading(true);
381
- const loginResult = await authService.emailChallengeLogin(
382
- mnemonic,
383
- token,
384
- username,
385
- email,
386
- );
387
- setLoading(false);
388
- if (
389
- typeof loginResult === 'object' &&
390
- 'token' in loginResult &&
391
- 'user' in loginResult &&
392
- 'wallet' in loginResult
393
- ) {
394
- setMnemonic(mnemonic, expireMnemonicSeconds);
395
- setUser(loginResult.user);
396
- setWallet(loginResult.wallet, expireWalletSeconds);
397
- setIsAuthenticated(true);
398
- setAuthState((prev) => prev + 1);
399
- localStorage.setItem('authToken', loginResult.token);
400
- localStorage.setItem('user', JSON.stringify(loginResult.user));
401
- await setUserSettingAndUpdateSettings({
402
- darkMode: loginResult.user.darkMode,
403
- currency: new CurrencyCode(loginResult.user.currency),
404
- timezone: new Timezone(loginResult.user.timezone),
405
- siteLanguage: loginResult.user.siteLanguage as CoreLanguageCode,
406
- email: new EmailString(loginResult.user.email),
407
- directChallenge: loginResult.user.directChallenge,
408
- });
409
- return loginResult;
410
- }
411
- return loginResult;
412
- }, [authService, setMnemonic, setWallet, setUserSettingAndUpdateSettings]);
413
- const getPasswordLoginService = useCallback(() => {
414
- const eciesService: ECIESService = new ECIESService(eciesConfig);
415
- return new PasswordLoginService(eciesService, new Pbkdf2Service(AppConstants.PBKDF2_PROFILES, AppConstants.ECIES, AppConstants.PBKDF2));
416
- }, [eciesConfig]);
417
-
418
- const isBrowserPasswordLoginAvailable = useCallback(() => {
419
- const storedEncryptedPassword = localStorage.getItem('encryptedPassword');
420
- return !!storedEncryptedPassword;
421
- }, []);
422
-
423
- const passwordLogin: AuthContextData['passwordLogin'] = useCallback(
424
- async (password: SecureString, username?: string, email?: EmailString) => {
425
- if (!isBrowserPasswordLoginAvailable()) {
426
- return { error: tComponent<SuiteCoreStringKey>(SuiteCoreComponentId, SuiteCoreStringKey.Error_Login_PasswordLoginNotSetup), errorType: 'PasswordLoginNotSetup' };
427
- }
428
- setLoading(true);
429
- const passwordLoginService: PasswordLoginService = getPasswordLoginService();
430
- const { wallet, mnemonic } = await passwordLoginService.getWalletAndMnemonicFromLocalStorageBundle(password);
431
- const loginResult = await authService.directLogin(
432
- mnemonic,
433
- username,
434
- email,
435
- );
436
- setLoading(false);
437
- setWallet(wallet);
438
- setMnemonic(mnemonic);
439
- // Set theme based on user's darkMode preference if login succeeded
440
- if ('user' in loginResult) {
441
- await setUserSettingAndUpdateSettings({
442
- darkMode: loginResult.user.darkMode,
443
- currency: new CurrencyCode(loginResult.user.currency),
444
- timezone: new Timezone(loginResult.user.timezone),
445
- siteLanguage: loginResult.user.siteLanguage as CoreLanguageCode,
446
- email: new EmailString(loginResult.user.email),
447
- directChallenge: loginResult.user.directChallenge,
448
- });
449
- }
450
- return loginResult;
451
- },
452
- [authService, getPasswordLoginService, setMnemonic, setWallet, t, tComponent, isBrowserPasswordLoginAvailable, setUserSettingAndUpdateSettings]
453
- );
454
-
455
- const refreshToken: AuthContextData['refreshToken'] =
456
- useCallback(async () => {
457
- try {
458
- const result = await authService.refreshToken();
459
- localStorage.setItem('authToken', result.token);
460
- localStorage.setItem('user', JSON.stringify(result.user));
461
- setUser(result.user);
462
- setIsAuthenticated(true);
463
- return result;
464
- } catch (error) {
465
- setUser(null);
466
- setIsAuthenticated(false);
467
- localStorage.removeItem('authToken');
468
- localStorage.removeItem('user');
469
- throw error;
470
- }
471
- }, [authService]);
472
-
473
- const register: AuthContextData['register'] = useCallback(
474
- async (
475
- username: string,
476
- email: string,
477
- timezone: string,
478
- password?: string,
479
- ) => {
480
- const registerResult = await authService.register(
481
- username,
482
- email,
483
- timezone,
484
- password,
485
- );
486
- return registerResult as Awaited<ReturnType<AuthContextData['register']>>;
487
- },
488
- [baseUrl],
489
- );
490
-
491
- const requestEmailLogin = useCallback(
492
- async (
493
- username?: string,
494
- email?: EmailString,
495
- ): Promise<string | { error: string; errorType?: string }> => {
496
- setLoading(true);
497
- const result = await authService.requestEmailLogin(username, email);
498
- setLoading(false);
499
- return result;
500
- },
501
- [baseUrl],
502
- );
503
-
504
- const setUpBrowserPasswordLogin = useCallback(
505
- async (mnemonic: SecureString, password: SecureString, username?: string, email?: EmailString): Promise<{ success: boolean; message: string } | { error: string; errorType?: string }> => {
506
- setLoading(true);
507
- const passwordLoginService: PasswordLoginService = getPasswordLoginService();
508
- try {
509
- const wallet = await passwordLoginService.setupPasswordLoginLocalStorageBundle(mnemonic, password);
510
- setLoading(false);
511
- setWallet(wallet);
512
- setMnemonic(mnemonic);
513
- return { success: true, message: tComponent<SuiteCoreStringKey>(SuiteCoreComponentId,SuiteCoreStringKey.PasswordLogin_Setup_Success) };
514
- } catch {
515
- setLoading(false);
516
- return { success: false, message: tComponent<SuiteCoreStringKey>(SuiteCoreComponentId, SuiteCoreStringKey.PasswordLogin_Setup_Failure) };
517
- }
518
- },
519
- [setMnemonic, setWallet, t, tComponent],
520
- );
521
-
522
- const backupCodeLogin = useCallback(
523
- async (
524
- identifier: string,
525
- code: string,
526
- isEmail: boolean,
527
- recoverMnemonic: boolean,
528
- newPassword?: string,
529
- ): Promise<
530
- | {
531
- token: string;
532
- codeCount: number;
533
- mnemonic?: string;
534
- message?: string;
535
- }
536
- | { error: string; status?: number }
537
- > => {
538
- setLoading(true);
539
- const loginResult = await authService.backupCodeLogin(
540
- identifier,
541
- code,
542
- isEmail,
543
- recoverMnemonic,
544
- newPassword,
545
- );
546
- setLoading(false);
547
- if (typeof loginResult === 'object' && 'token' in loginResult) {
548
- localStorage.setItem('authToken', loginResult.token);
549
- if (loginResult.user) {
550
- setUser(loginResult.user);
551
- setIsAuthenticated(true);
552
- await setUserSettingAndUpdateSettings({
553
- darkMode: loginResult.user.darkMode,
554
- currency: new CurrencyCode(loginResult.user.currency),
555
- timezone: new Timezone(loginResult.user.timezone),
556
- siteLanguage: loginResult.user.siteLanguage as CoreLanguageCode,
557
- email: new EmailString(loginResult.user.email),
558
- directChallenge: loginResult.user.directChallenge,
559
- });
560
- }
561
- setAuthState((prev) => prev + 1);
562
- return {
563
- token: loginResult.token,
564
- mnemonic: loginResult.mnemonic,
565
- message: loginResult.message,
566
- codeCount: loginResult.codeCount,
567
- };
568
- }
569
- return loginResult;
570
- },
571
- [authService, setUserSettingAndUpdateSettings],
572
- );
573
-
574
- const logout = useCallback(async () => {
575
- localStorage.removeItem('user');
576
- localStorage.removeItem('authToken');
577
- clearMnemonic();
578
- setUser(null);
579
- clearWallet();
580
- setIsAuthenticated(false);
581
- await setUserSettingAndUpdateSettings(undefined);
582
- setAuthState((prev) => prev + 1);
583
-
584
- // Call the optional navigation callback if provided
585
- if (onLogout) {
586
- onLogout();
587
- }
588
- }, [onLogout, clearMnemonic, clearWallet, setUserSettingAndUpdateSettings]);
589
-
590
- const verifyToken = useCallback(async (token: string) => {
591
- const requestUser = await authService.verifyToken(token);
592
- if (typeof requestUser === 'object' && 'error' in requestUser) {
593
- setIsAuthenticated(false);
594
- await setUserSettingAndUpdateSettings(undefined);
595
- return false;
596
- } else {
597
- setUser(requestUser);
598
- setIsAuthenticated(true);
599
- return true;
600
- }
601
- }, [authService, setUserSettingAndUpdateSettings]);
602
-
603
- const changePassword = useCallback(
604
- async (
605
- currentPassword: string,
606
- newPassword: string,
607
- ): Promise<
608
- | ISuccessMessage
609
- | {
610
- error: string;
611
- errorType?: string | undefined;
612
- }
613
- > => {
614
- if (!isBrowserPasswordLoginAvailable()) {
615
- return { error: tComponent<SuiteCoreStringKey>(SuiteCoreComponentId, SuiteCoreStringKey.Error_Login_PasswordLoginNotSetup), errorType: 'PasswordLoginNotSetup' };
616
- }
617
- setLoading(true);
618
- try {
619
- const passwordLoginService: PasswordLoginService = getPasswordLoginService();
620
- const { mnemonic, wallet } = await passwordLoginService.getWalletAndMnemonicFromLocalStorageBundle(new SecureString(currentPassword));
621
- if (!mnemonic) {
622
- setLoading(false);
623
- return { error: tComponent<SuiteCoreStringKey>(SuiteCoreComponentId, SuiteCoreStringKey.PasswordLogin_InvalidCurrentPassword), errorType: 'InvalidCurrentPassword' };
624
- }
625
- await passwordLoginService.setupPasswordLoginLocalStorageBundle(mnemonic, new SecureString(newPassword));
626
- setLoading(false);
627
- setWallet(wallet);
628
- setMnemonic(mnemonic);
629
- return { success: true, message: tComponent<SuiteCoreStringKey>(SuiteCoreComponentId, SuiteCoreStringKey.PasswordChange_Success) };
630
- } catch (error) {
631
- setLoading(false);
632
- return { error: 'Password change failed' };
633
- }
634
- },
635
- [setMnemonic, setWallet, t, tComponent, isBrowserPasswordLoginAvailable],
636
- );
637
-
638
- const contextValue = useMemo(() => {
639
- const setUserAndIsAuthenticated = async (newUser: IRequestUserDTO | null) => {
640
- setUser(newUser);
641
- setIsAuthenticated(!!newUser);
642
- };
643
-
644
- return {
645
- admin: isGlobalAdmin,
646
- authState,
647
- backupCodeLogin,
648
- changePassword,
649
- checkAuth,
650
- clearMnemonic,
651
- clearWallet,
652
- colorMode,
653
- currencyCode: userSettings?.currency,
654
- directLogin,
655
- emailChallengeLogin,
656
- getMnemonicRemainingTime,
657
- getWalletRemainingTime,
658
- isAuthenticated,
659
- isCheckingAuth,
660
- isBrowserPasswordLoginAvailable,
661
- loading,
662
- logout,
663
- mnemonic: mnemonicManager.value,
664
- mnemonicExpirationSeconds,
665
- passwordLogin,
666
- refreshToken,
667
- register,
668
- requestEmailLogin,
669
- serverPublicKey,
670
- setMnemonic,
671
- setMnemonicExpirationSeconds,
672
- setUpBrowserPasswordLogin,
673
- setUser: setUserAndIsAuthenticated,
674
- setUserSetting: setUserSettingAndUpdateSettings,
675
- setWallet,
676
- setWalletExpirationSeconds,
677
- token,
678
- user: frontendUser,
679
- userData: user,
680
- userSettings,
681
- verifyToken,
682
- wallet: walletManager.value,
683
- walletExpirationSeconds,
684
- };
685
- }, [
686
- authenticatedApi,
687
- authState,
688
- backupCodeLogin,
689
- changePassword,
690
- checkAuth,
691
- clearMnemonic,
692
- clearWallet,
693
- colorMode,
694
- directLogin,
695
- emailChallengeLogin,
696
- frontendUser,
697
- getMnemonicRemainingTime,
698
- getWalletRemainingTime,
699
- isAuthenticated,
700
- isCheckingAuth,
701
- isGlobalAdmin,
702
- isBrowserPasswordLoginAvailable,
703
- loading,
704
- logout,
705
- mnemonicManager.value,
706
- mnemonicExpirationSeconds,
707
- passwordLogin,
708
- refreshToken,
709
- register,
710
- requestEmailLogin,
711
- serverPublicKey,
712
- setMnemonic,
713
- setMnemonicExpirationSeconds,
714
- setUpBrowserPasswordLogin,
715
- setUserSettingAndUpdateSettings,
716
- setWallet,
717
- setWalletExpirationSeconds,
718
- token,
719
- user,
720
- userSettings,
721
- verifyToken,
722
- walletManager.value,
723
- walletExpirationSeconds,
724
- ]);
725
-
726
- return (
727
- <AuthContext.Provider value={contextValue}>{children}</AuthContext.Provider>
728
- );
729
- };
730
-
731
- export const AuthProvider = ({ children, baseUrl, constants, eciesConfig, onLogout }: AuthProviderProps) => {
732
- return (
733
- <AuthProviderInner baseUrl={baseUrl} constants={constants} eciesConfig={eciesConfig} onLogout={onLogout}>
734
- {children}
735
- </AuthProviderInner>
736
- );
737
- };
738
-
739
- export const useAuth = () => {
740
- return useContext(AuthContext);
741
- };