Files
virtual-webauthn/extension/background.js

125 lines
3.0 KiB
JavaScript
Raw Normal View History

2026-03-30 22:57:08 +09:00
const HOST_NAME = "com.example.virtual_webauthn";
2026-03-30 11:39:50 +09:00
2026-03-30 22:57:08 +09:00
let port = null;
let seq = 0;
const pending = new Map();
let sessionKey = null;
function connect() {
if (port) return;
try {
port = chrome.runtime.connectNative(HOST_NAME);
} catch {
return;
2026-03-30 11:39:50 +09:00
}
2026-03-30 22:57:08 +09:00
port.onMessage.addListener((msg) => {
if (msg.sessionKey) {
sessionKey = msg.sessionKey;
}
const cb = pending.get(msg.id);
if (cb) {
pending.delete(msg.id);
cb(msg);
}
});
port.onDisconnect.addListener(() => {
port = null;
for (const [id, cb] of pending) {
cb({ id, success: false, error: "Host disconnected" });
}
pending.clear();
updateIcon(false);
});
updateIcon(true);
}
function sendNative(msg) {
return new Promise((resolve, reject) => {
connect();
if (!port) {
reject(new Error("Cannot connect to native host"));
return;
}
const id = ++seq;
const timer = setTimeout(() => {
pending.delete(id);
reject(new Error("Timed out"));
}, 120_000);
pending.set(id, (resp) => {
clearTimeout(timer);
resolve(resp);
});
port.postMessage({ ...msg, id });
});
2026-03-30 11:39:50 +09:00
}
2026-03-30 22:57:08 +09:00
// --- Icon status ---
2026-03-30 11:39:50 +09:00
let lastStatus = null;
2026-03-30 22:57:08 +09:00
function updateIcon(connected) {
const status = connected ? "ok" : "err";
if (status === lastStatus) return;
lastStatus = status;
const icon = connected ? "icon-green.svg" : "icon-red.svg";
const title = connected
? "Virtual WebAuthn — Connected"
: "Virtual WebAuthn — Disconnected";
chrome.action.setIcon({ path: icon });
chrome.action.setTitle({ title });
}
async function pingLoop() {
2026-03-30 11:39:50 +09:00
try {
2026-03-30 22:57:08 +09:00
const resp = await sendNative({ type: "ping" });
updateIcon(resp.success === true);
2026-03-30 11:39:50 +09:00
} catch {
2026-03-30 22:57:08 +09:00
updateIcon(false);
2026-03-30 11:39:50 +09:00
}
2026-03-30 22:57:08 +09:00
setTimeout(pingLoop, 10_000);
2026-03-30 11:39:50 +09:00
}
2026-03-30 22:57:08 +09:00
pingLoop();
2026-03-30 11:39:50 +09:00
2026-03-30 22:57:08 +09:00
// --- Message relay from content script ---
2026-03-30 11:39:50 +09:00
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
2026-03-30 22:57:08 +09:00
if (message.type !== "VWEBAUTHN_REQUEST") return;
const msg = {
type: message.action,
data: message.payload,
};
// Password from content.js (already in isolated context)
if (message.password) {
msg.password = message.password;
} else if (sessionKey) {
msg.sessionKey = sessionKey;
2026-03-30 11:39:50 +09:00
}
2026-03-30 22:57:08 +09:00
if (message.action === "list" && message.rpId) {
msg.rpId = message.rpId;
}
sendNative(msg)
.then((resp) => {
if (!resp.success) {
const err = resp.error || "";
if (err.includes("session") || err.includes("Session")) {
sessionKey = null;
}
}
sendResponse(resp);
})
.catch((error) => {
sendResponse({ success: false, error: error.message });
});
return true;
2026-03-30 11:39:50 +09:00
});