Merge pull request #30 from outis1one/claude/read-repo-wA3y1
Claude/read repo w a3y1
This commit is contained in:
@@ -7,7 +7,7 @@ A browser extension (Chrome, Firefox, and Safari) that intercepts personal infor
|
|||||||
| Service | Domains | Status |
|
| Service | Domains | Status |
|
||||||
|---------|---------|--------|
|
|---------|---------|--------|
|
||||||
| Claude | claude.ai, claude.ai/code | Tested |
|
| Claude | claude.ai, claude.ai/code | Tested |
|
||||||
| ChatGPT | chatgpt.com, chat.openai.com | Untested |
|
| ChatGPT | chatgpt.com, chat.openai.com | Tested |
|
||||||
| Grok | grok.x.ai, x.com/i/grok | Untested |
|
| Grok | grok.x.ai, x.com/i/grok | Untested |
|
||||||
| Gemini | gemini.google.com | Untested |
|
| Gemini | gemini.google.com | Untested |
|
||||||
| OpenWebUI | localhost, 127.0.0.1, or custom domain | Untested |
|
| OpenWebUI | localhost, 127.0.0.1, or custom domain | Untested |
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "Silent Send",
|
"name": "Silent Send",
|
||||||
"version": "2.0.13",
|
"version": "2.0.14",
|
||||||
"description": "Intercepts personal info and substitutes it with user-defined replacements before sending to AI services.",
|
"description": "Intercepts personal info and substitutes it with user-defined replacements before sending to AI services.",
|
||||||
"browser_specific_settings": {
|
"browser_specific_settings": {
|
||||||
"gecko": {
|
"gecko": {
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "Silent Send",
|
"name": "Silent Send",
|
||||||
"version": "2.0.13",
|
"version": "2.0.14",
|
||||||
"description": "Intercepts personal info and substitutes it with user-defined replacements before sending to AI services.",
|
"description": "Intercepts personal info and substitutes it with user-defined replacements before sending to AI services.",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"storage",
|
"storage",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "silent-send",
|
"name": "silent-send",
|
||||||
"version": "2.0.13",
|
"version": "2.0.14",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "BSL-1.1",
|
"license": "BSL-1.1",
|
||||||
"description": "Browser extension that substitutes personal data before sending to AI services",
|
"description": "Browser extension that substitutes personal data before sending to AI services",
|
||||||
|
|||||||
@@ -221,13 +221,14 @@
|
|||||||
.ss-ps-add:disabled { border-color: #333; cursor: default; }
|
.ss-ps-add:disabled { border-color: #333; cursor: default; }
|
||||||
|
|
||||||
.ss-ps-ignore {
|
.ss-ps-ignore {
|
||||||
background: none;
|
background: #4b5563;
|
||||||
border: none;
|
border: none;
|
||||||
color: #6b7280;
|
color: #d1d5db;
|
||||||
font-size: 9px;
|
font-size: 9px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
padding: 2px 4px;
|
padding: 3px 6px;
|
||||||
|
border-radius: 3px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-17
@@ -578,7 +578,7 @@
|
|||||||
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);
|
||||||
|
|
||||||
// Build skip set from configured values
|
// Build skip set from configured values (identity + explicit mappings)
|
||||||
const configured = new Set();
|
const configured = new Set();
|
||||||
if (ident) {
|
if (ident) {
|
||||||
const addAll = (arr, key) => (arr || []).forEach(item => {
|
const addAll = (arr, key) => (arr || []).forEach(item => {
|
||||||
@@ -588,6 +588,11 @@
|
|||||||
addAll(ident.names); addAll(ident.emails);
|
addAll(ident.names); addAll(ident.emails);
|
||||||
addAll(ident.usernames); addAll(ident.hostnames); addAll(ident.phones);
|
addAll(ident.usernames); addAll(ident.hostnames); addAll(ident.phones);
|
||||||
}
|
}
|
||||||
|
// Also skip values that are already in explicit mappings
|
||||||
|
for (const m of mappings) {
|
||||||
|
if (m.real) configured.add(m.real.toLowerCase());
|
||||||
|
if (m.substitute) configured.add(m.substitute.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
const findings = [];
|
const findings = [];
|
||||||
for (const pat of PPI_PATTERNS) {
|
for (const pat of PPI_PATTERNS) {
|
||||||
@@ -1548,8 +1553,8 @@
|
|||||||
function revealInElement(el) {
|
function revealInElement(el) {
|
||||||
if (SKIP_REVEAL_TAGS.has(el.tagName)) return;
|
if (SKIP_REVEAL_TAGS.has(el.tagName)) return;
|
||||||
if (el.classList?.contains('ss-reveal-badge')) return;
|
if (el.classList?.contains('ss-reveal-badge')) return;
|
||||||
// Never touch contenteditable elements (chat input boxes)
|
|
||||||
if (el.isContentEditable) return;
|
if (el.isContentEditable) return;
|
||||||
|
if (isInNonChatArea(el)) return;
|
||||||
|
|
||||||
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, {
|
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, {
|
||||||
acceptNode(node) {
|
acceptNode(node) {
|
||||||
@@ -1557,6 +1562,7 @@
|
|||||||
if (parent && SKIP_REVEAL_TAGS.has(parent.tagName)) return NodeFilter.FILTER_REJECT;
|
if (parent && SKIP_REVEAL_TAGS.has(parent.tagName)) return NodeFilter.FILTER_REJECT;
|
||||||
if (parent?.closest?.('.ss-autodetect-warning, .ss-presend-warning, .ss-reveal-badge')) return NodeFilter.FILTER_REJECT;
|
if (parent?.closest?.('.ss-autodetect-warning, .ss-presend-warning, .ss-reveal-badge')) return NodeFilter.FILTER_REJECT;
|
||||||
if (parent?.closest?.('[contenteditable="true"]')) return NodeFilter.FILTER_REJECT;
|
if (parent?.closest?.('[contenteditable="true"]')) return NodeFilter.FILTER_REJECT;
|
||||||
|
if (isInNonChatArea(parent)) return NodeFilter.FILTER_REJECT;
|
||||||
return NodeFilter.FILTER_ACCEPT;
|
return NodeFilter.FILTER_ACCEPT;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1576,11 +1582,13 @@
|
|||||||
function unrevealInElement(el) {
|
function unrevealInElement(el) {
|
||||||
if (SKIP_REVEAL_TAGS.has(el.tagName)) return;
|
if (SKIP_REVEAL_TAGS.has(el.tagName)) return;
|
||||||
if (el.isContentEditable) return;
|
if (el.isContentEditable) return;
|
||||||
|
if (isInNonChatArea(el)) return;
|
||||||
|
|
||||||
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, {
|
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, {
|
||||||
acceptNode(node) {
|
acceptNode(node) {
|
||||||
const parent = node.parentElement;
|
const parent = node.parentElement;
|
||||||
if (parent?.closest?.('[contenteditable="true"]')) return NodeFilter.FILTER_REJECT;
|
if (parent?.closest?.('[contenteditable="true"]')) return NodeFilter.FILTER_REJECT;
|
||||||
|
if (isInNonChatArea(parent)) return NodeFilter.FILTER_REJECT;
|
||||||
return NodeFilter.FILTER_ACCEPT;
|
return NodeFilter.FILTER_ACCEPT;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1615,6 +1623,7 @@
|
|||||||
if (parent && SKIP_REVEAL_TAGS.has(parent.tagName)) return NodeFilter.FILTER_REJECT;
|
if (parent && SKIP_REVEAL_TAGS.has(parent.tagName)) return NodeFilter.FILTER_REJECT;
|
||||||
if (parent?.closest?.('.ss-autodetect-warning, .ss-presend-warning, .ss-reveal-badge')) return NodeFilter.FILTER_REJECT;
|
if (parent?.closest?.('.ss-autodetect-warning, .ss-presend-warning, .ss-reveal-badge')) return NodeFilter.FILTER_REJECT;
|
||||||
if (parent?.closest?.('[contenteditable="true"]')) return NodeFilter.FILTER_REJECT;
|
if (parent?.closest?.('[contenteditable="true"]')) return NodeFilter.FILTER_REJECT;
|
||||||
|
if (isInNonChatArea(parent)) return NodeFilter.FILTER_REJECT;
|
||||||
return NodeFilter.FILTER_ACCEPT;
|
return NodeFilter.FILTER_ACCEPT;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1653,11 +1662,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Elements to skip when revealing (inputs, scripts, styles, extension UI)
|
// Elements to skip when revealing (inputs, scripts, styles, extension UI, navigation)
|
||||||
const SKIP_REVEAL_TAGS = new Set([
|
const SKIP_REVEAL_TAGS = new Set([
|
||||||
'SCRIPT', 'STYLE', 'NOSCRIPT', 'IFRAME', 'INPUT', 'TEXTAREA', 'SELECT',
|
'SCRIPT', 'STYLE', 'NOSCRIPT', 'IFRAME', 'INPUT', 'TEXTAREA', 'SELECT',
|
||||||
|
'NAV', 'ASIDE', 'HEADER', 'FOOTER',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Skip reveal in navigation, sidebars, headers, and other non-chat UI
|
||||||
|
function isInNonChatArea(el) {
|
||||||
|
if (!el) return false;
|
||||||
|
return !!el.closest('nav, aside, header, footer, [role="navigation"], [role="banner"], [role="complementary"], [data-sidebar], [class*="sidebar"], [class*="Sidebar"], [class*="nav-"], [class*="Nav"], [class*="menu"], [class*="Menu"], [class*="header"], [class*="Header"]');
|
||||||
|
}
|
||||||
|
|
||||||
// Reveal ALL text on the page + apply highlights
|
// Reveal ALL text on the page + apply highlights
|
||||||
function revealAllResponses() {
|
function revealAllResponses() {
|
||||||
revealInElement(document.body);
|
revealInElement(document.body);
|
||||||
@@ -1695,10 +1711,11 @@
|
|||||||
// Only do text replacement in reveal mode
|
// Only do text replacement in reveal mode
|
||||||
if (settings.revealMode) {
|
if (settings.revealMode) {
|
||||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||||
// Skip contenteditable (chat input) and skipped tags
|
// Skip non-chat areas, contenteditable, and skipped tags
|
||||||
if (!SKIP_REVEAL_TAGS.has(node.tagName) &&
|
if (!SKIP_REVEAL_TAGS.has(node.tagName) &&
|
||||||
!node.isContentEditable &&
|
!node.isContentEditable &&
|
||||||
!node.closest?.('[contenteditable="true"]')) {
|
!node.closest?.('[contenteditable="true"]') &&
|
||||||
|
!isInNonChatArea(node)) {
|
||||||
revealInElement(node);
|
revealInElement(node);
|
||||||
}
|
}
|
||||||
} else if (node.nodeType === Node.TEXT_NODE) {
|
} else if (node.nodeType === Node.TEXT_NODE) {
|
||||||
@@ -1848,13 +1865,12 @@
|
|||||||
const items = warnings.slice(0, 8).map((w, i) => {
|
const items = warnings.slice(0, 8).map((w, i) => {
|
||||||
const fake = generateFake(w.name, w.value);
|
const fake = generateFake(w.name, w.value);
|
||||||
const displayVal = w.value.length > 25 ? w.value.slice(0, 22) + '...' : w.value;
|
const displayVal = w.value.length > 25 ? w.value.slice(0, 22) + '...' : w.value;
|
||||||
|
const displayFake = fake.length > 20 ? fake.slice(0, 17) + '...' : fake;
|
||||||
return `<div class="ss-ps-item">
|
return `<div class="ss-ps-item">
|
||||||
<span class="ss-ps-type">${w.name}</span>
|
<span class="ss-ps-type">${w.name}</span>
|
||||||
<code class="ss-ps-value">${displayVal}</code>
|
<code class="ss-ps-value">${displayVal}</code>
|
||||||
<span class="ss-ps-hint">${w.hint}</span>
|
<span class="ss-ps-hint">${w.hint}</span>
|
||||||
${settings.autoAddDetected !== false
|
<button class="ss-ps-add" data-real="${encodeURIComponent(w.value)}" data-fake="${encodeURIComponent(fake)}" data-cat="${w.category}" title="Add mapping: ${displayVal} → ${displayFake}">+</button>
|
||||||
? `<button class="ss-ps-add" data-real="${encodeURIComponent(w.value)}" data-fake="${encodeURIComponent(fake)}" data-cat="${w.category}" title="Add mapping: ${displayVal} → ${fake}">+</button>`
|
|
||||||
: ''}
|
|
||||||
<button class="ss-ps-ignore" data-value="${encodeURIComponent(w.value)}" title="Never flag this value again">ignore</button>
|
<button class="ss-ps-ignore" data-value="${encodeURIComponent(w.value)}" title="Never flag this value again">ignore</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
@@ -1881,28 +1897,26 @@
|
|||||||
preSendWarningEl.classList.remove('visible');
|
preSendWarningEl.classList.remove('visible');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Auto-add buttons
|
// Auto-add buttons (+)
|
||||||
preSendWarningEl.querySelectorAll('.ss-ps-add').forEach(btn => {
|
preSendWarningEl.querySelectorAll('.ss-ps-add').forEach(btn => {
|
||||||
btn.addEventListener('click', async () => {
|
btn.addEventListener('click', async () => {
|
||||||
const real = decodeURIComponent(btn.dataset.real);
|
const real = decodeURIComponent(btn.dataset.real);
|
||||||
const fake = decodeURIComponent(btn.dataset.fake);
|
const fake = decodeURIComponent(btn.dataset.fake);
|
||||||
const cat = btn.dataset.cat || 'general';
|
const cat = btn.dataset.cat || 'general';
|
||||||
|
|
||||||
// Add to mappings via storage
|
// Add to local mappings array (used by the fetch interceptor)
|
||||||
const result = await getStorageData('ss_mappings');
|
const newMapping = {
|
||||||
const currentMappings = result || [];
|
|
||||||
currentMappings.push({
|
|
||||||
id: crypto.randomUUID(),
|
id: crypto.randomUUID(),
|
||||||
real, substitute: fake,
|
real, substitute: fake,
|
||||||
category: cat,
|
category: cat,
|
||||||
caseSensitive: false,
|
caseSensitive: false,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
});
|
};
|
||||||
await setStorageData('ss_mappings', currentMappings);
|
mappings.push(newMapping);
|
||||||
|
|
||||||
// Update local mappings so the fetch interceptor uses them immediately
|
// Persist via storage bridge (handles encryption transparently)
|
||||||
mappings = currentMappings;
|
setStorageData('ss_mappings', mappings);
|
||||||
|
|
||||||
// Replace the PPI value in the current input right now
|
// Replace the PPI value in the current input right now
|
||||||
if (inputEl) {
|
if (inputEl) {
|
||||||
|
|||||||
@@ -591,7 +591,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<p>Silent Send v2.0.13</p>
|
<p>Silent Send v2.0.14</p>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -262,7 +262,6 @@
|
|||||||
PPI in images, file uploads, unusual name forms, or data you forgot to
|
PPI 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>
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user