diff --git a/apps/client/index.html b/apps/client/index.html index c46ec4f7f..7053111d3 100644 --- a/apps/client/index.html +++ b/apps/client/index.html @@ -3,14 +3,14 @@ - + - - - - + + + + ontime diff --git a/apps/client/public/manifest.json b/apps/client/public/manifest.json index 3c4b0e1a8..44d458dd5 100644 --- a/apps/client/public/manifest.json +++ b/apps/client/public/manifest.json @@ -11,8 +11,8 @@ "type": "image/png" } ], - "scope": "/", - "start_url": "/", + "scope": "./", + "start_url": "./", "display": "", "theme_color": "#121212", "background_color": "#ffffff" diff --git a/apps/client/public/site.webmanifest b/apps/client/public/site.webmanifest index 5e9522c3d..88ea7c3b1 100644 --- a/apps/client/public/site.webmanifest +++ b/apps/client/public/site.webmanifest @@ -1,7 +1,7 @@ { "name": "", "short_name": "", - "icons": [{ "src": "/ontime-logo.png", "sizes": "295x295", "type": "image/png" }], + "icons": [{ "src": "ontime-logo.png", "sizes": "295x295", "type": "image/png" }], "theme_color": "#2B5ABC", "background_color": "#101010", "display": "standalone" diff --git a/apps/server/src/middleware/__tests__/authenticate.test.ts b/apps/server/src/middleware/__tests__/authenticate.test.ts new file mode 100644 index 000000000..aa1bd897f --- /dev/null +++ b/apps/server/src/middleware/__tests__/authenticate.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from 'vitest'; + +import { isPublicAssetRequest } from '../authenticate.js'; + +describe('isPublicAssetRequest()', () => { + it('allows root public assets without a prefix', () => { + expect(isPublicAssetRequest('/site.webmanifest', '')).toBe(true); + expect(isPublicAssetRequest('/manifest.json', '')).toBe(true); + }); + + it('allows prefixed public assets in cloud deployments', () => { + expect(isPublicAssetRequest('/stage-hash/site.webmanifest', '/stage-hash')).toBe(true); + expect(isPublicAssetRequest('/stage-hash/ontime-logo.png?cache=1', '/stage-hash')).toBe(true); + }); + + it('keeps non-public paths protected', () => { + expect(isPublicAssetRequest('/stage-hash/data', '/stage-hash')).toBe(false); + expect(isPublicAssetRequest('/backstage', '')).toBe(false); + }); +}); diff --git a/apps/server/src/middleware/authenticate.ts b/apps/server/src/middleware/authenticate.ts index ed6da3cc9..74b6f9ddf 100644 --- a/apps/server/src/middleware/authenticate.ts +++ b/apps/server/src/middleware/authenticate.ts @@ -21,6 +21,20 @@ const publicAssets = new Set([ '/site.webmanifest', ]); +export function isPublicAssetRequest(originalUrl: string, prefix: string): boolean { + const pathname = originalUrl.split('?')[0]; + + if (publicAssets.has(pathname)) { + return true; + } + + if (prefix && pathname.startsWith(prefix)) { + return publicAssets.has(pathname.slice(prefix.length) || '/'); + } + + return false; +} + /** * Creates a login router with the provided prefix * @param {string} prefix - Prefix is used for the client hashes in Ontime Cloud @@ -81,7 +95,7 @@ export function makeAuthenticateMiddleware(prefix: string) { function authenticateAndRedirect(req: Request, res: Response, next: NextFunction) { // Allow access to specific public assets without authentication - if (publicAssets.has(req.originalUrl)) { + if (isPublicAssetRequest(req.originalUrl, prefix)) { return next(); }