@@ -6,6 +6,7 @@ import { logger } from '../../lib/logger';
66import { cacheable } from '@databuddy/redis/cacheable' ;
77import { Resolver } from "node:dns" ;
88import { randomUUID , randomBytes } from "node:crypto" ;
9+ import { z } from 'zod' ;
910
1011// DNS resolver setup
1112const resolver = new Resolver ( ) ;
@@ -84,6 +85,16 @@ function getOwnerData(user: any, data: any) {
8485 : { userId : user . id } ;
8586}
8687
88+ // Validation schemas
89+ const createDomainSchema = z . object ( {
90+ name : z . string ( ) . min ( 1 ) . max ( 253 ) . regex ( / ^ [ a - z A - Z 0 - 9 . - ] + \. [ a - z A - Z ] { 2 , } $ / , 'Invalid domain format' ) ,
91+ projectId : z . string ( ) . uuid ( ) . optional ( )
92+ } ) ;
93+
94+ const updateDomainSchema = z . object ( {
95+ name : z . string ( ) . min ( 1 ) . max ( 253 ) . regex ( / ^ [ a - z A - Z 0 - 9 . - ] + \. [ a - z A - Z ] { 2 , } $ / , 'Invalid domain format' ) . optional ( )
96+ } ) ;
97+
8798// Create router
8899export const domainsRouter = new Hono < DomainsContext > ( ) ;
89100
@@ -202,13 +213,21 @@ domainsRouter.get('/project/:projectId', async (c) => {
202213 */
203214domainsRouter . post ( '/' , async ( c ) => {
204215 const user = c . get ( 'user' ) ;
205- const data = await c . req . json ( ) ;
216+ const rawData = await c . req . json ( ) ;
206217
207218 if ( ! user || ! user . id ) {
208219 return c . json ( { success : false , error : 'Unauthorized' } , 401 ) ;
209220 }
210221
211222 try {
223+ // Validate input data
224+ const validationResult = createDomainSchema . safeParse ( rawData ) ;
225+ if ( ! validationResult . success ) {
226+ const { response, status } = createResponse ( false , undefined , 'Invalid input data' , 400 ) ;
227+ return c . json ( { ...response , details : validationResult . error . issues } , status as any ) ;
228+ }
229+
230+ const data = validationResult . data ;
212231 logger . info ( `[Domain API] Creating domain: ${ data . name } ` ) ;
213232
214233 // Check if domain already exists
@@ -239,7 +258,7 @@ domainsRouter.post('/', async (c) => {
239258 const { response, status } = createResponse ( true , createdDomain ) ;
240259 return c . json ( response , status as any ) ;
241260 } catch ( error ) {
242- const { response, status } = handleError ( 'Domain creation' , error , { domainName : data . name , userId : user . id } ) ;
261+ const { response, status } = handleError ( 'Domain creation' , error , { domainName : rawData ? .name || 'unknown' , userId : user . id } ) ;
243262 return c . json ( response , status as any ) ;
244263 }
245264} ) ;
@@ -509,7 +528,7 @@ domainsRouter.post('/:id/verify', async (c) => {
509528 exactMatch : cleanTxt === cleanToken
510529 } ) ;
511530
512- return cleanTxt . includes ( cleanToken ) ;
531+ return cleanTxt === cleanToken ;
513532 } )
514533 ) ;
515534
@@ -603,8 +622,7 @@ domainsRouter.post('/:id/regenerate-token', async (c) => {
603622 domainId : id ,
604623 domainName : domain . name ,
605624 newStatus : 'PENDING' ,
606- newToken : `${ verificationToken . substring ( 0 , 8 ) } ...` ,
607- fullNewToken : verificationToken
625+ newToken : `${ verificationToken . substring ( 0 , 8 ) } ...`
608626 } ) ;
609627
610628 const { response, status } = createResponse ( true , updatedDomain ) ;
0 commit comments