diff --git a/client/src/index.js b/client/src/index.js index de27de87..eea4c0da 100644 --- a/client/src/index.js +++ b/client/src/index.js @@ -11,14 +11,13 @@ import { DOM, BdUI, BdMenu, Modals, Toasts, Notifications, BdContextMenu, DiscordContextMenu } from 'ui'; import BdCss from './styles/index.scss'; import { Events, Globals, Settings, Database, Updater, ModuleManager, PluginManager, ThemeManager, ExtModuleManager, Vendor, Patcher, MonkeyPatch, ReactComponents, ReactHelpers, ReactAutoPatcher, DiscordApi, BdWebApi, Connectivity, Cache, Reflection, PackageInstaller } from 'modules'; -import { ClientLogger as Logger, ClientIPC, Utils } from 'common'; +import { ClientLogger as Logger, ClientIPC, Utils, Axi } from 'common'; import { BuiltinManager, EmoteModule, ReactDevtoolsModule, VueDevtoolsModule, TrackingProtection, E2EE } from 'builtin'; import electron from 'electron'; import path from 'path'; -import { setTimeout } from 'timers'; const tests = typeof PRODUCTION === 'undefined'; -const ignoreExternal = true; +const ignoreExternal = tests && true; class BetterDiscord { @@ -39,7 +38,7 @@ class BetterDiscord { BdWebApi, Connectivity, Cache, - Logger, ClientIPC, Utils, + Logger, ClientIPC, Utils, Axi, plugins: PluginManager.localContent, themes: ThemeManager.localContent, diff --git a/client/src/modules/globals.js b/client/src/modules/globals.js index 7c40a19a..0c9da1d6 100644 --- a/client/src/modules/globals.js +++ b/client/src/modules/globals.js @@ -102,7 +102,7 @@ export default new class extends Module { } get version() { - return this.config.version; + return this.config.versions.core; } } diff --git a/client/src/modules/imodule.js b/client/src/modules/imodule.js index b16b9ee8..bff59c68 100644 --- a/client/src/modules/imodule.js +++ b/client/src/modules/imodule.js @@ -39,7 +39,7 @@ export default class Module { } setState(newState) { - const oldState = this.state; + const oldState = Object.assign({}, this.state); Object.assign(this.state, newState); if (this.stateChanged) this.stateChanged(oldState, newState); } diff --git a/client/src/modules/updater.js b/client/src/modules/updater.js index 76b4ca29..a48c32c8 100644 --- a/client/src/modules/updater.js +++ b/client/src/modules/updater.js @@ -8,81 +8,183 @@ * LICENSE file in the root directory of this source tree. */ -import Events from './events'; -import Globals from './globals'; -import { ClientLogger as Logger } from 'common'; -import request from 'request-promise-native'; +import { Notifications } from 'ui'; +import { Reflection, Globals } from 'modules'; -export default new class { +import Events from './events'; +import Module from './imodule'; + +export default new class extends Module { + + get updates() { return this.state.updates } + get bdUpdates() { return this.state.updates.bd } + get error() { return null; } + get updatesAvailable() { return this.state.updatesAvailable; } constructor() { - this.updatesAvailable = false; - this.latestVersion = undefined; - this.error = undefined; - - this.init = this.init.bind(this); - this.checkForUpdates = this.checkForUpdates.bind(this); + super({ + updatesAvailable: false, + error: null, + updates: { bd: [] }, + updating: false + }); } - /** - * The interval to wait before checking for updates. - */ - get interval() { - return 60 * 1000 * 30; + bindings() { + this.restartNotif = this.restartNotif.bind(this); + this.reloadNotif = this.reloadNotif.bind(this); + this.startUpdate = this.startUpdate.bind(this); + this.setUpdateStatus = this.setUpdateStatus.bind(this); + this.testUi = this.testUi.bind(this); } - init() { - this.updateInterval = setInterval(this.checkForUpdates, this.interval); + restartNotif() { + Notifications.add('Updates Finished!', 'Restart required.', [ + { + text: 'Restart Later', + onClick: () => { setTimeout(this.restartNotif, 5 * 60000); return true; } + }, + { + text: 'Restart Now', + onClick: () => { + try { + const { remote } = Globals.require('electron'); + window.close(); + Reflection.module.byProps('showToken', 'hideToken').showToken(); + remote.app.relaunch(); + remote.app.exit(0); + } catch (err) { + console.err(err); + return true; + } + } + } + ]); } - /** - * Installs an update. - * TODO - */ - async update() { - try { - await new Promise(resolve => setTimeout(resolve, 5000)); - - this.updatesAvailable = false; - this.latestVersion = Globals.version; - Events.emit('update-check-end'); - } catch (err) { - this.error = err; - this.checkForUpdates(); - throw err; - } + reloadNotif() { + Notifications.add('Updates Finished!', 'Reload required.', [ + { + text: 'Reload Later', + onClick: () => { setTimeout(this.reloadNotif, 5 * 60000); return true; } + }, + { + text: 'Reload Now', + onClick: () => { + document.location.reload(); + } + } + ]); } - /** - * Checks for updates. - * @return {Promise} - */ - async checkForUpdates() { - if (this.updatesAvailable) return true; - Events.emit('update-check-start'); - Logger.info('Updater', 'Checking for updates'); + events(ipc) { + ipc.on('updater-checkForUpdates', () => { + if (this.state.updating) return; // We're already updating. Updater should be paused anyways at this point. + Events.emit('update-check-start'); + }); - try { - const response = await request({ - uri: 'https://rawgit.com/JsSucks/BetterDiscordApp/master/package.json', - json: true + ipc.on('updater-noUpdates', () => { + if (this.state.updatesAvailable) return; // If for some reason we get this even though we have updates already. + this.setState({ + updatesAvailable: false, + updates: {} }); + }); - this.latestVersion = response.version; - Events.emit('update-check-end'); - Logger.info('Updater', `Latest Version: ${response.version} - Current Version: ${Globals.version}`); + ipc.on('updater-updatesAvailable', (_, updates) => { + console.log(updates); + if (this.state.updating) return; // If for some reason we get more updates when we're already updating + updates.bd = updates.bd.map(update => { + update.text = `${update.id.charAt(0).toUpperCase()}${update.id.slice(1)}`; + update.hint = `Current: ${update.currentVersion} | Latest: ${update.version}`; + update.status = { + update: true, + updating: false, + updated: false, + error: null + }; - if (this.latestVersion !== Globals.version) { - this.updatesAvailable = true; - Events.emit('updates-available'); - return true; + return update; + }); + this.setState({ + updates, + updatesAvailable: true + }); + }); + + ipc.on('updater-updated', (_, info) => { + const { reloadRequired, restartRequired } = info; + if (restartRequired) { + this.restartNotif(); + return; } - return false; - } catch (err) { - Events.emit('update-check-fail', err); - throw err; + if (reloadRequired) { + this.reloadNotif(); + return; + } + }); + + ipc.on('updater-updateFinished', (_, update) => { + this.setUpdateStatus(update.id, 'updated', true); + }); + + ipc.on('updater-updateError', (_, update) => { + this.setUpdateStatus(update.id, 'error', update.error); + }); + } + + stateChanged(oldState, newState) { + if (!newState.updatesAvailable) return Events.emit('update-check-end'); + if (!oldState.updatesAvailable && newState.updatesAvailable) { + Events.emit('updates-available'); + Notifications.add('', 'Updates Available!', [ + { + text: 'Ignore', + onClick: () => { return true; } + }, + { + text: 'Show Updates', + onClick: () => { + Events.emit('bd-open-menu', 'updater'); + return true; + } + } + ]); } } + setUpdateStatus(updateId, statusChild, statusValue) { + for (const u of this.bdUpdates) { + if (u.id === updateId) { + u.status[statusChild] = statusValue; + return; + } + } + } + + toggleUpdate(update) { + update.status.update = !update.status.update; + } + + async startUpdate() { + console.log('start update'); + const updates = { bd: [] }; + for (const update of this.bdUpdates) { + if (update.status.update) { + update.status.updating = true; + updates.bd.push(update); + } + } + console.log(updates); + this.send('updater-startUpdate', updates); + } + + testUi(updates) { + this.setState({ + updates, + updatesAvailable: true + }); + } + } diff --git a/client/src/modules/vendor.js b/client/src/modules/vendor.js index efdf35c7..2c1d584a 100644 --- a/client/src/modules/vendor.js +++ b/client/src/modules/vendor.js @@ -11,6 +11,7 @@ import jQuery from 'jquery'; import lodash from 'lodash'; import Vue from 'vue'; +import { Axi } from 'common'; import request from 'request-promise-native'; @@ -40,6 +41,8 @@ export default class { */ static get Vue() { return Vue } + static get axios() { return Axi.axios } + static get request() { return request } static get Combokeys() { return Combokeys } diff --git a/client/src/styles/partials/bdsettings/devview.scss b/client/src/styles/partials/bdsettings/devview.scss new file mode 100644 index 00000000..5e32088d --- /dev/null +++ b/client/src/styles/partials/bdsettings/devview.scss @@ -0,0 +1,9 @@ +.bd-contentColumn .bd-devview { + display: grid; + grid-template-columns: 33% 33% 33%; + + .bd-button { + font-size: 10px; + height: 20px; + } +} diff --git a/client/src/styles/partials/bdsettings/index.scss b/client/src/styles/partials/bdsettings/index.scss index 4bcde300..0fbda29f 100644 --- a/client/src/styles/partials/bdsettings/index.scss +++ b/client/src/styles/partials/bdsettings/index.scss @@ -10,3 +10,4 @@ @import './kvp'; @import './collection'; @import './e2ee'; +@import './devview'; diff --git a/client/src/styles/partials/bdsettings/updater.scss b/client/src/styles/partials/bdsettings/updater.scss index 3e239974..8428036a 100644 --- a/client/src/styles/partials/bdsettings/updater.scss +++ b/client/src/styles/partials/bdsettings/updater.scss @@ -3,4 +3,22 @@ margin: 0 0 10px; color: #fff; } + + .bd-settingSwitch { + .bd-spinner7 { + height: 24px; + } + + .bd-updaterStatus { + text-align: right; + + &.bd-err { + color: $colerr; + } + + &.bd-ok { + color: $colok; + } + } + } } diff --git a/client/src/ui/components/BdSettings.vue b/client/src/ui/components/BdSettings.vue index 398437c7..ec1daae0 100644 --- a/client/src/ui/components/BdSettings.vue +++ b/client/src/ui/components/BdSettings.vue @@ -20,10 +20,11 @@ +
- v2.0.0a by Jiiks/JsSucks + {{versionString}}
@@ -37,7 +38,8 @@ -
+ +
@@ -63,11 +65,11 @@ diff --git a/client/src/ui/components/bd/UpdaterStatus.vue b/client/src/ui/components/bd/UpdaterStatus.vue new file mode 100644 index 00000000..76ef0b24 --- /dev/null +++ b/client/src/ui/components/bd/UpdaterStatus.vue @@ -0,0 +1,28 @@ +/** + * BetterDiscord Updater Status Component + * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks + * All rights reserved. + * https://betterdiscord.net + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. +*/ + + + + diff --git a/client/src/ui/components/bd/UpdaterToggle.vue b/client/src/ui/components/bd/UpdaterToggle.vue new file mode 100644 index 00000000..43f016fd --- /dev/null +++ b/client/src/ui/components/bd/UpdaterToggle.vue @@ -0,0 +1,28 @@ +/** + * BetterDiscord Updater Switch Component + * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks + * All rights reserved. + * https://betterdiscord.net + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. +*/ + + + + diff --git a/client/src/ui/components/bd/UpdaterView.vue b/client/src/ui/components/bd/UpdaterView.vue index 6c24e7a3..e9457d9a 100644 --- a/client/src/ui/components/bd/UpdaterView.vue +++ b/client/src/ui/components/bd/UpdaterView.vue @@ -11,19 +11,22 @@ @@ -32,7 +35,8 @@ import { Globals, Updater } from 'modules'; import { ClientLogger as Logger } from 'common'; import SettingsWrapper from './SettingsWrapper.vue'; - import { FormButton } from '../common'; + import UpdaterToggle from './UpdaterToggle.vue'; + import UpdaterStatus from './UpdaterStatus.vue'; export default { data() { @@ -44,26 +48,29 @@ }, components: { SettingsWrapper, - FormButton + UpdaterToggle, + UpdaterStatus }, computed: { updatesAvailable() { return this.updater.updatesAvailable; }, newVersion() { - return this.updater.latestVersion; + return '2.0.0-beta.4'; }, error() { return this.updater.error; + }, + updates() { + return this.updater.updates; + }, + bdUpdates() { + return this.updater.bdUpdates; } }, methods: { - async install() { - this.updating = true; - try { - await this.updater.update(); - } catch (err) {} - this.updating = false; + update() { + this.updater.startUpdate(); } } } diff --git a/client/src/ui/components/bd/index.js b/client/src/ui/components/bd/index.js index 5744e2ad..29b20c86 100644 --- a/client/src/ui/components/bd/index.js +++ b/client/src/ui/components/bd/index.js @@ -4,5 +4,8 @@ export { default as CssEditorView } from './CssEditor.vue'; export { default as PluginsView } from './PluginsView.vue'; export { default as ThemesView } from './ThemesView.vue'; export { default as UpdaterView } from './UpdaterView.vue'; +export { default as UpdaterStatus } from './UpdaterStatus.vue'; +export { default as UpdaterToggle } from './UpdaterToggle.vue'; export { default as BdBadge } from './BdBadge.vue'; export { default as ConnectivityView } from './ConnectivityView.vue'; +export { default as SuperSecretView } from './SuperSecretView.vue'; diff --git a/client/webpack.base.config.js b/client/webpack.base.config.js index 1e266fc9..acd514f9 100644 --- a/client/webpack.base.config.js +++ b/client/webpack.base.config.js @@ -28,7 +28,6 @@ module.exports = { }, externals: { electron: 'require("electron")', - asar: 'require("asar")', fs: 'require("fs")', path: 'require("path")', util: 'require("util")', diff --git a/client/webpack.config.js b/client/webpack.config.js index 06f40f34..878cb51f 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -13,7 +13,10 @@ const config = { }, plugins: [ new webpack.NamedModulesPlugin() - ] + ], + externals: { + asar: 'require("asar")' + } }; module.exports = merge(baseconfig, config); diff --git a/client/webpack.production.config.js b/client/webpack.production.config.js index 57bc0555..620a1b53 100644 --- a/client/webpack.production.config.js +++ b/client/webpack.production.config.js @@ -15,7 +15,10 @@ const config = { new webpack.DefinePlugin({ PRODUCTION: JSON.stringify(true) }) - ] + ], + externals: { + sparkplug: 'require("./sparkplug")' + } }; module.exports = merge(baseconfig, config); diff --git a/common/modules/axi.js b/common/modules/axi.js new file mode 100644 index 00000000..0d215063 --- /dev/null +++ b/common/modules/axi.js @@ -0,0 +1,51 @@ +/** + * BetterDiscord axios wrapper + * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks + * All rights reserved. + * https://betterdiscord.net + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. +*/ + +import axios from 'axios'; + +export default class AxiosWrapper { + + static get axios() { return axios; } + + static get github() { + return this._github ? this._github : ( + this._github = { + main: this.create('https://github.com'), + api: this.create('https://api.github.com') + } + ); + } + + static get zl() { + return this._zl ? this._zl : (this._zl = { + api: this.create('https://zl', 1000, this.zlHeaders), + cdn: this.create('https://zl', 1000, this.zlHeaders) + }); + } + + static create(baseUrl, timeout = 1000, headers = null) { + return axios.create({ baseURL: baseUrl, timeout, headers: headers ? headers : this.defaultHeaders }); + } + + static get defaultHeaders() { + return { + 'User-Agent': 'BetterDiscordApp User' + }; + } + + static get zlHeaders() { + return { + 'User-Agent': 'BetterDiscordApp User', + 'X-ZL-Apikey': '1a20cce89a2dbd163fc9570f3246c20891e62b2818ada55f82fa3d1d96fa7ef4', + 'X-ZL-User': 'anonymous' + } + } + +} diff --git a/common/modules/common.js b/common/modules/common.js index 3ae581aa..96fe4b72 100644 --- a/common/modules/common.js +++ b/common/modules/common.js @@ -3,3 +3,4 @@ export { default as Filters } from './filters'; export { default as Logger, ClientLogger } from './logger'; export { default as ClientIPC } from './bdipc'; export { default as AsyncEventEmitter } from './async-eventemitter'; +export { default as Axi } from './axi'; diff --git a/core/src/csp.json b/core/src/csp.json new file mode 100644 index 00000000..60cda831 --- /dev/null +++ b/core/src/csp.json @@ -0,0 +1,25 @@ +{ + "img-src": [ + "https://cdn.betterttv.net", + "https://cdn.frankerfacez.com", + "https://i.imgur.com" + ], + "style-src": [ + "https://fonts.googleapis.com" + ], + "script-src": [ + "'sha256-fSHKdpQGCHaIqWP3SpJOuUHrLp49jy4dWHzZ/RBJ/p4='", + "'sha256-VFJcfKY5B3EBkFDgQnv3CozPwBlZcxwssfLVWlPFfZU='", + "'sha256-VzDmLZ4PxPkOS/KY7ITzLQsSWhfCnvUrNculcj8UNgE='", + "'sha256-l6K+77Z1cmldR9gIvaVWlboF/zr5MXCQHcsEHfnr5TU='" + ], + "connect-src": [ + "https://github.com", + "https://api.github.com", + "https://betterdiscord.net", + "https://api.betterdiscord.net", + "https://cdn.betterdiscord.net", + "https://api.supersecretbdapiandcdn.net", + "https://cdn.supersecretbdapiandcdn.net" + ] +} diff --git a/core/src/csp.txt b/core/src/csp.txt new file mode 100644 index 00000000..cac197d7 --- /dev/null +++ b/core/src/csp.txt @@ -0,0 +1,3 @@ +React Devtools: sha256-fSHKdpQGCHaIqWP3SpJOuUHrLp49jy4dWHzZ/RBJ/p4= +Vue Devtools: sha256-VFJcfKY5B3EBkFDgQnv3CozPwBlZcxwssfLVWlPFfZU= +Vue Detector: sha256-l6K+77Z1cmldR9gIvaVWlboF/zr5MXCQHcsEHfnr5TU= diff --git a/core/src/main.js b/core/src/main.js index 58cbfa66..18cd626a 100644 --- a/core/src/main.js +++ b/core/src/main.js @@ -8,11 +8,24 @@ * LICENSE file in the root directory of this source tree. */ +/*PRODUCTION*/ const TESTS = typeof PRODUCTION === 'undefined'; const TEST_ARGS = () => { const _basePath = path.resolve(__dirname, '..', '..'); - const _baseDataPath = path.resolve(_basePath, 'tests'); + const _baseDataPath = path.resolve(_basePath, 'tests'); + + const _corePkg = require(path.resolve(_basePath, 'core', 'package.json')); + const _clientPkg = require(path.resolve(_basePath, 'client', 'package.json')); + const _editorPkg = require(path.resolve(_basePath, 'editor', 'package.json')); + + const coreVersion = _corePkg.version; + const clientVersion = _clientPkg.version; + const editorVersion = _editorPkg.version; + return { + coreVersion, + clientVersion, + editorVersion, 'options': { 'autoInject': true, 'commonCore': true, @@ -26,7 +39,7 @@ const TEST_ARGS = () => { } } } -const TEST_EDITOR = true; +const TEST_EDITOR = TESTS && true; import path from 'path'; import sass from 'node-sass'; @@ -35,21 +48,14 @@ import deepmerge from 'deepmerge'; import ContentSecurityPolicy from 'csp-parse'; import keytar from 'keytar'; -import { FileUtils, BDIpc, Config, WindowUtils, CSSEditor, Editor, Database } from './modules'; +import { FileUtils, BDIpc, Config, WindowUtils, Updater, Editor, Database } from './modules'; const packageJson = require(path.resolve(__dirname, 'package.json')); const sparkplug = path.resolve(__dirname, 'sparkplug.js'); let configProxy; -const CSP = { - 'img-src': ['https://cdn.betterttv.net', 'https://cdn.frankerfacez.com'], - 'script-src': [ - `'sha256-fSHKdpQGCHaIqWP3SpJOuUHrLp49jy4dWHzZ/RBJ/p4='`, // React Devtools - `'sha256-VFJcfKY5B3EBkFDgQnv3CozPwBlZcxwssfLVWlPFfZU='`, // Vue Devtools - `'sha256-VzDmLZ4PxPkOS/KY7ITzLQsSWhfCnvUrNculcj8UNgE=' 'sha256-l6K+77Z1cmldR9gIvaVWlboF/zr5MXCQHcsEHfnr5TU='` // Vue Detector - ] -}; +const CSP = TESTS ? require('../src/csp.json') : require('./csp.json'); class Comms { constructor(bd) { @@ -195,6 +201,8 @@ export class BetterDiscord { get config() { return this._config ? this._config : (this._config = new Config(this._args)); } get window() { return this.windowUtils ? this.windowUtils.window : undefined; } get editor() { return this._editor ? this._editor : (this._editor = new Editor(this, this.config.getPath('editor'))); } + get updater() { return this._updater ? this._updater : (this._updater = new Updater(this)); } + get sendToDiscord() { return this.windowUtils.send; } constructor(args) { if (TESTS) args = TEST_ARGS(); @@ -209,13 +217,16 @@ export class BetterDiscord { this.config.compatibility(); this.bindings(); - this.parseClientPackage(); this.extraPaths(); + this.parseClientPackage(); + this.parseEditorPackage(); + this.parseCorePackage(); this.database.init(); configProxy = () => this.config; const autoInitComms = this.comms; const autoInitEditor = this.editor; + this.updater.start(); this.init(); } @@ -280,7 +291,7 @@ export class BetterDiscord { */ parseClientPackage() { const clientPath = this.config.getPath('client'); - const clientPkg = TESTS ? require(`${path.resolve(clientPath, '..')}/package.json`) :require(`${clientPath}/package.json`); + const clientPkg = TESTS ? require(`${path.resolve(clientPath, '..')}/package.json`) : require(`${clientPath}/package.json`); const { version } = clientPkg; const main = TESTS ? 'betterdiscord.client.js' : clientPkg.main; this.config.addPath('client_script', `${clientPath}/${main}`); @@ -288,6 +299,20 @@ export class BetterDiscord { console.log(`[BetterDiscord] Client v${this.config.clientVersion} - ${this.config.getPath('client_script')}`); } + parseCorePackage() { + const corePath = this.config.getPath('core'); + const corePkg = TESTS ? require(`${path.resolve(corePath, '..')}/package.json`) : require(`${corePath}/package.json`); + const { version } = corePkg; + this.config.setCoreVersion(version); + } + + parseEditorPackage() { + const editorPath = this.config.getPath('editor'); + const editorPkg = TESTS ? require(`${path.resolve(editorPath, '..')}/package.json`) : require(`${editorPath}/package.json`); + const { version } = editorPkg; + this.config.setEditorVersion(version); + } + /** * Add extra paths to config */ diff --git a/core/src/modules/axi.js b/core/src/modules/axi.js new file mode 100644 index 00000000..84023088 --- /dev/null +++ b/core/src/modules/axi.js @@ -0,0 +1,53 @@ +/** + * BetterDiscord axios wrapper + * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks + * All rights reserved. + * https://betterdiscord.net + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. +*/ + +import axios from 'axios'; + +export default class AxiosWrapper { + + static get axios() { return axios; } + + static get(url) { return axios.get(url) } + + static get github() { + return this._github ? this._github : ( + this._github = { + main: this.create('https://github.com'), + api: this.create('https://api.github.com') + } + ); + } + + static get zl() { + return this._zl ? this._zl : (this._zl = { + api: this.create('https://zl', 1000, this.zlHeaders), + cdn: this.create('https://zl', 1000, this.zlHeaders) + }); + } + + static create(baseUrl, timeout = 1000, headers = null) { + return axios.create({ baseURL: baseUrl, timeout, headers: headers ? headers : this.defaultHeaders }); + } + + static get defaultHeaders() { + return { + 'User-Agent': 'BetterDiscordApp User' + }; + } + + static get zlHeaders() { + return { + 'User-Agent': 'BetterDiscordApp User', + 'X-ZL-Apikey': '1a20cce89a2dbd163fc9570f3246c20891e62b2818ada55f82fa3d1d96fa7ef4', + 'X-ZL-User': 'anonymous' + } + } + +} diff --git a/core/src/modules/config.js b/core/src/modules/config.js index c81ba5de..43559729 100644 --- a/core/src/modules/config.js +++ b/core/src/modules/config.js @@ -16,12 +16,36 @@ export default class Config extends Module { return this.args.version; } + get versions() { + return { + core: this.coreVersion, + client: this.clientVersion, + editor: this.editorVersion + }; + } + + get coreVersion() { + return this.state.coreVersion; + } + get clientVersion() { - return this.args.clientVersion; + return this.state.clientVersion; + } + + get editorVersion() { + return this.state.editorVersion; } setClientVersion(clientVersion) { - this.args.clientVersion = clientVersion; + this.state.clientVersion = clientVersion; + } + + setCoreVersion(coreVersion) { + this.state.coreVersion = coreVersion; + } + + setEditorVersion(editorVersion) { + this.state.editorVersion = editorVersion; } get paths() { @@ -41,6 +65,7 @@ export default class Config extends Module { get config() { return { version: this.version, + versions: this.versions, paths: this.paths }; } diff --git a/core/src/modules/index.js b/core/src/modules/index.js index 4a56e948..2b98833e 100644 --- a/core/src/modules/index.js +++ b/core/src/modules/index.js @@ -4,3 +4,4 @@ export { default as Config } from './config'; export { default as CSSEditor } from './csseditor'; export { default as Editor } from './editor'; export { default as Database } from './database'; +export { default as Updater } from './updater'; diff --git a/core/src/modules/modulebase.js b/core/src/modules/modulebase.js index 5623e3e9..6a630548 100644 --- a/core/src/modules/modulebase.js +++ b/core/src/modules/modulebase.js @@ -11,6 +11,9 @@ /** * Base Module that every non-static module should extend. */ + +import { default as BDIpc } from './bdipc'; + export default class Module { constructor(args) { @@ -24,6 +27,7 @@ export default class Module { init() { if (this.bindings) this.bindings(); if (this.setInitialState) this.setInitialState(this.state); + if (this.events) this.events(BDIpc); } set args(t) {} diff --git a/core/src/modules/updater.js b/core/src/modules/updater.js new file mode 100644 index 00000000..4c82f032 --- /dev/null +++ b/core/src/modules/updater.js @@ -0,0 +1,287 @@ +/** + * BetterDiscord Updater Module + * Copyright (c) 2015-present JsSucks - https://github.com/JsSucks + * All rights reserved. + * https://github.com/JsSucks - https://betterdiscord.net + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. +*/ + + +import Module from './modulebase'; +import { FileUtils } from './utils'; +import semver from 'semver'; +import Axi from './axi'; +import zlib from 'zlib'; +import tarfs from 'tar-fs'; + +const TEST_UPDATE = [ + { + 'id': 'core', + 'version': '2.0.0-beta.5' + }, + { + 'id': 'client', + 'version': '2.0.0-beta.5' + }, + { + 'id': 'editor', + 'version': '0.4.1' + } +]; + +class ReleaseInfo { + + constructor(versions) { + this.versions = versions; + } + + get core() { + const f = this.files.find(f => f.id === 'core'); + f.upToDate = semver.satisfies(this.versions.core, `>=${f.version}`, { includePrerelease: true }); + f.currentVersion = this.versions.core; + return f; + } + + get client() { + const f = this.files.find(f => f.id === 'client'); + f.upToDate = semver.satisfies(this.versions.client, `>=${f.version}`, { includePrerelease: true }); + f.currentVersion = this.versions.client; + return f; + } + + get editor() { + const f = this.files.find(f => f.id === 'editor'); + f.upToDate = semver.satisfies(this.versions.editor, `>=${f.version}`, { includePrerelease: true }); + f.currentVersion = this.versions.editor; + return f; + } + + test() { + this.files = TEST_UPDATE; + } + +} + +export default class Updater extends Module { + + constructor(bd) { + super(); + this.bd = bd; + } + + bindings() { + this.checkForUpdates = this.checkForUpdates.bind(this); + this.checkForBdUpdates = this.checkForBdUpdates.bind(this); + this.updateAll = this.updateAll.bind(this); + this.updateFinished = this.updateFinished.bind(this); + this.start = this.start.bind(this); + } + + events(ipc) { + ipc.on('updater-startUpdate', (_, updates) => { + clearInterval(this.updaterThread); + this.updateAll(updates); + }); + ipc.on('debug-updater-forceUpdate', () => { + this.checkForUpdates(true); + }); + } + + async updateBd(update) { + try { + console.log('[BetterDiscord:Updater] Updating', update.id); + await this.downloadTarGz(`https://github.com/JsSucks/BetterDiscordApp${update.remote}`, this.bd.config.getPath('base')); + this.updateFinished(update); + // Cleanup + await FileUtils.rm(`${this.bd.config.getPath(update.id)}_old`); + } catch (err) { + console.log('[BetterDiscord:Updater] Failed to update', update.id); + console.log(err); + update.error = err; + this.bd.sendToDiscord('updater-updateError', update); + } + } + + async updateAll(updates) { + const bd = updates.bd || []; + const plugins = updates.plugins || []; + const themes = updates.themes || []; + const modules = updates.modules || []; + + this.restartRequired = this.reloadRequired = false; + this.finishedUpdates = 0; + this.totalUpdates = bd.length + plugins.length + themes.length + modules.length; + + const renamed = []; + // TODO cleaner + if (bd.length) { + for (const update of bd) { + try { + await FileUtils.rm(`${this.bd.config.getPath(update.id)}_old`); + // Try to rename dirs first + await FileUtils.rn(this.bd.config.getPath(update.id), `${this.bd.config.getPath(update.id)}_old`); + renamed.push({ 'old': this.bd.config.getPath(update.id), 'new': `${this.bd.config.getPath(update.id)}_old`}); + } catch (err) { + if (renamed.length) { + // Restore dirs + for (const r of renamed) { + await FileUtils.rn(r.new, r.old); + } + } + + throw err; + } + } + + for (const update of bd) { + this.updateBd(update); + } + } + + } + + updateFinished(update) { + if (update.id === 'core') this.restartRequired = true; + if (update.id === 'client') this.reloadRequired = true; + + console.log('[BetterDiscord:Updater] Finished updating', update.id); + this.bd.sendToDiscord('updater-updateFinished', update); + + this.finishedUpdates++; + if (this.finishedUpdates >= this.totalUpdates) { + this.bd.sendToDiscord('updater-updated', { restartRequired: this.restartRequired, reloadRequired: this.reloadRequired }); + } + } + + start(interval = 30) { + this.updaterThread = setInterval(this.checkForUpdates, interval * 60 * 1000); + } + + validate(releaseInfo) { + return releaseInfo && + typeof releaseInfo === 'object' && + releaseInfo.files && + Array.isArray(releaseInfo.files) && + releaseInfo.files.length >= 4; + } + + async latestRelease() { + try { + const release = await Axi.github.api.get('repos/JsSucks/BetterDiscordApp/releases/latest'); // TODO replace with config + const releaseInfoAsset = release.data.assets.find(asset => asset.name === 'releaseinfo.json'); + const releaseInfo = await Axi.get(releaseInfoAsset['browser_download_url']); + + if (this.validate(releaseInfo.data)) return releaseInfo.data; + return this.latestReleaseFallback(); + } catch (err) { + console.log(err); + return this.latestReleaseFallback(); + } + } + + async latestReleaseFallback() { + console.log('fallback'); + } + + async checkForBdUpdates(forced = false) { + try { + const { coreVersion, clientVersion, editorVersion } = this.bd.config; + const releaseInfo = new ReleaseInfo({ core: coreVersion, client: clientVersion, editor: editorVersion }); + + const latestRelease = await this.latestRelease(); + + if (forced) { + latestRelease.files = latestRelease.files.map(file => { + file.version = '10.0.0'; + return file; + }); + } + + releaseInfo.files = latestRelease.files; + + const updates = []; + + const { core, client, editor } = releaseInfo; + if (!core.upToDate) updates.push(core); + if (!client.upToDate) updates.push(client); + if (!editor.upToDate) updates.push(editor); + + return updates; + + } catch (err) { + console.log('[BetterDiscord:Updater]', err); + return []; + } + } + + async checkForUpdates(forced = false) { + console.log('[BetterDiscord:Updater] Checking for updates'); + this.bd.sendToDiscord('updater-checkForUpdates', ''); + + try { + const bd = await this.checkForBdUpdates(forced); + const updates = { bd, haveUpdates: false }; + + if (bd.length) updates.haveUpdates = true; + + if (!updates.haveUpdates) { + this.bd.sendToDiscord('updater-noUpdates', ''); + return true; + } + + this.bd.sendToDiscord('updater-updatesAvailable', updates); + + return true; + + } catch (err) { + console.log('[BetterDiscord:Updater]', err); + this.bd.sendToDiscord('updater-error', err); + return 'err'; + } + } + + async downloadTarGz(url, dest, responseType = 'stream', headers = null) { + try { + const stream = await Axi.axios({ + url, + type: 'GET', + responseType, + headers: headers || + { + 'Content-Type': 'application/octet-stream', + 'Accept': 'application/octet-stream' + } + }); + + return new Promise((resolve, reject) => { + stream.data.pipe(zlib.createGunzip()).pipe(tarfs.extract(dest)).on('finish', resolve).on('error', reject); + }); + } catch (err) { + throw err; + } + } + + debug(releaseInfo) { + const { core, client, editor } = releaseInfo; + if (!core.upToDate) { + console.log(`[BetterDiscord:Updater] Core update available: ${core.currentVersion} > ${core.version}`); + } else { + console.log(`[BetterDiscord:Updater] Core up to date: ${core.currentVersion} = ${core.version}`); + } + + if (!client.upToDate) { + console.log(`[BetterDiscord:Updater] Client update available: ${client.currentVersion} > ${client.version}`); + } else { + console.log(`[BetterDiscord:Updater] Client up to date: ${client.currentVersion} = ${client.version}`); + } + + if (!editor.upToDate) { + console.log(`[BetterDiscord:Updater] Editor update available: ${editor.currentVersion} > ${editor.version}`); + } else { + console.log(`[BetterDiscord:Updater] Editor up to date: ${editor.currentVersion} = ${editor.version}`); + } + } + +} diff --git a/gulpfile.babel.js b/gulpfile.babel.js index 10b89c8b..1f1c3332 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -4,6 +4,7 @@ import del from 'del'; import copy from 'gulp-copy'; import rename from 'gulp-rename'; import inject from 'gulp-inject-string'; +import replace from 'gulp-replace'; import copydeps from './scripts/copydeps'; import file from 'gulp-file'; import editjson from 'gulp-json-editor'; @@ -14,10 +15,10 @@ import editorpkg from './editor/package'; // core-release > -gulp.task('core-main', function () { +gulp.task('core-main', function() { return pump([ gulp.src('core/dist/main.js'), - inject.after(`'use strict';\n`, 'const PRODUCTION = true;\n'), + replace('/*PRODUCTION*/', 'const PRODUCTION = true;'), rename(`core.${corepkg.version}.js`), gulp.dest('release/core') ]); @@ -36,27 +37,34 @@ gulp.task('core-pkg', function() { ]); }); -gulp.task('core-modules', function () { +gulp.task('core-modules', function() { return pump([ gulp.src('core/dist/modules/**/*'), copy('release/core', { prefix: 2 }) ]); }); -gulp.task('core-sparkplug', function () { +gulp.task('core-sparkplug', function() { return pump([ gulp.src('core/dist/sparkplug.js'), gulp.dest('release/core') ]); }); -gulp.task('core-release', gulp.parallel('core-main', 'core-pkg', 'core-sparkplug', 'core-modules')); +gulp.task('core-extras', function() { + return pump([ + gulp.src(['core/src/csp.json']), + gulp.dest('release/core') + ]); +}); + +gulp.task('core-release', gulp.parallel('core-main', 'core-pkg', 'core-sparkplug', 'core-modules', 'core-extras')); // < core-release // client -gulp.task('client-main', function () { +gulp.task('client-main', function() { return pump([ gulp.src('client/dist/*.client-release.js'), rename(`client.${clientpkg.version}.js`), @@ -76,7 +84,7 @@ gulp.task('client-pkg', function() { ]); }); -gulp.task('client-sparkplug', function () { +gulp.task('client-sparkplug', function() { return pump([ gulp.src('core/dist/sparkplug.js'), gulp.dest('release/client') @@ -87,7 +95,7 @@ gulp.task('client-release', gulp.parallel('client-main', 'client-pkg', 'client-s // Editor -gulp.task('editor-main', function () { +gulp.task('editor-main', function() { return pump([ gulp.src('editor/dist/editor.release.js'), rename(`editor.${editorpkg.version}.js`), @@ -95,10 +103,10 @@ gulp.task('editor-main', function () { ]); }); -gulp.task('editor-pkg', function () { +gulp.task('editor-pkg', function() { return pump([ gulp.src('editor/package.json'), - editjson(function (pkg) { + editjson(function(pkg) { pkg.main = `editor.${editorpkg.version}.js`; delete pkg.scripts; return pkg; @@ -118,18 +126,18 @@ gulp.task('node-modules', function() { ]); }); -gulp.task('node-sass-bindings', gulp.series(function () { +gulp.task('node-sass-bindings', gulp.series(function() { return del(['release/node_modules/node-sass/vendor']); -}, function () { +}, function() { return pump([ gulp.src('other/node_sass_bindings/**/*'), copy('release/core/node_modules/node-sass/vendor', { prefix: 2 }) ]); })); -gulp.task('keytar-bindings', gulp.series(function () { +gulp.task('keytar-bindings', gulp.series(function() { return del(['release/node_modules/keytar/build']); -}, function () { +}, function() { return pump([ gulp.src('other/keytar/**/*'), copy('release/core/node_modules/keytar/build/Release', { prefix: 2 }) @@ -144,4 +152,4 @@ gulp.task('del-release', function() { gulp.task('dependencies', gulp.series('node-modules', gulp.parallel('node-sass-bindings', 'keytar-bindings'))); gulp.task('build-release', gulp.parallel('core-release', 'client-release', 'editor-release', 'dependencies')); -gulp.task('release', gulp.series('del-release', 'build-release')); \ No newline at end of file +gulp.task('release', gulp.series('del-release', 'build-release')); diff --git a/other/keytar/keytar.node/keytar-4.4.1/win32-ia32-69.node b/other/keytar/keytar.node/keytar-4.4.1/win32-ia32-69.node new file mode 100644 index 00000000..6d726e46 Binary files /dev/null and b/other/keytar/keytar.node/keytar-4.4.1/win32-ia32-69.node differ diff --git a/other/node_sass_bindings/win32-ia32-69/binding.node b/other/node_sass_bindings/win32-ia32-69/binding.node new file mode 100644 index 00000000..3dfbc1e2 Binary files /dev/null and b/other/node_sass_bindings/win32-ia32-69/binding.node differ diff --git a/package-lock.json b/package-lock.json index 4a817999..e198080c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1583,6 +1583,15 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, + "axios": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "requires": { + "follow-redirects": "^1.3.0", + "is-buffer": "^1.1.5" + } + }, "babel-loader": { "version": "8.0.5", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.5.tgz", @@ -1776,6 +1785,12 @@ "underscore": "~1.4.4" } }, + "binaryextensions": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.2.tgz", + "integrity": "sha512-xVNN69YGDghOqCCtA6FI7avYrr02mTJjOgB0/f1VPD3pJC8QEvjTKWc4epDx8AqxxA75NI0QpVM2gPJXUbE4Tg==", + "dev": true + }, "bl": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", @@ -3037,6 +3052,12 @@ "safer-buffer": "^2.1.0" } }, + "editions": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", + "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==", + "dev": true + }, "editorconfig": { "version": "0.15.2", "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.2.tgz", @@ -4200,6 +4221,29 @@ "readable-stream": "^2.3.6" } }, + "follow-redirects": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", + "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", + "requires": { + "debug": "^3.2.6" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -5355,6 +5399,17 @@ "integrity": "sha512-swzbIGb/arEoFK89tPY58vg3Ok1bw+d35PfUNwWqdo7KM4jkmuGA78JiDNqR+JeZFaeeHnRg9N7aihX3YPmsyg==", "dev": true }, + "gulp-replace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.0.0.tgz", + "integrity": "sha512-lgdmrFSI1SdhNMXZQbrC75MOl1UjYWlOWNbNRnz+F/KHmgxt3l6XstBoAYIdadwETFyG/6i+vWUSCawdC3pqOw==", + "dev": true, + "requires": { + "istextorbinary": "2.2.1", + "readable-stream": "^2.0.1", + "replacestream": "^4.0.0" + } + }, "gulp-watch": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/gulp-watch/-/gulp-watch-5.0.1.tgz", @@ -6408,6 +6463,17 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, + "istextorbinary": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.2.1.tgz", + "integrity": "sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw==", + "dev": true, + "requires": { + "binaryextensions": "2", + "editions": "^1.3.3", + "textextensions": "2" + } + }, "jquery": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", @@ -8444,6 +8510,28 @@ "end-of-stream": "^1.1.0", "once": "^1.3.1" } + }, + "tar-fs": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", + "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", + "requires": { + "chownr": "^1.0.1", + "mkdirp": "^0.5.1", + "pump": "^1.0.0", + "tar-stream": "^1.1.2" + }, + "dependencies": { + "pump": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", + "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } } } }, @@ -8570,7 +8658,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -8946,6 +9033,17 @@ "remove-trailing-separator": "^1.1.0" } }, + "replacestream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz", + "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.3", + "object-assign": "^4.0.1", + "readable-stream": "^2.0.2" + } + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -10202,23 +10300,44 @@ } }, "tar-fs": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", - "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz", + "integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==", "requires": { - "chownr": "^1.0.1", + "chownr": "^1.1.1", "mkdirp": "^0.5.1", - "pump": "^1.0.0", - "tar-stream": "^1.1.2" + "pump": "^3.0.0", + "tar-stream": "^2.0.0" }, "dependencies": { - "pump": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", - "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", + "bl": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz", + "integrity": "sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==", "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "readable-stream": "^3.0.1" + } + }, + "readable-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.2.0.tgz", + "integrity": "sha512-RV20kLjdmpZuTF1INEb9IA3L68Nmi+Ri7ppZqo78wj//Pn62fCoJyV9zalccNzDD/OuJpMG4f+pfMl8+L6QdGw==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "tar-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.0.1.tgz", + "integrity": "sha512-I6OJF7wE62BC6zNPdHDtseK0D0187PBjbKSLYY4ffvVkBM6tyBn2O9plDvVM2229/mozfEL/X3++qSvYYQE2xw==", + "requires": { + "bl": "^3.0.0", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" } } } @@ -10361,6 +10480,12 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "textextensions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.4.0.tgz", + "integrity": "sha512-qftQXnX1DzpSV8EddtHIT0eDDEiBF8ywhFYR2lI9xrGtxqKN+CvLXhACeCIGbCpQfxxERbrkZEFb8cZcDKbVZA==", + "dev": true + }, "throttleit": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", diff --git a/package.json b/package.json index f061b504..f16a6191 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "private": false, "dependencies": { "asar": "^1.0.0", + "axios": "^0.18.0", "chokidar": "^2.1.2", "csp-parse": "github:macropodhq/csp-parse", "deepmerge": "^3.2.0", @@ -24,7 +25,9 @@ "keytar": "^4.4.1", "nedb": "^1.8.0", "node-sass": "^4.11.0", - "original-fs": "^1.0.0" + "original-fs": "^1.0.0", + "semver": "^5.6.0", + "tar-fs": "^2.0.0" }, "devDependencies": { "@babel/core": "^7.3.4", @@ -51,6 +54,7 @@ "gulp-inject-string": "^1.1.2", "gulp-json-editor": "^2.5.1", "gulp-rename": "^1.4.0", + "gulp-replace": "^1.0.0", "gulp-watch": "^5.0.1", "hash-files": "^1.1.1", "html-webpack-plugin": "^3.2.0", @@ -94,7 +98,8 @@ "package_release": "node scripts/package-release.js", "gulp_release": "gulp release", "release": "npm run lint && npm run build_release && gulp release && npm run package_release", - "update_release": "npm run build_release && gulp build-release", + "release_test": "npm run build_release && gulp release", + "update_release": "npm run build_release && gulp release", "inject": "node scripts/inject.js" } } diff --git a/scripts/package-release.js b/scripts/package-release.js index f69db474..de13c9a3 100644 --- a/scripts/package-release.js +++ b/scripts/package-release.js @@ -53,6 +53,7 @@ async function archiveCore(out = './release/core.tar.gz') { coreArchive.file('./release/core/package.json', { name: 'core/package.json' }); coreArchive.file('./release/core/index.js', { name: 'core/index.js' }); coreArchive.file(`./release/core/${mainFn}`, { name: `core/${mainFn}` }); + coreArchive.file('./release/core/csp.json', { name: 'core/csp.json' }); coreArchive.file('./release/core/sparkplug.js', { name: 'core/sparkplug.js' }); coreArchive.directory('./release/core/modules', 'core/modules'); coreArchive.directory('./release/core/node_modules', 'core/node_modules');