2019-08-28 04:35:07 +02:00
|
|
|
/* eslint no-console:0 */
|
|
|
|
/* eslint space-before-function-paren:0 */
|
2017-11-17 21:35:37 +01:00
|
|
|
// Module imports
|
2019-03-05 05:46:57 +01:00
|
|
|
import '@babel/polyfill';
|
2018-03-29 23:16:37 +02:00
|
|
|
import keytar from 'keytar';
|
2018-01-08 04:46:22 +01:00
|
|
|
import SemVer from 'semver';
|
|
|
|
import https from 'https';
|
2019-01-16 05:33:06 +01:00
|
|
|
import { app, dialog, ipcMain, session, shell } from 'electron';
|
2017-11-18 06:08:44 +01:00
|
|
|
import { autoUpdater } from 'electron-updater';
|
2019-02-18 18:33:02 +01:00
|
|
|
import { Lbry } from 'lbry-redux';
|
2018-01-18 03:13:08 +01:00
|
|
|
import Daemon from './Daemon';
|
2019-03-20 20:09:58 +01:00
|
|
|
import isDev from 'electron-is-dev';
|
2018-02-24 00:20:12 +01:00
|
|
|
import createTray from './createTray';
|
2018-01-18 03:13:08 +01:00
|
|
|
import createWindow from './createWindow';
|
2019-11-11 16:22:57 +01:00
|
|
|
import pjson from '../package.json';
|
2019-03-15 02:54:17 +01:00
|
|
|
import startSandbox from './startSandbox';
|
2019-03-20 20:09:58 +01:00
|
|
|
import installDevtools from './installDevtools';
|
2019-11-12 02:19:22 +01:00
|
|
|
import fs from 'fs';
|
|
|
|
import path from 'path';
|
|
|
|
const filePath = path.join(process.resourcesPath, 'static', 'upgradeDisabled');
|
|
|
|
let upgradeDisabled;
|
|
|
|
try {
|
|
|
|
fs.accessSync(filePath, fs.constants.R_OK);
|
|
|
|
upgradeDisabled = true;
|
|
|
|
} catch (err) {
|
|
|
|
upgradeDisabled = false;
|
|
|
|
}
|
|
|
|
autoUpdater.autoDownload = !upgradeDisabled;
|
2017-12-22 07:42:04 +01:00
|
|
|
|
2018-03-20 02:09:48 +01:00
|
|
|
// This is set to true if an auto update has been downloaded through the Electron
|
|
|
|
// auto-update system and is ready to install. If the user declined an update earlier,
|
|
|
|
// it will still install on shutdown.
|
|
|
|
let autoUpdateDownloaded = false;
|
|
|
|
|
|
|
|
// This is used to keep track of whether we are showing the special dialog
|
|
|
|
// that we show on Windows after you decline an upgrade and close the app later.
|
|
|
|
let showingAutoUpdateCloseAlert = false;
|
|
|
|
|
2018-01-18 03:13:08 +01:00
|
|
|
// Keep a global reference, if you don't, they will be closed automatically when the JavaScript
|
|
|
|
// object is garbage collected.
|
2017-12-21 18:32:51 +01:00
|
|
|
let rendererWindow;
|
2019-03-05 05:46:57 +01:00
|
|
|
|
2019-09-26 18:07:11 +02:00
|
|
|
let tray; // eslint-disable-line
|
2018-01-18 03:13:08 +01:00
|
|
|
let daemon;
|
|
|
|
|
2018-02-24 00:20:12 +01:00
|
|
|
const appState = {};
|
2018-01-18 03:13:08 +01:00
|
|
|
|
|
|
|
app.setAsDefaultProtocolClient('lbry');
|
|
|
|
app.setName('LBRY');
|
2018-03-20 20:51:28 +01:00
|
|
|
app.setAppUserModelId('io.lbry.LBRY');
|
2020-01-07 14:44:23 +01:00
|
|
|
app.commandLine.appendSwitch('force-color-profile', 'srgb');
|
2018-01-18 03:13:08 +01:00
|
|
|
|
2018-07-19 08:45:32 +02:00
|
|
|
if (isDev) {
|
2019-04-03 07:56:58 +02:00
|
|
|
// Disable security warnings in dev mode:
|
|
|
|
// https://github.com/electron/electron/blob/master/docs/tutorial/security.md#electron-security-warnings
|
2018-08-08 18:53:33 +02:00
|
|
|
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true;
|
2018-07-19 08:45:32 +02:00
|
|
|
}
|
|
|
|
|
2019-03-25 07:18:22 +01:00
|
|
|
const startDaemon = async () => {
|
2019-02-18 18:33:02 +01:00
|
|
|
let isDaemonRunning = false;
|
2019-03-20 20:09:58 +01:00
|
|
|
|
2019-02-18 18:33:02 +01:00
|
|
|
await Lbry.status()
|
|
|
|
.then(() => {
|
|
|
|
isDaemonRunning = true;
|
|
|
|
console.log('SDK already running');
|
|
|
|
})
|
|
|
|
.catch(() => {
|
|
|
|
console.log('Starting SDK');
|
|
|
|
});
|
2018-10-26 06:20:18 +02:00
|
|
|
|
2018-01-29 15:14:31 +01:00
|
|
|
if (!isDaemonRunning) {
|
|
|
|
daemon = new Daemon();
|
|
|
|
daemon.on('exit', () => {
|
2018-07-11 07:01:54 +02:00
|
|
|
if (!isDev) {
|
2018-07-11 06:14:50 +02:00
|
|
|
daemon = null;
|
|
|
|
if (!appState.isQuitting) {
|
|
|
|
dialog.showErrorBox(
|
|
|
|
'Daemon has Exited',
|
|
|
|
'The daemon may have encountered an unexpected error, or another daemon instance is already running. \n\n' +
|
|
|
|
'For more information please visit: \n' +
|
2019-03-20 22:43:00 +01:00
|
|
|
'https://lbry.com/faq/startup-troubleshooting'
|
2018-07-11 06:14:50 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
app.quit();
|
2018-01-29 15:14:31 +01:00
|
|
|
}
|
|
|
|
});
|
2019-05-01 16:18:26 +02:00
|
|
|
await daemon.launch();
|
2018-01-29 15:14:31 +01:00
|
|
|
}
|
2019-03-20 20:09:58 +01:00
|
|
|
};
|
2019-01-16 05:33:06 +01:00
|
|
|
|
2019-03-20 20:09:58 +01:00
|
|
|
// When we are starting the app, ensure there are no other apps already running
|
|
|
|
const gotSingleInstanceLock = app.requestSingleInstanceLock();
|
2019-03-19 04:33:46 +01:00
|
|
|
|
2019-03-20 20:09:58 +01:00
|
|
|
if (!gotSingleInstanceLock) {
|
|
|
|
// Another instance already has a lock, abort
|
|
|
|
app.quit();
|
|
|
|
} else {
|
|
|
|
app.on('second-instance', (event, argv) => {
|
|
|
|
// Send the url to the app to navigate first, then focus
|
|
|
|
if (rendererWindow) {
|
2019-05-07 23:38:29 +02:00
|
|
|
if ((process.platform === 'win32' || process.platform === 'linux') && String(argv[1]).startsWith('lbry')) {
|
2019-03-20 20:09:58 +01:00
|
|
|
let URI = argv[1];
|
|
|
|
|
|
|
|
// Keep only command line / deep linked arguments
|
|
|
|
// Windows normalizes URIs when they're passed in from other apps. On Windows, this tries to
|
|
|
|
// restore the original URI that was typed.
|
|
|
|
// - If the URI has no path, Windows adds a trailing slash. LBRY URIs can't have a slash with no
|
|
|
|
// path, so we just strip it off.
|
|
|
|
// - In a URI with a claim ID, like lbry://channel#claimid, Windows interprets the hash mark as
|
|
|
|
// an anchor and converts it to lbry://channel/#claimid. We remove the slash here as well.
|
|
|
|
// - ? also interpreted as an anchor, remove slash also.
|
|
|
|
if (process.platform === 'win32') {
|
|
|
|
URI = URI.replace(/\/$/, '')
|
|
|
|
.replace('/#', '#')
|
|
|
|
.replace('/?', '?');
|
|
|
|
}
|
2019-02-22 06:01:59 +01:00
|
|
|
|
2019-03-20 20:09:58 +01:00
|
|
|
rendererWindow.webContents.send('open-uri-requested', URI);
|
|
|
|
}
|
2019-03-20 18:57:31 +01:00
|
|
|
|
2019-03-20 20:09:58 +01:00
|
|
|
rendererWindow.show();
|
|
|
|
}
|
2018-05-23 04:37:09 +02:00
|
|
|
});
|
2019-02-22 06:01:59 +01:00
|
|
|
|
2019-03-25 07:18:22 +01:00
|
|
|
app.on('ready', async () => {
|
2019-05-01 16:18:26 +02:00
|
|
|
await startDaemon();
|
2019-03-20 20:09:58 +01:00
|
|
|
startSandbox();
|
|
|
|
|
|
|
|
if (isDev) {
|
|
|
|
await installDevtools();
|
2019-03-20 20:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
rendererWindow = createWindow(appState);
|
|
|
|
tray = createTray(rendererWindow);
|
|
|
|
|
|
|
|
if (!isDev) {
|
2019-03-20 20:09:58 +01:00
|
|
|
rendererWindow.webContents.on('devtools-opened', () => {
|
|
|
|
// Send a message to the renderer process so we can log a security warning
|
|
|
|
rendererWindow.webContents.send('devtools-is-opened');
|
|
|
|
});
|
2018-10-26 06:20:18 +02:00
|
|
|
}
|
2019-03-20 20:09:58 +01:00
|
|
|
|
|
|
|
// HACK: patch webrequest to fix devtools incompatibility with electron 2.x.
|
|
|
|
// See https://github.com/electron/electron/issues/13008#issuecomment-400261941
|
|
|
|
session.defaultSession.webRequest.onBeforeRequest({}, (details, callback) => {
|
2019-10-10 07:23:42 +02:00
|
|
|
if (details.url.includes('7accc8730b0f99b5e7c0702ea89d1fa7c17bfe33')) {
|
2019-03-20 20:09:58 +01:00
|
|
|
callback({
|
|
|
|
redirectURL: details.url.replace(
|
|
|
|
'7accc8730b0f99b5e7c0702ea89d1fa7c17bfe33',
|
|
|
|
'57c9d07b416b5a2ea23d28247300e4af36329bdc'
|
|
|
|
),
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
callback({ cancel: false });
|
|
|
|
}
|
|
|
|
});
|
2018-08-06 18:14:58 +02:00
|
|
|
});
|
2019-03-20 20:09:58 +01:00
|
|
|
}
|
2017-10-13 00:04:31 +02:00
|
|
|
|
2018-01-18 03:13:08 +01:00
|
|
|
app.on('activate', () => {
|
2018-07-03 06:57:01 +02:00
|
|
|
if (rendererWindow) {
|
|
|
|
rendererWindow.show();
|
|
|
|
}
|
2017-10-13 00:04:31 +02:00
|
|
|
});
|
2017-12-21 18:32:51 +01:00
|
|
|
|
2018-01-29 13:04:41 +01:00
|
|
|
app.on('will-quit', event => {
|
|
|
|
if (
|
|
|
|
process.platform === 'win32' &&
|
2018-03-20 02:09:48 +01:00
|
|
|
autoUpdateDownloaded &&
|
2018-03-17 21:44:46 +01:00
|
|
|
!appState.autoUpdateAccepted &&
|
2018-03-20 02:09:48 +01:00
|
|
|
!showingAutoUpdateCloseAlert
|
2018-01-29 13:04:41 +01:00
|
|
|
) {
|
2018-03-20 02:09:48 +01:00
|
|
|
// We're on Win and have an update downloaded, but the user declined it (or closed
|
2018-01-23 08:44:15 +01:00
|
|
|
// the app without accepting it). Now the user is closing the app, so the new update
|
|
|
|
// will install. On Mac this is silent, but on Windows they get a confusing permission
|
|
|
|
// escalation dialog, so we show Windows users a warning dialog first.
|
|
|
|
|
2018-03-20 02:09:48 +01:00
|
|
|
showingAutoUpdateCloseAlert = true;
|
2018-01-29 13:04:41 +01:00
|
|
|
dialog.showMessageBox(
|
|
|
|
{
|
|
|
|
type: 'info',
|
|
|
|
title: 'LBRY Will Upgrade',
|
2019-05-07 23:38:29 +02:00
|
|
|
message: 'LBRY has a pending upgrade. Please select "Yes" to install it on the prompt shown after this one.',
|
2018-01-29 13:04:41 +01:00
|
|
|
},
|
|
|
|
() => {
|
|
|
|
app.quit();
|
|
|
|
}
|
|
|
|
);
|
2017-12-04 21:46:51 +01:00
|
|
|
|
2018-01-24 01:46:49 +01:00
|
|
|
event.preventDefault();
|
2018-01-23 08:44:15 +01:00
|
|
|
return;
|
2017-12-04 21:46:51 +01:00
|
|
|
}
|
2017-01-16 20:06:53 +01:00
|
|
|
|
2018-02-24 00:20:12 +01:00
|
|
|
appState.isQuitting = true;
|
2018-03-20 20:01:18 +01:00
|
|
|
if (daemon) {
|
|
|
|
daemon.quit();
|
|
|
|
event.preventDefault();
|
|
|
|
}
|
2018-07-03 07:27:47 +02:00
|
|
|
|
|
|
|
if (rendererWindow) {
|
|
|
|
rendererWindow = null;
|
|
|
|
}
|
2017-12-13 22:36:30 +01:00
|
|
|
});
|
2017-02-23 19:46:25 +01:00
|
|
|
|
2019-05-09 15:53:43 +02:00
|
|
|
app.on('will-finish-launching', () => {
|
|
|
|
// Protocol handler for macOS
|
|
|
|
app.on('open-url', (event, URL) => {
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
if (rendererWindow) {
|
|
|
|
rendererWindow.webContents.send('open-uri-requested', URL);
|
|
|
|
rendererWindow.show();
|
|
|
|
} else {
|
|
|
|
appState.macDeepLinkingURI = URL;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-02-24 00:20:12 +01:00
|
|
|
app.on('before-quit', () => {
|
|
|
|
appState.isQuitting = true;
|
2017-03-24 00:07:08 +01:00
|
|
|
});
|
2017-02-20 19:59:03 +01:00
|
|
|
|
2017-12-21 18:32:51 +01:00
|
|
|
ipcMain.on('upgrade', (event, installerPath) => {
|
|
|
|
app.on('quit', () => {
|
|
|
|
console.log('Launching upgrade installer at', installerPath);
|
2017-03-24 00:07:08 +01:00
|
|
|
// This gets triggered called after *all* other quit-related events, so
|
|
|
|
// we'll only get here if we're fully prepared and quitting for real.
|
2018-01-18 03:13:08 +01:00
|
|
|
shell.openItem(installerPath);
|
2017-02-20 19:59:03 +01:00
|
|
|
});
|
2017-03-17 23:05:25 +01:00
|
|
|
// what to do if no shutdown in a long time?
|
2017-12-21 18:32:51 +01:00
|
|
|
console.log('Update downloaded to', installerPath);
|
2019-10-28 21:55:29 +01:00
|
|
|
console.log('The app will close and you will be prompted to install the latest version of LBRY.');
|
2017-12-21 18:32:51 +01:00
|
|
|
console.log('After the install is complete, please reopen the app.');
|
2018-01-18 03:13:08 +01:00
|
|
|
app.quit();
|
2017-12-04 21:46:51 +01:00
|
|
|
});
|
2017-02-20 19:59:03 +01:00
|
|
|
|
2018-01-23 08:44:15 +01:00
|
|
|
autoUpdater.on('update-downloaded', () => {
|
2018-03-20 02:09:48 +01:00
|
|
|
autoUpdateDownloaded = true;
|
2018-01-29 13:04:41 +01:00
|
|
|
});
|
2018-01-23 08:44:15 +01:00
|
|
|
|
|
|
|
ipcMain.on('autoUpdateAccepted', () => {
|
2018-03-17 21:44:46 +01:00
|
|
|
appState.autoUpdateAccepted = true;
|
2018-01-23 08:44:15 +01:00
|
|
|
autoUpdater.quitAndInstall();
|
2017-12-04 21:46:51 +01:00
|
|
|
});
|
2017-02-20 19:59:03 +01:00
|
|
|
|
2017-12-21 18:32:51 +01:00
|
|
|
ipcMain.on('version-info-requested', () => {
|
2017-12-04 21:46:51 +01:00
|
|
|
function formatRc(ver) {
|
2018-01-18 03:13:08 +01:00
|
|
|
// Adds dash if needed to make RC suffix SemVer friendly
|
2017-12-21 18:32:51 +01:00
|
|
|
return ver.replace(/([^-])rc/, '$1-rc');
|
2017-12-04 21:46:51 +01:00
|
|
|
}
|
2017-09-14 09:36:41 +02:00
|
|
|
|
2018-06-29 23:40:31 +02:00
|
|
|
const localVersion = pjson.version;
|
2018-01-18 03:13:08 +01:00
|
|
|
let result = '';
|
2018-05-23 21:30:45 +02:00
|
|
|
const onSuccess = res => {
|
2017-12-21 18:32:51 +01:00
|
|
|
res.on('data', data => {
|
|
|
|
result += data;
|
|
|
|
});
|
2018-05-23 21:30:45 +02:00
|
|
|
|
2017-12-21 18:32:51 +01:00
|
|
|
res.on('end', () => {
|
2019-03-19 04:33:46 +01:00
|
|
|
let json;
|
|
|
|
try {
|
|
|
|
json = JSON.parse(result);
|
2019-03-19 02:44:49 +01:00
|
|
|
} catch (e) {
|
2019-03-19 04:33:46 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
const tagName = json.tag_name;
|
2019-02-18 18:33:02 +01:00
|
|
|
if (tagName) {
|
|
|
|
const [, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
|
|
|
|
if (!remoteVersion) {
|
|
|
|
if (rendererWindow) {
|
|
|
|
rendererWindow.webContents.send('version-info-received', localVersion);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const upgradeAvailable = SemVer.gt(formatRc(remoteVersion), formatRc(localVersion));
|
|
|
|
if (rendererWindow) {
|
|
|
|
rendererWindow.webContents.send('version-info-received', {
|
|
|
|
remoteVersion,
|
|
|
|
localVersion,
|
|
|
|
upgradeAvailable,
|
|
|
|
});
|
|
|
|
}
|
2017-12-21 18:32:51 +01:00
|
|
|
}
|
2019-02-18 18:33:02 +01:00
|
|
|
} else if (rendererWindow) {
|
2019-11-12 02:19:22 +01:00
|
|
|
rendererWindow.webContents.send('version-info-received', { localVersion });
|
2017-12-21 18:32:51 +01:00
|
|
|
}
|
|
|
|
});
|
2018-05-23 21:30:45 +02:00
|
|
|
};
|
2017-05-10 10:44:06 +02:00
|
|
|
|
2019-03-19 04:33:46 +01:00
|
|
|
const requestLatestRelease = (alreadyRedirected = false) => {
|
2019-03-19 02:44:49 +01:00
|
|
|
const req = https.get(
|
|
|
|
{
|
|
|
|
hostname: 'api.github.com',
|
|
|
|
path: '/repos/lbryio/lbry-desktop/releases/latest',
|
|
|
|
headers: { 'user-agent': `LBRY/${localVersion}` },
|
|
|
|
},
|
|
|
|
res => {
|
|
|
|
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
|
|
requestLatestRelease(res.headers.location, true);
|
|
|
|
} else {
|
|
|
|
onSuccess(res);
|
|
|
|
}
|
2018-05-23 21:30:45 +02:00
|
|
|
}
|
2019-03-19 02:44:49 +01:00
|
|
|
);
|
2018-05-23 21:30:45 +02:00
|
|
|
|
|
|
|
if (alreadyRedirected) return;
|
|
|
|
req.on('error', err => {
|
|
|
|
console.log('Failed to get current version from GitHub. Error:', err);
|
|
|
|
if (rendererWindow) {
|
|
|
|
rendererWindow.webContents.send('version-info-received', null);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2019-11-12 02:19:22 +01:00
|
|
|
if (upgradeDisabled && rendererWindow) {
|
|
|
|
rendererWindow.webContents.send('version-info-received', { localVersion });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-19 04:33:46 +01:00
|
|
|
requestLatestRelease();
|
2017-12-04 21:46:51 +01:00
|
|
|
});
|
2020-01-16 23:03:41 +01:00
|
|
|
|
2020-01-15 05:34:28 +01:00
|
|
|
// In a few months, we can remove the keytar dependency and below calls once
|
|
|
|
// enough users have moved over to cookies
|
2019-09-26 18:07:11 +02:00
|
|
|
ipcMain.on('delete-auth-token', (event, password) => {
|
|
|
|
keytar.deletePassword('LBRY', 'auth_token', password).then(res => {
|
|
|
|
event.sender.send('delete-auth-token-response', res);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2019-08-28 04:35:07 +02:00
|
|
|
ipcMain.on('get-password', event => {
|
|
|
|
keytar.getPassword('LBRY', 'wallet_password').then(password => {
|
|
|
|
event.sender.send('get-password-response', password ? password.toString() : null);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2019-10-24 22:35:32 +02:00
|
|
|
ipcMain.on('delete-password', event => {
|
|
|
|
keytar.deletePassword('LBRY', 'wallet_password').then(res => {
|
|
|
|
event.sender.send('delete-password-response', res);
|
2019-08-28 04:35:07 +02:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-01-08 06:16:31 +01:00
|
|
|
process.on('uncaughtException', error => {
|
2019-03-19 04:33:46 +01:00
|
|
|
console.log(error);
|
2018-01-18 03:13:08 +01:00
|
|
|
dialog.showErrorBox('Error Encountered', `Caught error: ${error}`);
|
2018-02-24 00:20:12 +01:00
|
|
|
appState.isQuitting = true;
|
2018-01-18 03:13:08 +01:00
|
|
|
if (daemon) daemon.quit();
|
|
|
|
app.exit(1);
|
2018-01-05 07:29:31 +01:00
|
|
|
});
|