@functionalcms/svelte-components 5.15.1 → 5.16.1
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/dist/index-server.d.ts
CHANGED
|
@@ -10,3 +10,4 @@ export type { RedirectResponse } from './server-side/auth/RedirectResponse.js';
|
|
|
10
10
|
export { isHuman } from './components/form/AntiBot.js';
|
|
11
11
|
export { paraglideHandler } from './server-side/handlers/paraglideHandler.js';
|
|
12
12
|
export { redirectPipelineHandler } from './server-side/handlers/redirectPipelineHandler.js';
|
|
13
|
+
export { saveCookie, loadCookie } from './server-side/cookies.js';
|
package/dist/index-server.js
CHANGED
|
@@ -9,3 +9,4 @@ export { getCommunicationService, getDataService, getTemplateService, getWebsite
|
|
|
9
9
|
export { isHuman } from './components/form/AntiBot.js';
|
|
10
10
|
export { paraglideHandler } from './server-side/handlers/paraglideHandler.js';
|
|
11
11
|
export { redirectPipelineHandler } from './server-side/handlers/redirectPipelineHandler.js';
|
|
12
|
+
export { saveCookie, loadCookie } from './server-side/cookies.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@functionalcms/svelte-components",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.16.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"watch": {
|
|
6
6
|
"build": {
|
|
@@ -14,9 +14,11 @@
|
|
|
14
14
|
"scripts": {
|
|
15
15
|
"dev": "vite dev",
|
|
16
16
|
"build-css": "node -e \"const fs = require('node:fs'); fs.mkdirSync('./css', { recursive: true }); fs.copyFileSync('./src/css/functional.css', './css/functional.css');\"",
|
|
17
|
+
"build-modules": "node -e \"require('node:fs').cpSync('./src/pages', './dist/pages', { recursive: true })\"",
|
|
17
18
|
"build": "vite build && npm run package",
|
|
18
19
|
"preview": "vite preview",
|
|
19
20
|
"package": "npm run build-css && svelte-kit sync && svelte-package && publint",
|
|
21
|
+
"prepack": "npm run package",
|
|
20
22
|
"prepublishOnly": "npm run package",
|
|
21
23
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
22
24
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
@@ -37,6 +39,7 @@
|
|
|
37
39
|
"files": [
|
|
38
40
|
"dist",
|
|
39
41
|
"css",
|
|
42
|
+
"src/pages",
|
|
40
43
|
"!dist/**/*.test.*",
|
|
41
44
|
"!dist/**/*.spec.*"
|
|
42
45
|
],
|
|
@@ -46,6 +49,7 @@
|
|
|
46
49
|
"@sveltejs/kit": "^2.69.2",
|
|
47
50
|
"@sveltejs/package": "^2.5.8",
|
|
48
51
|
"@sveltejs/vite-plugin-svelte": "^7.2.0",
|
|
52
|
+
"cpy-cli": "^7.0.0",
|
|
49
53
|
"publint": "^0.3.21",
|
|
50
54
|
"svelte": "^5.56.4",
|
|
51
55
|
"svelte-check": "^4.7.2",
|
|
@@ -72,4 +76,4 @@
|
|
|
72
76
|
"main": "./dist/index.js",
|
|
73
77
|
"svelte": "./dist/index.js",
|
|
74
78
|
"types": "./dist/index.d.ts"
|
|
75
|
-
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { CACHE_TOKEN, CACHE_URL, CLIENT_ID, SERVER_URL, CACHE_SECRET } from '$env/static/private';
|
|
2
|
+
import { type RequestHandler } from '@sveltejs/kit';
|
|
3
|
+
import { Redis } from '@upstash/redis';
|
|
4
|
+
import * as o from "oauth4webapi";
|
|
5
|
+
import { saveCookie } from '@functionalcms/svelte-components/index-server.js';
|
|
6
|
+
import { loadCookie } from '../../../lib/index-server';
|
|
7
|
+
|
|
8
|
+
const pkceCookieName = "functionalcms_pkce";
|
|
9
|
+
const stateCookieName = "functionalcms_state";
|
|
10
|
+
const sessionCookieName = "functionalcms_sessionId";
|
|
11
|
+
|
|
12
|
+
function parseJwtToken(token: string) {
|
|
13
|
+
const base64 = token.split('.')[1]
|
|
14
|
+
.replace(/-/g, '+')
|
|
15
|
+
.replace(/_/g, '/');
|
|
16
|
+
|
|
17
|
+
const json = decodeURIComponent(
|
|
18
|
+
atob(base64)
|
|
19
|
+
.split('')
|
|
20
|
+
.map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
|
|
21
|
+
.join('')
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return JSON.parse(json);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function handleCallback (state: string, codeVerifier: string, callbackUrl: URL): Promise<any> {
|
|
28
|
+
const discovery = await o.discoveryRequest(new URL(SERVER_URL));
|
|
29
|
+
const metadata = await o.processDiscoveryResponse(new URL(SERVER_URL), discovery);
|
|
30
|
+
const client: o.Client = {
|
|
31
|
+
client_id: CLIENT_ID,
|
|
32
|
+
token_endpoint_auth_method: "none"
|
|
33
|
+
};
|
|
34
|
+
const callbackParameters
|
|
35
|
+
= o.validateAuthResponse(
|
|
36
|
+
metadata,
|
|
37
|
+
client,
|
|
38
|
+
callbackUrl,
|
|
39
|
+
state);
|
|
40
|
+
|
|
41
|
+
// Exchange code for tokens
|
|
42
|
+
const tokenResponse
|
|
43
|
+
= await o.authorizationCodeGrantRequest(
|
|
44
|
+
metadata,
|
|
45
|
+
client,
|
|
46
|
+
o.None(),
|
|
47
|
+
callbackParameters,
|
|
48
|
+
callbackUrl.toString(),
|
|
49
|
+
codeVerifier,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
// Parse tokens
|
|
53
|
+
const tokens
|
|
54
|
+
= await o.processAuthorizationCodeResponse(
|
|
55
|
+
metadata,
|
|
56
|
+
client,
|
|
57
|
+
tokenResponse
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
access_token: tokens.access_token,
|
|
62
|
+
id_token: tokens.id_token,
|
|
63
|
+
refresh_token: tokens.refresh_token,
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
/** @type {import('./$types').RequestHandler} */
|
|
69
|
+
export const GET: RequestHandler = async ({ url, cookies }) => {
|
|
70
|
+
const expectedState = await loadCookie(cookies, CACHE_SECRET, stateCookieName);
|
|
71
|
+
const codeVerifier = await loadCookie(cookies, CACHE_SECRET, pkceCookieName);
|
|
72
|
+
|
|
73
|
+
const response = await handleCallback(expectedState ?? '', codeVerifier ?? '', new URL(url));
|
|
74
|
+
|
|
75
|
+
const headers = new Headers();
|
|
76
|
+
headers.set('Location', url.origin);
|
|
77
|
+
const sessionId = crypto.randomUUID();
|
|
78
|
+
const accessToken = parseJwtToken(response.access_token);
|
|
79
|
+
|
|
80
|
+
await saveCookie(headers, CACHE_SECRET, sessionCookieName, sessionId);
|
|
81
|
+
|
|
82
|
+
const redis = new Redis({ url: CACHE_URL, token: CACHE_TOKEN });
|
|
83
|
+
const result = await redis.set(sessionId, JSON.stringify(response.access_token), { ex: accessToken.exp - Math.floor(Date.now() / 1000) });
|
|
84
|
+
|
|
85
|
+
cookies.delete(pkceCookieName, { path: "/" });
|
|
86
|
+
cookies.delete(stateCookieName, { path: "/" });
|
|
87
|
+
|
|
88
|
+
return new Response(null, { status: 302, headers });
|
|
89
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { CLIENT_ID, SERVER_URL, CACHE_SECRET } from '$env/static/private';
|
|
2
|
+
import { type RequestHandler } from '@sveltejs/kit';
|
|
3
|
+
import * as o from "oauth4webapi";
|
|
4
|
+
import { saveCookie } from '@functionalcms/svelte-components/index-server.js';
|
|
5
|
+
|
|
6
|
+
const pkceCookieName = "functionalcms_pkce";
|
|
7
|
+
const stateCookieName = "functionalcms_state";
|
|
8
|
+
|
|
9
|
+
function generateRandomState() {
|
|
10
|
+
const array = new Uint8Array(16);
|
|
11
|
+
crypto.getRandomValues(array);
|
|
12
|
+
return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function createLoginHeader(serverUrl: string, clientId: string, callbackUrl: URL) {
|
|
16
|
+
const code_verifier = o.generateRandomCodeVerifier();
|
|
17
|
+
const code_challenge = await o.calculatePKCECodeChallenge(code_verifier);
|
|
18
|
+
const state = generateRandomState();
|
|
19
|
+
|
|
20
|
+
const authUrl = new URL(serverUrl + '/login/oauth/authorize');
|
|
21
|
+
authUrl.searchParams.set('client_id', clientId);
|
|
22
|
+
authUrl.searchParams.set('redirect_uri', callbackUrl.toString());
|
|
23
|
+
authUrl.searchParams.set('response_type', 'code');
|
|
24
|
+
authUrl.searchParams.set('state', state);
|
|
25
|
+
authUrl.searchParams.set('code_challenge', code_challenge);
|
|
26
|
+
authUrl.searchParams.set('code_challenge_method', 'S256');
|
|
27
|
+
authUrl.searchParams.set('scope', 'openid profile email user.extended properties');
|
|
28
|
+
|
|
29
|
+
return { state, codeVerifier: code_verifier, authorisationUrl: authUrl.toString() };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** @type {import('./$types').RequestHandler} */
|
|
33
|
+
export const GET: RequestHandler = async ({ params, locals, url }) => {
|
|
34
|
+
const callbackUrl = new URL(`${url.origin}/auth/callback`);
|
|
35
|
+
const response = await createLoginHeader(SERVER_URL, CLIENT_ID, callbackUrl);
|
|
36
|
+
|
|
37
|
+
const headers = new Headers();
|
|
38
|
+
headers.set('Location', response.authorisationUrl);
|
|
39
|
+
|
|
40
|
+
await saveCookie(headers, CACHE_SECRET, pkceCookieName, response.codeVerifier);
|
|
41
|
+
await saveCookie(headers, CACHE_SECRET, stateCookieName, response.state);
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
return new Response(null, { status: 302, headers });
|
|
45
|
+
}
|