locizify 9.0.8 → 9.0.10
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/CHANGELOG.md +12 -0
- package/dist/commonjs/index.js +42 -3
- package/dist/es/index.js +42 -3
- package/dist/umd/locizify.js +798 -333
- package/dist/umd/locizify.min.js +2 -2
- package/locizify.js +798 -333
- package/locizify.min.js +2 -2
- package/package.json +14 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
### 9.0.10
|
|
2
|
+
|
|
3
|
+
Security release — includes upstream fixes from `i18next-locize-backend`, `i18nextify`, and `locize`.
|
|
4
|
+
|
|
5
|
+
- security: emit a one-time `console.warn` when `?apikey=` or `?projectid=` is read from the URL query string on a non-local host (anything other than `localhost`, `127.0.0.1`, `::1`, `*.localhost`, `*.local`). The feature itself is preserved — an attacker-crafted link on a production host could otherwise silently redirect translations (and `saveMissing` writes) to an attacker-chosen locize project (CWE-522); the warning is there so maintainers notice when it happens and can decide to disable the URL-credential path in their deployment. Prefer configuring credentials via the `<script id="locizify" apikey="…" projectid="…">` attributes, which are not attacker-controllable.
|
|
6
|
+
- chore: bump pinned deps (security releases): `i18next-locize-backend` 9.0.1 → **9.0.2** ([GHSA-mgcp-mfp8-3q45](https://github.com/locize/i18next-locize-backend/security/advisories/GHSA-mgcp-mfp8-3q45)), `i18nextify` 4.0.7 → **4.0.8** ([GHSA-6457-mxpq-4fqq](https://github.com/i18next/i18nextify/security/advisories/GHSA-6457-mxpq-4fqq)), `locize` 4.0.16 → **4.0.21** ([GHSA-w937-fg2h-xhq2](https://github.com/locize/locize/security/advisories/GHSA-w937-fg2h-xhq2)).
|
|
7
|
+
- chore: ignore `.env*` and `*.pem`/`*.key` files in `.gitignore`.
|
|
8
|
+
|
|
9
|
+
### 9.0.9
|
|
10
|
+
|
|
11
|
+
- update i18nextify
|
|
12
|
+
|
|
1
13
|
### 9.0.8
|
|
2
14
|
|
|
3
15
|
- update i18nextify
|
package/dist/commonjs/index.js
CHANGED
|
@@ -35,6 +35,30 @@ function getQsParameterByName(name, url) {
|
|
|
35
35
|
if (!results[2]) return '';
|
|
36
36
|
return decodeURIComponent(results[2].replace(/\+/g, ' '));
|
|
37
37
|
}
|
|
38
|
+
|
|
39
|
+
// Reading credentials from the URL query string is convenient for local
|
|
40
|
+
// development (run `?apikey=...&projectId=...` against a demo page) but is
|
|
41
|
+
// dangerous on deployed sites: an attacker-crafted link would cause the
|
|
42
|
+
// victim's page to send translation data (saveMissing) to the attacker's
|
|
43
|
+
// locize project, or to run against an attacker-chosen backend.
|
|
44
|
+
// The feature is preserved, but a warning is emitted when the URL
|
|
45
|
+
// overrides credential values on hosts that don't look like a local dev
|
|
46
|
+
// environment, so maintainers can notice and decide whether to disable it.
|
|
47
|
+
function isLocalDevHost() {
|
|
48
|
+
if (typeof window === 'undefined' || !window.location) return false;
|
|
49
|
+
var h = window.location.hostname;
|
|
50
|
+
if (!h) return false;
|
|
51
|
+
return h === 'localhost' || h === '127.0.0.1' || h === '::1' || h === '0.0.0.0' || h.endsWith('.localhost') || h.endsWith('.local');
|
|
52
|
+
}
|
|
53
|
+
var credentialWarningShown = false;
|
|
54
|
+
function warnIfCredentialFromUrlOnProdHost(attr) {
|
|
55
|
+
if (isLocalDevHost()) return;
|
|
56
|
+
if (credentialWarningShown) return; // only once per page
|
|
57
|
+
credentialWarningShown = true;
|
|
58
|
+
if (typeof console !== 'undefined' && typeof console.warn === 'function') {
|
|
59
|
+
console.warn('locizify: reading credential "' + attr + '" from URL query string on a non-local host. ' + 'An attacker-crafted link can replace your locize credentials, redirecting saveMissing writes ' + 'to an attacker-chosen project. Prefer configuring credentials via the ' + '<script id="locizify" apikey="..." projectid="..."> attributes instead.');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
38
62
|
var originalInit = i18next.init;
|
|
39
63
|
i18next.init = function () {
|
|
40
64
|
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -70,11 +94,20 @@ i18next.init = function () {
|
|
|
70
94
|
if (attr.toLowerCase() === 'autopilot' && value === '') value = true;
|
|
71
95
|
if (value !== undefined && value !== null) backend[attr] = value;
|
|
72
96
|
if (!value) {
|
|
73
|
-
|
|
97
|
+
var lc = attr.toLowerCase();
|
|
98
|
+
value = getQsParameterByName(lc);
|
|
74
99
|
if (value === 'true') value = true;
|
|
75
100
|
if (value === 'false') value = false;
|
|
76
|
-
if (
|
|
77
|
-
if (value !== undefined && value !== null)
|
|
101
|
+
if (lc === 'autopilot' && value === '') value = true;
|
|
102
|
+
if (value !== undefined && value !== null) {
|
|
103
|
+
backend[attr] = value;
|
|
104
|
+
// Credential-bearing attributes via URL on a non-local host is
|
|
105
|
+
// risky — attacker-crafted links can replace your credentials.
|
|
106
|
+
// Warn once per page load so maintainers notice.
|
|
107
|
+
if (lc === 'apikey' || lc === 'projectid') {
|
|
108
|
+
warnIfCredentialFromUrlOnProdHost(lc);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
78
111
|
}
|
|
79
112
|
});
|
|
80
113
|
if (backend.allowedAddOrUpdateHost) {
|
|
@@ -90,8 +123,14 @@ i18next.init = function () {
|
|
|
90
123
|
// call orginal callback
|
|
91
124
|
callback(err, t);
|
|
92
125
|
}
|
|
126
|
+
|
|
127
|
+
// Accept `?apikey=` from the URL query string as a fallback. On non-local
|
|
128
|
+
// hosts this is risky (attacker-crafted links can replace your credentials
|
|
129
|
+
// and redirect saveMissing writes to an attacker-chosen project), so warn
|
|
130
|
+
// once when it happens.
|
|
93
131
|
if (!options.backend.apiKey && getQsParameterByName('apikey')) {
|
|
94
132
|
options.backend.apiKey = getQsParameterByName('apikey');
|
|
133
|
+
warnIfCredentialFromUrlOnProdHost('apikey');
|
|
95
134
|
}
|
|
96
135
|
if (!options.backend.autoPilot || options.backend.autoPilot === 'false') {
|
|
97
136
|
return originalInit.call(i18next, _objectSpread(_objectSpread({}, options), enforce), handleI18nextInitialized);
|
package/dist/es/index.js
CHANGED
|
@@ -28,6 +28,30 @@ function getQsParameterByName(name, url) {
|
|
|
28
28
|
if (!results[2]) return '';
|
|
29
29
|
return decodeURIComponent(results[2].replace(/\+/g, ' '));
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
// Reading credentials from the URL query string is convenient for local
|
|
33
|
+
// development (run `?apikey=...&projectId=...` against a demo page) but is
|
|
34
|
+
// dangerous on deployed sites: an attacker-crafted link would cause the
|
|
35
|
+
// victim's page to send translation data (saveMissing) to the attacker's
|
|
36
|
+
// locize project, or to run against an attacker-chosen backend.
|
|
37
|
+
// The feature is preserved, but a warning is emitted when the URL
|
|
38
|
+
// overrides credential values on hosts that don't look like a local dev
|
|
39
|
+
// environment, so maintainers can notice and decide whether to disable it.
|
|
40
|
+
function isLocalDevHost() {
|
|
41
|
+
if (typeof window === 'undefined' || !window.location) return false;
|
|
42
|
+
var h = window.location.hostname;
|
|
43
|
+
if (!h) return false;
|
|
44
|
+
return h === 'localhost' || h === '127.0.0.1' || h === '::1' || h === '0.0.0.0' || h.endsWith('.localhost') || h.endsWith('.local');
|
|
45
|
+
}
|
|
46
|
+
var credentialWarningShown = false;
|
|
47
|
+
function warnIfCredentialFromUrlOnProdHost(attr) {
|
|
48
|
+
if (isLocalDevHost()) return;
|
|
49
|
+
if (credentialWarningShown) return; // only once per page
|
|
50
|
+
credentialWarningShown = true;
|
|
51
|
+
if (typeof console !== 'undefined' && typeof console.warn === 'function') {
|
|
52
|
+
console.warn('locizify: reading credential "' + attr + '" from URL query string on a non-local host. ' + 'An attacker-crafted link can replace your locize credentials, redirecting saveMissing writes ' + 'to an attacker-chosen project. Prefer configuring credentials via the ' + '<script id="locizify" apikey="..." projectid="..."> attributes instead.');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
31
55
|
var originalInit = i18next.init;
|
|
32
56
|
i18next.init = function () {
|
|
33
57
|
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -63,11 +87,20 @@ i18next.init = function () {
|
|
|
63
87
|
if (attr.toLowerCase() === 'autopilot' && value === '') value = true;
|
|
64
88
|
if (value !== undefined && value !== null) backend[attr] = value;
|
|
65
89
|
if (!value) {
|
|
66
|
-
|
|
90
|
+
var lc = attr.toLowerCase();
|
|
91
|
+
value = getQsParameterByName(lc);
|
|
67
92
|
if (value === 'true') value = true;
|
|
68
93
|
if (value === 'false') value = false;
|
|
69
|
-
if (
|
|
70
|
-
if (value !== undefined && value !== null)
|
|
94
|
+
if (lc === 'autopilot' && value === '') value = true;
|
|
95
|
+
if (value !== undefined && value !== null) {
|
|
96
|
+
backend[attr] = value;
|
|
97
|
+
// Credential-bearing attributes via URL on a non-local host is
|
|
98
|
+
// risky — attacker-crafted links can replace your credentials.
|
|
99
|
+
// Warn once per page load so maintainers notice.
|
|
100
|
+
if (lc === 'apikey' || lc === 'projectid') {
|
|
101
|
+
warnIfCredentialFromUrlOnProdHost(lc);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
71
104
|
}
|
|
72
105
|
});
|
|
73
106
|
if (backend.allowedAddOrUpdateHost) {
|
|
@@ -83,8 +116,14 @@ i18next.init = function () {
|
|
|
83
116
|
// call orginal callback
|
|
84
117
|
callback(err, t);
|
|
85
118
|
}
|
|
119
|
+
|
|
120
|
+
// Accept `?apikey=` from the URL query string as a fallback. On non-local
|
|
121
|
+
// hosts this is risky (attacker-crafted links can replace your credentials
|
|
122
|
+
// and redirect saveMissing writes to an attacker-chosen project), so warn
|
|
123
|
+
// once when it happens.
|
|
86
124
|
if (!options.backend.apiKey && getQsParameterByName('apikey')) {
|
|
87
125
|
options.backend.apiKey = getQsParameterByName('apikey');
|
|
126
|
+
warnIfCredentialFromUrlOnProdHost('apikey');
|
|
88
127
|
}
|
|
89
128
|
if (!options.backend.autoPilot || options.backend.autoPilot === 'false') {
|
|
90
129
|
return originalInit.call(i18next, _objectSpread(_objectSpread({}, options), enforce), handleI18nextInitialized);
|