aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrien Hopkins <[email protected]>2025-11-13 17:24:48 -0500
committerAdrien Hopkins <[email protected]>2025-11-13 17:25:13 -0500
commit64f200944f8016725016dfaa0e6db6a6f102b776 (patch)
tree56225bed364712e246f8c7ca6d402cf67732ce7f
parent3e4900606624220e6c112a5438698b03ee3c3943 (diff)
downloadcoinos-ui-64f200944f8016725016dfaa0e6db6a6f102b776.tar.gz
coinos-ui-64f200944f8016725016dfaa0e6db6a6f102b776.zip
Only send expiring DMs to compatible relays
-rw-r--r--src/locales/en.json1
-rw-r--r--src/locales/fr.json1
-rw-r--r--src/routes/(app)/dm/[recipient]/+page.svelte40
3 files changed, 37 insertions, 5 deletions
diff --git a/src/locales/en.json b/src/locales/en.json
index 427c8d96..869a6beb 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -97,6 +97,7 @@
"recipientMsg": "You are sending nostr messages to [R].",
"sendMessage": "Send Message",
"expiry": "Enable message expiry",
+ "cantSendExpiring": "None of [R]'s DM relays support message expiry. You can't send expiring messages to them.",
"fadedWarning": "To avoid metadata leaks, messages expire at a random time up to 2 days after you specify; each message has its own random expiry time. Messages which appear faded are close to expiring; nearby messages may be missing.",
"days": "days",
"relaysNotFound": "Could not find [R]’s DM relays.",
diff --git a/src/locales/fr.json b/src/locales/fr.json
index 4a096420..d8533bd7 100644
--- a/src/locales/fr.json
+++ b/src/locales/fr.json
@@ -29,6 +29,7 @@
"recipientMsg": "Vous envoyez messages nostr à [R].",
"sendMessage": "Envoyez Message",
"expiry": "Expirez messages",
+ "cantSendExpiring": "Aucun des relais de [R] expirent les messages expirants. Vous ne pouvez pas leur envoyer des messages expirants.",
"fadedWarning": "Pour protéger vos métadonées, vos messages expirent à un temps randomée au maximum 2 jours après la date que vous spécifiez; chaque message a son propre temps d’expiration randomée. Les messages qui semble faibles sont proche à expirer; les autres messages autours pouvait avoir déjà disparu.",
"days": "jours",
"relaysNotFound": "Ne pouvait pas trouvez les relais MD de [R].",
diff --git a/src/routes/(app)/dm/[recipient]/+page.svelte b/src/routes/(app)/dm/[recipient]/+page.svelte
index 443119fe..17a8ad23 100644
--- a/src/routes/(app)/dm/[recipient]/+page.svelte
+++ b/src/routes/(app)/dm/[recipient]/+page.svelte
@@ -2,6 +2,7 @@
import { tick } from "svelte";
import Icon from "$comp/Icon.svelte";
import { hexToBytes, bytesToHex } from '@noble/hashes/utils';
+ import { fetchRelayInformation } from 'nostr-tools/nip11';
import * as toolsnip17 from 'nostr-tools/nip17';
import { SimplePool } from 'nostr-tools/pool';
import * as libnip17 from '$lib/nip17';
@@ -25,6 +26,7 @@
let expiryEnabled = $state(false);
let expiryDays = $state(7);
let canSend = $state(false);
+ let canSendExpiring = $state(false);
const appendMultimap = (map: Map, key: string, value: object) => {
if (map.has(key)) {
@@ -66,6 +68,20 @@
return relays;
}
+ // Accepts a list of relays, and returns a list of the relays that support all the provided NIPs.
+ const relaysSupporting = async (relays: string[], nips: number[]) => {
+ let supportingRelays = [];
+
+ for (const relay of relays) {
+ const relayInfo = await fetchRelayInformation(relay);
+ if (nips.every(relay => relayInfo.supported_nips.includes(relay))) {
+ supportingRelays.push(relay);
+ }
+ }
+
+ return supportingRelays;
+ }
+
const expired = (event: object) => {
for (const tag of event.tags) {
if (tag[0] == "expiration") {
@@ -120,8 +136,11 @@
relayWarningShown = false;
loadEvents(relays);
});
- getPreferredRelays(recipient.pubkey)
- .then((relays) => canSend = relays && relays.length > 0);
+ getPreferredRelays(recipient.pubkey).then((relays) => {
+ canSend = relays && relays.length > 0;
+ relaysSupporting(relays, [40])
+ .then((supporting) => canSendExpiring = supporting.length > 0);
+ });
const sendMessage = async (message: string) => {
const expiry = expiryEnabled ? expiryDays : null;
@@ -139,10 +158,18 @@
message, sk, recipient.pubkey, user.pubkey, expiry);
}
- const recipientRelays = await getPreferredRelays(recipient.pubkey);
+ let recipientRelays = await getPreferredRelays(recipient.pubkey);
+ if (expiryEnabled) {
+ recipientRelays = relaysSupporting(recipientRelays, [40]);
+ }
const p1 = Promise.any(pool.publish(recipientRelays, event1));
- const senderRelays = await getPreferredRelays(user.pubkey);
+
+ let senderRelays = await getPreferredRelays(user.pubkey);
+ if (expiryEnabled) {
+ senderRelays = relaysSupporting(senderRelays, [40]);
+ }
const p2 = Promise.any(pool.publish(senderRelays, event2));
+
await Promise.all([p1, p2]);
getPreferredRelays(user.pubkey).then(loadEvents);
}
@@ -224,8 +251,11 @@
<textarea id="message-contents" bind:value={text}></textarea>
- <input type="checkbox" class="tiny" bind:checked={expiryEnabled}>{$t("dm.expiry")}: <input type="number" class="short" bind:value={expiryDays} disabled={!expiryEnabled} min="1" step="1" max="99999"> {$t("dm.days")}.
+ <input type="checkbox" class="tiny" bind:checked={expiryEnabled} disabled={!canSendExpiring}>{$t("dm.expiry")}: <input type="number" class="short" bind:value={expiryDays} disabled={!expiryEnabled} min="1" step="1" max="99999"> {$t("dm.days")}.
<p class="expiring">{$t("dm.fadedWarning")}</p>
+ {#if canSend && !canSendExpiring}
+ <p class="warning"><em>{$t("dm.cantSendExpiring").replace("[R]", recipient.username)}</em></p>
+ {/if}
<input id="send-message" type="button" class="btn" disabled={!canSend} value={canSend ? $t("dm.sendMessage") : $t("dm.relaysNotFound").replace("[R]", recipient.username)} on:click={async () => sendMessage(text)}>
{#if relayWarningShown}