-- Zweiter Faktor per TOTP (RFC 6238). -- -- totp_secret haelt das Base32-Geheimnis. Es steht schon vor der Bestaetigung -- in der Zeile, damit der eingegebene Code dagegen geprueft werden kann; -- scharf ist der zweite Faktor aber erst mit totp_confirmed_at. Wer die -- Einrichtung abbricht, sperrt sich damit nicht aus. -- -- totp_last_step merkt sich den zuletzt eingeloesten Zeitschritt. Ohne das -- liesse sich ein abgefangener Code innerhalb seines Gueltigkeitsfensters -- ein zweites Mal verwenden. ALTER TABLE users ADD COLUMN totp_secret VARCHAR(64) NULL AFTER password_hash, ADD COLUMN totp_confirmed_at DATETIME NULL AFTER totp_secret, ADD COLUMN totp_last_step BIGINT NULL AFTER totp_confirmed_at; -- Wiederherstellungscodes fuer den Fall, dass das Telefon verloren geht. -- Gespeichert wird nur der Hash: im Klartext sind die Codes genau einmal -- sichtbar, direkt nach der Einrichtung. CREATE TABLE IF NOT EXISTS totp_recovery_codes ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, code_hash VARCHAR(255) NOT NULL, used_at DATETIME NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, KEY idx_totp_recovery_codes_user (user_id, used_at), CONSTRAINT fk_totp_recovery_codes_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;