Skip to content

Commit

Permalink
doing a double check for authenticated users, to make sure the curren…
Browse files Browse the repository at this point in the history
…tUser's email is the same as the email of the invited user.
  • Loading branch information
DonKoko committed Mar 18, 2024
1 parent bf823b0 commit 7d6a9dc
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 71 deletions.
40 changes: 40 additions & 0 deletions app/modules/invite/service.server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { Invite, TeamMember } from "@prisma/client";
import { InviteStatuses } from "@prisma/client";
import type { AppLoadContext } from "@remix-run/node";
import type { Params } from "@remix-run/react";
import jwt from "jsonwebtoken";
import { db } from "~/database";
import { invitationTemplateString } from "~/emails/invite-template";
Expand Down Expand Up @@ -231,3 +233,41 @@ export async function updateInviteStatus({
});
return updatedInvite;
}

/**
* Checks if the user is already signed in and if the invite is for the same user
*/
export async function checkUserAndInviteMatch({
context,
params,
}: {
context: AppLoadContext;
params: Params<string>;
}) {
const authSession = context.getSession();
const { userId } = authSession;
/** We get the user, selecting only the email */
const user = await db.user.findFirst({
where: {
id: userId,
},
select: {
email: true,
},
});

/** We get the invite based on the id of the params */
const inv = await db.invite.findFirst({
where: {
id: params.inviteId,
},
});

if (user?.email !== inv?.inviteeEmail) {
throw new ShelfStackError({
title: "Wrong user",
message:
"Your user's email doesn't match with the invited user so you cannot accept the invite. If you already have a user, make sure that you are logged in with the correct user. If the issue persists, feel free to contact support.",
});
}
}
142 changes: 71 additions & 71 deletions app/routes/_auth+/accept-invite.$inviteId.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,95 +4,95 @@ import { json, redirect } from "@remix-run/node";
import jwt from "jsonwebtoken";
import { Spinner } from "~/components/shared/spinner";
import { signInWithEmail } from "~/modules/auth";
import { updateInviteStatus } from "~/modules/invite";
import { checkUserAndInviteMatch, updateInviteStatus } from "~/modules/invite";
import { generateRandomCode } from "~/modules/invite/helpers";
import { setSelectedOrganizationIdCookie } from "~/modules/organization/context.server";
import { INVITE_TOKEN_SECRET, safeRedirect } from "~/utils";
import { setCookie } from "~/utils/cookies.server";
import { ShelfStackError } from "~/utils/error";

export const loader = async ({ context, request }: LoaderFunctionArgs) => {
// if (context.isAuthenticated) return redirect("/assets");
try {
const searchParams = new URL(decodeURIComponent(request.url)).searchParams;
const token = searchParams.get("token") as string;
export const loader = async ({
context,
request,
params,
}: LoaderFunctionArgs) => {
/** Here we have to do a check based on the session of the current user
* If the user is already signed in, we have to make sure the invite sent, is for the same user
*/
if (context.isAuthenticated) {
await checkUserAndInviteMatch({ context, params });
}

if (!token) {
throw new ShelfStackError({
message:
"The invitation link doesn't have a token provided. Please try clicking the link in your email again or request a new invite. If the issue persists, feel free to contact support",
});
}
const decodedInvite = jwt.verify(token, INVITE_TOKEN_SECRET) as {
id: string;
};
const searchParams = new URL(decodeURIComponent(request.url)).searchParams;
const token = searchParams.get("token") as string;

const password = generateRandomCode(10);
const updatedInvite = await updateInviteStatus({
id: decodedInvite.id,
status: InviteStatuses.ACCEPTED,
password,
if (!token) {
throw new ShelfStackError({
message:
"The invitation link doesn't have a token provided. Please try clicking the link in your email again or request a new invite. If the issue persists, feel free to contact support",
});
}
const decodedInvite = jwt.verify(token, INVITE_TOKEN_SECRET) as {
id: string;
};

if (updatedInvite?.status !== InviteStatuses.ACCEPTED) {
throw new ShelfStackError({
message:
"Something went wrong with updating your invite. Please try again",
});
}
const password = generateRandomCode(10);
const updatedInvite = await updateInviteStatus({
id: decodedInvite.id,
status: InviteStatuses.ACCEPTED,
password,
});

if (updatedInvite?.status !== InviteStatuses.ACCEPTED) {
throw new ShelfStackError({
message:
"Something went wrong with updating your invite. Please try again",
});
}

/** If the user is already signed in, we jus redirect them to assets index and set */
if (context.isAuthenticated) {
return redirect(safeRedirect(`/assets`), {
headers: [
setCookie(
await setSelectedOrganizationIdCookie(updatedInvite.organizationId)
),
],
});
}

/** If the user is already signed in, we jus redirect them to assets index and set */
if (context.isAuthenticated) {
return redirect(safeRedirect(`/assets`), {
/** Sign in the user */
const signInResult = await signInWithEmail(
updatedInvite.inviteeEmail,
password
);
/**
* User could already be registered and hence loggin in with our password failed,
* redirect to home and let user login or go to home */
if (signInResult.status === "error") {
return redirect("/login?acceptedInvite=yes");
}

// Ensure that user property exists before proceeding
if (signInResult.status === "success" && signInResult.authSession) {
const { authSession } = signInResult;
// Commit the session
context.setSession({ ...authSession });
return redirect(
safeRedirect(
`/onboarding?organizationId=${updatedInvite.organizationId}`
),
{
headers: [
setCookie(
await setSelectedOrganizationIdCookie(updatedInvite.organizationId)
),
],
});
}

/** Sign in the user */
const signInResult = await signInWithEmail(
updatedInvite.inviteeEmail,
password
}
);
/**
* User could already be registered and hence loggin in with our password failed,
* redirect to home and let user login or go to home */
if (signInResult.status === "error") {
return redirect("/login?acceptedInvite=yes");
}

// Ensure that user property exists before proceeding
if (signInResult.status === "success" && signInResult.authSession) {
const { authSession } = signInResult;
// Commit the session
context.setSession({ ...authSession });
return redirect(
safeRedirect(
`/onboarding?organizationId=${updatedInvite.organizationId}`
),
{
headers: [
setCookie(
await setSelectedOrganizationIdCookie(
updatedInvite.organizationId
)
),
],
}
);
}

return json({ title: "Accept team invite" });
} catch (cause: unknown) {
throw new ShelfStackError({
cause,
// @ts-expect-error will be solved when we improve error handling
message: cause?.message || "Failed to accept invite",
});
}

return json({ title: "Accept team invite" });
};

export default function AcceptInvite() {
Expand Down

0 comments on commit 7d6a9dc

Please sign in to comment.