diff --git a/src/app/(main)/App.tsx b/src/app/(main)/App.tsx index 0323ec052..48e60bd57 100644 --- a/src/app/(main)/App.tsx +++ b/src/app/(main)/App.tsx @@ -22,7 +22,7 @@ export function App({ children }) { const config = useConfig(); const { pathname, router, teamId } = useNavigation(); const { isLoading: isTeamLoading, error: teamError } = useTeamQuery(teamId); - const { data: twoFactorStatus } = useTwoFactorStatusQuery(!!user); + const { data: twoFactorStatus } = useTwoFactorStatusQuery(!!user && !config?.cloudMode); const needsTwoFactorSetup = !!(twoFactorStatus?.isRequired && !twoFactorStatus?.isEnabled); useEffect(() => { diff --git a/src/app/api/2fa/disable/route.ts b/src/app/api/2fa/disable/route.ts index c33a6460a..27e60ca97 100644 --- a/src/app/api/2fa/disable/route.ts +++ b/src/app/api/2fa/disable/route.ts @@ -1,7 +1,7 @@ import { z } from 'zod'; import prisma from '@/lib/prisma'; import { parseRequest } from '@/lib/request'; -import { badRequest, forbidden, json } from '@/lib/response'; +import { badRequest, forbidden, json, notFound } from '@/lib/response'; import { decryptSecret } from '@/lib/two-factor/crypto'; import { checkRateLimit, recordFailedAttempt, resetRateLimit } from '@/lib/two-factor/rate-limit'; import { isOtpReplayed, markOtpUsed } from '@/lib/two-factor/replay-prevention'; @@ -10,6 +10,10 @@ import { checkPassword } from '@/lib/password'; import { getUser } from '@/queries/prisma/user'; export async function POST(request: Request) { + if (process.env.CLOUD_MODE) { + return notFound(); + } + const schema = z.object({ password: z.string(), token: z.string().length(6), diff --git a/src/app/api/2fa/setup/cancel/route.ts b/src/app/api/2fa/setup/cancel/route.ts index 76df6cb68..c2920bb74 100644 --- a/src/app/api/2fa/setup/cancel/route.ts +++ b/src/app/api/2fa/setup/cancel/route.ts @@ -1,8 +1,12 @@ import prisma from '@/lib/prisma'; import { parseRequest } from '@/lib/request'; -import { json } from '@/lib/response'; +import { json, notFound } from '@/lib/response'; export async function POST(request: Request) { + if (process.env.CLOUD_MODE) { + return notFound(); + } + const { auth, error } = await parseRequest(request); if (error) { diff --git a/src/app/api/2fa/setup/confirm/route.ts b/src/app/api/2fa/setup/confirm/route.ts index 1e262d065..ca3a6a6db 100644 --- a/src/app/api/2fa/setup/confirm/route.ts +++ b/src/app/api/2fa/setup/confirm/route.ts @@ -1,7 +1,7 @@ import { z } from 'zod'; import prisma from '@/lib/prisma'; import { parseRequest } from '@/lib/request'; -import { badRequest, json } from '@/lib/response'; +import { badRequest, json, notFound } from '@/lib/response'; import { generateBackupCodes } from '@/lib/two-factor/backup-codes'; import { decryptSecret } from '@/lib/two-factor/crypto'; import { checkRateLimit, recordFailedAttempt, resetRateLimit } from '@/lib/two-factor/rate-limit'; @@ -9,6 +9,10 @@ import { isOtpReplayed, markOtpUsed } from '@/lib/two-factor/replay-prevention'; import { verifyTotp } from '@/lib/two-factor/totp'; export async function POST(request: Request) { + if (process.env.CLOUD_MODE) { + return notFound(); + } + const schema = z.object({ token: z.string().length(6) }); const { auth, body, error } = await parseRequest(request, schema); diff --git a/src/app/api/2fa/setup/initiate/route.ts b/src/app/api/2fa/setup/initiate/route.ts index 00a071674..01288601e 100644 --- a/src/app/api/2fa/setup/initiate/route.ts +++ b/src/app/api/2fa/setup/initiate/route.ts @@ -1,5 +1,5 @@ import { parseRequest } from '@/lib/request'; -import { badRequest, json } from '@/lib/response'; +import { badRequest, json, notFound } from '@/lib/response'; import { encryptSecret } from '@/lib/two-factor/crypto'; import { generateOtpAuthUri, @@ -10,6 +10,10 @@ import prisma from '@/lib/prisma'; import { getUser } from '@/queries/prisma/user'; export async function POST(request: Request) { + if (process.env.CLOUD_MODE) { + return notFound(); + } + const { auth, error } = await parseRequest(request); if (error) { diff --git a/src/app/api/2fa/status/route.ts b/src/app/api/2fa/status/route.ts index 4da943af8..d7dc9a44f 100644 --- a/src/app/api/2fa/status/route.ts +++ b/src/app/api/2fa/status/route.ts @@ -9,6 +9,10 @@ export async function GET(request: Request) { return error(); } + if (process.env.CLOUD_MODE) { + return json({ isEnabled: false, isRequired: false, requiredReason: null }); + } + const userId = auth.user.id; const twoFactor = await prisma.client.twoFactorAuth.findUnique({ where: { userId } }); diff --git a/src/app/api/2fa/verify/route.ts b/src/app/api/2fa/verify/route.ts index 1a1790d94..14f45f7a3 100644 --- a/src/app/api/2fa/verify/route.ts +++ b/src/app/api/2fa/verify/route.ts @@ -5,7 +5,7 @@ import { ROLES } from '@/lib/constants'; import { secret } from '@/lib/crypto'; import { createSecureToken, parseSecureToken } from '@/lib/jwt'; import { parseRequest } from '@/lib/request'; -import { badRequest, json, unauthorized } from '@/lib/response'; +import { badRequest, json, notFound, unauthorized } from '@/lib/response'; import { verifyBackupCode } from '@/lib/two-factor/backup-codes'; import { decryptSecret } from '@/lib/two-factor/crypto'; import { checkRateLimit, recordFailedAttempt, resetRateLimit } from '@/lib/two-factor/rate-limit'; @@ -15,6 +15,10 @@ import { getAllUserTeams, getUser } from '@/queries/prisma'; import redis from '@/lib/redis'; export async function POST(request: Request) { + if (process.env.CLOUD_MODE) { + return notFound(); + } + const schema = z.union([ z.object({ token: z.string().length(6) }).strict(), z.object({ backupCode: z.string().min(1) }).strict(), diff --git a/src/app/api/admin/2fa/global/route.ts b/src/app/api/admin/2fa/global/route.ts index ee9640154..142b89e6e 100644 --- a/src/app/api/admin/2fa/global/route.ts +++ b/src/app/api/admin/2fa/global/route.ts @@ -1,10 +1,14 @@ import { z } from 'zod'; import prisma from '@/lib/prisma'; import { parseRequest } from '@/lib/request'; -import { json, unauthorized } from '@/lib/response'; +import { json, notFound, unauthorized } from '@/lib/response'; import { canEnforceTwoFactorAuthForEveryone } from '@/permissions'; export async function POST(request: Request) { + if (process.env.CLOUD_MODE) { + return notFound(); + } + const schema = z.object({ required: z.boolean() }); const { auth, body, error } = await parseRequest(request, schema); diff --git a/src/app/api/admin/teams/[teamId]/2fa/route.ts b/src/app/api/admin/teams/[teamId]/2fa/route.ts index bc3a66806..58cb2aab1 100644 --- a/src/app/api/admin/teams/[teamId]/2fa/route.ts +++ b/src/app/api/admin/teams/[teamId]/2fa/route.ts @@ -1,10 +1,14 @@ import { z } from 'zod'; import prisma from '@/lib/prisma'; import { parseRequest } from '@/lib/request'; -import { json, unauthorized } from '@/lib/response'; +import { json, notFound, unauthorized } from '@/lib/response'; import { canEnforceTwoFactorAuthForTeam } from '@/permissions'; export async function POST(request: Request, { params }: { params: Promise<{ teamId: string }> }) { + if (process.env.CLOUD_MODE) { + return notFound(); + } + const schema = z.object({ required: z.boolean() }); const { auth, body, error } = await parseRequest(request, schema); diff --git a/src/app/api/admin/users/[userId]/2fa/route.ts b/src/app/api/admin/users/[userId]/2fa/route.ts index b110a9e00..c2565a875 100644 --- a/src/app/api/admin/users/[userId]/2fa/route.ts +++ b/src/app/api/admin/users/[userId]/2fa/route.ts @@ -1,11 +1,15 @@ import { z } from 'zod'; import prisma from '@/lib/prisma'; import { parseRequest } from '@/lib/request'; -import { json, unauthorized } from '@/lib/response'; +import { json, notFound, unauthorized } from '@/lib/response'; import { updateUser } from '@/queries/prisma/user'; import { canEnforceTwoFactorAuthForUser } from '@/permissions'; export async function GET(request: Request, { params }: { params: Promise<{ userId: string }> }) { + if (process.env.CLOUD_MODE) { + return notFound(); + } + const { auth, error } = await parseRequest(request); if (error) { @@ -24,6 +28,10 @@ export async function GET(request: Request, { params }: { params: Promise<{ user } export async function POST(request: Request, { params }: { params: Promise<{ userId: string }> }) { + if (process.env.CLOUD_MODE) { + return notFound(); + } + const schema = z.object({ required: z.boolean() }); const { auth, body, error } = await parseRequest(request, schema); @@ -45,6 +53,10 @@ export async function POST(request: Request, { params }: { params: Promise<{ use } export async function DELETE(request: Request, { params }: { params: Promise<{ userId: string }> }) { + if (process.env.CLOUD_MODE) { + return notFound(); + } + const { auth, error } = await parseRequest(request); if (error) { diff --git a/src/app/api/auth/login/route.ts b/src/app/api/auth/login/route.ts index ca4ada55c..208717f17 100644 --- a/src/app/api/auth/login/route.ts +++ b/src/app/api/auth/login/route.ts @@ -31,9 +31,13 @@ export async function POST(request: Request) { } const { id, role, createdAt } = user; + const cloudMode = !!process.env.CLOUD_MODE; // Check if 2FA is enabled for this user - const twoFactor = await prisma.client.twoFactorAuth.findUnique({ where: { userId: id } }); + const twoFactor = !cloudMode + ? await prisma.client.twoFactorAuth.findUnique({ where: { userId: id } }) + : null; + if (twoFactor?.isEnabled) { const partialToken = createSecureToken({ userId: id, type: 'partial-auth' }, secret(), { expiresIn: '5m',