@functionalcms/svelte-components 2.26.1 → 2.28.0

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.
@@ -1,12 +1,13 @@
1
1
  import {} from '@sveltejs/kit';
2
2
  const authSessionCookieName = `auth_session`;
3
- const logout = async (cookies, sessionProvider, afterLogoutPath = '/') => {
3
+ const logout = async (cookies, token, provider, sessionProvider, afterLogoutPath = '/') => {
4
4
  const headers = new Headers();
5
5
  const state = cookies.get(authSessionCookieName);
6
6
  if (state) {
7
7
  cookies.delete('auth_session', { path: '/' });
8
8
  const sid = cookies.get('auth_session');
9
9
  await sessionProvider.deleteSession(sid);
10
+ await provider.logout(token);
10
11
  headers.append('Set-Cookie', `${authSessionCookieName}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT;`);
11
12
  headers.append('Location', afterLogoutPath);
12
13
  }
@@ -53,7 +54,7 @@ export const authenticationHandle = (provider, sessionProvider) => {
53
54
  //logout
54
55
  if (event.url.pathname === '/auth/logout') {
55
56
  // await provider.logout();
56
- const headers = await logout(event.cookies, sessionProvider);
57
+ const headers = await logout(event.cookies, event.locals.token, provider, sessionProvider);
57
58
  return new Response('Logging Out...', { status: 303, headers });
58
59
  }
59
60
  // login
@@ -3,5 +3,6 @@ export declare const machineAuthenticationProvider: (scope?: string, redirectPat
3
3
  getAuthIdentity: (domain: string) => Promise<any>;
4
4
  getValidation: (event: any) => Promise<Token>;
5
5
  getUser: (token: Token) => Promise<any>;
6
+ logout: (token: Token) => Promise<void>;
6
7
  redirectPath: string;
7
8
  };
@@ -63,6 +63,23 @@ const getUser = async (issuer, token) => {
63
63
  });
64
64
  }
65
65
  };
66
+ const logout = async (issuer, clientId, token) => {
67
+ const response = await fetch(`${issuer}/protocol/openid-connect/logout`, {
68
+ method: "POST",
69
+ body: new URLSearchParams({
70
+ client_id: clientId,
71
+ access_token: token.access_token,
72
+ }),
73
+ headers: {
74
+ "Content-Type": "application/x-www-form-urlencoded",
75
+ Accept: "application/json"
76
+ }
77
+ });
78
+ if (!response.ok) {
79
+ console.log('Response was NOT okay');
80
+ throw new Error('Token not validated.');
81
+ }
82
+ };
66
83
  export const machineAuthenticationProvider = (scope = '', redirectPath = '/') => {
67
84
  const extendedScope = `openid profile offline_access ${scope}`;
68
85
  const redirectUrl = "/auth/validate";
@@ -80,6 +97,9 @@ export const machineAuthenticationProvider = (scope = '', redirectPath = '/') =>
80
97
  const user = await getUser(AUTH_KEYCLOAK_ISSUER, token);
81
98
  return user;
82
99
  },
100
+ logout: async (token) => {
101
+ await logout(AUTH_KEYCLOAK_ISSUER, AUTH_KEYCLOAK_ID, token);
102
+ },
83
103
  redirectPath
84
104
  };
85
105
  };
@@ -0,0 +1,14 @@
1
+ import type { ISession, Sid } from './types.js';
2
+ declare function clean(): Promise<void>;
3
+ declare function createSession(session: ISession, maxAge: number): Promise<string>;
4
+ declare function updateSession(sid: string, session: ISession, maxAge: number): Promise<void>;
5
+ declare function getSession(sid: Sid): Promise<any>;
6
+ declare function deleteSession(sid: string): Promise<void>;
7
+ export declare const redisSessionProvider: {
8
+ clean: typeof clean;
9
+ createSession: typeof createSession;
10
+ getSession: typeof getSession;
11
+ deleteSession: typeof deleteSession;
12
+ updateSession: typeof updateSession;
13
+ };
14
+ export {};
@@ -0,0 +1,45 @@
1
+ import { getSid } from './sessionIdGenerator.js';
2
+ import Redis from "ioredis";
3
+ import { CACHE_SECRET } from '$env/static/private';
4
+ const url = "functional.redis.cache.windows.net:6380,password=cfENm4qUceDQ2lE8tl5LFLjg4IVx3F4mIAzCaA12xtg=,ssl=True,abortConnect=False";
5
+ const redis = new Redis(6380, "functional.redis.cache.windows.net", {
6
+ password: CACHE_SECRET,
7
+ tls: true
8
+ });
9
+ async function clean() {
10
+ }
11
+ async function createSession(session, maxAge) {
12
+ const sid = getSid();
13
+ const sessionObject = {
14
+ data: session,
15
+ invalidAt: Date.now() + maxAge + 3600
16
+ };
17
+ await redis.set(sid, JSON.stringify(sessionObject), "EX", maxAge);
18
+ return sid;
19
+ }
20
+ async function updateSession(sid, session, maxAge) {
21
+ await redis.del(sid);
22
+ const sessionObject = {
23
+ data: session,
24
+ invalidAt: Date.now() + maxAge + 3600
25
+ };
26
+ await redis.set(sid, JSON.stringify(sessionObject), "EX", maxAge);
27
+ }
28
+ async function getSession(sid) {
29
+ const savedSession = await redis.get(sid);
30
+ if (savedSession) {
31
+ const session = JSON.parse(savedSession);
32
+ return session.data;
33
+ }
34
+ return null;
35
+ }
36
+ async function deleteSession(sid) {
37
+ await redis.del(sid);
38
+ }
39
+ export const redisSessionProvider = {
40
+ clean: clean,
41
+ createSession: createSession,
42
+ getSession: getSession,
43
+ deleteSession: deleteSession,
44
+ updateSession: updateSession
45
+ };
@@ -0,0 +1,2 @@
1
+ import type { IProvider } from "./types.js";
2
+ export declare const getStandardHandle: (authProvider: IProvider) => import("@sveltejs/kit").Handle;
@@ -0,0 +1,7 @@
1
+ import { sequence } from "@sveltejs/kit/hooks";
2
+ import errorHandler from "./errorHandle.js";
3
+ import { tokenRefreshHandle } from "./tokenRefreshHandle.js";
4
+ import authorizationHandle from "./authorizationHandle.js";
5
+ import { authenticationHandle } from "./authenticationHandle.js";
6
+ import { redisSessionProvider } from "./redisSessionProvider.js";
7
+ export const getStandardHandle = (authProvider) => sequence(errorHandler, authenticationHandle(authProvider, redisSessionProvider), tokenRefreshHandle(redisSessionProvider), authorizationHandle(['/.+']));
@@ -0,0 +1,3 @@
1
+ import { type Handle } from '@sveltejs/kit';
2
+ import type { ISessionStorage } from './types.js';
3
+ export declare const tokenRefreshHandle: (sessionProvider: ISessionStorage) => Handle;
@@ -0,0 +1,48 @@
1
+ import {} from '@sveltejs/kit';
2
+ import { AUTH_KEYCLOAK_ID, AUTH_KEYCLOAK_SECRET, AUTH_KEYCLOAK_ISSUER } from '$env/static/private';
3
+ const authSessionCookieName = `auth_session`;
4
+ function isTokenExpired(token) {
5
+ const base64Url = token.split(".")[1];
6
+ const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
7
+ const jsonPayload = decodeURIComponent(atob(base64)
8
+ .split("")
9
+ .map(function (c) {
10
+ return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
11
+ })
12
+ .join(""));
13
+ const { exp } = JSON.parse(jsonPayload);
14
+ const expired = Date.now() >= exp * 1000;
15
+ return expired;
16
+ }
17
+ async function refreshToken(clientId, clientSecret, refresh_token) {
18
+ const response = await fetch(`${AUTH_KEYCLOAK_ISSUER}/protocol/openid-connect/token`, {
19
+ method: "POST",
20
+ body: new URLSearchParams({
21
+ grant_type: "refresh_token",
22
+ client_id: clientId,
23
+ client_secret: clientSecret,
24
+ refresh_token: refresh_token,
25
+ }),
26
+ headers: {
27
+ "Content-Type": "application/x-www-form-urlencoded",
28
+ Accept: "application/json"
29
+ }
30
+ });
31
+ const newToken = await response.json();
32
+ return newToken;
33
+ }
34
+ export const tokenRefreshHandle = (sessionProvider) => {
35
+ return async ({ event, resolve }) => {
36
+ const locals = event.locals;
37
+ if (locals?.token?.refresh_token) {
38
+ const isExpired = isTokenExpired(locals.token.access_token);
39
+ if (isExpired) {
40
+ const newToken = await refreshToken(AUTH_KEYCLOAK_ID, AUTH_KEYCLOAK_SECRET, locals.token.refresh_token);
41
+ locals.token = newToken;
42
+ const sid = event.cookies.get(authSessionCookieName);
43
+ sessionProvider.updateSession(sid, locals, newToken.expires_in);
44
+ }
45
+ }
46
+ return await resolve(event);
47
+ };
48
+ };
@@ -22,6 +22,7 @@ export interface IProvider {
22
22
  getAuthIdentity(domain: string): Promise<any>;
23
23
  getValidation(event: any): Promise<Token>;
24
24
  getUser(token: Token): any;
25
+ logout(token: Token): Promise<any>;
25
26
  }
26
27
  export interface ISessionStorage {
27
28
  clean(): Promise<void>;
@@ -3,5 +3,6 @@ export declare const userAuthenticationProvider: (scope?: string, redirectPath?:
3
3
  getAuthIdentity: (domain: string) => Promise<any>;
4
4
  getValidation: (event: any) => Promise<Token>;
5
5
  getUser: (token: Token) => Promise<any>;
6
+ logout: (token: Token) => Promise<void>;
6
7
  redirectPath: string;
7
8
  };
@@ -76,6 +76,23 @@ const getUser = async (issuer, token) => {
76
76
  });
77
77
  }
78
78
  };
79
+ const logout = async (issuer, clientId, token) => {
80
+ const response = await fetch(`${issuer}/protocol/openid-connect/logout`, {
81
+ method: "POST",
82
+ body: new URLSearchParams({
83
+ client_id: clientId,
84
+ access_token: token.access_token,
85
+ }),
86
+ headers: {
87
+ "Content-Type": "application/x-www-form-urlencoded",
88
+ Accept: "application/json"
89
+ }
90
+ });
91
+ if (!response.ok) {
92
+ console.log('Response was NOT okay');
93
+ throw new Error('Token not validated.');
94
+ }
95
+ };
79
96
  export const userAuthenticationProvider = (scope = '', redirectPath = '/') => {
80
97
  const extendedScope = `openid profile offline_access ${scope}`;
81
98
  const redirectUrl = "/auth/validate";
@@ -93,6 +110,9 @@ export const userAuthenticationProvider = (scope = '', redirectPath = '/') => {
93
110
  const user = await getUser(AUTH_KEYCLOAK_ISSUER, token);
94
111
  return user;
95
112
  },
113
+ logout: async (token) => {
114
+ await logout(AUTH_KEYCLOAK_ISSUER, AUTH_KEYCLOAK_ID, token);
115
+ },
96
116
  redirectPath
97
117
  };
98
118
  };
@@ -1,6 +1,8 @@
1
1
  export { authenticationHandle } from './auth/authenticationHandle.js';
2
2
  export { default as authorizationHandle } from './auth/authorizationHandle.js';
3
3
  export { default as errorHandler } from './auth/errorHandle.js';
4
+ export { tokenRefreshHandle } from './auth/tokenRefreshHandle.js';
5
+ export { getStandardHandle } from './auth/standardPipeline.js';
4
6
  export { inMemorySessionProvider } from './auth/inMemorySessionProvider.js';
5
7
  export { redisSessionProvider } from './auth/redisSessionProvider.js';
6
8
  export { machineAuthenticationProvider } from './auth/machineAuthenticationProvider.js';
@@ -1,6 +1,8 @@
1
1
  export { authenticationHandle } from './auth/authenticationHandle.js';
2
2
  export { default as authorizationHandle } from './auth/authorizationHandle.js';
3
3
  export { default as errorHandler } from './auth/errorHandle.js';
4
+ export { tokenRefreshHandle } from './auth/tokenRefreshHandle.js';
5
+ export { getStandardHandle } from './auth/standardPipeline.js';
4
6
  export { inMemorySessionProvider } from './auth/inMemorySessionProvider.js';
5
7
  export { redisSessionProvider } from './auth/redisSessionProvider.js';
6
8
  export { machineAuthenticationProvider } from './auth/machineAuthenticationProvider.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@functionalcms/svelte-components",
3
- "version": "2.26.1",
3
+ "version": "2.28.0",
4
4
  "watch": {
5
5
  "build": {
6
6
  "patterns": [