Compare commits

...

68 Commits

Author SHA1 Message Date
|| Prof. - Xadk3!#0000 || @naryal2580 5791d70e0d 🤔\ 2023-05-20 20:34:25 +05:30
|| Prof. - Xadk3!#0000 || @naryal2580 f95fef17d2 CORE+LATEST 2023-05-20 20:32:19 +05:30
|| Prof. - Xadk3!#0000 || @naryal2580 074436668f OXOO 2023-05-08 21:14:47 +05:30
|| Prof. - Xadk3! b390a93306 ok. QUAK! contribution self-leak . ;-; 2023-05-04 04:51:06 +00:00
|| Prof. - Xadk3! cc1ed1f005 idk what contribution but ok. 2023-05-04 04:24:32 +00:00
|| Prof. - Xadk3! b0078534d6 Merge branch 'main' of https://gitdab.com/naryal2580/OpenAsar 2023-04-13 20:40:22 +00:00
|| Prof. - Xadk3! b725e71d82 ci: disable size diff (for now) 2023-04-13 20:39:26 +00:00
Ducko 20b5fa3165 ci: disable size diff (for now) 2023-04-10 21:19:22 +01:00
Ducko 8cf5233e94 rewrite: replace requireNative with globalPaths workaround
Added Module.globalPaths workaround (reintroduce native usage instead of our own util using it) is needed as Discord's overlay code depends on their own implementation of this. Also removed requireNative and replace with just require since no longer needed with this hack anyway.
2023-04-10 20:59:54 +01:00
Ducko d8035e14b7 settings: rewrite item injection 2023-04-08 21:12:15 +01:00
Ducko 6705ee9933 autostart: only update on win32 2023-04-03 22:32:40 +01:00
Ducko 120d1a5b16 config: ensure window is not destroyed 2023-04-03 18:37:40 +01:00
Ducko be9f15dc45 config: show existing window if already open 2023-04-03 17:40:02 +01:00
Ducko 0d81eadaf0 domopt: remove append opt 2023-04-03 14:50:43 +01:00
Ducko 9052a5cb78 domopt: rewrite and apply to append too 2023-04-03 10:46:52 +01:00
Ducko 28e8ed4a60 inject: dom optimizer (wip) 2023-04-02 22:29:39 +01:00
Ducko ac0ad4d48a settings: make version hash look better 2023-04-01 21:46:04 +01:00
Ducko cc0cae97f9 settings: add openasar setting item (rewrite) 2023-04-01 20:51:02 +01:00
Ducko 3a52bd2ac7 autoStart: rewrite into monolithic file 2023-03-23 21:55:09 +00:00
Ducko a1be7204df ci: tweak release notes 2023-03-23 21:39:03 +00:00
Ducko be076a2fe4 ci: add size diff to release notes 2023-03-23 21:35:07 +00:00
Ducko 3279282c96 autoStart/linux: tweak desktop file 2023-03-23 20:53:23 +00:00
alsoGAMER 40b27dd1b8
[noTrack] Blocking improvements (#108)
* [noTrack] Also block metrics call

* [noTrack] Wildcard api version for science call
2023-01-13 15:05:43 +00:00
Ducko c2cd5449bd constants: use new, new endpoint 2023-01-11 22:00:30 +00:00
Ducko c9a4662008 bootstrap: minor code cleanup 2023-01-11 21:56:01 +00:00
Ducko 6b6cabecf0 autoStart/win32: quote executable path 2023-01-11 21:54:33 +00:00
Ducko 0b1d4685cb asarUpdate: rewrite to use async and no temp file 2022-12-11 12:51:28 +00:00
Ducko edb6a5b4fe updater: rewrite openasar retaining 2022-12-11 12:36:41 +00:00
Ducko 78b49c092c updater: skip host deltas 2022-12-11 12:35:40 +00:00
Ian Manske 9582d79109
Fix syntax error in injectPolyfills.sh (#115) 2022-12-08 06:42:20 +00:00
Ducko bb6165c1ad chore: add injectPolyfills script to stop older build scripts from breaking 2022-12-06 19:06:31 +00:00
Ducko ad9b161744 moduleUpdater: don't defer voice module 2022-12-02 22:38:48 +00:00
Ducko d1f9fe0024 remove polyfills 2022-12-02 22:32:16 +00:00
Ducko e1bd891f74 ci: revert to old 2022-12-02 22:29:17 +00:00
CanadaHonk ec5082860e
Remove Polyfills (#101)
* poly: remove completely

* bootstrap: remove unused request require

* asarUpdate: rewrite request -> https

* moduleUpdater: rewrite request -> https

* ui: fallback to channel instead of "custom" if no hash

* index: set name to branch for obvious testing

* config/backend: tweak source

* moduleUpdater: fix rewrite

* moduleUpdater: fix rewrite (x2)

* moduleUpdater: follow redirects with rewrite

* ci: start multi-branch rewrite

* ci: upgrade node to 18.x

* ci: rewrite version changing to use existing

* ci: change release version getting to in file

* ci: mess with yaml syntax

* ci: revert to node 16.x, fix version wrapped in quotes

* ci: fix invalid yaml

* ci: yaml syntax fixing

* ci: append to tag

* ci: make pre-release unless nightly build

* ci: add title nicening

* asarUpdate: fix release suffix

* asarUpdate: fix not following redirect

* winFirst: don't remake shortcuts, tweaks

* ui: add channel prefix if non-nightly

* chore: prep for main branch
2022-12-02 22:23:46 +00:00
Ducko f2da613f2b requireNative: fix reversing 2022-12-01 21:19:42 +00:00
Ducko 7a04cb57df css: fix escaping backticks 2022-10-10 16:41:39 +01:00
Kyiro c72f1a3fc0
paths: add DISCORD_USER_DATA_DIR support (#88) 2022-10-02 20:37:10 +01:00
Ducko 78204759a3 bootstrap: rewrite new blocking system 2022-09-29 17:07:54 +01:00
Ducko 1f0ac0f27e bootstrap: fix new blocking system 2022-09-29 17:04:13 +01:00
Ducko a6bd6654c9 ci: disable debugging 2022-09-29 16:26:07 +01:00
Ducko d16475714d ci: enable debugging 2022-09-29 16:18:51 +01:00
Ducko 3314bc9c28 bootstrap: tweak webRequest handling 2022-09-29 16:01:43 +01:00
Ducko 5c68a2a78f bootstrap: add noTyping 2022-09-29 15:52:57 +01:00
Ducko d63646ccfe mainWindow: fix OA version css 2022-09-29 14:09:36 +01:00
Ducko 3291e197af utils/win: tie window caching to version 2022-09-28 19:39:22 +01:00
Ducko 3e027d59f2 bootstrap: default css config for injection 2022-09-28 18:00:27 +01:00
Ducko 3278a3f97e mainWindow: rewrite css injection 2022-09-28 17:50:29 +01:00
Ducko 5d2bd94945 css: rewrite css injection to use mainWindow to fix imports 2022-09-28 17:33:31 +01:00
Ducko a021777ede bootstrap: disable CSP with css too 2022-09-28 16:21:30 +01:00
Ducko f425859c93 bootstrap: add CSS injection support (like JS) 2022-09-28 15:50:06 +01:00
Ducko 045f9db914 asarUpdate: clean up old code 2022-09-28 13:33:26 +01:00
Ducko 73fcc84e25 config: tweak preload 2022-09-28 10:58:07 +01:00
CanadaHonk e087078400
[Chore] Clean PR 2022-08-07 13:41:18 +01:00
Julian Pettersen 4606f93e52
Logic for opening settings.json (#77)
Co-authored-by: Julian pettersen <darlion2301@gmail.com>
2022-08-07 13:37:32 +01:00
CanadaHonk ed2d0045ff
roadmap: marked done as done 2022-07-15 22:10:27 +01:00
CanadaHonk 6f7505fb91
[Init] Don't die on QS globalPaths fail on Win 2022-06-27 08:00:16 +01:00
Ducko c6f2f5eb78 [NoTrack] Possible fix 2022-06-10 11:00:01 +01:00
Ducko e3cfc8dcdc [NoTrack] Disable console setting (temp) 2022-06-10 10:54:23 +01:00
Ducko 936ee08616 [NoTrack] Revert last 2022-06-10 09:12:04 +01:00
Ducko 967229fea8 [NoTrack] Fallback/more disabling of Sentry in inject 2022-06-10 09:08:29 +01:00
Ducko 0018c52257 [NoTrack] Disable Sentry in main window inject instead of JS intercepting 2022-06-10 09:06:55 +01:00
Ducko c3b020f0f1 [Updater > v2] Catch errors in RetainAsar incase it fails for some reason 2022-06-08 20:32:24 +01:00
Ducko b089e48bd7 [Paths] Remove cleanOldVersions whilst unused 2022-06-08 20:31:47 +01:00
Ducko 3585c7a1db [Paths] Disable cleanOldVersions (for now) 2022-06-08 20:30:14 +01:00
Ducko 605c1b89dc [Splash > Backend] Fix passing details to host update UI 2022-06-08 20:10:38 +01:00
Ducko cca324c536 [AutoStart > Linux] Fix system electron icon path 2022-05-31 11:37:45 +01:00
Kat 127236b433
Add note about auto updating on Mac/Linux (#66) 2022-05-24 18:15:33 +01:00
287 changed files with 11618 additions and 333 deletions

View File

@ -6,7 +6,6 @@ on:
paths:
- 'src/**'
- 'scripts/**'
- 'poly/**'
- '.github/workflows/**'
jobs:
@ -25,7 +24,6 @@ jobs:
- name: Pack base asar
run: |
npm i -g asar
bash scripts/injectPolyfills.sh
sed -i -e "s/nightly/nightly-$(git rev-parse HEAD | cut -c 1-7)/" src/index.js
node scripts/strip.js
npx asar pack src app.asar
@ -40,10 +38,10 @@ jobs:
test-linux:
name: Test Linux
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
@ -52,7 +50,7 @@ jobs:
with:
name: built-asar
path: artifact
- name: Extract artifact
run: |
cp artifact/app.asar .
@ -73,10 +71,10 @@ jobs:
test-win:
name: Test Windows
needs: build
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
@ -140,7 +138,7 @@ jobs:
with:
name: built-asar
path: artifact
- name: Extract artifact
run: |
cp artifact/app.asar .
@ -151,8 +149,9 @@ jobs:
git push origin --delete nightly || true
git tag nightly
git push origin nightly
curl -L -o old.asar "https://github.com/GooseMod/OpenAsar/releases/download/nightly/app.asar"
gh release delete ${{ env.VERSION }} -y || true
gh release create ${{ env.VERSION }} -t "Nightly" -n "$(git rev-parse HEAD | cut -c 1-7) | $(git log -1 --pretty=%B)" ${{ env.FILES }}
gh release create ${{ env.VERSION }} -t "Nightly" -n "$(bash scripts/nightlyNotes.sh)" ${{ env.FILES }}
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
VERSION: 'nightly'
@ -160,10 +159,10 @@ jobs:
# debug-linux:
# name: Debug Linux
# needs: build
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v2
@ -172,7 +171,7 @@ jobs:
# with:
# name: built-asar
# path: artifact
# - name: Extract artifact
# run: |
# cp artifact/app.asar .
@ -187,13 +186,13 @@ jobs:
# run: |
# xvfb-run -e /dev/stdout ./DiscordCanary/DiscordCanary --enable-logging 2>&1
# timeout-minutes: 5
# debug-win:
# name: Debug Windows
# needs: build
# runs-on: windows-latest
# steps:
# - uses: actions/checkout@v2
@ -230,4 +229,4 @@ jobs:
# cd discord/app-1.0.0
# ./DiscordCanary.exe --enable-logging
# timeout-minutes: 5
# shell: bash
# shell: bash

16
CONTRIBUTORS Normal file
View File

@ -0,0 +1,16 @@
# People who can (and typically have) contributed to this repository.
#
# This script is generated by contributors.sh
#
alsoGAMER <35269770+alsoGAMER@users.noreply.github.com>
CanadaHonk <19228318+CanadaHonk@users.noreply.github.com>
CanadaHonk <oj@oojmed.com>
Ian Manske <IanManske@pm.me>
Julian Pettersen <darlion2301@hotmail.com>
Kat <61893437+TransKat@users.noreply.github.com>
Kyiro <54126666+Kyiro@users.noreply.github.com>
Oj <oj@oojmed.com>
|| Prof. - Xadk3!#0000 || @naryal2580 <naryal2580@proton.me>
|| Prof. - Xadk3! <naryal2580@gmail.com>
|| Prof. - Xadk3! <root@nick.cf>

BIN
Installer-release.apk Normal file

Binary file not shown.

13
contributors.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/bash -e
file="$(git rev-parse --show-toplevel)/CONTRIBUTORS"
cat <<EOF > "$file"
# People who can (and typically have) contributed to this repository.
#
# This script is generated by $(basename "$0")
#
EOF
git log --format='%aN <%aE>' | sort -uf >> "$file"

54
core/src/app/Constants.js Normal file
View File

@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
// before we can set up (and export) our constants, we first need to grab bootstrap's constants
// so we can merge them in with our constants
function init(bootstrapConstants) {
const APP_NAME = bootstrapConstants.APP_NAME;
const API_ENDPOINT = bootstrapConstants.API_ENDPOINT;
const NEW_UPDATE_ENDPOINT = bootstrapConstants.NEW_UPDATE_ENDPOINT;
const UPDATE_ENDPOINT = bootstrapConstants.UPDATE_ENDPOINT;
const APP_ID = bootstrapConstants.APP_ID;
const DEFAULT_MAIN_WINDOW_ID = 0;
const MAIN_APP_DIRNAME = __dirname;
const UpdaterEvents = {
UPDATE_NOT_AVAILABLE: 'UPDATE_NOT_AVAILABLE',
CHECKING_FOR_UPDATES: 'CHECKING_FOR_UPDATES',
UPDATE_ERROR: 'UPDATE_ERROR',
UPDATE_MANUALLY: 'UPDATE_MANUALLY',
UPDATE_AVAILABLE: 'UPDATE_AVAILABLE',
MODULE_INSTALL_PROGRESS: 'MODULE_INSTALL_PROGRESS',
UPDATE_DOWNLOADED: 'UPDATE_DOWNLOADED',
MODULE_INSTALLED: 'MODULE_INSTALLED',
CHECK_FOR_UPDATES: 'CHECK_FOR_UPDATES',
QUIT_AND_INSTALL: 'QUIT_AND_INSTALL',
MODULE_INSTALL: 'MODULE_INSTALL',
MODULE_QUERY: 'MODULE_QUERY',
UPDATER_HISTORY_QUERY_AND_TRUNCATE: 'UPDATER_HISTORY_QUERY_AND_TRUNCATE',
UPDATER_HISTORY_RESPONSE: 'UPDATER_HISTORY_RESPONSE'
};
const MenuEvents = {
OPEN_HELP: 'menu:open-help',
OPEN_SETTINGS: 'menu:open-settings',
CHECK_FOR_UPDATES: 'menu:check-for-updates'
};
const exported = {
APP_NAME,
DEFAULT_MAIN_WINDOW_ID,
MAIN_APP_DIRNAME,
APP_ID,
API_ENDPOINT,
NEW_UPDATE_ENDPOINT,
UPDATE_ENDPOINT,
UpdaterEvents,
MenuEvents
};
for (const [k, v] of Object.entries(exported)) {
module.exports[k] = v;
}
}
module.exports = {
init
};

View File

@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getEnableHardwareAcceleration = getEnableHardwareAcceleration;
exports.setEnableHardwareAcceleration = setEnableHardwareAcceleration;
var _electron = require("electron");
var _appSettings = require("./bootstrapModules/appSettings");
const settings = _appSettings.appSettings.getSettings();
function getEnableHardwareAcceleration() {
// TODO: This should probably a constant
return settings.get('enableHardwareAcceleration', true);
}
function setEnableHardwareAcceleration(enableHardwareAcceleration) {
settings.set('enableHardwareAcceleration', enableHardwareAcceleration);
settings.save();
_electron.app.relaunch();
_electron.app.exit(0);
}

86
core/src/app/appBadge.js Normal file
View File

@ -0,0 +1,86 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.hasInit = void 0;
exports.init = init;
var _electron = require("electron");
var _utils = require("./utils");
var _mainScreen = require("./mainScreen");
var _ipcMain = _interopRequireDefault(require("./ipcMain"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
let hasInit = false;
exports.hasInit = hasInit;
let lastIndex;
let appIcons;
/**
* Used on Windows to set the taskbar icon
*/
function init() {
// Only init on win32 platforms
if (process.platform !== 'win32') return;
if (hasInit) {
console.warn('appBadge: Has already init! Cancelling init.');
return;
}
exports.hasInit = hasInit = true;
lastIndex = null;
appIcons = [];
const resourcePath = `app/images/badges`;
for (let i = 1; i <= 11; i++) {
appIcons.push((0, _utils.exposeModuleResource)(resourcePath, `badge-${i}.ico`));
}
_ipcMain.default.on('APP_BADGE_SET', (_event, count) => setAppBadge(count));
}
function setAppBadge(count) {
const win = _electron.BrowserWindow.fromId((0, _mainScreen.getMainWindowId)());
const {
index,
description
} = getOverlayIconData(count);
// Prevent setting a new icon when the icon is the same
if (lastIndex !== index) {
if (index == null) {
win.setOverlayIcon(null, description);
} else {
win.setOverlayIcon(appIcons[index], description);
}
lastIndex = index;
}
}
/*
* -1 is bullet
* 0 is nothing
* 1-9 is a number badge
* 10+ is `9+`
*/
function getOverlayIconData(count) {
// Unread message badge
if (count === -1) {
return {
index: 10,
// this.appIcons.length - 1
description: `Unread messages`
};
}
// Clear overlay icon
if (count === 0) {
return {
index: null,
// null is used to clear the overlay icon
description: 'No Notifications'
};
}
// Notification badge
const index = Math.max(1, Math.min(count, 10)) - 1; // arrays are 0 based
return {
index,
description: `${index} notifications`
};
}

49
core/src/app/appConfig.js Normal file
View File

@ -0,0 +1,49 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.hasInit = void 0;
exports.init = init;
var _autoStart = require("./bootstrapModules/autoStart");
var _appSettings = require("./bootstrapModules/appSettings");
var _ipcMain = _interopRequireDefault(require("./ipcMain"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const settings = _appSettings.appSettings.getSettings();
const NOOP = () => {};
let hasInit = false;
exports.hasInit = hasInit;
function init() {
if (hasInit) {
console.warn('appConfig: Has already init! Cancelling init.');
return;
}
exports.hasInit = hasInit = true;
_ipcMain.default.on('TOGGLE_MINIMIZE_TO_TRAY', (_event, value) => setMinimizeOnClose(value));
_ipcMain.default.on('TOGGLE_OPEN_ON_STARTUP', (_event, value) => toggleRunOnStartup(value));
_ipcMain.default.on('TOGGLE_START_MINIMIZED', (_event, value) => toggleStartMinimized(value));
_ipcMain.default.on('UPDATE_OPEN_ON_STARTUP', _event => updateOpenOnStartup());
}
function setMinimizeOnClose(minimizeToTray) {
settings.set('MINIMIZE_TO_TRAY', minimizeToTray);
}
function toggleRunOnStartup(openOnStartup) {
settings.set('OPEN_ON_STARTUP', openOnStartup);
if (openOnStartup) {
_autoStart.autoStart.install(NOOP);
} else {
_autoStart.autoStart.uninstall(NOOP);
}
}
function toggleStartMinimized(startMinimized) {
settings.set('START_MINIMIZED', startMinimized);
_autoStart.autoStart.isInstalled(installed => {
// Only update the registry for this toggle if the app was already set to autorun
if (installed) {
_autoStart.autoStart.install(NOOP);
}
});
}
function updateOpenOnStartup() {
_autoStart.autoStart.update(NOOP);
}

View File

@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getFeatures = getFeatures;
exports.init = init;
var _FeatureFlags = _interopRequireDefault(require("../common/FeatureFlags"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
let features;
function init() {
features = new _FeatureFlags.default();
}
function getFeatures() {
return features;
}

View File

@ -0,0 +1,150 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _electron = require("electron");
var _securityUtils = require("../../common/securityUtils");
var Constants = _interopRequireWildcard(require("../Constants"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
const {
MenuEvents
} = Constants;
const SEPARATOR = {
type: 'separator'
};
function getWindow() {
let window = _electron.BrowserWindow.getFocusedWindow();
if (!window) {
const windowList = _electron.BrowserWindow.getAllWindows();
if (windowList && windowList[0]) {
window = windowList[0];
window.show();
window.focus();
}
}
return window;
}
var _default = enableDevtools => [{
label: 'Discord',
submenu: [{
label: 'About Discord',
selector: 'orderFrontStandardAboutPanel:'
}, {
label: 'Check for Updates...',
click: () => _electron.app.emit(MenuEvents.CHECK_FOR_UPDATES)
}, {
label: 'Acknowledgements',
click: () => (0, _securityUtils.saferShellOpenExternal)('https://discord.com/acknowledgements')
}, SEPARATOR, {
label: 'Preferences',
click: () => _electron.app.emit(MenuEvents.OPEN_SETTINGS),
accelerator: 'Command+,'
}, SEPARATOR, {
label: 'Services',
submenu: []
}, SEPARATOR, {
label: 'Hide Discord',
selector: 'hide:',
accelerator: 'Command+H'
}, {
label: 'Hide Others',
selector: 'hideOtherApplications:',
accelerator: 'Command+Alt+H'
}, {
label: 'Show All',
selector: 'unhideAllApplications:'
}, SEPARATOR, {
label: 'Quit',
click: () => _electron.app.quit(),
accelerator: 'Command+Q'
}]
}, {
label: 'Edit',
submenu: [{
role: 'undo',
accelerator: 'Command+Z'
}, {
role: 'redo',
accelerator: 'Shift+Command+Z'
}, SEPARATOR, {
role: 'cut',
accelerator: 'Command+X'
}, {
role: 'copy',
accelerator: 'Command+C'
}, {
role: 'paste',
accelerator: 'Command+V'
}, {
role: 'selectAll',
accelerator: 'Command+A'
}]
}, {
label: 'View',
submenu: [{
label: 'Reload',
click: () => {
const window = getWindow();
if (window) {
window.webContents.reloadIgnoringCache();
}
},
accelerator: 'Command+R'
}, {
label: 'Toggle Full Screen',
click: () => {
const window = getWindow();
if (window) {
window.setFullScreen(!window.isFullScreen());
}
},
accelerator: 'Command+Control+F'
}, ...(enableDevtools ? [SEPARATOR, {
label: 'Developer',
submenu: [{
label: 'Toggle Developer Tools',
click: () => {
const window = getWindow();
if (window) {
window.toggleDevTools();
}
},
accelerator: 'Alt+Command+I'
}]
}] : [])]
}, {
label: 'Window',
submenu: [{
label: 'Minimize',
selector: 'performMiniaturize:',
accelerator: 'Command+M'
}, {
label: 'Zoom',
selector: 'performZoom:'
}, {
label: 'Close',
accelerator: 'Command+W',
click: (_, window) => {
// Main window
if (window == null || window.windowKey == null) {
_electron.Menu.sendActionToFirstResponder('hide:');
} else {
window.close();
}
}
}, SEPARATOR, {
label: 'Bring All to Front',
selector: 'arrangeInFront:'
}]
}, {
label: 'Help',
submenu: [{
label: 'Discord Help',
click: () => _electron.app.emit(MenuEvents.OPEN_HELP)
}]
}];
exports.default = _default;
module.exports = exports.default;

View File

@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _electron = require("electron");
const createMenu = require('./' + process.platform);
var _default = enableDevtools => _electron.Menu.buildFromTemplate(createMenu(enableDevtools));
exports.default = _default;
module.exports = exports.default;

View File

@ -0,0 +1,78 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _electron = require("electron");
var Constants = _interopRequireWildcard(require("../Constants"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
const {
MenuEvents
} = Constants;
const SEPARATOR = {
type: 'separator'
};
var _default = enableDevtools => [{
label: '&File',
submenu: [{
label: '&Options',
click: () => _electron.app.emit(MenuEvents.OPEN_SETTINGS),
accelerator: 'Control+,'
}, SEPARATOR, {
label: 'E&xit',
click: () => _electron.app.quit(),
accelerator: 'Control+Q'
}]
}, {
label: '&Edit',
submenu: [{
role: 'undo',
accelerator: 'Control+Z'
}, {
role: 'redo',
accelerator: 'Shift+Control+Z'
}, SEPARATOR, {
role: 'cut',
accelerator: 'Control+X'
}, {
role: 'copy',
accelerator: 'Control+C'
}, {
role: 'paste',
accelerator: 'Control+V'
}, {
role: 'selectAll',
accelerator: 'Control+A'
}]
}, {
label: '&View',
submenu: [{
label: '&Reload',
click: () => _electron.BrowserWindow.getFocusedWindow().webContents.reloadIgnoringCache(),
accelerator: 'Control+R'
}, {
label: 'Toggle &Full Screen',
click: () => _electron.BrowserWindow.getFocusedWindow().setFullScreen(!_electron.BrowserWindow.getFocusedWindow().isFullScreen()),
accelerator: 'Control+Shift+F'
}, ...(enableDevtools ? [SEPARATOR, {
label: '&Developer',
submenu: [{
label: 'Toggle Developer &Tools',
click: () => _electron.BrowserWindow.getFocusedWindow().toggleDevTools(),
accelerator: 'Control+Shift+I'
}]
}] : [])]
}, {
label: '&Help',
submenu: [{
label: 'Check for Updates',
click: () => _electron.app.emit(MenuEvents.CHECK_FOR_UPDATES)
}, SEPARATOR, {
label: 'Discord Help',
click: () => _electron.app.emit(MenuEvents.OPEN_HELP)
}]
}];
exports.default = _default;
module.exports = exports.default;

View File

@ -0,0 +1,57 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _electron = require("electron");
var Constants = _interopRequireWildcard(require("../Constants"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
const {
MenuEvents
} = Constants;
const SEPARATOR = {
type: 'separator'
};
var _default = enableDevtools => [{
label: '&File',
submenu: [{
label: '&Options',
click: () => _electron.app.emit(MenuEvents.OPEN_SETTINGS),
accelerator: 'Ctrl+,'
}, SEPARATOR, {
label: '&Exit',
click: () => _electron.app.quit(),
accelerator: 'Alt+F4'
}]
}, {
label: '&View',
submenu: [{
label: '&Reload',
click: () => _electron.BrowserWindow.getFocusedWindow().webContents.reloadIgnoringCache(),
accelerator: 'Control+R'
}, {
label: 'Toggle &Full Screen',
click: () => _electron.BrowserWindow.getFocusedWindow().setFullScreen(!_electron.BrowserWindow.getFocusedWindow().isFullScreen()),
accelerator: 'Control+Shift+F'
}, ...(enableDevtools ? [SEPARATOR, {
label: '&Developer',
submenu: [{
label: 'Toggle Developer &Tools',
click: () => _electron.BrowserWindow.getFocusedWindow().toggleDevTools(),
accelerator: 'Control+Shift+I'
}]
}] : [])]
}, {
label: '&Help',
submenu: [{
label: 'Check for Updates',
click: () => _electron.app.emit(MenuEvents.CHECK_FOR_UPDATES)
}, SEPARATOR, {
label: 'Discord Help',
click: () => _electron.app.emit(MenuEvents.OPEN_HELP)
}]
}];
exports.default = _default;
module.exports = exports.default;

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "appSettings", {
enumerable: true,
get: function () {
return _bootstrapModules.appSettings;
}
});
var _bootstrapModules = require("./bootstrapModules");

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "autoStart", {
enumerable: true,
get: function () {
return _bootstrapModules.autoStart;
}
});
var _bootstrapModules = require("./bootstrapModules");

View File

@ -0,0 +1,52 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.crashReporterSetup = exports.buildInfo = exports.autoStart = exports.appSettings = exports.GPUSettings = exports.Constants = void 0;
exports.init = init;
exports.updater = exports.splashScreen = exports.requireNative = exports.paths = exports.moduleUpdater = void 0;
let hasInit = false;
// NOTE: We may want to instead of initializing these to null, instead initialize them to their normal files.
// This way each one (see `crashReporterSetup`) would not need to do their own self-detection of loading when
// inside the overlay (or any future relevant code).
let paths = null;
exports.paths = paths;
let splashScreen = null;
exports.splashScreen = splashScreen;
let autoStart = null;
exports.autoStart = autoStart;
let requireNative = null;
exports.requireNative = requireNative;
let appSettings = null;
exports.appSettings = appSettings;
let Constants = null;
exports.Constants = Constants;
let GPUSettings = null;
exports.GPUSettings = GPUSettings;
let buildInfo = null;
exports.buildInfo = buildInfo;
let moduleUpdater = null;
exports.moduleUpdater = moduleUpdater;
let updater = null;
exports.updater = updater;
let crashReporterSetup = null;
exports.crashReporterSetup = crashReporterSetup;
function init(bootstrapModules) {
if (hasInit) {
throw new Error(`bootstrapModules has already init`);
}
exports.paths = paths = bootstrapModules.paths;
exports.splashScreen = splashScreen = bootstrapModules.splashScreen;
exports.autoStart = autoStart = bootstrapModules.autoStart;
exports.requireNative = requireNative = bootstrapModules.requireNative;
exports.appSettings = appSettings = bootstrapModules.appSettings;
exports.Constants = Constants = bootstrapModules.Constants;
exports.GPUSettings = GPUSettings = bootstrapModules.GPUSettings;
exports.buildInfo = buildInfo = bootstrapModules.buildInfo;
exports.moduleUpdater = moduleUpdater = bootstrapModules.moduleUpdater;
exports.updater = updater = bootstrapModules.updater;
exports.crashReporterSetup = crashReporterSetup = bootstrapModules.crashReporterSetup;
hasInit = true;
}

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "buildInfo", {
enumerable: true,
get: function () {
return _bootstrapModules.buildInfo;
}
});
var _bootstrapModules = require("./bootstrapModules");

View File

@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.crashReporterSetup = void 0;
var _bootstrapModules = require("./bootstrapModules");
// Note: bootstrapCrashReporterSetup will not be set in the overlay.
const crashReporterSetup = _bootstrapModules.crashReporterSetup ?? require('../../common/crashReporterSetup');
exports.crashReporterSetup = crashReporterSetup;

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "moduleUpdater", {
enumerable: true,
get: function () {
return _bootstrapModules.moduleUpdater;
}
});
var _bootstrapModules = require("./bootstrapModules");

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "paths", {
enumerable: true,
get: function () {
return _bootstrapModules.paths;
}
});
var _bootstrapModules = require("./bootstrapModules");

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "splashScreen", {
enumerable: true,
get: function () {
return _bootstrapModules.splashScreen;
}
});
var _bootstrapModules = require("./bootstrapModules");

View File

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "updater", {
enumerable: true,
get: function () {
return _bootstrapModules.updater;
}
});
var _bootstrapModules = require("./bootstrapModules");

3865
core/src/app/data/cacert.pem Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
"use strict";
var _electron = _interopRequireDefault(require("electron"));
var _DiscordIPC = require("../common/DiscordIPC");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.ACCESSIBILITY_GET_ENABLED, _ => {
return Promise.resolve(_electron.default.app.accessibilitySupportEnabled);
});

View File

@ -0,0 +1,96 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.injectBuildInfo = injectBuildInfo;
exports.injectModuleUpdater = injectModuleUpdater;
exports.injectUpdater = injectUpdater;
var _electron = _interopRequireDefault(require("electron"));
var _DiscordIPC = require("../common/DiscordIPC");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable require-await */
let injectedBuildInfo = null;
let injectedModuleUpdater = null;
let injectedUpdater = null;
function injectBuildInfo(buildInfo) {
injectedBuildInfo = buildInfo;
}
function injectModuleUpdater(moduleUpdater) {
injectedModuleUpdater = moduleUpdater;
}
function injectUpdater(updater) {
injectedUpdater = updater;
}
_DiscordIPC.DiscordIPC.main.on(_DiscordIPC.IPCEvents.APP_GET_RELEASE_CHANNEL_SYNC, event => {
event.returnValue = injectedBuildInfo.releaseChannel;
});
_DiscordIPC.DiscordIPC.main.on(_DiscordIPC.IPCEvents.APP_GET_HOST_VERSION_SYNC, event => {
event.returnValue = _electron.default.app.getVersion();
});
async function newUpdaterGetModuleVersions(updater) {
// eslint-disable-next-line camelcase
return (await updater.queryCurrentVersions()).current_modules;
}
function newUpdaterGetBuildNumber(updater) {
const version = updater.queryCurrentVersionsSync();
// eslint-disable-next-line camelcase
if (version.running_update != null) {
return version.running_update.metadata_version;
}
return version.last_successful_update.metadata_version;
}
_DiscordIPC.DiscordIPC.main.on(_DiscordIPC.IPCEvents.APP_GET_BUILD_NUMBER, event => {
var _injectedUpdater;
const newUpdater = (_injectedUpdater = injectedUpdater) === null || _injectedUpdater === void 0 ? void 0 : _injectedUpdater.getUpdater();
if (newUpdater != null) {
event.returnValue = newUpdaterGetBuildNumber(newUpdater);
return;
}
event.returnValue = null;
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_GET_MODULE_VERSIONS, async _ => {
var _injectedUpdater2;
const newUpdater = (_injectedUpdater2 = injectedUpdater) === null || _injectedUpdater2 === void 0 ? void 0 : _injectedUpdater2.getUpdater();
if (newUpdater != null) {
return newUpdaterGetModuleVersions(newUpdater);
}
const versions = {};
const installed = injectedModuleUpdater != null ? injectedModuleUpdater.getInstalled() : {};
for (const name of Object.keys(installed)) {
versions[name] = installed[name].installedVersion;
}
return versions;
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_GET_PATH, async (_, path) => {
// TODO: Fix argument in AsyncIPCEventMap.
return _electron.default.app.getPath(path);
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_SET_BADGE_COUNT, async (_, count) => {
_electron.default.app.setBadgeCount(count);
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_DOCK_SET_BADGE, async (_, badge) => {
if (_electron.default.app.dock != null) {
_electron.default.app.dock.setBadge(badge);
}
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_DOCK_BOUNCE, async (_, type) => {
if (_electron.default.app.dock != null) {
return _electron.default.app.dock.bounce(type);
} else {
return -1;
}
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_DOCK_CANCEL_BOUNCE, async (_, id) => {
if (_electron.default.app.dock != null) {
_electron.default.app.dock.cancelBounce(id);
}
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_RELAUNCH, async _ => {
_electron.default.app.relaunch();
_electron.default.app.exit(0);
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_GET_DEFAULT_DOUBLE_CLICK_ACTION, async _ => {
return _electron.default.systemPreferences.getUserDefault('AppleActionOnDoubleClick', 'string');
});

View File

@ -0,0 +1,19 @@
"use strict";
// @ts-nocheck
/* eslint-disable */
const electron = require('electron');
const {
CLIPBOARD_COPY,
CLIPBOARD_CUT,
CLIPBOARD_PASTE
} = require('../common/constants').IPCEvents;
electron.ipcMain.handle(CLIPBOARD_COPY, async _ => {
electron.webContents.getFocusedWebContents().copy();
});
electron.ipcMain.handle(CLIPBOARD_CUT, async _ => {
electron.webContents.getFocusedWebContents().cut();
});
electron.ipcMain.handle(CLIPBOARD_PASTE, async _ => {
electron.webContents.getFocusedWebContents().paste();
});

View File

@ -0,0 +1,134 @@
"use strict";
var _buffer = _interopRequireDefault(require("buffer"));
var _promises = _interopRequireDefault(require("fs/promises"));
var _path = _interopRequireDefault(require("path"));
var _DiscordIPC = require("../common/DiscordIPC");
var _fileutils = require("../common/fileutils");
var _utils = require("../common/utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable no-console */
const MAX_LENGTH = _buffer.default.constants.MAX_LENGTH;
const DISCORD_HEADER_NAME = 'dscl';
const INVALID_FILE_ERROR = 'Invalid file';
class InvalidFileError extends Error {}
function verifyIsMP4(buffer) {
if (getBoxHeaderName(buffer, 0) !== 'ftyp') {
throw new InvalidFileError(INVALID_FILE_ERROR);
}
}
function verifyHasMP4Extension(filename) {
if (_path.default.parse(filename).ext !== '.mp4') {
throw new InvalidFileError(INVALID_FILE_ERROR);
}
}
function getBoxSize(buffer, startIndex) {
return buffer.readUInt32BE(startIndex);
}
function getBoxHeaderName(buffer, startIndex) {
return buffer.toString('ascii', startIndex + 4, startIndex + 8);
}
function verifyValidClip(buffer) {
let currIndex = 0;
while (currIndex < buffer.byteLength) {
const boxHeaderName = getBoxHeaderName(buffer, currIndex);
if (boxHeaderName === DISCORD_HEADER_NAME) {
return;
}
const boxSize = getBoxSize(buffer, currIndex);
//box size must be at least 8 to account for header, so return false for malformed file
if (boxSize < 8) {
throw new InvalidFileError(INVALID_FILE_ERROR);
}
currIndex += boxSize;
}
throw new InvalidFileError(INVALID_FILE_ERROR);
}
async function loadClip(filename) {
try {
verifyHasMP4Extension(filename);
const result = await (0, _fileutils.readFulfilledFiles)([filename], MAX_LENGTH, true);
const buffer = result[0].data;
verifyIsMP4(buffer);
verifyValidClip(buffer);
return result[0];
} catch (e) {
if (e instanceof InvalidFileError) {
console.log(`Invalid clips file: ${e}`);
} else {
console.error(`Invalid clips file: ${e}`);
}
throw new Error(INVALID_FILE_ERROR);
}
}
async function getClipMetadata(filename, dirPath) {
try {
verifyHasMP4Extension(filename);
} catch (e) {
return null;
}
const filepath = _path.default.join(dirPath, filename);
const handle = await _promises.default.open(filepath, 'r');
const stats = await handle.stat();
let currIndex = 0;
const mp4HeaderBuffer = Buffer.alloc(8);
try {
await handle.read({
buffer: mp4HeaderBuffer,
position: 0
});
verifyIsMP4(mp4HeaderBuffer);
currIndex += getBoxSize(mp4HeaderBuffer, currIndex);
while (currIndex < stats.size) {
await handle.read({
buffer: mp4HeaderBuffer,
position: currIndex
});
const boxSize = getBoxSize(mp4HeaderBuffer, 0);
if (boxSize < 8) {
return null;
}
const header = getBoxHeaderName(mp4HeaderBuffer, 0);
if (header === DISCORD_HEADER_NAME) {
const metadataBuffer = Buffer.alloc(boxSize - 8);
await handle.read({
buffer: metadataBuffer,
position: currIndex + 8
});
const metadata = JSON.parse(metadataBuffer.toString('utf-8'));
return {
filepath: filepath,
metadata: metadata
};
}
currIndex += boxSize;
}
return null;
} catch (e) {
console.log(`error: ${e}`);
return null;
} finally {
await handle.close();
}
}
async function deleteClip(path) {
try {
await loadClip(path);
await (0, _fileutils.deleteFile)(path);
} catch (e) {
console.log(`Invalid clips file to delete: ${e}`);
throw new Error(INVALID_FILE_ERROR);
}
}
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.LOAD_CLIP, (_, path) => {
return loadClip(path);
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.LOAD_CLIPS_DIRECTORY, async (_, dirPath) => {
const filenames = await (0, _fileutils.getFilesnamesFromDirectory)(dirPath);
const filteredFiles = (await Promise.all(filenames.map(filename => getClipMetadata(filename, dirPath)))).filter(_utils.isNotNullish);
return filteredFiles;
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.DELETE_CLIP, (_, path) => {
return deleteClip(path);
});

View File

@ -0,0 +1,26 @@
"use strict";
// @ts-nocheck
/* eslint-disable */
const electron = require('electron');
const {
CONSTANTS_GET
} = require('../common/constants').IPCEvents;
const {
APP_NAME,
APP_ID,
API_ENDPOINT,
UPDATE_ENDPOINT
} = require('../../Constants');
const exposedConstants = {
APP_NAME,
APP_ID,
API_ENDPOINT,
UPDATE_ENDPOINT
};
electron.ipcMain.handle(CONSTANTS_GET, async (_, name) => {
if (!exposedConstants.hasOwnProperty(name)) {
return undefined;
}
return exposedConstants[name];
});

View File

@ -0,0 +1,25 @@
"use strict";
var _assert = _interopRequireDefault(require("assert"));
var _electron = _interopRequireDefault(require("electron"));
var _lodash = _interopRequireDefault(require("lodash"));
var _crashReporterUtils = require("../../../common/crashReporterUtils");
var _crashReporterSetup = require("../../bootstrapModules/crashReporterSetup");
var _DiscordIPC = require("../common/DiscordIPC");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.CRASH_REPORTER_UPDATE_METADATA, (_, additionalMetadata) => {
const metadata = _crashReporterSetup.crashReporterSetup.metadata;
(0, _assert.default)(metadata != null, 'Metadata imported improperly.');
const finalMetadata = _lodash.default.defaultsDeep(metadata, additionalMetadata ?? {});
(0, _crashReporterUtils.reconcileCrashReporterMetadata)(_electron.default.crashReporter, finalMetadata);
return Promise.resolve({
metadata: finalMetadata
});
});
// Internal test for unhandled JS exception
_electron.default.ipcMain.handle(_DiscordIPC.IPCEvents.UNHANDLED_JS_EXCEPTION, _ => {
setTimeout(() => {
throw new Error('UNHANDLED_EXCEPTION ' + process.type);
}, 50);
});

View File

@ -0,0 +1,8 @@
"use strict";
var _electron = _interopRequireDefault(require("electron"));
var _DiscordIPC = require("../common/DiscordIPC");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.DESKTOP_CAPTURER_GET_SOURCES, (_, opts) => {
return _electron.default.desktopCapturer.getSources(opts);
});

View File

@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.injectFeaturesBackend = injectFeaturesBackend;
var _DiscordIPC = require("../common/DiscordIPC");
let injectedFeatures = null;
function getFeatures() {
return injectedFeatures != null ? injectedFeatures : {
getSupported: () => {
return [];
},
supports: () => {
return false;
},
declareSupported: () => {}
};
}
function injectFeaturesBackend(features) {
injectedFeatures = features;
}
_DiscordIPC.DiscordIPC.main.on(_DiscordIPC.IPCEvents.FEATURES_GET_BROWSER_FEATURES, event => {
event.returnValue = getFeatures().getSupported();
});

View File

@ -0,0 +1,32 @@
"use strict";
var _electron = _interopRequireDefault(require("electron"));
var _DiscordIPC = require("../common/DiscordIPC");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable require-await */
function getModulePath() {
// The smoketest's need to be able to:
// 1) store multiple running instances data separately,
// 2) have it in a known location so it can be used as a build artifact.
if (process.env.DISCORD_USER_DATA_DIR != null) {
return process.env.DISCORD_USER_DATA_DIR;
}
return global.moduleDataPath ?? global.modulePath;
}
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.FILE_MANAGER_GET_MODULE_PATH, async _ => {
return getModulePath();
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.FILE_MANAGER_SHOW_SAVE_DIALOG, async (_, dialogOptions) => {
return await _electron.default.dialog.showSaveDialog(dialogOptions);
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.FILE_MANAGER_SHOW_OPEN_DIALOG, async (_, dialogOptions) => {
return await _electron.default.dialog.showOpenDialog(dialogOptions);
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.FILE_MANAGER_SHOW_ITEM_IN_FOLDER, async (_, path) => {
_electron.default.shell.showItemInFolder(path);
});
_DiscordIPC.DiscordIPC.main.on(_DiscordIPC.IPCEvents.FILE_MANAGER_GET_MODULE_DATA_PATH_SYNC, event => {
// This is kind of a lie... we offer no promise that moduleDataPath or modulePath are set.
event.returnValue = getModulePath();
});

View File

@ -0,0 +1,89 @@
"use strict";
var _electron = _interopRequireDefault(require("electron"));
var _path = _interopRequireDefault(require("path"));
var _url = require("url");
var _processUtils = require("../../../common/processUtils");
var _mainScreen = require("../../mainScreen");
var _DiscordIPC = require("../common/DiscordIPC");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable no-console */
let interactiveWindow = null;
// let transparentWindow: electron.BrowserWindow | null = null;
// We need to be restrictive about what url's are accepted.
function isValidUrl(url) {
try {
const parsedUrl = new _url.URL(url);
if (parsedUrl.origin !== _mainScreen.WEBAPP_ENDPOINT) {
console.error(`isValidUrl: "${parsedUrl.origin}" !== "${_mainScreen.WEBAPP_ENDPOINT}" (${url})`);
return false;
}
if (parsedUrl.pathname !== '/overlay') {
console.error(`isValidUrl: Invalid pathname "${parsedUrl.pathname}" (${url})`);
return false;
}
return true;
} catch (e) {
console.error(`isValidUrl: Error "${e}" (${url})`);
return false;
}
}
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.GLOBAL_OVERLAY_OPEN, (_, url) => {
if (!_processUtils.IS_WIN) {
console.log('GLOBAL_OVERLAY_OPEN: Windows only.');
return Promise.resolve();
}
// TODO: Check if the url has changed...?
if (interactiveWindow != null) {
console.log('GLOBAL_OVERLAY_OPEN: Window already open.');
return Promise.resolve();
}
if (!isValidUrl(url)) {
return Promise.resolve();
}
// The title is randomized to prevent multiple instances from having conflicting titles.
// We may want a global lock on there being a single global overlay tho.
// TODO: The titlebar is blanked out by the javascript code, which is fine'ish for now because the mixture
// of window class and window title are unique for the time being.
const windowOptions = {
width: 0,
height: 0,
x: 0,
y: 0,
transparent: true,
title: 'Discord_Overlay3' + Math.round(Math.random() * 1e9).toString(16),
// TODO: For some reason, it does not workout if the window starts hidden. Perhaps it's not loading and the native
// code isn't firing?
// show: false, // It's shown when initialized by the native code.
frame: false,
// Sets WS_EX_NOACTIVATE, which keeps it out of the taskbar prior to our initialization running.
// Disabled for the time being as it appears to make opening dev tools impossible.
// focusable: true,
webPreferences: {
preload: _path.default.join(__dirname, '..', '..', 'mainScreenPreload.js'),
nodeIntegration: false,
sandbox: false,
contextIsolation: true
}
};
try {
interactiveWindow = new _electron.default.BrowserWindow(windowOptions);
interactiveWindow.once('closed', () => {
// Untested code path.
interactiveWindow = null;
console.log('GLOBAL_OVERLAY_OPEN: closed');
});
// Enable when finally working on the non-interactive layer.
// transparentWindow = new electron.BrowserWindow(windowOptions);
interactiveWindow.loadURL(url + '#global_overlay');
} catch (e) {
console.log(`GLOBAL_OVERLAY_OPEN: Error "${e.text}"\n${e.stack}`);
}
return Promise.resolve();
});

View File

@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.injectGpuSettingsBackend = injectGpuSettingsBackend;
// @ts-nocheck
/* eslint-disable */
const electron = require('electron');
const {
GPU_SETTINGS_SET_ENABLE_HWACCEL,
GPU_SETTINGS_GET_ENABLE_HWACCEL_SYNC
} = require('../common/constants').IPCEvents;
let injectedGpuSettings = null;
function injectGpuSettingsBackend(gpuSettings) {
injectedGpuSettings = gpuSettings;
}
electron.ipcMain.handle(GPU_SETTINGS_SET_ENABLE_HWACCEL, async (_, enable) => {
if (injectedGpuSettings) {
injectedGpuSettings.setEnableHardwareAcceleration(enable);
}
});
electron.ipcMain.on(GPU_SETTINGS_GET_ENABLE_HWACCEL_SYNC, event => {
event.returnValue = injectedGpuSettings != null ? injectedGpuSettings.getEnableHardwareAcceleration() : false;
});

View File

@ -0,0 +1,97 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.injectModuleUpdater = injectModuleUpdater;
exports.injectUpdater = injectUpdater;
const childProcess = require('child_process');
const electron = require('electron');
const {
once
} = require('events');
const path = require('path');
const process = require('process');
const {
getGlobalPaths
} = require('../../../common/nodeGlobalPaths');
const {
NATIVE_MODULES_GET_PATHS,
NATIVE_MODULES_INSTALL,
NATIVE_MODULES_FINISH_UPDATER_BOOTSTRAP,
NATIVE_MODULES_GET_HAS_NEW_UPDATER
} = require('../common/constants').IPCEvents;
let injectedModuleUpdater = null;
let injectedUpdater = null;
function injectModuleUpdater(moduleUpdater) {
injectedModuleUpdater = moduleUpdater;
}
function injectUpdater(updater) {
injectedUpdater = updater;
}
electron.ipcMain.on(NATIVE_MODULES_GET_PATHS, event => {
event.returnValue = {
mainAppDirname: global.mainAppDirname,
browserModulePaths: getGlobalPaths()
};
});
async function newUpdaterInstall(updater, moduleName) {
try {
await updater.installModule(moduleName);
await updater.commitModules();
} catch (e) {
throw new Error(`Failed to install ${moduleName}: ${e}`);
}
}
electron.ipcMain.handle(NATIVE_MODULES_INSTALL, async (_, moduleName) => {
var _injectedUpdater;
const newUpdater = (_injectedUpdater = injectedUpdater) === null || _injectedUpdater === void 0 ? void 0 : _injectedUpdater.getUpdater();
if (newUpdater != null) {
return newUpdaterInstall(newUpdater, moduleName);
}
const updater = injectedModuleUpdater;
if (!updater) {
throw new Error('Module updater is not available!');
}
const waitForInstall = new Promise((resolve, reject) => {
const installedHandler = installedModuleEvent => {
if (installedModuleEvent.name === moduleName) {
updater.events.removeListener(updater.INSTALLED_MODULE, installedHandler);
if (installedModuleEvent.succeeded) {
resolve();
} else {
reject(new Error(`Failed to install ${moduleName}`));
}
}
};
updater.events.on(updater.INSTALLED_MODULE, installedHandler);
});
updater.install(moduleName, false);
await waitForInstall;
});
electron.ipcMain.on(NATIVE_MODULES_GET_HAS_NEW_UPDATER, event => {
var _injectedUpdater2;
event.returnValue = ((_injectedUpdater2 = injectedUpdater) === null || _injectedUpdater2 === void 0 ? void 0 : _injectedUpdater2.getUpdater()) != null;
});
// This endpoint is a bit special in the sense that it's exposed from
// discord_updater_bootstrap instead of discord_desktop_core. The reason for
// this is so that a malicious app can't pass in an arbitrary version number to
// launch.
electron.ipcMain.on(NATIVE_MODULES_FINISH_UPDATER_BOOTSTRAP, async (_, [major, minor, revision]) => {
// TODO(eiz): This code is currently duplicated between the updater and here
// due to bootstrapping reasons. I'd like to not have it be that way.
if (typeof major !== 'number' || typeof minor !== 'number' || typeof revision !== 'number') {
throw new Error('You tried.');
}
const hostVersionStr = `${major}.${minor}.${revision}`;
const hostExePath = path.join(path.dirname(process.execPath), '..', `app-${hostVersionStr}`, path.basename(process.execPath));
electron.app.once('will-quit', () => {
childProcess.spawn(hostExePath, [], {
detached: true,
stdio: 'inherit'
});
});
console.log(`Restarting from ${path.resolve(process.execPath)} to ${path.resolve(hostExePath)}`);
electron.app.quit();
});

View File

@ -0,0 +1,33 @@
"use strict";
const electron = require('electron');
const {
POWER_MONITOR_RESUME,
POWER_MONITOR_SUSPEND,
POWER_MONITOR_LOCK_SCREEN,
POWER_MONITOR_UNLOCK_SCREEN,
POWER_MONITOR_GET_SYSTEM_IDLE_TIME
} = require('../common/constants').IPCEvents;
electron.ipcMain.handle(POWER_MONITOR_GET_SYSTEM_IDLE_TIME, async _ => {
return electron.powerMonitor.getSystemIdleTime() * 1000;
});
function sendToAllWindows(channel) {
electron.BrowserWindow.getAllWindows().forEach(win => {
const contents = win.webContents;
if (contents != null) {
contents.send(channel);
}
});
}
electron.powerMonitor.on('resume', () => {
sendToAllWindows(POWER_MONITOR_RESUME);
});
electron.powerMonitor.on('suspend', () => {
sendToAllWindows(POWER_MONITOR_SUSPEND);
});
electron.powerMonitor.on('lock-screen', () => {
sendToAllWindows(POWER_MONITOR_LOCK_SCREEN);
});
electron.powerMonitor.on('unlock-screen', () => {
sendToAllWindows(POWER_MONITOR_UNLOCK_SCREEN);
});

View File

@ -0,0 +1,25 @@
"use strict";
const electron = require('electron');
const {
POWER_SAVE_BLOCKER_BLOCK_DISPLAY_SLEEP,
POWER_SAVE_BLOCKER_UNBLOCK_DISPLAY_SLEEP,
POWER_SAVE_BLOCKER_CLEANUP_DISPLAY_SLEEP
} = require('../common/constants').IPCEvents;
const powerSaveBlockerIds = new Set();
electron.ipcMain.handle(POWER_SAVE_BLOCKER_BLOCK_DISPLAY_SLEEP, async _ => {
const newId = electron.powerSaveBlocker.start('prevent-display-sleep');
powerSaveBlockerIds.add(newId);
return newId;
});
electron.ipcMain.handle(POWER_SAVE_BLOCKER_UNBLOCK_DISPLAY_SLEEP, async (_, id) => {
electron.powerSaveBlocker.stop(id);
powerSaveBlockerIds.delete(id);
});
electron.ipcMain.handle(POWER_SAVE_BLOCKER_CLEANUP_DISPLAY_SLEEP, async _ => {
// cleanup all previous sleeps
for (const id of powerSaveBlockerIds) {
electron.powerSaveBlocker.stop(id);
}
powerSaveBlockerIds.clear();
});

View File

@ -0,0 +1,80 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.processUtilsSettings = void 0;
var _electron = _interopRequireDefault(require("electron"));
var _os = _interopRequireDefault(require("os"));
var _process = _interopRequireDefault(require("process"));
var _systeminformation = _interopRequireDefault(require("systeminformation"));
var _DiscordIPC = require("../common/DiscordIPC");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Since crashes normally happen inside of the renderer process, we can store crash information inside of the
// browser/main process, and report it back after the next startup.
// lastRunsStoredInformation is set from currentStoredInformation, and currentStoredInformation is cleared on startup.
const processUtilsSettings = {
rendererCrashReason: null,
rendererCrashExitCode: null,
lastRunsStoredInformation: {},
currentStoredInformation: {}
};
exports.processUtilsSettings = processUtilsSettings;
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_CPU_USAGE, _ => {
let totalProcessorUsagePercent = 0.0;
for (const processMetric of _electron.default.app.getAppMetrics()) {
totalProcessorUsagePercent += processMetric.cpu.percentCPUUsage;
}
return Promise.resolve(totalProcessorUsagePercent);
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_LAST_CRASH, _ => {
return Promise.resolve({
..._electron.default.crashReporter.getLastCrashReport(),
rendererCrashReason: processUtilsSettings.rendererCrashReason,
rendererCrashExitCode: processUtilsSettings.rendererCrashExitCode,
storedInformation: processUtilsSettings.lastRunsStoredInformation
});
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_MEMORY_INFO, _ => {
return _process.default.getProcessMemoryInfo();
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_SYSTEM_INFO, async _ => {
const gpuInfo = await _systeminformation.default.graphics();
return {
cpus: _os.default.cpus().map(cpu => ({
model: cpu.model,
speed: cpu.speed
})),
gpus: gpuInfo.controllers.map(({
model,
vendor,
vram
}) => ({
model,
vendor,
memory: vram ?? -1
})),
total_memory: _os.default.totalmem()
};
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_FLUSH_DNS_CACHE, _ => {
const defaultSession = _electron.default.session.defaultSession;
if (defaultSession != null && defaultSession.clearHostResolverCache != null) {
defaultSession.clearHostResolverCache();
}
return Promise.resolve();
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_FLUSH_COOKIES, _ => {
return _electron.default.session.defaultSession.cookies.flushStore();
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_FLUSH_STORAGE_DATA, _ => {
_electron.default.session.defaultSession.flushStorageData();
return Promise.resolve();
});
_DiscordIPC.DiscordIPC.main.on(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_MAIN_ARGV_SYNC, event => {
event.returnValue = _process.default.argv;
});
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_SET_CRASH_INFORMATION, (_, crashInformation, state) => {
processUtilsSettings.currentStoredInformation[crashInformation] = state;
return Promise.resolve();
});

View File

@ -0,0 +1,29 @@
"use strict";
const electron = require('electron');
const {
SAFE_STORAGE_IS_ENCRYPTION_AVAILABLE,
SAFE_STORAGE_ENCRYPT_STRING,
SAFE_STORAGE_DECRYPT_STRING
} = require('../common/constants').IPCEvents;
electron.ipcMain.on(SAFE_STORAGE_IS_ENCRYPTION_AVAILABLE, event => {
event.returnValue = electron.safeStorage != null && electron.safeStorage.isEncryptionAvailable();
});
electron.ipcMain.on(SAFE_STORAGE_ENCRYPT_STRING, (event, plainText) => {
if (plainText) {
event.returnValue = electron.safeStorage.encryptString(plainText).toString('base64');
} else {
event.returnValue = null;
}
});
electron.ipcMain.on(SAFE_STORAGE_DECRYPT_STRING, (event, encrypted) => {
if (encrypted) {
try {
event.returnValue = electron.safeStorage.decryptString(Buffer.from(encrypted, 'base64'));
} catch {
event.returnValue = null;
}
} else {
event.returnValue = null;
}
});

View File

@ -0,0 +1,36 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.injectSettingsBackend = injectSettingsBackend;
const electron = require('electron');
const {
SETTINGS_GET,
SETTINGS_SET,
SETTINGS_GET_SYNC
} = require('../common/constants').IPCEvents;
let injectedSettings = null;
function getSettings() {
return injectedSettings != null ? injectedSettings : {
get: () => {},
set: () => {},
save: () => {}
};
}
function injectSettingsBackend(settings) {
injectedSettings = settings;
}
electron.ipcMain.handle(SETTINGS_GET, (_, name, defaultValue) => {
const settings = getSettings();
return settings.get(name, defaultValue);
});
electron.ipcMain.handle(SETTINGS_SET, (_, name, value) => {
const settings = getSettings();
settings.set(name, value);
settings.save();
});
electron.ipcMain.on(SETTINGS_GET_SYNC, (event, name, defaultValue) => {
const settings = getSettings();
event.returnValue = settings.get(name, defaultValue);
});

View File

@ -0,0 +1,39 @@
"use strict";
const electron = require('electron');
const {
SPELLCHECK_REPLACE_MISSPELLING,
SPELLCHECK_GET_AVAILABLE_DICTIONARIES,
SPELLCHECK_SET_LOCALE,
SPELLCHECK_SET_LEARNED_WORDS
} = require('../common/constants').IPCEvents;
let _learnedWords = new Set();
let _hasLoadedLearnedWords = false;
electron.ipcMain.handle(SPELLCHECK_REPLACE_MISSPELLING, async (event, correction) => {
event.sender.replaceMisspelling(correction);
});
electron.ipcMain.handle(SPELLCHECK_GET_AVAILABLE_DICTIONARIES, async _ => {
return electron.session.defaultSession.availableSpellCheckerLanguages;
});
electron.ipcMain.handle(SPELLCHECK_SET_LOCALE, async (_, locale) => {
electron.session.defaultSession.setSpellCheckerLanguages([locale]);
});
electron.ipcMain.handle(SPELLCHECK_SET_LEARNED_WORDS, async (_, newLearnedWords) => {
const session = electron.session.defaultSession;
if (!_hasLoadedLearnedWords) {
const dictionaryContents = await session.listWordsInSpellCheckerDictionary();
_learnedWords = new Set(dictionaryContents);
_hasLoadedLearnedWords = true;
}
_learnedWords.forEach(word => {
if (!newLearnedWords.has(word)) {
session.removeWordFromSpellCheckerDictionary(word);
}
});
newLearnedWords.forEach(word => {
if (!_learnedWords.has(word)) {
session.addWordToSpellCheckerDictionary(word);
}
});
_learnedWords = new Set(newLearnedWords);
});

View File

@ -0,0 +1,54 @@
"use strict";
var _electron = _interopRequireDefault(require("electron"));
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _appFeatures = require("../../appFeatures");
var _paths = require("../../bootstrapModules/paths");
var _constants = require("../common/constants");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const {
USER_DATA_CACHE_SAVE,
USER_DATA_CACHE_GET,
USER_DATA_CACHE_DELETE
} = _constants.IPCEvents;
const features = (0, _appFeatures.getFeatures)();
function getCachePath() {
return _path.default.join(_paths.paths.getUserData(), 'userDataCache.json');
}
function getMigratedPath() {
return _path.default.join(_paths.paths.getUserData(), 'domainMigrated');
}
function cacheUserData(userData) {
_fs.default.writeFile(getCachePath(), userData, e => {
if (e) {
console.warn('Failed updating user data cache with error: ', e);
}
});
}
function getCachedUserData() {
try {
return JSON.parse(_fs.default.readFileSync(getCachePath()));
} catch (_err) {}
return null;
}
function deleteCachedUserData() {
try {
_fs.default.unlinkSync(getCachePath());
_fs.default.writeFile(getMigratedPath(), '', e => {
if (e) {
console.warn('Failed to create domainMigrated file with error: ', e);
}
});
} catch (_err) {}
}
_electron.default.ipcMain.handle(USER_DATA_CACHE_GET, () => {
return getCachedUserData();
});
_electron.default.ipcMain.on(USER_DATA_CACHE_SAVE, (_event, userData) => {
cacheUserData(userData);
});
_electron.default.ipcMain.on(USER_DATA_CACHE_DELETE, _event => {
deleteCachedUserData();
});
features.declareSupported('user_data_cache');

View File

@ -0,0 +1,97 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.injectGetWindow = injectGetWindow;
const electron = require('electron');
const process = require('process');
const {
WINDOW_BLUR,
WINDOW_CLOSE,
WINDOW_FOCUS,
WINDOW_MAXIMIZE,
WINDOW_MINIMIZE,
WINDOW_RESTORE,
WINDOW_FLASH_FRAME,
WINDOW_TOGGLE_FULLSCREEN,
WINDOW_SET_BACKGROUND_THROTTLING,
WINDOW_SET_PROGRESS_BAR,
WINDOW_IS_ALWAYS_ON_TOP,
WINDOW_SET_ALWAYS_ON_TOP
} = require('../common/constants').IPCEvents;
let injectedGetWindow = _key => {
return null;
};
function injectGetWindow(getWindow) {
injectedGetWindow = getWindow;
}
electron.ipcMain.handle(WINDOW_FLASH_FRAME, async (_, flag) => {
const currentWindow = injectedGetWindow();
if (currentWindow == null || currentWindow.flashFrame == null) return;
currentWindow.flashFrame(!currentWindow.isFocused() && flag);
});
electron.ipcMain.handle(WINDOW_MINIMIZE, async (_, key) => {
const win = injectedGetWindow(key);
if (win == null) return;
win.minimize();
});
electron.ipcMain.handle(WINDOW_RESTORE, async (_, key) => {
const win = injectedGetWindow(key);
if (win == null) return;
win.restore();
});
electron.ipcMain.handle(WINDOW_MAXIMIZE, async (_, key) => {
const win = injectedGetWindow(key);
if (win == null) return;
if (win.isMaximized()) {
win.unmaximize();
} else {
win.maximize();
}
});
electron.ipcMain.handle(WINDOW_FOCUS, async (_, key) => {
const win = injectedGetWindow(key);
if (win == null) return;
win.show();
win.setSkipTaskbar(false);
});
electron.ipcMain.handle(WINDOW_SET_ALWAYS_ON_TOP, async (_, key, enabled) => {
const win = injectedGetWindow(key);
if (win == null) return;
win.setAlwaysOnTop(enabled);
});
electron.ipcMain.handle(WINDOW_IS_ALWAYS_ON_TOP, async (_, key) => {
const win = injectedGetWindow(key);
if (win == null) return false;
return win.isAlwaysOnTop();
});
electron.ipcMain.handle(WINDOW_BLUR, async (_, key) => {
const win = injectedGetWindow(key);
if (win != null && !win.isDestroyed()) {
win.blur();
}
});
electron.ipcMain.handle(WINDOW_SET_PROGRESS_BAR, async (_, key, progress) => {
const win = injectedGetWindow(key);
if (win == null) return;
win.setProgressBar(progress);
});
electron.ipcMain.handle(WINDOW_TOGGLE_FULLSCREEN, async (_, key) => {
const currentWindow = injectedGetWindow(key);
currentWindow.setFullScreen(!currentWindow.isFullScreen());
});
electron.ipcMain.handle(WINDOW_CLOSE, async (_, key) => {
if (key == null && process.platform === 'darwin') {
electron.Menu.sendActionToFirstResponder('hide:');
} else {
const win = injectedGetWindow(key);
if (win == null) return;
win.close();
}
});
electron.ipcMain.handle(WINDOW_SET_BACKGROUND_THROTTLING, async (_, enabled) => {
const win = injectedGetWindow();
if (win == null) return;
win.webContents.setBackgroundThrottling(enabled);
});

View File

@ -0,0 +1,62 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.DiscordIPC = void 0;
Object.defineProperty(exports, "IPCEvents", {
enumerable: true,
get: function () {
return _constants.IPCEvents;
}
});
var _electron = _interopRequireDefault(require("electron"));
var _constants = require("./constants");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable prefer-spread */
// Save people from needing two imports.
class DiscordMainIPC {
/**
* For handling sync events.
*/
static on(channel, listener) {
_electron.default.ipcMain.on(channel, (...args) => {
return listener.apply(this, args);
});
}
/**
* For handling async events.
*/
static handle(channel, listener) {
return _electron.default.ipcMain.handle(channel, (...args) => {
return listener.apply(this, args);
});
}
}
class DiscordRendererIPC {
/**
* For sending sync events.
*/
static sendSync(...args) {
return _electron.default.ipcRenderer.sendSync.apply(_electron.default.ipcRenderer, args);
}
/**
* For sending async events.
*/
static invoke(...args) {
return _electron.default.ipcRenderer.invoke.apply(_electron.default.ipcRenderer, args);
}
}
const DiscordIPC = {
main: DiscordMainIPC,
renderer: DiscordRendererIPC
};
exports.DiscordIPC = DiscordIPC;

View File

@ -0,0 +1,116 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.IPCEvents = void 0;
exports.getDiscordIPCEvent = getDiscordIPCEvent;
const discordPrefixRegex = /^DISCORD_/;
function getDiscordIPCEvent(ev) {
return discordPrefixRegex.test(ev) ? ev : `DISCORD_${ev}`;
}
// Namespace all event names with DISCORD_
let IPCEvents;
exports.IPCEvents = IPCEvents;
(function (IPCEvents) {
IPCEvents["ACCESSIBILITY_GET_ENABLED"] = "DISCORD_ACCESSIBILITY_GET_ENABLED";
IPCEvents["APP_BADGE_SET"] = "DISCORD_APP_BADGE_SET";
IPCEvents["APP_GET_RELEASE_CHANNEL_SYNC"] = "DISCORD_APP_GET_RELEASE_CHANNEL_SYNC";
IPCEvents["APP_GET_HOST_VERSION_SYNC"] = "DISCORD_APP_GET_HOST_VERSION_SYNC";
IPCEvents["APP_GET_BUILD_NUMBER"] = "DISCORD_APP_GET_BUILD_NUMBER";
IPCEvents["APP_GET_MODULE_VERSIONS"] = "DISCORD_APP_GET_MODULE_VERSIONS";
IPCEvents["APP_GET_PATH"] = "DISCORD_APP_GET_PATH";
IPCEvents["APP_SET_BADGE_COUNT"] = "DISCORD_APP_SET_BADGE_COUNT";
IPCEvents["APP_DOCK_SET_BADGE"] = "DISCORD_APP_DOCK_SET_BADGE";
IPCEvents["APP_DOCK_BOUNCE"] = "DISCORD_APP_DOCK_BOUNCE";
IPCEvents["APP_DOCK_CANCEL_BOUNCE"] = "DISCORD_APP_DOCK_CANCEL_BOUNCE";
IPCEvents["APP_RELAUNCH"] = "DISCORD_APP_RELAUNCH";
IPCEvents["APP_GET_DEFAULT_DOUBLE_CLICK_ACTION"] = "DISCORD_APP_GET_DEFAULT_DOUBLE_CLICK_ACTION";
IPCEvents["CLIPBOARD_COPY"] = "DISCORD_CLIPBOARD_COPY";
IPCEvents["CLIPBOARD_CUT"] = "DISCORD_CLIPBOARD_CUT";
IPCEvents["CLIPBOARD_PASTE"] = "DISCORD_CLIPBOARD_PASTE";
IPCEvents["LOAD_CLIP"] = "DISCORD_LOAD_CLIP";
IPCEvents["LOAD_CLIPS_DIRECTORY"] = "DISCORD_LOAD_CLIPS_DIRECTORY";
IPCEvents["DELETE_CLIP"] = "DISCORD_DELETE_CLIP";
IPCEvents["CHECK_FOR_UPDATES"] = "DISCORD_CHECK_FOR_UPDATES";
IPCEvents["DESKTOP_CAPTURER_GET_SOURCES"] = "DISCORD_DESKTOP_CAPTURER_GET_SOURCES";
IPCEvents["CONSTANTS_GET"] = "DISCORD_CONSTANTS_GET";
IPCEvents["CRASH_REPORTER_UPDATE_METADATA"] = "DISCORD_CRASH_REPORTER_UPDATE_METADATA";
IPCEvents["FEATURES_GET_BROWSER_FEATURES"] = "DISCORD_FEATURES_GET_BROWSER_FEATURES";
IPCEvents["FILE_MANAGER_GET_MODULE_PATH"] = "DISCORD_FILE_MANAGER_GET_MODULE_PATH";
IPCEvents["FILE_MANAGER_GET_MODULE_DATA_PATH_SYNC"] = "DISCORD_FILE_MANAGER_GET_MODULE_DATA_PATH_SYNC";
IPCEvents["FILE_MANAGER_SHOW_SAVE_DIALOG"] = "DISCORD_FILE_MANAGER_SHOW_SAVE_DIALOG";
IPCEvents["FILE_MANAGER_SHOW_OPEN_DIALOG"] = "DISCORD_FILE_MANAGER_SHOW_OPEN_DIALOG";
IPCEvents["FILE_MANAGER_SHOW_ITEM_IN_FOLDER"] = "DISCORD_FILE_MANAGER_SHOW_ITEM_IN_FOLDER";
IPCEvents["GPU_SETTINGS_SET_ENABLE_HWACCEL"] = "DISCORD_GPU_SETTINGS_SET_ENABLE_HWACCEL";
IPCEvents["GPU_SETTINGS_GET_ENABLE_HWACCEL_SYNC"] = "DISCORD_GPU_SETTINGS_GET_ENABLE_HWACCEL_SYNC";
IPCEvents["NATIVE_MODULES_GET_PATHS"] = "DISCORD_NATIVE_MODULES_GET_PATHS";
IPCEvents["NATIVE_MODULES_INSTALL"] = "DISCORD_NATIVE_MODULES_INSTALL";
IPCEvents["NATIVE_MODULES_FINISH_UPDATER_BOOTSTRAP"] = "DISCORD_NATIVE_MODULES_FINISH_UPDATER_BOOTSTRAP";
IPCEvents["NATIVE_MODULES_GET_HAS_NEW_UPDATER"] = "DISCORD_NATIVE_MODULES_GET_HAS_NEW_UPDATER";
IPCEvents["NOTIFICATION_CLOSE"] = "DISCORD_NOTIFICATION_CLOSE";
IPCEvents["NOTIFICATION_SHOW"] = "DISCORD_NOTIFICATION_SHOW";
IPCEvents["NOTIFICATIONS_CLEAR"] = "DISCORD_NOTIFICATIONS_CLEAR";
IPCEvents["OPEN_EXTERNAL_URL"] = "DISCORD_OPEN_EXTERNAL_URL";
IPCEvents["GLOBAL_OVERLAY_OPEN"] = "DISCORD_GLOBAL_OVERLAY_OPEN";
IPCEvents["POWER_MONITOR_RESUME"] = "DISCORD_POWER_MONITOR_RESUME";
IPCEvents["POWER_MONITOR_SUSPEND"] = "DISCORD_POWER_MONITOR_SUSPEND";
IPCEvents["POWER_MONITOR_LOCK_SCREEN"] = "DISCORD_POWER_MONITOR_LOCK_SCREEN";
IPCEvents["POWER_MONITOR_UNLOCK_SCREEN"] = "DISCORD_POWER_MONITOR_UNLOCK_SCREEN";
IPCEvents["POWER_MONITOR_GET_SYSTEM_IDLE_TIME"] = "DISCORD_POWER_MONITOR_GET_SYSTEM_IDLE_TIME";
IPCEvents["POWER_SAVE_BLOCKER_BLOCK_DISPLAY_SLEEP"] = "DISCORD_POWER_SAVE_BLOCKER_BLOCK_DISPLAY_SLEEP";
IPCEvents["POWER_SAVE_BLOCKER_UNBLOCK_DISPLAY_SLEEP"] = "DISCORD_POWER_SAVE_BLOCKER_UNBLOCK_DISPLAY_SLEEP";
IPCEvents["POWER_SAVE_BLOCKER_CLEANUP_DISPLAY_SLEEP"] = "DISCORD_POWER_SAVE_BLOCKER_CLEANUP_DISPLAY_SLEEP";
IPCEvents["PROCESS_UTILS_GET_CPU_USAGE"] = "DISCORD_PROCESS_UTILS_GET_CPU_USAGE";
IPCEvents["PROCESS_UTILS_GET_MEMORY_INFO"] = "DISCORD_PROCESS_UTILS_GET_MEMORY_INFO";
IPCEvents["PROCESS_UTILS_FLUSH_DNS_CACHE"] = "DISCORD_PROCESS_UTILS_FLUSH_DNS_CACHE";
IPCEvents["PROCESS_UTILS_FLUSH_COOKIES"] = "DISCORD_PROCESS_UTILS_FLUSH_COOKIES";
IPCEvents["PROCESS_UTILS_FLUSH_STORAGE_DATA"] = "DISCORD_PROCESS_UTILS_FLUSH_STORAGE_DATA";
IPCEvents["PROCESS_UTILS_GET_MAIN_ARGV_SYNC"] = "DISCORD_PROCESS_UTILS_GET_MAIN_ARGV_SYNC";
IPCEvents["PROCESS_UTILS_GET_LAST_CRASH"] = "DISCORD_PROCESS_UTILS_GET_LAST_CRASH";
IPCEvents["PROCESS_UTILS_SET_CRASH_INFORMATION"] = "DISCORD_PROCESS_UTILS_SET_CRASH_INFORMATION";
IPCEvents["PROCESS_UTILS_GET_SYSTEM_INFO"] = "DISCORD_PROCESS_UTILS_GET_SYSTEM_INFO";
IPCEvents["QUIT_AND_INSTALL"] = "DISCORD_QUIT_AND_INSTALL";
IPCEvents["SAFE_STORAGE_DECRYPT_STRING"] = "DISCORD_SAFE_STORAGE_DECRYPT_STRING";
IPCEvents["SAFE_STORAGE_ENCRYPT_STRING"] = "DISCORD_SAFE_STORAGE_ENCRYPT_STRING";
IPCEvents["SAFE_STORAGE_IS_ENCRYPTION_AVAILABLE"] = "DISCORD_SAFE_STORAGE_IS_ENCRYPTION_AVAILABLE";
IPCEvents["SETTINGS_GET"] = "DISCORD_SETTINGS_GET";
IPCEvents["SETTINGS_SET"] = "DISCORD_SETTINGS_SET";
IPCEvents["SETTINGS_GET_SYNC"] = "DISCORD_SETTINGS_GET_SYNC";
IPCEvents["SETTINGS_UPDATE_BACKGROUND_COLOR"] = "DISCORD_SETTINGS_UPDATE_BACKGROUND_COLOR";
IPCEvents["SPELLCHECK_RESULT"] = "DISCORD_SPELLCHECK_RESULT";
IPCEvents["SPELLCHECK_REPLACE_MISSPELLING"] = "DISCORD_SPELLCHECK_REPLACE_MISSPELLING";
IPCEvents["SPELLCHECK_GET_AVAILABLE_DICTIONARIES"] = "DISCORD_SPELLCHECK_GET_AVAILABLE_DICTIONARIES";
IPCEvents["SPELLCHECK_SET_LOCALE"] = "DISCORD_SPELLCHECK_SET_LOCALE";
IPCEvents["SPELLCHECK_SET_LEARNED_WORDS"] = "DISCORD_SPELLCHECK_SET_LEARNED_WORDS";
IPCEvents["SYSTEM_TRAY_SET_ICON"] = "DISCORD_SYSTEM_TRAY_SET_ICON";
IPCEvents["SYSTEM_TRAY_SET_APPLICATIONS"] = "DISCORD_SYSTEM_TRAY_SET_APPLICATIONS";
IPCEvents["THUMBAR_BUTTONS_UPDATE"] = "DISCORD_THUMBAR_BUTTONS_UPDATE";
IPCEvents["THUMBAR_BUTTONS_CLICKED"] = "DISCORD_THUMBAR_BUTTONS_CLICKED";
IPCEvents["TOGGLE_MINIMIZE_TO_TRAY"] = "DISCORD_TOGGLE_MINIMIZE_TO_TRAY";
IPCEvents["TOGGLE_OPEN_ON_STARTUP"] = "DISCORD_TOGGLE_OPEN_ON_STARTUP";
IPCEvents["TOGGLE_START_MINIMIZED"] = "DISCORD_TOGGLE_START_MINIMIZED";
IPCEvents["UPDATE_OPEN_ON_STARTUP"] = "DISCORD_UPDATE_OPEN_ON_STARTUP";
IPCEvents["UNHANDLED_JS_EXCEPTION"] = "DISCORD_UNHANDLED_JS_EXCEPTION";
IPCEvents["UPDATER_HISTORY_QUERY_AND_TRUNCATE"] = "DISCORD_UPDATER_HISTORY_QUERY_AND_TRUNCATE";
IPCEvents["UPDATED_QUOTES"] = "DISCORD_UPDATED_QUOTES";
IPCEvents["USER_DATA_CACHE_DELETE"] = "DISCORD_USER_DATA_CACHE_DELETE";
IPCEvents["USER_DATA_CACHE_GET"] = "DISCORD_USER_DATA_CACHE_GET";
IPCEvents["USER_DATA_CACHE_SAVE"] = "DISCORD_USER_DATA_CACHE_SAVE";
IPCEvents["WINDOW_BLUR"] = "DISCORD_WINDOW_BLUR";
IPCEvents["WINDOW_CLOSE"] = "DISCORD_WINDOW_CLOSE";
IPCEvents["WINDOW_FOCUS"] = "DISCORD_WINDOW_FOCUS";
IPCEvents["WINDOW_MAXIMIZE"] = "DISCORD_WINDOW_MAXIMIZE";
IPCEvents["WINDOW_MINIMIZE"] = "DISCORD_WINDOW_MINIMIZE";
IPCEvents["WINDOW_RESTORE"] = "DISCORD_WINDOW_RESTORE";
IPCEvents["WINDOW_FLASH_FRAME"] = "DISCORD_WINDOW_FLASH_FRAME";
IPCEvents["WINDOW_TOGGLE_FULLSCREEN"] = "DISCORD_WINDOW_TOGGLE_FULLSCREEN";
IPCEvents["WINDOW_SET_BACKGROUND_THROTTLING"] = "DISCORD_WINDOW_SET_BACKGROUND_THROTTLING";
IPCEvents["WINDOW_SET_PROGRESS_BAR"] = "DISCORD_WINDOW_SET_PROGRESS_BAR";
IPCEvents["WINDOW_IS_ALWAYS_ON_TOP"] = "DISCORD_WINDOW_IS_ALWAYS_ON_TOP";
IPCEvents["WINDOW_SET_ALWAYS_ON_TOP"] = "DISCORD_WINDOW_SET_ALWAYS_ON_TOP";
IPCEvents["WINDOW_DEVTOOLS_OPENED"] = "DISCORD_WINDOW_DEVTOOLS_OPENED";
IPCEvents["WINDOW_DEVTOOLS_CLOSED"] = "DISCORD_WINDOW_DEVTOOLS_CLOSED";
IPCEvents["GET_MOUSE_COORDINATES"] = "DISCORD_GET_MOUSE_COORDINATES";
})(IPCEvents || (exports.IPCEvents = IPCEvents = {}));

View File

@ -0,0 +1,105 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "basename", {
enumerable: true,
get: function () {
return _path.basename;
}
});
exports.deleteFile = deleteFile;
Object.defineProperty(exports, "dirname", {
enumerable: true,
get: function () {
return _path.dirname;
}
});
Object.defineProperty(exports, "extname", {
enumerable: true,
get: function () {
return _path.extname;
}
});
exports.getFilesnamesFromDirectory = getFilesnamesFromDirectory;
Object.defineProperty(exports, "join", {
enumerable: true,
get: function () {
return _path.join;
}
});
exports.readFiles = readFiles;
exports.readFulfilledFiles = readFulfilledFiles;
var _buffer = _interopRequireDefault(require("buffer"));
var _originalFs = _interopRequireDefault(require("original-fs"));
var _path = _interopRequireWildcard(require("path"));
var _util = _interopRequireDefault(require("util"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable no-console */
// eslint-disable-line import/no-unresolved
// Reason for original-fs being import/no-unresolved: https://github.com/discord/discord/pull/74159#discussion_r893733771
const MAX_LENGTH = _buffer.default.constants.MAX_LENGTH;
const promiseFs = {
readdir: _util.default.promisify(_originalFs.default.readdir),
open: _util.default.promisify(_originalFs.default.open),
fstat: _util.default.promisify(_originalFs.default.fstat),
stat: _util.default.promisify(_originalFs.default.stat),
unlink: _util.default.promisify(_originalFs.default.unlink),
read: _util.default.promisify(_originalFs.default.read),
close: _util.default.promisify(_originalFs.default.close)
};
// Perform `readFiles` but only return `fulfilled` results.
// If [orException] is set, exception if any of the results were rejected.
async function readFulfilledFiles(filenames, maxSize, orException) {
const files = await readFiles(filenames, maxSize);
if (orException) {
files.forEach(result => {
if (result.status === 'rejected') {
throw result.reason;
}
});
}
return files.filter(result => result.status === 'fulfilled').map(result => result.value);
}
function readFiles(filenames, maxSize) {
maxSize = Math.min(maxSize, MAX_LENGTH);
return Promise.allSettled(filenames.map(async filename => {
const handle = await promiseFs.open(filename, 'r');
try {
const stats = await promiseFs.fstat(handle);
if (maxSize != null && stats.size > maxSize) {
// Used to help determine why openFiles failed.
// Cannot use an error here because context bridge will remove the code field.
// eslint-disable-next-line no-throw-literal
throw {
code: 'ETOOLARGE',
message: 'upload too large',
filesize: stats.size,
maxSize
};
}
const buffer = Buffer.alloc(stats.size);
const data = await promiseFs.read(handle, buffer, 0, stats.size, 0);
return {
data: data.buffer.slice(0, data.bytesRead),
filename: _path.default.basename(filename)
};
} finally {
promiseFs.close(handle); // No reason to await?
}
}));
}
function getFilesnamesFromDirectory(path) {
return promiseFs.readdir(path);
}
function deleteFile(filename) {
return promiseFs.unlink(filename);
}

View File

@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getCrashFiles = getCrashFiles;
exports.getPath = getPath;
var _electron = _interopRequireDefault(require("electron"));
var _fs = _interopRequireDefault(require("fs"));
var _originalFs = _interopRequireDefault(require("original-fs"));
var _path = _interopRequireDefault(require("path"));
var _util = _interopRequireDefault(require("util"));
var _processUtils = require("../../../common/processUtils");
var _constants = require("../common/constants");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const allowedAppPaths = new Set(['home', 'appData', 'desktop', 'documents', 'downloads', 'crashDumps']);
const readdir = _util.default.promisify(_fs.default.readdir);
async function getPath(path) {
if (!allowedAppPaths.has(path)) {
throw new Error(`${path} is not an allowed app path`);
}
return _electron.default.ipcRenderer.invoke(_constants.IPCEvents.APP_GET_PATH, path);
}
function getTimes(filenames) {
return Promise.allSettled(filenames.map(filename => new Promise((resolve, reject) => {
_originalFs.default.stat(filename, (err, stats) => {
if (err) {
return reject(err);
}
if (!stats.isFile()) {
return reject(new Error('Not a file'));
}
return resolve({
filename,
mtime: stats.mtime
});
});
})));
}
async function orderedFiles(folder) {
try {
const filenames = await readdir(folder);
const times = await getTimes(filenames.map(filename => _path.default.join(folder, filename)));
return times.filter(result => result.status === 'fulfilled').map(result => result.value).sort((a, b) => b.mtime.getTime() - a.mtime.getTime()).map(a => a.filename);
} catch (err) {
return [];
}
}
async function getCrashFiles() {
const crashBaseFolder = await getPath('crashDumps');
const crashFolder = _processUtils.IS_WIN ? _path.default.join(crashBaseFolder, 'reports') : _path.default.join(crashBaseFolder, 'completed');
return orderedFiles(crashFolder);
}

View File

@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isNotNullish = isNotNullish;
/**
* This function is primarly useful to type-erase the `null | undefined` in
* filter statements, allowing you to write more ergonomic code down-the-line.
*
* Usage:
*
* values.filter(isNotNullish).map(v => v.toFoo());
*/
function isNotNullish(value) {
return value != null;
}

View File

@ -0,0 +1,9 @@
"use strict";
var _DiscordIPC = require("../common/DiscordIPC");
function isAccessibilitySupportEnabled() {
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.ACCESSIBILITY_GET_ENABLED);
}
module.exports = {
isAccessibilitySupportEnabled
};

View File

@ -0,0 +1,90 @@
"use strict";
var _electron = _interopRequireDefault(require("electron"));
var _DiscordIPC = require("../common/DiscordIPC");
var _paths = require("../common/paths");
var _crashReporter = require("./crashReporter");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const releaseChannel = _DiscordIPC.DiscordIPC.renderer.sendSync(_DiscordIPC.IPCEvents.APP_GET_RELEASE_CHANNEL_SYNC);
const hostVersion = _DiscordIPC.DiscordIPC.renderer.sendSync(_DiscordIPC.IPCEvents.APP_GET_HOST_VERSION_SYNC);
const buildNumber = _DiscordIPC.DiscordIPC.renderer.sendSync(_DiscordIPC.IPCEvents.APP_GET_BUILD_NUMBER);
(0, _crashReporter.updateCrashReporter)({
nativeBuildNumber: (buildNumber === null || buildNumber === void 0 ? void 0 : buildNumber.toString()) ?? 'null'
});
let moduleVersions = {};
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_GET_MODULE_VERSIONS).then(versions => {
moduleVersions = versions;
});
// TODO: Fix this .on to be part of our typing.
_electron.default.ipcRenderer.on('DISCORD_MODULE_INSTALLED', async _ => {
moduleVersions = await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_GET_MODULE_VERSIONS);
});
function getReleaseChannel() {
return releaseChannel;
}
function getVersion() {
return hostVersion;
}
function getBuildNumber() {
return buildNumber;
}
function getModuleVersions() {
return moduleVersions;
}
function setBadgeCount(count) {
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_SET_BADGE_COUNT, count);
return Promise.resolve();
}
function dockSetBadge(badge) {
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_DOCK_SET_BADGE, badge);
return Promise.resolve();
}
function dockBounce(type) {
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_DOCK_BOUNCE, type);
return Promise.resolve();
}
function dockCancelBounce(id) {
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_DOCK_CANCEL_BOUNCE, id);
return Promise.resolve();
}
function relaunch() {
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_RELAUNCH);
return Promise.resolve();
}
function getDefaultDoubleClickAction() {
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_GET_DEFAULT_DOUBLE_CLICK_ACTION);
}
function registerUserInteractionHandler(elementId, eventType, callback) {
const element = document.getElementById(elementId);
if (element == null) {
throw new Error(`Element with id '${elementId}' was not found`);
}
function handleUserInteraction(ev) {
if (!ev.isTrusted) {
return;
}
callback(ev);
}
element.addEventListener(eventType, handleUserInteraction);
return () => {
element.removeEventListener(eventType, handleUserInteraction);
};
}
module.exports = {
getReleaseChannel,
getVersion,
getModuleVersions,
getBuildNumber,
getPath: _paths.getPath,
// used via DiscordNative.remoteApp.getPath
setBadgeCount,
dock: {
setBadge: dockSetBadge,
bounce: dockBounce,
cancelBounce: dockCancelBounce
},
relaunch,
getDefaultDoubleClickAction,
registerUserInteractionHandler
};

View File

@ -0,0 +1,42 @@
"use strict";
// @ts-nocheck
/* eslint-disable */
const electron = require('electron');
const invariant = require('invariant');
const {
CLIPBOARD_COPY,
CLIPBOARD_CUT,
CLIPBOARD_PASTE
} = require('../common/constants').IPCEvents;
function copy(text) {
if (text) {
electron.clipboard.writeText(text);
} else {
electron.ipcRenderer.invoke(CLIPBOARD_COPY);
}
}
function copyImage(imageArrayBuffer, imageSrc) {
invariant(imageArrayBuffer != null, 'Image data is empty');
const nativeImg = electron.nativeImage.createFromBuffer(imageArrayBuffer);
electron.clipboard.write({
html: `<img src="${imageSrc}">`,
image: nativeImg
});
}
function cut() {
electron.ipcRenderer.invoke(CLIPBOARD_CUT);
}
function paste() {
electron.ipcRenderer.invoke(CLIPBOARD_PASTE);
}
function read() {
return electron.clipboard.readText();
}
module.exports = {
copy,
copyImage,
cut,
paste,
read
};

View File

@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.deleteClip = deleteClip;
exports.loadClip = loadClip;
exports.loadClipsDirectory = loadClipsDirectory;
var _DiscordIPC = require("../common/DiscordIPC");
function loadClip(path) {
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.LOAD_CLIP, path);
}
function loadClipsDirectory(path) {
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.LOAD_CLIPS_DIRECTORY, path);
}
function deleteClip(path) {
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.DELETE_CLIP, path);
}

View File

@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getMetadata = getMetadata;
exports.triggerUnhandledException = triggerUnhandledException;
exports.updateCrashReporter = updateCrashReporter;
var _electron = _interopRequireDefault(require("electron"));
var _crashReporterUtils = require("../../../common/crashReporterUtils");
var _DiscordIPC = require("../common/DiscordIPC");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
let metadata = {};
updateCrashReporter(metadata);
async function updateCrashReporter(additionalMetadata) {
const result = await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.CRASH_REPORTER_UPDATE_METADATA, additionalMetadata);
metadata = result.metadata ?? {};
(0, _crashReporterUtils.reconcileCrashReporterMetadata)(_electron.default.crashReporter, metadata);
}
function getMetadata() {
return metadata;
}
// Internal test for unhandled JS exception
async function triggerUnhandledException() {
await _electron.default.ipcRenderer.invoke(_DiscordIPC.IPCEvents.UNHANDLED_JS_EXCEPTION);
}

View File

@ -0,0 +1,25 @@
"use strict";
var _electron = _interopRequireDefault(require("electron"));
var _DiscordIPC = require("../common/DiscordIPC");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
async function getDesktopCaptureSources(options) {
let sources = null;
if (_electron.default.desktopCapturer != null) {
// TODO(atlante45): For backwards compatibility with Electron 13, remove once we've fully
// transitionned off of Electron 13
sources = await _electron.default.desktopCapturer.getSources(options);
} else {
sources = await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.DESKTOP_CAPTURER_GET_SOURCES, options);
}
return sources.map(source => {
return {
id: source.id,
name: source.name,
url: source.thumbnail.toDataURL()
};
});
}
module.exports = {
getDesktopCaptureSources
};

View File

@ -0,0 +1,14 @@
"use strict";
var _DiscordIPC = require("../common/DiscordIPC");
const supportedFeatures = new Set(_DiscordIPC.DiscordIPC.renderer.sendSync(_DiscordIPC.IPCEvents.FEATURES_GET_BROWSER_FEATURES));
function supports(feature) {
return supportedFeatures.has(feature);
}
function declareSupported(feature) {
supportedFeatures.add(feature);
}
module.exports = {
supports,
declareSupported
};

View File

@ -0,0 +1,167 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "basename", {
enumerable: true,
get: function () {
return _path.basename;
}
});
exports.cleanupTempFiles = cleanupTempFiles;
Object.defineProperty(exports, "dirname", {
enumerable: true,
get: function () {
return _path.dirname;
}
});
Object.defineProperty(exports, "extname", {
enumerable: true,
get: function () {
return _path.extname;
}
});
exports.getModuleDataPathSync = getModuleDataPathSync;
exports.getModulePath = getModulePath;
Object.defineProperty(exports, "join", {
enumerable: true,
get: function () {
return _path.join;
}
});
exports.openFiles = openFiles;
exports.readLogFiles = readLogFiles;
exports.readTimeSeriesLogFiles = readTimeSeriesLogFiles;
exports.saveWithDialog = saveWithDialog;
exports.showItemInFolder = showItemInFolder;
exports.showOpenDialog = showOpenDialog;
var _fs = _interopRequireDefault(require("fs"));
var _originalFs = _interopRequireDefault(require("original-fs"));
var _path = _interopRequireWildcard(require("path"));
var _util = _interopRequireDefault(require("util"));
var _DiscordIPC = require("../common/DiscordIPC");
var _fileutils = require("../common/fileutils");
var _paths = require("../common/paths");
var _files = require("./files");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable no-console */
// eslint-disable-line import/no-unresolved
// Reason for original-fs being import/no-unresolved: https://github.com/discord/discord/pull/74159#discussion_r893733771
const INVALID_FILENAME_CHAR_REGEX = /[^a-zA-Z0-9-_.]/g;
const promiseFs = {
readdir: _util.default.promisify(_originalFs.default.readdir),
open: _util.default.promisify(_originalFs.default.open),
fstat: _util.default.promisify(_originalFs.default.fstat),
stat: _util.default.promisify(_originalFs.default.stat),
unlink: _util.default.promisify(_originalFs.default.unlink),
read: _util.default.promisify(_originalFs.default.read),
close: _util.default.promisify(_originalFs.default.close)
};
async function saveWithDialog(fileContents, fileName) {
if (INVALID_FILENAME_CHAR_REGEX.test(fileName)) {
throw new Error('fileName has invalid characters');
}
const defaultPath = _path.default.join(await (0, _paths.getPath)('downloads'), fileName);
const results = await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.FILE_MANAGER_SHOW_SAVE_DIALOG, {
defaultPath
});
if (results != null && results.filePath != null) {
_fs.default.writeFileSync(results.filePath, fileContents);
}
}
async function showOpenDialog({
filters,
properties
}) {
const results = await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.FILE_MANAGER_SHOW_OPEN_DIALOG, {
filters,
properties
});
return results.filePaths;
}
async function readLogFiles(maxSize) {
// MAX_DEBUG_LOG_FILES may need to be increased as more files are added.
const modulePath = await getModulePath();
const voicePath = _path.default.join(modulePath, 'discord_voice');
const hookPath = _path.default.join(modulePath, 'discord_hook');
const utilsPath = _path.default.join(modulePath, 'discord_utils');
const filesToUpload = [_path.default.join(voicePath, 'discord-webrtc_0'), _path.default.join(voicePath, 'discord-webrtc_1'), _path.default.join(voicePath, 'discord-last-webrtc_0'), _path.default.join(voicePath, 'discord-last-webrtc_1'), _path.default.join(voicePath, 'audio_state.json'), _path.default.join(hookPath, 'hook.log'), _path.default.join(utilsPath, 'live_minidump.dmp')];
const crashFiles = await (0, _paths.getCrashFiles)();
if (crashFiles.length > 0) {
filesToUpload.push(crashFiles[0]);
}
return (0, _fileutils.readFulfilledFiles)(filesToUpload, maxSize, false);
}
async function readTimeSeriesLogFiles(maxSize, blindChannelId) {
if (blindChannelId == null) {
console.error('readTimeSeriesLogFiles: blindChannelId missing.');
return [];
}
const modulePath = await getModulePath();
const voicePath = _path.default.join(modulePath, 'discord_voice');
// Example filename: "channel.17812072731293278934.16605628624321906260.tsi"
const filter = new RegExp(`^channel\\.${blindChannelId}\\.\\d+\\.(?:tsi|tsd)$`, 'i');
const filenames = [];
for (const file of await promiseFs.readdir(voicePath)) {
if (filter.test(file)) {
filenames.push(_path.default.join(voicePath, file));
}
}
const allLogFiles = [...filenames];
const maxLogFiles = 10; // 10 is arbitrary but seems reasonable as each would be ~1mb.
if (filenames.length > maxLogFiles) {
console.warn(`readTimeSeriesLogFiles: Exceeded limit of ${maxLogFiles} files, had ${filenames.length}.`);
filenames.splice(maxLogFiles);
}
const readfiles = await (0, _fileutils.readFulfilledFiles)(filenames, maxSize, false);
// Delete the files after they've been read.
await Promise.all(allLogFiles.map(filename => promiseFs.unlink(filename)));
return readfiles;
}
async function cleanupTempFiles() {
// Since this runs on startup, handle and report all errors as cleanly as possible.
try {
const modulePath = await getModulePath();
const voicePath = _path.default.join(modulePath, 'discord_voice');
const deleteAgeTimeSpan = 1 * 24 * 60 * 60 * 1000; // 1 day.
const deleteAge = new Date(Date.now() - deleteAgeTimeSpan);
for (const filename of await promiseFs.readdir(voicePath)) {
if (!(0, _files.isTempFile)(filename)) {
continue;
}
const fullpath = _path.default.join(voicePath, filename);
const stat = await promiseFs.stat(fullpath);
if (!stat.isFile() || stat.mtime > deleteAge) {
continue;
}
console.log(`cleanupTempFiles: Deleting "${fullpath}" due to age.`);
try {
await promiseFs.unlink(fullpath);
} catch (e) {
console.error(`cleanupTempFiles: Failed to unlink ${fullpath}: ${e}`);
}
}
} catch (e) {
console.error(`cleanupTempFiles: Failed ${e}`);
}
}
function showItemInFolder(path) {
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.FILE_MANAGER_SHOW_ITEM_IN_FOLDER, path);
return Promise.resolve();
}
async function openFiles(dialogOptions, maxSize) {
const filenames = await showOpenDialog(dialogOptions);
return (0, _fileutils.readFulfilledFiles)(filenames, maxSize, true);
}
function getModulePath() {
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.FILE_MANAGER_GET_MODULE_PATH);
}
function getModuleDataPathSync() {
return _DiscordIPC.DiscordIPC.renderer.sendSync(_DiscordIPC.IPCEvents.FILE_MANAGER_GET_MODULE_DATA_PATH_SYNC);
}

View File

@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isTempFile = isTempFile;
function isTempFile(filename) {
return /(?:^channel\..+(?:tsi|tsd)$)|(?:^\.tmp.+)/i.test(filename);
}

View File

@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.openOverlay = openOverlay;
var _DiscordIPC = require("../common/DiscordIPC");
function openOverlay(url) {
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.GLOBAL_OVERLAY_OPEN, url);
}

View File

@ -0,0 +1,20 @@
"use strict";
// @ts-nocheck
/* eslint-disable */
const electron = require('electron');
const {
GPU_SETTINGS_SET_ENABLE_HWACCEL,
GPU_SETTINGS_GET_ENABLE_HWACCEL_SYNC
} = require('../common/constants').IPCEvents;
const hardwareAccelerationEnabled = electron.ipcRenderer.sendSync(GPU_SETTINGS_GET_ENABLE_HWACCEL_SYNC);
function getEnableHardwareAcceleration() {
return hardwareAccelerationEnabled;
}
async function setEnableHardwareAcceleration(enable) {
electron.ipcRenderer.invoke(GPU_SETTINGS_SET_ENABLE_HWACCEL, enable);
}
module.exports = {
getEnableHardwareAcceleration,
setEnableHardwareAcceleration
};

View File

@ -0,0 +1,96 @@
"use strict";
const electron = require('electron');
const http = require('http');
const https = require('https');
const {
CONSTANTS_GET
} = require('../common/constants').IPCEvents;
async function getAPIEndpoint() {
const apiEndpoint = await electron.ipcRenderer.invoke(CONSTANTS_GET, 'API_ENDPOINT');
if (apiEndpoint == null || apiEndpoint === '') {
return null;
}
return apiEndpoint;
}
async function makeChunkedRequest(route, chunks, options) {
/**
* Given an array of chunks, make a slow request, only writing chunks
* after a specified amount of time
*
* route: string
* options: object
* method: the method of the request
* contentType: the content type of the request
* chunkInterval: how long to wait to upload a chunk after the last chunk was flushed
* token: the token to make an authorized request from
* chunks: chunked body of the request to upload
*/
const {
method,
chunkInterval,
token,
contentType
} = options;
let httpModule = http;
if (route.startsWith('https')) {
httpModule = https;
}
// we will force the URL to hit only API_ENDPOINT
const apiEndpoint = await getAPIEndpoint();
if (apiEndpoint == null) {
throw new Error('missing api endpoint setting');
}
const apiEndpointUrl = new URL(apiEndpoint);
const url = new URL(route, apiEndpoint);
url.protocol = apiEndpointUrl.protocol;
url.host = apiEndpointUrl.host;
if (!url.pathname.startsWith(apiEndpointUrl.pathname)) {
url.pathname = `${apiEndpointUrl.pathname}${url.pathname}`;
}
return new Promise(async (resolve, reject) => {
let writeTimeout;
const req = httpModule.request(url.toString(), {
method,
headers: {
authorization: token,
'Content-Type': contentType,
'Content-Length': Buffer.byteLength(chunks.join(''))
}
}, res => {
let responseData = '';
res.setEncoding('utf8');
res.on('data', chunk => {
responseData += chunk;
});
res.on('end', () => {
resolve({
status: res.statusCode,
body: responseData
});
});
});
req.on('error', e => {
if (writeTimeout != null) {
clearTimeout(writeTimeout);
}
reject(e);
});
for (let i = 0; i < chunks.length; i++) {
await new Promise(resolve => {
req.write(chunks[i], () => {
writeTimeout = setTimeout(resolve, chunkInterval);
});
});
}
req.end();
});
}
module.exports = {
getAPIEndpoint,
makeChunkedRequest: function (route, chunks, options, callback) {
makeChunkedRequest(route, chunks, options).then(body => callback(null, body)).catch(err => callback(err));
}
};

View File

@ -0,0 +1,35 @@
"use strict";
const electron = require('electron');
const {
getDiscordIPCEvent,
IPCEvents
} = require('../common/constants');
const ipcRenderer = electron.ipcRenderer;
const RENDERER_IPC_SEND_WHITELIST = new Set([IPCEvents.APP_BADGE_SET, IPCEvents.CHECK_FOR_UPDATES, IPCEvents.NOTIFICATION_CLOSE, IPCEvents.NOTIFICATION_SHOW, IPCEvents.NOTIFICATIONS_CLEAR, IPCEvents.OPEN_EXTERNAL_URL, IPCEvents.QUIT_AND_INSTALL, IPCEvents.SETTINGS_UPDATE_BACKGROUND_COLOR, IPCEvents.SYSTEM_TRAY_SET_ICON, IPCEvents.SYSTEM_TRAY_SET_APPLICATIONS, IPCEvents.THUMBAR_BUTTONS_UPDATE, IPCEvents.TOGGLE_MINIMIZE_TO_TRAY, IPCEvents.TOGGLE_OPEN_ON_STARTUP, IPCEvents.TOGGLE_START_MINIMIZED, IPCEvents.UPDATE_OPEN_ON_STARTUP, IPCEvents.UPDATER_HISTORY_QUERY_AND_TRUNCATE, IPCEvents.UPDATED_QUOTES]);
const RENDERER_IPC_INVOKE_WHITELIST = new Set([IPCEvents.GET_MOUSE_COORDINATES]);
function send(ev, ...args) {
const prefixedEvent = getDiscordIPCEvent(ev);
if (!RENDERER_IPC_SEND_WHITELIST.has(prefixedEvent)) {
throw new Error('cannot send this event');
}
ipcRenderer.send(prefixedEvent, ...args);
}
function on(ev, callback) {
ipcRenderer.on(getDiscordIPCEvent(ev), function () {
// Sender is dangerous, do not expose.
callback.apply(callback, [null, ...[...arguments].slice(1)]);
});
}
function invoke(ev, ...args) {
const prefixedEvent = getDiscordIPCEvent(ev);
if (!RENDERER_IPC_INVOKE_WHITELIST.has(prefixedEvent)) {
throw new Error('cannot invoke this event');
}
return ipcRenderer.invoke(prefixedEvent, ...args);
}
module.exports = {
send,
on,
invoke
};

View File

@ -0,0 +1,458 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.readMinidump = readMinidump;
var _fs = _interopRequireDefault(require("fs"));
var _util = _interopRequireDefault(require("util"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable no-console */
/* eslint-disable @typescript-eslint/naming-convention */
const exceptionTypes = {
C0000005: 'EXCEPTION_ACCESS_VIOLATION',
'80000002': 'EXCEPTION_DATATYPE_MISALIGNMENT',
'80000003': 'EXCEPTION_BREAKPOINT',
'80000004': 'EXCEPTION_SINGLE_STEP',
C000008C: 'EXCEPTION_ARRAY_BOUNDS_EXCEEDED',
C000008D: 'EXCEPTION_FLT_DENORMAL_OPERAND',
C000008E: 'EXCEPTION_FLT_DIVIDE_BY_ZERO',
C000008F: 'EXCEPTION_FLT_INEXACT_RESULT',
C0000090: 'EXCEPTION_FLT_INVALID_OPERATION',
C0000091: 'EXCEPTION_FLT_OVERFLOW',
C0000092: 'EXCEPTION_FLT_STACK_CHECK',
C0000093: 'EXCEPTION_FLT_UNDERFLOW',
C0000094: 'EXCEPTION_INT_DIVIDE_BY_ZERO',
C0000095: 'EXCEPTION_INT_OVERFLOW',
C0000096: 'EXCEPTION_PRIV_INSTRUCTION',
C0000006: 'EXCEPTION_IN_PAGE_ERROR',
C000001D: 'EXCEPTION_ILLEGAL_INSTRUCTION',
C0000025: 'EXCEPTION_NONCONTINUABLE_EXCEPTION',
C00000FD: 'EXCEPTION_STACK_OVERFLOW',
C0000026: 'EXCEPTION_INVALID_DISPOSITION',
'80000001': 'EXCEPTION_GUARD_PAGE',
C0000008: 'EXCEPTION_INVALID_HANDLE'
};
class FileReader {
utf16Decoder = new _util.default.TextDecoder('utf-16');
static promiseFs = Object.freeze({
open: _util.default.promisify(_fs.default.open),
read: _util.default.promisify(_fs.default.read),
close: _util.default.promisify(_fs.default.close)
});
constructor(path, bufferSize = 2048) {
this.handle = FileReader.promiseFs.open(path, 'r');
this.buffer = new Uint8Array(bufferSize);
}
async read(u32toReadCount, position = null) {
const byteSize = u32toReadCount * 4;
await this.readCore(byteSize, position);
return new ReadResult(this.buffer.buffer.slice(0, byteSize));
}
async readMinidumpString(rva) {
if (rva === 0) {
return '';
}
// https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_string
await this.readCore(4, rva);
const length = this.buffer[0] | this.buffer[1] << 8 | this.buffer[2] << 16 | this.buffer[3] << 24;
await this.readCore(Math.min(length, this.buffer.byteLength), rva + 4);
return this.utf16Decoder.decode(this.buffer.slice(0, length));
}
async readCore(byteLength, position = null) {
if (byteLength > this.buffer.byteLength) {
throw new Error(`Requested nuber of bytes ${byteLength} exceeds buffer size ${this.buffer.byteLength}.`);
}
if (this.handle == null) {
throw new Error('Cannot use FileReader once closed.');
}
const handle = await this.handle;
const readResult = await FileReader.promiseFs.read(handle, this.buffer, 0, byteLength, position);
if (readResult.bytesRead < byteLength) {
throw new Error(`FileReader failed to read enough bytes: 0x${readResult.bytesRead}`);
}
}
async close() {
if (this.handle == null) {
return;
}
const handle = await this.handle;
this.handle = null;
await FileReader.promiseFs.close(handle);
}
}
class ReadResult {
index = 0;
// irl, this should likely take the uint8 and work from there, but this is fine for us.
// Maybe just steal my other impl here https://github.com/jlennox/WebWad/blob/main/wad.ts#L8
// but we likely don't want to load the entire file at once. But who knows, maybe the system
// call reduction is better and/or it irl doesn't matter either way.
constructor(buffer) {
this.u8 = new Uint8Array(buffer);
this.u16 = new Uint16Array(buffer);
this.u32 = new Uint32Array(buffer);
}
seek(index) {
this.index = index;
}
readuint32() {
const val = this.u32[this.index / 4];
this.index += 4;
return val;
}
readuint16() {
const val = this.u16[this.index / 2];
this.index += 2;
return val;
}
readByteArray(count) {
const val = Array.from(this.u8.slice(this.index, this.index + count));
this.index += count;
return val;
}
readuint64() {
const u32Index = this.index / 4;
const val = BigInt(this.u32[u32Index]) | BigInt(this.u32[u32Index + 1]) << BigInt(32);
this.index += 8;
return val;
}
}
function isMinidumpFilename(filename) {
return /\.dmp$/i.test(filename);
}
var MinidumpStreamType; // https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_header
(function (MinidumpStreamType) {
MinidumpStreamType[MinidumpStreamType["UnusedStream"] = 0] = "UnusedStream";
MinidumpStreamType[MinidumpStreamType["ReservedStream0"] = 1] = "ReservedStream0";
MinidumpStreamType[MinidumpStreamType["ReservedStream1"] = 2] = "ReservedStream1";
MinidumpStreamType[MinidumpStreamType["ThreadListStream"] = 3] = "ThreadListStream";
MinidumpStreamType[MinidumpStreamType["ModuleListStream"] = 4] = "ModuleListStream";
MinidumpStreamType[MinidumpStreamType["MemoryListStream"] = 5] = "MemoryListStream";
MinidumpStreamType[MinidumpStreamType["ExceptionStream"] = 6] = "ExceptionStream";
MinidumpStreamType[MinidumpStreamType["SystemInfoStream"] = 7] = "SystemInfoStream";
MinidumpStreamType[MinidumpStreamType["ThreadExListStream"] = 8] = "ThreadExListStream";
MinidumpStreamType[MinidumpStreamType["Memory64ListStream"] = 9] = "Memory64ListStream";
MinidumpStreamType[MinidumpStreamType["CommentStreamA"] = 10] = "CommentStreamA";
MinidumpStreamType[MinidumpStreamType["CommentStreamW"] = 11] = "CommentStreamW";
MinidumpStreamType[MinidumpStreamType["HandleDataStream"] = 12] = "HandleDataStream";
MinidumpStreamType[MinidumpStreamType["FunctionTableStream"] = 13] = "FunctionTableStream";
MinidumpStreamType[MinidumpStreamType["UnloadedModuleListStream"] = 14] = "UnloadedModuleListStream";
MinidumpStreamType[MinidumpStreamType["MiscInfoStream"] = 15] = "MiscInfoStream";
MinidumpStreamType[MinidumpStreamType["MemoryInfoListStream"] = 16] = "MemoryInfoListStream";
MinidumpStreamType[MinidumpStreamType["ThreadInfoListStream"] = 17] = "ThreadInfoListStream";
MinidumpStreamType[MinidumpStreamType["HandleOperationListStream"] = 18] = "HandleOperationListStream";
MinidumpStreamType[MinidumpStreamType["TokenStream"] = 19] = "TokenStream";
MinidumpStreamType[MinidumpStreamType["JavaScriptDataStream"] = 20] = "JavaScriptDataStream";
MinidumpStreamType[MinidumpStreamType["SystemMemoryInfoStream"] = 21] = "SystemMemoryInfoStream";
MinidumpStreamType[MinidumpStreamType["ProcessVmCountersStream"] = 22] = "ProcessVmCountersStream";
MinidumpStreamType[MinidumpStreamType["IptTraceStream"] = 23] = "IptTraceStream";
MinidumpStreamType[MinidumpStreamType["ThreadNamesStream"] = 24] = "ThreadNamesStream";
MinidumpStreamType[MinidumpStreamType["ceStreamNull"] = 32768] = "ceStreamNull";
MinidumpStreamType[MinidumpStreamType["ceStreamSystemInfo"] = 32769] = "ceStreamSystemInfo";
MinidumpStreamType[MinidumpStreamType["ceStreamException"] = 32770] = "ceStreamException";
MinidumpStreamType[MinidumpStreamType["ceStreamModuleList"] = 32771] = "ceStreamModuleList";
MinidumpStreamType[MinidumpStreamType["ceStreamProcessList"] = 32772] = "ceStreamProcessList";
MinidumpStreamType[MinidumpStreamType["ceStreamThreadList"] = 32773] = "ceStreamThreadList";
MinidumpStreamType[MinidumpStreamType["ceStreamThreadContextList"] = 32774] = "ceStreamThreadContextList";
MinidumpStreamType[MinidumpStreamType["ceStreamThreadCallStackList"] = 32775] = "ceStreamThreadCallStackList";
MinidumpStreamType[MinidumpStreamType["ceStreamMemoryVirtualList"] = 32776] = "ceStreamMemoryVirtualList";
MinidumpStreamType[MinidumpStreamType["ceStreamMemoryPhysicalList"] = 32777] = "ceStreamMemoryPhysicalList";
MinidumpStreamType[MinidumpStreamType["ceStreamBucketParameters"] = 32778] = "ceStreamBucketParameters";
MinidumpStreamType[MinidumpStreamType["ceStreamProcessModuleMap"] = 32779] = "ceStreamProcessModuleMap";
MinidumpStreamType[MinidumpStreamType["ceStreamDiagnosisList"] = 32780] = "ceStreamDiagnosisList";
MinidumpStreamType[MinidumpStreamType["LastReservedStream"] = 65535] = "LastReservedStream";
})(MinidumpStreamType || (MinidumpStreamType = {}));
class MINIDUMP_HEADER {
static U32_SIZE = 4;
constructor(reader) {
this.signature = reader.readuint32();
this.version = reader.readuint32();
this.numberOfStreams = reader.readuint32();
this.streamDirectoryOffset = reader.readuint32();
}
static async read(reader, position) {
return new MINIDUMP_HEADER(await reader.read(MINIDUMP_HEADER.U32_SIZE, position));
}
}
// https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_directory
class MINIDUMP_DIRECTORY {
static U32_SIZE = 3;
constructor(reader) {
this.streamType = reader.readuint32();
this.dataSize = reader.readuint32();
this.dataOffset = reader.readuint32();
}
static async read(reader, position) {
return new MINIDUMP_DIRECTORY(await reader.read(MINIDUMP_DIRECTORY.U32_SIZE, position));
}
}
// https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_exception_stream
class MINIDUMP_EXCEPTION_STREAM {
static U32_SIZE = 8;
constructor(reader) {
this.threadId = reader.readuint32();
this.alignment = reader.readuint32();
this.exceptionCode = reader.readuint32();
this.exceptionFlags = reader.readuint32();
this.exceptionRecord = reader.readuint64();
this.exceptionAddress = reader.readuint64();
}
static async read(reader, position) {
return new MINIDUMP_EXCEPTION_STREAM(await reader.read(MINIDUMP_EXCEPTION_STREAM.U32_SIZE, position));
}
getExceptionCodeString() {
const exceptionCode = this.exceptionCode.toString(16).toUpperCase().padStart(8, '0');
const exceptionString = exceptionTypes[exceptionCode] ?? exceptionCode;
return exceptionString;
}
}
// https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_location_descriptor
class MINIDUMP_LOCATION_DESCRIPTOR {
constructor(reader) {
this.dataSize = reader.readuint32();
this.rva = reader.readuint32();
}
}
// https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_module_list
class MINIDUMP_MODULE_LIST {
static U32_SIZE = 1;
constructor(reader) {
this.numberOfModules = reader.readuint32();
}
static async read(reader, position) {
return new MINIDUMP_MODULE_LIST(await reader.read(MINIDUMP_MODULE_LIST.U32_SIZE, position));
}
}
// https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_module
class MINIDUMP_MODULE {
// sizeof(MINIDUMP_MODULE) 108
// sizeof(VS_FIXEDFILEINFO) 52
// sizeof(MINIDUMP_LOCATION_DESCRIPTOR) 8
// sizeof(RVA) 4
static U32_SIZE = 108 / 4;
constructor(reader) {
this.baseOfImage = reader.readuint64();
this.sizeOfImage = reader.readuint32();
this.checkSum = reader.readuint32();
this.timeDateStamp = reader.readuint32();
this.moduleNameRva = reader.readuint32();
this.versionInfo = new VS_FIXEDFILEINFO(reader);
this.cvRecord = new MINIDUMP_LOCATION_DESCRIPTOR(reader);
this.miscRecord = new MINIDUMP_LOCATION_DESCRIPTOR(reader);
this.reserved0 = reader.readuint64();
this.reserved1 = reader.readuint64();
}
static async read(reader, position) {
return new MINIDUMP_MODULE(await reader.read(MINIDUMP_MODULE.U32_SIZE, position));
}
containsAddress(address) {
const endAddress = this.baseOfImage + BigInt(this.sizeOfImage);
return this.baseOfImage <= address && endAddress > address;
}
async getModuleFileName(reader) {
const moduleName = await reader.readMinidumpString(this.moduleNameRva);
let dirPos = moduleName.lastIndexOf('\\');
if (dirPos === -1) {
dirPos = moduleName.lastIndexOf('/');
}
dirPos = dirPos === -1 ? 0 : dirPos + 1;
return moduleName.slice(dirPos);
}
async getCVInfoIdString(reader) {
return (await CV_INFO.read(reader, this.cvRecord.rva)).getIdString();
}
getCodeIdString() {
return (this.timeDateStamp.toString(16).padStart(8, '0') + this.sizeOfImage.toString(16)).toUpperCase();
}
}
// https://learn.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
class VS_FIXEDFILEINFO {
constructor(reader) {
this.dwSignature = reader.readuint32();
this.dwStrucVersion = reader.readuint32();
this.dwFileVersionMS = reader.readuint32();
this.dwFileVersionLS = reader.readuint32();
this.dwProductVersionMS = reader.readuint32();
this.dwProductVersionLS = reader.readuint32();
this.dwFileFlagsMask = reader.readuint32();
this.dwFileFlags = reader.readuint32();
this.dwFileOS = reader.readuint32();
this.dwFileType = reader.readuint32();
this.dwFileSubtype = reader.readuint32();
this.dwFileDateMS = reader.readuint32();
this.dwFileDateLS = reader.readuint32();
}
getVersionString() {
const first = this.dwProductVersionMS >> 16 & 0xffff;
const second = this.dwProductVersionMS & 0xffff;
const third = this.dwProductVersionLS >> 16 & 0xffff;
const fourth = this.dwProductVersionLS & 0xffff;
return `${first}.${second}.${third}.${fourth}`;
}
}
// This isn't spec'ed on the minidump page (from what I could tell):
// https://github.com/rust-minidump/rust-minidump/blob/main/minidump/src/minidump.rs#L267
// This returns the ID string that is used by the Mozilla tools for PDB lookup.
class CV_INFO {
static async read(reader, position) {
if (position === 0) {
return new CV_INFO_UNKNOWN(0);
}
// 6 is the largest.
const readResult = await reader.read(6, position);
const cvSignature = readResult.readuint32();
switch (cvSignature) {
case CV_INFO_PDB20.SIGNATURE:
return new CV_INFO_PDB20(readResult);
case CV_INFO_PDB70.SIGNATURE:
return new CV_INFO_PDB70(readResult);
case CV_INFO_ELF.SIGNATURE:
return new CV_INFO_ELF();
default:
return new CV_INFO_UNKNOWN(cvSignature);
}
}
}
class CV_INFO_PDB20 {
static SIGNATURE = 0x3031424e;
constructor(reader) {
this.cvOffset = reader.readuint32();
this.signature = reader.readuint32();
this.age = reader.readuint32();
}
getIdString() {
// TODO: Probably uncommon at this point.
return 'CV_INFO_PDB20';
}
}
class GUID {
// fixed 8 length.
constructor(reader) {
this.data1 = reader.readuint32();
this.data2 = reader.readuint16();
this.data3 = reader.readuint16();
this.data4 = reader.readByteArray(8);
}
toString() {
if (this.data4.length !== 8) {
return 'Invalid';
}
return this.data1.toString(16).padStart(4, '0') + this.data2.toString(16).padStart(2, '0') + this.data3.toString(16).padStart(2, '0') + this.data4.map(b => b.toString(16).padStart(2, '0')).join('');
}
}
class CV_INFO_PDB70 {
static SIGNATURE = 0x53445352;
constructor(reader) {
this.signature = new GUID(reader);
this.age = reader.readuint32();
}
getIdString() {
// https://randomascii.wordpress.com/2013/03/09/symbols-the-microsoft-way/
return (this.signature.toString() + this.age.toString(16)).toUpperCase();
}
}
class CV_INFO_ELF {
static SIGNATURE = 0x4270454c;
getIdString() {
// TODO: Would be needed for macOS/linux support presumably?
return 'CV_INFO_ELF';
}
}
class CV_INFO_UNKNOWN {
constructor(cvSignature) {
this.cvSignature = cvSignature;
}
getIdString() {
return 'CV_INFO_UNKNOWN:' + this.cvSignature.toString(16).padStart(4, '0');
}
}
async function readMinidump(file) {
if (file == null || !isMinidumpFilename(file)) return null;
let reader = null;
const info = {};
try {
reader = new FileReader(file);
const header = await MINIDUMP_HEADER.read(reader, 0);
if (header.signature !== 0x504d444d) {
console.log(`readMinidump Bad signature: 0x${header.signature.toString(16)}`);
return null;
}
// Arbitrary number. Just a sanity check.
if (header.numberOfStreams > 0x100) {
console.log(`readMinidump Bad numberOfStreams: 0x${header.numberOfStreams.toString(16)}`);
return null;
}
const streamLookup = {};
// First create a lookup because we want to process the entries in a specific order.
for (let i = 0; i < header.numberOfStreams; ++i) {
const streamOffset = header.streamDirectoryOffset + i * 12;
const entry = await MINIDUMP_DIRECTORY.read(reader, streamOffset);
// We only care about a limited amount of stream types, so lets avoid some of the overhead.
switch (entry.streamType) {
case MinidumpStreamType.ExceptionStream:
case MinidumpStreamType.ModuleListStream:
break;
default:
continue;
}
streamLookup[entry.streamType] = entry;
}
const exceptionStreamEntry = streamLookup[MinidumpStreamType.ExceptionStream];
if (exceptionStreamEntry == null) {
console.log(`readMinidump: No ExceptionStream found.`);
return null;
}
const exceptionStream = await MINIDUMP_EXCEPTION_STREAM.read(reader, exceptionStreamEntry.dataOffset);
info.exceptionString = exceptionStream.getExceptionCodeString();
const exceptionAddrString = exceptionStream.exceptionAddress.toString(16);
console.log(`readMinidump exceptionCode: ${info.exceptionString}, exceptionAddress ${exceptionAddrString}`);
const moduleStreamEntry = streamLookup[MinidumpStreamType.ModuleListStream];
// Skip if `exceptionAddress` is 0 since there will be no crashing module.
if (moduleStreamEntry != null && exceptionStream.exceptionAddress !== BigInt(0)) {
// https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_module_list
// Do not read them all at once. This 1) allows us to exit early, 2) would require a variable sized buffer
// instead of our smaller fixed size buffer.
const moduleList = await MINIDUMP_MODULE_LIST.read(reader, moduleStreamEntry.dataOffset);
// Sanity check, this number is arbitrary.
if (moduleList.numberOfModules > 0x200) {
console.log(`readMinidump ModuleListstream Bad numberOfModules: 0x${moduleList.numberOfModules.toString(16)}`);
return info;
}
let moduleEntryOffset = moduleStreamEntry.dataOffset + 4;
for (let i = 0; i < moduleList.numberOfModules; ++i) {
const module = await MINIDUMP_MODULE.read(reader, moduleEntryOffset);
moduleEntryOffset += MINIDUMP_MODULE.U32_SIZE * 4;
if (module.containsAddress(exceptionStream.exceptionAddress)) {
info.exceptionModuleName = await module.getModuleFileName(reader);
info.exceptionModuleVersion = module.versionInfo.getVersionString();
info.relativeCrashAddress = (exceptionStream.exceptionAddress - module.baseOfImage).toString(16);
info.exceptionModuleCodeId = module.getCodeIdString();
break;
}
}
}
} catch (e) {
console.log(`readMinidump exception: ${e} ${e === null || e === void 0 ? void 0 : e.stack}`);
return null;
} finally {
var _reader;
(_reader = reader) === null || _reader === void 0 ? void 0 : _reader.close();
}
console.log(`readMinidump result ${JSON.stringify(info)}`);
return info;
}

View File

@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getNewestMinidumpInformation = getNewestMinidumpInformation;
var _processUtils = require("../../../common/processUtils");
var _paths = require("../common/paths");
var _minidump = require("./minidump");
/* eslint-disable no-console */
// This is unfortunately in its own file because Jest breaks when it sees original-fs.
async function getNewestMinidumpInformation() {
if (!_processUtils.IS_WIN) return null;
try {
const files = await (0, _paths.getCrashFiles)();
if (files == null || files.length === 0) return null;
return await (0, _minidump.readMinidump)(files[0]);
} catch (e) {
console.log(`getNewestMinidumpInformation exception: ${e}`);
return null;
}
}

View File

@ -0,0 +1,50 @@
"use strict";
const electron = require('electron');
const {
NATIVE_MODULES_GET_PATHS,
NATIVE_MODULES_INSTALL,
NATIVE_MODULES_GET_HAS_NEW_UPDATER
} = require('../common/constants').IPCEvents;
const modulePromises = {};
function getSanitizedModulePaths() {
let sanitizedModulePaths = [];
const {
mainAppDirname,
browserModulePaths
} = electron.ipcRenderer.sendSync(NATIVE_MODULES_GET_PATHS);
browserModulePaths.forEach(modulePath => {
if (!modulePath.includes('electron.asar')) {
sanitizedModulePaths.push(modulePath);
}
});
const rendererModulePaths = require('module')._nodeModulePaths(mainAppDirname);
sanitizedModulePaths = sanitizedModulePaths.concat(rendererModulePaths.slice(0, 2));
return sanitizedModulePaths;
}
function getHasNewUpdater() {
return electron.ipcRenderer.sendSync(NATIVE_MODULES_GET_HAS_NEW_UPDATER);
}
async function ensureModule(name) {
if (modulePromises[name] == null) {
modulePromises[name] = electron.ipcRenderer.invoke(NATIVE_MODULES_INSTALL, name);
}
const moduleInstall = modulePromises[name];
await moduleInstall.catch(e => {
modulePromises[name] = null;
return Promise.reject(e);
});
module.paths = getSanitizedModulePaths();
}
function requireModule(name) {
if (!/^discord_[a-z0-9_-]+$/.test(name) && name !== 'erlpack') {
throw new Error('"' + String(name) + '" is not a whitelisted native module');
}
return require(name);
}
module.paths = getSanitizedModulePaths();
module.exports = {
ensureModule,
requireModule,
canBootstrapNewUpdater: !getHasNewUpdater()
};

View File

@ -0,0 +1,12 @@
"use strict";
const os = require('os');
const process = require('process');
let arch = os.arch();
if (process.platform === 'win32' && process.env['PROCESSOR_ARCHITEW6432'] != null) {
arch = 'x64';
}
module.exports = {
release: os.release(),
arch
};

View File

@ -0,0 +1,42 @@
"use strict";
const electron = require('electron');
const EventEmitter = require('events');
const {
POWER_MONITOR_RESUME,
POWER_MONITOR_SUSPEND,
POWER_MONITOR_LOCK_SCREEN,
POWER_MONITOR_UNLOCK_SCREEN,
POWER_MONITOR_GET_SYSTEM_IDLE_TIME
} = require('../common/constants').IPCEvents;
const events = new EventEmitter();
electron.ipcRenderer.on(POWER_MONITOR_RESUME, () => {
events.emit('resume');
});
electron.ipcRenderer.on(POWER_MONITOR_SUSPEND, () => {
events.emit('suspend');
});
electron.ipcRenderer.on(POWER_MONITOR_LOCK_SCREEN, () => {
events.emit('lock-screen');
});
electron.ipcRenderer.on(POWER_MONITOR_UNLOCK_SCREEN, () => {
events.emit('unlock-screen');
});
function on() {
events.on.apply(events, arguments);
}
function removeListener() {
events.removeListener.apply(events, arguments);
}
function removeAllListeners() {
events.removeAllListeners.apply(events, arguments);
}
async function getSystemIdleTimeMs() {
return electron.ipcRenderer.invoke(POWER_MONITOR_GET_SYSTEM_IDLE_TIME);
}
module.exports = {
on,
removeListener,
removeAllListeners,
getSystemIdleTimeMs
};

View File

@ -0,0 +1,22 @@
"use strict";
const electron = require('electron');
const {
POWER_SAVE_BLOCKER_BLOCK_DISPLAY_SLEEP,
POWER_SAVE_BLOCKER_UNBLOCK_DISPLAY_SLEEP,
POWER_SAVE_BLOCKER_CLEANUP_DISPLAY_SLEEP
} = require('../common/constants').IPCEvents;
async function blockDisplaySleep() {
return electron.ipcRenderer.invoke(POWER_SAVE_BLOCKER_BLOCK_DISPLAY_SLEEP);
}
async function unblockDisplaySleep(id) {
return electron.ipcRenderer.invoke(POWER_SAVE_BLOCKER_UNBLOCK_DISPLAY_SLEEP, id);
}
async function cleanupDisplaySleep() {
return electron.ipcRenderer.invoke(POWER_SAVE_BLOCKER_CLEANUP_DISPLAY_SLEEP);
}
module.exports = {
blockDisplaySleep,
unblockDisplaySleep,
cleanupDisplaySleep
};

View File

@ -0,0 +1,18 @@
"use strict";
const process = require('process');
const env = process.env;
module.exports = {
platform: process.platform,
arch: process.arch,
env: {
DISCORD_TEST: env['DISCORD_TEST'],
DISCORD_GATEWAY_PLAINTEXT: env['DISCORD_GATEWAY_PLAINTEXT'],
DISCORD_DISALLOW_POPUPS: env['DISCORD_DISALLOW_POPUPS'],
LOCALAPPDATA: env['LOCALAPPDATA'],
'PROGRAMFILES(X86)': env['PROGRAMFILES(X86)'],
PROGRAMFILES: env['PROGRAMFILES'],
PROGRAMW6432: env['PROGRAMW6432'],
PROGRAMDATA: env['PROGRAMDATA']
}
};

View File

@ -0,0 +1,98 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.flushCookies = flushCookies;
exports.flushDNSCache = flushDNSCache;
exports.flushStorageData = flushStorageData;
exports.getCPUCoreCount = getCPUCoreCount;
exports.getCurrentCPUUsagePercent = getCurrentCPUUsagePercent;
exports.getCurrentMemoryUsageKB = getCurrentMemoryUsageKB;
exports.getLastCrash = getLastCrash;
exports.getMainArgvSync = getMainArgvSync;
exports.getSystemInfo = getSystemInfo;
exports.purgeMemory = purgeMemory;
exports.setCrashInformation = setCrashInformation;
var _electron = _interopRequireDefault(require("electron"));
var _os = _interopRequireDefault(require("os"));
var _process = _interopRequireDefault(require("process"));
var _DiscordIPC = require("../common/DiscordIPC");
var _minidumpReader = require("./minidumpReader");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Note: CPU interval should be kept insync with Android's DeviceResourceUsageMonitor interval.
const CPU_USAGE_GATHER_INTERVAL = 1000;
const MEMORY_USAGE_GATHER_INTERVAL = 5000;
const mainArgv = _DiscordIPC.DiscordIPC.renderer.sendSync(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_MAIN_ARGV_SYNC);
let totalProcessorUsagePercent = 0;
let totalMemoryUsageKB = 0;
const cpuCoreCount = _os.default.cpus().length;
setInterval(() => {
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_CPU_USAGE).then(usage => totalProcessorUsagePercent = usage);
}, CPU_USAGE_GATHER_INTERVAL);
let memoryUsageTimerRunning = false;
function getCurrentMemoryUsageKB() {
// Lazy initialize because this is only needed when the native process_utils are not available/updated.
if (memoryUsageTimerRunning) {
return totalMemoryUsageKB;
}
memoryUsageTimerRunning = true;
function computeMemoryUsage() {
const memoryUsage = _process.default.memoryUsage();
return (memoryUsage.heapTotal + memoryUsage.external) / 1024;
}
setInterval(() => {
totalMemoryUsageKB = computeMemoryUsage();
}, MEMORY_USAGE_GATHER_INTERVAL);
totalMemoryUsageKB = computeMemoryUsage();
return totalMemoryUsageKB;
}
function flushDNSCache() {
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.PROCESS_UTILS_FLUSH_DNS_CACHE);
}
async function getLastCrash() {
const lastCrash = await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_LAST_CRASH);
const minidumpInformation = lastCrash.id != null ? await (0, _minidumpReader.getNewestMinidumpInformation)() : null;
return {
date: lastCrash.date,
id: lastCrash.id,
rendererCrashReason: lastCrash.rendererCrashReason,
rendererCrashExitCode: lastCrash.rendererCrashExitCode,
minidumpInformation,
storedInformation: lastCrash.storedInformation
};
}
async function flushCookies(callback) {
try {
await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.PROCESS_UTILS_FLUSH_COOKIES);
callback();
} catch (err) {
callback(err);
}
}
function getSystemInfo() {
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_SYSTEM_INFO);
}
async function flushStorageData(callback) {
try {
await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.PROCESS_UTILS_FLUSH_STORAGE_DATA);
callback();
} catch (err) {
callback(err);
}
}
function purgeMemory() {
_electron.default.webFrame.clearCache();
}
function getCurrentCPUUsagePercent() {
return totalProcessorUsagePercent;
}
function getCPUCoreCount() {
return cpuCoreCount;
}
function getMainArgvSync() {
return mainArgv;
}
function setCrashInformation(crashInformation, state) {
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.PROCESS_UTILS_SET_CRASH_INFORMATION, crashInformation, state);
}

View File

@ -0,0 +1,22 @@
"use strict";
const electron = require('electron');
const {
SAFE_STORAGE_DECRYPT_STRING,
SAFE_STORAGE_ENCRYPT_STRING,
SAFE_STORAGE_IS_ENCRYPTION_AVAILABLE
} = require('../common/constants').IPCEvents;
function isEncryptionAvailable() {
return electron.ipcRenderer.sendSync(SAFE_STORAGE_IS_ENCRYPTION_AVAILABLE);
}
function decryptString(encrypted) {
return electron.ipcRenderer.sendSync(SAFE_STORAGE_DECRYPT_STRING, encrypted);
}
function encryptString(plainText) {
return electron.ipcRenderer.sendSync(SAFE_STORAGE_ENCRYPT_STRING, plainText);
}
module.exports = {
isEncryptionAvailable,
decryptString,
encryptString
};

View File

@ -0,0 +1,29 @@
"use strict";
const electron = require('electron');
const {
SETTINGS_GET,
SETTINGS_SET,
SETTINGS_GET_SYNC
} = require('../common/constants').IPCEvents;
// Updating app settings directly from the renderer is considered deprecated.
// Voice still sets a few options, so we whitelist those.
const RENDERER_SET_WHITELIST = ['audioSubsystem', 'useLegacyAudioDevice', 'debugLogging'];
async function get(name, defaultValue) {
return electron.ipcRenderer.invoke(SETTINGS_GET, name, defaultValue);
}
async function set(name, value) {
if (!RENDERER_SET_WHITELIST.includes(name)) {
throw new Error('cannot set this setting key');
}
return electron.ipcRenderer.invoke(SETTINGS_SET, name, value);
}
function getSync(name, defaultValue) {
return electron.ipcRenderer.sendSync(SETTINGS_GET_SYNC, name, defaultValue);
}
module.exports = {
get,
set,
getSync
};

View File

@ -0,0 +1,48 @@
"use strict";
const electron = require('electron');
const EventEmitter = require('events');
const {
SPELLCHECK_RESULT,
SPELLCHECK_REPLACE_MISSPELLING,
SPELLCHECK_GET_AVAILABLE_DICTIONARIES,
SPELLCHECK_SET_LOCALE,
SPELLCHECK_SET_LEARNED_WORDS
} = require('../common/constants').IPCEvents;
const events = new EventEmitter();
electron.ipcRenderer.on(SPELLCHECK_RESULT, handleSpellcheckData);
function handleSpellcheckData(_, misspelledWord, dictionarySuggestions) {
events.emit('spellcheck-result', misspelledWord, dictionarySuggestions);
}
function on() {
events.on.apply(events, arguments);
}
function removeListener() {
events.removeListener.apply(events, arguments);
}
async function getAvailableDictionaries() {
return electron.ipcRenderer.invoke(SPELLCHECK_GET_AVAILABLE_DICTIONARIES);
}
async function setLocale(locale) {
let succeeded = true;
try {
await electron.ipcRenderer.invoke(SPELLCHECK_SET_LOCALE, locale);
} catch (_) {
succeeded = false;
}
return succeeded;
}
async function setLearnedWords(learnedWords) {
return electron.ipcRenderer.invoke(SPELLCHECK_SET_LEARNED_WORDS, learnedWords);
}
async function replaceMisspelling(correction) {
return electron.ipcRenderer.invoke(SPELLCHECK_REPLACE_MISSPELLING, correction);
}
module.exports = {
on,
removeListener,
getAvailableDictionaries,
setLocale,
setLearnedWords,
replaceMisspelling
};

View File

@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _constants = require("../common/constants");
var _ipc = require("./ipc");
function setThumbarButtons(buttons, isSystemDarkMode) {
return (0, _ipc.send)(_constants.IPCEvents.THUMBAR_BUTTONS_UPDATE, buttons, isSystemDarkMode);
}
var _default = {
setThumbarButtons
};
exports.default = _default;
module.exports = exports.default;

View File

@ -0,0 +1,23 @@
"use strict";
const electron = require('electron');
const {
USER_DATA_CACHE_SAVE,
USER_DATA_CACHE_GET,
USER_DATA_CACHE_DELETE
} = require('../common/constants').IPCEvents;
async function getCached() {
const cached = await electron.ipcRenderer.invoke(USER_DATA_CACHE_GET);
return cached;
}
function cacheUserData(userData) {
electron.ipcRenderer.send(USER_DATA_CACHE_SAVE, userData);
}
function deleteCache() {
electron.ipcRenderer.send(USER_DATA_CACHE_DELETE);
}
module.exports = {
getCached,
cacheUserData,
deleteCache
};

View File

@ -0,0 +1,95 @@
"use strict";
const electron = require('electron');
const {
WINDOW_BLUR,
WINDOW_CLOSE,
WINDOW_FOCUS,
WINDOW_MAXIMIZE,
WINDOW_MINIMIZE,
WINDOW_RESTORE,
WINDOW_FLASH_FRAME,
WINDOW_TOGGLE_FULLSCREEN,
WINDOW_SET_BACKGROUND_THROTTLING,
WINDOW_SET_PROGRESS_BAR,
WINDOW_IS_ALWAYS_ON_TOP,
WINDOW_SET_ALWAYS_ON_TOP,
WINDOW_DEVTOOLS_OPENED,
WINDOW_DEVTOOLS_CLOSED
} = require('../common/constants').IPCEvents;
let devtoolsOpenedCallback = () => {};
let devtoolsClosedCallback = () => {};
electron.ipcRenderer.on(WINDOW_DEVTOOLS_OPENED, async _ => {
if (devtoolsOpenedCallback != null) {
devtoolsOpenedCallback();
}
});
electron.ipcRenderer.on(WINDOW_DEVTOOLS_CLOSED, async _ => {
if (devtoolsClosedCallback != null) {
devtoolsClosedCallback();
}
});
async function flashFrame(flag) {
electron.ipcRenderer.invoke(WINDOW_FLASH_FRAME, flag);
}
async function minimize(key) {
electron.ipcRenderer.invoke(WINDOW_MINIMIZE, key);
}
async function restore(key) {
electron.ipcRenderer.invoke(WINDOW_RESTORE, key);
}
async function maximize(key) {
electron.ipcRenderer.invoke(WINDOW_MAXIMIZE, key);
}
async function focus(_hack, key) {
electron.ipcRenderer.invoke(WINDOW_FOCUS, key);
}
async function setAlwaysOnTop(key, enabled) {
return electron.ipcRenderer.invoke(WINDOW_SET_ALWAYS_ON_TOP, key, enabled);
}
async function isAlwaysOnTop(key) {
return electron.ipcRenderer.invoke(WINDOW_IS_ALWAYS_ON_TOP, key);
}
async function blur(key) {
electron.ipcRenderer.invoke(WINDOW_BLUR, key);
}
async function setProgressBar(progress, key) {
electron.ipcRenderer.invoke(WINDOW_SET_PROGRESS_BAR, key, progress);
}
async function fullscreen(key) {
electron.ipcRenderer.invoke(WINDOW_TOGGLE_FULLSCREEN, key);
}
async function close(key) {
electron.ipcRenderer.invoke(WINDOW_CLOSE, key);
}
async function setZoomFactor(factor) {
if (!electron.webFrame.setZoomFactor) return;
electron.webFrame.setZoomFactor(factor / 100);
}
async function setBackgroundThrottling(enabled) {
electron.ipcRenderer.invoke(WINDOW_SET_BACKGROUND_THROTTLING, enabled);
}
async function setDevtoolsCallbacks(onOpened, onClosed) {
devtoolsOpenedCallback = onOpened;
devtoolsClosedCallback = onClosed;
}
// To synchronize web vs desktop release features
const USE_OSX_NATIVE_TRAFFIC_LIGHTS = true;
module.exports = {
flashFrame,
minimize,
restore,
maximize,
focus,
blur,
fullscreen,
close,
setAlwaysOnTop,
isAlwaysOnTop,
setZoomFactor,
setBackgroundThrottling,
setProgressBar,
setDevtoolsCallbacks,
USE_OSX_NATIVE_TRAFFIC_LIGHTS
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="20px" height="20px"
viewBox="40 40 20 20" enable-background="new 40 40 20 20" xml:space="preserve">
<title>Slice 1</title>
<description>Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
<g id="Page_1">
<path id="Close" fill="#99aab5" d="M40.445,42.853l2.408-2.408c0.593-0.593,1.555-0.593,2.147,0l5,5l5-5
c0.593-0.593,1.554-0.593,2.147,0l2.408,2.408c0.593,0.593,0.593,1.554,0,2.147l-5,5l5,5c0.593,0.593,0.592,1.554,0,2.147
l-2.408,2.408c-0.593,0.593-1.555,0.593-2.147,0l-5-5l-5,5c-0.593,0.593-1.554,0.593-2.147,0l-2.408-2.408
c-0.593-0.593-0.593-1.554,0-2.147l5-5l-5-5C39.852,44.407,39.852,43.445,40.445,42.853z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 168 190" enable-background="new 0 0 168 190" xml:space="preserve">
<g>
<rect x="14.4" y="46.1" fill="#FFFFFF" width="139.2" height="97.7"/>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="66.6616" y1="79.7119" x2="66.6616" y2="100.7434">
<stop offset="0" style="stop-color:#7491D5"/>
<stop offset="1" style="stop-color:#4E68A0"/>
</linearGradient>
<path fill="url(#SVGID_1_)" d="M66.7,79.7c-5.4,0-9.8,4.7-9.8,10.5c0,5.8,4.4,10.5,9.8,10.5c5.4,0,9.8-4.7,9.8-10.5
C76.5,84.4,72.1,79.7,66.7,79.7z"/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="101.661" y1="79.7119" x2="101.661" y2="100.7434">
<stop offset="0" style="stop-color:#7491D5"/>
<stop offset="1" style="stop-color:#4E68A0"/>
</linearGradient>
<path fill="url(#SVGID_2_)" d="M101.7,79.7c-5.4,0-9.8,4.7-9.8,10.5c0,5.8,4.4,10.5,9.8,10.5c5.4,0,9.8-4.7,9.8-10.5
C111.5,84.4,107.1,79.7,101.7,79.7z"/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="84" y1="-4.545736e-07" x2="84" y2="190">
<stop offset="0" style="stop-color:#7491D5"/>
<stop offset="1" style="stop-color:#4E68A0"/>
</linearGradient>
<path fill="url(#SVGID_3_)" d="M148.4,0H19.6C8.8,0,0,8.8,0,19.6v128.4c0,10.8,8.8,19.6,19.6,19.6h108.9l-5.1-17.5l12.3,11.3
l11.6,10.7L168,190v-41.9v-9.5V19.6C168,8.8,159.2,0,148.4,0z M111.3,124.1c0,0-3.4-4.1-6.3-7.7c12.6-3.5,17.4-11.3,17.4-11.3
c-4,2.6-7.7,4.4-11.1,5.6c-4.8,2-9.5,3.3-14,4.1c-9.2,1.7-17.6,1.3-24.9-0.1c-5.5-1-10.2-2.5-14.1-4.1c-2.2-0.8-4.6-1.9-7.1-3.3
c-0.3-0.2-0.6-0.3-0.9-0.5c-0.1-0.1-0.3-0.2-0.4-0.2c-1.7-1-2.6-1.6-2.6-1.6s4.6,7.6,16.8,11.2c-2.9,3.6-6.4,7.9-6.4,7.9
c-21.2-0.6-29.3-14.5-29.3-14.5c0-30.6,13.8-55.4,13.8-55.4c13.8-10.3,26.9-10,26.9-10l1,1.1C52.8,50.3,45,57.9,45,57.9
s2.1-1.2,5.7-2.7c10.3-4.5,18.4-5.7,21.8-6c0.5-0.1,1.1-0.2,1.6-0.2c5.9-0.7,12.5-0.9,19.4-0.2c9.1,1,18.9,3.7,28.9,9.1
c0,0-7.5-7.2-23.9-12.1l1.3-1.5c0,0,13.1-0.3,26.9,10c0,0,13.8,24.8,13.8,55.4C140.6,109.6,132.5,123.5,111.3,124.1z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Some files were not shown because too many files have changed in this diff Show More