account-security.sql 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637
  1. -- Run after registering the corresponding additive Parse _User fields.
  2. -- Existing accounts deliberately default to no legacy fallback: their password history is unknown.
  3. ALTER TABLE "_User" ADD COLUMN IF NOT EXISTS "legacyPasswordMigrationAllowed" boolean DEFAULT false;
  4. ALTER TABLE "_User" ADD COLUMN IF NOT EXISTS "credentialRevision" integer DEFAULT 0;
  5. ALTER TABLE "_User" ADD COLUMN IF NOT EXISTS "credentialExpectedRevision" integer;
  6. ALTER TABLE "_User" ADD COLUMN IF NOT EXISTS "credentialMigrationAttempt" boolean DEFAULT false;
  7. ALTER TABLE "_User" ADD COLUMN IF NOT EXISTS "passwordResetRequired" boolean DEFAULT false;
  8. CREATE OR REPLACE FUNCTION xs_credential_guard() RETURNS trigger LANGUAGE plpgsql AS $$
  9. BEGIN
  10. IF TG_OP='INSERT' THEN
  11. NEW."legacyPasswordMigrationAllowed":=false; NEW."credentialRevision":=0;
  12. NEW."credentialExpectedRevision":=NULL; NEW."credentialMigrationAttempt":=false;
  13. RETURN NEW;
  14. END IF;
  15. IF NEW."legacyPasswordMigrationAllowed" IS TRUE AND OLD."legacyPasswordMigrationAllowed" IS DISTINCT FROM true AND COALESCE(current_setting('xiaoshu.credential_bootstrap',true),'')<>'on' THEN RAISE EXCEPTION '禁止重新启用旧密码'; END IF;
  16. IF OLD."passwordResetRequired" IS TRUE AND NEW."passwordResetRequired" IS DISTINCT FROM true AND NEW."_hashed_password" IS NOT DISTINCT FROM OLD."_hashed_password" THEN RAISE EXCEPTION '须通过改密解除临时密码状态'; END IF;
  17. IF NEW."credentialRevision" IS DISTINCT FROM OLD."credentialRevision" THEN RAISE EXCEPTION '密码版本由系统维护'; END IF;
  18. IF NEW."_hashed_password" IS DISTINCT FROM OLD."_hashed_password" THEN
  19. IF NEW."credentialExpectedRevision" IS NOT NULL AND NEW."credentialExpectedRevision"<>COALESCE(OLD."credentialRevision",0) THEN RAISE EXCEPTION '密码已更新,请重新登录后重试'; END IF;
  20. IF NEW."credentialMigrationAttempt" IS TRUE AND (OLD."legacyPasswordMigrationAllowed" IS DISTINCT FROM true OR OLD."passwordResetRequired" IS TRUE) THEN RAISE EXCEPTION '旧密码迁移已关闭'; END IF;
  21. NEW."credentialRevision":=COALESCE(OLD."credentialRevision",0)+1;
  22. NEW."legacyPasswordMigrationAllowed":=false;
  23. DELETE FROM "_Session" WHERE "user"=OLD."objectId";
  24. END IF;
  25. NEW."credentialExpectedRevision":=NULL; NEW."credentialMigrationAttempt":=false;
  26. RETURN NEW;
  27. END $$;
  28. DROP TRIGGER IF EXISTS xs_credential_guard_trigger ON "_User";
  29. CREATE TRIGGER xs_credential_guard_trigger BEFORE INSERT OR UPDATE ON "_User" FOR EACH ROW EXECUTE FUNCTION xs_credential_guard();
  30. -- Only the server-side importer calls this immediately after creating a random-password account.
  31. CREATE OR REPLACE FUNCTION xs_enable_initial_legacy_login(co text, uid text) RETURNS void LANGUAGE plpgsql AS $$
  32. BEGIN
  33. PERFORM set_config('xiaoshu.credential_bootstrap','on',true);
  34. UPDATE "_User" SET "legacyPasswordMigrationAllowed"=true WHERE "objectId"=uid AND company=co AND COALESCE("credentialRevision",0)=0 AND "createdAt">now()-interval '2 minutes' AND NOT COALESCE("passwordResetRequired",false);
  35. IF NOT FOUND THEN RAISE EXCEPTION '账号不符合首次迁移条件'; END IF;
  36. PERFORM set_config('xiaoshu.credential_bootstrap','off',true);
  37. END $$;