From d5669b2988c1685829405a6b3b1371a6994bc38c Mon Sep 17 00:00:00 2001 From: Suraj B M Date: Tue, 8 Oct 2024 10:23:17 +0530 Subject: [PATCH] feat: remove complete dependency on bun to be able to compile to .js --- .gitignore | 1 + bun.lockb | Bin 37087 -> 37817 bytes confidant.ts | 4 +- package.json | 10 +++-- scripts/build.ts | 11 ------ scripts/init.ts | 4 +- src/main.ts | 30 +++++++++------ src/utils.ts | 94 +++++++++++++++++++++++------------------------ 8 files changed, 75 insertions(+), 79 deletions(-) delete mode 100644 scripts/build.ts diff --git a/.gitignore b/.gitignore index c7c1ff6..01b3d69 100644 --- a/.gitignore +++ b/.gitignore @@ -177,3 +177,4 @@ dist # confidant env.ts test +executables diff --git a/bun.lockb b/bun.lockb index 4a345c0b69868b9d82a7e5b46db540042bb05995..f7a93705505d2fab2227483c047b84640af0fa2e 100755 GIT binary patch delta 6396 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 delta 5656 zcmeHLYjjlA6+UOkgxn;Pkaun-JVF7Bk0I|#GRfQ|BnBKJBH}P$2q7dPkQaFX7GZ`K z6}k|K8<50C3`%8LwPHlkwt`h$RFsyoiVcX$va;+#+S0XHpjPa+@4W*7)F1ufubwsE z-S<0ZpMCb(XWw)0oL8T=eAI8*JiXi*=m|ZTl#~DMH=8u&z@$ z(UAuj56J_>qYpa_U0vUW>|zJ64zURM)q$T3TPEpZNcup!b(fUAG#IMMzmYmzlViw- z>n!TQwVwuYJx6MoCMS^(*LlE{XmSquA~dBBDa@9JQChfDo~A+6O+mVs z>HTUVoN@#CA~pFZ>cKUN1|v146zT0Y>?%%c0IZDqB3<$W>al6oF-Y=4>a)4zJ)}ly zawGY0Jw`paj-o+a>qw2(Y1B8|g=qU?HOt9J z>Wy{FG#ZT6 zl7ehx$1T(!<+N6VA-GX4OWz3UO>iqG&1Qwt!ko%{WDqNd>a*MpRu~*axnMFYoeImN z!9-2jf;_t$?Zeo#at4f}9j3F1cs`hg@Z7DPV5M|2)MeQpM=8l}kvQTLD(8_o-1`($KhwI(FaC$i@T34jHWd zDz*>oR=tgrE1Gk{GA3rlub1K2@iw%%R=$pcOW*xq!L&w%8@lKb6h%9%meW}<@2_e%QRSl*$9 zxC>ynyi8EOO|lz4z15IB>>QI1m0Uj;z>_QL0G`fbfD21*U%~_h(yv!E8C(pNc#y>k zfE`;2aL4-qE-blT_x>8mdI5mt8i31p%Pd3jr%(z39stT(5dMP>AMyql?GK+SF7Q%bfsM|CX;k9!(q~{hT^?CN=fJkPY&5ITgEvWk zp_ir<+Q?euk>xa_$V(T&_JCE8bbD!6k&Wuy9yyhEgUxo^C_(c`57lU13e#+K0IZT? zioLWKtgF}~r_&o?i;8VDzQlviwxuPQUx|(W0ydMOfSLm;E zc7nIj$ARs@6F@((1>o1xXkZMTt4Z?n%N?H&A_cGmqktBm4QK~CfKH$bSO)M*X)Ew3 zunpjMsRon)rNCr>U-Y*CD*=8d-3#!h-vg8Z{C=JW_ywN3Rk&FVM zTtESk2jl`dfD>Rpg7s5y&(`?Ef^}{MxV;=;AK6###}nruaGl$f9FSsw1HzMr9sgB> zaz}Q89TW|8wU9T}O9O#TwBSCe_%Xta+y|Jo}NA5NZ$_6$dc zBbRp7=gMmOs9u%L^hN!R;TGL0F3aeahUy<-we^1dae%Ltz=7riJKlO~{07~Ax+6n~ zO8F3d-H;`>QO2SMd4hUyJx#K4jeRTZDd<;F)mXTG!zU~CarJ)NsjpF$FVZWG zS#mp_(eJH``5yK5;30$-d1CE_mo_z<{ScB9)Vx@=2M;|`tUq7pdNX3PIUnRm4D~No z;lpoWE0z9<`_pu)S*5W{vW+{rnU*f8l<(8NCEO+(gH1O5)b5>5yzM>FDGul*{NL3xGyn)h|s(2f2M@5j|{N0zvY&R)|miCjxnd+;oyd(xbTChRH7M~}=*M~)*$ zOr+MJb$jq=CULVbvg5(dccGPSgk8654<6yXerMyGmP0%f+tU3*v9TjD1PE!7Wq2fTD*l^Kh$@ub!zZ5YUSq*@2!hH zGu9$`&&tGR?pNvYWy#;Nw5#z9VB5<}pd-u7XC?e1zY0;dby3vvVthZ%SUx(VB0~R< z9N6*xo)No`rmmg`j$fer#H+ojzgQpN2oeW=_E%xCOPfFa>OSgUuBA9rj5(~$%XwF> oh`MyJ%P?KBiN0K3HBh(05lQ env.ts`; +writeFileSync("./env.ts", envstring); console.log(chalkTemplate`{green env.ts initialized sucessfully!}`); diff --git a/src/main.ts b/src/main.ts index 8d4e321..fbc0a83 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,7 @@ import { parse, stringify } from "@iarna/toml"; -import { $ } from "bun"; import { pbkdf2Sync as pbkdf2, randomBytes } from "crypto"; import { derive, getPublic } from "eccrypto"; -import { readFileSync, writeFileSync } from "fs"; +import { readFileSync, rmSync, writeFileSync } from "fs"; import { buffer, decrypt, @@ -24,6 +23,7 @@ import env from "../env"; import { AES, enc, HmacSHA256 } from "crypto-js"; import chalk from "chalk-template"; import { input, password } from "@inquirer/prompts"; +import AdmZip from "adm-zip"; console.info = function () {}; const { exit } = process; @@ -36,8 +36,10 @@ export async function initialize(password: string, dirname: string) { const salt = randomBytes(32); const code = random(10000, 100000); const D = pbkdf2(S_AB, salt, code, 64, "sha256"); - await $`zip -r9 confidant.zip ${dirname} > /dev/null`; - await $`rm -rf ${dirname}`; + const zip = new AdmZip(); + zip.addLocalFolder("./" + dirname); + zip.writeZip("./confidant.zip"); + rmSync(dirname, { recursive: true }); const Z = readFileSync("confidant.zip"); const E_Z = encrypt_file(Z, D); @@ -84,13 +86,12 @@ export async function initialize(password: string, dirname: string) { console.log(`Recovery phrase:`); console.log(chalk`{magenta ${recovery_phrase}}`); - await $`rm confidant.zip`; + rmSync("confidant.zip"); // create .gitignore const gitignore = `# .gitignore -*.con -*.fid +*.key *_recovery.txt confidant.zip *.confidant @@ -132,7 +133,9 @@ export async function decrypt_vault(password: string, dirname: string) { const Z = decrypt_file(E_Z, D); writeFileSync(`confidant.zip`, Z); writeFileSync(`.${dirname}.confidant`, encrypt(D, buffer(env.AUTH_KEY))); - await $`unzip confidant.zip > /dev/null && rm confidant.zip`; + const unzip = new AdmZip("./confidant.zip"); + unzip.extractAllTo(`./${dirname}`, true); + rmSync("./confidant.zip"); } catch (e) { panic`Error decrypting vault. The files could be corrupted.`; } @@ -145,8 +148,10 @@ export async function encrypt_vault(dirname: string) { buffer(env.AUTH_KEY), ); // create zip file and encrypt it - await $`zip -r9 confidant.zip ${dirname} > /dev/null`; - await $`rm -rf ${dirname}`; + const zip = new AdmZip(); + zip.addLocalFolder("./" + dirname); + zip.writeZip("./confidant.zip"); + rmSync(dirname, { recursive: true }); const Z = readFileSync("confidant.zip"); const E_Z = encrypt_file(Z, D); @@ -159,7 +164,8 @@ export async function encrypt_vault(dirname: string) { `${dirname}.vault`, Buffer.concat([vaultfile.subarray(0, index), separator, E_Z]), ); - await $`rm confidant.zip .${dirname}.confidant`; + rmSync("./confidant.zip"); + rmSync(`./.${dirname}.confidant`); } catch (e) { panic`Error encrypting vault. The files could be corrupted.`; } @@ -231,7 +237,7 @@ export async function reset(dirname: string, recoverystring: string) { ]), ); - writeFileSync(`${dirname}_recovery.txt`, newrecphrase); + writeFileSync(`${dirname}_recovery.txt`, newrecphrase + "\n"); console.log(`New recovery phrase:`); console.log(chalk`{magenta ${newrecphrase}}`); } catch (e) { diff --git a/src/utils.ts b/src/utils.ts index 9226a1e..d144fa8 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -3,7 +3,6 @@ import { createHmac } from "crypto"; import { generatePrivate, getPublic } from "eccrypto"; import { generate } from "random-words"; import chalk from "chalk-template"; -import { $ } from "bun"; import { existsSync, readdirSync } from "fs"; import { select } from "@inquirer/prompts"; @@ -61,15 +60,6 @@ export function decrypt_file(input: Buffer, key: Buffer) { return Buffer.from(result.toString(enc.Utf8), "base64"); } -export async function exists(dir: string) { - try { - await $`test -d ${dir}`; - return true; - } catch (e) { - return false; - } -} - export function log( str: TemplateStringsArray, ...placeholders: unknown[] @@ -109,13 +99,17 @@ export function print(key: string, value: string) { export class Files { data: string[] | null = null; - constructor(regex?: RegExp | string) { + constructor(regex?: RegExp | string | string[]) { if (!regex) { return this; } try { - const data = readdirSync(".").filter((x) => x.match(regex)); - this.data = data ? data.map((x) => x.replace(regex, "$1")) : null; + if (Array.isArray(regex)) { + this.data = regex; + } else { + 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; @@ -130,51 +124,57 @@ export class Files { return `[ ${this.data ? this.data.join(", ") : "empty"} ]`; } - intersection(a: Files) { + intersection(a: Files): Files { const obj = new Files(); - obj.data = Array.from(new Set(this.data).intersection(new Set(a.data))); + if (this.data && a.data) { + obj.data = this.data.filter((x) => a.data!.includes(x)); + } return obj; } - difference(a: Files) { + difference(a: Files): Files { const obj = new Files(); - obj.data = Array.from(new Set(this.data).difference(new Set(a.data))); + if (this.data && a.data) { + obj.data = this.data.filter((x) => !a.data!.includes(x)); + } return obj; } } export async function getDirectoryNames() { - const dirlist = (await $`ls -d */`.text()).trim(); + try { + const dirlist = readdirSync(".", { withFileTypes: true }) + .filter((file) => file.isDirectory()) + .map((file) => file.name); - if (!dirlist) { - panic`No directories found in current directory, please create one and run "init" again.`; - return; + if (dirlist.length === 0) { + panic`No directories found in current directory, please create one and run "init" again.`; + return; + } + const dirs = new Files(dirlist); + const vaults = new Files(/.*\.vault/g); + const usableDirs = dirs.difference(vaults); + + if (usableDirs.data && usableDirs.data.length === 0) { + panic`No usable directories found in current directory, please create one and run "init" again.`; + return; + } else if (usableDirs.data && usableDirs.data.length === 1) { + return usableDirs.data[0]; + } + + const dirname = await select({ + message: "Select a directory to use:", + choices: usableDirs.data!.map((x) => ({ + name: x, + value: x, + })), + }); + + return dirname; + } catch (e) { + console.log(chalk`{red ${e.message}}`); + process.exit(1); } - let dirs: string[]; - const vaultList = (await $`ls *.vault`.text()).trim().match(/.*\.vault/g); - if (vaultList) { - const vaults = vaultList.map((x) => x.replace(".vault", "")); - dirs = Array.from(new Set(dirlist.split("\n")).difference(new Set(vaults))); - } else { - dirs = dirlist.split("\n"); - } - - if (dirs.length === 0) { - panic`No usable directories found in current directory, please create one and run "init" again.`; - return; - } else if (dirs.length === 1) { - return dirs[0]; - } - - const dirname = await select({ - message: "Select a directory to use:", - choices: dirs.map((x) => ({ - name: x, - value: x, - })), - }); - - return dirname; } export async function getVaultName() { @@ -252,7 +252,7 @@ export async function getDecryptedName() { export function getRandomPassword(length: number) { const STRING = - "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*ABCDEFGHIJKLMNOPQRSTUVWXYZ"; let pass = ""; while (pass.length < length) {