Version 4.7.0
This commit is contained in:
1 parent
517a5e1f70
commit
8ba7d43898
1933 files changed
+65613
-11332
No files matched your search
@@ -188,26 +188,18 @@ self.addEventListener("notificationclick", (e) => {
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener("message", (e) => {
|
||||
switch (e.data.type) {
|
||||
case "MEMBER_ID":
|
||||
idbKeyval.set("member_id", parseInt(e.data.id)).then(() => log(`Member ID is set to ${e.data.id}`));
|
||||
break;
|
||||
case "LOGGED_IN":
|
||||
idbKeyval.set("logged_in", e.data.value).then(() => log(`Logged in status is set to ${e.data.value}`));
|
||||
break;
|
||||
case "IS_ACP":
|
||||
idbKeyval.set("is_acp", e.data.value).then(() => log(`Is Admin status is set to ${e.data.value}`));
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// ------------------------------------------------
|
||||
// Fetch a resource - use to detect offline state
|
||||
// ------------------------------------------------
|
||||
self.addEventListener("fetch", (e) => {
|
||||
const { request } = e;
|
||||
|
||||
// We test /admin/ first and then a fallback for the deprecated custom admin directory name feature
|
||||
if (request.url.startsWith(BASE_URL + "admin/") || e.currentTarget.location.href.match(/type=admin/)) {
|
||||
log("In ACP, nothing to do...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!request.url.startsWith(BASE_URL) || (request.method === "GET" && request.mode !== "navigate")) {
|
||||
return;
|
||||
}
|
||||
@@ -215,11 +207,7 @@ self.addEventListener("fetch", (e) => {
|
||||
// We intercept fetch requests in the following situations:
|
||||
// 1: GET requests where we're offline
|
||||
// Show a cached offline page instead
|
||||
// 2: GET requests where have a loggedIn cookie
|
||||
// This can happen either when we're a guest but have a logged in cookie, or when we're
|
||||
// logged in but see a browser-cached guest page. We cachebust the url if we're within
|
||||
// the time when a cached page could exist,
|
||||
// 3: POST requests when we're a guest
|
||||
// 2: POST requests when we're a guest
|
||||
// We need to wrap POST requests in an additional call to get the correct csrf token first
|
||||
|
||||
// Situation 1: offline GET requests
|
||||
@@ -235,88 +223,60 @@ self.addEventListener("fetch", (e) => {
|
||||
return;
|
||||
}
|
||||
|
||||
let matches = e.currentTarget.location.href.match(/loggedIn=(true|false)/);
|
||||
const loggedIn = matches[1];
|
||||
|
||||
// If we're logged in, we need none of this
|
||||
if (loggedIn == 'true') {
|
||||
log("Logged in, nothing to do...");
|
||||
return;
|
||||
}
|
||||
|
||||
e.respondWith(
|
||||
new Promise((resolve, reject) => {
|
||||
// Fetch stored value from indexeddb
|
||||
idbKeyval
|
||||
.getMany(["logged_in", "member_id", "is_acp"])
|
||||
.then(([logged_in, member_id, is_acp]) => {
|
||||
log(`On navigation, logged_in is ${logged_in}`);
|
||||
log(`On navigation, is_acp is ${is_acp}`);
|
||||
log(`ServiceWorker cache busting is ${SW_CACHE_BUST}`);
|
||||
log(`On navigation, logged_in is ${loggedIn}`);
|
||||
|
||||
// Situation 2: GET requests where we have a logged_in cookie
|
||||
if (SW_CACHE_BUST && request.mode === "navigate" && request.method === "GET" && logged_in && !is_acp) {
|
||||
// Calculate whether we're outside of the window of the browser/CF having a cached version
|
||||
const outsideCacheWindow = Math.floor(Date.now() / 1000) - (HTTP_CACHE_DURATION + HTTP_CACHE_BUFFER) > logged_in;
|
||||
const curRequest = request.clone(); // Clone current request because we can't use it after reading it
|
||||
let curUrl = curRequest.url;
|
||||
// Situation 2: POST requests when we're a guest
|
||||
if (loggedIn == 'false' && request.method === "POST") {
|
||||
// Clone current request because we can't use it after reading headers later
|
||||
const curRequest = request.clone();
|
||||
|
||||
// If we are, just resolve normally
|
||||
if (outsideCacheWindow || curUrl.match(/[\?\&]ct=/)) {
|
||||
resolve(fetch(request));
|
||||
return;
|
||||
}
|
||||
log("Intercepting guest post request");
|
||||
|
||||
// If we're within the cache window, add a cache bust to the URL
|
||||
log(`Within potential cache window, adding cachebust to ${request.url}`);
|
||||
// Grab the path so we can check in PHP if it's a CP_DIRECTORY URL
|
||||
let url = new URL(curRequest.url);
|
||||
let path = url.pathname;
|
||||
|
||||
let ts = Math.round(new Date().getTime() / 1000);
|
||||
curUrl += curUrl.match(/\?/) ? "&ct=" + ts : "?ct=" + ts;
|
||||
log(`Request URL ${curUrl}`);
|
||||
// First get the current csrf key from the server
|
||||
fetch(`${BASE_URL}index.php?app=core&module=system&controller=ajax&do=getCsrfKey&path=${path}`)
|
||||
.then((response) => response.json())
|
||||
.then((response) => {
|
||||
log(`Got new csrf key: ${response.key}`);
|
||||
|
||||
const newRequest = new Request(curUrl, {
|
||||
method: curRequest.method,
|
||||
headers: curRequest.headers,
|
||||
mode: "same-origin",
|
||||
// Create new header object starting with existing headers and adding csrf
|
||||
const headers = new Headers(curRequest.headers);
|
||||
headers.set("X-Csrf-Token", response.key);
|
||||
|
||||
const newRequest = new Request(curRequest, {
|
||||
headers,
|
||||
credentials: curRequest.credentials,
|
||||
redirect: "manual",
|
||||
cache: "reload",
|
||||
referrer: curRequest.referrer,
|
||||
});
|
||||
|
||||
// Send cloned request
|
||||
resolve(fetch(newRequest));
|
||||
return;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
reject(err);
|
||||
});
|
||||
|
||||
// Situation 3: POST requests when we're a guest
|
||||
if (member_id === 0 && request.method === "POST" && !is_acp) {
|
||||
// Clone current request because we can't use it after reading headers later
|
||||
const curRequest = request.clone();
|
||||
return;
|
||||
}
|
||||
|
||||
log("Intercepting guest post request");
|
||||
|
||||
// First get the current csrf key from the server
|
||||
fetch(`${BASE_URL}index.php?app=core&module=system&controller=ajax&do=getCsrfKey`)
|
||||
.then((response) => response.json())
|
||||
.then((response) => {
|
||||
log(`Got new csrf key: ${response.key}`);
|
||||
|
||||
// Create new header object starting with existing headers and adding csrf
|
||||
const headers = new Headers(curRequest.headers);
|
||||
headers.set("X-Csrf-Token", response.key);
|
||||
|
||||
const newRequest = new Request(curRequest, {
|
||||
headers,
|
||||
});
|
||||
|
||||
log("Headers:");
|
||||
for (var pair of headers.entries()) {
|
||||
log(pair[0] + ": " + pair[1]);
|
||||
}
|
||||
|
||||
// Send cloned request
|
||||
resolve(fetch(newRequest));
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(fetch(request));
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
resolve(fetch(request));
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -336,8 +296,6 @@ const log = (message) => {
|
||||
|
||||
const cacheAssets = () => {
|
||||
return caches.open(CACHE_NAME).then((cache) => {
|
||||
log("Updating cache:");
|
||||
log(CACHED_ASSETS);
|
||||
return cache.addAll(CACHED_ASSETS);
|
||||
});
|
||||
};
|
||||
@@ -381,85 +339,4 @@ const pluralize = (word, params) => {
|
||||
});
|
||||
|
||||
return word;
|
||||
};
|
||||
|
||||
// https://github.com/jakearchibald/idb-keyval#readme
|
||||
const idbKeyval = (function (t) {
|
||||
"use strict";
|
||||
function e(t) {
|
||||
return new Promise((e, n) => {
|
||||
(t.oncomplete = t.onsuccess = () => e(t.result)), (t.onabort = t.onerror = () => n(t.error));
|
||||
});
|
||||
}
|
||||
function n(t, n) {
|
||||
const r = indexedDB.open(t);
|
||||
r.onupgradeneeded = () => r.result.createObjectStore(n);
|
||||
const o = e(r);
|
||||
return (t, e) => o.then((r) => e(r.transaction(n, t).objectStore(n)));
|
||||
}
|
||||
let r;
|
||||
function o() {
|
||||
return r || (r = n("keyval-store", "keyval")), r;
|
||||
}
|
||||
function u(t, n) {
|
||||
return t(
|
||||
"readonly",
|
||||
(t) => (
|
||||
(t.openCursor().onsuccess = function () {
|
||||
this.result && (n(this.result), this.result.continue());
|
||||
}),
|
||||
e(t.transaction)
|
||||
)
|
||||
);
|
||||
}
|
||||
return (
|
||||
(t.clear = function (t = o()) {
|
||||
return t("readwrite", (t) => (t.clear(), e(t.transaction)));
|
||||
}),
|
||||
(t.createStore = n),
|
||||
(t.del = function (t, n = o()) {
|
||||
return n("readwrite", (n) => (n.delete(t), e(n.transaction)));
|
||||
}),
|
||||
(t.entries = function (t = o()) {
|
||||
const e = [];
|
||||
return u(t, (t) => e.push([t.key, t.value])).then(() => e);
|
||||
}),
|
||||
(t.get = function (t, n = o()) {
|
||||
return n("readonly", (n) => e(n.get(t)));
|
||||
}),
|
||||
(t.getMany = function (t, n = o()) {
|
||||
return n("readonly", (n) => Promise.all(t.map((t) => e(n.get(t)))));
|
||||
}),
|
||||
(t.keys = function (t = o()) {
|
||||
const e = [];
|
||||
return u(t, (t) => e.push(t.key)).then(() => e);
|
||||
}),
|
||||
(t.promisifyRequest = e),
|
||||
(t.set = function (t, n, r = o()) {
|
||||
return r("readwrite", (r) => (r.put(n, t), e(r.transaction)));
|
||||
}),
|
||||
(t.setMany = function (t, n = o()) {
|
||||
return n("readwrite", (n) => (t.forEach((t) => n.put(t[1], t[0])), e(n.transaction)));
|
||||
}),
|
||||
(t.update = function (t, n, r = o()) {
|
||||
return r(
|
||||
"readwrite",
|
||||
(r) =>
|
||||
new Promise((o, u) => {
|
||||
r.get(t).onsuccess = function () {
|
||||
try {
|
||||
r.put(n(this.result), t), o(e(r.transaction));
|
||||
} catch (t) {
|
||||
u(t);
|
||||
}
|
||||
};
|
||||
})
|
||||
);
|
||||
}),
|
||||
(t.values = function (t = o()) {
|
||||
const e = [];
|
||||
return u(t, (t) => e.push(t.value)).then(() => e);
|
||||
}),
|
||||
t
|
||||
);
|
||||
})({});
|
||||
};
|
||||
Reference in new issue
Block a user