Skip to content

Commit

Permalink
Improve default privacy mode (highlight#7200)
Browse files Browse the repository at this point in the history
## Summary
Default privacy mode is missing a few fields and inputs. More
aggressively obfuscate these fields for default privacy mode:
- obfuscate all inputs
- allow inputs to be recorded with `data-hl-record` attribute

## How did you test this change?
1) Set the privacy mode of the Highlight app to be "default"
2) Click around the app, touch inputs and fields
3) Close out session
4) View session


https://www.loom.com/share/2473e236e70b424c9779ff76a242edec?sid=0707d37e-8799-4740-946a-191dcb8dc0cf

## Are there any deployment considerations?
N/A

## Does this work require review from our design team?
N/A
  • Loading branch information
SpennyNDaJets authored Nov 28, 2023
1 parent f0836d9 commit 84110ac
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 71 deletions.
5 changes: 5 additions & 0 deletions .changeset/empty-cherries-pay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'highlight.run': minor
---

Update default privacy mode to obfuscate all inputs by default. Allow user to override ofuscation with data-hl-record attribute. Fix regex expressions for telephone numbers and addresses.
37 changes: 15 additions & 22 deletions frontend/src/__generated/rr/rr.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,20 +222,18 @@ function shouldObfuscateTextByDefault(text) {
});
}
var maskedInputType = function(_a2) {
var maskInputOptions = _a2.maskInputOptions, tagName = _a2.tagName, type = _a2.type, inputId = _a2.inputId, inputName = _a2.inputName, autocomplete = _a2.autocomplete;
var maskInputOptions = _a2.maskInputOptions, tagName = _a2.tagName, type = _a2.type, overwriteRecord = _a2.overwriteRecord;
var actualType = type && type.toLowerCase();
return maskInputOptions[tagName.toLowerCase()] || actualType && maskInputOptions[actualType] || inputId && maskInputOptions[inputId] || inputName && maskInputOptions[inputName] || !!autocomplete && typeof autocomplete === "string" && !!maskInputOptions[autocomplete];
return overwriteRecord !== "true" && (!!maskInputOptions[tagName.toLowerCase()] || !!(actualType && maskInputOptions[actualType]));
};
function maskInputValue(_a2) {
var maskInputOptions = _a2.maskInputOptions, tagName = _a2.tagName, type = _a2.type, inputId = _a2.inputId, inputName = _a2.inputName, autocomplete = _a2.autocomplete, value = _a2.value, maskInputFn = _a2.maskInputFn;
var maskInputOptions = _a2.maskInputOptions, tagName = _a2.tagName, type = _a2.type, value = _a2.value, overwriteRecord = _a2.overwriteRecord, maskInputFn = _a2.maskInputFn;
var text = value || "";
if (maskedInputType({
maskInputOptions,
tagName,
type,
inputId,
inputName,
autocomplete
overwriteRecord
})) {
if (maskInputFn) {
text = maskInputFn(text);
Expand Down Expand Up @@ -599,7 +597,7 @@ function getRootId(doc, mirror2) {
return docId === 1 ? void 0 : docId;
}
function serializeTextNode(n2, options) {
var _a2;
var _a2, _b2;
var maskTextClass = options.maskTextClass, maskTextSelector = options.maskTextSelector, maskTextFn = options.maskTextFn, privacySetting = options.privacySetting, rootId = options.rootId;
var parentTagName = n2.parentNode && n2.parentNode.tagName;
var textContent = n2.textContent;
Expand Down Expand Up @@ -629,8 +627,9 @@ function serializeTextNode(n2, options) {
textContent = maskTextFn ? maskTextFn(textContent) : textContent.replace(/[\S]/g, "*");
}
var enableStrictPrivacy = privacySetting === "strict";
var highlightOverwriteRecord = (_b2 = n2.parentElement) === null || _b2 === void 0 ? void 0 : _b2.getAttribute("data-hl-record");
var obfuscateDefaultPrivacy = privacySetting === "default" && shouldObfuscateTextByDefault(textContent);
if ((enableStrictPrivacy || obfuscateDefaultPrivacy) && !textContentHandled && parentTagName) {
if ((enableStrictPrivacy || obfuscateDefaultPrivacy) && !highlightOverwriteRecord && !textContentHandled && parentTagName) {
var IGNORE_TAG_NAMES = /* @__PURE__ */ new Set([
"HEAD",
"TITLE",
Expand Down Expand Up @@ -694,9 +693,7 @@ function serializeElementNode(n2, options) {
type,
tagName,
value,
inputId: n2.id,
inputName: n2.name,
autocomplete: n2.autocomplete,
overwriteRecord: n2.getAttribute("data-hl-record"),
maskInputOptions,
maskInputFn
});
Expand Down Expand Up @@ -2572,10 +2569,12 @@ var MutationBuffer = class {
}
const payload = {
texts: this.texts.map((text) => {
var _a2, _b2;
let value = text.value;
const enableStrictPrivacy = this.privacySetting === "strict";
const obfuscateDefaultPrivacy = this.privacySetting === "default" && shouldObfuscateTextByDefault(value);
if ((enableStrictPrivacy || obfuscateDefaultPrivacy) && value) {
const highlightOverwriteRecord = (_b2 = (_a2 = text.node) === null || _a2 === void 0 ? void 0 : _a2.parentElement) === null || _b2 === void 0 ? void 0 : _b2.getAttribute("data-hl-record");
if ((enableStrictPrivacy || obfuscateDefaultPrivacy) && highlightOverwriteRecord && value) {
value = obfuscateText(value);
}
return {
Expand Down Expand Up @@ -2628,9 +2627,7 @@ var MutationBuffer = class {
tagName: target.tagName,
type,
value,
inputId: target.id,
inputName: target.getAttribute("name"),
autocomplete: target.getAttribute("autocomplete"),
overwriteRecord: target.getAttribute("data-hl-record"),
maskInputFn: this.maskInputFn
});
}
Expand Down Expand Up @@ -3053,25 +3050,21 @@ function initInputObserver({ inputCb, doc, mirror: mirror2, blockClass, blockSel
let text = target.value;
let isChecked = false;
const type = getInputType(target) || "";
const { id: inputId, name: inputName, autocomplete } = target;
const overwriteRecord = target.getAttribute("data-hl-record");
if (type === "radio" || type === "checkbox") {
isChecked = target.checked;
} else if (maskedInputType({
maskInputOptions,
type,
tagName,
inputId,
inputName,
autocomplete
overwriteRecord
})) {
text = maskInputValue({
maskInputOptions,
tagName,
type,
value: text,
inputId,
inputName,
autocomplete,
overwriteRecord,
maskInputFn
});
}
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/Search/SearchForm/SearchForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,7 @@ export const Search: React.FC<{
style={{
paddingLeft: hideIcon ? undefined : 40,
}}
data-hl-record
/>

{isDirty && !disableSearch && (
Expand Down
49 changes: 1 addition & 48 deletions sdk/client/src/utils/privacy.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,6 @@
import { MaskInputOptions } from '@highlight-run/rrweb-snapshot'
import { PrivacySettingOption } from '../types/types'

const DEFAULT_MASK_INPUT_OPTIONS: MaskInputOptions = {
password: true,
email: true,
tel: true,
name: true,
'given-name': true,
'family-name': true,
'additional-name': true,
'one-time-code': true,
'street-address': true,
address: true,
'address-line1': true,
'address-line2': true,
'address-line3': true,
'address-level4': true,
'address-level3': true,
'address-level2': true,
'address-level1': true,
city: true,
state: true,
country: true,
zip: true,
'country-name': true,
'postal-code': true,
'cc-name': true,
'cc-given-name': true,
'cc-additional-name': true,
'cc-family-name': true,
'cc-number': true,
'cc-exp': true,
'cc-exp-month': true,
'cc-exp-year': true,
'cc-csc': true,
'cc-type': true,
bday: true,
'bday-day': true,
'bday-month': true,
'bday-year': true,
sex: true,
'tel-country-code': true,
'tel-national': true,
'tel-area-code': true,
'tel-local': true,
'tel-extension': true,
ssn: true,
}

// returns (1) whether all inputs should be masked and (2) which inputs should be masked
export const determineMaskInputOptions = (
privacyPolicy: PrivacySettingOption,
Expand All @@ -56,7 +9,7 @@ export const determineMaskInputOptions = (
case 'strict':
return [true, undefined]
case 'default':
return [false, DEFAULT_MASK_INPUT_OPTIONS]
return [true, undefined]
case 'none': {
return [false, { password: true }]
}
Expand Down

0 comments on commit 84110ac

Please sign in to comment.