feat: new reset

This commit is contained in:
2024-09-30 22:46:47 +05:30
parent 17bd25b807
commit 5ea1746380
2 changed files with 96 additions and 51 deletions

View File

@@ -4,7 +4,7 @@ import { input, password } from "@inquirer/prompts";
import { $ } from "bun"; import { $ } from "bun";
import chalk from "chalk-template"; import chalk from "chalk-template";
import { Command } from "commander"; import { Command } from "commander";
import { decrypt_vault, encrypt_vault, initialize, recovery } from "./src/main"; import { decrypt_vault, encrypt_vault, initialize, reset } from "./src/main";
import { existsSync, readdirSync } from "fs"; import { existsSync, readdirSync } from "fs";
import checkForFiles, { import checkForFiles, {
Files, Files,
@@ -26,7 +26,7 @@ program.name("confidant").description("Creates a very secure file vault.");
program program
.command("init") .command("init")
.description("initialize a confidant vault") .description("initialize a confidant vault")
.argument("[directory]", "Directory to use to create a vault") .argument("[directory]", "directory to use to create a vault")
.action(async (dirname) => { .action(async (dirname) => {
if (!dirname) { if (!dirname) {
dirname = (await getDirectoryNames()) as string; dirname = (await getDirectoryNames()) as string;
@@ -61,7 +61,7 @@ program
program program
.command("decrypt") .command("decrypt")
.description("decrypt the vault") .description("decrypt the vault")
.argument("[vault]", "Name of the vault to decrypt") .argument("[vault]", "name of the vault to decrypt")
.option("-l, --live", "decrypt in live mode") .option("-l, --live", "decrypt in live mode")
.action(async (args, opts) => { .action(async (args, opts) => {
if (!args) { if (!args) {
@@ -98,7 +98,7 @@ program
program program
.command("encrypt") .command("encrypt")
.description("encrypt the vault") .description("encrypt the vault")
.argument("[vault]", "Name of the vault to decrypt") .argument("[vault]", "name of the vault to encrypt")
.action(async (vault) => { .action(async (vault) => {
if (!vault) { if (!vault) {
vault = await getDecryptedName(); vault = await getDecryptedName();
@@ -119,15 +119,29 @@ program
}); });
program program
.command("recover") .command("reset")
.description("recover vault when password is forgotten") .description("reset a vault's password")
.action(async () => { .argument("[vault]", "name of the vault to decrypt")
checkForFiles(); .action(async (vault) => {
if (!vault) {
vault = await getVaultName();
} else {
const vaults = new Files(/(.*).vault/g).intersection(
new Files(/(.*).key/g),
).data as string[];
if (!vaults.includes(vault)) {
console.log(
chalk`{red Vault "${vault}" not found in current directory.}`,
);
exit(1);
}
}
log`{blue Resetting password of "{green ${vault}}"...}`;
const recphrase = await input({ const recphrase = await input({
message: chalk`{reset {yellow Enter the recovery phrase:}}`, message: chalk`{reset {yellow Enter the recovery phrase:}}`,
}); });
recovery(recphrase); reset(vault, recphrase);
}); });
await program.parseAsync(); await program.parseAsync();

View File

@@ -11,6 +11,7 @@ import {
encrypt, encrypt,
encrypt_file, encrypt_file,
generate_recovery_phrase, generate_recovery_phrase,
getRandomPassword,
hmac, hmac,
log, log,
panic, panic,
@@ -22,8 +23,7 @@ import {
import env from "../env"; import env from "../env";
import { AES, enc, HmacSHA256 } from "crypto-js"; import { AES, enc, HmacSHA256 } from "crypto-js";
import chalk from "chalk-template"; import chalk from "chalk-template";
import type { ConData, Config, FidData } from "../types"; import { input, password } from "@inquirer/prompts";
import { password } from "@inquirer/prompts";
console.info = function () {}; console.info = function () {};
const { exit } = process; const { exit } = process;
@@ -165,45 +165,76 @@ export async function encrypt_vault(dirname: string) {
} }
} }
export async function recovery(recoverystring: string) { export async function reset(dirname: string, recoverystring: string) {
// Check if recovery phrase is correct try {
let config = Object(parse(readFileSync("config.toml").toString("utf8"))); // Read and split the vault file
let recovery_auth_key = HmacSHA256(recoverystring, env.AUTH_KEY).toString( const combined = readFileSync(`${dirname}.vault`);
enc.Base64, const index = combined.indexOf(separator);
); const D_C = combined.subarray(0, index).toString("utf8");
const dec = AES.decrypt( const E_Z = combined.subarray(index + separator.length);
config.config.recphrasestore,
recovery_auth_key, // Check if recovery key is correct
).toString(enc.Utf8); const recovery_auth_key = HmacSHA256(recoverystring, env.AUTH_KEY).toString(
if (dec !== env.PHRASE) { enc.Base64,
panic`Wrong recovery string. Please try again.`; );
const config = JSON.parse(Buffer.from(D_C, "base64").toString());
const phrase = AES.decrypt(
config.recphrasestore,
recovery_auth_key,
).toString(enc.Utf8);
if (phrase !== env.PHRASE) {
panic`Incorrect recovery phrase. Try again.`;
}
// create new credentials
const auth_secret = decrypt(
config.recoverystore,
buffer(recovery_auth_key),
);
const genPass = getRandomPassword(14);
const pass = await input({
message: chalk`{reset {yellow Enter a new password:}}`,
default: genPass,
});
const confpass = await input({
message: chalk`{reset {yellow Enter the password again:}}`,
default: genPass,
});
if (pass !== confpass) {
panic`Passwords don't match. Exiting...`;
}
const newrecphrase = generate_recovery_phrase();
const password_auth_key = HmacSHA256(pass, env.AUTH_KEY).toString(
enc.Base64,
);
const _recovery_auth_key = HmacSHA256(newrecphrase, env.AUTH_KEY).toString(
enc.Base64,
);
const _D_C = {
...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(),
};
// create dirname.vault
writeFileSync(
`${dirname}.vault`,
Buffer.concat([
Buffer.from(Buffer.from(JSON.stringify(_D_C)).toString("base64")),
separator,
E_Z,
]),
);
writeFileSync(`${dirname}_recovery.txt`, newrecphrase);
console.log(`New recovery phrase:`);
console.log(chalk`{magenta ${newrecphrase}}`);
} catch (e) {
panic`Error recovering vault. The files could be corrupted.`;
} }
// 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}}`;
} }