@@ -2,7 +2,7 @@ import type { Context, Env, MiddlewareHandler } from 'hono'
22import { getMimeType } from 'hono/utils/mime'
33import type { ReadStream , Stats } from 'node:fs'
44import { createReadStream , lstatSync } from 'node:fs'
5- import { join , resolve } from 'node:path'
5+ import { join } from 'node:path'
66
77export type ServeStaticOptions < E extends Env = Env > = {
88 /**
@@ -56,7 +56,7 @@ const getStats = (path: string) => {
5656export const serveStatic = < E extends Env = any > (
5757 options : ServeStaticOptions < E > = { root : '' }
5858) : MiddlewareHandler < E > => {
59- const root = resolve ( options . root || '.' )
59+ const root = options . root || ''
6060 const optionPath = options . path
6161
6262 return async ( c , next ) => {
@@ -67,44 +67,30 @@ export const serveStatic = <E extends Env = any>(
6767
6868 let filename : string
6969
70- try {
71- const rawPath = optionPath ?? c . req . path
72- // Prevent encoded path traversal attacks
73- if ( ! optionPath ) {
74- const decodedPath = decodeURIComponent ( rawPath )
75- if ( decodedPath . includes ( '..' ) ) {
76- await options . onNotFound ?.( rawPath , c )
77- return next ( )
70+ if ( optionPath ) {
71+ filename = optionPath
72+ } else {
73+ try {
74+ filename = decodeURIComponent ( c . req . path )
75+ if ( / (?: ^ | [ \/ \\ ] ) \. \. (?: $ | [ \/ \\ ] ) / . test ( filename ) ) {
76+ throw new Error ( )
7877 }
78+ } catch {
79+ await options . onNotFound ?.( c . req . path , c )
80+ return next ( )
7981 }
80- filename = optionPath ?? decodeURIComponent ( c . req . path )
81- } catch {
82- await options . onNotFound ?.( c . req . path , c )
83- return next ( )
8482 }
8583
86- const requestPath = options . rewriteRequestPath
87- ? options . rewriteRequestPath ( filename , c )
88- : filename
89-
90- let path = optionPath
91- ? options . root
92- ? resolve ( join ( root , optionPath ) )
93- : optionPath
94- : resolve ( join ( root , requestPath ) )
84+ let path = join (
85+ root ,
86+ ! optionPath && options . rewriteRequestPath ? options . rewriteRequestPath ( filename , c ) : filename
87+ )
9588
9689 let stats = getStats ( path )
9790
9891 if ( stats && stats . isDirectory ( ) ) {
9992 const indexFile = options . index ?? 'index.html'
100- path = resolve ( join ( path , indexFile ) )
101-
102- // Security check: prevent path traversal attacks
103- if ( ! optionPath && ! path . startsWith ( root ) ) {
104- await options . onNotFound ?.( path , c )
105- return next ( )
106- }
107-
93+ path = join ( path , indexFile )
10894 stats = getStats ( path )
10995 }
11096
0 commit comments