secrez 2.1.12 â 2.1.13
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/README.md +14 -15
- package/bin/secrez.js +18 -17
- package/package.json +1 -1
- package/scripts/preinstall.js +1 -1
- package/src/Welcome.js +1 -142
- package/src/commands/Conf.js +2 -295
- package/scripts/fido2_credential.py +0 -88
- package/scripts/hmac_secret.py +0 -111
- package/scripts/is_fido2_ready.py +0 -56
- package/src/utils/Fido2Client.js +0 -118
package/README.md
CHANGED
|
@@ -43,8 +43,6 @@ Secrez aims to provide a secure password management solution that is available e
|
|
|
43
43
|
|
|
44
44
|
To achieve its goal, Secrez uses several strategies. First, any secret is a local file. Second, any file, whether it's a tree version, a directory, a text file, or a binary file, is immutable. Finally, any change can be pulled/pushed to a remote private repository. You can either create a private repository on GitHub, BitBucket, etc. or set up your own self-hosted Git server.
|
|
45
45
|
|
|
46
|
-
In addition to functioning as a password manager, Secrez also includes an optional decentralized, surveillance-resistant, end-to-end encrypted messaging system. This provides an extra layer of security for your communications, ensuring that your messages cannot be intercepted or read by anyone other than the intended recipient.
|
|
47
|
-
|
|
48
46
|
Overall, Secrez offers a powerful and secure solution for managing your passwords and secrets, all from the command line.
|
|
49
47
|
|
|
50
48
|
## The structure
|
|
@@ -370,6 +368,10 @@ Secrez is not intended to compete with password managers, so do not expect it to
|
|
|
370
368
|
|
|
371
369
|
## History
|
|
372
370
|
|
|
371
|
+
**2.1.12**
|
|
372
|
+
|
|
373
|
+
- enforce the usage of pnpm during global install. When that is not possible, for example with yarn, it blocks the execution asking the user to uninstall and install it again properly
|
|
374
|
+
|
|
373
375
|
**2.1.11**
|
|
374
376
|
|
|
375
377
|
- fix warning "(node:70960) [DEP0190] DeprecationWarning: Passing args to a child process with shell option true can lead to security vulnerabilities" caused by the Git checker
|
|
@@ -498,6 +500,10 @@ Secrez is not intended to compete with password managers, so do not expect it to
|
|
|
498
500
|
- remove second factor authentication due to potentially critical issues with Python and the required libraries on macOS (2FA will be restored as soon as either a pure Javascript library is available or using external Python libraries is reliable again)
|
|
499
501
|
- `Bash` has been renamed `Shell`
|
|
500
502
|
|
|
503
|
+
**0.11.0**
|
|
504
|
+
|
|
505
|
+
- removed support for FIDO2 second factor authentication due to potential critical issues with Python and the required libraries on MacOS (2FA may be restored if a pure Javascript library becomes available)
|
|
506
|
+
|
|
501
507
|
**0.10.8**
|
|
502
508
|
|
|
503
509
|
- expose a prompt mock to allow other software to run commands programmatically
|
|
@@ -886,30 +892,29 @@ Thank you for any contributions! đ
|
|
|
886
892
|
## Test coverage
|
|
887
893
|
|
|
888
894
|
```
|
|
889
|
-
162 passing (
|
|
890
|
-
1 pending
|
|
895
|
+
162 passing (2m)
|
|
891
896
|
|
|
892
897
|
--------------------|---------|----------|---------|---------|--------------------------------------
|
|
893
898
|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
|
|
894
899
|
--------------------|---------|----------|---------|---------|--------------------------------------
|
|
895
|
-
All files |
|
|
900
|
+
All files | 81.62 | 68.94 | 83.57 | 81.53 |
|
|
896
901
|
src | 57.62 | 53.75 | 55 | 58.11 |
|
|
897
902
|
Command.js | 74.66 | 74.13 | 78.57 | 75.67 | ...5-62,73,80,93,127,164-172,179-182
|
|
898
903
|
PreCommand.js | 8.82 | 0 | 0 | 8.82 | 6-97
|
|
899
904
|
cliConfig.js | 100 | 100 | 100 | 100 |
|
|
900
|
-
src/commands | 83.
|
|
905
|
+
src/commands | 83.01 | 69.34 | 90.82 | 82.89 |
|
|
901
906
|
Alias.js | 88.6 | 78.68 | 100 | 88.46 | 101,112,139,169,173,180,190,213-214
|
|
902
907
|
Bash.js | 75 | 0 | 66.66 | 75 | 18-19
|
|
903
908
|
Cat.js | 98.91 | 88.88 | 100 | 98.91 | 152
|
|
904
909
|
Cd.js | 96.42 | 86.66 | 100 | 96.42 | 44
|
|
905
|
-
Conf.js | 8.64 | 0 | 20 | 8.64 |
|
|
910
|
+
Conf.js | 8.64 | 0 | 20 | 8.64 | 47-216
|
|
906
911
|
Contacts.js | 86.06 | 75.6 | 100 | 85.95 | ...5,165,172,184,237,250,260,268-269
|
|
907
912
|
Copy.js | 91.2 | 71.92 | 100 | 91.11 | 115,166,183,205-210,225-226,253
|
|
908
913
|
Ds.js | 90.27 | 82.6 | 100 | 90.14 | 99,108-113,125,147-148
|
|
909
914
|
Edit.js | 12.94 | 0 | 40 | 12.94 | 88-222
|
|
910
915
|
Export.js | 90.17 | 76.92 | 100 | 90.17 | ...3-198,209,227-231,236,248,257,260
|
|
911
916
|
Find.js | 93.58 | 86.66 | 100 | 93.42 | 101,164,200-203,209
|
|
912
|
-
Git.js |
|
|
917
|
+
Git.js | 92.3 | 66.66 | 100 | 92.3 | 40,61
|
|
913
918
|
Help.js | 100 | 80 | 100 | 100 | 29
|
|
914
919
|
Import.js | 92.41 | 85.38 | 100 | 92.34 | ...7,387,393,441,457-458,466-473,500
|
|
915
920
|
Lcat.js | 100 | 85.71 | 100 | 100 | 54
|
|
@@ -935,18 +940,12 @@ All files | 80.07 | 67.69 | 80.91 | 79.96 |
|
|
|
935
940
|
index.js | 87.5 | 50 | 100 | 86.95 | 15,22,31
|
|
936
941
|
src/prompts | 75 | 33.33 | 50 | 75 |
|
|
937
942
|
MainPromptMock.js | 75 | 33.33 | 50 | 75 | 29-35,44
|
|
938
|
-
src/utils |
|
|
943
|
+
src/utils | 83.07 | 78.43 | 66.66 | 82.81 |
|
|
939
944
|
AliasManager.js | 100 | 91.66 | 100 | 100 | 47
|
|
940
945
|
ContactManager.js | 73.33 | 60 | 85.71 | 73.33 | 12,34-36
|
|
941
|
-
Fido2Client.js | 9.61 | 0 | 0 | 9.61 | 8-108
|
|
942
946
|
HelpProto.js | 89.07 | 82.6 | 100 | 88.88 | 49,135-137,153-154,171-176,195
|
|
943
947
|
Logger.js | 63.63 | 56.25 | 36.84 | 62.79 | ...25,37-49,57,65-69,74,84,88,93,105
|
|
944
948
|
--------------------|---------|----------|---------|---------|--------------------------------------
|
|
945
|
-
|
|
946
|
-
> secrez@2.1.11-beta.0 posttest /Users/francescosullo/Projects/Secrez/secrez/packages/secrez
|
|
947
|
-
> nyc check-coverage --statements 65 --branches 50 --functions 65 --lines 65
|
|
948
|
-
|
|
949
|
-
|
|
950
949
|
```
|
|
951
950
|
|
|
952
951
|
## Copyright
|
package/bin/secrez.js
CHANGED
|
@@ -10,44 +10,45 @@ const pkg = require("../package");
|
|
|
10
10
|
const MainPrompt = require("../src/prompts/MainPrompt");
|
|
11
11
|
const Logger = require("../src/utils/Logger");
|
|
12
12
|
|
|
13
|
-
// Check if the package was installed with pnpm
|
|
13
|
+
// Check if the package was installed with pnpm (skip check in development)
|
|
14
14
|
const installPath = __dirname;
|
|
15
|
-
if (installPath.indexOf("pnpm") === -1) {
|
|
16
|
-
console.error(
|
|
17
|
-
chalk.red.bold("\nâ ď¸ Installation Error\n")
|
|
18
|
-
);
|
|
15
|
+
if (process.env.NODE_ENV !== "dev" && installPath.indexOf("pnpm") === -1) {
|
|
16
|
+
console.error(chalk.red.bold("\nâ ď¸ Installation Error\n"));
|
|
19
17
|
console.error(
|
|
20
18
|
chalk.yellow(
|
|
21
19
|
"Secrez must be installed globally using pnpm.\n" +
|
|
22
|
-
|
|
20
|
+
"It appears this package was installed with a different package manager.\n"
|
|
23
21
|
)
|
|
24
22
|
);
|
|
25
|
-
console.error(
|
|
26
|
-
chalk.white("\nPlease follow these steps:\n")
|
|
27
|
-
);
|
|
23
|
+
console.error(chalk.white("\nPlease follow these steps:\n"));
|
|
28
24
|
console.error(
|
|
29
25
|
chalk.cyan(
|
|
30
26
|
"1. Uninstall secrez using the package manager you previously used:\n" +
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
" - If you used npm: " +
|
|
28
|
+
chalk.bold("npm uninstall -g secrez") +
|
|
29
|
+
"\n" +
|
|
30
|
+
" - If you used yarn: " +
|
|
31
|
+
chalk.bold("yarn global remove secrez") +
|
|
32
|
+
"\n"
|
|
33
33
|
)
|
|
34
34
|
);
|
|
35
35
|
console.error(
|
|
36
36
|
chalk.cyan(
|
|
37
37
|
"2. Install pnpm globally if you haven't already:\n" +
|
|
38
|
-
|
|
38
|
+
" " +
|
|
39
|
+
chalk.bold("npm install -g pnpm") +
|
|
40
|
+
"\n"
|
|
39
41
|
)
|
|
40
42
|
);
|
|
41
43
|
console.error(
|
|
42
|
-
chalk.cyan(
|
|
43
|
-
"3. Setup pnpm:\n" +
|
|
44
|
-
" " + chalk.bold("pnpm setup") + "\n"
|
|
45
|
-
)
|
|
44
|
+
chalk.cyan("3. Setup pnpm:\n" + " " + chalk.bold("pnpm setup") + "\n")
|
|
46
45
|
);
|
|
47
46
|
console.error(
|
|
48
47
|
chalk.cyan(
|
|
49
48
|
"4. Install secrez globally using pnpm:\n" +
|
|
50
|
-
|
|
49
|
+
" " +
|
|
50
|
+
chalk.bold("pnpm install -g secrez") +
|
|
51
|
+
"\n"
|
|
51
52
|
)
|
|
52
53
|
);
|
|
53
54
|
process.exit(1);
|
package/package.json
CHANGED
package/scripts/preinstall.js
CHANGED
package/src/Welcome.js
CHANGED
|
@@ -3,7 +3,6 @@ const inquirer = require("inquirer");
|
|
|
3
3
|
const fs = require("fs-extra");
|
|
4
4
|
const Crypto = require("@secrez/crypto");
|
|
5
5
|
const Logger = require("./utils/Logger");
|
|
6
|
-
// const Fido2Client = require("./utils/Fido2Client"); // FIDO2 support removed
|
|
7
6
|
|
|
8
7
|
class Welcome {
|
|
9
8
|
async start(secrez, options) {
|
|
@@ -35,10 +34,7 @@ Thanks.`);
|
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
if (await fs.pathExists(this.secrez.config.keysPath)) {
|
|
38
|
-
|
|
39
|
-
if (errorCode === 1) {
|
|
40
|
-
await this.handleDeprecatedFido2();
|
|
41
|
-
}
|
|
37
|
+
await this.login();
|
|
42
38
|
} else {
|
|
43
39
|
Logger.grey("Please signup to create your local account");
|
|
44
40
|
await this.signup();
|
|
@@ -111,97 +107,6 @@ Thanks.`);
|
|
|
111
107
|
}
|
|
112
108
|
}
|
|
113
109
|
|
|
114
|
-
// sharedLogin() method removed - FIDO2 support deprecated
|
|
115
|
-
/*
|
|
116
|
-
async sharedLogin() {
|
|
117
|
-
let fido2Client = new Fido2Client(this.secrez);
|
|
118
|
-
let authenticator;
|
|
119
|
-
let list = await fido2Client.getKeys();
|
|
120
|
-
const conf = await this.secrez.readConf();
|
|
121
|
-
let choices = [];
|
|
122
|
-
for (let authenticator in conf.data.keys) {
|
|
123
|
-
choices.push(authenticator);
|
|
124
|
-
}
|
|
125
|
-
for (;;) {
|
|
126
|
-
if (list.length === 1) {
|
|
127
|
-
authenticator = list[0];
|
|
128
|
-
} else {
|
|
129
|
-
let p = await inquirer.prompt([
|
|
130
|
-
{
|
|
131
|
-
type: "list",
|
|
132
|
-
name: "authenticator",
|
|
133
|
-
message: "Which second factor would you like to use?",
|
|
134
|
-
choices,
|
|
135
|
-
},
|
|
136
|
-
]);
|
|
137
|
-
authenticator = p.authenticator;
|
|
138
|
-
}
|
|
139
|
-
let secret;
|
|
140
|
-
try {
|
|
141
|
-
try {
|
|
142
|
-
if (fido2Client.keys[authenticator]) {
|
|
143
|
-
Logger.grey("Touch your fido2 authenticator device now...");
|
|
144
|
-
secret = await fido2Client.verifySecret(authenticator);
|
|
145
|
-
} else {
|
|
146
|
-
let exitCode = Crypto.getRandomBase58String(2);
|
|
147
|
-
let p = await inquirer.prompt([
|
|
148
|
-
{
|
|
149
|
-
name: "recoveryCode",
|
|
150
|
-
type: "input",
|
|
151
|
-
message: "Type or paste your recovery code:",
|
|
152
|
-
validate: (value) => {
|
|
153
|
-
if (value.length) {
|
|
154
|
-
return true;
|
|
155
|
-
} else {
|
|
156
|
-
return `
|
|
157
|
-
Please
|
|
158
|
-
paste
|
|
159
|
-
a
|
|
160
|
-
valid
|
|
161
|
-
recovery
|
|
162
|
-
code
|
|
163
|
-
or
|
|
164
|
-
type ${exitCode}
|
|
165
|
-
to
|
|
166
|
-
choose
|
|
167
|
-
another
|
|
168
|
-
factor.`;
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
]);
|
|
173
|
-
if (p.recoveryCode === exitCode) {
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
secret = p.recoveryCode;
|
|
177
|
-
}
|
|
178
|
-
let resCode = await this.secrez.sharedSignin(authenticator, secret);
|
|
179
|
-
if (this.secrez.masterKeyHash) {
|
|
180
|
-
await this.saveIterations();
|
|
181
|
-
}
|
|
182
|
-
if (resCode === 1) {
|
|
183
|
-
Logger.bold(chalk.red("Your data has been upgraded."));
|
|
184
|
-
Logger.red(
|
|
185
|
-
"To avoid conflicts, any registered second factor has been removed."
|
|
186
|
-
);
|
|
187
|
-
Logger.grey("Please, register them again, thanks.");
|
|
188
|
-
}
|
|
189
|
-
return;
|
|
190
|
-
} catch (e) {
|
|
191
|
-
Logger.red(`${e.message}.Try
|
|
192
|
-
again
|
|
193
|
-
or
|
|
194
|
-
Ctrl - C
|
|
195
|
-
to
|
|
196
|
-
exit.`);
|
|
197
|
-
}
|
|
198
|
-
} catch (e) {
|
|
199
|
-
Logger.red("Unrecognized error. Try again or Ctrl-C to exit.");
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
*/
|
|
204
|
-
|
|
205
110
|
async signup() {
|
|
206
111
|
for (;;) {
|
|
207
112
|
try {
|
|
@@ -248,52 +153,6 @@ Thanks.`);
|
|
|
248
153
|
}
|
|
249
154
|
}
|
|
250
155
|
}
|
|
251
|
-
|
|
252
|
-
async handleDeprecatedFido2() {
|
|
253
|
-
Logger.yellow(
|
|
254
|
-
"FIDO2 second factor authentication is no longer supported in this version."
|
|
255
|
-
);
|
|
256
|
-
Logger.grey("Removing deprecated FIDO2 configuration...");
|
|
257
|
-
|
|
258
|
-
try {
|
|
259
|
-
const conf = await this.secrez.readConf();
|
|
260
|
-
const data = conf.data;
|
|
261
|
-
|
|
262
|
-
if (data.keys) {
|
|
263
|
-
// Remove all FIDO2 keys from the configuration
|
|
264
|
-
delete data.keys;
|
|
265
|
-
|
|
266
|
-
// Save the cleaned configuration
|
|
267
|
-
await this.secrez.saveConf(conf);
|
|
268
|
-
|
|
269
|
-
Logger.green("FIDO2 configuration has been removed successfully.");
|
|
270
|
-
Logger.grey("You can now login with your master password only.");
|
|
271
|
-
|
|
272
|
-
// Try to login again with the cleaned configuration
|
|
273
|
-
let errorCode = await this.login();
|
|
274
|
-
if (errorCode === 1) {
|
|
275
|
-
Logger.red(
|
|
276
|
-
"Login still failed. Please check your password or create a new account."
|
|
277
|
-
);
|
|
278
|
-
// eslint-disable-next-line no-process-exit
|
|
279
|
-
process.exit(1);
|
|
280
|
-
}
|
|
281
|
-
} else {
|
|
282
|
-
Logger.red(
|
|
283
|
-
"No FIDO2 keys found, but login still requires second factor. This may indicate a corrupted configuration."
|
|
284
|
-
);
|
|
285
|
-
// eslint-disable-next-line no-process-exit
|
|
286
|
-
process.exit(1);
|
|
287
|
-
}
|
|
288
|
-
} catch (e) {
|
|
289
|
-
Logger.red(`Failed to clean FIDO2 configuration: ${e.message}`);
|
|
290
|
-
Logger.grey(
|
|
291
|
-
"You may need to manually remove the keys.json file and create a new account."
|
|
292
|
-
);
|
|
293
|
-
// eslint-disable-next-line no-process-exit
|
|
294
|
-
process.exit(1);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
156
|
}
|
|
298
157
|
|
|
299
158
|
module.exports = new Welcome();
|
package/src/commands/Conf.js
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// const Case = require('case')
|
|
4
|
-
const {
|
|
5
|
-
//config,
|
|
6
|
-
ConfigUtils,
|
|
7
|
-
} = require("@secrez/core");
|
|
8
|
-
// const Crypto = require('@secrez/crypto')
|
|
1
|
+
const { ConfigUtils } = require("@secrez/core");
|
|
2
|
+
|
|
9
3
|
const chalk = require("chalk");
|
|
10
4
|
|
|
11
5
|
class Conf extends require("../Command") {
|
|
@@ -25,33 +19,6 @@ class Conf extends require("../Command") {
|
|
|
25
19
|
alias: "s",
|
|
26
20
|
type: Boolean,
|
|
27
21
|
},
|
|
28
|
-
// {
|
|
29
|
-
// name: 'register',
|
|
30
|
-
// alias: 'r',
|
|
31
|
-
// type: String
|
|
32
|
-
// },
|
|
33
|
-
// {
|
|
34
|
-
// name: 'unregister',
|
|
35
|
-
// alias: 'u',
|
|
36
|
-
// type: String
|
|
37
|
-
// },
|
|
38
|
-
// {
|
|
39
|
-
// name: 'recovery-code',
|
|
40
|
-
// type: Boolean
|
|
41
|
-
// },
|
|
42
|
-
// {
|
|
43
|
-
// name: 'fido2',
|
|
44
|
-
// type: Boolean
|
|
45
|
-
// },
|
|
46
|
-
// {
|
|
47
|
-
// name: 'list',
|
|
48
|
-
// alias: 'l',
|
|
49
|
-
// type: Boolean
|
|
50
|
-
// },
|
|
51
|
-
// {
|
|
52
|
-
// name: 'use-this',
|
|
53
|
-
// type: String
|
|
54
|
-
// },
|
|
55
22
|
{
|
|
56
23
|
name: "new-password",
|
|
57
24
|
type: Boolean,
|
|
@@ -72,28 +39,10 @@ class Conf extends require("../Command") {
|
|
|
72
39
|
["conf -s", "shows the general settings"],
|
|
73
40
|
["conf --new-password", "changes your password"],
|
|
74
41
|
["conf --new-iterations-number", "changes the number of iterations"],
|
|
75
|
-
// ['conf --fido2 -r solo',
|
|
76
|
-
// 'registers a new key saving it as "solo"; if there are registered keys, it will checks if the new one is one of them before adding it.'],
|
|
77
|
-
// ['conf -l', 'lists second factors'],
|
|
78
|
-
// ['conf --recovery-code -r memo',
|
|
79
|
-
// 'registers an emergency recovery code called "memo" to be used if all the factors are lost'],
|
|
80
|
-
// ['conf --recovery-code -r seed --use-this "salad spring peace silk snake real they thunder please final clinic close"', 'registers an emergency recovery code called "seed" using the seed passed with the parameter "--use-this"'],
|
|
81
|
-
// ['conf -u solo',
|
|
82
|
-
// 'unregister the fido2 key "solo"; if that is the only key, it unregister also any emergency code and restores the normal access.']
|
|
83
42
|
],
|
|
84
43
|
};
|
|
85
44
|
}
|
|
86
45
|
|
|
87
|
-
// isEmergencyCodeSetUp() {
|
|
88
|
-
// const conf = this.secrez.getConf()
|
|
89
|
-
// let keys = conf.data.keys || {}
|
|
90
|
-
// for (let authenticator in keys) {
|
|
91
|
-
// if (keys[authenticator].type === this.secrez.config.sharedKeys.RECOVERY_CODE) {
|
|
92
|
-
// return true
|
|
93
|
-
// }
|
|
94
|
-
// }
|
|
95
|
-
// }
|
|
96
|
-
//
|
|
97
46
|
async getAllFactors() {
|
|
98
47
|
let allFactors = {};
|
|
99
48
|
const conf = this.secrez.getConf();
|
|
@@ -103,32 +52,6 @@ class Conf extends require("../Command") {
|
|
|
103
52
|
}
|
|
104
53
|
return allFactors;
|
|
105
54
|
}
|
|
106
|
-
//
|
|
107
|
-
// async verifyIfAlreadyRegistered() {
|
|
108
|
-
// let client = this.fido2Client
|
|
109
|
-
// let list = await client.getKeys(true)
|
|
110
|
-
// let now = 'now'
|
|
111
|
-
// for (let l of list) {
|
|
112
|
-
// this.Logger.grey(`Touch your fido2 authenticator device ${now}...`)
|
|
113
|
-
// try {
|
|
114
|
-
// if (await client.verifySecret(l[0])) {
|
|
115
|
-
// return l[0]
|
|
116
|
-
// }
|
|
117
|
-
// } catch (e) {
|
|
118
|
-
// }
|
|
119
|
-
// now = 'again'
|
|
120
|
-
// }
|
|
121
|
-
// return false
|
|
122
|
-
// }
|
|
123
|
-
//
|
|
124
|
-
// exists(list, authenticator) {
|
|
125
|
-
// for (let l of list) {
|
|
126
|
-
// if (l[0] === authenticator) {
|
|
127
|
-
// return true
|
|
128
|
-
// }
|
|
129
|
-
// }
|
|
130
|
-
// return false
|
|
131
|
-
// }
|
|
132
55
|
|
|
133
56
|
async showConf(options) {
|
|
134
57
|
const env = await ConfigUtils.getEnv(this.secrez.config);
|
|
@@ -139,63 +62,6 @@ class Conf extends require("../Command") {
|
|
|
139
62
|
);
|
|
140
63
|
}
|
|
141
64
|
|
|
142
|
-
// async showList(options) {
|
|
143
|
-
// let allFactors = await this.getAllFactors()
|
|
144
|
-
// if (!Object.keys(allFactors).length) {
|
|
145
|
-
// return this.Logger.grey('No registered second factors')
|
|
146
|
-
// }
|
|
147
|
-
// this.Logger.reset('Registered second factors:')
|
|
148
|
-
// let max = 0
|
|
149
|
-
// let factors = []
|
|
150
|
-
// for (let factor in allFactors) {
|
|
151
|
-
// max = Math.max(max, factor.length)
|
|
152
|
-
// factors.push([factor, allFactors[factor]])
|
|
153
|
-
// }
|
|
154
|
-
// factors.sort((a, b) => {
|
|
155
|
-
// let A = a[1]
|
|
156
|
-
// let B = b[1]
|
|
157
|
-
// return A > B ? 1 : A < B ? -1 : 0
|
|
158
|
-
// })
|
|
159
|
-
// for (let factor of factors) {
|
|
160
|
-
// let type = factor[1]
|
|
161
|
-
// if ((options.fido2 && type !== config.sharedKeys.FIDO2_KEY)
|
|
162
|
-
// || (options.recoveryCode && type !== config.sharedKeys.RECOVERY_CODE)) {
|
|
163
|
-
// continue
|
|
164
|
-
// }
|
|
165
|
-
// type = chalk.grey(`(${type === config.sharedKeys.FIDO2_KEY ? 'fido2 key' : 'recoveryCode'})`)
|
|
166
|
-
// this.Logger.reset(`${factor[0]} ${' '.repeat(max - factor[0].length)} ${type}`)
|
|
167
|
-
// }
|
|
168
|
-
// }
|
|
169
|
-
//
|
|
170
|
-
// async setRecoveryCode(options) {
|
|
171
|
-
// let client = this.fido2Client
|
|
172
|
-
// let list = await client.getKeys(true)
|
|
173
|
-
// if (!Object.keys(list).length) {
|
|
174
|
-
// throw new Error('An emergency recovery code can be set only if at least one security key has been registered.')
|
|
175
|
-
// }
|
|
176
|
-
// let authenticator = Case.snake(_.trim(options.register))
|
|
177
|
-
// if (!authenticator) {
|
|
178
|
-
// throw new Error('A valid name for the recovery code is required')
|
|
179
|
-
// }
|
|
180
|
-
// let conf = this.secrez.getConf()
|
|
181
|
-
// if (conf.data.keys[authenticator]) {
|
|
182
|
-
// throw new Error('A second factor with this name already exists')
|
|
183
|
-
// }
|
|
184
|
-
// let recoveryCode = options.useThis || Crypto.getMnemonic()
|
|
185
|
-
// let type = this.secrez.config.sharedKeys.RECOVERY_CODE
|
|
186
|
-
// let parts = this.secrez.generateSharedSecrets(recoveryCode)
|
|
187
|
-
// let sharedData = {
|
|
188
|
-
// parts,
|
|
189
|
-
// type,
|
|
190
|
-
// authenticator
|
|
191
|
-
// }
|
|
192
|
-
// await this.secrez.saveSharedSecrets(sharedData)
|
|
193
|
-
// await client.updateConf()
|
|
194
|
-
// this.Logger.reset('Your recover code is:')
|
|
195
|
-
// this.Logger.yellow(recoveryCode)
|
|
196
|
-
// await this.saveAndOverwrite(`main:/.RECOVERY_CODE_${authenticator}`, 'recovery code', recoveryCode, 'it')
|
|
197
|
-
// }
|
|
198
|
-
//
|
|
199
65
|
async saveAndOverwrite(p, spec, content, message) {
|
|
200
66
|
try {
|
|
201
67
|
await this.prompt.commands.rm.rm({
|
|
@@ -211,135 +77,6 @@ class Conf extends require("../Command") {
|
|
|
211
77
|
`For your convenience, ${message} has been saved in main:${node.getPath()}`
|
|
212
78
|
);
|
|
213
79
|
}
|
|
214
|
-
//
|
|
215
|
-
// async setFido2(options) {
|
|
216
|
-
// let client = this.fido2Client
|
|
217
|
-
// let list = await client.getKeys(true)
|
|
218
|
-
// let authenticator = Case.snake(_.trim(options.register))
|
|
219
|
-
// if (!authenticator) {
|
|
220
|
-
// throw new Error('A valid name for the authenticator is required')
|
|
221
|
-
// }
|
|
222
|
-
// if (!options.register) {
|
|
223
|
-
// throw new Error('The nickname of the key is invalid')
|
|
224
|
-
// }
|
|
225
|
-
// let conf = {}
|
|
226
|
-
// let savedConf = await this.secrez.readConf()
|
|
227
|
-
// if (savedConf.data.keys) {
|
|
228
|
-
// conf = savedConf.data.keys
|
|
229
|
-
// }
|
|
230
|
-
// if (conf[authenticator]) {
|
|
231
|
-
// throw new Error('A second factor with this name already exists')
|
|
232
|
-
// }
|
|
233
|
-
// let len = list.length
|
|
234
|
-
// let existentName
|
|
235
|
-
// if (len) {
|
|
236
|
-
// this.Logger.reset(`${len} key${len > 1 ? 's' : ''} already registered. Before registering a new one, must be sure that this is a new one.`)
|
|
237
|
-
// existentName = await this.verifyIfAlreadyRegistered()
|
|
238
|
-
// }
|
|
239
|
-
// if (existentName) {
|
|
240
|
-
// throw new Error(`This key is already registered as "${existentName}"`)
|
|
241
|
-
// } else {
|
|
242
|
-
// this.Logger.bold('This device is not registered, yet. You can register it now.')
|
|
243
|
-
// }
|
|
244
|
-
//
|
|
245
|
-
// let fido2Options = {
|
|
246
|
-
// id: Crypto.getRandomBase58String(12),
|
|
247
|
-
// authenticator
|
|
248
|
-
// }
|
|
249
|
-
//
|
|
250
|
-
// this.Logger.grey('Touch your fido2 authenticator device now...')
|
|
251
|
-
// let result = await client.setCredential(fido2Options)
|
|
252
|
-
// client.checkErrorCode(result, 1)
|
|
253
|
-
//
|
|
254
|
-
// fido2Options.credential = result.message
|
|
255
|
-
// fido2Options.salt = Crypto.getRandomBase58String(32)
|
|
256
|
-
//
|
|
257
|
-
// this.Logger.grey('Touch your fido2 authenticator device again...')
|
|
258
|
-
// result = await client.getSecret(fido2Options)
|
|
259
|
-
// client.checkErrorCode(result, 2)
|
|
260
|
-
//
|
|
261
|
-
// fido2Options.secret = result.message
|
|
262
|
-
//
|
|
263
|
-
// let yes = await this.useConfirm({
|
|
264
|
-
// message: `Are you sure you want to use the key ${authenticator} as a second factor? If you lose it who could not be able to access you account anymore.`,
|
|
265
|
-
// default: false
|
|
266
|
-
// })
|
|
267
|
-
// if (yes) {
|
|
268
|
-
// let type = this.secrez.config.sharedKeys.FIDO2_KEY
|
|
269
|
-
// let parts = this.secrez.generateSharedSecrets(fido2Options.secret)
|
|
270
|
-
//
|
|
271
|
-
// let sharedData = {
|
|
272
|
-
// parts,
|
|
273
|
-
// type,
|
|
274
|
-
// authenticator,
|
|
275
|
-
// id: fido2Options.id,
|
|
276
|
-
// salt: fido2Options.salt,
|
|
277
|
-
// credential: fido2Options.credential,
|
|
278
|
-
// hash: Crypto.b58Hash(fido2Options.secret)
|
|
279
|
-
// }
|
|
280
|
-
// await this.secrez.saveSharedSecrets(sharedData)
|
|
281
|
-
// await client.updateConf()
|
|
282
|
-
// this.Logger.reset(`A second factor using ${authenticator} has been set.`)
|
|
283
|
-
// if (!this.isEmergencyCodeSetUp()) {
|
|
284
|
-
// let yes = await this.useConfirm({
|
|
285
|
-
// message: `An emergency recovery code would allow you to recover the account if you lose ${authenticator}. Would you like to set it now?`,
|
|
286
|
-
// default: true
|
|
287
|
-
// })
|
|
288
|
-
// if (yes) {
|
|
289
|
-
// let name = await this.useInput({
|
|
290
|
-
// message: 'Type the nickname of the recovery code'
|
|
291
|
-
// })
|
|
292
|
-
// if (name) {
|
|
293
|
-
// options.recoveryCode = true
|
|
294
|
-
// options.register = name
|
|
295
|
-
// return await this.conf(options)
|
|
296
|
-
// } else {
|
|
297
|
-
// this.Logger.grey('Emergency code not set')
|
|
298
|
-
// }
|
|
299
|
-
// }
|
|
300
|
-
// }
|
|
301
|
-
// } else {
|
|
302
|
-
// throw new Error('Operation canceled')
|
|
303
|
-
// }
|
|
304
|
-
// }
|
|
305
|
-
//
|
|
306
|
-
// async unregister(options) {
|
|
307
|
-
// let authenticator = Case.snake(_.trim(options.unregister))
|
|
308
|
-
// let allFactors = await this.getAllFactors()
|
|
309
|
-
// if (!allFactors[authenticator]) {
|
|
310
|
-
// throw new Error(`Authenticator ${authenticator} not found`)
|
|
311
|
-
// }
|
|
312
|
-
// let yes = await this.useConfirm({
|
|
313
|
-
// message: `Are you sure you want to remove the ${authenticator} authenticator?`,
|
|
314
|
-
// default: false
|
|
315
|
-
// })
|
|
316
|
-
// let code
|
|
317
|
-
// if (yes) {
|
|
318
|
-
// code = await this.secrez.removeSharedSecret(authenticator)
|
|
319
|
-
// this.Logger.reset(code === 1 ? `${authenticator} has been removed` : 'All second factors have been removed')
|
|
320
|
-
// } else {
|
|
321
|
-
// this.Logger.grey('Operation canceled')
|
|
322
|
-
// }
|
|
323
|
-
// if (code === 2) {
|
|
324
|
-
// for (let factor in allFactors) {
|
|
325
|
-
// if (allFactors[factor] === this.secrez.config.sharedKeys.RECOVERY_CODE) {
|
|
326
|
-
// try {
|
|
327
|
-
// await this.prompt.commands.rm.rm({
|
|
328
|
-
// path: `main:/.RECOVERY_CODE_${factor}`
|
|
329
|
-
// })
|
|
330
|
-
// } catch (e) {
|
|
331
|
-
// }
|
|
332
|
-
// }
|
|
333
|
-
// }
|
|
334
|
-
// } else if (allFactors[authenticator] === this.secrez.config.sharedKeys.RECOVERY_CODE) {
|
|
335
|
-
// try {
|
|
336
|
-
// await this.prompt.commands.rm.rm({
|
|
337
|
-
// path: `main:/.RECOVERY_CODE_${authenticator}`
|
|
338
|
-
// })
|
|
339
|
-
// } catch (e) {
|
|
340
|
-
// }
|
|
341
|
-
// }
|
|
342
|
-
// }
|
|
343
80
|
|
|
344
81
|
async upgradeAccount(options) {
|
|
345
82
|
let pw = options.newPassword;
|
|
@@ -448,28 +185,8 @@ class Conf extends require("../Command") {
|
|
|
448
185
|
}
|
|
449
186
|
|
|
450
187
|
async conf(options) {
|
|
451
|
-
// if (!this.fido2Client) {
|
|
452
|
-
// this.fido2Client = new Fido2Client(this.secrez)
|
|
453
|
-
// }
|
|
454
|
-
// if (options.list) {
|
|
455
|
-
// await this.showList(options)
|
|
456
|
-
// } else
|
|
457
188
|
if (options.show) {
|
|
458
189
|
await this.showConf(options);
|
|
459
|
-
// } else if (options.recoveryCode) {
|
|
460
|
-
// await this.setRecoveryCode(options)
|
|
461
|
-
// } else if (options.fido2) {
|
|
462
|
-
// let yes = await this.useConfirm({
|
|
463
|
-
// message: 'Fido2 requires external libraries written in Python. It is an experimental feature, and it is not guaranteed to work. Are you sure you want to set it up?',
|
|
464
|
-
// default: false
|
|
465
|
-
// })
|
|
466
|
-
// if (!yes) {
|
|
467
|
-
// throw new Error('Operation canceled')
|
|
468
|
-
// }
|
|
469
|
-
// await this.fido2Client.checkIfReady()
|
|
470
|
-
// await this.setFido2(options)
|
|
471
|
-
// } else if (options.unregister) {
|
|
472
|
-
// await this.unregister(options)
|
|
473
190
|
} else if (options.newPassword || options.newIterationsNumber) {
|
|
474
191
|
await this.upgradeAccount(options);
|
|
475
192
|
} else {
|
|
@@ -482,9 +199,6 @@ class Conf extends require("../Command") {
|
|
|
482
199
|
return this.showHelp();
|
|
483
200
|
}
|
|
484
201
|
try {
|
|
485
|
-
// if (!Object.keys(options).length) {
|
|
486
|
-
// options.list = true
|
|
487
|
-
// }
|
|
488
202
|
this.validate(options);
|
|
489
203
|
|
|
490
204
|
// Check for git conflicts before changing password or iterations
|
|
@@ -495,15 +209,8 @@ class Conf extends require("../Command") {
|
|
|
495
209
|
}
|
|
496
210
|
}
|
|
497
211
|
|
|
498
|
-
// if (options.fido2 && options.recoveryCode) {
|
|
499
|
-
// throw new Error('Conflicting params. Launch "conf -h" for examples.')
|
|
500
|
-
// }
|
|
501
|
-
// if (options.register && !(options.fido2 || options.recoveryCode)) {
|
|
502
|
-
// throw new Error('Missing parameters. Launch "conf -h" for examples.')
|
|
503
|
-
// }
|
|
504
212
|
await this.conf(options);
|
|
505
213
|
} catch (e) {
|
|
506
|
-
// console.error(e)
|
|
507
214
|
this.Logger.red(e.message);
|
|
508
215
|
}
|
|
509
216
|
await this.prompt.run();
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2018 Yubico AB
|
|
2
|
-
# All rights reserved.
|
|
3
|
-
#
|
|
4
|
-
# Redistribution and use in source and binary forms, with or
|
|
5
|
-
# without modification, are permitted provided that the following
|
|
6
|
-
# conditions are met:
|
|
7
|
-
#
|
|
8
|
-
# 1. Redistributions of source code must retain the above copyright
|
|
9
|
-
# notice, this list of conditions and the following disclaimer.
|
|
10
|
-
# 2. Redistributions in binary form must reproduce the above
|
|
11
|
-
# copyright notice, this list of conditions and the following
|
|
12
|
-
# disclaimer in the documentation and/or other materials provided
|
|
13
|
-
# with the distribution.
|
|
14
|
-
#
|
|
15
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
16
|
-
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
17
|
-
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
18
|
-
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
19
|
-
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
20
|
-
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
21
|
-
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
22
|
-
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
23
|
-
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
24
|
-
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
25
|
-
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
26
|
-
# POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
-
|
|
28
|
-
from __future__ import print_function, absolute_import, unicode_literals
|
|
29
|
-
|
|
30
|
-
from fido2.hid import CtapHidDevice
|
|
31
|
-
from fido2.client import Fido2Client
|
|
32
|
-
from fido2.ctap2.extensions import HmacSecretExtension
|
|
33
|
-
from fido2.utils import websafe_encode
|
|
34
|
-
|
|
35
|
-
import sys, getopt, random, string
|
|
36
|
-
|
|
37
|
-
def randomString(stringLength=8):
|
|
38
|
-
letters = string.ascii_lowercase
|
|
39
|
-
return ''.join(random.choice(letters) for i in range(stringLength))
|
|
40
|
-
|
|
41
|
-
argv = sys.argv[1:]
|
|
42
|
-
try:
|
|
43
|
-
opts, args = getopt.getopt(argv,"i:n:",[])
|
|
44
|
-
except getopt.GetoptError:
|
|
45
|
-
print('python fido2_credential.py -i id -n name')
|
|
46
|
-
sys.exit(2)
|
|
47
|
-
for opt, arg in opts:
|
|
48
|
-
if opt in ("-i"):
|
|
49
|
-
user_id = arg
|
|
50
|
-
elif opt in ("-n"):
|
|
51
|
-
user_name = arg
|
|
52
|
-
|
|
53
|
-
try:
|
|
54
|
-
from fido2.pcsc import CtapPcscDevice
|
|
55
|
-
except ImportError:
|
|
56
|
-
CtapPcscDevice = None
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def enumerate_devices():
|
|
60
|
-
for dev in CtapHidDevice.list_devices():
|
|
61
|
-
yield dev
|
|
62
|
-
if CtapPcscDevice:
|
|
63
|
-
for dev in CtapPcscDevice.list_devices():
|
|
64
|
-
yield dev
|
|
65
|
-
|
|
66
|
-
for dev in enumerate_devices():
|
|
67
|
-
client = Fido2Client(dev, "https://secrez.io")
|
|
68
|
-
if HmacSecretExtension.NAME in client.info.extensions:
|
|
69
|
-
break
|
|
70
|
-
else:
|
|
71
|
-
print("No Authenticator with the HmacSecret extension found!")
|
|
72
|
-
sys.exit(1)
|
|
73
|
-
|
|
74
|
-
rp = {"id": "secrez.io", "name": "secrez"}
|
|
75
|
-
user = {"id": bytes(user_id, encoding='utf-8'), "name": user_name}
|
|
76
|
-
challenge = bytes(randomString(12), encoding='utf-8')
|
|
77
|
-
hmac_ext = HmacSecretExtension(client.ctap2)
|
|
78
|
-
attestation_object, client_data = client.make_credential(
|
|
79
|
-
{
|
|
80
|
-
"rp": rp,
|
|
81
|
-
"user": user,
|
|
82
|
-
"challenge": challenge,
|
|
83
|
-
"pubKeyCredParams": [{"type": "public-key", "alg": -7}],
|
|
84
|
-
"extensions": hmac_ext.create_dict(),
|
|
85
|
-
}
|
|
86
|
-
)
|
|
87
|
-
credential = attestation_object.auth_data.credential_data
|
|
88
|
-
print(websafe_encode(credential))
|
package/scripts/hmac_secret.py
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2018 Yubico AB
|
|
2
|
-
# All rights reserved.
|
|
3
|
-
#
|
|
4
|
-
# Redistribution and use in source and binary forms, with or
|
|
5
|
-
# without modification, are permitted provided that the following
|
|
6
|
-
# conditions are met:
|
|
7
|
-
#
|
|
8
|
-
# 1. Redistributions of source code must retain the above copyright
|
|
9
|
-
# notice, this list of conditions and the following disclaimer.
|
|
10
|
-
# 2. Redistributions in binary form must reproduce the above
|
|
11
|
-
# copyright notice, this list of conditions and the following
|
|
12
|
-
# disclaimer in the documentation and/or other materials provided
|
|
13
|
-
# with the distribution.
|
|
14
|
-
#
|
|
15
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
16
|
-
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
17
|
-
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
18
|
-
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
19
|
-
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
20
|
-
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
21
|
-
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
22
|
-
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
23
|
-
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
24
|
-
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
25
|
-
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
26
|
-
# POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
-
|
|
28
|
-
from __future__ import print_function, absolute_import, unicode_literals
|
|
29
|
-
|
|
30
|
-
from fido2.hid import CtapHidDevice
|
|
31
|
-
from fido2.client import Fido2Client
|
|
32
|
-
from fido2.ctap2.extensions import HmacSecretExtension
|
|
33
|
-
from fido2.utils import websafe_encode, websafe_decode
|
|
34
|
-
from fido2.ctap2 import AttestedCredentialData
|
|
35
|
-
|
|
36
|
-
from binascii import b2a_hex
|
|
37
|
-
import sys, getopt, random, string
|
|
38
|
-
|
|
39
|
-
def randomString(stringLength=8):
|
|
40
|
-
letters = string.ascii_lowercase
|
|
41
|
-
return ''.join(random.choice(letters) for i in range(stringLength))
|
|
42
|
-
|
|
43
|
-
argv = sys.argv[1:]
|
|
44
|
-
try:
|
|
45
|
-
opts, args = getopt.getopt(argv,"i:n:s:c:",[])
|
|
46
|
-
except getopt.GetoptError:
|
|
47
|
-
print('test.py -i <inputfile> -o <outputfile>')
|
|
48
|
-
sys.exit(2)
|
|
49
|
-
for opt, arg in opts:
|
|
50
|
-
if opt in ("-i"):
|
|
51
|
-
user_id = arg
|
|
52
|
-
elif opt in ("-n"):
|
|
53
|
-
user_name = arg
|
|
54
|
-
elif opt in ("-s"):
|
|
55
|
-
salt = bytes(arg, encoding='utf-8')
|
|
56
|
-
elif opt in ("-c"):
|
|
57
|
-
credential = AttestedCredentialData(websafe_decode(arg))
|
|
58
|
-
|
|
59
|
-
try:
|
|
60
|
-
from fido2.pcsc import CtapPcscDevice
|
|
61
|
-
except ImportError:
|
|
62
|
-
CtapPcscDevice = None
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def enumerate_devices():
|
|
66
|
-
for dev in CtapHidDevice.list_devices():
|
|
67
|
-
yield dev
|
|
68
|
-
if CtapPcscDevice:
|
|
69
|
-
for dev in CtapPcscDevice.list_devices():
|
|
70
|
-
yield dev
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
# Locate a device
|
|
74
|
-
for dev in enumerate_devices():
|
|
75
|
-
client = Fido2Client(dev, "https://secrez.io")
|
|
76
|
-
if HmacSecretExtension.NAME in client.info.extensions:
|
|
77
|
-
break
|
|
78
|
-
else:
|
|
79
|
-
print("No Authenticator with the HmacSecret extension found!")
|
|
80
|
-
sys.exit(1)
|
|
81
|
-
|
|
82
|
-
# use_nfc = CtapPcscDevice and isinstance(dev, CtapPcscDevice)
|
|
83
|
-
|
|
84
|
-
# Prepare parameters for makeCredential
|
|
85
|
-
rp = {"id": "secrez.io", "name": "secrez.io"}
|
|
86
|
-
user = {"id": bytes(user_id, encoding='utf-8'), "name": user_name}
|
|
87
|
-
|
|
88
|
-
challenge = bytes(randomString(12), encoding='utf-8')
|
|
89
|
-
|
|
90
|
-
hmac_ext = HmacSecretExtension(client.ctap2)
|
|
91
|
-
|
|
92
|
-
challenge = bytes(randomString(12), encoding='utf-8')
|
|
93
|
-
|
|
94
|
-
allow_list = [{"type": "public-key", "id": credential.credential_id}]
|
|
95
|
-
|
|
96
|
-
assertions, client_data = client.get_assertion(
|
|
97
|
-
{
|
|
98
|
-
"rpId": rp["id"],
|
|
99
|
-
"challenge": challenge,
|
|
100
|
-
"allowCredentials": allow_list,
|
|
101
|
-
"extensions": hmac_ext.get_dict(salt),
|
|
102
|
-
}
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
assertion = assertions[0]
|
|
106
|
-
hmac_res = hmac_ext.results_for(assertion.auth_data)
|
|
107
|
-
|
|
108
|
-
secret = b2a_hex(hmac_res[0]).decode("utf-8")
|
|
109
|
-
|
|
110
|
-
print(secret)
|
|
111
|
-
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2018 Yubico AB
|
|
2
|
-
# All rights reserved.
|
|
3
|
-
#
|
|
4
|
-
# Redistribution and use in source and binary forms, with or
|
|
5
|
-
# without modification, are permitted provided that the following
|
|
6
|
-
# conditions are met:
|
|
7
|
-
#
|
|
8
|
-
# 1. Redistributions of source code must retain the above copyright
|
|
9
|
-
# notice, this list of conditions and the following disclaimer.
|
|
10
|
-
# 2. Redistributions in binary form must reproduce the above
|
|
11
|
-
# copyright notice, this list of conditions and the following
|
|
12
|
-
# disclaimer in the documentation and/or other materials provided
|
|
13
|
-
# with the distribution.
|
|
14
|
-
#
|
|
15
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
16
|
-
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
17
|
-
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
18
|
-
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
19
|
-
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
20
|
-
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
21
|
-
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
22
|
-
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
23
|
-
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
24
|
-
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
25
|
-
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
26
|
-
# POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
-
|
|
28
|
-
from __future__ import print_function, absolute_import, unicode_literals
|
|
29
|
-
|
|
30
|
-
from fido2.hid import CtapHidDevice
|
|
31
|
-
from fido2.client import Fido2Client
|
|
32
|
-
from fido2.ctap2.extensions import HmacSecretExtension
|
|
33
|
-
from fido2.utils import websafe_encode, websafe_decode
|
|
34
|
-
from fido2.ctap2 import AttestedCredentialData
|
|
35
|
-
|
|
36
|
-
from binascii import b2a_hex
|
|
37
|
-
import sys, getopt, random, string
|
|
38
|
-
|
|
39
|
-
try:
|
|
40
|
-
from fido2.pcsc import CtapPcscDevice
|
|
41
|
-
except ImportError:
|
|
42
|
-
CtapPcscDevice = None
|
|
43
|
-
|
|
44
|
-
def enumerate_devices():
|
|
45
|
-
for dev in CtapHidDevice.list_devices():
|
|
46
|
-
yield dev
|
|
47
|
-
if CtapPcscDevice:
|
|
48
|
-
for dev in CtapPcscDevice.list_devices():
|
|
49
|
-
yield dev
|
|
50
|
-
|
|
51
|
-
for dev in enumerate_devices():
|
|
52
|
-
client = Fido2Client(dev, "https://secrez.io")
|
|
53
|
-
if HmacSecretExtension.NAME in client.info.extensions:
|
|
54
|
-
break
|
|
55
|
-
|
|
56
|
-
print('Ready')
|
package/src/utils/Fido2Client.js
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
const path = require("path");
|
|
2
|
-
const { Crypto } = require("@secrez/core");
|
|
3
|
-
const { execAsync } = require("@secrez/utils");
|
|
4
|
-
const _ = require("lodash");
|
|
5
|
-
|
|
6
|
-
class Fido2Client {
|
|
7
|
-
constructor(secrez) {
|
|
8
|
-
this.keys = {};
|
|
9
|
-
this.secrez = secrez;
|
|
10
|
-
this.scriptsPath = path.resolve(__dirname, "../../scripts");
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
async updateConf() {
|
|
14
|
-
const conf = await this.secrez.readConf();
|
|
15
|
-
this.keys = {};
|
|
16
|
-
if (conf.data.keys) {
|
|
17
|
-
let keys = conf.data.keys;
|
|
18
|
-
for (let authenticator in keys) {
|
|
19
|
-
if (
|
|
20
|
-
keys[authenticator].type === this.secrez.config.sharedKeys.FIDO2_KEY
|
|
21
|
-
) {
|
|
22
|
-
let key = (this.keys[authenticator] = _.clone(keys[authenticator]));
|
|
23
|
-
key.id = this.secrez.preDecryptData(key.id);
|
|
24
|
-
key.salt = this.secrez.preDecryptData(key.salt);
|
|
25
|
-
key.credential = this.secrez.preDecryptData(key.credential);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async getKeys(asAList) {
|
|
32
|
-
await this.updateConf();
|
|
33
|
-
if (asAList) {
|
|
34
|
-
let list = [];
|
|
35
|
-
for (let authenticator in this.keys) {
|
|
36
|
-
list.push([authenticator, this.keys[authenticator].type]);
|
|
37
|
-
}
|
|
38
|
-
return list;
|
|
39
|
-
} else {
|
|
40
|
-
return this.keys;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
setParams(options) {
|
|
45
|
-
let params = [
|
|
46
|
-
options.credential ? "hmac_secret.py" : "fido2_credential.py",
|
|
47
|
-
"-n",
|
|
48
|
-
options.authenticator,
|
|
49
|
-
"-i",
|
|
50
|
-
options.id,
|
|
51
|
-
];
|
|
52
|
-
if (options.credential) {
|
|
53
|
-
params.push("-c", options.credential);
|
|
54
|
-
}
|
|
55
|
-
if (options.salt) {
|
|
56
|
-
params.push("-s", options.salt);
|
|
57
|
-
}
|
|
58
|
-
return params;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async checkIfReady() {
|
|
62
|
-
let result = await execAsync("which", __dirname, ["python"]);
|
|
63
|
-
if (result.code !== 0 || typeof result.message === "undefined") {
|
|
64
|
-
throw new Error(
|
|
65
|
-
"The Fido2 module requires Python. Please install it on your computer."
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
result = await execAsync("python", this.scriptsPath, ["is_fido2_ready.py"]);
|
|
69
|
-
if (result.message !== "Ready") {
|
|
70
|
-
throw new Error(
|
|
71
|
-
'Python-fido2 is required. Install it with "pip install fido2"'
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async setCredential(options) {
|
|
77
|
-
return await execAsync("python", this.scriptsPath, this.setParams(options));
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async getSecret(options) {
|
|
81
|
-
return await execAsync("python", this.scriptsPath, this.setParams(options));
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async verifySecret(authenticator) {
|
|
85
|
-
await this.updateConf();
|
|
86
|
-
let key = this.keys[authenticator];
|
|
87
|
-
let fido2Options = {
|
|
88
|
-
id: key.id,
|
|
89
|
-
authenticator,
|
|
90
|
-
salt: key.salt,
|
|
91
|
-
credential: key.credential,
|
|
92
|
-
};
|
|
93
|
-
let result = await this.getSecret(fido2Options);
|
|
94
|
-
this.checkErrorCode(result, 1);
|
|
95
|
-
if (Crypto.b58Hash(result.message) === key.hash) {
|
|
96
|
-
return result.message;
|
|
97
|
-
} else {
|
|
98
|
-
throw new Error(`You used a different key for ${authenticator}`);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
checkErrorCode(result, num) {
|
|
103
|
-
if (result.code !== 0) {
|
|
104
|
-
let err = "No Authenticator with the HmacSecret extension found!";
|
|
105
|
-
if (result.error === err) {
|
|
106
|
-
throw new Error(err);
|
|
107
|
-
} else {
|
|
108
|
-
throw new Error(
|
|
109
|
-
num === 1
|
|
110
|
-
? "Fido2 authenticator device not found"
|
|
111
|
-
: "Something went wrong"
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
module.exports = Fido2Client;
|