04/16 Upload codebase
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* extension/background.js — Manifest V3 service worker.
|
||||
*
|
||||
* Responsibilities:
|
||||
* - Update the action badge (number of matching vault items) for the active tab.
|
||||
* - Bridge SAVE_CREDENTIALS messages from content script → chrome.storage.session
|
||||
* so the popup can pick them up as a save-prompt.
|
||||
* - Re-update badges when the vault cache changes.
|
||||
*/
|
||||
|
||||
// ── Badge helpers ────────────────────────────────────────────────────────────
|
||||
|
||||
async function updateBadgeForTab(tabId, url) {
|
||||
try {
|
||||
const { vault_items } = await chrome.storage.session.get('vault_items');
|
||||
if (!vault_items?.length) {
|
||||
chrome.action.setBadgeText({ text: '', tabId });
|
||||
return;
|
||||
}
|
||||
|
||||
let hostname;
|
||||
try { hostname = new URL(url).hostname.replace(/^www\./, ''); }
|
||||
catch { chrome.action.setBadgeText({ text: '', tabId }); return; }
|
||||
|
||||
const matches = vault_items.filter(item => {
|
||||
if (item.item_type !== 'password' || !item.plain?.url) return false;
|
||||
try {
|
||||
const h = new URL(item.plain.url).hostname.replace(/^www\./, '');
|
||||
return h === hostname || h.endsWith(`.${hostname}`) || hostname.endsWith(`.${h}`);
|
||||
} catch { return false; }
|
||||
});
|
||||
|
||||
if (matches.length > 0) {
|
||||
chrome.action.setBadgeText({ text: String(matches.length), tabId });
|
||||
chrome.action.setBadgeBackgroundColor({ color: '#1a73e8', tabId });
|
||||
} else {
|
||||
chrome.action.setBadgeText({ text: '', tabId });
|
||||
}
|
||||
} catch { /* tab may have closed */ }
|
||||
}
|
||||
|
||||
async function refreshAllBadges() {
|
||||
const tabs = await chrome.tabs.query({});
|
||||
for (const tab of tabs) {
|
||||
if (tab.url?.startsWith('http')) updateBadgeForTab(tab.id, tab.url);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Tab events ───────────────────────────────────────────────────────────────
|
||||
|
||||
chrome.tabs.onActivated.addListener(async ({ tabId }) => {
|
||||
try {
|
||||
const tab = await chrome.tabs.get(tabId);
|
||||
if (tab.url?.startsWith('http')) updateBadgeForTab(tabId, tab.url);
|
||||
} catch {}
|
||||
});
|
||||
|
||||
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
|
||||
if (changeInfo.status === 'complete' && tab.url?.startsWith('http')) {
|
||||
updateBadgeForTab(tabId, tab.url);
|
||||
}
|
||||
});
|
||||
|
||||
// ── Message handler ──────────────────────────────────────────────────────────
|
||||
|
||||
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
|
||||
// Popup signals vault cache was refreshed → re-check all tab badges.
|
||||
if (msg.type === 'VAULT_UPDATED') {
|
||||
refreshAllBadges();
|
||||
sendResponse({ ok: true });
|
||||
return false;
|
||||
}
|
||||
|
||||
// Content script detected credentials on form submit → store for save-prompt.
|
||||
if (msg.type === 'SAVE_CREDENTIALS') {
|
||||
chrome.storage.session.set({ pending_save: msg.data });
|
||||
sendResponse({ ok: true });
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bridge: web app logged in → store tokens in extension storage.
|
||||
if (msg.type === 'WEB_SESSION_SYNC') {
|
||||
chrome.storage.session.set({
|
||||
access_token: msg.access_token,
|
||||
enc_key_salt: msg.enc_key_salt || '',
|
||||
});
|
||||
// Also persist enc_key_salt locally so the unlock-only view survives browser restarts
|
||||
chrome.storage.local.set({
|
||||
refresh_token: msg.refresh_token,
|
||||
...(msg.enc_key_salt ? { enc_key_salt: msg.enc_key_salt } : {}),
|
||||
});
|
||||
sendResponse({ ok: true });
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bridge: web app logged out → clear extension session.
|
||||
if (msg.type === 'WEB_SESSION_CLEAR') {
|
||||
chrome.storage.session.remove(['access_token', 'vault_key_jwk', 'vault_items', 'enc_key_salt']);
|
||||
chrome.storage.local.remove('refresh_token');
|
||||
sendResponse({ ok: true });
|
||||
return false;
|
||||
}
|
||||
|
||||
// Popup logged in via extension → inject session into open vault tabs.
|
||||
if (msg.type === 'EXT_SESSION_SYNC') {
|
||||
chrome.tabs.query({ url: 'https://pwkeeper.ngodanguyen.tech/*' }, tabs => {
|
||||
tabs.forEach(tab => {
|
||||
chrome.tabs.sendMessage(tab.id, {
|
||||
type: 'INJECT_SESSION',
|
||||
access_token: msg.access_token,
|
||||
refresh_token: msg.refresh_token,
|
||||
enc_key_salt: msg.enc_key_salt,
|
||||
}).catch(() => {});
|
||||
});
|
||||
});
|
||||
sendResponse({ ok: true });
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
Reference in New Issue
Block a user