factor out dangerous request checking logic

This commit is contained in:
Eric S. Londres 2022-08-20 11:02:35 -04:00
parent 2d8bb2c5da
commit 41167b128f
Signed by: slondr
GPG Key ID: A2D25B4D5CB970E4
2 changed files with 21 additions and 20 deletions

View File

@ -20,6 +20,12 @@ defmodule Egalaxyd.FileRetrieval do
"""
defp normalized_path(path) do
# Make sure the path is an absolute path to a file in the current working directory
if request_references_forbidden_secrets?(path) || request_attempts_to_escape?(path) do
Logger.notice("Client sent dangerous query")
{:error, :bad_request}
end
# TODO: Adjust file base path via config option
prefixed_path = if String.starts_with?(path, File.cwd!), do: path, else: (File.cwd! <> path)
@ -35,4 +41,18 @@ defmodule Egalaxyd.FileRetrieval do
{:ok, prefixed_path}
end
end
@doc "Check request to ensure secrets are not requests, if the setting is enabled"
defp request_references_forbidden_secrets?(path) do
keyfile = ConfigSentinel.getopt(:keyfile)
certfile = ConfigSentinel.getopt(:certfile)
(not ConfigSentinel.getopt(:allow_secrets)) && ((String.match?(path, ~r/#{keyfile}/)) || (String.match?(path, ~r/#{certfile}/)))
end
@doc "Check request to ensure directory traversal is not attempted, if the setting is enabled"
defp request_attempts_to_escape?(path) do
(not ConfigSentinel.getopt(:allow_updir)) && String.match?(path, ~r/\.\./)
end
end

View File

@ -54,14 +54,6 @@ defmodule Geminex.RequestParser do
req.scheme != "gemini" || (req.port != 1965 && req.port != nil) ->
# TODO: use the config option here
response("53 protocol refused\r\n") # this is a gemini server!
request_references_forbidden_secrets?(req.path) ->
# Settings disallow requesting secrets and the path seems to reference them
Logger.notice("Client requested forbidden secret")
response("59 bad request\r\n")
request_attempts_to_escape?(req.path) ->
# Settings disallow directory backtracking and the request path seems to attempt this
Logger.notice("Client requested directory backtrack")
response("59 bad request\r\n")
true ->
# todo: mime typing
case retrieve_file_contents(req.path) do
@ -93,23 +85,12 @@ defmodule Geminex.RequestParser do
Logger.info("Response: #{resp}")
{:reply, resp, []}
end
@doc "Check request to ensure secrets are not requests, if the setting is enabled"
defp request_references_forbidden_secrets?(path) do
keyfile = ConfigSentinel.getopt(:keyfile)
certfile = ConfigSentinel.getopt(:certfile)
(not ConfigSentinel.getopt(:allow_secrets)) && ((String.match?(path, ~r/#{keyfile}/)) || (String.match?(path, ~r/#{certfile}/)))
end
@doc "Check request to ensure directory traversal is not attempted, if the setting is enabled"
defp request_attempts_to_escape?(path) do
(not ConfigSentinel.getopt(:allow_updir)) && String.match?(path, ~r/\.\./)
end
defp retrieve_file_contents(path) do
case Egalaxyd.FileRetrieval.retrieve_file_contents(path) do
{:error, :enoent} -> {:error, "51 not found\r\n"}
{:error, :enametoolong} -> {:error, "59 bad request: Request too long\r\n"}
{:error, :bad_request} -> {:error, "59 bad request"}
{:error, other_error} ->
Logger.error other_error
{:error, "50 internal server error\r\n"}