diff --git a/js/passwordManager/onePassword.js b/js/passwordManager/onePassword.js index f5bee4c21..8f76901a1 100644 --- a/js/passwordManager/onePassword.js +++ b/js/passwordManager/onePassword.js @@ -3,9 +3,19 @@ const path = require('path') const fs = require('fs') var { ipcRenderer } = require('electron') const compareVersions = require('util/compareVersions.js') +const settings = require('util/settings/settings.js') // 1Password password manager. Requires session key to unlock the vault. class OnePassword { + _createDeviceID () { + const chars = 'abcdefghijklmnopqrstuvwxyz1234567890' + let out = '' + for (let i = 0; i < 26; i++) { + out += chars[Math.floor(Math.random() * chars.length)] + } + return out + } + constructor () { this.sessionKey = null this.sessionKeyCreated = 0 @@ -14,6 +24,10 @@ class OnePassword { this.sessionKeyLifetime = 30 * 60 * 1000 this.lastCallList = {} this.name = '1Password' + if (!settings.get('1passwordDeviceID')) { + settings.set('1passwordDeviceID', this._createDeviceID()) + } + this.deviceID = settings.get('1passwordDeviceID') } getDownloadLink () { @@ -109,7 +123,7 @@ class OnePassword { // Loads credential suggestions for given domain name. async loadSuggestions (command, domain) { try { - const process = new ProcessSpawner(command, ['item', 'list', '--categories', 'login', '--session=' + this.sessionKey, '--format=json']) + const process = new ProcessSpawner(command, ['item', 'list', '--categories', 'login', '--session=' + this.sessionKey, '--format=json'], { OP_DEVICE: this.deviceID }) const data = await process.executeSyncInAsyncContext() const matches = JSON.parse(data) @@ -130,7 +144,7 @@ class OnePassword { for (var i = 0; i < credentials.length; i++) { const item = credentials[i] - const process = new ProcessSpawner(command, ['item', 'get', item.id, '--session=' + this.sessionKey, '--format=json']) + const process = new ProcessSpawner(command, ['item', 'get', item.id, '--session=' + this.sessionKey, '--format=json'], { OP_DEVICE: this.deviceID }) const output = await process.executeSyncInAsyncContext() const credential = JSON.parse(output) @@ -157,7 +171,7 @@ class OnePassword { // Tries to unlock the password store with given master password. async unlockStore (password) { try { - const process = new ProcessSpawner(this.path, ['signin', '--raw', '--account', 'min-autofill']) + const process = new ProcessSpawner(this.path, ['signin', '--raw', '--account', 'min-autofill'], { OP_DEVICE: this.deviceID }) const result = await process.executeSyncInAsyncContext(password) // no session key -> invalid password if (!result) { @@ -176,7 +190,7 @@ class OnePassword { async signInAndSave (path = this.path) { // It's possible to be already logged in - const logoutProcess = new ProcessSpawner(path, ['signout']) + const logoutProcess = new ProcessSpawner(path, ['signout'], { OP_DEVICE: this.deviceID }, 5000) try { await logoutProcess.executeSyncInAsyncContext() } catch (e) { @@ -206,7 +220,7 @@ class OnePassword { } } - const process = new ProcessSpawner(path, ['account', 'add', '--address', 'my.1password.com', '--email', credentials.email, '--secret-key', credentials.secretKey, '--shorthand', 'min-autofill', '--signin', '--raw']) + const process = new ProcessSpawner(path, ['account', 'add', '--address', 'my.1password.com', '--email', credentials.email, '--secret-key', credentials.secretKey, '--shorthand', 'min-autofill', '--signin', '--raw'], { OP_DEVICE: this.deviceID }) const key = await process.executeSyncInAsyncContext(credentials.password) if (!key) { diff --git a/js/util/process.js b/js/util/process.js index 02ce0198c..f0ba5c46f 100644 --- a/js/util/process.js +++ b/js/util/process.js @@ -22,11 +22,12 @@ const customEnv = Object.assign({}, process.env, { PATH: processPath }) const maxBufferSize = 25 * 1024 * 1024 class ProcessSpawner { - constructor (command, args, env = {}) { + constructor (command, args, env = {}, timeout = undefined) { this.command = command this.args = args this.data = '' this.error = '' + this.timeout = timeout this.env = Object.assign({}, customEnv, env) } @@ -57,7 +58,7 @@ class ProcessSpawner { } executeSync (input) { - const process = spawnSync(this.command, this.args, { input: input, encoding: 'utf8', env: this.env, maxBuffer: maxBufferSize }) + const process = spawnSync(this.command, this.args, { input: input, encoding: 'utf8', env: this.env, maxBuffer: maxBufferSize, timeout: this.timeout }) return process.output[1].slice(0, -1) } @@ -79,7 +80,8 @@ class ProcessSpawner { input: input, customEnv: this.env, maxBuffer: maxBufferSize, - taskId: taskId + taskId: taskId, + timeout: this.timeout }) }) } @@ -87,7 +89,7 @@ class ProcessSpawner { checkCommandExists () { return new Promise((resolve, reject) => { const checkCommand = (platformType === 'windows') ? 'where' : 'which' - const process = spawn(checkCommand, [this.command], { env: this.env }) + const process = spawn(checkCommand, [this.command], { env: this.env, timeout: this.timeout }) process.stdout.on('data', (data) => { if (data.length > 0) { diff --git a/js/util/processWorker.js b/js/util/processWorker.js index f729f6d3e..d9eb66665 100644 --- a/js/util/processWorker.js +++ b/js/util/processWorker.js @@ -7,9 +7,10 @@ onmessage = function (e) { const input = e.data.input const customEnv = e.data.customEnv const maxBuffer = e.data.maxBuffer + const timeout = e.data.timeout try { - const process = spawnSync(command, args, { input: input, encoding: 'utf8', env: customEnv, maxBuffer: maxBuffer }) + const process = spawnSync(command, args, { input: input, encoding: 'utf8', env: customEnv, maxBuffer: maxBuffer, timeout: timeout }) if (process.error || process.signal) { throw new Error('Process terminated: ' + process.stderr + ', ' + process.signal + ', ' + process.error)