i18next-http-middleware 3.7.3 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/cjs/LanguageDetector.js +2 -3
- package/cjs/index.js +1 -1
- package/cjs/languageLookups/cookie.js +2 -1
- package/cjs/utils.js +8 -0
- package/esm/LanguageDetector.js +2 -3
- package/esm/index.js +1 -1
- package/esm/languageLookups/cookie.js +2 -1
- package/esm/utils.js +7 -0
- package/lib/LanguageDetector.js +3 -2
- package/lib/index.js +1 -0
- package/lib/languageLookups/cookie.js +1 -1
- package/lib/utils.js +23 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -403,6 +403,7 @@ As with all modules you can either pass the constructor function (class) to the
|
|
|
403
403
|
cookiePath: '/my/path',
|
|
404
404
|
cookieSecure: true, // if need secure cookie
|
|
405
405
|
cookieSameSite: 'strict', // 'strict', 'lax' or 'none'
|
|
406
|
+
cookieHttpOnly: true // prevent client-side script access to the cookie
|
|
406
407
|
|
|
407
408
|
// optional conversion function used to modify the detected language code
|
|
408
409
|
convertDetectedLanguage: 'Iso15897',
|
package/cjs/LanguageDetector.js
CHANGED
|
@@ -81,9 +81,8 @@ var LanguageDetector = function () {
|
|
|
81
81
|
if (!detections) return;
|
|
82
82
|
if (!Array.isArray(detections)) detections = [detections];
|
|
83
83
|
detections = detections.filter(function (d) {
|
|
84
|
-
return d !== undefined && d !== null;
|
|
85
|
-
})
|
|
86
|
-
detections = detections.map(function (d) {
|
|
84
|
+
return d !== undefined && d !== null && !utils.hasXSS(d);
|
|
85
|
+
}).map(function (d) {
|
|
87
86
|
return _this.options.convertDetectedLanguage(d);
|
|
88
87
|
});
|
|
89
88
|
if (_this.services.languageUtils.getBestMatchFromCodes) {
|
package/cjs/index.js
CHANGED
|
@@ -190,7 +190,7 @@ function getResourcesHandler(i18next) {
|
|
|
190
190
|
}
|
|
191
191
|
var resources = {};
|
|
192
192
|
options.setContentType(res, 'application/json');
|
|
193
|
-
if (options.cache !== undefined ? options.cache : typeof process !== 'undefined' && process.env && process.env.NODE_ENV === 'production') {
|
|
193
|
+
if (options.cache !== undefined ? options.cache : typeof process !== 'undefined' && typeof process.env !== 'undefined' && process.env && process.env.NODE_ENV === 'production') {
|
|
194
194
|
options.setHeader(res, 'Cache-Control', 'public, max-age=' + maxAge);
|
|
195
195
|
options.setHeader(res, 'Expires', new Date(new Date().getTime() + maxAge * 1000).toUTCString());
|
|
196
196
|
} else {
|
|
@@ -69,6 +69,7 @@ var _default = exports.default = {
|
|
|
69
69
|
cacheUserLanguage: function cacheUserLanguage(req, res, lng) {
|
|
70
70
|
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
71
71
|
if (options.lookupCookie && req !== 'undefined') {
|
|
72
|
+
var _options$cookieHttpOn;
|
|
72
73
|
var expirationDate = options.cookieExpirationDate;
|
|
73
74
|
if (!expirationDate) {
|
|
74
75
|
expirationDate = new Date();
|
|
@@ -78,7 +79,7 @@ var _default = exports.default = {
|
|
|
78
79
|
expires: expirationDate,
|
|
79
80
|
domain: options.cookieDomain,
|
|
80
81
|
path: options.cookiePath,
|
|
81
|
-
httpOnly: false,
|
|
82
|
+
httpOnly: (_options$cookieHttpOn = options.cookieHttpOnly) !== null && _options$cookieHttpOn !== void 0 ? _options$cookieHttpOn : false,
|
|
82
83
|
overwrite: true,
|
|
83
84
|
sameSite: options.cookieSameSite
|
|
84
85
|
};
|
package/cjs/utils.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.defaults = defaults;
|
|
7
7
|
exports.escape = escape;
|
|
8
8
|
exports.extend = extend;
|
|
9
|
+
exports.hasXSS = hasXSS;
|
|
9
10
|
exports.removeLngFromUrl = removeLngFromUrl;
|
|
10
11
|
exports.setPath = setPath;
|
|
11
12
|
function setPath(object, path, newValue) {
|
|
@@ -60,4 +61,11 @@ function removeLngFromUrl(url, lookupFromPathIndex) {
|
|
|
60
61
|
}
|
|
61
62
|
function escape(str) {
|
|
62
63
|
return str.replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, ''').replace(/</g, '<').replace(/>/g, '>').replace(/\//g, '/').replace(/\\/g, '\').replace(/`/g, '`');
|
|
64
|
+
}
|
|
65
|
+
function hasXSS(input) {
|
|
66
|
+
if (typeof input !== 'string') return false;
|
|
67
|
+
var xssPatterns = [/<\s*script.*?>/i, /<\s*\/\s*script\s*>/i, /<\s*img.*?on\w+\s*=/i, /<\s*\w+\s*on\w+\s*=.*?>/i, /javascript\s*:/i, /vbscript\s*:/i, /expression\s*\(/i, /eval\s*\(/i, /alert\s*\(/i, /document\.cookie/i, /document\.write\s*\(/i, /window\.location/i, /innerHTML/i];
|
|
68
|
+
return xssPatterns.some(function (pattern) {
|
|
69
|
+
return pattern.test(input);
|
|
70
|
+
});
|
|
63
71
|
}
|
package/esm/LanguageDetector.js
CHANGED
|
@@ -72,9 +72,8 @@ var LanguageDetector = function () {
|
|
|
72
72
|
if (!detections) return;
|
|
73
73
|
if (!Array.isArray(detections)) detections = [detections];
|
|
74
74
|
detections = detections.filter(function (d) {
|
|
75
|
-
return d !== undefined && d !== null;
|
|
76
|
-
})
|
|
77
|
-
detections = detections.map(function (d) {
|
|
75
|
+
return d !== undefined && d !== null && !utils.hasXSS(d);
|
|
76
|
+
}).map(function (d) {
|
|
78
77
|
return _this.options.convertDetectedLanguage(d);
|
|
79
78
|
});
|
|
80
79
|
if (_this.services.languageUtils.getBestMatchFromCodes) {
|
package/esm/index.js
CHANGED
|
@@ -173,7 +173,7 @@ export function getResourcesHandler(i18next) {
|
|
|
173
173
|
}
|
|
174
174
|
var resources = {};
|
|
175
175
|
options.setContentType(res, 'application/json');
|
|
176
|
-
if (options.cache !== undefined ? options.cache : typeof process !== 'undefined' && process.env && process.env.NODE_ENV === 'production') {
|
|
176
|
+
if (options.cache !== undefined ? options.cache : typeof process !== 'undefined' && typeof process.env !== 'undefined' && process.env && process.env.NODE_ENV === 'production') {
|
|
177
177
|
options.setHeader(res, 'Cache-Control', 'public, max-age=' + maxAge);
|
|
178
178
|
options.setHeader(res, 'Expires', new Date(new Date().getTime() + maxAge * 1000).toUTCString());
|
|
179
179
|
} else {
|
|
@@ -63,6 +63,7 @@ export default {
|
|
|
63
63
|
cacheUserLanguage: function cacheUserLanguage(req, res, lng) {
|
|
64
64
|
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
65
65
|
if (options.lookupCookie && req !== 'undefined') {
|
|
66
|
+
var _options$cookieHttpOn;
|
|
66
67
|
var expirationDate = options.cookieExpirationDate;
|
|
67
68
|
if (!expirationDate) {
|
|
68
69
|
expirationDate = new Date();
|
|
@@ -72,7 +73,7 @@ export default {
|
|
|
72
73
|
expires: expirationDate,
|
|
73
74
|
domain: options.cookieDomain,
|
|
74
75
|
path: options.cookiePath,
|
|
75
|
-
httpOnly: false,
|
|
76
|
+
httpOnly: (_options$cookieHttpOn = options.cookieHttpOnly) !== null && _options$cookieHttpOn !== void 0 ? _options$cookieHttpOn : false,
|
|
76
77
|
overwrite: true,
|
|
77
78
|
sameSite: options.cookieSameSite
|
|
78
79
|
};
|
package/esm/utils.js
CHANGED
|
@@ -50,4 +50,11 @@ export function removeLngFromUrl(url, lookupFromPathIndex) {
|
|
|
50
50
|
}
|
|
51
51
|
export function escape(str) {
|
|
52
52
|
return str.replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, ''').replace(/</g, '<').replace(/>/g, '>').replace(/\//g, '/').replace(/\\/g, '\').replace(/`/g, '`');
|
|
53
|
+
}
|
|
54
|
+
export function hasXSS(input) {
|
|
55
|
+
if (typeof input !== 'string') return false;
|
|
56
|
+
var xssPatterns = [/<\s*script.*?>/i, /<\s*\/\s*script\s*>/i, /<\s*img.*?on\w+\s*=/i, /<\s*\w+\s*on\w+\s*=.*?>/i, /javascript\s*:/i, /vbscript\s*:/i, /expression\s*\(/i, /eval\s*\(/i, /alert\s*\(/i, /document\.cookie/i, /document\.write\s*\(/i, /window\.location/i, /innerHTML/i];
|
|
57
|
+
return xssPatterns.some(function (pattern) {
|
|
58
|
+
return pattern.test(input);
|
|
59
|
+
});
|
|
53
60
|
}
|
package/lib/LanguageDetector.js
CHANGED
|
@@ -66,8 +66,9 @@ class LanguageDetector {
|
|
|
66
66
|
if (!detections) return
|
|
67
67
|
if (!Array.isArray(detections)) detections = [detections]
|
|
68
68
|
|
|
69
|
-
detections = detections
|
|
70
|
-
|
|
69
|
+
detections = detections
|
|
70
|
+
.filter((d) => d !== undefined && d !== null && !utils.hasXSS(d))
|
|
71
|
+
.map((d) => this.options.convertDetectedLanguage(d))
|
|
71
72
|
|
|
72
73
|
if (this.services.languageUtils.getBestMatchFromCodes) { // new i18next v19.5.0
|
|
73
74
|
found = this.services.languageUtils.getBestMatchFromCodes(detections)
|
package/lib/index.js
CHANGED
|
@@ -180,6 +180,7 @@ export function getResourcesHandler (i18next, options = {}) {
|
|
|
180
180
|
options.cache !== undefined
|
|
181
181
|
? options.cache
|
|
182
182
|
: typeof process !== 'undefined' &&
|
|
183
|
+
typeof process.env !== 'undefined' &&
|
|
183
184
|
process.env &&
|
|
184
185
|
process.env.NODE_ENV === 'production'
|
|
185
186
|
) {
|
package/lib/utils.js
CHANGED
|
@@ -69,3 +69,26 @@ export function escape (str) {
|
|
|
69
69
|
.replace(/\\/g, '\')
|
|
70
70
|
.replace(/`/g, '`'))
|
|
71
71
|
}
|
|
72
|
+
|
|
73
|
+
export function hasXSS (input) {
|
|
74
|
+
if (typeof input !== 'string') return false
|
|
75
|
+
|
|
76
|
+
// Common XSS attack patterns
|
|
77
|
+
const xssPatterns = [
|
|
78
|
+
/<\s*script.*?>/i,
|
|
79
|
+
/<\s*\/\s*script\s*>/i,
|
|
80
|
+
/<\s*img.*?on\w+\s*=/i,
|
|
81
|
+
/<\s*\w+\s*on\w+\s*=.*?>/i,
|
|
82
|
+
/javascript\s*:/i,
|
|
83
|
+
/vbscript\s*:/i,
|
|
84
|
+
/expression\s*\(/i,
|
|
85
|
+
/eval\s*\(/i,
|
|
86
|
+
/alert\s*\(/i,
|
|
87
|
+
/document\.cookie/i,
|
|
88
|
+
/document\.write\s*\(/i,
|
|
89
|
+
/window\.location/i,
|
|
90
|
+
/innerHTML/i
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
return xssPatterns.some((pattern) => pattern.test(input))
|
|
94
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "i18next-http-middleware",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.8.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./cjs/index.js",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"eslint-plugin-standard": "5.0.0",
|
|
46
46
|
"expect.js": "0.3.1",
|
|
47
47
|
"express": "4.21.1",
|
|
48
|
-
"fastify": "5.
|
|
48
|
+
"fastify": "5.3.2",
|
|
49
49
|
"i18next": "24.0.0",
|
|
50
50
|
"mocha": "10.8.2",
|
|
51
51
|
"supertest": "7.0.0",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"compile": "npm run compile:esm && npm run compile:cjs",
|
|
76
76
|
"build": "npm run compile",
|
|
77
77
|
"test": "npm run lint && npm run build && mocha test -R spec --exit --experimental-modules && npm run test:types",
|
|
78
|
-
"test:deno": "deno test --allow-net test/deno/*.js",
|
|
78
|
+
"test:deno": "deno test --allow-net --allow-env test/deno/*.js",
|
|
79
79
|
"test:types": "tsd",
|
|
80
80
|
"preversion": "npm run test && npm run build && git push",
|
|
81
81
|
"postversion": "git push && git push --tags"
|