securenow 5.10.2 → 5.11.1
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/CONSUMING-APPS-GUIDE.md +30 -0
- package/NPM_README.md +65 -0
- package/README.md +13 -0
- package/cidr.js +83 -0
- package/cli/auth.js +208 -208
- package/cli/config.js +117 -117
- package/cli/firewall.js +81 -0
- package/cli/fp.js +638 -0
- package/cli/security.js +4 -8
- package/cli.js +28 -1
- package/console-instrumentation.js +147 -147
- package/docs/ALL-FRAMEWORKS-QUICKSTART.md +40 -1
- package/docs/API-KEYS-GUIDE.md +215 -0
- package/docs/ENVIRONMENT-VARIABLES.md +880 -697
- package/docs/FIREWALL-GUIDE.md +388 -0
- package/docs/INDEX.md +8 -1
- package/firewall-cloud.js +212 -0
- package/firewall-iptables.js +139 -0
- package/firewall-tcp.js +58 -0
- package/firewall.js +235 -0
- package/free-trial-banner.js +174 -174
- package/nextjs-auto-capture.js +199 -199
- package/nextjs-middleware.js +186 -186
- package/nextjs-wrapper.js +158 -158
- package/nextjs.js +22 -2
- package/nuxt-server-plugin.mjs +400 -400
- package/package.json +30 -3
- package/resolve-ip.js +77 -0
- package/tracing.js +31 -56
- package/web-vite.mjs +239 -239
package/cli/config.js
CHANGED
|
@@ -1,117 +1,117 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const os = require('os');
|
|
6
|
-
|
|
7
|
-
const CONFIG_DIR = path.join(os.homedir(), '.securenow');
|
|
8
|
-
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
9
|
-
const CREDENTIALS_FILE = path.join(CONFIG_DIR, 'credentials.json');
|
|
10
|
-
|
|
11
|
-
const DEFAULTS = {
|
|
12
|
-
apiUrl: 'https://api.securenow.ai',
|
|
13
|
-
appUrl: 'https://app.securenow.ai',
|
|
14
|
-
defaultApp: null,
|
|
15
|
-
output: 'table',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
function ensureDir() {
|
|
19
|
-
if (!fs.existsSync(CONFIG_DIR)) {
|
|
20
|
-
fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function loadJSON(filepath) {
|
|
25
|
-
try {
|
|
26
|
-
return JSON.parse(fs.readFileSync(filepath, 'utf8'));
|
|
27
|
-
} catch {
|
|
28
|
-
return {};
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function saveJSON(filepath, data) {
|
|
33
|
-
ensureDir();
|
|
34
|
-
fs.writeFileSync(filepath, JSON.stringify(data, null, 2), { encoding: 'utf8', mode: 0o600 });
|
|
35
|
-
if (process.platform === 'win32') {
|
|
36
|
-
try {
|
|
37
|
-
const { execFileSync } = require('child_process');
|
|
38
|
-
execFileSync('icacls', [filepath, '/inheritance:r', '/grant:r', `${process.env.USERNAME}:F`], { stdio: 'ignore' });
|
|
39
|
-
} catch (_) {}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function loadConfig() {
|
|
44
|
-
return { ...DEFAULTS, ...loadJSON(CONFIG_FILE) };
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function saveConfig(config) {
|
|
48
|
-
const existing = loadJSON(CONFIG_FILE);
|
|
49
|
-
saveJSON(CONFIG_FILE, { ...existing, ...config });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function getConfigValue(key) {
|
|
53
|
-
const config = loadConfig();
|
|
54
|
-
return config[key];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function setConfigValue(key, value) {
|
|
58
|
-
saveConfig({ [key]: value });
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function loadCredentials() {
|
|
62
|
-
return loadJSON(CREDENTIALS_FILE);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function saveCredentials(creds) {
|
|
66
|
-
saveJSON(CREDENTIALS_FILE, creds);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function clearCredentials() {
|
|
70
|
-
try {
|
|
71
|
-
fs.unlinkSync(CREDENTIALS_FILE);
|
|
72
|
-
} catch {}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function getToken() {
|
|
76
|
-
const creds = loadCredentials();
|
|
77
|
-
if (!creds.token) return null;
|
|
78
|
-
|
|
79
|
-
if (creds.expiresAt && Date.now() > creds.expiresAt) {
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
return creds.token;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function setAuth(token, email, expiresAt) {
|
|
86
|
-
saveCredentials({ token, email, expiresAt });
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function getApiUrl() {
|
|
90
|
-
return process.env.SECURENOW_API_URL || loadConfig().apiUrl;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function getAppUrl() {
|
|
94
|
-
return process.env.SECURENOW_APP_URL || loadConfig().appUrl;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function getDefaultApp() {
|
|
98
|
-
return process.env.SECURENOW_APP || loadConfig().defaultApp;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
module.exports = {
|
|
102
|
-
CONFIG_DIR,
|
|
103
|
-
CONFIG_FILE,
|
|
104
|
-
CREDENTIALS_FILE,
|
|
105
|
-
loadConfig,
|
|
106
|
-
saveConfig,
|
|
107
|
-
getConfigValue,
|
|
108
|
-
setConfigValue,
|
|
109
|
-
loadCredentials,
|
|
110
|
-
saveCredentials,
|
|
111
|
-
clearCredentials,
|
|
112
|
-
getToken,
|
|
113
|
-
setAuth,
|
|
114
|
-
getApiUrl,
|
|
115
|
-
getAppUrl,
|
|
116
|
-
getDefaultApp,
|
|
117
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
|
|
7
|
+
const CONFIG_DIR = path.join(os.homedir(), '.securenow');
|
|
8
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
9
|
+
const CREDENTIALS_FILE = path.join(CONFIG_DIR, 'credentials.json');
|
|
10
|
+
|
|
11
|
+
const DEFAULTS = {
|
|
12
|
+
apiUrl: 'https://api.securenow.ai',
|
|
13
|
+
appUrl: 'https://app.securenow.ai',
|
|
14
|
+
defaultApp: null,
|
|
15
|
+
output: 'table',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function ensureDir() {
|
|
19
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
20
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function loadJSON(filepath) {
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(fs.readFileSync(filepath, 'utf8'));
|
|
27
|
+
} catch {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function saveJSON(filepath, data) {
|
|
33
|
+
ensureDir();
|
|
34
|
+
fs.writeFileSync(filepath, JSON.stringify(data, null, 2), { encoding: 'utf8', mode: 0o600 });
|
|
35
|
+
if (process.platform === 'win32') {
|
|
36
|
+
try {
|
|
37
|
+
const { execFileSync } = require('child_process');
|
|
38
|
+
execFileSync('icacls', [filepath, '/inheritance:r', '/grant:r', `${process.env.USERNAME}:F`], { stdio: 'ignore' });
|
|
39
|
+
} catch (_) {}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function loadConfig() {
|
|
44
|
+
return { ...DEFAULTS, ...loadJSON(CONFIG_FILE) };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function saveConfig(config) {
|
|
48
|
+
const existing = loadJSON(CONFIG_FILE);
|
|
49
|
+
saveJSON(CONFIG_FILE, { ...existing, ...config });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getConfigValue(key) {
|
|
53
|
+
const config = loadConfig();
|
|
54
|
+
return config[key];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function setConfigValue(key, value) {
|
|
58
|
+
saveConfig({ [key]: value });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function loadCredentials() {
|
|
62
|
+
return loadJSON(CREDENTIALS_FILE);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function saveCredentials(creds) {
|
|
66
|
+
saveJSON(CREDENTIALS_FILE, creds);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function clearCredentials() {
|
|
70
|
+
try {
|
|
71
|
+
fs.unlinkSync(CREDENTIALS_FILE);
|
|
72
|
+
} catch {}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getToken() {
|
|
76
|
+
const creds = loadCredentials();
|
|
77
|
+
if (!creds.token) return null;
|
|
78
|
+
|
|
79
|
+
if (creds.expiresAt && Date.now() > creds.expiresAt) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
return creds.token;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function setAuth(token, email, expiresAt) {
|
|
86
|
+
saveCredentials({ token, email, expiresAt });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function getApiUrl() {
|
|
90
|
+
return process.env.SECURENOW_API_URL || loadConfig().apiUrl;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function getAppUrl() {
|
|
94
|
+
return process.env.SECURENOW_APP_URL || loadConfig().appUrl;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function getDefaultApp() {
|
|
98
|
+
return process.env.SECURENOW_APP || loadConfig().defaultApp;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
module.exports = {
|
|
102
|
+
CONFIG_DIR,
|
|
103
|
+
CONFIG_FILE,
|
|
104
|
+
CREDENTIALS_FILE,
|
|
105
|
+
loadConfig,
|
|
106
|
+
saveConfig,
|
|
107
|
+
getConfigValue,
|
|
108
|
+
setConfigValue,
|
|
109
|
+
loadCredentials,
|
|
110
|
+
saveCredentials,
|
|
111
|
+
clearCredentials,
|
|
112
|
+
getToken,
|
|
113
|
+
setAuth,
|
|
114
|
+
getApiUrl,
|
|
115
|
+
getAppUrl,
|
|
116
|
+
getDefaultApp,
|
|
117
|
+
};
|
package/cli/firewall.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { api, requireAuth } = require('./client');
|
|
4
|
+
const ui = require('./ui');
|
|
5
|
+
|
|
6
|
+
async function status(args, flags) {
|
|
7
|
+
requireAuth();
|
|
8
|
+
const s = ui.spinner('Checking firewall status');
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const data = await api.get('/firewall/status');
|
|
12
|
+
|
|
13
|
+
s.stop('Firewall status retrieved');
|
|
14
|
+
|
|
15
|
+
if (flags.json) {
|
|
16
|
+
ui.json(data);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
console.log('');
|
|
21
|
+
console.log(` ${ui.c.bold(ui.c.green('Firewall: ENABLED'))}`);
|
|
22
|
+
console.log('');
|
|
23
|
+
ui.keyValue([
|
|
24
|
+
['Blocked IPs', `${data.totalIps} total (${data.exactCount} exact + ${data.cidrCount} CIDR ranges)`],
|
|
25
|
+
['Last updated', data.updatedAt || 'unknown'],
|
|
26
|
+
['Sync TTL', `${data.ttl || 60}s`],
|
|
27
|
+
]);
|
|
28
|
+
console.log('');
|
|
29
|
+
console.log(` ${ui.c.dim('Manage your blocklist:')} securenow blocklist`);
|
|
30
|
+
console.log(` ${ui.c.dim('Test an IP:')} securenow firewall test-ip <ip>`);
|
|
31
|
+
console.log('');
|
|
32
|
+
} catch (err) {
|
|
33
|
+
if (err.statusCode === 401 || err.status === 401) {
|
|
34
|
+
s.fail('Authentication failed');
|
|
35
|
+
ui.error('API key is invalid or missing the firewall:read scope.');
|
|
36
|
+
ui.info('Create an API key with firewall:read scope in the dashboard.');
|
|
37
|
+
} else {
|
|
38
|
+
s.fail('Failed to check firewall status');
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function testIp(args, flags) {
|
|
45
|
+
requireAuth();
|
|
46
|
+
const ip = args[0];
|
|
47
|
+
if (!ip) {
|
|
48
|
+
ui.error('Usage: securenow firewall test-ip <ip-address>');
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const s = ui.spinner(`Testing IP ${ip}`);
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const data = await api.get(`/firewall/check/${encodeURIComponent(ip)}`);
|
|
56
|
+
|
|
57
|
+
s.stop(`IP ${ip} checked`);
|
|
58
|
+
|
|
59
|
+
if (flags.json) {
|
|
60
|
+
ui.json(data);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log('');
|
|
65
|
+
if (data.blocked) {
|
|
66
|
+
console.log(` ${ui.c.bold(ui.c.red('BLOCKED'))} — ${ip} is in the blocklist`);
|
|
67
|
+
if (data.matchedEntry && data.matchedEntry !== ip) {
|
|
68
|
+
console.log(` ${ui.c.dim(`Matched by: ${data.matchedEntry}`)}`);
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
console.log(` ${ui.c.bold(ui.c.green('ALLOWED'))} — ${ip} is not in the blocklist`);
|
|
72
|
+
}
|
|
73
|
+
console.log(` ${ui.c.dim(`Blocklist contains ${data.totalBlockedIps} entries`)}`);
|
|
74
|
+
console.log('');
|
|
75
|
+
} catch (err) {
|
|
76
|
+
s.fail('Failed to test IP');
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = { status, testIp };
|