firstly 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/esm/FF_Entity.js +20 -4
- package/esm/ROUTES.d.ts +11 -11
- package/esm/ROUTES.js +5 -5
- package/esm/SqlDatabase/FF_LogToConsole.d.ts +4 -1
- package/esm/SqlDatabase/FF_LogToConsole.js +15 -8
- package/esm/api/index.d.ts +2 -2
- package/esm/api/index.js +9 -9
- package/esm/auth/Adapter.js +1 -7
- package/esm/auth/AuthController.server.d.ts +1 -2
- package/esm/auth/AuthController.server.js +96 -65
- package/esm/auth/RoleHelpers.d.ts +1 -1
- package/esm/auth/RoleHelpers.js +9 -9
- package/esm/auth/client/Auth.d.ts +11 -4
- package/esm/auth/client/Auth.js +13 -5
- package/esm/auth/{Entities.d.ts → client/Entities.d.ts} +3 -3
- package/esm/auth/{Entities.js → client/Entities.js} +30 -14
- package/esm/auth/client/index.d.ts +5 -0
- package/esm/auth/client/index.js +5 -0
- package/esm/auth/helper.d.ts +6 -1
- package/esm/auth/helper.js +11 -4
- package/esm/auth/index.d.ts +9 -11
- package/esm/auth/index.js +74 -70
- package/esm/auth/providers/github.js +2 -1
- package/esm/auth/providers/index.js +1 -1
- package/esm/auth/providers/strava.js +2 -1
- package/esm/auth/static/assets/{Page-RIbXHuZG.d.ts → Page-BEFYPjis.d.ts} +1 -1
- package/esm/auth/static/assets/{Page-RIbXHuZG.js → Page-BEFYPjis.js} +1 -1
- package/esm/auth/static/assets/Page-Cfysx_UV.d.ts +6 -0
- package/esm/auth/static/assets/Page-Cfysx_UV.js +18 -0
- package/esm/auth/static/assets/{Page-DBWJjlEQ.d.ts → Page-DtgkOCJs.d.ts} +1 -1
- package/esm/auth/static/assets/{Page-DBWJjlEQ.js → Page-DtgkOCJs.js} +1 -1
- package/esm/auth/static/assets/index-QypqCYwC.d.ts +63 -0
- package/esm/auth/static/assets/index-QypqCYwC.js +2 -0
- package/esm/auth/static/index.html +1 -1
- package/esm/auth/types.d.ts +7 -5
- package/esm/bin/cmd.js +28 -14
- package/esm/cellsBuildor.d.ts +1 -0
- package/esm/cellsBuildor.js +24 -12
- package/esm/changeLog/index.d.ts +23 -7
- package/esm/changeLog/index.js +24 -18
- package/esm/feedback/FeedbackController.d.ts +12 -3
- package/esm/feedback/FeedbackController.js +62 -11
- package/esm/feedback/index.d.ts +1 -0
- package/esm/feedback/ui/DialogIssue.svelte +28 -9
- package/esm/feedback/ui/DialogIssues.svelte +7 -2
- package/esm/handle/index.d.ts +1 -1
- package/esm/index.d.ts +4 -2
- package/esm/index.js +1 -1
- package/esm/mail/index.js +1 -1
- package/esm/mail/templates/DefaultMail.svelte +1 -1
- package/esm/ui/Field.svelte +2 -10
- package/esm/ui/GridPaginate.svelte +7 -7
- package/esm/ui/GridPaginate.svelte.d.ts +1 -1
- package/esm/vite/index.js +4 -1
- package/package.json +8 -8
- package/esm/auth/static/assets/Page-apb_xgZT.d.ts +0 -6
- package/esm/auth/static/assets/Page-apb_xgZT.js +0 -18
- package/esm/auth/static/assets/index-qfq98Nyd.d.ts +0 -63
- package/esm/auth/static/assets/index-qfq98Nyd.js +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# firstly
|
|
2
2
|
|
|
3
|
+
## 0.0.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#27](https://github.com/jycouet/firstly/pull/27)
|
|
8
|
+
[`66711b2`](https://github.com/jycouet/firstly/commit/66711b2373c69006d7ae5f06d8f4a6cb0e43670b)
|
|
9
|
+
Thanks [@jycouet](https://github.com/jycouet)! - fix the session creation on signIn! (+default
|
|
10
|
+
expiration is 30 days)
|
|
11
|
+
|
|
12
|
+
- [#27](https://github.com/jycouet/firstly/pull/27)
|
|
13
|
+
[`0657c5c`](https://github.com/jycouet/firstly/commit/0657c5ca8b81673b493a6815a196a8c5351ecdf0)
|
|
14
|
+
Thanks [@jycouet](https://github.com/jycouet)! - add uiStaticPath option in auth module to
|
|
15
|
+
overwrite where are the static files for the module (dev option)
|
|
16
|
+
|
|
17
|
+
## 0.0.7
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- [#25](https://github.com/jycouet/firstly/pull/25)
|
|
22
|
+
[`54f2f6a`](https://github.com/jycouet/firstly/commit/54f2f6a833c1977c3163e91ce3172fa8edc9da47)
|
|
23
|
+
Thanks [@jycouet](https://github.com/jycouet)! - adding e2e tests for accounts
|
|
24
|
+
|
|
25
|
+
- [#25](https://github.com/jycouet/firstly/pull/25)
|
|
26
|
+
[`943e9d0`](https://github.com/jycouet/firstly/commit/943e9d0b6d5d6a631dc78661d188a76f254d4632)
|
|
27
|
+
Thanks [@jycouet](https://github.com/jycouet)! - rename name to identifier in db
|
|
28
|
+
|
|
3
29
|
## 0.0.6
|
|
4
30
|
|
|
5
31
|
### Patch Changes
|
package/esm/FF_Entity.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Entity } from 'remult';
|
|
2
|
+
import { recordDeleted, recordSaved } from './changeLog';
|
|
2
3
|
const toAllow = (permission) => {
|
|
3
4
|
if (permission) {
|
|
4
5
|
if (Array.isArray(permission)) {
|
|
@@ -16,9 +17,24 @@ export function FF_Entity(key, options) {
|
|
|
16
17
|
allowApiInsert: options.allowApiInsert ?? toAllow(options.permissionApiInsert),
|
|
17
18
|
allowApiRead: options.allowApiRead ?? toAllow(options.permissionApiRead),
|
|
18
19
|
allowApiUpdate: options.allowApiUpdate ?? toAllow(options.permissionApiUpdate),
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
// changesLogs
|
|
21
|
+
saved: async (entity, e) => {
|
|
22
|
+
await options?.saved?.(entity, e);
|
|
23
|
+
if (options.changeLog === false) {
|
|
24
|
+
// Don't log changes
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
await recordSaved(entity, e, options.changeLog);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
deleted: async (entity, e) => {
|
|
31
|
+
await options?.deleted?.(entity, e);
|
|
32
|
+
if (options.changeLog === false) {
|
|
33
|
+
// Don't log changes
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
await recordDeleted(entity, e, options.changeLog);
|
|
37
|
+
}
|
|
38
|
+
},
|
|
23
39
|
});
|
|
24
40
|
}
|
package/esm/ROUTES.d.ts
CHANGED
|
@@ -32,16 +32,16 @@ declare const AllObjs: {
|
|
|
32
32
|
repo?: (string | number);
|
|
33
33
|
}) => string;
|
|
34
34
|
"/": string;
|
|
35
|
+
"/auth": string;
|
|
35
36
|
"/mail": string;
|
|
36
|
-
"/
|
|
37
|
-
"/
|
|
38
|
-
"/
|
|
39
|
-
"/
|
|
40
|
-
"/ui": string;
|
|
37
|
+
"/ui/dialog": string;
|
|
38
|
+
"/ui/enum": string;
|
|
39
|
+
"/ui/fieldGroup": string;
|
|
40
|
+
"/ui/select": string;
|
|
41
41
|
};
|
|
42
42
|
type AllTypes = typeof AllObjs;
|
|
43
43
|
export type Routes = keyof AllTypes extends `${string}/${infer Route}` ? `/${Route}` : keyof AllTypes;
|
|
44
|
-
export declare const routes: ("/" | "/
|
|
44
|
+
export declare const routes: ("/" | "/auth" | "/mail" | "/ui/dialog" | "/ui/enum" | "/ui/fieldGroup" | "/ui/select" | "firstly_sign_in" | "remult_admin" | "github")[];
|
|
45
45
|
/**
|
|
46
46
|
* To be used like this:
|
|
47
47
|
* ```ts
|
|
@@ -70,12 +70,12 @@ export declare function route<T extends NonFunctionKeys<AllTypes>>(key: T): stri
|
|
|
70
70
|
export type KIT_ROUTES = {
|
|
71
71
|
PAGES: {
|
|
72
72
|
'/': never;
|
|
73
|
+
'/auth': never;
|
|
73
74
|
'/mail': never;
|
|
74
|
-
'/
|
|
75
|
-
'/
|
|
76
|
-
'/
|
|
77
|
-
'/
|
|
78
|
-
'/ui': never;
|
|
75
|
+
'/ui/dialog': never;
|
|
76
|
+
'/ui/enum': never;
|
|
77
|
+
'/ui/fieldGroup': never;
|
|
78
|
+
'/ui/select': never;
|
|
79
79
|
};
|
|
80
80
|
SERVERS: Record<string, never>;
|
|
81
81
|
ACTIONS: Record<string, never>;
|
package/esm/ROUTES.js
CHANGED
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
*/
|
|
10
10
|
const PAGES = {
|
|
11
11
|
"/": `/`,
|
|
12
|
+
"/auth": `/auth`,
|
|
12
13
|
"/mail": `/mail`,
|
|
13
|
-
"/
|
|
14
|
-
"/
|
|
15
|
-
"/
|
|
16
|
-
"/
|
|
17
|
-
"/ui": `/ui`
|
|
14
|
+
"/ui/dialog": `/ui/dialog`,
|
|
15
|
+
"/ui/enum": `/ui/enum`,
|
|
16
|
+
"/ui/fieldGroup": `/ui/fieldGroup`,
|
|
17
|
+
"/ui/select": `/ui/select`
|
|
18
18
|
};
|
|
19
19
|
/**
|
|
20
20
|
* SERVERS
|
|
@@ -1 +1,4 @@
|
|
|
1
|
-
export declare const FF_LogToConsole: (duration: number, query: string, args: Record<string, any>,
|
|
1
|
+
export declare const FF_LogToConsole: (duration: number, query: string, args: Record<string, any>, options?: {
|
|
2
|
+
withDetails?: boolean;
|
|
3
|
+
tablesToHide?: string[][];
|
|
4
|
+
}) => string | undefined;
|
|
@@ -16,7 +16,7 @@ const typeQuery = new Map([
|
|
|
16
16
|
]);
|
|
17
17
|
const keys = ['FROM', 'WHERE', 'LIMIT', 'OFFSET'];
|
|
18
18
|
const typeQueryKey = Array.from(typeQuery.keys());
|
|
19
|
-
export const FF_LogToConsole = (duration, query, args,
|
|
19
|
+
export const FF_LogToConsole = (duration, query, args, options) => {
|
|
20
20
|
const rawSql = query
|
|
21
21
|
.replace(/(\r\n|\n|\r|\t)/gm, ' ')
|
|
22
22
|
.replace(/ +/g, ' ')
|
|
@@ -79,7 +79,10 @@ export const FF_LogToConsole = (duration, query, args, short = true) => {
|
|
|
79
79
|
const subTables = uniqueTables.slice(0, -1);
|
|
80
80
|
const time = ` ${bgCyan((duration * 1000).toFixed(0).padStart(3) + ' ms ')}`;
|
|
81
81
|
let toLog = '';
|
|
82
|
-
if (
|
|
82
|
+
if (options?.withDetails) {
|
|
83
|
+
toLog = `${typeQuery.get(first) || '💢'}` + time + ` ${final_s}`;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
83
86
|
toLog =
|
|
84
87
|
`${typeQuery.get(first) || '💢'}` +
|
|
85
88
|
`${time}` +
|
|
@@ -87,12 +90,16 @@ export const FF_LogToConsole = (duration, query, args, short = true) => {
|
|
|
87
90
|
`${listArgs.length > 0 ? ` { ${listArgs.join(', ')} }` : ``}` +
|
|
88
91
|
`${subTables.length > 0 ? magenta(` (sub: ${subTables.join(', ')})`) : ``}`;
|
|
89
92
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
const toFilterOut = options?.tablesToHide ?? [
|
|
94
|
+
['__remult_migrations_version'],
|
|
95
|
+
['information_Schema.tables'],
|
|
96
|
+
['information_schema.columns'],
|
|
97
|
+
['ff_auth.accounts'],
|
|
98
|
+
['ff_auth.users'],
|
|
99
|
+
['ff_auth.users_sessions'],
|
|
100
|
+
['_ff_change_logs'],
|
|
101
|
+
];
|
|
102
|
+
const OnoOfFiltered = toFilterOut.some((item) => item.every((i) => tables.map((c) => c.replaceAll('"', '')).includes(i)));
|
|
96
103
|
if (!OnoOfFiltered) {
|
|
97
104
|
// console.log(`toLogLong`, toLogLong)
|
|
98
105
|
log.info(toLog);
|
package/esm/api/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/// <reference types=".pnpm/@sveltejs+kit@2.5.24_@sveltejs+vite-plugin-svelte@3.1.
|
|
1
|
+
/// <reference types=".pnpm/@sveltejs+kit@2.5.24_@sveltejs+vite-plugin-svelte@3.1.2_svelte@4.2.18_vite@5.4.1_@types+node@_lnml5jetshdinsnlj53joqxhde/node_modules/@sveltejs/kit" />
|
|
2
2
|
import { type Handle, type MaybePromise, type RequestEvent } from '@sveltejs/kit';
|
|
3
3
|
import { type ClassType } from 'remult';
|
|
4
4
|
import type { RemultServerOptions } from 'remult/server';
|
|
@@ -17,7 +17,7 @@ export type Module = {
|
|
|
17
17
|
handlePosRemult?: Handle;
|
|
18
18
|
earlyReturn?: (input: Parameters<Handle>[0]) => MaybePromise<{
|
|
19
19
|
early: false;
|
|
20
|
-
resolve?:
|
|
20
|
+
resolve?: undefined;
|
|
21
21
|
} | {
|
|
22
22
|
early: true;
|
|
23
23
|
resolve: ReturnType<Handle>;
|
package/esm/api/index.js
CHANGED
|
@@ -36,6 +36,15 @@ export const firstly = (o) => {
|
|
|
36
36
|
initRequest: async (kitEvent, op) => {
|
|
37
37
|
// usefull for later...
|
|
38
38
|
remult.context.url = kitEvent.url;
|
|
39
|
+
remult.context.setHeaders = (headers) => {
|
|
40
|
+
kitEvent.setHeaders(headers);
|
|
41
|
+
};
|
|
42
|
+
remult.context.setCookie = (name, value, opts) => {
|
|
43
|
+
kitEvent.cookies.set(name, value, opts);
|
|
44
|
+
};
|
|
45
|
+
remult.context.deleteCookie = (name, opts) => {
|
|
46
|
+
kitEvent.cookies.delete(name, opts);
|
|
47
|
+
};
|
|
39
48
|
for (let i = 0; i < modulesSorted.length; i++) {
|
|
40
49
|
const f = modulesSorted[i].initRequest;
|
|
41
50
|
if (f) {
|
|
@@ -48,15 +57,6 @@ export const firstly = (o) => {
|
|
|
48
57
|
}
|
|
49
58
|
}
|
|
50
59
|
}
|
|
51
|
-
remult.context.setHeaders = (headers) => {
|
|
52
|
-
kitEvent.setHeaders(headers);
|
|
53
|
-
};
|
|
54
|
-
remult.context.setCookie = (name, value, opts) => {
|
|
55
|
-
kitEvent.cookies.set(name, value, opts);
|
|
56
|
-
};
|
|
57
|
-
remult.context.deleteCookie = (name, opts) => {
|
|
58
|
-
kitEvent.cookies.delete(name, opts);
|
|
59
|
-
};
|
|
60
60
|
},
|
|
61
61
|
initApi: async (r) => {
|
|
62
62
|
if (!building) {
|
package/esm/auth/Adapter.js
CHANGED
|
@@ -9,13 +9,7 @@ export class RemultLuciaAdapter {
|
|
|
9
9
|
if (user) {
|
|
10
10
|
return [
|
|
11
11
|
{ ...session, attributes: {} },
|
|
12
|
-
{
|
|
13
|
-
...user,
|
|
14
|
-
attributes: {
|
|
15
|
-
...user,
|
|
16
|
-
session: { id: session.id, expiresAt: session.expiresAt },
|
|
17
|
-
},
|
|
18
|
-
},
|
|
12
|
+
{ ...user, attributes: oSafe.transformDbUserToClientUser(session, user) },
|
|
19
13
|
];
|
|
20
14
|
}
|
|
21
15
|
}
|
|
@@ -10,8 +10,7 @@ export declare class AuthControllerServer {
|
|
|
10
10
|
*/
|
|
11
11
|
static signInDemo(name: string): Promise<string>;
|
|
12
12
|
/**
|
|
13
|
-
* This is for login / password authentication
|
|
14
|
-
* _(The first param `name` can be "anything")_
|
|
13
|
+
* This is for login / password authentication invite
|
|
15
14
|
*/
|
|
16
15
|
static invite(email: string): Promise<"Mail sent !" | "Demo Mail sent !" | "ok">;
|
|
17
16
|
/**
|
|
@@ -3,11 +3,12 @@ import { DEV } from 'esm-env';
|
|
|
3
3
|
import { generateId } from 'lucia';
|
|
4
4
|
import { createDate, TimeSpan } from 'oslo';
|
|
5
5
|
import { remult } from 'remult';
|
|
6
|
-
import { green, yellow } from '@kitql/helpers';
|
|
7
|
-
import { AUTH_OPTIONS, getSafeOptions,
|
|
6
|
+
import { green, magenta, yellow } from '@kitql/helpers';
|
|
7
|
+
import { AUTH_OPTIONS, getSafeOptions, lucia } from '.';
|
|
8
8
|
import { sendMail } from '../mail';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { logAuth } from './client';
|
|
10
|
+
import { FFAuthProvider } from './client/Entities.js';
|
|
11
|
+
import { createOrExtendSession } from './helper';
|
|
11
12
|
import { mergeRoles } from './RoleHelpers';
|
|
12
13
|
async function getArgon() {
|
|
13
14
|
const { Argon2id } = await import('oslo/password');
|
|
@@ -58,39 +59,55 @@ export class AuthControllerServer {
|
|
|
58
59
|
throw new Error(`${name} not found as demo account!`);
|
|
59
60
|
}
|
|
60
61
|
const oSafe = getSafeOptions();
|
|
61
|
-
let user = await remult.repo(oSafe.User).findFirst({ name });
|
|
62
|
+
let user = await remult.repo(oSafe.User).findFirst({ identifier: name });
|
|
62
63
|
if (!user) {
|
|
63
64
|
user = remult.repo(oSafe.User).create();
|
|
64
65
|
}
|
|
65
|
-
user.
|
|
66
|
+
user.identifier = name;
|
|
66
67
|
const r = mergeRoles(user.roles, account.roles);
|
|
67
68
|
user.roles = r.roles;
|
|
68
69
|
await remult.repo(oSafe.User).save(user);
|
|
69
|
-
await
|
|
70
|
+
await createOrExtendSession(user.id);
|
|
70
71
|
return "You're in with demo account!";
|
|
71
72
|
}
|
|
72
73
|
/**
|
|
73
|
-
* This is for login / password authentication
|
|
74
|
-
* _(The first param `name` can be "anything")_
|
|
74
|
+
* This is for login / password authentication invite
|
|
75
75
|
*/
|
|
76
76
|
static async invite(email) {
|
|
77
77
|
const oSafe = getSafeOptions();
|
|
78
|
-
const
|
|
79
|
-
|
|
78
|
+
const existingAccount = await remult.repo(oSafe.Account).findOne({
|
|
79
|
+
where: {
|
|
80
|
+
providerUserId: email,
|
|
81
|
+
provider: FFAuthProvider.PASSWORD.id,
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
if (existingAccount) {
|
|
80
85
|
// throw Error("Already invited !")
|
|
81
86
|
}
|
|
82
87
|
else {
|
|
83
|
-
const
|
|
84
|
-
|
|
88
|
+
const token = generateId(40);
|
|
89
|
+
// TODO: Do we create the user or just the account ?!
|
|
90
|
+
// 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({
|
|
92
|
+
// identifier: email,
|
|
93
|
+
// })
|
|
94
|
+
await remult.repo(oSafe.Account).insert({
|
|
95
|
+
provider: FFAuthProvider.PASSWORD.id,
|
|
96
|
+
providerUserId: email,
|
|
97
|
+
// userId: user.id,
|
|
98
|
+
// hashPassword: await passwordHash(password),
|
|
99
|
+
token: token,
|
|
100
|
+
expiresAt: createDate(new TimeSpan(AUTH_OPTIONS.providers?.password?.verifyMailExpiresIn ?? 5 * 60, 's')),
|
|
101
|
+
lastVerifiedAt: undefined,
|
|
85
102
|
});
|
|
86
|
-
const url = `${remult.context.url.origin}`;
|
|
103
|
+
const url = `${remult.context.url.origin}${oSafe.firstlyData.props.ui?.paths.reset_password}?token=${token}`;
|
|
87
104
|
if (AUTH_OPTIONS?.invitationSend) {
|
|
88
105
|
await AUTH_OPTIONS?.invitationSend({ email, url });
|
|
89
|
-
logAuth.success(
|
|
106
|
+
logAuth.success(`${green('[custom]')}${magenta('[invitationSend]')} (${yellow(url)})`);
|
|
90
107
|
return 'Mail sent !';
|
|
91
108
|
}
|
|
92
109
|
else {
|
|
93
|
-
await sendMail('
|
|
110
|
+
await sendMail('invitationSend', {
|
|
94
111
|
to: email,
|
|
95
112
|
subject: 'Invitation',
|
|
96
113
|
templateProps: {
|
|
@@ -111,7 +128,7 @@ export class AuthControllerServer {
|
|
|
111
128
|
],
|
|
112
129
|
},
|
|
113
130
|
});
|
|
114
|
-
logAuth.success(
|
|
131
|
+
logAuth.success(`${magenta('[invitationSend]')} (${yellow(url)})`);
|
|
115
132
|
return 'Demo Mail sent !';
|
|
116
133
|
}
|
|
117
134
|
}
|
|
@@ -129,37 +146,49 @@ export class AuthControllerServer {
|
|
|
129
146
|
if (!oSafe.password_enabled) {
|
|
130
147
|
throw Error('Password is not enabled!');
|
|
131
148
|
}
|
|
132
|
-
const
|
|
133
|
-
|
|
149
|
+
const existingAccount = await remult.repo(oSafe.Account).findOne({
|
|
150
|
+
where: {
|
|
151
|
+
providerUserId: email,
|
|
152
|
+
provider: FFAuthProvider.PASSWORD.id,
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
if (existingAccount) {
|
|
134
156
|
throw Error("You can't signup twice !");
|
|
135
157
|
}
|
|
136
158
|
checkPassword(password);
|
|
137
|
-
const user = await remult.repo(oSafe.User).insert({
|
|
138
|
-
name: email,
|
|
139
|
-
});
|
|
140
159
|
const token = generateId(40);
|
|
141
|
-
await remult.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
:
|
|
150
|
-
|
|
160
|
+
await remult.dataProvider.transaction(async () => {
|
|
161
|
+
const user = await remult.repo(oSafe.User).insert({
|
|
162
|
+
identifier: email,
|
|
163
|
+
});
|
|
164
|
+
await remult.repo(oSafe.Account).insert({
|
|
165
|
+
provider: FFAuthProvider.PASSWORD.id,
|
|
166
|
+
providerUserId: email,
|
|
167
|
+
userId: user.id,
|
|
168
|
+
hashPassword: await passwordHash(password),
|
|
169
|
+
token: oSafe.verifiedMethod === 'auto' ? undefined : token,
|
|
170
|
+
expiresAt: oSafe.verifiedMethod === 'auto'
|
|
171
|
+
? undefined
|
|
172
|
+
: createDate(new TimeSpan(AUTH_OPTIONS.providers?.password?.verifyMailExpiresIn ?? 5 * 60, 's')),
|
|
173
|
+
lastVerifiedAt: oSafe.verifiedMethod === 'auto' ? new Date() : undefined,
|
|
174
|
+
});
|
|
151
175
|
});
|
|
152
176
|
if (oSafe.verifiedMethod === 'auto') {
|
|
153
|
-
await
|
|
177
|
+
const user = await remult.repo(oSafe.User).findFirst({
|
|
178
|
+
identifier: email,
|
|
179
|
+
});
|
|
180
|
+
if (user) {
|
|
181
|
+
await createOrExtendSession(user.id);
|
|
182
|
+
}
|
|
154
183
|
}
|
|
155
184
|
else {
|
|
156
185
|
const url = `${remult.context.url.origin}${oSafe.firstlyData.props.ui?.paths.verify_email}?token=${token}`;
|
|
157
186
|
if (AUTH_OPTIONS.providers?.password?.verifyMailSend) {
|
|
158
187
|
await AUTH_OPTIONS.providers?.password.verifyMailSend({ email, url });
|
|
159
|
-
logAuth.success(
|
|
188
|
+
logAuth.success(`${green('[custom]')}${magenta('[verifyMailSend]')} (${yellow(url)})`);
|
|
160
189
|
}
|
|
161
190
|
else {
|
|
162
|
-
await sendMail('
|
|
191
|
+
await sendMail('verifyMailSend', {
|
|
163
192
|
to: email,
|
|
164
193
|
subject: 'Wecome',
|
|
165
194
|
templateProps: {
|
|
@@ -176,7 +205,7 @@ export class AuthControllerServer {
|
|
|
176
205
|
],
|
|
177
206
|
},
|
|
178
207
|
});
|
|
179
|
-
logAuth.success(
|
|
208
|
+
logAuth.success(`${magenta('[verifyMailSend]')} (${yellow(url)})`);
|
|
180
209
|
}
|
|
181
210
|
}
|
|
182
211
|
return 'ok';
|
|
@@ -190,14 +219,16 @@ export class AuthControllerServer {
|
|
|
190
219
|
if (!oSafe.password_enabled) {
|
|
191
220
|
throw Error('Password is not enabled!');
|
|
192
221
|
}
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
222
|
+
const existingAccount = await remult.repo(oSafe.Account).findOne({
|
|
223
|
+
where: {
|
|
224
|
+
providerUserId: email,
|
|
225
|
+
provider: FFAuthProvider.PASSWORD.id,
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
if (existingAccount) {
|
|
229
|
+
const validPassword = await passwordVerify(existingAccount?.hashPassword ?? '', password ?? '');
|
|
199
230
|
if (validPassword) {
|
|
200
|
-
await
|
|
231
|
+
await createOrExtendSession(existingAccount.userId);
|
|
201
232
|
return 'ok';
|
|
202
233
|
}
|
|
203
234
|
throw Error('Incorrect username or password');
|
|
@@ -212,29 +243,25 @@ export class AuthControllerServer {
|
|
|
212
243
|
if (!oSafe.password_enabled) {
|
|
213
244
|
throw Error('Password is not enabled!');
|
|
214
245
|
}
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
authAccount.userId = u.id;
|
|
223
|
-
authAccount.provider = FFAuthProvider.PASSWORD.id;
|
|
224
|
-
authAccount.providerUserId = email;
|
|
225
|
-
}
|
|
246
|
+
const existingAccount = await remult.repo(oSafe.Account).findOne({
|
|
247
|
+
where: {
|
|
248
|
+
providerUserId: email,
|
|
249
|
+
provider: FFAuthProvider.PASSWORD.id,
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
if (existingAccount) {
|
|
226
253
|
const token = generateId(40);
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
await remult.repo(oSafe.Account).save(
|
|
254
|
+
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);
|
|
230
257
|
const url = `${remult.context.url.origin}${oSafe.firstlyData.props.ui?.paths.reset_password}?token=${token}`;
|
|
231
258
|
if (AUTH_OPTIONS.providers?.password?.resetPasswordSend) {
|
|
232
259
|
await AUTH_OPTIONS.providers?.password.resetPasswordSend({ email, url });
|
|
233
|
-
logAuth.success(
|
|
260
|
+
logAuth.success(`${green('[custom]')}${magenta('[resetPasswordSend]')} (${yellow(url)})`);
|
|
234
261
|
return 'Mail sent !';
|
|
235
262
|
}
|
|
236
263
|
else {
|
|
237
|
-
await sendMail('
|
|
264
|
+
await sendMail('resetPasswordSend', {
|
|
238
265
|
to: email,
|
|
239
266
|
subject: 'Reset your password',
|
|
240
267
|
templateProps: {
|
|
@@ -255,7 +282,7 @@ export class AuthControllerServer {
|
|
|
255
282
|
],
|
|
256
283
|
},
|
|
257
284
|
});
|
|
258
|
-
logAuth.success(
|
|
285
|
+
logAuth.success(`${magenta('[resetPasswordSend]')} (${yellow(url)})`);
|
|
259
286
|
return 'Demo Mail sent !';
|
|
260
287
|
}
|
|
261
288
|
}
|
|
@@ -279,6 +306,10 @@ export class AuthControllerServer {
|
|
|
279
306
|
throw new Error('token expired');
|
|
280
307
|
}
|
|
281
308
|
checkPassword(password);
|
|
309
|
+
if (account.userId === undefined) {
|
|
310
|
+
const user = await remult.repo(oSafe.User).insert({ identifier: account.providerUserId });
|
|
311
|
+
account.userId = user.id;
|
|
312
|
+
}
|
|
282
313
|
await lucia.invalidateUserSessions(account.userId);
|
|
283
314
|
// update elements
|
|
284
315
|
account.hashPassword = await passwordHash(password);
|
|
@@ -286,7 +317,7 @@ export class AuthControllerServer {
|
|
|
286
317
|
account.expiresAt = undefined;
|
|
287
318
|
account.lastVerifiedAt = new Date();
|
|
288
319
|
await remult.repo(oSafe.Account).save(account);
|
|
289
|
-
await
|
|
320
|
+
await createOrExtendSession(account.userId);
|
|
290
321
|
return 'reseted';
|
|
291
322
|
}
|
|
292
323
|
/** OTP */
|
|
@@ -308,11 +339,11 @@ export class AuthControllerServer {
|
|
|
308
339
|
const issuer = AUTH_OPTIONS.providers.otp.issuer ?? 'firstly';
|
|
309
340
|
const uri = createTOTPKeyURI(issuer, email, secret);
|
|
310
341
|
const oSafe = getSafeOptions();
|
|
311
|
-
let user = await remult.repo(oSafe.User).findFirst({
|
|
342
|
+
let user = await remult.repo(oSafe.User).findFirst({ identifier: email });
|
|
312
343
|
if (!user) {
|
|
313
344
|
user = remult.repo(oSafe.User).create();
|
|
314
345
|
}
|
|
315
|
-
user.
|
|
346
|
+
user.identifier = email;
|
|
316
347
|
user = await remult.repo(oSafe.User).save(user);
|
|
317
348
|
let account = await remult
|
|
318
349
|
.repo(oSafe.Account)
|
|
@@ -347,7 +378,7 @@ export class AuthControllerServer {
|
|
|
347
378
|
}
|
|
348
379
|
const account = accounts[0];
|
|
349
380
|
const user = await remult.repo(oSafe.User).findId(account.userId);
|
|
350
|
-
if (user?.
|
|
381
|
+
if (user?.identifier !== email) {
|
|
351
382
|
throw new Error('Invalid otp.');
|
|
352
383
|
}
|
|
353
384
|
const { decodeHex } = await import('oslo/encoding');
|
|
@@ -363,7 +394,7 @@ export class AuthControllerServer {
|
|
|
363
394
|
account.token = undefined;
|
|
364
395
|
account.expiresAt = undefined;
|
|
365
396
|
await remult.repo(oSafe.Account).save(account);
|
|
366
|
-
await
|
|
397
|
+
await createOrExtendSession(account.userId);
|
|
367
398
|
return 'verified';
|
|
368
399
|
}
|
|
369
400
|
/** OAUTH */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ClassType } from 'remult';
|
|
2
2
|
import { Log } from '@kitql/helpers';
|
|
3
|
-
import { FFAuthUser } from './Entities';
|
|
3
|
+
import { FFAuthUser } from './client/Entities';
|
|
4
4
|
/**
|
|
5
5
|
* will merge the roles and remove duplicates
|
|
6
6
|
* will return a new array & a status if the array was changed
|
package/esm/auth/RoleHelpers.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { repo } from 'remult';
|
|
2
2
|
import { cyan, green, Log, yellow } from '@kitql/helpers';
|
|
3
|
-
import { FFAuthUser } from './Entities';
|
|
3
|
+
import { FFAuthUser } from './client/Entities';
|
|
4
4
|
/**
|
|
5
5
|
* will merge the roles and remove duplicates
|
|
6
6
|
* will return a new array & a status if the array was changed
|
|
@@ -17,13 +17,13 @@ export const mergeRoles = (existing, newOnes) => {
|
|
|
17
17
|
return { roles: Array.from(result), changed };
|
|
18
18
|
};
|
|
19
19
|
export const initRoleFromEnv = async (log, userEntity, envValue, role) => {
|
|
20
|
-
const
|
|
21
|
-
for (let i = 0; i <
|
|
22
|
-
const
|
|
23
|
-
if (
|
|
24
|
-
let user = await repo(userEntity).findFirst({
|
|
20
|
+
const identifiers = envValue === undefined ? [] : (envValue ?? '').split(',').map((c) => c.trim());
|
|
21
|
+
for (let i = 0; i < identifiers.length; i++) {
|
|
22
|
+
const identifier = identifiers[i].trim();
|
|
23
|
+
if (identifier !== '') {
|
|
24
|
+
let user = await repo(userEntity).findFirst({ identifier });
|
|
25
25
|
if (!user) {
|
|
26
|
-
user = repo(userEntity).create({
|
|
26
|
+
user = repo(userEntity).create({ identifier, roles: [role] });
|
|
27
27
|
await repo(userEntity).save(user);
|
|
28
28
|
}
|
|
29
29
|
else {
|
|
@@ -34,8 +34,8 @@ export const initRoleFromEnv = async (log, userEntity, envValue, role) => {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
if (
|
|
38
|
-
log.info(`${cyan(role)}: ${
|
|
37
|
+
if (identifiers.length > 0) {
|
|
38
|
+
log.info(`${cyan(role)}: ${identifiers.map((c) => green(c.trim())).join(', ')} added via ${yellow(`.env`)}.`);
|
|
39
39
|
}
|
|
40
40
|
else {
|
|
41
41
|
log.info(`${cyan(role)}: No users added via ${yellow(`.env`)}.`);
|
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
import type { AuthorizationURLOptions } from '..';
|
|
2
2
|
export declare class Auth {
|
|
3
|
+
/** DO NOT USE */
|
|
3
4
|
static signOutFn: any;
|
|
5
|
+
/** DO NOT USE */
|
|
4
6
|
static signInDemoFn: any;
|
|
7
|
+
/** DO NOT USE */
|
|
5
8
|
static inviteFn: any;
|
|
9
|
+
/** DO NOT USE */
|
|
6
10
|
static signUpPasswordFn: any;
|
|
11
|
+
/** DO NOT USE */
|
|
7
12
|
static signInPasswordFn: any;
|
|
13
|
+
/** DO NOT USE */
|
|
8
14
|
static forgotPasswordFn: any;
|
|
15
|
+
/** DO NOT USE */
|
|
9
16
|
static resetPasswordFn: any;
|
|
17
|
+
/** DO NOT USE */
|
|
10
18
|
static signInOTPFn: any;
|
|
19
|
+
/** DO NOT USE */
|
|
11
20
|
static verifyOtpFn: any;
|
|
21
|
+
/** DO NOT USE */
|
|
12
22
|
static signInOAuthGetUrlFn: any;
|
|
13
23
|
/**
|
|
14
24
|
* Sign out the current user
|
|
@@ -20,18 +30,15 @@ export declare class Auth {
|
|
|
20
30
|
*/
|
|
21
31
|
static signInDemo(name: string): Promise<any>;
|
|
22
32
|
/**
|
|
23
|
-
* This is for login / password authentication
|
|
24
|
-
* _(The first param `name` can be "anything")_
|
|
33
|
+
* This is for login / password authentication Invite someone
|
|
25
34
|
*/
|
|
26
35
|
static invite(email: string): Promise<any>;
|
|
27
36
|
/**
|
|
28
37
|
* This is for login / password authentication SignUp
|
|
29
|
-
* _(The first param `email` can be "anything")_
|
|
30
38
|
*/
|
|
31
39
|
static signUpPassword(email: string, password: string): Promise<any>;
|
|
32
40
|
/**
|
|
33
41
|
* This is for login / password authentication SignIn
|
|
34
|
-
* _(The first param `email` can be "anything")_
|
|
35
42
|
*/
|
|
36
43
|
static signInPassword(email: string, password: string): Promise<any>;
|
|
37
44
|
/**
|