Skip to content

Commit

Permalink
Feature/output different format (#18)
Browse files Browse the repository at this point in the history
* Add different output formats

* Run lint

* Remove debug log
  • Loading branch information
jboillot authored Apr 20, 2022
1 parent cefb67c commit 88cbd7b
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 34 deletions.
40 changes: 30 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { program } from 'commander';
import winston from 'winston';
import { sync } from './middleware/sync.js';
import { getNote } from './middleware/getSecureNotes.js';
import { getOtp, getPassword } from './middleware/getPasswords.js';
import { getOtp, getPassword, selectCredentials } from './middleware/getPasswords.js';
import { connectAndPrepare } from './database/index.js';

const debugLevel = process.argv.indexOf('--debug') !== -1 ? 'debug' : 'info';
Expand Down Expand Up @@ -31,16 +31,36 @@ program
.command('password')
.alias('p')
.description('Retrieve passwords from local vault and save it in the clipboard.')
.option('--print, -p', 'Prints just the password, instead of copying it inside the clipboard')
.option(
'--output <type>',
'How to print the passwords among `clipboard, password, json`. The JSON option outputs all the matching credentials.',
'clipboard'
)
.argument('[filter]', 'Filter passwords based on their title (usually the website)')
.action(async (filter: string | null, options: { print: boolean }) => {
.action(async (filter: string | null, options: { output: string | null }) => {
const { db, deviceKeys } = await connectAndPrepare();
await getPassword({
titleFilter: filter,
login: deviceKeys.login,
print: options.print,
db,
});

if (options.output === 'json') {
console.log(
JSON.stringify(
await selectCredentials({
titleFilter: filter,
login: deviceKeys.login,
output: options.output,
db,
}),
null,
4
)
);
} else {
await getPassword({
titleFilter: filter,
login: deviceKeys.login,
output: options.output,
db,
});
}
db.close();
});

Expand All @@ -55,7 +75,7 @@ program
await getOtp({
titleFilter: filter,
login: deviceKeys.login,
print: options.print,
output: options.print ? 'otp' : 'clipboard',
db,
});
db.close();
Expand Down
56 changes: 35 additions & 21 deletions src/middleware/getPasswords.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import winston from 'winston';
import { decryptTransaction, getDerivate } from '../crypto/decrypt.js';
import { BackupEditTransaction, VaultCredential, AuthentifiantTransactionContent } from '../types.js';
import { askReplaceMasterPassword, getMasterPassword, setMasterPassword } from '../steps/keychainManager.js';
import { notEmpty } from '../utils';
import { notEmpty } from '../utils.js';

interface GetCredential {
titleFilter: string | null;
login: string;
print: boolean;
output: string | null;
db: Database.Database;
}

Expand Down Expand Up @@ -55,7 +55,7 @@ const decryptPasswordTransactions = async (
}
};

export const selectCredential = async (params: GetCredential, onlyOtpCredentials = false): Promise<VaultCredential> => {
export const selectCredentials = async (params: GetCredential): Promise<VaultCredential[]> => {
const { login, titleFilter, db } = params;

const masterPassword = await getMasterPassword(login);
Expand Down Expand Up @@ -91,6 +91,12 @@ export const selectCredential = async (params: GetCredential, onlyOtpCredentials
);
}

return matchedCredentials;
};

export const selectCredential = async (params: GetCredential, onlyOtpCredentials = false): Promise<VaultCredential> => {
let matchedCredentials = await selectCredentials(params);

if (onlyOtpCredentials) {
matchedCredentials = matchedCredentials.filter((credential) => credential.otpSecret);
}
Expand All @@ -101,7 +107,7 @@ export const selectCredential = async (params: GetCredential, onlyOtpCredentials
return matchedCredentials[0];
}

const message = titleFilter
const message = params.titleFilter
? 'There are multiple results for your query, pick one:'
: 'What password would you like to get?';

Expand Down Expand Up @@ -141,18 +147,22 @@ export const selectCredential = async (params: GetCredential, onlyOtpCredentials
export const getPassword = async (params: GetCredential): Promise<void> => {
const selectedCredential = await selectCredential(params);

if (params.print) {
console.log(selectedCredential.password);
return;
}
switch (params.output || 'clipboard') {
case 'clipboard':
clipboard.default.writeSync(selectedCredential.password);
console.log(`🔓 Password for "${selectedCredential.title}" copied to clipboard!`);

clipboard.default.writeSync(selectedCredential.password);
console.log(`🔓 Password for "${selectedCredential.title}" copied to clipboard!`);

if (selectedCredential.otpSecret) {
const token = authenticator.generate(selectedCredential.otpSecret);
const timeRemaining = authenticator.timeRemaining();
console.log(`🔢 OTP code: ${token} \u001B[3m(expires in ${timeRemaining} seconds)\u001B[0m`);
if (selectedCredential.otpSecret) {
const token = authenticator.generate(selectedCredential.otpSecret);
const timeRemaining = authenticator.timeRemaining();
console.log(`🔢 OTP code: ${token} \u001B[3m(expires in ${timeRemaining} seconds)\u001B[0m`);
}
break;
case 'password':
console.log(selectedCredential.password);
break;
default:
throw new Error('Unable to recognize the output mode.');
}
};

Expand All @@ -162,11 +172,15 @@ export const getOtp = async (params: GetCredential): Promise<void> => {
// otpSecret can't be null because onlyOtpCredentials is set to true above
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const token = authenticator.generate(selectedCredential.otpSecret!);
if (params.print) {
console.log(token);
return;
}

const timeRemaining = authenticator.timeRemaining();
console.log(`🔢 OTP code: ${token} \u001B[3m(expires in ${timeRemaining} seconds)\u001B[0m`);
switch (params.output || 'clipboard') {
case 'clipboard':
console.log(`🔢 OTP code: ${token} \u001B[3m(expires in ${timeRemaining} seconds)\u001B[0m`);
break;
case 'otp':
console.log(token);
break;
default:
throw new Error('Unable to recognize the output mode.');
}
};
6 changes: 3 additions & 3 deletions src/middleware/getSecureNotes.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import winston from 'winston';
import Database from 'better-sqlite3';
import inquirer from 'inquirer';
import inquirerAutocomplete from 'inquirer-autocomplete-prompt';

import { BackupEditTransaction, SecureNoteTransactionContent, VaultNote } from '../types.js';
import { decryptTransaction, getDerivate } from '../crypto/decrypt.js';
import { askReplaceMasterPassword, getMasterPassword, setMasterPassword } from '../steps/index.js';
import inquirer from 'inquirer';
import inquirerAutocomplete from 'inquirer-autocomplete-prompt';
import { notEmpty } from '../utils';
import { notEmpty } from '../utils.js';

interface GetSecureNote {
titleFilter: string | null;
Expand Down

0 comments on commit 88cbd7b

Please sign in to comment.