mirror of
https://github.com/fosrl/pangolin.git
synced 2026-06-27 01:29:14 +00:00
improve org policy error message responses
This commit is contained in:
@@ -12,7 +12,7 @@ import {
|
|||||||
users
|
users
|
||||||
} from "@server/db";
|
} from "@server/db";
|
||||||
import { db } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import { eq, inArray } from "drizzle-orm";
|
import { and, eq, inArray, ne } from "drizzle-orm";
|
||||||
import config from "@server/lib/config";
|
import config from "@server/lib/config";
|
||||||
import type { RandomReader } from "@oslojs/crypto/random";
|
import type { RandomReader } from "@oslojs/crypto/random";
|
||||||
import { generateRandomString } from "@oslojs/crypto/random";
|
import { generateRandomString } from "@oslojs/crypto/random";
|
||||||
@@ -136,6 +136,45 @@ export async function invalidateAllSessions(userId: string): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function invalidateAllSessionsExceptCurrent(
|
||||||
|
userId: string,
|
||||||
|
currentSessionId: string
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
await db.transaction(async (trx) => {
|
||||||
|
const userSessions = await trx
|
||||||
|
.select()
|
||||||
|
.from(sessions)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(sessions.userId, userId),
|
||||||
|
ne(sessions.sessionId, currentSessionId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (userSessions.length > 0) {
|
||||||
|
await trx.delete(resourceSessions).where(
|
||||||
|
inArray(
|
||||||
|
resourceSessions.userSessionId,
|
||||||
|
userSessions.map((s) => s.sessionId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await trx
|
||||||
|
.delete(sessions)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(sessions.userId, userId),
|
||||||
|
ne(sessions.sessionId, currentSessionId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
logger.error("Failed to invalidate user sessions except current", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function serializeSessionCookie(
|
export function serializeSessionCookie(
|
||||||
token: string,
|
token: string,
|
||||||
isSecure: boolean,
|
isSecure: boolean,
|
||||||
|
|||||||
@@ -119,8 +119,7 @@ export async function verifyAccessTokenAccess(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,8 +56,7 @@ export async function verifyAdmin(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,8 +113,7 @@ export async function verifyApiKeyAccess(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,8 +107,7 @@ export async function verifyClientAccess(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -129,10 +128,7 @@ export async function verifyClientAccess(
|
|||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(roleClients.clientId, client.clientId),
|
eq(roleClients.clientId, client.clientId),
|
||||||
inArray(
|
inArray(roleClients.roleId, req.userOrgRoleIds!)
|
||||||
roleClients.roleId,
|
|
||||||
req.userOrgRoleIds!
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.limit(1)
|
.limit(1)
|
||||||
|
|||||||
@@ -88,8 +88,7 @@ export async function verifyDomainAccess(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import HttpCode from "@server/types/HttpCode";
|
|||||||
import { checkOrgAccessPolicy } from "#dynamic/lib/checkOrgAccessPolicy";
|
import { checkOrgAccessPolicy } from "#dynamic/lib/checkOrgAccessPolicy";
|
||||||
import { getUserOrgRoleIds } from "@server/lib/userOrgRoles";
|
import { getUserOrgRoleIds } from "@server/lib/userOrgRoles";
|
||||||
import { getFirstString } from "@server/lib/requestParams";
|
import { getFirstString } from "@server/lib/requestParams";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
|
||||||
export async function verifyOrgAccess(
|
export async function verifyOrgAccess(
|
||||||
req: Request,
|
req: Request,
|
||||||
@@ -54,13 +55,15 @@ export async function verifyOrgAccess(
|
|||||||
userId,
|
userId,
|
||||||
session: req.session
|
session: req.session
|
||||||
});
|
});
|
||||||
|
logger.debug("failed policy check", {
|
||||||
|
policyCheck
|
||||||
|
});
|
||||||
req.orgPolicyAllowed = policyCheck.allowed;
|
req.orgPolicyAllowed = policyCheck.allowed;
|
||||||
if (!policyCheck.allowed || policyCheck.error) {
|
if (!policyCheck.allowed || policyCheck.error) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,8 +105,7 @@ export async function verifyResourceAccess(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,8 +102,7 @@ export async function verifyResourcePolicyAccess(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,8 +132,7 @@ export async function verifyRoleAccess(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,8 +45,7 @@ export async function verifySetResourceClients(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,8 +40,7 @@ export async function verifySetResourceUsers(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,8 +115,7 @@ export async function verifySiteAccess(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,8 +115,7 @@ export async function verifySiteProvisioningKeyAccess(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,8 +103,7 @@ export async function verifySiteResourceAccess(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,8 +122,7 @@ export async function verifyTargetAccess(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,8 +59,7 @@ export async function verifyUserAccess(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (policyCheck.error || "Unknown error")
|
||||||
(policyCheck.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,49 @@ import {
|
|||||||
} from "@server/lib/checkOrgAccessPolicy";
|
} from "@server/lib/checkOrgAccessPolicy";
|
||||||
import { UserType } from "@server/types/UserTypes";
|
import { UserType } from "@server/types/UserTypes";
|
||||||
|
|
||||||
|
function formatMaxSessionLengthRequirement(
|
||||||
|
maxSessionLengthHours: number
|
||||||
|
): string {
|
||||||
|
if (maxSessionLengthHours < 24) {
|
||||||
|
return `This organization requires you to log in every ${maxSessionLengthHours} hours.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxDays = Math.round(maxSessionLengthHours / 24);
|
||||||
|
return `This organization requires you to log in every ${maxDays} days.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildOrgAccessPolicyError(
|
||||||
|
policies: CheckOrgAccessPolicyResult["policies"]
|
||||||
|
): string | undefined {
|
||||||
|
if (!policies) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const errors: string[] = [];
|
||||||
|
|
||||||
|
if (policies.requiredTwoFactor === false) {
|
||||||
|
errors.push(
|
||||||
|
"This organization requires two-factor authentication. Enable two-factor authentication on your account to continue."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (policies.maxSessionLength?.compliant === false) {
|
||||||
|
errors.push(
|
||||||
|
`Your session has expired. ${formatMaxSessionLengthRequirement(
|
||||||
|
policies.maxSessionLength.maxSessionLengthHours
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (policies.passwordAge?.compliant === false) {
|
||||||
|
errors.push(
|
||||||
|
`Your password has expired. This organization requires you to change your password every ${policies.passwordAge.maxPasswordAgeDays} days.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.length > 0 ? errors.join(" ") : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export function enforceResourceSessionLength(
|
export function enforceResourceSessionLength(
|
||||||
resourceSession: ResourceSession,
|
resourceSession: ResourceSession,
|
||||||
org: Org
|
org: Org
|
||||||
@@ -36,13 +79,17 @@ export function enforceResourceSessionLength(
|
|||||||
if (sessionAgeMs > maxSessionLengthMs) {
|
if (sessionAgeMs > maxSessionLengthMs) {
|
||||||
return {
|
return {
|
||||||
valid: false,
|
valid: false,
|
||||||
error: `Resource session has expired due to organization policy (max session length: ${maxSessionLengthHours} hours)`
|
error: `Your resource session has expired. ${formatMaxSessionLengthRequirement(
|
||||||
|
maxSessionLengthHours
|
||||||
|
)}`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
valid: false,
|
valid: false,
|
||||||
error: `Resource session is invalid due to organization policy (max session length: ${maxSessionLengthHours} hours)`
|
error: `Your resource session is invalid. ${formatMaxSessionLengthRequirement(
|
||||||
|
maxSessionLengthHours
|
||||||
|
)}`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,14 +107,20 @@ export async function checkOrgAccessPolicy(
|
|||||||
if (!orgId) {
|
if (!orgId) {
|
||||||
return {
|
return {
|
||||||
allowed: false,
|
allowed: false,
|
||||||
error: "Organization ID is required"
|
error: "Unable to verify organization access. Organization information is missing."
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
return { allowed: false, error: "User ID is required" };
|
return {
|
||||||
|
allowed: false,
|
||||||
|
error: "Unable to verify organization access. User information is missing."
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (!sessionId) {
|
if (!sessionId) {
|
||||||
return { allowed: false, error: "Session ID is required" };
|
return {
|
||||||
|
allowed: false,
|
||||||
|
error: "Your session is invalid. Please log in again."
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (build === "enterprise") {
|
if (build === "enterprise") {
|
||||||
@@ -89,7 +142,10 @@ export async function checkOrgAccessPolicy(
|
|||||||
.where(eq(orgs.orgId, orgId));
|
.where(eq(orgs.orgId, orgId));
|
||||||
props.org = orgQuery;
|
props.org = orgQuery;
|
||||||
if (!props.org) {
|
if (!props.org) {
|
||||||
return { allowed: false, error: "Organization not found" };
|
return {
|
||||||
|
allowed: false,
|
||||||
|
error: "This organization could not be found."
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +156,10 @@ export async function checkOrgAccessPolicy(
|
|||||||
.where(eq(users.userId, userId));
|
.where(eq(users.userId, userId));
|
||||||
props.user = userQuery;
|
props.user = userQuery;
|
||||||
if (!props.user) {
|
if (!props.user) {
|
||||||
return { allowed: false, error: "User not found" };
|
return {
|
||||||
|
allowed: false,
|
||||||
|
error: "Your account could not be found."
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,14 +170,17 @@ export async function checkOrgAccessPolicy(
|
|||||||
.where(eq(sessions.sessionId, sessionId));
|
.where(eq(sessions.sessionId, sessionId));
|
||||||
props.session = sessionQuery;
|
props.session = sessionQuery;
|
||||||
if (!props.session) {
|
if (!props.session) {
|
||||||
return { allowed: false, error: "Session not found" };
|
return {
|
||||||
|
allowed: false,
|
||||||
|
error: "Your session has expired. Please log in again."
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.session.userId !== props.user.userId) {
|
if (props.session.userId !== props.user.userId) {
|
||||||
return {
|
return {
|
||||||
allowed: false,
|
allowed: false,
|
||||||
error: "Session does not belong to the user"
|
error: "Your session is invalid. Please log in again."
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,8 +249,14 @@ export async function checkOrgAccessPolicy(
|
|||||||
allowed = false;
|
allowed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const policyError = buildOrgAccessPolicyError(policies);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
allowed,
|
allowed,
|
||||||
policies
|
policies,
|
||||||
|
error: allowed
|
||||||
|
? undefined
|
||||||
|
: (policyError ??
|
||||||
|
"You do not meet this organization's security requirements.")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,8 @@ import { hashPassword, verifyPassword } from "@server/auth/password";
|
|||||||
import { verifyTotpCode } from "@server/auth/totp";
|
import { verifyTotpCode } from "@server/auth/totp";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { unauthorized } from "@server/auth/unauthorizedResponse";
|
import { unauthorized } from "@server/auth/unauthorizedResponse";
|
||||||
import { invalidateAllSessions } from "@server/auth/sessions/app";
|
import { invalidateAllSessionsExceptCurrent } from "@server/auth/sessions/app";
|
||||||
import { sessions, resourceSessions } from "@server/db";
|
import { eq } from "drizzle-orm";
|
||||||
import { and, eq, ne, inArray } from "drizzle-orm";
|
|
||||||
import { passwordSchema } from "@server/auth/passwordSchema";
|
import { passwordSchema } from "@server/auth/passwordSchema";
|
||||||
import { UserType } from "@server/types/UserTypes";
|
import { UserType } from "@server/types/UserTypes";
|
||||||
import { sendEmail } from "@server/emails";
|
import { sendEmail } from "@server/emails";
|
||||||
@@ -31,48 +30,6 @@ export type ChangePasswordResponse = {
|
|||||||
codeRequested?: boolean;
|
codeRequested?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function invalidateAllSessionsExceptCurrent(
|
|
||||||
userId: string,
|
|
||||||
currentSessionId: string
|
|
||||||
): Promise<void> {
|
|
||||||
try {
|
|
||||||
await db.transaction(async (trx) => {
|
|
||||||
// Get all user sessions except the current one
|
|
||||||
const userSessions = await trx
|
|
||||||
.select()
|
|
||||||
.from(sessions)
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(sessions.userId, userId),
|
|
||||||
ne(sessions.sessionId, currentSessionId)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Delete resource sessions for the sessions we're invalidating
|
|
||||||
if (userSessions.length > 0) {
|
|
||||||
await trx.delete(resourceSessions).where(
|
|
||||||
inArray(
|
|
||||||
resourceSessions.userSessionId,
|
|
||||||
userSessions.map((s) => s.sessionId)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the user sessions (except current)
|
|
||||||
await trx
|
|
||||||
.delete(sessions)
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(sessions.userId, userId),
|
|
||||||
ne(sessions.sessionId, currentSessionId)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
logger.error("Failed to invalidate user sessions except current", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function changePassword(
|
export async function changePassword(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ import TwoFactorAuthNotification from "@server/emails/templates/TwoFactorAuthNot
|
|||||||
import config from "@server/lib/config";
|
import config from "@server/lib/config";
|
||||||
import { UserType } from "@server/types/UserTypes";
|
import { UserType } from "@server/types/UserTypes";
|
||||||
import { generateBackupCodes } from "@server/lib/totp";
|
import { generateBackupCodes } from "@server/lib/totp";
|
||||||
|
import {
|
||||||
|
invalidateAllSessions,
|
||||||
|
invalidateAllSessionsExceptCurrent
|
||||||
|
} from "@server/auth/sessions/app";
|
||||||
import { verifySession } from "@server/auth/sessions/verifySession";
|
import { verifySession } from "@server/auth/sessions/verifySession";
|
||||||
import { unauthorized } from "@server/auth/unauthorizedResponse";
|
import { unauthorized } from "@server/auth/unauthorizedResponse";
|
||||||
|
|
||||||
@@ -168,6 +172,15 @@ export async function verifyTotp(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (existingSession) {
|
||||||
|
await invalidateAllSessionsExceptCurrent(
|
||||||
|
user.userId,
|
||||||
|
existingSession.sessionId
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await invalidateAllSessions(user.userId);
|
||||||
|
}
|
||||||
|
|
||||||
sendEmail(
|
sendEmail(
|
||||||
TwoFactorAuthNotification({
|
TwoFactorAuthNotification({
|
||||||
email: user.email!,
|
email: user.email!,
|
||||||
|
|||||||
@@ -80,8 +80,7 @@ export async function getExchangeToken(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Failed organization access policy check: " +
|
"" + (hasAccess.error || "Unknown error")
|
||||||
(hasAccess.error || "Unknown error")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user