|
@ -5,7 +5,7 @@ const bwRun = require('./exec-bitwarden-cli') |
|
|
const obfuscate = require('./util/obfuscate/object') |
|
|
const obfuscate = require('./util/obfuscate/object') |
|
|
|
|
|
|
|
|
// get a session token, either from existing sessionFile or by `bw unlock [password]`
|
|
|
// get a session token, either from existing sessionFile or by `bw unlock [password]`
|
|
|
const getSessionVar = async ({ saveSession, sessionFile }) => { |
|
|
|
|
|
|
|
|
const getSessionVar = async ({ dmenuPswdArgs, saveSession, sessionFile }) => { |
|
|
if (saveSession) { |
|
|
if (saveSession) { |
|
|
console.debug(`checking for session file at ${sessionFile}`) |
|
|
console.debug(`checking for session file at ${sessionFile}`) |
|
|
const sessionFileExists = existsSync(sessionFile) |
|
|
const sessionFileExists = existsSync(sessionFile) |
|
@ -19,7 +19,7 @@ const getSessionVar = async ({ saveSession, sessionFile }) => { |
|
|
} else { |
|
|
} else { |
|
|
console.debug('no session file found.') |
|
|
console.debug('no session file found.') |
|
|
// prompt for password in dmenu
|
|
|
// prompt for password in dmenu
|
|
|
const password = await dmenuRun('-p Password: -nf black -nb black')('\n') |
|
|
|
|
|
|
|
|
const password = await dmenuRun(`-p Password: -nf black -nb black ${dmenuPswdArgs}`)('\n') |
|
|
if (!password) throw new Error('no password given!') |
|
|
if (!password) throw new Error('no password given!') |
|
|
const session = bwRun('unlock', password, '--raw') |
|
|
const session = bwRun('unlock', password, '--raw') |
|
|
writeFileSync(sessionFile, session) |
|
|
writeFileSync(sessionFile, session) |
|
@ -27,7 +27,8 @@ const getSessionVar = async ({ saveSession, sessionFile }) => { |
|
|
return session |
|
|
return session |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
const password = await dmenuRun('-p Password: -nf black -nb black')('\n') |
|
|
|
|
|
|
|
|
// Why doesn't dmenuRun('...', dmenuPswdArgs)('\n') work here?
|
|
|
|
|
|
const password = await dmenuRun(`-p Password: -nf black -nb black ${dmenuPswdArgs}`)('\n') |
|
|
if (!password) throw new Error('no password given!') |
|
|
if (!password) throw new Error('no password given!') |
|
|
const session = bwRun('unlock', password, '--raw') |
|
|
const session = bwRun('unlock', password, '--raw') |
|
|
return session |
|
|
return session |
|
@ -47,23 +48,20 @@ const syncIfNecessary = ({ session, oldestAllowedVaultSync }) => { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// get the list all password accounts in the vault
|
|
|
// get the list all password accounts in the vault
|
|
|
const getAccounts = ({ session, urlFilter }) => { |
|
|
|
|
|
const listStr = urlFilter |
|
|
|
|
|
? bwRun('list', 'items', `--url=${urlFilter}`, `--session=${session}`) |
|
|
|
|
|
: bwRun('list', 'items', `--session=${session}`) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const getAccounts = ({ session, bwListArgs }) => { |
|
|
|
|
|
const listStr = bwRun('list', 'items', bwListArgs, `--session=${session}`) |
|
|
const list = JSON.parse(listStr) |
|
|
const list = JSON.parse(listStr) |
|
|
return list |
|
|
return list |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// choose one account with dmenu
|
|
|
// choose one account with dmenu
|
|
|
const chooseAccount = async ({ list, length }) => { |
|
|
|
|
|
|
|
|
const chooseAccount = async ({ list, dmenuArgs }) => { |
|
|
const LOGIN_TYPE = 1 |
|
|
const LOGIN_TYPE = 1 |
|
|
const loginList = list.filter(a => a.type === LOGIN_TYPE) |
|
|
const loginList = list.filter(a => a.type === LOGIN_TYPE) |
|
|
|
|
|
|
|
|
const accountNames = loginList.map(a => `${a.name}: ${a.login.username}`) |
|
|
const accountNames = loginList.map(a => `${a.name}: ${a.login.username}`) |
|
|
// -i allows case insensitive matching
|
|
|
// -i allows case insensitive matching
|
|
|
const selected = await dmenuRun(`-l ${length}`)(accountNames.join('\n')) |
|
|
|
|
|
|
|
|
const selected = await dmenuRun(dmenuArgs)(accountNames.join('\n')) |
|
|
const index = accountNames.indexOf(selected) |
|
|
const index = accountNames.indexOf(selected) |
|
|
// accountNames indexes match loginList indexes
|
|
|
// accountNames indexes match loginList indexes
|
|
|
const selectedAccount = loginList[index] |
|
|
const selectedAccount = loginList[index] |
|
@ -72,7 +70,7 @@ const chooseAccount = async ({ list, length }) => { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// choose one field with dmenu
|
|
|
// choose one field with dmenu
|
|
|
const chooseField = async ({ selectedAccount, length }) => { |
|
|
|
|
|
|
|
|
const chooseField = async ({ selectedAccount, dmenuArgs }) => { |
|
|
if (!selectedAccount) throw new Error('no account selected!') |
|
|
if (!selectedAccount) throw new Error('no account selected!') |
|
|
const copyable = { |
|
|
const copyable = { |
|
|
password: selectedAccount.login.password, |
|
|
password: selectedAccount.login.password, |
|
@ -86,36 +84,37 @@ const chooseField = async ({ selectedAccount, length }) => { |
|
|
{} |
|
|
{} |
|
|
) |
|
|
) |
|
|
} |
|
|
} |
|
|
const field = await dmenuRun(`-l ${length}`)(Object.keys(copyable).join('\n')) |
|
|
|
|
|
|
|
|
const field = await dmenuRun(dmenuArgs)(Object.keys(copyable).join('\n')) |
|
|
console.debug(`selected field '${field}'`) |
|
|
console.debug(`selected field '${field}'`) |
|
|
const valueToCopy = copyable[field] |
|
|
const valueToCopy = copyable[field] |
|
|
return valueToCopy |
|
|
return valueToCopy |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
module.exports = async ({ |
|
|
module.exports = async ({ |
|
|
length, |
|
|
|
|
|
|
|
|
bwListArgs, |
|
|
|
|
|
dmenuArgs, |
|
|
|
|
|
dmenuPswdArgs, |
|
|
saveSession, |
|
|
saveSession, |
|
|
sessionFile, |
|
|
sessionFile, |
|
|
stdout, |
|
|
stdout, |
|
|
oldestAllowedVaultSync, |
|
|
|
|
|
urlFilter, |
|
|
|
|
|
|
|
|
oldestAllowedVaultSync |
|
|
}) => { |
|
|
}) => { |
|
|
const session = await getSessionVar({ saveSession, sessionFile }) |
|
|
|
|
|
|
|
|
const session = await getSessionVar({ dmenuPswdArgs, saveSession, sessionFile }) |
|
|
|
|
|
|
|
|
// bw sync if necessary
|
|
|
// bw sync if necessary
|
|
|
syncIfNecessary({ session, oldestAllowedVaultSync }) |
|
|
syncIfNecessary({ session, oldestAllowedVaultSync }) |
|
|
|
|
|
|
|
|
// bw list
|
|
|
// bw list
|
|
|
const list = getAccounts({ session, urlFilter }) |
|
|
|
|
|
|
|
|
const list = getAccounts({ session, bwListArgs }) |
|
|
|
|
|
|
|
|
// choose account in dmenu
|
|
|
// choose account in dmenu
|
|
|
const selectedAccount = await chooseAccount({ list, length }) |
|
|
|
|
|
|
|
|
const selectedAccount = await chooseAccount({ list, dmenuArgs }) |
|
|
|
|
|
|
|
|
if(stdout) { |
|
|
if(stdout) { |
|
|
console.log(`${selectedAccount.login.username}\n${selectedAccount.login.password}`) |
|
|
console.log(`${selectedAccount.login.username}\n${selectedAccount.login.password}`) |
|
|
} else { |
|
|
} else { |
|
|
// choose field to copy in dmenu
|
|
|
// choose field to copy in dmenu
|
|
|
const valueToCopy = await chooseField({ selectedAccount, length }) |
|
|
|
|
|
|
|
|
const valueToCopy = await chooseField({ selectedAccount, dmenuArgs }) |
|
|
|
|
|
|
|
|
// copy to clipboard
|
|
|
// copy to clipboard
|
|
|
clipboardy.writeSync(valueToCopy) |
|
|
clipboardy.writeSync(valueToCopy) |
|
|