Merge pull request #18 from outis1one/claude/read-repo-wA3y1

Claude/read repo w a3y1
This commit is contained in:
Outis
2026-03-26 23:17:47 -04:00
committed by GitHub
11 changed files with 396 additions and 23 deletions
+66
View File
@@ -0,0 +1,66 @@
#!/bin/bash
#
# Convert Silent Send for Safari using Apple's safari-web-extension-converter.
#
# Prerequisites:
# - macOS with Xcode installed (free from Mac App Store)
# - Apple Developer account ($99/year) for App Store distribution
# - Xcode Command Line Tools: xcode-select --install
#
# This script:
# 1. Builds the Firefox variant (Safari uses browser.* API like Firefox)
# 2. Runs safari-web-extension-converter to generate an Xcode project
# 3. The Xcode project can then be built, tested, and submitted to App Store
#
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
OUT_DIR="$SCRIPT_DIR/safari-build"
# Check for Xcode
if ! command -v xcrun &> /dev/null; then
echo "Error: Xcode is required. Install from the Mac App Store."
echo "Then run: xcode-select --install"
exit 1
fi
if ! xcrun --find safari-web-extension-converter &> /dev/null; then
echo "Error: safari-web-extension-converter not found."
echo "Make sure Xcode is installed and up to date."
exit 1
fi
# Build the Firefox variant (Safari uses browser.* API)
echo "Building extension..."
"$SCRIPT_DIR/build.sh" firefox
echo ""
echo "Converting for Safari..."
# Remove previous build
rm -rf "$OUT_DIR"
# Convert — generates an Xcode project
xcrun safari-web-extension-converter \
"$SCRIPT_DIR/dist/firefox" \
--project-location "$OUT_DIR" \
--app-name "Silent Send" \
--bundle-identifier "com.silentsend.extension" \
--swift \
--macos-only \
--no-open
echo ""
echo "Safari project created at: $OUT_DIR"
echo ""
echo "Next steps:"
echo " 1. Open $OUT_DIR/Silent Send.xcodeproj in Xcode"
echo " 2. Select your Apple Developer Team in Signing & Capabilities"
echo " 3. Build and run (Cmd+R) to test in Safari"
echo " 4. To distribute: Product → Archive → Distribute App"
echo ""
echo "For App Store submission, you'll also need:"
echo " - App Store screenshots (1280x800 for Mac)"
echo " - Privacy policy URL"
echo " - App description and keywords"
+1 -1
View File
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Silent Send",
"version": "2.0.3",
"version": "2.0.5",
"description": "Intercepts personal info and substitutes it with user-defined replacements before sending to AI services.",
"browser_specific_settings": {
"gecko": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Silent Send",
"version": "2.0.3",
"version": "2.0.5",
"description": "Intercepts personal info and substitutes it with user-defined replacements before sending to AI services.",
"permissions": [
"storage",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "silent-send",
"version": "2.0.3",
"version": "2.0.5",
"private": true,
"license": "BSL-1.1",
"description": "Browser extension that substitutes personal data before sending to AI services",
+137 -16
View File
@@ -14,7 +14,8 @@
function safeHTML(el, html) {
const template = document.createElement('template');
template.innerHTML = html;
el.replaceChildren(...template.content.childNodes);
// Convert to static array — childNodes is live and shrinks as nodes move
el.replaceChildren(...Array.from(template.content.childNodes));
}
// ============================================================
@@ -181,6 +182,32 @@
replacements.push({ original: matched, replaced: sub, category: 'name', pattern: 'smart' });
return sub;
});
// Concatenated forms: JohnSmith, johnsmith, john.smith, john_smith, john-smith
// Also reversed: SmithJohn, smithjohn, smith.john, etc.
const f = first.real, l = last.real;
const fs = first.substitute, ls = last.substitute;
const concatPatterns = [
// first+last
[f + l, fs + ls],
[f + '.' + l, fs + '.' + ls],
[f + '_' + l, fs + '_' + ls],
[f + '-' + l, fs + '-' + ls],
// last+first
[l + f, ls + fs],
[l + '.' + f, ls + '.' + fs],
[l + '_' + f, ls + '_' + fs],
[l + '-' + f, ls + '-' + fs],
];
for (const [real, sub] of concatPatterns) {
result = result.replace(new RegExp('\\b' + esc(real) + '\\b', 'gi'), (matched) => {
// Preserve case: all-lower→lower, ALL-UPPER→upper, else use sub as-is
let replacement = sub;
if (matched === matched.toLowerCase()) replacement = sub.toLowerCase();
else if (matched === matched.toUpperCase()) replacement = sub.toUpperCase();
replacements.push({ original: matched, replaced: replacement, category: 'name', pattern: 'smart-concat' });
return replacement;
});
}
}
}
@@ -355,17 +382,26 @@
// Common English words that are capitalized but aren't proper nouns.
// Used by the proper noun heuristic to reduce false positives.
// Includes common verbs, nouns, adjectives that appear in titles,
// headings, UI buttons, and instructions.
const COMMON_CAPITALIZED = new Set([
// Prepositions, conjunctions, articles, pronouns
'the', 'a', 'an', 'and', 'or', 'but', 'if', 'then', 'else', 'when',
'at', 'by', 'for', 'with', 'about', 'against', 'between', 'through',
'during', 'before', 'after', 'above', 'below', 'to', 'from', 'up',
'down', 'in', 'out', 'on', 'off', 'over', 'under', 'again', 'further',
'then', 'once', 'here', 'there', 'all', 'each', 'every', 'both',
'once', 'here', 'there', 'all', 'each', 'every', 'both',
'few', 'more', 'most', 'other', 'some', 'such', 'no', 'nor', 'not',
'only', 'own', 'same', 'so', 'than', 'too', 'very', 'can', 'will',
'just', 'should', 'now', 'also', 'into', 'could', 'would', 'may',
'might', 'shall', 'must', 'need', 'have', 'has', 'had', 'do', 'does',
'did', 'be', 'is', 'am', 'are', 'was', 'were', 'been', 'being',
'i', 'you', 'he', 'she', 'it', 'we', 'they', 'me', 'him', 'her',
'us', 'them', 'my', 'your', 'his', 'its', 'our', 'their',
'this', 'that', 'these', 'those', 'what', 'who', 'how', 'why',
'which', 'where', 'when', 'while', 'since', 'because', 'although',
'however', 'therefore', 'moreover', 'furthermore', 'nevertheless',
// Common verbs (appear in titles, headings, buttons, instructions)
'get', 'got', 'make', 'made', 'go', 'went', 'gone', 'take', 'took',
'come', 'came', 'see', 'saw', 'know', 'knew', 'think', 'thought',
'say', 'said', 'tell', 'told', 'give', 'gave', 'find', 'found',
@@ -378,25 +414,110 @@
'buy', 'wait', 'serve', 'die', 'send', 'expect', 'build', 'stay',
'fall', 'cut', 'reach', 'kill', 'remain', 'suggest', 'raise', 'pass',
'sell', 'require', 'report', 'decide', 'pull', 'develop', 'note',
'however', 'because', 'although', 'since', 'while', 'where', 'which',
'what', 'who', 'how', 'why', 'this', 'that', 'these', 'those',
'i', 'you', 'he', 'she', 'it', 'we', 'they', 'me', 'him', 'her',
'us', 'them', 'my', 'your', 'his', 'its', 'our', 'their',
'new', 'old', 'big', 'small', 'long', 'short', 'good', 'bad',
'great', 'little', 'right', 'left', 'first', 'last', 'next',
'sure', 'like', 'well', 'back', 'still', 'even', 'much', 'many',
// Programming/tech words that appear capitalized
'generate', 'design', 'manage', 'process', 'handle', 'check', 'verify',
'submit', 'apply', 'accept', 'reject', 'approve', 'deny', 'confirm',
'cancel', 'delete', 'remove', 'edit', 'modify', 'view', 'display',
'search', 'filter', 'sort', 'select', 'choose', 'pick', 'enter',
'input', 'output', 'upload', 'download', 'install', 'uninstall',
'enable', 'disable', 'activate', 'deactivate', 'toggle', 'switch',
'connect', 'disconnect', 'sync', 'refresh', 'reload', 'reset',
'save', 'load', 'store', 'restore', 'backup', 'export', 'import',
'copy', 'paste', 'drag', 'drop', 'click', 'press', 'hold', 'release',
'scroll', 'zoom', 'resize', 'expand', 'collapse', 'hide', 'reveal',
'lock', 'unlock', 'encrypt', 'decrypt', 'sign', 'register', 'login',
'logout', 'subscribe', 'unsubscribe', 'share', 'publish', 'deploy',
'launch', 'test', 'debug', 'fix', 'patch', 'merge', 'split', 'join',
'link', 'attach', 'detach', 'insert', 'append', 'prepend', 'wrap',
'format', 'parse', 'convert', 'transform', 'translate', 'compile',
'execute', 'render', 'animate', 'validate', 'sanitize', 'escape',
// Common nouns (appear in titles, headings, labels)
'account', 'action', 'address', 'alert', 'analysis', 'answer',
'application', 'area', 'article', 'asset', 'background', 'badge',
'banner', 'board', 'body', 'border', 'bottom', 'box', 'brand',
'browser', 'buffer', 'button', 'cache', 'calendar', 'card', 'case',
'category', 'center', 'channel', 'chart', 'chat', 'child', 'choice',
'class', 'client', 'cloud', 'cluster', 'code', 'collection', 'color',
'column', 'command', 'comment', 'community', 'company', 'component',
'config', 'configuration', 'connection', 'console', 'contact',
'container', 'content', 'context', 'control', 'corner', 'count',
'country', 'cover', 'custom', 'dashboard', 'data', 'database',
'date', 'day', 'default', 'description', 'design', 'desktop',
'detail', 'device', 'dialog', 'directory', 'document', 'domain',
'draft', 'driver', 'edge', 'editor', 'element', 'email', 'end',
'engine', 'entry', 'environment', 'error', 'event', 'example',
'exception', 'extension', 'feature', 'feedback', 'field', 'file',
'filter', 'folder', 'font', 'footer', 'form', 'format', 'frame',
'function', 'gallery', 'general', 'global', 'grid', 'group',
'guide', 'handler', 'header', 'health', 'help', 'helper', 'history',
'home', 'host', 'icon', 'image', 'index', 'info', 'input', 'instance',
'interface', 'issue', 'item', 'job', 'key', 'label', 'language',
'layout', 'level', 'library', 'light', 'limit', 'line', 'link',
'list', 'local', 'location', 'log', 'logo', 'main', 'manager',
'manual', 'map', 'margin', 'master', 'match', 'media', 'member',
'memory', 'menu', 'message', 'method', 'middle', 'mobile', 'modal',
'mode', 'model', 'module', 'monitor', 'name', 'navigation', 'network',
'node', 'note', 'notification', 'number', 'object', 'option',
'order', 'origin', 'output', 'overlay', 'overview', 'owner', 'package',
'padding', 'page', 'panel', 'parent', 'parser', 'password', 'path',
'pattern', 'permission', 'photo', 'pipeline', 'placeholder', 'plan',
'platform', 'player', 'plugin', 'point', 'policy', 'pool', 'popup',
'port', 'position', 'post', 'power', 'preview', 'primary', 'print',
'priority', 'process', 'product', 'profile', 'program', 'progress',
'project', 'prompt', 'property', 'protocol', 'provider', 'proxy',
'public', 'query', 'queue', 'quick', 'radio', 'range', 'rate',
'reader', 'record', 'region', 'release', 'remote', 'render',
'report', 'request', 'resource', 'response', 'result', 'review',
'role', 'root', 'route', 'row', 'rule', 'runtime', 'sample',
'scanner', 'schema', 'scope', 'screen', 'script', 'search',
'section', 'security', 'select', 'sender', 'server', 'service',
'session', 'setting', 'settings', 'setup', 'share', 'shell',
'shortcut', 'sidebar', 'signal', 'simple', 'single', 'site', 'size',
'slider', 'slot', 'snapshot', 'socket', 'solution', 'source', 'space',
'stage', 'standard', 'start', 'state', 'status', 'step', 'stop',
'storage', 'store', 'stream', 'string', 'style', 'subject',
'success', 'summary', 'support', 'switch', 'symbol', 'syntax',
'system', 'table', 'target', 'task', 'team', 'template', 'terminal',
'test', 'text', 'theme', 'thread', 'time', 'timer', 'title', 'token',
'tool', 'toolbar', 'tooltip', 'top', 'total', 'track', 'traffic',
'tree', 'trigger', 'type', 'unit', 'update', 'upload', 'user',
'util', 'utility', 'value', 'variable', 'version', 'video', 'view',
'virtual', 'warning', 'watch', 'web', 'widget', 'width', 'window',
'wizard', 'word', 'worker', 'workspace', 'wrapper', 'zone',
// Common adjectives
'active', 'advanced', 'available', 'basic', 'best', 'better', 'blank',
'bold', 'clean', 'clear', 'close', 'closed', 'complete', 'complex',
'connected', 'correct', 'critical', 'current', 'dark', 'deep',
'detailed', 'different', 'direct', 'double', 'dynamic', 'early',
'easy', 'empty', 'entire', 'equal', 'essential', 'exact', 'extra',
'fast', 'final', 'fine', 'fixed', 'flat', 'free', 'fresh', 'front',
'full', 'generic', 'given', 'good', 'great', 'green', 'hard',
'hidden', 'high', 'hot', 'huge', 'human', 'initial', 'inner',
'internal', 'invalid', 'large', 'late', 'latest', 'left', 'light',
'live', 'long', 'low', 'major', 'maximum', 'middle', 'minimum',
'minor', 'mixed', 'modern', 'multiple', 'native', 'natural',
'nested', 'neutral', 'new', 'normal', 'null', 'old', 'online',
'open', 'optional', 'outer', 'overall', 'parallel', 'partial',
'pending', 'plain', 'popular', 'possible', 'previous', 'primary',
'private', 'proper', 'protected', 'quick', 'random', 'raw', 'ready',
'real', 'recent', 'red', 'related', 'relative', 'remote', 'required',
'responsive', 'rich', 'right', 'round', 'safe', 'secure', 'selected',
'sensitive', 'separate', 'serial', 'shared', 'short', 'silent',
'similar', 'simple', 'single', 'small', 'smart', 'smooth', 'soft',
'solid', 'special', 'specific', 'stable', 'standard', 'static',
'strict', 'strong', 'supported', 'sweet', 'thin', 'tight', 'tiny',
'total', 'true', 'unique', 'universal', 'unknown', 'upper', 'valid',
'various', 'virtual', 'visible', 'visual', 'warm', 'weak', 'white',
'whole', 'wide', 'wild',
// Programming/tech terms
'string', 'number', 'boolean', 'object', 'array', 'function', 'class',
'type', 'error', 'null', 'undefined', 'true', 'false', 'return',
'import', 'export', 'default', 'const', 'let', 'var', 'async', 'await',
'try', 'catch', 'throw', 'finally', 'switch', 'case', 'break',
'note', 'example', 'warning', 'important', 'todo', 'fixme', 'hack',
'step', 'option', 'result', 'value', 'key', 'data', 'info',
'file', 'code', 'test', 'debug', 'config', 'setup', 'update',
// Common sentence starters that aren't names
'example', 'warning', 'important', 'todo', 'fixme', 'hack',
// Common sentence starters
'please', 'thanks', 'hello', 'hi', 'hey', 'dear', 'sincerely',
'regards', 'best', 'cheers', 'sorry', 'yes', 'no', 'ok', 'okay',
// Days and months (not PPI)
'regards', 'best', 'cheers', 'sorry', 'yes', 'ok', 'okay',
// Days and months
'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday',
'january', 'february', 'march', 'april', 'may', 'june', 'july',
'august', 'september', 'october', 'november', 'december',
+80
View File
@@ -257,6 +257,8 @@ const AutoDetect = {
};
// Common English words to exclude from proper noun detection
// Comprehensive list including verbs, nouns, adjectives that appear
// in titles, headings, UI buttons, and instructions
const COMMON_WORDS = new Set([
'the', 'and', 'but', 'for', 'not', 'you', 'all', 'can', 'had', 'her',
'was', 'one', 'our', 'out', 'are', 'has', 'his', 'how', 'its', 'may',
@@ -276,6 +278,84 @@ const COMMON_WORDS = new Set([
'number', 'other', 'point', 'right', 'small', 'state', 'thing',
'think', 'those', 'three', 'through', 'under', 'until', 'water',
'world', 'write', 'might', 'should', 'because', 'although',
// Common verbs (titles, headings, buttons, instructions)
'generate', 'design', 'manage', 'process', 'handle', 'check', 'verify',
'submit', 'apply', 'accept', 'reject', 'approve', 'deny', 'confirm',
'cancel', 'delete', 'remove', 'edit', 'modify', 'view', 'display',
'search', 'filter', 'sort', 'select', 'choose', 'pick', 'enter',
'upload', 'download', 'install', 'enable', 'disable', 'activate',
'connect', 'disconnect', 'sync', 'refresh', 'reload', 'reset',
'save', 'load', 'store', 'restore', 'backup', 'copy', 'paste',
'lock', 'unlock', 'encrypt', 'decrypt', 'sign', 'register', 'login',
'logout', 'subscribe', 'share', 'publish', 'deploy', 'launch',
'merge', 'split', 'join', 'link', 'attach', 'insert', 'append',
'format', 'parse', 'convert', 'transform', 'translate', 'compile',
'execute', 'render', 'animate', 'validate', 'sanitize', 'escape',
'create', 'build', 'start', 'stop', 'open', 'close', 'run', 'send',
// Common nouns (titles, headings, labels)
'account', 'action', 'address', 'alert', 'analysis', 'application',
'area', 'article', 'asset', 'background', 'badge', 'banner', 'board',
'body', 'border', 'bottom', 'box', 'browser', 'buffer', 'button',
'cache', 'calendar', 'card', 'category', 'center', 'channel', 'chart',
'chat', 'child', 'choice', 'client', 'cloud', 'code', 'collection',
'color', 'column', 'command', 'comment', 'community', 'company',
'component', 'config', 'configuration', 'connection', 'console',
'contact', 'container', 'content', 'context', 'control', 'count',
'country', 'custom', 'dashboard', 'data', 'database', 'date', 'day',
'default', 'description', 'design', 'desktop', 'detail', 'device',
'dialog', 'directory', 'document', 'domain', 'draft', 'driver',
'edge', 'editor', 'element', 'email', 'engine', 'entry', 'environment',
'error', 'event', 'example', 'extension', 'feature', 'feedback',
'field', 'file', 'filter', 'folder', 'font', 'footer', 'form',
'frame', 'function', 'gallery', 'general', 'global', 'grid',
'guide', 'handler', 'header', 'health', 'help', 'history', 'home',
'host', 'icon', 'image', 'index', 'info', 'input', 'instance',
'interface', 'issue', 'item', 'job', 'key', 'label', 'language',
'layout', 'level', 'library', 'light', 'limit', 'line', 'link',
'list', 'local', 'location', 'log', 'logo', 'main', 'manager',
'manual', 'map', 'media', 'member', 'memory', 'menu', 'message',
'method', 'mobile', 'modal', 'mode', 'model', 'module', 'monitor',
'navigation', 'network', 'node', 'note', 'notification', 'object',
'option', 'order', 'origin', 'output', 'overlay', 'overview', 'owner',
'package', 'page', 'panel', 'parent', 'parser', 'password', 'path',
'pattern', 'permission', 'photo', 'pipeline', 'placeholder', 'plan',
'platform', 'player', 'plugin', 'point', 'policy', 'pool', 'popup',
'port', 'position', 'post', 'power', 'preview', 'primary', 'print',
'priority', 'process', 'product', 'profile', 'program', 'progress',
'project', 'prompt', 'property', 'protocol', 'provider', 'proxy',
'public', 'query', 'queue', 'quick', 'range', 'rate', 'reader',
'record', 'region', 'release', 'remote', 'report', 'request',
'resource', 'response', 'result', 'review', 'role', 'root', 'route',
'row', 'rule', 'runtime', 'sample', 'scanner', 'schema', 'scope',
'screen', 'script', 'search', 'section', 'security', 'select',
'sender', 'server', 'service', 'session', 'setting', 'settings',
'setup', 'share', 'shell', 'shortcut', 'sidebar', 'signal', 'simple',
'single', 'site', 'size', 'slider', 'snapshot', 'socket', 'solution',
'source', 'space', 'stage', 'standard', 'status', 'step', 'storage',
'stream', 'string', 'style', 'subject', 'success', 'summary',
'support', 'switch', 'symbol', 'syntax', 'system', 'table', 'target',
'task', 'team', 'template', 'terminal', 'test', 'text', 'theme',
'thread', 'title', 'token', 'tool', 'toolbar', 'tooltip', 'total',
'track', 'traffic', 'tree', 'trigger', 'type', 'unit', 'update',
'upload', 'user', 'utility', 'value', 'variable', 'version', 'video',
'view', 'virtual', 'warning', 'watch', 'web', 'widget', 'width',
'window', 'wizard', 'word', 'worker', 'workspace', 'wrapper', 'zone',
// Common adjectives
'active', 'advanced', 'available', 'basic', 'clean', 'clear', 'complete',
'connected', 'correct', 'critical', 'current', 'dark', 'deep',
'different', 'direct', 'double', 'dynamic', 'easy', 'empty', 'entire',
'exact', 'extra', 'fast', 'final', 'fixed', 'flat', 'free', 'fresh',
'full', 'generic', 'given', 'hidden', 'initial', 'inner', 'internal',
'invalid', 'latest', 'live', 'major', 'maximum', 'minimum', 'minor',
'mixed', 'modern', 'multiple', 'native', 'natural', 'nested', 'normal',
'online', 'optional', 'outer', 'overall', 'partial', 'pending', 'plain',
'popular', 'possible', 'previous', 'private', 'proper', 'protected',
'random', 'raw', 'ready', 'real', 'recent', 'related', 'relative',
'required', 'responsive', 'safe', 'secure', 'selected', 'sensitive',
'separate', 'shared', 'silent', 'similar', 'smart', 'smooth', 'solid',
'special', 'specific', 'stable', 'static', 'strict', 'strong',
'supported', 'unique', 'universal', 'unknown', 'upper', 'valid',
'various', 'visible', 'visual', 'whole', 'wide',
// Programming / tech terms
'string', 'number', 'boolean', 'object', 'array', 'function', 'class',
'type', 'error', 'null', 'undefined', 'true', 'false', 'return',
+1 -1
View File
@@ -589,7 +589,7 @@
</section>
<footer>
<p>Silent Send v2.0.3</p>
<p>Silent Send v2.0.5</p>
</footer>
</div>
+1 -1
View File
@@ -17,7 +17,7 @@ const $ = (sel) => document.querySelector(sel);
// --- Safe innerHTML replacement (AMO-compliant) ---
function safeHTML(el, html) {
const doc = new DOMParser().parseFromString(html, 'text/html');
el.replaceChildren(...doc.body.childNodes);
el.replaceChildren(...Array.from(doc.body.childNodes));
}
document.addEventListener('DOMContentLoaded', async () => {
+29
View File
@@ -623,6 +623,35 @@ body {
font-size: 12px;
}
/* Options tab */
.setting-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 0;
border-bottom: 1px solid #f3f4f6;
}
.setting-item:last-of-type { border-bottom: none; }
.setting-label {
flex: 1;
min-width: 0;
}
.setting-label strong {
font-size: 12px;
display: block;
color: #1f2937;
}
.setting-label .setting-desc {
font-size: 10px;
color: #9ca3af;
display: block;
margin-top: 1px;
}
/* Footer */
.footer {
padding: 8px 16px;
+49
View File
@@ -33,6 +33,7 @@
<button class="tab" data-tab="mappings">Mappings</button>
<button class="tab" data-tab="activity">Activity</button>
<button class="tab" data-tab="test">Test</button>
<button class="tab" data-tab="options">Options</button>
</nav>
<!-- Locked State Overlay -->
@@ -193,6 +194,54 @@
<div class="test-identity-status" id="identityStatus"></div>
</section>
<!-- Options Tab -->
<section class="tab-content" id="tab-options">
<div class="setting-item">
<div class="setting-label">
<strong>Secret scanning</strong>
<span class="setting-desc">Auto-redact API keys, tokens, passwords, SSNs, credit cards</span>
</div>
<label class="toggle"><input type="checkbox" id="optSecretScanning" checked><span class="toggle-slider"></span></label>
</div>
<div class="setting-item">
<div class="setting-label">
<strong>Auto-detect PPI</strong>
<span class="setting-desc">Warn about unconfigured personal data (IPs, addresses, paths)</span>
</div>
<label class="toggle"><input type="checkbox" id="optAutoDetect" checked><span class="toggle-slider"></span></label>
</div>
<div class="setting-item">
<div class="setting-label">
<strong>Auto-redact detected PPI</strong>
<span class="setting-desc">Replace detected PPI with placeholders on send</span>
</div>
<label class="toggle"><input type="checkbox" id="optAutoRedact" checked><span class="toggle-slider"></span></label>
</div>
<div class="setting-item">
<div class="setting-label">
<strong>Show highlights</strong>
<span class="setting-desc">Highlight substituted values in AI responses</span>
</div>
<label class="toggle"><input type="checkbox" id="optHighlights"><span class="toggle-slider"></span></label>
</div>
<div class="setting-item">
<div class="setting-label">
<strong>Document scan preview</strong>
<span class="setting-desc">Show PPI findings before uploading documents</span>
</div>
<label class="toggle"><input type="checkbox" id="optDocPreview" checked><span class="toggle-slider"></span></label>
</div>
<div style="margin-top:12px;padding-top:10px;border-top:1px solid #e5e7eb">
<button class="btn" id="btnOpenFullOptions" style="width:100%;font-size:12px">Open Full Options Page</button>
<p class="help-text" style="margin-top:6px;text-align:center">Sync, encryption, org, version history, import/export, and more</p>
</div>
</section>
<!-- Footer -->
<footer class="footer">
<div class="privacy-note">
+30 -2
View File
@@ -21,7 +21,7 @@ const $$ = (sel) => document.querySelectorAll(sel);
// --- Safe innerHTML replacement (AMO-compliant) ---
function safeHTML(el, html) {
const doc = new DOMParser().parseFromString(html, 'text/html');
el.replaceChildren(...doc.body.childNodes);
el.replaceChildren(...Array.from(doc.body.childNodes));
}
// --- Init ---
@@ -208,12 +208,40 @@ async function initUnlockedUI() {
});
});
// Options link
// Options link (footer)
$('#btnOptions').addEventListener('click', (e) => {
e.preventDefault();
api.runtime.openOptionsPage();
});
// Options tab
$('#btnOpenFullOptions').addEventListener('click', () => {
api.runtime.openOptionsPage();
});
// Load options tab settings
$('#optSecretScanning').checked = settings.secretScanning !== false;
$('#optAutoDetect').checked = settings.autoDetect !== false;
$('#optAutoRedact').checked = settings.autoRedactDetected !== false;
$('#optHighlights').checked = settings.showHighlights || false;
$('#optDocPreview').checked = settings.docScanPreview !== false;
// Options tab change handlers
const optHandlers = [
['optSecretScanning', 'secretScanning'],
['optAutoDetect', 'autoDetect'],
['optAutoRedact', 'autoRedactDetected'],
['optHighlights', 'showHighlights'],
['optDocPreview', 'docScanPreview'],
];
for (const [id, key] of optHandlers) {
$(`#${id}`).addEventListener('change', async (e) => {
settings[key] = e.target.checked;
await Storage.saveSettings({ [key]: e.target.checked });
api.runtime.sendMessage({ type: 'update:settings', settings });
});
}
// Update privacy note based on encryption state
const encEnabled = await Storage._isAtRestEncryptionEnabled();
const encNote = $('#privacyEncNote');