i18next-http-middleware 3.9.6 → 3.9.7
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 -1
- package/cjs/index.js +2 -1
- package/cjs/utils.js +25 -0
- package/esm/index.js +2 -1
- package/esm/utils.js +24 -0
- package/lib/index.js +5 -2
- package/lib/utils.js +21 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -510,7 +510,7 @@ Don't forget: You have to add the name of your detector (`myDetectorsName` in th
|
|
|
510
510
|
<h3 align='center'>Gold Sponsors</h3>
|
|
511
511
|
|
|
512
512
|
<p align='center'>
|
|
513
|
-
<a href='https://locize.com
|
|
513
|
+
<a href='https://www.locize.com/?utm_source=i18next_http_middleware_readme&utm_medium=github&utm_campaign=readme' target='_blank'>
|
|
514
514
|
<img src='https://raw.githubusercontent.com/i18next/i18next/master/assets/locize_sponsor_240.gif' width='240px'>
|
|
515
515
|
</a>
|
|
516
516
|
</p>
|
package/cjs/index.js
CHANGED
|
@@ -285,11 +285,12 @@ function missingKeyHandler(i18next) {
|
|
|
285
285
|
return options.send(res, 'i18next-express-middleware:: no backend configured');
|
|
286
286
|
}
|
|
287
287
|
var body = options.getBody(req);
|
|
288
|
+
var keySeparator = i18next.options && i18next.options.keySeparator;
|
|
288
289
|
var saveMissingKeys = function saveMissingKeys(src) {
|
|
289
290
|
if (!src || _typeof(src) !== 'object') return;
|
|
290
291
|
for (var _i = 0, _Object$keys = Object.keys(src); _i < _Object$keys.length; _i++) {
|
|
291
292
|
var m = _Object$keys[_i];
|
|
292
|
-
if (utils.
|
|
293
|
+
if (utils.hasUnsafeKeySegment(m, keySeparator)) continue;
|
|
293
294
|
i18next.services.backendConnector.saveMissing([lng], ns, m, src[m]);
|
|
294
295
|
}
|
|
295
296
|
};
|
package/cjs/utils.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.UNSAFE_KEYS = void 0;
|
|
|
7
7
|
exports.defaults = defaults;
|
|
8
8
|
exports.escape = escape;
|
|
9
9
|
exports.extend = extend;
|
|
10
|
+
exports.hasUnsafeKeySegment = hasUnsafeKeySegment;
|
|
10
11
|
exports.hasXSS = hasXSS;
|
|
11
12
|
exports.isSafeIdentifier = void 0;
|
|
12
13
|
exports.isSafeLangIdentifier = isSafeLangIdentifier;
|
|
@@ -14,6 +15,9 @@ exports.isSafeNsIdentifier = isSafeNsIdentifier;
|
|
|
14
15
|
exports.removeLngFromUrl = removeLngFromUrl;
|
|
15
16
|
exports.sanitizeHeaderValue = sanitizeHeaderValue;
|
|
16
17
|
exports.setPath = setPath;
|
|
18
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
19
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
20
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
17
21
|
var UNSAFE_KEYS = exports.UNSAFE_KEYS = ['__proto__', 'constructor', 'prototype'];
|
|
18
22
|
function isSafeIdentifierBase(v) {
|
|
19
23
|
if (typeof v !== 'string') return false;
|
|
@@ -33,6 +37,27 @@ function isSafeNsIdentifier(v) {
|
|
|
33
37
|
return isSafeIdentifierBase(v);
|
|
34
38
|
}
|
|
35
39
|
var isSafeIdentifier = exports.isSafeIdentifier = isSafeLangIdentifier;
|
|
40
|
+
function hasUnsafeKeySegment(key, keySeparator) {
|
|
41
|
+
if (typeof key !== 'string') return false;
|
|
42
|
+
if (UNSAFE_KEYS.indexOf(key) > -1) return true;
|
|
43
|
+
if (keySeparator === false) return false;
|
|
44
|
+
var sep = keySeparator || '.';
|
|
45
|
+
if (key.indexOf(sep) < 0) return false;
|
|
46
|
+
var segments = key.split(sep);
|
|
47
|
+
var _iterator = _createForOfIteratorHelper(segments),
|
|
48
|
+
_step;
|
|
49
|
+
try {
|
|
50
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
51
|
+
var s = _step.value;
|
|
52
|
+
if (UNSAFE_KEYS.indexOf(s) > -1) return true;
|
|
53
|
+
}
|
|
54
|
+
} catch (err) {
|
|
55
|
+
_iterator.e(err);
|
|
56
|
+
} finally {
|
|
57
|
+
_iterator.f();
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
36
61
|
function setPath(object, path, newValue) {
|
|
37
62
|
var stack;
|
|
38
63
|
if (typeof path !== 'string') stack = [].concat(path);
|
package/esm/index.js
CHANGED
|
@@ -268,11 +268,12 @@ export function missingKeyHandler(i18next) {
|
|
|
268
268
|
return options.send(res, 'i18next-express-middleware:: no backend configured');
|
|
269
269
|
}
|
|
270
270
|
var body = options.getBody(req);
|
|
271
|
+
var keySeparator = i18next.options && i18next.options.keySeparator;
|
|
271
272
|
var saveMissingKeys = function saveMissingKeys(src) {
|
|
272
273
|
if (!src || _typeof(src) !== 'object') return;
|
|
273
274
|
for (var _i = 0, _Object$keys = Object.keys(src); _i < _Object$keys.length; _i++) {
|
|
274
275
|
var m = _Object$keys[_i];
|
|
275
|
-
if (utils.
|
|
276
|
+
if (utils.hasUnsafeKeySegment(m, keySeparator)) continue;
|
|
276
277
|
i18next.services.backendConnector.saveMissing([lng], ns, m, src[m]);
|
|
277
278
|
}
|
|
278
279
|
};
|
package/esm/utils.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
2
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
3
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
1
4
|
export var UNSAFE_KEYS = ['__proto__', 'constructor', 'prototype'];
|
|
2
5
|
function isSafeIdentifierBase(v) {
|
|
3
6
|
if (typeof v !== 'string') return false;
|
|
@@ -17,6 +20,27 @@ export function isSafeNsIdentifier(v) {
|
|
|
17
20
|
return isSafeIdentifierBase(v);
|
|
18
21
|
}
|
|
19
22
|
export var isSafeIdentifier = isSafeLangIdentifier;
|
|
23
|
+
export function hasUnsafeKeySegment(key, keySeparator) {
|
|
24
|
+
if (typeof key !== 'string') return false;
|
|
25
|
+
if (UNSAFE_KEYS.indexOf(key) > -1) return true;
|
|
26
|
+
if (keySeparator === false) return false;
|
|
27
|
+
var sep = keySeparator || '.';
|
|
28
|
+
if (key.indexOf(sep) < 0) return false;
|
|
29
|
+
var segments = key.split(sep);
|
|
30
|
+
var _iterator = _createForOfIteratorHelper(segments),
|
|
31
|
+
_step;
|
|
32
|
+
try {
|
|
33
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
34
|
+
var s = _step.value;
|
|
35
|
+
if (UNSAFE_KEYS.indexOf(s) > -1) return true;
|
|
36
|
+
}
|
|
37
|
+
} catch (err) {
|
|
38
|
+
_iterator.e(err);
|
|
39
|
+
} finally {
|
|
40
|
+
_iterator.f();
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
20
44
|
export function setPath(object, path, newValue) {
|
|
21
45
|
var stack;
|
|
22
46
|
if (typeof path !== 'string') stack = [].concat(path);
|
package/lib/index.js
CHANGED
|
@@ -311,12 +311,15 @@ export function missingKeyHandler (i18next, options = {}) {
|
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
const body = options.getBody(req)
|
|
314
|
+
const keySeparator = i18next.options && i18next.options.keySeparator
|
|
314
315
|
|
|
315
|
-
// iterate only over own, non-prototype-polluting keys
|
|
316
|
+
// iterate only over own, non-prototype-polluting keys. The check also
|
|
317
|
+
// rejects dotted variants like `__proto__.polluted` whose segments under
|
|
318
|
+
// the configured keySeparator land on an unsafe key — see utils.js.
|
|
316
319
|
const saveMissingKeys = src => {
|
|
317
320
|
if (!src || typeof src !== 'object') return
|
|
318
321
|
for (const m of Object.keys(src)) {
|
|
319
|
-
if (utils.
|
|
322
|
+
if (utils.hasUnsafeKeySegment(m, keySeparator)) continue
|
|
320
323
|
i18next.services.backendConnector.saveMissing([lng], ns, m, src[m])
|
|
321
324
|
}
|
|
322
325
|
}
|
package/lib/utils.js
CHANGED
|
@@ -43,6 +43,27 @@ export function isSafeNsIdentifier (v) {
|
|
|
43
43
|
// exported this symbol; external callers (if any) get the pre-fix behaviour.
|
|
44
44
|
export const isSafeIdentifier = isSafeLangIdentifier
|
|
45
45
|
|
|
46
|
+
// Defense-in-depth check for `missingKeyHandler`. The literal-key denylist
|
|
47
|
+
// catches `{"__proto__": ...}` but misses dotted variants like
|
|
48
|
+
// `{"__proto__.polluted": "x"}` — backends that split the missing-key string
|
|
49
|
+
// on a configured keySeparator (e.g. i18next-fs-backend's writeFile()) would
|
|
50
|
+
// hand that key to an unguarded setPath and walk into Object.prototype.
|
|
51
|
+
// Reject any key whose segments — under the configured keySeparator (default
|
|
52
|
+
// `.`) — include an unsafe key. keySeparator === false means "no splitting",
|
|
53
|
+
// in which case only the literal-key check applies.
|
|
54
|
+
export function hasUnsafeKeySegment (key, keySeparator) {
|
|
55
|
+
if (typeof key !== 'string') return false
|
|
56
|
+
if (UNSAFE_KEYS.indexOf(key) > -1) return true
|
|
57
|
+
if (keySeparator === false) return false
|
|
58
|
+
const sep = keySeparator || '.'
|
|
59
|
+
if (key.indexOf(sep) < 0) return false
|
|
60
|
+
const segments = key.split(sep)
|
|
61
|
+
for (const s of segments) {
|
|
62
|
+
if (UNSAFE_KEYS.indexOf(s) > -1) return true
|
|
63
|
+
}
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
|
|
46
67
|
export function setPath (object, path, newValue) {
|
|
47
68
|
let stack
|
|
48
69
|
if (typeof path !== 'string') stack = [].concat(path)
|