firstly 0.0.11 → 0.0.13
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 +20 -21
- package/esm/api/index.js +74 -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} +133 -171
- package/esm/auth/server/handleAuth.d.ts +2 -0
- package/esm/auth/server/handleAuth.js +140 -0
- package/esm/auth/server/handleGuard.d.ts +16 -0
- package/esm/auth/server/handleGuard.js +67 -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 +7 -0
- package/esm/auth/server/index.js +7 -0
- package/esm/auth/server/module.d.ts +257 -0
- package/esm/auth/server/module.js +197 -0
- package/esm/auth/{providers → server/providers}/github.d.ts +6 -4
- package/esm/auth/{providers → server/providers}/github.js +29 -20
- 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-BUfjaN-D.d.ts +5 -0
- package/esm/auth/static/assets/Page-BUfjaN-D.js +19 -0
- package/esm/auth/static/assets/Page-CJ58H1vl.css +1 -0
- package/esm/auth/static/assets/Page-CaDAqmBS.d.ts +5 -0
- package/esm/auth/static/assets/Page-CaDAqmBS.js +1 -0
- package/esm/auth/static/assets/Page-DhdZddzJ.d.ts +5 -0
- package/esm/auth/static/assets/Page-DhdZddzJ.js +1 -0
- package/esm/auth/static/assets/index-BDy4A_14.css +4 -0
- package/esm/auth/static/assets/index-D-Ztdt2o.d.ts +54 -0
- package/esm/auth/static/assets/index-D-Ztdt2o.js +2 -0
- package/esm/auth/static/index.html +11 -11
- package/esm/auth/types.d.ts +5 -0
- package/esm/bin/cmd.js +122 -54
- package/esm/cellsBuildor.js +7 -7
- 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/common.d.ts +5 -0
- package/esm/common.js +8 -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 +4 -5
- 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 +52 -56
- package/esm/feedback/ui/DialogIssues.svelte +71 -71
- package/esm/feedback/ui/DialogMilestones.svelte +22 -22
- package/esm/helper.js +3 -3
- package/esm/index.d.ts +3 -20
- package/esm/index.js +3 -10
- 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/mail/templates/DefaultMail.svelte +17 -17
- package/esm/storeItem.js +8 -2
- package/esm/storeList.d.ts +1 -1
- package/esm/storeList.js +1 -1
- package/esm/sveltekit/server/index.d.ts +14 -0
- package/esm/sveltekit/server/index.js +24 -0
- package/esm/ui/Button.svelte +33 -33
- package/esm/ui/Button.svelte.d.ts +2 -2
- package/esm/ui/Clipboardable.svelte +11 -8
- package/esm/ui/Clipboardable.svelte.d.ts +4 -4
- package/esm/ui/Field.svelte +142 -149
- package/esm/ui/Field.svelte.d.ts +2 -2
- package/esm/ui/FieldGroup.svelte +38 -38
- package/esm/ui/Grid.svelte +212 -222
- package/esm/ui/GridLoading.svelte +18 -22
- package/esm/ui/GridPaginate.svelte +38 -38
- package/esm/ui/Icon.svelte +50 -49
- package/esm/ui/Icon.svelte.d.ts +18 -18
- package/esm/ui/Loading.svelte +5 -2
- package/esm/ui/Tooltip.svelte +16 -16
- package/esm/ui/dialog/DialogForm.svelte +23 -23
- package/esm/ui/dialog/DialogManagement.svelte +74 -74
- package/esm/ui/dialog/DialogPrimitive.svelte +50 -51
- package/esm/ui/dialog/FormEditAction.svelte +34 -34
- package/esm/ui/dialog/dialog.d.ts +2 -2
- package/esm/ui/dialog/dialog.js +1 -1
- package/esm/ui/internals/FieldContainer.svelte +11 -12
- package/esm/ui/internals/FieldContainer.svelte.d.ts +3 -3
- package/esm/ui/internals/Input.svelte +25 -25
- package/esm/ui/internals/Input.svelte.d.ts +1 -1
- package/esm/ui/internals/Textarea.svelte +21 -21
- package/esm/ui/internals/Textarea.svelte.d.ts +2 -2
- package/esm/ui/internals/select/MultiSelectMelt.svelte +69 -73
- package/esm/ui/internals/select/SelectMelt.svelte +86 -86
- package/esm/ui/internals/select/SelectRadio.svelte +22 -22
- package/esm/ui/link/Link.svelte +14 -14
- package/esm/ui/link/Link.svelte.d.ts +3 -4
- package/esm/ui/link/LinkPlus.svelte +33 -35
- package/esm/vite/index.js +24 -25
- package/package.json +50 -42
- 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-BEFYPjis.d.ts +0 -4
- package/esm/auth/static/assets/Page-BEFYPjis.js +0 -1
- 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/Page-DtgkOCJs.d.ts +0 -4
- package/esm/auth/static/assets/Page-DtgkOCJs.js +0 -1
- package/esm/auth/static/assets/index-CR_3yNaJ.css +0 -4
- 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,16 @@
|
|
|
1
|
+
import { type Handle } from '@sveltejs/kit';
|
|
2
|
+
export type RouteGuardConfig = {
|
|
3
|
+
anonymous?: string[];
|
|
4
|
+
authenticated: string[];
|
|
5
|
+
redirectToLogin: string;
|
|
6
|
+
redirectAuthenticated: string;
|
|
7
|
+
/**
|
|
8
|
+
* We need this import
|
|
9
|
+
*
|
|
10
|
+
* `import { redirect } from '@sveltejs/kit'` */
|
|
11
|
+
redirect: (status: number, url: string) => void;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Creates a handle function with the provided route guard configuration
|
|
15
|
+
*/
|
|
16
|
+
export declare function handleGuard(config: RouteGuardConfig): Handle;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {} from '@sveltejs/kit';
|
|
2
|
+
import { remult } from 'remult';
|
|
3
|
+
/**
|
|
4
|
+
* Checks if a path matches a pattern that may include wildcards
|
|
5
|
+
* @param path The actual path to check
|
|
6
|
+
* @param pattern The pattern that may include wildcards (*)
|
|
7
|
+
*/
|
|
8
|
+
function pathMatchesPattern(path, pattern) {
|
|
9
|
+
// Convert the pattern to a regex
|
|
10
|
+
const regexPattern = pattern.replace(/\//g, '\\/').replace(/\*/g, '.*');
|
|
11
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
12
|
+
return regex.test(path);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Checks if a path matches any of the patterns in the array
|
|
16
|
+
*/
|
|
17
|
+
function pathMatchesAnyPattern(path, patterns) {
|
|
18
|
+
return patterns.some((pattern) => pathMatchesPattern(path, pattern));
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Creates a handle function with the provided route guard configuration
|
|
22
|
+
*/
|
|
23
|
+
export function handleGuard(config) {
|
|
24
|
+
return async ({ event, resolve }) => {
|
|
25
|
+
const path = event.url.pathname;
|
|
26
|
+
const fullUrl = event.url.pathname + event.url.search;
|
|
27
|
+
const isAuthenticated = !!remult.user;
|
|
28
|
+
// Check if the path is in the anonymous routes
|
|
29
|
+
const isAnonymousRoute = config.anonymous ? pathMatchesAnyPattern(path, config.anonymous) : false;
|
|
30
|
+
// Check if the path is in the authenticated routes
|
|
31
|
+
const isAuthenticatedRoute = pathMatchesAnyPattern(path, config.authenticated);
|
|
32
|
+
// Check if the current path is the login page
|
|
33
|
+
const isLoginPage = path === config.redirectToLogin || path === config.redirectToLogin.replace(/\/$/, '');
|
|
34
|
+
// Create login URL with redirect parameter
|
|
35
|
+
const createLoginUrl = (returnUrl) => {
|
|
36
|
+
const encodedReturnUrl = encodeURIComponent(returnUrl);
|
|
37
|
+
const separator = config.redirectToLogin.includes('?') ? '&' : '?';
|
|
38
|
+
return `${config.redirectToLogin}${separator}redirect=${encodedReturnUrl}`;
|
|
39
|
+
};
|
|
40
|
+
// Handle root path
|
|
41
|
+
if (path === config.redirectToLogin) {
|
|
42
|
+
if (isAuthenticated) {
|
|
43
|
+
config.redirect(302, config.redirectAuthenticated);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// Only redirect if we're not already on the login page
|
|
47
|
+
if (!isLoginPage) {
|
|
48
|
+
config.redirect(302, config.redirectToLogin);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// If user is not authenticated and tries to access an authenticated route
|
|
53
|
+
if (!isAuthenticated && isAuthenticatedRoute) {
|
|
54
|
+
// Redirect to login with the current URL as the redirect target
|
|
55
|
+
// Only redirect if we're not already on the login page
|
|
56
|
+
if (!isLoginPage) {
|
|
57
|
+
config.redirect(302, createLoginUrl(fullUrl));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// If user is authenticated and tries to access an anonymous-only route
|
|
61
|
+
// Only check if anonymous routes are defined
|
|
62
|
+
if (config.anonymous && isAuthenticated && isAnonymousRoute) {
|
|
63
|
+
config.redirect(302, config.redirectAuthenticated);
|
|
64
|
+
}
|
|
65
|
+
return resolve(event);
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -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,7 @@
|
|
|
1
|
+
import * as arctic from 'arctic';
|
|
2
|
+
import { handleAuth } from './handleAuth.js';
|
|
3
|
+
import { handleGuard } from './handleGuard.js';
|
|
4
|
+
export { auth, authModuleRaw } from './module';
|
|
5
|
+
export { checkOAuthConfig } from './providers/helperProvider';
|
|
6
|
+
export { github } from './providers/github';
|
|
7
|
+
export { arctic, handleAuth, handleGuard };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as arctic from 'arctic';
|
|
2
|
+
import { handleAuth } from './handleAuth.js';
|
|
3
|
+
import { handleGuard } from './handleGuard.js';
|
|
4
|
+
export { auth, authModuleRaw } from './module';
|
|
5
|
+
export { checkOAuthConfig } from './providers/helperProvider';
|
|
6
|
+
export { github } from './providers/github';
|
|
7
|
+
export { arctic, handleAuth, handleGuard };
|