From 2881d9b8608d322c2e44ef6345098b403450964d Mon Sep 17 00:00:00 2001 From: Suraj B M Date: Sun, 29 Sep 2024 12:58:05 +0530 Subject: [PATCH] init: inital commit --- .gitignore | 178 ++++++++++++++++++++++++++++++++++++++ README.md | 62 ++++++++++++++ bun.lockb | Bin 0 -> 37087 bytes confidant.ts | 114 +++++++++++++++++++++++++ package.json | 36 ++++++++ scripts/build.ts | 11 +++ scripts/init.ts | 22 +++++ src/main.ts | 217 +++++++++++++++++++++++++++++++++++++++++++++++ src/utils.ts | 94 ++++++++++++++++++++ tsconfig.json | 27 ++++++ types.d.ts | 24 ++++++ 11 files changed, 785 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100755 bun.lockb create mode 100755 confidant.ts create mode 100644 package.json create mode 100644 scripts/build.ts create mode 100644 scripts/init.ts create mode 100644 src/main.ts create mode 100644 src/utils.ts create mode 100644 tsconfig.json create mode 100644 types.d.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..66fa52b --- /dev/null +++ b/.gitignore @@ -0,0 +1,178 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + +# confidant +env.ts diff --git a/README.md b/README.md new file mode 100644 index 0000000..327cb5f --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +# Confidant + +## Table of Contents +1. [Introduction](#introduction) +2. [Installation](#installation) + a. [Linux](#linux) + b. [Windows](#windows) + c. [MacOS](#macos) +3. [Usage](#usage) +4. [Build from source](#build-from-source) +--- + +## Introduction +Confidant is a CLI tool used to create a triple-layer protected vault, written in TypeScript. It makes use of a combination of ECDH, AES256 and HMAC-SHA256 to create the vault, which can be acessible only if 3 particular files, namely `data.con`, `key.fid` and `vault.ant` (and a `config.toml`), are present. It also requires a password to start the decryption process. In case the password is lost, the vault can be recovered using the recovery phrase, which is a 12-word phrase that is generated during the vault creation process. + +## Installation +### Linux +1. Download the latest release from the releases page. +2. Give it executable permissions by running `chmod +x confidant`. +3. Move it to a directory in your PATH, like `/usr/local/bin`. +4. Run `confidant --help` to verify the installation. + +### Windows +1. Download the latest release from the releases page. +2. Move it to a directory in your PATH. +3. Run `confidant --help` to verify the installation. + +### MacOS +1. Download the latest release from the releases page. +2. Give it executable permissions by running `chmod +x confidant`. +3. Move it to a directory in your PATH, like `/usr/local/bin`. +4. Run `confidant --help` to verify the installation. + +--- + +## Usage +### Create a new vault +To create a new vault, run the following command: +```bash +confidant init +``` +This will show a list of directories in your current directory. Select the directory where you want to create the vault. Also specify a password to encrypt the vault. The recovery phrase will be shown after the vault is created. Save it in a safe place. The following files will be created: +- `data.con`: Primary key +- `key.fid`: Secondary key +- `vault.ant`: Encrypted vault +- `config.toml`: Configuration file +- `.gitignore`: To ignore the vault files +After this, you can push the vault files to a remote repository. The `.gitignore` file will make sure the key files are not pushed to the repository. Make sure to never store the key files in the same place as the vault files. + +### Decrypt a vault +To decrypt a vault, run the following command: +```bash +confidant decrypt +``` +Make sure all the files `data.con`, `key.fid` and `vault.ant` are present in the current directory. Also make sure you have the password and the recovery phrase. The vault will be decrypted and the contents will be shown. + +### Encrypt a vault +To encrypt a vault, run the following command: +```bash +confidant encrypt +``` +Make sure the files `data.con`, `key.fid` and `vault.ant` are present in the current directory. The vault will be encrypted and the files will be updated, after which you can move them to a safe place. diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..4a345c0b69868b9d82a7e5b46db540042bb05995 GIT binary patch literal 37087 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ØuH`77v*q{Q$$4}6Qg=O@ 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%0A3i^jXRN6i z%=YH+_`%^C0fGL$JPmHJwi^ux832lIgVgO1mSvVW?5y$4~vrx|*9vd_gsH3MpN4pgPn#xeJ3(JG(c=`iu z9>HwTISWq(cy3;7mV1bo7dyB$zUETM*c@ZwV;#lW3L4Ih00sY{3-EZQEky_o@S-Aw zmn`aVio*H3d9cvLu0JP$;}5TMcwnlR<%VOQ|5K81AcgQbeyt6d7BNtJi+Rv5FgDw0 z#!qO0fWLAIQrpGmL)r}-P1o&13hWglPH;tyDuXtpC(n)mBbU?!(rp7LJOu-o@QSLf ztuCid)ewVU{$aru7w2m0b4+Mv89>6TW@SLlVK5#zUg0b^T*3r{9TeEg7^Rg0N?NR0 zTOOQ1u=vb!cSG(#w!f#gzE&%Yf)fZJ6I_7ys6))wTh&AixTb4L@j8?~pa&@dTB#R% znJNPmP1i8@am+&Hpbbwqcd)|^D<|8{zZIfiN}@zRV}Vp3razDZ7u*RrZVt{UYBnpm9 z04TViYHaHcK^se0WAn(O+T4ywMjPNj@bidomRhi|v*vPx*`a~6+{5v$4R;PZyp=xr zxgc==oIuGpybXOeSBtVyHy4zleOP=gfG`XJq21=)mb_x1Kmr@+fWxOp=yl5EJlM}= z@wu!(H@;6RE&sJB@co)ZwV1J4aZi-F&JcN;*B1`a&tt~;(E`8I65%E7I zP(!6nkrC1arCtZNQLEtnB0vNeu%*M7iwLp^^zqR2;s*P>@dIGhW4U>HasyayfgCF4 z9UchVDvqD$&oLG^kk8@5qXY@ze)mfWoTC&H+REcYek)_-XDCSda{_dup`yXK1UA%Sdo0ZcBb{-pN4!ZO%2QhaV8+k@Xqn|>;Xq!a)s z@qD+fwg{efusWg)IKhL5dBlal`r-kL2|gROQa`;IkkF&Bm4%~ZY87aOK-hq$2?-=k z*VN=}>$XS;$Q(lga*f+?d`%DSX-$M*AMk)e_^1bM5bl4Qp8`F6*dBA-xpQeL+yF05 zuzzy`+mplR2Ginm1L3KzInD_P4BU>8v~_@oyW$a&_=-p^_(Y|=S@XC;5ORK?Zxp931;(}6L3(t1@Jg5*mJtU_z35E z@VOpbKW;FO<1Jo zc#z)iL4!bo$2}A^ef&eXdQkwcp*h9b}yrS^bn$k+^n>!Ty8^9Q_ zs23U7c;UpNNhM4P3w8@+q0&A4IIJ*^C*Ow$pEY#zW3lIQ__!$*=o)D?kN{}4j=HJ?LS975z zB1BNP+_r9yv_TDES`3;be8g-;Ax(1wD<<=#UC3W&84xs24eI4iTT2tJNId#-0u;1q zOr6%X)%xbeL2#=<6;St_<{oIJ_04GEoeSW?tLFPnyYPX+dm#{z%im-W++6`LxcE)^ zsarLGsqi;zhRqn<_5m!o_+2!$i9j@U(Trvb59wKgj8@e6OG!!+!2!Pz3#7uK%)yDt z^5e96i~(Em&G>jY#u#y1^dJh&Oc lyE$sq3SLVIUPZOie5$$B+a(}qjzHzYBSpbWs{g(J{|7^y?J)oV literal 0 HcmV?d00001 diff --git a/confidant.ts b/confidant.ts new file mode 100755 index 0000000..ad6945d --- /dev/null +++ b/confidant.ts @@ -0,0 +1,114 @@ +#!/bin/env bun + +import { input, password, select } 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 { existsSync } from "fs"; +import checkForFiles, { log, panic } from "./src/utils"; + +const program = new Command(); +const { exit } = process; +$.nothrow(); + +program.name("confidant").description("Creates a very secure file vault."); + +program + .command("init") + .description("initialize a confidant vault") + .action(async () => { + // check if a vault already exists + if (await $`test -e config.toml`) { + console.log( + chalk`{red A Confidant vault already exists in this directory.}`, + ); + exit(1); + } + + // select a directory + let dirs; + try { + dirs = (await $`ls -d */`.text()).trim(); + } catch (e) { + console.error( + 'No directories found in current directory, please create one and run "init" again.', + ); + process.exit(1); + } + + let dirlist = dirs.split("\n"); + const dirname = await select({ + message: "Select a directory to use:", + choices: dirlist.map((x) => ({ + name: x, + value: x, + })), + }); + const pass = await password({ + message: chalk`{reset {yellow Enter a password to use:}}`, + mask: "•", + }); + const confpass = await password({ + message: chalk`{reset {yellow Enter the password again:}}`, + mask: "•", + }); + if (pass !== confpass) { + console.log(chalk`Passwords don't math.`); + exit(1); + } + + await initialize(pass, dirname); + console.log(chalk`{green Initialized a new Confidant vault sucessfully!}`); + }); + +program + .command("decrypt") + .description("decrypt the vault") + .option("-l, --live", "decrypt in live mode") + .action(async (args) => { + checkForFiles(); + + const pass = await password({ + message: chalk`{reset {yellow Enter the password:}}`, + mask: "•", + }); + await decrypt_diary(pass); + if (args.live) { + await input({ + message: chalk`{yellow Live mode started. Press ENTER to encrypt}`, + }); + await encrypt_diary(); + console.log(chalk`{green Successfully encrypted!}`); + } else { + console.log(chalk`{green Decrypted sucessfully!}`); + } + }); + +program + .command("encrypt") + .description("encrypt the vault") + .action(async () => { + checkForFiles(); + + if (!existsSync(".confidant")) { + panic`The vault was not decrypted yet!`; + } + + await encrypt_diary(); + console.log(chalk`{green Successfully encrypted!}`); + }); + +program + .command("recover") + .description("recover vault when password is forgotten") + .action(async () => { + checkForFiles(); + + const recphrase = await input({ + message: chalk`{reset {yellow Enter the recovery phrase:}}`, + }); + recovery(recphrase); + }); + +await program.parseAsync(); diff --git a/package.json b/package.json new file mode 100644 index 0000000..e25e1a3 --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "name": "confidant", + "version": "1.0.0", + "module": "confidant.ts", + "type": "module", + "scripts": { + "init": "bun ./scripts/init.ts", + "build": "bun ./scripts/build.ts" + }, + "bin": { + "confidant": "./confidant.ts" + }, + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "@iarna/toml": "^2.2.5", + "@inquirer/prompts": "^6.0.1", + "@types/commander": "^2.12.2", + "@types/crypto-js": "^4.2.2", + "@types/eccrypto": "^1.1.6", + "argon2": "^0.41.1", + "chalk": "^5.3.0", + "chalk-template": "^1.1.0", + "commander": "^12.1.0", + "crypto": "^1.0.1", + "crypto-js": "^4.2.0", + "dotenv": "^16.4.5", + "eccrypto": "^1.1.6", + "fs": "^0.0.1-security", + "random-words": "^2.0.1" + } +} diff --git a/scripts/build.ts b/scripts/build.ts new file mode 100644 index 0000000..c30aa1d --- /dev/null +++ b/scripts/build.ts @@ -0,0 +1,11 @@ +import { $ } from "bun"; +import data from "../package.json"; + +const { version: ver } = data; + +await $` +rm -rf ./dist +bun build --compile --target=bun-linux-x64 ./confidant.ts --outfile ./dist/confidant_${ver}_linux_x64 +bun build --compile --target=bun-windows-x64 ./confidant.ts --outfile ./dist/confidant_${ver}_win_x64.exe +bun build --compile --target=bun-darwin-x64 ./confidant.ts --outfile ./dist/confidant_${ver}_darwin_x64 +`; diff --git a/scripts/init.ts b/scripts/init.ts new file mode 100644 index 0000000..dd4547c --- /dev/null +++ b/scripts/init.ts @@ -0,0 +1,22 @@ +import { $ } from "bun"; +import { stringy } from "../src/utils"; +import { randomBytes } from "crypto"; +import chalkTemplate from "chalk-template"; + +const envstring = `// env.ts +const env = { + // Re-run to get a new value + AUTH_KEY: "${stringy(randomBytes(32))}", + + // Re-run to get a new value + AUTH_SALT: "${stringy(randomBytes(64))}", + + // Can be literally anything! + PHRASE: "May the Force be with you!", +} + +export default env; +`; + +await $`echo ${envstring} > env.ts`; +console.log(chalkTemplate`{green env.ts initialized sucessfully!}`); diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..02883d2 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,217 @@ +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 { + buffer, + decrypt, + decrypt_file, + ECDH, + encrypt, + encrypt_file, + generate_recovery_phrase, + hmac, + log, + panic, + random, + stringy, +} from "./utils"; +import env from "../env"; +import { AES, enc, HmacSHA256 } from "crypto-js"; +import chalk from "chalk-template"; +import type { ConData, Config, FidData } from "../types"; +import { password } from "@inquirer/prompts"; + +console.info = function () {}; +const { exit } = process; + +export async function initialize(password: string, dirname: string) { + // compressing and encrypting diary + const [K_C, P_C] = ECDH(); + const [K_F, P_F] = ECDH(); + const S_CF = await derive(K_C, P_F); + const fidsalt = randomBytes(32); + const fidcode = random(10000, 100000); + const D = pbkdf2(S_CF, fidsalt, fidcode, 64, "sha256"); + 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); + + // creating key.fid + const fidData = { + privateKey: stringy(K_F), + salt: stringy(fidsalt), + code: fidcode, + }; + const fidkey = randomBytes(32); + const consalt = randomBytes(32); + const D_C = hmac(consalt, fidkey); + const E_F = encrypt_file(buffer(stringify(fidData), "utf8"), D_C); + writeFileSync(`key.fid`, E_F); + + // create data.con + const auth_secret = randomBytes(32); + const conData = { + privateKey: stringy(K_C), + fidkey: stringy(fidkey), + consalt: stringy(consalt), + }; + const D_U = hmac(auth_secret, buffer(env.AUTH_KEY)); + const E_C = encrypt_file(buffer(stringify(conData), "utf8"), D_U); + writeFileSync("data.con", E_C); + + const recovery_phrase = generate_recovery_phrase(); + writeFileSync("recovery.txt", recovery_phrase + "\n"); + const recovery_auth_key = HmacSHA256(recovery_phrase, env.AUTH_KEY).toString( + enc.Base64, + ); + const password_auth_key = HmacSHA256(password, env.AUTH_KEY).toString( + enc.Base64, + ); + + // create config.toml + const configData = { + config: { + con: "data.con", + fid: "key.fid", + ant: "vault.ant", + dir: dirname, + keystore: stringy(encrypt(auth_secret, buffer(password_auth_key))), + recoverystore: stringy(encrypt(auth_secret, buffer(recovery_auth_key))), + phrasestore: AES.encrypt(env.PHRASE, password_auth_key).toString(), + recphrasestore: AES.encrypt(env.PHRASE, recovery_auth_key).toString(), + }, + }; + writeFileSync("config.toml", buffer(stringify(configData), "utf8")); + console.log(`Recovery phrase:`); + console.log(chalk`{magenta ${recovery_phrase}}`); + await $`rm confidant.zip`; + + const gitignore = `# .gitignore + +data.con +key.fid +recovery.txt +confidant.zip +.confidant +${dirname} +.env +`; + writeFileSync(".gitignore", gitignore); +} + +export async function decrypt_diary(password: string) { + // Check if password is correct + const config = Object( + parse(readFileSync("config.toml").toString("utf8")), + ) as Config; + const password_auth_key = HmacSHA256(password, env.AUTH_KEY).toString( + enc.Base64, + ); + const dec = AES.decrypt( + config.config.phrasestore, + password_auth_key, + ).toString(enc.Utf8); + if (dec !== env.PHRASE) { + panic`Wrong password. Try again or reset it.`; + } + + // Decrypt data.con + const auth_secret = decrypt( + buffer(config.config.keystore), + buffer(password_auth_key), + ); + const D_U = hmac(auth_secret, buffer(env.AUTH_KEY)); + const conData = Object( + parse(decrypt_file(readFileSync(config.config.con), D_U).toString("utf8")), + ) as ConData; + + // Decrypt key.fid + const { consalt, fidkey, privateKey: conK } = conData; + const D_C = hmac(buffer(consalt), buffer(fidkey)); + const fidData = Object( + parse(decrypt_file(readFileSync(config.config.fid), D_C).toString("utf8")), + ) as FidData; + const { privateKey: fidK, salt, code } = fidData; + + // Decrypt diary.ant + const S_CF = await derive(buffer(conK), getPublic(buffer(fidK))); + const D = pbkdf2(S_CF, buffer(salt), code, 64, "sha256"); + writeFileSync( + ".confidant", + encrypt( + Buffer.from( + JSON.stringify({ + dirname: config.config.dir, + key: stringy(D), + }), + "utf8", + ), + buffer(env.AUTH_KEY), + ), + ); + writeFileSync( + "confidant.zip", + decrypt_file(readFileSync(config.config.ant), D), + ); + 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"), + ); + const D = buffer(key); + 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`; +} + +export async function recovery(recoverystring: string) { + // Check if recovery phrase is correct + let config = Object(parse(readFileSync("config.toml").toString("utf8"))); + let recovery_auth_key = HmacSHA256(recoverystring, env.AUTH_KEY).toString( + enc.Base64, + ); + const dec = AES.decrypt( + config.config.recphrasestore, + recovery_auth_key, + ).toString(enc.Utf8); + if (dec !== env.PHRASE) { + panic`Wrong recovery string. Please try again.`; + } + + // Generate a fresh config file + const auth_secret = decrypt( + buffer(config.config.recoverystore), + buffer(recovery_auth_key), + ); + const newpass = await password({ + message: chalk`{reset {yellow Enter a new password:}}`, + mask: "•", + }); + const recstring = generate_recovery_phrase(); + recovery_auth_key = HmacSHA256(recstring, env.AUTH_KEY).toString(enc.Base64); + const password_auth_key = HmacSHA256(newpass, env.AUTH_KEY).toString( + enc.Base64, + ); + + config.config = { + ...config.config, + keystore: stringy(encrypt(auth_secret, buffer(password_auth_key))), + recoverystore: stringy(encrypt(auth_secret, buffer(recovery_auth_key))), + phrasestore: AES.encrypt(env.PHRASE, password_auth_key).toString(), + recphrasestore: AES.encrypt(env.PHRASE, recovery_auth_key).toString(), + }; + writeFileSync("config.toml", buffer(stringify(config), "utf8")); + + writeFileSync("recovery.txt", recstring + "\n"); + console.log(`New recovery phrase:`); + log`{magenta ${recstring}}`; +} diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..8845a45 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,94 @@ +import { AES, enc } from "crypto-js"; +import { createHmac } from "crypto"; +import { generatePrivate, getPublic } from "eccrypto"; +import { generate } from "random-words"; +import chalk from "chalk-template"; +import { $ } from "bun"; +import { existsSync } from "fs"; + +export function buffer(input: string): Buffer; +export function buffer(input: string, encoding: BufferEncoding): Buffer; +export function buffer(input: string, encoding?: BufferEncoding): Buffer { + return Buffer.from(input, encoding || "base64"); +} + +export function stringy(input: Buffer): string { + return input.toString("base64"); +} + +export function encrypt(input: Buffer, key: Buffer) { + const result = AES.encrypt(stringy(input), stringy(key)); + return buffer(result.toString()); +} + +export function decrypt(input: Buffer, key: Buffer) { + const result = AES.decrypt(stringy(input), stringy(key)); + return buffer(result.toString(enc.Utf8)); +} + +export function random(start: number, end: number) { + return Math.floor((end - start) * Math.random() + start); +} + +export function ECDH() { + const privkey = generatePrivate(); + const pubkey = getPublic(privkey); + return [privkey, pubkey]; +} + +export function hmac(message: Buffer, key: Buffer): Buffer { + return buffer( + createHmac("sha256", stringy(key)) + .update(stringy(message)) + .digest("base64"), + ); +} + +export function generate_recovery_phrase(): string { + return ( + generate({ exactly: 12, minLength: 5, maxLength: 7 }) as string[] + ).join(" "); +} + +export function encrypt_file(input: Buffer, key: Buffer) { + const result = AES.encrypt(input.toString("base64"), key.toString("base64")); + return Buffer.from(result.toString(), "base64"); +} + +export function decrypt_file(input: Buffer, key: Buffer) { + const result = AES.decrypt(input.toString("base64"), key.toString("base64")); + 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[]) { + console.log(chalk(str, placeholders)); +} + +export function panic(str: TemplateStringsArray) { + console.log(chalk`{red ${str}}`); + process.exit(1); +} + +export default function checkForFiles() { + const missing: string[] = []; + ["data.con", "key.fid", "vault.ant", "config.toml"].forEach((val) => { + if (!existsSync(val)) { + missing.push(val); + } + }); + if (missing.length > 0) { + missing.forEach((val) => { + console.log(chalk`{red File "${val}" not found!}`); + }); + process.exit(1); + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..238655f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +} diff --git a/types.d.ts b/types.d.ts new file mode 100644 index 0000000..1e70316 --- /dev/null +++ b/types.d.ts @@ -0,0 +1,24 @@ +export interface Config { + config: { + con: string; + fid: string; + ant: string; + dir: string; + keystore: string; + recoverystore: string; + phrasestore: string; + recphrasestore: string; + }; +} + +export interface ConData { + privateKey: string; + fidkey: string; + consalt: string; +} + +export interface FidData { + privateKey: string; + salt: string; + code: number; +}