File size: 1,771 Bytes
8da2481 | 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 | defmodule Plausible.Shield.HostnameRule do
@moduledoc """
Schema for Hostnames allow list
"""
use Ecto.Schema
import Ecto.Changeset
@type t() :: %__MODULE__{}
@primary_key {:id, :binary_id, autogenerate: true}
schema "shield_rules_hostname" do
belongs_to :site, Plausible.Site
field :hostname, :string
field :hostname_pattern, Plausible.Ecto.Types.CompiledRegex
field :action, Ecto.Enum, values: [:deny, :allow], default: :allow
field :added_by, :string
# If `from_cache?` is set, the struct might be incomplete - see `Plausible.Site.Shield.Rules.IP.Cache`
field :from_cache?, :boolean, virtual: true, default: false
timestamps()
end
def changeset(rule \\ %__MODULE__{}, attrs) do
rule
|> cast(attrs, [:hostname])
|> validate_required([:hostname])
|> validate_length(:hostname, max: 250)
|> store_regex()
|> unique_constraint(:hostname_pattern,
name: :shield_rules_hostname_site_id_hostname_pattern_index,
error_key: :hostname,
message: "rule already exists"
)
end
defp store_regex(changeset) do
case fetch_change(changeset, :hostname) do
{:ok, hostname} ->
hostname
|> build_regex()
|> verify_and_put_regex(changeset)
:error ->
changeset
end
end
defp build_regex(hostname) do
regex =
hostname
|> Regex.escape()
|> String.replace("\\*\\*", ".*")
|> String.replace("\\*", ".*")
"^#{regex}$"
end
defp verify_and_put_regex(regex, changeset) do
case Regex.compile(regex) do
{:ok, _} ->
put_change(changeset, :hostname_pattern, regex)
{:error, _} ->
add_error(changeset, :hostname, "could not compile regular expression")
end
end
end
|