@@ -3,32 +3,81 @@ import { handleRequest } from '@/api-helpers/axios';
33import * as yup from 'yup' ;
44
55const payloadSchema = yup . object ( {
6- username : yup . string ( ) . required ( 'Username is required' ) ,
7- appPassword : yup . string ( ) . required ( 'App password is required' ) ,
8- customDomain : yup . string ( ) . url ( 'Custom domain must be a valid URL' ) ,
6+ username : yup
7+ . string ( )
8+ . required ( 'Username is required' )
9+ . trim ( )
10+ . min ( 1 , 'Username cannot be empty' )
11+ . max ( 100 , 'Username too long' ) ,
12+ appPassword : yup
13+ . string ( )
14+ . required ( 'App password is required' )
15+ . min ( 1 , 'App password cannot be empty' )
16+ . max ( 500 , 'App password too long' )
917} ) ;
1018
1119const endpoint = new Endpoint ( nullSchema ) ;
1220
1321endpoint . handle . POST ( payloadSchema , async ( req , res ) => {
1422 try {
15- const { username, appPassword, customDomain } = req . payload ;
16- const baseUrl = customDomain || 'https://api.bitbucket.org/2.0' ;
17- const url = `${ baseUrl } /user` ;
23+ const { username, appPassword } = req . payload ;
24+ const sanitizedUsername = username . replace ( / [ ^ \w . - ] / g, '' ) ;
25+
26+ if ( sanitizedUsername !== username ) {
27+ return res . status ( 400 ) . json ( {
28+ message : 'Invalid username format. Only alphanumeric characters, dots, and hyphens are allowed.'
29+ } ) ;
30+ }
31+
32+ const url = 'https://api.bitbucket.org/2.0/user' ;
33+
1834 const response = await handleRequest ( url , {
1935 method : 'GET' ,
20- auth : {
21- username ,
22- password : appPassword ,
36+ headers : {
37+ Authorization : `Basic ${ Buffer . from ( ` ${ sanitizedUsername } : ${ appPassword } ` ) . toString ( 'base64' ) } ` ,
38+ 'User-Agent' : 'MiddlewareApp/1.0'
2339 } ,
24- } , true ) ;
40+ timeout : 10000
41+ } , true ) ;
2542
26- res . status ( 200 ) . json ( response ) ;
43+ if ( ! response . headers ) {
44+ return res . status ( 400 ) . json ( {
45+ message : 'Unable to retrieve permission information from BitBucket'
46+ } ) ;
47+ }
48+
49+ res . status ( 200 ) . json ( {
50+ ...response ,
51+ headers : response . headers
52+ } ) ;
2753 } catch ( error : any ) {
28- console . error ( 'Error fetching Bitbucket user:' , error . message ) ;
29- res . status ( error . response ?. status || 500 ) . json ( {
30- message : error . response ?. data ?. error ?. message || 'Internal Server Error' ,
54+ console . error ( 'Error fetching Bitbucket user:' , {
55+ message : error . message ,
56+ status : error . response ?. status ,
57+ hasCredentials : ! ! ( req . payload ?. username && req . payload ?. appPassword )
3158 } ) ;
59+
60+ const status = error . response ?. status || 500 ;
61+ let message = 'Internal Server Error' ;
62+
63+ switch ( status ) {
64+ case 401 :
65+ message = 'Invalid BitBucket credentials' ;
66+ break ;
67+ case 403 :
68+ message = 'Access forbidden. Check your App Password permissions' ;
69+ break ;
70+ case 404 :
71+ message = 'BitBucket user not found' ;
72+ break ;
73+ case 429 :
74+ message = 'Rate limit exceeded. Please try again later' ;
75+ break ;
76+ default :
77+ message = error . response ?. data ?. error ?. message || message ;
78+ }
79+
80+ res . status ( status ) . json ( { message } ) ;
3281 }
3382} ) ;
3483
0 commit comments