Allow users to opt-in to spaces that strip signatures
This commit is contained in:
@@ -49,7 +49,7 @@
|
||||
import ThunkToast from "@app/components/ThunkToast.svelte"
|
||||
import {
|
||||
INDEXER_RELAYS,
|
||||
userSettingValues,
|
||||
userSettingsValues,
|
||||
deriveChat,
|
||||
splitChatId,
|
||||
PLATFORM_NAME,
|
||||
@@ -130,7 +130,7 @@
|
||||
const template = templates[i]
|
||||
|
||||
thunks.push(
|
||||
await sendWrapped({pubkeys, template, delay: $userSettingValues.send_delay + ms(i)}),
|
||||
await sendWrapped({pubkeys, template, delay: $userSettingsValues.send_delay + ms(i)}),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
import ContentQuote from "@app/components/ContentQuote.svelte"
|
||||
import ContentTopic from "@app/components/ContentTopic.svelte"
|
||||
import ContentMention from "@app/components/ContentMention.svelte"
|
||||
import {entityLink, userSettingValues} from "@app/core/state"
|
||||
import {entityLink, userSettingsValues} from "@app/core/state"
|
||||
|
||||
interface Props {
|
||||
event: any
|
||||
@@ -68,7 +68,7 @@
|
||||
|
||||
if (!parsed || hideMediaAtDepth <= depth) return false
|
||||
|
||||
if (isLink(parsed) && $userSettingValues.show_media && isStartOrEnd(i)) {
|
||||
if (isLink(parsed) && $userSettingsValues.show_media && isStartOrEnd(i)) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
}
|
||||
|
||||
let warning = $state(
|
||||
$userSettingValues.hide_sensitive && event.tags.find(nthEq(0, "content-warning"))?.[1],
|
||||
$userSettingsValues.hide_sensitive && event.tags.find(nthEq(0, "content-warning"))?.[1],
|
||||
)
|
||||
|
||||
const shortContent = $derived(
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<script lang="ts">
|
||||
import Link from "@lib/components/Link.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||
|
||||
const back = () => history.back()
|
||||
</script>
|
||||
|
||||
<div class="column gap-4">
|
||||
<ModalHeader>
|
||||
{#snippet title()}
|
||||
<div>What are digital signatures?</div>
|
||||
{/snippet}
|
||||
</ModalHeader>
|
||||
<p>
|
||||
Most online services ask their users to trust them that they're being honest, and they usually
|
||||
are. However, traditional social media platforms have the ability to <strong
|
||||
>create forged content</strong> that can appear to be genuinely authored, but which are actually
|
||||
counterfeit.
|
||||
</p>
|
||||
<p>
|
||||
On <Link external href="https://nostr.com/">Nostr</Link>, all your content is authenticated
|
||||
using <strong>digital signatures</strong>, which cryptographically tie a particular person to a
|
||||
given post or message.
|
||||
</p>
|
||||
<p>
|
||||
The result is that you don't normally have to trust service providers not to tamper with the
|
||||
information flowing through the network — instead, your client software can prove that a given
|
||||
piece of data is authentic.
|
||||
</p>
|
||||
<Button class="btn btn-primary" onclick={back}>Got it</Button>
|
||||
</div>
|
||||
@@ -7,7 +7,7 @@
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||
import {removeSpaceMembership} from "@app/core/commands"
|
||||
import {removeSpaceMembership, removeTrustedRelay} from "@app/core/commands"
|
||||
|
||||
const {url} = $props()
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
try {
|
||||
await removeSpaceMembership(url)
|
||||
await removeTrustedRelay(url)
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<script lang="ts">
|
||||
import {goto} from "$app/navigation"
|
||||
import {remove} from "@welshman/lib"
|
||||
import {displayRelayUrl} from "@welshman/util"
|
||||
import {preventDefault} from "@lib/html"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||
import InfoSignatures from "@app/components/InfoSignatures.svelte"
|
||||
import {relaysPendingTrust} from "@app/core/state"
|
||||
import {removeSpaceMembership, addTrustedRelay, removeTrustedRelay} from "@app/core/commands"
|
||||
import {pushModal} from "@app/util/modal"
|
||||
|
||||
type Props = {
|
||||
url: string
|
||||
}
|
||||
|
||||
const {url}: Props = $props()
|
||||
|
||||
const showInfoSignatures = () => pushModal(InfoSignatures)
|
||||
|
||||
const untrustSpace = async () => {
|
||||
loading = true
|
||||
|
||||
try {
|
||||
await removeSpaceMembership(url)
|
||||
await removeTrustedRelay(url)
|
||||
goto("/")
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
|
||||
const trustSpace = async () => {
|
||||
loading = true
|
||||
|
||||
try {
|
||||
await addTrustedRelay(url)
|
||||
|
||||
relaysPendingTrust.update($r => remove(url, $r))
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
|
||||
let loading = $state(false)
|
||||
</script>
|
||||
|
||||
<form class="column gap-4" onsubmit={preventDefault(trustSpace)}>
|
||||
<ModalHeader>
|
||||
{#snippet title()}
|
||||
Do you trust this space?
|
||||
{/snippet}
|
||||
{#snippet info()}
|
||||
<div>
|
||||
Only join <span class="text-primary">{displayRelayUrl(url)}</span> if you trust the adminstrator
|
||||
</div>
|
||||
{/snippet}
|
||||
</ModalHeader>
|
||||
<div class="m-auto flex flex-col gap-4">
|
||||
<p>
|
||||
This space has opted not to publish <Button class="link" onclick={showInfoSignatures}
|
||||
>digital signatures</Button
|
||||
>, which means that they have the ability to forge messages from other users.
|
||||
</p>
|
||||
<p>
|
||||
If you trust this space's admin, you can continue. Otherwise, it may be safer not to join this
|
||||
space.
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 flex flex-col gap-2 sm:flex-row sm:justify-between">
|
||||
<Button class="btn btn-neutral" onclick={untrustSpace} disabled={loading}>
|
||||
{#if !loading}
|
||||
<Icon icon="close-circle" />
|
||||
{/if}
|
||||
<Spinner {loading}>I don't trust this space</Spinner>
|
||||
</Button>
|
||||
<Button type="submit" class="btn btn-primary" disabled={loading}>
|
||||
{#if !loading}
|
||||
<Icon icon="check-circle" />
|
||||
{/if}
|
||||
<Spinner {loading}>I trust this space, continue</Spinner>
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -1,7 +1,17 @@
|
||||
import {nwc} from "@getalby/sdk"
|
||||
import * as nip19 from "nostr-tools/nip19"
|
||||
import {get} from "svelte/store"
|
||||
import {randomId, flatten, poll, uniq, equals, TIMEZONE, LOCALE} from "@welshman/lib"
|
||||
import {
|
||||
randomId,
|
||||
append,
|
||||
remove,
|
||||
flatten,
|
||||
poll,
|
||||
uniq,
|
||||
equals,
|
||||
TIMEZONE,
|
||||
LOCALE,
|
||||
} from "@welshman/lib"
|
||||
import type {Feed} from "@welshman/feeds"
|
||||
import type {TrustedEvent, EventContent} from "@welshman/util"
|
||||
import {
|
||||
@@ -19,6 +29,7 @@ import {
|
||||
ALERT_WEB,
|
||||
ALERT_IOS,
|
||||
ALERT_ANDROID,
|
||||
APP_DATA,
|
||||
isSignedEvent,
|
||||
makeEvent,
|
||||
displayProfile,
|
||||
@@ -56,13 +67,16 @@ import {
|
||||
tagEventForQuote,
|
||||
getThunkError,
|
||||
} from "@welshman/app"
|
||||
import type {SettingsValues} from "@app/core/state"
|
||||
import {
|
||||
SETTINGS,
|
||||
PROTECTED,
|
||||
userMembership,
|
||||
INDEXER_RELAYS,
|
||||
NOTIFIER_PUBKEY,
|
||||
NOTIFIER_RELAY,
|
||||
userRoomsByUrl,
|
||||
userSettingsValues,
|
||||
} from "@app/core/state"
|
||||
|
||||
// Utils
|
||||
@@ -461,6 +475,25 @@ export const makeAlert = async (params: AlertParams) => {
|
||||
export const publishAlert = async (params: AlertParams) =>
|
||||
publishThunk({event: await makeAlert(params), relays: [NOTIFIER_RELAY]})
|
||||
|
||||
// Settings
|
||||
|
||||
export const makeSettings = async (params: Partial<SettingsValues>) => {
|
||||
const json = JSON.stringify({...userSettingsValues.get(), ...params})
|
||||
const content = await signer.get().nip44.encrypt(pubkey.get()!, json)
|
||||
const tags = [["d", SETTINGS]]
|
||||
|
||||
return makeEvent(APP_DATA, {content, tags})
|
||||
}
|
||||
|
||||
export const publishSettings = async (params: Partial<SettingsValues>) =>
|
||||
publishThunk({event: await makeSettings(params), relays: Router.get().FromUser().getUrls()})
|
||||
|
||||
export const addTrustedRelay = async (url: string) =>
|
||||
publishSettings({trusted_relays: append(url, userSettingsValues.get().trusted_relays)})
|
||||
|
||||
export const removeTrustedRelay = async (url: string) =>
|
||||
publishSettings({trusted_relays: remove(url, userSettingsValues.get().trusted_relays)})
|
||||
|
||||
// Lightning
|
||||
|
||||
export const getWebLn = () => (window as any).webln
|
||||
|
||||
+28
-15
@@ -1,6 +1,6 @@
|
||||
import twColors from "tailwindcss/colors"
|
||||
import {Capacitor} from "@capacitor/core"
|
||||
import {get, derived} from "svelte/store"
|
||||
import {get, derived, writable} from "svelte/store"
|
||||
import * as nip19 from "nostr-tools/nip19"
|
||||
import {
|
||||
on,
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
always,
|
||||
} from "@welshman/lib"
|
||||
import type {Socket} from "@welshman/net"
|
||||
import {Pool, load, AuthStateEvent, SocketEvent} from "@welshman/net"
|
||||
import {Pool, load, AuthStateEvent, SocketEvent, netContext} from "@welshman/net"
|
||||
import {
|
||||
collection,
|
||||
custom,
|
||||
@@ -56,6 +56,7 @@ import {
|
||||
ALERT_IOS,
|
||||
ALERT_ANDROID,
|
||||
ALERT_STATUS,
|
||||
APP_DATA,
|
||||
getGroupTags,
|
||||
getRelayTagValues,
|
||||
getPubkeyTagValues,
|
||||
@@ -68,6 +69,7 @@ import {
|
||||
getTag,
|
||||
getTagValue,
|
||||
getTagValues,
|
||||
verifyEvent,
|
||||
} from "@welshman/util"
|
||||
import type {TrustedEvent, SignedEvent, PublishedList, List, Filter} from "@welshman/util"
|
||||
import {Nip59, decrypt} from "@welshman/signer"
|
||||
@@ -304,6 +306,9 @@ appContext.dufflepudUrl = DUFFLEPUD_URL
|
||||
|
||||
routerContext.getIndexerRelays = always(INDEXER_RELAYS)
|
||||
|
||||
netContext.isEventValid = (event: TrustedEvent, url: string) =>
|
||||
getSetting<string[]>("trusted_relays").includes(url) || verifyEvent(event)
|
||||
|
||||
// Settings
|
||||
|
||||
export const canDecrypt = synced({
|
||||
@@ -312,23 +317,27 @@ export const canDecrypt = synced({
|
||||
storage: localStorageProvider,
|
||||
})
|
||||
|
||||
export const SETTINGS = 38489
|
||||
export const SETTINGS = "flotilla/settings"
|
||||
|
||||
export type SettingsValues = {
|
||||
show_media: boolean
|
||||
hide_sensitive: boolean
|
||||
trusted_relays: string[]
|
||||
report_usage: boolean
|
||||
report_errors: boolean
|
||||
send_delay: number
|
||||
font_size: number
|
||||
}
|
||||
|
||||
export type Settings = {
|
||||
event: TrustedEvent
|
||||
values: {
|
||||
show_media: boolean
|
||||
hide_sensitive: boolean
|
||||
report_usage: boolean
|
||||
report_errors: boolean
|
||||
send_delay: number
|
||||
font_size: number
|
||||
}
|
||||
values: SettingsValues
|
||||
}
|
||||
|
||||
export const defaultSettings = {
|
||||
show_media: true,
|
||||
hide_sensitive: true,
|
||||
trusted_relays: [],
|
||||
report_usage: true,
|
||||
report_errors: true,
|
||||
send_delay: 3000,
|
||||
@@ -336,7 +345,7 @@ export const defaultSettings = {
|
||||
}
|
||||
|
||||
export const settings = deriveEventsMapped<Settings>(repository, {
|
||||
filters: [{kinds: [SETTINGS]}],
|
||||
filters: [{kinds: [APP_DATA], "#d": [SETTINGS]}],
|
||||
itemToEvent: item => item.event,
|
||||
eventToItem: async (event: TrustedEvent) => ({
|
||||
event,
|
||||
@@ -352,9 +361,13 @@ export const {
|
||||
name: "settings",
|
||||
store: settings,
|
||||
getKey: settings => settings.event.pubkey,
|
||||
load: makeOutboxLoader(SETTINGS),
|
||||
load: makeOutboxLoader(APP_DATA, {"#d": [SETTINGS]}),
|
||||
})
|
||||
|
||||
// Relays sending events with empty signatures that the user has to choose to trust
|
||||
|
||||
export const relaysPendingTrust = writable<string[]>([])
|
||||
|
||||
// Alerts
|
||||
|
||||
export type Alert = {
|
||||
@@ -610,11 +623,11 @@ export const userSettings = withGetter(
|
||||
}),
|
||||
)
|
||||
|
||||
export const userSettingValues = withGetter(
|
||||
export const userSettingsValues = withGetter(
|
||||
derived(userSettings, $s => $s?.values || defaultSettings),
|
||||
)
|
||||
|
||||
export const getSetting = <T>(key: keyof Settings["values"]) => userSettingValues.get()[key] as T
|
||||
export const getSetting = <T>(key: keyof Settings["values"]) => userSettingsValues.get()[key] as T
|
||||
|
||||
export const userMembership = withGetter(
|
||||
derived([pubkey, membershipsByPubkey], ([$pubkey, $membershipsByPubkey]) => {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script lang="ts">
|
||||
import type {Snippet} from "svelte"
|
||||
|
||||
interface Props {
|
||||
children?: import("svelte").Snippet
|
||||
children?: Snippet
|
||||
}
|
||||
|
||||
const {children}: Props = $props()
|
||||
|
||||
@@ -9,11 +9,23 @@
|
||||
import {dev} from "$app/environment"
|
||||
import {goto} from "$app/navigation"
|
||||
import {sync, localStorageProvider} from "@welshman/store"
|
||||
import {identity, memoize, spec, sleep, defer, ago, WEEK, TaskQueue} from "@welshman/lib"
|
||||
import {
|
||||
identity,
|
||||
call,
|
||||
memoize,
|
||||
spec,
|
||||
sleep,
|
||||
on,
|
||||
defer,
|
||||
ago,
|
||||
WEEK,
|
||||
TaskQueue,
|
||||
} from "@welshman/lib"
|
||||
import type {TrustedEvent, StampedEvent} from "@welshman/util"
|
||||
import {
|
||||
WRAP,
|
||||
EVENT_TIME,
|
||||
APP_DATA,
|
||||
THREAD,
|
||||
MESSAGE,
|
||||
INBOX_RELAYS,
|
||||
@@ -28,8 +40,14 @@
|
||||
getRelaysFromList,
|
||||
} from "@welshman/util"
|
||||
import {Nip46Broker, makeSecret} from "@welshman/signer"
|
||||
import type {Socket} from "@welshman/net"
|
||||
import {request, defaultSocketPolicies, makeSocketPolicyAuth} from "@welshman/net"
|
||||
import type {Socket, RelayMessage} from "@welshman/net"
|
||||
import {
|
||||
request,
|
||||
defaultSocketPolicies,
|
||||
makeSocketPolicyAuth,
|
||||
SocketEvent,
|
||||
isRelayEvent,
|
||||
} from "@welshman/net"
|
||||
import {
|
||||
loadRelay,
|
||||
db,
|
||||
@@ -64,9 +82,11 @@
|
||||
import {
|
||||
INDEXER_RELAYS,
|
||||
userMembership,
|
||||
userSettingValues,
|
||||
userSettingsValues,
|
||||
relaysPendingTrust,
|
||||
ensureUnwrapped,
|
||||
canDecrypt,
|
||||
getSetting,
|
||||
} from "@app/core/state"
|
||||
import {loadUserData, listenForNotifications} from "@app/core/requests"
|
||||
import {theme} from "@app/util/theme"
|
||||
@@ -162,9 +182,9 @@
|
||||
})
|
||||
|
||||
// Sync font size
|
||||
userSettingValues.subscribe($userSettingValues => {
|
||||
userSettingsValues.subscribe($userSettingsValues => {
|
||||
// @ts-ignore
|
||||
document.documentElement.style["font-size"] = `${$userSettingValues.font_size}rem`
|
||||
document.documentElement.style["font-size"] = `${$userSettingsValues.font_size}rem`
|
||||
})
|
||||
|
||||
if (!db) {
|
||||
@@ -214,9 +234,16 @@
|
||||
repository,
|
||||
rankEvent: (e: TrustedEvent) => {
|
||||
if (
|
||||
[PROFILE, FOLLOWS, MUTES, RELAYS, BLOSSOM_SERVERS, INBOX_RELAYS, ROOMS].includes(
|
||||
e.kind,
|
||||
)
|
||||
[
|
||||
PROFILE,
|
||||
FOLLOWS,
|
||||
MUTES,
|
||||
RELAYS,
|
||||
BLOSSOM_SERVERS,
|
||||
INBOX_RELAYS,
|
||||
ROOMS,
|
||||
APP_DATA,
|
||||
].includes(e.kind)
|
||||
) {
|
||||
return 1
|
||||
}
|
||||
@@ -239,6 +266,40 @@
|
||||
sign: (event: StampedEvent) => signer.get()?.sign(event),
|
||||
shouldAuth: (socket: Socket) => true,
|
||||
}),
|
||||
(socket: Socket) => {
|
||||
const buffer: RelayMessage[] = []
|
||||
|
||||
const unsubscribers = [
|
||||
// When the socket goes from untrusted to trusted, receive all buffered messages
|
||||
userSettingsValues.subscribe($settings => {
|
||||
if ($settings.trusted_relays.includes(socket.url)) {
|
||||
for (const message of buffer.splice(0)) {
|
||||
socket._recvQueue.push(message)
|
||||
}
|
||||
}
|
||||
}),
|
||||
// When we get an event with no signature from an untrusted relay, remove it from
|
||||
// the receive queue. If trust status is undefined, buffer it for later.
|
||||
on(socket, SocketEvent.Receiving, (message: RelayMessage) => {
|
||||
if (isRelayEvent(message) && !message[2]?.sig) {
|
||||
const isTrusted = getSetting<string[]>("trusted_relays").includes(socket.url)
|
||||
|
||||
if (!isTrusted) {
|
||||
socket._recvQueue.remove(message)
|
||||
buffer.push(message)
|
||||
|
||||
if (!$relaysPendingTrust.includes(socket.url)) {
|
||||
relaysPendingTrust.update($r => [...$r, socket.url])
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
]
|
||||
|
||||
return () => {
|
||||
unsubscribers.forEach(call)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
// Load relay info
|
||||
|
||||
@@ -9,14 +9,7 @@
|
||||
BLOSSOM_SERVERS,
|
||||
} from "@welshman/util"
|
||||
import {Router} from "@welshman/router"
|
||||
import {
|
||||
pubkey,
|
||||
signer,
|
||||
userMutes,
|
||||
tagPubkey,
|
||||
publishThunk,
|
||||
userBlossomServers,
|
||||
} from "@welshman/app"
|
||||
import {userMutes, tagPubkey, publishThunk, userBlossomServers} from "@welshman/app"
|
||||
import {preventDefault} from "@lib/html"
|
||||
import Field from "@lib/components/Field.svelte"
|
||||
import FieldInline from "@lib/components/FieldInline.svelte"
|
||||
@@ -24,38 +17,32 @@
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import ProfileMultiSelect from "@app/components/ProfileMultiSelect.svelte"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
import {SETTINGS, PLATFORM_NAME, userSettingValues} from "@app/core/state"
|
||||
import {PLATFORM_NAME, userSettingsValues} from "@app/core/state"
|
||||
import {publishSettings} from "@app/core/commands"
|
||||
|
||||
const reset = () => {
|
||||
settings = {...$userSettingValues}
|
||||
settings = {...$userSettingsValues}
|
||||
mutedPubkeys = getPubkeyTagValues(getListTags($userMutes))
|
||||
blossomServers = getTagValues("server", getListTags($userBlossomServers))
|
||||
}
|
||||
|
||||
const onsubmit = preventDefault(async () => {
|
||||
const json = JSON.stringify($state.snapshot(settings))
|
||||
const content = await $signer!.nip44.encrypt($pubkey!, json)
|
||||
const relays = Router.get().FromUser().getUrls()
|
||||
|
||||
publishThunk({
|
||||
event: makeEvent(SETTINGS, {content}),
|
||||
relays,
|
||||
})
|
||||
await publishSettings($state.snapshot(settings))
|
||||
|
||||
publishThunk({
|
||||
event: makeEvent(MUTES, {tags: mutedPubkeys.map(tagPubkey)}),
|
||||
relays,
|
||||
relays: Router.get().FromUser().getUrls(),
|
||||
})
|
||||
|
||||
publishThunk({
|
||||
event: makeEvent(BLOSSOM_SERVERS, {tags: blossomServers.map(tagger("server"))}),
|
||||
relays,
|
||||
relays: Router.get().FromUser().getUrls(),
|
||||
})
|
||||
|
||||
pushToast({message: "Your settings have been saved!"})
|
||||
})
|
||||
|
||||
let settings = $state({...$userSettingValues})
|
||||
let settings = $state({...$userSettingsValues})
|
||||
let mutedPubkeys = $state(getPubkeyTagValues(getListTags($userMutes)))
|
||||
let blossomServers = $state(getTagValues("server", getListTags($userBlossomServers)))
|
||||
</script>
|
||||
|
||||
@@ -5,14 +5,16 @@
|
||||
import {ago, MONTH} from "@welshman/lib"
|
||||
import {ROOM_META, EVENT_TIME, THREAD, COMMENT, MESSAGE} from "@welshman/util"
|
||||
import Page from "@lib/components/Page.svelte"
|
||||
import Dialog from "@lib/components/Dialog.svelte"
|
||||
import SecondaryNav from "@lib/components/SecondaryNav.svelte"
|
||||
import MenuSpace from "@app/components/MenuSpace.svelte"
|
||||
import SpaceAuthError from "@app/components/SpaceAuthError.svelte"
|
||||
import SpaceTrustRelay from "@app/components/SpaceTrustRelay.svelte"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
import {pushModal} from "@app/util/modal"
|
||||
import {setChecked} from "@app/util/notifications"
|
||||
import {checkRelayConnection, checkRelayAuth, checkRelayAccess} from "@app/core/commands"
|
||||
import {decodeRelay, userRoomsByUrl} from "@app/core/state"
|
||||
import {decodeRelay, userRoomsByUrl, relaysPendingTrust} from "@app/core/state"
|
||||
import {pullConservatively} from "@app/core/requests"
|
||||
import {notifications} from "@app/util/notifications"
|
||||
|
||||
@@ -82,3 +84,9 @@
|
||||
{@render children?.()}
|
||||
{/key}
|
||||
</Page>
|
||||
|
||||
{#if $relaysPendingTrust.includes(url)}
|
||||
<Dialog>
|
||||
<SpaceTrustRelay {url} />
|
||||
</Dialog>
|
||||
{/if}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
import ChannelComposeParent from "@app/components/ChannelComposeParent.svelte"
|
||||
import {
|
||||
userRoomsByUrl,
|
||||
userSettingValues,
|
||||
userSettingsValues,
|
||||
decodeRelay,
|
||||
getEventsForUrl,
|
||||
deriveUserMembershipStatus,
|
||||
@@ -128,7 +128,7 @@
|
||||
const thunk = publishThunk({
|
||||
relays: [url],
|
||||
event: makeEvent(MESSAGE, template),
|
||||
delay: $userSettingValues.send_delay,
|
||||
delay: $userSettingsValues.send_delay,
|
||||
})
|
||||
|
||||
pushToast({
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
import ChannelCompose from "@app/components/ChannelCompose.svelte"
|
||||
import ChannelComposeParent from "@app/components/ChannelComposeParent.svelte"
|
||||
import {
|
||||
userSettingValues,
|
||||
userSettingsValues,
|
||||
decodeRelay,
|
||||
getEventsForUrl,
|
||||
PROTECTED,
|
||||
@@ -69,7 +69,7 @@
|
||||
const thunk = publishThunk({
|
||||
relays: [url],
|
||||
event: makeEvent(MESSAGE, template),
|
||||
delay: $userSettingValues.send_delay,
|
||||
delay: $userSettingsValues.send_delay,
|
||||
})
|
||||
|
||||
pushToast({
|
||||
|
||||
Reference in New Issue
Block a user