mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Handle custom auth providers in saved profiles
This commit is contained in:
1 parent
1137a8ca78
commit
ea45488ee4
5 files changed
+256
-23
No files matched your search
@@ -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
@@ -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
@@ -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()
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
Reference in new issue
Block a user