This commit is contained in:
Zerebos 2024-02-22 18:08:28 +11:00 committed by GitHub
commit 545d73cb85
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 132 additions and 27 deletions

View File

@ -1,14 +1,105 @@
import electron from "electron";
const whitelist = {
// Discord includes unsafe-inline already
script: [
"https://*.github.io",
"https://cdnjs.cloudflare.com" // Used for Monaco
],
// Discord includes unsafe-inline already
style: [
"https://*.github.io",
"https://cdnjs.cloudflare.com", // Used for Monaco
"https://fonts.googleapis.com",
"https://fonts.cdnfonts.com",
"https://cdn.statically.io",
"https://rawgit.com",
"https://raw.githack.com",
"https://rsms.me",
"https://cdn.jsdelivr.net",
],
// Discord includes fonts.gstatic.com
font: [
"data:",
"https://*.github.io",
"https://cdnjs.cloudflare.com",
"https://fonts.googleapis.com",
"https://raw.githack.com",
"https://cdn.jsdelivr.net",
],
// Discord includes several sources already including imgur and data:
img: [
"https://*.github.io",
"https://ik.imagekit.io",
"https://source.unsplash.com",
"https://raw.githubusercontent.com",
"https://svgur.com",
"https://i.ibb.co",
"https://rawgit.com",
"https://bowmanfox.xyz",
"https://paz.pw",
"https://adx74.fr",
"https://media.tenor.com", // included by discord already
"https://upload.wikimedia.org",
"https://svgrepo.com",
"https://ch3rry.red",
"https://teamcofh.com",
"https://icon-library.net",
"https://images.pexels.com",
"https://user-images.githubusercontent.com",
"https://emoji.gg",
"https://cdn-icons-png.flaticon.com",
],
// Discord does not include this normally
worker: [
"'self'", // To allow Discord's own workers
"data:", // Used for Monaco
],
};
const types = Object.keys(whitelist);
const strings = {};
for (const key of types) strings[key] = whitelist[key].join(" ") + " ";
function addToCSP(csp, type) {
// If it's in the middle of the policy (most common case)
if (csp.includes(`; ${type}-src `)) return csp.replace(`; ${type}-src `, `; ${type}-src ${strings[type]}`);
// If it's the first rule (very uncommon, default-src should be first)
else if (csp.includes(`${type}-src `)) return csp.replace(`${type}-src `, `${type}-src ${strings[type]}`);
// Otherwise, rule doesn't exist, add it to the end
return csp = csp + `; ${type}-src ${strings[type]}; `;
}
export default class {
static remove() {
electron.session.defaultSession.webRequest.onHeadersReceived(function(details, callback) {
const headers = Object.keys(details.responseHeaders);
for (let h = 0; h < headers.length; h++) {
const key = headers[h];
const headerKeys = Object.keys(details.responseHeaders);
for (let h = 0; h < headerKeys.length; h++) {
const key = headerKeys[h];
// Because the casing is inconsistent for whatever reason...
if (key.toLowerCase().indexOf("content-security-policy") !== 0) continue;
delete details.responseHeaders[key];
// Grab current CSP policy and make sure it's Discord's
// since that's the only one we need to modify
let csp = details.responseHeaders[key];
if (Array.isArray(csp)) csp = csp[0];
if (!csp.toLowerCase().includes("discordapp")) continue;
// Iterate over all whitelisted types and update the header
for (let k = 0; k < types.length; k++) csp = addToCSP(csp, types[k]);
details.responseHeaders[key] = [csp];
}
callback({cancel: false, responseHeaders: details.responseHeaders});
});
}

View File

@ -75,31 +75,45 @@ export class CoreUpdater {
}
static async checkForUpdate(showNotice = true) {
const resp = await fetch(`https://api.github.com/repos/BetterDiscord/BetterDiscord/releases/latest`,{
method: "GET",
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"User-Agent": "BetterDiscord Updater"
}
});
try {
const buffer = await new Promise((resolve, reject) => {
request({
url: "https://api.github.com/repos/BetterDiscord/BetterDiscord/releases/latest",
method: "get",
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"User-Agent": "BetterDiscord Updater"
}
}, (err, resp, body) => {
if (err || resp.statusCode != 200) return reject(err || `${resp.statusCode} ${resp.statusMessage}`);
return resolve(body);
});
});
const data = await resp.json();
this.apiData = data;
const remoteVersion = data.tag_name.startsWith("v") ? data.tag_name.slice(1) : data.tag_name;
this.hasUpdate = remoteVersion > Config.version;
this.remoteVersion = remoteVersion;
if (!this.hasUpdate || !showNotice) return;
const data = JSON.parse(buffer.toString());
this.apiData = data;
const remoteVersion = data.tag_name.startsWith("v") ? data.tag_name.slice(1) : data.tag_name;
this.hasUpdate = remoteVersion > Config.version;
this.remoteVersion = remoteVersion;
if (!this.hasUpdate || !showNotice) return;
const close = Notices.info(Strings.Updater.updateAvailable.format({version: remoteVersion}), {
buttons: [{
label: Strings.Notices.moreInfo,
onClick: () => {
close();
UserSettingsWindow?.open?.("updates");
}
}]
});
const close = Notices.info(Strings.Updater.updateAvailable.format({version: remoteVersion}), {
buttons: [{
label: Strings.Notices.moreInfo,
onClick: () => {
close();
UserSettingsWindow?.open?.("updates");
}
}]
});
}
catch (err) {
Logger.stacktrace("Updater", "Failed to check update", err);
Modals.showConfirmationModal(Strings.Updater.updateFailed, Strings.Updater.updateFailedMessage, {
cancelText: null
});
}
}
static async update() {