@@ -12,13 +12,32 @@ function fetchWithtimeout(
1212 url : string ,
1313 options : RequestInit ,
1414 timeout = 5000
15- ) : any {
16- return Promise . race ( [
17- fetch ( url , options ) ,
18- new Promise ( ( _ , reject ) =>
19- setTimeout ( ( ) => reject ( new Error ( "Request timed out" ) ) , timeout )
20- ) ,
21- ] ) ;
15+ ) : Promise < Response > {
16+ let parsedUrl : URL ;
17+ try {
18+ parsedUrl = new URL ( url ) ;
19+ } catch ( e ) {
20+ throw new Error ( "Invalid URL" ) ;
21+ }
22+
23+ if ( ! [ 'http:' , 'https:' ] . includes ( parsedUrl . protocol ) ) {
24+ throw new Error ( `Forbidden protocol: ${ parsedUrl . protocol } ` ) ;
25+ }
26+
27+ const forbiddenHosts = [ 'localhost' , '127.0.0.1' , '169.254.169.254' ] ;
28+ if ( forbiddenHosts . includes ( parsedUrl . hostname ) ) {
29+ throw new Error ( "Access to internal resources is forbidden" ) ;
30+ }
31+
32+ const controller = new AbortController ( ) ;
33+ const id = setTimeout ( ( ) => controller . abort ( ) , timeout ) ;
34+
35+ return fetch ( parsedUrl . toString ( ) , {
36+ ...options ,
37+ signal : controller . signal ,
38+ } ) . finally ( ( ) => {
39+ clearTimeout ( id ) ;
40+ } ) ;
2241}
2342
2443async function loadImage ( content : Blob ) : Promise < string | ArrayBuffer | null > {
@@ -223,24 +242,22 @@ async function makeRequest(
223242 }
224243
225244 if ( fileExtension ) {
226- return response . blob ( ) . then ( ( blob : Blob ) => {
245+ return response . blob ( ) . then ( ( blob : any ) => {
227246 const url = window . URL . createObjectURL ( blob ) ;
228247
229248 const link = document . createElement ( "a" ) ;
230249 link . href = url ;
231250 // Now the file name includes the extension
232251 link . setAttribute ( "download" , `file${ fileExtension } ` ) ;
233252
234- // These lines are necessary to make the link click in Firefox
235- const hiddenContainer = document . createElement ( "div" ) ;
236- hiddenContainer . style . display = "none" ;
237- hiddenContainer . appendChild ( link ) ;
238- document . body . appendChild ( hiddenContainer ) ;
253+ // These two lines are necessary to make the link click in Firefox
254+ link . style . display = "none" ;
255+ document . body . appendChild ( link ) ;
239256
240257 link . click ( ) ;
241258
242259 // After link is clicked, it's safe to remove it.
243- setTimeout ( ( ) => document . body . removeChild ( hiddenContainer ) , 0 ) ;
260+ setTimeout ( ( ) => document . body . removeChild ( link ) , 0 ) ;
244261
245262 return response ;
246263 } ) ;
0 commit comments