forked from cambecc/earth
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdev-server.js
More file actions
78 lines (64 loc) · 2.3 KB
/
dev-server.js
File metadata and controls
78 lines (64 loc) · 2.3 KB
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
/**
* dev-server - serves static resources for developing "earth" locally
* Updated to use Node's built-in http server for better compatibility
*/
"use strict";
console.log("============================================================");
console.log(new Date().toISOString() + " - Starting");
var http = require("http");
var fs = require("fs");
var path = require("path");
var port = process.argv[2] || 8080;
var publicDir = path.join(__dirname, "public");
var publicDirResolved = path.resolve(publicDir);
var mimeTypes = {
".html": "text/html",
".js": "application/javascript",
".json": "application/json",
".css": "text/css",
".png": "image/png",
".jpg": "image/jpeg",
".gif": "image/gif",
".svg": "image/svg+xml",
".ico": "image/x-icon",
".ttf": "font/ttf",
".woff": "font/woff",
".woff2": "font/woff2"
};
var server = http.createServer(function (req, res) {
// Extract pathname from URL (handle query strings)
var urlPath = req.url;
var queryIndex = urlPath.indexOf('?');
var pathname = queryIndex >= 0 ? urlPath.substring(0, queryIndex) : urlPath;
// Default to index.html for root
if (pathname === "/") {
pathname = "/index.html";
}
// Resolve absolute path and guard against path traversal (CVE-2025-23084 / CVE-2025-27210)
var filePath = path.resolve(publicDirResolved, "." + pathname);
// Security check - ensure file is within public directory
if (filePath !== publicDirResolved && !filePath.startsWith(publicDirResolved + path.sep)) {
res.writeHead(403);
res.end("Forbidden");
return;
}
fs.stat(filePath, function (err, stats) {
if (err || !stats.isFile()) {
res.writeHead(404);
res.end("Not Found");
return;
}
var ext = path.extname(filePath).toLowerCase();
var contentType = mimeTypes[ext] || "application/octet-stream";
res.setHeader("Content-Type", contentType);
res.setHeader("Cache-Control", "public, max-age=300");
var stream = fs.createReadStream(filePath);
stream.on("error", function () {
res.writeHead(500);
res.end("Internal Server Error");
});
stream.pipe(res);
});
});
server.listen(port);
console.log("Listening on port " + port + "...");