|
9 | 9 | -include_lib("kernel/include/file.hrl").
|
10 | 10 |
|
11 | 11 | -define(TABLE, elli_static_table).
|
12 |
| - |
| 12 | +-define(NOT_FOUND, {404, [], <<"Not Found">>}). |
13 | 13 |
|
14 | 14 | %% elli_handler callbacks
|
15 | 15 | -export([handle/2, handle_event/3]).
|
@@ -81,15 +81,31 @@ file_info(Filename) ->
|
81 | 81 | {error, Reason} -> throw(Reason)
|
82 | 82 | end.
|
83 | 83 |
|
84 |
| - |
85 | 84 | maybe_file(Req, Prefix, Dir) ->
|
| 85 | + %% all paths start with a slash which `safe_relative_path/1' interprets as |
| 86 | + %% unsafe (absolute path), so temporarily remove it |
| 87 | + <<"/", RawPath/binary>> = elli_request:raw_path(Req), |
| 88 | + |
| 89 | + %% santize the path ensuring the request doesn't access any parent |
| 90 | + %% directories ... and reattach the slash if deemed safe |
| 91 | + SafePath = case filename:safe_relative_path(RawPath) of |
| 92 | + unsafe -> |
| 93 | + throw(?NOT_FOUND); |
| 94 | + %% return type quirk work around |
| 95 | + [] -> |
| 96 | + <<"/">>; |
| 97 | + Sanitized -> |
| 98 | + <<"/", Sanitized/binary>> |
| 99 | + end, |
| 100 | + |
86 | 101 | Size = byte_size(Prefix),
|
87 |
| - case elli_request:raw_path(Req) of |
| 102 | + case SafePath of |
| 103 | + %% ensure that `SafePath' starts with the correct prefix |
88 | 104 | <<Prefix:Size/binary,"/",Path/binary>> ->
|
89 | 105 | Filename = filename:join(Dir, Path),
|
90 | 106 | case filelib:is_regular(Filename) of
|
91 | 107 | true -> {just, Filename};
|
92 |
| - false -> throw({404, [], <<"Not Found">>}) |
| 108 | + false -> throw(?NOT_FOUND) |
93 | 109 | end;
|
94 | 110 | _ ->
|
95 | 111 | nothing
|
|
0 commit comments