Files

213 lines
5.5 KiB
TypeScript

"use server";
import { AuthError } from "next-auth";
import { signIn, signOut } from "@/auth.config";
import { apiBaseUrl } from "@/lib";
import { UserMeError } from "@/lib/auth-errors";
import { addAuthEvent } from "@/lib/sentry-breadcrumbs";
import type { UtmParams } from "@/lib/utm";
import type { SignInFormData, SignUpFormData } from "@/types";
export async function authenticate(
prevState: unknown,
formData: SignInFormData,
) {
try {
addAuthEvent("login", { email: formData.email });
await signIn("credentials", {
...formData,
redirect: false,
});
return {
message: "Success",
};
} catch (error) {
if (error instanceof AuthError) {
addAuthEvent("error", { type: error.type });
switch (error.type) {
case "CredentialsSignin":
return {
message: "Credentials error",
errors: {
credentials: "Invalid email or password",
},
};
case "CallbackRouteError":
return {
message: error.cause?.err?.message,
};
default:
return {
message: "Unknown error",
errors: {
unknown: "Unknown error",
},
};
}
}
}
}
export const createNewUser = async (
formData: SignUpFormData,
attribution: UtmParams = {},
) => {
const url = new URL(`${apiBaseUrl}/users`);
if (formData.invitationToken) {
url.searchParams.append("invitation_token", formData.invitationToken);
}
for (const [key, value] of Object.entries(attribution)) {
url.searchParams.append(key, value);
}
const bodyData = {
data: {
type: "users",
attributes: {
name: formData.name,
email: formData.email,
password: formData.password,
...(formData.company && { company_name: formData.company }),
},
},
};
try {
const response = await fetch(url.toString(), {
method: "POST",
headers: {
"Content-Type": "application/vnd.api+json",
Accept: "application/vnd.api+json",
},
body: JSON.stringify(bodyData),
});
const parsedResponse = await response.json();
if (!response.ok) {
return { ...parsedResponse, status: response.status };
}
return parsedResponse;
} catch (_error) {
return {
errors: [
{
source: { pointer: "" },
detail: "Network error or server is unreachable",
},
],
};
}
};
export const getToken = async (formData: SignInFormData) => {
const url = new URL(`${apiBaseUrl}/tokens`);
const bodyData = {
data: {
type: "tokens",
attributes: {
email: formData.email,
password: formData.password,
},
},
};
try {
const response = await fetch(url.toString(), {
method: "POST",
headers: {
"Content-Type": "application/vnd.api+json",
Accept: "application/vnd.api+json",
},
body: JSON.stringify(bodyData),
});
if (!response.ok) return null;
const parsedResponse = await response.json();
const accessToken = parsedResponse.data.attributes.access;
const refreshToken = parsedResponse.data.attributes.refresh;
return {
accessToken,
refreshToken,
};
} catch (_error) {
throw new Error("Error in trying to get token");
}
};
export const getUserByMe = async (
accessToken: string,
signal?: AbortSignal,
) => {
const url = new URL(`${apiBaseUrl}/users/me?include=roles`);
try {
const response = await fetch(url.toString(), {
method: "GET",
headers: {
Accept: "application/vnd.api+json",
Authorization: `Bearer ${accessToken}`,
},
signal,
});
if (!response.ok) {
const errorMessage =
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(errorMessage, response.status);
}
const parsedResponse = await response.json();
const userRole = parsedResponse.included?.find(
(item: any) => item.type === "roles",
);
const permissions = {
manage_users: userRole.attributes.manage_users || false,
manage_account: userRole.attributes.manage_account || false,
manage_providers: userRole.attributes.manage_providers || false,
manage_scans: userRole.attributes.manage_scans || false,
manage_ingestions: userRole.attributes.manage_ingestions || false,
manage_integrations: userRole.attributes.manage_integrations || false,
manage_billing: userRole.attributes.manage_billing || false,
manage_alerts: userRole.attributes.manage_alerts || false,
manage_lighthouse_ai_configuration:
userRole.attributes.manage_lighthouse_ai_configuration || false,
unlimited_visibility: userRole.attributes.unlimited_visibility || false,
};
return {
name: parsedResponse.data.attributes.name,
email: parsedResponse.data.attributes.email,
company: parsedResponse.data.attributes.company_name,
dateJoined: parsedResponse.data.attributes.date_joined,
permissions,
};
} catch (error: unknown) {
if (error instanceof UserMeError) throw error;
throw new UserMeError(
error instanceof Error
? error.message
: "Network error or server unreachable",
);
}
};
export async function logOut() {
await signOut({ redirectTo: "/sign-in" });
}