@blamejs/blamejs-shop 0.5.19 → 0.5.21
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 +4 -0
- package/README.md +1 -0
- package/SECURITY.md +17 -0
- package/lib/addresses.js +2 -2
- package/lib/admin.js +49 -45
- package/lib/affiliates.js +7 -23
- package/lib/announcement-bar.js +5 -22
- package/lib/api-keys.js +4 -13
- package/lib/asset-manifest.json +1 -1
- package/lib/banner-ab-tests.js +5 -9
- package/lib/blog-articles.js +8 -26
- package/lib/captcha-gate.js +7 -17
- package/lib/carrier-accounts.js +3 -10
- package/lib/catalog-drafts.js +5 -12
- package/lib/category-navigation.js +4 -20
- package/lib/cms-blocks.js +4 -7
- package/lib/compliance-export.js +4 -11
- package/lib/consent-ledger.js +2 -4
- package/lib/cost-layers.js +56 -21
- package/lib/customer-import.js +2 -2
- package/lib/customer-notes.js +7 -23
- package/lib/customer-roles.js +3 -5
- package/lib/customer-segments.js +17 -14
- package/lib/customer-surveys.js +7 -14
- package/lib/customers.js +2 -4
- package/lib/dispute-resolution.js +5 -13
- package/lib/dropship-forwarding.js +3 -5
- package/lib/dunning.js +2 -7
- package/lib/email-ab-tests.js +4 -8
- package/lib/email-campaigns.js +25 -14
- package/lib/email-warmup.js +2 -7
- package/lib/experiments.js +6 -10
- package/lib/externaldb-d1.js +78 -44
- package/lib/geolocation.js +18 -28
- package/lib/gift-options.js +5 -23
- package/lib/knowledge-base.js +7 -22
- package/lib/line-gift-wrap.js +3 -17
- package/lib/live-chat.js +5 -18
- package/lib/metered-usage.js +3 -8
- package/lib/notifications.js +3 -7
- package/lib/operator-accounts.js +3 -5
- package/lib/operator-approvals.js +6 -8
- package/lib/operator-audit-log.js +2 -7
- package/lib/operator-help-center.js +5 -21
- package/lib/operator-inbox.js +4 -11
- package/lib/operator-roles.js +5 -7
- package/lib/order-escalation.js +2 -2
- package/lib/order-export.js +24 -20
- package/lib/order-notes.js +4 -14
- package/lib/order-ratings.js +4 -10
- package/lib/payment-methods.js +5 -13
- package/lib/payment-retries.js +2 -7
- package/lib/payment.js +103 -58
- package/lib/pixel-events.js +8 -23
- package/lib/plan-changes.js +2 -7
- package/lib/product-qa.js +4 -8
- package/lib/promo-banners.js +7 -15
- package/lib/purchase-orders.js +3 -6
- package/lib/push-notifications.js +7 -32
- package/lib/pwa-manifest.js +6 -11
- package/lib/quotes.js +5 -9
- package/lib/referrals.js +10 -6
- package/lib/reviews.js +4 -10
- package/lib/robots-config.js +6 -14
- package/lib/sales-tax-filings.js +2 -2
- package/lib/search-facets.js +5 -5
- package/lib/search-ranking.js +4 -7
- package/lib/search-synonyms.js +7 -21
- package/lib/security-middleware.js +125 -70
- package/lib/seller-signup.js +10 -26
- package/lib/sidebar-widgets.js +6 -15
- package/lib/site-redirects.js +49 -137
- package/lib/sitemap-generator.js +3 -7
- package/lib/sms-dispatcher.js +7 -23
- package/lib/stock-receipts.js +4 -10
- package/lib/storefront-dashboards.js +2 -10
- package/lib/storefront-forms.js +9 -22
- package/lib/storefront-pages.js +6 -20
- package/lib/storefront.js +21 -23
- package/lib/subscription-billing.js +3 -8
- package/lib/subscription-controls.js +2 -7
- package/lib/suggestion-box.js +9 -26
- package/lib/support-tickets.js +6 -24
- package/lib/tax-remittance.js +2 -2
- package/lib/tenants.js +2 -7
- package/lib/text-guard.js +137 -35
- package/lib/theme-assets.js +4 -16
- package/lib/translations.js +3 -6
- package/lib/trust-badges.js +4 -7
- package/lib/vendor/MANIFEST.json +107 -97
- package/lib/vendor/blamejs/CHANGELOG.md +180 -0
- package/lib/vendor/blamejs/NOTICE +14 -10
- package/lib/vendor/blamejs/README.md +17 -5
- package/lib/vendor/blamejs/index.js +2 -0
- package/lib/vendor/blamejs/lib/acme.js +9 -9
- package/lib/vendor/blamejs/lib/api-snapshot.js +35 -16
- package/lib/vendor/blamejs/lib/app-shutdown.js +1 -1
- package/lib/vendor/blamejs/lib/archive-adapters.js +1 -1
- package/lib/vendor/blamejs/lib/archive.js +13 -24
- package/lib/vendor/blamejs/lib/auth/access-lock.js +2 -1
- package/lib/vendor/blamejs/lib/auth/bot-challenge.js +3 -6
- package/lib/vendor/blamejs/lib/auth/ciba.js +32 -3
- package/lib/vendor/blamejs/lib/auth/oauth.js +65 -8
- package/lib/vendor/blamejs/lib/auth/password.js +1 -1
- package/lib/vendor/blamejs/lib/auth/saml.js +21 -3
- package/lib/vendor/blamejs/lib/auth-bot-challenge.js +3 -3
- package/lib/vendor/blamejs/lib/backup/index.js +5 -5
- package/lib/vendor/blamejs/lib/case-fold-classes.js +491 -0
- package/lib/vendor/blamejs/lib/codepoint-class.js +131 -0
- package/lib/vendor/blamejs/lib/constants.js +79 -0
- package/lib/vendor/blamejs/lib/db-declare-view.js +8 -2
- package/lib/vendor/blamejs/lib/error-page.js +20 -1
- package/lib/vendor/blamejs/lib/external-db.js +5 -1
- package/lib/vendor/blamejs/lib/flag-evaluation-context.js +24 -6
- package/lib/vendor/blamejs/lib/flag.js +28 -2
- package/lib/vendor/blamejs/lib/framework-schema.js +14 -3
- package/lib/vendor/blamejs/lib/guard-regex.js +2345 -89
- package/lib/vendor/blamejs/lib/http-client.js +217 -40
- package/lib/vendor/blamejs/lib/mail-bimi.js +1 -1
- package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +3 -2
- package/lib/vendor/blamejs/lib/mail-dav.js +26 -26
- package/lib/vendor/blamejs/lib/mail-deploy.js +10 -10
- package/lib/vendor/blamejs/lib/mail-scan.js +3 -0
- package/lib/vendor/blamejs/lib/mail-store.js +7 -1
- package/lib/vendor/blamejs/lib/mail.js +5 -1
- package/lib/vendor/blamejs/lib/middleware/age-gate.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/assetlinks.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/bearer-auth.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/compression.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/cors.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/csp-report.js +5 -5
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +2 -2
- package/lib/vendor/blamejs/lib/middleware/deny-response.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/dpop.js +2 -2
- package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/flag-context.js +17 -0
- package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +10 -8
- package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/require-aal.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/require-auth.js +4 -3
- package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +4 -3
- package/lib/vendor/blamejs/lib/middleware/require-content-type.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/require-methods.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/require-mtls.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/security-txt.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/web-app-manifest.js +2 -1
- package/lib/vendor/blamejs/lib/network-dns-resolver.js +1 -1
- package/lib/vendor/blamejs/lib/network-dns.js +3 -3
- package/lib/vendor/blamejs/lib/network-nts.js +35 -14
- package/lib/vendor/blamejs/lib/network-proxy.js +42 -4
- package/lib/vendor/blamejs/lib/network-smtp-policy.js +1 -1
- package/lib/vendor/blamejs/lib/network-tls.js +341 -11
- package/lib/vendor/blamejs/lib/nist-crosswalk.js +2 -2
- package/lib/vendor/blamejs/lib/ntp-check.js +30 -19
- package/lib/vendor/blamejs/lib/object-store/azure-blob.js +1 -1
- package/lib/vendor/blamejs/lib/object-store/gcs.js +1 -1
- package/lib/vendor/blamejs/lib/object-store/http-put.js +2 -1
- package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -5
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +2 -2
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +4 -2
- package/lib/vendor/blamejs/lib/openapi.js +1 -1
- package/lib/vendor/blamejs/lib/pqc-agent.js +4 -7
- package/lib/vendor/blamejs/lib/problem-details.js +2 -1
- package/lib/vendor/blamejs/lib/redis-client.js +12 -1
- package/lib/vendor/blamejs/lib/regex-linear.js +1349 -0
- package/lib/vendor/blamejs/lib/render.js +531 -7
- package/lib/vendor/blamejs/lib/request-helpers.js +181 -5
- package/lib/vendor/blamejs/lib/router.js +37 -13
- package/lib/vendor/blamejs/lib/safe-async.js +142 -0
- package/lib/vendor/blamejs/lib/safe-icap.js +3 -0
- package/lib/vendor/blamejs/lib/safe-sql.js +15 -3
- package/lib/vendor/blamejs/lib/self-update.js +2 -2
- package/lib/vendor/blamejs/lib/testing.js +54 -7
- package/lib/vendor/blamejs/lib/validate-opts.js +56 -0
- package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +62 -25
- package/lib/vendor/blamejs/lib/vendor/blamejs-pki.cjs +2004 -142
- package/lib/vendor/blamejs/lib/vendor/browser/noble-ciphers.mjs +727 -0
- package/lib/vendor/blamejs/lib/vendor/browser/noble-hashes.mjs +1070 -0
- package/lib/vendor/blamejs/lib/vendor/browser/noble-post-quantum.mjs +1090 -0
- package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +510 -227
- package/lib/vendor/blamejs/lib/webhook-hmac.js +19 -2
- package/lib/vendor/blamejs/lib/webhook.js +1 -1
- package/lib/vendor/blamejs/lib/ws-client.js +24 -2
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/sbom.cdx.json +6 -6
- package/lib/vendor-invoices.js +3 -6
- package/lib/vendors.js +5 -19
- package/lib/webhook-receiver.js +46 -83
- package/lib/webhook-subscriptions.js +3 -13
- package/lib/wishlist-sharing.js +5 -10
- package/package.json +1 -1
package/lib/text-guard.js
CHANGED
|
@@ -36,7 +36,11 @@
|
|
|
36
36
|
* - slugLabel(s, label, opts?) — lowercase URL-slug label
|
|
37
37
|
* - hostLabel(host, label?) — outbound host SSRF + by-name denylist
|
|
38
38
|
* - freeText(s, label, policy?) — dangerous-codepoint screen for
|
|
39
|
-
* unconstrained UTF-8 text fields
|
|
39
|
+
* unconstrained UTF-8 text fields, throwing on a refusal
|
|
40
|
+
* - hasCodepointThreat(s, policy?) — the same screen for a defensive
|
|
41
|
+
* reader that DROPS a bad value instead of refusing the request
|
|
42
|
+
* - firstCodepointThreat(s, policy?) — the one decision both run, so
|
|
43
|
+
* the throwing and dropping paths cannot disagree
|
|
40
44
|
*
|
|
41
45
|
* @primitive textGuard
|
|
42
46
|
* @related b.money, b.ssrfGuard, b.safeUrl, shop.currencyRounding,
|
|
@@ -52,6 +56,41 @@ var b = require("./vendor/blamejs");
|
|
|
52
56
|
// second copy of the tables.
|
|
53
57
|
var codepointClass = b.codepointClass;
|
|
54
58
|
|
|
59
|
+
// Two invisible-codepoint groups this shop refuses that the framework catalog
|
|
60
|
+
// does not carry yet. Built with codepointClass.charClass off a range table so
|
|
61
|
+
// the escaping is the catalog's, not a second hand-spelled class:
|
|
62
|
+
//
|
|
63
|
+
// U+007F DELETE — grouped with the C0 controls everywhere it matters, but
|
|
64
|
+
// outside the 0x00-0x1F block the framework's C0_CTRL_RANGES covers.
|
|
65
|
+
// U+2061-2064 FUNCTION APPLICATION / INVISIBLE TIMES / INVISIBLE SEPARATOR /
|
|
66
|
+
// INVISIBLE PLUS — zero-width invisible operators, the same spoofing class
|
|
67
|
+
// as U+2060 WORD JOINER, which the framework's ZERO_WIDTH_RANGES does have.
|
|
68
|
+
//
|
|
69
|
+
// Requested upstream (blamejs#580). When a vendor refresh lands them in the
|
|
70
|
+
// catalog this supplement becomes dead weight and comes out — the drift test
|
|
71
|
+
// in test/layer-1-state/text-guard.test.js fails the moment that happens, so
|
|
72
|
+
// it cannot be silently carried forever.
|
|
73
|
+
//
|
|
74
|
+
// Kept as two classes rather than one so each joins the check whose refusal
|
|
75
|
+
// message is already true of it.
|
|
76
|
+
// allow:dynamic-regex — codepoints from a literal range table
|
|
77
|
+
var DEL_RE = new RegExp("[" + codepointClass.charClass([0x007F]) + "]");
|
|
78
|
+
// allow:dynamic-regex — codepoints from a literal range table
|
|
79
|
+
var INVISIBLE_OP_RE = new RegExp("[" + codepointClass.charClass([[0x2061, 0x2064]]) + "]");
|
|
80
|
+
// Global twin for the strip pass; the unglobbed one above is the presence test.
|
|
81
|
+
// allow:dynamic-regex — codepoints from a literal range table
|
|
82
|
+
var INVISIBLE_OP_RE_G = new RegExp("[" + codepointClass.charClass([[0x2061, 0x2064]]) + "]", "g");
|
|
83
|
+
|
|
84
|
+
// Everything that ends a line or pads it out, for a value that must stay on
|
|
85
|
+
// one. Tab / LF / CR sit outside the framework's C0 table on purpose — a
|
|
86
|
+
// multi-line body needs them — so a single-line field asks for them here.
|
|
87
|
+
// U+2028 / U+2029 are not control characters at all, but they terminate a
|
|
88
|
+
// line for both a renderer and a JS string literal.
|
|
89
|
+
// allow:dynamic-regex — codepoints from a literal range table
|
|
90
|
+
var LINE_BREAK_RE = new RegExp(
|
|
91
|
+
"[" + codepointClass.charClass([0x0009, 0x000A, 0x000D, [0x2028, 0x2029]]) + "]"
|
|
92
|
+
);
|
|
93
|
+
|
|
55
94
|
// ---- shop validators ----------------------------------------------------
|
|
56
95
|
|
|
57
96
|
// asciiUpperLetters(s, label, n?) — exactly `n` (default 3) ASCII
|
|
@@ -157,45 +196,105 @@ function hostLabel(host, label) {
|
|
|
157
196
|
return h;
|
|
158
197
|
}
|
|
159
198
|
|
|
160
|
-
//
|
|
161
|
-
//
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
//
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
199
|
+
// firstCodepointThreat(s, policy?) — the single decision both the throwing
|
|
200
|
+
// screen (freeText) and the drop-silent one (hasCodepointThreat) run, so a
|
|
201
|
+
// field guarded one way and a field guarded the other can never disagree
|
|
202
|
+
// about what "dangerous" means. Returns a short reason string naming the
|
|
203
|
+
// class, or null when the text is clean. The reason is the clause that
|
|
204
|
+
// follows the field name in a refusal ("contains a null byte"), so a caller
|
|
205
|
+
// building a message just joins the two.
|
|
206
|
+
//
|
|
207
|
+
// Policies, each "reject" to enable and any other value to allow:
|
|
208
|
+
// bidi — default "reject". Bidi overrides (CVE-2021-42574).
|
|
209
|
+
// nullByte — default "reject". U+0000.
|
|
210
|
+
// control — default "reject". C0 controls + U+007F DELETE. Tab, LF and
|
|
211
|
+
// CR are ALLOWED here: a multi-line body legitimately has
|
|
212
|
+
// them. Use singleLine for a field that must not.
|
|
213
|
+
// singleLine — off by default. Tab / LF / CR, plus U+2028 LINE SEPARATOR
|
|
214
|
+
// and U+2029 PARAGRAPH SEPARATOR, which break a line without
|
|
215
|
+
// being C0 at all. For a value rendered on one line — a URL,
|
|
216
|
+
// a subject, a title, a header value.
|
|
217
|
+
// zeroWidth — off by default. Zero-width / invisible formatting. Includes
|
|
218
|
+
// U+00AD SOFT HYPHEN, which text pasted out of a hyphenating
|
|
219
|
+
// word processor or PDF carries invisibly.
|
|
220
|
+
// mixedScript — off by default. Confusable / homograph across writing
|
|
221
|
+
// systems, narrowed by policy.allowedScripts.
|
|
222
|
+
function firstCodepointThreat(s, policy) {
|
|
175
223
|
policy = policy || {};
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
var controlP = policy.control || "reject";
|
|
179
|
-
if (bidiP === "reject" && codepointClass.BIDI_RE.test(s)) {
|
|
180
|
-
throw new TypeError(name + " contains a Unicode bidi override (CVE-2021-42574 Trojan Source)");
|
|
224
|
+
if ((policy.bidi || "reject") === "reject" && codepointClass.BIDI_RE.test(s)) {
|
|
225
|
+
return "contains a Unicode bidi override (CVE-2021-42574 Trojan Source)";
|
|
181
226
|
}
|
|
182
|
-
if (
|
|
183
|
-
|
|
227
|
+
if ((policy.nullByte || "reject") === "reject" &&
|
|
228
|
+
s.indexOf(codepointClass.NULL_BYTE) !== -1) {
|
|
229
|
+
return "contains a null byte";
|
|
184
230
|
}
|
|
185
|
-
if (
|
|
186
|
-
|
|
231
|
+
if ((policy.control || "reject") === "reject" &&
|
|
232
|
+
(codepointClass.C0_CTRL_RE.test(s) || DEL_RE.test(s))) {
|
|
233
|
+
return "contains a C0 control character";
|
|
187
234
|
}
|
|
188
|
-
if (policy.
|
|
189
|
-
|
|
235
|
+
if (policy.singleLine === "reject" && LINE_BREAK_RE.test(s)) {
|
|
236
|
+
return "contains a line break or tab but must be a single line";
|
|
237
|
+
}
|
|
238
|
+
if (policy.zeroWidth === "reject" &&
|
|
239
|
+
(codepointClass.ZERO_WIDTH_RE.test(s) || INVISIBLE_OP_RE.test(s))) {
|
|
240
|
+
return "contains a zero-width / invisible formatting character";
|
|
190
241
|
}
|
|
191
242
|
if (policy.mixedScript === "reject") {
|
|
192
243
|
var scripts = codepointClass.detectMixedScripts(s, policy.allowedScripts);
|
|
193
244
|
if (scripts) {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
);
|
|
245
|
+
return "mixes writing systems (" + scripts.join(", ") +
|
|
246
|
+
") — possible confusable / homograph";
|
|
197
247
|
}
|
|
198
248
|
}
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// hasCodepointThreat(s, policy?) — the non-throwing sibling of freeText, for
|
|
253
|
+
// the defensive readers that DROP a bad value rather than refusing the
|
|
254
|
+
// request (a link URL inside a rendered body, a header line being assembled).
|
|
255
|
+
// A non-string is dangerous by definition here: the caller is about to render
|
|
256
|
+
// or transmit it. Returns true when the text must not be used.
|
|
257
|
+
function hasCodepointThreat(s, policy) {
|
|
258
|
+
if (typeof s !== "string") return true;
|
|
259
|
+
return firstCodepointThreat(s, policy) !== null;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// scrubInvisible(s) — remove every bidi override and invisible-formatting
|
|
263
|
+
// codepoint and return the cleaned string. The third disposition, alongside
|
|
264
|
+
// throwing and dropping: for a value that must be ACCEPTED whatever it
|
|
265
|
+
// contains, because refusing it would hand an attacker a denial-of-service
|
|
266
|
+
// against a legitimate user (a search query is the standing example — a
|
|
267
|
+
// pasted BOM must not cost the shopper their search).
|
|
268
|
+
//
|
|
269
|
+
// Composes the framework's strip pass and then removes the codepoints the
|
|
270
|
+
// catalog does not carry yet, so what this deletes is exactly what
|
|
271
|
+
// hasCodepointThreat would have objected to under zeroWidth: "reject".
|
|
272
|
+
// Control characters are deliberately NOT touched: a caller stripping those
|
|
273
|
+
// usually wants to substitute a space to avoid welding two words together,
|
|
274
|
+
// which is its own decision.
|
|
275
|
+
function scrubInvisible(s) {
|
|
276
|
+
if (typeof s !== "string") return s;
|
|
277
|
+
var out = codepointClass.applyCharStripPolicies(s, {
|
|
278
|
+
bidiPolicy: "strip",
|
|
279
|
+
zeroWidthPolicy: "strip",
|
|
280
|
+
tagsPolicy: "strip",
|
|
281
|
+
});
|
|
282
|
+
return out.replace(INVISIBLE_OP_RE_G, "");
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// freeText(s, label, policy?) — the dangerous-codepoint screen for an
|
|
286
|
+
// UNCONSTRAINED UTF-8 text field (customer note, review body, gift
|
|
287
|
+
// message, product Q&A). Unlike the ASCII-allowlist validators above,
|
|
288
|
+
// these fields legitimately carry arbitrary letters, so the codepoint
|
|
289
|
+
// catalog is the right backing. Throws TypeError on a refused codepoint;
|
|
290
|
+
// returns the input on success. See firstCodepointThreat for the policies.
|
|
291
|
+
function freeText(s, label, policy) {
|
|
292
|
+
var name = label || "value";
|
|
293
|
+
if (typeof s !== "string") {
|
|
294
|
+
throw new TypeError(name + " must be a string");
|
|
295
|
+
}
|
|
296
|
+
var reason = firstCodepointThreat(s, policy);
|
|
297
|
+
if (reason) throw new TypeError(name + " " + reason);
|
|
199
298
|
return s;
|
|
200
299
|
}
|
|
201
300
|
|
|
@@ -213,9 +312,12 @@ module.exports = {
|
|
|
213
312
|
applyCharStripPolicies: codepointClass.applyCharStripPolicies,
|
|
214
313
|
|
|
215
314
|
// Shop validators.
|
|
216
|
-
asciiUpperLetters:
|
|
217
|
-
currencyCode:
|
|
218
|
-
slugLabel:
|
|
219
|
-
hostLabel:
|
|
220
|
-
freeText:
|
|
315
|
+
asciiUpperLetters: asciiUpperLetters,
|
|
316
|
+
currencyCode: currencyCode,
|
|
317
|
+
slugLabel: slugLabel,
|
|
318
|
+
hostLabel: hostLabel,
|
|
319
|
+
freeText: freeText,
|
|
320
|
+
hasCodepointThreat: hasCodepointThreat,
|
|
321
|
+
firstCodepointThreat: firstCodepointThreat,
|
|
322
|
+
scrubInvisible: scrubInvisible,
|
|
221
323
|
};
|
package/lib/theme-assets.js
CHANGED
|
@@ -84,6 +84,7 @@
|
|
|
84
84
|
*/
|
|
85
85
|
|
|
86
86
|
var b = require("./vendor/blamejs");
|
|
87
|
+
var textGuard = require("./text-guard");
|
|
87
88
|
|
|
88
89
|
var MAX_SLUG_LEN = 80;
|
|
89
90
|
var MAX_THEME_SLUG_LEN = 80;
|
|
@@ -130,14 +131,10 @@ var SHA3_512_HEX_RE = /^[0-9a-f]{128}$/;
|
|
|
130
131
|
var CONTENT_TYPE_RE = /^[A-Za-z0-9!#$&^_.+-]+\/[A-Za-z0-9!#$&^_.+-]+(?:\s*;\s*[A-Za-z0-9!#$&^_.+-]+\s*=\s*(?:"[^"\x00-\x1f]*"|[A-Za-z0-9!#$&^_.+-]+))*$/;
|
|
131
132
|
|
|
132
133
|
// Refuse C0 control bytes + DEL in operator-authored text fields.
|
|
133
|
-
var CONTROL_BYTE_LINE_RE = /[\x00-\x1f\x7f]/;
|
|
134
134
|
|
|
135
135
|
// Zero-width / direction-override family — mirrors the rest of the
|
|
136
136
|
// shop primitives. Spelled with \u-escapes so ESLint's
|
|
137
137
|
// no-irregular-whitespace stays happy.
|
|
138
|
-
var ZERO_WIDTH_RE = new RegExp(
|
|
139
|
-
"[\\u200B-\\u200F\\u202A-\\u202E\\u2060-\\u2064\\u2066-\\u2069\\uFEFF\\u061C]"
|
|
140
|
-
);
|
|
141
138
|
|
|
142
139
|
var MS_PER_DAY = b.constants.TIME.days(1);
|
|
143
140
|
|
|
@@ -181,9 +178,7 @@ function _contentType(s) {
|
|
|
181
178
|
MAX_CONTENT_TYPE_LEN + " chars"
|
|
182
179
|
);
|
|
183
180
|
}
|
|
184
|
-
|
|
185
|
-
throw new TypeError("themeAssets: content_type contains control bytes");
|
|
186
|
-
}
|
|
181
|
+
textGuard.freeText(s, "themeAssets: content_type", { singleLine: "reject" });
|
|
187
182
|
if (!CONTENT_TYPE_RE.test(s)) {
|
|
188
183
|
throw new TypeError(
|
|
189
184
|
"themeAssets: content_type " + JSON.stringify(s) +
|
|
@@ -230,9 +225,7 @@ function _sourceUrl(s) {
|
|
|
230
225
|
MAX_SOURCE_URL_LEN + " chars"
|
|
231
226
|
);
|
|
232
227
|
}
|
|
233
|
-
|
|
234
|
-
throw new TypeError("themeAssets: source_url contains control / zero-width bytes");
|
|
235
|
-
}
|
|
228
|
+
textGuard.freeText(s, "themeAssets: source_url", { singleLine: "reject", zeroWidth: "reject" });
|
|
236
229
|
if (s.charCodeAt(0) === 47 /* "/" */) {
|
|
237
230
|
if (s.length > 1 && s.charCodeAt(1) === 47) {
|
|
238
231
|
throw new TypeError(
|
|
@@ -264,12 +257,7 @@ function _altText(s) {
|
|
|
264
257
|
MAX_ALT_TEXT_LEN + " chars (or null)"
|
|
265
258
|
);
|
|
266
259
|
}
|
|
267
|
-
|
|
268
|
-
throw new TypeError("themeAssets: alt_text contains control bytes (incl. CR/LF)");
|
|
269
|
-
}
|
|
270
|
-
if (ZERO_WIDTH_RE.test(s)) {
|
|
271
|
-
throw new TypeError("themeAssets: alt_text contains zero-width / direction-override characters");
|
|
272
|
-
}
|
|
260
|
+
textGuard.freeText(s, "themeAssets: alt_text", { singleLine: "reject", zeroWidth: "reject" });
|
|
273
261
|
return s;
|
|
274
262
|
}
|
|
275
263
|
|
package/lib/translations.js
CHANGED
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
*/
|
|
59
59
|
|
|
60
60
|
var b = require("./vendor/blamejs");
|
|
61
|
+
var textGuard = require("./text-guard");
|
|
61
62
|
|
|
62
63
|
var MAX_KIND_LEN = 64;
|
|
63
64
|
var MAX_RESOURCE_ID_LEN = 128;
|
|
@@ -90,14 +91,10 @@ var LOCALE_RE = /^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/;
|
|
|
90
91
|
// allowed (operators author multi-line page bodies) — the rest of
|
|
91
92
|
// the C0 range would only reach the storefront as a smuggling
|
|
92
93
|
// payload or a copy-paste accident from a terminal.
|
|
93
|
-
var CONTROL_BYTE_RE = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/;
|
|
94
94
|
|
|
95
95
|
// Zero-width / direction-override family. Spelled with \u-escapes
|
|
96
96
|
// so ESLint's no-irregular-whitespace stays happy. Same defence the
|
|
97
97
|
// rest of the shop uses on operator-authored strings.
|
|
98
|
-
var ZERO_WIDTH_RE = new RegExp(
|
|
99
|
-
"[\\u200B-\\u200F\\u202A-\\u202E\\u2060-\\u2064\\u2066-\\u2069\\uFEFF\\u061C]"
|
|
100
|
-
);
|
|
101
98
|
|
|
102
99
|
// ---- validators ---------------------------------------------------------
|
|
103
100
|
|
|
@@ -193,10 +190,10 @@ function _value(s, fnLabel) {
|
|
|
193
190
|
if (s.length > MAX_VALUE_LEN) {
|
|
194
191
|
throw new TypeError(fnLabel + ": value must be <= " + MAX_VALUE_LEN + " characters");
|
|
195
192
|
}
|
|
196
|
-
if (
|
|
193
|
+
if (textGuard.hasCodepointThreat(s)) {
|
|
197
194
|
throw new TypeError(fnLabel + ": value contains forbidden control bytes");
|
|
198
195
|
}
|
|
199
|
-
if (
|
|
196
|
+
if (textGuard.hasCodepointThreat(s, { zeroWidth: "reject" })) {
|
|
200
197
|
throw new TypeError(fnLabel + ": value contains zero-width / direction-override characters");
|
|
201
198
|
}
|
|
202
199
|
return s;
|
package/lib/trust-badges.js
CHANGED
|
@@ -116,13 +116,9 @@ var EVENT_TYPES = Object.freeze(["impression", "click"]);
|
|
|
116
116
|
var SLUG_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,79}$/;
|
|
117
117
|
|
|
118
118
|
// Refuse C0 control bytes + DEL in single-line operator strings.
|
|
119
|
-
var CONTROL_BYTE_LINE_RE = /[\x00-\x1f\x7f]/;
|
|
120
119
|
|
|
121
120
|
// Zero-width / direction-override family — same catalogue as the
|
|
122
121
|
// other operator-authored primitives.
|
|
123
|
-
var ZERO_WIDTH_RE = new RegExp(
|
|
124
|
-
"[\\u200B-\\u200F\\u202A-\\u202E\\u2060-\\u2064\\u2066-\\u2069\\uFEFF\\u061C]"
|
|
125
|
-
);
|
|
126
122
|
|
|
127
123
|
// Hash namespace — opaque per-primitive constant so a session_id_hash
|
|
128
124
|
// emitted by trustBadges can't collide with one emitted by analytics
|
|
@@ -142,6 +138,7 @@ var ALLOWED_PATCH_COLUMNS = Object.freeze([
|
|
|
142
138
|
]);
|
|
143
139
|
|
|
144
140
|
var b = require("./vendor/blamejs");
|
|
141
|
+
var textGuard = require("./text-guard");
|
|
145
142
|
|
|
146
143
|
// ---- validators ---------------------------------------------------------
|
|
147
144
|
|
|
@@ -184,10 +181,10 @@ function _line(s, label, maxLen) {
|
|
|
184
181
|
if (typeof s !== "string" || !s.length || s.length > maxLen) {
|
|
185
182
|
throw new TypeError("trustBadges: " + label + " must be a non-empty string ≤ " + maxLen + " chars");
|
|
186
183
|
}
|
|
187
|
-
if (
|
|
184
|
+
if (textGuard.hasCodepointThreat(s, { singleLine: "reject" })) {
|
|
188
185
|
throw new TypeError("trustBadges: " + label + " contains control bytes (incl. CR/LF)");
|
|
189
186
|
}
|
|
190
|
-
if (
|
|
187
|
+
if (textGuard.hasCodepointThreat(s, { zeroWidth: "reject" })) {
|
|
191
188
|
throw new TypeError("trustBadges: " + label + " contains zero-width / direction-override characters");
|
|
192
189
|
}
|
|
193
190
|
return s;
|
|
@@ -201,7 +198,7 @@ function _httpsOrRootUrl(s, label, maxLen) {
|
|
|
201
198
|
if (typeof s !== "string" || !s.length || s.length > maxLen) {
|
|
202
199
|
throw new TypeError("trustBadges: " + label + " must be a non-empty string ≤ " + maxLen + " chars");
|
|
203
200
|
}
|
|
204
|
-
if (
|
|
201
|
+
if (textGuard.hasCodepointThreat(s, { singleLine: "reject", zeroWidth: "reject" })) {
|
|
205
202
|
throw new TypeError("trustBadges: " + label + " contains control / zero-width bytes");
|
|
206
203
|
}
|
|
207
204
|
if (s.charCodeAt(0) === 47 /* "/" */) {
|