From 009f16796cd536eb797a7633f932ccd6c0cffa32 Mon Sep 17 00:00:00 2001 From: Suraj B M Date: Mon, 30 Sep 2024 10:18:23 +0530 Subject: [PATCH] feat: new encrypt --- confidant.ts | 22 ++++++++-------- src/main.ts | 24 ++++++++++++------ src/utils.ts | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 96 insertions(+), 21 deletions(-) diff --git a/confidant.ts b/confidant.ts index e338811..476a4d2 100755 --- a/confidant.ts +++ b/confidant.ts @@ -1,15 +1,15 @@ #!/bin/env bun -import { checkbox, input, password, select } from "@inquirer/prompts"; +import { input, password } from "@inquirer/prompts"; import { $ } from "bun"; import chalk from "chalk-template"; import { Command } from "commander"; -import { decrypt_diary, encrypt_diary, initialize, recovery } from "./src/main"; +import { decrypt_vault, encrypt_vault, initialize, recovery } from "./src/main"; import { existsSync } from "fs"; import checkForFiles, { + getDecryptedName, getDirectoryNames, getVaultName, - log, panic, } from "./src/utils"; @@ -47,7 +47,6 @@ program .option("-l, --live", "decrypt in live mode") .option("-v, --vault ", "name of the vault to decrypt") .action(async (args) => { - let files: string[]; if (!args.vault) { args.vault = await getVaultName(); } @@ -56,12 +55,12 @@ program message: chalk`{reset {yellow Enter the password:}}`, mask: "•", }); - await decrypt_diary(pass, args.vault); + await decrypt_vault(pass, args.vault); if (args.live) { await input({ message: chalk`{yellow Live mode started. Press ENTER to encrypt}`, }); - await encrypt_diary(); + await encrypt_vault(args.vault); console.log(chalk`{green Successfully encrypted!}`); } else { console.log(chalk`{green Decrypted sucessfully!}`); @@ -71,14 +70,13 @@ program program .command("encrypt") .description("encrypt the vault") - .action(async () => { - checkForFiles(); - - if (!existsSync(".confidant")) { - panic`The vault was not decrypted yet!`; + .option("-v, --vault ", "name of the vault to decrypt") + .action(async (args) => { + if (!args.vault) { + args.vault = await getDecryptedName(); } - await encrypt_diary(); + await encrypt_vault(args.vault); console.log(chalk`{green Successfully encrypted!}`); }); diff --git a/src/main.ts b/src/main.ts index 03a961e..a01bbcc 100644 --- a/src/main.ts +++ b/src/main.ts @@ -94,7 +94,7 @@ confidant.zip writeFileSync(`.gitignore`, gitignore); } -export async function decrypt_diary(password: string, dirname: string) { +export async function decrypt_vault(password: string, dirname: string) { // Read and split the vault file const combined = readFileSync(`${dirname}.vault`); const index = combined.indexOf(separator); @@ -130,17 +130,27 @@ export async function decrypt_diary(password: string, dirname: string) { await $`unzip confidant.zip > /dev/null && rm confidant.zip`; } -export async function encrypt_diary() { - const { dirname, key }: { dirname: string; key: string } = JSON.parse( - decrypt(readFileSync(".confidant"), buffer(env.AUTH_KEY)).toString("utf8"), +export async function encrypt_vault(dirname: string) { + const D = decrypt( + readFileSync(`.${dirname}.confidant`), + buffer(env.AUTH_KEY), ); - const D = buffer(key); + // create zip file and encrypt it await $`zip -r9 confidant.zip ${dirname} > /dev/null`; await $`rm -rf ${dirname}`; const Z = readFileSync("confidant.zip"); const E_Z = encrypt_file(Z, D); - writeFileSync(`vault.ant`, E_Z); - await $`rm confidant.zip .confidant`; + + // read original vault file to get header data + const vaultfile = readFileSync(`${dirname}.vault`); + const index = vaultfile.indexOf(separator); + + // write new data to vault + writeFileSync( + `${dirname}.vault`, + Buffer.concat([vaultfile.subarray(0, index), separator, E_Z]), + ); + await $`rm confidant.zip .${dirname}.confidant`; } export async function recovery(recoverystring: string) { diff --git a/src/utils.ts b/src/utils.ts index 18d3698..7ab774e 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -4,7 +4,7 @@ import { generatePrivate, getPublic } from "eccrypto"; import { generate } from "random-words"; import chalk from "chalk-template"; import { $ } from "bun"; -import { existsSync } from "fs"; +import { existsSync, readdirSync } from "fs"; import { select } from "@inquirer/prompts"; export function buffer(input: string): Buffer; @@ -106,6 +106,32 @@ export function print(key: string, value: string) { console.log(chalk`{green ${key}:} {blue ${value}}`); } +export class Files { + data: string[] | null = null; + + constructor(regex: RegExp | string) { + try { + const data = readdirSync(".").filter((x) => x.match(regex)); + this.data = data ? data.map((x) => x.replace(regex, "$1")) : null; + } catch (error) { + console.error("Error executing command:", error); + this.data = null; + } + } + + toString(): string { + return `[ ${this.data ? this.data.join(", ") : "empty"} ]`; + } + + intersection(a: Files) { + return Array.from(new Set(this.data).intersection(new Set(a.data))); + } + + difference(a: Files) { + return Array.from(new Set(this.data).difference(new Set(a.data))); + } +} + export async function getDirectoryNames() { const dirlist = (await $`ls -d */`.text()).trim(); @@ -147,12 +173,25 @@ export async function getVaultName() { return; } + const keyList = (await $`ls *.key`.text()) + .trim() + .match(/.*\.key/g) as string[]; + if (!keyList) { + panic`No vaults with keys found in the current directory.`; + return; + } + + const vaults = Array.from( + new Set(vaultList.map((x) => x.replace(".vault", ""))).intersection( + new Set(keyList.map((x) => x.replace(".key", ""))), + ), + ); + let files: string[]; const decryptedList = (await $`bash -c "ls .*.confidant"`.text()) .trim() .match(/\.(.*)\.confidant/g); if (decryptedList) { - const vaults = vaultList.map((x) => x.replace(".vault", "")); const decs = decryptedList.map((x) => x.replace(/\.(.*)\.confidant/, "$1")); files = Array.from(new Set(vaults).difference(new Set(decs))); } else { @@ -171,3 +210,31 @@ export async function getVaultName() { }); return vault; } + +export async function getDecryptedName() { + const dec = new Files(/\.(.*)\.confidant/g); + if (dec.data === null || dec.data.length === 0) { + panic`No decrypted vaults found.`; + } + + const vaults = new Files(/(.*).vault/g); + if (vaults.data === null) { + panic`No vaults found.`; + } + + const decrypted = dec.intersection(vaults); + + if (decrypted.length === 1) { + return decrypted[0]; + } + + const vault = await select({ + message: "Select vault to encrypt:", + choices: decrypted.map((x) => ({ + name: x.replace(".vault", ""), + value: x.replace(".vault", ""), + })), + }); + + return vault; +}