11import { NextResponse } from 'next/server'
22import { authorizeCredentialUse } from '@/lib/auth/credential-access'
3+ import { validateMicrosoftGraphId } from '@/lib/core/security/input-validation'
34import { createLogger } from '@/lib/logs/console/logger'
45import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
56
67export const dynamic = 'force-dynamic'
78
89const logger = createLogger ( 'TeamsChatsAPI' )
910
10- // Helper function to get chat members and create a meaningful name
11+ /**
12+ * Helper function to get chat members and create a meaningful name
13+ *
14+ * @param chatId - Microsoft Teams chat ID to get display name for
15+ * @param accessToken - Access token for Microsoft Graph API
16+ * @param chatTopic - Optional existing chat topic
17+ * @returns A meaningful display name for the chat
18+ */
1119const getChatDisplayName = async (
1220 chatId : string ,
1321 accessToken : string ,
1422 chatTopic ?: string
1523) : Promise < string > => {
1624 try {
17- // If the chat already has a topic, use it
25+ const chatIdValidation = validateMicrosoftGraphId ( chatId , 'chatId' )
26+ if ( ! chatIdValidation . isValid ) {
27+ logger . warn ( 'Invalid chat ID in getChatDisplayName' , {
28+ error : chatIdValidation . error ,
29+ chatId : chatId . substring ( 0 , 50 ) ,
30+ } )
31+ return `Chat ${ chatId . substring ( 0 , 8 ) } ...`
32+ }
33+
1834 if ( chatTopic ?. trim ( ) && chatTopic !== 'null' ) {
1935 return chatTopic
2036 }
2137
22- // Fetch chat members to create a meaningful name
2338 const membersResponse = await fetch (
24- `https://graph.microsoft.com/v1.0/chats/${ chatId } /members` ,
39+ `https://graph.microsoft.com/v1.0/chats/${ encodeURIComponent ( chatId ) } /members` ,
2540 {
2641 method : 'GET' ,
2742 headers : {
@@ -35,27 +50,25 @@ const getChatDisplayName = async (
3550 const membersData = await membersResponse . json ( )
3651 const members = membersData . value || [ ]
3752
38- // Filter out the current user and get display names
3953 const memberNames = members
4054 . filter ( ( member : any ) => member . displayName && member . displayName !== 'Unknown' )
4155 . map ( ( member : any ) => member . displayName )
42- . slice ( 0 , 3 ) // Limit to first 3 names to avoid very long names
56+ . slice ( 0 , 3 )
4357
4458 if ( memberNames . length > 0 ) {
4559 if ( memberNames . length === 1 ) {
46- return memberNames [ 0 ] // 1:1 chat
60+ return memberNames [ 0 ]
4761 }
4862 if ( memberNames . length === 2 ) {
49- return memberNames . join ( ' & ' ) // 2-person group
63+ return memberNames . join ( ' & ' )
5064 }
51- return `${ memberNames . slice ( 0 , 2 ) . join ( ', ' ) } & ${ memberNames . length - 2 } more` // Larger group
65+ return `${ memberNames . slice ( 0 , 2 ) . join ( ', ' ) } & ${ memberNames . length - 2 } more`
5266 }
5367 }
5468
55- // Fallback: try to get a better name from recent messages
5669 try {
5770 const messagesResponse = await fetch (
58- `https://graph.microsoft.com/v1.0/chats/${ chatId } /messages?$top=10&$orderby=createdDateTime desc` ,
71+ `https://graph.microsoft.com/v1.0/chats/${ encodeURIComponent ( chatId ) } /messages?$top=10&$orderby=createdDateTime desc` ,
5972 {
6073 method : 'GET' ,
6174 headers : {
@@ -69,14 +82,12 @@ const getChatDisplayName = async (
6982 const messagesData = await messagesResponse . json ( )
7083 const messages = messagesData . value || [ ]
7184
72- // Look for chat rename events
7385 for ( const message of messages ) {
7486 if ( message . eventDetail ?. chatDisplayName ) {
7587 return message . eventDetail . chatDisplayName
7688 }
7789 }
7890
79- // Get unique sender names from recent messages as last resort
8091 const senderNames = [
8192 ...new Set (
8293 messages
@@ -103,7 +114,6 @@ const getChatDisplayName = async (
103114 )
104115 }
105116
106- // Final fallback
107117 return `Chat ${ chatId . split ( ':' ) [ 0 ] || chatId . substring ( 0 , 8 ) } ...`
108118 } catch ( error ) {
109119 logger . warn (
@@ -146,7 +156,6 @@ export async function POST(request: Request) {
146156 return NextResponse . json ( { error : 'Could not retrieve access token' } , { status : 401 } )
147157 }
148158
149- // Now try to fetch the chats
150159 const response = await fetch ( 'https://graph.microsoft.com/v1.0/me/chats' , {
151160 method : 'GET' ,
152161 headers : {
@@ -163,7 +172,6 @@ export async function POST(request: Request) {
163172 endpoint : 'https://graph.microsoft.com/v1.0/me/chats' ,
164173 } )
165174
166- // Check for auth errors specifically
167175 if ( response . status === 401 ) {
168176 return NextResponse . json (
169177 {
@@ -179,7 +187,6 @@ export async function POST(request: Request) {
179187
180188 const data = await response . json ( )
181189
182- // Process chats with enhanced display names
183190 const chats = await Promise . all (
184191 data . value . map ( async ( chat : any ) => ( {
185192 id : chat . id ,
@@ -193,7 +200,6 @@ export async function POST(request: Request) {
193200 } catch ( innerError ) {
194201 logger . error ( 'Error during API requests:' , innerError )
195202
196- // Check if it's an authentication error
197203 const errorMessage = innerError instanceof Error ? innerError . message : String ( innerError )
198204 if (
199205 errorMessage . includes ( 'auth' ) ||
0 commit comments