Remove legacy npub1 bunker URI format

This commit is contained in:
hzrd149 2024-11-14 13:44:58 -06:00
parent 8c7dac82f8
commit 0438f3ef28
7 changed files with 71 additions and 151 deletions

View File

@ -0,0 +1,5 @@
---
"nostrudel": minor
---
Remove legacy npub1 bunker URI format

72
pnpm-lock.yaml generated
View File

@ -95,25 +95,25 @@ importers:
version: 4.9.2(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
applesauce-channel:
specifier: next
version: 0.0.0-next-20241113103021(typescript@5.6.3)
version: 0.0.0-next-20241114194041(typescript@5.6.3)
applesauce-content:
specifier: next
version: 0.0.0-next-20241113103021(typescript@5.6.3)
version: 0.0.0-next-20241114194041(typescript@5.6.3)
applesauce-core:
specifier: next
version: 0.0.0-next-20241113103021(typescript@5.6.3)
version: 0.0.0-next-20241114194041(typescript@5.6.3)
applesauce-lists:
specifier: next
version: 0.0.0-next-20241113103021(typescript@5.6.3)
version: 0.0.0-next-20241114194041(typescript@5.6.3)
applesauce-net:
specifier: next
version: 0.0.0-next-20241113103021(typescript@5.6.3)
version: 0.0.0-next-20241114194041(typescript@5.6.3)
applesauce-react:
specifier: next
version: 0.0.0-next-20241113103021(typescript@5.6.3)
version: 0.0.0-next-20241114194041(typescript@5.6.3)
applesauce-signer:
specifier: next
version: 0.0.0-next-20241113103021(typescript@5.6.3)
version: 0.0.0-next-20241114194041(typescript@5.6.3)
bech32:
specifier: ^2.0.0
version: 2.0.0
@ -1878,26 +1878,26 @@ packages:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
applesauce-channel@0.0.0-next-20241113103021:
resolution: {integrity: sha512-QwI8tKRrRwn0+jo6f9vYXDCuIxEuJkw/W61FzqlbZeZkj5rtyQE3Ih0VaL5Frvxel/c9uq7LxyGpMkQ5Y+If4w==}
applesauce-channel@0.0.0-next-20241114194041:
resolution: {integrity: sha512-8ItnMP36x33EdgKPJ6EDn0I2ETCW5EfbrvNpQUfh8wP+ppBVQFuhaV3UmLVRRbv+Mq4RL1Jo60HLqul60O0kYw==}
applesauce-content@0.0.0-next-20241113103021:
resolution: {integrity: sha512-znPdbaJVf2pYiUl72O8y1hmnoKcc95xqq87gXy0wbs3fnKheK44/ww3NPlYqzTskE4KzxTr2zWrPb3+x9khqmQ==}
applesauce-content@0.0.0-next-20241114194041:
resolution: {integrity: sha512-0nOMZN8Jdcge4lxeuWxLIfMHfbfwdUFKEJRIxo4nb9nbms5Tuhjz9TQhvlQ/PN+0f0ioIy0nFjw7xTyJV/6sMg==}
applesauce-core@0.0.0-next-20241113103021:
resolution: {integrity: sha512-kGCz7+MZ6t+xJRHoxYN1lR5Dl4TXNDurlpd543JT2e6etAeGKOCH+dHjYFivIG6rPfoDuYvWtlKEI1S+ajQd7Q==}
applesauce-core@0.0.0-next-20241114194041:
resolution: {integrity: sha512-vPeqWHLr0DklswpmCDEMKaZ4yVwaM+8lxX7Yix8cCZvZzaXv/yxg3AlxbUcwjIVuVscuQp/zO1+soB27Coh4fQ==}
applesauce-lists@0.0.0-next-20241113103021:
resolution: {integrity: sha512-3j20zT82l0/UygZtGqFY2I4c8qJpzIqMiGX0iCoK3FojvHiZjLV2rgoJniGe3kq6Bc3kXVfNTI3XrzxRtbx27A==}
applesauce-lists@0.0.0-next-20241114194041:
resolution: {integrity: sha512-OGNQxwJ7rdunWkNaUxKkOmm0ioIAaOVEVUpKi6KWHKob4Z+I8B2onWMz/ROtNnsUafitIGK6Vp5pl3EJpzGsuw==}
applesauce-net@0.0.0-next-20241113103021:
resolution: {integrity: sha512-UsXadbsmsFjHurHbE6go/7vtDhQC06tUF+KMBvTbDBy4QiCxk0DyhTW0MUMLCOXwP+FBDdfFAEmc0qHRyU3PwA==}
applesauce-net@0.0.0-next-20241114194041:
resolution: {integrity: sha512-WtaXP59JGzCE2TJlJQ25AudcgI5rp6jI5Y7cxtYey+vxdcu931MMvod9Uo6ppgvP/U5voJusWrxEXxUWKbUIZw==}
applesauce-react@0.0.0-next-20241113103021:
resolution: {integrity: sha512-0toPu+z9iQPfx7DF03ERCxpLp7TdyMSwkRtYLYvey+E9A+QR3NtUkHDZjtuzkxcz5iRzaLJbADOAC82AjqNMFw==}
applesauce-react@0.0.0-next-20241114194041:
resolution: {integrity: sha512-ARJjt60kjXPZk8Jeoa0xOgu5c7j66kmzqdBs+eFW7246oVxzUHyy2JpwewPNASDCjHNhaOnUVmspU2gBTF4svA==}
applesauce-signer@0.0.0-next-20241113103021:
resolution: {integrity: sha512-8oFs98HGsvsq+VfPCYiBKew/GLck9Fgom70MVyBmlKjFMGS1KQAdlGhZpkcSpfbSxj45ZEwTR4IZIIBdSmbh9A==}
applesauce-signer@0.0.0-next-20241114194041:
resolution: {integrity: sha512-cxZVB3dcTwMq4XzOCOZheMlKB0My//x278fR/JCfaYiL9dghMCZCWwU4vUOXgyMQ4cW3csD+8RXNo0ICAG8Fpw==}
argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
@ -6173,22 +6173,22 @@ snapshots:
dependencies:
color-convert: 2.0.1
applesauce-channel@0.0.0-next-20241113103021(typescript@5.6.3):
applesauce-channel@0.0.0-next-20241114194041(typescript@5.6.3):
dependencies:
applesauce-core: 0.0.0-next-20241113103021(typescript@5.6.3)
applesauce-core: 0.0.0-next-20241114194041(typescript@5.6.3)
nostr-tools: 2.10.3(typescript@5.6.3)
rxjs: 7.8.1
transitivePeerDependencies:
- supports-color
- typescript
applesauce-content@0.0.0-next-20241113103021(typescript@5.6.3):
applesauce-content@0.0.0-next-20241114194041(typescript@5.6.3):
dependencies:
'@cashu/cashu-ts': 2.0.0-rc1
'@types/hast': 3.0.4
'@types/mdast': 4.0.4
'@types/unist': 3.0.3
applesauce-core: 0.0.0-next-20241113103021(typescript@5.6.3)
applesauce-core: 0.0.0-next-20241114194041(typescript@5.6.3)
mdast-util-find-and-replace: 3.0.1
nostr-tools: 2.10.3(typescript@5.6.3)
remark: 15.0.1
@ -6199,7 +6199,7 @@ snapshots:
- supports-color
- typescript
applesauce-core@0.0.0-next-20241113103021(typescript@5.6.3):
applesauce-core@0.0.0-next-20241114194041(typescript@5.6.3):
dependencies:
debug: 4.3.7
json-stringify-deterministic: 1.0.12
@ -6211,13 +6211,13 @@ snapshots:
- supports-color
- typescript
applesauce-lists@0.0.0-next-20241113103021(typescript@5.6.3):
applesauce-lists@0.0.0-next-20241114194041(typescript@5.6.3):
dependencies:
'@noble/hashes': 1.5.0
'@noble/secp256k1': 1.7.1
'@scure/base': 1.1.9
'@types/dom-serial': 1.0.6
applesauce-core: 0.0.0-next-20241113103021(typescript@5.6.3)
applesauce-core: 0.0.0-next-20241114194041(typescript@5.6.3)
debug: 4.3.7
nostr-tools: 2.10.3(typescript@5.6.3)
rxjs: 7.8.1
@ -6225,9 +6225,9 @@ snapshots:
- supports-color
- typescript
applesauce-net@0.0.0-next-20241113103021(typescript@5.6.3):
applesauce-net@0.0.0-next-20241114194041(typescript@5.6.3):
dependencies:
applesauce-core: 0.0.0-next-20241113103021(typescript@5.6.3)
applesauce-core: 0.0.0-next-20241114194041(typescript@5.6.3)
nanoid: 5.0.8
nostr-tools: 2.10.3(typescript@5.6.3)
rxjs: 7.8.1
@ -6236,10 +6236,10 @@ snapshots:
- supports-color
- typescript
applesauce-react@0.0.0-next-20241113103021(typescript@5.6.3):
applesauce-react@0.0.0-next-20241114194041(typescript@5.6.3):
dependencies:
applesauce-content: 0.0.0-next-20241113103021(typescript@5.6.3)
applesauce-core: 0.0.0-next-20241113103021(typescript@5.6.3)
applesauce-content: 0.0.0-next-20241114194041(typescript@5.6.3)
applesauce-core: 0.0.0-next-20241114194041(typescript@5.6.3)
nostr-tools: 2.10.3(typescript@5.6.3)
react: 18.3.1
rxjs: 7.8.1
@ -6247,14 +6247,14 @@ snapshots:
- supports-color
- typescript
applesauce-signer@0.0.0-next-20241113103021(typescript@5.6.3):
applesauce-signer@0.0.0-next-20241114194041(typescript@5.6.3):
dependencies:
'@noble/hashes': 1.5.0
'@noble/secp256k1': 1.7.1
'@scure/base': 1.1.9
'@types/dom-serial': 1.0.6
applesauce-core: 0.0.0-next-20241113103021(typescript@5.6.3)
applesauce-net: 0.0.0-next-20241113103021(typescript@5.6.3)
applesauce-core: 0.0.0-next-20241114194041(typescript@5.6.3)
applesauce-net: 0.0.0-next-20241114194041(typescript@5.6.3)
debug: 4.3.7
nanoid: 5.0.8
nostr-tools: 2.10.3(typescript@5.6.3)

View File

@ -1,8 +1,17 @@
import { NostrConnectSigner } from "applesauce-signer/signers";
import { NostrConnectSigner, SimpleSigner } from "applesauce-signer/signers";
import { DEFAULT_NOSTR_CONNECT_RELAYS } from "../../const";
import nostrConnectService from "../../services/nostr-connect";
import { Account } from "./account";
import { hexToBytes } from "@noble/hashes/utils";
import relayPoolService from "../../services/relay-pool";
function createSigner(pubkey: string, relays: string[], secretKey?: string, provider?: string) {
const signer = secretKey ? new SimpleSigner(hexToBytes(secretKey)) : undefined;
const client = new NostrConnectSigner({ pool: relayPoolService, pubkey, relays, signer, remote: provider });
return client;
}
export default class NostrConnectAccount extends Account {
readonly type = "nostr-connect";
@ -17,7 +26,7 @@ export default class NostrConnectAccount extends Account {
constructor(pubkey: string, signer?: NostrConnectSigner) {
super(pubkey);
this.signer = signer || nostrConnectService.createSigner(pubkey, DEFAULT_NOSTR_CONNECT_RELAYS);
this.signer = signer || createSigner(pubkey, DEFAULT_NOSTR_CONNECT_RELAYS);
}
toJSON() {
@ -30,10 +39,7 @@ export default class NostrConnectAccount extends Account {
}
fromJSON(data: any): this {
super.fromJSON(data);
this.signer = nostrConnectService.createSigner(data.pubkey, data.signerRelays, data.clientSecretKey);
// presume the client has already connected
nostrConnectService.saveSigner(data.pubKey);
this.signer = createSigner(data.pubkey, data.signerRelays, data.clientSecretKey);
return this;
}

View File

@ -1,80 +0,0 @@
import { nip19 } from "nostr-tools";
import { NostrConnectSigner, SimpleSigner } from "applesauce-signer";
import { hexToBytes } from "@noble/hashes/utils";
import { getPubkeyFromDecodeResult, isHexKey, normalizeToHexPubkey } from "../helpers/nip19";
import { logger } from "../helpers/debug";
import { safeRelayUrl } from "../helpers/relay";
import relayPoolService from "./relay-pool";
/** @deprecated use account manager instead */
class NostrConnectService {
log = logger.extend("NostrConnect");
clients: NostrConnectSigner[] = [];
getSigner(pubkey: string) {
return this.clients.find((client) => client.pubkey === pubkey);
}
saveSigner(client: NostrConnectSigner) {
if (!this.clients.includes(client)) this.clients.push(client);
}
createSigner(pubkey: string, relays: string[], secretKey?: string, provider?: string) {
if (this.getSigner(pubkey)) throw new Error("A client for that pubkey already exists");
const signer = secretKey ? new SimpleSigner(hexToBytes(secretKey)) : undefined;
const client = new NostrConnectSigner({ pool: relayPoolService, pubkey, relays, signer, remote: provider });
this.log(`Created client for ${pubkey} using ${relays.join(", ")}`);
return client;
}
fromHostedBunker(pubkey: string, relays: string[], provider?: string) {
return this.createSigner(pubkey, relays, undefined, provider);
}
/** create client from: pubkey@wss://relay.com (with optional bunker://) */
fromBunkerAddress(address: string) {
const parts = address.replace("bunker://", "").split("@");
if (parts.length !== 2) throw new Error("Invalid bunker address");
const pubkey = normalizeToHexPubkey(parts[0]);
const pathRelay = safeRelayUrl("wss://" + parts[1]);
if (!pathRelay) throw new Error("Missing relay");
if (!pubkey || !isHexKey(pubkey)) throw new Error("Missing pubkey");
return this.createSigner(pubkey, [pathRelay]);
}
/** create client from: bunker://<pubkey>?relay=<relay> */
fromBunkerURI(uri: string) {
const url = new URL(uri);
// firefox puts pubkey part in host, chrome puts pubkey in pathname
const pubkey = url.host || url.pathname.replace("//", "");
if (!isHexKey(pubkey)) throw new Error("Invalid connection URI");
const relays = url.searchParams.getAll("relay");
if (relays.length === 0) throw new Error("Missing relays");
return this.createSigner(pubkey, relays);
}
/** create client from: pubkey#token */
fromBunkerToken(pubkeyWithToken: string) {
const [npub, hexToken] = pubkeyWithToken.split("#");
const decoded = nip19.decode(npub);
const pubkey = getPubkeyFromDecodeResult(decoded);
if (!pubkey) throw new Error("Cant find pubkey");
const relays = ["wss://relay.nsecbunker.com", "wss://nos.lol"];
if (relays.length === 0) throw new Error("Missing relays");
return this.createSigner(pubkey, relays);
}
}
const nostrConnectService = new NostrConnectService();
if (import.meta.env.DEV) {
// @ts-ignore
window.nostrConnectService = nostrConnectService;
}
export default nostrConnectService;

View File

@ -17,24 +17,25 @@ import {
} from "@chakra-ui/react";
import { useNavigate } from "react-router-dom";
import { NostrEvent } from "nostr-tools";
import { NostrConnectSigner } from "applesauce-signer/signers/nostr-connect-signer";
import { ProfileContent } from "applesauce-core/helpers";
import useNip05Providers from "../../../hooks/use-nip05-providers";
import { Kind0ParsedContent } from "../../../helpers/nostr/user-metadata";
import HoverLinkOverlay from "../../../components/hover-link-overlay";
import { getEventCoordinate } from "../../../helpers/nostr/event";
import { MetadataAvatar } from "../../../components/user/user-avatar";
import { ErrorBoundary } from "../../../components/error-boundary";
import dnsIdentityService from "../../../services/dns-identity";
import useUserProfile from "../../../hooks/use-user-profile";
import nostrConnectService from "../../../services/nostr-connect";
import accountService from "../../../services/account";
import { safeRelayUrls } from "../../../helpers/relay";
import { safeJson } from "../../../helpers/parse";
import { NOSTR_CONNECT_PERMISSIONS } from "../../../const";
import NostrConnectAccount from "../../../classes/accounts/nostr-connect-account";
import relayPoolService from "../../../services/relay-pool";
function ProviderCard({ onClick, provider }: { onClick: () => void; provider: NostrEvent }) {
const metadata = JSON.parse(provider.content) as Kind0ParsedContent;
const metadata = JSON.parse(provider.content) as ProfileContent;
const features = provider.tags.filter((t) => t[0] === "f").map((t) => t[1]);
if (!metadata.nip05) return null;
@ -72,7 +73,7 @@ export default function LoginNostrAddressCreate() {
const providers = useNip05Providers();
const [selected, setSelected] = useState<NostrEvent>();
const userMetadata = useUserProfile(selected?.pubkey);
const providerMetadata = useMemo<Kind0ParsedContent | undefined>(
const providerMetadata = useMemo<ProfileContent | undefined>(
() => selected && safeJson(selected.content, undefined),
[selected],
);
@ -83,7 +84,7 @@ export default function LoginNostrAddressCreate() {
try {
setLoading("Creating...");
const metadata: Kind0ParsedContent = { ...userMetadata, ...providerMetadata };
const metadata: ProfileContent = { ...userMetadata, ...providerMetadata };
if (!metadata.nip05) throw new Error("Provider missing nip05 address");
const nip05 = await dnsIdentityService.fetchIdentity(metadata.nip05);
if (!nip05 || nip05.pubkey !== selected.pubkey) throw new Error("Invalid provider");
@ -92,7 +93,7 @@ export default function LoginNostrAddressCreate() {
const relays = safeRelayUrls(nip05.nip46Relays || nip05.relays || []);
if (relays.length === 0) throw new Error("Cant find providers relays");
const signer = nostrConnectService.createSigner("", relays, undefined, nip05.pubkey);
const signer = new NostrConnectSigner({ pool: relayPoolService, relays, remote: nip05.pubkey });
const createPromise = signer.createAccount(name, nip05.domain, undefined, NOSTR_CONNECT_PERMISSIONS);
await createPromise;
@ -100,7 +101,6 @@ export default function LoginNostrAddressCreate() {
const account = new NostrConnectAccount(signer.pubkey!, signer);
nostrConnectService.saveSigner(signer);
accountService.addAccount(account);
accountService.switchAccount(account.pubkey);
} catch (e) {
@ -113,7 +113,7 @@ export default function LoginNostrAddressCreate() {
if (loading) return <Text fontSize="lg">{loading}</Text>;
if (selected) {
const metadata = JSON.parse(selected.content) as Kind0ParsedContent;
const metadata = JSON.parse(selected.content) as ProfileContent;
const [_, domain] = metadata.nip05!.split("@");
return (

View File

@ -1,11 +1,11 @@
import { useState } from "react";
import { Button, Card, CardProps, Flex, FormControl, FormLabel, Image, Input, Text, useToast } from "@chakra-ui/react";
import { useNavigate, Link as RouterLink } from "react-router-dom";
import { NostrConnectSigner } from "applesauce-signer/signers/nostr-connect-signer";
import { useDebounce } from "react-use";
import dnsIdentityService, { DnsIdentity } from "../../../services/dns-identity";
import { CheckIcon } from "../../../components/icons";
import nostrConnectService from "../../../services/nostr-connect";
import accountService from "../../../services/account";
import { NOSTR_CONNECT_PERMISSIONS } from "../../../const";
import { safeRelayUrls } from "../../../helpers/relay";
@ -13,6 +13,7 @@ import { getMatchSimpleEmail } from "../../../helpers/regexp";
import QRCodeScannerButton from "../../../components/qr-code/qr-code-scanner-button";
import NostrConnectAccount from "../../../classes/accounts/nostr-connect-account";
import PubkeyAccount from "../../../classes/accounts/pubkey-account";
import relayPoolService from "../../../services/relay-pool";
export default function LoginNostrAddressView() {
const navigate = useNavigate();
@ -46,10 +47,9 @@ export default function LoginNostrAddressView() {
const relays = safeRelayUrls(
nip05.nip46Relays || rootNip05?.nip46Relays || rootNip05?.relays || nip05.relays || [],
);
const signer = nostrConnectService.fromHostedBunker(nip05.pubkey, relays);
const signer = new NostrConnectSigner({ pubkey: nip05.pubkey, relays, pool: relayPoolService });
await signer.connect(undefined, NOSTR_CONNECT_PERMISSIONS);
nostrConnectService.saveSigner(signer);
const account = new NostrConnectAccount(signer.pubkey!, signer);
accountService.addAccount(account);
accountService.switchAccount(signer.pubkey!);

View File

@ -12,16 +12,16 @@ import {
useToast,
} from "@chakra-ui/react";
import { useNavigate } from "react-router-dom";
import { NostrConnectSigner } from "applesauce-signer";
import { NostrConnectSigner } from "applesauce-signer/signers/nostr-connect-signer";
import accountService from "../../services/account";
import nostrConnectService from "../../services/nostr-connect";
import QRCodeScannerButton from "../../components/qr-code/qr-code-scanner-button";
import { RelayUrlInput } from "../../components/relay-url-input";
import QrCodeSvg from "../../components/qr-code/qr-code-svg";
import { CopyIconButton } from "../../components/copy-icon-button";
import NostrConnectAccount from "../../classes/accounts/nostr-connect-account";
import relayPoolService from "../../services/relay-pool";
import { NOSTR_CONNECT_PERMISSIONS } from "../../const";
function ClientConnectForm() {
const navigate = useNavigate();
@ -47,7 +47,6 @@ function ClientConnectForm() {
const c = new NostrConnectSigner({ relays: [relay], pool: relayPoolService });
setSigner(c);
c.waitForSigner().then(() => {
nostrConnectService.saveSigner(c);
const account = new NostrConnectAccount(c.pubkey!, c);
accountService.addAccount(account);
accountService.switchAccount(c.pubkey!);
@ -110,22 +109,12 @@ export default function LoginNostrConnectView() {
try {
setLoading("Connecting...");
let client: NostrConnectSigner;
if (connection.startsWith("bunker://")) {
if (connection.includes("@")) client = nostrConnectService.fromBunkerAddress(connection);
else client = nostrConnectService.fromBunkerURI(connection);
let client = await NostrConnectSigner.fromBunkerURI(connection, relayPoolService, NOSTR_CONNECT_PERMISSIONS);
const pubkey = await client.getPublicKey();
await client.connect(new URL(connection).searchParams.get("secret") ?? undefined);
} else if (connection.startsWith("npub")) {
client = nostrConnectService.fromBunkerToken(connection);
const [npub, hexToken] = connection.split("#");
await client.connect(hexToken);
} else throw new Error("Unknown format");
nostrConnectService.saveSigner(client);
const account = new NostrConnectAccount(client.pubkey!, client);
const account = new NostrConnectAccount(pubkey, client);
accountService.addAccount(account);
accountService.switchAccount(client.pubkey!);
accountService.switchAccount(pubkey);
} catch (e) {
if (e instanceof Error) toast({ status: "error", description: e.message });
}