Skip to content

Commit

Permalink
Merge pull request #852 from Shelf-nu/improvements-to-invite-accepting
Browse files Browse the repository at this point in the history
doing a double check for authenticated users, to make sure the curren…
  • Loading branch information
DonKoko authored Mar 18, 2024
2 parents bf823b0 + 7d6a9dc commit 0fa66bd
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 0fa66bd

Please sign in to comment.