Merge branches 'develop' and 't3chguy/electron9' of https://github.com/vector-im/riot-desktop into t3chguy/electron9

This commit is contained in:
Michael Telatynski 2020-06-17 16:57:17 +01:00
commit a95e40506b
12 changed files with 275 additions and 52 deletions

View file

@ -1,3 +1,48 @@
Changes in [1.6.5](https://github.com/vector-im/riot-desktop/releases/tag/v1.6.5) (2020-06-16)
==============================================================================================
[Full Changelog](https://github.com/vector-im/riot-desktop/compare/v1.6.4...v1.6.5)
* No changes since 1.6.4
Changes in [1.6.4](https://github.com/vector-im/riot-desktop/releases/tag/v1.6.4) (2020-06-05)
==============================================================================================
[Full Changelog](https://github.com/vector-im/riot-desktop/compare/v1.6.3...v1.6.4)
* No changes since 1.6.3
Changes in [1.6.3](https://github.com/vector-im/riot-desktop/releases/tag/v1.6.3) (2020-06-04)
==============================================================================================
[Full Changelog](https://github.com/vector-im/riot-desktop/compare/v1.6.3-rc.1...v1.6.3)
* No changes since rc.1
Changes in [1.6.3-rc.1](https://github.com/vector-im/riot-desktop/releases/tag/v1.6.3-rc.1) (2020-06-02)
========================================================================================================
[Full Changelog](https://github.com/vector-im/riot-desktop/compare/v1.6.2...v1.6.3-rc.1)
* Fix electron context menu copy/save-as
[\#96](https://github.com/vector-im/riot-desktop/pull/96)
* Fixed error in README.md/User-specified config.json
[\#97](https://github.com/vector-im/riot-desktop/pull/97)
* Update Modular hosting link
[\#92](https://github.com/vector-im/riot-desktop/pull/92)
* Enforce sandbox on all spawned BrowserWindow objects
[\#91](https://github.com/vector-im/riot-desktop/pull/91)
* Run before-quit on updates too to flush rageshake
[\#93](https://github.com/vector-im/riot-desktop/pull/93)
* Enable new room list labs flag
[\#87](https://github.com/vector-im/riot-desktop/pull/87)
* Add asar-webapp script
[\#59](https://github.com/vector-im/riot-desktop/pull/59)
* Bump acorn from 6.4.0 to 6.4.1
[\#50](https://github.com/vector-im/riot-desktop/pull/50)
* Enable font scaling flag for nightly
[\#89](https://github.com/vector-im/riot-desktop/pull/89)
* Enable IRC UI labs flag in nightly
[\#88](https://github.com/vector-im/riot-desktop/pull/88)
* Update help message to fix broken url to electron docs
[\#86](https://github.com/vector-im/riot-desktop/pull/86)
Changes in [1.6.2](https://github.com/vector-im/riot-desktop/releases/tag/v1.6.2) (2020-05-22)
==============================================================================================
[Full Changelog](https://github.com/vector-im/riot-desktop/compare/v1.6.1...v1.6.2)

View file

@ -129,7 +129,7 @@ User-specified config.json
+ `%APPDATA%\$NAME\config.json` on Windows
+ `$XDG_CONFIG_HOME\$NAME\config.json` or `~/.config/$NAME/config.json` on Linux
+ `~Library/Application Support/$NAME/config.json` on macOS
+ `~/Library/Application Support/$NAME/config.json` on macOS
In the paths above, `$NAME` is typically `Riot`, unless you use `--profile
$PROFILE` in which case it becomes `Riot-$PROFILE`.

42
hak/keytar/build.js Normal file
View file

@ -0,0 +1,42 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const path = require('path');
const childProcess = require('child_process');
module.exports = async function(hakEnv, moduleInfo) {
await buildKeytar(hakEnv, moduleInfo);
};
async function buildKeytar(hakEnv, moduleInfo) {
const env = hakEnv.makeGypEnv();
console.log("Running yarn with env", env);
await new Promise((resolve, reject) => {
const proc = childProcess.spawn(
path.join(moduleInfo.nodeModuleBinDir, 'node-gyp' + (hakEnv.isWin() ? '.cmd' : '')),
['rebuild'],
{
cwd: moduleInfo.moduleBuildDir,
env,
stdio: 'inherit',
},
);
proc.on('exit', (code) => {
code ? reject(code) : resolve();
});
});
}

36
hak/keytar/check.js Normal file
View file

@ -0,0 +1,36 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const childProcess = require('child_process');
module.exports = async function(hakEnv, moduleInfo) {
const tools = [['python', '--version']]; // node-gyp uses python for reasons beyond comprehension
for (const tool of tools) {
await new Promise((resolve, reject) => {
const proc = childProcess.spawn(tool[0], tool.slice(1), {
stdio: ['ignore'],
});
proc.on('exit', (code) => {
if (code !== 0) {
reject("Can't find " + tool);
} else {
resolve();
}
});
});
}
};

10
hak/keytar/hak.json Normal file
View file

@ -0,0 +1,10 @@
{
"scripts": {
"check": "check.js",
"build": "build.js"
},
"copy": "build/Release/keytar.node",
"dependencies": {
"libsecret": "0.20.3"
}
}

View file

@ -2,7 +2,7 @@
"name": "riot-desktop",
"productName": "Riot",
"main": "src/electron-main.js",
"version": "1.6.2",
"version": "1.6.5",
"description": "A feature-rich client for Matrix.org",
"author": "New Vector Ltd.",
"repository": {
@ -50,15 +50,16 @@
"glob": "^7.1.6",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
"mkdirp": "^1.0.3",
"needle": "^2.3.2",
"node-pre-gyp": "^0.14.0",
"needle": "^2.5.0",
"node-pre-gyp": "^0.15.0",
"npm": "^6.13.7",
"rimraf": "^3.0.2",
"semver": "^7.1.3",
"tar": "^6.0.1"
},
"hakDependencies": {
"matrix-seshat": "^1.3.3"
"matrix-seshat": "^1.3.3",
"keytar": "^5.6.0"
},
"build": {
"appId": "im.riot.app",

View file

@ -11,7 +11,7 @@
"https://scalar-staging.vector.im/api",
"https://scalar-staging.riot.im/scalar/api"
],
"hosting_signup_link": "https://modular.im/?utm_source=riot-web&utm_medium=web",
"hosting_signup_link": "https://modular.im/services/matrix-hosting-riot?utm_source=riot-web&utm_medium=web",
"bug_report_endpoint_url": "https://riot.im/bugreports/submit",
"features": {
"feature_pinning": "labs",

View file

@ -11,7 +11,7 @@
"https://scalar-staging.vector.im/api",
"https://scalar-staging.riot.im/scalar/api"
],
"hosting_signup_link": "https://modular.im/?utm_source=riot-web&utm_medium=web",
"hosting_signup_link": "https://modular.im/services/matrix-hosting-riot?utm_source=riot-web&utm_medium=web",
"bug_report_endpoint_url": "https://riot.im/bugreports/submit",
"roomDirectory": {
"servers": [

View file

@ -3,6 +3,7 @@ Copyright 2016 Aviral Dasgupta
Copyright 2016 OpenMarket Ltd
Copyright 2018, 2019 New Vector Ltd
Copyright 2017, 2019 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -43,6 +44,18 @@ const Store = require('electron-store');
const fs = require('fs');
const afs = fs.promises;
const crypto = require('crypto');
let keytar;
try {
keytar = require('keytar');
} catch (e) {
if (e.code === "MODULE_NOT_FOUND") {
console.log("Keytar isn't installed; secure key storage is disabled.");
} else {
console.warn("Keytar unexpected error:", e);
}
}
let seshatSupported = false;
let Seshat;
let SeshatRecovery;
@ -241,17 +254,6 @@ ipcMain.on('app_onAction', function(ev, payload) {
}
});
autoUpdater.on('update-downloaded', (ev, releaseNotes, releaseName, releaseDate, updateURL) => {
if (!mainWindow) return;
// forward to renderer
mainWindow.webContents.send('update-downloaded', {
releaseNotes,
releaseName,
releaseDate,
updateURL,
});
});
ipcMain.on('ipcCall', async function(ev, payload) {
if (!mainWindow) return;
@ -365,6 +367,41 @@ ipcMain.on('ipcCall', async function(ev, payload) {
recordSSOSession(args[0]);
break;
case 'getPickleKey':
try {
ret = await keytar.getPassword("riot.im", `${args[0]}|${args[1]}`);
} catch (e) {
// if an error is thrown (e.g. keytar can't connect to the keychain),
// then return null, which means the default pickle key will be used
ret = null;
}
break;
case 'createPickleKey':
try {
const randomArray = await new Promise((resolve, reject) => {
crypto.randomBytes(32, (err, buf) => {
if (err) {
reject(err);
} else {
resolve(buf);
}
});
});
const pickleKey = randomArray.toString("base64").replace(/=+$/g, '');
await keytar.setPassword("riot.im", `${args[0]}|${args[1]}`, pickleKey);
ret = pickleKey;
} catch (e) {
ret = null;
}
break;
case 'destroyPickleKey':
try {
await keytar.deletePassword("riot.im", `${args[0]}|${args[1]}`);
} catch (e) {}
break;
default:
mainWindow.webContents.send('ipcReply', {
id: payload.id,
@ -615,6 +652,17 @@ protocol.registerSchemesAsPrivileged([{
},
}]);
// Turn the sandbox on for *all* windows we might generate. Doing this means we don't
// have to specify a `sandbox: true` to each BrowserWindow.
//
// This also fixes an issue with window.open where if we only specified the sandbox
// on the main window we'd run into cryptic "ipc_renderer be broke" errors. Turns out
// it's trying to jump the sandbox and make some calls into electron, which it can't
// do when half of it is sandboxed. By turning on the sandbox for everything, the new
// window (no matter how temporary it may be) is also sandboxed, allowing for a clean
// transition into the user's browser.
app.enableSandbox();
app.on('ready', async () => {
try {
await setupGlobals();
@ -725,7 +773,7 @@ app.on('ready', async () => {
webPreferences: {
preload: preloadScript,
nodeIntegration: false,
sandbox: true,
//sandbox: true, // We enable sandboxing from app.enableSandbox() above
enableRemoteModule: false,
// We don't use this: it's useful for the preload script to
// share a context with the main page so we can give select
@ -790,12 +838,15 @@ app.on('activate', () => {
mainWindow.show();
});
app.on('before-quit', () => {
function beforeQuit() {
global.appQuitting = true;
if (mainWindow) {
mainWindow.webContents.send('before-quit');
}
});
}
app.on('before-quit', beforeQuit);
app.on('before-quit-for-update', beforeQuit);
app.on('second-instance', (ev, commandLine, workingDirectory) => {
// If other instance launched with --hidden then skip showing window

View file

@ -69,15 +69,31 @@ ipcMain.on('install_update', installUpdate);
ipcMain.on('check_updates', pollForUpdates);
function ipcChannelSendUpdateStatus(status) {
if (global.mainWindow) {
global.mainWindow.webContents.send('check_updates', status);
}
if (!global.mainWindow) return;
global.mainWindow.webContents.send('check_updates', status);
}
// cache the latest update which has been downloaded as electron offers no api to read it
let latestUpdateDownloaded;
autoUpdater.on('update-available', function() {
ipcChannelSendUpdateStatus(true);
}).on('update-not-available', function() {
ipcChannelSendUpdateStatus(false);
if (latestUpdateDownloaded) {
// the only time we will get `update-not-available` if `latestUpdateDownloaded` is already set
// is if the user used the Manual Update check and there is no update newer than the one we
// have downloaded, so show it to them as the latest again.
if (!global.mainWindow) return;
global.mainWindow.webContents.send('update-downloaded', latestUpdateDownloaded);
} else {
ipcChannelSendUpdateStatus(false);
}
}).on('error', function(error) {
ipcChannelSendUpdateStatus(error.message);
});
autoUpdater.on('update-downloaded', (ev, releaseNotes, releaseName, releaseDate, updateURL) => {
if (!global.mainWindow) return;
// forward to renderer
latestUpdateDownloaded = { releaseNotes, releaseName, releaseDate, updateURL };
global.mainWindow.webContents.send('update-downloaded', latestUpdateDownloaded);
});

View file

@ -35,10 +35,27 @@ function onWindowOrNavigate(ev, target) {
safeOpenURL(target);
}
function writeNativeImage(filePath, img) {
switch (filePath.split('.').pop().toLowerCase()) {
case "jpg":
case "jpeg":
return fs.promises.writeFile(filePath, img.toJPEG(100));
case "bmp":
return fs.promises.writeFile(filePath, img.toBitmap());
case "png":
default:
return fs.promises.writeFile(filePath, img.toPNG());
}
}
function onLinkContextMenu(ev, params) {
let url = params.linkURL || params.srcURL;
if (url.startsWith('vector://vector/webapp')) {
// Avoid showing a context menu for app icons
if (params.hasImageContents) return;
// Rewrite URL so that it can be used outside of the app
url = "https://riot.im/app/" + url.substring(23);
}
@ -53,22 +70,13 @@ function onLinkContextMenu(ev, params) {
}));
}
let addSaveAs = false;
if (params.mediaType && params.mediaType === 'image' && !url.startsWith('file://')) {
if (params.hasImageContents) {
popupMenu.append(new MenuItem({
label: '&Copy image',
click() {
if (url.startsWith('data:')) {
clipboard.writeImage(nativeImage.createFromDataURL(url));
} else {
ev.sender.copyImageAt(params.x, params.y);
}
ev.sender.copyImageAt(params.x, params.y);
},
}));
// We want the link to be ordered below the copy stuff, but don't want to duplicate
// the `if` statement, so use a flag.
addSaveAs = true;
}
// No point offering to copy a blob: URL either
@ -91,12 +99,14 @@ function onLinkContextMenu(ev, params) {
}
}
if (addSaveAs) {
// XXX: We cannot easily save a blob from the main process as
// only the renderer can resolve them so don't give the user an option to.
if (params.hasImageContents && !url.startsWith('blob:')) {
popupMenu.append(new MenuItem({
label: 'Sa&ve image as...',
click() {
async click() {
const targetFileName = params.titleText || "image.png";
const filePath = dialog.showSaveDialog({
const {filePath} = await dialog.showSaveDialog({
defaultPath: targetFileName,
});
@ -104,7 +114,7 @@ function onLinkContextMenu(ev, params) {
try {
if (url.startsWith("data:")) {
fs.writeFileSync(filePath, nativeImage.createFromDataURL(url));
await writeNativeImage(filePath, nativeImage.createFromDataURL(url));
} else {
request.get(url).pipe(fs.createWriteStream(filePath));
}

View file

@ -2863,8 +2863,8 @@ map-age-cleaner@^0.1.1:
p-defer "^1.0.0"
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop":
version "6.1.0"
resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/a4a7097c103da42075f2c70e070fd01fa6fb0d48"
version "6.2.2"
resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/1c194e81637fb07fe6ad67cda33be0d5d4c10115"
dependencies:
"@babel/runtime" "^7.8.3"
another-json "^0.2.0"
@ -2958,6 +2958,11 @@ minimist@^1.2.0, minimist@^1.2.3:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.3.tgz#3db5c0765545ab8637be71f333a104a965a9ca3f"
integrity sha512-+bMdgqjMN/Z77a6NlY/I3U5LlRDbnmaAk6lDveAPKwSpcPM4tKAuYsvYF8xjhOPXhOYGe/73vVLVez5PW+jqhw==
minimist@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
minipass@^2.3.5, minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6"
@ -3011,6 +3016,13 @@ mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
dependencies:
minimist "0.0.8"
mkdirp@^0.5.3:
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
dependencies:
minimist "^1.2.5"
mkdirp@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.3.tgz#4cf2e30ad45959dddea53ad97d518b6c8205e1ea"
@ -3053,10 +3065,10 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
needle@^2.2.1, needle@^2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.2.tgz#3342dea100b7160960a450dc8c22160ac712a528"
integrity sha512-DUzITvPVDUy6vczKKYTnWc/pBZ0EnjMJnQ3y+Jo5zfKFimJs7S3HFCxCRZYB9FUZcrzUQr3WsmvZgddMEIZv6w==
needle@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/needle/-/needle-2.5.0.tgz#e6fc4b3cc6c25caed7554bd613a5cf0bac8c31c0"
integrity sha512-o/qITSDR0JCyCKEQ1/1bnUXMmznxabbwi/Y4WwJElf+evwJNFNwIDMCCt5IigFVxgeGBJESLohGtIS9gEzo1fA==
dependencies:
debug "^3.2.6"
iconv-lite "^0.4.4"
@ -3093,14 +3105,14 @@ node-gyp@^5.0.2, node-gyp@^5.0.7:
tar "^4.4.12"
which "^1.3.1"
node-pre-gyp@^0.14.0:
version "0.14.0"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83"
integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==
node-pre-gyp@^0.15.0:
version "0.15.0"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.15.0.tgz#c2fc383276b74c7ffa842925241553e8b40f1087"
integrity sha512-7QcZa8/fpaU/BKenjcaeFF9hLz2+7S9AqyXFhlH/rilsQ/hPZKK32RtR5EQHJElgu+q5RfbJ34KriI79UWaorA==
dependencies:
detect-libc "^1.0.2"
mkdirp "^0.5.1"
needle "^2.2.1"
mkdirp "^0.5.3"
needle "^2.5.0"
nopt "^4.0.1"
npm-packlist "^1.1.6"
npmlog "^4.0.2"