@loginguards/loginguards-win 0.1.2 → 0.1.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 +1 -1
- package/src/cli/commands/check.js +84 -0
- package/src/cli/index.js +1 -0
- package/src/service/engine.js +6 -1
package/package.json
CHANGED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const storage = require('../../storage');
|
|
3
|
+
const apiClient = require('../../apiClient');
|
|
4
|
+
const { logger } = require('../../logger');
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
command: 'check',
|
|
8
|
+
describe: 'Check one or more passwords against LoginGuards (no passwords are logged or stored)',
|
|
9
|
+
builder: {
|
|
10
|
+
password: { type: 'string', describe: 'Password to check (avoid history; prefer --prompt or --stdin)' },
|
|
11
|
+
prompt: { type: 'boolean', default: false, describe: 'Securely prompt for a password' },
|
|
12
|
+
stdin: { type: 'boolean', default: false, describe: 'Read newline-separated passwords from stdin' },
|
|
13
|
+
debug: { type: 'boolean', default: false, describe: 'Print raw API response (sanitized)' }
|
|
14
|
+
},
|
|
15
|
+
handler: async (args) => {
|
|
16
|
+
const apiKey = await storage.getApiKey();
|
|
17
|
+
if (!apiKey) {
|
|
18
|
+
console.log('✖ API key not configured. Run "loginguards-win configure".');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function evalOne(pwd) {
|
|
23
|
+
try {
|
|
24
|
+
const res = await apiClient.checkPlain(pwd, apiKey);
|
|
25
|
+
if (args.debug) {
|
|
26
|
+
try { console.log('debug response:', JSON.stringify(res)); } catch {}
|
|
27
|
+
}
|
|
28
|
+
const compromised = (typeof res.breached !== 'undefined') ? !!res.breached
|
|
29
|
+
: (typeof res.compromised !== 'undefined') ? !!res.compromised
|
|
30
|
+
: (typeof res.is_compromised !== 'undefined') ? !!res.is_compromised
|
|
31
|
+
: (typeof res.isCompromised !== 'undefined') ? !!res.isCompromised
|
|
32
|
+
: (typeof res.count === 'number') ? res.count > 0
|
|
33
|
+
: false;
|
|
34
|
+
if (compromised) {
|
|
35
|
+
console.log('✖ COMPROMISED');
|
|
36
|
+
} else {
|
|
37
|
+
console.log('✔ NOT COMPROMISED');
|
|
38
|
+
}
|
|
39
|
+
} catch (e) {
|
|
40
|
+
const status = e && e.response && e.response.status;
|
|
41
|
+
if (status === 401) console.log('✖ Error: Unauthorized (invalid API key)');
|
|
42
|
+
else if (status === 429) console.log('✖ Error: Rate limited');
|
|
43
|
+
else console.log('✖ Error:', e.message || String(e));
|
|
44
|
+
logger.warn(`check command API error: ${status || e.code || e.message}`);
|
|
45
|
+
process.exitCode = 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (args.stdin) {
|
|
50
|
+
// batch mode from stdin
|
|
51
|
+
const chunks = [];
|
|
52
|
+
process.stdin.setEncoding('utf8');
|
|
53
|
+
process.stdin.on('data', (d) => chunks.push(d));
|
|
54
|
+
process.stdin.on('end', async () => {
|
|
55
|
+
const text = chunks.join('');
|
|
56
|
+
const lines = text.split(/\r?\n/).map(s => s.trim()).filter(Boolean);
|
|
57
|
+
if (!lines.length) { console.log('No input passwords.'); return; }
|
|
58
|
+
for (const line of lines) {
|
|
59
|
+
await evalOne(line);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
if (process.stdin.readableEnded) {
|
|
63
|
+
// no stdin piped
|
|
64
|
+
console.log('No stdin provided. Use --password or --prompt instead.');
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (typeof args.password === 'string' && args.password.length > 0) {
|
|
70
|
+
await evalOne(args.password);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// prompt safely
|
|
75
|
+
try {
|
|
76
|
+
const inquirer = (await import('inquirer')).default;
|
|
77
|
+
const ans = await inquirer.prompt([{ type: 'password', name: 'pwd', message: 'Enter password to check', mask: '*', validate: v => v ? true : 'Required' }]);
|
|
78
|
+
await evalOne(ans.pwd);
|
|
79
|
+
} catch (e) {
|
|
80
|
+
console.error('✖ Prompt failed:', e.message || String(e));
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
package/src/cli/index.js
CHANGED
|
@@ -11,6 +11,7 @@ async function run(argvInput) {
|
|
|
11
11
|
.usage('$0 <cmd> [args]')
|
|
12
12
|
.command(require('./commands/install'))
|
|
13
13
|
.command(require('./commands/configure'))
|
|
14
|
+
.command(require('./commands/check'))
|
|
14
15
|
.command(require('./commands/test'))
|
|
15
16
|
.command(require('./commands/pipe-test'))
|
|
16
17
|
.command(require('./commands/uninstall'))
|
package/src/service/engine.js
CHANGED
|
@@ -23,7 +23,12 @@ async function evaluatePassword(password) {
|
|
|
23
23
|
}
|
|
24
24
|
try {
|
|
25
25
|
const res = await apiClient.checkPlain(password, apiKey);
|
|
26
|
-
const compromised = !!res.
|
|
26
|
+
const compromised = (typeof res.breached !== 'undefined') ? !!res.breached
|
|
27
|
+
: (typeof res.compromised !== 'undefined') ? !!res.compromised
|
|
28
|
+
: (typeof res.is_compromised !== 'undefined') ? !!res.is_compromised
|
|
29
|
+
: (typeof res.isCompromised !== 'undefined') ? !!res.isCompromised
|
|
30
|
+
: (typeof res.count === 'number') ? res.count > 0
|
|
31
|
+
: false;
|
|
27
32
|
return { allow: !compromised, reason: compromised ? 'compromised' : 'ok' };
|
|
28
33
|
} catch (e) {
|
|
29
34
|
logger.warn(`API error during evaluation: ${e.status || e.code || e.message}`);
|