106 lines
3.4 KiB
TypeScript
106 lines
3.4 KiB
TypeScript
import type { AuthSession, AuthUser } from "@/lib/auth/session";
|
|
import type { PlatformRole } from "@/lib/types";
|
|
|
|
export type PlatformAuthorizationAccount = {
|
|
id: string;
|
|
phone: string;
|
|
displayName: string;
|
|
role: string;
|
|
organizationId?: string;
|
|
status: string;
|
|
sessionVersion: number;
|
|
};
|
|
|
|
export type PlatformAuthorizationOrganization = {
|
|
id: string;
|
|
name: string;
|
|
status: string;
|
|
};
|
|
|
|
export type PlatformAuthorizationSnapshot = {
|
|
account: PlatformAuthorizationAccount;
|
|
organization: PlatformAuthorizationOrganization | null;
|
|
};
|
|
|
|
export type PlatformSessionAuthorizationResult =
|
|
| { outcome: "authenticated"; session: AuthSession }
|
|
| { outcome: "unauthenticated"; reason: PlatformSessionRejectionReason };
|
|
|
|
export type PlatformSessionRejectionReason =
|
|
| "client_mismatch"
|
|
| "account_not_found"
|
|
| "account_disabled"
|
|
| "invalid_role"
|
|
| "session_version_mismatch"
|
|
| "organization_required"
|
|
| "organization_not_active";
|
|
|
|
export type PlatformAuthorizationLoader = (
|
|
accountId: string,
|
|
) => PlatformAuthorizationSnapshot | null | Promise<PlatformAuthorizationSnapshot | null>;
|
|
|
|
export async function authorizePlatformSession(
|
|
session: AuthSession,
|
|
loadSnapshot: PlatformAuthorizationLoader,
|
|
requiredClientId = "platform",
|
|
): Promise<PlatformSessionAuthorizationResult> {
|
|
if (session.user.clientId !== requiredClientId) {
|
|
return { outcome: "unauthenticated", reason: "client_mismatch" };
|
|
}
|
|
|
|
const snapshot = await loadSnapshot(session.user.id);
|
|
if (!snapshot) return { outcome: "unauthenticated", reason: "account_not_found" };
|
|
|
|
const { account, organization } = snapshot;
|
|
if (account.status !== "active") {
|
|
return { outcome: "unauthenticated", reason: "account_disabled" };
|
|
}
|
|
if (session.sessionVersion && session.sessionVersion !== account.sessionVersion) {
|
|
return { outcome: "unauthenticated", reason: "session_version_mismatch" };
|
|
}
|
|
if (!isPlatformRole(account.role)) {
|
|
return { outcome: "unauthenticated", reason: "invalid_role" };
|
|
}
|
|
if (account.role !== "super_admin") {
|
|
if (!account.organizationId) {
|
|
return { outcome: "unauthenticated", reason: "organization_required" };
|
|
}
|
|
if (!organization || organization.id !== account.organizationId || organization.status !== "active") {
|
|
return { outcome: "unauthenticated", reason: "organization_not_active" };
|
|
}
|
|
}
|
|
|
|
return {
|
|
outcome: "authenticated",
|
|
session: {
|
|
...session,
|
|
authMode: account.role === "user" ? "user" : "admin",
|
|
sessionVersion: account.sessionVersion,
|
|
user: {
|
|
id: account.id,
|
|
subject: account.id,
|
|
username: account.phone,
|
|
phone: account.phone,
|
|
displayName: account.displayName,
|
|
clientId: requiredClientId,
|
|
organizationId: account.organizationId,
|
|
organizationName: organization?.name,
|
|
role: account.role,
|
|
status: "active",
|
|
authorities: authoritiesForRole(account.role),
|
|
scope: [],
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
function isPlatformRole(role: string): role is PlatformRole {
|
|
return role === "user" || role === "organization_admin" || role === "super_admin";
|
|
}
|
|
|
|
function authoritiesForRole(role: PlatformRole): AuthUser["authorities"] {
|
|
if (role === "super_admin") return ["ROLE_SUPER_ADMIN", "SUPER_ADMIN"];
|
|
if (role === "organization_admin") return ["ROLE_ORGANIZATION_ADMIN", "ORGANIZATION_ADMIN"];
|
|
return ["ROLE_USER"];
|
|
}
|