Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const config = convict({
},
enforceCsrf: {
format: Boolean,
default: isProduction,
default: true,
env: 'ENFORCE_CSRF'
},

Expand Down
74 changes: 0 additions & 74 deletions src/server/plugins/engine/helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
getExponentialBackoffDelay,
getPageHref,
proceed,
safeGenerateCrumb,
type GlobalScope
} from '~/src/server/plugins/engine/helpers.js'
import { handleLegacyRedirect } from '~/src/server/plugins/engine/helpers.js'
Expand All @@ -30,7 +29,6 @@ import {
import {
FormAction,
FormStatus,
type FormRequest,
type FormResponseToolkit
} from '~/src/server/routes/types.js'
import definition from '~/test/form/definitions/basic.js'
Expand Down Expand Up @@ -446,78 +444,6 @@ describe('Helpers', () => {
})
})

describe('safeGenerateCrumb', () => {
it('should return undefined when request.state is missing (malformed request)', () => {
const malformedRequest = {
server: {
plugins: {
crumb: {
generate: jest.fn()
}
}
},
plugins: {},
route: { settings: { plugins: {} } },
path: '/test',
url: { search: '' }
// state intentionally omitted
} as unknown as FormRequest

const crumbToken = safeGenerateCrumb(malformedRequest)
expect(crumbToken).toBeUndefined()
expect(
malformedRequest.server.plugins.crumb.generate
).not.toHaveBeenCalled()
})

it('should return undefined if crumb is disabled in route settings', () => {
const requestWithDisabledCrumb = {
server: {
plugins: {
crumb: {
generate: jest.fn().mockReturnValue('test-token')
}
}
},
plugins: {},
route: { settings: { plugins: { crumb: false } } },
path: '/test',
url: { search: '' },
state: {}
} as unknown as FormRequest

const crumbToken = safeGenerateCrumb(requestWithDisabledCrumb)
expect(crumbToken).toBeUndefined()
expect(
requestWithDisabledCrumb.server.plugins.crumb.generate
).not.toHaveBeenCalled()
})

it('should generate crumb when state exists and crumb plugin is available', () => {
const mockCrumb = 'generated-crumb-value'
const validRequest = {
server: {
plugins: {
crumb: {
generate: jest.fn().mockReturnValue(mockCrumb)
}
}
},
plugins: {},
route: { settings: { plugins: {} } },
path: '/test',
url: { search: '' },
state: {}
} as unknown as FormRequest

const crumbToken = safeGenerateCrumb(validRequest)
expect(crumbToken).toBe(mockCrumb)
expect(validRequest.server.plugins.crumb.generate).toHaveBeenCalledWith(
validRequest
)
})
})

describe('getExponentialBackoffDelay', () => {
it.each([
{ depth: 1, expected: 2000 },
Expand Down
27 changes: 0 additions & 27 deletions src/server/plugins/engine/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
import { type FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
import { type PageControllerClass } from '~/src/server/plugins/engine/pageControllers/helpers/pages.js'
import {
type AnyFormRequest,
type FormContext,
type FormContextRequest,
type FormSubmissionError
Expand Down Expand Up @@ -320,32 +319,6 @@ export function getError(detail: ValidationErrorItem): FormSubmissionError {
}
}

/**
* A small helper to safely generate a crumb token.
* Checks that the crumb plugin is available, that crumb
* is not disabled on the current route, and that cookies/state are present.
*/
export function safeGenerateCrumb(
request: AnyFormRequest | null
): string | undefined {
// no request or no .state
if (!request?.state) {
return undefined
}

// crumb plugin or its generate method doesn't exist
if (!request.server.plugins.crumb.generate) {
return undefined
}

// crumb is explicitly disabled for this route
if (request.route.settings.plugins?.crumb === false) {
return undefined
}

return request.server.plugins.crumb.generate(request)
}

/**
* Calculates an exponential backoff delay (in milliseconds) based on the current retry depth,
* using a base delay of 2000ms (2 seconds) and doubling for each additional depth, while capping the delay at 25,000ms (25 seconds).
Expand Down
4 changes: 1 addition & 3 deletions src/server/plugins/nunjucks/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import { config } from '~/src/config/index.js'
import { createLogger } from '~/src/server/common/helpers/logging/logger.js'
import {
checkFormStatus,
encodeUrl,
safeGenerateCrumb
encodeUrl
} from '~/src/server/plugins/engine/helpers.js'

const logger = createLogger()
Expand Down Expand Up @@ -51,7 +50,6 @@ export async function context(request) {
// take consumers props first so we can override it
...consumerViewContext,
baseLayoutPath: pluginStorage.baseLayoutPath,
crumb: safeGenerateCrumb(request),
currentPath: `${request.path}${request.url.search}`,
previewMode: isPreviewMode ? formState : undefined,
slug: isResponseOK ? params?.slug : undefined
Expand Down
33 changes: 0 additions & 33 deletions src/server/plugins/nunjucks/context.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,39 +98,6 @@ describe('Nunjucks context', () => {
malformedRequest.server.plugins.crumb.generate
).not.toHaveBeenCalled()
})

it('should generate crumb when state exists', async () => {
const mockCrumb = 'generated-crumb-value'
const validRequest = /** @type {FormRequest} */ (
/** @type {unknown} */ ({
server: {
plugins: {
crumb: {
generate: jest.fn().mockReturnValue(mockCrumb)
},
'forms-engine-plugin': {
baseLayoutPath: 'randomValue'
}
}
},
plugins: {},
route: {
settings: {
plugins: {}
}
},
path: '/test',
url: { search: '' },
state: {}
})
)

const { crumb } = await context(validRequest)
expect(crumb).toBe(mockCrumb)
expect(validRequest.server.plugins.crumb.generate).toHaveBeenCalledWith(
validRequest
)
})
})
})

Expand Down
4 changes: 3 additions & 1 deletion src/server/routes/dummy-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ describe('Dummy API', () => {

beforeAll(async () => {
MockDate.set('2025-01-01T00:00:00Z')
server = await createServer()
server = await createServer({
enforceCsrf: false
})
await server.initialize()
})

Expand Down
3 changes: 2 additions & 1 deletion test/condition/checkboxes.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ describe('Checkboxes based conditions', () => {
beforeAll(async () => {
server = await createServer({
formFileName: 'checkboxes.json',
formFilePath: resolve(import.meta.dirname, '../form/definitions')
formFilePath: resolve(import.meta.dirname, '../form/definitions'),
enforceCsrf: false
})

await server.initialize()
Expand Down
3 changes: 2 additions & 1 deletion test/condition/radios.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ describe('Radio based conditions', () => {
beforeAll(async () => {
server = await createServer({
formFileName: 'radios.json',
formFilePath: resolve(import.meta.dirname, '../form/definitions')
formFilePath: resolve(import.meta.dirname, '../form/definitions'),
enforceCsrf: false
})

await server.initialize()
Expand Down
3 changes: 2 additions & 1 deletion test/condition/text.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ describe('TextField based conditions', () => {
beforeAll(async () => {
server = await createServer({
formFileName: 'text.json',
formFilePath: resolve(import.meta.dirname, '../form/definitions')
formFilePath: resolve(import.meta.dirname, '../form/definitions'),
enforceCsrf: false
})

await server.initialize()
Expand Down
3 changes: 2 additions & 1 deletion test/form/file-upload.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ describe('File upload POST tests', () => {
beforeAll(async () => {
server = await createServer({
formFileName: 'file-upload.js',
formFilePath: resolve(import.meta.dirname, '../form/definitions')
formFilePath: resolve(import.meta.dirname, '../form/definitions'),
enforceCsrf: false
})

await server.initialize()
Expand Down
3 changes: 2 additions & 1 deletion test/form/govuk-notify.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ describe('Submission journey test', () => {
beforeAll(async () => {
server = await createServer({
formFileName: 'components.json',
formFilePath: join(import.meta.dirname, 'definitions')
formFilePath: join(import.meta.dirname, 'definitions'),
enforceCsrf: false
})

await server.initialize()
Expand Down
6 changes: 4 additions & 2 deletions test/form/joined-conditions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ describe('Joined conditions functional tests', () => {
beforeAll(async () => {
server = await createServer({
formFileName: 'joined-conditions-simple-v2.js',
formFilePath: resolve(import.meta.dirname, 'definitions')
formFilePath: resolve(import.meta.dirname, 'definitions'),
enforceCsrf: false
})
await server.initialize()
})
Expand Down Expand Up @@ -270,7 +271,8 @@ describe('Joined conditions functional tests', () => {
beforeAll(async () => {
server = await createServer({
formFileName: 'joined-conditions-complex-v2.js',
formFilePath: resolve(import.meta.dirname, 'definitions')
formFilePath: resolve(import.meta.dirname, 'definitions'),
enforceCsrf: false
})
await server.initialize()
})
Expand Down
3 changes: 2 additions & 1 deletion test/form/persist-files.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ describe('Submission journey test', () => {
beforeAll(async () => {
server = await createServer({
formFileName: 'file-upload-basic.js',
formFilePath: join(import.meta.dirname, 'definitions')
formFilePath: join(import.meta.dirname, 'definitions'),
enforceCsrf: false
})

await server.initialize()
Expand Down
6 changes: 4 additions & 2 deletions test/form/repeat.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ describe('Repeat GET tests', () => {
beforeAll(async () => {
server = await createServer({
formFileName: 'repeat.js',
formFilePath: resolve(import.meta.dirname, '../form/definitions')
formFilePath: resolve(import.meta.dirname, '../form/definitions'),
enforceCsrf: false
})

const model = server.app.model
Expand Down Expand Up @@ -363,7 +364,8 @@ describe('Repeat POST tests', () => {
server = await createServer({
formFileName: 'repeat.js',
formFilePath: resolve(import.meta.dirname, '../form/definitions'),
saveAndExit: (request, h, _context) => h.redirect('/my-save-and-exit')
saveAndExit: (request, h, _context) => h.redirect('/my-save-and-exit'),
enforceCsrf: false
})

const model = server.app.model
Expand Down
Loading