diff --git a/components/profile-modal.html b/components/profile-modal.html
index 9018e1ac..be56000c 100644
--- a/components/profile-modal.html
+++ b/components/profile-modal.html
@@ -930,7 +930,7 @@
Whitelist
- Creators listed here remain visible when whitelist mode is enabled. Adding someone removes them from the blacklist.
+ Creators listed here remain visible when whitelist mode is enabled. Accounts can appear in both lists, and the blacklist always takes precedence.
@@ -966,7 +966,7 @@
Blacklist
- Creators on the blacklist are hidden from bitvid everywhere. Adding someone removes them from the whitelist.
+ Creators on the blacklist are hidden from bitvid everywhere. Accounts can appear in both lists, and the blacklist always takes precedence.
diff --git a/js/accessControl.js b/js/accessControl.js
index 0e0f4b70..96dd35d8 100644
--- a/js/accessControl.js
+++ b/js/accessControl.js
@@ -581,9 +581,7 @@ class AccessControl {
}
const nextWhitelist = dedupeNpubs([...this.getWhitelist(), normalized]);
- const nextBlacklist = this.getBlacklist().filter(
- (value) => value !== normalized
- );
+ const nextBlacklist = this.getBlacklist();
try {
await persistAdminState(actorNpub, {
@@ -642,9 +640,7 @@ class AccessControl {
}
const nextBlacklist = dedupeNpubs([...this.getBlacklist(), normalized]);
- const nextWhitelist = this.getWhitelist().filter(
- (value) => value !== normalized
- );
+ const nextWhitelist = this.getWhitelist();
try {
await persistAdminState(actorNpub, {
diff --git a/js/adminListStore.js b/js/adminListStore.js
index 5d070bf1..4e1aadf7 100644
--- a/js/adminListStore.js
+++ b/js/adminListStore.js
@@ -193,7 +193,6 @@ function sanitizeNpubList(values) {
function sanitizeAdminState(state = {}) {
const sanitizedEditors = sanitizeNpubList(state.editors || []);
const sanitizedWhitelist = sanitizeNpubList(state.whitelist || []);
- const whitelistSet = new Set(sanitizedWhitelist.map(normalizeNpub));
const adminGuardSet = new Set([
normalizeNpub(ADMIN_SUPER_NPUB),
@@ -207,9 +206,6 @@ function sanitizeAdminState(state = {}) {
if (!normalized) {
return false;
}
- if (whitelistSet.has(normalized)) {
- return false;
- }
if (adminGuardSet.has(normalized)) {
return false;
}
@@ -848,9 +844,6 @@ async function persistNostrState(actorNpub, updates = {}) {
}
if (Array.isArray(updates.blacklist)) {
- const whitelistSet = new Set(
- (sanitizedUpdates.whitelist || []).map(normalizeNpub)
- );
const editorGuard = new Set([
normalizeNpub(ADMIN_SUPER_NPUB),
...ADMIN_EDITORS_NPUBS.map(normalizeNpub),
@@ -867,9 +860,6 @@ async function persistNostrState(actorNpub, updates = {}) {
if (!normalized) {
return false;
}
- if (whitelistSet.has(normalized)) {
- return false;
- }
if (editorGuard.has(normalized)) {
return false;
}
diff --git a/js/ui/profileModalController.js b/js/ui/profileModalController.js
index 23aa5c1b..aa6e962e 100644
--- a/js/ui/profileModalController.js
+++ b/js/ui/profileModalController.js
@@ -7033,8 +7033,14 @@ export class ProfileModalController {
return;
}
- const { onRemove, removeLabel = "Remove", confirmMessage, removable = true } =
- options;
+ const {
+ onRemove,
+ removeLabel = "Remove",
+ confirmMessage,
+ removable = true,
+ overlapSet,
+ overlapLabel,
+ } = options;
const formatNpub =
typeof this.formatShortNpub === "function"
@@ -7076,6 +7082,8 @@ export class ProfileModalController {
"card flex flex-col gap-3 p-4 sm:flex-row sm:items-center sm:justify-between";
const normalizedNpub = typeof npub === "string" ? npub.trim() : "";
+ const comparableNpub =
+ this.normalizeNpubValue(normalizedNpub) || normalizedNpub;
const decodedHex =
normalizedNpub && normalizedNpub.startsWith("npub1")
? this.safeDecodeNpub(normalizedNpub)
@@ -7110,6 +7118,20 @@ export class ProfileModalController {
avatarSrc,
});
+ if (
+ summary &&
+ overlapLabel &&
+ overlapSet instanceof Set &&
+ comparableNpub &&
+ overlapSet.has(comparableNpub)
+ ) {
+ const overlapBadge = document.createElement("span");
+ overlapBadge.className = "badge whitespace-nowrap";
+ overlapBadge.dataset.variant = "warning";
+ overlapBadge.textContent = overlapLabel;
+ summary.appendChild(overlapBadge);
+ }
+
const actions = document.createElement("div");
actions.className =
"flex flex-wrap items-center justify-end gap-2 sm:flex-none";
@@ -7175,6 +7197,15 @@ export class ProfileModalController {
const blacklist = this.normalizeAdminListEntries(
this.services.accessControl.getBlacklist(),
);
+ const normalizeForCompare = (value) =>
+ this.normalizeNpubValue(value) ||
+ (typeof value === "string" ? value.trim() : "");
+ const whitelistCompare = new Set(
+ whitelist.map(normalizeForCompare).filter(Boolean),
+ );
+ const blacklistCompare = new Set(
+ blacklist.map(normalizeForCompare).filter(Boolean),
+ );
this.renderAdminList(
this.adminModeratorList,
@@ -7199,6 +7230,8 @@ export class ProfileModalController {
removeLabel: "Remove",
confirmMessage: "Remove {npub} from the whitelist?",
removable: true,
+ overlapSet: blacklistCompare,
+ overlapLabel: "Also blacklisted",
},
);
@@ -7212,6 +7245,8 @@ export class ProfileModalController {
removeLabel: "Unblock",
confirmMessage: "Remove {npub} from the blacklist?",
removable: true,
+ overlapSet: whitelistCompare,
+ overlapLabel: "Also whitelisted",
},
);
}