mirror of
https://github.com/silicoflare/confidant.git
synced 2026-05-26 20:48:01 +05:30
feat: new reset
This commit is contained in:
32
confidant.ts
32
confidant.ts
@@ -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();
|
||||||
|
|||||||
79
src/main.ts
79
src/main.ts
@@ -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`);
|
||||||
|
const index = combined.indexOf(separator);
|
||||||
|
const D_C = combined.subarray(0, index).toString("utf8");
|
||||||
|
const E_Z = combined.subarray(index + separator.length);
|
||||||
|
|
||||||
|
// Check if recovery key is correct
|
||||||
|
const recovery_auth_key = HmacSHA256(recoverystring, env.AUTH_KEY).toString(
|
||||||
enc.Base64,
|
enc.Base64,
|
||||||
);
|
);
|
||||||
const dec = AES.decrypt(
|
const config = JSON.parse(Buffer.from(D_C, "base64").toString());
|
||||||
config.config.recphrasestore,
|
const phrase = AES.decrypt(
|
||||||
|
config.recphrasestore,
|
||||||
recovery_auth_key,
|
recovery_auth_key,
|
||||||
).toString(enc.Utf8);
|
).toString(enc.Utf8);
|
||||||
if (dec !== env.PHRASE) {
|
if (phrase !== env.PHRASE) {
|
||||||
panic`Wrong recovery string. Please try again.`;
|
panic`Incorrect recovery phrase. Try again.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a fresh config file
|
// create new credentials
|
||||||
const auth_secret = decrypt(
|
const auth_secret = decrypt(
|
||||||
buffer(config.config.recoverystore),
|
config.recoverystore,
|
||||||
buffer(recovery_auth_key),
|
buffer(recovery_auth_key),
|
||||||
);
|
);
|
||||||
const newpass = await password({
|
|
||||||
|
const genPass = getRandomPassword(14);
|
||||||
|
const pass = await input({
|
||||||
message: chalk`{reset {yellow Enter a new password:}}`,
|
message: chalk`{reset {yellow Enter a new password:}}`,
|
||||||
mask: "•",
|
default: genPass,
|
||||||
});
|
});
|
||||||
const recstring = generate_recovery_phrase();
|
const confpass = await input({
|
||||||
recovery_auth_key = HmacSHA256(recstring, env.AUTH_KEY).toString(enc.Base64);
|
message: chalk`{reset {yellow Enter the password again:}}`,
|
||||||
const password_auth_key = HmacSHA256(newpass, env.AUTH_KEY).toString(
|
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,
|
enc.Base64,
|
||||||
);
|
);
|
||||||
|
|
||||||
config.config = {
|
const _D_C = {
|
||||||
...config.config,
|
...config,
|
||||||
keystore: stringy(encrypt(auth_secret, buffer(password_auth_key))),
|
keystore: stringy(encrypt(auth_secret, buffer(password_auth_key))),
|
||||||
recoverystore: stringy(encrypt(auth_secret, buffer(recovery_auth_key))),
|
recoverystore: stringy(encrypt(auth_secret, buffer(_recovery_auth_key))),
|
||||||
phrasestore: AES.encrypt(env.PHRASE, password_auth_key).toString(),
|
phrasestore: AES.encrypt(env.PHRASE, password_auth_key).toString(),
|
||||||
recphrasestore: AES.encrypt(env.PHRASE, recovery_auth_key).toString(),
|
recphrasestore: AES.encrypt(env.PHRASE, _recovery_auth_key).toString(),
|
||||||
};
|
};
|
||||||
writeFileSync("config.toml", buffer(stringify(config), "utf8"));
|
|
||||||
|
|
||||||
writeFileSync("recovery.txt", recstring + "\n");
|
// 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(`New recovery phrase:`);
|
||||||
log`{magenta ${recstring}}`;
|
console.log(chalk`{magenta ${newrecphrase}}`);
|
||||||
|
} catch (e) {
|
||||||
|
panic`Error recovering vault. The files could be corrupted.`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user