11import type { AuthContext } from "better-auth" ;
22import { createAuthEndpoint , getSessionFromCtx , sessionMiddleware } from "better-auth/api" ;
33import type { FieldAttribute } from "better-auth/db" ;
4- import { z , type ZodRawShape , type ZodTypeAny } from "zod" ;
4+ import { z , type ZodType } from "zod" ;
55import type { FileMetadata , R2Config } from "./types" ;
66
77export const R2_ERROR_CODES = {
@@ -86,10 +86,10 @@ function validateFileMetadata(record: any): record is FileMetadata {
8686 * Converts Better Auth FieldAttribute to Zod schema (same pattern as feedback plugin)
8787 */
8888function convertFieldAttributesToZodSchema ( additionalFields : Record < string , FieldAttribute > ) {
89- const zodSchema : ZodRawShape = { } ;
89+ const zodSchema : Record < string , ZodType > = { } ;
9090
9191 for ( const [ key , value ] of Object . entries ( additionalFields ) ) {
92- let fieldSchema : ZodTypeAny ;
92+ let fieldSchema : ZodType ;
9393
9494 if ( value . type === "string" ) {
9595 fieldSchema = z . string ( ) ;
@@ -120,7 +120,7 @@ function convertFieldAttributesToZodSchema(additionalFields: Record<string, Fiel
120120// Zod schemas for validation
121121export const createFileMetadataSchema = ( additionalFields ?: Record < string , FieldAttribute > ) => {
122122 if ( ! additionalFields || Object . keys ( additionalFields ) . length === 0 ) {
123- return z . record ( z . any ( ) ) . optional ( ) ;
123+ return z . record ( z . string ( ) , z . any ( ) ) . optional ( ) ;
124124 }
125125 return convertFieldAttributesToZodSchema ( additionalFields ) . optional ( ) ;
126126} ;
@@ -141,7 +141,7 @@ export const listFilesSchema = z
141141 * Creates upload schema dynamically based on additionalFields configuration
142142 */
143143export const createUploadFileSchema = ( additionalFields ?: Record < string , FieldAttribute > ) => {
144- const baseShape : ZodRawShape = {
144+ const baseShape : Record < string , ZodType > = {
145145 file : z . instanceof ( File ) ,
146146 } ;
147147
@@ -151,7 +151,7 @@ export const createUploadFileSchema = (additionalFields?: Record<string, FieldAt
151151
152152 // Add additionalFields to the schema
153153 for ( const [ key , value ] of Object . entries ( additionalFields ) ) {
154- let fieldSchema : ZodTypeAny ;
154+ let fieldSchema : ZodType ;
155155
156156 if ( value . type === "string" ) {
157157 fieldSchema = z . string ( ) ;
@@ -257,7 +257,7 @@ export const createFileValidator = (config: R2Config) => {
257257
258258 if ( ! result . success ) {
259259 // Extract detailed error information from Zod
260- const errorMessages = result . error . errors
260+ const errorMessages = result . error . issues
261261 . map ( err => {
262262 const path = err . path . length > 0 ? `${ err . path . join ( "." ) } : ` : "" ;
263263 return `${ path } ${ err . message } ` ;
@@ -268,7 +268,7 @@ export const createFileValidator = (config: R2Config) => {
268268 ctx ?. logger ?. error ( `[R2]: Metadata validation failed:` , {
269269 error : detailedError ,
270270 metadata,
271- zodErrors : result . error . errors ,
271+ zodErrors : result . error . issues ,
272272 } ) ;
273273
274274 return error ( detailedError , "INVALID_METADATA" ) ;
@@ -561,13 +561,32 @@ export const createR2Endpoints = (
561561 }
562562
563563 // Get filename and metadata from headers
564- const filename = ctx . request ?. headers ?. get ( "x-filename" ) ;
565- const metadataHeader = ctx . request ?. headers ?. get ( "x-file-metadata" ) ;
564+ const rawFilename = ctx . request ?. headers ?. get ( "x-filename" ) ;
565+ const rawMetadataHeader = ctx . request ?. headers ?. get ( "x-file-metadata" ) ;
566566
567- if ( ! filename ) {
567+ if ( ! rawFilename ) {
568568 throw new Error ( "x-filename header is required" ) ;
569569 }
570570
571+ // Sanitize header values to ensure it only contains ASCII characters
572+ const filename = rawFilename
573+ . split ( "" )
574+ . map ( char => {
575+ const code = char . charCodeAt ( 0 ) ;
576+ return code <= 127 ? char : "?" ;
577+ } )
578+ . join ( "" ) ;
579+
580+ const metadataHeader = rawMetadataHeader
581+ ? rawMetadataHeader
582+ . split ( "" )
583+ . map ( char => {
584+ const code = char . charCodeAt ( 0 ) ;
585+ return code <= 127 ? char : "?" ;
586+ } )
587+ . join ( "" )
588+ : undefined ;
589+
571590 // Parse metadata from headers
572591 let additionalFields : Record < string , any > = { } ;
573592 if ( metadataHeader ) {
0 commit comments