Allow URLs containing absolute filepaths in imports if they match specific file extensions

This is to support ../../ imports

Allowlisting to specific file extensions prevents common webserver security vulnerabilities like reading /etc/passwd
This commit is contained in:
Jarred Sumner
2021-09-22 16:19:16 -07:00
parent 39323b46ba
commit e00c1e99d6
3 changed files with 46 additions and 5 deletions

View File

@@ -273,10 +273,8 @@ pub const RequestContext = struct {
defer this.done();
try this.writeStatus(500);
const route_name = if (route_index > -1) this.matched_route.?.name else this.url.pathname;
Output.prettyErrorln("<r><red>500<r> - <b>{s}<r> rendering <b>/{s}<r>", .{
@errorName(err),
route_name,
});
if (comptime fmt.len > 0) Output.prettyErrorln(fmt, args);
Output.flush();
this.appendHeader("Content-Type", MimeType.html.value);
var bb = std.ArrayList(u8).init(allocator);
defer bb.deinit();
@@ -2250,6 +2248,37 @@ pub const RequestContext = struct {
}
}
fn handleAbsURL(ctx: *RequestContext, server: *Server) !void {
const extname = ctx.url.extname;
switch (extname.len) {
3 => {
if (!(strings.eqlComptime(extname, "css") or strings.eqlComptime(extname, "tsx") or strings.eqlComptime(extname, "jsx") or strings.eqlComptime(extname, "mjs"))) return try ctx.sendNotFound();
},
2 => {
if (!(strings.eqlComptime(extname, "js") or strings.eqlComptime(extname, "ts"))) return try ctx.sendNotFound();
},
4 => {
if (!(strings.eqlComptime(extname, "json") or strings.eqlComptime(extname, "yaml"))) return try ctx.sendNotFound();
},
else => {
return try ctx.sendNotFound();
},
}
switch (ctx.method) {
.GET, .HEAD => {
const result = try ctx.buildFile(
ctx.url.path["abs:".len..],
ctx.url.extname,
);
try @call(.{ .modifier = .always_inline }, RequestContext.renderServeResult, .{ ctx, result });
},
else => {
try ctx.sendNotFound();
},
}
}
pub fn handleReservedRoutes(ctx: *RequestContext, server: *Server) !bool {
if (strings.eqlComptime(ctx.url.extname, "bun") and ctx.bundler.options.node_modules_bundle != null) {
try ctx.sendJSB();
@@ -2262,12 +2291,16 @@ pub const RequestContext = struct {
}
const isMaybePrefix = ctx.url.path.len > "bun:".len;
if (isMaybePrefix and strings.eqlComptimeIgnoreLen(ctx.url.path[0.."bun:".len], "bun:")) {
try ctx.handleBunURL(server);
return true;
} else if (isMaybePrefix and strings.eqlComptimeIgnoreLen(ctx.url.path[0.."src:".len], "src:")) {
try ctx.handleSrcURL(server);
return true;
} else if (isMaybePrefix and strings.eqlComptimeIgnoreLen(ctx.url.path[0.."abs:".len], "abs:")) {
try ctx.handleAbsURL(server);
return true;
}
return false;

View File

@@ -650,6 +650,7 @@ pub fn NewLinker(comptime BundlerType: type) type {
dirname,
basename,
absolute_pathname.ext,
source_path,
));
}
},

View File

@@ -1104,7 +1104,14 @@ pub const BundleOptions = struct {
opts.node_modules_bundle = node_module_bundle;
if (opts.origin.isAbsolute()) {
opts.node_modules_bundle_url = try opts.origin.joinAlloc(allocator, "", "", node_module_bundle.bundle.import_from_name, "");
opts.node_modules_bundle_url = try opts.origin.joinAlloc(
allocator,
"",
"",
node_module_bundle.bundle.import_from_name,
"",
"",
);
opts.node_modules_bundle_pretty_path = opts.node_modules_bundle_url[opts.node_modules_bundle_url.len - node_module_bundle.bundle.import_from_name.len - 1 ..];
} else {
opts.node_modules_bundle_pretty_path = try allocator.dupe(u8, pretty_path);