Add support for blocked relays
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
* Fix memory leak, notification badge not showing
|
* Fix memory leak, notification badge not showing
|
||||||
* Improve space join flow
|
* Improve space join flow
|
||||||
* Fix opening images in fullscreen dialog
|
* Fix opening images in fullscreen dialog
|
||||||
|
* Add support for blocked relays
|
||||||
|
|
||||||
# 1.6.2
|
# 1.6.2
|
||||||
|
|
||||||
|
|||||||
@@ -52,10 +52,8 @@ import {
|
|||||||
removeFromListByPredicate,
|
removeFromListByPredicate,
|
||||||
getTag,
|
getTag,
|
||||||
getListTags,
|
getListTags,
|
||||||
getRelayTags,
|
|
||||||
getRelayTagValues,
|
getRelayTagValues,
|
||||||
toNostrURI,
|
toNostrURI,
|
||||||
getRelaysFromList,
|
|
||||||
RelayMode,
|
RelayMode,
|
||||||
getAddress,
|
getAddress,
|
||||||
getTagValue,
|
getTagValue,
|
||||||
@@ -80,8 +78,6 @@ import {
|
|||||||
publishThunk,
|
publishThunk,
|
||||||
tagEvent,
|
tagEvent,
|
||||||
tagEventForReaction,
|
tagEventForReaction,
|
||||||
userRelayList,
|
|
||||||
userMessagingRelayList,
|
|
||||||
nip44EncryptToSelf,
|
nip44EncryptToSelf,
|
||||||
dropSession,
|
dropSession,
|
||||||
tagEventForComment,
|
tagEventForComment,
|
||||||
@@ -208,42 +204,6 @@ export const removeRoomMembership = async (url: string, h: string) => {
|
|||||||
return publishThunk({event, relays})
|
return publishThunk({event, relays})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const setRelayPolicy = (url: string, read: boolean, write: boolean) => {
|
|
||||||
const list = get(userRelayList) || makeList({kind: RELAYS})
|
|
||||||
const tags = getRelayTags(getListTags(list)).filter(t => normalizeRelayUrl(t[1]) !== url)
|
|
||||||
|
|
||||||
if (read && write) {
|
|
||||||
tags.push(["r", url])
|
|
||||||
} else if (read) {
|
|
||||||
tags.push(["r", url, "read"])
|
|
||||||
} else if (write) {
|
|
||||||
tags.push(["r", url, "write"])
|
|
||||||
}
|
|
||||||
|
|
||||||
return publishThunk({
|
|
||||||
event: makeEvent(list.kind, {tags}),
|
|
||||||
relays: [url, ...INDEXER_RELAYS, ...Router.get().FromUser().getUrls(), ...get(userSpaceUrls)],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const setMessagingRelayPolicy = (url: string, enabled: boolean) => {
|
|
||||||
const list = get(userMessagingRelayList) || makeList({kind: MESSAGING_RELAYS})
|
|
||||||
|
|
||||||
// Only update messaging policies if they already exist or we're adding them
|
|
||||||
if (enabled || getRelaysFromList(list).includes(url)) {
|
|
||||||
const tags = getRelayTags(getListTags(list)).filter(t => normalizeRelayUrl(t[1]) !== url)
|
|
||||||
|
|
||||||
if (enabled) {
|
|
||||||
tags.push(["relay", url])
|
|
||||||
}
|
|
||||||
|
|
||||||
return publishThunk({
|
|
||||||
event: makeEvent(list.kind, {tags}),
|
|
||||||
relays: [...INDEXER_RELAYS, ...Router.get().FromUser().getUrls(), ...get(userSpaceUrls)],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Relay access
|
// Relay access
|
||||||
|
|
||||||
export const canEnforceNip70 = async (url: string) => {
|
export const canEnforceNip70 = async (url: string) => {
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import {
|
|||||||
loadRelayList,
|
loadRelayList,
|
||||||
loadMessagingRelayList,
|
loadMessagingRelayList,
|
||||||
loadBlossomServerList,
|
loadBlossomServerList,
|
||||||
|
loadBlockedRelayList,
|
||||||
loadFollowList,
|
loadFollowList,
|
||||||
loadMuteList,
|
loadMuteList,
|
||||||
loadProfile,
|
loadProfile,
|
||||||
@@ -215,6 +216,7 @@ const syncUserData = () => {
|
|||||||
loadAlerts($userRelayList.event.pubkey)
|
loadAlerts($userRelayList.event.pubkey)
|
||||||
loadAlertStatuses($userRelayList.event.pubkey)
|
loadAlertStatuses($userRelayList.event.pubkey)
|
||||||
loadBlossomServerList($userRelayList.event.pubkey)
|
loadBlossomServerList($userRelayList.event.pubkey)
|
||||||
|
loadBlockedRelayList($userRelayList.event.pubkey)
|
||||||
loadFollowList($userRelayList.event.pubkey)
|
loadFollowList($userRelayList.event.pubkey)
|
||||||
loadGroupList($userRelayList.event.pubkey)
|
loadGroupList($userRelayList.event.pubkey)
|
||||||
loadMuteList($userRelayList.event.pubkey)
|
loadMuteList($userRelayList.event.pubkey)
|
||||||
@@ -229,13 +231,13 @@ const syncUserData = () => {
|
|||||||
await sleep(1000)
|
await sleep(1000)
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
pubkeys.map(async pk => {
|
pubkeys.flatMap(pk => [
|
||||||
await loadRelayList(pk)
|
loadRelayList(pk),
|
||||||
await loadGroupList(pk)
|
loadGroupList(pk),
|
||||||
await loadProfile(pk)
|
loadProfile(pk),
|
||||||
await loadFollowList(pk)
|
loadFollowList(pk),
|
||||||
await loadMuteList(pk)
|
loadMuteList(pk),
|
||||||
}),
|
]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import {on, always, call, dissoc, assoc, uniq} from "@welshman/lib"
|
import {on, always, call, dissoc, assoc, uniq} from "@welshman/lib"
|
||||||
|
import {RelayMode} from "@welshman/util"
|
||||||
import type {Socket, RelayMessage, ClientMessage} from "@welshman/net"
|
import type {Socket, RelayMessage, ClientMessage} from "@welshman/net"
|
||||||
import {
|
import {
|
||||||
makeSocketPolicyAuth,
|
makeSocketPolicyAuth,
|
||||||
@@ -13,7 +14,7 @@ import {
|
|||||||
isClientNegOpen,
|
isClientNegOpen,
|
||||||
isClientNegClose,
|
isClientNegClose,
|
||||||
} from "@welshman/net"
|
} from "@welshman/net"
|
||||||
import {sign} from "@welshman/app"
|
import {sign, pubkey, getPubkeyRelays} from "@welshman/app"
|
||||||
import {
|
import {
|
||||||
userSettingsValues,
|
userSettingsValues,
|
||||||
getSetting,
|
getSetting,
|
||||||
@@ -23,6 +24,22 @@ import {
|
|||||||
|
|
||||||
export const authPolicy = makeSocketPolicyAuth({sign, shouldAuth: always(true)})
|
export const authPolicy = makeSocketPolicyAuth({sign, shouldAuth: always(true)})
|
||||||
|
|
||||||
|
export const blockPolicy = (socket: Socket) => {
|
||||||
|
const previousOpen = socket.open
|
||||||
|
|
||||||
|
socket.open = () => {
|
||||||
|
const $pubkey = pubkey.get()
|
||||||
|
|
||||||
|
if (!$pubkey || !getPubkeyRelays($pubkey, RelayMode.Blocked).includes(socket.url)) {
|
||||||
|
return previousOpen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
socket.open = previousOpen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const trustPolicy = (socket: Socket) => {
|
export const trustPolicy = (socket: Socket) => {
|
||||||
const buffer: RelayMessage[] = []
|
const buffer: RelayMessage[] = []
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
import {setupHistory} from "@app/util/history"
|
import {setupHistory} from "@app/util/history"
|
||||||
import {setupTracking} from "@app/util/tracking"
|
import {setupTracking} from "@app/util/tracking"
|
||||||
import {setupAnalytics} from "@app/util/analytics"
|
import {setupAnalytics} from "@app/util/analytics"
|
||||||
import {authPolicy, trustPolicy, mostlyRestrictedPolicy} from "@app/util/policies"
|
import {authPolicy, blockPolicy, trustPolicy, mostlyRestrictedPolicy} from "@app/util/policies"
|
||||||
import {kv, db} from "@app/core/storage"
|
import {kv, db} from "@app/core/storage"
|
||||||
import {userSettingsValues} from "@app/core/state"
|
import {userSettingsValues} from "@app/core/state"
|
||||||
import {syncApplicationData} from "@app/core/sync"
|
import {syncApplicationData} from "@app/core/sync"
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
const {children} = $props()
|
const {children} = $props()
|
||||||
|
|
||||||
const policies = [authPolicy, trustPolicy, mostlyRestrictedPolicy]
|
const policies = [authPolicy, blockPolicy, trustPolicy, mostlyRestrictedPolicy]
|
||||||
|
|
||||||
// Add stuff to window for convenience
|
// Add stuff to window for convenience
|
||||||
Object.assign(window, {
|
Object.assign(window, {
|
||||||
|
|||||||
@@ -1,6 +1,16 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {onMount} from "svelte"
|
import {onMount} from "svelte"
|
||||||
import {pubkey, getRelayLists, getMessagingRelayLists, derivePubkeyRelays} from "@welshman/app"
|
import {
|
||||||
|
pubkey,
|
||||||
|
getRelayLists,
|
||||||
|
derivePubkeyRelays,
|
||||||
|
addRelay,
|
||||||
|
removeRelay,
|
||||||
|
addBlockedRelay,
|
||||||
|
removeBlockedRelay,
|
||||||
|
addMessagingRelay,
|
||||||
|
removeMessagingRelay,
|
||||||
|
} from "@welshman/app"
|
||||||
import {RelayMode} from "@welshman/util"
|
import {RelayMode} from "@welshman/util"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
@@ -9,43 +19,42 @@
|
|||||||
import RelayAdd from "@app/components/RelayAdd.svelte"
|
import RelayAdd from "@app/components/RelayAdd.svelte"
|
||||||
import {pushModal} from "@app/util/modal"
|
import {pushModal} from "@app/util/modal"
|
||||||
import {discoverRelays} from "@app/core/requests"
|
import {discoverRelays} from "@app/core/requests"
|
||||||
import {setRelayPolicy, setMessagingRelayPolicy} from "@app/core/commands"
|
|
||||||
import Globus from "@assets/icons/globus.svg?dataurl"
|
import Globus from "@assets/icons/globus.svg?dataurl"
|
||||||
import Inbox from "@assets/icons/inbox.svg?dataurl"
|
import Inbox from "@assets/icons/inbox.svg?dataurl"
|
||||||
import Mailbox from "@assets/icons/mailbox.svg?dataurl"
|
import Mailbox from "@assets/icons/mailbox.svg?dataurl"
|
||||||
|
import ForbiddenCircle from "@assets/icons/forbidden-circle.svg?dataurl"
|
||||||
import CloseCircle from "@assets/icons/close-circle.svg?dataurl"
|
import CloseCircle from "@assets/icons/close-circle.svg?dataurl"
|
||||||
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
||||||
|
|
||||||
const readRelayUrls = derivePubkeyRelays($pubkey!, RelayMode.Read)
|
const readRelayUrls = derivePubkeyRelays($pubkey!, RelayMode.Read)
|
||||||
const writeRelayUrls = derivePubkeyRelays($pubkey!, RelayMode.Write)
|
const writeRelayUrls = derivePubkeyRelays($pubkey!, RelayMode.Write)
|
||||||
|
const blockedRelayUrls = derivePubkeyRelays($pubkey!, RelayMode.Blocked)
|
||||||
const messagingRelayUrls = derivePubkeyRelays($pubkey!, RelayMode.Messaging)
|
const messagingRelayUrls = derivePubkeyRelays($pubkey!, RelayMode.Messaging)
|
||||||
|
|
||||||
const addReadRelay = () =>
|
const addReadRelays = () =>
|
||||||
pushModal(RelayAdd, {
|
pushModal(RelayAdd, {
|
||||||
relays: readRelayUrls,
|
relays: readRelayUrls,
|
||||||
addRelay: (url: string) => setRelayPolicy(url, true, $writeRelayUrls.includes(url)),
|
addRelay: (url: string) => addRelay(url, RelayMode.Read),
|
||||||
})
|
})
|
||||||
|
|
||||||
const addWriteRelay = () =>
|
const addWriteRelays = () =>
|
||||||
pushModal(RelayAdd, {
|
pushModal(RelayAdd, {
|
||||||
relays: writeRelayUrls,
|
relays: writeRelayUrls,
|
||||||
addRelay: (url: string) => setRelayPolicy(url, $readRelayUrls.includes(url), true),
|
addRelay: (url: string) => addRelay(url, RelayMode.Write),
|
||||||
})
|
})
|
||||||
|
|
||||||
const addMessagingRelay = () =>
|
const addBlockedRelays = () =>
|
||||||
pushModal(RelayAdd, {
|
pushModal(RelayAdd, {relays: blockedRelayUrls, addRelay: addBlockedRelay})
|
||||||
relays: messagingRelayUrls,
|
|
||||||
addRelay: (url: string) => setMessagingRelayPolicy(url, true),
|
|
||||||
})
|
|
||||||
|
|
||||||
const removeReadRelay = (url: string) => setRelayPolicy(url, false, $writeRelayUrls.includes(url))
|
const addMessagingRelays = () =>
|
||||||
|
pushModal(RelayAdd, {relays: messagingRelayUrls, addRelay: addMessagingRelay})
|
||||||
|
|
||||||
const removeWriteRelay = (url: string) => setRelayPolicy(url, $readRelayUrls.includes(url), false)
|
const removeReadRelay = (url: string) => removeRelay(url, RelayMode.Read)
|
||||||
|
|
||||||
const removeMessagingRelay = (url: string) => setMessagingRelayPolicy(url, false)
|
const removeWriteRelay = (url: string) => removeRelay(url, RelayMode.Write)
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
discoverRelays([...getRelayLists(), ...getMessagingRelayLists()])
|
discoverRelays(getRelayLists())
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -77,7 +86,7 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<p class="text-center text-sm">No relays found</p>
|
<p class="text-center text-sm">No relays found</p>
|
||||||
{/each}
|
{/each}
|
||||||
<Button class="btn btn-primary mt-2" onclick={addWriteRelay}>
|
<Button class="btn btn-primary mt-2" onclick={addWriteRelays}>
|
||||||
<Icon icon={AddCircle} />
|
<Icon icon={AddCircle} />
|
||||||
Add Relay
|
Add Relay
|
||||||
</Button>
|
</Button>
|
||||||
@@ -109,7 +118,7 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<p class="text-center text-sm">No relays found</p>
|
<p class="text-center text-sm">No relays found</p>
|
||||||
{/each}
|
{/each}
|
||||||
<Button class="btn btn-primary mt-2" onclick={addReadRelay}>
|
<Button class="btn btn-primary mt-2" onclick={addReadRelays}>
|
||||||
<Icon icon={AddCircle} />
|
<Icon icon={AddCircle} />
|
||||||
Add Relay
|
Add Relay
|
||||||
</Button>
|
</Button>
|
||||||
@@ -142,7 +151,38 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<p class="text-center text-sm">No relays found</p>
|
<p class="text-center text-sm">No relays found</p>
|
||||||
{/each}
|
{/each}
|
||||||
<Button class="btn btn-primary mt-2" onclick={addMessagingRelay}>
|
<Button class="btn btn-primary mt-2" onclick={addMessagingRelays}>
|
||||||
|
<Icon icon={AddCircle} />
|
||||||
|
Add Relay
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Collapse>
|
||||||
|
<Collapse class="card2 bg-alt column gap-4 shadow-md">
|
||||||
|
{#snippet title()}
|
||||||
|
<h2 class="flex items-center gap-3 text-xl">
|
||||||
|
<Icon icon={ForbiddenCircle} />
|
||||||
|
Blocked Relays
|
||||||
|
</h2>
|
||||||
|
{/snippet}
|
||||||
|
{#snippet description()}
|
||||||
|
<p class="text-sm">
|
||||||
|
These relays will never be connected to by clients supporting this policy.
|
||||||
|
</p>
|
||||||
|
{/snippet}
|
||||||
|
<div class="column gap-2">
|
||||||
|
{#each $blockedRelayUrls.sort() as url (url)}
|
||||||
|
<RelayItem {url}>
|
||||||
|
<Button
|
||||||
|
class="tooltip flex items-center"
|
||||||
|
data-tip="Stop using this relay"
|
||||||
|
onclick={() => removeBlockedRelay(url)}>
|
||||||
|
<Icon icon={CloseCircle} />
|
||||||
|
</Button>
|
||||||
|
</RelayItem>
|
||||||
|
{:else}
|
||||||
|
<p class="text-center text-sm">No relays found</p>
|
||||||
|
{/each}
|
||||||
|
<Button class="btn btn-primary mt-2" onclick={addBlockedRelays}>
|
||||||
<Icon icon={AddCircle} />
|
<Icon icon={AddCircle} />
|
||||||
Add Relay
|
Add Relay
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user