Added recaptcha compatibility
This commit is contained in:
parent
4c93119f73
commit
5948124586
6 changed files with 313 additions and 203 deletions
|
@ -1,52 +1,62 @@
|
||||||
// Module imports
|
// Module imports
|
||||||
const {app, BrowserWindow, ipcMain, Menu, Tray, globalShortcut} = require('electron');
|
const {
|
||||||
const path = require('path');
|
app,
|
||||||
const url = require('url');
|
BrowserWindow,
|
||||||
const jayson = require('jayson');
|
ipcMain,
|
||||||
const semver = require('semver');
|
Menu,
|
||||||
const https = require('https');
|
Tray,
|
||||||
const keytar = require('keytar');
|
globalShortcut,
|
||||||
|
} = require("electron");
|
||||||
|
const path = require("path");
|
||||||
|
const url = require("url");
|
||||||
|
const jayson = require("jayson");
|
||||||
|
const semver = require("semver");
|
||||||
|
const https = require("https");
|
||||||
|
const keytar = require("keytar");
|
||||||
// tree-kill has better cross-platform handling of
|
// tree-kill has better cross-platform handling of
|
||||||
// killing a process. child-process.kill was unreliable
|
// killing a process. child-process.kill was unreliable
|
||||||
const kill = require('tree-kill');
|
const kill = require("tree-kill");
|
||||||
const child_process = require('child_process');
|
const child_process = require("child_process");
|
||||||
const assert = require('assert');
|
const assert = require("assert");
|
||||||
const localVersion = app.getVersion();
|
const localVersion = app.getVersion();
|
||||||
const setMenu = require('./menu/main-menu.js');
|
const setMenu = require("./menu/main-menu.js");
|
||||||
export const contextMenu = require('./menu/context-menu');
|
export const contextMenu = require("./menu/context-menu");
|
||||||
|
|
||||||
// Debug configs
|
// Debug configs
|
||||||
const isDevelopment = process.env.NODE_ENV === 'development';
|
const isDevelopment = process.env.NODE_ENV === "development";
|
||||||
if (isDevelopment) {
|
if (isDevelopment) {
|
||||||
try
|
try {
|
||||||
{
|
const {
|
||||||
const { default: installExtension, REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS } = require('electron-devtools-installer');
|
default: installExtension,
|
||||||
app.on('ready', () => {
|
REACT_DEVELOPER_TOOLS,
|
||||||
|
REDUX_DEVTOOLS,
|
||||||
|
} = require("electron-devtools-installer");
|
||||||
|
app.on("ready", () => {
|
||||||
[REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS].forEach(extension => {
|
[REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS].forEach(extension => {
|
||||||
installExtension(extension)
|
installExtension(extension)
|
||||||
.then((name) => console.log(`Added Extension: ${name}`))
|
.then(name => console.log(`Added Extension: ${name}`))
|
||||||
.catch((err) => console.log('An error occurred: ', err));
|
.catch(err => console.log("An error occurred: ", err));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
} catch (err) {
|
||||||
catch (err)
|
console.error(err);
|
||||||
{
|
|
||||||
console.error(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Misc constants
|
// Misc constants
|
||||||
const LATEST_RELEASE_API_URL = 'https://api.github.com/repos/lbryio/lbry-app/releases/latest';
|
const LATEST_RELEASE_API_URL =
|
||||||
const DAEMON_PATH = process.env.LBRY_DAEMON || path.join(__static, 'daemon/lbrynet-daemon');
|
"https://api.github.com/repos/lbryio/lbry-app/releases/latest";
|
||||||
|
const DAEMON_PATH =
|
||||||
|
process.env.LBRY_DAEMON || path.join(__static, "daemon/lbrynet-daemon");
|
||||||
const rendererUrl = isDevelopment
|
const rendererUrl = isDevelopment
|
||||||
? `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`
|
? `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`
|
||||||
: `file://${__dirname}/index.html`;
|
: `file://${__dirname}/index.html`;
|
||||||
|
|
||||||
let client = jayson.client.http({
|
let client = jayson.client.http({
|
||||||
host: 'localhost',
|
host: "localhost",
|
||||||
port: 5279,
|
port: 5279,
|
||||||
path: '/',
|
path: "/",
|
||||||
timeout: 1000
|
timeout: 1000,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Keep a global reference of the window object, if you don't, the window will
|
// Keep a global reference of the window object, if you don't, the window will
|
||||||
|
@ -84,8 +94,8 @@ function processRequestedUri(uri) {
|
||||||
// lbry://channel/#claimid. We remove the slash here as well.
|
// lbry://channel/#claimid. We remove the slash here as well.
|
||||||
// On Linux and Mac, we just return the URI as given.
|
// On Linux and Mac, we just return the URI as given.
|
||||||
|
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === "win32") {
|
||||||
return uri.replace(/\/$/, '').replace('/#', '#');
|
return uri.replace(/\/$/, "").replace("/#", "#");
|
||||||
} else {
|
} else {
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
@ -97,69 +107,87 @@ function processRequestedUri(uri) {
|
||||||
* when no windows are open.
|
* when no windows are open.
|
||||||
*/
|
*/
|
||||||
function openItem(fullPath) {
|
function openItem(fullPath) {
|
||||||
const subprocOptions = {
|
const subprocOptions = {
|
||||||
detached: true,
|
detached: true,
|
||||||
stdio: 'ignore',
|
stdio: "ignore",
|
||||||
};
|
};
|
||||||
|
|
||||||
let child;
|
let child;
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === "darwin") {
|
||||||
child = child_process.spawn('open', [fullPath], subprocOptions);
|
child = child_process.spawn("open", [fullPath], subprocOptions);
|
||||||
} else if (process.platform === 'linux') {
|
} else if (process.platform === "linux") {
|
||||||
child = child_process.spawn('xdg-open', [fullPath], subprocOptions);
|
child = child_process.spawn("xdg-open", [fullPath], subprocOptions);
|
||||||
} else if (process.platform === 'win32') {
|
} else if (process.platform === "win32") {
|
||||||
child = child_process.spawn(fullPath, Object.assign({}, subprocOptions, {shell: true}));
|
child = child_process.spawn(
|
||||||
}
|
fullPath,
|
||||||
|
Object.assign({}, subprocOptions, { shell: true })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Causes child process reference to be garbage collected, allowing main process to exit
|
// Causes child process reference to be garbage collected, allowing main process to exit
|
||||||
child.unref();
|
child.unref();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPidsForProcessName(name) {
|
function getPidsForProcessName(name) {
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === "win32") {
|
||||||
const tasklistOut = child_process.execSync(`tasklist /fi "Imagename eq ${name}.exe" /nh`, {encoding: 'utf8'});
|
const tasklistOut = child_process.execSync(
|
||||||
if (tasklistOut.startsWith('INFO')) {
|
`tasklist /fi "Imagename eq ${name}.exe" /nh`,
|
||||||
|
{ encoding: "utf8" }
|
||||||
|
);
|
||||||
|
if (tasklistOut.startsWith("INFO")) {
|
||||||
return [];
|
return [];
|
||||||
} else {
|
} else {
|
||||||
return tasklistOut.match(/[^\r\n]+/g).map((line) => line.split(/\s+/)[1]); // Second column of every non-empty line
|
return tasklistOut.match(/[^\r\n]+/g).map(line => line.split(/\s+/)[1]); // Second column of every non-empty line
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const pgrepOut = child_process.spawnSync('pgrep', ['-x', name], {encoding: 'utf8'}).stdout;
|
const pgrepOut = child_process.spawnSync("pgrep", ["-x", name], {
|
||||||
|
encoding: "utf8",
|
||||||
|
}).stdout;
|
||||||
return pgrepOut.match(/\d+/g);
|
return pgrepOut.match(/\d+/g);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createWindow () {
|
function createWindow() {
|
||||||
// Disable renderer process's webSecurity on development to enable CORS.
|
// Disable renderer process's webSecurity on development to enable CORS.
|
||||||
win = isDevelopment
|
win = isDevelopment
|
||||||
? new BrowserWindow({backgroundColor: '#155B4A', minWidth: 800, minHeight: 600, webPreferences: {webSecurity: false}})
|
? new BrowserWindow({
|
||||||
: new BrowserWindow({backgroundColor: '#155B4A', minWidth: 800, minHeight: 600});
|
backgroundColor: "#155B4A",
|
||||||
|
minWidth: 800,
|
||||||
|
minHeight: 600,
|
||||||
|
webPreferences: { webSecurity: false },
|
||||||
|
})
|
||||||
|
: new BrowserWindow({
|
||||||
|
backgroundColor: "#155B4A",
|
||||||
|
minWidth: 800,
|
||||||
|
minHeight: 600,
|
||||||
|
});
|
||||||
|
|
||||||
win.webContents.session.setUserAgent(`LBRY/${localVersion}`);
|
win.webContents.session.setUserAgent(`LBRY/${localVersion}`);
|
||||||
|
|
||||||
win.maximize()
|
win.maximize();
|
||||||
if (isDevelopment) {
|
if (isDevelopment) {
|
||||||
win.webContents.openDevTools();
|
win.webContents.openDevTools();
|
||||||
}
|
}
|
||||||
win.loadURL(rendererUrl)
|
win.loadURL(rendererUrl);
|
||||||
if (openUri) { // We stored and received a URI that an external app requested before we had a window object
|
if (openUri) {
|
||||||
win.webContents.on('did-finish-load', () => {
|
// We stored and received a URI that an external app requested before we had a window object
|
||||||
win.webContents.send('open-uri-requested', openUri);
|
win.webContents.on("did-finish-load", () => {
|
||||||
|
win.webContents.send("open-uri-requested", openUri, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
win.removeAllListeners();
|
win.removeAllListeners();
|
||||||
|
|
||||||
win.on('close', function(event) {
|
win.on("close", function(event) {
|
||||||
if (minimize) {
|
if (minimize) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
win.hide();
|
win.hide();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
win.on('closed', () => {
|
win.on("closed", () => {
|
||||||
win = null
|
win = null;
|
||||||
})
|
});
|
||||||
|
|
||||||
win.on("hide", () => {
|
win.on("hide", () => {
|
||||||
// Checks what to show in the tray icon menu
|
// Checks what to show in the tray icon menu
|
||||||
|
@ -176,7 +204,7 @@ function createWindow () {
|
||||||
if (minimize) updateTray();
|
if (minimize) updateTray();
|
||||||
|
|
||||||
// Unregisters Alt+F4 shortcut
|
// Unregisters Alt+F4 shortcut
|
||||||
globalShortcut.unregister('Alt+F4');
|
globalShortcut.unregister("Alt+F4");
|
||||||
});
|
});
|
||||||
|
|
||||||
win.on("focus", () => {
|
win.on("focus", () => {
|
||||||
|
@ -184,23 +212,22 @@ function createWindow () {
|
||||||
if (minimize) updateTray();
|
if (minimize) updateTray();
|
||||||
|
|
||||||
// Registers shortcut for closing(quitting) the app
|
// Registers shortcut for closing(quitting) the app
|
||||||
globalShortcut.register('Alt+F4', () => safeQuit());
|
globalShortcut.register("Alt+F4", () => safeQuit());
|
||||||
|
|
||||||
win.webContents.send('window-is-focused', null);
|
win.webContents.send("window-is-focused", null);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Menu bar
|
// Menu bar
|
||||||
win.setAutoHideMenuBar(true);
|
win.setAutoHideMenuBar(true);
|
||||||
win.setMenuBarVisibility(isDevelopment);
|
win.setMenuBarVisibility(isDevelopment);
|
||||||
setMenu();
|
setMenu();
|
||||||
|
}
|
||||||
|
|
||||||
};
|
function createTray() {
|
||||||
|
|
||||||
function createTray () {
|
|
||||||
// Minimize to tray logic follows:
|
// Minimize to tray logic follows:
|
||||||
// Set the tray icon
|
// Set the tray icon
|
||||||
let iconPath;
|
let iconPath;
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === "darwin") {
|
||||||
// Using @2x for mac retina screens so the icon isn't blurry
|
// Using @2x for mac retina screens so the icon isn't blurry
|
||||||
// file name needs to include "Template" at the end for dark menu bar
|
// file name needs to include "Template" at the end for dark menu bar
|
||||||
iconPath = path.join(__static, "/img/fav/macTemplate@2x.png");
|
iconPath = path.join(__static, "/img/fav/macTemplate@2x.png");
|
||||||
|
@ -211,9 +238,9 @@ function createTray () {
|
||||||
tray = new Tray(iconPath);
|
tray = new Tray(iconPath);
|
||||||
tray.setToolTip("LBRY App");
|
tray.setToolTip("LBRY App");
|
||||||
tray.setTitle("LBRY");
|
tray.setTitle("LBRY");
|
||||||
tray.on('double-click', () => {
|
tray.on("double-click", () => {
|
||||||
win.show()
|
win.show();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// This needs to be done as for linux the context menu doesn't update automatically(docs)
|
// This needs to be done as for linux the context menu doesn't update automatically(docs)
|
||||||
|
@ -226,27 +253,26 @@ function updateTray() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMenuTemplate () {
|
function getMenuTemplate() {
|
||||||
return [
|
return [
|
||||||
getToggleItem(),
|
getToggleItem(),
|
||||||
{
|
{
|
||||||
label: "Quit",
|
label: "Quit",
|
||||||
click: () => safeQuit(),
|
click: () => safeQuit(),
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
function getToggleItem () {
|
function getToggleItem() {
|
||||||
if (win.isVisible() && win.isFocused()) {
|
if (win.isVisible() && win.isFocused()) {
|
||||||
return {
|
return {
|
||||||
label: 'Hide LBRY App',
|
label: "Hide LBRY App",
|
||||||
click: () => win.hide()
|
click: () => win.hide(),
|
||||||
|
};
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
label: 'Show LBRY App',
|
label: "Show LBRY App",
|
||||||
click: () => win.show()
|
click: () => win.show(),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,20 +282,19 @@ function handleOpenUriRequested(uri) {
|
||||||
// Window not created yet, so store up requested URI for when it is
|
// Window not created yet, so store up requested URI for when it is
|
||||||
openUri = processRequestedUri(uri);
|
openUri = processRequestedUri(uri);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (win.isMinimized()) {
|
if (win.isMinimized()) {
|
||||||
win.restore()
|
win.restore();
|
||||||
} else if (!win.isVisible()) {
|
} else if (!win.isVisible()) {
|
||||||
win.show()
|
win.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
win.focus();
|
win.focus();
|
||||||
win.webContents.send('open-uri-requested', processRequestedUri(uri));
|
win.webContents.send("open-uri-requested", processRequestedUri(uri));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDaemonSubprocessExited() {
|
function handleDaemonSubprocessExited() {
|
||||||
console.log('The daemon has exited.');
|
console.log("The daemon has exited.");
|
||||||
daemonSubprocess = null;
|
daemonSubprocess = null;
|
||||||
if (!daemonStopRequested) {
|
if (!daemonStopRequested) {
|
||||||
// We didn't request to stop the daemon, so display a
|
// We didn't request to stop the daemon, so display a
|
||||||
|
@ -277,27 +302,31 @@ function handleDaemonSubprocessExited() {
|
||||||
//
|
//
|
||||||
// TODO: maybe it would be better to restart the daemon?
|
// TODO: maybe it would be better to restart the daemon?
|
||||||
if (win) {
|
if (win) {
|
||||||
console.log('Did not request daemon stop, so quitting in 5 seconds.');
|
console.log("Did not request daemon stop, so quitting in 5 seconds.");
|
||||||
win.loadURL(`file://${__static}/warning.html`);
|
win.loadURL(`file://${__static}/warning.html`);
|
||||||
setTimeout(quitNow, 5000);
|
setTimeout(quitNow, 5000);
|
||||||
} else {
|
} else {
|
||||||
console.log('Did not request daemon stop, so quitting.');
|
console.log("Did not request daemon stop, so quitting.");
|
||||||
quitNow();
|
quitNow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function launchDaemon() {
|
function launchDaemon() {
|
||||||
assert(!daemonSubprocess, 'Tried to launch daemon twice');
|
assert(!daemonSubprocess, "Tried to launch daemon twice");
|
||||||
|
|
||||||
console.log('Launching daemon:', DAEMON_PATH)
|
console.log("Launching daemon:", DAEMON_PATH);
|
||||||
daemonSubprocess = child_process.spawn(DAEMON_PATH)
|
daemonSubprocess = child_process.spawn(DAEMON_PATH);
|
||||||
// Need to handle the data event instead of attaching to
|
// Need to handle the data event instead of attaching to
|
||||||
// process.stdout because the latter doesn't work. I believe on
|
// process.stdout because the latter doesn't work. I believe on
|
||||||
// windows it buffers stdout and we don't get any meaningful output
|
// windows it buffers stdout and we don't get any meaningful output
|
||||||
daemonSubprocess.stdout.on('data', (buf) => {console.log(String(buf).trim());});
|
daemonSubprocess.stdout.on("data", buf => {
|
||||||
daemonSubprocess.stderr.on('data', (buf) => {console.log(String(buf).trim());});
|
console.log(String(buf).trim());
|
||||||
daemonSubprocess.on('exit', handleDaemonSubprocessExited);
|
});
|
||||||
|
daemonSubprocess.stderr.on("data", buf => {
|
||||||
|
console.log(String(buf).trim());
|
||||||
|
});
|
||||||
|
daemonSubprocess.on("exit", handleDaemonSubprocessExited);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -318,7 +347,7 @@ function quitNow() {
|
||||||
safeQuit();
|
safeQuit();
|
||||||
}
|
}
|
||||||
|
|
||||||
const isSecondaryInstance = app.makeSingleInstance((argv) => {
|
const isSecondaryInstance = app.makeSingleInstance(argv => {
|
||||||
if (argv.length >= 2) {
|
if (argv.length >= 2) {
|
||||||
handleOpenUriRequested(argv[1]); // This will handle restoring and focusing the window
|
handleOpenUriRequested(argv[1]); // This will handle restoring and focusing the window
|
||||||
} else if (win) {
|
} else if (win) {
|
||||||
|
@ -331,25 +360,23 @@ const isSecondaryInstance = app.makeSingleInstance((argv) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isSecondaryInstance) { // We're not in the original process, so quit
|
if (isSecondaryInstance) {
|
||||||
|
// We're not in the original process, so quit
|
||||||
quitNow();
|
quitNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
function launchDaemonIfNotRunning() {
|
function launchDaemonIfNotRunning() {
|
||||||
// Check if the daemon is already running. If we get
|
// Check if the daemon is already running. If we get
|
||||||
// an error its because its not running
|
// an error its because its not running
|
||||||
console.log('Checking for lbrynet daemon');
|
console.log("Checking for lbrynet daemon");
|
||||||
client.request(
|
client.request("status", [], function(err, res) {
|
||||||
'status', [],
|
if (err) {
|
||||||
function (err, res) {
|
console.log("lbrynet daemon needs to be launched");
|
||||||
if (err) {
|
launchDaemon();
|
||||||
console.log('lbrynet daemon needs to be launched')
|
} else {
|
||||||
launchDaemon();
|
console.log("lbrynet daemon is already running");
|
||||||
} else {
|
|
||||||
console.log('lbrynet daemon is already running')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -358,21 +385,31 @@ function launchDaemonIfNotRunning() {
|
||||||
* tries to force kill them.
|
* tries to force kill them.
|
||||||
*/
|
*/
|
||||||
function forceKillAllDaemonsAndQuit() {
|
function forceKillAllDaemonsAndQuit() {
|
||||||
console.log('Attempting to force kill any running lbrynet-daemon instances...');
|
console.log(
|
||||||
|
"Attempting to force kill any running lbrynet-daemon instances..."
|
||||||
|
);
|
||||||
|
|
||||||
const daemonPids = getPidsForProcessName('lbrynet-daemon');
|
const daemonPids = getPidsForProcessName("lbrynet-daemon");
|
||||||
if (!daemonPids) {
|
if (!daemonPids) {
|
||||||
console.log('No lbrynet-daemon found running.');
|
console.log("No lbrynet-daemon found running.");
|
||||||
quitNow();
|
quitNow();
|
||||||
} else {
|
} else {
|
||||||
console.log(`Found ${daemonPids.length} running daemon instances. Attempting to force kill...`);
|
console.log(
|
||||||
|
`Found ${
|
||||||
|
daemonPids.length
|
||||||
|
} running daemon instances. Attempting to force kill...`
|
||||||
|
);
|
||||||
|
|
||||||
for (const pid of daemonPids) {
|
for (const pid of daemonPids) {
|
||||||
let daemonKillAttemptsComplete = 0;
|
let daemonKillAttemptsComplete = 0;
|
||||||
kill(pid, 'SIGKILL', (err) => {
|
kill(pid, "SIGKILL", err => {
|
||||||
daemonKillAttemptsComplete++;
|
daemonKillAttemptsComplete++;
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(`Failed to force kill daemon task with pid ${pid}. Error message: ${err.message}`);
|
console.log(
|
||||||
|
`Failed to force kill daemon task with pid ${pid}. Error message: ${
|
||||||
|
err.message
|
||||||
|
}`
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log(`Force killed daemon task with pid ${pid}.`);
|
console.log(`Force killed daemon task with pid ${pid}.`);
|
||||||
}
|
}
|
||||||
|
@ -384,15 +421,15 @@ function forceKillAllDaemonsAndQuit() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.setAsDefaultProtocolClient('lbry');
|
app.setAsDefaultProtocolClient("lbry");
|
||||||
|
|
||||||
app.on('ready', function() {
|
app.on("ready", function() {
|
||||||
launchDaemonIfNotRunning();
|
launchDaemonIfNotRunning();
|
||||||
if (process.platform === "linux") {
|
if (process.platform === "linux") {
|
||||||
checkLinuxTraySupport( err => {
|
checkLinuxTraySupport(err => {
|
||||||
if (!err) createTray();
|
if (!err) createTray();
|
||||||
else minimize = false;
|
else minimize = false;
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
createTray();
|
createTray();
|
||||||
}
|
}
|
||||||
|
@ -400,36 +437,35 @@ app.on('ready', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Quit when all windows are closed.
|
// Quit when all windows are closed.
|
||||||
app.on('window-all-closed', () => {
|
app.on("window-all-closed", () => {
|
||||||
// On macOS it is common for applications and their menu bar
|
// On macOS it is common for applications and their menu bar
|
||||||
// to stay active until the user quits explicitly with Cmd + Q
|
// to stay active until the user quits explicitly with Cmd + Q
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== "darwin") {
|
||||||
app.quit()
|
app.quit();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
app.on("before-quit", event => {
|
||||||
app.on('before-quit', (event) => {
|
|
||||||
if (!readyToQuit) {
|
if (!readyToQuit) {
|
||||||
// We need to shutdown the daemon before we're ready to actually quit. This
|
// We need to shutdown the daemon before we're ready to actually quit. This
|
||||||
// event will be triggered re-entrantly once preparation is done.
|
// event will be triggered re-entrantly once preparation is done.
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
shutdownDaemonAndQuit();
|
shutdownDaemonAndQuit();
|
||||||
} else {
|
} else {
|
||||||
console.log('Quitting.')
|
console.log("Quitting.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('activate', () => {
|
app.on("activate", () => {
|
||||||
// On macOS it's common to re-create a window in the app when the
|
// On macOS it's common to re-create a window in the app when the
|
||||||
// dock icon is clicked and there are no other windows open.
|
// dock icon is clicked and there are no other windows open.
|
||||||
if (win === null) {
|
if (win === null) {
|
||||||
createWindow()
|
createWindow();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === "darwin") {
|
||||||
app.on('open-url', (event, uri) => {
|
app.on("open-url", (event, uri) => {
|
||||||
handleOpenUriRequested(uri);
|
handleOpenUriRequested(uri);
|
||||||
});
|
});
|
||||||
} else if (process.argv.length >= 2) {
|
} else if (process.argv.length >= 2) {
|
||||||
|
@ -440,14 +476,18 @@ if (process.platform === 'darwin') {
|
||||||
// then calls quitNow() to quit for real.
|
// then calls quitNow() to quit for real.
|
||||||
function shutdownDaemonAndQuit(evenIfNotStartedByApp = false) {
|
function shutdownDaemonAndQuit(evenIfNotStartedByApp = false) {
|
||||||
function doShutdown() {
|
function doShutdown() {
|
||||||
console.log('Shutting down daemon');
|
console.log("Shutting down daemon");
|
||||||
daemonStopRequested = true;
|
daemonStopRequested = true;
|
||||||
client.request('daemon_stop', [], (err, res) => {
|
client.request("daemon_stop", [], (err, res) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(`received error when stopping lbrynet-daemon. Error message: ${err.message}\n`);
|
console.log(
|
||||||
console.log('You will need to manually kill the daemon.');
|
`received error when stopping lbrynet-daemon. Error message: ${
|
||||||
|
err.message
|
||||||
|
}\n`
|
||||||
|
);
|
||||||
|
console.log("You will need to manually kill the daemon.");
|
||||||
} else {
|
} else {
|
||||||
console.log('Successfully stopped daemon via RPC call.')
|
console.log("Successfully stopped daemon via RPC call.");
|
||||||
quitNow();
|
quitNow();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -456,7 +496,7 @@ function shutdownDaemonAndQuit(evenIfNotStartedByApp = false) {
|
||||||
if (daemonSubprocess) {
|
if (daemonSubprocess) {
|
||||||
doShutdown();
|
doShutdown();
|
||||||
} else if (!evenIfNotStartedByApp) {
|
} else if (!evenIfNotStartedByApp) {
|
||||||
console.log('Not killing lbrynet-daemon because app did not start it');
|
console.log("Not killing lbrynet-daemon because app did not start it");
|
||||||
quitNow();
|
quitNow();
|
||||||
} else {
|
} else {
|
||||||
doShutdown();
|
doShutdown();
|
||||||
|
@ -467,24 +507,27 @@ function shutdownDaemonAndQuit(evenIfNotStartedByApp = false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Taken from webtorrent-desktop
|
// Taken from webtorrent-desktop
|
||||||
function checkLinuxTraySupport (cb) {
|
function checkLinuxTraySupport(cb) {
|
||||||
// Check that we're on Ubuntu (or another debian system) and that we have
|
// Check that we're on Ubuntu (or another debian system) and that we have
|
||||||
// libappindicator1.
|
// libappindicator1.
|
||||||
child_process.exec('dpkg --get-selections libappindicator1', function (err, stdout) {
|
child_process.exec("dpkg --get-selections libappindicator1", function(
|
||||||
if (err) return cb(err)
|
err,
|
||||||
|
stdout
|
||||||
|
) {
|
||||||
|
if (err) return cb(err);
|
||||||
// Unfortunately there's no cleaner way, as far as I can tell, to check
|
// Unfortunately there's no cleaner way, as far as I can tell, to check
|
||||||
// whether a debian package is installed:
|
// whether a debian package is installed:
|
||||||
if (stdout.endsWith('\tinstall\n')) {
|
if (stdout.endsWith("\tinstall\n")) {
|
||||||
cb(null)
|
cb(null);
|
||||||
} else {
|
} else {
|
||||||
cb(new Error('debian package not installed'))
|
cb(new Error("debian package not installed"));
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.on('upgrade', (event, installerPath) => {
|
ipcMain.on("upgrade", (event, installerPath) => {
|
||||||
app.on('quit', () => {
|
app.on("quit", () => {
|
||||||
console.log('Launching upgrade installer at', installerPath);
|
console.log("Launching upgrade installer at", installerPath);
|
||||||
// This gets triggered called after *all* other quit-related events, so
|
// 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.
|
// we'll only get here if we're fully prepared and quitting for real.
|
||||||
openItem(installerPath);
|
openItem(installerPath);
|
||||||
|
@ -497,58 +540,77 @@ ipcMain.on('upgrade', (event, installerPath) => {
|
||||||
shutdownDaemonAndQuit(true);
|
shutdownDaemonAndQuit(true);
|
||||||
// wait for daemon to shut down before upgrading
|
// wait for daemon to shut down before upgrading
|
||||||
// what to do if no shutdown in a long time?
|
// what to do if no shutdown in a long time?
|
||||||
console.log('Update downloaded to', installerPath);
|
console.log("Update downloaded to", installerPath);
|
||||||
console.log('The app will close, and you will be prompted to install the latest version of LBRY.');
|
console.log(
|
||||||
console.log('After the install is complete, please reopen the app.');
|
"The app will close, and you will be prompted to install the latest version of LBRY."
|
||||||
|
);
|
||||||
|
console.log("After the install is complete, please reopen the app.");
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('version-info-requested', () => {
|
ipcMain.on("version-info-requested", () => {
|
||||||
function formatRc(ver) {
|
function formatRc(ver) {
|
||||||
// Adds dash if needed to make RC suffix semver friendly
|
// Adds dash if needed to make RC suffix semver friendly
|
||||||
return ver.replace(/([^-])rc/, '$1-rc');
|
return ver.replace(/([^-])rc/, "$1-rc");
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = '';
|
let result = "";
|
||||||
const opts = {
|
const opts = {
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': `LBRY/${localVersion}`,
|
"User-Agent": `LBRY/${localVersion}`,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const req = https.get(Object.assign(opts, url.parse(LATEST_RELEASE_API_URL)), (res) => {
|
const req = https.get(
|
||||||
res.on('data', (data) => {
|
Object.assign(opts, url.parse(LATEST_RELEASE_API_URL)),
|
||||||
result += data;
|
res => {
|
||||||
});
|
res.on("data", data => {
|
||||||
res.on('end', () => {
|
result += data;
|
||||||
const tagName = JSON.parse(result).tag_name;
|
});
|
||||||
const [_, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
|
res.on("end", () => {
|
||||||
if (!remoteVersion) {
|
const tagName = JSON.parse(result).tag_name;
|
||||||
if (win) {
|
const [_, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
|
||||||
win.webContents.send('version-info-received', null);
|
if (!remoteVersion) {
|
||||||
|
if (win) {
|
||||||
|
win.webContents.send("version-info-received", null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const upgradeAvailable = semver.gt(
|
||||||
|
formatRc(remoteVersion),
|
||||||
|
formatRc(localVersion)
|
||||||
|
);
|
||||||
|
if (win) {
|
||||||
|
win.webContents.send("version-info-received", {
|
||||||
|
remoteVersion,
|
||||||
|
localVersion,
|
||||||
|
upgradeAvailable,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
});
|
||||||
const upgradeAvailable = semver.gt(formatRc(remoteVersion), formatRc(localVersion));
|
}
|
||||||
if (win) {
|
);
|
||||||
win.webContents.send('version-info-received', {remoteVersion, localVersion, upgradeAvailable});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
req.on('error', (err) => {
|
req.on("error", err => {
|
||||||
console.log('Failed to get current version from GitHub. Error:', err);
|
console.log("Failed to get current version from GitHub. Error:", err);
|
||||||
if (win) {
|
if (win) {
|
||||||
win.webContents.send('version-info-received', null);
|
win.webContents.send("version-info-received", null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('get-auth-token', (event) => {
|
ipcMain.on("get-auth-token", event => {
|
||||||
keytar.getPassword("LBRY", "auth_token").then(token => {
|
keytar.getPassword("LBRY", "auth_token").then(token => {
|
||||||
event.sender.send('auth-token-response', token ? token.toString().trim() : null)
|
event.sender.send(
|
||||||
|
"auth-token-response",
|
||||||
|
token ? token.toString().trim() : null
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('set-auth-token', (event, token) => {
|
ipcMain.on("set-auth-token", (event, token) => {
|
||||||
keytar.setPassword("LBRY", "auth_token", token ? token.toString().trim() : null);
|
keytar.setPassword(
|
||||||
|
"LBRY",
|
||||||
|
"auth_token",
|
||||||
|
token ? token.toString().trim() : null
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { doUserEmailVerify } from "redux/actions/user";
|
import {
|
||||||
|
doUserEmailVerify,
|
||||||
|
doUserEmailVerifyFailure,
|
||||||
|
} from "redux/actions/user";
|
||||||
import {
|
import {
|
||||||
selectEmailVerifyIsPending,
|
selectEmailVerifyIsPending,
|
||||||
selectEmailToVerify,
|
selectEmailToVerify,
|
||||||
|
@ -20,7 +23,9 @@ const select = state => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
verifyUserEmail: code => dispatch(doUserEmailVerify(code)),
|
verifyUserEmail: (code, recaptcha) =>
|
||||||
|
dispatch(doUserEmailVerify(code, recaptcha)),
|
||||||
|
verifyUserEmailFailure: error => dispatch(doUserEmailVerifyFailure(error)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(UserEmailVerify);
|
export default connect(select, perform)(UserEmailVerify);
|
||||||
|
|
|
@ -20,7 +20,12 @@ class UserEmailVerify extends React.PureComponent {
|
||||||
|
|
||||||
handleSubmit() {
|
handleSubmit() {
|
||||||
const { code } = this.state;
|
const { code } = this.state;
|
||||||
this.props.verifyUserEmail(code);
|
try {
|
||||||
|
let verification = JSON.parse(atob(code));
|
||||||
|
this.props.verifyUserEmail(verification.token, verification.recaptcha);
|
||||||
|
} catch (error) {
|
||||||
|
this.props.verifyUserEmailFailure("Invalid Verification Token");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -5,8 +5,13 @@ import SnackBar from "component/snackBar";
|
||||||
import { Provider } from "react-redux";
|
import { Provider } from "react-redux";
|
||||||
import store from "store.js";
|
import store from "store.js";
|
||||||
import SplashScreen from "component/splash";
|
import SplashScreen from "component/splash";
|
||||||
import { doDaemonReady } from "redux/actions/app";
|
import {
|
||||||
|
doDaemonReady,
|
||||||
|
doShowSnackBar,
|
||||||
|
doConditionalAuthNavigate,
|
||||||
|
} from "redux/actions/app";
|
||||||
import { doNavigate } from "redux/actions/navigation";
|
import { doNavigate } from "redux/actions/navigation";
|
||||||
|
import { doUserEmailVerify } from "redux/actions/user";
|
||||||
import { doDownloadLanguages } from "redux/actions/settings";
|
import { doDownloadLanguages } from "redux/actions/settings";
|
||||||
import * as types from "constants/action_types";
|
import * as types from "constants/action_types";
|
||||||
import amplitude from "amplitude-js";
|
import amplitude from "amplitude-js";
|
||||||
|
@ -37,9 +42,26 @@ window.addEventListener("contextmenu", event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcRenderer.on("open-uri-requested", (event, uri) => {
|
ipcRenderer.on("open-uri-requested", (event, uri, newSession) => {
|
||||||
if (uri && uri.startsWith("lbry://")) {
|
if (uri && uri.startsWith("lbry://")) {
|
||||||
app.store.dispatch(doNavigate("/show", { uri }));
|
if (uri.startsWith("lbry://?verify=")) {
|
||||||
|
let verification = {};
|
||||||
|
try {
|
||||||
|
verification = JSON.parse(atob(uri.substring(15)));
|
||||||
|
} catch (error) {}
|
||||||
|
if (verification.token && verification.recaptcha) {
|
||||||
|
app.store.dispatch(doConditionalAuthNavigate(newSession));
|
||||||
|
app.store.dispatch(
|
||||||
|
doUserEmailVerify(verification.token, verification.recaptcha)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
app.store.dispatch(
|
||||||
|
doShowSnackBar({ message: "Invalid Verification URI" })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
app.store.dispatch(doNavigate("/show", { uri }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
selectUpgradeFilename,
|
selectUpgradeFilename,
|
||||||
selectIsUpgradeSkipped,
|
selectIsUpgradeSkipped,
|
||||||
selectRemoteVersion,
|
selectRemoteVersion,
|
||||||
|
selectCurrentModal,
|
||||||
} from "redux/selectors/app";
|
} from "redux/selectors/app";
|
||||||
import { doFetchDaemonSettings } from "redux/actions/settings";
|
import { doFetchDaemonSettings } from "redux/actions/settings";
|
||||||
import { doBalanceSubscribe } from "redux/actions/wallet";
|
import { doBalanceSubscribe } from "redux/actions/wallet";
|
||||||
|
@ -14,8 +15,7 @@ import { doAuthenticate } from "redux/actions/user";
|
||||||
import { doFetchFileInfosAndPublishedClaims } from "redux/actions/file_info";
|
import { doFetchFileInfosAndPublishedClaims } from "redux/actions/file_info";
|
||||||
import * as modals from "constants/modal_types";
|
import * as modals from "constants/modal_types";
|
||||||
import { doFetchRewardedContent } from "redux/actions/content";
|
import { doFetchRewardedContent } from "redux/actions/content";
|
||||||
import { selectCurrentModal } from "redux/selectors/app";
|
import { doAuthNavigate } from "redux/actions/navigation";
|
||||||
|
|
||||||
const { remote, ipcRenderer, shell } = require("electron");
|
const { remote, ipcRenderer, shell } = require("electron");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const { download } = remote.require("electron-dl");
|
const { download } = remote.require("electron-dl");
|
||||||
|
@ -266,3 +266,12 @@ export function doChangeVolume(volume) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function doConditionalAuthNavigate(newSession) {
|
||||||
|
return function(dispatch, getState) {
|
||||||
|
const state = getState();
|
||||||
|
if (newSession || selectCurrentModal(state) !== "email_collection") {
|
||||||
|
dispatch(doAuthNavigate());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -68,14 +68,14 @@ export function doUserEmailNew(email) {
|
||||||
data: { email },
|
data: { email },
|
||||||
});
|
});
|
||||||
dispatch(doUserFetch());
|
dispatch(doUserFetch());
|
||||||
}
|
};
|
||||||
|
|
||||||
const failure = error => {
|
const failure = error => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.USER_EMAIL_NEW_FAILURE,
|
type: types.USER_EMAIL_NEW_FAILURE,
|
||||||
data: { error },
|
data: { error },
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
lbryio
|
lbryio
|
||||||
.call(
|
.call(
|
||||||
|
@ -86,12 +86,14 @@ export function doUserEmailNew(email) {
|
||||||
)
|
)
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
if (error.response && error.response.status == 409) {
|
if (error.response && error.response.status == 409) {
|
||||||
return lbryio.call(
|
return lbryio
|
||||||
"user_email",
|
.call(
|
||||||
"resend_token",
|
"user_email",
|
||||||
{ email: email, only_if_expired: true },
|
"resend_token",
|
||||||
"post"
|
{ email: email, only_if_expired: true },
|
||||||
).then(success, failure);
|
"post"
|
||||||
|
)
|
||||||
|
.then(success, failure);
|
||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
})
|
})
|
||||||
|
@ -99,21 +101,25 @@ export function doUserEmailNew(email) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doUserEmailVerify(verificationToken) {
|
export function doUserEmailVerify(verificationToken, recaptcha) {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch, getState) {
|
||||||
const email = selectEmailToVerify(getState());
|
const email = selectEmailToVerify(getState());
|
||||||
verificationToken = verificationToken.toString().trim();
|
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.USER_EMAIL_VERIFY_STARTED,
|
type: types.USER_EMAIL_VERIFY_STARTED,
|
||||||
code: verificationToken,
|
code: verificationToken,
|
||||||
|
recaptcha: recaptcha,
|
||||||
});
|
});
|
||||||
|
|
||||||
lbryio
|
lbryio
|
||||||
.call(
|
.call(
|
||||||
"user_email",
|
"user_email",
|
||||||
"confirm",
|
"confirm",
|
||||||
{ verification_token: verificationToken, email: email },
|
{
|
||||||
|
verification_token: verificationToken,
|
||||||
|
email: email,
|
||||||
|
recaptcha: recaptcha,
|
||||||
|
},
|
||||||
"post"
|
"post"
|
||||||
)
|
)
|
||||||
.then(userEmail => {
|
.then(userEmail => {
|
||||||
|
@ -128,12 +134,13 @@ export function doUserEmailVerify(verificationToken) {
|
||||||
throw new Error("Your email is still not verified."); //shouldn't happen
|
throw new Error("Your email is still not verified."); //shouldn't happen
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => dispatch(doUserEmailVerifyFailure(error)));
|
||||||
dispatch({
|
};
|
||||||
type: types.USER_EMAIL_VERIFY_FAILURE,
|
}
|
||||||
data: { error },
|
export function doUserEmailVerifyFailure(error) {
|
||||||
});
|
return {
|
||||||
});
|
type: types.USER_EMAIL_VERIFY_FAILURE,
|
||||||
|
data: { error },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue