Improve locked vault browser workflow
This commit is contained in:
@@ -292,6 +292,16 @@ function approvalHintForState(state) {
|
||||
return state.pendingMessage || "Approve or deny the fill request in KeePassGO.";
|
||||
}
|
||||
|
||||
function shouldContinueWatchingState(state) {
|
||||
if (!state?.pageHasLoginForm) {
|
||||
return false;
|
||||
}
|
||||
if (state?.pendingFill) {
|
||||
return true;
|
||||
}
|
||||
return Boolean(state?.status?.locked);
|
||||
}
|
||||
|
||||
function schedulePendingPoll(tabId, pageUrl) {
|
||||
if (!Number.isInteger(tabId)) {
|
||||
return;
|
||||
@@ -492,7 +502,7 @@ async function refreshPageState(tabId, pageUrl, options = {}) {
|
||||
state.matches = [];
|
||||
state.updatedAt = Date.now();
|
||||
const saved = await setPageState(tabId, state);
|
||||
if (saved.pendingFill) {
|
||||
if (shouldContinueWatchingState(saved)) {
|
||||
schedulePendingPoll(tabId, resolvedURL);
|
||||
} else {
|
||||
clearPendingPoll(tabId);
|
||||
@@ -502,7 +512,7 @@ async function refreshPageState(tabId, pageUrl, options = {}) {
|
||||
|
||||
if (shouldReuseMatches(state, force)) {
|
||||
const saved = await setPageState(tabId, state);
|
||||
if (saved.pendingFill) {
|
||||
if (shouldContinueWatchingState(saved)) {
|
||||
schedulePendingPoll(tabId, resolvedURL);
|
||||
} else {
|
||||
clearPendingPoll(tabId);
|
||||
@@ -529,7 +539,7 @@ async function refreshPageState(tabId, pageUrl, options = {}) {
|
||||
updatedAt: Date.now()
|
||||
};
|
||||
const saved = await setPageState(tabId, state);
|
||||
if (saved.pendingFill) {
|
||||
if (shouldContinueWatchingState(saved)) {
|
||||
schedulePendingPoll(tabId, resolvedURL);
|
||||
} else {
|
||||
clearPendingPoll(tabId);
|
||||
@@ -657,6 +667,7 @@ const backgroundTestExports = {
|
||||
normalizePageState,
|
||||
actionPresentationForState,
|
||||
shouldReuseMatches,
|
||||
shouldContinueWatchingState,
|
||||
tokenPendingApprovalCount,
|
||||
defaultSettings
|
||||
};
|
||||
|
||||
@@ -49,6 +49,24 @@ test("tokenPendingApprovalCount reads token-scoped approval state", () => {
|
||||
assert.equal(background.tokenPendingApprovalCount({}), 0);
|
||||
});
|
||||
|
||||
test("shouldContinueWatchingState keeps polling locked login pages", () => {
|
||||
assert.equal(background.shouldContinueWatchingState({
|
||||
pageHasLoginForm: true,
|
||||
pendingFill: false,
|
||||
status: { locked: true }
|
||||
}), true);
|
||||
assert.equal(background.shouldContinueWatchingState({
|
||||
pageHasLoginForm: true,
|
||||
pendingFill: true,
|
||||
status: { locked: false }
|
||||
}), true);
|
||||
assert.equal(background.shouldContinueWatchingState({
|
||||
pageHasLoginForm: true,
|
||||
pendingFill: false,
|
||||
status: { locked: false }
|
||||
}), false);
|
||||
});
|
||||
|
||||
test("default settings include a blank bearer token that can be overridden by harness patching", () => {
|
||||
assert.equal(background.defaultSettings.bearerToken, "");
|
||||
});
|
||||
|
||||
@@ -429,6 +429,7 @@ function shouldShowInlineOverlay(state, hasTarget, suppressed, idleHidden) {
|
||||
state?.pageHasLoginForm &&
|
||||
(
|
||||
state?.pendingFill ||
|
||||
(state?.configured && state?.success && state?.status?.locked) ||
|
||||
(state?.configured && state?.success && !state?.status?.locked && Array.isArray(state?.matches) && state.matches.length > 0)
|
||||
)
|
||||
);
|
||||
@@ -727,10 +728,13 @@ if (isNodeTestEnv) {
|
||||
|
||||
ensureRootMounted();
|
||||
dock.style.display = "block";
|
||||
trigger.dataset.tone = pageState.pendingFill ? "warning" : (pageState.error ? "error" : "ready");
|
||||
trigger.dataset.tone = pageState.pendingFill || pageState.status?.locked ? "warning" : (pageState.error ? "error" : "ready");
|
||||
if (pageState.pendingFill) {
|
||||
meta.textContent = "Approval needed in KeePassGO";
|
||||
panelCopy.textContent = pageState.pendingMessage || "Approve or deny the fill request in KeePassGO.";
|
||||
} else if (pageState.status?.locked) {
|
||||
meta.textContent = "Unlock KeePassGO";
|
||||
panelCopy.textContent = "Unlock KeePassGO to turn this field back into live login suggestions.";
|
||||
} else {
|
||||
const count = Array.isArray(pageState.matches) ? pageState.matches.length : 0;
|
||||
meta.textContent = count === 1 ? "1 login ready" : `${count} logins ready`;
|
||||
|
||||
@@ -94,6 +94,19 @@ test("shouldShowInlineOverlay hides the page overlay after it is suppressed", ()
|
||||
assert.equal(content.shouldShowInlineOverlay(state, true, true, false), false);
|
||||
});
|
||||
|
||||
test("shouldShowInlineOverlay stays visible for locked login pages", () => {
|
||||
const state = {
|
||||
pageHasLoginForm: true,
|
||||
configured: true,
|
||||
success: true,
|
||||
status: { locked: true },
|
||||
matches: [],
|
||||
pendingFill: false
|
||||
};
|
||||
|
||||
assert.equal(content.shouldShowInlineOverlay(state, true, false, false), true);
|
||||
});
|
||||
|
||||
test("shouldShowInlineOverlay hides the page overlay after idle expiry", () => {
|
||||
const state = {
|
||||
pageHasLoginForm: true,
|
||||
|
||||
@@ -115,6 +115,25 @@ Expected behavior:
|
||||
- custom URL fields such as `URL1`, `URL2`, and similar KeePass-style URL
|
||||
slots
|
||||
|
||||
## Locked Vault Workflow
|
||||
|
||||
User story:
|
||||
|
||||
- When the current page has a login form but KeePassGO is locked, the browser
|
||||
must still make that state visible on the page and in the popup.
|
||||
- Unlocking KeePassGO should not require the user to reopen the popup multiple
|
||||
times or reload the page before the extension becomes usable again.
|
||||
|
||||
Expected behavior:
|
||||
|
||||
- The popup shows a locked-state message instead of silently falling back to
|
||||
"no matches."
|
||||
- The inline page affordance stays visible on login forms while KeePassGO is
|
||||
locked and tells the user to unlock the vault.
|
||||
- After the vault is unlocked, the extension rechecks the page automatically
|
||||
and turns the locked affordance back into live matches without requiring a
|
||||
page reload.
|
||||
|
||||
For extension-side regression checks, run:
|
||||
|
||||
```bash
|
||||
|
||||
Reference in New Issue
Block a user