Handle custom auth providers in saved profiles

This commit is contained in:
thePR0M3TH3AN committed 2025-10-21 13:56:38 -04:00
1 parent 1137a8ca78
commit ea45488ee4
5 files changed
+256 -23

No files matched your search

+30 -2
View File
@@ -1961,11 +1961,39 @@ class Application {
setLoadingState(true);
try {
const { pubkey } = await this.authService.requestLogin({
const loginResult = await this.authService.requestLogin({
allowAccountSelection: true,
autoApply: false,
});
const { pubkey, authType: loginAuthType, providerId } =
typeof loginResult === "object" && loginResult
? loginResult
: { pubkey: loginResult };
const detailAuthType =
typeof loginResult?.detail?.authType === "string"
? loginResult.detail.authType
: null;
const detailProviderId =
typeof loginResult?.detail?.providerId === "string"
? loginResult.detail.providerId
: null;
const resolvedAuthType = (() => {
const candidates = [detailAuthType, loginAuthType, detailProviderId, providerId];
for (const candidate of candidates) {
if (typeof candidate !== "string") {
continue;
}
const trimmed = candidate.trim();
if (trimmed) {
return trimmed;
}
}
return "nip07";
})();
const normalizedPubkey = this.normalizeHexPubkey(pubkey);
if (!normalizedPubkey) {
throw new Error(
@@ -1999,7 +2027,7 @@ class Application {
npub,
name,
picture,
authType: "nip07",
authType: resolvedAuthType,
});
persistSavedProfiles({ persistActive: false });
+55 -16
View File
@@ -151,6 +151,39 @@ export default class AuthService {
: "nip07";
}
normalizeAuthType(authTypeCandidate, providerId, providerResult) {
const candidates = [];
if (typeof authTypeCandidate === "string") {
candidates.push(authTypeCandidate);
}
if (providerResult && typeof providerResult === "object") {
const resultAuthType = providerResult.authType;
if (typeof resultAuthType === "string") {
candidates.push(resultAuthType);
}
const resultProviderId = providerResult.providerId;
if (typeof resultProviderId === "string") {
candidates.push(resultProviderId);
}
}
if (typeof providerId === "string") {
candidates.push(providerId);
}
for (const candidate of candidates) {
const trimmed = candidate.trim();
if (trimmed) {
return trimmed;
}
}
return "nip07";
}
log(...args) {
try {
this.logger(...args);
@@ -327,10 +360,11 @@ export default class AuthService {
providerResult && typeof providerResult === "object"
? providerResult.authType
: null;
const authType =
typeof authTypeCandidate === "string" && authTypeCandidate.trim()
? authTypeCandidate.trim()
: providerId;
const authType = this.normalizeAuthType(
authTypeCandidate,
providerId,
providerResult,
);
const signer =
providerResult && typeof providerResult === "object"
? providerResult.signer || null
@@ -401,20 +435,24 @@ export default class AuthService {
const persistActive =
normalizedOptions.persistActive === false ? false : true;
const providerId = this.normalizeProviderId(normalizedOptions.providerId);
const authTypeCandidate =
typeof normalizedOptions.authType === "string" && normalizedOptions.authType.trim()
? normalizedOptions.authType.trim()
: providerId;
const authType = authTypeCandidate || "nip07";
const signer = Object.prototype.hasOwnProperty.call(normalizedOptions, "signer")
? normalizedOptions.signer ?? null
: null;
const providerResult = Object.prototype.hasOwnProperty.call(
normalizedOptions,
"providerResult",
)
? normalizedOptions.providerResult ?? null
: null;
const authTypeCandidate =
typeof normalizedOptions.authType === "string"
? normalizedOptions.authType
: null;
const authType = this.normalizeAuthType(
authTypeCandidate,
providerId,
providerResult,
);
const signer = Object.prototype.hasOwnProperty.call(normalizedOptions, "signer")
? normalizedOptions.signer ?? null
: null;
const previousPubkey = this.normalizeHexPubkey(getPubkey()) || getPubkey();
const normalized = this.normalizeHexPubkey(pubkey);
@@ -477,10 +515,11 @@ export default class AuthService {
setCurrentUserNpub(npub);
let savedProfilesMutated = false;
const entryAuthType =
typeof authType === "string" && authType.trim()
? authType.trim()
: "nip07";
const entryAuthType = this.normalizeAuthType(
authType,
providerId,
providerResult,
);
mutateSavedProfiles((profiles) => {
const draft = Array.isArray(profiles) ? profiles.slice() : [];
+23 -2
View File
@@ -360,7 +360,10 @@ export function persistSavedProfiles({ persistActive = true } = {}) {
typeof entry.npub === "string" && entry.npub.trim() ? entry.npub.trim() : null,
name: typeof entry.name === "string" ? entry.name : "",
picture: typeof entry.picture === "string" ? entry.picture : "",
authType: entry.authType === "nsec" ? "nsec" : "nip07",
authType:
typeof entry.authType === "string" && entry.authType.trim()
? entry.authType.trim()
: null,
})),
activePubkey: activePubkeyToPersist,
};
@@ -408,7 +411,25 @@ export function loadSavedProfilesFromStorage() {
}
seenPubkeys.add(normalizedPubkey);
const storedAuthType = candidate.authType === "nsec" ? "nsec" : "nip07";
const rawAuthType =
typeof candidate.authType === "string" ? candidate.authType : null;
let storedAuthType = null;
if (rawAuthType) {
const trimmedAuthType = rawAuthType.trim();
if (trimmedAuthType) {
storedAuthType = trimmedAuthType;
if (trimmedAuthType !== rawAuthType) {
needsRewrite = true;
}
}
}
if (!storedAuthType) {
storedAuthType = "nip07";
if (rawAuthType !== "nip07") {
needsRewrite = true;
}
}
const npub =
typeof candidate.npub === "string" && candidate.npub.trim()
? candidate.npub.trim()
+7 -3
View File
@@ -1518,8 +1518,12 @@ export class ProfileModalController {
if (meta.npub) {
button.dataset.npub = meta.npub;
}
if (entry.authType) {
button.dataset.authType = entry.authType;
const normalizedAuthType =
typeof entry.authType === "string" && entry.authType.trim()
? entry.authType.trim()
: null;
if (normalizedAuthType) {
button.dataset.authType = normalizedAuthType;
}
const normalizedPubkey = this.normalizeHexPubkey(entry.pubkey);
@@ -1555,7 +1559,7 @@ export class ProfileModalController {
label.className =
"text-3xs font-semibold uppercase tracking-extra-wide text-status-info";
label.textContent =
entry.authType === "nsec" ? "Direct key" : "Saved profile";
normalizedAuthType === "nsec" ? "Direct key" : "Saved profile";
const action = document.createElement("span");
action.className = "text-xs font-medium text-muted";
+141
View File
@@ -0,0 +1,141 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
setSavedProfiles,
persistSavedProfiles,
loadSavedProfilesFromStorage,
mutateSavedProfiles,
setActiveProfilePubkey,
} from "../../js/state/cache.js";
const STORAGE_KEY = "bitvid:savedProfiles:v1";
const SAMPLE_PUBKEY =
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
function resetSavedProfilesState() {
if (typeof localStorage?.clear === "function") {
localStorage.clear();
}
mutateSavedProfiles(() => [], { persist: false, persistActive: false });
setActiveProfilePubkey(null, { persist: false });
loadSavedProfilesFromStorage();
mutateSavedProfiles(() => [], { persist: false, persistActive: false });
setActiveProfilePubkey(null, { persist: false });
if (typeof localStorage?.clear === "function") {
localStorage.clear();
}
}
test("persistSavedProfiles preserves custom authType strings", () => {
resetSavedProfilesState();
setSavedProfiles(
[
{
pubkey: SAMPLE_PUBKEY,
npub: null,
name: "",
picture: "",
authType: "custom-wallet",
},
],
{ persist: false, persistActive: false },
);
persistSavedProfiles({ persistActive: false });
const storedRaw = localStorage.getItem(STORAGE_KEY);
assert.ok(storedRaw, "expected saved profiles to be written to storage");
const stored = JSON.parse(storedRaw);
assert.equal(stored.entries.length, 1);
assert.equal(stored.entries[0].authType, "custom-wallet");
});
test("loadSavedProfilesFromStorage retains custom provider authType", () => {
resetSavedProfilesState();
localStorage.setItem(
STORAGE_KEY,
JSON.stringify({
version: 1,
entries: [
{
pubkey: SAMPLE_PUBKEY,
npub: null,
name: "",
picture: "",
authType: "nostr-wallet-connect",
},
],
activePubkey: null,
}),
);
const { profiles } = loadSavedProfilesFromStorage();
assert.equal(profiles.length, 1);
assert.equal(profiles[0].authType, "nostr-wallet-connect");
const stored = JSON.parse(localStorage.getItem(STORAGE_KEY));
assert.equal(stored.entries[0].authType, "nostr-wallet-connect");
});
test("loadSavedProfilesFromStorage migrates missing authType to nip07", () => {
resetSavedProfilesState();
localStorage.setItem(
STORAGE_KEY,
JSON.stringify({
version: 1,
entries: [
{
pubkey: SAMPLE_PUBKEY,
npub: null,
name: "",
picture: "",
},
],
activePubkey: null,
}),
);
const { profiles } = loadSavedProfilesFromStorage();
assert.equal(profiles.length, 1);
assert.equal(profiles[0].authType, "nip07");
const stored = JSON.parse(localStorage.getItem(STORAGE_KEY));
assert.equal(stored.entries[0].authType, "nip07");
});
test("loadSavedProfilesFromStorage trims stored authType values", () => {
resetSavedProfilesState();
localStorage.setItem(
STORAGE_KEY,
JSON.stringify({
version: 1,
entries: [
{
pubkey: SAMPLE_PUBKEY,
npub: null,
name: "",
picture: "",
authType: " extension-provider ",
},
],
activePubkey: null,
}),
);
const { profiles } = loadSavedProfilesFromStorage();
assert.equal(profiles.length, 1);
assert.equal(profiles[0].authType, "extension-provider");
const stored = JSON.parse(localStorage.getItem(STORAGE_KEY));
assert.equal(stored.entries[0].authType, "extension-provider");
});