88*/
99
1010async function handles3filebaseRequest ( request ) {
11- if ( request . method !== 'POST' || ! request . headers . get ( 'Content-Type' ) . includes ( 'multipart/form-data' ) ) {
12- return new Response ( 'Invalid request' , { status : 400 } ) ;
13- }
11+ console . log ( '[S3-Filebase] Starting request handling' ) ;
1412
15- try {
16- // 从 KV 获取配置
13+ if ( request . method !== 'POST' || ! request . headers . get ( 'Content-Type' ) . includes ( 'multipart/form-data' ) ) {
14+ console . error ( '[S3-Filebase] Invalid request method or content type:' , {
15+ method : request . method ,
16+ contentType : request . headers . get ( 'Content-Type' )
17+ } ) ;
18+ return new Response ( 'Invalid request' , { status : 400 } ) ;
19+ }
20+
21+ try {
22+ console . log ( '[S3-Filebase] Fetching configuration from KV store' ) ;
1723 const config = await WORKER_IMGBED . get ( 's3filebase_config' , 'json' ) ;
1824 if ( ! config || ! config . accessKey || ! config . secretKey || ! config . bucket ) {
19- throw new Error ( 'Invalid S3 configuration' ) ;
25+ console . error ( '[S3-Filebase] Invalid configuration:' , {
26+ hasConfig : ! ! config ,
27+ hasAccessKey : ! ! config ?. accessKey ,
28+ hasSecretKey : ! ! config ?. secretKey ,
29+ hasBucket : ! ! config ?. bucket
30+ } ) ;
31+ throw new Error ( 'Invalid S3 configuration' ) ;
2032 }
21-
33+ console . log ( '[S3-Filebase] Configuration loaded successfully' ) ;
34+
2235 const formData = await request . formData ( ) ;
2336 const file = formData . get ( 'image' ) ;
2437 if ( ! file ) {
25- return new Response ( 'No file found' , { status : 400 } ) ;
38+ console . error ( '[S3-Filebase] No file found in form data' ) ;
39+ return new Response ( 'No file found' , { status : 400 } ) ;
2640 }
27-
28- const now = new Date ( ) ;
29- const timestamp = now . toISOString ( )
30- . replace ( / [ - : ] / g, '' )
31- . split ( '.' ) [ 0 ]
32- . replace ( 'T' , '_' ) ;
41+
42+ // 获取安全的文件名
43+ const originalName = file . name ;
44+ const extension = originalName . split ( '.' ) . pop ( ) || '' ;
45+ const timestamp = new Date ( ) . toISOString ( )
46+ . replace ( / [ - : ] / g, '' )
47+ . split ( '.' ) [ 0 ]
48+ . replace ( 'T' , '_' ) ;
3349
34- const fileName = file . name . split ( '.' ) [ 0 ] ;
35- const extension = file . name . split ( '.' ) . pop ( ) || '' ;
36- const s3Key = `${ fileName } _${ timestamp } .${ extension } ` ;
50+ // 生成安全的文件名:使用时间戳和随机字符串,避免中文和特殊字符
51+ const safeFileName = `${ timestamp } _${ Math . random ( ) . toString ( 36 ) . substring ( 2 , 15 ) } .${ extension } ` ;
52+ console . log ( '[S3-Filebase] File details:' , {
53+ originalName,
54+ safeFileName,
55+ type : file . type ,
56+ size : file . size
57+ } ) ;
58+
3759 const content = await file . arrayBuffer ( ) ;
38-
60+ console . log ( '[S3-Filebase] File content loaded:' , {
61+ contentSize : content . byteLength
62+ } ) ;
63+
64+ // AWS 签名所需的时间戳
65+ const now = new Date ( ) ;
3966 const amzdate = now . toISOString ( ) . replace ( / [: -] | \. \d { 3 } / g, '' ) ;
4067 const dateStamp = amzdate . slice ( 0 , 8 ) ;
68+
69+ // 计算内容哈希
4170 const contentHash = await crypto . subtle . digest ( 'SHA-256' , content )
42- . then ( buf => Array . from ( new Uint8Array ( buf ) )
43- . map ( b => b . toString ( 16 ) . padStart ( 2 , '0' ) )
44- . join ( '' ) ) ;
45-
46- const canonicalUri = `/${ config . bucket } /${ s3Key } ` ;
71+ . then ( buf => Array . from ( new Uint8Array ( buf ) )
72+ . map ( b => b . toString ( 16 ) . padStart ( 2 , '0' ) )
73+ . join ( '' ) ) ;
74+
75+ // URI 编码的路径
76+ const encodedKey = encodeURIComponent ( safeFileName ) . replace ( / % 2 0 / g, '+' ) ;
77+ const canonicalUri = `/${ config . bucket } /${ encodedKey } ` ;
78+
79+ // 准备签名所需的头部
4780 const uploadHeaders = {
48- 'Host' : 's3.filebase.com' ,
49- 'Content-Type' : file . type || 'application/octet-stream' ,
50- 'X-Amz-Content-SHA256' : contentHash ,
51- 'X-Amz-Date' : amzdate
81+ 'Host' : 's3.filebase.com' ,
82+ 'Content-Type' : file . type || 'application/octet-stream' ,
83+ 'X-Amz-Content-SHA256' : contentHash ,
84+ 'X-Amz-Date' : amzdate
5285 } ;
53-
86+
87+ console . log ( '[S3-Filebase] Request preparation:' , {
88+ canonicalUri,
89+ amzdate,
90+ contentHashPrefix : contentHash . substring ( 0 , 16 ) + '...'
91+ } ) ;
92+
5493 const algorithm = 'AWS4-HMAC-SHA256' ;
5594 const region = 'us-east-1' ;
5695 const service = 's3' ;
5796 const scope = `${ dateStamp } /${ region } /${ service } /aws4_request` ;
58-
97+
98+ // 准备规范请求
5999 const canonicalHeaders = Object . entries ( uploadHeaders )
60- . map ( ( [ k , v ] ) => `${ k . toLowerCase ( ) } :${ v } \n` )
61- . sort ( )
62- . join ( '' ) ;
100+ . map ( ( [ k , v ] ) => `${ k . toLowerCase ( ) } :${ v } \n` )
101+ . sort ( )
102+ . join ( '' ) ;
63103 const signedHeaders = Object . keys ( uploadHeaders )
64- . map ( k => k . toLowerCase ( ) )
65- . sort ( )
66- . join ( ';' ) ;
67-
104+ . map ( k => k . toLowerCase ( ) )
105+ . sort ( )
106+ . join ( ';' ) ;
107+
68108 const canonicalRequest = [
69- 'PUT' ,
70- canonicalUri ,
71- '' ,
72- canonicalHeaders ,
73- signedHeaders ,
74- contentHash
109+ 'PUT' ,
110+ canonicalUri ,
111+ '' ,
112+ canonicalHeaders ,
113+ signedHeaders ,
114+ contentHash
75115 ] . join ( '\n' ) ;
76-
116+
117+ console . log ( '[S3-Filebase] Canonical request prepared:' , {
118+ method : 'PUT' ,
119+ uri : canonicalUri ,
120+ signedHeaders
121+ } ) ;
122+
77123 const stringToSign = [
78- algorithm ,
79- amzdate ,
80- scope ,
81- await crypto . subtle . digest ( 'SHA-256' , new TextEncoder ( ) . encode ( canonicalRequest ) )
82- . then ( buf => Array . from ( new Uint8Array ( buf ) )
83- . map ( b => b . toString ( 16 ) . padStart ( 2 , '0' ) )
84- . join ( '' ) )
124+ algorithm ,
125+ amzdate ,
126+ scope ,
127+ await crypto . subtle . digest ( 'SHA-256' , new TextEncoder ( ) . encode ( canonicalRequest ) )
128+ . then ( buf => Array . from ( new Uint8Array ( buf ) )
129+ . map ( b => b . toString ( 16 ) . padStart ( 2 , '0' ) )
130+ . join ( '' ) )
85131 ] . join ( '\n' ) ;
86-
132+
133+ // 生成签名密钥
87134 let key = await crypto . subtle . importKey (
88- 'raw' ,
89- new TextEncoder ( ) . encode ( `AWS4${ config . secretKey } ` ) ,
90- { name : 'HMAC' , hash : 'SHA-256' } ,
91- false ,
92- [ 'sign' ]
93- ) ;
94-
95- for ( const msg of [ dateStamp , region , service , 'aws4_request' ] ) {
96- key = await crypto . subtle . importKey (
97135 'raw' ,
98- await crypto . subtle . sign ( 'HMAC' , key , new TextEncoder ( ) . encode ( msg ) ) ,
136+ new TextEncoder ( ) . encode ( `AWS4 ${ config . secretKey } ` ) ,
99137 { name : 'HMAC' , hash : 'SHA-256' } ,
100138 false ,
101139 [ 'sign' ]
102- ) ;
140+ ) ;
141+
142+ for ( const msg of [ dateStamp , region , service , 'aws4_request' ] ) {
143+ key = await crypto . subtle . importKey (
144+ 'raw' ,
145+ await crypto . subtle . sign ( 'HMAC' , key , new TextEncoder ( ) . encode ( msg ) ) ,
146+ { name : 'HMAC' , hash : 'SHA-256' } ,
147+ false ,
148+ [ 'sign' ]
149+ ) ;
103150 }
104-
151+
152+ // 计算最终签名
105153 const signature = await crypto . subtle . sign (
106- 'HMAC' ,
107- key ,
108- new TextEncoder ( ) . encode ( stringToSign )
154+ 'HMAC' ,
155+ key ,
156+ new TextEncoder ( ) . encode ( stringToSign )
109157 ) ;
110-
111- const authorization =
112- `${ algorithm } ` +
113- `Credential=${ config . accessKey } /${ scope } , ` +
114- `SignedHeaders=${ signedHeaders } , ` +
115- `Signature=${ Array . from ( new Uint8Array ( signature ) )
116- . map ( b => b . toString ( 16 ) . padStart ( 2 , '0' ) )
117- . join ( '' ) } `;
118-
119- const uploadResponse = await fetch ( `https://s3.filebase.com${ canonicalUri } ` , {
120- method : 'PUT' ,
121- headers : {
122- ...uploadHeaders ,
123- 'Authorization' : authorization
124- } ,
125- body : content
158+
159+ // 构建授权头
160+ const credential = `${ config . accessKey } /${ dateStamp } /${ region } /${ service } /aws4_request` ;
161+ const authorization = [
162+ `${ algorithm } Credential=${ credential } ` ,
163+ `SignedHeaders=${ signedHeaders } ` ,
164+ `Signature=${ Array . from ( new Uint8Array ( signature ) )
165+ . map ( b => b . toString ( 16 ) . padStart ( 2 , '0' ) )
166+ . join ( '' ) } `
167+ ] . join ( ', ' ) ;
168+
169+ console . log ( '[S3-Filebase] Authorization prepared:' , {
170+ credentialPrefix : credential . split ( '/' ) [ 0 ] + '/...' ,
171+ signedHeadersCount : signedHeaders . split ( ';' ) . length
126172 } ) ;
127-
173+
174+ // 发送上传请求
175+ const uploadUrl = `https://s3.filebase.com${ canonicalUri } ` ;
176+ console . log ( '[S3-Filebase] Sending upload request to:' , uploadUrl ) ;
177+
178+ const uploadResponse = await fetch ( uploadUrl , {
179+ method : 'PUT' ,
180+ headers : {
181+ ...uploadHeaders ,
182+ 'Authorization' : authorization
183+ } ,
184+ body : content
185+ } ) ;
186+
128187 if ( ! uploadResponse . ok ) {
129- throw new Error ( `Upload failed with status ${ uploadResponse . status } ` ) ;
188+ const errorBody = await uploadResponse . text ( ) ;
189+ console . error ( '[S3-Filebase] Upload failed:' , {
190+ status : uploadResponse . status ,
191+ statusText : uploadResponse . statusText ,
192+ responseBody : errorBody ,
193+ headers : Object . fromEntries ( [ ...uploadResponse . headers ] )
194+ } ) ;
195+ throw new Error ( `Upload failed with status ${ uploadResponse . status } : ${ errorBody } ` ) ;
130196 }
131-
197+
198+ console . log ( '[S3-Filebase] Upload successful' ) ;
132199 const cid = uploadResponse . headers . get ( 'x-amz-meta-cid' ) ;
133200 if ( ! cid ) {
134- throw new Error ( 'CID not found in response' ) ;
201+ console . error ( '[S3-Filebase] CID not found in response headers:' ,
202+ Object . fromEntries ( [ ...uploadResponse . headers ] ) ) ;
203+ throw new Error ( 'CID not found in response' ) ;
135204 }
136-
137- return new Response ( `https://i0.wp.com/i0.img2ipfs.com/ipfs/${ cid } ` ) ;
138-
139- } catch ( error ) {
140- return new Response ( `Upload failed: ${ error . message } ` , { status : 500 } ) ;
141- }
142- }
205+
206+ const finalUrl = `https://i0.wp.com/i0.img2ipfs.com/ipfs/${ cid } ` ;
207+ console . log ( '[S3-Filebase] Generated final URL:' , finalUrl ) ;
208+ return new Response ( finalUrl ) ;
209+
210+ } catch ( error ) {
211+ console . error ( '[S3-Filebase] Error in request handling:' , {
212+ name : error . name ,
213+ message : error . message ,
214+ stack : error . stack
215+ } ) ;
216+ return new Response ( `Upload failed: ${ error . message } ` , {
217+ status : 500 ,
218+ headers : {
219+ 'Content-Type' : 'text/plain' ,
220+ 'X-Error-Details' : error . message
221+ }
222+ } ) ;
223+ }
224+ }
0 commit comments