autho 0.0.4 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,25 +1,53 @@
1
1
  {
2
2
  "name": "autho",
3
- "version": "0.0.4",
4
- "main": "index.js",
5
- "type": "module",
3
+ "version": "0.0.7",
4
+ "main": "build/bin.js",
5
+ "type": "commonjs",
6
6
  "bin": {
7
- "autho": "src/cli/bin.js"
7
+ "autho": "build/bin.js"
8
8
  },
9
- "scripts": {
10
- "test": "echo \"Error: no test specified\" && exit 1"
9
+ "keywords": [
10
+ "secrets",
11
+ "otp"
12
+ ],
13
+ "author": "Nir Adler",
14
+ "license": "MIT",
15
+ "description": "Open Source Authentication and Password Management Tool",
16
+ "devDependencies": {
17
+ "@eslint/js": "^9.0.0",
18
+ "esbuild": "0.20.2",
19
+ "eslint": "^9.0.0",
20
+ "eslint-config-prettier": "^9.1.0",
21
+ "globals": "^15.0.0",
22
+ "jest": "^29.7.0",
23
+ "pkg": "^5.8.1",
24
+ "prettier": "^3.2.5"
11
25
  },
12
- "keywords": [],
13
- "author": "",
14
- "license": "ISC",
15
- "dependencies": {
16
- "commander": "^12.0.0",
17
- "conf": "^12.0.0",
18
- "inquirer": "^9.2.17",
19
- "inquirer-autocomplete-standalone": "^0.8.1",
20
- "joi": "^17.12.2",
21
- "otpauth": "^9.2.2"
26
+ "files": [
27
+ "build/bin.js"
28
+ ],
29
+ "pkg": {
30
+ "scripts": "build/**/*.js",
31
+ "assets": [],
32
+ "targets": [
33
+ "node18-win-x64",
34
+ "node18-linux-arm64",
35
+ "node18-linux-x64",
36
+ "node18-macos-x64"
37
+ ],
38
+ "outputPath": "dist"
22
39
  },
23
- "devDependencies": {},
24
- "description": "Open Source Authentication and Password Management Tool"
25
- }
40
+ "scripts": {
41
+ "format": "prettier --check .",
42
+ "format:write": "prettier --write .",
43
+ "lint": "eslint .",
44
+ "lint:fix": "eslint --fix .",
45
+ "build": "esbuild packages/cli/bin.js --bundle --platform=node --target=node18 --outdir=build",
46
+ "pkg": "npm run pkg:linux && npm run pkg:macos && npm run pkg:win",
47
+ "pkg:macos-arm64": "pkg build/bin.js --output dist/autho --target node18-macos-arm64",
48
+ "pkg:macos": "pkg build/bin.js --output dist/autho-macos --target node18-macos-x64",
49
+ "pkg:linux": "pkg build/bin.js --output dist/autho-linux --target node18-linux-x64",
50
+ "pkg:win": "pkg build/bin.js --output dist/autho-win --target node18-win-x64",
51
+ "release": "gh release create v0.0.6 ./dist"
52
+ }
53
+ }
package/src/cli/bin.js DELETED
@@ -1,126 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { Command } from "commander";
4
- import chalk from "chalk";
5
- import { prompt, ask } from "./utils.js";
6
- import DB from "../sdk/db.js";
7
- import Cipher from "../sdk/cipher.js";
8
- import createSecret from "./wizards/createSecret.js";
9
- import getEncryptionKey from "./wizards/getEncryptionKey.js";
10
- import getSecret from "./wizards/getSecret.js";
11
- import Secrets from "../sdk/secrets.js";
12
- import OTP from "../sdk/otp.js";
13
-
14
- const program = new Command();
15
-
16
- //type AppOptions = {
17
- // masterPasswordHash?: string;
18
- // masterPassword?: string;
19
- // appFolder?: string;
20
- // };
21
-
22
- class App {
23
- constructor(options = {}) {
24
- let masterPasswordHash =
25
- options.masterPasswordHash || process.env.AUTHO_MASTER_PASSWORD_HASH;
26
- const masterPassword = options.masterPassword || process.env.AUTHO_MASTER_PASSWORD;
27
- if (!masterPasswordHash && !masterPassword) {
28
- throw new Error("Master password or master password hash is required")
29
- }
30
- masterPasswordHash =
31
- masterPasswordHash ||
32
- Cipher.hash(masterPassword);
33
- this.db = new DB({ encryptionKey: masterPasswordHash });
34
- this.secrets = new Secrets(this);
35
- }
36
-
37
- }
38
-
39
- program
40
- .name("autho")
41
- .description("Secrets manager")
42
- .version("0.0.1")
43
- .option("-p, --password <password>", "Master password")
44
- .action(async (args) => {
45
- try {
46
- const masterPassword = args.password
47
- ? args.password
48
- : await ask({
49
- name: "masterPassword",
50
- message: "Password:",
51
- type: "password",
52
- required: true,
53
- });
54
-
55
- const app = new App({ masterPassword });
56
-
57
- let choices = [
58
- { value: "create", name: "Create new secret" },
59
- { value: "read", name: "Read secret" },
60
- { value: "delete", name: "Delete secret" },
61
- ];
62
-
63
- const { action } = await prompt({
64
- name: "action",
65
- type: "list",
66
- choices,
67
- required: true,
68
- });
69
-
70
- switch (action) {
71
- case "create":
72
- await createSecret(app);
73
- break;
74
-
75
- case "read":
76
- const readSecret = await getSecret(app);
77
- let encryptionKey = app.db.encryptionKey
78
- if (readSecret.protected) {
79
- encryptionKey = await getEncryptionKey()
80
- }
81
-
82
- readSecret.value = Cipher.decrypt(
83
- readSecret.value,
84
- readSecret.publicKey,
85
- encryptionKey,
86
- readSecret.signature
87
- );
88
- switch (readSecret.type) {
89
- case "password":
90
- console.log("Username:", readSecret.typeOptions.username);
91
- console.log("Password:", readSecret.value);
92
- break;
93
- case "note":
94
- console.log("Note:", readSecret.value);
95
- break;
96
- case "otp":
97
- const otp = new OTP(readSecret);
98
- console.log("OTP code:", otp.generate());
99
- setTimeout(() => {
100
- console.log("Expired");
101
- process.exit(0);
102
- }, 30000);
103
- break;
104
- }
105
-
106
- break;
107
- case "delete":
108
- const deleteSecret = await getSecret(app);
109
- await app.secrets.remove(deleteSecret.id);
110
- console.log("Removed");
111
- process.exit(0);
112
- default:
113
- console.log("Unknown action:", action);
114
- process.exit(1);
115
- }
116
- } catch (error) {
117
- console.log(
118
- chalk.redBright("Something went wrong, Error: "),
119
- error.message
120
- );
121
- console.log(error.stack);
122
- process.exit(1);
123
- }
124
- });
125
-
126
- program.parse();
package/src/cli/utils.js DELETED
@@ -1,15 +0,0 @@
1
- import inquirer from "inquirer";
2
-
3
- export const prompt = inquirer.prompt;
4
-
5
- export const ask = async ({ name = "", message = "", type = "input" }) => {
6
- const answers = await inquirer.prompt([
7
- {
8
- name,
9
- message,
10
- type,
11
- },
12
- ]);
13
-
14
- return answers[name];
15
- };
@@ -1,106 +0,0 @@
1
- import { prompt } from "../utils.js";
2
- import getEncryptionKey from "./getEncryptionKey.js";
3
-
4
- const wizard = async (app) => {
5
- const secrets = app.secrets;
6
- const info = await prompt([
7
- {
8
- name: "name",
9
- message: "name:",
10
- type: "input",
11
- required: true,
12
- },
13
- {
14
- name: "type",
15
- message: "type:",
16
- type: "list",
17
- default: "password",
18
- choices: ["password", "otp", "note"],
19
- required: true,
20
- },
21
- {
22
- name: "protected",
23
- message: "protected:",
24
- type: "confirm",
25
- default: false,
26
- required: true,
27
- }
28
- ]);
29
-
30
- let newSecret = {};
31
- let encryptionKey = app.db.encryptionKey
32
-
33
- if (info.protected) {
34
- encryptionKey = await getEncryptionKey(true)
35
- }
36
-
37
- switch (info.type) {
38
- case "password":
39
- const password = await prompt([
40
- {
41
- name: "username",
42
- message: "username:",
43
- type: "input",
44
- required: true,
45
- },
46
- {
47
- name: "value",
48
- message: "password:",
49
- type: "password",
50
- required: true,
51
- },
52
- ]);
53
- newSecret = {
54
- ...info,
55
- value: password.value,
56
- typeOptions: {
57
- username: password.username,
58
- },
59
- };
60
- break;
61
- case "note":
62
- const note = await prompt([
63
- {
64
- name: "value",
65
- message: "note:",
66
- type: "password",
67
- required: true,
68
- },
69
- ]);
70
- newSecret = {
71
- ...info,
72
- value: note.value,
73
- typeOptions: {
74
-
75
- },
76
- };
77
- break;
78
- case "otp":
79
- const otp = await prompt([
80
- {
81
- name: "username",
82
- message: "username:",
83
- type: "input",
84
- required: true,
85
- },
86
- {
87
- name: "value",
88
- message: "value:",
89
- type: "password",
90
- required: true,
91
- },
92
- ]);
93
- newSecret = {
94
- ...info,
95
- value: otp.value,
96
- typeOptions: {
97
- username: otp.username,
98
- },
99
- };
100
- break;
101
- }
102
-
103
- await secrets.add(newSecret, encryptionKey);
104
- };
105
-
106
- export default wizard;
@@ -1,30 +0,0 @@
1
- import Cipher from "../../sdk/cipher.js";
2
- import { prompt } from "../utils.js";
3
-
4
- const wizard = async (confirm = false) => {
5
- const questions = [{
6
- name: "password",
7
- message: "password:",
8
- type: "password",
9
- required: true,
10
- }
11
- ]
12
- if (confirm) {
13
- questions.push({
14
- name: "confirmPassword",
15
- message: "confirm password:",
16
- type: "password",
17
- required: true,
18
- });
19
- }
20
- const input = await prompt(questions);
21
-
22
- if (input.confirmPassword && input.password !== input.confirmPassword) {
23
- throw new Error("Passwords do not match");
24
- }
25
-
26
- return Cipher.hash(input.password);
27
- }
28
-
29
-
30
- export default wizard;
@@ -1,31 +0,0 @@
1
- import { prompt } from "../utils.js";
2
-
3
- const wizard = async (app) => {
4
- const existingSecrets = app.db.get("secrets", []);
5
-
6
- if (existingSecrets.length === 0) {
7
- throw new Error("No secrets found");
8
- }
9
-
10
- const choices = existingSecrets.map((secret) => ({
11
- value: secret.id,
12
- name: `${secret.name} (${secret.typeOptions.username || secret.id})`,
13
- }));
14
-
15
- const { id: secretId } = await prompt({
16
- name: "id",
17
- message: "Secrets:",
18
- type: "list",
19
- choices,
20
- required: true,
21
- });
22
- const secret = await app.secrets.get(secretId);
23
-
24
- if (!secret) {
25
- throw new Error("Secret not found");
26
- }
27
-
28
- return secret;
29
- };
30
-
31
- export default wizard;
@@ -1,12 +0,0 @@
1
- import Joi from 'joi';
2
- import Cipher from "../sdk/cipher.js";
3
-
4
- export const createSecretSchema = Joi.object({
5
- id: Joi.string().default(Cipher.randomString()),
6
- protected: Joi.boolean().default(false), // ask for password
7
- name: Joi.string().required(),
8
- type: Joi.string().required().valid('otp', 'password', 'note'),
9
- value: Joi.string().required(),
10
- typeOptions: Joi.object().default({}),
11
- createdAt: Joi.date().default(new Date()),
12
- })
package/src/sdk/cipher.js DELETED
@@ -1,70 +0,0 @@
1
- import crypto from "crypto";
2
-
3
- export default class Cipher {
4
-
5
- static hash(text, algorithm = "sha256") {
6
- const hash = crypto.createHash(algorithm);
7
- hash.update(text);
8
-
9
- return hash.digest("hex");
10
- }
11
-
12
- static random(size = 16) {
13
- const rnd = crypto.randomBytes(size);
14
-
15
- return rnd;
16
- }
17
-
18
- static randomString() {
19
- const rnd = Cipher.random().toString("hex");
20
-
21
- return rnd;
22
- }
23
-
24
- static sign(text) {
25
- const hash = Cipher.hash(text)
26
- const signature = `${hash.substring(0, 10)}:${hash.substring(hash.length - 10)}`;
27
-
28
- return signature;
29
- }
30
-
31
- static verify(text, signature) {
32
- const expectedSignature = Cipher.sign(text)
33
-
34
- return expectedSignature === signature;
35
- }
36
-
37
- static encrypt(text, encryptionKey, algorithm = "aes-256-ctr") {
38
- const publicKey = Cipher.randomString();
39
- let cipher = crypto.createCipheriv(
40
- algorithm,
41
- Buffer.from(encryptionKey, "hex"),
42
- Buffer.from(publicKey, "hex"),
43
- );
44
- let encrypted = cipher.update(text);
45
- encrypted = Buffer.concat([encrypted, cipher.final()]);
46
- encrypted = encrypted.toString("hex");
47
-
48
- return { publicKey, encrypted, algorithm, signature: Cipher.sign(text) };
49
- }
50
-
51
- static decrypt(encryptedText, publicKey, encryptionKey, signature, algorithm = "aes-256-ctr") {
52
- encryptedText = Buffer.from(encryptedText, "hex");
53
-
54
- let decipher = crypto.createDecipheriv(
55
- algorithm,
56
- Buffer.from(encryptionKey, "hex"),
57
- Buffer.from(publicKey, "hex")
58
- );
59
-
60
- let decrypted = decipher.update(encryptedText);
61
- decrypted = Buffer.concat([decrypted, decipher.final()]);
62
- decrypted = decrypted.toString();
63
-
64
- if (!Cipher.verify(decrypted, signature)) {
65
- throw new Error("Invalid signature")
66
- }
67
-
68
- return decrypted;
69
- }
70
- }
package/src/sdk/db.js DELETED
@@ -1,23 +0,0 @@
1
- import Conf from "conf";
2
-
3
- const { AUTHO_ENCRYPTION_KEY = "", AUTHO_NAME = 'default' } = process.env;
4
-
5
- export default class DB {
6
- constructor({
7
- encryptionKey = AUTHO_ENCRYPTION_KEY,
8
- configName = AUTHO_NAME
9
- }) {
10
- this.encryptionKey = encryptionKey;
11
- this.client = new Conf({ projectName: "autho", encryptionKey, configName });
12
- }
13
-
14
- get(key, defaultValue) {
15
- return this.client.get(key, defaultValue);
16
- }
17
-
18
- set(key, value) {
19
- this.client.set(key, value);
20
- }
21
-
22
- }
23
-
package/src/sdk/otp.js DELETED
@@ -1,25 +0,0 @@
1
- import * as OTPAuth from "otpauth";
2
-
3
- export default class OTP {
4
- constructor(secret) {
5
-
6
- const options = {
7
- issuer: "Autho",
8
- label: secret.name,
9
- algorithm: "SHA1",
10
- digits: 6,
11
- period: 30,
12
- secret: secret.value,
13
- };
14
-
15
- this.totp = new OTPAuth.TOTP(options);
16
- }
17
-
18
- generate() {
19
- return this.totp.generate();
20
- }
21
-
22
- validate(token, window = 1) {
23
- return this.totp.validate({ token, window });
24
- }
25
- }
@@ -1,39 +0,0 @@
1
- import { createSecretSchema } from "../models/Secret.js";
2
- import Cipher from "../sdk/cipher.js";
3
-
4
- export default class Secrets {
5
- constructor(app) {
6
- this.db = app.db;
7
- }
8
-
9
- get secrets() {
10
- return this.db.get("secrets", []);
11
- }
12
-
13
- set secrets(value) {
14
- this.db.set("secrets", value);
15
- }
16
-
17
- async get(id) {
18
- return this.secrets.find((secret) => secret.id == id);
19
- }
20
-
21
- async add(secret, encryptionKey) {
22
- const { value, error } = createSecretSchema.validate(secret);
23
- if (error) {
24
- throw new Error(error);
25
- }
26
-
27
- const { encrypted, ...encryption } = Cipher.encrypt(value.value, encryptionKey);
28
-
29
- this.secrets = [...this.secrets, { ...value, ...encryption, value: encrypted }];
30
- }
31
-
32
- async remove(id) {
33
- this.secrets = this.secrets.filter((secret) => secret.id != id);
34
- }
35
-
36
- async clear() {
37
- this.secrets = [];
38
- }
39
- }