merge: integrate claude/read-repo-YMu21 branch

Merged changes from the other session:
- Ko-fi support link in options footer
- PPI → PII renaming across codebase
- Legal/licensing updates (stronger disclaimer, non-commercial only)
- Custom secret/auto-redact patterns
- Internal refactoring of secret scanner to auto-redact naming
- Custom domains in popup Options tab
- Additional AI services (Perplexity, DeepSeek, HuggingChat, Poe)
- Developer sites (GitHub, GitLab, Reddit, StackOverflow, Pastebin)
- Dynamic content script registration for custom domains

Resolved conflicts in options.html and popup.html (kept newer
"Auto Redact" naming with custom patterns description).

https://claude.ai/code/session_01SWSwDfMVij53bCTNSCLMwn
This commit is contained in:
Claude
2026-03-28 16:39:27 +00:00
14 changed files with 372 additions and 136 deletions
+7 -7
View File
@@ -1,14 +1,14 @@
/**
* Silent Send - Auto-Detect
*
* Scans text for potential PPI that the user hasn't configured.
* This catches things the identity and secret scanner can't —
* Scans text for potential PII that the user hasn't configured.
* This catches things the identity and auto-redact scanner can't —
* because the user forgot or didn't know to configure them.
*
* Returns warnings (not auto-redactions) so the user can decide.
*/
const PPI_PATTERNS = [
const PII_PATTERNS = [
// --- Network ---
{
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,
category: '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)$/,
},
{
@@ -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 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.
*
* 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
if (pattern.contextRequired && !hasContext) continue;
@@ -1,11 +1,13 @@
/**
* Silent Send - Secret Scanner
* Silent Send - Auto Redact
*
* Detects common secret/credential patterns in text and either
* warns or auto-redacts them. This catches things the identity-based
* smart patterns can't: API keys, tokens, passwords, SSNs, credit
* cards, private keys, connection strings, etc.
*
* Supports user-defined custom patterns for proprietary token formats.
*
* Each pattern has:
* - name: human-readable label
* - regex: detection pattern
@@ -13,7 +15,7 @@
* - severity: 'critical' (always redact) or 'warning' (flag but allow)
*/
const SECRET_PATTERNS = [
const REDACT_PATTERNS = [
// --- API Keys ---
{
name: 'OpenAI API Key',
@@ -161,14 +163,39 @@ const SECRET_PATTERNS = [
},
];
const SecretScanner = {
const AutoRedact = {
/**
* Build the full pattern list (built-in + custom).
* Custom patterns come from settings.customRedactPatterns.
*/
_buildPatterns(customPatterns) {
const all = [...REDACT_PATTERNS];
if (Array.isArray(customPatterns)) {
for (const cp of customPatterns) {
if (!cp.enabled || !cp.pattern) continue;
try {
all.push({
name: cp.name || 'Custom Pattern',
regex: new RegExp(cp.pattern, 'g'),
redact: cp.redact || '[REDACTED-CUSTOM]',
severity: 'critical',
});
} catch { /* invalid regex — skip */ }
}
}
return all;
},
/**
* Scan text for secrets. Returns list of findings.
* @param {string} text
* @param {Array} [customPatterns] from settings.customRedactPatterns
*/
scan(text) {
scan(text, customPatterns) {
const findings = [];
const patterns = this._buildPatterns(customPatterns);
for (const pattern of SECRET_PATTERNS) {
for (const pattern of patterns) {
// Reset regex lastIndex
pattern.regex.lastIndex = 0;
let match;
@@ -204,9 +231,11 @@ const SecretScanner = {
/**
* Redact all critical secrets in text. Warnings are not auto-redacted.
* Returns { text, redactions[] }
* @param {string} text
* @param {Array} [customPatterns] from settings.customRedactPatterns
*/
redact(text) {
const findings = this.scan(text);
redact(text, customPatterns) {
const findings = this.scan(text, customPatterns);
const redactions = [];
let result = text;
@@ -220,7 +249,7 @@ const SecretScanner = {
redactions.push({
original: f.value,
replaced: f.redactTo,
category: 'secret',
category: 'redact',
pattern: f.name,
});
}
@@ -237,7 +266,7 @@ const SecretScanner = {
};
if (typeof globalThis !== 'undefined') {
globalThis.SecretScanner = SecretScanner;
globalThis.AutoRedact = AutoRedact;
}
export default SecretScanner;
export default AutoRedact;
+5 -5
View File
@@ -1,11 +1,11 @@
/**
* Silent Send - Document Scanner
*
* Scans uploaded documents for PPI and substitutes/redacts before
* Scans uploaded documents for PII and substitutes/redacts before
* the file reaches the AI service.
*
* Supported formats:
* - PDF: Extract text, scan for PPI, create sanitized plaintext version
* - PDF: Extract text, scan for PII, create sanitized plaintext version
* (PDFs can't be reliably edited in-place without breaking layout)
* - DOCX: Parse XML, find-replace text, repackage ZIP (layout preserved)
* - XLSX: Parse cells, find-replace values, repackage (formatting preserved)
@@ -13,7 +13,7 @@
*
* Modes:
* - Silent: substitute and upload (default for text files)
* - Preview: show PPI findings, let user confirm before upload (default for PDF/DOCX/XLSX)
* - Preview: show PII findings, let user confirm before upload (default for PDF/DOCX/XLSX)
*
* Integration:
* - The fetch interceptor in content.js detects multipart/form-data uploads
@@ -70,9 +70,9 @@ const DocumentScanner = {
},
/**
* PDF: extract text, scan for PPI, create sanitized text file.
* PDF: extract text, scan for PII, create sanitized text file.
* PDFs can't be reliably edited in-place, so we extract text,
* substitute PPI, and send the clean text instead.
* substitute PII, and send the clean text instead.
*/
async _processPDF(file, filename, substituteAll, options) {
const text = await this._extractPDFText(file);
+5 -5
View File
@@ -12,7 +12,7 @@
* - Policy updates are applied automatically
*
* 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';
@@ -198,11 +198,11 @@ const OrgPolicy = {
},
/**
* Get org-required secret scanner patterns.
* Get org-required auto-redact patterns.
*
* @returns {Array} additional patterns to add to the secret scanner
* @returns {Array} additional patterns to add to auto-redact
*/
async getOrgSecretPatterns() {
async getOrgRedactPatterns() {
const policy = await this.getPolicy();
if (!policy?.requiredSecretPatterns?.length) return [];
@@ -220,7 +220,7 @@ const OrgPolicy = {
/**
* 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[] }}
*/
+3 -2
View File
@@ -23,7 +23,7 @@ const KEYS = {
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
// custom domains and configuration can reveal what services the user
// accesses. Only ss_sync_encryption (salt, verification blob) and
@@ -34,12 +34,13 @@ const DEFAULT_SETTINGS = {
enabled: true,
showHighlights: false,
revealMode: false,
secretScanning: true,
autoRedact: true,
autoDetect: true,
autoRedactDetected: true,
autoAddDetected: true,
maxLogEntries: 100,
customDomains: [],
customRedactPatterns: [],
categories: ['name', 'email', 'phone', 'address', 'ssn', 'dob', 'domain', 'password', 'general'],
browserSync: false,
};