From b43b80222193b628dad5d23613aa7bf762f006b4 Mon Sep 17 00:00:00 2001 From: Niccolo Borgioli Date: Thu, 25 May 2023 10:16:44 +0200 Subject: [PATCH] add --all option, stdin and password option --- packages/cli/src/download.ts | 57 +++++++++++++++++++++--------------- packages/cli/src/index.ts | 6 +++- packages/cli/src/stdin.ts | 22 ++++++++------ 3 files changed, 51 insertions(+), 34 deletions(-) diff --git a/packages/cli/src/download.ts b/packages/cli/src/download.ts index 88a72d1..8fb574f 100644 --- a/packages/cli/src/download.ts +++ b/packages/cli/src/download.ts @@ -7,7 +7,7 @@ import pretty from 'pretty-bytes' import { exit } from './utils' -export async function download(url: URL) { +export async function download(url: URL, all: boolean, suggestedPassword?: string) { setBase(url.origin) const id = url.pathname.split('/')[2] const preview = await info(id).catch(() => exit('Note does not exist or is expired')) @@ -16,14 +16,18 @@ export async function download(url: URL) { let password: string const derivation = preview?.meta.derivation if (derivation) { - const response = await inquirer.prompt([ - { - type: 'password', - message: 'Note password', - name: 'password', - }, - ]) - password = response.password + if (suggestedPassword) { + password = suggestedPassword + } else { + const response = await inquirer.prompt([ + { + type: 'password', + message: 'Note password', + name: 'password', + }, + ]) + password = response.password + } } else { password = url.hash.slice(1) } @@ -39,25 +43,29 @@ export async function download(url: URL) { exit('No files found in note') return } - const { names } = await inquirer.prompt([ - { - type: 'checkbox', - message: 'What files should be saved?', - name: 'names', - choices: files.map((file) => ({ - value: file.name, - name: `${file.name} - ${file.type} - ${pretty(file.size, { binary: true })}`, - checked: true, - })), - }, - ]) - const selected = files.filter((file) => names.includes(file.name)) + let selected: typeof files + if (all) { + selected = files + } else { + const { names } = await inquirer.prompt([ + { + type: 'checkbox', + message: 'What files should be saved?', + name: 'names', + choices: files.map((file) => ({ + value: file.name, + name: `${file.name} - ${file.type} - ${pretty(file.size, { binary: true })}`, + checked: true, + })), + }, + ]) + selected = files.filter((file) => names.includes(file.name)) + } if (!selected.length) exit('No files selected') - await Promise.all( - files.map(async (file) => { + selected.map(async (file) => { let filename = resolve(file.name) try { // If exists -> prepend timestamp to not overwrite the current file @@ -68,6 +76,7 @@ export async function download(url: URL) { console.log(`Saved: ${basename(filename)}`) }) ) + break case 'text': const plaintext = await Adapters.Text.decrypt(note.contents, key).catch(couldNotDecrypt) diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index af86cfe..ee51e45 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -15,6 +15,7 @@ const server = new Option('-s --server ', 'the cryptgeon server to use').de const files = new Argument('', 'Files to be sent').argParser(parseFile) const text = new Argument('', 'Text content of the note') const password = new Option('-p --password ', 'manually set a password') +const all = new Option('-a --all', 'Save all files without prompt').default(false) const url = new Argument('', 'The url to open') const views = new Option('-v --views ', 'Amount of views before getting destroyed').argParser(parseNumber) const minutes = new Option('-m --minutes ', 'Minutes before the note expires').argParser(parseNumber) @@ -86,10 +87,13 @@ send program .command('open') .addArgument(url) + .addOption(password) + .addOption(all) .action(async (note, options) => { try { const url = new URL(note) - await download(url) + options.password ||= await getStdin() + await download(url, options.all, options.password) } catch { exit('Invalid URL') } diff --git a/packages/cli/src/stdin.ts b/packages/cli/src/stdin.ts index d7714e6..d94b46a 100644 --- a/packages/cli/src/stdin.ts +++ b/packages/cli/src/stdin.ts @@ -2,19 +2,23 @@ export function getStdin(timeout: number = 10): Promise { return new Promise((resolve, reject) => { // Store the data from stdin in a buffer let buffer = '' - process.stdin.on('data', (d) => (buffer += d.toString())) + let t: NodeJS.Timeout + + const dataHandler = (d: Buffer) => (buffer += d.toString()) + const endHandler = () => { + clearTimeout(t) + resolve(buffer.trim()) + } // Stop listening for data after the timeout, otherwise hangs indefinitely - const t = setTimeout(() => { - process.stdin.destroy() + t = setTimeout(() => { + process.stdin.removeListener('data', dataHandler) + process.stdin.removeListener('end', endHandler) + process.stdin.pause() resolve('') }, timeout) - // Listen for end and error events - process.stdin.on('end', () => { - clearTimeout(t) - resolve(buffer.trim()) - }) - process.stdin.on('error', reject) + process.stdin.on('data', dataHandler) + process.stdin.on('end', endHandler) }) }