601 lines
32 KiB
HTML
601 lines
32 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Silent Send - Options</title>
|
|
<link rel="stylesheet" href="options.css">
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<header>
|
|
<h1>Silent Send Options</h1>
|
|
<p class="subtitle">Manage your privacy substitution mappings</p>
|
|
</header>
|
|
|
|
<section class="section">
|
|
<h2>Keyboard Shortcuts</h2>
|
|
<div class="setting-row">
|
|
<div>
|
|
<label>Toggle Reveal Mode</label>
|
|
<p class="setting-desc">Show your real data in AI responses</p>
|
|
</div>
|
|
<code style="font-size:12px;background:#f3f4f6;padding:4px 8px;border-radius:4px">Alt+Shift+R</code>
|
|
</div>
|
|
<div class="setting-row">
|
|
<div>
|
|
<label>Toggle Silent Send on/off</label>
|
|
<p class="setting-desc">Quickly enable or disable all substitution</p>
|
|
</div>
|
|
<code style="font-size:12px;background:#f3f4f6;padding:4px 8px;border-radius:4px">Alt+Shift+S</code>
|
|
</div>
|
|
<p class="section-desc" style="margin-top:8px;margin-bottom:0">
|
|
To change these shortcuts:<br>
|
|
<strong>Chrome:</strong> <code>chrome://extensions/shortcuts</code><br>
|
|
<strong>Firefox:</strong> <code>about:addons</code> → gear icon → Manage Extension Shortcuts
|
|
</p>
|
|
</section>
|
|
|
|
<section class="section">
|
|
<h2>Settings</h2>
|
|
<div class="setting-row">
|
|
<div>
|
|
<label>Show inline highlights</label>
|
|
<p class="setting-desc">Show a subtle underline on text that will be substituted</p>
|
|
</div>
|
|
<label class="toggle">
|
|
<input type="checkbox" id="showHighlights">
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
</div>
|
|
<div class="setting-row">
|
|
<div>
|
|
<label>Secret scanning</label>
|
|
<p class="setting-desc">Auto-detect and redact API keys, tokens, passwords, SSNs, credit card numbers</p>
|
|
</div>
|
|
<label class="toggle">
|
|
<input type="checkbox" id="secretScanning" checked>
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
</div>
|
|
<div class="setting-row">
|
|
<div>
|
|
<label>Auto-detect unconfigured PPI</label>
|
|
<p class="setting-desc">Warn when potential personal data (IPs, addresses, paths) is detected that you haven't configured</p>
|
|
</div>
|
|
<label class="toggle">
|
|
<input type="checkbox" id="autoDetect" checked>
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
</div>
|
|
<div class="setting-row">
|
|
<div>
|
|
<label>Auto-redact detected PPI 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>
|
|
</div>
|
|
<label class="toggle">
|
|
<input type="checkbox" id="autoRedactDetected" checked>
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
</div>
|
|
<div class="setting-row">
|
|
<div>
|
|
<label>Offer to auto-add detected PPI</label>
|
|
<p class="setting-desc">Show a + button on detected PPI to instantly create a mapping with a suggested fake value</p>
|
|
</div>
|
|
<label class="toggle">
|
|
<input type="checkbox" id="autoAddDetected" checked>
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
</div>
|
|
<div class="setting-row">
|
|
<div>
|
|
<label>Max log entries</label>
|
|
<p class="setting-desc">Number of activity log entries to keep</p>
|
|
</div>
|
|
<input type="number" id="maxLogEntries" class="input-small" min="10" max="1000" value="100">
|
|
</div>
|
|
</section>
|
|
|
|
<section class="section">
|
|
<h2>Sync Between Browsers</h2>
|
|
<p class="section-desc">Keep your identities, mappings, and settings in sync across browsers.</p>
|
|
|
|
<!-- Sync Encryption -->
|
|
<div style="margin-bottom:20px;padding:12px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px">
|
|
<h3 style="font-size:13px;font-weight:600;margin:0 0 8px;display:flex;align-items:center;gap:6px">
|
|
<span>🔒</span> Sync Encryption
|
|
</h3>
|
|
<p class="section-desc" style="margin-bottom:10px">
|
|
Encryption is required for all sync channels. Set up a password (and optionally TOTP) before enabling any sync method. Authentication is only required when new data arrives and your cached key has expired.
|
|
</p>
|
|
|
|
<div id="syncEncryptionSetup">
|
|
<!-- Shown when encryption is NOT set up -->
|
|
<div id="encryptionNotConfigured">
|
|
<div style="display:flex;flex-direction:column;gap:8px">
|
|
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:end">
|
|
<div style="flex:1;min-width:160px">
|
|
<label style="font-size:11px;color:#6b7280;display:block;margin-bottom:2px">Password</label>
|
|
<input type="password" id="syncEncPassword" placeholder="Encryption password" autocomplete="new-password"
|
|
style="width:100%;box-sizing:border-box;font-size:12px;padding:5px 8px;border:1px solid #d1d5db;border-radius:6px">
|
|
</div>
|
|
<div style="flex:1;min-width:160px">
|
|
<label style="font-size:11px;color:#6b7280;display:block;margin-bottom:2px">Confirm Password</label>
|
|
<input type="password" id="syncEncPasswordConfirm" placeholder="Confirm password" autocomplete="new-password"
|
|
style="width:100%;box-sizing:border-box;font-size:12px;padding:5px 8px;border:1px solid #d1d5db;border-radius:6px">
|
|
</div>
|
|
</div>
|
|
<div style="display:flex;gap:12px;flex-wrap:wrap;align-items:center">
|
|
<label style="font-size:12px;display:flex;align-items:center;gap:4px;cursor:pointer">
|
|
<input type="checkbox" id="syncEncTOTP"> Enable TOTP (authenticator app)
|
|
</label>
|
|
<label style="font-size:12px;display:flex;align-items:center;gap:4px;cursor:pointer" id="syncEncWebAuthnLabel">
|
|
<input type="checkbox" id="syncEncWebAuthn"> Biometric/PIN re-auth
|
|
</label>
|
|
<div style="display:flex;align-items:center;gap:4px">
|
|
<label style="font-size:12px;white-space:nowrap">Re-auth every</label>
|
|
<select id="syncEncTTL" style="font-size:12px;padding:3px 6px;border:1px solid #d1d5db;border-radius:4px">
|
|
<option value="0">Each session</option>
|
|
<option value="30">30 days</option>
|
|
<option value="90" selected>90 days</option>
|
|
<option value="180">180 days</option>
|
|
<option value="365">1 year</option>
|
|
<option value="-1">Never</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<button class="btn btn-primary" id="btnSetupEncryption">Enable Encryption</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Shown when encryption IS set up -->
|
|
<div id="encryptionConfigured" style="display:none">
|
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
<span style="font-size:12px;color:#10b981;font-weight:500">✓ Encryption active</span>
|
|
<span id="encryptionInfo" style="font-size:11px;color:#6b7280"></span>
|
|
<button class="btn btn-sm" id="btnChangeEncPassword">Change Password</button>
|
|
<button class="btn btn-sm btn-danger" id="btnDisableEncryption">Disable</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Auth prompt — first-device setup (password + optional TOTP) -->
|
|
<div id="syncAuthPrompt" style="display:none;margin-top:10px;padding:10px;background:#fffbeb;border:1px solid #fcd34d;border-radius:6px">
|
|
<p style="font-size:12px;font-weight:500;margin:0 0 8px;color:#92400e">Authentication required</p>
|
|
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:end">
|
|
<input type="password" id="syncAuthPassword" placeholder="Password" autocomplete="current-password"
|
|
style="flex:1;min-width:120px;font-size:12px;padding:5px 8px;border:1px solid #d1d5db;border-radius:6px">
|
|
<input type="text" id="syncAuthTOTPForPassword" placeholder="TOTP code" autocomplete="one-time-code" inputmode="numeric" maxlength="6"
|
|
style="width:80px;font-size:12px;padding:5px 8px;border:1px solid #d1d5db;border-radius:6px;display:none">
|
|
<button class="btn btn-primary btn-sm" id="btnSyncAuth">Unlock</button>
|
|
</div>
|
|
<!-- Re-verify alternatives (shown when key exists but TTL expired) -->
|
|
<div id="reverifyOptions" style="display:none;margin-top:8px;padding-top:8px;border-top:1px solid #fde68a">
|
|
<p style="font-size:11px;color:#92400e;margin:0 0 6px">Or re-verify with any one of these:</p>
|
|
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:end">
|
|
<button class="btn btn-sm" id="btnSyncAuthBiometric" style="display:none">Biometric / PIN</button>
|
|
<div id="totpReverifyGroup" style="display:none;display:flex;gap:4px;align-items:end">
|
|
<input type="text" id="syncAuthTOTP" placeholder="TOTP code" autocomplete="one-time-code" inputmode="numeric" maxlength="6"
|
|
style="width:80px;font-size:12px;padding:5px 8px;border:1px solid #d1d5db;border-radius:6px">
|
|
<button class="btn btn-sm" id="btnSyncAuthTOTP">Verify</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="syncAuthStatus" style="font-size:11px;margin-top:4px;min-height:14px"></div>
|
|
</div>
|
|
|
|
<!-- TOTP setup result -->
|
|
<div id="totpSetupResult" style="display:none;margin-top:10px;padding:10px;background:#f0fdf4;border:1px solid #86efac;border-radius:6px">
|
|
<p style="font-size:12px;font-weight:500;margin:0 0 6px;color:#166534">TOTP Secret — save this in your authenticator app:</p>
|
|
<code id="totpSecretDisplay" style="font-size:13px;font-weight:600;letter-spacing:2px;display:block;margin-bottom:6px;word-break:break-all"></code>
|
|
<p style="font-size:11px;color:#6b7280;margin:0">Or use the otpauth URI: <code id="totpURIDisplay" style="font-size:10px;word-break:break-all"></code></p>
|
|
<button class="btn btn-sm" id="btnDismissTOTP" style="margin-top:8px">Done — I've saved it</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="syncEncStatus" style="font-size:12px;margin-top:6px;min-height:14px"></div>
|
|
</div>
|
|
|
|
<div class="setting-row">
|
|
<div>
|
|
<label>Browser account sync</label>
|
|
<p class="setting-desc">Automatically sync via your browser account (Firefox Sync / Chrome account). Works across devices using the same browser.</p>
|
|
</div>
|
|
<label class="toggle">
|
|
<input type="checkbox" id="browserSync">
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
</div>
|
|
|
|
<div style="margin-top:16px">
|
|
<h3 style="font-size:13px;font-weight:600;margin:0 0 4px">Sync Code — cross-browser copy-paste</h3>
|
|
<p class="section-desc" style="margin-bottom:8px">Generate a code in one browser, paste it in another. Newest data wins automatically.</p>
|
|
<div class="bulk-actions">
|
|
<button class="btn btn-primary" id="btnGenerateSyncCode">Generate Sync Code</button>
|
|
<button class="btn" id="btnImportSyncCode">Import from Code</button>
|
|
</div>
|
|
|
|
<div id="syncCodeDisplay" style="display:none;margin-top:10px">
|
|
<textarea id="syncCodeText" rows="3" style="width:100%;box-sizing:border-box;font-family:monospace;font-size:11px;resize:vertical;padding:6px;border:1px solid #d1d5db;border-radius:6px" readonly></textarea>
|
|
<div style="display:flex;align-items:center;gap:8px;margin-top:6px">
|
|
<button class="btn btn-primary" id="btnCopySyncCode">Copy to Clipboard</button>
|
|
<span id="syncCodeTime" style="font-size:11px;color:#6b7280"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="syncImportSection" style="display:none;margin-top:10px">
|
|
<textarea id="syncImportText" rows="3" placeholder="Paste sync code here…" style="width:100%;box-sizing:border-box;font-family:monospace;font-size:11px;resize:vertical;padding:6px;border:1px solid #d1d5db;border-radius:6px"></textarea>
|
|
<div style="display:flex;align-items:center;gap:8px;margin-top:6px;flex-wrap:wrap">
|
|
<button class="btn btn-primary" id="btnApplySyncCode">Apply</button>
|
|
<button class="btn" id="btnCancelSyncImport">Cancel</button>
|
|
<label style="font-size:12px;display:flex;align-items:center;gap:4px;cursor:pointer">
|
|
<input type="checkbox" id="syncForce"> Force (override if local is newer)
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="syncStatus" style="margin-top:8px;font-size:12px;min-height:16px"></div>
|
|
</div>
|
|
|
|
<div id="fileSyncSection" style="margin-top:20px;padding-top:16px;border-top:1px solid #e5e7eb">
|
|
<h3 style="font-size:13px;font-weight:600;margin:0 0 4px">Auto-Sync Folder — fully automatic, no copy-paste</h3>
|
|
<p class="section-desc" style="margin-bottom:8px">
|
|
Pick the same folder in each browser once. Changes are written to
|
|
<code>silent-send-sync.json</code> automatically whenever settings change,
|
|
and read back whenever this page is opened or regains focus.
|
|
Works with <strong>any cloud storage that has a desktop sync client</strong> —
|
|
Dropbox, OneDrive, Google Drive, iCloud Drive, Box, pCloud, Nextcloud,
|
|
Synology Drive, or any network share. Just pick the cloud-synced folder.
|
|
</p>
|
|
<div class="bulk-actions" style="align-items:center">
|
|
<button class="btn btn-primary" id="btnPickSyncFolder">Choose Sync Folder</button>
|
|
<span id="syncFolderName" style="font-size:12px;color:#6b7280;font-family:monospace"></span>
|
|
<button class="btn btn-danger btn-sm" id="btnClearSyncFolder" style="display:none">Clear</button>
|
|
</div>
|
|
<div id="fileSyncStatus" style="margin-top:6px;font-size:12px;min-height:16px"></div>
|
|
</div>
|
|
|
|
<div style="margin-top:20px;padding-top:16px;border-top:1px solid #e5e7eb">
|
|
<h3 style="font-size:13px;font-weight:600;margin:0 0 4px">GitHub Gist Sync — no desktop client needed</h3>
|
|
<p class="section-desc" style="margin-bottom:8px">
|
|
Store settings in a private GitHub Gist. Works across any browser or device
|
|
with just a GitHub account. Create a
|
|
<a href="https://github.com/settings/tokens/new?scopes=gist&description=SilentSend" target="_blank" rel="noopener">
|
|
Personal Access Token
|
|
</a>
|
|
with the <code>gist</code> scope, paste it below, and click Push.
|
|
The Gist ID is remembered — future pushes update the same Gist.
|
|
</p>
|
|
<div style="display:flex;gap:8px;margin-bottom:6px;flex-wrap:wrap">
|
|
<input type="password" id="gistToken" placeholder="GitHub PAT (ghp_…)" autocomplete="off"
|
|
style="flex:1;min-width:180px;font-family:monospace;font-size:12px;padding:5px 8px;border:1px solid #d1d5db;border-radius:6px">
|
|
<button class="btn btn-primary" id="btnGistPush">Push</button>
|
|
<button class="btn" id="btnGistPull">Pull</button>
|
|
</div>
|
|
<div id="gistSyncStatus" style="font-size:12px;min-height:16px"></div>
|
|
</div>
|
|
|
|
<!-- Auto Sync -->
|
|
<div style="margin-top:20px;padding-top:16px;border-top:1px solid #e5e7eb">
|
|
<h3 style="font-size:13px;font-weight:600;margin:0 0 4px">Auto Sync — works in all browsers</h3>
|
|
<p class="section-desc" style="margin-bottom:8px">
|
|
Automatically push and pull settings in the background on a schedule.
|
|
Uses GitHub Gist or Custom URL — configure one of those above first, then enable auto sync here.
|
|
Changes you make locally are pushed immediately; remote changes are pulled on the interval.
|
|
</p>
|
|
<div style="display:flex;gap:12px;flex-wrap:wrap;align-items:center;margin-bottom:8px">
|
|
<label class="toggle" title="Enable auto sync">
|
|
<input type="checkbox" id="autoSyncEnabled">
|
|
<span class="toggle-slider"></span>
|
|
</label>
|
|
<select id="autoSyncMethod" style="font-size:12px;padding:3px 6px;border:1px solid #d1d5db;border-radius:4px">
|
|
<option value="gist">GitHub Gist</option>
|
|
<option value="url">Custom URL</option>
|
|
</select>
|
|
<div style="display:flex;align-items:center;gap:4px">
|
|
<label style="font-size:12px;white-space:nowrap">Every</label>
|
|
<select id="autoSyncInterval" style="font-size:12px;padding:3px 6px;border:1px solid #d1d5db;border-radius:4px">
|
|
<option value="5">5 min</option>
|
|
<option value="15" selected>15 min</option>
|
|
<option value="30">30 min</option>
|
|
<option value="60">1 hour</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div id="autoSyncStatus" style="font-size:12px;min-height:16px"></div>
|
|
</div>
|
|
|
|
<div style="margin-top:20px;padding-top:16px;border-top:1px solid #e5e7eb">
|
|
<h3 style="font-size:13px;font-weight:600;margin:0 0 4px">Custom URL Sync</h3>
|
|
<p class="section-desc" style="margin-bottom:8px">
|
|
Any URL that supports HTTP GET (read) and PUT (write). Works with
|
|
Nextcloud/ownCloud WebDAV, a self-hosted server, or a cloud function.
|
|
Add custom headers (e.g. Authorization) as JSON if needed.
|
|
</p>
|
|
<div style="display:flex;gap:8px;margin-bottom:6px;flex-wrap:wrap">
|
|
<input type="url" id="customSyncUrl" placeholder="https://…/silent-send-sync.json"
|
|
style="flex:2;min-width:200px;font-size:12px;padding:5px 8px;border:1px solid #d1d5db;border-radius:6px">
|
|
<input type="text" id="customSyncHeaders" placeholder='{"Authorization":"Bearer …"}' autocomplete="off"
|
|
style="flex:1;min-width:160px;font-family:monospace;font-size:11px;padding:5px 8px;border:1px solid #d1d5db;border-radius:6px">
|
|
</div>
|
|
<div class="bulk-actions">
|
|
<button class="btn btn-primary" id="btnUrlPush">Push</button>
|
|
<button class="btn" id="btnUrlPull">Pull</button>
|
|
</div>
|
|
<div id="urlSyncStatus" style="margin-top:6px;font-size:12px;min-height:16px"></div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Sync Conflicts -->
|
|
<section class="section" id="conflictSection" style="display:none">
|
|
<h2 style="color:#b45309">Sync Conflicts</h2>
|
|
<p class="section-desc">Both this device and another device changed the same data. Choose which version to keep for each conflict.</p>
|
|
<div id="conflictList"></div>
|
|
</section>
|
|
|
|
<!-- Connected Devices -->
|
|
<section class="section">
|
|
<h2>Connected Devices</h2>
|
|
<p class="section-desc">Devices that sync with this extension. The device list is shared via sync data.</p>
|
|
<div style="display:flex;gap:8px;align-items:center;margin-bottom:10px">
|
|
<label style="font-size:12px;white-space:nowrap">This device:</label>
|
|
<input type="text" id="deviceName" placeholder="Device name" style="flex:1;font-size:12px;padding:5px 8px;border:1px solid #d1d5db;border-radius:6px">
|
|
<button class="btn btn-sm" id="btnRenameDevice">Rename</button>
|
|
</div>
|
|
<div id="deviceList" style="font-size:13px"></div>
|
|
</section>
|
|
|
|
<!-- Version History -->
|
|
<section class="section">
|
|
<h2>Version History</h2>
|
|
<p class="section-desc">Snapshots of your data are saved automatically on each sync. Restore a previous version if a sync overwrote something important.</p>
|
|
<div style="display:flex;gap:8px;align-items:center;margin-bottom:10px">
|
|
<label style="font-size:12px;white-space:nowrap">Max snapshots</label>
|
|
<input type="number" id="maxVersionHistory" class="input-small" min="3" max="50" value="10">
|
|
<button class="btn btn-sm btn-danger" id="btnClearVersionHistory">Clear History</button>
|
|
</div>
|
|
<div id="versionHistoryList" style="font-size:13px"></div>
|
|
</section>
|
|
|
|
<!-- Organization -->
|
|
<section class="section">
|
|
<h2>Organization</h2>
|
|
<p class="section-desc">Join an organization to receive required substitution rules and secret scanner patterns from your admin. Org rules merge with your personal rules and cannot be disabled.</p>
|
|
|
|
<div id="orgNotJoined">
|
|
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:8px">
|
|
<input type="text" id="orgInviteCode" placeholder="Invite code" style="flex:1;min-width:140px;font-size:12px;padding:5px 8px;border:1px solid #d1d5db;border-radius:6px;font-family:monospace">
|
|
<button class="btn btn-primary" id="btnJoinOrgCode">Join</button>
|
|
</div>
|
|
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:8px">
|
|
<input type="url" id="orgPolicyUrl" placeholder="Policy URL (https://…/policy.json)" style="flex:1;min-width:200px;font-size:12px;padding:5px 8px;border:1px solid #d1d5db;border-radius:6px">
|
|
<button class="btn" id="btnJoinOrgUrl">Join by URL</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="orgJoined" style="display:none">
|
|
<div style="padding:10px;background:#f0fdf4;border:1px solid #86efac;border-radius:6px;margin-bottom:8px">
|
|
<div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:8px">
|
|
<div>
|
|
<strong id="orgNameDisplay" style="font-size:13px"></strong>
|
|
<span id="orgPolicyVersion" style="font-size:11px;color:#6b7280;margin-left:6px"></span>
|
|
</div>
|
|
<button class="btn btn-sm btn-danger" id="btnLeaveOrg">Leave</button>
|
|
</div>
|
|
<div id="orgComplianceStatus" style="font-size:12px;margin-top:6px"></div>
|
|
<div id="orgRequiredMappings" style="font-size:11px;color:#6b7280;margin-top:4px"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="orgStatus" style="font-size:12px;min-height:16px"></div>
|
|
</section>
|
|
|
|
<section class="section">
|
|
<h2>Transfer Data</h2>
|
|
<p class="section-desc">Export all your identities, mappings, and settings to a file. Encrypted exports require a password to decrypt.</p>
|
|
<div class="bulk-actions">
|
|
<button class="btn" id="btnExportAll">Export All (plain)</button>
|
|
<button class="btn" id="btnExportEncrypted">Export Encrypted</button>
|
|
<button class="btn" id="btnImportAll">Import from File</button>
|
|
<input type="file" id="fileImportAll" accept=".json,.ssbackup" hidden>
|
|
</div>
|
|
|
|
<div style="margin-top:20px;padding-top:16px;border-top:1px solid #e5e7eb">
|
|
<h3 style="font-size:13px;font-weight:600;margin:0 0 4px">Bulk Import — populate from existing data</h3>
|
|
<p class="section-desc" style="margin-bottom:8px">
|
|
Import real values from a CSV, password manager export, or browser autofill export.
|
|
Passwords are <strong>never</strong> imported — only usernames, emails, names, and domains.
|
|
Imported values appear with blank substitutes so you can fill in fakes.
|
|
</p>
|
|
<div style="display:flex;gap:8px;margin-bottom:6px;flex-wrap:wrap;align-items:center">
|
|
<button class="btn btn-primary" id="btnBulkImport">Import CSV / Password Export</button>
|
|
<input type="file" id="fileBulkImport" accept=".csv,.tsv,.txt" hidden>
|
|
<span style="font-size:11px;color:#6b7280">Chrome passwords, Firefox logins, Bitwarden, 1Password, autofill, or plain CSV</span>
|
|
</div>
|
|
|
|
<div id="bulkImportPreview" style="display:none;margin-top:10px;padding:10px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px">
|
|
<h4 style="font-size:12px;font-weight:600;margin:0 0 8px">Import Preview</h4>
|
|
<div id="bulkImportSummary" style="font-size:12px;margin-bottom:8px"></div>
|
|
<div id="bulkImportItems" style="max-height:200px;overflow-y:auto;font-size:11px;margin-bottom:8px"></div>
|
|
<div style="display:flex;gap:8px">
|
|
<button class="btn btn-primary btn-sm" id="btnApplyBulkImport">Apply Import</button>
|
|
<button class="btn btn-sm" id="btnCancelBulkImport">Cancel</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="bulkImportStatus" style="font-size:12px;margin-top:6px;min-height:16px"></div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="section">
|
|
<h2>Mappings</h2>
|
|
<p class="section-desc">Manage all your substitution rules. Longer matches take priority.</p>
|
|
|
|
<div class="bulk-actions">
|
|
<button class="btn" id="btnExport">Export Mappings</button>
|
|
<button class="btn" id="btnImport">Import Mappings</button>
|
|
<input type="file" id="fileImport" accept=".json" hidden>
|
|
<button class="btn btn-danger" id="btnClearAll">Clear All</button>
|
|
</div>
|
|
|
|
<table class="mapping-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Real Value</th>
|
|
<th>Substitute</th>
|
|
<th>Category</th>
|
|
<th>Case</th>
|
|
<th>Enabled</th>
|
|
<th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="mappingTableBody">
|
|
</tbody>
|
|
</table>
|
|
|
|
<div class="add-row">
|
|
<input type="text" id="newReal" placeholder="Real value" class="input">
|
|
<input type="text" id="newSub" placeholder="Substitute" class="input">
|
|
<select id="newCategory" class="select">
|
|
<option value="name">Name</option>
|
|
<option value="email">Email</option>
|
|
<option value="phone">Phone</option>
|
|
<option value="address">Address</option>
|
|
<option value="ssn">SSN</option>
|
|
<option value="dob">DOB</option>
|
|
<option value="domain">Domain</option>
|
|
<option value="password">Password</option>
|
|
<option value="general">General</option>
|
|
</select>
|
|
<label class="checkbox-label">
|
|
<input type="checkbox" id="newCaseSensitive">
|
|
Aa
|
|
</label>
|
|
<button class="btn btn-primary" id="btnAddMapping">Add</button>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="section">
|
|
<h2>Passwords</h2>
|
|
<p class="section-desc">
|
|
Imported passwords are automatically redacted when sent to AI services.
|
|
Password values are hidden by default — enter your vault password to reveal them.
|
|
</p>
|
|
|
|
<div id="passwordsLocked" style="margin-bottom:12px">
|
|
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
|
<span style="font-size:12px;color:#6b7280">🔒 Password values are hidden</span>
|
|
<input type="password" id="passwordRevealKey" placeholder="Vault password to reveal" autocomplete="current-password"
|
|
style="font-size:12px;padding:5px 8px;border:1px solid #d1d5db;border-radius:6px;width:180px">
|
|
<button class="btn btn-sm" id="btnRevealPasswords">Reveal</button>
|
|
</div>
|
|
<div id="passwordRevealStatus" style="font-size:11px;margin-top:4px;min-height:14px"></div>
|
|
</div>
|
|
|
|
<div id="passwordsUnlocked" style="display:none;margin-bottom:12px">
|
|
<div style="display:flex;gap:8px;align-items:center">
|
|
<span style="font-size:12px;color:#b45309">🔓 Passwords visible</span>
|
|
<button class="btn btn-sm" id="btnHidePasswords">Hide</button>
|
|
</div>
|
|
</div>
|
|
|
|
<table class="mapping-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Password</th>
|
|
<th>Redacted As</th>
|
|
<th>Enabled</th>
|
|
<th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="passwordTableBody">
|
|
</tbody>
|
|
</table>
|
|
<div id="noPasswordsMsg" style="text-align:center;color:#9ca3af;padding:16px;font-size:13px;display:none">
|
|
No passwords imported. Use Transfer Data → Import to add passwords from your password manager.
|
|
</div>
|
|
</section>
|
|
|
|
<section class="section">
|
|
<h2>Custom Domains</h2>
|
|
<p class="section-desc">Add domains for self-hosted AI services (like OpenWebUI). The extension will activate on these domains in addition to the built-in ones.</p>
|
|
<div class="domain-list" id="domainList"></div>
|
|
<div class="add-row">
|
|
<input type="text" id="newDomain" placeholder="https://ai.myserver.com" class="input" style="flex:2">
|
|
<button class="btn btn-primary" id="btnAddDomain">Add Domain</button>
|
|
</div>
|
|
<p class="section-desc" style="margin-top:8px;margin-bottom:0">
|
|
When you click "Add Domain", your browser will ask you to confirm access. No extra steps needed.
|
|
</p>
|
|
</section>
|
|
|
|
<section class="section">
|
|
<h2>Activity Log</h2>
|
|
<div class="log-actions">
|
|
<span id="logCount">0 entries</span>
|
|
<button class="btn btn-danger" id="btnClearLog">Clear Log</button>
|
|
</div>
|
|
<div class="log-list" id="logList"></div>
|
|
</section>
|
|
|
|
<section class="section">
|
|
<h2>Danger Zone</h2>
|
|
|
|
<!-- Tamper Protection -->
|
|
<div style="margin-bottom:16px;padding:12px;background:#fef2f2;border:1px solid #fecaca;border-radius:8px">
|
|
<h3 style="font-size:13px;font-weight:600;margin:0 0 6px">Tamper Protection</h3>
|
|
<p class="section-desc" style="margin-bottom:8px">
|
|
Require a separate admin password to disable the extension, clear data, or change org settings.
|
|
This is a deterrent — it cannot prevent browser-level uninstall or dev tools access.
|
|
</p>
|
|
<div id="tamperNotEnabled">
|
|
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:end">
|
|
<input type="password" id="tamperAdminPassword" placeholder="Admin password" autocomplete="new-password"
|
|
style="flex:1;min-width:120px;font-size:12px;padding:5px 8px;border:1px solid #d1d5db;border-radius:6px">
|
|
<input type="password" id="tamperAdminPasswordConfirm" placeholder="Confirm" autocomplete="new-password"
|
|
style="flex:1;min-width:120px;font-size:12px;padding:5px 8px;border:1px solid #d1d5db;border-radius:6px">
|
|
<button class="btn btn-primary btn-sm" id="btnEnableTamper">Enable</button>
|
|
</div>
|
|
</div>
|
|
<div id="tamperEnabled" style="display:none">
|
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
|
<span style="font-size:12px;color:#dc2626;font-weight:500">🔒 Active</span>
|
|
<button class="btn btn-sm" id="btnChangeTamperPassword">Change Password</button>
|
|
<button class="btn btn-sm btn-danger" id="btnDisableTamper">Disable</button>
|
|
</div>
|
|
</div>
|
|
<div id="tamperStatus" style="font-size:12px;margin-top:4px;min-height:14px"></div>
|
|
</div>
|
|
|
|
<!-- Admin auth dialog (reusable prompt for protected actions) -->
|
|
<dialog id="adminAuthDialog" style="border:1px solid #d1d5db;border-radius:8px;padding:20px;max-width:300px">
|
|
<h3 style="margin:0 0 8px;font-size:14px">Admin Password Required</h3>
|
|
<p id="adminAuthReason" style="font-size:12px;color:#6b7280;margin:0 0 12px"></p>
|
|
<input type="password" id="adminAuthInput" placeholder="Admin password" autocomplete="current-password"
|
|
style="width:100%;box-sizing:border-box;font-size:13px;padding:8px;border:1px solid #d1d5db;border-radius:6px;margin-bottom:8px">
|
|
<div style="display:flex;gap:8px;justify-content:flex-end">
|
|
<button class="btn btn-sm" id="btnAdminAuthCancel">Cancel</button>
|
|
<button class="btn btn-primary btn-sm" id="btnAdminAuthSubmit">Confirm</button>
|
|
</div>
|
|
<div id="adminAuthStatus" style="font-size:11px;margin-top:4px;min-height:14px;color:#dc2626"></div>
|
|
</dialog>
|
|
|
|
<div class="setting-row">
|
|
<div>
|
|
<label>Reset all data</label>
|
|
<p class="setting-desc">Clears all identities, mappings, settings, and logs. Cannot be undone.</p>
|
|
</div>
|
|
<button class="btn btn-danger" id="btnResetAll">Reset Everything</button>
|
|
</div>
|
|
</section>
|
|
|
|
<footer>
|
|
<p>Silent Send v2.0.11</p>
|
|
</footer>
|
|
</div>
|
|
|
|
<script src="options.js" type="module"></script>
|
|
</body>
|
|
</html>
|