@@ -12,7 +12,6 @@ import ResizeType from './enums/resize-type.enum';
1212
1313const IMGPROXY_ENDPOINT = '/_next/imgproxy' ;
1414const SRC_REGEX = / ^ [ ^ / . ] + \/ .+ [ ^ / ] $ / ;
15-
1615const FORWARDED_HEADERS = [
1716 'date' ,
1817 'expires' ,
@@ -22,6 +21,49 @@ const FORWARDED_HEADERS = [
2221 'content-disposition' ,
2322] ;
2423
24+ /**
25+ * Generates the signature for the specified uery
26+ * @param key The signature key
27+ * @param salt The signature salt$
28+ * @param buff The full request path
29+ * @returns The imgproxy signature
30+ */
31+ const generateSignature = ( key : string , salt : string , buff : string ) : string => {
32+ const hmac = createHmac ( 'sha256' , Buffer . from ( key , 'hex' ) ) ;
33+ hmac . update ( Buffer . from ( salt , 'hex' ) ) ;
34+ hmac . update ( buff ) ;
35+ return hmac . digest ( ) . toString ( 'base64url' ) ;
36+ } ;
37+
38+ /**
39+ * Builds the final reuest path to retrieve
40+ * an image from the imgproxy instance
41+ * @param src The source file
42+ * @param options The imgproxy options
43+ * @returns The imgproxy request path
44+ */
45+ const buildRequestPath = (
46+ src : string ,
47+ options ?: {
48+ imgproxyParams ?: string ;
49+ signature ?: {
50+ key : string ;
51+ salt : string ;
52+ } ;
53+ } ,
54+ ) : string => {
55+ const { imgproxyParams, signature } = options ?? { } ;
56+
57+ const paramString = imgproxyParams ? `${ imgproxyParams } /` : '' ;
58+ const requestPath = `/${ paramString } plain/s3://${ src } ` ;
59+
60+ const urlSignature = signature
61+ ? generateSignature ( signature . key , signature . salt , requestPath )
62+ : '' ;
63+
64+ return `/${ urlSignature } ${ requestPath } ` ;
65+ } ;
66+
2567type ImageOptimizerOptions = {
2668 signature ?: {
2769 key : string ;
@@ -32,19 +74,20 @@ type ImageOptimizerOptions = {
3274 forwardedHeaders ?: string [ ] ;
3375} ;
3476
35- const generateSignature = ( key : string , salt : string , buff : string ) : string => {
36- const hmac = createHmac ( 'sha256' , Buffer . from ( key , 'hex' ) ) ;
37- hmac . update ( Buffer . from ( salt , 'hex' ) ) ;
38- hmac . update ( buff ) ;
39- return hmac . digest ( ) . toString ( 'base64url' ) ;
40- } ;
41-
42- const imageOptimizer = (
77+ /**
78+ * Handles an image request
79+ * @param imgproxyBaseUrl The URL to the imgproxy instance
80+ * @param query The URL query generated by the {@link ImgProxyParamBuilder}
81+ * @param res The response to which the resulting file should be piped to
82+ * @param options Optional configuration options for the imgproxy connection
83+ * @returns
84+ */
85+ const handle = (
4386 imgproxyBaseUrl : URL ,
4487 query : ParsedUrlQuery ,
4588 res : ServerResponse ,
4689 options ?: ImageOptimizerOptions ,
47- ) => {
90+ ) : void => {
4891 const { src, params } = query ;
4992 const { authToken, bucketWhitelist, forwardedHeaders, signature } =
5093 options ?? { } ;
@@ -64,12 +107,10 @@ const imageOptimizer = (
64107 return ;
65108 }
66109
67- const paramString = params ? `${ params } /` : '' ;
68- const requestPath = `/${ paramString } plain/s3://${ src } ` ;
69-
70- const urlSignature = signature
71- ? generateSignature ( signature . key , signature . salt , requestPath )
72- : '' ;
110+ const requestPath = buildRequestPath ( src , {
111+ imgproxyParams : params as string ,
112+ signature,
113+ } ) ;
73114
74115 const reqMethod = imgproxyBaseUrl . protocol . startsWith ( 'https' )
75116 ? httpsRequest
@@ -79,7 +120,7 @@ const imageOptimizer = (
79120 {
80121 hostname : imgproxyBaseUrl . hostname ,
81122 ...( imgproxyBaseUrl . port ? { port : imgproxyBaseUrl . port } : { } ) ,
82- path : `/ ${ urlSignature } ${ requestPath } ` ,
123+ path : requestPath ,
83124 method : 'GET' ,
84125 headers : {
85126 ...( authToken ? { Authorization : `Bearer ${ authToken } ` } : { } ) ,
@@ -161,7 +202,8 @@ export default ProxyImage;
161202export {
162203 IMGPROXY_ENDPOINT ,
163204 buildProxyImagePath ,
164- imageOptimizer ,
205+ handle ,
206+ generateSignature ,
165207 ImgProxyParamBuilder ,
166208 GravityType ,
167209 ResizeType ,
0 commit comments