diff --git a/build.sh b/build.sh index 8e2a1aa..0db8f4c 100755 --- a/build.sh +++ b/build.sh @@ -2,4 +2,8 @@ for package in $(./get_packages.py); do ./build_and_link.sh $package + + if [[ $? -eq 1 ]]; then + exit 1 + fi done diff --git a/build_and_link.sh b/build_and_link.sh index 259cc92..c6e7e60 100755 --- a/build_and_link.sh +++ b/build_and_link.sh @@ -5,6 +5,10 @@ upstream=$1 npm run fix -w @welshman/$upstream npm run build -w @welshman/$upstream +if [[ $? -eq 1 ]]; then + exit 1 +fi + for downstream in $(./get_packages.py); do n=@welshman/$upstream f=packages/$downstream/package.json diff --git a/package-lock.json b/package-lock.json index d7c4180..f8ec749 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2695,6 +2695,10 @@ "resolved": "packages/net", "link": true }, + "node_modules/@welshman/relay": { + "resolved": "packages/relay", + "link": true + }, "node_modules/@welshman/signer": { "resolved": "packages/signer", "link": true @@ -5334,8 +5338,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/nostr-wasm/-/nostr-wasm-0.1.0.tgz", "integrity": "sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/npm-run-path": { "version": "4.0.1", @@ -7677,6 +7680,7 @@ "@welshman/feeds": "^0.1.0", "@welshman/lib": "^0.1.0", "@welshman/net": "^0.0.49", + "@welshman/relay": "^0.1.0", "@welshman/signer": "^0.1.0", "@welshman/store": "^0.1.0", "@welshman/util": "^0.1.0", @@ -7849,10 +7853,11 @@ }, "packages/net": { "name": "@welshman/net", - "version": "0.0.48", + "version": "0.0.49", "license": "MIT", "dependencies": { "@welshman/lib": "^0.1.0", + "@welshman/relay": "^0.1.0", "@welshman/util": "^0.1.0", "isomorphic-ws": "^5.0.0", "nostr-tools": "^2.11.0", @@ -7871,6 +7876,15 @@ "typed-emitter": "^2.1.0" } }, + "packages/relay": { + "name": "@welshman/relay", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@welshman/lib": "^0.1.0", + "@welshman/util": "^0.1.0" + } + }, "packages/signer": { "name": "@welshman/signer", "version": "0.1.1", @@ -7941,6 +7955,7 @@ "license": "MIT", "dependencies": { "@welshman/lib": "^0.1.0", + "@welshman/relay": "^0.1.0", "@welshman/util": "^0.1.0", "svelte": "^4.2.18" } @@ -7952,7 +7967,8 @@ "dependencies": { "@types/ws": "^8.5.13", "@welshman/lib": "^0.1.0", - "nostr-tools": "^2.7.2" + "nostr-tools": "^2.7.2", + "nostr-wasm": "^0.1.0" }, "engines": { "node": ">=10.4.0" diff --git a/packages/app/src/core.ts b/packages/app/src/core.ts index 6033370..58b6cec 100644 --- a/packages/app/src/core.ts +++ b/packages/app/src/core.ts @@ -1,14 +1,26 @@ import {throttle} from "@welshman/lib" -import {Repository, LocalRelay} from "@welshman/relay" -import {Tracker} from "@welshman/net" +import {verifyEvent, isEphemeralKind, isDVMKind} from "@welshman/util" +import {Repository} from "@welshman/relay" +import {Pool, Tracker, SocketEvent, isRelayEvent} from "@welshman/net" import {custom} from "@welshman/store" export const repository = Repository.getSingleton() -export const relay = new LocalRelay(repository) - export const tracker = new Tracker() +Pool.getSingleton().subscribe(socket => { + socket.on(SocketEvent.Receive, message => { + if (isRelayEvent(message)) { + const event = message[2] + + if (!isEphemeralKind(event.kind) && !isDVMKind(event.kind) && verifyEvent(event)) { + tracker.track(event.id, socket.url) + repository.publish(event) + } + } + }) +}) + // Adapt above objects to stores export const makeRepositoryStore = ({throttle: t = 300}: {throttle?: number} = {}) => diff --git a/packages/dvm/package.json b/packages/dvm/package.json index 44ab6d0..78ab25b 100644 --- a/packages/dvm/package.json +++ b/packages/dvm/package.json @@ -30,6 +30,6 @@ "@welshman/lib": "^0.1.0", "@welshman/net": "^0.0.49", "@welshman/util": "^0.1.0", - "nostr-tools": "^2.7.2" + "@welshman/signer": "^0.1.1" } } diff --git a/packages/dvm/src/handler.ts b/packages/dvm/src/handler.ts index 5b8d2e8..21c3cd7 100644 --- a/packages/dvm/src/handler.ts +++ b/packages/dvm/src/handler.ts @@ -1,6 +1,5 @@ -import {hexToBytes} from "@noble/hashes/utils" -import {getPublicKey, finalizeEvent} from "nostr-tools/pure" import {now} from "@welshman/lib" +import {Nip01Signer} from "@welshman/signer" import {TrustedEvent, StampedEvent, Filter} from "@welshman/util" import {MultiRequest, MultiPublish, PublishEvent, RequestEvent, AdapterContext} from "@welshman/net" @@ -25,8 +24,11 @@ export class DVM { logEvents = false seen = new Set() handlers = new Map() + signer: Nip01Signer constructor(readonly opts: DVMOpts) { + this.signer = new Nip01Signer(opts.sk) + for (const [kind, createHandler] of Object.entries(this.opts.handlers)) { this.handlers.set(parseInt(kind), createHandler(this)) } @@ -35,7 +37,8 @@ export class DVM { async start() { this.active = true - const {sk, relays, context, requireMention = false} = this.opts + const {relays, context, requireMention = false} = this.opts + const pubkey = await this.signer.getPubkey() while (this.active) { await new Promise(resolve => { @@ -44,7 +47,7 @@ export class DVM { const filter: Filter = {kinds, since} if (requireMention) { - filter["#p"] = [getPublicKey(hexToBytes(sk))] + filter["#p"] = [pubkey] } const req = new MultiRequest({relays, filter, context}) @@ -109,8 +112,8 @@ export class DVM { } async publish(template: StampedEvent) { - const {sk, relays, context} = this.opts - const event = finalizeEvent(template, hexToBytes(sk)) + const {relays, context} = this.opts + const event = await this.signer.sign(template) await new Promise(resolve => { new MultiPublish({event, relays, context}).on(PublishEvent.Complete, resolve) diff --git a/packages/net/package.json b/packages/net/package.json index 9c6b034..c9059c6 100644 --- a/packages/net/package.json +++ b/packages/net/package.json @@ -30,7 +30,6 @@ "@welshman/util": "^0.1.0", "@welshman/relay": "^0.1.0", "isomorphic-ws": "^5.0.0", - "nostr-tools": "^2.11.0", "typed-emitter": "^2.1.0" } } diff --git a/packages/net/src/request.ts b/packages/net/src/request.ts index b0e0ad8..fb66a67 100644 --- a/packages/net/src/request.ts +++ b/packages/net/src/request.ts @@ -1,5 +1,4 @@ import {EventEmitter} from "events" -import {verifyEvent as nostrToolsVerifyEvent} from "nostr-tools/pure" import {on, call, randomId, yieldThread, pushToMapKey, batcher} from "@welshman/lib" import { Filter, @@ -7,6 +6,7 @@ import { matchFilter, TrustedEvent, getFilterResultCardinality, + verifyEvent as defaultVerifyEvent, } from "@welshman/util" import {RelayMessage, ClientMessageType, isRelayEvent, isRelayEose} from "./message.js" import {getAdapter, AdapterContext, AbstractAdapter, AdapterEvent} from "./adapter.js" @@ -14,14 +14,6 @@ import {SocketEvent, SocketStatus} from "./socket.js" import {TypedEmitter, Unsubscriber} from "./util.js" import {Tracker} from "./tracker.js" -export const defaultVerifyEvent = (event: any) => { - try { - return nostrToolsVerifyEvent(event) - } catch (e) { - return false - } -} - export enum RequestEvent { Close = "request:event:close", Disconnect = "request:event:disconnect", diff --git a/packages/util/package.json b/packages/util/package.json index 5b2acee..494915e 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -31,6 +31,7 @@ "dependencies": { "@types/ws": "^8.5.13", "@welshman/lib": "^0.1.0", - "nostr-tools": "^2.7.2" + "nostr-tools": "^2.7.2", + "nostr-wasm": "^0.1.0" } } diff --git a/packages/util/src/Events.ts b/packages/util/src/Events.ts index 27117b2..57c694c 100644 --- a/packages/util/src/Events.ts +++ b/packages/util/src/Events.ts @@ -1,5 +1,7 @@ -import {verifiedSymbol, getEventHash, verifyEvent} from "nostr-tools/pure" -import {cached, mapVals, first, pick, now} from "@welshman/lib" +import {verifiedSymbol, verifyEvent as verifyEventPure} from "nostr-tools/pure" +import {setNostrWasm, verifyEvent as verifyEventWasm} from "nostr-tools/wasm" +import {initNostrWasm} from "nostr-wasm" +import {mapVals, first, pick, now} from "@welshman/lib" import {getReplyTagValues, getCommentTagValues} from "./Tags.js" import {getAddress, Address} from "./Address.js" import { @@ -59,6 +61,20 @@ export const makeEvent = ( export const createEvent = makeEvent +export const verifyEvent = (() => { + let verify = verifyEventPure + + if (typeof WebAssembly === "object") { + initNostrWasm() + .then(setNostrWasm) + .then(() => { + verify = verifyEventWasm + }) + } + + return (event: TrustedEvent) => event.sig && verify(event as SignedEvent) +})() + export const isEventTemplate = (e: EventTemplate): e is EventTemplate => Boolean(typeof e.kind === "number" && Array.isArray(e.tags) && typeof e.content === "string") @@ -100,28 +116,6 @@ export const asUnwrappedEvent = (e: UnwrappedEvent): UnwrappedEvent => export const asTrustedEvent = (e: TrustedEvent): TrustedEvent => pick(["kind", "tags", "content", "created_at", "pubkey", "id", "sig", "wrap"], e) -const _hasValidSignature = cached({ - maxSize: 10000, - getKey: ([e]: [SignedEvent]) => { - try { - return `${getEventHash(e)}:${e.sig}` - } catch (err) { - return "invalid" - } - }, - getValue: ([e]: [SignedEvent]) => { - try { - verifyEvent(e) - } catch (err) { - return false - } - - return true - }, -}) - -export const hasValidSignature = (e: SignedEvent) => e[verifiedSymbol] || _hasValidSignature(e) - export const getIdentifier = (e: EventTemplate) => e.tags.find(t => t[0] === "d")?.[1] export const getIdOrAddress = (e: HashedEvent) => (isReplaceable(e) ? getAddress(e) : e.id)