Merge pull request #3721 from Infisical/fix/user-stuck-on-invited

fix invite bug
This commit is contained in:
x032205
2025-06-06 13:43:33 -04:00
committed by GitHub
7 changed files with 28 additions and 32 deletions
@@ -397,7 +397,7 @@ export const authLoginServiceFactory = ({
// Check if the user actually has access to the specified organization. // Check if the user actually has access to the specified organization.
const userOrgs = await orgDAL.findAllOrgsByUserId(user.id); const userOrgs = await orgDAL.findAllOrgsByUserId(user.id);
const hasOrganizationMembership = userOrgs.some((org) => org.id === organizationId); const hasOrganizationMembership = userOrgs.some((org) => org.id === organizationId && org.userStatus !== "invited");
const selectedOrg = await orgDAL.findById(organizationId); const selectedOrg = await orgDAL.findById(organizationId);
if (!hasOrganizationMembership) { if (!hasOrganizationMembership) {
+3 -2
View File
@@ -212,7 +212,7 @@ export const orgDALFactory = (db: TDbClient) => {
// special query // special query
const findAllOrgsByUserId = async ( const findAllOrgsByUserId = async (
userId: string userId: string
): Promise<(TOrganizations & { orgAuthMethod: string; userRole: string })[]> => { ): Promise<(TOrganizations & { orgAuthMethod: string; userRole: string; userStatus: string })[]> => {
try { try {
const org = (await db const org = (await db
.replicaNode()(TableName.OrgMembership) .replicaNode()(TableName.OrgMembership)
@@ -234,6 +234,7 @@ export const orgDALFactory = (db: TDbClient) => {
}) })
.select(selectAllTableCols(TableName.Organization)) .select(selectAllTableCols(TableName.Organization))
.select(db.ref("role").withSchema(TableName.OrgMembership).as("userRole")) .select(db.ref("role").withSchema(TableName.OrgMembership).as("userRole"))
.select(db.ref("status").withSchema(TableName.OrgMembership).as("userStatus"))
.select( .select(
db.raw(` db.raw(`
CASE CASE
@@ -242,7 +243,7 @@ export const orgDALFactory = (db: TDbClient) => {
ELSE '' ELSE ''
END as "orgAuthMethod" END as "orgAuthMethod"
`) `)
)) as (TOrganizations & { orgAuthMethod: string; userRole: string })[]; )) as (TOrganizations & { orgAuthMethod: string; userRole: string; userStatus: string })[];
return org; return org;
} catch (error) { } catch (error) {
+3 -1
View File
@@ -183,7 +183,9 @@ export const orgServiceFactory = ({
* */ * */
const findAllOrganizationOfUser = async (userId: string) => { const findAllOrganizationOfUser = async (userId: string) => {
const orgs = await orgDAL.findAllOrgsByUserId(userId); const orgs = await orgDAL.findAllOrgsByUserId(userId);
return orgs;
// Filter out orgs where the membership object is an invitation
return orgs.filter((org) => org.userStatus !== "invited");
}; };
/* /*
* Get all workspace members * Get all workspace members
@@ -3,7 +3,7 @@ import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { faArrowRight } from "@fortawesome/free-solid-svg-icons"; import { faArrowRight } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Link, useNavigate } from "@tanstack/react-router"; import { Link, useNavigate, useRouter } from "@tanstack/react-router";
import axios from "axios"; import axios from "axios";
import { addSeconds, formatISO } from "date-fns"; import { addSeconds, formatISO } from "date-fns";
import { jwtDecode } from "jwt-decode"; import { jwtDecode } from "jwt-decode";
@@ -51,6 +51,7 @@ export const SelectOrganizationSection = () => {
const [mfaSuccessCallback, setMfaSuccessCallback] = useState<() => void>(() => {}); const [mfaSuccessCallback, setMfaSuccessCallback] = useState<() => void>(() => {});
const router = useRouter();
const queryParams = new URLSearchParams(window.location.search); const queryParams = new URLSearchParams(window.location.search);
const orgId = queryParams.get("org_id"); const orgId = queryParams.get("org_id");
const callbackPort = queryParams.get("callback_port"); const callbackPort = queryParams.get("callback_port");
@@ -118,6 +119,8 @@ export const SelectOrganizationSection = () => {
}) })
.finally(() => setIsInitialOrgCheckLoading(false)); .finally(() => setIsInitialOrgCheckLoading(false));
await router.invalidate();
if (isMfaEnabled) { if (isMfaEnabled) {
SecurityClient.setMfaToken(token); SecurityClient.setMfaToken(token);
if (mfaMethod) { if (mfaMethod) {
@@ -7,7 +7,8 @@ import { SelectOrganizationPage } from "./SelectOrgPage";
export const SelectOrganizationPageQueryParams = z.object({ export const SelectOrganizationPageQueryParams = z.object({
org_id: z.string().optional().catch(""), org_id: z.string().optional().catch(""),
callback_port: z.coerce.number().optional().catch(undefined), callback_port: z.coerce.number().optional().catch(undefined),
is_admin_login: z.boolean().optional().catch(false) is_admin_login: z.boolean().optional().catch(false),
force: z.boolean().optional()
}); });
export const Route = createFileRoute("/_restrict-login-signup/login/select-organization")({ export const Route = createFileRoute("/_restrict-login-signup/login/select-organization")({
@@ -28,8 +28,7 @@ import {
import { MfaMethod } from "@app/hooks/api/auth/types"; import { MfaMethod } from "@app/hooks/api/auth/types";
import { fetchOrganizations } from "@app/hooks/api/organization/queries"; import { fetchOrganizations } from "@app/hooks/api/organization/queries";
import { ProjectType } from "@app/hooks/api/workspace/types"; import { ProjectType } from "@app/hooks/api/workspace/types";
import { isLoggedIn } from "@app/hooks/api/reactQuery";
import { navigateUserToOrg } from "../LoginPage/Login.utils";
// eslint-disable-next-line new-cap // eslint-disable-next-line new-cap
const client = new jsrp.client(); const client = new jsrp.client();
@@ -71,6 +70,8 @@ export const SignupInvitePage = () => {
const { mutateAsync: selectOrganization } = useSelectOrganization(); const { mutateAsync: selectOrganization } = useSelectOrganization();
const loggedIn = isLoggedIn();
// Verifies if the information that the users entered (name, workspace) is there, and if the password matched the criteria. // Verifies if the information that the users entered (name, workspace) is there, and if the password matched the criteria.
const signupErrorCheck = async () => { const signupErrorCheck = async () => {
setIsLoading(true); setIsLoading(true);
@@ -242,29 +243,10 @@ export const SignupInvitePage = () => {
if (response?.token) { if (response?.token) {
SecurityClient.setSignupToken(response.token); SecurityClient.setSignupToken(response.token);
setStep(2); setStep(2);
} else if (loggedIn) {
navigate({ to: "/login/select-organization", search: { force: true } });
} else { } else {
const redirectExistingUser = async () => { navigate({ to: "/login" });
try {
const { token: mfaToken, isMfaEnabled } = await selectOrganization({
organizationId
});
if (isMfaEnabled) {
SecurityClient.setMfaToken(mfaToken);
toggleShowMfa.on();
setMfaSuccessCallback(() => redirectExistingUser);
return;
}
// user will be redirected to dashboard
// if not logged in gets kicked out to login
await navigateUserToOrg(navigate, organizationId);
} catch (err) {
navigate({ to: "/login" });
}
};
await redirectExistingUser();
} }
} }
} catch (err) { } catch (err) {
@@ -15,7 +15,8 @@ import { setAuthToken } from "@app/hooks/api/reactQuery";
import { ProjectType } from "@app/hooks/api/workspace/types"; import { ProjectType } from "@app/hooks/api/workspace/types";
const QueryParamsSchema = z.object({ const QueryParamsSchema = z.object({
callback_port: z.coerce.number().optional().catch(undefined) callback_port: z.coerce.number().optional().catch(undefined),
force: z.boolean().optional()
}); });
export const AuthConsentWrapper = () => { export const AuthConsentWrapper = () => {
@@ -71,7 +72,7 @@ export const AuthConsentWrapper = () => {
export const Route = createFileRoute("/_restrict-login-signup")({ export const Route = createFileRoute("/_restrict-login-signup")({
validateSearch: zodValidator(QueryParamsSchema), validateSearch: zodValidator(QueryParamsSchema),
search: { search: {
middlewares: [stripSearchParams({ callback_port: undefined })] middlewares: [stripSearchParams({ callback_port: undefined, force: undefined })]
}, },
beforeLoad: async ({ context, location, search }) => { beforeLoad: async ({ context, location, search }) => {
if (!context.serverConfig.initialized) { if (!context.serverConfig.initialized) {
@@ -90,6 +91,12 @@ export const Route = createFileRoute("/_restrict-login-signup")({
if (!data) return; if (!data) return;
setAuthToken(data.token); setAuthToken(data.token);
if (location.pathname === "/signupinvite") return;
// Avoid redirect if on select-organization page with force=true
if (location.pathname.endsWith("select-organization") && search?.force === true) return;
// to do cli login // to do cli login
if (search?.callback_port) { if (search?.callback_port) {
if (location.pathname.endsWith("select-organization") || location.pathname.endsWith("login")) if (location.pathname.endsWith("select-organization") || location.pathname.endsWith("login"))