signing_key: ensure only one key per user exists
Fixes: AkkomaGang/akkoma issue 858
This commit is contained in:
parent
2a4587f201
commit
ea2de1f28a
2 changed files with 47 additions and 2 deletions
|
@ -201,13 +201,22 @@ def fetch_remote_key(key_id) do
|
|||
{:ok, user} <- User.get_or_fetch_by_ap_id(ap_id) do
|
||||
Logger.debug("Fetched remote key: #{ap_id}")
|
||||
# store the key
|
||||
key = %__MODULE__{
|
||||
key = %{
|
||||
user_id: user.id,
|
||||
public_key: public_key_pem,
|
||||
key_id: key_id
|
||||
}
|
||||
|
||||
Repo.insert(key, on_conflict: :replace_all, conflict_target: :key_id)
|
||||
key_cs =
|
||||
cast(%__MODULE__{}, key, [:user_id, :public_key, :key_id])
|
||||
|> unique_constraint(:user_id)
|
||||
|
||||
Repo.insert(key_cs,
|
||||
# while this should never run for local users anyway, etc make sure we really never loose privkey info!
|
||||
on_conflict: {:replace_all_except, [:inserted_at, :private_key]},
|
||||
# if the key owner overlaps with a distinct existing key entry, this intetionally still errros
|
||||
conflict_target: :key_id
|
||||
)
|
||||
else
|
||||
e ->
|
||||
Logger.debug("Failed to fetch remote key: #{inspect(e)}")
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
defmodule Pleroma.Repo.Migrations.SigningKeyUniqueUserId do
|
||||
use Ecto.Migration
|
||||
|
||||
import Ecto.Query
|
||||
|
||||
def up() do
|
||||
# If dupes exists for any local user we do NOT want to delete the genuine privkey alongside the fake.
|
||||
# Instead just filter out anything pertaining to local users, if dupes exists manual intervention
|
||||
# is required anyway and index creation will just fail later (check against legacy field in users table)
|
||||
dupes =
|
||||
Pleroma.User.SigningKey
|
||||
|> join(:inner, [s], u in Pleroma.User, on: s.user_id == u.id)
|
||||
|> group_by([s], s.user_id)
|
||||
|> having([], count() > 1)
|
||||
|> having([_s, u], not fragment("bool_or(?)", u.local))
|
||||
|> select([s], s.user_id)
|
||||
|
||||
# Delete existing remote duplicates
|
||||
# they’ll be reinserted on the next user update
|
||||
# or proactively fetched when receiving a signature from it
|
||||
Pleroma.User.SigningKey
|
||||
|> where([s], s.user_id in subquery(dupes))
|
||||
|> Pleroma.Repo.delete_all()
|
||||
|
||||
drop_if_exists(index(:signing_keys, [:user_id]))
|
||||
|
||||
create_if_not_exists(
|
||||
index(:signing_keys, [:user_id], name: :signing_keys_user_id_index, unique: true)
|
||||
)
|
||||
end
|
||||
|
||||
def down() do
|
||||
drop_if_exists(index(:signing_keys, [:user_id]))
|
||||
create_if_not_exists(index(:signing_keys, [:user_id], name: :signing_keys_user_id_index))
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue