fix(security): add authentication to remaining tool API routes (#3028)

* fix(security): add authentication to tool API routes

* fix(drive): use checkSessionOrInternalAuth to allow browser access

* fix(selectors): use checkSessionOrInternalAuth for UI-accessible routes
This commit is contained in:
Waleed
2026-01-27 12:37:03 -08:00
committed by GitHub
parent dddd0c8277
commit 6b412c578d
74 changed files with 729 additions and 105 deletions

View File

@@ -10,6 +10,7 @@ describe('OAuth Token API Routes', () => {
const mockGetUserId = vi.fn()
const mockGetCredential = vi.fn()
const mockRefreshTokenIfNeeded = vi.fn()
const mockGetOAuthToken = vi.fn()
const mockAuthorizeCredentialUse = vi.fn()
const mockCheckHybridAuth = vi.fn()
@@ -29,6 +30,7 @@ describe('OAuth Token API Routes', () => {
getUserId: mockGetUserId,
getCredential: mockGetCredential,
refreshTokenIfNeeded: mockRefreshTokenIfNeeded,
getOAuthToken: mockGetOAuthToken,
}))
vi.doMock('@sim/logger', () => ({
@@ -230,6 +232,140 @@ describe('OAuth Token API Routes', () => {
expect(response.status).toBe(401)
expect(data).toHaveProperty('error', 'Failed to refresh access token')
})
describe('credentialAccountUserId + providerId path', () => {
it('should reject unauthenticated requests', async () => {
mockCheckHybridAuth.mockResolvedValueOnce({
success: false,
error: 'Authentication required',
})
const req = createMockRequest('POST', {
credentialAccountUserId: 'target-user-id',
providerId: 'google',
})
const { POST } = await import('@/app/api/auth/oauth/token/route')
const response = await POST(req)
const data = await response.json()
expect(response.status).toBe(401)
expect(data).toHaveProperty('error', 'User not authenticated')
expect(mockGetOAuthToken).not.toHaveBeenCalled()
})
it('should reject API key authentication', async () => {
mockCheckHybridAuth.mockResolvedValueOnce({
success: true,
authType: 'api_key',
userId: 'test-user-id',
})
const req = createMockRequest('POST', {
credentialAccountUserId: 'test-user-id',
providerId: 'google',
})
const { POST } = await import('@/app/api/auth/oauth/token/route')
const response = await POST(req)
const data = await response.json()
expect(response.status).toBe(401)
expect(data).toHaveProperty('error', 'User not authenticated')
expect(mockGetOAuthToken).not.toHaveBeenCalled()
})
it('should reject internal JWT authentication', async () => {
mockCheckHybridAuth.mockResolvedValueOnce({
success: true,
authType: 'internal_jwt',
userId: 'test-user-id',
})
const req = createMockRequest('POST', {
credentialAccountUserId: 'test-user-id',
providerId: 'google',
})
const { POST } = await import('@/app/api/auth/oauth/token/route')
const response = await POST(req)
const data = await response.json()
expect(response.status).toBe(401)
expect(data).toHaveProperty('error', 'User not authenticated')
expect(mockGetOAuthToken).not.toHaveBeenCalled()
})
it('should reject requests for other users credentials', async () => {
mockCheckHybridAuth.mockResolvedValueOnce({
success: true,
authType: 'session',
userId: 'attacker-user-id',
})
const req = createMockRequest('POST', {
credentialAccountUserId: 'victim-user-id',
providerId: 'google',
})
const { POST } = await import('@/app/api/auth/oauth/token/route')
const response = await POST(req)
const data = await response.json()
expect(response.status).toBe(403)
expect(data).toHaveProperty('error', 'Unauthorized')
expect(mockGetOAuthToken).not.toHaveBeenCalled()
})
it('should allow session-authenticated users to access their own credentials', async () => {
mockCheckHybridAuth.mockResolvedValueOnce({
success: true,
authType: 'session',
userId: 'test-user-id',
})
mockGetOAuthToken.mockResolvedValueOnce('valid-access-token')
const req = createMockRequest('POST', {
credentialAccountUserId: 'test-user-id',
providerId: 'google',
})
const { POST } = await import('@/app/api/auth/oauth/token/route')
const response = await POST(req)
const data = await response.json()
expect(response.status).toBe(200)
expect(data).toHaveProperty('accessToken', 'valid-access-token')
expect(mockGetOAuthToken).toHaveBeenCalledWith('test-user-id', 'google')
})
it('should return 404 when credential not found for user', async () => {
mockCheckHybridAuth.mockResolvedValueOnce({
success: true,
authType: 'session',
userId: 'test-user-id',
})
mockGetOAuthToken.mockResolvedValueOnce(null)
const req = createMockRequest('POST', {
credentialAccountUserId: 'test-user-id',
providerId: 'nonexistent-provider',
})
const { POST } = await import('@/app/api/auth/oauth/token/route')
const response = await POST(req)
const data = await response.json()
expect(response.status).toBe(404)
expect(data.error).toContain('No credential found')
})
})
})
/**

View File

@@ -71,6 +71,22 @@ export async function POST(request: NextRequest) {
providerId,
})
const auth = await checkHybridAuth(request, { requireWorkflowId: false })
if (!auth.success || auth.authType !== 'session' || !auth.userId) {
logger.warn(`[${requestId}] Unauthorized request for credentialAccountUserId path`, {
success: auth.success,
authType: auth.authType,
})
return NextResponse.json({ error: 'User not authenticated' }, { status: 401 })
}
if (auth.userId !== credentialAccountUserId) {
logger.warn(
`[${requestId}] User ${auth.userId} attempted to access credentials for ${credentialAccountUserId}`
)
return NextResponse.json({ error: 'Unauthorized' }, { status: 403 })
}
try {
const accessToken = await getOAuthToken(credentialAccountUserId, providerId)
if (!accessToken) {

View File

@@ -1,13 +1,19 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
export const dynamic = 'force-dynamic'
const logger = createLogger('AsanaAddCommentAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { accessToken, taskGid, text } = await request.json()
if (!accessToken) {

View File

@@ -1,13 +1,19 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
export const dynamic = 'force-dynamic'
const logger = createLogger('AsanaCreateTaskAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { accessToken, workspace, name, notes, assignee, due_on } = await request.json()
if (!accessToken) {

View File

@@ -1,13 +1,19 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
export const dynamic = 'force-dynamic'
const logger = createLogger('AsanaGetProjectsAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { accessToken, workspace } = await request.json()
if (!accessToken) {

View File

@@ -1,13 +1,19 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
export const dynamic = 'force-dynamic'
const logger = createLogger('AsanaGetTaskAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { accessToken, taskGid, workspace, project, limit } = await request.json()
if (!accessToken) {

View File

@@ -1,13 +1,19 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
export const dynamic = 'force-dynamic'
const logger = createLogger('AsanaSearchTasksAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { accessToken, workspace, text, assignee, projects, completed } = await request.json()
if (!accessToken) {

View File

@@ -1,13 +1,19 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
export const dynamic = 'force-dynamic'
const logger = createLogger('AsanaUpdateTaskAPI')
export async function PUT(request: Request) {
export async function PUT(request: NextRequest) {
try {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { accessToken, taskGid, name, notes, assignee, completed, due_on } = await request.json()
if (!accessToken) {

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getConfluenceCloudId } from '@/tools/confluence/utils'
@@ -8,8 +9,13 @@ const logger = createLogger('ConfluenceAttachmentAPI')
export const dynamic = 'force-dynamic'
// Delete an attachment
export async function DELETE(request: Request) {
export async function DELETE(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { domain, accessToken, cloudId: providedCloudId, attachmentId } = await request.json()
if (!domain) {

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getConfluenceCloudId } from '@/tools/confluence/utils'
@@ -8,8 +9,13 @@ const logger = createLogger('ConfluenceAttachmentsAPI')
export const dynamic = 'force-dynamic'
// List attachments on a page
export async function GET(request: Request) {
export async function GET(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { searchParams } = new URL(request.url)
const domain = searchParams.get('domain')
const accessToken = searchParams.get('accessToken')

View File

@@ -1,6 +1,7 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getConfluenceCloudId } from '@/tools/confluence/utils'
@@ -46,8 +47,13 @@ const deleteCommentSchema = z
)
// Update a comment
export async function PUT(request: Request) {
export async function PUT(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const validation = putCommentSchema.safeParse(body)
@@ -128,8 +134,13 @@ export async function PUT(request: Request) {
}
// Delete a comment
export async function DELETE(request: Request) {
export async function DELETE(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const validation = deleteCommentSchema.safeParse(body)

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getConfluenceCloudId } from '@/tools/confluence/utils'
@@ -8,8 +9,13 @@ const logger = createLogger('ConfluenceCommentsAPI')
export const dynamic = 'force-dynamic'
// Create a comment
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { domain, accessToken, cloudId: providedCloudId, pageId, comment } = await request.json()
if (!domain) {
@@ -86,8 +92,13 @@ export async function POST(request: Request) {
}
// List comments on a page
export async function GET(request: Request) {
export async function GET(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { searchParams } = new URL(request.url)
const domain = searchParams.get('domain')
const accessToken = searchParams.get('accessToken')

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getConfluenceCloudId } from '@/tools/confluence/utils'
@@ -7,8 +8,13 @@ const logger = createLogger('ConfluenceCreatePageAPI')
export const dynamic = 'force-dynamic'
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const {
domain,
accessToken,

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getConfluenceCloudId } from '@/tools/confluence/utils'
@@ -8,8 +9,13 @@ const logger = createLogger('ConfluenceLabelsAPI')
export const dynamic = 'force-dynamic'
// Add a label to a page
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const {
domain,
accessToken,
@@ -87,8 +93,13 @@ export async function POST(request: Request) {
}
// List labels on a page
export async function GET(request: Request) {
export async function GET(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { searchParams } = new URL(request.url)
const domain = searchParams.get('domain')
const accessToken = searchParams.get('accessToken')

View File

@@ -1,6 +1,7 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getConfluenceCloudId } from '@/tools/confluence/utils'
@@ -73,8 +74,13 @@ const deletePageSchema = z
}
)
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const validation = postPageSchema.safeParse(body)
@@ -144,8 +150,13 @@ export async function POST(request: Request) {
}
}
export async function PUT(request: Request) {
export async function PUT(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const validation = putPageSchema.safeParse(body)
@@ -248,8 +259,13 @@ export async function PUT(request: Request) {
}
}
export async function DELETE(request: Request) {
export async function DELETE(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const validation = deletePageSchema.safeParse(body)

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getConfluenceCloudId } from '@/tools/confluence/utils'
@@ -8,8 +9,13 @@ const logger = createLogger('ConfluencePagesAPI')
export const dynamic = 'force-dynamic'
// List pages or search pages
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const {
domain,
accessToken,

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getConfluenceCloudId } from '@/tools/confluence/utils'
@@ -7,8 +8,13 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('Confluence Search')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const {
domain,
accessToken,

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getConfluenceCloudId } from '@/tools/confluence/utils'
@@ -8,8 +9,13 @@ const logger = createLogger('ConfluenceSpaceAPI')
export const dynamic = 'force-dynamic'
// Get a specific space
export async function GET(request: Request) {
export async function GET(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { searchParams } = new URL(request.url)
const domain = searchParams.get('domain')
const accessToken = searchParams.get('accessToken')

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getConfluenceCloudId } from '@/tools/confluence/utils'
@@ -8,8 +9,13 @@ const logger = createLogger('ConfluenceSpacesAPI')
export const dynamic = 'force-dynamic'
// List all spaces
export async function GET(request: Request) {
export async function GET(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { searchParams } = new URL(request.url)
const domain = searchParams.get('domain')
const accessToken = searchParams.get('accessToken')

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { processSingleFileToUserFile } from '@/lib/uploads/utils/file-utils'
import { downloadFileFromStorage } from '@/lib/uploads/utils/file-utils.server'
@@ -11,6 +12,11 @@ export const dynamic = 'force-dynamic'
export async function POST(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const { domain, accessToken, cloudId: providedCloudId, pageId, file, fileName, comment } = body

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateNumericId } from '@/lib/core/security/input-validation'
interface DiscordChannel {
@@ -13,7 +14,12 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('DiscordChannelsAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const { botToken, serverId, channelId } = await request.json()

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateNumericId } from '@/lib/core/security/input-validation'
interface DiscordServer {
@@ -12,7 +13,12 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('DiscordServersAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const { botToken, serverId } = await request.json()

View File

@@ -1,6 +1,7 @@
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { authorizeCredentialUse } from '@/lib/auth/credential-access'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
import { generateRequestId } from '@/lib/core/utils/request'
import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
@@ -15,6 +16,11 @@ export async function GET(request: NextRequest) {
const requestId = generateRequestId()
logger.info(`[${requestId}] Google Drive file request received`)
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const { searchParams } = new URL(request.url)
const credentialId = searchParams.get('credentialId')

View File

@@ -1,7 +1,7 @@
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { getSession } from '@/lib/auth'
import { authorizeCredentialUse } from '@/lib/auth/credential-access'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
import { generateRequestId } from '@/lib/core/utils/request'
import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
@@ -73,14 +73,12 @@ export async function GET(request: NextRequest) {
const requestId = generateRequestId()
logger.info(`[${requestId}] Google Drive files request received`)
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const session = await getSession()
if (!session?.user?.id) {
logger.warn(`[${requestId}] Unauthenticated request rejected`)
return NextResponse.json({ error: 'User not authenticated' }, { status: 401 })
}
const { searchParams } = new URL(request.url)
const credentialId = searchParams.get('credentialId')
const mimeType = searchParams.get('mimeType')

View File

@@ -1,5 +1,6 @@
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createDynamoDBClient, deleteItem } from '@/app/api/tools/dynamodb/utils'
const DeleteSchema = z.object({
@@ -13,8 +14,13 @@ const DeleteSchema = z.object({
conditionExpression: z.string().optional(),
})
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const validatedData = DeleteSchema.parse(body)

View File

@@ -1,5 +1,6 @@
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createDynamoDBClient, getItem } from '@/app/api/tools/dynamodb/utils'
const GetSchema = z.object({
@@ -19,8 +20,13 @@ const GetSchema = z.object({
}),
})
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const validatedData = GetSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createRawDynamoDBClient, describeTable, listTables } from '@/app/api/tools/dynamodb/utils'
const logger = createLogger('DynamoDBIntrospectAPI')
@@ -17,6 +18,11 @@ export async function POST(request: NextRequest) {
const requestId = randomUUID().slice(0, 8)
try {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const params = IntrospectSchema.parse(body)

View File

@@ -1,5 +1,6 @@
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createDynamoDBClient, putItem } from '@/app/api/tools/dynamodb/utils'
const PutSchema = z.object({
@@ -12,8 +13,13 @@ const PutSchema = z.object({
}),
})
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const validatedData = PutSchema.parse(body)

View File

@@ -1,5 +1,6 @@
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createDynamoDBClient, queryItems } from '@/app/api/tools/dynamodb/utils'
const QuerySchema = z.object({
@@ -15,8 +16,13 @@ const QuerySchema = z.object({
limit: z.number().positive().optional(),
})
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const validatedData = QuerySchema.parse(body)

View File

@@ -1,5 +1,6 @@
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createDynamoDBClient, scanItems } from '@/app/api/tools/dynamodb/utils'
const ScanSchema = z.object({
@@ -14,8 +15,13 @@ const ScanSchema = z.object({
limit: z.number().positive().optional(),
})
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const validatedData = ScanSchema.parse(body)

View File

@@ -1,5 +1,6 @@
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createDynamoDBClient, updateItem } from '@/app/api/tools/dynamodb/utils'
const UpdateSchema = z.object({
@@ -16,8 +17,13 @@ const UpdateSchema = z.object({
conditionExpression: z.string().optional(),
})
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const validatedData = UpdateSchema.parse(body)

View File

@@ -1,6 +1,7 @@
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { authorizeCredentialUse } from '@/lib/auth/credential-access'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { generateRequestId } from '@/lib/core/utils/request'
import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
@@ -29,6 +30,11 @@ export async function GET(request: NextRequest) {
const requestId = generateRequestId()
logger.info(`[${requestId}] Google Sheets sheets request received`)
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const { searchParams } = new URL(request.url)
const credentialId = searchParams.get('credentialId')

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
import { getJiraCloudId } from '@/tools/jira/utils'
@@ -7,8 +8,13 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('JiraIssueAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { domain, accessToken, issueId, cloudId: providedCloudId } = await request.json()
if (!domain) {
logger.error('Missing domain in request')

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getJiraCloudId } from '@/tools/jira/utils'
@@ -26,8 +27,13 @@ const validateRequiredParams = (domain: string | null, accessToken: string | nul
return null
}
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { domain, accessToken, issueKeys = [], cloudId: providedCloudId } = await request.json()
const validationError = validateRequiredParams(domain || null, accessToken || null)
@@ -101,8 +107,13 @@ export async function POST(request: Request) {
}
}
export async function GET(request: Request) {
export async function GET(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const url = new URL(request.url)
const domain = url.searchParams.get('domain')?.trim()
const accessToken = url.searchParams.get('accessToken')

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getJiraCloudId } from '@/tools/jira/utils'
@@ -7,8 +8,13 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('JiraProjectsAPI')
export async function GET(request: Request) {
export async function GET(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const url = new URL(request.url)
const domain = url.searchParams.get('domain')?.trim()
const accessToken = url.searchParams.get('accessToken')
@@ -98,8 +104,13 @@ export async function GET(request: Request) {
}
}
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const { domain, accessToken, projectId, cloudId: providedCloudId } = await request.json()
if (!domain) {

View File

@@ -1,6 +1,7 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
import { getJiraCloudId } from '@/tools/jira/utils'
@@ -21,8 +22,13 @@ const jiraUpdateSchema = z.object({
cloudId: z.string().optional(),
})
export async function PUT(request: Request) {
export async function PUT(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const validation = jiraUpdateSchema.safeParse(body)

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getJiraCloudId } from '@/tools/jira/utils'
@@ -7,8 +8,13 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('JiraWriteAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const auth = await checkSessionOrInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
const {
domain,
accessToken,

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import {
validateAlphanumericId,
validateEnum,
@@ -15,7 +16,12 @@ const logger = createLogger('JsmApprovalsAPI')
const VALID_ACTIONS = ['get', 'answer'] as const
const VALID_DECISIONS = ['approve', 'decline'] as const
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const {

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
@@ -7,7 +8,12 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('JsmCommentAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const {
domain,

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
@@ -7,7 +8,12 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('JsmCommentsAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const {

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
@@ -7,7 +8,12 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('JsmCustomersAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const {

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import {
validateAlphanumericId,
validateEnum,
@@ -13,7 +14,12 @@ const logger = createLogger('JsmOrganizationAPI')
const VALID_ACTIONS = ['create', 'add_to_service_desk'] as const
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const {

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
@@ -7,7 +8,12 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('JsmOrganizationsAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const { domain, accessToken, cloudId: cloudIdParam, serviceDeskId, start, limit } = body

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import {
validateEnum,
validateJiraCloudId,
@@ -13,7 +14,12 @@ const logger = createLogger('JsmParticipantsAPI')
const VALID_ACTIONS = ['get', 'add'] as const
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const {

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
@@ -7,7 +8,12 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('JsmQueuesAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const {

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import {
validateAlphanumericId,
validateJiraCloudId,
@@ -11,7 +12,12 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('JsmRequestAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const {

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
@@ -7,7 +8,12 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('JsmRequestsAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const {

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
@@ -7,7 +8,12 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('JsmRequestTypesAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const { domain, accessToken, cloudId: cloudIdParam, serviceDeskId, start, limit } = body

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateJiraCloudId } from '@/lib/core/security/input-validation'
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
@@ -7,7 +8,12 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('JsmServiceDesksAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const { domain, accessToken, cloudId: cloudIdParam, start, limit } = body

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
@@ -7,7 +8,12 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('JsmSlaAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const { domain, accessToken, cloudId: cloudIdParam, issueIdOrKey, start, limit } = body

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import {
validateAlphanumericId,
validateJiraCloudId,
@@ -11,7 +12,12 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('JsmTransitionAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const {
domain,

View File

@@ -1,5 +1,6 @@
import { createLogger } from '@sim/logger'
import { NextResponse } from 'next/server'
import { type NextRequest, NextResponse } from 'next/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
import { getJiraCloudId, getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
@@ -7,7 +8,12 @@ export const dynamic = 'force-dynamic'
const logger = createLogger('JsmTransitionsAPI')
export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const { domain, accessToken, cloudId: cloudIdParam, issueIdOrKey } = body

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createMongoDBConnection, sanitizeCollectionName, validateFilter } from '../utils'
const logger = createLogger('MongoDBDeleteAPI')
@@ -40,6 +41,12 @@ export async function POST(request: NextRequest) {
const requestId = randomUUID().slice(0, 8)
let client = null
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
logger.warn(`[${requestId}] Unauthorized MongoDB delete attempt`)
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = DeleteSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createMongoDBConnection, sanitizeCollectionName, validatePipeline } from '../utils'
const logger = createLogger('MongoDBExecuteAPI')
@@ -32,6 +33,12 @@ export async function POST(request: NextRequest) {
const requestId = randomUUID().slice(0, 8)
let client = null
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
logger.warn(`[${requestId}] Unauthorized MongoDB execute attempt`)
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = ExecuteSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createMongoDBConnection, sanitizeCollectionName } from '../utils'
const logger = createLogger('MongoDBInsertAPI')
@@ -37,6 +38,12 @@ export async function POST(request: NextRequest) {
const requestId = randomUUID().slice(0, 8)
let client = null
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
logger.warn(`[${requestId}] Unauthorized MongoDB insert attempt`)
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = InsertSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createMongoDBConnection, executeIntrospect } from '../utils'
const logger = createLogger('MongoDBIntrospectAPI')
@@ -20,6 +21,12 @@ export async function POST(request: NextRequest) {
const requestId = randomUUID().slice(0, 8)
let client = null
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
logger.warn(`[${requestId}] Unauthorized MongoDB introspect attempt`)
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = IntrospectSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createMongoDBConnection, sanitizeCollectionName, validateFilter } from '../utils'
const logger = createLogger('MongoDBQueryAPI')
@@ -49,6 +50,12 @@ export async function POST(request: NextRequest) {
const requestId = randomUUID().slice(0, 8)
let client = null
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
logger.warn(`[${requestId}] Unauthorized MongoDB query attempt`)
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = QuerySchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createMongoDBConnection, sanitizeCollectionName, validateFilter } from '../utils'
const logger = createLogger('MongoDBUpdateAPI')
@@ -59,6 +60,12 @@ export async function POST(request: NextRequest) {
const requestId = randomUUID().slice(0, 8)
let client = null
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
logger.warn(`[${requestId}] Unauthorized MongoDB update attempt`)
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = UpdateSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import {
convertNeo4jTypesToJSON,
createNeo4jDriver,
@@ -26,6 +27,12 @@ export async function POST(request: NextRequest) {
let driver = null
let session = null
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
logger.warn(`[${requestId}] Unauthorized Neo4j create attempt`)
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = CreateSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createNeo4jDriver, validateCypherQuery } from '@/app/api/tools/neo4j/utils'
const logger = createLogger('Neo4jDeleteAPI')
@@ -23,6 +24,12 @@ export async function POST(request: NextRequest) {
let driver = null
let session = null
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
logger.warn(`[${requestId}] Unauthorized Neo4j delete attempt`)
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = DeleteSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import {
convertNeo4jTypesToJSON,
createNeo4jDriver,
@@ -26,6 +27,12 @@ export async function POST(request: NextRequest) {
let driver = null
let session = null
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
logger.warn(`[${requestId}] Unauthorized Neo4j execute attempt`)
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = ExecuteSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createNeo4jDriver } from '@/app/api/tools/neo4j/utils'
import type { Neo4jNodeSchema, Neo4jRelationshipSchema } from '@/tools/neo4j/types'
@@ -21,6 +22,12 @@ export async function POST(request: NextRequest) {
let driver = null
let session = null
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
logger.warn(`[${requestId}] Unauthorized Neo4j introspect attempt`)
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = IntrospectSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import {
convertNeo4jTypesToJSON,
createNeo4jDriver,
@@ -26,6 +27,12 @@ export async function POST(request: NextRequest) {
let driver = null
let session = null
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
logger.warn(`[${requestId}] Unauthorized Neo4j merge attempt`)
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = MergeSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import {
convertNeo4jTypesToJSON,
createNeo4jDriver,
@@ -26,6 +27,12 @@ export async function POST(request: NextRequest) {
let driver = null
let session = null
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
logger.warn(`[${requestId}] Unauthorized Neo4j query attempt`)
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = QuerySchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import {
convertNeo4jTypesToJSON,
createNeo4jDriver,
@@ -26,6 +27,12 @@ export async function POST(request: NextRequest) {
let driver = null
let session = null
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
logger.warn(`[${requestId}] Unauthorized Neo4j update attempt`)
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = UpdateSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createRdsClient, executeDelete } from '@/app/api/tools/rds/utils'
const logger = createLogger('RDSDeleteAPI')
@@ -22,6 +23,11 @@ const DeleteSchema = z.object({
export async function POST(request: NextRequest) {
const requestId = randomUUID().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = DeleteSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createRdsClient, executeStatement } from '@/app/api/tools/rds/utils'
const logger = createLogger('RDSExecuteAPI')
@@ -19,6 +20,11 @@ const ExecuteSchema = z.object({
export async function POST(request: NextRequest) {
const requestId = randomUUID().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = ExecuteSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createRdsClient, executeInsert } from '@/app/api/tools/rds/utils'
const logger = createLogger('RDSInsertAPI')
@@ -22,6 +23,11 @@ const InsertSchema = z.object({
export async function POST(request: NextRequest) {
const requestId = randomUUID().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = InsertSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createRdsClient, executeIntrospect, type RdsEngine } from '@/app/api/tools/rds/utils'
const logger = createLogger('RDSIntrospectAPI')
@@ -20,6 +21,11 @@ const IntrospectSchema = z.object({
export async function POST(request: NextRequest) {
const requestId = randomUUID().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = IntrospectSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createRdsClient, executeStatement, validateQuery } from '@/app/api/tools/rds/utils'
const logger = createLogger('RDSQueryAPI')
@@ -19,6 +20,11 @@ const QuerySchema = z.object({
export async function POST(request: NextRequest) {
const requestId = randomUUID().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = QuerySchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createRdsClient, executeUpdate } from '@/app/api/tools/rds/utils'
const logger = createLogger('RDSUpdateAPI')
@@ -25,6 +26,11 @@ const UpdateSchema = z.object({
export async function POST(request: NextRequest) {
const requestId = randomUUID().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = UpdateSchema.parse(body)

View File

@@ -2,6 +2,7 @@ import { randomUUID } from 'crypto'
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { createSqsClient, sendMessage } from '../utils'
const logger = createLogger('SQSSendMessageAPI')
@@ -21,6 +22,11 @@ const SendMessageSchema = z.object({
export async function POST(request: NextRequest) {
const requestId = randomUUID().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const body = await request.json()
const params = SendMessageSchema.parse(body)

View File

@@ -1,6 +1,7 @@
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { env } from '@/lib/core/config/env'
import { isSensitiveKey, REDACTED_MARKER } from '@/lib/core/security/redaction'
import { ensureZodObject, normalizeUrl } from '@/app/api/tools/stagehand/utils'
@@ -91,6 +92,11 @@ function substituteVariables(text: string, variables: Record<string, string> | u
}
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
let stagehand: StagehandType | null = null
try {

View File

@@ -1,6 +1,7 @@
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { env } from '@/lib/core/config/env'
import { ensureZodObject, normalizeUrl } from '@/app/api/tools/stagehand/utils'
@@ -22,6 +23,11 @@ const requestSchema = z.object({
})
export async function POST(request: NextRequest) {
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
let stagehand: StagehandType | null = null
try {