Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 3.8k
fix(credentials): credential dependent endpoints#3309
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
e74a04af494475032df8b16d64127086b63877e84aFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -6,7 +6,7 @@ import { type NextRequest, NextResponse } from 'next/server' | ||
| import { getSession } from '@/lib/auth' | ||
| import { validateEnum, validatePathSegment } from '@/lib/core/security/input-validation' | ||
| import { generateRequestId } from '@/lib/core/utils/request' | ||
| import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils' | ||
| import { refreshAccessTokenIfNeeded, resolveOAuthAccountId } from '@/app/api/auth/oauth/utils' | ||
| export const dynamic = 'force-dynamic' | ||
| @@ -57,24 +57,41 @@ export async function GET(request: NextRequest) { | ||
| return NextResponse.json({ error: itemIdValidation.error }, { status: 400 }) | ||
| } | ||
| const credentials = await db.select().from(account).where(eq(account.id, credentialId)).limit(1) | ||
| const resolved = await resolveOAuthAccountId(credentialId) | ||
| if (!resolved) { | ||
| return NextResponse.json({ error: 'Credential not found' }, { status: 404 }) | ||
| } | ||
| if (resolved.workspaceId) { | ||
| const { getUserEntityPermissions } = await import('@/lib/workspaces/permissions/utils') | ||
| const perm = await getUserEntityPermissions( | ||
| session.user.id, | ||
| 'workspace', | ||
| resolved.workspaceId | ||
| ) | ||
| if (perm === null) { | ||
| return NextResponse.json({ error: 'Forbidden' }, { status: 403 }) | ||
| } | ||
| } | ||
| const credentials = await db | ||
| .select() | ||
| .from(account) | ||
| .where(eq(account.id, resolved.accountId)) | ||
| .limit(1) | ||
| if (!credentials.length) { | ||
| logger.warn(`[${requestId}] Credential not found`, { credentialId }) | ||
| return NextResponse.json({ error: 'Credential not found' }, { status: 404 }) | ||
| } | ||
| const credential = credentials[0] | ||
| const accountRow = credentials[0] | ||
| if (credential.userId !== session.user.id) { | ||
| logger.warn(`[${requestId}] Unauthorized credential access attempt`, { | ||
| credentialUserId: credential.userId, | ||
| requestUserId: session.user.id, | ||
| }) | ||
| return NextResponse.json({ error: 'Unauthorized' }, { status: 403 }) | ||
| } | ||
| const accessToken = await refreshAccessTokenIfNeeded(credentialId, session.user.id, requestId) | ||
icecrasher321 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| const accessToken = await refreshAccessTokenIfNeeded( | ||
| resolved.accountId, | ||
| accountRow.userId, | ||
| requestId | ||
| ) | ||
| if (!accessToken) { | ||
| logger.error(`[${requestId}] Failed to obtain valid access token`) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,12 @@ | ||
| import { db } from '@sim/db' | ||
| import { account } from '@sim/db/schema' | ||
| import { createLogger } from '@sim/logger' | ||
| import { and, eq } from 'drizzle-orm' | ||
| import { eq } from 'drizzle-orm' | ||
| import { type NextRequest, NextResponse } from 'next/server' | ||
| import { getSession } from '@/lib/auth' | ||
| import { validateAlphanumericId } from '@/lib/core/security/input-validation' | ||
| import { generateRequestId } from '@/lib/core/utils/request' | ||
| import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils' | ||
| import { refreshAccessTokenIfNeeded, resolveOAuthAccountId } from '@/app/api/auth/oauth/utils' | ||
| export const dynamic = 'force-dynamic' | ||
| @@ -41,24 +41,45 @@ export async function GET(request: NextRequest) { | ||
| return NextResponse.json({ error: labelIdValidation.error }, { status: 400 }) | ||
| } | ||
| const resolved = await resolveOAuthAccountId(credentialId) | ||
| if (!resolved) { | ||
| return NextResponse.json({ error: 'Credential not found' }, { status: 404 }) | ||
| } | ||
| if (resolved.workspaceId) { | ||
| const { getUserEntityPermissions } = await import('@/lib/workspaces/permissions/utils') | ||
| const perm = await getUserEntityPermissions( | ||
| session.user.id, | ||
| 'workspace', | ||
| resolved.workspaceId | ||
| ) | ||
| if (perm === null) { | ||
| return NextResponse.json({ error: 'Forbidden' }, { status: 403 }) | ||
| } | ||
| } | ||
icecrasher321 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| const credentials = await db | ||
| .select() | ||
| .from(account) | ||
| .where(and(eq(account.id, credentialId), eq(account.userId, session.user.id))) | ||
| .where(eq(account.id, resolved.accountId)) | ||
| .limit(1) | ||
| if (!credentials.length) { | ||
| logger.warn(`[${requestId}] Credential not found`) | ||
| return NextResponse.json({ error: 'Credential not found' }, { status: 404 }) | ||
| } | ||
| const credential = credentials[0] | ||
| const accountRow = credentials[0] | ||
| logger.info( | ||
| `[${requestId}] Using credential: ${credential.id}, provider: ${credential.providerId}` | ||
| `[${requestId}] Using credential: ${accountRow.id}, provider: ${accountRow.providerId}` | ||
| ) | ||
| const accessToken = await refreshAccessTokenIfNeeded(credentialId, session.user.id, requestId) | ||
| const accessToken = await refreshAccessTokenIfNeeded( | ||
| resolved.accountId, | ||
| accountRow.userId, | ||
| requestId | ||
| ) | ||
icecrasher321 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. icecrasher321 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| if (!accessToken) { | ||
| return NextResponse.json({ error: 'Failed to obtain valid access token' }, { status: 401 }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,12 @@ | ||
| import { db } from '@sim/db' | ||
| import { account } from '@sim/db/schema' | ||
| import { createLogger } from '@sim/logger' | ||
| import { and, eq } from 'drizzle-orm' | ||
| import { eq } from 'drizzle-orm' | ||
| import { type NextRequest, NextResponse } from 'next/server' | ||
| import { getSession } from '@/lib/auth' | ||
| import { validateAlphanumericId } from '@/lib/core/security/input-validation' | ||
| import { generateRequestId } from '@/lib/core/utils/request' | ||
| import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils' | ||
| import { refreshAccessTokenIfNeeded, resolveOAuthAccountId } from '@/app/api/auth/oauth/utils' | ||
| export const dynamic = 'force-dynamic' | ||
| const logger = createLogger('GmailLabelsAPI') | ||
| @@ -45,27 +45,45 @@ export async function GET(request: NextRequest) { | ||
| return NextResponse.json({ error: credentialIdValidation.error }, { status: 400 }) | ||
| } | ||
| let credentials = await db | ||
| const resolved = await resolveOAuthAccountId(credentialId) | ||
| if (!resolved) { | ||
| return NextResponse.json({ error: 'Credential not found' }, { status: 404 }) | ||
| } | ||
| if (resolved.workspaceId) { | ||
| const { getUserEntityPermissions } = await import('@/lib/workspaces/permissions/utils') | ||
| const perm = await getUserEntityPermissions( | ||
| session.user.id, | ||
| 'workspace', | ||
| resolved.workspaceId | ||
| ) | ||
| if (perm === null) { | ||
| return NextResponse.json({ error: 'Forbidden' }, { status: 403 }) | ||
| } | ||
| } | ||
| const credentials = await db | ||
| .select() | ||
| .from(account) | ||
| .where(and(eq(account.id, credentialId), eq(account.userId, session.user.id))) | ||
| .where(eq(account.id, resolved.accountId)) | ||
| .limit(1) | ||
| if (!credentials.length) { | ||
| credentials = await db.select().from(account).where(eq(account.id, credentialId)).limit(1) | ||
| if (!credentials.length) { | ||
| logger.warn(`[${requestId}] Credential not found`) | ||
| return NextResponse.json({ error: 'Credential not found' }, { status: 404 }) | ||
| } | ||
| logger.warn(`[${requestId}] Credential not found`) | ||
| return NextResponse.json({ error: 'Credential not found' }, { status: 404 }) | ||
| } | ||
| const credential = credentials[0] | ||
| const accountRow = credentials[0] | ||
| logger.info( | ||
| `[${requestId}] Using credential: ${credential.id}, provider: ${credential.providerId}` | ||
| `[${requestId}] Using credential: ${accountRow.id}, provider: ${accountRow.providerId}` | ||
| ) | ||
| const accessToken = await refreshAccessTokenIfNeeded(credentialId, credential.userId, requestId) | ||
| const accessToken = await refreshAccessTokenIfNeeded( | ||
| resolved.accountId, | ||
| accountRow.userId, | ||
| requestId | ||
| ) | ||
icecrasher321 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| if (!accessToken) { | ||
| return NextResponse.json({ error: 'Failed to obtain valid access token' }, { status: 401 }) | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.