invictus
Version:
A cli based password manager application, also has a web interface for doing things
657 lines (611 loc) • 19.8 kB
JavaScript
import { readDb, writeDb } from "./db.js";
import clipboardy from "clipboardy";
import keytar from "keytar";
import { formatDate, askConfirmation } from "./utils/utils.js";
import chalk from "chalk";
export const showError = () => {
console.error(chalk.red("Error: there is some error in the package"));
console.log("- Make sure you have installed a latest version");
console.log(
`- If it is a latest version, you can open a github issue here ${chalk.cyanBright.underline(
"https://github.com/kanhaiyadav/invictus/issues"
)} and wait for new version.`
);
};
export const isOrgExists = async (orgTitle) => {
try {
if (!orgTitle) {
return false;
}
const db = await readDb();
return db.orgs.some((org) => org.title.toLowerCase() === orgTitle.toLowerCase());
} catch (error) {
showError();
return false;
}
};
export const isAccountExists = async (orgTitle, account) => {
try {
if (!orgTitle || !account) {
return false;
}
const db = await readDb();
const org = db.orgs.find((item) => item.title === orgTitle);
if (!org) {
return false;
}
return org.accounts.some((acc) => acc.email === account);
} catch (error) {
showError();
return false;
}
};
export const addPassword = async (data) => {
try {
const db = await readDb();
const orgIdx = db.orgs.findIndex(
(item) => item.title === data.title || item.domain === data.domain
);
if (orgIdx !== -1) {
const org = db.orgs[orgIdx];
if (org.accounts.find((item) => item.email === data.email)) {
console.error("Account already exists!!!");
return {
err: true,
message: "Account already exists!!!",
code: 409,
};
}
db.orgs[orgIdx].accounts.push({
email: data.email,
description: data.description,
createdAt: formatDate(new Date()),
});
await keytar.setPassword(data.title, data.email, data.password);
writeDb(db);
return {
err: false,
message: "Account created successfully",
data: db,
};
} else {
db.orgs.push({
title: data.title,
domain: data.domain,
favourite: false,
archived: false,
accounts: [
{
email: data.email,
description: data.description,
createdAt: formatDate(new Date()),
},
],
});
await keytar.setPassword(data.title, data.email, data.password);
writeDb(db);
return {
err: false,
message: "Account created successfully",
data: db,
};
}
} catch (error) {
console.log(error);
showError();
return {
err: true,
message: "Error: there is some error in the package",
code: 500,
};
}
};
export const logPasswords = async (orgTitle) => {
try {
if (!orgTitle) {
console.error(
chalk.redBright(
`${
orgTitle || "This organisation"
} doesn't exist in your database!!!`
)
);
process.exit(1);
}
const db = await readDb();
if (orgTitle) {
const org = db.orgs.find((item) => item.title === orgTitle);
if (!org) {
console.error(
chalk.redBright(
`${
orgTitle || "This organisation"
} doesn't exist in your database!!!`
)
);
process.exit(1);
}
console.log(`${org.title}(${chalk.cyanBright.underline(org.domain)})`);
console.table(org.accounts, ["email", "description", "createdAt"]);
} else {
console.error(
chalk.redBright(
`${
orgTitle || "This organisation"
} doesn't exist in your database!!!`
)
);
process.exit(1);
}
} catch (error) {
showError();
}
};
export const logAllPasswords = async () => {
try {
const db = await readDb();
if (db.orgs.length === 0) {
console.log(chalk.yellow("No data exist!!!"));
return;
}
db.orgs.forEach((org) => {
console.log(
`${org.title}(${chalk.cyanBright.underline(org.domain)})`
);
console.table(org.accounts, ["email", "description", "createdAt"]);
console.log('\n');
});
} catch (error) {
showError();
}
};
export const deletePassword = async (data) => {
try {
const db = await readDb();
const orgIdx = db.orgs.findIndex((item) => item.title === data.title);
if (orgIdx === -1) {
console.error(`${data.title} doesn't exist in your database!!!`);
return {
err: true,
message: `${data.title} doesn't exist in your database!!!`,
code: 404,
};
}
const accountIdx = db.orgs[orgIdx].accounts.findIndex(
(item) => item.email === data.email
);
if (accountIdx === -1) {
console.error(chalk.red("Error: Account not found!!!"));
return {
err: true,
message: "Account not found!!!",
code: 404,
};
}
db.orgs[orgIdx].accounts.splice(accountIdx, 1);
await keytar.deletePassword(data.title, data.email);
writeDb(db);
return {
err: false,
message: "Account deleted successfully",
data: db,
};
} catch (error) {
showError();
return {
err: true,
message: "Error: there is some error in the package",
code: 500,
};
}
};
export const updatePassword = async (data) => {
try {
const db = await readDb();
const orgIdx = db.orgs.findIndex((item) => item.title === data.title);
if (orgIdx === -1) {
console.log(
chalk.red(`${data.title} doesn't exist in your database!!!`)
);
return {
err: true,
message: `${data.title} doesn't exist in your database!!!`,
code: 404,
};
}
const accountIdx = db.orgs[orgIdx].accounts.findIndex(
(item) => item.email === data.email
);
if (accountIdx === -1) {
console.log(chalk.red("Account not found!!!"));
return {
err: true,
message: "Account not found!!!",
code: 404,
};
}
await keytar.setPassword(data.title, data.email, data.password);
writeDb(db);
return {
err: false,
message: "Password updated successfully",
data: db,
};
} catch (error) {
showError();
return {
err: true,
message: "Error: there is some error in the package",
code: 500,
};
}
};
export const copyPassword = async (service, account) => {
try {
if (!(await isOrgExists(service))) {
console.error(
chalk.red(`${service} doesn't exist in your database!!!`)
);
return;
} else {
if (!(await isAccountExists(service, account))) {
console.error(chalk.red("Account not found!!!"));
return;
}
}
const confirm = await askConfirmation(
"confirm you want to copy password to clipboard?"
);
if (!confirm) {
console.log(chalk.red("Operation canceled!"));
return;
}
const password = await keytar.getPassword(service, account);
if (password) {
await clipboardy.write(password);
console.log(chalk.greenBright(`Password copied to clipboard.`));
let countdown = 10;
const interval = setInterval(() => {
process.stdout.write(
`\rClearing clipboard in: ${chalk.yellow(countdown)} `
);
countdown--;
if (countdown < 0) {
clearInterval(interval);
clipboardy.write("");
console.log(
chalk.cyan("\nClipboard cleared for security.")
);
}
}, 1000);
} else {
console.log(chalk.red("No password found!"));
}
} catch (error) {
showError();
}
};
export const getOrgs = async () => {
try {
const db = await readDb();
if (db.orgs.length === 0) {
return [];
}
return db.orgs.map((org) => {
return org;
});
} catch (error) {
showError();
return [];
}
};
export const getAccounts = async (orgTitle) => {
try {
if (!orgTitle) {
return [];
}
const db = await readDb();
const org = db.orgs.find((item) => item.title === orgTitle);
if (!org) {
return [];
}
return org.accounts.map((account) => {
return account.email;
});
} catch (error) {
showError();
return [];
}
};
export const getPassword = async (service, account) => {
try {
const password = await keytar.getPassword(service, account);
if (password) {
return password;
} else {
return "404 not found";
}
} catch (error) {
showError();
return "Error";
}
};
export const createOrg = async (data) => {
try {
const db = await readDb();
const orgIdx = db.orgs.findIndex((item) => item.title === data.title);
if (orgIdx !== -1) {
console.error("Organization already exists!!!");
return {
err: true,
message: "Organization already exists!!!",
code: 409,
};
}
db.orgs.push({
title: data.title,
domain: data.domain,
favourite: false,
archived: false,
accounts: [],
});
writeDb(db);
return {
err: false,
message: "Organization created successfully",
data: db,
};
} catch (error) {
showError();
return {
err: true,
message: "Error: there is some error in the package",
code: 500,
};
}
};
export const deleteOrg = async (orgTitle) => {
try {
if (!orgTitle) {
console.error(
chalk.red(
`${
orgTitle || "This organisation"
} doesn't exist in your database!!!`
)
);
return {
err: true,
message: `${
orgTitle || "This organisation"
} doesn't exist in your database!!!`,
code: 404,
};
}
const db = await readDb();
const orgIdx = db.orgs.findIndex((item) => item.title === orgTitle);
if (orgIdx === -1) {
console.error(
chalk.red(
`${
orgTitle || "This organisation"
} doesn't exist in your database!!!`
)
);
return {
err: true,
message: `${
orgTitle || "This organisation"
} doesn't exist in your database!!!`,
code: 404,
};
}
db.orgs.splice(orgIdx, 1);
const accounts = await keytar.findCredentials(orgTitle);
if (accounts.length) {
for (const account of accounts) {
await keytar.deletePassword(orgTitle, account.account);
}
}
await writeDb(db);
return {
err: false,
message: "Organization deleted successfully",
data: db,
};
} catch (error) {
showError();
return {
err: true,
message: "Error: there is some error in the package",
code: 500,
};
}
};
export const markFavourite = async (orgTitle) => {
try {
if (!orgTitle) {
console.error(
chalk.red(
`${
orgTitle || "This organisation"
} doesn't exist in your database!!!`
)
);
return {
err: true,
message: `${
orgTitle || "This organisation"
} doesn't exist in your database!!!`,
code: 404,
};
}
const db = await readDb();
const orgIdx = db.orgs.findIndex((item) => item.title === orgTitle);
if (orgIdx === -1) {
console.error(
chalk.red(
`${
orgTitle || "This organisation"
} doesn't exist in your database!!!`
)
);
return {
err: true,
message: `${
orgTitle || "This organisation"
} doesn't exist in your database!!!`,
code: 404,
};
}
db.orgs[orgIdx].favourite = !db.orgs[orgIdx].favourite;
writeDb(db);
return {
err: false,
message: db.orgs[orgIdx].favourite
? "Organization added to favourites"
: "Organization removed from favourites",
data: db,
};
} catch (error) {
showError();
return {
err: true,
message: "Error: there is some error in the package",
code: 500,
};
}
};
export const markArchived = async (orgTitle) => {
try {
if (!orgTitle) {
console.error(
chalk.red(
`${
orgTitle || "This organisation"
} doesn't exist in your database!!!`
)
);
return {
err: true,
message: `${
orgTitle || "This organisation"
} doesn't exist in your database!!!`,
code: 404,
};
}
const db = await readDb();
const orgIdx = db.orgs.findIndex((item) => item.title === orgTitle);
if (orgIdx === -1) {
console.error(
chalk.red(
`${
orgTitle || "This organisation"
} doesn't exist in your database!!!`
)
);
return {
err: true,
message: `${
orgTitle || "This organisation"
} doesn't exist in your database!!!`,
code: 404,
};
}
db.orgs[orgIdx].archived = !db.orgs[orgIdx].archived;
writeDb(db);
return {
err: false,
message: db.orgs[orgIdx].archived
? "Organization archived"
: "Organization unarchived",
data: db,
};
} catch (error) {
showError();
return {
err: true,
message: "Error: there is some error in the package",
code: 500,
};
}
};
export const logOrgs = async (isFav, isArchived) => {
try {
const db = await readDb();
if (isFav) {
if (isArchived) {
const favArchivedOrgs = db.orgs.filter(
(org) => org.favourite && org.archived
);
if (favArchivedOrgs.length === 0) {
console.log(
`\nFavourite and Archived Organizations: \n${chalk.yellow(
"No data exist!!!"
)}\n`
);
} else {
console.log("\nFavourite and Archived Organizations:");
console.table(favArchivedOrgs, [
"title",
"domain",
"favourite",
"archived",
]);
}
} else {
const favOrgs = db.orgs.filter((org) => org.favourite);
if (favOrgs.length === 0) {
console.log(
`\nFavourite Organizations: \n${chalk.yellow(
"No data exist!!!"
)}\n`
);
} else {
console.log("\nFavourite Organizations:");
console.table(favOrgs, [
"title",
"domain",
"favourite",
"archived",
]);
}
}
} else if (isArchived) {
const archivedOrgs = db.orgs.filter((org) => org.archived);
if (archivedOrgs.length === 0) {
console.log(
`\nArchived Organizations: \n${chalk.yellow(
"No data exist!!!"
)}\n`
);
} else {
console.log("\nArchived Organizations:");
console.table(archivedOrgs, [
"title",
"domain",
"favourite",
"archived",
]);
}
} else {
if (db.orgs.length === 0) {
console.log(
`\n\nAll Organizations: \n${chalk.yellow(
"No data exist!!!"
)}\n`
);
} else {
console.log("\n\nAll Organizations:");
console.table(db.orgs, [
"title",
"domain",
"favourite",
"archived",
]);
}
}
} catch (error) {
showError();
}
};