diff --git a/packages/app/src/Element/Chat/DM.tsx b/packages/app/src/Element/Chat/DM.tsx index 42e9be7d..17c592bc 100644 --- a/packages/app/src/Element/Chat/DM.tsx +++ b/packages/app/src/Element/Chat/DM.tsx @@ -19,7 +19,7 @@ export interface DMProps { export default function DM(props: DMProps) { const { publicKey } = useLogin(s => ({ publicKey: s.publicKey })); - const publisher = useEventPublisher(); + const { publisher } = useEventPublisher(); const msg = props.data; const [content, setContent] = useState(); const { ref, inView } = useInView({ triggerOnce: true }); diff --git a/packages/app/src/Element/Chat/WriteMessage.tsx b/packages/app/src/Element/Chat/WriteMessage.tsx index 26eb3429..1a78f1b9 100644 --- a/packages/app/src/Element/Chat/WriteMessage.tsx +++ b/packages/app/src/Element/Chat/WriteMessage.tsx @@ -6,7 +6,6 @@ import { useState } from "react"; import useFileUpload from "Upload"; import { openFile } from "SnortUtils"; import Textarea from "../Textarea"; -import { System } from "index"; import { Chat } from "chat"; export default function WriteMessage({ chat }: { chat: Chat }) { @@ -15,7 +14,7 @@ export default function WriteMessage({ chat }: { chat: Chat }) { const [uploading, setUploading] = useState(false); const [otherEvents, setOtherEvents] = useState>([]); const [error, setError] = useState(""); - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); const uploader = useFileUpload(); async function attachFile() { @@ -59,7 +58,7 @@ export default function WriteMessage({ chat }: { chat: Chat }) { if (msg && publisher && chat) { setSending(true); const ev = await chat.createMessage(msg, publisher); - await chat.sendMessage(ev, System); + await chat.sendMessage(ev, system); setMsg(""); setSending(false); } diff --git a/packages/app/src/Element/Embed/PubkeyList.tsx b/packages/app/src/Element/Embed/PubkeyList.tsx index 5e2b2946..518e708b 100644 --- a/packages/app/src/Element/Embed/PubkeyList.tsx +++ b/packages/app/src/Element/Embed/PubkeyList.tsx @@ -16,7 +16,7 @@ import { WalletInvoiceState } from "Wallet"; export default function PubkeyList({ ev, className }: { ev: NostrEvent; className?: string }) { const wallet = useWallet(); const login = useLogin(); - const publisher = useEventPublisher(); + const { publisher } = useEventPublisher(); const ids = dedupe(ev.tags.filter(a => a[0] === "p").map(a => a[1])); async function zapAll() { diff --git a/packages/app/src/Element/Event/NoteBroadcaster.tsx b/packages/app/src/Element/Event/NoteBroadcaster.tsx index 83ee660e..0b3d2936 100644 --- a/packages/app/src/Element/Event/NoteBroadcaster.tsx +++ b/packages/app/src/Element/Event/NoteBroadcaster.tsx @@ -6,7 +6,6 @@ import { NostrEvent, OkResponse } from "@snort/system"; import AsyncButton from "Element/AsyncButton"; import Icon from "Icons/Icon"; import { getRelayName, sanitizeRelayUrl } from "SnortUtils"; -import { System } from "index"; import { removeRelay } from "Login"; import useLogin from "Hooks/useLogin"; import useEventPublisher from "Hooks/useEventPublisher"; @@ -23,7 +22,7 @@ export function NoteBroadcaster({ const [results, setResults] = useState>([]); const { formatMessage } = useIntl(); const login = useLogin(); - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); async function sendEventToRelays(ev: NostrEvent) { if (customRelays) { @@ -31,7 +30,7 @@ export function NoteBroadcaster({ await Promise.all( customRelays.map(async r => { try { - return await System.WriteOnceToRelay(r, ev); + return await system.WriteOnceToRelay(r, ev); } catch (e) { console.error(e); } @@ -39,7 +38,7 @@ export function NoteBroadcaster({ ), ); } else { - return await System.BroadcastEvent(ev, r => setResults(x => [...x, r])); + return await system.BroadcastEvent(ev, r => setResults(x => [...x, r])); } } @@ -58,7 +57,7 @@ export function NoteBroadcaster({ if (publisher) { removeRelay(login, unwrap(sanitizeRelayUrl(r.relay))); const ev = await publisher.contactList(login.follows.item, login.relays.item); - await System.BroadcastEvent(ev); + await system.BroadcastEvent(ev); setResults(s => s.filter(a => a.relay !== r.relay)); } } @@ -66,7 +65,7 @@ export function NoteBroadcaster({ async function retryPublish(r: OkResponse) { const ev = evs.find(a => a.id === r.id); if (ev) { - const rsp = await System.WriteOnceToRelay(unwrap(sanitizeRelayUrl(r.relay)), ev); + const rsp = await system.WriteOnceToRelay(unwrap(sanitizeRelayUrl(r.relay)), ev); setResults(s => s.map(x => { if (x.relay === r.relay && x.id === r.id) { diff --git a/packages/app/src/Element/Event/NoteContextMenu.tsx b/packages/app/src/Element/Event/NoteContextMenu.tsx index 04e9988c..b35cfb44 100644 --- a/packages/app/src/Element/Event/NoteContextMenu.tsx +++ b/packages/app/src/Element/Event/NoteContextMenu.tsx @@ -1,9 +1,9 @@ +import { useState } from "react"; import { FormattedMessage, useIntl } from "react-intl"; import { HexKey, Lists, NostrLink, TaggedNostrEvent } from "@snort/system"; import { Menu, MenuItem } from "@szhsin/react-menu"; import { TranslateHost } from "Const"; -import { System } from "index"; import Icon from "Icons/Icon"; import { setPinned, setBookmarked } from "Login"; import messages from "Element/messages"; @@ -11,7 +11,6 @@ import useLogin from "Hooks/useLogin"; import useModeration from "Hooks/useModeration"; import useEventPublisher from "Hooks/useEventPublisher"; import { ReBroadcaster } from "../ReBroadcaster"; -import { useState } from "react"; export interface NoteTranslation { text: string; @@ -30,7 +29,7 @@ export function NoteContextMenu({ ev, ...props }: NosteContextMenuProps) { const { formatMessage } = useIntl(); const login = useLogin(); const { mute, block } = useModeration(); - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); const [showBroadcast, setShowBroadcast] = useState(false); const lang = window.navigator.language; const langNames = new Intl.DisplayNames([...window.navigator.languages], { @@ -41,7 +40,7 @@ export function NoteContextMenu({ ev, ...props }: NosteContextMenuProps) { async function deleteEvent() { if (window.confirm(formatMessage(messages.ConfirmDeletion, { id: ev.id.substring(0, 8) })) && publisher) { const evDelete = await publisher.delete(ev.id); - System.BroadcastEvent(evDelete); + system.BroadcastEvent(evDelete); } } @@ -90,7 +89,7 @@ export function NoteContextMenu({ ev, ...props }: NosteContextMenuProps) { if (publisher) { const es = [...login.pinned.item, id]; const ev = await publisher.noteList(es, Lists.Pinned); - System.BroadcastEvent(ev); + system.BroadcastEvent(ev); setPinned(login, es, ev.created_at * 1000); } } @@ -99,7 +98,7 @@ export function NoteContextMenu({ ev, ...props }: NosteContextMenuProps) { if (publisher) { const es = [...login.bookmarked.item, id]; const ev = await publisher.noteList(es, Lists.Bookmarked); - System.BroadcastEvent(ev); + system.BroadcastEvent(ev); setBookmarked(login, es, ev.created_at * 1000); } } diff --git a/packages/app/src/Element/Event/NoteCreator.tsx b/packages/app/src/Element/Event/NoteCreator.tsx index f1880bb3..0393b249 100644 --- a/packages/app/src/Element/Event/NoteCreator.tsx +++ b/packages/app/src/Element/Event/NoteCreator.tsx @@ -25,7 +25,8 @@ export function NoteCreator() { const { formatMessage } = useIntl(); const uploader = useFileUpload(); const login = useLogin(s => ({ relays: s.relays, publicKey: s.publicKey, pow: s.preferences.pow })); - const publisher = login.pow ? useEventPublisher()?.pow(login.pow, GetPowWorker()) : useEventPublisher(); + const { publisher: pub } = useEventPublisher(); + const publisher = login.pow ? pub?.pow(login.pow, GetPowWorker()) : pub; const note = useNoteCreator(); const relays = login.relays; diff --git a/packages/app/src/Element/Event/NoteFooter.tsx b/packages/app/src/Element/Event/NoteFooter.tsx index 1ee72bd6..8f770eea 100644 --- a/packages/app/src/Element/Event/NoteFooter.tsx +++ b/packages/app/src/Element/Event/NoteFooter.tsx @@ -1,8 +1,8 @@ -import React, { HTMLProps, useContext, useEffect, useState } from "react"; +import React, { HTMLProps, useEffect, useState } from "react"; import { FormattedMessage, useIntl } from "react-intl"; import { useLongPress } from "use-long-press"; import { TaggedNostrEvent, ParsedZap, countLeadingZeros, NostrLink } from "@snort/system"; -import { SnortContext, useUserProfile } from "@snort/system-react"; +import { useUserProfile } from "@snort/system-react"; import { Menu, MenuItem } from "@szhsin/react-menu"; import { formatShort } from "Number"; @@ -17,7 +17,6 @@ import { useWallet } from "Wallet"; import useLogin from "Hooks/useLogin"; import { useInteractionCache } from "Hooks/useInteractionCache"; import { ZapPoolController } from "ZapPoolController"; -import { System } from "index"; import { Zapper, ZapTarget } from "Zapper"; import { getDisplayName } from "Element/User/DisplayName"; import { useNoteCreator } from "State/NoteCreator"; @@ -48,7 +47,6 @@ export interface NoteFooterProps { export default function NoteFooter(props: NoteFooterProps) { const { ev, positive, reposts, zaps } = props; - const system = useContext(SnortContext); const { formatMessage } = useIntl(); const { publicKey, @@ -57,7 +55,7 @@ export default function NoteFooter(props: NoteFooterProps) { } = useLogin(s => ({ preferences: s.preferences, publicKey: s.publicKey, readonly: s.readonly })); const author = useUserProfile(ev.pubkey); const interactionCache = useInteractionCache(publicKey, ev.id); - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); const note = useNoteCreator(n => ({ show: n.show, replyTo: n.replyTo, update: n.update, quote: n.quote })); const willRenderNoteCreator = note.show && (note.replyTo?.id === ev.id || note.quote); const [tip, setTip] = useState(false); @@ -93,7 +91,7 @@ export default function NoteFooter(props: NoteFooterProps) { async function react(content: string) { if (!hasReacted(content) && publisher) { const evLike = await publisher.react(ev, content); - System.BroadcastEvent(evLike); + system.BroadcastEvent(evLike); await interactionCache.react(); } } @@ -102,7 +100,7 @@ export default function NoteFooter(props: NoteFooterProps) { if (!hasReposted() && publisher) { if (!prefs.confirmReposts || window.confirm(formatMessage(messages.ConfirmRepost, { id: ev.id }))) { const evRepost = await publisher.repost(ev); - System.BroadcastEvent(evRepost); + system.BroadcastEvent(evRepost); await interactionCache.repost(); } } diff --git a/packages/app/src/Element/Event/NoteInner.tsx b/packages/app/src/Element/Event/NoteInner.tsx index de2a8c90..3557e396 100644 --- a/packages/app/src/Element/Event/NoteInner.tsx +++ b/packages/app/src/Element/Event/NoteInner.tsx @@ -10,7 +10,6 @@ import useEventPublisher from "Hooks/useEventPublisher"; import { NoteContextMenu, NoteTranslation } from "./NoteContextMenu"; import { UserCache } from "../../Cache"; import messages from "../messages"; -import { System } from "../../index"; import { setBookmarked, setPinned } from "../../Login"; import Text from "../Text"; import Reveal from "./Reveal"; @@ -37,7 +36,7 @@ export function NoteInner(props: NoteProps) { const { reactions, reposts, deletions, zaps } = useEventReactions(ev, related); const login = useLogin(); const { pinned, bookmarked } = login; - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); const [translated, setTranslated] = useState(); const { formatMessage } = useIntl(); @@ -58,7 +57,7 @@ export function NoteInner(props: NoteProps) { if (window.confirm(formatMessage(messages.ConfirmUnpin))) { const es = pinned.item.filter(e => e !== id); const ev = await publisher.noteList(es, Lists.Pinned); - System.BroadcastEvent(ev); + system.BroadcastEvent(ev); setPinned(login, es, ev.created_at * 1000); } } @@ -69,7 +68,7 @@ export function NoteInner(props: NoteProps) { if (window.confirm(formatMessage(messages.ConfirmUnbookmark))) { const es = bookmarked.item.filter(e => e !== id); const ev = await publisher.noteList(es, Lists.Bookmarked); - System.BroadcastEvent(ev); + system.BroadcastEvent(ev); setBookmarked(login, es, ev.created_at * 1000); } } diff --git a/packages/app/src/Element/Event/Poll.tsx b/packages/app/src/Element/Event/Poll.tsx index 3223914a..05f43ade 100644 --- a/packages/app/src/Element/Event/Poll.tsx +++ b/packages/app/src/Element/Event/Poll.tsx @@ -21,7 +21,7 @@ type PollTally = "zaps" | "pubkeys"; export default function Poll(props: PollProps) { const { formatMessage } = useIntl(); - const publisher = useEventPublisher(); + const { publisher } = useEventPublisher(); const { wallet } = useWallet(); const { preferences: prefs, publicKey: myPubKey, relays } = useLogin(); const pollerProfile = useUserProfile(props.ev.pubkey); diff --git a/packages/app/src/Element/IrisAccount/ActiveAccount.tsx b/packages/app/src/Element/IrisAccount/ActiveAccount.tsx index fb77be99..6fc1c9dd 100644 --- a/packages/app/src/Element/IrisAccount/ActiveAccount.tsx +++ b/packages/app/src/Element/IrisAccount/ActiveAccount.tsx @@ -1,10 +1,10 @@ +import { mapEventToProfile } from "@snort/system"; +import { useUserProfile } from "@snort/system-react"; + import AccountName from "./AccountName"; import useLogin from "../../Hooks/useLogin"; -import { useUserProfile } from "@snort/system-react"; -import { System } from "../../index"; import { UserCache } from "../../Cache"; import useEventPublisher from "../../Hooks/useEventPublisher"; -import { mapEventToProfile } from "@snort/system"; import FormattedMessage from "Element/FormattedMessage"; export default function ActiveAccount({ name = "", setAsPrimary = () => {} }) { @@ -13,7 +13,7 @@ export default function ActiveAccount({ name = "", setAsPrimary = () => {} }) { readonly: s.readonly, })); const profile = useUserProfile(publicKey); - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); async function saveProfile(nip05: string) { if (readonly) { @@ -35,7 +35,7 @@ export default function ActiveAccount({ name = "", setAsPrimary = () => {} }) { if (publisher) { const ev = await publisher.metadata(userCopy); - System.BroadcastEvent(ev); + system.BroadcastEvent(ev); const newProfile = mapEventToProfile(ev); if (newProfile) { diff --git a/packages/app/src/Element/Nip5Service.tsx b/packages/app/src/Element/Nip5Service.tsx index 434dfa9a..f52514ca 100644 --- a/packages/app/src/Element/Nip5Service.tsx +++ b/packages/app/src/Element/Nip5Service.tsx @@ -25,7 +25,6 @@ import SnortServiceProvider from "Nip05/SnortServiceProvider"; import { UserCache } from "Cache"; import messages from "./messages"; -import { System } from "index"; type Nip05ServiceProps = { name: string; @@ -45,7 +44,7 @@ export default function Nip5Service(props: Nip05ServiceProps) { const { formatMessage } = useIntl(); const { publicKey } = useLogin(s => ({ publicKey: s.publicKey })); const user = useUserProfile(publicKey); - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); const svc = useMemo(() => new ServiceProvider(props.service), [props.service]); const [serviceConfig, setServiceConfig] = useState(); const [error, setError] = useState(); @@ -216,7 +215,7 @@ export default function Nip5Service(props: Nip05ServiceProps) { nip05, } as UserMetadata; const ev = await publisher.metadata(newProfile); - System.BroadcastEvent(ev); + system.BroadcastEvent(ev); if (props.onSuccess) { props.onSuccess(nip05); } diff --git a/packages/app/src/Element/PinPrompt.tsx b/packages/app/src/Element/PinPrompt.tsx index 129a1230..e5811cca 100644 --- a/packages/app/src/Element/PinPrompt.tsx +++ b/packages/app/src/Element/PinPrompt.tsx @@ -93,7 +93,7 @@ export function PinPrompt({ export function LoginUnlock() { const login = useLogin(); - const publisher = useEventPublisher(); + const { publisher } = useEventPublisher(); async function encryptMigration(pin: string) { const k = unwrap(login.privateKey); diff --git a/packages/app/src/Element/Relay/Relay.tsx b/packages/app/src/Element/Relay/Relay.tsx index a576e6b4..8c059c0d 100644 --- a/packages/app/src/Element/Relay/Relay.tsx +++ b/packages/app/src/Element/Relay/Relay.tsx @@ -1,12 +1,12 @@ import "./Relay.css"; -import { useMemo } from "react"; +import { useContext, useMemo } from "react"; import FormattedMessage from "Element/FormattedMessage"; import { useNavigate } from "react-router-dom"; import { RelaySettings } from "@snort/system"; import { unixNowMs } from "@snort/shared"; import useRelayState from "Feed/RelayState"; -import { System } from "index"; +import { SnortContext } from "@snort/system-react"; import { getRelayName, unwrap } from "SnortUtils"; import useLogin from "Hooks/useLogin"; import { setRelays } from "Login"; @@ -20,9 +20,11 @@ export interface RelayProps { export default function Relay(props: RelayProps) { const navigate = useNavigate(); + const system = useContext(SnortContext); const login = useLogin(); + const relaySettings = unwrap( - login.relays.item[props.addr] ?? System.Sockets.find(a => a.address === props.addr)?.settings ?? {}, + login.relays.item[props.addr] ?? system.Sockets.find(a => a.address === props.addr)?.settings ?? {}, ); const state = useRelayState(props.addr); const name = useMemo(() => getRelayName(props.addr), [props.addr]); diff --git a/packages/app/src/Element/SendSats.tsx b/packages/app/src/Element/SendSats.tsx index 7bbd7a78..f06d601d 100644 --- a/packages/app/src/Element/SendSats.tsx +++ b/packages/app/src/Element/SendSats.tsx @@ -1,9 +1,8 @@ import "./SendSats.css"; -import React, { ReactNode, useContext, useEffect, useState } from "react"; +import React, { ReactNode, useEffect, useState } from "react"; import { useIntl, FormattedMessage } from "react-intl"; import { HexKey } from "@snort/system"; -import { SnortContext } from "@snort/system-react"; import { LNURLSuccessAction } from "@snort/shared"; import { formatShort } from "Number"; @@ -48,8 +47,7 @@ export default function SendSats(props: SendSatsProps) { const [success, setSuccess] = useState(); const [amount, setAmount] = useState(); - const system = useContext(SnortContext); - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); const walletState = useWallet(); const wallet = walletState.wallet; diff --git a/packages/app/src/Element/SubDebug.css b/packages/app/src/Element/SubDebug.css deleted file mode 100644 index 5f6b9fdb..00000000 --- a/packages/app/src/Element/SubDebug.css +++ /dev/null @@ -1,14 +0,0 @@ -.sub-debug { - display: block; - position: fixed; - top: 5px; - left: 5px; - opacity: 0.8; - border: 1px solid; - padding: 5px; - font-family: monospace; - font-size: x-small; - background-color: black; - z-index: 999999; - color: white; -} diff --git a/packages/app/src/Element/SubDebug.tsx b/packages/app/src/Element/SubDebug.tsx deleted file mode 100644 index f47477c6..00000000 --- a/packages/app/src/Element/SubDebug.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import "./SubDebug.css"; -import { useState } from "react"; -import { ReqFilter } from "@snort/system"; -import { useSystemState } from "@snort/system-react"; - -import useRelayState from "Feed/RelayState"; -import Tabs, { Tab } from "Element/Tabs"; -import { unwrap } from "SnortUtils"; -import { useCopy } from "useCopy"; -import { System } from "index"; - -function RelayInfo({ id }: { id: string }) { - const state = useRelayState(id); - return
{state?.connected ? <>{id} : {id}}
; -} - -function Queries() { - const qs = useSystemState(System); - const { copy } = useCopy(); - - function countElements(filters: Array) { - let total = 0; - for (const f of filters) { - for (const v of Object.values(f)) { - if (Array.isArray(v)) { - total += v.length; - } - } - } - return total; - } - - function queryInfo(q: { id: string; filters: Array; subFilters: Array }) { - return ( -
- {q.id} -
- copy(JSON.stringify(q.filters))} className="pointer"> -   Filters: {q.filters.length} ({countElements(q.filters)} elements) - -
- copy(JSON.stringify(q.subFilters))} className="pointer"> -   SubQueries: {q.subFilters.length} ({countElements(q.subFilters)} elements) - -
- ); - } - - return ( - <> - Queries - {qs?.queries.map(v => queryInfo(v))} - - ); -} - -const SubDebug = () => { - const [onTab, setTab] = useState(0); - - function connections() { - return ( - <> - Connections: - {System.Sockets.map(k => ( - - ))} - - ); - } - - const tabs: Tab[] = [ - { - text: "Connections", - value: 0, - }, - { - text: "Queries", - value: 1, - }, - ]; - - return ( -
- setTab(v.value)} tab={unwrap(tabs.find(a => a.value === onTab))} /> - {(() => { - switch (onTab) { - case 0: - return connections(); - case 1: - return ; - default: - return null; - } - })()} -
- ); -}; - -export default SubDebug; diff --git a/packages/app/src/Element/User/FollowButton.tsx b/packages/app/src/Element/User/FollowButton.tsx index e32e24b0..4f8902b3 100644 --- a/packages/app/src/Element/User/FollowButton.tsx +++ b/packages/app/src/Element/User/FollowButton.tsx @@ -5,7 +5,6 @@ import useEventPublisher from "Hooks/useEventPublisher"; import { parseId } from "SnortUtils"; import useLogin from "Hooks/useLogin"; import AsyncButton from "Element/AsyncButton"; -import { System } from "index"; import messages from "../messages"; import { FollowsFeed } from "Cache"; @@ -16,7 +15,7 @@ export interface FollowButtonProps { } export default function FollowButton(props: FollowButtonProps) { const pubkey = parseId(props.pubkey); - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); const { follows, relays, readonly } = useLogin(s => ({ follows: s.follows, relays: s.relays, readonly: s.readonly })); const isFollowing = follows.item.includes(pubkey); const baseClassname = props.className ? `${props.className} ` : ""; @@ -24,8 +23,8 @@ export default function FollowButton(props: FollowButtonProps) { async function follow(pubkey: HexKey) { if (publisher) { const ev = await publisher.contactList([pubkey, ...follows.item], relays.item); - System.BroadcastEvent(ev); - await FollowsFeed.backFill(System, [pubkey]); + system.BroadcastEvent(ev); + await FollowsFeed.backFill(system, [pubkey]); } } @@ -35,7 +34,7 @@ export default function FollowButton(props: FollowButtonProps) { follows.item.filter(a => a !== pubkey), relays.item, ); - System.BroadcastEvent(ev); + system.BroadcastEvent(ev); } } diff --git a/packages/app/src/Element/User/FollowListBase.tsx b/packages/app/src/Element/User/FollowListBase.tsx index d169d086..9e8dc2c3 100644 --- a/packages/app/src/Element/User/FollowListBase.tsx +++ b/packages/app/src/Element/User/FollowListBase.tsx @@ -1,17 +1,16 @@ import { ReactNode } from "react"; import FormattedMessage from "Element/FormattedMessage"; import { HexKey } from "@snort/system"; +import { dedupe } from "@snort/shared"; import useEventPublisher from "Hooks/useEventPublisher"; import ProfilePreview from "Element/User/ProfilePreview"; import useLogin from "Hooks/useLogin"; -import { System } from "index"; import messages from "../messages"; import { FollowsFeed } from "Cache"; import AsyncButton from "../AsyncButton"; import { setFollows } from "Login"; -import { dedupe } from "@snort/shared"; export interface FollowListBaseProps { pubkeys: HexKey[]; @@ -32,15 +31,15 @@ export default function FollowListBase({ actions, profileActions, }: FollowListBaseProps) { - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); const login = useLogin(); async function followAll() { if (publisher) { const newFollows = dedupe([...pubkeys, ...login.follows.item]); const ev = await publisher.contactList(newFollows, login.relays.item); - System.BroadcastEvent(ev); - await FollowsFeed.backFill(System, pubkeys); + system.BroadcastEvent(ev); + await FollowsFeed.backFill(system, pubkeys); setFollows(login, newFollows, ev.created_at); } } diff --git a/packages/app/src/Feed/LoginFeed.ts b/packages/app/src/Feed/LoginFeed.ts index 400bb6dc..03452c5b 100644 --- a/packages/app/src/Feed/LoginFeed.ts +++ b/packages/app/src/Feed/LoginFeed.ts @@ -24,7 +24,6 @@ import { SnortPubKey } from "Const"; import { SubscriptionEvent } from "Subscription"; import useRelaysFeedFollows from "./RelaysFeedFollows"; import { FollowsFeed, GiftsCache, Notifications, UserRelays } from "Cache"; -import { System } from "index"; import { Nip28Chats, Nip4Chats } from "chat"; import { useRefreshFeedCache } from "Hooks/useRefreshFeedcache"; @@ -35,12 +34,16 @@ export default function useLoginFeed() { const login = useLogin(); const { publicKey: pubKey, readNotifications, follows } = login; const { isMuted } = useModeration(); - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); useRefreshFeedCache(Notifications, true); useRefreshFeedCache(FollowsFeed, true); useRefreshFeedCache(GiftsCache, true); + useEffect(() => { + system.checkSigs = login.preferences.checkSigs; + }, [login]); + const subLogin = useMemo(() => { if (!login || !pubKey) return null; @@ -88,7 +91,7 @@ export default function useLoginFeed() { const pTags = contactList.tags.filter(a => a[0] === "p").map(a => a[1]); setFollows(login, pTags, contactList.created_at * 1000); - FollowsFeed.backFillIfMissing(System, pTags); + FollowsFeed.backFillIfMissing(system, pTags); } Nip4Chats.onEvent(loginFeed.data); @@ -202,7 +205,7 @@ export default function useLoginFeed() { useEffect(() => { UserRelays.buffer(follows.item).catch(console.error); - System.ProfileLoader.TrackMetadata(follows.item); // always track follows profiles + system.ProfileLoader.TrackMetadata(follows.item); // always track follows profiles }, [follows.item]); const fRelays = useRelaysFeedFollows(follows.item); diff --git a/packages/app/src/Feed/RelayState.ts b/packages/app/src/Feed/RelayState.ts index c5c5c5a1..9af0f454 100644 --- a/packages/app/src/Feed/RelayState.ts +++ b/packages/app/src/Feed/RelayState.ts @@ -1,6 +1,8 @@ -import { System } from "index"; +import { useContext } from "react"; +import { SnortContext } from "@snort/system-react"; export default function useRelayState(addr: string) { - const c = System.Sockets.find(a => a.address === addr); + const system = useContext(SnortContext); + const c = system.Sockets.find(a => a.address === addr); return c; } diff --git a/packages/app/src/Feed/TimelineFeed.ts b/packages/app/src/Feed/TimelineFeed.ts index 490fb681..26bcf15f 100644 --- a/packages/app/src/Feed/TimelineFeed.ts +++ b/packages/app/src/Feed/TimelineFeed.ts @@ -89,7 +89,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel const rb = createBuilder(); if (rb) { if (options.method === "LIMIT_UNTIL") { - rb.filter.until(until).limit(200); + rb.filter.until(until).limit(100); } else { rb.filter.since(since).until(until); if (since === undefined) { diff --git a/packages/app/src/Hooks/useEventPublisher.tsx b/packages/app/src/Hooks/useEventPublisher.tsx index b686b0c8..0dafd295 100644 --- a/packages/app/src/Hooks/useEventPublisher.tsx +++ b/packages/app/src/Hooks/useEventPublisher.tsx @@ -1,8 +1,11 @@ +import { useContext } from "react"; +import { SnortContext } from "@snort/system-react"; import useLogin from "Hooks/useLogin"; import { LoginStore, createPublisher, sessionNeedsPin } from "Login"; export default function useEventPublisher() { const login = useLogin(); + const system = useContext(SnortContext); let existing = LoginStore.getPublisher(login.id); @@ -12,5 +15,8 @@ export default function useEventPublisher() { LoginStore.setPublisher(login.id, existing); } } - return existing; + return { + publisher: existing, + system, + }; } diff --git a/packages/app/src/Hooks/useLoginRelays.tsx b/packages/app/src/Hooks/useLoginRelays.tsx index b09a2bb9..3d413726 100644 --- a/packages/app/src/Hooks/useLoginRelays.tsx +++ b/packages/app/src/Hooks/useLoginRelays.tsx @@ -1,19 +1,20 @@ -import { System } from "index"; import { useEffect } from "react"; import useLogin from "./useLogin"; +import useEventPublisher from "./useEventPublisher"; export function useLoginRelays() { const { relays } = useLogin(); + const { system } = useEventPublisher(); useEffect(() => { if (relays) { (async () => { for (const [k, v] of Object.entries(relays.item)) { - await System.ConnectToRelay(k, v); + await system.ConnectToRelay(k, v); } - for (const v of System.Sockets) { + for (const v of system.Sockets) { if (!relays.item[v.address] && !v.ephemeral) { - System.DisconnectRelay(v.address); + system.DisconnectRelay(v.address); } } })(); diff --git a/packages/app/src/Hooks/useModeration.tsx b/packages/app/src/Hooks/useModeration.tsx index 36b767ed..3156b9bf 100644 --- a/packages/app/src/Hooks/useModeration.tsx +++ b/packages/app/src/Hooks/useModeration.tsx @@ -3,17 +3,16 @@ import useEventPublisher from "Hooks/useEventPublisher"; import useLogin from "Hooks/useLogin"; import { setBlocked, setMuted } from "Login"; import { appendDedupe } from "SnortUtils"; -import { System } from "index"; export default function useModeration() { const login = useLogin(); const { muted, blocked, appData } = login; - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); async function setMutedList(pub: HexKey[], priv: HexKey[]) { if (publisher) { const ev = await publisher.muted(pub, priv); - System.BroadcastEvent(ev); + system.BroadcastEvent(ev); return ev.created_at * 1000; } return 0; diff --git a/packages/app/src/Hooks/useRefreshFeedcache.tsx b/packages/app/src/Hooks/useRefreshFeedcache.tsx index 7ad793e3..5e66d400 100644 --- a/packages/app/src/Hooks/useRefreshFeedcache.tsx +++ b/packages/app/src/Hooks/useRefreshFeedcache.tsx @@ -1,5 +1,4 @@ -import { SnortContext } from "@snort/system-react"; -import { useContext, useEffect, useMemo } from "react"; +import { useEffect, useMemo } from "react"; import { NoopStore, RequestBuilder, TaggedNostrEvent } from "@snort/system"; import { RefreshFeedCache } from "Cache/RefreshFeedCache"; @@ -8,9 +7,8 @@ import useEventPublisher from "./useEventPublisher"; import { unwrap } from "@snort/shared"; export function useRefreshFeedCache(c: RefreshFeedCache, leaveOpen = false) { - const system = useContext(SnortContext); const login = useLogin(); - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); const sub = useMemo(() => { if (login.publicKey) { diff --git a/packages/app/src/Login/Functions.ts b/packages/app/src/Login/Functions.ts index f6af4681..f4c95bf3 100644 --- a/packages/app/src/Login/Functions.ts +++ b/packages/app/src/Login/Functions.ts @@ -1,4 +1,12 @@ -import { RelaySettings, EventPublisher, Nip46Signer, Nip7Signer, PrivateKeySigner, KeyStorage } from "@snort/system"; +import { + RelaySettings, + EventPublisher, + Nip46Signer, + Nip7Signer, + PrivateKeySigner, + KeyStorage, + SystemInterface, +} from "@snort/system"; import { unixNowMs } from "@snort/shared"; import * as secp from "@noble/curves/secp256k1"; import * as utils from "@noble/curves/abstract/utils"; @@ -8,7 +16,6 @@ import { LoginStore, UserPreferences, LoginSession, LoginSessionType, SnortAppDa import { generateBip39Entropy, entropyToPrivateKey } from "nip6"; import { bech32ToHex, dedupeById, randomSample, sanitizeRelayUrl, unwrap } from "SnortUtils"; import { SubscriptionEvent } from "Subscription"; -import { System } from "index"; import { Chats, FollowsFeed, GiftsCache, Notifications } from "Cache"; import { Nip7OsSigner } from "./Nip7OsSigner"; @@ -63,7 +70,7 @@ export function clearEntropy(state: LoginSession) { /** * Generate a new key and login with this generated key */ -export async function generateNewLogin(pin: (key: string) => Promise) { +export async function generateNewLogin(system: SystemInterface, pin: (key: string) => Promise) { const ent = generateBip39Entropy(); const entropy = utils.bytesToHex(ent); const privateKey = entropyToPrivateKey(ent); @@ -87,7 +94,7 @@ export async function generateNewLogin(pin: (key: string) => Promise const publicKey = utils.bytesToHex(secp.schnorr.getPublicKey(privateKey)); const publisher = EventPublisher.privateKey(privateKey); const ev = await publisher.contactList([bech32ToHex(SnortPubKey), publicKey], newRelays); - System.BroadcastEvent(ev); + system.BroadcastEvent(ev); LoginStore.loginWithPrivateKey(await pin(privateKey), entropy, newRelays); } diff --git a/packages/app/src/Login/MultiAccountStore.ts b/packages/app/src/Login/MultiAccountStore.ts index a471744b..27461672 100644 --- a/packages/app/src/Login/MultiAccountStore.ts +++ b/packages/app/src/Login/MultiAccountStore.ts @@ -74,11 +74,12 @@ export class MultiAccountStore extends ExternalStore { if (!this.#activeAccount) { this.#activeAccount = this.#accounts.keys().next().value; } - // reset readonly on load for (const [, v] of this.#accounts) { + // reset readonly on load if (v.type === LoginSessionType.PrivateKey && v.readonly) { v.readonly = false; } + // fill possibly undefined (migrate up) v.appData ??= { item: { mutedWords: [], @@ -86,6 +87,7 @@ export class MultiAccountStore extends ExternalStore { timestamp: 0, }; v.extraChats ??= []; + v.preferences.checkSigs ??= true; if (v.privateKeyData) { v.privateKeyData = KeyStorage.fromPayload(v.privateKeyData as object); } diff --git a/packages/app/src/Login/Preferences.ts b/packages/app/src/Login/Preferences.ts index 15f09085..f8cec937 100644 --- a/packages/app/src/Login/Preferences.ts +++ b/packages/app/src/Login/Preferences.ts @@ -86,6 +86,11 @@ export interface UserPreferences { * Show user status messages on profiles */ showStatus?: boolean; + + /** + * Check event signatures + */ + checkSigs: boolean; } export const DefaultPreferences = { @@ -105,4 +110,5 @@ export const DefaultPreferences = { telemetry: true, showBadges: false, showStatus: true, + checkSigs: true, } as UserPreferences; diff --git a/packages/app/src/Pages/Debug.tsx b/packages/app/src/Pages/Debug.tsx deleted file mode 100644 index 37c650d6..00000000 --- a/packages/app/src/Pages/Debug.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import SubDebug from "Element/SubDebug"; - -export default function DebugPage() { - return ( - <> - - - ); -} diff --git a/packages/app/src/Pages/HashTagsPage.tsx b/packages/app/src/Pages/HashTagsPage.tsx index 132b9283..d3bbc736 100644 --- a/packages/app/src/Pages/HashTagsPage.tsx +++ b/packages/app/src/Pages/HashTagsPage.tsx @@ -6,7 +6,6 @@ import Timeline from "Element/Feed/Timeline"; import useEventPublisher from "Hooks/useEventPublisher"; import useLogin from "Hooks/useLogin"; import { setTags } from "Login"; -import { System } from "index"; const HashTagsPage = () => { const params = useParams(); @@ -15,12 +14,12 @@ const HashTagsPage = () => { const isFollowing = useMemo(() => { return login.tags.item.includes(tag); }, [login, tag]); - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); async function followTags(ts: string[]) { if (publisher) { const ev = await publisher.tags(ts); - System.BroadcastEvent(ev); + system.BroadcastEvent(ev); setTags(login, ts, ev.created_at * 1000); } } diff --git a/packages/app/src/Pages/LoginPage.tsx b/packages/app/src/Pages/LoginPage.tsx index c8e0a899..a2a2265c 100644 --- a/packages/app/src/Pages/LoginPage.tsx +++ b/packages/app/src/Pages/LoginPage.tsx @@ -19,6 +19,7 @@ import QrCode from "Element/QrCode"; import Copy from "Element/Copy"; import { delay } from "SnortUtils"; import { PinPrompt } from "Element/PinPrompt"; +import useEventPublisher from "Hooks/useEventPublisher"; declare global { interface Window { @@ -85,6 +86,7 @@ export default function LoginPage() { const { proxy } = useImgProxy(); const loginHandler = useLoginHandler(); const hasNip7 = "nostr" in window; + const { system } = useEventPublisher(); const hasSubtleCrypto = window.crypto.subtle !== undefined; const [nostrConnect, setNostrConnect] = useState(""); @@ -123,7 +125,7 @@ export default function LoginPage() { async function makeRandomKey(pin?: string) { try { - await generateNewLogin(key => makeKeyStore(key, pin)); + await generateNewLogin(system, key => makeKeyStore(key, pin)); window.plausible?.("Generate Account"); navigate("/new"); } catch (e) { diff --git a/packages/app/src/Pages/Root.tsx b/packages/app/src/Pages/Root.tsx index 69255d00..afea7a37 100644 --- a/packages/app/src/Pages/Root.tsx +++ b/packages/app/src/Pages/Root.tsx @@ -3,9 +3,9 @@ import { Link, Outlet, RouteObject, useParams } from "react-router-dom"; import FormattedMessage from "Element/FormattedMessage"; import { unixNow } from "@snort/shared"; import { NostrLink } from "@snort/system"; +import { SnortContext } from "@snort/system-react"; import Timeline from "Element/Feed/Timeline"; -import { System } from "index"; import { TimelineSubject } from "Feed/TimelineFeed"; import { debounce, getRelayName, sha256 } from "SnortUtils"; import useLogin from "Hooks/useLogin"; @@ -63,6 +63,7 @@ export const GlobalTab = () => { const [relay, setRelay] = useState(); const [allRelays, setAllRelays] = useState(); const [now] = useState(unixNow()); + const system = useContext(SnortContext); const subject: TimelineSubject = { type: "global", @@ -111,7 +112,7 @@ export const GlobalTab = () => { useEffect(() => { return debounce(500, () => { const ret: RelayOption[] = []; - System.Sockets.forEach(v => { + system.Sockets.forEach(v => { ret.push({ url: v.address, paid: v.info?.limitation?.payment_required ?? false, diff --git a/packages/app/src/Pages/ZapPool.tsx b/packages/app/src/Pages/ZapPool.tsx index 3d1504a3..e49150cc 100644 --- a/packages/app/src/Pages/ZapPool.tsx +++ b/packages/app/src/Pages/ZapPool.tsx @@ -12,7 +12,7 @@ import { bech32ToHex, getRelayName, unwrap } from "SnortUtils"; import { ZapPoolController, ZapPoolRecipient, ZapPoolRecipientType } from "ZapPoolController"; import AsyncButton from "Element/AsyncButton"; import { useWallet } from "Wallet"; -import { System } from "index"; +import useEventPublisher from "Hooks/useEventPublisher"; const DataProviders = [ { @@ -71,6 +71,7 @@ function ZapTarget({ target }: { target: ZapPoolRecipient }) { export default function ZapPoolPage() { const login = useLogin(); + const { system } = useEventPublisher(); const zapPool = useSyncExternalStore( c => ZapPoolController.hook(c), () => ZapPoolController.snapshot(), @@ -78,7 +79,7 @@ export default function ZapPoolPage() { const { wallet } = useWallet(); const relayConnections = useMemo(() => { - return System.Sockets.map(a => { + return system.Sockets.map(a => { if (a.info?.pubkey && !a.ephemeral) { return { address: a.address, diff --git a/packages/app/src/Pages/new/ProfileSetup.tsx b/packages/app/src/Pages/new/ProfileSetup.tsx index dd4d17a6..4fe4c160 100644 --- a/packages/app/src/Pages/new/ProfileSetup.tsx +++ b/packages/app/src/Pages/new/ProfileSetup.tsx @@ -10,7 +10,6 @@ import useLogin from "Hooks/useLogin"; import { UserCache } from "Cache"; import AvatarEditor from "Element/User/AvatarEditor"; import { DISCOVER } from "."; -import { System } from "index"; import messages from "./messages"; @@ -20,7 +19,7 @@ export default function ProfileSetup() { const [username, setUsername] = useState(""); const [picture, setPicture] = useState(""); const { formatMessage } = useIntl(); - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); const navigate = useNavigate(); useEffect(() => { @@ -37,7 +36,7 @@ export default function ProfileSetup() { name: username, picture, }); - System.BroadcastEvent(ev); + system.BroadcastEvent(ev); const profile = mapEventToProfile(ev); if (profile) { UserCache.set(profile); diff --git a/packages/app/src/Pages/settings/Preferences.tsx b/packages/app/src/Pages/settings/Preferences.tsx index 8991b4fd..d87ea5bb 100644 --- a/packages/app/src/Pages/settings/Preferences.tsx +++ b/packages/app/src/Pages/settings/Preferences.tsx @@ -176,6 +176,23 @@ const PreferencesPage = () => { +
+
+

+ +

+ + + +
+
+ updatePreferences(login, { ...perf, checkSigs: e.target.checked })} + /> +
+

diff --git a/packages/app/src/Pages/settings/Profile.tsx b/packages/app/src/Pages/settings/Profile.tsx index 15f66c90..8382539b 100644 --- a/packages/app/src/Pages/settings/Profile.tsx +++ b/packages/app/src/Pages/settings/Profile.tsx @@ -5,7 +5,6 @@ import { useNavigate } from "react-router-dom"; import { mapEventToProfile } from "@snort/system"; import { useUserProfile } from "@snort/system-react"; -import { System } from "index"; import useEventPublisher from "Hooks/useEventPublisher"; import { openFile } from "SnortUtils"; import useFileUpload from "Upload"; @@ -24,7 +23,7 @@ export default function ProfileSettings(props: ProfileSettingsProps) { const navigate = useNavigate(); const { publicKey: id, readonly } = useLogin(s => ({ publicKey: s.publicKey, readonly: s.readonly })); const user = useUserProfile(id ?? ""); - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); const uploader = useFileUpload(); const [name, setName] = useState(); @@ -70,7 +69,7 @@ export default function ProfileSettings(props: ProfileSettingsProps) { if (publisher) { const ev = await publisher.metadata(userCopy); - System.BroadcastEvent(ev); + system.BroadcastEvent(ev); const newProfile = mapEventToProfile(ev); if (newProfile) { diff --git a/packages/app/src/Pages/settings/RelayInfo.tsx b/packages/app/src/Pages/settings/RelayInfo.tsx index 196dc47f..f7e837c5 100644 --- a/packages/app/src/Pages/settings/RelayInfo.tsx +++ b/packages/app/src/Pages/settings/RelayInfo.tsx @@ -3,18 +3,19 @@ import ProfilePreview from "Element/User/ProfilePreview"; import useRelayState from "Feed/RelayState"; import { useNavigate, useParams } from "react-router-dom"; import { parseId, unwrap } from "SnortUtils"; -import { System } from "index"; import { removeRelay } from "Login"; import useLogin from "Hooks/useLogin"; import messages from "./messages"; +import useEventPublisher from "Hooks/useEventPublisher"; const RelayInfo = () => { const params = useParams(); const navigate = useNavigate(); const login = useLogin(); + const { system } = useEventPublisher(); - const conn = System.Sockets.find(a => a.id === params.id); + const conn = system.Sockets.find(a => a.id === params.id); const stats = useRelayState(conn?.address ?? ""); return ( diff --git a/packages/app/src/Pages/settings/Relays.tsx b/packages/app/src/Pages/settings/Relays.tsx index 035d9f39..bb6f7153 100644 --- a/packages/app/src/Pages/settings/Relays.tsx +++ b/packages/app/src/Pages/settings/Relays.tsx @@ -5,7 +5,6 @@ import { unixNowMs } from "@snort/shared"; import { randomSample } from "SnortUtils"; import Relay from "Element/Relay/Relay"; import useEventPublisher from "Hooks/useEventPublisher"; -import { System } from "index"; import useLogin from "Hooks/useLogin"; import { setRelays } from "Login"; import AsyncButton from "Element/AsyncButton"; @@ -13,25 +12,25 @@ import AsyncButton from "Element/AsyncButton"; import messages from "./messages"; const RelaySettingsPage = () => { - const publisher = useEventPublisher(); + const { publisher, system } = useEventPublisher(); const login = useLogin(); const relays = login.relays; const [newRelay, setNewRelay] = useState(); const otherConnections = useMemo(() => { - return System.Sockets.filter(a => relays.item[a.address] === undefined); + return system.Sockets.filter(a => relays.item[a.address] === undefined); }, [relays]); async function saveRelays() { if (publisher) { const ev = await publisher.contactList(login.follows.item, login.relays.item); - System.BroadcastEvent(ev); + system.BroadcastEvent(ev); try { const onlineRelays = await fetch("https://api.nostr.watch/v1/online").then(r => r.json()); const relayList = await publisher.relayList(login.relays.item); const rs = Object.keys(relays.item).concat(randomSample(onlineRelays, 20)); rs.forEach(r => { - System.WriteOnceToRelay(r, relayList); + system.WriteOnceToRelay(r, relayList); }); } catch (error) { console.error(error); diff --git a/packages/app/src/Pages/settings/handle/LNAddress.tsx b/packages/app/src/Pages/settings/handle/LNAddress.tsx index 1f4d5fc0..bf6133c7 100644 --- a/packages/app/src/Pages/settings/handle/LNAddress.tsx +++ b/packages/app/src/Pages/settings/handle/LNAddress.tsx @@ -9,7 +9,7 @@ import SnortServiceProvider, { ManageHandle } from "Nip05/SnortServiceProvider"; export default function LNForwardAddress({ handle }: { handle: ManageHandle }) { const { formatMessage } = useIntl(); - const publisher = useEventPublisher(); + const { publisher } = useEventPublisher(); const [newAddress, setNewAddress] = useState(handle.lnAddress ?? ""); const [error, setError] = useState(""); diff --git a/packages/app/src/Pages/settings/handle/ListHandles.tsx b/packages/app/src/Pages/settings/handle/ListHandles.tsx index 7677f72f..cd3b6bf7 100644 --- a/packages/app/src/Pages/settings/handle/ListHandles.tsx +++ b/packages/app/src/Pages/settings/handle/ListHandles.tsx @@ -8,7 +8,7 @@ import SnortServiceProvider, { ManageHandle } from "Nip05/SnortServiceProvider"; export default function ListHandles() { const navigate = useNavigate(); - const publisher = useEventPublisher(); + const { publisher } = useEventPublisher(); const [handles, setHandles] = useState>([]); useEffect(() => { diff --git a/packages/app/src/Pages/settings/handle/TransferHandle.tsx b/packages/app/src/Pages/settings/handle/TransferHandle.tsx index d21249f2..5cf311e0 100644 --- a/packages/app/src/Pages/settings/handle/TransferHandle.tsx +++ b/packages/app/src/Pages/settings/handle/TransferHandle.tsx @@ -1,14 +1,15 @@ +import { useState } from "react"; +import { FormattedMessage, useIntl } from "react-intl"; +import { useNavigate } from "react-router-dom"; + import { ApiHost } from "Const"; import AsyncButton from "Element/AsyncButton"; import useEventPublisher from "Hooks/useEventPublisher"; import { ServiceError } from "Nip05/ServiceProvider"; import SnortServiceProvider, { ManageHandle } from "Nip05/SnortServiceProvider"; -import { useState } from "react"; -import { FormattedMessage, useIntl } from "react-intl"; -import { useNavigate } from "react-router-dom"; export default function TransferHandle({ handle }: { handle: ManageHandle }) { - const publisher = useEventPublisher(); + const { publisher } = useEventPublisher(); const navigate = useNavigate(); const { formatMessage } = useIntl(); diff --git a/packages/app/src/Pages/subscribe/ManageSubscription.tsx b/packages/app/src/Pages/subscribe/ManageSubscription.tsx index b4b194c4..6557ec79 100644 --- a/packages/app/src/Pages/subscribe/ManageSubscription.tsx +++ b/packages/app/src/Pages/subscribe/ManageSubscription.tsx @@ -9,7 +9,7 @@ import { mapSubscriptionErrorCode } from "."; import SubscriptionCard from "./SubscriptionCard"; export default function ManageSubscriptionPage() { - const publisher = useEventPublisher(); + const { publisher } = useEventPublisher(); const api = new SnortApi(undefined, publisher); const navigate = useNavigate(); diff --git a/packages/app/src/Pages/subscribe/SubscriptionCard.tsx b/packages/app/src/Pages/subscribe/SubscriptionCard.tsx index 610cd39f..8c0519f1 100644 --- a/packages/app/src/Pages/subscribe/SubscriptionCard.tsx +++ b/packages/app/src/Pages/subscribe/SubscriptionCard.tsx @@ -12,7 +12,7 @@ import { SnortNostrAddressService } from "Pages/NostrAddressPage"; import Nip05 from "Element/User/Nip05"; export default function SubscriptionCard({ sub }: { sub: Subscription }) { - const publisher = useEventPublisher(); + const { publisher } = useEventPublisher(); const { formatMessage } = useIntl(); const created = new Date(sub.created * 1000); diff --git a/packages/app/src/Pages/subscribe/index.tsx b/packages/app/src/Pages/subscribe/index.tsx index 9167956f..00c299bd 100644 --- a/packages/app/src/Pages/subscribe/index.tsx +++ b/packages/app/src/Pages/subscribe/index.tsx @@ -58,7 +58,7 @@ export function mapSubscriptionErrorCode(c: SubscriptionError) { } export function SubscribePage() { - const publisher = useEventPublisher(); + const { publisher } = useEventPublisher(); const api = new SnortApi(undefined, publisher); const [invoice, setInvoice] = useState(""); const [error, setError] = useState(); diff --git a/packages/app/src/Upload/index.ts b/packages/app/src/Upload/index.ts index ce993af4..93f641ae 100644 --- a/packages/app/src/Upload/index.ts +++ b/packages/app/src/Upload/index.ts @@ -41,7 +41,6 @@ export interface Uploader { export default function useFileUpload(): Uploader { const fileUploader = useLogin().preferences.fileUploader; - //const publisher = useEventPublisher(); switch (fileUploader) { case "nostr.build": { diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx index d2ece538..55b02de6 100644 --- a/packages/app/src/index.tsx +++ b/packages/app/src/index.tsx @@ -43,7 +43,6 @@ import NostrLinkHandler from "Pages/NostrLinkHandler"; import { ThreadRoute } from "Element/Event/Thread"; import { SubscribeRoutes } from "Pages/subscribe"; import ZapPoolPage from "Pages/ZapPool"; -import DebugPage from "Pages/Debug"; import { db } from "Db"; import { preload, RelayMetrics, SystemDb, UserCache, UserRelays } from "Cache"; import { LoginStore } from "Login"; @@ -80,7 +79,7 @@ export const GetPowWorker = () => (hasWasm ? new WasmPowWorker() : unwrap(Defaul /** * Singleton nostr system */ -export const System = new NostrSystem({ +const System = new NostrSystem({ relayCache: UserRelays, profileCache: UserCache, relayMetrics: RelayMetrics, @@ -229,10 +228,6 @@ export const router = createBrowserRouter([ ...NewUserRoutes, ...WalletRoutes, ...(CONFIG.features.subscriptions ? SubscribeRoutes : []), - { - path: "/debug", - element: , - }, { path: "/*", element: , diff --git a/packages/app/src/lang.json b/packages/app/src/lang.json index 679be1f7..700ad1b4 100644 --- a/packages/app/src/lang.json +++ b/packages/app/src/lang.json @@ -90,6 +90,9 @@ "1nYUGC": { "defaultMessage": "{n} Following" }, + "1o2BgB": { + "defaultMessage": "Check Signatures" + }, "1udzha": { "defaultMessage": "Conversations" }, @@ -832,6 +835,9 @@ "UJTWqI": { "defaultMessage": "Remove from my relays" }, + "UNjfWJ": { + "defaultMessage": "Check all event signatures received from relays" + }, "UT7Nkj": { "defaultMessage": "New Chat" }, diff --git a/packages/app/src/translations/en.json b/packages/app/src/translations/en.json index 275e08f8..daa444a9 100644 --- a/packages/app/src/translations/en.json +++ b/packages/app/src/translations/en.json @@ -29,6 +29,7 @@ "1c4YST": "Connected to: {node} 🎉", "1iQ8GN": "Toggle Preview", "1nYUGC": "{n} Following", + "1o2BgB": "Check Signatures", "1udzha": "Conversations", "2/2yg+": "Add", "25V4l1": "Banner", @@ -272,6 +273,7 @@ "Tpy00S": "People", "UDYlxu": "Pending Subscriptions", "UJTWqI": "Remove from my relays", + "UNjfWJ": "Check all event signatures received from relays", "UT7Nkj": "New Chat", "UUPFlt": "Users must accept the content warning to show the content of your note.", "Up5U7K": "Block", diff --git a/packages/system/src/event-ext.ts b/packages/system/src/event-ext.ts index 575c5d53..ff763023 100644 --- a/packages/system/src/event-ext.ts +++ b/packages/system/src/event-ext.ts @@ -176,6 +176,6 @@ export abstract class EventExt { if (type === EventType.ParameterizedReplaceable) { if (!findTag(ev, "d")) return false; } - return EventExt.verify(ev); + return true; } } diff --git a/packages/system/src/index.ts b/packages/system/src/index.ts index 26548f24..51b26af0 100644 --- a/packages/system/src/index.ts +++ b/packages/system/src/index.ts @@ -41,6 +41,11 @@ export * from "./cache/user-metadata"; export * from "./cache/relay-metric"; export interface SystemInterface { + /** + * Check event signatures (reccomended) + */ + checkSigs: boolean; + /** * Handler function for NIP-42 */ diff --git a/packages/system/src/nostr-system.ts b/packages/system/src/nostr-system.ts index e741b3aa..e4428f8f 100644 --- a/packages/system/src/nostr-system.ts +++ b/packages/system/src/nostr-system.ts @@ -81,6 +81,11 @@ export class NostrSystem extends ExternalStore implements System */ #queryOptimizer: QueryOptimizer; + /** + * Check event signatures (reccomended) + */ + checkSigs: boolean; + constructor(props: { authHandler?: AuthHandler; relayCache?: FeedCache; @@ -89,6 +94,7 @@ export class NostrSystem extends ExternalStore implements System eventsCache?: FeedCache; queryOptimizer?: QueryOptimizer; db?: SnortSystemDb; + checkSigs?: boolean; }) { super(); this.#handleAuth = props.authHandler; @@ -100,6 +106,7 @@ export class NostrSystem extends ExternalStore implements System this.#profileLoader = new ProfileLoaderService(this, this.#profileCache); this.#relayMetrics = new RelayMetricHandler(this.#relayMetricsCache); + this.checkSigs = props.checkSigs ?? true; this.#cleanup(); } @@ -183,6 +190,10 @@ export class NostrSystem extends ExternalStore implements System this.#log("Rejecting invalid event %O", ev); return; } + if (this.checkSigs && !EventExt.verify(ev)) { + this.#log("Invalid sig %O", ev); + return; + } for (const [, v] of this.Queries) { v.handleEvent(sub, ev);