@phishnoo/cli 0.0.0-stage → 0.1.0

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.
Files changed (3) hide show
  1. package/README.md +4 -2
  2. package/cli.mjs +68 -0
  3. package/package.json +1 -6
package/README.md CHANGED
@@ -1,3 +1,5 @@
1
- # Temporary Holding Version
1
+ # Phishnoo Sandbox CLI
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Use Node.js 20 or newer. Run `phishnoo login` and enter the sandbox key at the hidden prompt. Try `phishnoo score` and `phishnoo report "Example notice" https://example.invalid/notice`. Use synthetic data only. Run `phishnoo logout` to remove the local key.
4
+
5
+ [Phishnoo](https://phishnoo.com) · [Developer guide](https://api.phishnoo.nl/docs)
package/cli.mjs ADDED
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+ import {mkdir, readFile, writeFile, rm} from 'node:fs/promises';
3
+ import {homedir} from 'node:os';
4
+ import {join} from 'node:path';
5
+ import {createInterface} from 'node:readline/promises';
6
+ import {Writable} from 'node:stream';
7
+
8
+ const dir = join(homedir(), '.phishnoo');
9
+ const file = join(dir, 'sandbox.key');
10
+ const [command, title, url] = process.argv.slice(2);
11
+ const keyPattern = /^phn_sandbox_[A-Za-z0-9_-]{43}$/;
12
+ const origin = new URL(process.env.PHISHNOO_ORIGIN || 'https://api.phishnoo.nl');
13
+ if (origin.origin !== 'https://api.phishnoo.nl' &&
14
+ !(origin.protocol === 'http:' && origin.hostname === '127.0.0.1')) {
15
+ console.error('Unsupported service origin.');
16
+ process.exit(1);
17
+ }
18
+ async function request(endpoint, key, report) {
19
+ const response = await fetch(new URL('/v1/' + endpoint, origin), {
20
+ headers: {Authorization: 'Bearer ' + key, ...(report && {'Content-Type':'application/json'})},
21
+ method: report ? 'POST' : 'GET', body: report && JSON.stringify(report),
22
+ redirect: 'error', signal: AbortSignal.timeout(10000)
23
+ });
24
+ if (!response.ok) throw Error(`Request failed (HTTP ${response.status}).`);
25
+ return response.json();
26
+ }
27
+ try {
28
+ if (command === 'logout') {
29
+ await rm(file, {force:true});
30
+ console.log('Saved key removed.');
31
+ } else if (command === 'login') {
32
+ let key = process.env.PHISHNOO_KEY;
33
+ if (!key && process.stdin.isTTY) {
34
+ process.stderr.write('Sandbox key (hidden): ');
35
+ const sink = new Writable({write(_chunk, _encoding, done) {done();}});
36
+ const rl = createInterface({input:process.stdin, output:sink, terminal:true, historySize:0});
37
+ try { key = await rl.question(''); } finally { rl.close(); process.stderr.write('\n'); }
38
+ } else if (!key) {
39
+ const chunks = [];
40
+ let length = 0;
41
+ for await (const chunk of process.stdin) {
42
+ length += chunk.length;
43
+ if (length > 256) throw Error('Invalid sandbox key.');
44
+ chunks.push(chunk);
45
+ }
46
+ key = Buffer.concat(chunks).toString().trim();
47
+ }
48
+ if (!keyPattern.test(key ?? '')) throw Error('Invalid sandbox key.');
49
+ const tenant = await request('me', key);
50
+ await mkdir(dir, {recursive:true, mode:0o700});
51
+ await rm(file, {force:true});
52
+ await writeFile(file, key, {flag:'wx', mode:0o600});
53
+ console.log('Connected to ' + tenant.company);
54
+ } else if (['me','score','campaigns','progress','threats','report'].includes(command)) {
55
+ const key = process.env.PHISHNOO_KEY || await readFile(file, 'utf8').catch(() => '');
56
+ if (!keyPattern.test(key)) throw Error('Run phishnoo login first.');
57
+ if (command === 'report' && !title) throw Error('Usage: phishnoo report "Example notice" [URL]');
58
+ const result = await request(({score:'scores', report:'threats'})[command] || command, key,
59
+ command === 'report' ? {title, ...(url && {url})} : undefined);
60
+ console.log(JSON.stringify(result, null, 2));
61
+ } else {
62
+ console.log('Usage: phishnoo <login|logout|me|score|campaigns|progress|threats|report>');
63
+ process.exitCode = command ? 1 : 0;
64
+ }
65
+ } catch (error) {
66
+ console.error(error.message);
67
+ process.exitCode = 1;
68
+ }
package/package.json CHANGED
@@ -1,6 +1 @@
1
- {
2
- "name": "@phishnoo/cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
1
+ {"name":"@phishnoo/cli","version":"0.1.0","description":"Command-line client for the Phishnoo sandbox","homepage":"https://phishnoo.com","author":"Pieter","bin":{"phishnoo":"cli.mjs"},"engines":{"node":">=20"},"files":["cli.mjs","README.md"]}