@@ -17,6 +17,27 @@ function getServiceRoleClient() {
1717// Create regular client for JWT validation
1818const supabaseClient = createClient ( process . env . NEXT_PUBLIC_SUPABASE_URL , process . env . NEXT_PUBLIC_SUPABASE_ANON_KEY ) ;
1919
20+ export const MAX_PUBLIC_KEY_BATCH_SIZE = 100 ;
21+
22+ export function normalizePublicKeyUserIds ( value ) {
23+ if ( ! Array . isArray ( value ) || value . length > MAX_PUBLIC_KEY_BATCH_SIZE ) {
24+ return null ;
25+ }
26+
27+ const userIds = [ ] ;
28+ const seen = new Set ( ) ;
29+ for ( const candidate of value ) {
30+ if ( typeof candidate !== 'string' ) return null ;
31+ const userId = candidate . trim ( ) ;
32+ if ( ! userId || userId . length > 128 ) return null ;
33+ if ( seen . has ( userId ) ) continue ;
34+ seen . add ( userId ) ;
35+ userIds . push ( userId ) ;
36+ }
37+
38+ return userIds ;
39+ }
40+
2041/**
2142 * Authenticate user from request cookies
2243 * @param {Request } request
@@ -159,17 +180,26 @@ export async function POST(request) {
159180 return NextResponse . json ( { error : 'Unauthorized' } , { status : 401 } ) ;
160181 }
161182
162- const { user_ids } = await request . json ( ) ;
163-
164- if ( ! user_ids || ! Array . isArray ( user_ids ) ) {
165- return NextResponse . json ( { error : 'Missing or invalid user_ids array' } , { status : 400 } ) ;
183+ let body ;
184+ try {
185+ body = await request . json ( ) ;
186+ } catch {
187+ return NextResponse . json ( { error : 'Invalid request body' } , { status : 400 } ) ;
188+ }
189+
190+ const userIds = normalizePublicKeyUserIds ( body ?. user_ids ) ;
191+ if ( ! userIds ) {
192+ return NextResponse . json (
193+ { error : `user_ids must contain at most ${ MAX_PUBLIC_KEY_BATCH_SIZE } non-empty strings` } ,
194+ { status : 400 }
195+ ) ;
166196 }
167197
168- /** @type {Record <string, string|null> } */
169- const publicKeys = { } ;
198+ /** @type {Map <string, string|null> } */
199+ const publicKeys = new Map ( ) ;
170200
171201 // Process each user ID
172- for ( const userId of user_ids ) {
202+ for ( const userId of userIds ) {
173203 try {
174204 // Get the user's auth_user_id from the internal user ID
175205 const { data : userData , error : userError } = await getServiceRoleClient ( )
@@ -179,8 +209,8 @@ export async function POST(request) {
179209 . single ( ) ;
180210
181211 if ( userError || ! userData ?. auth_user_id ) {
182- console . log ( `🔑 No auth_user_id found for internal user ${ userId } ` ) ;
183- publicKeys [ userId ] = null ;
212+ console . log ( ' No auth_user_id found for requested public key' ) ;
213+ publicKeys . set ( userId , null ) ;
184214 continue ;
185215 }
186216
@@ -192,19 +222,19 @@ export async function POST(request) {
192222 } ) ;
193223
194224 if ( error ) {
195- console . error ( ` Error fetching public key for user ${ userId } :` , error ) ;
196- publicKeys [ userId ] = null ;
225+ console . error ( ' Error fetching requested public key:' , error ) ;
226+ publicKeys . set ( userId , null ) ;
197227 } else {
198- publicKeys [ userId ] = publicKey ;
228+ publicKeys . set ( userId , publicKey ) ;
199229 }
200230
201231 } catch ( error ) {
202- console . error ( ` Error processing user ${ userId } :` , error ) ;
203- publicKeys [ userId ] = null ;
232+ console . error ( ' Error processing public key lookup:' , error ) ;
233+ publicKeys . set ( userId , null ) ;
204234 }
205235 }
206236
207- return NextResponse . json ( { public_keys : publicKeys } ) ;
237+ return NextResponse . json ( { public_keys : Object . fromEntries ( publicKeys ) } ) ;
208238
209239 } catch ( error ) {
210240 console . error ( 'Error in POST /api/crypto/public-keys:' , error ) ;
0 commit comments