New installer compliance

This commit is contained in:
Jiiks 2019-02-17 11:12:12 +02:00
parent c88d2cdae9
commit 2c23f18e89
2 changed files with 129 additions and 105 deletions

View File

@ -8,6 +8,8 @@
* LICENSE file in the root directory of this source tree.
*/
const tests = false;
import path from 'path';
import sass from 'node-sass';
import { BrowserWindow as OriginalBrowserWindow, dialog, session } from 'electron';
@ -17,43 +19,10 @@ import keytar from 'keytar';
import { FileUtils, BDIpc, Config, WindowUtils, CSSEditor, Database } from './modules';
const tests = typeof PRODUCTION === 'undefined';
const _basePath = tests ? path.resolve(__dirname, '..', '..') : __dirname;
const _baseDataPath = tests ? path.resolve(_basePath, 'tests') : _basePath;
const packageJson = require(path.resolve(__dirname, 'package.json'));
const sparkplug = path.resolve(__dirname, 'sparkplug.js');
const _clientScript = tests
? path.resolve(_basePath, 'client', 'dist', 'betterdiscord.client.js')
: path.resolve(_basePath, 'betterdiscord.client.js');
const _cssEditorPath = tests
? path.resolve(__dirname, '..', '..', 'csseditor', 'dist')
: path.resolve(__dirname, 'csseditor');
const _dataPath = path.resolve(_baseDataPath, 'data');
const _extPath = path.resolve(_baseDataPath, 'ext');
const _pluginPath = path.resolve(_extPath, 'plugins');
const _themePath = path.resolve(_extPath, 'themes');
const _modulePath = path.resolve(_extPath, 'modules');
const version = require(path.resolve(_basePath, 'package.json')).version;
const paths = [
{ id: 'base', path: _basePath },
{ id: 'cs', path: _clientScript },
{ id: 'data', path: _dataPath },
{ id: 'ext', path: _extPath },
{ id: 'plugins', path: _pluginPath },
{ id: 'themes', path: _themePath },
{ id: 'modules', path: _modulePath },
{ id: 'csseditor', path: _cssEditorPath }
];
const globals = {
version,
paths
};
let configProxy;
const CSP = {
'img-src': ['https://cdn.betterttv.net', 'https://cdn.frankerfacez.com'],
@ -64,45 +33,6 @@ const CSP = {
]
};
class BrowserWindow extends OriginalBrowserWindow {
constructor(originalOptions) {
const userOptions = BrowserWindow.userWindowPreferences;
const options = deepmerge(originalOptions, userOptions);
options.webPreferences = Object.assign({}, options.webPreferences);
// Make sure Node integration is enabled
options.webPreferences.preload = sparkplug;
super(options);
Object.defineProperty(this, '__bd_preload', {value: []});
if (originalOptions.webPreferences && originalOptions.webPreferences.preload) {
this.__bd_preload.push(originalOptions.webPreferences.preload);
}
if (userOptions.webPreferences && userOptions.webPreferences.preload) {
this.__bd_preload.push(path.resolve(_dataPath, userOptions.webPreferences.preload));
}
Object.defineProperty(this, '__bd_options', {value: options});
Object.freeze(options);
Object.freeze(options.webPreferences);
Object.freeze(this.__bd_preload);
}
static get userWindowPreferences() {
try {
const userWindowPreferences = require(path.join(_dataPath, 'window'));
if (typeof userWindowPreferences === 'object') return userWindowPreferences;
} catch (err) {
console.log('[BetterDiscord] Error getting window preferences:', err);
}
return {};
}
}
class Comms {
constructor(bd) {
this.bd = bd;
@ -139,10 +69,10 @@ class Comms {
BDIpc.on('bd-dba', (event, options) => this.bd.dbInstance.exec(options), true);
BDIpc.on('bd-keytar-get', (event, {service, account}) => keytar.getPassword(service, account), true);
BDIpc.on('bd-keytar-set', (event, {service, account, password}) => keytar.setPassword(service, account, password), true);
BDIpc.on('bd-keytar-delete', (event, {service, account}) => keytar.deletePassword(service, account), true);
BDIpc.on('bd-keytar-find-credentials', (event, {service}) => keytar.findCredentials(service), true);
BDIpc.on('bd-keytar-get', (event, { service, account }) => keytar.getPassword(service, account), true);
BDIpc.on('bd-keytar-set', (event, { service, account, password }) => keytar.setPassword(service, account, password), true);
BDIpc.on('bd-keytar-delete', (event, { service, account }) => keytar.deletePassword(service, account), true);
BDIpc.on('bd-keytar-find-credentials', (event, { service }) => keytar.findCredentials(service), true);
}
async send(channel, message) {
@ -158,38 +88,84 @@ class Comms {
}
}
class BrowserWindow extends OriginalBrowserWindow {
constructor(originalOptions) {
const userOptions = BrowserWindow.userWindowPreferences;
const options = deepmerge(originalOptions, userOptions);
options.webPreferences = Object.assign({}, options.webPreferences);
// Make sure Node integration is enabled
options.webPreferences.preload = sparkplug;
super(options);
Object.defineProperty(this, '__bd_preload', { value: [] });
if (originalOptions.webPreferences && originalOptions.webPreferences.preload) {
this.__bd_preload.push(originalOptions.webPreferences.preload);
}
if (userOptions.webPreferences && userOptions.webPreferences.preload) {
this.__bd_preload.push(path.resolve(configProxy().getPath('data'), userOptions.webPreferences.preload));
}
Object.defineProperty(this, '__bd_options', { value: options });
Object.freeze(options);
Object.freeze(options.webPreferences);
Object.freeze(this.__bd_preload);
}
static get userWindowPreferences() {
try {
const userWindowPreferences = require(path.join(configProxy().getPath('data'), 'window'));
if (typeof userWindowPreferences === 'object') return userWindowPreferences;
} catch (err) {
console.log('[BetterDiscord] Error getting window preferences:', err);
}
return {};
}
}
export class BetterDiscord {
get comms() { return this._comms ? this._comms : (this._commas = new Comms(this)); }
get database() { return this._db ? this._db : (this._db = new Database(this.config.getPath('data'))); }
get config() { return this._config ? this._config : (this._config = new Config(this._args)); }
get window() { return this.windowUtils ? this.windowUtils.window : undefined; }
constructor(args) {
console.log('[BetterDiscord|args] ', JSON.stringify(args, null, 4));
if (BetterDiscord.loaded) {
console.log('Creating two BetterDiscord objects???');
console.log('[BetterDiscord] Creating two BetterDiscord objects???');
return null;
}
BetterDiscord.loaded = true;
this._args = args;
this.injectScripts = this.injectScripts.bind(this);
this.ignite = this.ignite.bind(this);
this.config = new Config(args || globals);
this.dbInstance = new Database(this.config.getPath('data'));
this.comms = new Comms(this);
this.bindings();
this.parseClientPackage();
this.extraPaths();
this.database.init();
configProxy = () => this.config;
this.init();
}
bindings() {
this.injectScripts = this.injectScripts.bind(this);
this.ignite = this.ignite.bind(this);
this.ensureDirectories = this.ensureDirectories.bind(this);
}
async init() {
console.log('[BetterDiscord] init');
await this.waitForWindowUtils();
await this.ensureDirectories();
if (!tests) {
const basePath = this.config.getPath('base');
const files = await FileUtils.listDirectory(basePath);
const latestCs = FileUtils.resolveLatest(files, file => file.endsWith('.js') && file.startsWith('client.'), file => file.replace('client.', '').replace('.js', ''), 'client.', '.js');
this.config.getPath('cs', true).path = path.resolve(basePath, latestCs);
}
await FileUtils.ensureDirectory(this.config.getPath('ext'));
this.csseditor = new CSSEditor(this, this.config.getPath('csseditor'));
// TODO
// this.csseditor = new CSSEditor(this, this.config.getPath('csseditor'));
this.windowUtils.on('did-finish-load', () => this.injectScripts(true));
@ -202,6 +178,24 @@ export class BetterDiscord {
}, 500);
}
async ensureDirectories() {
await FileUtils.ensureDirectory(this.config.getPath('ext'));
await Promise.all([
FileUtils.ensureDirectory(this.config.getPath('plugins')),
FileUtils.ensureDirectory(this.config.getPath('themes')),
FileUtils.ensureDirectory(this.config.getPath('modules'))
]);
}
async waitForWindowUtils() {
if (this.windowUtils) return this.windowUtils;
const window = await this.waitForWindow();
return this.windowUtils = new WindowUtils({ window });
}
/**
* Wait for Discord to load before doing any injection
*/
async waitForWindow() {
return new Promise(resolve => {
const defer = setInterval(() => {
@ -215,14 +209,31 @@ export class BetterDiscord {
});
}
async waitForWindowUtils() {
if (this.windowUtils) return this.windowUtils;
const window = await this.waitForWindow();
return this.windowUtils = new WindowUtils({ window });
/**
* Parses the package.json of client script into config
*/
parseClientPackage() {
const clientPath = this.config.getPath('client');
const { version, main } = require(`${clientPath}/package.json`);
this.config.addPath('client_script', `${clientPath}/${main}`);
this.config.setClientVersion(version);
console.log(`[BetterDiscord] Client v${this.config.clientVersion} - ${this.config.getPath('client_script')}`);
}
get window() {
return this.windowUtils ? this.windowUtils.window : undefined;
/**
* Add extra paths to config
*/
extraPaths() {
const baseDataPath = path.resolve(this.config.getPath('data'), '..');
const extPath = path.resolve(baseDataPath, 'ext');
const pluginPath = path.resolve(extPath, 'plugins');
const themePath = path.resolve(extPath, 'themes');
const modulePath = path.resolve(extPath, 'modules');
this.config.addPath('ext', extPath);
this.config.addPath('plugins', pluginPath);
this.config.addPath('themes', themePath);
this.config.addPath('modules', modulePath);
}
/**
@ -245,8 +256,8 @@ export class BetterDiscord {
* @param {Boolean} reload Whether the main window was reloaded
*/
async injectScripts(reload = false) {
console.log(`RELOAD? ${reload}`);
return this.windowUtils.injectScript(this.config.getPath('cs'));
console.log(`[BetterDiscord] injecting ${this.config.getPath('client_script')}. Reload: ${reload}`);
return this.windowUtils.injectScript(this.config.getPath('client_script'));
}
/**
@ -255,10 +266,11 @@ export class BetterDiscord {
* Basically BetterDiscord needs to load before discord_desktop_core.
*/
static patchBrowserWindow() {
console.log('[BetterDiscord] patching BrowserWindow');
const electron = require('electron');
const electron_path = require.resolve('electron');
Object.assign(BrowserWindow, electron.BrowserWindow); // Assigns the new chrome-specific ones
const newElectron = Object.assign({}, electron, {BrowserWindow});
const newElectron = Object.assign({}, electron, { BrowserWindow });
require.cache[electron_path].exports = newElectron;
}
@ -266,6 +278,7 @@ export class BetterDiscord {
* Attaches an event handler for HTTP requests to update the Content Security Policy.
*/
static hookSessionRequest() {
console.log('[BetterDiscord] hook session request');
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
for (const [header, values] of Object.entries(details.responseHeaders)) {
if (!header.match(/^Content-Security-Policy(-Report-Only)?$/i)) continue;
@ -283,7 +296,6 @@ export class BetterDiscord {
callback({ responseHeaders: details.responseHeaders });
});
}
}
BetterDiscord.patchBrowserWindow();

View File

@ -16,6 +16,14 @@ export default class Config extends Module {
return this.args.version;
}
get clientVersion() {
return this.args.clientVersion;
}
setClientVersion(clientVersion) {
this.args.clientVersion = clientVersion;
}
get paths() {
return this.args.paths;
}
@ -26,6 +34,10 @@ export default class Config extends Module {
// return full ? path : path.path;
}
addPath(id, path) {
this.paths[id] = path;
}
get config() {
return {
version: this.version,