11import fs from 'node:fs' ;
22import https from 'node:https' ;
3- import process from 'node:process' ;
43import express from 'express' ;
54import { describe , it } from 'mocha' ;
65import request from 'supertest' ;
76import yes from '../lib/index.js' ;
87
9- process . env . NODE_TLS_REJECT_UNAUTHORIZED = 0 ;
8+ const TEST_SERVER_CERT = fs . readFileSync ( './test/certs/server.crt' ) ;
109
1110describe ( 'yes' , ( ) => {
1211 it ( 'should perform the 301 for an http request' , ( done ) => {
@@ -40,16 +39,15 @@ describe('yes', () => {
4039
4140 // Verify the request returns the right header when using https
4241 const server = createSecureServer ( app ) ;
43- request ( 'https://localhost:8443' )
42+ request ( server )
4443 . get ( '/test' )
44+ . ca ( TEST_SERVER_CERT )
4545 . expect ( 'Strict-Transport-Security' , 'max-age=86400; includeSubDomains' )
4646 . expect ( 200 )
4747 . end ( ( error ) => {
4848 if ( error ) {
4949 throw error ;
5050 }
51-
52- server . close ( ) ;
5351 done ( ) ;
5452 } ) ;
5553 } ) . timeout ( 60_000 ) ;
@@ -66,16 +64,15 @@ describe('yes', () => {
6664 } ) ;
6765
6866 const server = createSecureServer ( app ) ;
69- request ( 'https://localhost:8443' )
67+ request ( server )
7068 . get ( '/test' )
69+ . ca ( TEST_SERVER_CERT )
7170 . expect ( 'Strict-Transport-Security' , 'max-age=86400' )
7271 . expect ( 200 )
7372 . end ( ( error ) => {
7473 if ( error ) {
7574 throw error ;
7675 }
77-
78- server . close ( ) ;
7976 done ( ) ;
8077 } ) ;
8178 } ) . timeout ( 60_000 ) ;
@@ -92,16 +89,15 @@ describe('yes', () => {
9289 } ) ;
9390
9491 const server = createSecureServer ( app ) ;
95- request ( 'https://localhost:8443' )
92+ request ( server )
9693 . get ( '/test' )
94+ . ca ( TEST_SERVER_CERT )
9795 . expect ( 'Strict-Transport-Security' , 'max-age=86400' )
9896 . expect ( 200 )
9997 . end ( ( error ) => {
10098 if ( error ) {
10199 throw error ;
102100 }
103-
104- server . close ( ) ;
105101 done ( ) ;
106102 } ) ;
107103 } ) . timeout ( 60_000 ) ;
@@ -131,20 +127,162 @@ describe('yes', () => {
131127 done ( ) ;
132128 } ) ;
133129 } ) ;
130+
131+ it ( 'should include preload when configured' , ( done ) => {
132+ const app = express ( ) ;
133+ app . use ( yes ( { preload : true } ) ) ;
134+ app . get ( '/test' , ( _request , response ) => {
135+ response . sendStatus ( 200 ) ;
136+ } ) ;
137+
138+ const server = createSecureServer ( app ) ;
139+ request ( server )
140+ . get ( '/test' )
141+ . ca ( TEST_SERVER_CERT )
142+ . expect (
143+ 'Strict-Transport-Security' ,
144+ 'max-age=86400; includeSubDomains; preload' ,
145+ )
146+ . expect ( 200 )
147+ . end ( ( error ) => {
148+ if ( error ) {
149+ throw error ;
150+ }
151+ done ( ) ;
152+ } ) ;
153+ } ) . timeout ( 60_000 ) ;
154+
155+ it ( 'should omit includeSubDomains when disabled' , ( done ) => {
156+ const app = express ( ) ;
157+ app . use ( yes ( { includeSubDomains : false } ) ) ;
158+ app . get ( '/test' , ( _request , response ) => {
159+ response . sendStatus ( 200 ) ;
160+ } ) ;
161+
162+ const server = createSecureServer ( app ) ;
163+ request ( server )
164+ . get ( '/test' )
165+ . ca ( TEST_SERVER_CERT )
166+ . expect ( 'Strict-Transport-Security' , 'max-age=86400' )
167+ . expect ( 200 )
168+ . end ( ( error ) => {
169+ if ( error ) {
170+ throw error ;
171+ }
172+ done ( ) ;
173+ } ) ;
174+ } ) . timeout ( 60_000 ) ;
175+
176+ it ( 'should include includeSubDomains when explicitly enabled' , ( done ) => {
177+ const app = express ( ) ;
178+ app . use ( yes ( { includeSubDomains : true } ) ) ;
179+ app . get ( '/test' , ( _request , response ) => {
180+ response . sendStatus ( 200 ) ;
181+ } ) ;
182+
183+ const server = createSecureServer ( app ) ;
184+ request ( server )
185+ . get ( '/test' )
186+ . ca ( TEST_SERVER_CERT )
187+ . expect ( 'Strict-Transport-Security' , 'max-age=86400; includeSubDomains' )
188+ . expect ( 200 )
189+ . end ( ( error ) => {
190+ if ( error ) {
191+ throw error ;
192+ }
193+ done ( ) ;
194+ } ) ;
195+ } ) . timeout ( 60_000 ) ;
196+
197+ describe ( 'includeSubDomains' , ( ) => {
198+ it ( 'should include the directive by default over a secure connection' , ( ) => {
199+ return expectSecureHeader ( { } , 'max-age=86400; includeSubDomains' ) ;
200+ } ) ;
201+
202+ it ( 'should include the directive when explicitly enabled over a secure connection' , ( ) => {
203+ return expectSecureHeader (
204+ { includeSubDomains : true } ,
205+ 'max-age=86400; includeSubDomains' ,
206+ ) ;
207+ } ) ;
208+
209+ it ( 'should omit the directive when disabled over a secure connection' , ( ) => {
210+ return expectSecureHeader ( { includeSubDomains : false } , 'max-age=86400' ) ;
211+ } ) ;
212+
213+ it ( 'should compose correctly with preload and maxAge when enabled' , ( ) => {
214+ return expectSecureHeader (
215+ { includeSubDomains : true , preload : true , maxAge : 31_536_000 } ,
216+ 'max-age=31536000; includeSubDomains; preload' ,
217+ ) ;
218+ } ) ;
219+
220+ it ( 'should compose correctly with preload and maxAge when disabled' , ( ) => {
221+ return expectSecureHeader (
222+ { includeSubDomains : false , preload : true , maxAge : 31_536_000 } ,
223+ 'max-age=31536000; preload' ,
224+ ) ;
225+ } ) ;
226+
227+ it ( 'should include the directive by default for forwarded https requests' , ( ) => {
228+ return expectForwardedSecureHeader (
229+ { } ,
230+ 'max-age=86400; includeSubDomains' ,
231+ ) ;
232+ } ) ;
233+
234+ it ( 'should honor an explicit true value for forwarded https requests' , ( ) => {
235+ return expectForwardedSecureHeader (
236+ { includeSubDomains : true } ,
237+ 'max-age=86400; includeSubDomains' ,
238+ ) ;
239+ } ) ;
240+
241+ it ( 'should honor an explicit false value for forwarded https requests' , ( ) => {
242+ return expectForwardedSecureHeader (
243+ { includeSubDomains : false } ,
244+ 'max-age=86400' ,
245+ ) ;
246+ } ) ;
247+ } ) ;
134248} ) ;
135249
136250function createSecureServer ( app ) {
137- // Server the app over https
138- return https
139- . createServer (
140- {
141- key : fs . readFileSync ( './test/certs/server.key' ) ,
142- cert : fs . readFileSync ( './test/certs/server.crt' ) ,
143- ca : fs . readFileSync ( './test/certs/ca.crt' ) ,
144- requestCert : true ,
145- rejectUnauthorized : false ,
146- } ,
147- app ,
148- )
149- . listen ( '8443' ) ;
251+ return https . createServer (
252+ {
253+ key : fs . readFileSync ( './test/certs/server.key' ) ,
254+ cert : fs . readFileSync ( './test/certs/server.crt' ) ,
255+ } ,
256+ app ,
257+ ) ;
258+ }
259+
260+ function expectSecureHeader ( options , expectedHeader ) {
261+ const app = express ( ) ;
262+ app . use ( yes ( options ) ) ;
263+ app . get ( '/test' , ( _request , response ) => {
264+ response . sendStatus ( 200 ) ;
265+ } ) ;
266+
267+ const server = createSecureServer ( app ) ;
268+ return request ( server )
269+ . get ( '/test' )
270+ . ca ( TEST_SERVER_CERT )
271+ . expect ( 'Strict-Transport-Security' , expectedHeader )
272+ . expect ( 200 ) ;
273+ }
274+
275+ function expectForwardedSecureHeader ( options , expectedHeader ) {
276+ const app = express ( ) ;
277+ app . use ( yes ( options ) ) ;
278+ app . get ( '/test' , ( _request , response ) => {
279+ response . sendStatus ( 200 ) ;
280+ } ) ;
281+
282+ return request ( app )
283+ . get ( '/test' )
284+ . set ( 'X-Forwarded-Proto' , 'https' )
285+ . set ( 'Host' , 'example.com' )
286+ . expect ( 'Strict-Transport-Security' , expectedHeader )
287+ . expect ( 200 ) ;
150288}
0 commit comments