@anyreplay/browser 0.2.0 → 0.2.1
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 +4 -1
- package/dist/index.cjs +41 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +41 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,7 +77,10 @@ Some fields are masked in every mode and no option records them: passwords and
|
|
|
77
77
|
one-time codes; card numbers, security codes, expiry dates and cardholder names
|
|
78
78
|
(from `autocomplete="cc-…"` or from a name, label or placeholder that reads like
|
|
79
79
|
one); IBANs, routing numbers and sort codes; any value of 13–19 digits that
|
|
80
|
-
passes the card-number check
|
|
80
|
+
passes the card-number check — and, because a number is typed one key at a
|
|
81
|
+
time, any value that could still become one: digits only, starting 2–6,
|
|
82
|
+
grouped like a card, more than six digits long. At most the first six digits
|
|
83
|
+
of a card number are ever recorded. Masking always happens in the page, before
|
|
81
84
|
anything is sent.
|
|
82
85
|
|
|
83
86
|
`type="email"` and `type="tel"` are not on that list. An address and a phone
|
package/dist/index.cjs
CHANGED
|
@@ -3864,10 +3864,12 @@ var AssetCollector = class {
|
|
|
3864
3864
|
body: JSON.stringify(body)
|
|
3865
3865
|
});
|
|
3866
3866
|
const known = await post("/v1/ingest/assets/known", { projectKey, hashes: [sha256], ...app });
|
|
3867
|
-
if (known.ok) {
|
|
3868
|
-
|
|
3869
|
-
|
|
3867
|
+
if (!known.ok) {
|
|
3868
|
+
if (known.status === 401 || known.status === 403) this.stop();
|
|
3869
|
+
return false;
|
|
3870
3870
|
}
|
|
3871
|
+
const answer = await known.json();
|
|
3872
|
+
if (Array.isArray(answer.known) && answer.known.includes(sha256)) return true;
|
|
3871
3873
|
const upload = await post("/v1/ingest/assets", { projectKey, sha256, data: toBase64(bytes), ...app });
|
|
3872
3874
|
return upload.ok;
|
|
3873
3875
|
}
|
|
@@ -4172,6 +4174,13 @@ function looksLikeCardNumber(text) {
|
|
|
4172
4174
|
}
|
|
4173
4175
|
return sum % 10 === 0;
|
|
4174
4176
|
}
|
|
4177
|
+
function mayBecomeCardNumber(text) {
|
|
4178
|
+
if (!/^[2-6][0-9 -]*$/.test(text)) return false;
|
|
4179
|
+
const groups = text.split(/[ -]+/);
|
|
4180
|
+
if (groups.slice(0, -1).some((group) => group.length < 4)) return false;
|
|
4181
|
+
const digits = groups.join("").length;
|
|
4182
|
+
return digits > 6 && digits <= 19;
|
|
4183
|
+
}
|
|
4175
4184
|
function isMarkedByCustomer(node, maskClass) {
|
|
4176
4185
|
var _a;
|
|
4177
4186
|
let element = asElement(node);
|
|
@@ -4186,8 +4195,19 @@ function shouldMaskValue(text, node, policy) {
|
|
|
4186
4195
|
if (policy.maskEveryField) return true;
|
|
4187
4196
|
if (isSensitiveField(node)) return true;
|
|
4188
4197
|
if (isMarkedByCustomer(node, policy.maskClass)) return true;
|
|
4189
|
-
return
|
|
4198
|
+
return cardShaped(text);
|
|
4199
|
+
}
|
|
4200
|
+
var cardShaped = (text) => looksLikeCardNumber(text) || mayBecomeCardNumber(text);
|
|
4201
|
+
var EDITABLE = '[contenteditable]:not([contenteditable="false"])';
|
|
4202
|
+
function insideEditable(node) {
|
|
4203
|
+
var _a;
|
|
4204
|
+
const live = node;
|
|
4205
|
+
const element = (live == null ? void 0 : live.nodeType) === 3 ? (_a = live.parentElement) != null ? _a : null : asElement(live);
|
|
4206
|
+
return typeof (element == null ? void 0 : element.closest) === "function" && element.closest(EDITABLE) !== null;
|
|
4190
4207
|
}
|
|
4208
|
+
var isEditableSerialised = (attributes) => attributes.contenteditable !== void 0 && attributes.contenteditable !== "false";
|
|
4209
|
+
var typedCardShaped = (text) => cardShaped(text.replace(/\u00a0/g, " ").trim());
|
|
4210
|
+
var maskText = (text) => text.replace(/\S/g, "*");
|
|
4191
4211
|
var MUTATION = 0;
|
|
4192
4212
|
var INPUT = 5;
|
|
4193
4213
|
var ELEMENT_NODE = 2;
|
|
@@ -4202,23 +4222,27 @@ function maskTextChildren(node) {
|
|
|
4202
4222
|
maskTextChildren(child);
|
|
4203
4223
|
}
|
|
4204
4224
|
}
|
|
4205
|
-
function scrubTree(node, policy, masked) {
|
|
4225
|
+
function scrubTree(node, policy, masked, editable = false) {
|
|
4206
4226
|
var _a, _b;
|
|
4207
4227
|
if (!node) return;
|
|
4208
4228
|
const attributes = (_a = node.attributes) != null ? _a : {};
|
|
4209
4229
|
const inheritedMask = masked || hasClass(attributes, policy.maskClass);
|
|
4230
|
+
const inheritedEditable = editable || node.type === ELEMENT_NODE && isEditableSerialised(attributes);
|
|
4231
|
+
if (editable && node.type === TEXT_NODE && typeof node.textContent === "string" && typedCardShaped(node.textContent)) {
|
|
4232
|
+
node.textContent = maskText(node.textContent);
|
|
4233
|
+
}
|
|
4210
4234
|
if (node.type === ELEMENT_NODE && node.tagName && FIELD_TAGS.has(node.tagName.toLowerCase())) {
|
|
4211
4235
|
const value = attributes.value;
|
|
4212
|
-
const shouldMask = policy.maskEveryField || inheritedMask || isSensitiveSerialised(attributes) || typeof value === "string" &&
|
|
4236
|
+
const shouldMask = policy.maskEveryField || inheritedMask || isSensitiveSerialised(attributes) || typeof value === "string" && cardShaped(value);
|
|
4213
4237
|
if (shouldMask) {
|
|
4214
4238
|
if (typeof value === "string" && value !== "") attributes.value = maskValue(value);
|
|
4215
4239
|
if (node.tagName.toLowerCase() === "textarea") maskTextChildren(node);
|
|
4216
4240
|
}
|
|
4217
4241
|
}
|
|
4218
|
-
for (const child of (_b = node.childNodes) != null ? _b : []) scrubTree(child, policy, inheritedMask);
|
|
4242
|
+
for (const child of (_b = node.childNodes) != null ? _b : []) scrubTree(child, policy, inheritedMask, inheritedEditable);
|
|
4219
4243
|
}
|
|
4220
4244
|
function scrubEvent(event, getNode, policy) {
|
|
4221
|
-
var _a, _b, _c, _d, _e;
|
|
4245
|
+
var _a, _b, _c, _d, _e, _f;
|
|
4222
4246
|
if (!event.data) return;
|
|
4223
4247
|
if (event.type === 2) {
|
|
4224
4248
|
scrubTree(event.data.node, policy, false);
|
|
@@ -4243,7 +4267,11 @@ function scrubEvent(event, getNode, policy) {
|
|
|
4243
4267
|
}
|
|
4244
4268
|
for (const add of (_e = data.adds) != null ? _e : []) {
|
|
4245
4269
|
const parent = typeof (add == null ? void 0 : add.parentId) === "number" ? getNode(add.parentId) : null;
|
|
4246
|
-
scrubTree(add == null ? void 0 : add.node, policy, isMarkedByCustomer(parent, policy.maskClass));
|
|
4270
|
+
scrubTree(add == null ? void 0 : add.node, policy, isMarkedByCustomer(parent, policy.maskClass), insideEditable(parent));
|
|
4271
|
+
}
|
|
4272
|
+
for (const change of (_f = data.texts) != null ? _f : []) {
|
|
4273
|
+
if (typeof (change == null ? void 0 : change.value) !== "string" || !typedCardShaped(change.value)) continue;
|
|
4274
|
+
if (typeof change.id === "number" && insideEditable(getNode(change.id))) change.value = maskText(change.value);
|
|
4247
4275
|
}
|
|
4248
4276
|
}
|
|
4249
4277
|
|
|
@@ -5049,7 +5077,7 @@ var Transport = class {
|
|
|
5049
5077
|
|
|
5050
5078
|
// src/version.ts
|
|
5051
5079
|
var SDK_NAME = "@anyreplay/browser";
|
|
5052
|
-
var SDK_VERSION = true ? "0.2.
|
|
5080
|
+
var SDK_VERSION = true ? "0.2.1" : "0.0.0-dev";
|
|
5053
5081
|
var PLATFORM = "web";
|
|
5054
5082
|
|
|
5055
5083
|
// src/visitor.ts
|
|
@@ -5156,6 +5184,8 @@ function forgetVisitor(local, session) {
|
|
|
5156
5184
|
}
|
|
5157
5185
|
|
|
5158
5186
|
// src/recorder.ts
|
|
5187
|
+
var RRWEB_DOM_CONTENT_LOADED = 0;
|
|
5188
|
+
var RRWEB_LOAD = 1;
|
|
5159
5189
|
var RAGE_CLICK_COUNT = 3;
|
|
5160
5190
|
var RAGE_CLICK_WINDOW_MS = 1e3;
|
|
5161
5191
|
var RAGE_CLICK_RADIUS_PX = 30;
|
|
@@ -5353,6 +5383,7 @@ function createRecorder(rawOptions, shell) {
|
|
|
5353
5383
|
stopRecording = record({
|
|
5354
5384
|
emit: (event) => {
|
|
5355
5385
|
const typed = event;
|
|
5386
|
+
if (typed.type === RRWEB_DOM_CONTENT_LOADED || typed.type === RRWEB_LOAD) return;
|
|
5356
5387
|
scrubEvent(typed, (id) => record.mirror.getNode(id), policy);
|
|
5357
5388
|
assets == null ? void 0 : assets.scan(typed);
|
|
5358
5389
|
noteInteraction(typed, channel);
|