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
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { redirect } from '@sveltejs/kit';
|
|
2
|
+
import { repo } from 'remult';
|
|
3
|
+
import { read } from '@kitql/internals';
|
|
4
|
+
import { FFAuthProvider } from '../Entities';
|
|
5
|
+
import { ff_createSession } from './helperFirstly';
|
|
6
|
+
import { getSafeOptions } from './module';
|
|
7
|
+
export const handleAuth = async ({ event, resolve }) => {
|
|
8
|
+
const oSafe = getSafeOptions();
|
|
9
|
+
if (event.url.pathname === oSafe.firstlyData.props.ui?.paths?.verify_email) {
|
|
10
|
+
const token = event.url.searchParams.get('token') ?? '';
|
|
11
|
+
if (!oSafe.password.enabled) {
|
|
12
|
+
throw Error('Password is not enabled!');
|
|
13
|
+
}
|
|
14
|
+
const account = await repo(oSafe.Account).findFirst({
|
|
15
|
+
token,
|
|
16
|
+
provider: FFAuthProvider.PASSWORD.id,
|
|
17
|
+
});
|
|
18
|
+
if (!account) {
|
|
19
|
+
throw new Error('Invalid token');
|
|
20
|
+
}
|
|
21
|
+
if (account.expiresAt && account.expiresAt < new Date()) {
|
|
22
|
+
throw new Error('token expired');
|
|
23
|
+
}
|
|
24
|
+
// update elements
|
|
25
|
+
account.token = undefined;
|
|
26
|
+
account.expiresAt = undefined;
|
|
27
|
+
account.lastVerifiedAt = new Date();
|
|
28
|
+
await repo(oSafe.Account).save(account);
|
|
29
|
+
await ff_createSession(account.userId);
|
|
30
|
+
redirect(302, oSafe.redirectUrl);
|
|
31
|
+
}
|
|
32
|
+
if (oSafe.firstlyData.props.ui?.paths?.base &&
|
|
33
|
+
event.url.pathname.startsWith(oSafe.firstlyData.props.ui.paths.base)) {
|
|
34
|
+
const content = read(`${oSafe.uiStaticPath}index.html`);
|
|
35
|
+
return new Response(content + `<script>const firstlyData = ${JSON.stringify(oSafe.firstlyData)}</script>`, {
|
|
36
|
+
headers: { 'content-type': 'text/html' },
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
if (event.url.pathname.startsWith('/api/static')) {
|
|
40
|
+
const content = read(`${oSafe.uiStaticPath}${event.url.pathname.replaceAll('/api/static/', '')}`);
|
|
41
|
+
if (content) {
|
|
42
|
+
const seg = event.url.pathname.split('.');
|
|
43
|
+
const map = {
|
|
44
|
+
js: 'text/javascript',
|
|
45
|
+
css: 'text/css',
|
|
46
|
+
svg: 'image/svg+xml',
|
|
47
|
+
};
|
|
48
|
+
return new Response(content, {
|
|
49
|
+
headers: { 'content-type': map[seg[seg.length - 1]] ?? 'text/plain' },
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (event.url.pathname === '/api/auth_callback') {
|
|
54
|
+
const code = event.url.searchParams.get('code');
|
|
55
|
+
const state = event.url.searchParams.get('state');
|
|
56
|
+
const keys = oSafe.providers?.oAuths?.map((c) => c.name) ?? [];
|
|
57
|
+
let storedState = null;
|
|
58
|
+
let keyState = null;
|
|
59
|
+
for (const key of keys) {
|
|
60
|
+
storedState = event.cookies.get(`${key}_oauth_state`) ?? null;
|
|
61
|
+
if (storedState) {
|
|
62
|
+
keyState = key;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const redirectUrlCookie = event.cookies.get(`remult_redirect`);
|
|
67
|
+
if (redirectUrlCookie) {
|
|
68
|
+
event.cookies.delete(`remult_redirect`, { path: '/' });
|
|
69
|
+
}
|
|
70
|
+
const redirectUrl = redirectUrlCookie ?? oSafe.redirectUrl;
|
|
71
|
+
if (!code || !state || !storedState || state !== storedState || !keyState) {
|
|
72
|
+
redirect(302, redirectUrl);
|
|
73
|
+
}
|
|
74
|
+
const selectedOAuth = oSafe.providers?.oAuths?.find((c) => c.name === keyState);
|
|
75
|
+
if (selectedOAuth && code) {
|
|
76
|
+
const tokens = (await selectedOAuth
|
|
77
|
+
.getArcticProvider()
|
|
78
|
+
.validateAuthorizationCode(code));
|
|
79
|
+
let info;
|
|
80
|
+
try {
|
|
81
|
+
info = await selectedOAuth.getUserInfo(tokens);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
console.error(error);
|
|
85
|
+
redirect(302, redirectUrl);
|
|
86
|
+
}
|
|
87
|
+
if (!info.providerUserId) {
|
|
88
|
+
redirect(302, redirectUrl);
|
|
89
|
+
}
|
|
90
|
+
let account = await repo(oSafe.Account).findFirst({
|
|
91
|
+
provider: keyState,
|
|
92
|
+
providerUserId: info.providerUserId,
|
|
93
|
+
});
|
|
94
|
+
if (!account) {
|
|
95
|
+
if (!oSafe.signUp) {
|
|
96
|
+
console.error("You can't signup by yourself! Contact the administrator.");
|
|
97
|
+
// throw Error("You can't signup by yourself! Contact the administrator.")
|
|
98
|
+
redirect(302, redirectUrl);
|
|
99
|
+
}
|
|
100
|
+
// for each info.name, we check if it exists take the first option
|
|
101
|
+
// and add the providerUserId to the name if no option available
|
|
102
|
+
let nameToUse = '';
|
|
103
|
+
for (let i = 0; i < info.nameOptions.length; i++) {
|
|
104
|
+
const existingUser = await repo(oSafe.User).findOne({
|
|
105
|
+
where: { identifier: info.nameOptions[i] },
|
|
106
|
+
});
|
|
107
|
+
if (existingUser) {
|
|
108
|
+
// Don't do anything
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
nameToUse = info.nameOptions[i];
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (nameToUse === '') {
|
|
116
|
+
nameToUse = `${info.nameOptions[0]}-${info.providerUserId}`;
|
|
117
|
+
}
|
|
118
|
+
const user = repo(oSafe.User).create();
|
|
119
|
+
user.identifier = nameToUse;
|
|
120
|
+
account = repo(oSafe.Account).create();
|
|
121
|
+
account.provider = keyState;
|
|
122
|
+
account.providerUserId = info.providerUserId;
|
|
123
|
+
account.token = tokens.accessToken();
|
|
124
|
+
account.userId = user.id;
|
|
125
|
+
account.lastVerifiedAt = new Date();
|
|
126
|
+
await repo(oSafe.User).save(user);
|
|
127
|
+
await repo(oSafe.Account).save(account);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
account.token = tokens.accessToken();
|
|
131
|
+
await repo(oSafe.Account).save(account);
|
|
132
|
+
}
|
|
133
|
+
await ff_createSession(account.userId);
|
|
134
|
+
event.cookies.delete(`${keyState}_oauth_state`, { path: '/' });
|
|
135
|
+
event.cookies.delete(`code_verifier`, { path: '/' });
|
|
136
|
+
}
|
|
137
|
+
redirect(302, redirectUrl);
|
|
138
|
+
}
|
|
139
|
+
return resolve(event);
|
|
140
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type UserInfo } from 'remult';
|
|
2
|
+
export declare function createSession(token: string, userId: string): Promise<import("..").FFAuthUserSession>;
|
|
3
|
+
export declare function validateSessionToken(token: string): Promise<{
|
|
4
|
+
user: UserInfo | undefined;
|
|
5
|
+
freshSession: {
|
|
6
|
+
sessionToken: string;
|
|
7
|
+
expiresAt: Date;
|
|
8
|
+
} | undefined;
|
|
9
|
+
}>;
|
|
10
|
+
export declare function invalidateSession(sessionId: string): Promise<void>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { repo } from 'remult';
|
|
2
|
+
import { encodeToken } from './helperOslo';
|
|
3
|
+
import { getSafeOptions } from './module';
|
|
4
|
+
export async function createSession(token, userId) {
|
|
5
|
+
const sessionId = encodeToken(token);
|
|
6
|
+
const oSafe = getSafeOptions();
|
|
7
|
+
const session = await repo(oSafe.Session).insert({
|
|
8
|
+
id: sessionId,
|
|
9
|
+
userId,
|
|
10
|
+
expiresAt: new Date(Date.now() + oSafe.session.expiresInMs),
|
|
11
|
+
});
|
|
12
|
+
return session;
|
|
13
|
+
}
|
|
14
|
+
export async function validateSessionToken(token) {
|
|
15
|
+
const sessionId = encodeToken(token);
|
|
16
|
+
const oSafe = getSafeOptions();
|
|
17
|
+
const sessionDb = await repo(oSafe.Session).findId(sessionId);
|
|
18
|
+
if (!sessionDb) {
|
|
19
|
+
return { user: undefined, freshSession: undefined };
|
|
20
|
+
}
|
|
21
|
+
// TODO TRANSFORM
|
|
22
|
+
const session = {
|
|
23
|
+
//
|
|
24
|
+
id: sessionDb.id,
|
|
25
|
+
userId: sessionDb.userId,
|
|
26
|
+
expiresAt: sessionDb.expiresAt,
|
|
27
|
+
};
|
|
28
|
+
// TODO: Why I can't do 1 query ?!
|
|
29
|
+
const userDb = await repo(oSafe.User).findId(sessionDb.userId);
|
|
30
|
+
if (!userDb) {
|
|
31
|
+
await invalidateSession(sessionId);
|
|
32
|
+
return { user: undefined, freshSession: undefined };
|
|
33
|
+
}
|
|
34
|
+
const user = oSafe.transformDbUserToClientUser(sessionDb, userDb);
|
|
35
|
+
const sessionExpired = Date.now() >= session.expiresAt.getTime();
|
|
36
|
+
if (sessionExpired) {
|
|
37
|
+
await repo(oSafe.Session).delete(sessionId);
|
|
38
|
+
return { user: undefined, freshSession: undefined };
|
|
39
|
+
}
|
|
40
|
+
// To not renew non stop... Let's wait 10% of the session expires
|
|
41
|
+
const renewSession = Date.now() >= session.expiresAt.getTime() - oSafe.session.expiresInMs * 0.9;
|
|
42
|
+
if (renewSession) {
|
|
43
|
+
session.expiresAt = new Date(Date.now() + oSafe.session.expiresInMs);
|
|
44
|
+
await repo(oSafe.Session).update(sessionId, { expiresAt: session.expiresAt });
|
|
45
|
+
return { user, freshSession: { sessionToken: token, expiresAt: session.expiresAt } };
|
|
46
|
+
}
|
|
47
|
+
return { user, freshSession: undefined };
|
|
48
|
+
}
|
|
49
|
+
export async function invalidateSession(sessionId) {
|
|
50
|
+
const oSafe = getSafeOptions();
|
|
51
|
+
try {
|
|
52
|
+
// silent error. If the session is already deleted, it will throw an error
|
|
53
|
+
await repo(oSafe.Session).delete(sessionId);
|
|
54
|
+
}
|
|
55
|
+
catch (error) { }
|
|
56
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ff_createSession: (userId: string) => Promise<void>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createSession } from './helperDb';
|
|
2
|
+
import { generateToken } from './helperOslo';
|
|
3
|
+
import { setSessionTokenCookie } from './helperRemultServer';
|
|
4
|
+
export const ff_createSession = async (userId) => {
|
|
5
|
+
const token = generateToken();
|
|
6
|
+
const session = await createSession(token, userId);
|
|
7
|
+
setSessionTokenCookie(token, session.expiresAt);
|
|
8
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function generateId(): string;
|
|
2
|
+
export declare function generateToken(): string;
|
|
3
|
+
export declare function encodeToken(token: string): string;
|
|
4
|
+
export declare function generateAndEncodeToken(): string;
|
|
5
|
+
export declare function createDate(timeSpan_seconds: number, options?: {
|
|
6
|
+
from?: Date;
|
|
7
|
+
}): Date;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { sha256 } from '@oslojs/crypto/sha2';
|
|
2
|
+
import { encodeBase32LowerCase, encodeBase64url, encodeHexLowerCase } from '@oslojs/encoding';
|
|
3
|
+
export function generateId() {
|
|
4
|
+
// ID with 120 bits of entropy, or about the same as UUID v4.
|
|
5
|
+
const bytes = crypto.getRandomValues(new Uint8Array(15));
|
|
6
|
+
const id = encodeBase32LowerCase(bytes);
|
|
7
|
+
return id;
|
|
8
|
+
}
|
|
9
|
+
export function generateToken() {
|
|
10
|
+
const bytes = crypto.getRandomValues(new Uint8Array(18));
|
|
11
|
+
const token = encodeBase64url(bytes);
|
|
12
|
+
return token;
|
|
13
|
+
}
|
|
14
|
+
export function encodeToken(token) {
|
|
15
|
+
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
|
|
16
|
+
return sessionId;
|
|
17
|
+
}
|
|
18
|
+
export function generateAndEncodeToken() {
|
|
19
|
+
return encodeToken(generateToken());
|
|
20
|
+
}
|
|
21
|
+
export function createDate(timeSpan_seconds, options) {
|
|
22
|
+
const from = options?.from ?? new Date();
|
|
23
|
+
return new Date(from.getTime() + timeSpan_seconds * 1000);
|
|
24
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function setSessionTokenCookie(token: string, expiresAt: Date): void;
|
|
2
|
+
export declare function deleteSessionTokenCookie(): void;
|
|
3
|
+
export declare function setCodeVerifierCookie(codeVerifier: string): void;
|
|
4
|
+
export declare function setOAuthStateCookie(provider: string, state: string): void;
|
|
5
|
+
export declare function setRedirectCookie(redirect: string): void;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { DEV } from 'esm-env';
|
|
2
|
+
import { remult } from 'remult';
|
|
3
|
+
import { getSafeOptions } from './module';
|
|
4
|
+
export function setSessionTokenCookie(token, expiresAt) {
|
|
5
|
+
const oSafe = getSafeOptions();
|
|
6
|
+
if (remult.context.setCookie) {
|
|
7
|
+
remult.context.setCookie(oSafe.session.cookieName, token, {
|
|
8
|
+
expires: expiresAt,
|
|
9
|
+
path: '/',
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function deleteSessionTokenCookie() {
|
|
14
|
+
const oSafe = getSafeOptions();
|
|
15
|
+
remult.context.deleteCookie(oSafe.session.cookieName, {
|
|
16
|
+
path: '/',
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
export function setCodeVerifierCookie(codeVerifier) {
|
|
20
|
+
remult.context.setCookie('code_verifier', codeVerifier, {
|
|
21
|
+
secure: !DEV,
|
|
22
|
+
path: '/',
|
|
23
|
+
httpOnly: true,
|
|
24
|
+
maxAge: 60 * 10, // 10 min
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
export function setOAuthStateCookie(provider, state) {
|
|
28
|
+
remult.context.setCookie(`${provider}_oauth_state`, state, {
|
|
29
|
+
path: '/',
|
|
30
|
+
secure: !DEV,
|
|
31
|
+
httpOnly: true,
|
|
32
|
+
maxAge: 60 * 10,
|
|
33
|
+
sameSite: 'lax',
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export function setRedirectCookie(redirect) {
|
|
37
|
+
remult.context.setCookie(`remult_redirect`, redirect, {
|
|
38
|
+
path: '/',
|
|
39
|
+
secure: !DEV,
|
|
40
|
+
httpOnly: true,
|
|
41
|
+
maxAge: 60 * 10,
|
|
42
|
+
sameSite: 'lax',
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ClassType } from 'remult';
|
|
2
2
|
import { Log } from '@kitql/helpers';
|
|
3
|
-
import { FFAuthUser } from '
|
|
3
|
+
import { FFAuthUser } from '../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
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { repo } from 'remult';
|
|
2
2
|
import { cyan, green, Log, yellow } from '@kitql/helpers';
|
|
3
3
|
import { env } from '$env/dynamic/private';
|
|
4
|
-
import { FFAuthUser } from '
|
|
4
|
+
import { FFAuthUser } from '../Entities';
|
|
5
5
|
/**
|
|
6
6
|
* will merge the roles and remove duplicates
|
|
7
7
|
* will return a new array & a status if the array was changed
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import type { OAuth2Tokens } from 'arctic';
|
|
2
|
+
import type { ClassType, UserInfo } from 'remult';
|
|
3
|
+
import { Module } from '../../api';
|
|
4
|
+
import type { RecursivePartial } from '../../utils/types';
|
|
5
|
+
import { FFAuthAccount, FFAuthUser, FFAuthUserSession } from '../Entities';
|
|
6
|
+
import type { firstlyData, firstlyDataAuth } from '../types';
|
|
7
|
+
import { initRoleFromEnv } from './helperRole';
|
|
8
|
+
export type { firstlyData };
|
|
9
|
+
export type ProviderConfigured = Record<string, ProviderAuthorizationURLOptions>;
|
|
10
|
+
export type ProviderAuthorizationURLOptions = string[];
|
|
11
|
+
export type OAuth2UserInfo = {
|
|
12
|
+
raw?: any;
|
|
13
|
+
providerUserId: string;
|
|
14
|
+
/** Will take the first option available */
|
|
15
|
+
nameOptions: string[];
|
|
16
|
+
};
|
|
17
|
+
export type FFOAuth2Provider<T = any, LitName extends string = string> = {
|
|
18
|
+
name: LitName;
|
|
19
|
+
getArcticProvider: () => T;
|
|
20
|
+
authorizationURLOptions: () => ProviderAuthorizationURLOptions;
|
|
21
|
+
getUserInfo(tokens: OAuth2Tokens): Promise<OAuth2UserInfo>;
|
|
22
|
+
};
|
|
23
|
+
type AuthOptions<TUserEntity extends FFAuthUser = FFAuthUser, TSessionEntity extends FFAuthUserSession = FFAuthUserSession, TAccountEntity extends FFAuthAccount = FFAuthAccount> = {
|
|
24
|
+
customEntities?: {
|
|
25
|
+
User?: ClassType<TUserEntity>;
|
|
26
|
+
Session?: ClassType<TSessionEntity>;
|
|
27
|
+
Account?: ClassType<TAccountEntity>;
|
|
28
|
+
};
|
|
29
|
+
debug?: boolean;
|
|
30
|
+
ui?: false | RecursivePartial<firstlyDataAuth['ui']>;
|
|
31
|
+
/** Usefull to overwrite where the static files are */
|
|
32
|
+
uiStaticPath?: string;
|
|
33
|
+
session?: {
|
|
34
|
+
/** in milliseconds @default 30 days (1000 * 60 * 60 * 24 * 30) */
|
|
35
|
+
expiresIn?: number;
|
|
36
|
+
COOKIE_NAME?: string;
|
|
37
|
+
};
|
|
38
|
+
defaultRedirect?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Can a user sign up by itself? Or we can join only by invitation ?
|
|
41
|
+
* If false, no one can sign up alone.
|
|
42
|
+
* @default true
|
|
43
|
+
**/
|
|
44
|
+
signUp?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* To be able to sign in user needs to be verified or not?
|
|
47
|
+
* ```
|
|
48
|
+
* `Auto` => noting will be checked
|
|
49
|
+
* `Email` => users needs to click a link in an email
|
|
50
|
+
* `Manual` => an admin needs to verify the user and set verifiedAt in the database
|
|
51
|
+
* ```
|
|
52
|
+
* @default auto
|
|
53
|
+
**/
|
|
54
|
+
verifiedMethod?: 'auto' | 'email' | 'manual';
|
|
55
|
+
invitationSend?: (args: {
|
|
56
|
+
email: string;
|
|
57
|
+
url: string;
|
|
58
|
+
}) => Promise<void>;
|
|
59
|
+
transformDbUserToClientUser?: (session: TSessionEntity, user: TUserEntity) => UserInfo;
|
|
60
|
+
providers?: {
|
|
61
|
+
demo?: {
|
|
62
|
+
name: string;
|
|
63
|
+
roles?: string[];
|
|
64
|
+
}[];
|
|
65
|
+
password?: {
|
|
66
|
+
/**
|
|
67
|
+
* Reseting the password
|
|
68
|
+
*/
|
|
69
|
+
resetPasswordSend?: (args: {
|
|
70
|
+
email: string;
|
|
71
|
+
url: string;
|
|
72
|
+
}) => Promise<void>;
|
|
73
|
+
/** in secondes @default 5 minutes */
|
|
74
|
+
resetPasswordExpiresIn?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Verify the Mail
|
|
77
|
+
*/
|
|
78
|
+
verifyMailSend?: (args: {
|
|
79
|
+
email: string;
|
|
80
|
+
url: string;
|
|
81
|
+
}) => Promise<void>;
|
|
82
|
+
/** in secondes @default 5 minutes */
|
|
83
|
+
verifyMailExpiresIn?: number;
|
|
84
|
+
settings?: {
|
|
85
|
+
bcrypt?: {
|
|
86
|
+
/**
|
|
87
|
+
* Validate the password or throw an error.
|
|
88
|
+
*
|
|
89
|
+
* Here is an example (and it's the default implementation):
|
|
90
|
+
* ```
|
|
91
|
+
* function validatePassword(password: string) {
|
|
92
|
+
* if (typeof password !== 'string' || password.length < 6 || password.length > 255) {
|
|
93
|
+
* throw new EntityError({ message: 'Invalid password' })
|
|
94
|
+
* }
|
|
95
|
+
* }
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
validatePassword?: (password: string) => void;
|
|
99
|
+
/**
|
|
100
|
+
* If you want to NOT use the default bcrypt, you can pass your own thing!
|
|
101
|
+
*/
|
|
102
|
+
passwordHash?: (password: string) => string;
|
|
103
|
+
/**
|
|
104
|
+
* The number of rounds to use for the bcrypt hash.
|
|
105
|
+
* @default 10
|
|
106
|
+
*/
|
|
107
|
+
saltRounds?: number;
|
|
108
|
+
/**
|
|
109
|
+
* If you want to NOT use the default bcrypt, you can pass your own thing!
|
|
110
|
+
*/
|
|
111
|
+
passwordVerify?: (password: string, hash: string) => boolean;
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
otp?: {
|
|
116
|
+
issuer?: string;
|
|
117
|
+
/** in secondes @default 30 seconds */
|
|
118
|
+
expiresIn?: number;
|
|
119
|
+
/** Number of digits @default 6 */
|
|
120
|
+
digits?: number;
|
|
121
|
+
send?: (data: {
|
|
122
|
+
name: string;
|
|
123
|
+
otp: string;
|
|
124
|
+
uri: string;
|
|
125
|
+
}) => Promise<void>;
|
|
126
|
+
};
|
|
127
|
+
oAuths?: FFOAuth2Provider[];
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
export declare let AUTH_OPTIONS: AuthOptions;
|
|
131
|
+
export declare const getSafeOptions: <TUserEntity extends FFAuthUser = FFAuthUser, TSessionEntity extends FFAuthUserSession = FFAuthUserSession, TAccountEntity extends FFAuthAccount = FFAuthAccount>() => {
|
|
132
|
+
User: ClassType<TUserEntity>;
|
|
133
|
+
Session: ClassType<TSessionEntity>;
|
|
134
|
+
Account: ClassType<TAccountEntity>;
|
|
135
|
+
signUp: boolean;
|
|
136
|
+
password: {
|
|
137
|
+
enabled: boolean;
|
|
138
|
+
validatePassword: (password: string) => void;
|
|
139
|
+
passwordHash: (password: string) => string;
|
|
140
|
+
passwordVerify: (password: string, hash: string) => boolean;
|
|
141
|
+
};
|
|
142
|
+
otp: {
|
|
143
|
+
enabled: boolean;
|
|
144
|
+
};
|
|
145
|
+
verifiedMethod: "email" | "auto" | "manual";
|
|
146
|
+
redirectUrl: string;
|
|
147
|
+
firstlyData: firstlyData;
|
|
148
|
+
transformDbUserToClientUser: (session: TSessionEntity, user: TUserEntity) => UserInfo;
|
|
149
|
+
uiStaticPath: string;
|
|
150
|
+
session: {
|
|
151
|
+
expiresInMs: number;
|
|
152
|
+
cookieName: string;
|
|
153
|
+
};
|
|
154
|
+
providers: {
|
|
155
|
+
demo?: {
|
|
156
|
+
name: string;
|
|
157
|
+
roles?: string[];
|
|
158
|
+
}[];
|
|
159
|
+
password?: {
|
|
160
|
+
/**
|
|
161
|
+
* Reseting the password
|
|
162
|
+
*/
|
|
163
|
+
resetPasswordSend?: (args: {
|
|
164
|
+
email: string;
|
|
165
|
+
url: string;
|
|
166
|
+
}) => Promise<void>;
|
|
167
|
+
/** in secondes @default 5 minutes */
|
|
168
|
+
resetPasswordExpiresIn?: number;
|
|
169
|
+
/**
|
|
170
|
+
* Verify the Mail
|
|
171
|
+
*/
|
|
172
|
+
verifyMailSend?: (args: {
|
|
173
|
+
email: string;
|
|
174
|
+
url: string;
|
|
175
|
+
}) => Promise<void>;
|
|
176
|
+
/** in secondes @default 5 minutes */
|
|
177
|
+
verifyMailExpiresIn?: number;
|
|
178
|
+
settings?: {
|
|
179
|
+
bcrypt?: {
|
|
180
|
+
/**
|
|
181
|
+
* Validate the password or throw an error.
|
|
182
|
+
*
|
|
183
|
+
* Here is an example (and it's the default implementation):
|
|
184
|
+
* ```
|
|
185
|
+
* function validatePassword(password: string) {
|
|
186
|
+
* if (typeof password !== 'string' || password.length < 6 || password.length > 255) {
|
|
187
|
+
* throw new EntityError({ message: 'Invalid password' })
|
|
188
|
+
* }
|
|
189
|
+
* }
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
validatePassword?: (password: string) => void;
|
|
193
|
+
/**
|
|
194
|
+
* If you want to NOT use the default bcrypt, you can pass your own thing!
|
|
195
|
+
*/
|
|
196
|
+
passwordHash?: (password: string) => string;
|
|
197
|
+
/**
|
|
198
|
+
* The number of rounds to use for the bcrypt hash.
|
|
199
|
+
* @default 10
|
|
200
|
+
*/
|
|
201
|
+
saltRounds?: number;
|
|
202
|
+
/**
|
|
203
|
+
* If you want to NOT use the default bcrypt, you can pass your own thing!
|
|
204
|
+
*/
|
|
205
|
+
passwordVerify?: (password: string, hash: string) => boolean;
|
|
206
|
+
};
|
|
207
|
+
};
|
|
208
|
+
};
|
|
209
|
+
otp?: {
|
|
210
|
+
issuer?: string;
|
|
211
|
+
/** in secondes @default 30 seconds */
|
|
212
|
+
expiresIn?: number;
|
|
213
|
+
/** Number of digits @default 6 */
|
|
214
|
+
digits?: number;
|
|
215
|
+
send?: (data: {
|
|
216
|
+
name: string;
|
|
217
|
+
otp: string;
|
|
218
|
+
uri: string;
|
|
219
|
+
}) => Promise<void>;
|
|
220
|
+
};
|
|
221
|
+
oAuths?: FFOAuth2Provider[];
|
|
222
|
+
} | undefined;
|
|
223
|
+
};
|
|
224
|
+
export declare const authModuleRaw: Module;
|
|
225
|
+
/**
|
|
226
|
+
* To enable authentication in your app in a few lines of code.
|
|
227
|
+
* _Info: index: -777_
|
|
228
|
+
*/
|
|
229
|
+
export declare const auth: <TUserEntity extends FFAuthUser = FFAuthUser, TSessionEntity extends FFAuthUserSession = FFAuthUserSession, TAccountEntity extends FFAuthAccount = FFAuthAccount>(o: AuthOptions<TUserEntity, TSessionEntity, TAccountEntity>) => Module;
|
|
230
|
+
export { initRoleFromEnv };
|
|
231
|
+
declare module 'remult' {
|
|
232
|
+
interface UserInfo {
|
|
233
|
+
session: {
|
|
234
|
+
id: string;
|
|
235
|
+
expiresAt: Date;
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|