firstly 0.0.10 → 0.0.12

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 (112) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/esm/BaseEnum.d.ts +2 -0
  3. package/esm/BaseEnum.js +2 -0
  4. package/esm/FF_Fields.js +0 -1
  5. package/esm/ROUTES.d.ts +2 -2
  6. package/esm/ROUTES.js +10 -5
  7. package/esm/SqlDatabase/FF_LogToConsole.d.ts +1 -0
  8. package/esm/SqlDatabase/FF_LogToConsole.js +22 -16
  9. package/esm/api/index.d.ts +19 -21
  10. package/esm/api/index.js +72 -62
  11. package/esm/auth/{client/Auth.d.ts → AuthController.d.ts} +18 -25
  12. package/esm/auth/{client/Auth.js → AuthController.js} +48 -44
  13. package/esm/auth/{client/Entities.d.ts → Entities.d.ts} +4 -3
  14. package/esm/auth/{client/Entities.js → Entities.js} +7 -7
  15. package/esm/auth/README.md +0 -10
  16. package/esm/auth/index.d.ts +5 -149
  17. package/esm/auth/index.js +5 -316
  18. package/esm/auth/{AuthController.server.d.ts → server/AuthController.server.d.ts} +10 -10
  19. package/esm/auth/{AuthController.server.js → server/AuthController.server.js} +126 -164
  20. package/esm/auth/server/handleAuth.d.ts +2 -0
  21. package/esm/auth/server/handleAuth.js +140 -0
  22. package/esm/auth/server/helperDb.d.ts +10 -0
  23. package/esm/auth/server/helperDb.js +56 -0
  24. package/esm/auth/server/helperFirstly.d.ts +1 -0
  25. package/esm/auth/server/helperFirstly.js +8 -0
  26. package/esm/auth/server/helperOslo.d.ts +7 -0
  27. package/esm/auth/server/helperOslo.js +24 -0
  28. package/esm/auth/server/helperRemultServer.d.ts +5 -0
  29. package/esm/auth/server/helperRemultServer.js +44 -0
  30. package/esm/auth/{RoleHelpers.d.ts → server/helperRole.d.ts} +1 -1
  31. package/esm/auth/{RoleHelpers.js → server/helperRole.js} +1 -1
  32. package/esm/auth/server/index.d.ts +5 -0
  33. package/esm/auth/server/index.js +5 -0
  34. package/esm/auth/server/module.d.ts +238 -0
  35. package/esm/auth/server/module.js +184 -0
  36. package/esm/auth/{providers → server/providers}/github.d.ts +6 -5
  37. package/esm/auth/{providers → server/providers}/github.js +30 -21
  38. package/esm/auth/{providers/index.d.ts → server/providers/helperProvider.d.ts} +0 -2
  39. package/esm/auth/{providers/index.js → server/providers/helperProvider.js} +5 -6
  40. package/esm/auth/static/assets/{Page-BEFYPjis.d.ts → Page-Bb8bFlrP.d.ts} +1 -1
  41. package/esm/auth/static/assets/{Page-DtgkOCJs.js → Page-Bb8bFlrP.js} +1 -1
  42. package/esm/auth/static/assets/{Page-DtgkOCJs.d.ts → Page-BxomFlZ8.d.ts} +1 -1
  43. package/esm/auth/static/assets/{Page-BEFYPjis.js → Page-BxomFlZ8.js} +1 -1
  44. package/esm/auth/static/assets/Page-CaIYu0-y.d.ts +6 -0
  45. package/esm/auth/static/assets/Page-CaIYu0-y.js +19 -0
  46. package/esm/auth/static/assets/Page-MkYglNtu.css +1 -0
  47. package/esm/auth/static/assets/index-Bl0Bk5u0.d.ts +64 -0
  48. package/esm/auth/static/assets/index-Bl0Bk5u0.js +2 -0
  49. package/esm/auth/static/assets/{index-CR_3yNaJ.css → index-R27C_TlP.css} +1 -1
  50. package/esm/auth/static/index.html +2 -2
  51. package/esm/auth/types.d.ts +5 -0
  52. package/esm/bin/cmd.js +13 -22
  53. package/esm/cellsBuildor.js +6 -6
  54. package/esm/changeLog/index.d.ts +0 -36
  55. package/esm/changeLog/index.js +3 -43
  56. package/esm/changeLog/server/index.d.ts +36 -0
  57. package/esm/changeLog/server/index.js +42 -0
  58. package/esm/cron/{index.d.ts → server/index.d.ts} +1 -1
  59. package/esm/cron/server/index.js +103 -0
  60. package/esm/feedback/FeedbackController.js +3 -3
  61. package/esm/feedback/index.d.ts +0 -16
  62. package/esm/feedback/index.js +0 -11
  63. package/esm/feedback/server/index.d.ts +17 -0
  64. package/esm/feedback/server/index.js +13 -0
  65. package/esm/feedback/ui/DialogIssue.svelte +4 -2
  66. package/esm/feedback/ui/DialogIssues.svelte +13 -4
  67. package/esm/feedback/ui/DialogMilestones.svelte +1 -1
  68. package/esm/feedback/ui/Feedback.svelte +3 -1
  69. package/esm/helper.d.ts +0 -1
  70. package/esm/helper.js +3 -17
  71. package/esm/index.d.ts +3 -17
  72. package/esm/index.js +3 -4
  73. package/esm/mail/index.d.ts +2 -30
  74. package/esm/mail/index.js +2 -79
  75. package/esm/mail/server/index.d.ts +31 -0
  76. package/esm/mail/server/index.js +88 -0
  77. package/esm/storeItem.d.ts +4 -1
  78. package/esm/storeItem.js +8 -2
  79. package/esm/storeList.d.ts +5 -2
  80. package/esm/storeList.js +1 -1
  81. package/esm/sveltekit/server/index.d.ts +11 -0
  82. package/esm/sveltekit/server/index.js +21 -0
  83. package/esm/ui/Button.svelte +1 -1
  84. package/esm/ui/Clipboardable.svelte +5 -2
  85. package/esm/ui/Field.svelte +4 -1
  86. package/esm/ui/Loading.svelte +4 -1
  87. package/esm/ui/Tooltip.svelte +2 -2
  88. package/esm/ui/dialog/DialogForm.svelte +1 -1
  89. package/esm/ui/dialog/DialogPrimitive.svelte +1 -2
  90. package/esm/ui/dialog/dialog.d.ts +6 -3
  91. package/esm/ui/dialog/dialog.js +1 -1
  92. package/esm/ui/internals/FieldContainer.svelte +0 -1
  93. package/esm/ui/internals/Input.svelte +3 -1
  94. package/esm/ui/internals/Textarea.svelte +2 -2
  95. package/esm/vite/index.js +24 -25
  96. package/package.json +50 -38
  97. package/esm/auth/Adapter.d.ts +0 -10
  98. package/esm/auth/Adapter.js +0 -50
  99. package/esm/auth/client/index.d.ts +0 -7
  100. package/esm/auth/client/index.js +0 -7
  101. package/esm/auth/helper.d.ts +0 -6
  102. package/esm/auth/helper.js +0 -14
  103. package/esm/auth/providers/strava.d.ts +0 -30
  104. package/esm/auth/providers/strava.js +0 -60
  105. package/esm/auth/static/assets/Page-BGTO8LC5.css +0 -1
  106. package/esm/auth/static/assets/Page-Cfysx_UV.d.ts +0 -6
  107. package/esm/auth/static/assets/Page-Cfysx_UV.js +0 -18
  108. package/esm/auth/static/assets/index-QypqCYwC.d.ts +0 -63
  109. package/esm/auth/static/assets/index-QypqCYwC.js +0 -2
  110. package/esm/cron/index.js +0 -102
  111. package/esm/handle/index.d.ts +0 -7
  112. package/esm/handle/index.js +0 -40
@@ -1,49 +1,25 @@
1
- import { generateCodeVerifier, generateState } from 'arctic';
2
- import { DEV } from 'esm-env';
3
- import { generateId } from 'lucia';
4
- import { createDate, TimeSpan } from 'oslo';
5
- import { remult } from 'remult';
1
+ import { decodeHex, encodeHexLowerCase } from '@oslojs/encoding';
2
+ import { createTOTPKeyURI, generateTOTP, verifyTOTPWithGracePeriod } from '@oslojs/otp';
3
+ import { generateState } from 'arctic';
4
+ import { EntityError, remult, repo } from 'remult';
6
5
  import { green, magenta, yellow } from '@kitql/helpers';
7
- import { AUTH_OPTIONS, getSafeOptions, lucia } from '.';
8
- import { sendMail } from '../mail';
9
- import { logAuth } from './client';
10
- import { FFAuthProvider } from './client/Entities.js';
11
- import { createOrExtendSession } from './helper';
12
- import { mergeRoles } from './RoleHelpers';
13
- async function getArgon() {
14
- const { Argon2id } = await import('oslo/password');
15
- return new Argon2id({
16
- ...AUTH_OPTIONS.providers?.password?.argon2Settings,
17
- });
18
- }
19
- async function passwordVerify(hash, password) {
20
- const argon = await getArgon();
21
- return await argon.verify(hash, password);
22
- }
23
- async function passwordHash(password) {
24
- const argon = await getArgon();
25
- return await argon.hash(password);
26
- }
27
- function checkPassword(password) {
28
- if (typeof password !== 'string' || password.length < 6 || password.length > 255) {
29
- throw Error('Invalid password');
30
- }
31
- }
6
+ import { sendMail } from '../../mail/server/index.js';
7
+ import { FFAuthProvider } from '../Entities.js';
8
+ import { invalidateSession } from './helperDb.js';
9
+ import { ff_createSession } from './helperFirstly.js';
10
+ import { createDate, generateAndEncodeToken } from './helperOslo.js';
11
+ import { deleteSessionTokenCookie, setOAuthStateCookie, setRedirectCookie, } from './helperRemultServer.js';
12
+ import { mergeRoles } from './helperRole.js';
13
+ import { AUTH_OPTIONS, authModuleRaw, getSafeOptions } from './module.js';
32
14
  export class AuthControllerServer {
33
15
  /**
34
16
  * Sign out the current user
35
17
  */
36
18
  static async signOut() {
37
19
  if (remult.user?.session.id) {
38
- await lucia.invalidateSession(remult.user?.session.id);
20
+ await invalidateSession(remult.user?.session.id);
39
21
  }
40
- // Lucia is advertising for createBlankSessionCookie (and not delete Cookie)
41
- // remult.context.deleteCookie(lucia.sessionCookieName, { path: '/' })
42
- const sessionCookie = lucia.createBlankSessionCookie();
43
- remult.context.setCookie(sessionCookie.name, sessionCookie.value, {
44
- path: '/',
45
- ...sessionCookie.attributes,
46
- });
22
+ deleteSessionTokenCookie();
47
23
  }
48
24
  /**
49
25
  * Sign in with a demo account
@@ -52,58 +28,60 @@ export class AuthControllerServer {
52
28
  static async signInDemo(name) {
53
29
  const accounts = AUTH_OPTIONS.providers?.demo ?? [];
54
30
  if (accounts.length === 0) {
55
- throw new Error(`Demo accounts are not enabled!`);
31
+ throw new EntityError({ message: `Demo accounts are not enabled!` });
56
32
  }
57
33
  const account = accounts.find((a) => a.name === name);
58
34
  if (!account) {
59
- throw new Error(`${name} not found as demo account!`);
35
+ throw new EntityError({ message: `${name} not found as demo account!` });
60
36
  }
61
37
  const oSafe = getSafeOptions();
62
- let user = await remult.repo(oSafe.User).findFirst({ identifier: name });
38
+ let user = await repo(oSafe.User).findFirst({ identifier: name });
63
39
  if (!user) {
64
- user = remult.repo(oSafe.User).create();
40
+ user = repo(oSafe.User).create();
65
41
  }
66
42
  user.identifier = name;
67
43
  const r = mergeRoles(user.roles, account.roles);
68
44
  user.roles = r.roles;
69
- await remult.repo(oSafe.User).save(user);
70
- await createOrExtendSession(user.id);
45
+ await repo(oSafe.User).save(user);
46
+ await ff_createSession(user.id);
71
47
  return "You're in with demo account!";
72
48
  }
73
49
  /**
74
50
  * This is for login / password authentication invite
75
51
  */
76
- static async invite(email) {
52
+ static async invite(emailParam) {
53
+ const email = emailParam.toLowerCase();
77
54
  const oSafe = getSafeOptions();
78
- const existingAccount = await remult.repo(oSafe.Account).findOne({
55
+ const existingAccount = await repo(oSafe.Account).findOne({
79
56
  where: {
80
57
  providerUserId: email,
81
58
  provider: FFAuthProvider.PASSWORD.id,
82
59
  },
83
60
  });
84
61
  if (existingAccount) {
85
- // throw Error("Already invited !")
62
+ // Already invited, it's all good.
86
63
  }
87
64
  else {
88
- const token = generateId(40);
65
+ const token = generateAndEncodeToken();
89
66
  // TODO: Do we create the user or just the account ?!
90
67
  // TODO 2: Invite is by mail... But the invitee can log with another provider... So what do we do?! maybe not checking the provider... and updating?
91
- // const user = await remult.repo(oSafe.User).insert({
68
+ // const user = await repo(oSafe.User).insert({
92
69
  // identifier: email,
93
70
  // })
94
- await remult.repo(oSafe.Account).insert({
71
+ oSafe.providers?.password?.verifyMailExpiresIn;
72
+ await repo(oSafe.Account).insert({
95
73
  provider: FFAuthProvider.PASSWORD.id,
96
74
  providerUserId: email,
97
75
  // userId: user.id,
98
76
  // hashPassword: await passwordHash(password),
99
77
  token: token,
100
- expiresAt: createDate(new TimeSpan(AUTH_OPTIONS.providers?.password?.verifyMailExpiresIn ?? 5 * 60, 's')),
78
+ expiresAt: createDate(AUTH_OPTIONS.providers?.password?.verifyMailExpiresIn ?? 5 * 60),
101
79
  lastVerifiedAt: undefined,
102
80
  });
103
- const url = `${remult.context.url.origin}${oSafe.firstlyData.props.ui?.paths.reset_password}?token=${token}`;
81
+ const url = `${remult.context.request.url.origin}${oSafe.firstlyData.props.ui?.paths.reset_password}?token=${token}`;
104
82
  if (AUTH_OPTIONS?.invitationSend) {
105
83
  await AUTH_OPTIONS?.invitationSend({ email, url });
106
- logAuth.success(`${green('[custom]')}${magenta('[invitationSend]')} (${yellow(url)})`);
84
+ authModuleRaw.log.success(`${green('[custom]')}${magenta('[invitationSend]')} (${yellow(url)})`);
107
85
  return 'Mail sent !';
108
86
  }
109
87
  else {
@@ -128,7 +106,7 @@ export class AuthControllerServer {
128
106
  ],
129
107
  },
130
108
  });
131
- logAuth.success(`${magenta('[invitationSend]')} (${yellow(url)})`);
109
+ authModuleRaw.log.success(`${magenta('[invitationSend]')} (${yellow(url)})`);
132
110
  return 'Demo Mail sent !';
133
111
  }
134
112
  }
@@ -138,54 +116,55 @@ export class AuthControllerServer {
138
116
  * This is for login / password authentication SignUp
139
117
  * _(The first param `email` can be "anything")_
140
118
  */
141
- static async signUpPassword(email, password) {
119
+ static async signUpPassword(emailParam, password) {
120
+ const email = emailParam.toLowerCase();
142
121
  const oSafe = getSafeOptions();
143
122
  if (!oSafe.signUp) {
144
- throw Error("You can't signup by yourself! Contact the administrator.");
123
+ throw new EntityError({ message: "You can't signup by yourself! Contact the administrator." });
145
124
  }
146
- if (!oSafe.password_enabled) {
147
- throw Error('Password is not enabled!');
125
+ if (!oSafe.password.enabled) {
126
+ throw new EntityError({ message: 'Password is not enabled!' });
148
127
  }
149
- const existingAccount = await remult.repo(oSafe.Account).findOne({
128
+ const existingAccount = await repo(oSafe.Account).findOne({
150
129
  where: {
151
130
  providerUserId: email,
152
131
  provider: FFAuthProvider.PASSWORD.id,
153
132
  },
154
133
  });
155
134
  if (existingAccount) {
156
- throw Error("You can't signup twice !");
135
+ throw new EntityError({ message: "You can't signup twice !" });
157
136
  }
158
- checkPassword(password);
159
- const token = generateId(40);
137
+ oSafe.password.validatePassword(password);
138
+ const token = generateAndEncodeToken();
160
139
  await remult.dataProvider.transaction(async () => {
161
- const user = await remult.repo(oSafe.User).insert({
140
+ const user = await repo(oSafe.User).insert({
162
141
  identifier: email,
163
142
  });
164
- await remult.repo(oSafe.Account).insert({
143
+ await repo(oSafe.Account).insert({
165
144
  provider: FFAuthProvider.PASSWORD.id,
166
145
  providerUserId: email,
167
146
  userId: user.id,
168
- hashPassword: await passwordHash(password),
147
+ hashPassword: oSafe.password.passwordHash(password),
169
148
  token: oSafe.verifiedMethod === 'auto' ? undefined : token,
170
149
  expiresAt: oSafe.verifiedMethod === 'auto'
171
150
  ? undefined
172
- : createDate(new TimeSpan(AUTH_OPTIONS.providers?.password?.verifyMailExpiresIn ?? 5 * 60, 's')),
151
+ : createDate(AUTH_OPTIONS.providers?.password?.verifyMailExpiresIn ?? 5 * 60),
173
152
  lastVerifiedAt: oSafe.verifiedMethod === 'auto' ? new Date() : undefined,
174
153
  });
175
154
  });
176
155
  if (oSafe.verifiedMethod === 'auto') {
177
- const user = await remult.repo(oSafe.User).findFirst({
156
+ const user = await repo(oSafe.User).findFirst({
178
157
  identifier: email,
179
158
  });
180
159
  if (user) {
181
- await createOrExtendSession(user.id);
160
+ await ff_createSession(user.id);
182
161
  }
183
162
  }
184
163
  else {
185
- const url = `${remult.context.url.origin}${oSafe.firstlyData.props.ui?.paths.verify_email}?token=${token}`;
164
+ const url = `${remult.context.request.url.origin}${oSafe.firstlyData.props.ui?.paths.verify_email}?token=${token}`;
186
165
  if (AUTH_OPTIONS.providers?.password?.verifyMailSend) {
187
166
  await AUTH_OPTIONS.providers?.password.verifyMailSend({ email, url });
188
- logAuth.success(`${green('[custom]')}${magenta('[verifyMailSend]')} (${yellow(url)})`);
167
+ authModuleRaw.log.success(`${green('[custom]')}${magenta('[verifyMailSend]')} (${yellow(url)})`);
189
168
  }
190
169
  else {
191
170
  await sendMail('verifyMailSend', {
@@ -205,7 +184,7 @@ export class AuthControllerServer {
205
184
  ],
206
185
  },
207
186
  });
208
- logAuth.success(`${magenta('[verifyMailSend]')} (${yellow(url)})`);
187
+ authModuleRaw.log.success(`${magenta('[verifyMailSend]')} (${yellow(url)})`);
209
188
  }
210
189
  }
211
190
  return 'ok';
@@ -214,50 +193,54 @@ export class AuthControllerServer {
214
193
  * This is for login / password authentication SignIn
215
194
  * _(The first param `email` can be "anything")_
216
195
  */
217
- static async signInPassword(email, password) {
196
+ static async signInPassword(emailParam, password) {
197
+ const email = emailParam.toLowerCase();
218
198
  const oSafe = getSafeOptions();
219
- if (!oSafe.password_enabled) {
220
- throw Error('Password is not enabled!');
199
+ if (!oSafe.password.enabled) {
200
+ throw new EntityError({ message: 'Password is not enabled!' });
221
201
  }
222
- const existingAccount = await remult.repo(oSafe.Account).findOne({
202
+ const existingAccount = await repo(oSafe.Account).findOne({
223
203
  where: {
224
204
  providerUserId: email,
225
205
  provider: FFAuthProvider.PASSWORD.id,
226
206
  },
227
207
  });
228
208
  if (existingAccount) {
229
- const validPassword = await passwordVerify(existingAccount?.hashPassword ?? '', password ?? '');
209
+ const validPassword = oSafe.password.passwordVerify(password ?? '', existingAccount?.hashPassword ?? '');
230
210
  if (validPassword) {
231
- await createOrExtendSession(existingAccount.userId);
211
+ await ff_createSession(existingAccount.userId);
232
212
  return 'ok';
233
213
  }
234
- throw Error('Incorrect username or password');
214
+ authModuleRaw.log.error({ email, passwordLength: password.length });
215
+ throw new EntityError({ message: 'Incorrect username or password' });
235
216
  }
236
- throw Error('Incorrect username or password.');
217
+ authModuleRaw.log.error({ email, passwordLength: password.length });
218
+ throw new EntityError({ message: 'Incorrect username or password.' });
237
219
  }
238
220
  /**
239
221
  * Forgot your password ? Send a mail to reset it.
240
222
  */
241
- static async forgotPassword(email) {
223
+ static async forgotPassword(emailParam) {
224
+ const email = emailParam.toLowerCase();
242
225
  const oSafe = getSafeOptions();
243
- if (!oSafe.password_enabled) {
244
- throw Error('Password is not enabled!');
226
+ if (!oSafe.password.enabled) {
227
+ throw new EntityError({ message: 'Password is not enabled!' });
245
228
  }
246
- const existingAccount = await remult.repo(oSafe.Account).findOne({
229
+ const existingAccount = await repo(oSafe.Account).findOne({
247
230
  where: {
248
231
  providerUserId: email,
249
232
  provider: FFAuthProvider.PASSWORD.id,
250
233
  },
251
234
  });
252
235
  if (existingAccount) {
253
- const token = generateId(40);
236
+ const token = generateAndEncodeToken();
254
237
  existingAccount.token = token;
255
- existingAccount.expiresAt = createDate(new TimeSpan(AUTH_OPTIONS.providers?.password?.resetPasswordExpiresIn ?? 5 * 60, 's'));
256
- await remult.repo(oSafe.Account).save(existingAccount);
257
- const url = `${remult.context.url.origin}${oSafe.firstlyData.props.ui?.paths.reset_password}?token=${token}`;
238
+ existingAccount.expiresAt = createDate(AUTH_OPTIONS.providers?.password?.resetPasswordExpiresIn ?? 5 * 60);
239
+ await repo(oSafe.Account).save(existingAccount);
240
+ const url = `${remult.context.request.url.origin}${oSafe.firstlyData.props.ui?.paths.reset_password}?token=${token}`;
258
241
  if (AUTH_OPTIONS.providers?.password?.resetPasswordSend) {
259
242
  await AUTH_OPTIONS.providers?.password.resetPasswordSend({ email, url });
260
- logAuth.success(`${green('[custom]')}${magenta('[resetPasswordSend]')} (${yellow(url)})`);
243
+ authModuleRaw.log.success(`${green('[custom]')}${magenta('[resetPasswordSend]')} (${yellow(url)})`);
261
244
  return 'Mail sent !';
262
245
  }
263
246
  else {
@@ -282,119 +265,120 @@ export class AuthControllerServer {
282
265
  ],
283
266
  },
284
267
  });
285
- logAuth.success(`${magenta('[resetPasswordSend]')} (${yellow(url)})`);
268
+ authModuleRaw.log.success(`${magenta('[resetPasswordSend]')} (${yellow(url)})`);
286
269
  return 'Demo Mail sent !';
287
270
  }
288
271
  }
289
- throw new Error("Une erreur est survenue, contacte l'administrateur!");
272
+ throw new EntityError({ message: "Une erreur est survenue, contacte l'administrateur!" });
290
273
  }
291
274
  /**
292
275
  * Reset your password with a token
293
276
  */
294
277
  static async resetPassword(token, password) {
295
278
  const oSafe = getSafeOptions();
296
- if (!oSafe.password_enabled) {
297
- throw Error('Password is not enabled!');
279
+ if (!oSafe.password.enabled) {
280
+ throw new EntityError({ message: 'Password is not enabled!' });
298
281
  }
299
282
  const account = await remult
300
283
  .repo(oSafe.Account)
301
284
  .findFirst({ token, provider: FFAuthProvider.PASSWORD.id });
302
285
  if (!account) {
303
- throw new Error('Invalid token');
286
+ throw new EntityError({ message: 'Invalid token' });
304
287
  }
305
288
  if (account.expiresAt && account.expiresAt < new Date()) {
306
- throw new Error('token expired');
289
+ throw new EntityError({ message: 'token expired' });
307
290
  }
308
- checkPassword(password);
291
+ oSafe.password.validatePassword(password);
309
292
  if (account.userId === undefined) {
310
- const user = await remult.repo(oSafe.User).insert({ identifier: account.providerUserId });
293
+ const user = await repo(oSafe.User).insert({ identifier: account.providerUserId });
311
294
  account.userId = user.id;
312
295
  }
313
- await lucia.invalidateUserSessions(account.userId);
296
+ await invalidateSession(account.userId);
314
297
  // update elements
315
- account.hashPassword = await passwordHash(password);
298
+ account.hashPassword = oSafe.password.passwordHash(password);
316
299
  account.token = undefined;
317
300
  account.expiresAt = undefined;
318
301
  account.lastVerifiedAt = new Date();
319
- await remult.repo(oSafe.Account).save(account);
320
- await createOrExtendSession(account.userId);
302
+ await repo(oSafe.Account).save(account);
303
+ await ff_createSession(account.userId);
321
304
  return 'reseted';
322
305
  }
323
306
  /** OTP */
324
- static async signInOTP(email) {
307
+ static async signInOTP(emailParam) {
308
+ const email = emailParam.toLowerCase();
325
309
  const oSafe = getSafeOptions();
326
- if (!oSafe.otp_enabled) {
327
- throw new Error(`OPT is not enabled!`);
310
+ if (!oSafe.otp.enabled) {
311
+ throw new EntityError({ message: `OPT is not enabled!` });
328
312
  }
329
313
  if (AUTH_OPTIONS.providers?.otp?.send) {
330
- const { createTOTPKeyURI } = await import('oslo/otp');
331
- const { encodeHex } = await import('oslo/encoding');
332
- const { TOTPController } = await import('oslo/otp');
333
- const secret = crypto.getRandomValues(new Uint8Array(20));
334
- const otp = await new TOTPController({
335
- period: new TimeSpan(AUTH_OPTIONS.providers?.otp.expiresIn ?? 30, 's'),
336
- digits: AUTH_OPTIONS.providers?.otp.digits ?? 6,
337
- }).generate(secret);
338
- const secretEncoded = encodeHex(secret);
314
+ const key = crypto.getRandomValues(new Uint8Array(20));
315
+ const intervalInSeconds = AUTH_OPTIONS.providers?.otp?.expiresIn ?? 30;
316
+ const digits = AUTH_OPTIONS.providers?.otp.digits ?? 6;
317
+ const otp = generateTOTP(key, intervalInSeconds, digits);
318
+ const keyEncoded = encodeHexLowerCase(key);
339
319
  const issuer = AUTH_OPTIONS.providers.otp.issuer ?? 'firstly';
340
- const uri = createTOTPKeyURI(issuer, email, secret);
320
+ const uri = createTOTPKeyURI(issuer, email, key, intervalInSeconds, digits);
341
321
  const oSafe = getSafeOptions();
342
- let user = await remult.repo(oSafe.User).findFirst({ identifier: email });
322
+ let user = await repo(oSafe.User).findFirst({ identifier: email });
343
323
  if (!user) {
344
- user = remult.repo(oSafe.User).create();
324
+ user = repo(oSafe.User).create();
345
325
  }
346
326
  user.identifier = email;
347
- user = await remult.repo(oSafe.User).save(user);
327
+ user = await repo(oSafe.User).save(user);
348
328
  let account = await remult
349
329
  .repo(oSafe.Account)
350
330
  .findFirst({ userId: user.id, provider: FFAuthProvider.OTP.id });
351
331
  if (!account) {
352
- account = remult.repo(oSafe.Account).create();
332
+ account = repo(oSafe.Account).create();
353
333
  }
354
334
  account.userId = user.id;
355
335
  account.provider = FFAuthProvider.OTP.id;
356
336
  account.token = otp;
357
- account.hashPassword = secretEncoded;
358
- await remult.repo(oSafe.Account).save(account);
337
+ account.hashPassword = keyEncoded;
338
+ await repo(oSafe.Account).save(account);
359
339
  await AUTH_OPTIONS.providers.otp?.send({ name: email, otp, uri });
360
- logAuth.success(`name: ${yellow(email)}, otp: ${yellow(otp)}, uri: ${yellow(uri)}`);
340
+ authModuleRaw.log.success(`name: ${yellow(email)}, otp: ${yellow(otp)}, uri: ${yellow(uri)}`);
361
341
  return 'Mail sent !';
362
342
  }
363
343
  else {
364
- logAuth.error(`You need to provide a otp.send hook in the auth options!`);
344
+ authModuleRaw.log.error(`You need to provide a otp.send hook in the auth options!`);
365
345
  }
366
346
  return 'Hum, something went wrong !';
367
347
  }
368
348
  /**
369
349
  * Verify the OTP code
370
350
  */
371
- static async verifyOtp(email, otp) {
351
+ static async verifyOtp(emailParam, otp) {
352
+ const email = emailParam.toLowerCase();
372
353
  const oSafe = getSafeOptions();
373
- const accounts = await remult.repo(oSafe.Account).find({
354
+ if (!oSafe.otp.enabled) {
355
+ throw new EntityError({ message: `OPT is not enabled!` });
356
+ }
357
+ const accounts = await repo(oSafe.Account).find({
374
358
  where: { token: String(otp), provider: FFAuthProvider.OTP.id },
375
359
  });
376
360
  if (accounts.length === 0) {
377
- throw new Error('Invalid otp');
361
+ throw new EntityError({ message: 'Invalid otp' });
378
362
  }
379
363
  const account = accounts[0];
380
- const user = await remult.repo(oSafe.User).findId(account.userId);
364
+ const user = await repo(oSafe.User).findId(account.userId);
381
365
  if (user?.identifier !== email) {
382
- throw new Error('Invalid otp.');
366
+ throw new EntityError({ message: 'Invalid otp.' });
383
367
  }
384
- const { decodeHex } = await import('oslo/encoding');
385
- const { TOTPController } = await import('oslo/otp');
386
- const secretDecoded = decodeHex(account.hashPassword ?? '');
387
- const validOTP = await new TOTPController().verify(String(otp), secretDecoded);
368
+ const intervalInSeconds = oSafe.providers?.otp?.expiresIn ?? 30;
369
+ const digits = oSafe.providers?.otp?.digits ?? 6;
370
+ const keyDecoded = decodeHex(account.hashPassword ?? '');
371
+ const validOTP = verifyTOTPWithGracePeriod(keyDecoded, intervalInSeconds, digits, otp, 30);
388
372
  if (!validOTP) {
389
- throw new Error('Invalid otp!');
373
+ throw new EntityError({ message: 'Invalid otp!' });
390
374
  }
391
- await lucia.invalidateUserSessions(account.userId);
375
+ await invalidateSession(account.userId);
392
376
  // update elements
393
377
  account.hashPassword = undefined;
394
378
  account.token = undefined;
395
379
  account.expiresAt = undefined;
396
- await remult.repo(oSafe.Account).save(account);
397
- await createOrExtendSession(account.userId);
380
+ await repo(oSafe.Account).save(account);
381
+ await ff_createSession(account.userId);
398
382
  return 'verified';
399
383
  }
400
384
  /** OAUTH */
@@ -417,17 +401,6 @@ export class AuthControllerServer {
417
401
  try {
418
402
  const arcticProvider = selectedOAuth.getArcticProvider();
419
403
  const args = [state];
420
- if (selectedOAuth.isPKCE) {
421
- const codeVerifier = generateCodeVerifier();
422
- args.push(codeVerifier);
423
- // store code verifier as cookie
424
- remult.context.setCookie('code_verifier', codeVerifier, {
425
- secure: true, // set to false in localhost
426
- path: '/',
427
- httpOnly: true,
428
- maxAge: 60 * 10, // 10 min
429
- });
430
- }
431
404
  if (o.options) {
432
405
  args.push(o.options);
433
406
  }
@@ -436,35 +409,24 @@ export class AuthControllerServer {
436
409
  args.push(selectedOAuth.authorizationURLOptions());
437
410
  }
438
411
  }
439
- // @ts-ignore
440
412
  const url = await arcticProvider.createAuthorizationURL(...args);
441
413
  if (!url) {
442
- throw new Error('No url returned');
414
+ throw new EntityError({ message: 'No url returned' });
443
415
  }
444
- remult.context.setCookie(`${o.provider}_oauth_state`, state, {
445
- path: '/',
446
- secure: !DEV,
447
- httpOnly: true,
448
- maxAge: 60 * 10,
449
- sameSite: 'lax',
450
- });
416
+ setOAuthStateCookie(selectedOAuth.name, state);
451
417
  if (o.redirect) {
452
- remult.context.setCookie(`remult_redirect`, o.redirect, {
453
- path: '/',
454
- secure: !DEV,
455
- httpOnly: true,
456
- maxAge: 60 * 10,
457
- sameSite: 'lax',
458
- });
418
+ setRedirectCookie(o.redirect);
459
419
  }
460
420
  return url.toString();
461
421
  }
462
422
  catch (error) {
463
423
  // display error for the server only
464
- logAuth.error(error);
465
- throw new Error(`${o.provider} not well configured!`);
424
+ authModuleRaw.log.error(error);
425
+ throw new EntityError({ message: `${selectedOAuth.name} not well configured!` });
466
426
  }
467
427
  }
468
- throw new Error(`${o.provider} is not configured! (Module: auth, section: providers.oAuths: [${o.provider}] missing)`);
428
+ throw new EntityError({
429
+ message: `${o.provider} is not configured! (Module: auth, section: providers.oAuths: [${o.provider}] missing)`,
430
+ });
469
431
  }
470
432
  }
@@ -0,0 +1,2 @@
1
+ import { type Handle } from '@sveltejs/kit';
2
+ export declare const handleAuth: Handle;