@@ -4,7 +4,7 @@ import fnv1a from '@sindresorhus/fnv1a';
4
4
5
5
import { noCacheFetchOptions } from '@/lib/cache/http' ;
6
6
7
- import { rootUrl } from './links' ;
7
+ import { host , rootUrl } from './links' ;
8
8
import { getImageAPIUrl } from './urls' ;
9
9
10
10
export interface CloudflareImageJsonFormat {
@@ -31,6 +31,8 @@ export interface CloudflareImageOptions {
31
31
quality ?: number ;
32
32
}
33
33
34
+ export const imagesResizingSignVersion = '2' ;
35
+
34
36
/**
35
37
* Return true if images resizing is enabled.
36
38
*/
@@ -83,7 +85,7 @@ export function getResizedImageURLFactory(
83
85
return null ;
84
86
}
85
87
86
- const signature = generateSignatureV1 ( input ) ;
88
+ const signature = generateSignature ( input ) ;
87
89
88
90
return ( options ) => {
89
91
const url = new URL ( '/~gitbook/image' , rootUrl ( ) ) ;
@@ -103,7 +105,7 @@ export function getResizedImageURLFactory(
103
105
}
104
106
105
107
url . searchParams . set ( 'sign' , signature ) ;
106
- url . searchParams . set ( 'sv' , '1' ) ;
108
+ url . searchParams . set ( 'sv' , imagesResizingSignVersion ) ;
107
109
108
110
return url . toString ( ) ;
109
111
} ;
@@ -123,11 +125,9 @@ export function getResizedImageURL(input: string, options: ResizeImageOptions):
123
125
*/
124
126
export async function verifyImageSignature (
125
127
input : string ,
126
- { signature, version } : { signature : string ; version : '1' | '0' } ,
128
+ { signature } : { signature : string } ,
127
129
) : Promise < boolean > {
128
- const expectedSignature =
129
- version === '1' ? generateSignatureV1 ( input ) : await generateSignatureV0 ( input ) ;
130
- return expectedSignature === signature ;
130
+ return generateSignature ( input ) === signature ;
131
131
}
132
132
133
133
/**
@@ -229,26 +229,17 @@ function stringifyOptions(options: CloudflareImageOptions): string {
229
229
const fnv1aUtf8Buffer = new Uint8Array ( 512 ) ;
230
230
231
231
/**
232
- * New and faster algorithm to generate a signature for an image.
233
- * When setting it in a URL, we use version '1' for the 'sv' querystring parameneter
234
- * to know that it was the algorithm that was used.
232
+ * Generate a signature for an image.
233
+ * The signature is relative to the current site being rendered to avoid serving images from other sites on the same domain.
235
234
*/
236
- function generateSignatureV1 ( input : string ) : string {
237
- const all = [ input , process . env . GITBOOK_IMAGE_RESIZE_SIGNING_KEY ] . filter ( Boolean ) . join ( ':' ) ;
235
+ function generateSignature ( input : string ) {
236
+ const hostName = host ( ) ;
237
+ const all = [
238
+ input ,
239
+ hostName , // The hostname is used to avoid serving images from other sites on the same domain
240
+ process . env . GITBOOK_IMAGE_RESIZE_SIGNING_KEY ,
241
+ ]
242
+ . filter ( Boolean )
243
+ . join ( ':' ) ;
238
244
return fnv1a ( all , { utf8Buffer : fnv1aUtf8Buffer } ) . toString ( 16 ) ;
239
245
}
240
-
241
- /**
242
- * Initial algorithm used to generate a signature for an image. It didn't use any versioning in the URL.
243
- * We still need it to validate older signatures that were generated without versioning
244
- * but still exist in previously generated and cached content.
245
- */
246
- async function generateSignatureV0 ( input : string ) : Promise < string > {
247
- const all = [ input , process . env . GITBOOK_IMAGE_RESIZE_SIGNING_KEY ] . filter ( Boolean ) . join ( ':' ) ;
248
- const hash = await crypto . subtle . digest ( 'SHA-256' , new TextEncoder ( ) . encode ( all ) ) ;
249
-
250
- // Convert ArrayBuffer to hex string
251
- const hashArray = Array . from ( new Uint8Array ( hash ) ) ;
252
- const hashHex = hashArray . map ( ( b ) => b . toString ( 16 ) . padStart ( 2 , '0' ) ) . join ( '' ) ;
253
- return hashHex ;
254
- }
0 commit comments