04/16 Upload codebase
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* extension/bridge/bridge.js
|
||||
*
|
||||
* Content script injected ONLY on pwkeeper.ngodanguyen.tech.
|
||||
*
|
||||
* Web app → Extension:
|
||||
* Listens for the 'passkeeper:session' custom event dispatched by auth.js
|
||||
* after login, and forwards access_token + refresh_token + enc_key_salt to
|
||||
* the background service worker via chrome.runtime.sendMessage.
|
||||
*
|
||||
* Extension → Web app:
|
||||
* Listens for INJECT_SESSION messages from the background (triggered when the
|
||||
* user logs in through the popup). Writes tokens into the web app's storage
|
||||
* and fires 'passkeeper:ext-login' so auth.js can unlock the vault overlay.
|
||||
*/
|
||||
(() => {
|
||||
'use strict';
|
||||
|
||||
// ── Web app → Extension ────────────────────────────────────────────────────
|
||||
|
||||
function syncToExtension(access_token, refresh_token, enc_key_salt) {
|
||||
if (!access_token || !refresh_token) return;
|
||||
chrome.runtime.sendMessage({
|
||||
type: 'WEB_SESSION_SYNC',
|
||||
access_token,
|
||||
refresh_token,
|
||||
enc_key_salt: enc_key_salt || '',
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
// Fired by auth.js completeLogin
|
||||
window.addEventListener('passkeeper:session', e => {
|
||||
const { access_token, refresh_token, enc_key_salt } = e.detail || {};
|
||||
syncToExtension(access_token, refresh_token, enc_key_salt);
|
||||
});
|
||||
|
||||
// Fired by auth.js on logout / sign-out
|
||||
window.addEventListener('passkeeper:logout', () => {
|
||||
chrome.runtime.sendMessage({ type: 'WEB_SESSION_CLEAR' }).catch(() => {});
|
||||
});
|
||||
|
||||
// On initial page load: sync in both directions
|
||||
|
||||
// Web → Extension: if the web app is already logged in, forward tokens to extension
|
||||
const existing_token = sessionStorage.getItem('access_token');
|
||||
const existing_refresh = localStorage.getItem('refresh_token');
|
||||
const existing_salt = sessionStorage.getItem('enc_key_salt');
|
||||
if (existing_token && existing_refresh) {
|
||||
syncToExtension(existing_token, existing_refresh, existing_salt);
|
||||
}
|
||||
|
||||
// Extension → Web: if the web app has no session but the extension does,
|
||||
// refresh the access token first (so we inject a guaranteed-fresh pair) then
|
||||
// fire passkeeper:ext-login so vault.js can proceed without hitting 401.
|
||||
if (!existing_token) {
|
||||
(async () => {
|
||||
try {
|
||||
const local = await chrome.storage.local.get(['refresh_token', 'enc_key_salt']);
|
||||
const refresh = local.refresh_token;
|
||||
const salt = local.enc_key_salt ||
|
||||
(await chrome.storage.session.get('enc_key_salt')).enc_key_salt || '';
|
||||
if (!refresh || !salt) return;
|
||||
|
||||
// Exchange the stored refresh token for a fresh access token
|
||||
const res = await fetch(`${location.origin}/api/auth/refresh`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ refresh_token: refresh }),
|
||||
});
|
||||
if (!res.ok) return;
|
||||
const data = await res.json();
|
||||
|
||||
const freshAccess = data.access_token;
|
||||
const freshRefresh = data.refresh_token || refresh;
|
||||
|
||||
// Write fresh tokens into the page session so vault.js works immediately
|
||||
sessionStorage.setItem('access_token', freshAccess);
|
||||
localStorage.setItem('refresh_token', freshRefresh);
|
||||
sessionStorage.setItem('enc_key_salt', salt);
|
||||
|
||||
// Keep extension storage in sync with the rotated tokens
|
||||
chrome.storage.session.set({ access_token: freshAccess, enc_key_salt: salt });
|
||||
chrome.storage.local.set({ refresh_token: freshRefresh, enc_key_salt: salt });
|
||||
|
||||
window.dispatchEvent(new CustomEvent('passkeeper:ext-login', {
|
||||
detail: { enc_key_salt: salt },
|
||||
}));
|
||||
} catch {}
|
||||
})();
|
||||
}
|
||||
|
||||
// ── Extension → Web app ────────────────────────────────────────────────────
|
||||
|
||||
chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
|
||||
if (msg.type === 'INJECT_SESSION') {
|
||||
// Write tokens so the web app is effectively logged in
|
||||
sessionStorage.setItem('access_token', msg.access_token);
|
||||
localStorage.setItem('refresh_token', msg.refresh_token);
|
||||
if (msg.enc_key_salt) sessionStorage.setItem('enc_key_salt', msg.enc_key_salt);
|
||||
|
||||
// Tell the web app a session was injected — vault.js listens for this
|
||||
// to dismiss the unlock overlay and load the vault
|
||||
window.dispatchEvent(new CustomEvent('passkeeper:ext-login', {
|
||||
detail: { enc_key_salt: msg.enc_key_salt },
|
||||
}));
|
||||
|
||||
sendResponse({ ok: true });
|
||||
}
|
||||
return false;
|
||||
});
|
||||
})();
|
||||
Reference in New Issue
Block a user