44import { NextRequest } from 'next/server' ;
55import { getSessionServer } from '@utils/amplify-utils' ;
66import { middleware } from '../middleware' ;
7+ import { getClientIdFromToken } from '@utils/token-utils' ;
78
89jest . mock ( '@utils/amplify-utils' ) ;
10+ jest . mock ( '@utils/token-utils' ) ;
911
1012const getTokenMock = jest . mocked ( getSessionServer ) ;
13+ const getClientIdFromTokenMock = jest . mocked ( getClientIdFromToken ) ;
1114
1215function getCsp ( response : Response ) {
1316 const csp = response . headers . get ( 'Content-Security-Policy' ) ;
@@ -19,6 +22,13 @@ afterAll(() => {
1922 process . env = OLD_ENV ;
2023} ) ;
2124
25+ beforeEach ( ( ) => {
26+ jest . resetAllMocks ( ) ;
27+ getClientIdFromTokenMock . mockImplementation ( ( token ) =>
28+ token ? 'client1' : undefined
29+ ) ;
30+ } ) ;
31+
2232describe ( 'middleware function' , ( ) => {
2333 it ( 'If route is not registered in middleware, respond with 404' , async ( ) => {
2434 const url = new URL ( 'https://url.com/message-templates/does-not-exist' ) ;
@@ -28,7 +38,7 @@ describe('middleware function', () => {
2838 expect ( response . status ) . toBe ( 404 ) ;
2939 } ) ;
3040
31- it ( 'if request path is protected, and no access token is obtained, redirect to auth page' , async ( ) => {
41+ it ( 'if request path is protected, and no access/id token is obtained, redirect to auth page' , async ( ) => {
3242 const url = new URL ( 'https://url.com/message-templates' ) ;
3343 const request = new NextRequest ( url ) ;
3444 request . cookies . set ( 'csrf_token' , 'some-csrf-value' ) ;
@@ -50,9 +60,9 @@ describe('middleware function', () => {
5060 expect ( response . cookies . get ( 'csrf_token' ) ?. value ) . toEqual ( '' ) ;
5161 } ) ;
5262
53- it ( 'if request path is protected, and access token is obtained , respond with CSP' , async ( ) => {
63+ it ( 'if request path is protected, tokens exist AND token has client-id , respond with CSP' , async ( ) => {
5464 getTokenMock . mockResolvedValueOnce ( {
55- accessToken : 'token' ,
65+ accessToken : 'access- token' ,
5666 clientId : 'client1' ,
5767 } ) ;
5868
@@ -61,6 +71,9 @@ describe('middleware function', () => {
6171 const response = await middleware ( request ) ;
6272 const csp = getCsp ( response ) ;
6373
74+ expect ( response . status ) . toBe ( 200 ) ;
75+ expect ( getClientIdFromTokenMock ) . toHaveBeenCalledTimes ( 1 ) ;
76+
6477 expect ( csp ) . toEqual ( [
6578 "base-uri 'self'" ,
6679 "default-src 'none'" ,
@@ -79,12 +92,58 @@ describe('middleware function', () => {
7992 ] ) ;
8093 } ) ;
8194
95+ it ( 'if request path is protected, tokens exist BUT token missing client-id, redirect to request-to-be-added page' , async ( ) => {
96+ getTokenMock . mockResolvedValueOnce ( {
97+ accessToken : 'access-token' ,
98+ } ) ;
99+
100+ getClientIdFromTokenMock . mockReturnValueOnce ( undefined ) ;
101+ getClientIdFromTokenMock . mockReturnValueOnce ( undefined ) ;
102+
103+ const url = new URL ( 'https://url.com/message-templates' ) ;
104+ const request = new NextRequest ( url ) ;
105+ const response = await middleware ( request ) ;
106+
107+ expect ( response . status ) . toBe ( 307 ) ;
108+ expect ( response . headers . get ( 'location' ) ) . toBe (
109+ 'https://url.com/auth/request-to-be-added-to-a-service?redirect=%2Ftemplates%2Fmessage-templates'
110+ ) ;
111+ } ) ;
112+
82113 it ( 'if request path is not protected, respond with CSP' , async ( ) => {
83114 const url = new URL ( 'https://url.com/create-and-submit-templates' ) ;
84115 const request = new NextRequest ( url ) ;
85116 const response = await middleware ( request ) ;
86117 const csp = getCsp ( response ) ;
87118
119+ expect ( response . status ) . toBe ( 200 ) ;
120+ expect ( csp ) . toEqual ( [
121+ "base-uri 'self'" ,
122+ "default-src 'none'" ,
123+ "frame-ancestors 'none'" ,
124+ "font-src 'self' https://assets.nhs.uk" ,
125+ "form-action 'self'" ,
126+ "frame-src 'self'" ,
127+ "connect-src 'self' https://cognito-idp.eu-west-2.amazonaws.com" ,
128+ "img-src 'self'" ,
129+ "manifest-src 'self'" ,
130+ "object-src 'none'" ,
131+ expect . stringMatching ( / ^ s c r i p t - s r c ' s e l f ' ' n o n c e - [ \d A - Z a - z ] + ' $ / ) ,
132+ expect . stringMatching ( / ^ s t y l e - s r c ' s e l f ' ' n o n c e - [ \d A - Z a - z ] + ' $ / ) ,
133+ 'upgrade-insecure-requests' ,
134+ '' ,
135+ ] ) ;
136+ } ) ;
137+
138+ it ( 'public path (/auth/request-to-be-added-to-a-service) responds with CSP' , async ( ) => {
139+ const url = new URL (
140+ 'https://url.com/auth/request-to-be-added-to-a-service'
141+ ) ;
142+ const request = new NextRequest ( url ) ;
143+ const response = await middleware ( request ) ;
144+ const csp = getCsp ( response ) ;
145+
146+ expect ( response . status ) . toBe ( 200 ) ;
88147 expect ( csp ) . toEqual ( [
89148 "base-uri 'self'" ,
90149 "default-src 'none'" ,
0 commit comments