@@ -266,19 +266,55 @@ function validateOptionalBase64String (
266266 * @throws WERR_INVALID_PARAMETER when invalid
267267 */
268268function validateBase64String ( s : string , name : string , min ?: number , max ?: number ) : string {
269- // Remove any whitespace and check if the string length is valid for Base64
270269 s = s . trim ( )
271- const base64Regex = / ^ (?: [ A - Z a - z 0 - 9 + / ] { 4 } ) * (?: [ A - Z a - z 0 - 9 + / ] { 2 } = = | [ A - Z a - z 0 - 9 + / ] { 3 } = ) ? $ /
272- const paddingMatch = / = + $ / . exec ( s )
273- const paddingCount = ( paddingMatch != null ) ? paddingMatch [ 0 ] . length : 0
270+ if ( s . length === 0 ) {
271+ throw new WERR_INVALID_PARAMETER ( name , 'valid base64 string' )
272+ }
274273
275- if ( paddingCount > 2 || ( s . length % 4 !== 0 && paddingCount !== 0 ) || ! base64Regex . test ( s ) ) {
274+ let paddingCount = 0
275+ let validCharCount = 0
276+
277+ for ( let i = 0 ; i < s . length ; i ++ ) {
278+ const char = s . charCodeAt ( i )
279+ if ( char >= 65 && char <= 90 ) continue // A-Z
280+ if ( char >= 97 && char <= 122 ) continue // a-z
281+ if ( char >= 48 && char <= 57 ) continue // 0-9
282+ if ( char === 43 ) continue // +
283+ if ( char === 47 ) continue // /
284+ if ( char === 61 ) { // =
285+ if ( i < s . length - 2 ) {
286+ throw new WERR_INVALID_PARAMETER ( name , 'valid base64 string' )
287+ }
288+ paddingCount ++
289+ continue
290+ }
276291 throw new WERR_INVALID_PARAMETER ( name , 'valid base64 string' )
277292 }
278293
279- const bytes = Utils . toArray ( s , 'base64' ) . length
280- if ( min !== undefined && bytes < min ) throw new WERR_INVALID_PARAMETER ( name , `at least ${ min } length.` )
281- if ( max !== undefined && bytes > max ) throw new WERR_INVALID_PARAMETER ( name , `no more than ${ max } length.` )
294+ // Padding rules
295+ if ( paddingCount > 2 ) {
296+ throw new WERR_INVALID_PARAMETER ( name , 'valid base64 string' )
297+ }
298+ if ( paddingCount > 0 && s . length % 4 !== 0 ) {
299+ throw new WERR_INVALID_PARAMETER ( name , 'valid base64 string' )
300+ }
301+
302+ // Length must be multiple of 4 if no padding, or valid with padding
303+ const mod = s . length % 4
304+ if ( mod !== 0 && mod !== ( 4 - paddingCount ) ) {
305+ throw new WERR_INVALID_PARAMETER ( name , 'valid base64 string' )
306+ }
307+
308+ // Calculate decoded byte length: (valid chars * 6) / 8
309+ const encodedLength = s . length - paddingCount
310+ const bytes = Math . floor ( encodedLength * 3 / 4 )
311+
312+ if ( min !== undefined && bytes < min ) {
313+ throw new WERR_INVALID_PARAMETER ( name , `at least ${ min } bytes` )
314+ }
315+ if ( max !== undefined && bytes > max ) {
316+ throw new WERR_INVALID_PARAMETER ( name , `no more than ${ max } bytes` )
317+ }
282318
283319 return s
284320}
0 commit comments