170 lines
3.7 KiB
JavaScript
170 lines
3.7 KiB
JavaScript
const tabForms = {};
|
|
const tabMatches = {};
|
|
|
|
let lastTabId = null;
|
|
let currentPageForms = null;
|
|
let currentPageMatches = null;
|
|
let addedContexts = [];
|
|
|
|
function askNative(msg) {
|
|
const port = chrome.runtime.connectNative('ee.lunasqu.password_manager');
|
|
|
|
return new Promise((resolve, reject) => {
|
|
let gotResponse = false;
|
|
port.onMessage.addListener((msg) => {
|
|
gotResponse = true;
|
|
resolve(msg);
|
|
port.disconnect();
|
|
});
|
|
|
|
port.onDisconnect.addListener((msg) => {
|
|
if (!gotResponse) {
|
|
gotResponse = true;
|
|
reject(msg);
|
|
}
|
|
});
|
|
|
|
port.postMessage(msg);
|
|
});
|
|
}
|
|
|
|
chrome.runtime.onInstalled.addListener(() => {
|
|
chrome.contextMenus.create({
|
|
id: 'fillContextMenu',
|
|
title: 'Autofill password',
|
|
contexts: ['editable'],
|
|
});
|
|
});
|
|
|
|
function addContextMenuItems() {
|
|
if (!currentPageMatches) {
|
|
return;
|
|
}
|
|
|
|
clearContextMenu();
|
|
for (const match of currentPageMatches) {
|
|
const ctxID = `fill-${match}`;
|
|
chrome.contextMenus.create({
|
|
id: ctxID,
|
|
title: match,
|
|
contexts: ['editable'],
|
|
parentId: 'fillContextMenu',
|
|
});
|
|
addedContexts.push(ctxID);
|
|
}
|
|
}
|
|
|
|
function clearContextMenu() {
|
|
addedContexts.forEach((id) => {
|
|
try {
|
|
chrome.contextMenus.remove(id);
|
|
} catch (e) {
|
|
console.error(e);
|
|
}
|
|
});
|
|
addedContexts.length = 0;
|
|
}
|
|
|
|
async function injectForeground() {
|
|
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
|
|
|
if (!tab || !tab.url) {
|
|
return;
|
|
}
|
|
|
|
lastTabId = tab.id;
|
|
|
|
await chrome.scripting.executeScript({
|
|
target: { tabId: tab.id },
|
|
files: ['./foreground.js'],
|
|
});
|
|
|
|
const parsed = new URL(tab.url);
|
|
|
|
askNative({
|
|
domain: parsed.hostname,
|
|
}).then(({ results }) => {
|
|
if (results && results.length) {
|
|
currentPageMatches = results;
|
|
tabMatches[tab.id] = results;
|
|
chrome.tabs.sendMessage(tab.id, {
|
|
message: 'has_entries',
|
|
payload: results,
|
|
});
|
|
addContextMenuItems();
|
|
}
|
|
});
|
|
}
|
|
|
|
async function sendPasswordToTab(rdata, existingTab) {
|
|
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
|
const realTab = existingTab || tab;
|
|
|
|
if (!realTab || !realTab.url) {
|
|
return;
|
|
}
|
|
|
|
chrome.tabs.sendMessage(realTab.id, {
|
|
message: 'fill_password',
|
|
payload: rdata,
|
|
});
|
|
}
|
|
|
|
chrome.webNavigation.onCompleted.addListener((ee) => {
|
|
if (ee.frameType !== 'outermost_frame') {
|
|
return;
|
|
}
|
|
currentPageForms = null;
|
|
currentPageMatches = null;
|
|
injectForeground();
|
|
});
|
|
|
|
chrome.tabs.onActivated.addListener(function (activeInfo) {
|
|
lastTabId = activeInfo.tabId;
|
|
currentPageForms = tabForms[activeInfo.tabId];
|
|
currentPageMatches = tabMatches[activeInfo.tabId];
|
|
|
|
clearContextMenu();
|
|
if (currentPageMatches) {
|
|
addContextMenuItems();
|
|
}
|
|
});
|
|
|
|
chrome.tabs.onRemoved.addListener(function (tabId, info) {
|
|
delete tabForms[tabId];
|
|
delete tabMatches[tabId];
|
|
});
|
|
|
|
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|
if (request.message === 'login_forms') {
|
|
if (sender && sender.tab && sender.tab.id) {
|
|
tabForms[sender.tab.id] = request.payload;
|
|
}
|
|
|
|
if (sender.tab.id === lastTabId) {
|
|
currentPageForms = request.payload;
|
|
}
|
|
sendResponse(true);
|
|
}
|
|
|
|
if (request.message === 'autofill') {
|
|
askNative({
|
|
getPassword: request.payload,
|
|
}).then((response) => {
|
|
sendPasswordToTab(response);
|
|
});
|
|
sendResponse(true);
|
|
}
|
|
});
|
|
|
|
chrome.contextMenus.onClicked.addListener((info, tab) => {
|
|
if (info && info.menuItemId && info.menuItemId.startsWith('fill-')) {
|
|
const fillId = info.menuItemId.substring(5);
|
|
askNative({
|
|
getPassword: fillId,
|
|
}).then((response) => {
|
|
sendPasswordToTab(response, tab);
|
|
});
|
|
}
|
|
});
|