1.2 KiB · text 5af55d9
defmodule GitGud.Repo.Migrations.CreateUserTwoFactor do
use Ecto.Migration
def change do
alter table(:users) do
# AES-256-GCM components for the user's TOTP secret. NULL across
# the board = no 2FA configured. `totp_enabled_at` only flips
# after the user successfully verifies the *first* TOTP code, so
# a half-enrolled secret never gates login.
add :totp_key_id, :string, size: 40
add :totp_ciphertext, :binary
add :totp_iv, :binary
add :totp_tag, :binary
add :totp_enabled_at, :utc_datetime
end
# Recovery codes — one-shot single-use, hashed at rest. Storing in a
# separate table (rather than a JSONB array on `users`) keeps the
# consume operation a clean DB-level update with no read/modify/write
# race.
create table(:user_recovery_codes) do
add :user_id, references(:users, on_delete: :delete_all), null: false
add :code_hash, :string, null: false
add :used_at, :utc_datetime
timestamps(type: :utc_datetime, updated_at: false)
end
create index(:user_recovery_codes, [:user_id])
create unique_index(:user_recovery_codes, [:code_hash])
end
end