Basis: Certvia dev@a48c5fb als Fundament für Craftvia
Unveränderter Stand von certvia/dev (a48c5fb) plus Craftvia-Spezifikation und Brandbook unter docs/craftvia/. ISMS-Module werden im Folgecommit entfernt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import Link from "next/link";
|
||||
import { prisma } from "@/server/db";
|
||||
import { CertviaLogo } from "@/components/brand/certvia-logo";
|
||||
import { PoweredByGefim } from "@/components/brand/powered-by-gefim";
|
||||
import { ResetPasswordForm } from "@/components/auth-recovery-forms";
|
||||
import { checkInvitationToken } from "@/server/actions/auth-recovery";
|
||||
import { describePasswordPolicy, resolvePasswordPolicy } from "@/lib/password-policy";
|
||||
import { peekToken } from "@/server/auth-token";
|
||||
|
||||
/**
|
||||
* Option C (WS3) — Einlösung eines Einladungs-Links. Die Nutzeranlage erfolgt
|
||||
* ausschließlich per Einladung (goldene Regel 4): der Eingeladene setzt hier sein
|
||||
* Erst-Passwort an der globalen Identity. Der Token wird nur geprüft (nicht
|
||||
* verbraucht) — verbraucht wird er erst beim Absenden.
|
||||
*/
|
||||
export default async function InvitePage({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: Promise<{ token?: string }>;
|
||||
}) {
|
||||
const params = await searchParams;
|
||||
const token = params.token ?? "";
|
||||
const valid = token ? await checkInvitationToken(token) : false;
|
||||
|
||||
let policyHint = describePasswordPolicy(resolvePasswordPolicy(undefined));
|
||||
if (valid) {
|
||||
const resolved = await peekToken(token, "invitation");
|
||||
if (resolved?.tenantId) {
|
||||
const settings = await prisma.tenantSettings.findUnique({
|
||||
where: { tenantId: resolved.tenantId },
|
||||
select: { securityPolicy: true },
|
||||
});
|
||||
policyHint = describePasswordPolicy(resolvePasswordPolicy(settings?.securityPolicy));
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="flex flex-1 items-center justify-center p-6">
|
||||
<div className="shadow-card w-full max-w-sm rounded-2xl border bg-card p-8">
|
||||
<CertviaLogo variant="lockup" theme="dark" height={36} />
|
||||
<p className="mt-5 font-heading text-lg font-semibold">Konto einrichten</p>
|
||||
|
||||
{valid ? (
|
||||
<>
|
||||
<p className="mt-1 text-sm text-muted-foreground">
|
||||
Willkommen! Vergeben Sie ein Passwort für Ihr Konto. Ihre E-Mail-Adresse ist zugleich Ihr Anmeldename.
|
||||
</p>
|
||||
<ResetPasswordForm token={token} domain="tenant" policyHint={policyHint} loginPath="/login" variant="invite" />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p role="alert" className="mt-4 rounded-lg bg-[rgba(255,107,107,0.16)] px-3 py-2 text-sm text-[var(--risk)]">
|
||||
Der Einladungs-Link ist ungültig oder abgelaufen. Bitte wenden Sie sich an Ihre Administration.
|
||||
</p>
|
||||
<Link href="/login" className="mt-4 block text-center text-[13px] font-semibold text-[var(--primary)]">
|
||||
Zur Anmeldung →
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
|
||||
<PoweredByGefim className="mt-7 border-t border-[var(--panel-brd)] pt-4" />
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user