mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-31 18:02:27 +00:00
[auth] Add "Lock this device" control to re-lock a kept-unlocked session (#51)
The opt-in "keep unlocked" cache had no user-facing way to undo it mid-session
(it cleared only on logout / clear-site-data). Add a "Lock this device" button to
the profile modal footer (desktop + mobile), shown only when the active account
has a cached key to forget (app.isSessionKeptUnlocked -> client.hasCachedUnlockedKey).
Clicking it runs app.lockKeptUnlockedSession(pubkey), which re-locks in one action
everything the signer unlocks:
- forgets the cached key (both tiers) so future reloads re-prompt for the PIN,
- drops the in-memory signer (logoutSigner) so the CURRENT session re-locks now
(the next signing action prompts again via ensureEncryptionCapableSigner),
- storageService.lock(pubkey), and
- nwcSettingsService.clearCache() (re-hydrates from the signer next time).
Visibility refreshes on renderSavedProfiles + selectPane. Tests: 2 in
tests/profile-modal-controller.test.mjs (shown only when kept-unlocked; click locks
the active pubkey). Lint + build green.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
b0a2eeaf72
commit
cebd3dc1e7
7 files changed
+255
-6
No files matched your search
@@ -360,6 +360,8 @@ export class ProfileModalController {
|
||||
this.closeButton = null;
|
||||
this.logoutButton = null;
|
||||
this.mobileLogoutButton = null;
|
||||
this.lockNowButton = null;
|
||||
this.mobileLockNowButton = null;
|
||||
this.channelLink = null;
|
||||
this.addAccountButton = null;
|
||||
this.navButtons = {
|
||||
@@ -657,6 +659,9 @@ export class ProfileModalController {
|
||||
this.logoutButton = document.getElementById("profileLogoutBtn") || null;
|
||||
this.mobileLogoutButton =
|
||||
document.getElementById("profileMobileLogoutBtn") || null;
|
||||
this.lockNowButton = document.getElementById("profileLockNowBtn") || null;
|
||||
this.mobileLockNowButton =
|
||||
document.getElementById("profileMobileLockNowBtn") || null;
|
||||
this.channelLink = document.getElementById("profileChannelLink") || null;
|
||||
this.addAccountButton =
|
||||
document.getElementById("profileAddAccountBtn") || null;
|
||||
@@ -1291,6 +1296,25 @@ export class ProfileModalController {
|
||||
}
|
||||
}
|
||||
|
||||
// Show the "Lock this device" control only when there is a cached "keep
|
||||
// unlocked" key to forget (an nsec account currently kept unlocked). TODO #51.
|
||||
updateLockNowVisibility() {
|
||||
const check = this.services?.isSessionKeptUnlocked;
|
||||
let unlocked = false;
|
||||
if (typeof check === "function") {
|
||||
try {
|
||||
unlocked = Boolean(check(this.getActivePubkey()));
|
||||
} catch (error) {
|
||||
unlocked = false;
|
||||
}
|
||||
}
|
||||
for (const button of [this.lockNowButton, this.mobileLockNowButton]) {
|
||||
if (button instanceof HTMLElement) {
|
||||
button.classList.toggle("hidden", !unlocked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setMessagesUnreadIndicator(visible) {
|
||||
if (!(this.dmController.profileMessagesUnreadDot instanceof HTMLElement)) {
|
||||
return;
|
||||
@@ -1672,6 +1696,25 @@ export class ProfileModalController {
|
||||
});
|
||||
}
|
||||
|
||||
const handleLockNow = () => {
|
||||
const lock = this.services?.lockKeptUnlockedSession;
|
||||
if (typeof lock !== "function") {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
lock(this.getActivePubkey());
|
||||
} catch (error) {
|
||||
devLogger.warn("[profileModal] Lock this device failed:", error);
|
||||
}
|
||||
this.updateLockNowVisibility();
|
||||
};
|
||||
if (this.lockNowButton instanceof HTMLElement) {
|
||||
this.lockNowButton.addEventListener("click", handleLockNow);
|
||||
}
|
||||
if (this.mobileLockNowButton instanceof HTMLElement) {
|
||||
this.mobileLockNowButton.addEventListener("click", handleLockNow);
|
||||
}
|
||||
|
||||
if (this.channelLink instanceof HTMLElement) {
|
||||
this.channelLink.addEventListener("click", (event) => {
|
||||
event.preventDefault();
|
||||
@@ -2365,6 +2408,7 @@ export class ProfileModalController {
|
||||
* Triggers a batch fetch for any missing profile metadata.
|
||||
*/
|
||||
renderSavedProfiles() {
|
||||
this.updateLockNowVisibility();
|
||||
const normalizedActive = this.normalizeHexPubkey(this.getActivePubkey());
|
||||
const entriesNeedingFetch = new Set();
|
||||
const savedProfiles = this.getSavedProfiles();
|
||||
@@ -3237,6 +3281,7 @@ export class ProfileModalController {
|
||||
}
|
||||
|
||||
selectPane(name = "account", options = {}) {
|
||||
this.updateLockNowVisibility();
|
||||
const { keepMenuView = false } =
|
||||
options && typeof options === "object" ? options : {};
|
||||
const normalized = typeof name === "string" ? name.toLowerCase() : "account";
|
||||
|
||||
Reference in new issue
Block a user