Fix PPI → PII terminology across entire codebase

All references to "PPI" (Personal Private Information) have been
corrected to the industry-standard "PII" (Personally Identifiable
Information). This includes UI labels, comments, CSS class comments,
and variable/function names (PPI_PATTERNS → PII_PATTERNS,
autoDetectPPI → autoDetectPII, scanInputForPPI → scanInputForPII,
ppiWarnings → piiWarnings).

Files changed: README.md, content.css, content.js, auto-detect.js,
org-policy.js, storage.js, options.html, popup.html, popup.js

https://claude.ai/code/session_01NNBEPuXMFGWezJb1f958nL
This commit is contained in:
Claude
2026-03-29 19:32:02 +00:00
parent a0202625ac
commit bc1492032d
9 changed files with 44 additions and 44 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ A browser extension (Chrome, Firefox, and Safari) that intercepts personal infor
> **Browsers:** Chrome, Edge, Brave, Firefox, and Safari. Edge and Brave use the Chrome extension directly. > **Browsers:** Chrome, Edge, Brave, Firefox, and Safari. Edge and Brave use the Chrome extension directly.
> >
> **Desktop apps** (Claude, ChatGPT, Copilot) bypass the browser — use the web version with the extension for PPI protection. > **Desktop apps** (Claude, ChatGPT, Copilot) bypass the browser — use the web version with the extension for PII protection.
> >
> **Note:** Claude and ChatGPT are tested. Other services have interception patterns defined but may need adjustments. PRs welcome. > **Note:** Claude and ChatGPT are tested. Other services have interception patterns defined but may need adjustments. PRs welcome.
+2 -2
View File
@@ -35,7 +35,7 @@
border-radius: 2px; border-radius: 2px;
} }
/* Auto-detect PPI warning banner */ /* Auto-detect PII warning banner */
.ss-autodetect-warning { .ss-autodetect-warning {
position: fixed; position: fixed;
top: 16px; top: 16px;
@@ -136,7 +136,7 @@
font-style: italic; font-style: italic;
} }
/* Pre-send PPI warning (spellcheck-style, appears while typing) */ /* Pre-send PII warning (spellcheck-style, appears while typing) */
.ss-presend-warning { .ss-presend-warning {
position: fixed; position: fixed;
top: 16px; top: 16px;
+19 -19
View File
@@ -254,7 +254,7 @@
// ============================================================ // ============================================================
// Combined substitution: smart patterns + explicit + secret scan // Combined substitution: smart patterns + explicit + secret scan
// + auto-detect warning for unconfigured PPI // + auto-detect warning for unconfigured PII
// ============================================================ // ============================================================
function substituteAll(text) { function substituteAll(text) {
const allReplacements = []; const allReplacements = [];
@@ -275,12 +275,12 @@
finalText = secrets.text; finalText = secrets.text;
} }
// 4. Auto-detect: scan the FINAL text for unconfigured PPI // 4. Auto-detect: scan the FINAL text for unconfigured PII
// Auto-redact if enabled, otherwise just warn // Auto-redact if enabled, otherwise just warn
if (settings.autoDetect !== false) { if (settings.autoDetect !== false) {
const warnings = autoDetectPPI(finalText, identity); const warnings = autoDetectPII(finalText, identity);
if (warnings.length > 0) { if (warnings.length > 0) {
// Auto-redact detected PPI in the outbound text // Auto-redact detected PII in the outbound text
if (settings.autoRedactDetected !== false) { if (settings.autoRedactDetected !== false) {
for (let i = warnings.length - 1; i >= 0; i--) { for (let i = warnings.length - 1; i >= 0; i--) {
const w = warnings[i]; const w = warnings[i];
@@ -309,9 +309,9 @@
} }
// ============================================================ // ============================================================
// Auto-Detect PPI Scanner (inline for page world) // Auto-Detect PII Scanner (inline for page world)
// ============================================================ // ============================================================
const PPI_PATTERNS = [ const PII_PATTERNS = [
// Network // Network
{ name: 'Private IP', re: /\b(?:10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3})\b/g, { name: 'Private IP', re: /\b(?:10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3})\b/g,
hint: 'Private IP address', cat: 'network' }, hint: 'Private IP address', cat: 'network' },
@@ -389,7 +389,7 @@
// Common sentence starters that aren't names // Common sentence starters that aren't names
'please', 'thanks', 'hello', 'hi', 'hey', 'dear', 'sincerely', 'please', 'thanks', 'hello', 'hi', 'hey', 'dear', 'sincerely',
'regards', 'best', 'cheers', 'sorry', 'yes', 'no', 'ok', 'okay', 'regards', 'best', 'cheers', 'sorry', 'yes', 'no', 'ok', 'okay',
// Days and months (not PPI) // Days and months (not PII)
'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday',
'january', 'february', 'march', 'april', 'may', 'june', 'july', 'january', 'february', 'march', 'april', 'may', 'june', 'july',
'august', 'september', 'october', 'november', 'december', 'august', 'september', 'october', 'november', 'december',
@@ -454,7 +454,7 @@
}); });
} }
function autoDetectPPI(text, ident) { function autoDetectPII(text, ident) {
if (!text || text.length < 5) return []; if (!text || text.length < 5) return [];
const hasContext = CONTEXT_WORDS_RE.test(text); const hasContext = CONTEXT_WORDS_RE.test(text);
@@ -470,7 +470,7 @@
} }
const findings = []; const findings = [];
for (const pat of PPI_PATTERNS) { for (const pat of PII_PATTERNS) {
if (pat.contextRequired && !hasContext) continue; if (pat.contextRequired && !hasContext) continue;
pat.re.lastIndex = 0; pat.re.lastIndex = 0;
let m; let m;
@@ -521,7 +521,7 @@
warningEl.innerHTML = ` warningEl.innerHTML = `
<div class="ss-ad-header"> <div class="ss-ad-header">
<strong>Silent Send detected potential PPI that may not be substituted:</strong> <strong>Silent Send detected potential PII that may not be substituted:</strong>
<button class="ss-ad-close">&times;</button> <button class="ss-ad-close">&times;</button>
</div> </div>
${items} ${items}
@@ -1180,7 +1180,7 @@
} }
// ============================================================ // ============================================================
// Pre-Send PPI Detection — scans as you type/paste (spellcheck style) // Pre-Send PII Detection — scans as you type/paste (spellcheck style)
// ============================================================ // ============================================================
// Generate obviously-fake values using reserved/standard ranges // Generate obviously-fake values using reserved/standard ranges
@@ -1244,7 +1244,7 @@
preSendWarningEl.innerHTML = ` preSendWarningEl.innerHTML = `
<div class="ss-ad-header"> <div class="ss-ad-header">
<strong>Potential PPI detected — not yet configured:</strong> <strong>Potential PII detected — not yet configured:</strong>
<button class="ss-ad-close">&times;</button> <button class="ss-ad-close">&times;</button>
</div> </div>
${items} ${items}
@@ -1285,12 +1285,12 @@
// Update local mappings so the fetch interceptor uses them immediately // Update local mappings so the fetch interceptor uses them immediately
mappings = currentMappings; mappings = currentMappings;
// Replace the PPI value in the current input right now // Replace the PII value in the current input right now
if (inputEl) { if (inputEl) {
replaceInInput(inputEl, real, fake); replaceInInput(inputEl, real, fake);
// Re-scan — will dismiss warning if no more PPI remains // Re-scan — will dismiss warning if no more PII remains
if (inputScanTimer) clearTimeout(inputScanTimer); if (inputScanTimer) clearTimeout(inputScanTimer);
inputScanTimer = setTimeout(() => scanInputForPPI(inputEl), 150); inputScanTimer = setTimeout(() => scanInputForPII(inputEl), 150);
} }
// Visual feedback // Visual feedback
@@ -1346,14 +1346,14 @@
// Scan input on type and paste // Scan input on type and paste
let inputScanTimer = null; let inputScanTimer = null;
function scanInputForPPI(target) { function scanInputForPII(target) {
const text = target.textContent || target.value || ''; const text = target.textContent || target.value || '';
if (!text || text.length < 5) { if (!text || text.length < 5) {
if (preSendWarningEl) preSendWarningEl.classList.remove('visible'); if (preSendWarningEl) preSendWarningEl.classList.remove('visible');
return; return;
} }
const warnings = autoDetectPPI(text, identity); const warnings = autoDetectPII(text, identity);
if (warnings.length > 0) { if (warnings.length > 0) {
showPreSendWarning(warnings, target); showPreSendWarning(warnings, target);
} else if (preSendWarningEl) { } else if (preSendWarningEl) {
@@ -1367,7 +1367,7 @@
if (target.matches?.('[contenteditable], textarea, input[type="text"]')) { if (target.matches?.('[contenteditable], textarea, input[type="text"]')) {
// Debounce — don't scan on every keystroke // Debounce — don't scan on every keystroke
if (inputScanTimer) clearTimeout(inputScanTimer); if (inputScanTimer) clearTimeout(inputScanTimer);
inputScanTimer = setTimeout(() => scanInputForPPI(target), 800); inputScanTimer = setTimeout(() => scanInputForPII(target), 800);
} }
}, true); }, true);
@@ -1377,7 +1377,7 @@
if (target.matches?.('[contenteditable], textarea, input[type="text"]') || if (target.matches?.('[contenteditable], textarea, input[type="text"]') ||
target.closest?.('[contenteditable]')) { target.closest?.('[contenteditable]')) {
// Scan shortly after paste completes // Scan shortly after paste completes
setTimeout(() => scanInputForPPI(target.closest?.('[contenteditable]') || target), 200); setTimeout(() => scanInputForPII(target.closest?.('[contenteditable]') || target), 200);
} }
}, true); }, true);
+6 -6
View File
@@ -1,14 +1,14 @@
/** /**
* Silent Send - Auto-Detect * Silent Send - Auto-Detect
* *
* Scans text for potential PPI that the user hasn't configured. * Scans text for potential PII that the user hasn't configured.
* This catches things the identity and secret scanner can't — * This catches things the identity and secret scanner can't —
* because the user forgot or didn't know to configure them. * because the user forgot or didn't know to configure them.
* *
* Returns warnings (not auto-redactions) so the user can decide. * Returns warnings (not auto-redactions) so the user can decide.
*/ */
const PPI_PATTERNS = [ const PII_PATTERNS = [
// --- Network --- // --- Network ---
{ {
name: 'Private IP Address', name: 'Private IP Address',
@@ -21,7 +21,7 @@ const PPI_PATTERNS = [
regex: /\b(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\b/g, regex: /\b(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\b/g,
category: 'network', category: 'network',
hint: 'IP address — could identify your network', hint: 'IP address — could identify your network',
// Exclude common non-PPI IPs // Exclude common non-PII IPs
exclude: /^(?:127\.0\.0\.1|0\.0\.0\.0|255\.255\.255\.\d+|8\.8\.[84]\.[84]|1\.1\.1\.1|1\.0\.0\.1)$/, exclude: /^(?:127\.0\.0\.1|0\.0\.0\.0|255\.255\.255\.\d+|8\.8\.[84]\.[84]|1\.1\.1\.1|1\.0\.0\.1)$/,
}, },
{ {
@@ -126,12 +126,12 @@ const PPI_PATTERNS = [
}, },
]; ];
// Context words that make ambiguous patterns more likely to be PPI // Context words that make ambiguous patterns more likely to be PII
const CONTEXT_WORDS = /\b(?:born|birthday|dob|birth|passport|license|driver|ssn|social\s*security|address|home|live|lives|reside|zip|postal)\b/i; const CONTEXT_WORDS = /\b(?:born|birthday|dob|birth|passport|license|driver|ssn|social\s*security|address|home|live|lives|reside|zip|postal)\b/i;
const AutoDetect = { const AutoDetect = {
/** /**
* Scan text for potential unconfigured PPI. * Scan text for potential unconfigured PII.
* Pass in identity so we can skip values the user already configured. * Pass in identity so we can skip values the user already configured.
* *
* Returns array of { name, value, hint, category, index } * Returns array of { name, value, hint, category, index }
@@ -167,7 +167,7 @@ const AutoDetect = {
} }
} }
for (const pattern of PPI_PATTERNS) { for (const pattern of PII_PATTERNS) {
// Skip context-dependent patterns if no context words present // Skip context-dependent patterns if no context words present
if (pattern.contextRequired && !hasContext) continue; if (pattern.contextRequired && !hasContext) continue;
+2 -2
View File
@@ -12,7 +12,7 @@
* - Policy updates are applied automatically * - Policy updates are applied automatically
* *
* Privacy: the org admin can check compliance (are required fields * Privacy: the org admin can check compliance (are required fields
* configured?) but CANNOT see individual PPI values. * configured?) but CANNOT see individual PII values.
*/ */
import api from './browser-polyfill.js'; import api from './browser-polyfill.js';
@@ -220,7 +220,7 @@ const OrgPolicy = {
/** /**
* Check if the user's configuration meets org policy requirements. * Check if the user's configuration meets org policy requirements.
* Returns compliance status WITHOUT revealing actual PPI values. * Returns compliance status WITHOUT revealing actual PII values.
* *
* @returns {{ compliant: boolean, missing: string[], configured: string[] }} * @returns {{ compliant: boolean, missing: string[], configured: string[] }}
*/ */
+1 -1
View File
@@ -23,7 +23,7 @@ const KEYS = {
SETTINGS: 'ss_settings', SETTINGS: 'ss_settings',
}; };
// Keys that contain sensitive PPI and should be encrypted at rest // Keys that contain sensitive PII and should be encrypted at rest
// All user data keys are encrypted at rest — settings included since // All user data keys are encrypted at rest — settings included since
// custom domains and configuration can reveal what services the user // custom domains and configuration can reveal what services the user
// accesses. Only ss_sync_encryption (salt, verification blob) and // accesses. Only ss_sync_encryption (salt, verification blob) and
+5 -5
View File
@@ -59,7 +59,7 @@
</div> </div>
<div class="setting-row"> <div class="setting-row">
<div> <div>
<label>Auto-detect unconfigured PPI</label> <label>Auto-detect unconfigured PII</label>
<p class="setting-desc">Warn when potential personal data (IPs, addresses, paths) is detected that you haven't configured</p> <p class="setting-desc">Warn when potential personal data (IPs, addresses, paths) is detected that you haven't configured</p>
</div> </div>
<label class="toggle"> <label class="toggle">
@@ -69,8 +69,8 @@
</div> </div>
<div class="setting-row"> <div class="setting-row">
<div> <div>
<label>Auto-redact detected PPI on send</label> <label>Auto-redact detected PII on send</label>
<p class="setting-desc">Automatically replace detected PPI with generic placeholders (192.0.2.1, 123 Example Street, etc.) when sending</p> <p class="setting-desc">Automatically replace detected PII with generic placeholders (192.0.2.1, 123 Example Street, etc.) when sending</p>
</div> </div>
<label class="toggle"> <label class="toggle">
<input type="checkbox" id="autoRedactDetected" checked> <input type="checkbox" id="autoRedactDetected" checked>
@@ -79,8 +79,8 @@
</div> </div>
<div class="setting-row"> <div class="setting-row">
<div> <div>
<label>Offer to auto-add detected PPI</label> <label>Offer to auto-add detected PII</label>
<p class="setting-desc">Show a + button on detected PPI to instantly create a mapping with a suggested fake value</p> <p class="setting-desc">Show a + button on detected PII to instantly create a mapping with a suggested fake value</p>
</div> </div>
<label class="toggle"> <label class="toggle">
<input type="checkbox" id="autoAddDetected" checked> <input type="checkbox" id="autoAddDetected" checked>
+1 -1
View File
@@ -202,7 +202,7 @@
</div> </div>
<div class="privacy-note" style="color:#b45309;background:#fef3c7;padding:6px 8px;border-radius:4px;margin-bottom:6px"> <div class="privacy-note" style="color:#b45309;background:#fef3c7;padding:6px 8px;border-radius:4px;margin-bottom:6px">
Silent Send is a convenience tool, not a security guarantee. It can miss Silent Send is a convenience tool, not a security guarantee. It can miss
PPI in images, file uploads, unusual name forms, or data you forgot to PII in images, file uploads, unusual name forms, or data you forgot to
configure. Always verify sensitive messages before sending. configure. Always verify sensitive messages before sending.
</div> </div>
<a href="#" id="btnOptions">Options</a> <a href="#" id="btnOptions">Options</a>
+7 -7
View File
@@ -715,17 +715,17 @@ function renderTestDiff() {
if (secretCount > 0) parts.push(`${secretCount} secrets redacted`); if (secretCount > 0) parts.push(`${secretCount} secrets redacted`);
if (warnCount > 0) parts.push(`${warnCount} warnings`); if (warnCount > 0) parts.push(`${warnCount} warnings`);
// Auto-detect unconfigured PPI in the final text // Auto-detect unconfigured PII in the final text
const ppiWarnings = AutoDetect.scan(finalText, identity); const piiWarnings = AutoDetect.scan(finalText, identity);
if (ppiWarnings.length > 0) parts.push(`${ppiWarnings.length} PPI detected`); if (piiWarnings.length > 0) parts.push(`${piiWarnings.length} PII detected`);
stats.textContent = `${allReplacements.length} substitution${allReplacements.length !== 1 ? 's' : ''} (${parts.join(', ')})`; stats.textContent = `${allReplacements.length} substitution${allReplacements.length !== 1 ? 's' : ''} (${parts.join(', ')})`;
// Show PPI warnings below stats // Show PII warnings below stats
if (ppiWarnings.length > 0) { if (piiWarnings.length > 0) {
stats.innerHTML += `<div style="margin-top:6px;padding:6px 8px;background:#fef3c7;border-radius:4px;color:#92400e;font-size:11px"> stats.innerHTML += `<div style="margin-top:6px;padding:6px 8px;background:#fef3c7;border-radius:4px;color:#92400e;font-size:11px">
<strong>Unconfigured PPI detected:</strong> <strong>Unconfigured PII detected:</strong>
${ppiWarnings.map(w => `<div style="margin-top:3px"><code style="background:#fff;padding:1px 4px;border-radius:2px;color:#b45309">${escapeHtml(w.value)}</code> — ${w.hint}</div>`).join('')} ${piiWarnings.map(w => `<div style="margin-top:3px"><code style="background:#fff;padding:1px 4px;border-radius:2px;color:#b45309">${escapeHtml(w.value)}</code> — ${w.hint}</div>`).join('')}
</div>`; </div>`;
} }
} }