Add DB constraints for binary identifier lengths
This commit is contained in:
@@ -0,0 +1,46 @@
|
|||||||
|
defmodule Parrhesia.Repo.Migrations.AddBinaryIdentifierLengthConstraints do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
@constraints [
|
||||||
|
{"event_ids", "event_ids_id_length_check", "octet_length(id) = 32"},
|
||||||
|
{"events", "events_id_length_check", "octet_length(id) = 32"},
|
||||||
|
{"events", "events_pubkey_length_check", "octet_length(pubkey) = 32"},
|
||||||
|
{"events", "events_sig_length_check", "octet_length(sig) = 64"},
|
||||||
|
{"event_tags", "event_tags_event_id_length_check", "octet_length(event_id) = 32"},
|
||||||
|
{"replaceable_event_state", "replaceable_event_state_pubkey_length_check",
|
||||||
|
"octet_length(pubkey) = 32"},
|
||||||
|
{"replaceable_event_state", "replaceable_event_state_event_id_length_check",
|
||||||
|
"octet_length(event_id) = 32"},
|
||||||
|
{"addressable_event_state", "addressable_event_state_pubkey_length_check",
|
||||||
|
"octet_length(pubkey) = 32"},
|
||||||
|
{"addressable_event_state", "addressable_event_state_event_id_length_check",
|
||||||
|
"octet_length(event_id) = 32"},
|
||||||
|
{"banned_pubkeys", "banned_pubkeys_pubkey_length_check", "octet_length(pubkey) = 32"},
|
||||||
|
{"allowed_pubkeys", "allowed_pubkeys_pubkey_length_check", "octet_length(pubkey) = 32"},
|
||||||
|
{"banned_events", "banned_events_event_id_length_check", "octet_length(event_id) = 32"},
|
||||||
|
{"group_memberships", "group_memberships_pubkey_length_check", "octet_length(pubkey) = 32"},
|
||||||
|
{"group_roles", "group_roles_pubkey_length_check", "octet_length(pubkey) = 32"},
|
||||||
|
{"management_audit_logs", "management_audit_logs_actor_pubkey_length_check",
|
||||||
|
"actor_pubkey IS NULL OR octet_length(actor_pubkey) = 32"},
|
||||||
|
{"acl_rules", "acl_rules_principal_length_check", "octet_length(principal) = 32"}
|
||||||
|
]
|
||||||
|
|
||||||
|
def up do
|
||||||
|
Enum.each(@constraints, fn {table_name, constraint_name, expression} ->
|
||||||
|
execute("""
|
||||||
|
ALTER TABLE #{table_name}
|
||||||
|
ADD CONSTRAINT #{constraint_name}
|
||||||
|
CHECK (#{expression})
|
||||||
|
""")
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
Enum.each(@constraints, fn {table_name, constraint_name, _expression} ->
|
||||||
|
execute("""
|
||||||
|
ALTER TABLE #{table_name}
|
||||||
|
DROP CONSTRAINT #{constraint_name}
|
||||||
|
""")
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
defmodule Parrhesia.Storage.Adapters.Postgres.BinaryIdentifierConstraintsTest do
|
||||||
|
use Parrhesia.IntegrationCase, async: false, sandbox: true
|
||||||
|
|
||||||
|
alias Parrhesia.Repo
|
||||||
|
|
||||||
|
test "events rejects malformed binary identifier lengths at the database layer" do
|
||||||
|
assert_check_violation(
|
||||||
|
"""
|
||||||
|
INSERT INTO events (created_at, id, pubkey, kind, content, sig, inserted_at, updated_at)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW())
|
||||||
|
""",
|
||||||
|
[
|
||||||
|
1_700_123_456,
|
||||||
|
:binary.copy(<<0x10>>, 31),
|
||||||
|
:binary.copy(<<0x20>>, 32),
|
||||||
|
1,
|
||||||
|
"invalid event id length",
|
||||||
|
:binary.copy(<<0x30>>, 64)
|
||||||
|
],
|
||||||
|
"events_id_length_check"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "management audit logs allow nil actor pubkeys but reject malformed ones" do
|
||||||
|
assert {:ok, %{num_rows: 1}} =
|
||||||
|
Repo.query(
|
||||||
|
"""
|
||||||
|
INSERT INTO management_audit_logs (actor_pubkey, method, params, inserted_at)
|
||||||
|
VALUES ($1, $2, $3, NOW())
|
||||||
|
""",
|
||||||
|
[nil, "ping", %{}]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert_check_violation(
|
||||||
|
"""
|
||||||
|
INSERT INTO management_audit_logs (actor_pubkey, method, params, inserted_at)
|
||||||
|
VALUES ($1, $2, $3, NOW())
|
||||||
|
""",
|
||||||
|
[:binary.copy(<<0x40>>, 31), "ping", %{}],
|
||||||
|
"management_audit_logs_actor_pubkey_length_check"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "acl rules reject malformed principal lengths at the database layer" do
|
||||||
|
assert_check_violation(
|
||||||
|
"""
|
||||||
|
INSERT INTO acl_rules (principal_type, principal, capability, match, inserted_at)
|
||||||
|
VALUES ($1, $2, $3, $4, NOW())
|
||||||
|
""",
|
||||||
|
["pubkey", :binary.copy(<<0x50>>, 31), "sync_read", %{}],
|
||||||
|
"acl_rules_principal_length_check"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp assert_check_violation(sql, params, constraint_name) do
|
||||||
|
assert {:error,
|
||||||
|
%Postgrex.Error{
|
||||||
|
postgres: %{code: :check_violation, constraint: ^constraint_name}
|
||||||
|
}} = Repo.query(sql, params)
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user