38 lines
1.9 KiB
TypeScript
38 lines
1.9 KiB
TypeScript
import { hashIp, lookupCountry } from "~/modules/ipAddress/services/geoip.server";
|
|
import { getClientIPAddress } from "~/utils/server/IpUtils";
|
|
|
|
import { createUserSession as createServerSessionRow, revokeSessionByToken } from "./sessionStore.server";
|
|
|
|
// R-P2a S4b — Bruecke zwischen Cookie-Login und dem serverseitigen Session-Store. Additiv:
|
|
// das Login-Cookie bleibt der primaere Auth-Mechanismus, parallel wird eine UserSession-Zeile
|
|
// gefuehrt, damit Geraeteliste, Revoke und "ueberall abmelden" greifen.
|
|
|
|
export function extractRawClientIp(request: Request): string | null {
|
|
return getClientIPAddress(request.headers)?.toString() ?? null;
|
|
}
|
|
|
|
// AD-22: persistiert KEINE Klartext-IP. Die IP wird gehasht (hashIp, Wiedererkennung "gleiches
|
|
// Geraet") und das Land lokal aufgeloest (lookupCountry; die IP verlaesst die Infra nicht).
|
|
export async function buildSessionDeviceContext(request: Request): Promise<{ ipHash: string | null; userAgent: string | null; approxLocation: string | null }> {
|
|
const rawIp = extractRawClientIp(request);
|
|
const country = rawIp ? await lookupCountry(rawIp) : null;
|
|
return {
|
|
ipHash: rawIp ? hashIp(rawIp) : null,
|
|
userAgent: request.headers.get("user-agent"),
|
|
approxLocation: country?.countryName ?? null,
|
|
};
|
|
}
|
|
|
|
// Beim Login/Signup aufgerufen: legt die Session-Zeile mit (pseudonymisiertem) Geraete-Kontext an und
|
|
// liefert den rohen Token zurueck, der ins Cookie wandert. Best-effort: ein Store-Fehler darf den Login
|
|
// nicht verhindern (Cookie ist Source-of-Truth fuer die Identitaet).
|
|
export async function startServerSession({ request, userId }: { request: Request; userId: string }): Promise<string | null> {
|
|
const context = await buildSessionDeviceContext(request);
|
|
const { rawToken } = await createServerSessionRow({ userId, ...context });
|
|
return rawToken;
|
|
}
|
|
|
|
export async function endServerSession(rawToken: string | undefined | null): Promise<void> {
|
|
await revokeSessionByToken(rawToken);
|
|
}
|