diff --git a/services/web/app/src/infrastructure/UnsupportedBrowserMiddleware.js b/services/web/app/src/infrastructure/UnsupportedBrowserMiddleware.js new file mode 100644 index 0000000000..e07f709481 --- /dev/null +++ b/services/web/app/src/infrastructure/UnsupportedBrowserMiddleware.js @@ -0,0 +1,23 @@ +const Bowser = require('bowser') +const Settings = require('settings-sharelatex') + +function unsupportedBrowserMiddleware(req, res, next) { + if (!Settings.unsupportedBrowsers) return next() + + const userAgent = req.headers['user-agent'] + + const parser = Bowser.getParser(userAgent) + + // Allow bots through by only ignoring bots or unrecognised UA strings + const isBot = parser.isPlatform('bot') || !parser.getBrowserName() + if (isBot) return next() + + const isUnsupported = parser.satisfies(Settings.unsupportedBrowsers) + if (isUnsupported) { + return res.redirect('/unsupported-browser') + } + + next() +} + +module.exports = { unsupportedBrowserMiddleware } diff --git a/services/web/app/src/router.js b/services/web/app/src/router.js index 4a844309cc..cd50032b20 100644 --- a/services/web/app/src/router.js +++ b/services/web/app/src/router.js @@ -49,6 +49,9 @@ const InstitutionsController = require('./Features/Institutions/InstitutionsCont const UserMembershipRouter = require('./Features/UserMembership/UserMembershipRouter') const SystemMessageController = require('./Features/SystemMessages/SystemMessageController') const { Joi, validate } = require('./infrastructure/Validation') +const { + unsupportedBrowserMiddleware +} = require('./infrastructure/UnsupportedBrowserMiddleware') const logger = require('logger-sharelatex') const _ = require('underscore') @@ -263,6 +266,7 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) { maxRequests: 30, timeInterval: 60 }), + unsupportedBrowserMiddleware, ProjectController.projectListPage ) webRouter.post( @@ -284,6 +288,7 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) { maxRequests: 15, timeInterval: 60 }), + unsupportedBrowserMiddleware, AuthenticationController.validateUserSession(), AuthorizationMiddleware.ensureUserCanReadProject, ProjectController.loadEditor @@ -1138,5 +1143,9 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) { TokenAccessController.grantTokenAccessReadOnly ) + webRouter.get('/unsupported-browser', (req, res) => { + res.render('general/unsupported-browser') + }) + webRouter.get('*', ErrorController.notFound) } diff --git a/services/web/app/views/general/unsupported-browser.pug b/services/web/app/views/general/unsupported-browser.pug new file mode 100644 index 0000000000..dcf5135953 --- /dev/null +++ b/services/web/app/views/general/unsupported-browser.pug @@ -0,0 +1,16 @@ +extends ../layout/layout-no-js + +block vars + - metadata = { title: 'Unsupported browser', viewport: true } + +block body + body.full-height + main.content.content-alt.full-height + .container.full-height + .error-container.full-height + .error-details + h1.error-status Unsupported Browser + p.error-description + | Sorry, we don't support your browser anymore. Find out more about #[a(href="https://www.overleaf.com/learn/how-to/What_browsers_do_you_support") what browsers we support]. + br + | If you think you're seeing this message in error, please #[a(href="/contact") let us know]. diff --git a/services/web/package-lock.json b/services/web/package-lock.json index 633ad494db..5a7a5db47d 100644 --- a/services/web/package-lock.json +++ b/services/web/package-lock.json @@ -2710,7 +2710,17 @@ "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==" + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } } } }, @@ -5848,6 +5858,12 @@ "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", "dev": true }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, "@uppy/companion-client": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/@uppy/companion-client/-/companion-client-1.8.2.tgz", @@ -6000,12 +6016,6 @@ "cuid": "^2.1.1" } }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, "@webassemblyjs/ast": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", @@ -8815,9 +8825,9 @@ "dev": true }, "bowser": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz", - "integrity": "sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA==" + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" }, "boxen": { "version": "4.2.0", @@ -16681,6 +16691,13 @@ "camelize": "1.0.0", "content-security-policy-builder": "2.1.0", "dasherize": "2.0.0" + }, + "dependencies": { + "bowser": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz", + "integrity": "sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA==" + } } }, "hex-color-regex": { diff --git a/services/web/package.json b/services/web/package.json index fecab3cb6c..1f647c83ab 100644 --- a/services/web/package.json +++ b/services/web/package.json @@ -69,6 +69,7 @@ "basic-auth-connect": "^1.0.0", "bcrypt": "^5.0.0", "body-parser": "^1.19.0", + "bowser": "^2.11.0", "bufferedstream": "1.6.0", "bull": "^3.18.0", "celebrate": "^10.0.1",