mirror of
https://github.com/overleaf/overleaf.git
synced 2024-12-24 05:42:55 +00:00
Merge pull request #6523 from overleaf/jpa-translations-check-sanitize
[web] scripts/translations: add script for checking html sanitization GitOrigin-RevId: d4b9c9a7eb1ed0ca9202b0cb6e4c33f3e73bd0e4
This commit is contained in:
parent
64423936b9
commit
58cf92620a
3 changed files with 88 additions and 43 deletions
42
services/web/scripts/translations/checkSanitizeOptions.js
Normal file
42
services/web/scripts/translations/checkSanitizeOptions.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
const Path = require('path')
|
||||
const fs = require('fs')
|
||||
const { sanitize } = require('./sanitize')
|
||||
|
||||
async function main() {
|
||||
let ok = true
|
||||
const base = Path.join(__dirname, '/../../locales')
|
||||
for (const name of await fs.promises.readdir(base)) {
|
||||
if (name === 'README.md') continue
|
||||
const blob = await fs.promises.readFile(
|
||||
Path.join(__dirname, '/../../locales', name),
|
||||
'utf-8'
|
||||
)
|
||||
const locales = JSON.parse(blob)
|
||||
|
||||
for (const key of Object.keys(locales)) {
|
||||
const want = locales[key]
|
||||
const got = sanitize(locales[key])
|
||||
if (got !== want) {
|
||||
if (want === 'Editor & PDF' && got === 'Editor & PDF') {
|
||||
// Ignore this mismatch. React cannot handle escaped labels.
|
||||
continue
|
||||
}
|
||||
ok = false
|
||||
console.warn(`${name}: ${key}: want: ${want}`)
|
||||
console.warn(`${name}: ${key}: got: ${got}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
throw new Error('Check the logs, some values changed.')
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => {
|
||||
process.exit(0)
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error)
|
||||
process.exit(1)
|
||||
})
|
|
@ -1,7 +1,7 @@
|
|||
const path = require('path')
|
||||
const { promises: fs } = require('fs')
|
||||
const oneSky = require('@brainly/onesky-utils')
|
||||
const sanitizeHtml = require('sanitize-html')
|
||||
const { sanitize } = require('./sanitize')
|
||||
const { withAuth } = require('./config')
|
||||
|
||||
async function run() {
|
||||
|
@ -46,45 +46,3 @@ async function run() {
|
|||
}
|
||||
}
|
||||
run()
|
||||
|
||||
/**
|
||||
* Sanitize a translation string to prevent injection attacks
|
||||
*
|
||||
* @param {string} input
|
||||
* @returns {string}
|
||||
*/
|
||||
function sanitize(input) {
|
||||
// Block Angular XSS
|
||||
// Ticket: https://github.com/overleaf/issues/issues/4478
|
||||
input = input.replace(/'/g, '’')
|
||||
// Use left quote where (likely) appropriate.
|
||||
input.replace(/ ’/g, ' ‘')
|
||||
|
||||
return sanitizeHtml(input, {
|
||||
// Allow "replacement" tags (in the format <0>, <1>, <2>, etc) used by
|
||||
// react-i18next to allow for HTML insertion via the Trans component.
|
||||
// See: https://github.com/overleaf/developer-manual/blob/master/code/translations.md
|
||||
// Unfortunately the sanitizeHtml library does not accept regexes or a
|
||||
// function for the allowedTags option, so we are limited to a hard-coded
|
||||
// number of "replacement" tags.
|
||||
allowedTags: ['b', 'strong', 'a', 'code', ...range(10)],
|
||||
allowedAttributes: {
|
||||
a: ['href', 'class'],
|
||||
},
|
||||
textFilter(text) {
|
||||
return text
|
||||
.replace(/\{\{/, '{{')
|
||||
.replace(/\}\}/, '}}')
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a range of numbers as strings up to the given size
|
||||
*
|
||||
* @param {number} size Size of range
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function range(size) {
|
||||
return Array.from(Array(size).keys()).map(n => n.toString())
|
||||
}
|
||||
|
|
45
services/web/scripts/translations/sanitize.js
Normal file
45
services/web/scripts/translations/sanitize.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
const sanitizeHtml = require('sanitize-html')
|
||||
|
||||
/**
|
||||
* Sanitize a translation string to prevent injection attacks
|
||||
*
|
||||
* @param {string} input
|
||||
* @returns {string}
|
||||
*/
|
||||
function sanitize(input) {
|
||||
// Block Angular XSS
|
||||
// Ticket: https://github.com/overleaf/issues/issues/4478
|
||||
input = input.replace(/'/g, '’')
|
||||
// Use left quote where (likely) appropriate.
|
||||
input.replace(/ ’/g, ' ‘')
|
||||
|
||||
return sanitizeHtml(input, {
|
||||
// Allow "replacement" tags (in the format <0>, <1>, <2>, etc) used by
|
||||
// react-i18next to allow for HTML insertion via the Trans component.
|
||||
// See: https://github.com/overleaf/developer-manual/blob/master/code/translations.md
|
||||
// Unfortunately the sanitizeHtml library does not accept regexes or a
|
||||
// function for the allowedTags option, so we are limited to a hard-coded
|
||||
// number of "replacement" tags.
|
||||
allowedTags: ['b', 'strong', 'a', 'code', ...range(10)],
|
||||
allowedAttributes: {
|
||||
a: ['href', 'class'],
|
||||
},
|
||||
textFilter(text) {
|
||||
return text
|
||||
.replace(/\{\{/, '{{')
|
||||
.replace(/\}\}/, '}}')
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a range of numbers as strings up to the given size
|
||||
*
|
||||
* @param {number} size Size of range
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function range(size) {
|
||||
return Array.from(Array(size).keys()).map(n => n.toString())
|
||||
}
|
||||
|
||||
module.exports = { sanitize }
|
Loading…
Reference in a new issue