mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 09:42:07 +08:00
8ebd5edd1e
This commit renames all secure_media related settings to secure_uploads_* along with the associated functionality. This is being done because "media" does not really cover it, we aren't just doing this for images and videos etc. but for all uploads in the site. Additionally, in future we want to secure more types of uploads, and enable a kind of "mixed mode" where some uploads are secure and some are not, so keeping media in the name is just confusing. This also keeps compatibility with the `secure-media-uploads` path, and changes new secure URLs to be `secure-uploads`. Deprecated settings: * secure_media -> secure_uploads * secure_media_allow_embed_images_in_emails -> secure_uploads_allow_embed_images_in_emails * secure_media_max_email_embed_image_size_kb -> secure_uploads_max_email_embed_image_size_kb
225 lines
7.2 KiB
Plaintext
225 lines
7.2 KiB
Plaintext
'use strict';
|
|
|
|
importScripts("<%= "#{Discourse.asset_host}#{Discourse.base_path}/javascripts/workbox/workbox-sw.js" %>");
|
|
|
|
workbox.setConfig({
|
|
modulePathPrefix: "<%= "#{Discourse.asset_host}#{Discourse.base_path}/javascripts/workbox" %>",
|
|
debug: false
|
|
});
|
|
|
|
var authUrls = ["auth", "session/sso_login", "session/sso"].map(path => `<%= Discourse.base_path %>/${path}`);
|
|
|
|
var cacheVersion = "1";
|
|
var discourseCacheName = "discourse-" + cacheVersion;
|
|
var externalCacheName = "external-" + cacheVersion;
|
|
|
|
// Chrome 97 shipped with broken samesite cookie handling when proxying requests through service workers
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=1286367
|
|
var chromeVersionMatch = navigator.userAgent.match(/Chrome\/97.0.(\d+)/);
|
|
var isBrokenChrome97 = chromeVersionMatch && parseInt(chromeVersionMatch[1]) <= 4692;
|
|
|
|
// Cache all GET requests, so Discourse can be used while offline
|
|
workbox.routing.registerRoute(
|
|
function(args) {
|
|
return args.url.origin === location.origin && !authUrls.some(u => args.url.pathname.startsWith(u)) && !isBrokenChrome97;
|
|
}, // Match all except auth routes
|
|
new workbox.strategies.NetworkFirst({ // This will only use the cache when a network request fails
|
|
cacheName: discourseCacheName,
|
|
plugins: [
|
|
new workbox.cacheableResponse.Plugin({
|
|
statuses: [200] // opaque responses will return status code '0'
|
|
}), // for s3 secure uploads signed urls
|
|
new workbox.expiration.Plugin({
|
|
maxAgeSeconds: 7* 24 * 60 * 60, // 7 days
|
|
maxEntries: 250,
|
|
purgeOnQuotaError: true, // safe to automatically delete if exceeding the available storage
|
|
}),
|
|
],
|
|
})
|
|
);
|
|
|
|
var cdnUrls = [];
|
|
|
|
<% if GlobalSetting.try(:cdn_cors_enabled) %>
|
|
cdnUrls = ["<%= "#{GlobalSetting.s3_cdn_url}" %>", "<%= "#{GlobalSetting.cdn_url}" %>"].filter(Boolean);
|
|
|
|
if (cdnUrls.length > 0) {
|
|
var cdnCacheName = "cdn-" + cacheVersion;
|
|
var cdnUrl = "<%= "#{GlobalSetting.cdn_url}" %>";
|
|
|
|
var appendQueryStringPlugin = {
|
|
requestWillFetch: function (args) {
|
|
var request = args.request;
|
|
|
|
if (request.url.startsWith(cdnUrl)) {
|
|
var url = new URL(request.url);
|
|
// Using this temporary query param to force browsers to redownload images from server.
|
|
url.searchParams.append('refresh', 'true');
|
|
return new Request(url.href, request);
|
|
}
|
|
|
|
return request;
|
|
}
|
|
};
|
|
|
|
workbox.routing.registerRoute(
|
|
function(args) {
|
|
var matching = cdnUrls.filter(
|
|
function(url) {
|
|
return args.url.href.startsWith(url);
|
|
}
|
|
);
|
|
return matching.length > 0;
|
|
}, // Match all cdn resources
|
|
new workbox.strategies.NetworkFirst({ // This will only use the cache when a network request fails
|
|
cacheName: cdnCacheName,
|
|
fetchOptions: {
|
|
mode: 'cors',
|
|
credentials: 'omit'
|
|
},
|
|
plugins: [
|
|
new workbox.expiration.Plugin({
|
|
maxAgeSeconds: 7* 24 * 60 * 60, // 7 days
|
|
maxEntries: 250,
|
|
purgeOnQuotaError: true, // safe to automatically delete if exceeding the available storage
|
|
}),
|
|
appendQueryStringPlugin
|
|
],
|
|
})
|
|
);
|
|
}
|
|
<% end %>
|
|
|
|
workbox.routing.registerRoute(
|
|
function(args) {
|
|
if (args.url.origin === location.origin) {
|
|
return false;
|
|
}
|
|
|
|
var matching = cdnUrls.filter(
|
|
function(url) {
|
|
return args.url.href.startsWith(url);
|
|
}
|
|
);
|
|
return matching.length === 0;
|
|
}, // Match all other external resources
|
|
new workbox.strategies.NetworkFirst({ // This will only use the cache when a network request fails
|
|
cacheName: externalCacheName,
|
|
plugins: [
|
|
new workbox.cacheableResponse.Plugin({
|
|
statuses: [200] // opaque responses will return status code '0'
|
|
}),
|
|
new workbox.expiration.Plugin({
|
|
maxAgeSeconds: 7* 24 * 60 * 60, // 7 days
|
|
maxEntries: 250,
|
|
purgeOnQuotaError: true, // safe to automatically delete if exceeding the available storage
|
|
}),
|
|
],
|
|
})
|
|
);
|
|
|
|
var idleThresholdTime = 1000 * 10; // 10 seconds
|
|
var lastAction = -1;
|
|
|
|
function isIdle() {
|
|
return lastAction + idleThresholdTime < Date.now();
|
|
}
|
|
|
|
function showNotification(title, body, icon, badge, tag, baseUrl, url) {
|
|
var notificationOptions = {
|
|
body: body,
|
|
icon: icon,
|
|
badge: badge,
|
|
data: { url: url, baseUrl: baseUrl },
|
|
tag: tag
|
|
}
|
|
|
|
return self.registration.showNotification(title, notificationOptions);
|
|
}
|
|
|
|
self.addEventListener('push', function(event) {
|
|
var payload = event.data.json();
|
|
if(!isIdle() && payload.hide_when_active) {
|
|
return false;
|
|
}
|
|
|
|
event.waitUntil(
|
|
self.registration.getNotifications({ tag: payload.tag }).then(function(notifications) {
|
|
if (notifications && notifications.length > 0) {
|
|
notifications.forEach(function(notification) {
|
|
notification.close();
|
|
});
|
|
}
|
|
|
|
return showNotification(payload.title, payload.body, payload.icon, payload.badge, payload.tag, payload.base_url, payload.url);
|
|
})
|
|
);
|
|
});
|
|
|
|
self.addEventListener('notificationclick', function(event) {
|
|
// Android doesn't close the notification when you click on it
|
|
// See: http://crbug.com/463146
|
|
event.notification.close();
|
|
var url = event.notification.data.url;
|
|
var baseUrl = event.notification.data.baseUrl;
|
|
|
|
// This looks to see if the current window is already open and
|
|
// focuses if it is
|
|
event.waitUntil(
|
|
clients.matchAll({ type: "window" })
|
|
.then(function(clientList) {
|
|
var reusedClientWindow = clientList.some(function(client) {
|
|
if (client.url === baseUrl + url && 'focus' in client) {
|
|
client.focus();
|
|
return true;
|
|
}
|
|
|
|
if ('postMessage' in client && 'focus' in client) {
|
|
client.focus();
|
|
client.postMessage({ url: url });
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
|
|
if (!reusedClientWindow && clients.openWindow) return clients.openWindow(baseUrl + url);
|
|
})
|
|
);
|
|
});
|
|
|
|
self.addEventListener('message', function(event) {
|
|
if('lastAction' in event.data){
|
|
lastAction = event.data.lastAction;
|
|
}
|
|
});
|
|
|
|
self.addEventListener('pushsubscriptionchange', function(event) {
|
|
event.waitUntil(
|
|
Promise.all(
|
|
fetch('<%= Discourse.base_url %>/push_notifications/subscribe', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
|
|
body: new URLSearchParams({
|
|
"subscription[endpoint]": event.newSubscription.endpoint,
|
|
"subscription[keys][auth]": event.newSubscription.toJSON().keys.auth,
|
|
"subscription[keys][p256dh]": event.newSubscription.toJSON().keys.p256dh,
|
|
"send_confirmation": false
|
|
})
|
|
}),
|
|
fetch('<%= Discourse.base_url %>/push_notifications/unsubscribe', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
|
|
body: new URLSearchParams({
|
|
"subscription[endpoint]": event.oldSubscription.endpoint,
|
|
"subscription[keys][auth]": event.oldSubscription.toJSON().keys.auth,
|
|
"subscription[keys][p256dh]": event.oldSubscription.toJSON().keys.p256dh
|
|
})
|
|
})
|
|
)
|
|
);
|
|
});
|
|
|
|
<% DiscoursePluginRegistry.service_workers.each do |js| %>
|
|
<%=raw "#{File.read(js)}" %>
|
|
<% end %>
|