autho 0.0.2 → 0.0.3

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,10 +1,11 @@
1
1
  {
2
2
  "name": "autho",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
- "bin":{
7
- "autho": "./src/cli/bin.js"},
6
+ "bin": {
7
+ "autho": "src/cli/bin.js"
8
+ },
8
9
  "scripts": {
9
10
  "test": "echo \"Error: no test specified\" && exit 1"
10
11
  },
package/src/cli/bin.js CHANGED
@@ -13,9 +13,14 @@ const program = new Command();
13
13
 
14
14
  const getSecret = async (config) => {
15
15
  const existingSecrets = config.get("secrets", []);
16
+
17
+ if (existingSecrets.length === 0) {
18
+ throw new Error("No secrets found");
19
+ }
20
+
16
21
  const choices = existingSecrets.map((secret) => ({
17
22
  value: secret.id,
18
- name: secret.name,
23
+ name: `${secret.name} (${secret.typeOptions.username || secret.id})`,
19
24
  }));
20
25
 
21
26
  const { id: secretId } = await prompt({
@@ -25,7 +30,6 @@ const getSecret = async (config) => {
25
30
  choices,
26
31
  required: true,
27
32
  });
28
-
29
33
  const secrets = new Secrets(config);
30
34
  const secret = await secrets.get(secretId);
31
35
 
@@ -46,19 +50,13 @@ program
46
50
  const masterPassword = args.password
47
51
  ? args.password
48
52
  : await ask({
49
- name: "masterPassword",
50
- message: "Password:",
51
- type: "password",
52
- required: true,
53
- });
53
+ name: "masterPassword",
54
+ message: "Password:",
55
+ type: "password",
56
+ required: true,
57
+ });
54
58
  const masterPasswordHash = Cipher.hash(masterPassword);
55
59
  const config = new Config({ encryptionKey: masterPasswordHash });
56
- let salt = config.get();
57
-
58
- if (!salt) {
59
- salt = Cipher.random();
60
- config.set("salt", salt);
61
- }
62
60
 
63
61
  let choices = [
64
62
  { value: "create", name: "Create new secret" },
@@ -79,23 +77,33 @@ program
79
77
 
80
78
  case "read":
81
79
  const readSecret = await getSecret(config);
82
-
83
- switch (readSecret.type) {
84
- case "otp":
85
- const otp = new OTP(config, readSecret, masterPasswordHash);
86
- console.log(otp.generate());
87
- setTimeout(() => {
88
- console.log("Expired");
89
- process.exit(0);
90
- }, 30000);
91
- break;
92
- }
93
-
80
+ readSecret.value = Cipher.decrypt(readSecret.value, readSecret.publicKey, masterPasswordHash)
81
+
82
+ switch (readSecret.type) {
83
+ case "password":
84
+ console.log("Username:", readSecret.typeOptions.username);
85
+ console.log("Password:", readSecret.value);
86
+ break;
87
+ case "note":
88
+ console.log("Note:", readSecret.value);
89
+ break;
90
+ case "otp":
91
+ const otp = new OTP(readSecret);
92
+ console.log("OTP code:", otp.generate());
93
+ setTimeout(() => {
94
+ console.log("Expired");
95
+ process.exit(0);
96
+ }, 30000);
97
+ break;
98
+ }
99
+
94
100
  break;
95
101
  case "delete":
96
- const deleteSecret = getSecret(config);
97
- const secrets = new Secrets(config);
98
- secrets.remove(deleteSecret.id)
102
+ const deleteSecret = await getSecret(config);
103
+ const secrets = new Secrets(config);
104
+ await secrets.remove(deleteSecret.id)
105
+ console.log("Removed");
106
+ process.exit(0);
99
107
  break;
100
108
  }
101
109
  } catch (error) {
@@ -12,9 +12,9 @@ const wizard = async (config, masterPasswordHash) => {
12
12
  {
13
13
  name: "type",
14
14
  message: "type:",
15
- type: "choice",
16
- default: "otp",
17
- choices: ["otp"],
15
+ type: "list",
16
+ default: "password",
17
+ choices: ["password", "otp", "note"],
18
18
  required: true,
19
19
  }
20
20
  ]);
@@ -22,29 +22,71 @@ const wizard = async (config, masterPasswordHash) => {
22
22
  let newSecret = {};
23
23
 
24
24
  switch (info.type) {
25
+ case "password":
26
+ const password = await prompt([
27
+ {
28
+ name: "username",
29
+ message: "username:",
30
+ type: "input",
31
+ required: true,
32
+ },
33
+ {
34
+ name: "value",
35
+ message: "password:",
36
+ type: "password",
37
+ required: true,
38
+ },
39
+ ]);
40
+ newSecret = {
41
+ name: info.name,
42
+ type: info.type,
43
+ value: password.value,
44
+ typeOptions: {
45
+ username: password.username,
46
+ },
47
+ };
48
+ break;
49
+ case "note":
50
+ const note = await prompt([
51
+ {
52
+ name: "value",
53
+ message: "note:",
54
+ type: "password",
55
+ required: true,
56
+ },
57
+ ]);
58
+ newSecret = {
59
+ name: info.name,
60
+ type: info.type,
61
+ value: note.value,
62
+ typeOptions: {
63
+
64
+ },
65
+ };
66
+ break;
25
67
  case "otp":
26
- const secret = await prompt([
27
- {
28
- name: "username",
29
- message: "username:",
30
- type: "input",
31
- required: true,
32
- },
33
- {
34
- name: "value",
35
- message: "value:",
36
- type: "password",
37
- required: true,
38
- },
39
- ]);
40
- newSecret = {
41
- name: info.name,
42
- type: info.type,
43
- value: secret.value,
44
- typeOptions: {
45
- username: secret.username,
46
- },
47
- };
68
+ const otp = await prompt([
69
+ {
70
+ name: "username",
71
+ message: "username:",
72
+ type: "input",
73
+ required: true,
74
+ },
75
+ {
76
+ name: "value",
77
+ message: "value:",
78
+ type: "password",
79
+ required: true,
80
+ },
81
+ ]);
82
+ newSecret = {
83
+ name: info.name,
84
+ type: info.type,
85
+ value: otp.value,
86
+ typeOptions: {
87
+ username: otp.username,
88
+ },
89
+ };
48
90
  break;
49
91
  }
50
92
 
@@ -2,10 +2,10 @@ import Joi from 'joi';
2
2
  import Cipher from "../sdk/cipher.js";
3
3
 
4
4
  export const createSecretSchema = Joi.object({
5
- id: Joi.string().default(Cipher.random()),
5
+ id: Joi.string().default(Cipher.randomString()),
6
6
  protected: Joi.boolean().default(false), // ask for password
7
7
  name: Joi.string().required(),
8
- type: Joi.string().required().valid('otp'),
8
+ type: Joi.string().required().valid('otp', 'password', 'note'),
9
9
  value: Joi.string().required(),
10
10
  typeOptions: Joi.object().default({}),
11
11
  createdAt: Joi.date().default(new Date()),
package/src/sdk/cipher.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import crypto from "crypto";
2
2
 
3
+ const algorithm = "aes-256-ctr";
4
+ const IV_LENGTH = 16;
5
+
3
6
  export default class Cipher {
4
- constructor(config) {
5
- this.config = config;
6
- this.salt = config.get("salt", "");
7
- }
7
+ constructor() { }
8
8
 
9
9
  static hash(text) {
10
10
  const hash = crypto.createHash("sha256");
@@ -13,38 +13,42 @@ export default class Cipher {
13
13
  return hash.digest("hex");
14
14
  }
15
15
 
16
- static random() {
17
- const rnd = crypto.randomBytes(16).toString("hex");
16
+ static random(size = IV_LENGTH) {
17
+ const rnd = crypto.randomBytes(size);
18
18
 
19
19
  return rnd;
20
20
  }
21
21
 
22
- static createKey(salt="") {
23
- const rnd = Cipher.random(salt)
22
+ static randomString() {
23
+ const rnd = Cipher.random().toString("hex");
24
24
 
25
- return Cipher.hash(salt+rnd);
25
+ return rnd;
26
26
  }
27
27
 
28
- encrypt(text, password) {
29
- const publicKey = Cipher.createKey(this.salt);
30
- const cipher = crypto.createCipher(
31
- "aes-256-cbc",
32
- publicKey + password
28
+ static encrypt(text, password) {
29
+ const publicKey = Cipher.randomString();
30
+ let cipher = crypto.createCipheriv(
31
+ algorithm,
32
+ Buffer.from(password, "hex"),
33
+ Buffer.from(publicKey, "hex"),
33
34
  );
34
- let encrypted = cipher.update(text, "utf8", "hex");
35
- encrypted += cipher.final("hex");
35
+ let encrypted = cipher.update(text);
36
+ encrypted = Buffer.concat([encrypted, cipher.final()]);
37
+ encrypted = encrypted.toString("hex");
36
38
 
37
39
  return { publicKey, encrypted };
38
40
  }
39
41
 
40
- decrypt(encryptedText, publicKey, password) {
41
- const decipher = crypto.createDecipher(
42
- "aes-256-cbc",
43
- publicKey + password
42
+ static decrypt(encryptedText, publicKey, password) {
43
+ encryptedText = Buffer.from(encryptedText, "hex");
44
+ let decipher = crypto.createDecipheriv(
45
+ algorithm,
46
+ Buffer.from(password, "hex"),
47
+ Buffer.from(publicKey, "hex")
44
48
  );
45
- let decrypted = decipher.update(encryptedText, "hex", "utf8");
46
- decrypted += decipher.final("utf8");
49
+ let decrypted = decipher.update(encryptedText);
50
+ decrypted = Buffer.concat([decrypted, decipher.final()]);
47
51
 
48
- return decrypted;
52
+ return decrypted.toString();
49
53
  }
50
54
  }
package/src/sdk/config.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import Conf from "conf";
2
2
 
3
+ const { AUTHO_ENCRYPTION_KEY = "", AUTHO_NAME = 'default' } = process.env;
4
+
3
5
  export default class Config {
4
6
  constructor({
5
- encryptionKey,
6
- configName='default'
7
+ encryptionKey = AUTHO_ENCRYPTION_KEY,
8
+ configName = AUTHO_NAME
7
9
  }) {
8
10
  this.config = new Conf({ projectName: "autho", encryptionKey, configName });
9
11
  }
package/src/sdk/otp.js CHANGED
@@ -1,16 +1,15 @@
1
1
  import * as OTPAuth from "otpauth";
2
- import Cipher from "./cipher.js";
3
2
 
4
3
  export default class OTP {
5
- constructor(config, secret, password) {
6
- const cipher = new Cipher(config);
4
+ constructor(secret) {
5
+
7
6
  const options = {
8
- issuer: "ACME",
7
+ issuer: "Autho",
9
8
  label: secret.name,
10
9
  algorithm: "SHA1",
11
10
  digits: 6,
12
11
  period: 30,
13
- secret: cipher.decrypt(secret.value, secret.publicKey, password),
12
+ secret: secret.value,
14
13
  };
15
14
 
16
15
  this.totp = new OTPAuth.TOTP(options);
@@ -4,7 +4,6 @@ import Cipher from "./cipher.js";
4
4
  export default class Secrets {
5
5
  constructor(config) {
6
6
  this.config = config;
7
- this.cipher = new Cipher(config);
8
7
  }
9
8
 
10
9
  get secrets() {
@@ -25,7 +24,7 @@ export default class Secrets {
25
24
  throw new Error(error);
26
25
  }
27
26
 
28
- const { publicKey, encrypted } = this.cipher.encrypt(value.value, password);
27
+ const { publicKey, encrypted } = Cipher.encrypt(value.value, password);
29
28
  value.value = encrypted;
30
29
  value.publicKey = publicKey;
31
30
 
@@ -35,4 +34,8 @@ export default class Secrets {
35
34
  async remove(id) {
36
35
  this.secrets = this.secrets.filter((secret) => secret.id != id);
37
36
  }
37
+
38
+ async clear() {
39
+ this.secrets = [];
40
+ }
38
41
  }