better path validation
This commit is contained in:
parent
2e04ebf470
commit
8ccd8e6586
|
@ -31,26 +31,42 @@ defmodule BallsPDS.Ecto.Schema.Object do
|
|||
:path,
|
||||
:public
|
||||
])
|
||||
|> validate_format(:path, ~r/^[^<>:"\\|\?\*\0]+$/, message: "Invalid characters")
|
||||
|> validate_format(:path, ~r/^\/$|^\/.*[^\/]$/,
|
||||
message: "Must have leading slash but no trailing slash"
|
||||
)
|
||||
|> validate_format(:path, ~r/(?<!\/)\/{1}(?!\/)/, message: "Multiple sequential slashes")
|
||||
|> validate_path(:path)
|
||||
|> validate_format(
|
||||
:content_type,
|
||||
~r/^(application|audio|font|image|message|model|multipart|text|video)\/[\w\-\+\.]+(?:;\s*charset=[\w\-]+)?$/i,
|
||||
allow_nil: true
|
||||
)
|
||||
|> validate_format(:activitypub_type, ~r/[A-Z][a-zA-Z0-9]*/, allow_nil: true)
|
||||
|> validate_format(:storage_key, ~r/^[0-9a-f]{64}$/,
|
||||
|> validate_format(:storage_key, ~r/^[0-9a-f]+$/,
|
||||
allow_nil: true,
|
||||
message: "Invalid 256-bit hexadecimal string"
|
||||
message: "Invalid hexadecimal string"
|
||||
)
|
||||
|> validate_inclusion(:public, [true, false])
|
||||
|> validate_number(:total_items, greater_than: -1, allow_nil: true)
|
||||
|> unique_constraint(:path)
|
||||
end
|
||||
|
||||
defp validate_path(changeset, field) do
|
||||
validate_change(changeset, field, fn _, path ->
|
||||
case BallsPDS.Util.Util.is_valid_path?(path) do
|
||||
:ok -> []
|
||||
|
||||
{:error, :invalid_char} ->
|
||||
[{field, "Invalid characters"}]
|
||||
|
||||
{:error, :trailing_or_no_starting_slash} ->
|
||||
[{field, "Trailing slash, or no starting slash"}]
|
||||
|
||||
{:error, :sequential_slashes} ->
|
||||
[{field, "Sequential slashes"}]
|
||||
|
||||
{:error, :relative_path} ->
|
||||
[{field, "Relative path"}]
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
def get_by_path(path) when is_binary(path) do
|
||||
query =
|
||||
from(o in __MODULE__,
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
defmodule BallsPDS.Util.Util do
|
||||
@valid_path_chars_regex ~r/^[^<>:"\\|\?\*\0\s]+$/
|
||||
@starting_trailing_slashes_regex ~r/^\/$|^\/.*[^\/]$/
|
||||
@sequential_slashes_regex ~r/(?<!\/)\/{1}(?!\/)/
|
||||
@relative_path_regex ~r{^(?!.*(/\./|/\.\./)).*$}
|
||||
|
||||
@doc """
|
||||
A valid path inside the PDS.
|
||||
"""
|
||||
def is_valid_path?(path) when is_binary(path) do
|
||||
with {:invalid_char, false} <- {:invalid_char, Regex.match?(@valid_path_chars_regex, path)},
|
||||
{:trailing_or_no_starting_slash, false} <-
|
||||
{:trailing_or_no_starting_slash, Regex.match?(@starting_trailing_slashes_regex, path)},
|
||||
{:sequential_slashes, false} <-
|
||||
{:sequential_slashes, Regex.match?(@sequential_slashes_regex, path)},
|
||||
{:relative_path, false} <- {:relative_path, Regex.match?(@relative_path_regex, path)} do
|
||||
:ok
|
||||
else
|
||||
{error, _} -> {:error, error}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Every AP ID in an AP object should validate against this function.
|
||||
"""
|
||||
def is_valid_personal_ap_id(id) when is_binary(id) do
|
||||
owner = Application.get_env(:balls_pds, :owner_ap_id)
|
||||
service = Application.get_env(:balls_pds, :did_service)
|
||||
prefix = "#{owner}?service=#{URI.encode(service)}&relativeRef="
|
||||
|
||||
with {:prefix, ^prefix <> relative_ref} <- {:prefix, id},
|
||||
{:decode, relative_ref} <- {:decode, URI.decode(relative_ref)},
|
||||
{:valid, :ok} <- {:valid, is_valid_path?(relative_ref)} do
|
||||
true
|
||||
else
|
||||
_ -> false
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue