@blamejs/blamejs-shop 0.5.21 → 0.5.22
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 +2 -0
- package/README.md +1 -1
- package/SECURITY.md +7 -1
- package/lib/addresses.js +16 -2
- package/lib/affiliates.js +3 -3
- package/lib/announcement-bar.js +2 -2
- package/lib/api-keys.js +2 -2
- package/lib/asset-manifest.json +1 -1
- package/lib/blog-articles.js +2 -2
- package/lib/carrier-accounts.js +2 -2
- package/lib/catalog-drafts.js +1 -1
- package/lib/category-navigation.js +6 -3
- package/lib/compliance-export.js +8 -1
- package/lib/customer-notes.js +1 -1
- package/lib/customer-roles.js +1 -1
- package/lib/customer-surveys.js +2 -2
- package/lib/customers.js +1 -1
- package/lib/dispute-resolution.js +3 -3
- package/lib/dropship-forwarding.js +1 -1
- package/lib/dunning.js +1 -1
- package/lib/email-ab-tests.js +1 -1
- package/lib/email-campaigns.js +15 -2
- package/lib/email-warmup.js +1 -1
- package/lib/externaldb-d1.js +0 -8
- package/lib/gift-options.js +3 -3
- package/lib/knowledge-base.js +3 -3
- package/lib/line-gift-wrap.js +6 -2
- package/lib/live-chat.js +1 -1
- package/lib/notifications.js +1 -1
- package/lib/operator-accounts.js +1 -1
- package/lib/operator-help-center.js +3 -3
- package/lib/operator-inbox.js +2 -2
- package/lib/operator-roles.js +1 -1
- package/lib/order-notes.js +2 -2
- package/lib/order-ratings.js +3 -3
- package/lib/payment-methods.js +1 -1
- package/lib/payment-retries.js +1 -1
- package/lib/pixel-events.js +14 -6
- package/lib/plan-changes.js +1 -1
- package/lib/product-qa.js +1 -1
- package/lib/push-notifications.js +2 -2
- package/lib/reviews.js +3 -3
- package/lib/seller-signup.js +4 -4
- package/lib/sidebar-widgets.js +1 -1
- package/lib/sms-dispatcher.js +3 -3
- package/lib/stock-receipts.js +1 -1
- package/lib/storefront-dashboards.js +1 -1
- package/lib/storefront-forms.js +1 -1
- package/lib/storefront-pages.js +2 -2
- package/lib/subscription-billing.js +1 -1
- package/lib/subscription-controls.js +1 -1
- package/lib/suggestion-box.js +4 -4
- package/lib/support-tickets.js +3 -3
- package/lib/tenants.js +1 -1
- package/lib/text-guard.js +44 -2
- package/lib/theme-assets.js +1 -1
- package/lib/vendor/MANIFEST.json +12 -12
- package/lib/vendor/blamejs/CHANGELOG.md +32 -0
- package/lib/vendor/blamejs/NOTICE +1 -1
- package/lib/vendor/blamejs/README.md +1 -1
- package/lib/vendor/blamejs/lib/network-tls.js +98 -13
- package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +12 -12
- package/lib/vendor/blamejs/lib/vendor/blamejs-pki.cjs +568 -304
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/sbom.cdx.json +6 -6
- package/lib/vendors.js +3 -3
- package/lib/webhook-receiver.js +1 -1
- package/lib/webhook-subscriptions.js +1 -1
- package/lib/wishlist-sharing.js +1 -1
- package/package.json +1 -1
|
@@ -164,7 +164,7 @@ function _title(s) {
|
|
|
164
164
|
if (s.length > MAX_TITLE_LEN) {
|
|
165
165
|
throw new TypeError("operatorHelpCenter: title must be <= " + MAX_TITLE_LEN + " characters");
|
|
166
166
|
}
|
|
167
|
-
textGuard.freeText(s, "operatorHelpCenter: title", { singleLine: "reject", zeroWidth: "reject" });
|
|
167
|
+
textGuard.freeText(s, "operatorHelpCenter: title", { singleLine: "reject", zeroWidth: "reject", bidiMarks: "allow" });
|
|
168
168
|
return s;
|
|
169
169
|
}
|
|
170
170
|
|
|
@@ -179,7 +179,7 @@ function _body(s) {
|
|
|
179
179
|
if (s.length > MAX_BODY_LEN) {
|
|
180
180
|
throw new TypeError("operatorHelpCenter: body must be <= " + MAX_BODY_LEN + " characters");
|
|
181
181
|
}
|
|
182
|
-
textGuard.freeText(s, "operatorHelpCenter: body", { zeroWidth: "reject" });
|
|
182
|
+
textGuard.freeText(s, "operatorHelpCenter: body", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
183
183
|
return s;
|
|
184
184
|
}
|
|
185
185
|
|
|
@@ -290,7 +290,7 @@ function _queryStr(s) {
|
|
|
290
290
|
if (s.length > MAX_QUERY_LEN) {
|
|
291
291
|
throw new TypeError("operatorHelpCenter: query must be <= " + MAX_QUERY_LEN + " characters");
|
|
292
292
|
}
|
|
293
|
-
textGuard.freeText(s, "operatorHelpCenter: query", { zeroWidth: "reject" });
|
|
293
|
+
textGuard.freeText(s, "operatorHelpCenter: query", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
294
294
|
return s;
|
|
295
295
|
}
|
|
296
296
|
|
package/lib/operator-inbox.js
CHANGED
|
@@ -248,7 +248,7 @@ function _subject(s) {
|
|
|
248
248
|
if (typeof s !== "string" || !s.length || s.length > MAX_SUBJECT_LEN) {
|
|
249
249
|
throw new TypeError("operatorInbox: subject must be a non-empty string <= " + MAX_SUBJECT_LEN + " chars");
|
|
250
250
|
}
|
|
251
|
-
textGuard.freeText(s, "operatorInbox: subject");
|
|
251
|
+
textGuard.freeText(s, "operatorInbox: subject", { bidiMarks: "allow" });
|
|
252
252
|
return s;
|
|
253
253
|
}
|
|
254
254
|
|
|
@@ -256,7 +256,7 @@ function _body(s) {
|
|
|
256
256
|
if (typeof s !== "string" || !s.length || s.length > MAX_BODY_LEN) {
|
|
257
257
|
throw new TypeError("operatorInbox: body must be a non-empty string <= " + MAX_BODY_LEN + " chars");
|
|
258
258
|
}
|
|
259
|
-
textGuard.freeText(s, "operatorInbox: body");
|
|
259
|
+
textGuard.freeText(s, "operatorInbox: body", { bidiMarks: "allow" });
|
|
260
260
|
return s;
|
|
261
261
|
}
|
|
262
262
|
|
package/lib/operator-roles.js
CHANGED
|
@@ -185,7 +185,7 @@ function _title(s) {
|
|
|
185
185
|
if (typeof s !== "string" || !s.length || s.length > MAX_TITLE_LEN) {
|
|
186
186
|
throw new TypeError("operatorRoles: title must be a non-empty string <= " + MAX_TITLE_LEN + " chars");
|
|
187
187
|
}
|
|
188
|
-
textGuard.freeText(s, "operatorRoles: title", { singleLine: "reject" });
|
|
188
|
+
textGuard.freeText(s, "operatorRoles: title", { singleLine: "reject", bidiMarks: "allow" });
|
|
189
189
|
return s;
|
|
190
190
|
}
|
|
191
191
|
|
package/lib/order-notes.js
CHANGED
|
@@ -95,7 +95,7 @@ function _body(s) {
|
|
|
95
95
|
if (s.length > MAX_BODY_LEN) {
|
|
96
96
|
throw new TypeError("orderNotes: body must be <= " + MAX_BODY_LEN + " characters");
|
|
97
97
|
}
|
|
98
|
-
textGuard.freeText(s, "orderNotes: body", { zeroWidth: "reject" });
|
|
98
|
+
textGuard.freeText(s, "orderNotes: body", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
99
99
|
return s;
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -131,7 +131,7 @@ function _resolution(s) {
|
|
|
131
131
|
if (s.length > MAX_RESOLUTION_LEN) {
|
|
132
132
|
throw new TypeError("orderNotes: resolution must be <= " + MAX_RESOLUTION_LEN + " characters");
|
|
133
133
|
}
|
|
134
|
-
textGuard.freeText(s, "orderNotes: resolution", { zeroWidth: "reject" });
|
|
134
|
+
textGuard.freeText(s, "orderNotes: resolution", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
135
135
|
return s;
|
|
136
136
|
}
|
|
137
137
|
|
package/lib/order-ratings.js
CHANGED
|
@@ -130,7 +130,7 @@ function _comment(s) {
|
|
|
130
130
|
if (s.length > MAX_COMMENT_LEN) {
|
|
131
131
|
throw new TypeError("orderRatings: comment must be <= " + MAX_COMMENT_LEN + " chars");
|
|
132
132
|
}
|
|
133
|
-
textGuard.freeText(s, "orderRatings: comment");
|
|
133
|
+
textGuard.freeText(s, "orderRatings: comment", { bidiMarks: "allow" });
|
|
134
134
|
return s;
|
|
135
135
|
}
|
|
136
136
|
|
|
@@ -138,7 +138,7 @@ function _flagReason(s) {
|
|
|
138
138
|
if (typeof s !== "string" || !s.length || s.length > MAX_FLAG_REASON_LEN) {
|
|
139
139
|
throw new TypeError("orderRatings: reason must be a non-empty string <= " + MAX_FLAG_REASON_LEN + " chars");
|
|
140
140
|
}
|
|
141
|
-
textGuard.freeText(s, "orderRatings: reason");
|
|
141
|
+
textGuard.freeText(s, "orderRatings: reason", { bidiMarks: "allow" });
|
|
142
142
|
return s;
|
|
143
143
|
}
|
|
144
144
|
|
|
@@ -146,7 +146,7 @@ function _responseText(s) {
|
|
|
146
146
|
if (typeof s !== "string" || !s.length || s.length > MAX_RESPONSE_LEN) {
|
|
147
147
|
throw new TypeError("orderRatings: response must be a non-empty string <= " + MAX_RESPONSE_LEN + " chars");
|
|
148
148
|
}
|
|
149
|
-
textGuard.freeText(s, "orderRatings: response");
|
|
149
|
+
textGuard.freeText(s, "orderRatings: response", { bidiMarks: "allow" });
|
|
150
150
|
return s;
|
|
151
151
|
}
|
|
152
152
|
|
package/lib/payment-methods.js
CHANGED
|
@@ -140,7 +140,7 @@ function _label(s) {
|
|
|
140
140
|
if (s.length > MAX_LABEL_LEN) {
|
|
141
141
|
throw new TypeError("paymentMethods: label must be <= " + MAX_LABEL_LEN + " characters");
|
|
142
142
|
}
|
|
143
|
-
textGuard.freeText(s, "paymentMethods: label", { singleLine: "reject" });
|
|
143
|
+
textGuard.freeText(s, "paymentMethods: label", { singleLine: "reject", bidiMarks: "allow" });
|
|
144
144
|
return s;
|
|
145
145
|
}
|
|
146
146
|
|
package/lib/payment-retries.js
CHANGED
|
@@ -229,7 +229,7 @@ function _reason(s) {
|
|
|
229
229
|
if (s.length > MAX_REASON_LEN) {
|
|
230
230
|
throw new TypeError("paymentRetries: reason must be <= " + MAX_REASON_LEN + " characters");
|
|
231
231
|
}
|
|
232
|
-
textGuard.freeText(s, "paymentRetries: reason", { zeroWidth: "reject" });
|
|
232
|
+
textGuard.freeText(s, "paymentRetries: reason", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
233
233
|
return s;
|
|
234
234
|
}
|
|
235
235
|
|
package/lib/pixel-events.js
CHANGED
|
@@ -403,12 +403,20 @@ function _responseBody(s) {
|
|
|
403
403
|
if (s.length > MAX_RESPONSE_BODY_LEN) {
|
|
404
404
|
throw new TypeError("pixelEvents: response_body must be <= " + MAX_RESPONSE_BODY_LEN + " characters");
|
|
405
405
|
}
|
|
406
|
-
//
|
|
407
|
-
//
|
|
408
|
-
//
|
|
409
|
-
//
|
|
410
|
-
|
|
411
|
-
|
|
406
|
+
// SCRUBBED, never refused. This string is whatever an upstream provider sent
|
|
407
|
+
// back, and `markDispatched` runs this validator BEFORE it transitions the
|
|
408
|
+
// event — so any refusal here leaves the row in `queued` and the scheduler
|
|
409
|
+
// re-sends the identical pixel on every tick, forever, because we disliked a
|
|
410
|
+
// byte in the reply. A provider must never be able to hold an event open by
|
|
411
|
+
// choosing its response body.
|
|
412
|
+
//
|
|
413
|
+
// The interest in this field is only that an operator reading the audit
|
|
414
|
+
// trail is not shown invisible characters. Removing them satisfies that
|
|
415
|
+
// without ever failing: the bidi overrides, the direction marks, the
|
|
416
|
+
// zero-width family and the Unicode Tags block all come out, and everything
|
|
417
|
+
// legible — including the tabs and newlines a real response is full of —
|
|
418
|
+
// stays exactly as the provider sent it.
|
|
419
|
+
return textGuard.scrubInvisible(s);
|
|
412
420
|
}
|
|
413
421
|
|
|
414
422
|
function _responseStatus(n) {
|
package/lib/plan-changes.js
CHANGED
|
@@ -115,7 +115,7 @@ function _optReason(s) {
|
|
|
115
115
|
if (s.length > MAX_REASON_LEN) {
|
|
116
116
|
throw new TypeError("planChanges: reason must be <= " + MAX_REASON_LEN + " characters");
|
|
117
117
|
}
|
|
118
|
-
textGuard.freeText(s, "planChanges: reason", { zeroWidth: "reject" });
|
|
118
|
+
textGuard.freeText(s, "planChanges: reason", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
119
119
|
return s;
|
|
120
120
|
}
|
|
121
121
|
|
package/lib/product-qa.js
CHANGED
|
@@ -131,7 +131,7 @@ function _reason(s) {
|
|
|
131
131
|
if (s.length > MAX_REASON_LEN) {
|
|
132
132
|
throw new TypeError("productQA: reason must be <= " + MAX_REASON_LEN + " characters");
|
|
133
133
|
}
|
|
134
|
-
textGuard.freeText(s, "productQA: reason");
|
|
134
|
+
textGuard.freeText(s, "productQA: reason", { bidiMarks: "allow" });
|
|
135
135
|
return s;
|
|
136
136
|
}
|
|
137
137
|
|
|
@@ -195,7 +195,7 @@ function _title(s) {
|
|
|
195
195
|
if (s.length > MAX_TITLE_LEN) {
|
|
196
196
|
throw new TypeError("pushNotifications: title must be <= " + MAX_TITLE_LEN + " characters");
|
|
197
197
|
}
|
|
198
|
-
textGuard.freeText(s, "pushNotifications: title", { zeroWidth: "reject" });
|
|
198
|
+
textGuard.freeText(s, "pushNotifications: title", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
199
199
|
return s;
|
|
200
200
|
}
|
|
201
201
|
|
|
@@ -206,7 +206,7 @@ function _body(s) {
|
|
|
206
206
|
if (s.length > MAX_BODY_LEN) {
|
|
207
207
|
throw new TypeError("pushNotifications: body must be <= " + MAX_BODY_LEN + " characters");
|
|
208
208
|
}
|
|
209
|
-
textGuard.freeText(s, "pushNotifications: body", { zeroWidth: "reject" });
|
|
209
|
+
textGuard.freeText(s, "pushNotifications: body", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
210
210
|
return s;
|
|
211
211
|
}
|
|
212
212
|
|
package/lib/reviews.js
CHANGED
|
@@ -75,7 +75,7 @@ function _title(s) {
|
|
|
75
75
|
if (s.length > MAX_TITLE_LEN) {
|
|
76
76
|
throw new TypeError("reviews: title must be <= " + MAX_TITLE_LEN + " characters");
|
|
77
77
|
}
|
|
78
|
-
textGuard.freeText(s, "reviews: title");
|
|
78
|
+
textGuard.freeText(s, "reviews: title", { bidiMarks: "allow" });
|
|
79
79
|
return s;
|
|
80
80
|
}
|
|
81
81
|
|
|
@@ -87,7 +87,7 @@ function _body(s) {
|
|
|
87
87
|
if (s.length > MAX_BODY_LEN) {
|
|
88
88
|
throw new TypeError("reviews: body must be <= " + MAX_BODY_LEN + " characters");
|
|
89
89
|
}
|
|
90
|
-
textGuard.freeText(s, "reviews: body");
|
|
90
|
+
textGuard.freeText(s, "reviews: body", { bidiMarks: "allow" });
|
|
91
91
|
return s;
|
|
92
92
|
}
|
|
93
93
|
|
|
@@ -284,7 +284,7 @@ function create(opts) {
|
|
|
284
284
|
if (reason.length > MAX_REJECT_REASON_LEN) {
|
|
285
285
|
throw new TypeError("reviews.reject: reason must be <= " + MAX_REJECT_REASON_LEN + " characters");
|
|
286
286
|
}
|
|
287
|
-
textGuard.freeText(reason, "reviews.reject: reason");
|
|
287
|
+
textGuard.freeText(reason, "reviews.reject: reason", { bidiMarks: "allow" });
|
|
288
288
|
}
|
|
289
289
|
var ts = _now();
|
|
290
290
|
var existing = (await query("SELECT id, status FROM reviews WHERE id = ?1", [id])).rows[0];
|
package/lib/seller-signup.js
CHANGED
|
@@ -154,7 +154,7 @@ function _businessName(s) {
|
|
|
154
154
|
if (s.length > MAX_BUSINESS_NAME_LEN) {
|
|
155
155
|
throw new TypeError("seller-signup: business_name must be <= " + MAX_BUSINESS_NAME_LEN + " characters");
|
|
156
156
|
}
|
|
157
|
-
textGuard.freeText(s, "seller-signup: business_name", { singleLine: "reject", zeroWidth: "reject" });
|
|
157
|
+
textGuard.freeText(s, "seller-signup: business_name", { singleLine: "reject", zeroWidth: "reject", bidiMarks: "allow" });
|
|
158
158
|
return s;
|
|
159
159
|
}
|
|
160
160
|
|
|
@@ -211,7 +211,7 @@ function _businessAddress(value) {
|
|
|
211
211
|
if (encoded.length > MAX_ADDRESS_JSON_LEN) {
|
|
212
212
|
throw new TypeError("seller-signup: business_address JSON must be <= " + MAX_ADDRESS_JSON_LEN + " characters serialised");
|
|
213
213
|
}
|
|
214
|
-
textGuard.freeText(encoded, "seller-signup: business_address", { singleLine: "reject", zeroWidth: "reject" });
|
|
214
|
+
textGuard.freeText(encoded, "seller-signup: business_address", { singleLine: "reject", zeroWidth: "reject", bidiMarks: "allow" });
|
|
215
215
|
return encoded;
|
|
216
216
|
}
|
|
217
217
|
|
|
@@ -316,7 +316,7 @@ function _instructions(s) {
|
|
|
316
316
|
if (textGuard.hasCodepointThreat(s)) {
|
|
317
317
|
throw new TypeError("seller-signup: instructions contains control bytes");
|
|
318
318
|
}
|
|
319
|
-
textGuard.freeText(s, "seller-signup: instructions", { zeroWidth: "reject" });
|
|
319
|
+
textGuard.freeText(s, "seller-signup: instructions", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
320
320
|
return s;
|
|
321
321
|
}
|
|
322
322
|
|
|
@@ -330,7 +330,7 @@ function _rejectReason(s) {
|
|
|
330
330
|
if (textGuard.hasCodepointThreat(s)) {
|
|
331
331
|
throw new TypeError("seller-signup: reason contains control bytes");
|
|
332
332
|
}
|
|
333
|
-
textGuard.freeText(s, "seller-signup: reason", { zeroWidth: "reject" });
|
|
333
|
+
textGuard.freeText(s, "seller-signup: reason", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
334
334
|
return s;
|
|
335
335
|
}
|
|
336
336
|
|
package/lib/sidebar-widgets.js
CHANGED
|
@@ -172,7 +172,7 @@ function _title(s) {
|
|
|
172
172
|
if (typeof s !== "string" || !s.length || s.length > MAX_TITLE_LEN) {
|
|
173
173
|
throw new TypeError("sidebarWidgets: title must be a non-empty string <= " + MAX_TITLE_LEN + " chars");
|
|
174
174
|
}
|
|
175
|
-
textGuard.freeText(s, "sidebarWidgets: title", { singleLine: "reject", zeroWidth: "reject" });
|
|
175
|
+
textGuard.freeText(s, "sidebarWidgets: title", { singleLine: "reject", zeroWidth: "reject", bidiMarks: "allow" });
|
|
176
176
|
return s;
|
|
177
177
|
}
|
|
178
178
|
|
package/lib/sms-dispatcher.js
CHANGED
|
@@ -147,7 +147,7 @@ function _name(s) {
|
|
|
147
147
|
if (s.length > MAX_NAME_LEN) {
|
|
148
148
|
throw new TypeError("smsDispatcher: name must be <= " + MAX_NAME_LEN + " characters");
|
|
149
149
|
}
|
|
150
|
-
textGuard.freeText(s, "smsDispatcher: name", { zeroWidth: "reject" });
|
|
150
|
+
textGuard.freeText(s, "smsDispatcher: name", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
151
151
|
return s;
|
|
152
152
|
}
|
|
153
153
|
|
|
@@ -267,7 +267,7 @@ function _optInText(s) {
|
|
|
267
267
|
if (s.length > MAX_OPT_IN_TEXT_LEN) {
|
|
268
268
|
throw new TypeError("smsDispatcher: opt_in_text must be <= " + MAX_OPT_IN_TEXT_LEN + " characters");
|
|
269
269
|
}
|
|
270
|
-
textGuard.freeText(s, "smsDispatcher: opt_in_text", { zeroWidth: "reject" });
|
|
270
|
+
textGuard.freeText(s, "smsDispatcher: opt_in_text", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
271
271
|
return s;
|
|
272
272
|
}
|
|
273
273
|
|
|
@@ -322,7 +322,7 @@ function _body(s) {
|
|
|
322
322
|
if (s.length > MAX_BODY_LEN) {
|
|
323
323
|
throw new TypeError("smsDispatcher: body must be <= " + MAX_BODY_LEN + " characters");
|
|
324
324
|
}
|
|
325
|
-
textGuard.freeText(s, "smsDispatcher: body", { zeroWidth: "reject" });
|
|
325
|
+
textGuard.freeText(s, "smsDispatcher: body", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
326
326
|
// Refuse the degenerate emoji-only shape. Walk the string by code
|
|
327
327
|
// point so surrogate pairs in the SMP emoji blocks count as one
|
|
328
328
|
// character.
|
package/lib/stock-receipts.js
CHANGED
|
@@ -171,7 +171,7 @@ function _reason(s) {
|
|
|
171
171
|
if (typeof s !== "string" || !s.length || s.length > MAX_REASON_LEN) {
|
|
172
172
|
throw new TypeError("stockReceipts: reason must be a non-empty string <= " + MAX_REASON_LEN + " chars");
|
|
173
173
|
}
|
|
174
|
-
textGuard.freeText(s, "stockReceipts: reason");
|
|
174
|
+
textGuard.freeText(s, "stockReceipts: reason", { bidiMarks: "allow" });
|
|
175
175
|
return s;
|
|
176
176
|
}
|
|
177
177
|
|
|
@@ -163,7 +163,7 @@ function _title(s) {
|
|
|
163
163
|
if (typeof s !== "string" || !s.length || s.length > MAX_TITLE_LEN) {
|
|
164
164
|
throw new TypeError("storefrontDashboards: title must be a non-empty string <= " + MAX_TITLE_LEN + " chars");
|
|
165
165
|
}
|
|
166
|
-
textGuard.freeText(s, "storefrontDashboards: title", { singleLine: "reject", zeroWidth: "reject" });
|
|
166
|
+
textGuard.freeText(s, "storefrontDashboards: title", { singleLine: "reject", zeroWidth: "reject", bidiMarks: "allow" });
|
|
167
167
|
return s;
|
|
168
168
|
}
|
|
169
169
|
|
package/lib/storefront-forms.js
CHANGED
|
@@ -180,7 +180,7 @@ function _description(s) {
|
|
|
180
180
|
if (typeof s !== "string" || s.length > MAX_DESCRIPTION_LEN) {
|
|
181
181
|
throw new TypeError("storefrontForms: description must be a string ≤ " + MAX_DESCRIPTION_LEN + " chars");
|
|
182
182
|
}
|
|
183
|
-
textGuard.freeText(s, "storefrontForms: description", { zeroWidth: "reject" });
|
|
183
|
+
textGuard.freeText(s, "storefrontForms: description", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
184
184
|
return s;
|
|
185
185
|
}
|
|
186
186
|
|
package/lib/storefront-pages.js
CHANGED
|
@@ -131,7 +131,7 @@ function _title(s) {
|
|
|
131
131
|
if (typeof s !== "string" || !s.length || s.length > MAX_TITLE_LEN) {
|
|
132
132
|
throw new TypeError("storefrontPages: title must be a non-empty string ≤ " + MAX_TITLE_LEN + " chars");
|
|
133
133
|
}
|
|
134
|
-
textGuard.freeText(s, "storefrontPages: title", { singleLine: "reject", zeroWidth: "reject" });
|
|
134
|
+
textGuard.freeText(s, "storefrontPages: title", { singleLine: "reject", zeroWidth: "reject", bidiMarks: "allow" });
|
|
135
135
|
return s;
|
|
136
136
|
}
|
|
137
137
|
|
|
@@ -139,7 +139,7 @@ function _body(s) {
|
|
|
139
139
|
if (typeof s !== "string" || !s.length || s.length > MAX_BODY_LEN) {
|
|
140
140
|
throw new TypeError("storefrontPages: body must be a non-empty string ≤ " + MAX_BODY_LEN + " chars");
|
|
141
141
|
}
|
|
142
|
-
textGuard.freeText(s, "storefrontPages: body", { zeroWidth: "reject" });
|
|
142
|
+
textGuard.freeText(s, "storefrontPages: body", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
143
143
|
return s;
|
|
144
144
|
}
|
|
145
145
|
|
|
@@ -143,7 +143,7 @@ function _reason(s) {
|
|
|
143
143
|
if (s.length > MAX_REASON_LEN) {
|
|
144
144
|
throw new TypeError("subscriptionBilling: reason must be <= " + MAX_REASON_LEN + " characters");
|
|
145
145
|
}
|
|
146
|
-
textGuard.freeText(s, "subscriptionBilling: reason", { zeroWidth: "reject" });
|
|
146
|
+
textGuard.freeText(s, "subscriptionBilling: reason", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
147
147
|
return s;
|
|
148
148
|
}
|
|
149
149
|
|
|
@@ -139,7 +139,7 @@ function _reason(s) {
|
|
|
139
139
|
if (s.length > MAX_REASON_LEN) {
|
|
140
140
|
throw new TypeError("subscriptionControls: reason must be <= " + MAX_REASON_LEN + " characters");
|
|
141
141
|
}
|
|
142
|
-
textGuard.freeText(s, "subscriptionControls: reason", { zeroWidth: "reject" });
|
|
142
|
+
textGuard.freeText(s, "subscriptionControls: reason", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
143
143
|
return s;
|
|
144
144
|
}
|
|
145
145
|
|
package/lib/suggestion-box.js
CHANGED
|
@@ -201,7 +201,7 @@ function _title(s) {
|
|
|
201
201
|
if (s.length > MAX_TITLE_LEN) {
|
|
202
202
|
throw new TypeError("suggestionBox: title must be <= " + MAX_TITLE_LEN + " characters");
|
|
203
203
|
}
|
|
204
|
-
textGuard.freeText(s, "suggestionBox: title", { singleLine: "reject", zeroWidth: "reject" });
|
|
204
|
+
textGuard.freeText(s, "suggestionBox: title", { singleLine: "reject", zeroWidth: "reject", bidiMarks: "allow" });
|
|
205
205
|
return s;
|
|
206
206
|
}
|
|
207
207
|
|
|
@@ -219,7 +219,7 @@ function _body(s) {
|
|
|
219
219
|
if (textGuard.hasCodepointThreat(s)) {
|
|
220
220
|
throw new TypeError("suggestionBox: body must not contain control bytes");
|
|
221
221
|
}
|
|
222
|
-
textGuard.freeText(s, "suggestionBox: body", { zeroWidth: "reject" });
|
|
222
|
+
textGuard.freeText(s, "suggestionBox: body", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
223
223
|
return s;
|
|
224
224
|
}
|
|
225
225
|
|
|
@@ -310,7 +310,7 @@ function _response(s) {
|
|
|
310
310
|
if (textGuard.hasCodepointThreat(s)) {
|
|
311
311
|
throw new TypeError("suggestionBox: response must not contain control bytes");
|
|
312
312
|
}
|
|
313
|
-
textGuard.freeText(s, "suggestionBox: response", { zeroWidth: "reject" });
|
|
313
|
+
textGuard.freeText(s, "suggestionBox: response", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
314
314
|
// A status-only transition is allowed with response === "" (no
|
|
315
315
|
// operator-visible reply, just a state change). Trim-then-check
|
|
316
316
|
// for the operator-supplied case below in respondToSuggestion.
|
|
@@ -324,7 +324,7 @@ function _responder(s) {
|
|
|
324
324
|
if (s.length > MAX_RESPONDER_LEN) {
|
|
325
325
|
throw new TypeError("suggestionBox: responder must be <= " + MAX_RESPONDER_LEN + " characters");
|
|
326
326
|
}
|
|
327
|
-
textGuard.freeText(s, "suggestionBox: responder", { singleLine: "reject", zeroWidth: "reject" });
|
|
327
|
+
textGuard.freeText(s, "suggestionBox: responder", { singleLine: "reject", zeroWidth: "reject", bidiMarks: "allow" });
|
|
328
328
|
return s;
|
|
329
329
|
}
|
|
330
330
|
|
package/lib/support-tickets.js
CHANGED
|
@@ -155,7 +155,7 @@ function _subject(s) {
|
|
|
155
155
|
if (s.length > MAX_SUBJECT_LEN) {
|
|
156
156
|
throw new TypeError("supportTickets: subject must be <= " + MAX_SUBJECT_LEN + " characters");
|
|
157
157
|
}
|
|
158
|
-
textGuard.freeText(s, "supportTickets: subject", { singleLine: "reject", zeroWidth: "reject" });
|
|
158
|
+
textGuard.freeText(s, "supportTickets: subject", { singleLine: "reject", zeroWidth: "reject", bidiMarks: "allow" });
|
|
159
159
|
return s;
|
|
160
160
|
}
|
|
161
161
|
|
|
@@ -170,7 +170,7 @@ function _body(s) {
|
|
|
170
170
|
if (s.length > MAX_BODY_LEN) {
|
|
171
171
|
throw new TypeError("supportTickets: body must be <= " + MAX_BODY_LEN + " characters");
|
|
172
172
|
}
|
|
173
|
-
textGuard.freeText(s, "supportTickets: body", { zeroWidth: "reject" });
|
|
173
|
+
textGuard.freeText(s, "supportTickets: body", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
174
174
|
return s;
|
|
175
175
|
}
|
|
176
176
|
|
|
@@ -219,7 +219,7 @@ function _reason(r) {
|
|
|
219
219
|
if (r.length > MAX_REASON_LEN) {
|
|
220
220
|
throw new TypeError("supportTickets: reason must be <= " + MAX_REASON_LEN + " characters");
|
|
221
221
|
}
|
|
222
|
-
textGuard.freeText(r, "supportTickets: reason", { zeroWidth: "reject" });
|
|
222
|
+
textGuard.freeText(r, "supportTickets: reason", { zeroWidth: "reject", bidiMarks: "allow" });
|
|
223
223
|
return r;
|
|
224
224
|
}
|
|
225
225
|
|
package/lib/tenants.js
CHANGED
|
@@ -128,7 +128,7 @@ function _name(s) {
|
|
|
128
128
|
if (s.length > MAX_NAME_LEN) {
|
|
129
129
|
throw new TypeError("tenants: name must be <= " + MAX_NAME_LEN + " characters");
|
|
130
130
|
}
|
|
131
|
-
textGuard.freeText(s, "tenants: name", { singleLine: "reject", zeroWidth: "reject" });
|
|
131
|
+
textGuard.freeText(s, "tenants: name", { singleLine: "reject", zeroWidth: "reject", bidiMarks: "allow" });
|
|
132
132
|
return s;
|
|
133
133
|
}
|
|
134
134
|
|
package/lib/text-guard.js
CHANGED
|
@@ -81,6 +81,32 @@ var INVISIBLE_OP_RE = new RegExp("[" + codepointClass.charClass([[0x2061, 0x2064
|
|
|
81
81
|
// allow:dynamic-regex — codepoints from a literal range table
|
|
82
82
|
var INVISIBLE_OP_RE_G = new RegExp("[" + codepointClass.charClass([[0x2061, 0x2064]]) + "]", "g");
|
|
83
83
|
|
|
84
|
+
// The framework's BIDI_RE is the union of two groups that do NOT carry the
|
|
85
|
+
// same risk, and refusing both is what broke right-to-left addresses:
|
|
86
|
+
//
|
|
87
|
+
// OVERRIDES + ISOLATES — U+202A-202E and U+2066-2069. These reorder a RUN
|
|
88
|
+
// of surrounding text, which is the Trojan Source primitive: a value that
|
|
89
|
+
// displays as something other than what it says. Nothing legitimate in a
|
|
90
|
+
// shop's stored text needs them.
|
|
91
|
+
// MARKS — U+200E LEFT-TO-RIGHT MARK, U+200F RIGHT-TO-LEFT MARK, U+061C
|
|
92
|
+
// ARABIC LETTER MARK. These only resolve the direction of ADJACENT
|
|
93
|
+
// NEUTRAL characters — a house number inside an Arabic street name, a
|
|
94
|
+
// Latin brand inside a Hebrew sentence. They are how mixed-direction text
|
|
95
|
+
// is correctly authored, and an Arabic or Hebrew postal address routinely
|
|
96
|
+
// contains one. They cannot reverse a run.
|
|
97
|
+
//
|
|
98
|
+
// So the marks are ALLOWED by default and the overrides are refused. A field
|
|
99
|
+
// that genuinely wants neither (a machine-readable identifier, a slug) asks
|
|
100
|
+
// for `bidiMarks: "reject"`.
|
|
101
|
+
// allow:dynamic-regex — codepoints from a literal range table
|
|
102
|
+
var BIDI_OVERRIDE_RE = new RegExp(
|
|
103
|
+
"[" + codepointClass.charClass([[0x202A, 0x202E], [0x2066, 0x2069]]) + "]"
|
|
104
|
+
);
|
|
105
|
+
// allow:dynamic-regex — codepoints from a literal range table
|
|
106
|
+
var BIDI_MARK_RE = new RegExp(
|
|
107
|
+
"[" + codepointClass.charClass([0x200E, 0x200F, 0x061C]) + "]"
|
|
108
|
+
);
|
|
109
|
+
|
|
84
110
|
// Everything that ends a line or pads it out, for a value that must stay on
|
|
85
111
|
// one. Tab / LF / CR sit outside the framework's C0 table on purpose — a
|
|
86
112
|
// multi-line body needs them — so a single-line field asks for them here.
|
|
@@ -205,7 +231,20 @@ function hostLabel(host, label) {
|
|
|
205
231
|
// building a message just joins the two.
|
|
206
232
|
//
|
|
207
233
|
// Policies, each "reject" to enable and any other value to allow:
|
|
208
|
-
// bidi — default "reject". Bidi
|
|
234
|
+
// bidi — default "reject". Bidi OVERRIDES and ISOLATES only
|
|
235
|
+
// (U+202A-202E, U+2066-2069) — the codepoints that reorder a
|
|
236
|
+
// run of text (CVE-2021-42574).
|
|
237
|
+
// bidiMarks — default "reject". U+200E / U+200F / U+061C, the direction
|
|
238
|
+
// MARKS. These are legitimate in NATURAL-LANGUAGE text — an
|
|
239
|
+
// Arabic postal address or a Hebrew gift message carries one
|
|
240
|
+
// wherever a Latin word or number sits inside the line — and
|
|
241
|
+
// illegitimate in a machine-readable value, where the only
|
|
242
|
+
// reason for an invisible character is to make the value read
|
|
243
|
+
// as something it is not. Neither case is the majority, so
|
|
244
|
+
// the default is chosen by how each mistake fails: refusing a
|
|
245
|
+
// mark that belonged is reported by the customer it turned
|
|
246
|
+
// away, while accepting one that did not is silent. A prose
|
|
247
|
+
// field therefore opts OUT with `bidiMarks: "allow"`.
|
|
209
248
|
// nullByte — default "reject". U+0000.
|
|
210
249
|
// control — default "reject". C0 controls + U+007F DELETE. Tab, LF and
|
|
211
250
|
// CR are ALLOWED here: a multi-line body legitimately has
|
|
@@ -221,9 +260,12 @@ function hostLabel(host, label) {
|
|
|
221
260
|
// systems, narrowed by policy.allowedScripts.
|
|
222
261
|
function firstCodepointThreat(s, policy) {
|
|
223
262
|
policy = policy || {};
|
|
224
|
-
if ((policy.bidi || "reject") === "reject" &&
|
|
263
|
+
if ((policy.bidi || "reject") === "reject" && BIDI_OVERRIDE_RE.test(s)) {
|
|
225
264
|
return "contains a Unicode bidi override (CVE-2021-42574 Trojan Source)";
|
|
226
265
|
}
|
|
266
|
+
if ((policy.bidiMarks || "reject") === "reject" && BIDI_MARK_RE.test(s)) {
|
|
267
|
+
return "contains a Unicode bidi direction mark";
|
|
268
|
+
}
|
|
227
269
|
if ((policy.nullByte || "reject") === "reject" &&
|
|
228
270
|
s.indexOf(codepointClass.NULL_BYTE) !== -1) {
|
|
229
271
|
return "contains a null byte";
|
package/lib/theme-assets.js
CHANGED
|
@@ -257,7 +257,7 @@ function _altText(s) {
|
|
|
257
257
|
MAX_ALT_TEXT_LEN + " chars (or null)"
|
|
258
258
|
);
|
|
259
259
|
}
|
|
260
|
-
textGuard.freeText(s, "themeAssets: alt_text", { singleLine: "reject", zeroWidth: "reject" });
|
|
260
|
+
textGuard.freeText(s, "themeAssets: alt_text", { singleLine: "reject", zeroWidth: "reject", bidiMarks: "allow" });
|
|
261
261
|
return s;
|
|
262
262
|
}
|
|
263
263
|
|
package/lib/vendor/MANIFEST.json
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"_about": "blamejs.shop vendors a single framework — blamejs — which itself bundles every server-side crypto/identity dependency. The transitive packages blamejs ships are surfaced in its own MANIFEST.json at lib/vendor/blamejs/lib/vendor/MANIFEST.json — Trivy / Grype rely on that nested data for CVE attribution.",
|
|
4
4
|
"packages": {
|
|
5
5
|
"blamejs": {
|
|
6
|
-
"version": "0.18.
|
|
7
|
-
"tag": "v0.18.
|
|
6
|
+
"version": "0.18.24",
|
|
7
|
+
"tag": "v0.18.24",
|
|
8
8
|
"license": "Apache-2.0",
|
|
9
9
|
"author": "blamejs contributors",
|
|
10
10
|
"source": "https://github.com/blamejs/blamejs",
|
|
@@ -599,15 +599,15 @@
|
|
|
599
599
|
"package.json": "lib/vendor/blamejs/package.json",
|
|
600
600
|
"sbom.cdx.json": "lib/vendor/blamejs/sbom.cdx.json"
|
|
601
601
|
},
|
|
602
|
-
"bundler": "signed release tarball blamejs-core-0.18.
|
|
603
|
-
"bundledAt": "2026-08-
|
|
602
|
+
"bundler": "signed release tarball blamejs-core-0.18.24.tgz from github.com/blamejs/blamejs — SHA3-512 digest and ML-DSA-65 signature verified against keys/vendor-blamejs-pqc-pub.json before unpacking",
|
|
603
|
+
"bundledAt": "2026-08-11",
|
|
604
604
|
"hashes": {
|
|
605
|
-
"CHANGELOG.md": "sha256:
|
|
605
|
+
"CHANGELOG.md": "sha256:2ac9860b3cc5e84c9103557a9610d3e60af5f9a3f648d22aa127c55f9c72cf0e",
|
|
606
606
|
"LICENSE": "sha256:812075be5abe785284e823a97d09b5d1515b0221e3128059e1f5065de3c907d5",
|
|
607
607
|
"LTS-CALENDAR.md": "sha256:fbdf074ca0d9544bf10fff87c8947ba38aa5ac0500267796dc8f0c92822aacbe",
|
|
608
608
|
"MIGRATING.md": "sha256:7bee6f55c28f017d4083132dbe45e0e63bcdb7ad3086b95b02551eaa4cc052bc",
|
|
609
|
-
"NOTICE": "sha256:
|
|
610
|
-
"README.md": "sha256:
|
|
609
|
+
"NOTICE": "sha256:979a65f58486faf2defacd821fa97476149a3a4efe1ddea8f6b53b3283175fe5",
|
|
610
|
+
"README.md": "sha256:4ea822a1e856e860ea6d24b01a6dbb34252d519f78707eccdcb0a6de3d3775e8",
|
|
611
611
|
"bin/blamejs.js": "sha256:59798e63ad43c0afdf03ab88aaae105fa1f525c2703d80903eee48717db567c4",
|
|
612
612
|
"index.js": "sha256:2d2c81c19e4177450b701dba05f582a8b6ef9581d202f01ec04d912556266a2f",
|
|
613
613
|
"lib/_test/crypto-fixtures.js": "sha256:16055e38d3c1a3065735e50fe43e81de1ed5d90cf72d7fb90ac263d07deb7ced",
|
|
@@ -1019,7 +1019,7 @@
|
|
|
1019
1019
|
"lib/network-nts.js": "sha256:947e1887f339ef1bb20891d5c9531e2969653b162886b576c9b8a723d6b62002",
|
|
1020
1020
|
"lib/network-proxy.js": "sha256:392e79ddc58ae7125cd7a8abec872df50ffee76170ea40ff6847d581b2a405a3",
|
|
1021
1021
|
"lib/network-smtp-policy.js": "sha256:b8b88766be9dd1a0e4dfe60b21f97fe8b166d76328ecbbbb4e1349bfb2335e95",
|
|
1022
|
-
"lib/network-tls.js": "sha256:
|
|
1022
|
+
"lib/network-tls.js": "sha256:0a2b52cf7d9e35d988ba0a6d3d0afd22536c7f68ff047f24981e0732964a4fa3",
|
|
1023
1023
|
"lib/network-tsig.js": "sha256:233b008815bbbd60e6914e4a74b41de0d9136c27331bf00827ca4a983ddd29e2",
|
|
1024
1024
|
"lib/network.js": "sha256:a4a4bd54396c0e162f1d5469d4d3e264a9f4537179446843589674e551ac1f29",
|
|
1025
1025
|
"lib/nis2-report.js": "sha256:d54937f1fe996c5316756cfcf9095c67c8f955621c199079abb87862a82afd75",
|
|
@@ -1158,10 +1158,10 @@
|
|
|
1158
1158
|
"lib/vc.js": "sha256:2f0e2a32bb52f53e4c38df64a2a658665cf5e442b56882d3b3bbdf31c7124132",
|
|
1159
1159
|
"lib/vendor-data.js": "sha256:365b0dcca1198e4fad647b3873b82702fcf90a5ee2d8c7f25c78864cadb7d717",
|
|
1160
1160
|
"lib/vendor/.vendor-data-pubkey": "sha256:73a935b8c72f55d821c22ddb8188453bab324f80d229d033a0a1549819a1f096",
|
|
1161
|
-
"lib/vendor/MANIFEST.json": "sha256:
|
|
1161
|
+
"lib/vendor/MANIFEST.json": "sha256:75576b6fbcb07383d382c94fbf3fb317703d5cb4bf838b55801b93d7ead3de08",
|
|
1162
1162
|
"lib/vendor/bimi-trust-anchors.data.js": "sha256:aa7a4d33b65a68422a2a2c1670177689f66fdcaa08bd2514d78798b827bd1608",
|
|
1163
1163
|
"lib/vendor/bimi-trust-anchors.pem": "sha256:81ff9f5ab3c9774132c845684e783be95cf73146f8b670d964105f0a3765b4b4",
|
|
1164
|
-
"lib/vendor/blamejs-pki.cjs": "sha256:
|
|
1164
|
+
"lib/vendor/blamejs-pki.cjs": "sha256:96a873b733c95b53b8e2ced065a82192b6acabcede312cf68a45a128857cc3bc",
|
|
1165
1165
|
"lib/vendor/browser/noble-ciphers.mjs": "sha256:0ffd91540bcb586a29b56e52ee1c29df69097b50776beb4036a07558f7a4e12e",
|
|
1166
1166
|
"lib/vendor/browser/noble-hashes.mjs": "sha256:dfe4b7ae3c9880e388c8da4b68f44742b229b53afacd1e674179527e33da62b0",
|
|
1167
1167
|
"lib/vendor/browser/noble-post-quantum.mjs": "sha256:cae1d5bbdc7184b202b6ca68df6e1db7b0d0f668c77809ded189ca7f271accc9",
|
|
@@ -1188,8 +1188,8 @@
|
|
|
1188
1188
|
"lib/ws-client.js": "sha256:348d01cd552fed583f05944d1853f71b0119105cb067c2e607b19ec9e6f47aee",
|
|
1189
1189
|
"lib/x509-chain.js": "sha256:c2b5544202601a50230c7c652ff028e73e9d29a34d58db349beb5b5164b7b4d5",
|
|
1190
1190
|
"lib/xml-c14n.js": "sha256:6239db09b021f032a78aa101fe295238db4ad91acc93ae13eef7d14efd797b94",
|
|
1191
|
-
"package.json": "sha256:
|
|
1192
|
-
"sbom.cdx.json": "sha256:
|
|
1191
|
+
"package.json": "sha256:ab52ca260fa6408d4910a3d9a726d442e61127e883e920c965e7ef31c9319a0d",
|
|
1192
|
+
"sbom.cdx.json": "sha256:b47182cff49c56cc0534ba835f62bd8ddebcb659ae3d693bbfc1f4b059a427c7"
|
|
1193
1193
|
}
|
|
1194
1194
|
}
|
|
1195
1195
|
}
|