i18next-http-middleware 3.9.10 → 3.10.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/cjs/index.js CHANGED
@@ -300,12 +300,14 @@ function missingKeyHandler(i18next) {
300
300
  }
301
301
  var body = options.getBody(req);
302
302
  var keySeparator = i18next.options && i18next.options.keySeparator;
303
+ var utilsOfRequest = req.i18n && req.i18n.services && req.i18n.services.utils;
304
+ var hasLoadedNamespace = utilsOfRequest && utilsOfRequest.hasLoadedNamespace;
303
305
  var saveMissingKeys = function saveMissingKeys(src) {
304
306
  if (!src || _typeof(src) !== 'object') return;
305
307
  for (var _i = 0, _Object$keys = Object.keys(src); _i < _Object$keys.length; _i++) {
306
308
  var m = _Object$keys[_i];
307
309
  if (utils.hasUnsafeKeySegment(m, keySeparator)) continue;
308
- i18next.services.backendConnector.saveMissing([lng], ns, m, src[m]);
310
+ i18next.services.backendConnector.saveMissing([lng], ns, m, src[m], undefined, undefined, undefined, hasLoadedNamespace);
309
311
  }
310
312
  };
311
313
  if (typeof body === 'function') {
@@ -32,7 +32,7 @@ var _default = exports.default = {
32
32
  var lng = m[1];
33
33
  var weight = m[5] || '1';
34
34
  var q = Number(weight);
35
- if (lng && !isNaN(q)) {
35
+ if (lng && q > 0) {
36
36
  lngs.push({
37
37
  lng: lng,
38
38
  q: q
package/cjs/utils.js CHANGED
@@ -30,8 +30,7 @@ function isSafeIdentifierBase(v) {
30
30
  }
31
31
  function isSafeLangIdentifier(v) {
32
32
  if (!isSafeIdentifierBase(v)) return false;
33
- if (v.indexOf('/') > -1) return false;
34
- return true;
33
+ return /^[A-Za-z0-9_@.-]+$/.test(v);
35
34
  }
36
35
  function isSafeNsIdentifier(v) {
37
36
  return isSafeIdentifierBase(v);
package/esm/index.js CHANGED
@@ -283,12 +283,14 @@ export function missingKeyHandler(i18next) {
283
283
  }
284
284
  var body = options.getBody(req);
285
285
  var keySeparator = i18next.options && i18next.options.keySeparator;
286
+ var utilsOfRequest = req.i18n && req.i18n.services && req.i18n.services.utils;
287
+ var hasLoadedNamespace = utilsOfRequest && utilsOfRequest.hasLoadedNamespace;
286
288
  var saveMissingKeys = function saveMissingKeys(src) {
287
289
  if (!src || _typeof(src) !== 'object') return;
288
290
  for (var _i = 0, _Object$keys = Object.keys(src); _i < _Object$keys.length; _i++) {
289
291
  var m = _Object$keys[_i];
290
292
  if (utils.hasUnsafeKeySegment(m, keySeparator)) continue;
291
- i18next.services.backendConnector.saveMissing([lng], ns, m, src[m]);
293
+ i18next.services.backendConnector.saveMissing([lng], ns, m, src[m], undefined, undefined, undefined, hasLoadedNamespace);
292
294
  }
293
295
  };
294
296
  if (typeof body === 'function') {
@@ -26,7 +26,7 @@ export default {
26
26
  var lng = m[1];
27
27
  var weight = m[5] || '1';
28
28
  var q = Number(weight);
29
- if (lng && !isNaN(q)) {
29
+ if (lng && q > 0) {
30
30
  lngs.push({
31
31
  lng: lng,
32
32
  q: q
package/esm/utils.js CHANGED
@@ -13,8 +13,7 @@ function isSafeIdentifierBase(v) {
13
13
  }
14
14
  export function isSafeLangIdentifier(v) {
15
15
  if (!isSafeIdentifierBase(v)) return false;
16
- if (v.indexOf('/') > -1) return false;
17
- return true;
16
+ return /^[A-Za-z0-9_@.-]+$/.test(v);
18
17
  }
19
18
  export function isSafeNsIdentifier(v) {
20
19
  return isSafeIdentifierBase(v);
package/lib/index.js CHANGED
@@ -335,6 +335,8 @@ export function missingKeyHandler (i18next, options = {}) {
335
335
 
336
336
  const body = options.getBody(req)
337
337
  const keySeparator = i18next.options && i18next.options.keySeparator
338
+ const utilsOfRequest = req.i18n && req.i18n.services && req.i18n.services.utils
339
+ const hasLoadedNamespace = utilsOfRequest && utilsOfRequest.hasLoadedNamespace
338
340
 
339
341
  // iterate only over own, non-prototype-polluting keys. The check also
340
342
  // rejects dotted variants like `__proto__.polluted` whose segments under
@@ -343,7 +345,9 @@ export function missingKeyHandler (i18next, options = {}) {
343
345
  if (!src || typeof src !== 'object') return
344
346
  for (const m of Object.keys(src)) {
345
347
  if (utils.hasUnsafeKeySegment(m, keySeparator)) continue
346
- i18next.services.backendConnector.saveMissing([lng], ns, m, src[m])
348
+ // i18next >= 26.7 takes the check of this request's instance (one clone per
349
+ // request) as the 8th argument; without it, it checks the newest clone
350
+ i18next.services.backendConnector.saveMissing([lng], ns, m, src[m], undefined, undefined, undefined, hasLoadedNamespace)
347
351
  }
348
352
  }
349
353
 
@@ -26,7 +26,7 @@ export default {
26
26
  m = rgx.exec(acceptLanguage)
27
27
  if (m) {
28
28
  const lng = m[1]; const weight = m[5] || '1'; const q = Number(weight)
29
- if (lng && !isNaN(q)) {
29
+ if (lng && q > 0) {
30
30
  lngs.push({ lng, q })
31
31
  }
32
32
  }
package/lib/utils.js CHANGED
@@ -17,14 +17,16 @@ function isSafeIdentifierBase (v) {
17
17
  return true
18
18
  }
19
19
 
20
- // Strict — also rejects `/`. Applied to `lng`:
21
- // no legitimate BCP-47 / i18next language-code shape
22
- // (https://www.i18next.com/how-to/faq#how-should-the-language-codes-be-formatted)
23
- // contains `/`, so allowing it would only enable attacks.
20
+ // Strict, applied to `lng`: on top of the base checks, the shape i18next accepts
21
+ // for a language code from outside since 26.7 (the rule of its exported
22
+ // `isSafeLanguageCode`): letters, digits, `-`, `_`, `@` and `.`. It is not a
23
+ // BCP-47 check (https://www.i18next.com/how-to/faq#how-should-the-language-codes-be-formatted),
24
+ // so `en_US`, `zh_Hant_TW` and `sr@latin` pass. `/`, quotes, spaces and `=` do
25
+ // not: a detected language ends up in `<html lang="...">`, and a value like
26
+ // `" onmouseover="x()` passed the base checks and the XSS patterns.
24
27
  export function isSafeLangIdentifier (v) {
25
28
  if (!isSafeIdentifierBase(v)) return false
26
- if (v.indexOf('/') > -1) return false
27
- return true
29
+ return /^[A-Za-z0-9_@.-]+$/.test(v)
28
30
  }
29
31
 
30
32
  // Loose — allows `/`. Applied to `ns`:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i18next-http-middleware",
3
- "version": "3.9.10",
3
+ "version": "3.10.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./cjs/index.js",
@@ -47,7 +47,7 @@
47
47
  "eslint-plugin-standard": "5.0.0",
48
48
  "expect.js": "0.3.1",
49
49
  "express": "5.2.1",
50
- "fastify": "5.12.1",
50
+ "fastify": "5.12.6",
51
51
  "i18next": "26.0.5",
52
52
  "mocha": "11.7.5",
53
53
  "preact": "10.29.1",