Merge pull request #65 from outis1one/claude/read-repo-yLNcT
Claude/read repo y l nc t
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "Silent Send",
|
"name": "Silent Send",
|
||||||
"version": "0.9.32",
|
"version": "0.9.33",
|
||||||
"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": "0.9.32",
|
"version": "0.9.33",
|
||||||
"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": "0.9.32",
|
"version": "0.9.33",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"description": "Browser extension that substitutes personal data before sending to AI services",
|
"description": "Browser extension that substitutes personal data before sending to AI services",
|
||||||
|
|||||||
@@ -184,6 +184,23 @@ const messageHandlers = {
|
|||||||
sendResponse({ locked });
|
sendResponse({ locked });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Content script requests decrypted data on page load when it sees
|
||||||
|
// encrypted storage but the key is already cached (e.g. after a sync import).
|
||||||
|
async 'vault:request-unlock'(_message, sender) {
|
||||||
|
const locked = await Storage.isLocked();
|
||||||
|
if (locked) return; // key not available — user must unlock via popup
|
||||||
|
|
||||||
|
const mappings = await Storage.getMappings();
|
||||||
|
const identity = await Storage.getIdentity();
|
||||||
|
const settings = await Storage.getSettings();
|
||||||
|
api.tabs.sendMessage(sender.tab.id, {
|
||||||
|
type: 'vault:unlocked',
|
||||||
|
mappings,
|
||||||
|
identity,
|
||||||
|
settings,
|
||||||
|
}).catch(() => {});
|
||||||
|
},
|
||||||
|
|
||||||
async 'vault:unlocked'() {
|
async 'vault:unlocked'() {
|
||||||
// User unlocked the vault — clear the LOCK badge and refresh icon
|
// User unlocked the vault — clear the LOCK badge and refresh icon
|
||||||
api.action.setBadgeText({ text: '' });
|
api.action.setBadgeText({ text: '' });
|
||||||
|
|||||||
@@ -60,13 +60,19 @@
|
|||||||
const result = await api.storage.local.get(['ss_mappings', 'ss_identity', 'ss_settings']);
|
const result = await api.storage.local.get(['ss_mappings', 'ss_identity', 'ss_settings']);
|
||||||
const settings = result.ss_settings || { enabled: true };
|
const settings = result.ss_settings || { enabled: true };
|
||||||
|
|
||||||
// Check if data is encrypted (locked) — pass empty config
|
// Check if data is encrypted — pass empty config and request decryption
|
||||||
// The background will send decrypted data via vault:unlocked when ready
|
// The background will send decrypted data via vault:unlocked when ready
|
||||||
const isLocked = result.ss_mappings?._ssLocalEncrypted ||
|
const isLocked = result.ss_mappings?._ssLocalEncrypted ||
|
||||||
result.ss_identity?._ssLocalEncrypted;
|
result.ss_identity?._ssLocalEncrypted;
|
||||||
const mappings = isLocked ? [] : (result.ss_mappings || []);
|
const mappings = isLocked ? [] : (result.ss_mappings || []);
|
||||||
const identityData = isLocked ? {} : (result.ss_identity || {});
|
const identityData = isLocked ? {} : (result.ss_identity || {});
|
||||||
|
|
||||||
|
// If data is encrypted but the vault key may already be cached
|
||||||
|
// (e.g. after a sync import), ask the background to push decrypted data
|
||||||
|
if (isLocked) {
|
||||||
|
api.runtime.sendMessage({ type: 'vault:request-unlock' }).catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
// Merge active profiles into a flat identity object for the content script
|
// Merge active profiles into a flat identity object for the content script
|
||||||
const identity = mergeProfiles(identityData);
|
const identity = mergeProfiles(identityData);
|
||||||
|
|
||||||
|
|||||||
+5
-2
@@ -901,7 +901,7 @@ const SilentSendSync = {
|
|||||||
const result = await api.storage.local.get('ss_lastModified');
|
const result = await api.storage.local.get('ss_lastModified');
|
||||||
return {
|
return {
|
||||||
version: '1',
|
version: '1',
|
||||||
lastModified: result.ss_lastModified || Date.now(),
|
lastModified: result.ss_lastModified || 0,
|
||||||
identity: identity || {},
|
identity: identity || {},
|
||||||
mappings: mappings || [],
|
mappings: mappings || [],
|
||||||
settings: settings || {},
|
settings: settings || {},
|
||||||
@@ -924,9 +924,12 @@ const SilentSendSync = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Metadata stays plaintext
|
// Metadata stays plaintext
|
||||||
|
const now = Date.now();
|
||||||
await api.storage.local.set({
|
await api.storage.local.set({
|
||||||
ss_lastModified: data.lastModified,
|
ss_lastModified: data.lastModified,
|
||||||
ss_sync_notification: { source, time: Date.now() },
|
ss_sync_notification: { source, time: now },
|
||||||
|
ss_last_pull_time: now,
|
||||||
|
ss_last_pull_source: source,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
+10
-2
@@ -161,9 +161,13 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
// --- GitHub Gist sync ---
|
// --- GitHub Gist sync ---
|
||||||
// Restore saved token (session only — never persisted to storage)
|
// Restore saved token (session only — never persisted to storage)
|
||||||
{
|
{
|
||||||
const stored = await api.storage.local.get('ss_gist_id');
|
const stored = await api.storage.local.get(['ss_gist_id', 'ss_last_pull_time', 'ss_last_pull_source']);
|
||||||
if (stored.ss_gist_id) {
|
if (stored.ss_gist_id) {
|
||||||
setGistSyncStatus(`Gist ID: ${stored.ss_gist_id.slice(0, 12)}…`, 'ok');
|
let status = `Gist ID: ${stored.ss_gist_id.slice(0, 12)}…`;
|
||||||
|
if (stored.ss_last_pull_time && stored.ss_last_pull_source === 'gist') {
|
||||||
|
status += ` · Last pulled: ${new Date(stored.ss_last_pull_time).toLocaleString()}`;
|
||||||
|
}
|
||||||
|
setGistSyncStatus(status, 'ok');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,6 +201,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
setGistSyncStatus('Pull failed: ' + r2.reason, 'error');
|
setGistSyncStatus('Pull failed: ' + r2.reason, 'error');
|
||||||
} else if (r2.imported) {
|
} else if (r2.imported) {
|
||||||
setGistSyncStatus(`Pulled (${r2.time}). Refreshing…`, 'ok');
|
setGistSyncStatus(`Pulled (${r2.time}). Refreshing…`, 'ok');
|
||||||
|
api.runtime.sendMessage({ type: 'vault:unlocked' }).catch(() => {});
|
||||||
mappings = await Storage.getMappings();
|
mappings = await Storage.getMappings();
|
||||||
settings = await Storage.getSettings();
|
settings = await Storage.getSettings();
|
||||||
renderMappings();
|
renderMappings();
|
||||||
@@ -211,6 +216,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
setGistSyncStatus('Pull failed: ' + r.reason, 'error');
|
setGistSyncStatus('Pull failed: ' + r.reason, 'error');
|
||||||
} else if (r.imported) {
|
} else if (r.imported) {
|
||||||
setGistSyncStatus(`Pulled (${r.time}). Refreshing…`, 'ok');
|
setGistSyncStatus(`Pulled (${r.time}). Refreshing…`, 'ok');
|
||||||
|
api.runtime.sendMessage({ type: 'vault:unlocked' }).catch(() => {});
|
||||||
mappings = await Storage.getMappings();
|
mappings = await Storage.getMappings();
|
||||||
settings = await Storage.getSettings();
|
settings = await Storage.getSettings();
|
||||||
renderMappings();
|
renderMappings();
|
||||||
@@ -254,6 +260,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
setUrlSyncStatus('Pull failed: ' + r2.reason, 'error');
|
setUrlSyncStatus('Pull failed: ' + r2.reason, 'error');
|
||||||
} else if (r2.imported) {
|
} else if (r2.imported) {
|
||||||
setUrlSyncStatus(`Pulled (${r2.time}). Refreshing…`, 'ok');
|
setUrlSyncStatus(`Pulled (${r2.time}). Refreshing…`, 'ok');
|
||||||
|
api.runtime.sendMessage({ type: 'vault:unlocked' }).catch(() => {});
|
||||||
mappings = await Storage.getMappings();
|
mappings = await Storage.getMappings();
|
||||||
settings = await Storage.getSettings();
|
settings = await Storage.getSettings();
|
||||||
renderMappings();
|
renderMappings();
|
||||||
@@ -268,6 +275,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
setUrlSyncStatus('Pull failed: ' + r.reason, 'error');
|
setUrlSyncStatus('Pull failed: ' + r.reason, 'error');
|
||||||
} else if (r.imported) {
|
} else if (r.imported) {
|
||||||
setUrlSyncStatus(`Pulled (${r.time}). Refreshing…`, 'ok');
|
setUrlSyncStatus(`Pulled (${r.time}). Refreshing…`, 'ok');
|
||||||
|
api.runtime.sendMessage({ type: 'vault:unlocked' }).catch(() => {});
|
||||||
mappings = await Storage.getMappings();
|
mappings = await Storage.getMappings();
|
||||||
settings = await Storage.getSettings();
|
settings = await Storage.getSettings();
|
||||||
renderMappings();
|
renderMappings();
|
||||||
|
|||||||
Reference in New Issue
Block a user