feat: error correction and new features to init, decrypt and encrypt

This commit is contained in:
2024-09-30 19:42:56 +05:30
parent 009f16796c
commit 3a90ed0d61
4 changed files with 171 additions and 99 deletions

View File

@@ -75,7 +75,11 @@ export async function initialize(password: string, dirname: string) {
// create dirname.vault
writeFileSync(
`${dirname}.vault`,
Buffer.concat([Buffer.from(JSON.stringify(D_C)), separator, E_Z]),
Buffer.concat([
Buffer.from(Buffer.from(JSON.stringify(D_C)).toString("base64")),
separator,
E_Z,
]),
);
console.log(`Recovery phrase:`);
@@ -95,62 +99,70 @@ confidant.zip
}
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);
const D_C = combined.subarray(0, index).toString("utf8");
const E_Z = combined.subarray(index + separator.length);
try {
// Read and split the vault file
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 password is correct
const password_auth_key = HmacSHA256(password, env.AUTH_KEY).toString(
enc.Base64,
);
const config = JSON.parse(D_C);
const phrase = AES.decrypt(config.phrasestore, password_auth_key).toString(
enc.Utf8,
);
if (phrase !== env.PHRASE) {
panic`Incorrect password. Try again or reset it.`;
// Check if password is correct
const password_auth_key = HmacSHA256(password, env.AUTH_KEY).toString(
enc.Base64,
);
const config = JSON.parse(Buffer.from(D_C, "base64").toString());
const phrase = AES.decrypt(config.phrasestore, password_auth_key).toString(
enc.Utf8,
);
if (phrase !== env.PHRASE) {
panic`Incorrect password. Try again or reset it.`;
}
const auth_secret = decrypt(config.keystore, buffer(password_auth_key));
const K = hmac(auth_secret, config.confsalt);
const E_K = readFileSync(`${dirname}.key`);
const keyfile = JSON.parse(decrypt_file(E_K, K).toString("utf8"));
const K_A = buffer(keyfile.privateKey);
const K_B = buffer(config.privateKey);
const P_B = getPublic(K_B);
const S_AB = await derive(K_A, P_B);
const D = pbkdf2(S_AB, buffer(keyfile.salt), keyfile.code, 64, "sha256");
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`;
} catch (e) {
panic`Error decrypting vault. The files could be corrupted.`;
}
const auth_secret = decrypt(config.keystore, buffer(password_auth_key));
const K = hmac(auth_secret, config.confsalt);
const E_K = readFileSync(`${dirname}.key`);
const keyfile = JSON.parse(decrypt_file(E_K, K).toString("utf8"));
const K_A = buffer(keyfile.privateKey);
const K_B = buffer(config.privateKey);
const P_B = getPublic(K_B);
const S_AB = await derive(K_A, P_B);
const D = pbkdf2(S_AB, buffer(keyfile.salt), keyfile.code, 64, "sha256");
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`;
}
export async function encrypt_vault(dirname: string) {
const D = decrypt(
readFileSync(`.${dirname}.confidant`),
buffer(env.AUTH_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);
try {
const D = decrypt(
readFileSync(`.${dirname}.confidant`),
buffer(env.AUTH_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);
// read original vault file to get header data
const vaultfile = readFileSync(`${dirname}.vault`);
const index = vaultfile.indexOf(separator);
// 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`;
// write new data to vault
writeFileSync(
`${dirname}.vault`,
Buffer.concat([vaultfile.subarray(0, index), separator, E_Z]),
);
await $`rm confidant.zip .${dirname}.confidant`;
} catch (e) {
panic`Error encrypting vault. The files could be corrupted.`;
}
}
export async function recovery(recoverystring: string) {

View File

@@ -109,7 +109,10 @@ export function print(key: string, value: string) {
export class Files {
data: string[] | null = null;
constructor(regex: RegExp | string) {
constructor(regex?: RegExp | 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;
@@ -119,16 +122,24 @@ export class Files {
}
}
empty(): boolean {
return this.data === null || this.data.length === 0;
}
toString(): string {
return `[ ${this.data ? this.data.join(", ") : "empty"} ]`;
}
intersection(a: Files) {
return Array.from(new Set(this.data).intersection(new Set(a.data)));
const obj = new Files();
obj.data = Array.from(new Set(this.data).intersection(new Set(a.data)));
return obj;
}
difference(a: Files) {
return Array.from(new Set(this.data).difference(new Set(a.data)));
const obj = new Files();
obj.data = Array.from(new Set(this.data).difference(new Set(a.data)));
return obj;
}
}
@@ -167,35 +178,25 @@ export async function getDirectoryNames() {
}
export async function getVaultName() {
const vaultList = (await $`ls *.vault`.text()).trim().match(/.*\.vault/g);
if (!vaultList) {
const vaultList = new Files(/(.*)\.vault/g);
if (vaultList.empty()) {
panic`No vaults found in the current directory.`;
return;
}
const keyList = (await $`ls *.key`.text())
.trim()
.match(/.*\.key/g) as string[];
if (!keyList) {
const keyList = new Files(/(.*)\.key/g);
if (keyList.empty()) {
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", ""))),
),
);
const vaults = vaultList.intersection(keyList);
let files: string[];
const decryptedList = (await $`bash -c "ls .*.confidant"`.text())
.trim()
.match(/\.(.*)\.confidant/g);
if (decryptedList) {
const decs = decryptedList.map((x) => x.replace(/\.(.*)\.confidant/, "$1"));
files = Array.from(new Set(vaults).difference(new Set(decs)));
const decryptedList = new Files(/\.(.*)\.confidant/g);
if (decryptedList.empty()) {
files = vaults.difference(decryptedList).data as string[];
} else {
files = vaultList.map((x) => x.replace(".vault", ""));
files = vaults.data as string[];
}
if (files.length === 1) {
return files[0];
@@ -203,11 +204,21 @@ export async function getVaultName() {
const vault = await select({
message: "Select vault to decrypt:",
choices: files.map((x) => ({
name: x.replace(".vault", ""),
value: x.replace(".vault", ""),
})),
choices: [
...files.map((x) => ({
name: x.replace(".vault", ""),
value: x.replace(".vault", ""),
})),
{
name: chalk`{red EXIT}`,
value: "exit",
},
],
});
if (vault === "exit") {
log`{yellow Exiting...}`;
process.exit(0);
}
return vault;
}
@@ -222,7 +233,7 @@ export async function getDecryptedName() {
panic`No vaults found.`;
}
const decrypted = dec.intersection(vaults);
const decrypted = dec.intersection(vaults).data as string[];
if (decrypted.length === 1) {
return decrypted[0];
@@ -238,3 +249,14 @@ export async function getDecryptedName() {
return vault;
}
export function getRandomPassword(length: number) {
const STRING =
"0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ";
let pass = "";
while (pass.length < length) {
pass += STRING[Math.floor(Math.random() * STRING.length)];
}
return pass;
}