@alore/auth-react-ui 1.0.0-alpha

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 (144) hide show
  1. package/LICENSE +504 -0
  2. package/dist/cjs/Auth.d.ts +18 -0
  3. package/dist/cjs/Auth.js +74 -0
  4. package/dist/cjs/Auth.js.map +1 -0
  5. package/dist/cjs/auth/Login.d.ts +15 -0
  6. package/dist/cjs/auth/Login.js +714 -0
  7. package/dist/cjs/auth/Login.js.map +1 -0
  8. package/dist/cjs/auth/Register.d.ts +16 -0
  9. package/dist/cjs/auth/Register.js +633 -0
  10. package/dist/cjs/auth/Register.js.map +1 -0
  11. package/dist/cjs/components/AuthProvider.d.ts +473 -0
  12. package/dist/cjs/components/AuthProvider.js +36 -0
  13. package/dist/cjs/components/AuthProvider.js.map +1 -0
  14. package/dist/cjs/components/BackButton.d.ts +9 -0
  15. package/dist/cjs/components/BackButton.js +28 -0
  16. package/dist/cjs/components/BackButton.js.map +1 -0
  17. package/dist/cjs/components/CheckboxForm.d.ts +12 -0
  18. package/dist/cjs/components/CheckboxForm.js +29 -0
  19. package/dist/cjs/components/CheckboxForm.js.map +1 -0
  20. package/dist/cjs/components/FormRules/helpers/index.d.ts +13 -0
  21. package/dist/cjs/components/FormRules/helpers/index.js +52 -0
  22. package/dist/cjs/components/FormRules/helpers/index.js.map +1 -0
  23. package/dist/cjs/components/FormRules/index.d.ts +11 -0
  24. package/dist/cjs/components/FormRules/index.js +19 -0
  25. package/dist/cjs/components/FormRules/index.js.map +1 -0
  26. package/dist/cjs/components/InputErrorHelperText.d.ts +7 -0
  27. package/dist/cjs/components/InputErrorHelperText.js +10 -0
  28. package/dist/cjs/components/InputErrorHelperText.js.map +1 -0
  29. package/dist/cjs/components/InputForm.d.ts +14 -0
  30. package/dist/cjs/components/InputForm.js +80 -0
  31. package/dist/cjs/components/InputForm.js.map +1 -0
  32. package/dist/cjs/components/InputOTP.d.ts +12 -0
  33. package/dist/cjs/components/InputOTP.js +118 -0
  34. package/dist/cjs/components/InputOTP.js.map +1 -0
  35. package/dist/cjs/components/TermsModal.d.ts +10 -0
  36. package/dist/cjs/components/TermsModal.js +27 -0
  37. package/dist/cjs/components/TermsModal.js.map +1 -0
  38. package/dist/cjs/components/index.d.ts +6 -0
  39. package/dist/cjs/components/index.js +19 -0
  40. package/dist/cjs/components/index.js.map +1 -0
  41. package/dist/cjs/dictionaries/en.json +116 -0
  42. package/dist/cjs/dictionaries/pt.json +116 -0
  43. package/dist/cjs/get-dictionary.d.ts +356 -0
  44. package/dist/cjs/get-dictionary.js +46 -0
  45. package/dist/cjs/get-dictionary.js.map +1 -0
  46. package/dist/cjs/helpers/index.d.ts +8 -0
  47. package/dist/cjs/helpers/index.js +27 -0
  48. package/dist/cjs/helpers/index.js.map +1 -0
  49. package/dist/cjs/hooks/useAuthService.d.ts +1400 -0
  50. package/dist/cjs/hooks/useAuthService.js +15 -0
  51. package/dist/cjs/hooks/useAuthService.js.map +1 -0
  52. package/dist/cjs/hooks/useAuthServiceInstance.d.ts +469 -0
  53. package/dist/cjs/hooks/useAuthServiceInstance.js +13 -0
  54. package/dist/cjs/hooks/useAuthServiceInstance.js.map +1 -0
  55. package/dist/cjs/hooks/useDictionary.d.ts +118 -0
  56. package/dist/cjs/hooks/useDictionary.js +15 -0
  57. package/dist/cjs/hooks/useDictionary.js.map +1 -0
  58. package/dist/cjs/index.d.ts +7 -0
  59. package/dist/cjs/index.js +13 -0
  60. package/dist/cjs/index.js.map +1 -0
  61. package/dist/cjs/machine/index.d.ts +937 -0
  62. package/dist/cjs/machine/index.js +1208 -0
  63. package/dist/cjs/machine/index.js.map +1 -0
  64. package/dist/cjs/machine/index.typegen.d.ts +164 -0
  65. package/dist/cjs/machine/index.typegen.js +4 -0
  66. package/dist/cjs/machine/index.typegen.js.map +1 -0
  67. package/dist/cjs/machine/types.d.ts +324 -0
  68. package/dist/cjs/machine/types.js +3 -0
  69. package/dist/cjs/machine/types.js.map +1 -0
  70. package/dist/cjs/utils/index.d.ts +7 -0
  71. package/dist/cjs/utils/index.js +19 -0
  72. package/dist/cjs/utils/index.js.map +1 -0
  73. package/dist/mjs/Auth.d.ts +18 -0
  74. package/dist/mjs/Auth.js +46 -0
  75. package/dist/mjs/Auth.js.map +1 -0
  76. package/dist/mjs/auth/Login.d.ts +15 -0
  77. package/dist/mjs/auth/Login.js +688 -0
  78. package/dist/mjs/auth/Login.js.map +1 -0
  79. package/dist/mjs/auth/Register.d.ts +16 -0
  80. package/dist/mjs/auth/Register.js +603 -0
  81. package/dist/mjs/auth/Register.js.map +1 -0
  82. package/dist/mjs/components/AuthProvider.d.ts +473 -0
  83. package/dist/mjs/components/AuthProvider.js +9 -0
  84. package/dist/mjs/components/AuthProvider.js.map +1 -0
  85. package/dist/mjs/components/BackButton.d.ts +9 -0
  86. package/dist/mjs/components/BackButton.js +9 -0
  87. package/dist/mjs/components/BackButton.js.map +1 -0
  88. package/dist/mjs/components/CheckboxForm.d.ts +12 -0
  89. package/dist/mjs/components/CheckboxForm.js +10 -0
  90. package/dist/mjs/components/CheckboxForm.js.map +1 -0
  91. package/dist/mjs/components/FormRules/helpers/index.d.ts +13 -0
  92. package/dist/mjs/components/FormRules/helpers/index.js +48 -0
  93. package/dist/mjs/components/FormRules/helpers/index.js.map +1 -0
  94. package/dist/mjs/components/FormRules/index.d.ts +11 -0
  95. package/dist/mjs/components/FormRules/index.js +14 -0
  96. package/dist/mjs/components/FormRules/index.js.map +1 -0
  97. package/dist/mjs/components/InputErrorHelperText.d.ts +7 -0
  98. package/dist/mjs/components/InputErrorHelperText.js +5 -0
  99. package/dist/mjs/components/InputErrorHelperText.js.map +1 -0
  100. package/dist/mjs/components/InputForm.d.ts +14 -0
  101. package/dist/mjs/components/InputForm.js +58 -0
  102. package/dist/mjs/components/InputForm.js.map +1 -0
  103. package/dist/mjs/components/InputOTP.d.ts +12 -0
  104. package/dist/mjs/components/InputOTP.js +93 -0
  105. package/dist/mjs/components/InputOTP.js.map +1 -0
  106. package/dist/mjs/components/TermsModal.d.ts +10 -0
  107. package/dist/mjs/components/TermsModal.js +21 -0
  108. package/dist/mjs/components/TermsModal.js.map +1 -0
  109. package/dist/mjs/components/index.d.ts +6 -0
  110. package/dist/mjs/components/index.js +7 -0
  111. package/dist/mjs/components/index.js.map +1 -0
  112. package/dist/mjs/dictionaries/en.json +116 -0
  113. package/dist/mjs/dictionaries/pt.json +116 -0
  114. package/dist/mjs/get-dictionary.d.ts +356 -0
  115. package/dist/mjs/get-dictionary.js +10 -0
  116. package/dist/mjs/get-dictionary.js.map +1 -0
  117. package/dist/mjs/helpers/index.d.ts +8 -0
  118. package/dist/mjs/helpers/index.js +23 -0
  119. package/dist/mjs/helpers/index.js.map +1 -0
  120. package/dist/mjs/hooks/useAuthService.d.ts +1400 -0
  121. package/dist/mjs/hooks/useAuthService.js +13 -0
  122. package/dist/mjs/hooks/useAuthService.js.map +1 -0
  123. package/dist/mjs/hooks/useAuthServiceInstance.d.ts +469 -0
  124. package/dist/mjs/hooks/useAuthServiceInstance.js +11 -0
  125. package/dist/mjs/hooks/useAuthServiceInstance.js.map +1 -0
  126. package/dist/mjs/hooks/useDictionary.d.ts +118 -0
  127. package/dist/mjs/hooks/useDictionary.js +13 -0
  128. package/dist/mjs/hooks/useDictionary.js.map +1 -0
  129. package/dist/mjs/index.d.ts +7 -0
  130. package/dist/mjs/index.js +6 -0
  131. package/dist/mjs/index.js.map +1 -0
  132. package/dist/mjs/machine/index.d.ts +937 -0
  133. package/dist/mjs/machine/index.js +1189 -0
  134. package/dist/mjs/machine/index.js.map +1 -0
  135. package/dist/mjs/machine/index.typegen.d.ts +164 -0
  136. package/dist/mjs/machine/index.typegen.js +3 -0
  137. package/dist/mjs/machine/index.typegen.js.map +1 -0
  138. package/dist/mjs/machine/types.d.ts +324 -0
  139. package/dist/mjs/machine/types.js +2 -0
  140. package/dist/mjs/machine/types.js.map +1 -0
  141. package/dist/mjs/utils/index.d.ts +7 -0
  142. package/dist/mjs/utils/index.js +16 -0
  143. package/dist/mjs/utils/index.js.map +1 -0
  144. package/package.json +46 -0
@@ -0,0 +1,603 @@
1
+ 'use client';
2
+ import { ArrowRightIcon, EnvelopeIcon } from '@heroicons/react/20/solid';
3
+ import { KeyIcon, LockOpenIcon } from '@heroicons/react/24/outline';
4
+ import { yupResolver } from '@hookform/resolvers/yup';
5
+ import { useGoogleLogin } from '@react-oauth/google';
6
+ import { useActor } from '@xstate/react';
7
+ import { randomBytes } from 'crypto';
8
+ import { Button, Card, Spinner } from 'flowbite-react';
9
+ import jwt_decode from 'jwt-decode';
10
+ import React, { useEffect, useMemo, useRef, useState } from 'react';
11
+ import { useForm, useWatch } from 'react-hook-form';
12
+ import { twMerge } from 'tailwind-merge';
13
+ import * as yup from 'yup';
14
+ import { passwordRules, ruleValidation } from '../components/FormRules/helpers';
15
+ import { verifyEmptyValues } from '../helpers';
16
+ import useDictionary from '../hooks/useDictionary';
17
+ import { aloreLogoBlack, google, metamaskLogo, walletConnectLogo } from '../utils';
18
+ const InputForm = React.lazy(() => import('../components/InputForm'));
19
+ const InputOTP = React.lazy(() => import('../components/InputOTP'));
20
+ const BackButton = React.lazy(() => import('../components/BackButton'));
21
+ const CheckboxForm = React.lazy(() => import('../components/CheckboxForm'));
22
+ const TermsModal = React.lazy(() => import('../components/TermsModal'));
23
+ const FormRules = React.lazy(() => import('../components/FormRules'));
24
+ const envelopIcon = () => React.createElement(EnvelopeIcon, { className: "size-4 text-gray-500" });
25
+ export const Register = ({ locale = 'pt', authServiceInstance, forgeId, logoImage, inviteToken, keyshareWorker, cryptoUtils, }) => {
26
+ const { hashUserInfo, generateSecureHash } = cryptoUtils;
27
+ const dictionary = useDictionary(locale);
28
+ const registerDictionary = dictionary?.auth.register;
29
+ const [secureCode, setSecureCode] = useState('');
30
+ const [sendEmailCooldown, setSendEmailCooldown] = useState(0);
31
+ const [cooldownMultiplier, setCooldownMultiplier] = useState(1);
32
+ const [authState, sendAuth] = useActor(authServiceInstance);
33
+ const intervalRef = useRef();
34
+ const { salt, error: authError, registerUser, googleUser, sessionUser, CCRPublicKey, RCRPublicKey, } = authState.context;
35
+ const [userSalt, setUserSalt] = useState('');
36
+ const [registrationMethod, setRegistrationMethod] = useState('password');
37
+ const login = useGoogleLogin({
38
+ onSuccess: (tokenResponse) => {
39
+ resetUserInfo();
40
+ sendAuth({
41
+ type: 'GOOGLE_LOGIN',
42
+ googleToken: tokenResponse.access_token,
43
+ });
44
+ },
45
+ });
46
+ const handleLogin = () => login();
47
+ const selectRegisterMethod = () => {
48
+ if (registrationMethod === 'password') {
49
+ sendAuth('SELECT_PASSWORD');
50
+ }
51
+ else {
52
+ const nickname = registerUser ? registerUser.nickname : userInfoGetValues('nickname');
53
+ const email = registerUser ? registerUser.email : userInfoGetValues('email');
54
+ const device = hashUserInfo(window.navigator.userAgent);
55
+ sendAuth({
56
+ type: 'START_PASSKEY_REGISTER',
57
+ payload: {
58
+ email,
59
+ nickname,
60
+ device,
61
+ },
62
+ });
63
+ }
64
+ };
65
+ const finishPasskeyRegistration = async () => {
66
+ const publicKey = CCRPublicKey?.publicKey;
67
+ if (!publicKey || !navigator.credentials) {
68
+ sendAuth({
69
+ type: 'PASSKEY_NOT_SUPPORTED',
70
+ payload: { error: registerDictionary?.passkeyNotSupported },
71
+ });
72
+ return;
73
+ }
74
+ // TODO: Validate prf on ios/macos when 18.0 drops
75
+ const email = registerUser ? registerUser.email : userInfoGetValues('email');
76
+ const nickname = registerUser ? registerUser.nickname : userInfoGetValues('nickname');
77
+ const device = hashUserInfo(window.navigator.userAgent);
78
+ const extensions = {
79
+ prf: {
80
+ eval: {
81
+ first: new TextEncoder().encode('Alore'),
82
+ },
83
+ },
84
+ largeBlob: {
85
+ support: 'preferred',
86
+ },
87
+ };
88
+ // eslint-disable-next-line no-undef
89
+ const credentialCreationOptions = {
90
+ publicKey: {
91
+ ...publicKey,
92
+ // @ts-ignore
93
+ challenge: Buffer.from(publicKey.challenge, 'base64'),
94
+ user: {
95
+ // @ts-ignore
96
+ id: Buffer.from(publicKey.user.id, 'base64'),
97
+ name: email,
98
+ displayName: nickname,
99
+ },
100
+ authenticatorSelection: {
101
+ requireResidentKey: true,
102
+ residentKey: 'required',
103
+ userVerification: 'required',
104
+ },
105
+ timeout: 10000,
106
+ // @ts-ignore
107
+ extensions,
108
+ },
109
+ };
110
+ try {
111
+ const _registerCredential = await navigator.credentials
112
+ .create(credentialCreationOptions)
113
+ .catch((err) => {
114
+ console.error('err', err);
115
+ });
116
+ if (!_registerCredential) {
117
+ sendAuth({
118
+ type: 'PASSKEY_NOT_SUPPORTED',
119
+ payload: { error: registerDictionary?.passkeyNotSupported },
120
+ });
121
+ return;
122
+ }
123
+ // eslint-disable-next-line no-undef
124
+ const registerCredential = _registerCredential;
125
+ const extensionResults = registerCredential.getClientExtensionResults();
126
+ // @ts-ignore
127
+ const prfSupported = !!extensionResults?.prf?.enabled;
128
+ // @ts-ignore
129
+ const largeBlobSupported = !!extensionResults?.largeBlob?.supported;
130
+ if (!prfSupported && !largeBlobSupported) {
131
+ sendAuth({
132
+ type: 'PASSKEY_NOT_SUPPORTED',
133
+ payload: { error: registerDictionary?.passkeyNotSupported },
134
+ });
135
+ }
136
+ else {
137
+ sendAuth([
138
+ {
139
+ type: 'FINISH_PASSKEY_REGISTER',
140
+ payload: {
141
+ passkeyRegistration: {
142
+ id: registerCredential.id,
143
+ rawId: Buffer.from(registerCredential.rawId).toString('base64'),
144
+ response: {
145
+ attestationObject: Buffer.from(
146
+ // eslint-disable-next-line no-undef
147
+ registerCredential.response
148
+ .attestationObject).toString('base64'),
149
+ clientDataJSON: Buffer.from(
150
+ // eslint-disable-next-line no-undef
151
+ registerCredential.response
152
+ .clientDataJSON).toString('base64'),
153
+ },
154
+ type: 'public-key',
155
+ },
156
+ email,
157
+ device,
158
+ nickname,
159
+ },
160
+ },
161
+ ]);
162
+ }
163
+ }
164
+ catch (_err) {
165
+ sendAuth({
166
+ type: 'PASSKEY_NOT_SUPPORTED',
167
+ payload: { error: registerDictionary?.passkeyNotSupported },
168
+ });
169
+ }
170
+ };
171
+ const finishPasskeyFirstAuth = async () => {
172
+ const publicKey = RCRPublicKey?.publicKey;
173
+ if (!publicKey || !navigator.credentials) {
174
+ sendAuth('BACK_TO_IDLE');
175
+ return;
176
+ }
177
+ const largeBlob = new Uint8Array(randomBytes(32));
178
+ const extensions = {
179
+ prf: { eval: { first: new TextEncoder().encode('Alore') } },
180
+ largeBlob: {
181
+ write: largeBlob,
182
+ },
183
+ };
184
+ try {
185
+ const firstLoginCredential = (await navigator.credentials.get({
186
+ publicKey: {
187
+ ...publicKey,
188
+ // @ts-ignore
189
+ challenge: Buffer.from(publicKey.challenge, 'base64'),
190
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
191
+ allowCredentials: publicKey.allowCredentials?.map((cred) => ({
192
+ ...cred,
193
+ id: Buffer.from(cred.id, 'base64'),
194
+ })),
195
+ extensions: {
196
+ ...publicKey.extensions,
197
+ // @ts-ignore
198
+ ...extensions,
199
+ },
200
+ },
201
+ // eslint-disable-next-line no-undef
202
+ }));
203
+ if (!firstLoginCredential) {
204
+ sendAuth('BACK_TO_IDLE');
205
+ return;
206
+ }
207
+ const extensionResults = firstLoginCredential.getClientExtensionResults();
208
+ // @ts-ignore
209
+ const prfWritten = !!extensionResults?.prf?.results?.first;
210
+ // @ts-ignore
211
+ const blobWritten = !!extensionResults?.largeBlob?.written;
212
+ let secretFromCredential;
213
+ if (prfWritten) {
214
+ // @ts-ignore
215
+ secretFromCredential = extensionResults?.prf?.results?.first;
216
+ }
217
+ else if (blobWritten) {
218
+ secretFromCredential = largeBlob;
219
+ }
220
+ const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
221
+ if (blobWritten && isSafari) {
222
+ secretFromCredential = largeBlob;
223
+ }
224
+ if (!secretFromCredential) {
225
+ sendAuth({
226
+ type: 'PASSKEY_NOT_SUPPORTED',
227
+ payload: { error: registerDictionary?.passkeyNotSupported },
228
+ });
229
+ return;
230
+ }
231
+ sendAuth({
232
+ type: 'FINISH_PASSKEY_AUTH',
233
+ payload: {
234
+ passkeyAuth: {
235
+ id: firstLoginCredential.id,
236
+ rawId: Buffer.from(firstLoginCredential.rawId).toString('base64'),
237
+ response: {
238
+ authenticatorData: Buffer.from(
239
+ // eslint-disable-next-line no-undef
240
+ firstLoginCredential.response.authenticatorData).toString('base64'),
241
+ clientDataJSON: Buffer.from(
242
+ // eslint-disable-next-line no-undef
243
+ firstLoginCredential.response.clientDataJSON).toString('base64'),
244
+ signature: Buffer.from(
245
+ // eslint-disable-next-line no-undef
246
+ firstLoginCredential.response.signature).toString('base64'),
247
+ userHandle: Buffer.from(
248
+ // @ts-ignore
249
+ firstLoginCredential.response.userHandle || [0]).toString('base64'),
250
+ },
251
+ type: 'public-key',
252
+ },
253
+ },
254
+ });
255
+ if (keyshareWorker) {
256
+ keyshareWorker.postMessage({
257
+ method: 'derive-password',
258
+ payload: {
259
+ password: new TextDecoder().decode(secretFromCredential),
260
+ email: firstLoginCredential.id,
261
+ },
262
+ });
263
+ }
264
+ }
265
+ catch (_err) {
266
+ sendAuth('BACK_TO_IDLE');
267
+ }
268
+ };
269
+ useEffect(() => {
270
+ if (authState.matches('active.register.localCCRSign')) {
271
+ finishPasskeyRegistration();
272
+ }
273
+ }, [authState.matches('active.register.localCCRSign')]);
274
+ useEffect(() => {
275
+ if (authState.matches('active.register.localRCRSign')) {
276
+ finishPasskeyFirstAuth();
277
+ }
278
+ }, [authState.matches('active.register.localRCRSign')]);
279
+ useEffect(() => {
280
+ if (authState.matches('active.register.waitingForRCR')) {
281
+ sendAuth({
282
+ type: 'START_PASSKEY_LOGIN',
283
+ payload: {
284
+ email: registerUser ? registerUser.email : userInfoGetValues('email'),
285
+ },
286
+ });
287
+ }
288
+ }, [authState.matches('active.register.waitingForRCR')]);
289
+ const userInfoFormSchema = yup
290
+ .object({
291
+ email: yup
292
+ .string()
293
+ .required(dictionary?.formValidation.required)
294
+ .email(dictionary?.formValidation.invalidEmail),
295
+ nickname: yup
296
+ .string()
297
+ .matches(/^[a-zA-Z].*$/, dictionary?.formValidation.validName)
298
+ .max(40)
299
+ .required(dictionary?.formValidation.required),
300
+ agreedWithTerms: yup.boolean().isTrue(dictionary?.formValidation.agreeTerms),
301
+ })
302
+ .required();
303
+ const passwordFormSchema = yup
304
+ .object({
305
+ password: yup.string().required(dictionary?.formValidation.required),
306
+ confirmPassword: yup.string().required(dictionary?.formValidation.required),
307
+ })
308
+ .required();
309
+ const userInfoDefaultValues = {
310
+ email: '',
311
+ nickname: '',
312
+ agreedWithTerms: false,
313
+ };
314
+ const { control: userInfoControl, formState: { errors: userInfoErrors, dirtyFields: userInfoDirtyFields }, handleSubmit: userInfoHandleSubmit, setValue: userInfoSetValue, getValues: userInfoGetValues, reset: resetUserInfo, } = useForm({
315
+ resolver: yupResolver(userInfoFormSchema),
316
+ defaultValues: userInfoDefaultValues,
317
+ });
318
+ const passwordDefaultValues = {
319
+ password: '',
320
+ confirmPassword: '',
321
+ };
322
+ const { control: passwordControl, formState: { errors: passwordErrors, dirtyFields: passwordDirtyFields }, handleSubmit: passwordHandleSubmit, getValues: passwordGetValues, } = useForm({
323
+ resolver: yupResolver(passwordFormSchema),
324
+ defaultValues: passwordDefaultValues,
325
+ });
326
+ useWatch({ control: passwordControl, name: 'password' });
327
+ useWatch({ control: passwordControl, name: 'confirmPassword' });
328
+ const isLoading = useMemo(() => authState.matches('active.register.completingRegistration') ||
329
+ authState.matches('active.register.sendingEmail') ||
330
+ authState.matches('active.register.verifyingEmail') ||
331
+ authState.matches('active.register.resendingRegistrationEmail') ||
332
+ authState.matches('active.register.googleLogin') ||
333
+ authState.matches('active.register.retrievingCCR') ||
334
+ authState.matches('active.register.retrievingRCR') ||
335
+ authState.matches('active.register.localCCRSign') ||
336
+ authState.matches('active.register.localRCRSign') ||
337
+ authState.matches('active.register.waitingForRCR') ||
338
+ authState.matches('active.register.sendingPublicCredential') ||
339
+ authState.matches('active.register.sendingAuthPublicCredential') ||
340
+ authState.matches('active.web3Connector.verifyingClaimNftEmail2fa') ||
341
+ authState.matches('active.web3Connector.verifyingEmailEligibility'), [authState.value]);
342
+ useEffect(() => {
343
+ if (registerUser) {
344
+ sendAuth([{ type: 'INITIALIZE', forgeId }, 'SIGN_UP', 'ADVANCE_TO_PASSWORD']);
345
+ }
346
+ else
347
+ sendAuth([{ type: 'INITIALIZE', forgeId }, 'SIGN_UP']);
348
+ }, []);
349
+ useEffect(() => {
350
+ if (inviteToken) {
351
+ try {
352
+ const decoded = jwt_decode(inviteToken);
353
+ const { email, nickname } = decoded;
354
+ userInfoSetValue('email', email);
355
+ userInfoSetValue('nickname', nickname);
356
+ setUserSalt(decoded.salt);
357
+ }
358
+ catch (err) {
359
+ console.error('Invalid inviteToken');
360
+ }
361
+ }
362
+ }, [inviteToken]);
363
+ // TODO new social login logic
364
+ // useEffect(() => {
365
+ // if (
366
+ // status === 'authenticated' &&
367
+ // // @ts-ignore
368
+ // session.user?.provider === 'google' &&
369
+ // authState.matches('active.register.idle')
370
+ // ) {
371
+ // const sessionUser: any = session?.user;
372
+ // signOut({ redirect: false });
373
+ // sendAuth({
374
+ // type: 'GOOGLE_LOGIN',
375
+ // // @ts-ignore
376
+ // googleToken: session?.accessToken,
377
+ // googleUser: {
378
+ // email: sessionUser?.email || '',
379
+ // nickname: sessionUser?.name || '',
380
+ // },
381
+ // });
382
+ // }
383
+ // }, [session]);
384
+ useEffect(() => {
385
+ if (googleUser) {
386
+ sendAuth(['RESET', 'INITIALIZE']);
387
+ }
388
+ }, [googleUser]);
389
+ useEffect(() => {
390
+ if (secureCode.length === 6) {
391
+ onClickSecureCodeSubmit();
392
+ }
393
+ }, [secureCode]);
394
+ useEffect(() => {
395
+ if (sendEmailCooldown <= 0) {
396
+ clearInterval(intervalRef.current);
397
+ }
398
+ }, [sendEmailCooldown]);
399
+ function onClickSecureCodeSubmit() {
400
+ sendAuth({ type: 'VERIFY_EMAIL', payload: { secureCode } });
401
+ setSecureCode('');
402
+ }
403
+ function resendSecureCode() {
404
+ const { email, nickname } = userInfoGetValues();
405
+ sendAuth({
406
+ type: 'RESEND_CODE',
407
+ payload: { email, nickname, isForgeClaim: !!forgeId, locale },
408
+ });
409
+ setSendEmailCooldown(15 * cooldownMultiplier);
410
+ intervalRef.current = setInterval(() => setSendEmailCooldown((state) => state - 1), 1000);
411
+ setCooldownMultiplier((state) => state + 1);
412
+ }
413
+ async function onSubmitUserData(data) {
414
+ if (inviteToken) {
415
+ sendAuth('ADVANCE_TO_PASSWORD');
416
+ }
417
+ else {
418
+ const { email, nickname } = data;
419
+ sendAuth({
420
+ type: 'SEND_REGISTRATION_EMAIL',
421
+ payload: {
422
+ email,
423
+ nickname,
424
+ isForgeClaim: !!forgeId,
425
+ locale,
426
+ },
427
+ });
428
+ }
429
+ }
430
+ async function onSubmitPassword(data) {
431
+ const { password } = data;
432
+ const email = registerUser ? registerUser.email : userInfoGetValues('email');
433
+ const nickname = registerUser ? registerUser.nickname : userInfoGetValues('nickname');
434
+ const { userAgent } = window.navigator;
435
+ const device = hashUserInfo(userAgent);
436
+ const saltWallet = registerUser ? registerUser.salt : salt || userSalt;
437
+ if (saltWallet) {
438
+ if (keyshareWorker) {
439
+ keyshareWorker.postMessage({
440
+ method: 'derive-password',
441
+ payload: { password, email },
442
+ });
443
+ const secureHashArgon2d = await generateSecureHash(password, saltWallet, 'argon2d');
444
+ sendAuth({
445
+ type: 'COMPLETE_REGISTRATION',
446
+ payload: {
447
+ email,
448
+ passwordHash: secureHashArgon2d,
449
+ device,
450
+ nickname,
451
+ },
452
+ });
453
+ }
454
+ }
455
+ }
456
+ const isUserInfoSubmitDisabled = useMemo(() => verifyEmptyValues(userInfoGetValues()), [userInfoGetValues(), userInfoDirtyFields]);
457
+ const isPasswordSubmitDisabled = useMemo(() => {
458
+ const passwordValues = passwordGetValues();
459
+ const userInfoValues = registerUser || userInfoGetValues();
460
+ let isValid = true;
461
+ passwordRules.forEach((rule) => {
462
+ if (!ruleValidation(rule, passwordValues, userInfoValues)) {
463
+ isValid = false;
464
+ }
465
+ });
466
+ return !isValid;
467
+ }, [passwordGetValues(), passwordDirtyFields]);
468
+ const UserInfo = useMemo(() => (React.createElement(React.Fragment, null,
469
+ inviteToken ? (React.createElement("div", { className: "flex flex-col gap-2.5" },
470
+ React.createElement("h1", { className: "text-alr-grey mb-1 text-center text-[1.75rem] font-bold" }, registerDictionary?.welcome),
471
+ React.createElement("div", { className: "mb-5 text-gray-600" },
472
+ registerDictionary?.invitedBy,
473
+ React.createElement("span", { className: "font-semibold" }, " 0xCarbon "),
474
+ registerDictionary?.toJoin,
475
+ React.createElement("span", { className: "text-alr-red" }, " Alore.")))) : (React.createElement("h1", { className: "font-inter mb-1 text-center font-semibold text-gray-600 md:text-lg" }, forgeId ? registerDictionary?.forgeTitle : registerDictionary?.title)),
476
+ authError?.includes('beta') && (React.createElement("span", { className: "font-poppins text-alr-red text-center text-xl font-bold" }, authError)),
477
+ React.createElement("form", { onSubmit: userInfoHandleSubmit((data) => onSubmitUserData(data)), className: "mb-1 flex flex-col gap-y-5", "data-test": "register-new-account-step" },
478
+ React.createElement(InputForm, { control: userInfoControl, errors: userInfoErrors, name: "email", type: "email", placeholder: inviteToken
479
+ ? `${registerDictionary?.emailInvitePlaceholder}`
480
+ : `${registerDictionary?.emailLabel}`, "data-test": "register-email", icon: envelopIcon, autoFocus: true, disabled: isLoading || !!inviteToken }),
481
+ React.createElement(InputForm, { control: userInfoControl, errors: userInfoErrors, name: "nickname", type: "text", placeholder: registerDictionary?.nicknameLabel, "data-test": "register-first-name", disabled: isLoading }),
482
+ React.createElement(CheckboxForm, { className: "flex items-center justify-center", control: userInfoControl, name: "agreedWithTerms", "data-test": "register-agreed-with-terms", label: React.createElement("span", { className: "text-xs font-light text-gray-400 md:text-sm md:font-normal" },
483
+ registerDictionary?.agreeTermsPart1,
484
+ React.createElement("span", { onClick: () => sendAuth('SHOW_TERMS_MODAL'), className: "text-alr-red cursor-pointer underline", "data-test": "terms-of-service" }, registerDictionary?.agreeTermsPart2)) }),
485
+ React.createElement(Button, { "data-test": "register-button", type: "submit", disabled: isUserInfoSubmitDisabled || isLoading, className: "bg-alr-red hover:bg-alr-dark-red group relative flex items-center justify-center rounded-lg border border-transparent p-0.5 text-center font-medium text-white duration-300 focus:z-10 focus:outline-none focus:ring-2 focus:ring-red-300 enabled:hover:bg-red-700 disabled:hover:bg-red-900 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900 dark:enabled:hover:bg-red-700 dark:disabled:hover:bg-red-600" },
486
+ isLoading && React.createElement(Spinner, { className: "mr-2 !h-5 w-6 !fill-gray-300" }),
487
+ registerDictionary?.buttonStart)),
488
+ React.createElement("div", { className: "flex w-full cursor-pointer flex-row items-center justify-center gap-1.5 text-sm text-gray-500", onClick: () => {
489
+ sendAuth(['RESET', { type: 'INITIALIZE', forgeId }, 'LOGIN']);
490
+ } },
491
+ React.createElement("span", { className: "font-inter font-semibold" }, registerDictionary?.alreadyHaveAccount),
492
+ React.createElement(ArrowRightIcon, { className: "size-4" })),
493
+ forgeId && (React.createElement(React.Fragment, null,
494
+ React.createElement("div", { className: "h-[0.5px] w-full bg-gray-300" }),
495
+ React.createElement(Button, { color: "light", onClick: handleLogin, outline: true },
496
+ React.createElement("div", { className: "flex flex-row items-center justify-center gap-2" },
497
+ React.createElement("img", { src: google, alt: "google logo", width: 16 }),
498
+ dictionary?.auth.continueGoogle)),
499
+ React.createElement(Button, { color: "light", onClick: () => sendAuth('LOGIN_WITH_WEB3CONNECTOR'), outline: true },
500
+ React.createElement("div", { className: "flex flex-row items-center justify-center gap-2" },
501
+ React.createElement("div", { className: "relative flex flex-row" },
502
+ React.createElement("img", { src: metamaskLogo, alt: "metamask logo", width: 20, className: "absolute right-3" }),
503
+ React.createElement("img", { src: walletConnectLogo, alt: "walletconnect logo", width: 20 })),
504
+ "Metamask/WalletConnect")))))), [
505
+ isUserInfoSubmitDisabled,
506
+ userInfoControl,
507
+ userInfoErrors,
508
+ userInfoGetValues(),
509
+ userInfoDirtyFields,
510
+ isLoading,
511
+ ]);
512
+ const VerifyEmail = useMemo(() => (React.createElement(React.Fragment, null,
513
+ React.createElement(BackButton, { disabled: isLoading, onClick: () => sendAuth('BACK') }),
514
+ React.createElement("div", { className: "flex w-full flex-col items-center", "data-test": "register-verify-email-step" },
515
+ React.createElement("span", { className: "font-poppins text-alr-grey mb-6 text-2xl font-bold md:text-[1.75rem]" }, registerDictionary?.verifyEmail),
516
+ React.createElement("span", { className: "text-alr-grey mb-6 w-full text-center font-medium" }, registerDictionary?.informCode),
517
+ React.createElement("div", { className: "mb-6 flex" },
518
+ React.createElement(InputOTP, { className: "child:gap-x-3 md:child:gap-x-5 [&>div>input]:!h-9 [&>div>input]:!w-9", value: secureCode, onChange: (value) => setSecureCode(value), inputLength: 6, "data-test": "secure-code", errorMessage: authError?.includes('wrong') ? `${registerDictionary?.wrongCode}` : undefined, disabled: isLoading })),
519
+ React.createElement(Button, { "data-test": "secure-code-submit", onClick: () => onClickSecureCodeSubmit(), className: "bg-alr-red hover:bg-alr-dark-red group relative mb-6 flex w-full items-center justify-center rounded-lg border border-transparent p-0.5 text-center font-medium text-white duration-300 focus:z-10 focus:outline-none focus:ring-2 focus:ring-red-300 enabled:hover:bg-red-700 disabled:hover:bg-red-900 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900 dark:enabled:hover:bg-red-700 dark:disabled:hover:bg-red-600", disabled: secureCode.length !== 6 || isLoading },
520
+ isLoading && React.createElement(Spinner, { className: "mr-3 !h-5 w-full !fill-gray-300" }),
521
+ registerDictionary?.confirmCode),
522
+ React.createElement("span", { onClick: () => resendSecureCode(), className: twMerge(`text-base font-medium duration-300`, sendEmailCooldown > 0
523
+ ? 'pointer-events-none opacity-50'
524
+ : 'hover:text-alr-red cursor-pointer opacity-100') }, `${registerDictionary?.resendCode}${sendEmailCooldown ? ` (${sendEmailCooldown}s)` : ''}`)))), [secureCode, sendEmailCooldown, isLoading]);
525
+ const SelectRegisterMethod = useMemo(() => (React.createElement("div", null,
526
+ React.createElement(BackButton, { disabled: isLoading, onClick: () => sendAuth('BACK') }),
527
+ React.createElement("div", { className: "mt-2 flex w-full flex-col items-center", "data-test": "register-method-selection-step" },
528
+ isLoading && React.createElement(Spinner, { className: "mr-3 !h-5 w-full !fill-gray-300" }),
529
+ authError?.toLocaleLowerCase().includes('passkey') && (React.createElement("span", { className: "font-poppins text-alr-red mb-4 text-center text-xl font-bold" }, registerDictionary?.passkeyNotSupported)),
530
+ React.createElement("span", { className: "font-poppins text-alr-grey mb-6 text-2xl font-bold md:text-[1.75rem]" }, registerDictionary?.selectMethodTitle),
531
+ React.createElement("span", { className: "text-alr-grey mb-6 w-full text-center font-medium" }, registerDictionary?.selectMethodDescription),
532
+ React.createElement("div", { className: "flex flex-col gap-5" },
533
+ React.createElement("div", { className: "flex w-full gap-2" },
534
+ React.createElement(Button, { "data-test": "register-method-selection-password", onClick: () => setRegistrationMethod('password'), color: "light", className: `${registrationMethod === 'password' ? '!border-alr-red' : '!border-gray-500'} child:h-full w-full cursor-pointer items-start border focus:ring-0` },
535
+ React.createElement("div", { className: "flex flex-col items-start justify-center gap-2" },
536
+ React.createElement(LockOpenIcon, { className: `${registrationMethod === 'password' ? 'text-alr-red' : 'text-gray-500'} size-7` }),
537
+ React.createElement("span", { className: "font-semibold text-gray-900" }, registerDictionary?.password),
538
+ React.createElement("span", { className: "text-start text-xs font-normal text-gray-600" }, registerDictionary?.selectMethodPassword))),
539
+ React.createElement(Button, { disabled: typeof window.PublicKeyCredential === 'undefined', "data-test": "register-method-selection-passkey", onClick: () => setRegistrationMethod('passkey'), color: "light", className: `${registrationMethod === 'passkey' ? '!border-alr-red' : '!border-gray-500'} child:h-full w-full cursor-pointer items-start border focus:ring-0` },
540
+ React.createElement("div", { className: "flex flex-col items-start justify-center gap-2" },
541
+ React.createElement(KeyIcon, { className: `${registrationMethod === 'passkey' ? 'text-alr-red' : 'text-gray-500'} size-7` }),
542
+ React.createElement("span", { className: "font-semibold text-gray-900" }, registerDictionary?.passkey),
543
+ React.createElement("span", { className: "text-start text-xs font-normal text-gray-600" }, registerDictionary?.selectMethodPasskey)))),
544
+ React.createElement(Button, { "data-test": "register-method-selection-submit", onClick: () => selectRegisterMethod(), className: "bg-alr-red text-alr-white mb-6 flex w-full cursor-pointer items-center" }, registerDictionary?.continue))))), [isLoading, registrationMethod]);
545
+ const Password = useMemo(() => (React.createElement(React.Fragment, null,
546
+ React.createElement(BackButton, { disabled: isLoading, onClick: () => sendAuth(inviteToken || registerUser ? 'BACK_TO_IDLE' : 'BACK') }, userInfoGetValues('email')),
547
+ React.createElement("div", { className: "flex w-full flex-col", "data-test": "register-password-step" },
548
+ React.createElement("span", { className: "font-poppins text-alr-grey mb-5 text-center font-bold" }, registerDictionary?.createPassword),
549
+ React.createElement("form", { onSubmit: passwordHandleSubmit((data) => onSubmitPassword(data)), className: "flex flex-col gap-y-4" },
550
+ React.createElement(InputForm, { control: passwordControl, errors: passwordErrors, name: "password", autoFocus: true, placeholder: registerDictionary?.passwordPlaceholder, label: registerDictionary?.passwordLabel, type: "password", "data-test": "register-password", disabled: isLoading }),
551
+ React.createElement(InputForm, { control: passwordControl, errors: passwordErrors, name: "confirmPassword", placeholder: registerDictionary?.passwordConfirmPlaceholder, label: registerDictionary?.passwordConfirmLabel, type: "password", "data-test": "register-confirm-password", disabled: isLoading }),
552
+ React.createElement(FormRules, { locale: locale, className: "!gap-y-1 md:!gap-y-2", passwordValues: passwordGetValues(), userValues: registerUser || userInfoGetValues() }),
553
+ React.createElement(Button, { "data-test": "password-submit", type: "submit", className: "bg-alr-red hover:bg-alr-dark-red group relative flex items-center justify-center rounded-lg border border-transparent p-0.5 text-center font-medium text-white duration-300 focus:z-10 focus:outline-none focus:ring-2 focus:ring-red-300 enabled:hover:bg-red-700 disabled:hover:bg-red-900 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900 dark:enabled:hover:bg-red-700 dark:disabled:hover:bg-red-600", disabled: isPasswordSubmitDisabled || isLoading },
554
+ isLoading && React.createElement(Spinner, { className: "mr-3 !h-5 w-full !fill-gray-300" }),
555
+ dictionary?.next))))), [
556
+ isPasswordSubmitDisabled,
557
+ passwordControl,
558
+ passwordErrors,
559
+ passwordGetValues(),
560
+ passwordDirtyFields,
561
+ isLoading,
562
+ registerUser,
563
+ ]);
564
+ return (React.createElement("div", { className: "flex size-full min-h-screen flex-col items-center justify-center gap-y-2 sm:gap-y-7", "data-test": "register-page" },
565
+ React.createElement(TermsModal, { locale: locale, show: authState.matches('active.register.termsModal'), onClose: () => sendAuth('CLOSE_TERMS_MODAL'), onSubmit: () => {
566
+ userInfoSetValue('agreedWithTerms', true);
567
+ sendAuth('CLOSE_TERMS_MODAL');
568
+ } }),
569
+ forgeId ? (React.createElement("div", { className: "flex flex-col" },
570
+ React.createElement("span", { className: "font-poppins text-alr-grey text-center text-2xl font-black" }, "Tardezinha com Thiaguinho"),
571
+ React.createElement("div", { className: "flex w-full flex-row items-center justify-center gap-2" },
572
+ React.createElement("span", { className: "font-inter text-sm font-medium text-gray-900" }, dictionary?.auth.poweredBy),
573
+ React.createElement("img", { src: aloreLogoBlack, alt: "alore logo", width: "60" })))) : (logoImage || (React.createElement("img", { src: aloreLogoBlack, alt: "alore logo", width: authState.matches('active.login.newDevice') ? 153 : 201 }))),
574
+ React.createElement(Card, { className: twMerge(`md:child:!px-9 mx-5 flex min-w-[20rem] py-2 md:mx-7 md:w-96`, isLoading ? 'pointer-events-none opacity-50' : '') },
575
+ forgeId && authState.matches('active.web3Connector') && 'TODO',
576
+ (authState.matches('active.register.idle') ||
577
+ authState.matches('active.register.termsModal') ||
578
+ authState.matches('active.register.googleLogin') ||
579
+ authState.matches('active.register.sendingEmail')) &&
580
+ UserInfo,
581
+ (authState.matches('active.register.emailValidation') ||
582
+ authState.matches('active.register.verifyingEmail') ||
583
+ authState.matches('active.register.resendingRegistrationEmail')) &&
584
+ VerifyEmail,
585
+ (authState.matches('active.register.registerMethodSelection') ||
586
+ authState.matches('active.register.retrievingCCR') ||
587
+ authState.matches('active.register.retrievingRCR') ||
588
+ authState.matches('active.register.localCCRSign') ||
589
+ authState.matches('active.register.localRCRSign') ||
590
+ authState.matches('active.register.waitingForRCR') ||
591
+ authState.matches('active.register.sendingAuthPublicCredential') ||
592
+ authState.matches('active.register.sendingPublicCredential')) &&
593
+ SelectRegisterMethod,
594
+ (authState.matches('active.register.createPassword') ||
595
+ authState.matches('active.register.completingRegistration')) &&
596
+ Password,
597
+ authState.matches('active.register.userCreated') && (React.createElement("div", { className: "flex flex-col items-center justify-center gap-4" },
598
+ React.createElement("div", { className: "flex flex-row items-center justify-center gap-2" },
599
+ React.createElement("span", null, "Registration complete for"),
600
+ React.createElement("span", { className: "font-semibold" }, sessionUser?.nickname)),
601
+ React.createElement(Button, { className: "bg-alr-red hover:bg-alr-dark-red group relative flex items-center justify-center rounded-lg border border-transparent p-0.5 text-center font-medium text-white duration-300 focus:z-10 focus:outline-none focus:ring-2 focus:ring-red-300 enabled:hover:bg-red-700 disabled:hover:bg-red-900 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900 dark:enabled:hover:bg-red-700 dark:disabled:hover:bg-red-600", onClick: () => sendAuth(['RESET_CONTEXT', 'INITIALIZE']) }, "LOGOUT"))))));
602
+ };
603
+ //# sourceMappingURL=Register.js.map