securenow 6.0.2 → 7.0.0-anas
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 +455 -0
- package/NPM_README.md +2029 -0
- package/README.md +297 -40
- package/SKILL-API.md +634 -0
- package/SKILL-CLI.md +454 -0
- package/app-config.js +130 -0
- package/cidr.js +83 -0
- package/cli/apps.js +608 -0
- package/cli/auth.js +298 -0
- package/cli/client.js +115 -0
- package/cli/config.js +202 -0
- package/cli/diagnostics.js +387 -0
- package/cli/firewall.js +100 -0
- package/cli/fp.js +638 -0
- package/cli/init.js +201 -0
- package/cli/monitor.js +440 -0
- package/cli/run.js +148 -0
- package/cli/security.js +980 -0
- package/cli/ui.js +386 -0
- package/cli/utils.js +127 -0
- package/cli.js +469 -455
- package/console-instrumentation.js +147 -136
- package/docs/ALL-FRAMEWORKS-QUICKSTART.md +1377 -455
- package/docs/API-KEYS-GUIDE.md +233 -0
- package/docs/ARCHITECTURE.md +3 -3
- package/docs/AUTO-BODY-CAPTURE.md +1 -1
- package/docs/AUTO-SETUP-SUMMARY.md +331 -0
- package/docs/AUTO-SETUP.md +4 -4
- package/docs/AUTOMATIC-IP-CAPTURE.md +5 -5
- package/docs/BODY-CAPTURE-FIX.md +261 -0
- package/docs/BODY-CAPTURE-QUICKSTART.md +2 -2
- package/docs/CHANGELOG-NEXTJS.md +1 -35
- package/docs/COMPLETION-REPORT.md +408 -0
- package/docs/CUSTOMER-GUIDE.md +16 -16
- package/docs/EASIEST-SETUP.md +5 -5
- package/docs/ENVIRONMENT-VARIABLES.md +880 -652
- package/docs/EXPRESS-BODY-CAPTURE.md +13 -12
- package/docs/EXPRESS-SETUP-GUIDE.md +719 -720
- package/docs/FINAL-SOLUTION.md +335 -0
- package/docs/FIREWALL-GUIDE.md +426 -0
- package/docs/IMPLEMENTATION-SUMMARY.md +410 -0
- package/docs/INDEX.md +22 -4
- package/docs/LOGGING-GUIDE.md +701 -708
- package/docs/LOGGING-QUICKSTART.md +234 -255
- package/docs/NEXTJS-BODY-CAPTURE-COMPARISON.md +323 -0
- package/docs/NEXTJS-BODY-CAPTURE.md +2 -2
- package/docs/NEXTJS-GUIDE.md +14 -14
- package/docs/NEXTJS-QUICKSTART.md +1 -1
- package/docs/NEXTJS-SETUP-COMPLETE.md +795 -0
- package/docs/NEXTJS-WRAPPER-APPROACH.md +1 -1
- package/docs/NUXT-GUIDE.md +166 -0
- package/docs/QUICKSTART-BODY-CAPTURE.md +2 -2
- package/docs/REDACTION-EXAMPLES.md +1 -1
- package/docs/REQUEST-BODY-CAPTURE.md +19 -10
- package/docs/SOLUTION-SUMMARY.md +312 -0
- package/docs/VERCEL-OTEL-MIGRATION.md +3 -3
- package/examples/README.md +6 -6
- package/examples/instrumentation-with-auto-capture.ts +1 -1
- package/examples/nextjs-env-example.txt +2 -2
- package/examples/nextjs-instrumentation.js +1 -1
- package/examples/nextjs-instrumentation.ts +1 -1
- package/examples/nextjs-with-logging-example.md +6 -6
- package/examples/nextjs-with-options.ts +1 -1
- package/examples/test-nextjs-setup.js +1 -1
- package/firewall-cloud.js +212 -0
- package/firewall-iptables.js +139 -0
- package/firewall-only.js +38 -0
- package/firewall-tcp.js +74 -0
- package/firewall.js +720 -0
- package/free-trial-banner.js +174 -0
- package/nextjs-auto-capture.js +198 -207
- package/nextjs-middleware.js +186 -181
- package/nextjs-webpack-config.js +88 -53
- package/nextjs-wrapper.js +158 -158
- package/nextjs.d.ts +1 -1
- package/nextjs.js +638 -647
- package/nuxt-server-plugin.mjs +425 -0
- package/nuxt.d.ts +60 -0
- package/nuxt.mjs +75 -0
- package/package.json +172 -164
- package/postinstall.js +42 -14
- package/register.d.ts +1 -1
- package/register.js +39 -4
- package/resolve-ip.js +77 -0
- package/tracing.d.ts +2 -1
- package/tracing.js +318 -45
- package/web-vite.mjs +239 -156
- package/LICENSE +0 -15
package/package.json
CHANGED
|
@@ -1,164 +1,172 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "securenow",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "OpenTelemetry instrumentation for Node.js
|
|
5
|
-
"type": "commonjs",
|
|
6
|
-
"main": "register.js",
|
|
7
|
-
"types": "register.d.ts",
|
|
8
|
-
"bin": {
|
|
9
|
-
"securenow": "cli.js"
|
|
10
|
-
},
|
|
11
|
-
"scripts": {
|
|
12
|
-
"postinstall": "node postinstall.js || exit 0"
|
|
13
|
-
},
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
"./
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
"
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
"
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
"
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
"
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
"
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"
|
|
120
|
-
"
|
|
121
|
-
"
|
|
122
|
-
"
|
|
123
|
-
"
|
|
124
|
-
"
|
|
125
|
-
"
|
|
126
|
-
"
|
|
127
|
-
"
|
|
128
|
-
"
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
"
|
|
132
|
-
"
|
|
133
|
-
"
|
|
134
|
-
"
|
|
135
|
-
"
|
|
136
|
-
"
|
|
137
|
-
"
|
|
138
|
-
"
|
|
139
|
-
"
|
|
140
|
-
"
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
"@opentelemetry/
|
|
144
|
-
"@opentelemetry/
|
|
145
|
-
"@opentelemetry/
|
|
146
|
-
"@opentelemetry/
|
|
147
|
-
"@
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
"
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
"
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
"
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
"
|
|
164
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "securenow",
|
|
3
|
+
"version": "7.0.0-anas",
|
|
4
|
+
"description": "OpenTelemetry instrumentation for Node.js, Next.js, and Nuxt - Send traces and logs to any OTLP-compatible backend",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"main": "register.js",
|
|
7
|
+
"types": "register.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"securenow": "cli.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"postinstall": "node postinstall.js || exit 0"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"opentelemetry",
|
|
16
|
+
"otel",
|
|
17
|
+
"tracing",
|
|
18
|
+
"logging",
|
|
19
|
+
"logs",
|
|
20
|
+
"observability",
|
|
21
|
+
"apm",
|
|
22
|
+
"monitoring",
|
|
23
|
+
"cli",
|
|
24
|
+
"nextjs",
|
|
25
|
+
"next.js",
|
|
26
|
+
"instrumentation",
|
|
27
|
+
"telemetry",
|
|
28
|
+
"distributed-tracing",
|
|
29
|
+
"node",
|
|
30
|
+
"express",
|
|
31
|
+
"fastify",
|
|
32
|
+
"nestjs",
|
|
33
|
+
"nuxt",
|
|
34
|
+
"nuxt3",
|
|
35
|
+
"nitro",
|
|
36
|
+
"vue",
|
|
37
|
+
"firewall",
|
|
38
|
+
"ip-blocking",
|
|
39
|
+
"waf",
|
|
40
|
+
"security"
|
|
41
|
+
],
|
|
42
|
+
"exports": {
|
|
43
|
+
".": {
|
|
44
|
+
"types": "./register.d.ts",
|
|
45
|
+
"default": "./register.js"
|
|
46
|
+
},
|
|
47
|
+
"./register": {
|
|
48
|
+
"types": "./register.d.ts",
|
|
49
|
+
"default": "./register.js"
|
|
50
|
+
},
|
|
51
|
+
"./tracing": {
|
|
52
|
+
"types": "./tracing.d.ts",
|
|
53
|
+
"default": "./tracing.js"
|
|
54
|
+
},
|
|
55
|
+
"./console-instrumentation": {
|
|
56
|
+
"default": "./console-instrumentation.js"
|
|
57
|
+
},
|
|
58
|
+
"./nextjs": {
|
|
59
|
+
"types": "./nextjs.d.ts",
|
|
60
|
+
"default": "./nextjs.js"
|
|
61
|
+
},
|
|
62
|
+
"./nextjs-auto-capture": {
|
|
63
|
+
"types": "./nextjs-auto-capture.d.ts",
|
|
64
|
+
"default": "./nextjs-auto-capture.js"
|
|
65
|
+
},
|
|
66
|
+
"./nextjs-middleware": {
|
|
67
|
+
"types": "./nextjs-middleware.d.ts",
|
|
68
|
+
"default": "./nextjs-middleware.js"
|
|
69
|
+
},
|
|
70
|
+
"./nextjs-wrapper": {
|
|
71
|
+
"types": "./nextjs-wrapper.d.ts",
|
|
72
|
+
"default": "./nextjs-wrapper.js"
|
|
73
|
+
},
|
|
74
|
+
"./nextjs-webpack-config": "./nextjs-webpack-config.js",
|
|
75
|
+
"./package.json": "./package.json",
|
|
76
|
+
"./nuxt": {
|
|
77
|
+
"types": "./nuxt.d.ts",
|
|
78
|
+
"import": "./nuxt.mjs",
|
|
79
|
+
"default": "./nuxt.mjs"
|
|
80
|
+
},
|
|
81
|
+
"./firewall": {
|
|
82
|
+
"default": "./firewall.js"
|
|
83
|
+
},
|
|
84
|
+
"./firewall-only": {
|
|
85
|
+
"default": "./firewall-only.js"
|
|
86
|
+
},
|
|
87
|
+
"./cidr": {
|
|
88
|
+
"default": "./cidr.js"
|
|
89
|
+
},
|
|
90
|
+
"./resolve-ip": {
|
|
91
|
+
"default": "./resolve-ip.js"
|
|
92
|
+
},
|
|
93
|
+
"./register-vite": "./register-vite.js",
|
|
94
|
+
"./web-vite": {
|
|
95
|
+
"import": "./web-vite.mjs",
|
|
96
|
+
"default": "./web-vite.mjs"
|
|
97
|
+
},
|
|
98
|
+
"./app-config": {
|
|
99
|
+
"default": "./app-config.js"
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
"files": [
|
|
103
|
+
"register.js",
|
|
104
|
+
"register.d.ts",
|
|
105
|
+
"tracing.js",
|
|
106
|
+
"tracing.d.ts",
|
|
107
|
+
"console-instrumentation.js",
|
|
108
|
+
"nextjs.js",
|
|
109
|
+
"nextjs.d.ts",
|
|
110
|
+
"nextjs-auto-capture.js",
|
|
111
|
+
"nextjs-auto-capture.d.ts",
|
|
112
|
+
"nextjs-middleware.js",
|
|
113
|
+
"nextjs-middleware.d.ts",
|
|
114
|
+
"nextjs-wrapper.js",
|
|
115
|
+
"nextjs-wrapper.d.ts",
|
|
116
|
+
"nextjs-webpack-config.js",
|
|
117
|
+
"nuxt.mjs",
|
|
118
|
+
"nuxt.d.ts",
|
|
119
|
+
"nuxt-server-plugin.mjs",
|
|
120
|
+
"cli.js",
|
|
121
|
+
"cli/",
|
|
122
|
+
"free-trial-banner.js",
|
|
123
|
+
"resolve-ip.js",
|
|
124
|
+
"cidr.js",
|
|
125
|
+
"firewall.js",
|
|
126
|
+
"firewall-only.js",
|
|
127
|
+
"firewall-tcp.js",
|
|
128
|
+
"firewall-iptables.js",
|
|
129
|
+
"firewall-cloud.js",
|
|
130
|
+
"postinstall.js",
|
|
131
|
+
"register-vite.js",
|
|
132
|
+
"web-vite.mjs",
|
|
133
|
+
"app-config.js",
|
|
134
|
+
"examples/",
|
|
135
|
+
"docs/",
|
|
136
|
+
"README.md",
|
|
137
|
+
"NPM_README.md",
|
|
138
|
+
"CONSUMING-APPS-GUIDE.md",
|
|
139
|
+
"SKILL-CLI.md",
|
|
140
|
+
"SKILL-API.md"
|
|
141
|
+
],
|
|
142
|
+
"dependencies": {
|
|
143
|
+
"@opentelemetry/api": "1.7.0",
|
|
144
|
+
"@opentelemetry/api-logs": "0.47.0",
|
|
145
|
+
"@opentelemetry/auto-instrumentations-node": "0.47.0",
|
|
146
|
+
"@opentelemetry/exporter-logs-otlp-http": "0.47.0",
|
|
147
|
+
"@opentelemetry/exporter-trace-otlp-http": "0.47.0",
|
|
148
|
+
"@opentelemetry/instrumentation": "0.47.0",
|
|
149
|
+
"@opentelemetry/instrumentation-document-load": "0.47.0",
|
|
150
|
+
"@opentelemetry/instrumentation-fetch": "0.47.0",
|
|
151
|
+
"@opentelemetry/instrumentation-http": "0.47.0",
|
|
152
|
+
"@opentelemetry/instrumentation-mongodb": "0.46.0",
|
|
153
|
+
"@opentelemetry/instrumentation-user-interaction": "0.47.0",
|
|
154
|
+
"@opentelemetry/instrumentation-xml-http-request": "0.47.0",
|
|
155
|
+
"@opentelemetry/resources": "1.20.0",
|
|
156
|
+
"@opentelemetry/sdk-logs": "0.47.0",
|
|
157
|
+
"@opentelemetry/sdk-node": "0.47.0",
|
|
158
|
+
"@opentelemetry/sdk-trace-web": "1.20.0",
|
|
159
|
+
"@opentelemetry/semantic-conventions": "1.20.0",
|
|
160
|
+
"dotenv": "^17.2.1",
|
|
161
|
+
"uuid": "^9.0.0"
|
|
162
|
+
},
|
|
163
|
+
"optionalDependencies": {
|
|
164
|
+
"@vercel/otel": "^1.14.0"
|
|
165
|
+
},
|
|
166
|
+
"overrides": {
|
|
167
|
+
"@opentelemetry/api": "1.7.0",
|
|
168
|
+
"@opentelemetry/api-logs": "0.47.0"
|
|
169
|
+
},
|
|
170
|
+
"sideEffects": true,
|
|
171
|
+
"license": "ISC"
|
|
172
|
+
}
|
package/postinstall.js
CHANGED
|
@@ -11,6 +11,35 @@ const fs = require('fs');
|
|
|
11
11
|
const path = require('path');
|
|
12
12
|
const readline = require('readline');
|
|
13
13
|
|
|
14
|
+
// Make sure `.securenow/` is in the project's .gitignore so credentials never get committed.
|
|
15
|
+
function ensureGitignore() {
|
|
16
|
+
try {
|
|
17
|
+
// Skip if we're not in an npm install of a user project
|
|
18
|
+
// (e.g., securenow's own CI, or nested install under another node_modules).
|
|
19
|
+
const cwd = process.cwd();
|
|
20
|
+
if (!fs.existsSync(path.join(cwd, 'package.json'))) return;
|
|
21
|
+
if (cwd.includes(`${path.sep}node_modules${path.sep}`)) return;
|
|
22
|
+
|
|
23
|
+
const gitignorePath = path.join(cwd, '.gitignore');
|
|
24
|
+
const entry = '.securenow/';
|
|
25
|
+
const header = '# SecureNow local credentials';
|
|
26
|
+
|
|
27
|
+
if (fs.existsSync(gitignorePath)) {
|
|
28
|
+
const content = fs.readFileSync(gitignorePath, 'utf8');
|
|
29
|
+
const alreadyListed = content.split('\n').some((line) => line.trim() === entry);
|
|
30
|
+
if (!alreadyListed) {
|
|
31
|
+
const prefix = content.endsWith('\n') ? '' : '\n';
|
|
32
|
+
fs.appendFileSync(gitignorePath, `${prefix}\n${header}\n${entry}\n`);
|
|
33
|
+
}
|
|
34
|
+
} else if (fs.existsSync(path.join(cwd, '.git'))) {
|
|
35
|
+
// Only create a new .gitignore if this is actually a git repo.
|
|
36
|
+
fs.writeFileSync(gitignorePath, `${header}\n${entry}\n`);
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
// Non-fatal
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
14
43
|
// Check if we're in a Next.js project
|
|
15
44
|
function isNextJsProject() {
|
|
16
45
|
try {
|
|
@@ -53,7 +82,7 @@ export function register() {
|
|
|
53
82
|
* SECURENOW_APPID=my-nextjs-app
|
|
54
83
|
*
|
|
55
84
|
* Optional:
|
|
56
|
-
* SECURENOW_INSTANCE=http://your-
|
|
85
|
+
* SECURENOW_INSTANCE=http://your-otlp-backend:4318
|
|
57
86
|
* OTEL_EXPORTER_OTLP_HEADERS="x-api-key=your-key"
|
|
58
87
|
* OTEL_LOG_LEVEL=info
|
|
59
88
|
*/
|
|
@@ -77,13 +106,12 @@ export function register() {
|
|
|
77
106
|
* SECURENOW_APPID=my-nextjs-app
|
|
78
107
|
*
|
|
79
108
|
* Optional:
|
|
80
|
-
* SECURENOW_INSTANCE=http://your-
|
|
109
|
+
* SECURENOW_INSTANCE=http://your-otlp-backend:4318
|
|
81
110
|
* OTEL_EXPORTER_OTLP_HEADERS="x-api-key=your-key"
|
|
82
111
|
* OTEL_LOG_LEVEL=info
|
|
83
112
|
*
|
|
84
|
-
* Optional:
|
|
85
|
-
* SECURENOW_CAPTURE_BODY=
|
|
86
|
-
* (Also create middleware.ts to activate - run: npx securenow init)
|
|
113
|
+
* Optional: Disable request body capture (enabled by default)
|
|
114
|
+
* SECURENOW_CAPTURE_BODY=0
|
|
87
115
|
*/
|
|
88
116
|
`;
|
|
89
117
|
|
|
@@ -150,9 +178,9 @@ function createEnvTemplate(targetPath) {
|
|
|
150
178
|
# Required: Your application identifier
|
|
151
179
|
SECURENOW_APPID=my-nextjs-app
|
|
152
180
|
|
|
153
|
-
# Optional: Your
|
|
181
|
+
# Optional: Your OTLP-compatible backend / collector endpoint
|
|
154
182
|
# Default: https://freetrial.securenow.ai:4318
|
|
155
|
-
SECURENOW_INSTANCE=http://your-
|
|
183
|
+
SECURENOW_INSTANCE=http://your-otlp-backend:4318
|
|
156
184
|
|
|
157
185
|
# Optional: API key or authentication headers
|
|
158
186
|
# OTEL_EXPORTER_OTLP_HEADERS="x-api-key=your-api-key-here"
|
|
@@ -160,8 +188,8 @@ SECURENOW_INSTANCE=http://your-signoz-server:4318
|
|
|
160
188
|
# Optional: Log level (debug|info|warn|error)
|
|
161
189
|
# OTEL_LOG_LEVEL=info
|
|
162
190
|
|
|
163
|
-
# Optional:
|
|
164
|
-
# SECURENOW_CAPTURE_BODY=
|
|
191
|
+
# Optional: Disable request body capture (enabled by default)
|
|
192
|
+
# SECURENOW_CAPTURE_BODY=0
|
|
165
193
|
# SECURENOW_MAX_BODY_SIZE=10240
|
|
166
194
|
# SECURENOW_SENSITIVE_FIELDS=email,phone
|
|
167
195
|
`;
|
|
@@ -176,6 +204,9 @@ function isTypeScriptProject() {
|
|
|
176
204
|
|
|
177
205
|
// Main setup function
|
|
178
206
|
async function setup() {
|
|
207
|
+
// Always make sure .securenow/ is gitignored (cheap, non-destructive).
|
|
208
|
+
ensureGitignore();
|
|
209
|
+
|
|
179
210
|
// Skip if not in Next.js project
|
|
180
211
|
if (!isNextJsProject()) {
|
|
181
212
|
console.log('[securenow] Not a Next.js project, skipping auto-setup');
|
|
@@ -270,14 +301,11 @@ async function setup() {
|
|
|
270
301
|
console.log('│ │');
|
|
271
302
|
console.log('│ 1. Edit .env.local and set: │');
|
|
272
303
|
console.log('│ SECURENOW_APPID=your-app-name │');
|
|
273
|
-
console.log('│ SECURENOW_INSTANCE=http://
|
|
274
|
-
if (shouldCreateMiddleware) {
|
|
275
|
-
console.log('│ SECURENOW_CAPTURE_BODY=1 │');
|
|
276
|
-
}
|
|
304
|
+
console.log('│ SECURENOW_INSTANCE=http://your-otlp-backend:4318 │');
|
|
277
305
|
console.log('│ │');
|
|
278
306
|
console.log('│ 2. Run your app: npm run dev │');
|
|
279
307
|
console.log('│ │');
|
|
280
|
-
console.log('│ 3. Check
|
|
308
|
+
console.log('│ 3. Check SecureNow for traces! │');
|
|
281
309
|
console.log('│ │');
|
|
282
310
|
if (shouldCreateMiddleware) {
|
|
283
311
|
console.log('│ 📝 Body capture enabled with auto-redaction │');
|
package/register.d.ts
CHANGED
package/register.js
CHANGED
|
@@ -1,14 +1,49 @@
|
|
|
1
|
-
// securenow/
|
|
1
|
+
// securenow/register.js — the only preload customers need:
|
|
2
|
+
// node --require securenow/register app.js
|
|
3
|
+
//
|
|
4
|
+
// For ESM apps ("type": "module"), this file auto-registers the
|
|
5
|
+
// OpenTelemetry ESM loader hook via module.register() (Node >=20.6).
|
|
6
|
+
// On older Node versions it falls back to a warning.
|
|
2
7
|
'use strict';
|
|
3
8
|
|
|
4
|
-
//
|
|
9
|
+
// 1. load .env before anything else
|
|
5
10
|
try {
|
|
6
11
|
require('dotenv').config();
|
|
7
12
|
console.log('[securenow] dotenv loaded from', process.env.DOTENV_CONFIG_PATH || '.env');
|
|
8
13
|
} catch (e) {
|
|
9
|
-
// dotenv is optional — only warn if it’s missing
|
|
10
14
|
console.warn('[securenow] dotenv not found or failed to load');
|
|
11
15
|
}
|
|
12
16
|
|
|
13
|
-
//
|
|
17
|
+
// 2. Auto-register the ESM loader hook so customers never need --import
|
|
18
|
+
(() => {
|
|
19
|
+
try {
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
const pkgPath = path.resolve(process.cwd(), 'package.json');
|
|
23
|
+
if (!fs.existsSync(pkgPath)) return;
|
|
24
|
+
|
|
25
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
26
|
+
if (pkg.type !== 'module') return;
|
|
27
|
+
|
|
28
|
+
// Already registered via --import?
|
|
29
|
+
const execArgv = process.execArgv.join(' ');
|
|
30
|
+
if (execArgv.includes('hook.mjs') || execArgv.includes('import-in-the-middle')) return;
|
|
31
|
+
|
|
32
|
+
// Node >=20.6 exposes module.register() for programmatic ESM hooks
|
|
33
|
+
const mod = require('node:module');
|
|
34
|
+
if (typeof mod.register !== 'function') {
|
|
35
|
+
console.warn('[securenow] ESM app detected but Node %s lacks module.register().', process.version);
|
|
36
|
+
console.warn('[securenow] Upgrade to Node >=20.6 or add: --import @opentelemetry/instrumentation/hook.mjs');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const { pathToFileURL } = require('node:url');
|
|
41
|
+
mod.register('@opentelemetry/instrumentation/hook.mjs', pathToFileURL(__filename));
|
|
42
|
+
console.log('[securenow] ESM loader hook auto-registered (module.register)');
|
|
43
|
+
} catch (_) {
|
|
44
|
+
// Non-fatal — tracing.js will show its own ESM warning if the hook is missing
|
|
45
|
+
}
|
|
46
|
+
})();
|
|
47
|
+
|
|
48
|
+
// 3. Run the OTel SDK setup
|
|
14
49
|
require('./tracing');
|
package/resolve-ip.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const os = require('os');
|
|
4
|
+
|
|
5
|
+
const LOOPBACK_RE = /^(127\.|::1$|::ffff:127\.)/;
|
|
6
|
+
const PRIVATE_IP_RE = /^(127\.|::1$|::ffff:127\.|10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.|f[cd][0-9a-f]{2}:)/;
|
|
7
|
+
|
|
8
|
+
const trustedProxyCsv = (process.env.SECURENOW_TRUSTED_PROXIES || '').trim();
|
|
9
|
+
const trustedProxySet = trustedProxyCsv
|
|
10
|
+
? new Set(trustedProxyCsv.split(',').map(s => s.trim()).filter(Boolean))
|
|
11
|
+
: null;
|
|
12
|
+
|
|
13
|
+
let _hostIp = null;
|
|
14
|
+
function getHostIp() {
|
|
15
|
+
if (_hostIp !== null) return _hostIp;
|
|
16
|
+
try {
|
|
17
|
+
const ifaces = os.networkInterfaces();
|
|
18
|
+
for (const name of Object.keys(ifaces)) {
|
|
19
|
+
for (const iface of ifaces[name]) {
|
|
20
|
+
if (!iface.internal && iface.family === 'IPv4') { _hostIp = iface.address; return _hostIp; }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
} catch (_) {}
|
|
24
|
+
_hostIp = '';
|
|
25
|
+
return _hostIp;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function isFromTrustedProxy(socketIp) {
|
|
29
|
+
if (!socketIp) return false;
|
|
30
|
+
const normalized = socketIp.replace(/^::ffff:/, '');
|
|
31
|
+
if (trustedProxySet && trustedProxySet.has(normalized)) return true;
|
|
32
|
+
return PRIVATE_IP_RE.test(socketIp);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Resolve the real client IP from an HTTP request, respecting trusted proxies.
|
|
37
|
+
* Reads X-Forwarded-For / X-Real-IP only when the direct connection comes
|
|
38
|
+
* from a private/trusted proxy IP. Prevents client-side IP spoofing.
|
|
39
|
+
*/
|
|
40
|
+
function resolveClientIp(request) {
|
|
41
|
+
const socketIp = request.socket?.remoteAddress || '';
|
|
42
|
+
if (!isFromTrustedProxy(socketIp)) return socketIp;
|
|
43
|
+
|
|
44
|
+
const fwd = request.headers['x-forwarded-for'];
|
|
45
|
+
if (fwd) {
|
|
46
|
+
const chain = String(fwd).split(',').map(s => s.trim()).filter(Boolean);
|
|
47
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
48
|
+
if (!isFromTrustedProxy(chain[i])) return chain[i];
|
|
49
|
+
}
|
|
50
|
+
return socketIp;
|
|
51
|
+
}
|
|
52
|
+
const headerIp = request.headers['x-real-ip'];
|
|
53
|
+
if (headerIp) return headerIp;
|
|
54
|
+
|
|
55
|
+
if (LOOPBACK_RE.test(socketIp)) {
|
|
56
|
+
const hostIp = getHostIp();
|
|
57
|
+
if (hostIp) return hostIp;
|
|
58
|
+
}
|
|
59
|
+
return socketIp;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Resolve IP from a raw TCP socket (no HTTP headers available).
|
|
64
|
+
* Normalizes IPv6-mapped IPv4 addresses.
|
|
65
|
+
*/
|
|
66
|
+
function resolveSocketIp(socket) {
|
|
67
|
+
const raw = socket?.remoteAddress || '';
|
|
68
|
+
return raw.replace(/^::ffff:/, '');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = {
|
|
72
|
+
resolveClientIp,
|
|
73
|
+
resolveSocketIp,
|
|
74
|
+
isFromTrustedProxy,
|
|
75
|
+
LOOPBACK_RE,
|
|
76
|
+
PRIVATE_IP_RE,
|
|
77
|
+
};
|
package/tracing.d.ts
CHANGED
|
@@ -112,7 +112,7 @@ export interface LoggerProvider {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
|
-
* Get a logger instance for sending structured logs to
|
|
115
|
+
* Get a logger instance for sending structured logs to any OTLP-compatible backend
|
|
116
116
|
*
|
|
117
117
|
* @param name - Logger name (e.g., 'my-service', 'auth-module')
|
|
118
118
|
* @param version - Logger version (optional, defaults to '1.0.0')
|
|
@@ -178,5 +178,6 @@ export const loggerProvider: LoggerProvider | null;
|
|
|
178
178
|
* - SECURENOW_DISABLE_INSTRUMENTATIONS=pkg1,pkg2
|
|
179
179
|
* - OTEL_LOG_LEVEL=info|debug
|
|
180
180
|
* - SECURENOW_TEST_SPAN=1
|
|
181
|
+
* - SECURENOW_TRUSTED_PROXIES=ip1,ip2 # Additional trusted proxy IPs for X-Forwarded-For
|
|
181
182
|
* - OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=... # Override logs endpoint
|
|
182
183
|
*/
|