forked from CycloneDX/cdxgen
-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
124 lines (117 loc) · 3.43 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
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
import connect from "connect";
import http from "node:http";
import bodyParser from "body-parser";
import url from "node:url";
import { spawnSync } from "node:child_process";
import os from "node:os";
import fs from "node:fs";
import path from "node:path";
import { createBom } from "./index.js";
import compression from "compression";
// Timeout milliseconds. Default 10 mins
const TIMEOUT_MS =
parseInt(process.env.CDXGEN_SERVER_TIMEOUT_MS) || 10 * 60 * 1000;
const app = connect();
app.use(
bodyParser.json({
deflate: true,
limit: "1mb"
})
);
app.use(compression());
const gitClone = (repoUrl) => {
const tempDir = fs.mkdtempSync(
path.join(os.tmpdir(), path.basename(repoUrl))
);
console.log("Cloning", repoUrl, "to", tempDir);
const result = spawnSync("git", ["clone", repoUrl, "--depth", "1", tempDir], {
encoding: "utf-8",
shell: false
});
if (result.status !== 0 || result.error) {
console.log(result.error);
}
return tempDir;
};
const parseQueryString = (q, body, options = {}) => {
if (body && Object.keys(body).length) {
options = Object.assign(options, body);
}
if (q.type) {
options.projectType = q.type;
}
if (q.multiProject && q.multiProject !== "false") {
options.multiProject = true;
}
if (q.requiredOnly && q.requiredOnly !== "false") {
options.requiredOnly = true;
}
if (q.noBabel) {
options.noBabel = q.noBabel;
}
if (q.installDeps) {
options.installDeps = q.installDeps;
}
if (q.project) {
options.project = q.project;
}
if (q.projectName) {
options.projectName = q.projectName;
}
if (q.projectGroup) {
options.projectGroup = q.projectGroup;
}
if (q.projectVersion) {
options.projectVersion = q.projectVersion;
}
return options;
};
const configureServer = (cdxgenServer) => {
cdxgenServer.headersTimeout = TIMEOUT_MS;
cdxgenServer.requestTimeout = TIMEOUT_MS;
cdxgenServer.timeout = 0;
cdxgenServer.keepAliveTimeout = 0;
};
const start = (options) => {
console.log("Listening on", options.serverHost, options.serverPort);
const cdxgenServer = http
.createServer(app)
.listen(options.serverPort, options.serverHost);
configureServer(cdxgenServer);
app.use("/sbom", async function (req, res) {
const q = url.parse(req.url, true).query;
let cleanup = false;
options = parseQueryString(q, req.body, options);
const filePath = q.path || q.url || req.body.path || req.body.url;
if (!filePath) {
res.writeHead(500, { "Content-Type": "application/json" });
return res.end(
"{'error': 'true', 'message': 'path or url is required.'}\n"
);
}
res.writeHead(200, { "Content-Type": "application/json" });
let srcDir = filePath;
if (filePath.startsWith("http") || filePath.startsWith("git")) {
srcDir = gitClone(filePath);
cleanup = true;
}
console.log("Generating SBoM for", srcDir);
const bomNSData = (await createBom(srcDir, options)) || {};
if (bomNSData.bomJson) {
if (
typeof bomNSData.bomJson === "string" ||
bomNSData.bomJson instanceof String
) {
res.write(bomNSData.bomJson);
} else {
res.write(JSON.stringify(bomNSData.bomJson, null, 2));
}
}
res.end("\n");
if (cleanup && srcDir && srcDir.startsWith(os.tmpdir()) && fs.rmSync) {
console.log(`Cleaning up ${srcDir}`);
fs.rmSync(srcDir, { recursive: true, force: true });
}
});
};
export { configureServer, start };