2022-02-10 10:44:44 +01:00
|
|
|
import bcrypt from "bcryptjs";
|
|
|
|
|
import { createCookieSessionStorage, redirect } from "remix";
|
|
|
|
|
import { db } from "./db.server";
|
|
|
|
|
|
|
|
|
|
type LoginForm = {
|
|
|
|
|
username: string;
|
|
|
|
|
password: string;
|
2022-02-13 21:25:00 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
type RegisterForm = {
|
|
|
|
|
username: string;
|
|
|
|
|
password: string;
|
|
|
|
|
icon: string;
|
2022-02-10 10:44:44 +01:00
|
|
|
teamId: string;
|
|
|
|
|
};
|
|
|
|
|
|
2022-02-14 17:05:17 +01:00
|
|
|
type UpdateUserForm = {
|
|
|
|
|
id: string;
|
|
|
|
|
password?: string;
|
|
|
|
|
icon?: string;
|
|
|
|
|
teamId?: string;
|
|
|
|
|
};
|
|
|
|
|
|
2022-02-10 10:44:44 +01:00
|
|
|
export async function register({
|
|
|
|
|
username,
|
|
|
|
|
password,
|
|
|
|
|
icon,
|
|
|
|
|
teamId,
|
2022-02-13 21:25:00 +01:00
|
|
|
}: RegisterForm) {
|
2022-02-10 10:44:44 +01:00
|
|
|
const passwordHash = await bcrypt.hash(password, 10);
|
|
|
|
|
const team = await db.team.findUnique({ where: { id: teamId } });
|
|
|
|
|
if (!team) {
|
|
|
|
|
await db.team.create({
|
|
|
|
|
data: {
|
|
|
|
|
id: teamId,
|
|
|
|
|
icon: teamId[0],
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
const user = await db.user.create({
|
|
|
|
|
data: { username, passwordHash, icon: icon ?? username[0], teamId },
|
|
|
|
|
});
|
|
|
|
|
return user;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-14 17:05:17 +01:00
|
|
|
export async function updateUser({ id, ...data }: UpdateUserForm) {
|
|
|
|
|
if (data.teamId) {
|
|
|
|
|
const team = await db.team.findUnique({ where: { id: data.teamId } });
|
|
|
|
|
if (!team) {
|
|
|
|
|
await db.team.create({
|
|
|
|
|
data: {
|
|
|
|
|
id: data.teamId,
|
|
|
|
|
icon: data.teamId[0],
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const passwordHash = await bcrypt.hash(data.password ?? "", 10);
|
|
|
|
|
const user = await db.user.update({
|
|
|
|
|
data: {
|
|
|
|
|
...(data?.icon ? { icon: data.icon } : {}),
|
|
|
|
|
...(data?.password ? { passwordHash } : {}),
|
|
|
|
|
...(data?.teamId ? { teamId: data.teamId } : {}),
|
|
|
|
|
},
|
|
|
|
|
where: { id },
|
|
|
|
|
});
|
|
|
|
|
return user;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-10 10:44:44 +01:00
|
|
|
export async function login({ username, password }: LoginForm) {
|
|
|
|
|
const user = await db.user.findUnique({
|
|
|
|
|
where: { username },
|
|
|
|
|
});
|
|
|
|
|
if (!user) return null;
|
|
|
|
|
const isCorrectPassword = await bcrypt.compare(password, user.passwordHash);
|
|
|
|
|
if (!isCorrectPassword) return null;
|
|
|
|
|
return user;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const sessionSecret = process.env.SESSION_SECRET;
|
|
|
|
|
if (!sessionSecret) {
|
|
|
|
|
throw new Error("SESSION_SECRET must be set");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const storage = createCookieSessionStorage({
|
|
|
|
|
cookie: {
|
|
|
|
|
name: "RJ_session",
|
|
|
|
|
// normally you want this to be `secure: true`
|
|
|
|
|
// but that doesn't work on localhost for Safari
|
|
|
|
|
// https://web.dev/when-to-use-local-https/
|
|
|
|
|
secure: process.env.NODE_ENV === "production",
|
|
|
|
|
secrets: [sessionSecret],
|
|
|
|
|
sameSite: "lax",
|
|
|
|
|
path: "/",
|
|
|
|
|
maxAge: 60 * 60 * 24 * 30,
|
|
|
|
|
httpOnly: true,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export function getUserSession(request: Request) {
|
|
|
|
|
return storage.getSession(request.headers.get("Cookie"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function getUserId(request: Request) {
|
|
|
|
|
const session = await getUserSession(request);
|
|
|
|
|
const userId = session.get("userId");
|
|
|
|
|
if (!userId || typeof userId !== "string") return null;
|
|
|
|
|
return userId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function requireUserId(
|
|
|
|
|
request: Request,
|
|
|
|
|
redirectTo: string = new URL(request.url).pathname
|
|
|
|
|
) {
|
|
|
|
|
const session = await getUserSession(request);
|
|
|
|
|
const userId = session.get("userId");
|
|
|
|
|
if (!userId || typeof userId !== "string") {
|
|
|
|
|
const searchParams = new URLSearchParams([["redirectTo", redirectTo]]);
|
|
|
|
|
throw redirect(`/login?${searchParams}`);
|
|
|
|
|
}
|
|
|
|
|
return userId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function getUser(request: Request) {
|
|
|
|
|
const userId = await getUserId(request);
|
|
|
|
|
if (typeof userId !== "string") {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const user = await db.user.findUnique({
|
|
|
|
|
where: { id: userId },
|
2022-02-13 21:25:00 +01:00
|
|
|
include: {
|
|
|
|
|
team: {
|
|
|
|
|
include: {
|
|
|
|
|
members: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
2022-02-10 10:44:44 +01:00
|
|
|
});
|
|
|
|
|
return user;
|
|
|
|
|
} catch {
|
|
|
|
|
throw logout(request);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-14 14:30:42 +01:00
|
|
|
export async function getUsersByTeam(request: Request) {
|
|
|
|
|
const user = await getUser(request);
|
|
|
|
|
if (!user) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const users = await db.user.findMany({
|
|
|
|
|
where: { teamId: user.teamId },
|
|
|
|
|
});
|
|
|
|
|
return users;
|
|
|
|
|
} catch {
|
|
|
|
|
throw logout(request);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-10 10:44:44 +01:00
|
|
|
export async function logout(request: Request) {
|
|
|
|
|
const session = await storage.getSession(request.headers.get("Cookie"));
|
2022-02-13 21:25:00 +01:00
|
|
|
return redirect("/", {
|
2022-02-10 10:44:44 +01:00
|
|
|
headers: {
|
|
|
|
|
"Set-Cookie": await storage.destroySession(session),
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function createUserSession(userId: string, redirectTo: string) {
|
|
|
|
|
const session = await storage.getSession();
|
|
|
|
|
session.set("userId", userId);
|
|
|
|
|
return redirect(redirectTo, {
|
|
|
|
|
headers: {
|
|
|
|
|
"Set-Cookie": await storage.commitSession(session),
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|