diff --git a/server/routes/alerts-and-warnings.js b/server/routes/alerts-and-warnings.js index 66557dc37..eedf34064 100644 --- a/server/routes/alerts-and-warnings.js +++ b/server/routes/alerts-and-warnings.js @@ -11,7 +11,8 @@ const { failActionHandler, renderNotFound, renderLocationNotFound, - createQueryParametersString + createQueryParametersString, + hasInvalidCharacters } = require('./lib/utils') const route = 'alerts-and-warnings' @@ -37,6 +38,10 @@ async function routeHandler (request, h) { return h.view(route, { model }) } + if (hasInvalidCharacters(location, request.query.q)) { + return renderNotFound(location) + } + if (!location) { const data = await request.server.methods.flood.getFloods() floods = new Floods(data) @@ -44,10 +49,6 @@ async function routeHandler (request, h) { return h.view(route, { model }) } - if (isLocationEngland(location)) { - return h.redirect(`/${route}`) - } - const [place] = await locationService.find(location) if (!place) { @@ -106,7 +107,13 @@ async function locationRouteHandler (request, h) { module.exports = [{ method: 'GET', path: `/${route}`, - handler: routeHandler, + handler: (request, h) => { + if (request.query.q && isLocationEngland(util.cleanseLocation(request.query.q))) { + return h.redirect(`/${route}`) + } + + return routeHandler(request, h) + }, options: { validate: { query: joi.object({ @@ -146,7 +153,13 @@ module.exports = [{ { method: 'POST', path: `/${route}`, - handler: routeHandler, + handler: (request, h) => { + if (isLocationEngland(util.cleanseLocation(request.payload.location))) { + return h.redirect(`/${route}`) + } + + return routeHandler(request, h) + }, options: { validate: { payload: joi.object({ diff --git a/server/routes/lib/utils.js b/server/routes/lib/utils.js index 6cd3dc854..64dc727f5 100644 --- a/server/routes/lib/utils.js +++ b/server/routes/lib/utils.js @@ -5,6 +5,10 @@ function slugify (text = '') { return text.replace(/,/g, '').replace(/ /g, '-').toLowerCase() } +function hasInvalidCharacters (location, q) { + return !location && q +} + function filterDisambiguationPlaces (places) { return isPlaceEngland(places[0]) ? places : [] } @@ -63,6 +67,7 @@ module.exports = { isLocationEngland, isPlaceEngland, isValidLocationSlug, + hasInvalidCharacters, renderNotFound, renderLocationNotFound, createQueryParametersString, diff --git a/server/routes/river-and-sea-levels.js b/server/routes/river-and-sea-levels.js index 633f76786..dad1e80d1 100644 --- a/server/routes/river-and-sea-levels.js +++ b/server/routes/river-and-sea-levels.js @@ -22,7 +22,8 @@ const { filterDisambiguationPlaces, isValidLocationSlug, isLocationEngland, - isPlaceEngland + isPlaceEngland, + hasInvalidCharacters } = require('./lib/utils') const route = 'river-and-sea-levels' @@ -66,12 +67,12 @@ async function locationQueryHandler (request, h) { request.yar.set('q', { location }) - if (!location) { - return h.view(route, { model: emptyResultsModel() }) + if (hasInvalidCharacters(location, request.query.q)) { + return renderNotFound(location) } - if (isLocationEngland(location)) { - return h.redirect(`/${route}`) + if (!location) { + return h.view(route, { model: emptyResultsModel() }) } const rivers = await request.server.methods.flood.getRiversByName(location) @@ -213,6 +214,10 @@ module.exports = [{ // note: the redirects below are to handle any bookmarks users may have as all internal links use the new format // the redirects can be removed at some point in the future when we are no longer concerned about broken bookmarks if (request.query.q) { + if (isLocationEngland(util.cleanseLocation(request.query.q))) { + return h.redirect(`/${route}`) + } + return locationQueryHandler(request, h) } if (rainfallid) { @@ -266,7 +271,13 @@ module.exports = [{ }, { method: 'POST', path: `/${route}`, - handler: locationQueryHandler, + handler: (request, h) => { + if (isLocationEngland(util.cleanseLocation(request.payload.location))) { + return h.redirect(`/${route}`) + } + + return locationQueryHandler(request, h) + }, options: { validate: { payload: joi.object({ diff --git a/server/util.js b/server/util.js index 9aca3893c..baaf51fb5 100644 --- a/server/util.js +++ b/server/util.js @@ -5,7 +5,7 @@ const wreck = require('@hapi/wreck').defaults({ timeout: config.httpTimeoutMs }) const LocationSearchError = require('./location-search-error') -const ALLOWED_SEARCH_CHARS = 'a-zA-Z0-9\',-.& ()' +const ALLOWED_SEARCH_CHARS = 'a-zA-Z0-9\',-.& ()!' async function request (method, url, options) { let res, payload diff --git a/test/routes/alerts-and-warnings.js b/test/routes/alerts-and-warnings.js index d504aa015..caa59b8ad 100644 --- a/test/routes/alerts-and-warnings.js +++ b/test/routes/alerts-and-warnings.js @@ -311,6 +311,37 @@ lab.experiment('Test - /alerts-warnings', () => { Code.expect(response.statusCode).to.equal(200) }) + lab.test('GET /alerts-and-warnings with non-latin characters should 404', async () => { + stubs.getJson.callsFake(() => data.nonLocationGetJson) + stubs.getFloods.callsFake(() => ({ floods: [] })) + + const options = { + method: 'GET', + url: '/alerts-and-warnings?q=你好' + } + + const response = await server.inject(options) + + Code.expect(response.statusCode).to.equal(404) + }) + + lab.test('POST /alerts-and-warnings with non-latin characters should return default page', async () => { + stubs.getJson.callsFake(() => {}) + stubs.getFloods.callsFake(() => ({ floods: [] })) + + const options = { + method: 'POST', + url: '/alerts-and-warnings', + payload: { + location: '你好' + } + } + + const response = await server.inject(options) + + Code.expect(response.statusCode).to.equal(200) + }) + lab.test('POST /alerts-and-warnings with location payload', async () => { stubs.getJson.callsFake(() => data.warringtonGetJson) stubs.getIsEngland.callsFake(() => ({ is_england: true })) diff --git a/test/routes/river-and-sea-levels.js b/test/routes/river-and-sea-levels.js index 9e8341aa8..36935a7d1 100644 --- a/test/routes/river-and-sea-levels.js +++ b/test/routes/river-and-sea-levels.js @@ -1290,4 +1290,35 @@ lab.experiment('Test - /river-and-sea-levels', () => { fullRelatedContentChecker(root) }) }) + + lab.test('GET /river-and-sea-levels with non-latin characters should 404', async () => { + stubs.getStations.callsFake(() => []) + stubs.getIsEngland.callsFake(() => ({ is_england: true })) + + const options = { + method: 'GET', + url: '/river-and-sea-levels?q=你好' + } + + const response = await server.inject(options) + + Code.expect(response.statusCode).to.equal(404) + }) + + lab.test('POST /river-and-sea-levels with non-latin characters should return default page', async () => { + stubs.getStations.callsFake(() => []) + stubs.getIsEngland.callsFake(() => ({ is_england: true })) + + const options = { + method: 'POST', + url: '/river-and-sea-levels', + payload: { + location: '你好' + } + } + + const response = await server.inject(options) + + Code.expect(response.statusCode).to.equal(200) + }) })