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.
- package/CHANGELOG.md +16 -0
- package/esm/BaseEnum.d.ts +2 -0
- package/esm/BaseEnum.js +2 -0
- package/esm/FF_Fields.js +0 -1
- package/esm/ROUTES.d.ts +2 -2
- package/esm/ROUTES.js +10 -5
- package/esm/SqlDatabase/FF_LogToConsole.d.ts +1 -0
- package/esm/SqlDatabase/FF_LogToConsole.js +22 -16
- package/esm/api/index.d.ts +19 -21
- package/esm/api/index.js +72 -62
- package/esm/auth/{client/Auth.d.ts → AuthController.d.ts} +18 -25
- package/esm/auth/{client/Auth.js → AuthController.js} +48 -44
- package/esm/auth/{client/Entities.d.ts → Entities.d.ts} +4 -3
- package/esm/auth/{client/Entities.js → Entities.js} +7 -7
- package/esm/auth/README.md +0 -10
- package/esm/auth/index.d.ts +5 -149
- package/esm/auth/index.js +5 -316
- package/esm/auth/{AuthController.server.d.ts → server/AuthController.server.d.ts} +10 -10
- package/esm/auth/{AuthController.server.js → server/AuthController.server.js} +126 -164
- package/esm/auth/server/handleAuth.d.ts +2 -0
- package/esm/auth/server/handleAuth.js +140 -0
- package/esm/auth/server/helperDb.d.ts +10 -0
- package/esm/auth/server/helperDb.js +56 -0
- package/esm/auth/server/helperFirstly.d.ts +1 -0
- package/esm/auth/server/helperFirstly.js +8 -0
- package/esm/auth/server/helperOslo.d.ts +7 -0
- package/esm/auth/server/helperOslo.js +24 -0
- package/esm/auth/server/helperRemultServer.d.ts +5 -0
- package/esm/auth/server/helperRemultServer.js +44 -0
- package/esm/auth/{RoleHelpers.d.ts → server/helperRole.d.ts} +1 -1
- package/esm/auth/{RoleHelpers.js → server/helperRole.js} +1 -1
- package/esm/auth/server/index.d.ts +5 -0
- package/esm/auth/server/index.js +5 -0
- package/esm/auth/server/module.d.ts +238 -0
- package/esm/auth/server/module.js +184 -0
- package/esm/auth/{providers → server/providers}/github.d.ts +6 -5
- package/esm/auth/{providers → server/providers}/github.js +30 -21
- package/esm/auth/{providers/index.d.ts → server/providers/helperProvider.d.ts} +0 -2
- package/esm/auth/{providers/index.js → server/providers/helperProvider.js} +5 -6
- package/esm/auth/static/assets/{Page-BEFYPjis.d.ts → Page-Bb8bFlrP.d.ts} +1 -1
- package/esm/auth/static/assets/{Page-DtgkOCJs.js → Page-Bb8bFlrP.js} +1 -1
- package/esm/auth/static/assets/{Page-DtgkOCJs.d.ts → Page-BxomFlZ8.d.ts} +1 -1
- package/esm/auth/static/assets/{Page-BEFYPjis.js → Page-BxomFlZ8.js} +1 -1
- package/esm/auth/static/assets/Page-CaIYu0-y.d.ts +6 -0
- package/esm/auth/static/assets/Page-CaIYu0-y.js +19 -0
- package/esm/auth/static/assets/Page-MkYglNtu.css +1 -0
- package/esm/auth/static/assets/index-Bl0Bk5u0.d.ts +64 -0
- package/esm/auth/static/assets/index-Bl0Bk5u0.js +2 -0
- package/esm/auth/static/assets/{index-CR_3yNaJ.css → index-R27C_TlP.css} +1 -1
- package/esm/auth/static/index.html +2 -2
- package/esm/auth/types.d.ts +5 -0
- package/esm/bin/cmd.js +13 -22
- package/esm/cellsBuildor.js +6 -6
- package/esm/changeLog/index.d.ts +0 -36
- package/esm/changeLog/index.js +3 -43
- package/esm/changeLog/server/index.d.ts +36 -0
- package/esm/changeLog/server/index.js +42 -0
- package/esm/cron/{index.d.ts → server/index.d.ts} +1 -1
- package/esm/cron/server/index.js +103 -0
- package/esm/feedback/FeedbackController.js +3 -3
- package/esm/feedback/index.d.ts +0 -16
- package/esm/feedback/index.js +0 -11
- package/esm/feedback/server/index.d.ts +17 -0
- package/esm/feedback/server/index.js +13 -0
- package/esm/feedback/ui/DialogIssue.svelte +4 -2
- package/esm/feedback/ui/DialogIssues.svelte +13 -4
- package/esm/feedback/ui/DialogMilestones.svelte +1 -1
- package/esm/feedback/ui/Feedback.svelte +3 -1
- package/esm/helper.d.ts +0 -1
- package/esm/helper.js +3 -17
- package/esm/index.d.ts +3 -17
- package/esm/index.js +3 -4
- package/esm/mail/index.d.ts +2 -30
- package/esm/mail/index.js +2 -79
- package/esm/mail/server/index.d.ts +31 -0
- package/esm/mail/server/index.js +88 -0
- package/esm/storeItem.d.ts +4 -1
- package/esm/storeItem.js +8 -2
- package/esm/storeList.d.ts +5 -2
- package/esm/storeList.js +1 -1
- package/esm/sveltekit/server/index.d.ts +11 -0
- package/esm/sveltekit/server/index.js +21 -0
- package/esm/ui/Button.svelte +1 -1
- package/esm/ui/Clipboardable.svelte +5 -2
- package/esm/ui/Field.svelte +4 -1
- package/esm/ui/Loading.svelte +4 -1
- package/esm/ui/Tooltip.svelte +2 -2
- package/esm/ui/dialog/DialogForm.svelte +1 -1
- package/esm/ui/dialog/DialogPrimitive.svelte +1 -2
- package/esm/ui/dialog/dialog.d.ts +6 -3
- package/esm/ui/dialog/dialog.js +1 -1
- package/esm/ui/internals/FieldContainer.svelte +0 -1
- package/esm/ui/internals/Input.svelte +3 -1
- package/esm/ui/internals/Textarea.svelte +2 -2
- package/esm/vite/index.js +24 -25
- package/package.json +50 -38
- package/esm/auth/Adapter.d.ts +0 -10
- package/esm/auth/Adapter.js +0 -50
- package/esm/auth/client/index.d.ts +0 -7
- package/esm/auth/client/index.js +0 -7
- package/esm/auth/helper.d.ts +0 -6
- package/esm/auth/helper.js +0 -14
- package/esm/auth/providers/strava.d.ts +0 -30
- package/esm/auth/providers/strava.js +0 -60
- package/esm/auth/static/assets/Page-BGTO8LC5.css +0 -1
- package/esm/auth/static/assets/Page-Cfysx_UV.d.ts +0 -6
- package/esm/auth/static/assets/Page-Cfysx_UV.js +0 -18
- package/esm/auth/static/assets/index-QypqCYwC.d.ts +0 -63
- package/esm/auth/static/assets/index-QypqCYwC.js +0 -2
- package/esm/cron/index.js +0 -102
- package/esm/handle/index.d.ts +0 -7
- package/esm/handle/index.js +0 -40
|
@@ -6,9 +6,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
var FFAuthProvider_1;
|
|
8
8
|
import { Fields, Relations, Validators, ValueListFieldType } from 'remult';
|
|
9
|
-
import { BaseEnum, FF_Entity, FF_Role } from '
|
|
9
|
+
import { BaseEnum, FF_Entity, FF_Role } from '..';
|
|
10
10
|
export const FF_Role_Auth = {
|
|
11
|
-
|
|
11
|
+
FF_Role_Auth_Admin: 'FF_Role_Auth.Admin',
|
|
12
|
+
FF_Role_Auth_Invite: 'FF_Role_Auth.Invite',
|
|
12
13
|
};
|
|
13
14
|
let FFAuthUser = class FFAuthUser {
|
|
14
15
|
id;
|
|
@@ -65,7 +66,7 @@ __decorate([
|
|
|
65
66
|
], FFAuthUser.prototype, "sessions", void 0);
|
|
66
67
|
FFAuthUser = __decorate([
|
|
67
68
|
FF_Entity('ff_auth.users', {
|
|
68
|
-
allowApiCrud: [FF_Role_Auth.
|
|
69
|
+
allowApiCrud: [FF_Role_Auth.FF_Role_Auth_Admin, FF_Role.FF_Role_Admin],
|
|
69
70
|
caption: 'FF Auth - Users',
|
|
70
71
|
})
|
|
71
72
|
], FFAuthUser);
|
|
@@ -118,9 +119,8 @@ __decorate([
|
|
|
118
119
|
], FFAuthAccount.prototype, "lastVerifiedAt", void 0);
|
|
119
120
|
FFAuthAccount = __decorate([
|
|
120
121
|
FF_Entity('ff_auth.accounts', {
|
|
121
|
-
allowApiCrud: [FF_Role_Auth.
|
|
122
|
+
allowApiCrud: [FF_Role_Auth.FF_Role_Auth_Admin, FF_Role.FF_Role_Admin],
|
|
122
123
|
caption: 'FF Auth - Accounts',
|
|
123
|
-
// id: { provider: true, userId: true },
|
|
124
124
|
changeLog: {
|
|
125
125
|
excludeColumns: (e) => {
|
|
126
126
|
return [e.hashPassword, e.token];
|
|
@@ -136,7 +136,7 @@ let FFAuthUserSession = class FFAuthUserSession {
|
|
|
136
136
|
user;
|
|
137
137
|
};
|
|
138
138
|
__decorate([
|
|
139
|
-
Fields.
|
|
139
|
+
Fields.string()
|
|
140
140
|
], FFAuthUserSession.prototype, "id", void 0);
|
|
141
141
|
__decorate([
|
|
142
142
|
Fields.date()
|
|
@@ -149,7 +149,7 @@ __decorate([
|
|
|
149
149
|
], FFAuthUserSession.prototype, "user", void 0);
|
|
150
150
|
FFAuthUserSession = __decorate([
|
|
151
151
|
FF_Entity('ff_auth.users_sessions', {
|
|
152
|
-
allowApiCrud: [FF_Role_Auth.
|
|
152
|
+
allowApiCrud: [FF_Role_Auth.FF_Role_Auth_Admin, FF_Role.FF_Role_Admin],
|
|
153
153
|
caption: 'FF Auth - Users sessions',
|
|
154
154
|
changeLog: false,
|
|
155
155
|
})
|
package/esm/auth/README.md
CHANGED
|
@@ -1,13 +1,3 @@
|
|
|
1
1
|
# Firstly - Module - Auth
|
|
2
2
|
|
|
3
3
|
➡️ Doc available [here](https://firstly.fun/modules/auth).
|
|
4
|
-
|
|
5
|
-
## Complement
|
|
6
|
-
|
|
7
|
-
### Lucia adapter
|
|
8
|
-
|
|
9
|
-
Under the hood, we created a lucia adapter, you can check the code [here](./Adapter.ts) . Feel free
|
|
10
|
-
to copy/paste it in your own codebase. You can also suggest improvements here 😉.
|
|
11
|
-
|
|
12
|
-
By default, all tables/fields will show up in your admin and you are able to extend then with your
|
|
13
|
-
own fields.
|
package/esm/auth/index.d.ts
CHANGED
|
@@ -1,149 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { FFAuthAccount, FFAuthUser, FFAuthUserSession } from './client/Entities';
|
|
7
|
-
import { initRoleFromEnv } from './RoleHelpers';
|
|
8
|
-
import type { firstlyData, firstlyDataAuth } from './types';
|
|
9
|
-
export type { firstlyData };
|
|
10
|
-
export type AuthorizationURLOptions = Record<string, {
|
|
11
|
-
scopes?: string[];
|
|
12
|
-
}>;
|
|
13
|
-
export type DynamicAuthorizationURLOptions<T extends FFOAuth2Provider[] = FFOAuth2Provider[]> = T extends Array<infer O> ? O extends FFOAuth2Provider ? {
|
|
14
|
-
[P in O['name']]: ReturnType<O['authorizationURLOptions']>;
|
|
15
|
-
} : never : never;
|
|
16
|
-
type OAuth2UserInfo = {
|
|
17
|
-
raw?: any;
|
|
18
|
-
providerUserId: string;
|
|
19
|
-
/** Will take the first option available */
|
|
20
|
-
nameOptions: string[];
|
|
21
|
-
};
|
|
22
|
-
export type FFOAuth2Provider<LitName extends string = string, T extends ArcticOAuth2Provider | ArcticOAuth2ProviderWithPKCE = ArcticOAuth2Provider> = {
|
|
23
|
-
name: LitName;
|
|
24
|
-
getArcticProvider: () => T;
|
|
25
|
-
isPKCE: T extends ArcticOAuth2Provider ? false : T extends ArcticOAuth2ProviderWithPKCE ? true : never;
|
|
26
|
-
authorizationURLOptions: () => T extends ArcticOAuth2Provider ? Parameters<T['createAuthorizationURL']>[1] : T extends ArcticOAuth2ProviderWithPKCE ? Parameters<T['createAuthorizationURL']>[2] : never;
|
|
27
|
-
getUserInfo(tokens: ResolvedType<ReturnType<T['validateAuthorizationCode']>>): Promise<OAuth2UserInfo>;
|
|
28
|
-
};
|
|
29
|
-
type AuthOptions<TUserEntity extends FFAuthUser = FFAuthUser, TSessionEntity extends FFAuthUserSession = FFAuthUserSession, TAccountEntity extends FFAuthAccount = FFAuthAccount> = {
|
|
30
|
-
customEntities?: {
|
|
31
|
-
User?: ClassType<TUserEntity>;
|
|
32
|
-
Session?: ClassType<TSessionEntity>;
|
|
33
|
-
Account?: ClassType<TAccountEntity>;
|
|
34
|
-
};
|
|
35
|
-
debug?: boolean;
|
|
36
|
-
ui?: false | RecursivePartial<firstlyDataAuth['ui']>;
|
|
37
|
-
/** Usefull to overwrite where the static files are */
|
|
38
|
-
uiStaticPath?: string;
|
|
39
|
-
/** in secondes @default 30 days */
|
|
40
|
-
sessionExpiresIn?: number;
|
|
41
|
-
sessionCookie?: SessionCookieOptions;
|
|
42
|
-
defaultRedirect?: string;
|
|
43
|
-
/**
|
|
44
|
-
* Can a user sign up by itself? Or we can join only by invitation ?
|
|
45
|
-
* If false, no one can sign up alone.
|
|
46
|
-
* @default true
|
|
47
|
-
**/
|
|
48
|
-
signUp?: boolean;
|
|
49
|
-
/**
|
|
50
|
-
* To be able to sign in user needs to be verified or not?
|
|
51
|
-
* ```
|
|
52
|
-
* `Auto` => noting will be checked
|
|
53
|
-
* `Email` => users needs to click a link in an email
|
|
54
|
-
* `Manual` => an admin needs to verify the user and set verifiedAt in the database
|
|
55
|
-
* ```
|
|
56
|
-
* @default auto
|
|
57
|
-
**/
|
|
58
|
-
verifiedMethod?: 'auto' | 'email' | 'manual';
|
|
59
|
-
invitationSend?: (args: {
|
|
60
|
-
email: string;
|
|
61
|
-
url: string;
|
|
62
|
-
}) => Promise<void>;
|
|
63
|
-
transformDbUserToClientUser?: (session: any, user: TUserEntity) => DatabaseUserAttributes;
|
|
64
|
-
providers?: {
|
|
65
|
-
demo?: {
|
|
66
|
-
name: string;
|
|
67
|
-
roles?: string[];
|
|
68
|
-
}[];
|
|
69
|
-
password?: {
|
|
70
|
-
/**
|
|
71
|
-
* Reseting the password
|
|
72
|
-
*/
|
|
73
|
-
resetPasswordSend?: (args: {
|
|
74
|
-
email: string;
|
|
75
|
-
url: string;
|
|
76
|
-
}) => Promise<void>;
|
|
77
|
-
/** in secondes @default 5 minutes */
|
|
78
|
-
resetPasswordExpiresIn?: number;
|
|
79
|
-
/**
|
|
80
|
-
* Verify the Mail
|
|
81
|
-
*/
|
|
82
|
-
verifyMailSend?: (args: {
|
|
83
|
-
email: string;
|
|
84
|
-
url: string;
|
|
85
|
-
}) => Promise<void>;
|
|
86
|
-
/** in secondes @default 5 minutes */
|
|
87
|
-
verifyMailExpiresIn?: number;
|
|
88
|
-
/**
|
|
89
|
-
* Some settings for the password hashing algorithm _(using argon2 under the hood)_
|
|
90
|
-
*/
|
|
91
|
-
argon2Settings?: {
|
|
92
|
-
memorySize?: number | undefined;
|
|
93
|
-
iterations?: number | undefined;
|
|
94
|
-
tagLength?: number | undefined;
|
|
95
|
-
parallelism?: number | undefined;
|
|
96
|
-
secret?: ArrayBuffer | undefined;
|
|
97
|
-
};
|
|
98
|
-
};
|
|
99
|
-
otp?: {
|
|
100
|
-
issuer?: string;
|
|
101
|
-
/** in secondes @default 30 seconds */
|
|
102
|
-
expiresIn?: number;
|
|
103
|
-
/** Number of digits @default 6 */
|
|
104
|
-
digits?: number;
|
|
105
|
-
send?: (data: {
|
|
106
|
-
name: string;
|
|
107
|
-
otp: string;
|
|
108
|
-
uri: string;
|
|
109
|
-
}) => Promise<void>;
|
|
110
|
-
};
|
|
111
|
-
oAuths?: FFOAuth2Provider[];
|
|
112
|
-
};
|
|
113
|
-
};
|
|
114
|
-
export declare let AUTH_OPTIONS: AuthOptions;
|
|
115
|
-
export declare const getSafeOptions: () => {
|
|
116
|
-
User: ClassType<FFAuthUser>;
|
|
117
|
-
Session: ClassType<FFAuthUserSession>;
|
|
118
|
-
Account: ClassType<FFAuthAccount>;
|
|
119
|
-
signUp: boolean;
|
|
120
|
-
password_enabled: boolean;
|
|
121
|
-
otp_enabled: boolean;
|
|
122
|
-
verifiedMethod: "email" | "auto" | "manual";
|
|
123
|
-
redirectUrl: string;
|
|
124
|
-
firstlyData: firstlyData;
|
|
125
|
-
transformDbUserToClientUser: (session: any, user: FFAuthUser) => DatabaseUserAttributes;
|
|
126
|
-
uiStaticPath: string;
|
|
127
|
-
};
|
|
128
|
-
/**
|
|
129
|
-
* To enable authentication in your app in a few lines of code.
|
|
130
|
-
* _Info: index: -777_
|
|
131
|
-
*/
|
|
132
|
-
export declare const auth: (o: AuthOptions) => Module;
|
|
133
|
-
export { initRoleFromEnv };
|
|
134
|
-
export declare let lucia: Lucia<Record<any, any>, UserInfo>;
|
|
135
|
-
declare module 'lucia' {
|
|
136
|
-
interface Register {
|
|
137
|
-
Lucia: typeof lucia;
|
|
138
|
-
DatabaseSessionAttributes: DatabaseSessionAttributes;
|
|
139
|
-
DatabaseUserAttributes: DatabaseUserAttributes;
|
|
140
|
-
}
|
|
141
|
-
interface DatabaseSessionAttributes {
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
interface DatabaseUserAttributes extends UserInfo {
|
|
145
|
-
session: {
|
|
146
|
-
id: string;
|
|
147
|
-
expiresAt: Date;
|
|
148
|
-
};
|
|
149
|
-
}
|
|
1
|
+
import { AuthController } from './AuthController';
|
|
2
|
+
import { FFAuthAccount, FFAuthProvider, FFAuthUser, FFAuthUserSession } from './Entities';
|
|
3
|
+
export { FF_Role_Auth } from './Entities';
|
|
4
|
+
export { AuthController };
|
|
5
|
+
export { FFAuthUser, FFAuthAccount, FFAuthProvider, FFAuthUserSession };
|
package/esm/auth/index.js
CHANGED
|
@@ -1,316 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { getRelativePackagePath, read } from '@kitql/internals';
|
|
7
|
-
import { FF_Role } from '../';
|
|
8
|
-
import { RemultLuciaAdapter } from './Adapter';
|
|
9
|
-
import { AuthControllerServer } from './AuthController.server';
|
|
10
|
-
import { Auth, logAuth } from './client';
|
|
11
|
-
import { FF_Role_Auth, FFAuthAccount, FFAuthProvider, FFAuthUser, FFAuthUserSession, } from './client/Entities';
|
|
12
|
-
import { createOrExtendSession } from './helper';
|
|
13
|
-
import { initRoleFromEnv } from './RoleHelpers';
|
|
14
|
-
export let AUTH_OPTIONS = { ui: {} };
|
|
15
|
-
const buildUrlOrDefault = (base, userSetting, fallback) => {
|
|
16
|
-
if (userSetting === false) {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
if (userSetting === undefined) {
|
|
20
|
-
return `${base}/${fallback}`;
|
|
21
|
-
}
|
|
22
|
-
return `${base}/${userSetting}`;
|
|
23
|
-
};
|
|
24
|
-
export const getSafeOptions = () => {
|
|
25
|
-
const signUp = AUTH_OPTIONS.signUp ?? true;
|
|
26
|
-
const base = AUTH_OPTIONS.ui === false ? 'NO_BASE_PATH' : (AUTH_OPTIONS.ui?.paths?.base ?? '/ff/auth');
|
|
27
|
-
const firstlyData = {
|
|
28
|
-
module: 'auth',
|
|
29
|
-
debug: AUTH_OPTIONS.debug,
|
|
30
|
-
props: {
|
|
31
|
-
ui: AUTH_OPTIONS.ui === false
|
|
32
|
-
? undefined
|
|
33
|
-
: {
|
|
34
|
-
paths: {
|
|
35
|
-
base,
|
|
36
|
-
sign_up: buildUrlOrDefault(base, AUTH_OPTIONS.ui?.paths?.sign_up, 'sign-up'),
|
|
37
|
-
sign_in: buildUrlOrDefault(base, AUTH_OPTIONS.ui?.paths?.sign_in, 'sign-in'),
|
|
38
|
-
forgot_password: buildUrlOrDefault(base, AUTH_OPTIONS.ui?.paths?.forgot_password, 'forgot-password'),
|
|
39
|
-
reset_password: buildUrlOrDefault(base, AUTH_OPTIONS.ui?.paths?.reset_password, 'reset-password'),
|
|
40
|
-
verify_email: buildUrlOrDefault(base, AUTH_OPTIONS.ui?.paths?.verify_email, 'verify-email'),
|
|
41
|
-
},
|
|
42
|
-
strings: {
|
|
43
|
-
email: AUTH_OPTIONS.ui?.strings?.email ?? 'Email',
|
|
44
|
-
email_placeholder: AUTH_OPTIONS.ui?.strings?.email_placeholder ?? 'Your email address',
|
|
45
|
-
password: AUTH_OPTIONS.ui?.strings?.password ?? 'Password',
|
|
46
|
-
confirm: AUTH_OPTIONS.ui?.strings?.confirm ?? 'Confirm',
|
|
47
|
-
reset: AUTH_OPTIONS.ui?.strings?.reset ?? 'Reset',
|
|
48
|
-
btn_sign_up: AUTH_OPTIONS.ui?.strings?.btn_sign_up ?? 'Sign up',
|
|
49
|
-
btn_sign_in: AUTH_OPTIONS.ui?.strings?.btn_sign_in ?? 'Sign in',
|
|
50
|
-
forgot_password: AUTH_OPTIONS.ui?.strings?.forgot_password ?? 'Forgot your password?',
|
|
51
|
-
send_password_reset_instructions: AUTH_OPTIONS.ui?.strings?.send_password_reset_instructions ??
|
|
52
|
-
'Send password reset instructions',
|
|
53
|
-
back_to_sign_in: AUTH_OPTIONS.ui?.strings?.back_to_sign_in ?? 'Back to sign in',
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
let uiStaticPath = AUTH_OPTIONS.uiStaticPath ?? '';
|
|
59
|
-
if (!AUTH_OPTIONS.uiStaticPath) {
|
|
60
|
-
const installedFirstlyPath = getRelativePackagePath('firstly');
|
|
61
|
-
if (installedFirstlyPath) {
|
|
62
|
-
uiStaticPath = `${installedFirstlyPath}/esm/auth/static/`;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
let redirectUrl = AUTH_OPTIONS.defaultRedirect ?? '/';
|
|
66
|
-
if (!redirectUrl.startsWith('/')) {
|
|
67
|
-
logAuth.error(`Invalid redirect url ${red(redirectUrl)} (it should be a local one starting with /)`);
|
|
68
|
-
redirectUrl = '/';
|
|
69
|
-
}
|
|
70
|
-
let transformDbUserToClientUserToUse;
|
|
71
|
-
if (AUTH_OPTIONS.transformDbUserToClientUser) {
|
|
72
|
-
transformDbUserToClientUserToUse = AUTH_OPTIONS.transformDbUserToClientUser;
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
// Need in src/app.d.ts this code to be able to have the correct transformDbUserToClientUser returned type.
|
|
76
|
-
// In the lib, let's force to this default
|
|
77
|
-
/**
|
|
78
|
-
* declare module 'remult' {
|
|
79
|
-
* export interface UserInfo {
|
|
80
|
-
* specificThing: string
|
|
81
|
-
* }
|
|
82
|
-
* }
|
|
83
|
-
*/
|
|
84
|
-
// @ts-ignore
|
|
85
|
-
transformDbUserToClientUserToUse = (session, user) => {
|
|
86
|
-
return {
|
|
87
|
-
id: user.id,
|
|
88
|
-
name: user.identifier,
|
|
89
|
-
roles: user.roles,
|
|
90
|
-
session: {
|
|
91
|
-
id: session.id,
|
|
92
|
-
expiresAt: session.expiresAt,
|
|
93
|
-
},
|
|
94
|
-
};
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
return {
|
|
98
|
-
User: AUTH_OPTIONS.customEntities?.User ?? FFAuthUser,
|
|
99
|
-
Session: AUTH_OPTIONS.customEntities?.Session ?? FFAuthUserSession,
|
|
100
|
-
Account: AUTH_OPTIONS.customEntities?.Account ?? FFAuthAccount,
|
|
101
|
-
signUp,
|
|
102
|
-
password_enabled: AUTH_OPTIONS.providers?.password ? true : false,
|
|
103
|
-
otp_enabled: AUTH_OPTIONS.providers?.otp ? true : false,
|
|
104
|
-
verifiedMethod: AUTH_OPTIONS.verifiedMethod ?? 'auto',
|
|
105
|
-
redirectUrl,
|
|
106
|
-
firstlyData,
|
|
107
|
-
transformDbUserToClientUser: transformDbUserToClientUserToUse,
|
|
108
|
-
uiStaticPath,
|
|
109
|
-
};
|
|
110
|
-
};
|
|
111
|
-
/**
|
|
112
|
-
* To enable authentication in your app in a few lines of code.
|
|
113
|
-
* _Info: index: -777_
|
|
114
|
-
*/
|
|
115
|
-
export const auth = (o) => {
|
|
116
|
-
AUTH_OPTIONS = o;
|
|
117
|
-
const oSafe = getSafeOptions();
|
|
118
|
-
// abstract the call
|
|
119
|
-
Auth.signOutFn = AuthControllerServer.signOut;
|
|
120
|
-
Auth.signInDemoFn = AuthControllerServer.signInDemo;
|
|
121
|
-
Auth.inviteFn = AuthControllerServer.invite;
|
|
122
|
-
Auth.signUpPasswordFn = AuthControllerServer.signUpPassword;
|
|
123
|
-
Auth.signInPasswordFn = AuthControllerServer.signInPassword;
|
|
124
|
-
Auth.forgotPasswordFn = AuthControllerServer.forgotPassword;
|
|
125
|
-
Auth.resetPasswordFn = AuthControllerServer.resetPassword;
|
|
126
|
-
Auth.signInOTPFn = AuthControllerServer.signInOTP;
|
|
127
|
-
Auth.verifyOtpFn = AuthControllerServer.verifyOtp;
|
|
128
|
-
Auth.signInOAuthGetUrlFn = AuthControllerServer.signInOAuthGetUrl;
|
|
129
|
-
const adapter = new RemultLuciaAdapter();
|
|
130
|
-
const defaultExpiresIn = 60 * 60 * 24 * 30; // 30 days
|
|
131
|
-
const sessionExpiresIn = new TimeSpan(AUTH_OPTIONS.sessionExpiresIn ?? defaultExpiresIn, 's');
|
|
132
|
-
lucia = new Lucia(adapter, {
|
|
133
|
-
sessionExpiresIn,
|
|
134
|
-
sessionCookie: {
|
|
135
|
-
name: AUTH_OPTIONS.sessionCookie?.name ?? 'firstly_auth_session',
|
|
136
|
-
expires: AUTH_OPTIONS.sessionCookie?.expires,
|
|
137
|
-
attributes: {
|
|
138
|
-
// set to `true` when using HTTPS
|
|
139
|
-
secure: !DEV,
|
|
140
|
-
...AUTH_OPTIONS.sessionCookie?.attributes,
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
getSessionAttributes: (attributes) => attributes,
|
|
144
|
-
getUserAttributes: (attributes) => attributes,
|
|
145
|
-
});
|
|
146
|
-
return {
|
|
147
|
-
name: 'auth',
|
|
148
|
-
index: -777,
|
|
149
|
-
entities: [oSafe.User, oSafe.Session, oSafe.Account],
|
|
150
|
-
controllers: [Auth],
|
|
151
|
-
initRequest: async (event) => {
|
|
152
|
-
// REMULT: storing user in local should probably be done in remult directly
|
|
153
|
-
if (event?.locals?.user) {
|
|
154
|
-
// console.log('initRequest OK')
|
|
155
|
-
remult.user = event.locals.user;
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
// console.log('initRequest WORK...')
|
|
159
|
-
// std session
|
|
160
|
-
const sessionId = event.cookies.get(lucia.sessionCookieName);
|
|
161
|
-
if (sessionId) {
|
|
162
|
-
const { session, user } = await lucia.validateSession(sessionId);
|
|
163
|
-
if (session && session.fresh) {
|
|
164
|
-
await createOrExtendSession(session.id, session);
|
|
165
|
-
}
|
|
166
|
-
remult.user = user ?? undefined;
|
|
167
|
-
if (event.locals) {
|
|
168
|
-
event.locals.user = user ?? undefined;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
},
|
|
173
|
-
earlyReturn: async ({ event, resolve }) => {
|
|
174
|
-
const oSafe = getSafeOptions();
|
|
175
|
-
if (event.url.pathname === oSafe.firstlyData.props.ui?.paths?.verify_email) {
|
|
176
|
-
const token = event.url.searchParams.get('token') ?? '';
|
|
177
|
-
if (!oSafe.password_enabled) {
|
|
178
|
-
throw Error('Password is not enabled!');
|
|
179
|
-
}
|
|
180
|
-
const account = await remult
|
|
181
|
-
.repo(oSafe.Account)
|
|
182
|
-
.findFirst({ token, provider: FFAuthProvider.PASSWORD.id });
|
|
183
|
-
if (!account) {
|
|
184
|
-
throw new Error('Invalid token');
|
|
185
|
-
}
|
|
186
|
-
if (account.expiresAt && account.expiresAt < new Date()) {
|
|
187
|
-
throw new Error('token expired');
|
|
188
|
-
}
|
|
189
|
-
await lucia.invalidateUserSessions(account.userId);
|
|
190
|
-
// update elements
|
|
191
|
-
account.token = undefined;
|
|
192
|
-
account.expiresAt = undefined;
|
|
193
|
-
account.lastVerifiedAt = new Date();
|
|
194
|
-
await remult.repo(oSafe.Account).save(account);
|
|
195
|
-
await createOrExtendSession(account.userId);
|
|
196
|
-
redirect(302, oSafe.redirectUrl);
|
|
197
|
-
}
|
|
198
|
-
if (oSafe.firstlyData.props.ui?.paths?.base &&
|
|
199
|
-
event.url.pathname.startsWith(oSafe.firstlyData.props.ui.paths.base)) {
|
|
200
|
-
const content = read(`${oSafe.uiStaticPath}index.html`);
|
|
201
|
-
return {
|
|
202
|
-
early: true,
|
|
203
|
-
resolve: new Response(content + `<script>const firstlyData = ${JSON.stringify(oSafe.firstlyData)}</script>`, {
|
|
204
|
-
headers: { 'content-type': 'text/html' },
|
|
205
|
-
}),
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
if (event.url.pathname.startsWith('/api/static')) {
|
|
209
|
-
const content = read(`${oSafe.uiStaticPath}${event.url.pathname.replaceAll('/api/static/', '')}`);
|
|
210
|
-
if (content) {
|
|
211
|
-
const seg = event.url.pathname.split('.');
|
|
212
|
-
const map = {
|
|
213
|
-
js: 'text/javascript',
|
|
214
|
-
css: 'text/css',
|
|
215
|
-
svg: 'image/svg+xml',
|
|
216
|
-
};
|
|
217
|
-
return {
|
|
218
|
-
early: true,
|
|
219
|
-
resolve: new Response(content, {
|
|
220
|
-
headers: { 'content-type': map[seg[seg.length - 1]] ?? 'text/plain' },
|
|
221
|
-
}),
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
if (event.url.pathname === '/api/auth_callback') {
|
|
226
|
-
const code = event.url.searchParams.get('code');
|
|
227
|
-
const state = event.url.searchParams.get('state');
|
|
228
|
-
const keys = AUTH_OPTIONS.providers?.oAuths?.map((c) => c.name) ?? [];
|
|
229
|
-
let storedState = null;
|
|
230
|
-
let keyState = null;
|
|
231
|
-
for (const key of keys) {
|
|
232
|
-
storedState = event.cookies.get(`${key}_oauth_state`) ?? null;
|
|
233
|
-
if (storedState) {
|
|
234
|
-
keyState = key;
|
|
235
|
-
break;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
const redirectUrlCookie = event.cookies.get(`remult_redirect`);
|
|
239
|
-
if (redirectUrlCookie) {
|
|
240
|
-
event.cookies.delete(`remult_redirect`, { path: '/' });
|
|
241
|
-
}
|
|
242
|
-
const redirectUrl = redirectUrlCookie ?? oSafe.redirectUrl;
|
|
243
|
-
if (!code || !state || !storedState || state !== storedState || !keyState) {
|
|
244
|
-
redirect(302, redirectUrl);
|
|
245
|
-
}
|
|
246
|
-
const selectedOAuth = AUTH_OPTIONS.providers?.oAuths?.find((c) => c.name === keyState);
|
|
247
|
-
if (selectedOAuth && code) {
|
|
248
|
-
const tokens = await selectedOAuth.getArcticProvider().validateAuthorizationCode(code);
|
|
249
|
-
let info;
|
|
250
|
-
try {
|
|
251
|
-
info = await selectedOAuth.getUserInfo(tokens);
|
|
252
|
-
}
|
|
253
|
-
catch (error) {
|
|
254
|
-
redirect(302, redirectUrl);
|
|
255
|
-
}
|
|
256
|
-
if (!info.providerUserId) {
|
|
257
|
-
redirect(302, redirectUrl);
|
|
258
|
-
}
|
|
259
|
-
let account = await remult
|
|
260
|
-
.repo(oSafe.Account)
|
|
261
|
-
.findFirst({ provider: keyState, providerUserId: info.providerUserId });
|
|
262
|
-
if (!account) {
|
|
263
|
-
if (!oSafe.signUp) {
|
|
264
|
-
// throw Error("You can't signup by yourself! Contact the administrator.")
|
|
265
|
-
redirect(302, redirectUrl);
|
|
266
|
-
}
|
|
267
|
-
// for each info.name, we check if it exists take the first option
|
|
268
|
-
// and add the providerUserId to the name if no option available
|
|
269
|
-
let nameToUse = '';
|
|
270
|
-
for (let i = 0; i < info.nameOptions.length; i++) {
|
|
271
|
-
const existingUser = await remult
|
|
272
|
-
.repo(oSafe.User)
|
|
273
|
-
.findOne({ where: { identifier: info.nameOptions[i] } });
|
|
274
|
-
if (existingUser) {
|
|
275
|
-
// Don't do anything
|
|
276
|
-
}
|
|
277
|
-
else {
|
|
278
|
-
nameToUse = info.nameOptions[i];
|
|
279
|
-
break;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
if (nameToUse === '') {
|
|
283
|
-
nameToUse = `${info.nameOptions[0]}-${info.providerUserId}`;
|
|
284
|
-
}
|
|
285
|
-
const user = remult.repo(oSafe.User).create();
|
|
286
|
-
user.identifier = nameToUse;
|
|
287
|
-
account = remult.repo(oSafe.Account).create();
|
|
288
|
-
account.provider = keyState;
|
|
289
|
-
account.providerUserId = info.providerUserId;
|
|
290
|
-
account.token = tokens.accessToken;
|
|
291
|
-
account.userId = user.id;
|
|
292
|
-
account.lastVerifiedAt = new Date();
|
|
293
|
-
await remult.repo(oSafe.User).save(user);
|
|
294
|
-
await remult.repo(oSafe.Account).save(account);
|
|
295
|
-
}
|
|
296
|
-
else {
|
|
297
|
-
account.token = tokens.accessToken;
|
|
298
|
-
await remult.repo(oSafe.Account).save(account);
|
|
299
|
-
}
|
|
300
|
-
await createOrExtendSession(account.userId);
|
|
301
|
-
event.cookies.delete(`${keyState}_oauth_state`, { path: '/' });
|
|
302
|
-
event.cookies.delete(`code_verifier`, { path: '/' });
|
|
303
|
-
}
|
|
304
|
-
redirect(302, redirectUrl);
|
|
305
|
-
}
|
|
306
|
-
return { early: false };
|
|
307
|
-
},
|
|
308
|
-
initApi: async () => {
|
|
309
|
-
await initRoleFromEnv(logAuth, oSafe.User, 'FF_ROLE_ADMIN', FF_Role.Admin);
|
|
310
|
-
await initRoleFromEnv(logAuth, oSafe.User, 'FF_ROLE_AUTH_ADMIN', FF_Role_Auth.Admin);
|
|
311
|
-
},
|
|
312
|
-
};
|
|
313
|
-
};
|
|
314
|
-
export { initRoleFromEnv };
|
|
315
|
-
// Maybe moving this to /auth/server.ts would be better, people will be able to import from firstly all the time
|
|
316
|
-
export let lucia;
|
|
1
|
+
import { AuthController } from './AuthController';
|
|
2
|
+
import { FFAuthAccount, FFAuthProvider, FFAuthUser, FFAuthUserSession } from './Entities';
|
|
3
|
+
export { FF_Role_Auth } from './Entities';
|
|
4
|
+
export { AuthController };
|
|
5
|
+
export { FFAuthUser, FFAuthAccount, FFAuthProvider, FFAuthUserSession };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ProviderConfigured } from './module.js';
|
|
2
2
|
export declare class AuthControllerServer {
|
|
3
3
|
/**
|
|
4
4
|
* Sign out the current user
|
|
@@ -12,31 +12,31 @@ export declare class AuthControllerServer {
|
|
|
12
12
|
/**
|
|
13
13
|
* This is for login / password authentication invite
|
|
14
14
|
*/
|
|
15
|
-
static invite(
|
|
15
|
+
static invite(emailParam: string): Promise<"Mail sent !" | "Demo Mail sent !" | "ok">;
|
|
16
16
|
/**
|
|
17
17
|
* This is for login / password authentication SignUp
|
|
18
18
|
* _(The first param `email` can be "anything")_
|
|
19
19
|
*/
|
|
20
|
-
static signUpPassword(
|
|
20
|
+
static signUpPassword(emailParam: string, password: string): Promise<string>;
|
|
21
21
|
/**
|
|
22
22
|
* This is for login / password authentication SignIn
|
|
23
23
|
* _(The first param `email` can be "anything")_
|
|
24
24
|
*/
|
|
25
|
-
static signInPassword(
|
|
25
|
+
static signInPassword(emailParam: string, password: string): Promise<string>;
|
|
26
26
|
/**
|
|
27
27
|
* Forgot your password ? Send a mail to reset it.
|
|
28
28
|
*/
|
|
29
|
-
static forgotPassword(
|
|
29
|
+
static forgotPassword(emailParam: string): Promise<"Mail sent !" | "Demo Mail sent !">;
|
|
30
30
|
/**
|
|
31
31
|
* Reset your password with a token
|
|
32
32
|
*/
|
|
33
33
|
static resetPassword(token: string, password: string): Promise<string>;
|
|
34
34
|
/** OTP */
|
|
35
|
-
static signInOTP(
|
|
35
|
+
static signInOTP(emailParam: string): Promise<"Mail sent !" | "Hum, something went wrong !">;
|
|
36
36
|
/**
|
|
37
37
|
* Verify the OTP code
|
|
38
38
|
*/
|
|
39
|
-
static verifyOtp(
|
|
39
|
+
static verifyOtp(emailParam: string, otp: string): Promise<string>;
|
|
40
40
|
/** OAUTH */
|
|
41
41
|
/**
|
|
42
42
|
* The the url to redirect to for the OAuth provider
|
|
@@ -50,9 +50,9 @@ export declare class AuthControllerServer {
|
|
|
50
50
|
*
|
|
51
51
|
* _(popup example should work too, and a nice example/componant would be appreciated)_
|
|
52
52
|
*/
|
|
53
|
-
static signInOAuthGetUrl<T extends keyof
|
|
53
|
+
static signInOAuthGetUrl<T extends keyof ProviderConfigured>(o: {
|
|
54
54
|
provider: T;
|
|
55
|
-
options?:
|
|
55
|
+
options?: ProviderConfigured[T];
|
|
56
56
|
redirect?: string;
|
|
57
|
-
}): Promise<
|
|
57
|
+
}): Promise<any>;
|
|
58
58
|
}
|