import { NextResponse } from 'next/server'; import { getServerSession } from 'next-auth'; import { authOptions } from "@/app/api/auth/options"; import { logger } from '@/lib/logger'; /** * Get RocketChat user token for WebSocket connection * This endpoint returns the user's auth token and userId for real-time connections */ export async function GET(request: Request) { try { const session = await getServerSession(authOptions); if (!session?.user?.email) { return NextResponse.json( { error: "Not authenticated" }, { status: 401 } ); } // Extract base URL, removing any paths like /channel, /_oauth/connect, etc. let baseUrl = process.env.NEXT_PUBLIC_IFRAME_PAROLE_URL; if (baseUrl) { // Remove /channel and everything after baseUrl = baseUrl.split('/channel')[0]; // Remove /_oauth/connect and everything after baseUrl = baseUrl.split('/_oauth')[0]; // Remove trailing slashes baseUrl = baseUrl.replace(/\/+$/, ''); } if (!baseUrl) { logger.error('[ROCKET_CHAT_USER_TOKEN] Failed to get Rocket.Chat base URL'); return NextResponse.json( { error: 'Server configuration error' }, { status: 500 } ); } logger.debug('[ROCKET_CHAT_USER_TOKEN] Using Rocket.Chat base URL', { baseUrl, hasToken: !!process.env.ROCKET_CHAT_TOKEN, hasUserId: !!process.env.ROCKET_CHAT_USER_ID, hasSecret: !!process.env.ROCKET_CHAT_CREATE_TOKEN_SECRET, }); // Use admin token to authenticate const adminHeaders = { 'X-Auth-Token': process.env.ROCKET_CHAT_TOKEN!, 'X-User-Id': process.env.ROCKET_CHAT_USER_ID!, 'Content-Type': 'application/json' }; // Get username from email const username = session.user.email.split('@')[0]; if (!username) { logger.error('[ROCKET_CHAT_USER_TOKEN] No username found in session email'); return NextResponse.json( { error: 'Invalid user' }, { status: 400 } ); } // Get all users to find the current user let usersResponse; const usersListUrl = `${baseUrl}/api/v1/users.list`; try { logger.debug('[ROCKET_CHAT_USER_TOKEN] Fetching users list', { url: usersListUrl }); usersResponse = await fetch(usersListUrl, { method: 'GET', headers: adminHeaders }); logger.debug('[ROCKET_CHAT_USER_TOKEN] Users list response', { status: usersResponse.status, statusText: usersResponse.statusText, contentType: usersResponse.headers.get('content-type'), }); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); logger.error('[ROCKET_CHAT_USER_TOKEN] Error fetching users list', { error: errorMessage, baseUrl, url: usersListUrl, }); return NextResponse.json( { error: 'Failed to connect to RocketChat' }, { status: 500 } ); } if (!usersResponse.ok) { const errorText = await usersResponse.text().catch(() => 'Unknown error'); logger.error('[ROCKET_CHAT_USER_TOKEN] Failed to get users list', { status: usersResponse.status, statusText: usersResponse.statusText, errorPreview: errorText.substring(0, 200), }); return NextResponse.json( { error: 'Failed to get user list from RocketChat' }, { status: 500 } ); } const contentType = usersResponse.headers.get('content-type') || ''; if (!contentType.includes('application/json')) { const errorText = await usersResponse.text().catch(() => 'Unknown error'); logger.error('[ROCKET_CHAT_USER_TOKEN] Expected JSON, got HTML', { contentType, errorPreview: errorText.substring(0, 200), }); return NextResponse.json( { error: 'RocketChat returned invalid response format' }, { status: 500 } ); } let usersData; try { usersData = await usersResponse.json(); } catch (error) { logger.error('[ROCKET_CHAT_USER_TOKEN] Failed to parse users list JSON', { error: error instanceof Error ? error.message : String(error), }); return NextResponse.json( { error: 'Failed to parse RocketChat response' }, { status: 500 } ); } const currentUser = usersData.users?.find((u: any) => u.username?.toLowerCase() === username.toLowerCase() || u.emails?.some((e: any) => e.address?.toLowerCase() === session.user.email?.toLowerCase()) ); if (!currentUser) { logger.error('[ROCKET_CHAT_USER_TOKEN] User not found in RocketChat', { username }); return NextResponse.json( { error: 'User not found' }, { status: 404 } ); } // Create user token const secret = process.env.ROCKET_CHAT_CREATE_TOKEN_SECRET; if (!secret) { logger.error('[ROCKET_CHAT_USER_TOKEN] ROCKET_CHAT_CREATE_TOKEN_SECRET not configured'); return NextResponse.json( { error: 'Server configuration error' }, { status: 500 } ); } let createTokenResponse; try { createTokenResponse = await fetch(`${baseUrl}/api/v1/users.createToken`, { method: 'POST', headers: adminHeaders, body: JSON.stringify({ userId: currentUser._id, secret: secret }) }); } catch (error) { logger.error('[ROCKET_CHAT_USER_TOKEN] Error creating token', { error: error instanceof Error ? error.message : String(error), }); return NextResponse.json( { error: 'Failed to connect to RocketChat' }, { status: 500 } ); } if (!createTokenResponse.ok) { const errorText = await createTokenResponse.text().catch(() => 'Unknown error'); logger.error('[ROCKET_CHAT_USER_TOKEN] Failed to create user token', { status: createTokenResponse.status, statusText: createTokenResponse.statusText, errorPreview: errorText.substring(0, 200), }); return NextResponse.json( { error: 'Failed to create token' }, { status: 500 } ); } const tokenContentType = createTokenResponse.headers.get('content-type') || ''; if (!tokenContentType.includes('application/json')) { const errorText = await createTokenResponse.text().catch(() => 'Unknown error'); logger.error('[ROCKET_CHAT_USER_TOKEN] Expected JSON, got HTML', { contentType: tokenContentType, errorPreview: errorText.substring(0, 200), }); return NextResponse.json( { error: 'RocketChat returned invalid response format' }, { status: 500 } ); } let tokenData; try { tokenData = await createTokenResponse.json(); } catch (error) { logger.error('[ROCKET_CHAT_USER_TOKEN] Failed to parse token JSON', { error: error instanceof Error ? error.message : String(error), }); return NextResponse.json( { error: 'Failed to parse RocketChat response' }, { status: 500 } ); } logger.debug('[ROCKET_CHAT_USER_TOKEN] Token created', { emailHash: Buffer.from(session.user.email.toLowerCase()).toString('base64').slice(0, 12), hasAuthToken: !!tokenData.data?.authToken, tokenLength: tokenData.data?.authToken?.length, }); return NextResponse.json({ userId: currentUser._id, authToken: tokenData.data.authToken, username: currentUser.username, // Also return the full token data for debugging tokenData: tokenData.data, }); } catch (error: any) { logger.error('[ROCKET_CHAT_USER_TOKEN] Error', { error: error instanceof Error ? error.message : String(error), }); return NextResponse.json( { error: "Internal server error", message: error.message }, { status: 500 } ); } }