11import { env } from '$env/dynamic/private' ;
2- import { error } from '@sveltejs/kit ' ;
2+ import { getCurrentUser } from '$lib/server/api/v1/auth_api ' ;
33import { getLogger } from '$lib/server/logger.js' ;
4+ import { error , redirect } from '@sveltejs/kit' ;
45
56const logger = getLogger ( 'hooks' ) ;
67
8+ if ( env . FRACTAL_SERVER_HOST . endsWith ( '/' ) ) {
9+ env . FRACTAL_SERVER_HOST = env . FRACTAL_SERVER_HOST . substring (
10+ 0 ,
11+ env . FRACTAL_SERVER_HOST . length - 1
12+ ) ;
13+ logger . trace (
14+ 'Removing final slash from FRACTAL_SERVER_HOST, new value is %s' ,
15+ env . FRACTAL_SERVER_HOST
16+ ) ;
17+ }
18+
719export async function handle ( { event, resolve } ) {
20+ if ( event . url . pathname . startsWith ( '/_app' ) ) {
21+ // The _app folder contains static files that are the result of npm build.
22+ // The hooks handle function is not called when loading valid static files, however we can
23+ // reach this point if a not existing file is requested. That could happen after an update
24+ // if the browser is loading a cached page that references to outdated contents.
25+ // In that case we can just skip the whole function.
26+ await resolve ( event ) ;
27+ }
28+
29+ if ( event . url . pathname . startsWith ( '/api' ) ) {
30+ // API page - AJAX request - handled in proxy'
31+ logger . trace ( 'API endpoint detected, leaving the handling to the proxy' ) ;
32+ return await resolve ( event ) ;
33+ }
34+
835 logger . info ( '[%s] - %s' , event . request . method , event . url . pathname ) ;
936
10- if (
37+ // Retrieve server info (alive and version)
38+ const serverInfo = await getServerInfo ( event . fetch ) ;
39+
40+ // Check if auth cookie is present
41+ const fastApiUsersAuth = event . cookies . get ( 'fastapiusersauth' ) ;
42+ if ( ! fastApiUsersAuth ) {
43+ logger . debug ( 'No auth cookie found' ) ;
44+ }
45+
46+ // Retrieve user info
47+ let userInfo = null ;
48+ if ( serverInfo . alive && fastApiUsersAuth ) {
49+ userInfo = await getUserInfo ( event . fetch ) ;
50+ logger . trace ( 'User: %s' , userInfo ?. email ) ;
51+ }
52+
53+ // Store the pageInfo in locals variable to use the in +layout.server.js
54+ event . locals [ 'pageInfo' ] = { serverInfo, userInfo } ;
55+
56+ const isPublicPage =
1157 event . url . pathname == '/' ||
1258 event . url . pathname . startsWith ( '/auth' ) ||
13- event . url . pathname . startsWith ( '/sandbox/jsonschema' )
14- ) {
59+ event . url . pathname . startsWith ( '/sandbox/jsonschema' ) ;
60+
61+ if ( isPublicPage ) {
1562 logger . debug ( 'Public page - No auth required' ) ;
1663 return await resolve ( event ) ;
1764 }
1865
19- if ( event . url . pathname . startsWith ( '/api' ) ) {
20- // API page - AJAX request - handled in proxy'
21- return await resolve ( event ) ;
66+ if ( ! serverInfo . alive && ! isPublicPage ) {
67+ // If fractal-server is not available, redirect to the home page to display the maintenance banner
68+ throw redirect ( 302 , '/?invalidate=true' ) ;
2269 }
2370
2471 // Authentication guard
25- const fastApiUsersAuth = event . cookies . get ( 'fastapiusersauth' ) ;
26- if ( ! fastApiUsersAuth ) {
72+ if ( ! isPublicPage && userInfo === null ) {
2773 logger . debug ( 'Authentication required - No auth cookie found - Redirecting to login' ) ;
28- return new Response ( null , {
29- status : 302 ,
30- headers : { location : '/auth/login?invalidate=true' }
31- } ) ;
32- }
33-
34- const currentUser = await event . fetch ( `${ env . FRACTAL_SERVER_HOST } /auth/current-user/` ) ;
35- if ( ! currentUser . ok ) {
36- logger . debug ( 'Validation of authentication - Error loading user info' ) ;
37- return new Response ( null , {
38- status : 302 ,
39- headers : { location : '/auth/login?invalidate=true' }
40- } ) ;
74+ throw redirect ( 302 , '/auth/login?invalidate=true' ) ;
4175 }
4276
77+ // Admin area check
4378 if ( event . url . pathname . startsWith ( '/v1/admin' ) || event . url . pathname . startsWith ( '/v2/admin' ) ) {
44- const user = await currentUser . json ( ) ;
45- if ( ! user . is_superuser ) {
79+ if ( ! ( /** @type {import('$lib/types').User } */ ( userInfo ) . is_superuser ) ) {
4680 throw error ( 403 , `Only superusers can access the admin area` ) ;
4781 }
4882 }
@@ -57,11 +91,6 @@ export async function handleFetch({ event, request, fetch }) {
5791 1. https://github.com/fractal-analytics-platform/fractal-web/issues/274
5892 2. https://kit.svelte.dev/docs/hooks#server-hooks-handlefetch
5993 */
60-
61- if ( env . FRACTAL_SERVER_HOST . endsWith ( '/' ) ) {
62- env . FRACTAL_SERVER_HOST = env . FRACTAL_SERVER_HOST . substring ( 0 , env . FRACTAL_SERVER_HOST . length - 1 ) ;
63- }
64-
6594 if ( request . url . startsWith ( env . FRACTAL_SERVER_HOST ) ) {
6695 logger . trace ( 'Including cookie into request to %s, via handleFetch' , request . url ) ;
6796 const cookie = event . request . headers . get ( 'cookie' ) ;
@@ -71,3 +100,41 @@ export async function handleFetch({ event, request, fetch }) {
71100 }
72101 return fetch ( request ) ;
73102}
103+
104+ /**
105+ * @param {typeof fetch } fetch
106+ * @returns {Promise<{ alive: boolean, version: string | null }> }
107+ */
108+ async function getServerInfo ( fetch ) {
109+ let serverInfo = { alive : false , version : null } ;
110+
111+ try {
112+ const serverInfoResponse = await fetch ( env . FRACTAL_SERVER_HOST + '/api/alive/' ) ;
113+ if ( serverInfoResponse . ok ) {
114+ serverInfo = await serverInfoResponse . json ( ) ;
115+ logger . debug ( 'Server info loaded: Alive %s - %s' , serverInfo . alive , serverInfo . version ) ;
116+ } else {
117+ logger . error (
118+ 'Alive endpoint replied with unsuccessful status code %d' ,
119+ serverInfoResponse . status
120+ ) ;
121+ }
122+ } catch ( error ) {
123+ logger . fatal ( 'Error loading server info' , error ) ;
124+ }
125+
126+ return serverInfo ;
127+ }
128+
129+ /**
130+ * @param {typeof fetch } fetch
131+ * @returns {Promise<import('$lib/types').User|null> }
132+ */
133+ async function getUserInfo ( fetch ) {
134+ try {
135+ return await getCurrentUser ( fetch ) ;
136+ } catch ( error ) {
137+ logger . error ( 'Error loading user info' , error ) ;
138+ return null ;
139+ }
140+ }
0 commit comments