mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-04 02:04:06 +00:00
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
103 lines
2.8 KiB
TypeScript
103 lines
2.8 KiB
TypeScript
import { z } from "zod";
|
|
|
|
import { apiBaseUrl } from "@/lib";
|
|
import { UserMeError } from "@/lib/auth-errors";
|
|
import { PERMISSION_KEY, type RolePermissionAttributes } from "@/types/users";
|
|
|
|
const currentUserDocumentSchema = z.object({
|
|
data: z.object({
|
|
type: z.literal("users"),
|
|
id: z.string().min(1),
|
|
attributes: z.object({
|
|
name: z.string(),
|
|
email: z.string(),
|
|
company_name: z.string().optional(),
|
|
date_joined: z.string().optional(),
|
|
}),
|
|
}),
|
|
included: z.array(
|
|
z.object({
|
|
type: z.literal("roles"),
|
|
id: z.string().min(1),
|
|
attributes: z.record(z.string(), z.unknown()),
|
|
}),
|
|
),
|
|
});
|
|
|
|
export interface CurrentUser {
|
|
name: string;
|
|
email: string;
|
|
company?: string;
|
|
dateJoined?: string;
|
|
permissions: RolePermissionAttributes;
|
|
manageRegistry: true | false | undefined;
|
|
}
|
|
|
|
const toPermissions = (
|
|
roles: readonly Record<string, unknown>[],
|
|
): RolePermissionAttributes =>
|
|
Object.fromEntries(
|
|
Object.values(PERMISSION_KEY).map((key) => [
|
|
key,
|
|
roles.some((attributes) => attributes[key] === true),
|
|
]),
|
|
) as RolePermissionAttributes;
|
|
|
|
export async function fetchCurrentUser(
|
|
accessToken: string,
|
|
options: { signal?: AbortSignal } = {},
|
|
): Promise<CurrentUser> {
|
|
if (!accessToken.trim()) throw new Error("Current user token is required");
|
|
|
|
let response: Response;
|
|
try {
|
|
response = await fetch(`${apiBaseUrl}/users/me?include=roles`, {
|
|
method: "GET",
|
|
cache: "no-store",
|
|
signal: options.signal,
|
|
headers: {
|
|
Accept: "application/vnd.api+json",
|
|
Authorization: `Bearer ${accessToken}`,
|
|
},
|
|
});
|
|
} catch {
|
|
throw new UserMeError("Unable to load user");
|
|
}
|
|
|
|
if (!response.ok) {
|
|
const message =
|
|
response.status === 401
|
|
? "Invalid or expired token"
|
|
: response.status === 403
|
|
? "Access denied"
|
|
: response.status === 404
|
|
? "User not found"
|
|
: "Unable to load user";
|
|
throw new UserMeError(message, response.status);
|
|
}
|
|
|
|
const parsed = currentUserDocumentSchema.safeParse(
|
|
await response.json().catch(() => undefined),
|
|
);
|
|
if (!parsed.success) throw new Error("Malformed current user response");
|
|
|
|
const roles = parsed.data.included.map((role) => role.attributes);
|
|
if (roles.length === 0) {
|
|
throw new Error("Missing current user role");
|
|
}
|
|
|
|
const permissions = toPermissions(roles);
|
|
return {
|
|
name: parsed.data.data.attributes.name,
|
|
email: parsed.data.data.attributes.email,
|
|
company: parsed.data.data.attributes.company_name,
|
|
dateJoined: parsed.data.data.attributes.date_joined,
|
|
permissions,
|
|
manageRegistry: permissions.manage_registry
|
|
? true
|
|
: roles.every((attributes) => attributes.manage_registry === false)
|
|
? false
|
|
: undefined,
|
|
};
|
|
}
|