Add profile switching support for NIP-07 accounts

This commit is contained in:
thePR0M3TH3AN committed 2025-09-29 23:14:52 -04:00
1 parent c617fcbfda
commit ee09b723af
2 files changed
+164 -1

No files matched your search

+123
View File
@@ -3897,6 +3897,16 @@ class bitvidApp {
});
}
if (
this.profileAddAccountBtn &&
this.profileAddAccountBtn.dataset.bound !== "true"
) {
this.profileAddAccountBtn.dataset.bound = "true";
this.profileAddAccountBtn.addEventListener("click", () => {
this.handleAddProfile();
});
}
Object.entries(this.profileNavButtons).forEach(([name, button]) => {
if (!button || button.dataset.navBound === "true") {
return;
@@ -4440,6 +4450,119 @@ class bitvidApp {
});
}
async handleAddProfile() {
if (!this.profileAddAccountBtn) {
return;
}
const button = this.profileAddAccountBtn;
if (button.dataset.loading === "true") {
return;
}
const titleEl = button.querySelector(".profile-switcher__addTitle");
const hintEl = button.querySelector(".profile-switcher__addHint");
const originalTitle = titleEl ? titleEl.textContent : "";
const originalHint = hintEl ? hintEl.textContent : "";
const originalAriaLabel = button.getAttribute("aria-label");
const originalDisabled = button.disabled;
const setLoadingState = (isLoading) => {
button.disabled = isLoading ? true : originalDisabled;
button.dataset.loading = isLoading ? "true" : "false";
button.setAttribute("aria-busy", isLoading ? "true" : "false");
if (isLoading) {
button.setAttribute("aria-disabled", "true");
} else if (originalDisabled) {
button.setAttribute("aria-disabled", "true");
} else {
button.removeAttribute("aria-disabled");
}
if (isLoading) {
if (titleEl) {
titleEl.textContent = "Connecting...";
}
if (hintEl) {
hintEl.textContent = "Check your extension";
}
button.setAttribute(
"aria-label",
"Connecting to your Nostr extension"
);
} else {
if (titleEl) {
titleEl.textContent = originalTitle;
}
if (hintEl) {
hintEl.textContent = originalHint;
}
if (originalAriaLabel === null) {
button.removeAttribute("aria-label");
} else {
button.setAttribute("aria-label", originalAriaLabel);
}
}
};
setLoadingState(true);
try {
const pubkey = await nostrClient.login({
allowAccountSelection: true,
});
const normalizedPubkey = this.normalizeHexPubkey(pubkey);
if (!normalizedPubkey) {
throw new Error(
"Received an invalid public key from the Nostr extension."
);
}
const alreadySaved = this.savedProfiles.some(
(entry) =>
this.normalizeHexPubkey(entry.pubkey) === normalizedPubkey
);
if (alreadySaved) {
this.showSuccess("That profile is already saved on this device.");
return;
}
const npub = this.safeEncodeNpub(normalizedPubkey) || "";
let profileMeta = this.getProfileCacheEntry(normalizedPubkey)?.profile;
if (!profileMeta) {
await this.loadOwnProfile(normalizedPubkey);
profileMeta = this.getProfileCacheEntry(normalizedPubkey)?.profile;
}
const name = profileMeta?.name || "";
const picture =
profileMeta?.picture || "assets/svg/default-profile.svg";
this.savedProfiles.push({
pubkey: normalizedPubkey,
npub,
name,
picture,
authType: "nip07",
});
this.persistSavedProfiles({ persistActive: false });
this.renderSavedProfiles();
this.showSuccess("Profile added. Select it when you're ready to switch.");
} catch (error) {
console.error("Failed to add profile via NIP-07:", error);
const message =
error && typeof error.message === "string" && error.message.trim()
? error.message.trim()
: "Couldn't add that profile. Please try again.";
this.showError(message);
} finally {
setLoadingState(false);
}
}
async handleAddBlockedCreator() {
if (!this.profileBlockedInput) {
return;
+41 -1
View File
@@ -593,7 +593,7 @@ class NostrClient {
/**
* Attempt login with a Nostr extension
*/
async login() {
async login(options = {}) {
try {
const extension = window.nostr;
if (!extension) {
@@ -603,6 +603,13 @@ class NostrClient {
);
}
const { allowAccountSelection = false, expectPubkey } =
typeof options === "object" && options !== null ? options : {};
const normalizedExpectedPubkey =
typeof expectPubkey === "string" && expectPubkey.trim()
? expectPubkey.trim().toLowerCase()
: null;
if (typeof extension.getPublicKey !== "function") {
throw new Error(
"This NIP-07 extension is missing getPublicKey support. Please update the extension."
@@ -624,6 +631,30 @@ class NostrClient {
}
}
if (allowAccountSelection && typeof extension.selectAccounts === "function") {
try {
const selection = await extension.selectAccounts(
expectPubkey ? [expectPubkey] : undefined
);
const didCancelSelection =
selection === undefined ||
selection === null ||
selection === false ||
(Array.isArray(selection) && selection.length === 0);
if (didCancelSelection) {
throw new Error("Account selection was cancelled.");
}
} catch (selectionErr) {
const message =
selectionErr && typeof selectionErr.message === "string"
? selectionErr.message
: "Account selection was cancelled.";
throw new Error(message);
}
}
let timeoutId;
const pubkey = await Promise.race([
extension.getPublicKey(),
@@ -646,6 +677,15 @@ class NostrClient {
"The NIP-07 extension did not return a public key. Please try again."
);
}
if (
normalizedExpectedPubkey &&
pubkey.toLowerCase() !== normalizedExpectedPubkey
) {
throw new Error(
"The selected account doesn't match the expected profile. Please try again."
);
}
const npub = window.NostrTools.nip19.npubEncode(pubkey);
if (isDevMode) {