Bypass auth/session pages in frontend serviceworker cache
This commit is contained in:
@@ -77,6 +77,6 @@
|
||||
- The frontend sharp runtime patch makes icon generation non-fatal on FreeBSD when `sharp` cannot load, preventing startup crashes in asset controller imports.
|
||||
- The files upload route patch fixes browser multi-upload by posting to `/files/upload` (session-authenticated) instead of direct `/media` calls without bearer token.
|
||||
- The files upload locale patch adds missing `files.upload.dropText`/`files.upload.browse`/`files.upload.submitMultiple` labels in endpoint locale files so UI text does not render raw translation keys.
|
||||
- The frontend serviceworker patch ensures `@indiekit/frontend/lib/serviceworker.js` exists at runtime to avoid ENOENT in the offline/service worker route.
|
||||
- The frontend serviceworker patch ensures `@indiekit/frontend/lib/serviceworker.js` exists at runtime, and forces network-only handling for `/auth` and `/session` pages to avoid stale cached login/consent screens.
|
||||
- The conversations guard patch prevents `Cannot read properties of undefined (reading 'find')` when the `conversation_items` collection is temporarily unavailable.
|
||||
- The indieauth dev-mode guard patch prevents accidental production auth bypass by requiring explicit `INDIEKIT_ALLOW_DEV_AUTH=1` to enable dev auto-login.
|
||||
|
||||
@@ -23,6 +23,51 @@ self.addEventListener("activate", (event) => {
|
||||
self.addEventListener("fetch", () => {});
|
||||
`;
|
||||
|
||||
const authBypassMarker = "Never cache auth/session pages";
|
||||
const oldFetchCacheLine = " const retrieveFromCache = caches.match(request);";
|
||||
const newFetchCacheBlock = ` const requestUrl = new URL(request.url);
|
||||
|
||||
// Never cache auth/session pages; always go to network.
|
||||
if (
|
||||
requestUrl.origin === self.location.origin &&
|
||||
/^\\/(auth|session)(?:\\/|$)/.test(requestUrl.pathname)
|
||||
) {
|
||||
event.respondWith(fetch(request));
|
||||
return;
|
||||
}
|
||||
|
||||
const retrieveFromCache = caches.match(request);`;
|
||||
|
||||
const clearAuthSessionEntriesFn = `
|
||||
async function clearAuthSessionEntries() {
|
||||
try {
|
||||
const pagesCache = await caches.open(pagesCacheName);
|
||||
const keys = await pagesCache.keys();
|
||||
|
||||
await Promise.all(
|
||||
keys
|
||||
.filter((request) => {
|
||||
const requestUrl = new URL(request.url);
|
||||
return (
|
||||
requestUrl.origin === self.location.origin &&
|
||||
/^\\/(auth|session)(?:\\/|$)/.test(requestUrl.pathname)
|
||||
);
|
||||
})
|
||||
.map((request) => pagesCache.delete(request)),
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error clearing auth/session cache entries", error);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const activateOld = ` await clearOldCaches();
|
||||
await clients.claim();`;
|
||||
|
||||
const activateNew = ` await clearOldCaches();
|
||||
await clearAuthSessionEntries();
|
||||
await clients.claim();`;
|
||||
|
||||
async function exists(filePath) {
|
||||
try {
|
||||
await access(filePath);
|
||||
@@ -32,26 +77,61 @@ async function exists(filePath) {
|
||||
}
|
||||
}
|
||||
|
||||
if (await exists(expected)) {
|
||||
console.log("[postinstall] frontend serviceworker already present");
|
||||
process.exit(0);
|
||||
function patchServiceworker(content) {
|
||||
let updated = content;
|
||||
|
||||
if (!updated.includes(authBypassMarker) && updated.includes(oldFetchCacheLine)) {
|
||||
updated = updated.replace(oldFetchCacheLine, newFetchCacheBlock);
|
||||
}
|
||||
|
||||
if (
|
||||
!updated.includes("async function clearAuthSessionEntries()") &&
|
||||
updated.includes("async function trimCache(cacheName, maxItems)")
|
||||
) {
|
||||
updated = updated.replace(
|
||||
"async function trimCache(cacheName, maxItems)",
|
||||
`${clearAuthSessionEntriesFn}\nasync function trimCache(cacheName, maxItems)`,
|
||||
);
|
||||
}
|
||||
|
||||
if (updated.includes(activateOld)) {
|
||||
updated = updated.replace(activateOld, activateNew);
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
let sourcePath = null;
|
||||
for (const candidate of candidates) {
|
||||
if (await exists(candidate)) {
|
||||
sourcePath = candidate;
|
||||
break;
|
||||
let restored = false;
|
||||
|
||||
if (!(await exists(expected))) {
|
||||
let sourcePath = null;
|
||||
for (const candidate of candidates) {
|
||||
if (await exists(candidate)) {
|
||||
sourcePath = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
await mkdir(path.dirname(expected), { recursive: true });
|
||||
|
||||
if (sourcePath) {
|
||||
const content = await readFile(sourcePath, "utf8");
|
||||
await writeFile(expected, content, "utf8");
|
||||
restored = true;
|
||||
console.log(`[postinstall] Restored frontend serviceworker from ${sourcePath}`);
|
||||
} else {
|
||||
await writeFile(expected, fallback, "utf8");
|
||||
restored = true;
|
||||
console.log("[postinstall] Created fallback frontend serviceworker");
|
||||
}
|
||||
}
|
||||
|
||||
await mkdir(path.dirname(expected), { recursive: true });
|
||||
const source = await readFile(expected, "utf8");
|
||||
const updated = patchServiceworker(source);
|
||||
|
||||
if (sourcePath) {
|
||||
const content = await readFile(sourcePath, "utf8");
|
||||
await writeFile(expected, content, "utf8");
|
||||
console.log(`[postinstall] Restored frontend serviceworker from ${sourcePath}`);
|
||||
} else {
|
||||
await writeFile(expected, fallback, "utf8");
|
||||
console.log("[postinstall] Created fallback frontend serviceworker");
|
||||
if (updated !== source) {
|
||||
await writeFile(expected, updated, "utf8");
|
||||
console.log("[postinstall] Patched frontend serviceworker auth/session cache bypass");
|
||||
} else if (!restored) {
|
||||
console.log("[postinstall] frontend serviceworker already present");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user