Tweak access terminology, relay access attempts

This commit is contained in:
Jon Staab
2025-10-31 16:00:14 -07:00
parent ba2b5d182e
commit 3978e32d5f
4 changed files with 75 additions and 105 deletions

View File

@@ -170,26 +170,38 @@
</FieldInline> </FieldInline>
<FieldInline> <FieldInline>
{#snippet label()} {#snippet label()}
<p>Access Control</p> <strong>Restricted</strong>
{/snippet} {/snippet}
{#snippet input()} {#snippet input()}
<div class="flex items-center justify-end gap-4"> <input type="checkbox" class="checkbox" bind:checked={values.isRestricted} />
<span class="flex gap-3"> <span class="text-sm opacity-75">Only allow members to send messages</span>
<input type="checkbox" class="checkbox" bind:checked={values.isClosed} />
Closed
</span>
<span class="flex gap-3">
<input type="checkbox" class="checkbox" bind:checked={values.isPrivate} />
Private
</span>
<span class="flex gap-3">
<input type="checkbox" class="checkbox" bind:checked={values.isHidden} />
Hidden
</span>
</div>
{/snippet} {/snippet}
{#snippet info()} </FieldInline>
<p>Only members can send messages to closed groups and read messages from private groups.</p> <FieldInline>
{#snippet label()}
<strong>Private</strong>
{/snippet}
{#snippet input()}
<input type="checkbox" class="checkbox" bind:checked={values.isPrivate} />
<span class="text-sm opacity-75">Only allow members to read messages</span>
{/snippet}
</FieldInline>
<FieldInline>
{#snippet label()}
<strong>Hidden</strong>
{/snippet}
{#snippet input()}
<input type="checkbox" class="checkbox" bind:checked={values.isHidden} />
<span class="text-sm opacity-75">Hide this group from non-members</span>
{/snippet}
</FieldInline>
<FieldInline>
{#snippet label()}
<strong>Closed</strong>
{/snippet}
{#snippet input()}
<input type="checkbox" class="checkbox" bind:checked={values.isClosed} />
<span class="text-sm opacity-75">Ignore requests to join</span>
{/snippet} {/snippet}
</FieldInline> </FieldInline>
{@render footer({loading})} {@render footer({loading})}

View File

@@ -14,7 +14,7 @@
import SpaceJoinConfirm, {confirmSpaceJoin} from "@app/components/SpaceJoinConfirm.svelte" import SpaceJoinConfirm, {confirmSpaceJoin} from "@app/components/SpaceJoinConfirm.svelte"
import {pushToast} from "@app/util/toast" import {pushToast} from "@app/util/toast"
import {pushModal} from "@app/util/modal" import {pushModal} from "@app/util/modal"
import {checkRelayAccess} from "@app/core/commands" import {attemptRelayAccess} from "@app/core/commands"
import {deriveSocket} from "@app/core/state" import {deriveSocket} from "@app/core/state"
type Props = { type Props = {
@@ -31,7 +31,7 @@
loading = true loading = true
try { try {
const message = await checkRelayAccess(url, claim) const message = await attemptRelayAccess(url, claim)
if (message) { if (message) {
return pushToast({theme: "error", message, timeout: 30_000}) return pushToast({theme: "error", message, timeout: 30_000})

View File

@@ -84,7 +84,6 @@ import {
userRelaySelections, userRelaySelections,
userInboxRelaySelections, userInboxRelaySelections,
nip44EncryptToSelf, nip44EncryptToSelf,
loadRelay,
dropSession, dropSession,
tagEventForComment, tagEventForComment,
tagEventForQuote, tagEventForQuote,
@@ -264,43 +263,7 @@ export const canEnforceNip70 = async (url: string) => {
return socket.auth.status !== AuthStatus.None return socket.auth.status !== AuthStatus.None
} }
export const checkRelayAccess = async (url: string, claim = "") => { export const attemptRelayAccess = async (url: string, claim = "") => {
const socket = Pool.get().get(url)
await attemptAuth(url)
const thunk = publishJoinRequest({url, claim})
const error = await waitForThunkError(thunk)
if (error) {
const message =
socket.auth.details?.replace(/^\w+: /, "") ||
error.replace(/^\w+: /, "") ||
"join request rejected"
// If it's a strict NIP 29 relay don't worry about requesting access
// TODO: remove this if relay29 ever gets less strict
if (message === "missing group (`h`) tag") return
// Ignore messages about the relay ignoring ours
if (error?.startsWith("mute: ")) return
// Ignore rejected empty claims
if (!claim && error?.includes("invite code")) return
return message
}
}
export const checkRelayProfile = async (url: string) => {
const relay = await loadRelay(url)
if (!relay) {
return "Sorry, we weren't able to find that relay."
}
}
export const checkRelayConnection = async (url: string) => {
const socket = Pool.get().get(url) const socket = Pool.get().get(url)
socket.attemptToOpen() socket.attemptToOpen()
@@ -313,39 +276,30 @@ export const checkRelayConnection = async (url: string) => {
if (socket.status !== SocketStatus.Open) { if (socket.status !== SocketStatus.Open) {
return `Failed to connect` return `Failed to connect`
} }
}
export const checkRelayAuth = async (url: string) => {
const socket = Pool.get().get(url)
const okStatuses = [AuthStatus.None, AuthStatus.Ok]
await attemptAuth(url) await attemptAuth(url)
// Only raise an error if it's not a timeout. // Only raise an error if it's not a timeout.
// If it is, odds are the problem is with our signer, not the relay // If it is, odds are the problem is with our signer, not the relay
if (!okStatuses.includes(socket.auth.status)) { if (![AuthStatus.None, AuthStatus.Ok].includes(socket.auth.status)) {
if (socket.auth.details) { if (socket.auth.details) {
return `Failed to authenticate (${socket.auth.details})` return `Failed to authenticate (${socket.auth.details})`
} else { } else {
return `Failed to authenticate (${last(socket.auth.status.split(":"))})` return `Failed to authenticate (${last(socket.auth.status.split(":"))})`
} }
} }
}
export const attemptRelayAccess = async (url: string, claim = "") => { const thunk = publishJoinRequest({url, claim})
const checks = [ const error = await waitForThunkError(thunk)
() => checkRelayConnection(url),
() => checkRelayAccess(url, claim),
() => checkRelayAuth(url),
]
for (const check of checks) { // Ignore messages about the relay ignoring our messages
const error = await check() if (error?.startsWith("mute: ")) return
if (error) { // If it's a strict NIP 29 relay don't worry about requesting access
return error // TODO: remove this if relay29 ever gets less strict
} if (error?.includes("missing group (`h`) tag")) return
}
return error?.replace(/^\w+: /, "")
} }
// Deletions // Deletions

View File

@@ -390,6 +390,7 @@
<div class="py-20"> <div class="py-20">
<div class="card2 col-8 m-auto max-w-md items-center text-center"> <div class="card2 col-8 m-auto max-w-md items-center text-center">
<p class="opacity-75">You aren't currently a member of this room.</p> <p class="opacity-75">You aren't currently a member of this room.</p>
{#if !$room?.isClosed}
{#if $membershipStatus === MembershipStatus.Pending} {#if $membershipStatus === MembershipStatus.Pending}
<Button class="btn btn-neutral btn-sm" disabled={leaving} onclick={leave}> <Button class="btn btn-neutral btn-sm" disabled={leaving} onclick={leave}>
<Icon icon={ClockCircle} /> <Icon icon={ClockCircle} />
@@ -405,6 +406,7 @@
Join Room Join Room
</Button> </Button>
{/if} {/if}
{/if}
</div> </div>
</div> </div>
{:else} {:else}
@@ -452,9 +454,10 @@
<div class="chat__compose bg-base-200" bind:this={chatCompose}> <div class="chat__compose bg-base-200" bind:this={chatCompose}>
{#if $room?.isPrivate && $membershipStatus !== MembershipStatus.Granted} {#if $room?.isPrivate && $membershipStatus !== MembershipStatus.Granted}
<!-- pass --> <!-- pass -->
{:else if $room?.isClosed && $membershipStatus !== MembershipStatus.Granted} {:else if $room?.isRestricted && $membershipStatus !== MembershipStatus.Granted}
<div class="bg-alt card m-4 flex flex-row items-center justify-between px-4 py-3"> <div class="bg-alt card m-4 flex flex-row items-center justify-between px-4 py-3">
<p>Only members are allowed to post to this room.</p> <p>Only members are allowed to post to this room.</p>
{#if !$room?.isClosed}
{#if $membershipStatus === MembershipStatus.Pending} {#if $membershipStatus === MembershipStatus.Pending}
<Button class="btn btn-neutral btn-sm" disabled={leaving} onclick={leave}> <Button class="btn btn-neutral btn-sm" disabled={leaving} onclick={leave}>
<Icon icon={ClockCircle} /> <Icon icon={ClockCircle} />
@@ -470,6 +473,7 @@
Ask to Join Ask to Join
</Button> </Button>
{/if} {/if}
{/if}
</div> </div>
{:else} {:else}
<div> <div>