2023-03-28 14:34:01 +00:00
|
|
|
import { useMemo } from "react";
|
2023-01-15 19:40:47 +00:00
|
|
|
import { useSelector } from "react-redux";
|
2023-02-18 20:36:42 +00:00
|
|
|
import * as secp from "@noble/secp256k1";
|
2023-03-28 14:34:01 +00:00
|
|
|
import { EventKind, RelaySettings, TaggedRawEvent, HexKey, RawEvent, u256, UserMetadata, Lists } from "@snort/nostr";
|
2023-01-27 10:47:05 +00:00
|
|
|
|
2023-01-20 11:11:50 +00:00
|
|
|
import { RootState } from "State/Store";
|
2023-02-28 19:25:10 +00:00
|
|
|
import { bech32ToHex, delay, unwrap } from "Util";
|
2023-01-21 17:55:49 +00:00
|
|
|
import { DefaultRelays, HashtagRegex } from "Const";
|
2023-02-20 23:14:15 +00:00
|
|
|
import { System } from "System";
|
2023-03-28 14:34:01 +00:00
|
|
|
import { EventExt } from "System/EventExt";
|
2023-01-15 19:40:47 +00:00
|
|
|
|
|
|
|
declare global {
|
2023-02-07 20:04:50 +00:00
|
|
|
interface Window {
|
|
|
|
nostr: {
|
|
|
|
getPublicKey: () => Promise<HexKey>;
|
|
|
|
signEvent: (event: RawEvent) => Promise<RawEvent>;
|
2023-02-09 12:26:54 +00:00
|
|
|
getRelays: () => Promise<Record<string, { read: boolean; write: boolean }>>;
|
2023-02-07 20:04:50 +00:00
|
|
|
nip04: {
|
|
|
|
encrypt: (pubkey: HexKey, content: string) => Promise<string>;
|
|
|
|
decrypt: (pubkey: HexKey, content: string) => Promise<string>;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
2023-01-15 19:40:47 +00:00
|
|
|
}
|
|
|
|
|
2023-02-13 15:29:25 +00:00
|
|
|
export type EventPublisher = ReturnType<typeof useEventPublisher>;
|
|
|
|
|
2023-01-15 19:40:47 +00:00
|
|
|
export default function useEventPublisher() {
|
2023-02-09 12:26:54 +00:00
|
|
|
const pubKey = useSelector<RootState, HexKey | undefined>(s => s.login.publicKey);
|
|
|
|
const privKey = useSelector<RootState, HexKey | undefined>(s => s.login.privateKey);
|
|
|
|
const follows = useSelector<RootState, HexKey[]>(s => s.login.follows);
|
2023-02-07 20:04:50 +00:00
|
|
|
const relays = useSelector((s: RootState) => s.login.relays);
|
|
|
|
const hasNip07 = "nostr" in window;
|
2023-01-15 19:40:47 +00:00
|
|
|
|
2023-03-28 14:34:01 +00:00
|
|
|
async function signEvent(ev: RawEvent): Promise<RawEvent> {
|
2023-04-10 12:53:53 +00:00
|
|
|
if (!pubKey) {
|
|
|
|
throw new Error("Cant sign events when logged out");
|
|
|
|
}
|
|
|
|
|
2023-02-07 20:04:50 +00:00
|
|
|
if (hasNip07 && !privKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.id = await EventExt.createId(ev);
|
|
|
|
const tmpEv = (await barrierNip07(() => window.nostr.signEvent(ev))) as RawEvent;
|
|
|
|
ev.sig = tmpEv.sig;
|
|
|
|
return ev;
|
2023-02-07 20:04:50 +00:00
|
|
|
} else if (privKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
await EventExt.sign(ev, privKey);
|
2023-02-07 20:04:50 +00:00
|
|
|
} else {
|
|
|
|
console.warn("Count not sign event, no private keys available");
|
2023-01-15 19:40:47 +00:00
|
|
|
}
|
2023-02-07 20:04:50 +00:00
|
|
|
return ev;
|
|
|
|
}
|
2023-01-15 19:40:47 +00:00
|
|
|
|
2023-03-28 14:34:01 +00:00
|
|
|
function processContent(ev: RawEvent, msg: string) {
|
2023-02-07 20:04:50 +00:00
|
|
|
const replaceNpub = (match: string) => {
|
|
|
|
const npub = match.slice(1);
|
|
|
|
try {
|
|
|
|
const hex = bech32ToHex(npub);
|
2023-03-28 14:34:01 +00:00
|
|
|
const idx = ev.tags.length;
|
|
|
|
ev.tags.push(["p", hex]);
|
2023-02-07 20:04:50 +00:00
|
|
|
return `#[${idx}]`;
|
|
|
|
} catch (error) {
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
const replaceNoteId = (match: string) => {
|
2023-03-16 01:02:54 +00:00
|
|
|
const noteId = match.slice(1);
|
2023-02-07 20:04:50 +00:00
|
|
|
try {
|
2023-03-16 01:02:54 +00:00
|
|
|
const hex = bech32ToHex(noteId);
|
2023-03-28 14:34:01 +00:00
|
|
|
const idx = ev.tags.length;
|
|
|
|
ev.tags.push(["e", hex, "", "mention"]);
|
2023-02-07 20:04:50 +00:00
|
|
|
return `#[${idx}]`;
|
|
|
|
} catch (error) {
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
const replaceHashtag = (match: string) => {
|
|
|
|
const tag = match.slice(1);
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.tags.push(["t", tag.toLowerCase()]);
|
2023-02-07 20:04:50 +00:00
|
|
|
return match;
|
|
|
|
};
|
|
|
|
const content = msg
|
|
|
|
.replace(/@npub[a-z0-9]+/g, replaceNpub)
|
2023-03-16 01:02:54 +00:00
|
|
|
.replace(/@note1[acdefghjklmnpqrstuvwxyz023456789]{58}/g, replaceNoteId)
|
2023-02-07 20:04:50 +00:00
|
|
|
.replace(HashtagRegex, replaceHashtag);
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.content = content;
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
|
|
|
|
2023-02-13 15:29:25 +00:00
|
|
|
const ret = {
|
2023-02-07 20:04:50 +00:00
|
|
|
nip42Auth: async (challenge: string, relay: string) => {
|
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, EventKind.Auth);
|
|
|
|
ev.tags.push(["relay", relay]);
|
|
|
|
ev.tags.push(["challenge", challenge]);
|
2023-02-07 20:04:50 +00:00
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
2023-03-28 14:34:01 +00:00
|
|
|
broadcast: (ev: RawEvent | undefined) => {
|
2023-02-07 20:04:50 +00:00
|
|
|
if (ev) {
|
2023-04-10 14:55:25 +00:00
|
|
|
console.debug(ev);
|
2023-02-07 20:04:50 +00:00
|
|
|
System.BroadcastEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Write event to DefaultRelays, this is important for profiles / relay lists to prevent bugs
|
|
|
|
* If a user removes all the DefaultRelays from their relay list and saves that relay list,
|
|
|
|
* When they open the site again we wont see that updated relay list and so it will appear to reset back to the previous state
|
|
|
|
*/
|
2023-03-28 14:34:01 +00:00
|
|
|
broadcastForBootstrap: (ev: RawEvent | undefined) => {
|
2023-02-07 20:04:50 +00:00
|
|
|
if (ev) {
|
2023-02-07 19:47:57 +00:00
|
|
|
for (const [k] of DefaultRelays) {
|
2023-02-07 20:04:50 +00:00
|
|
|
System.WriteOnceToRelay(k, ev);
|
2023-01-23 15:31:59 +00:00
|
|
|
}
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
|
|
|
},
|
2023-02-10 19:23:52 +00:00
|
|
|
/**
|
|
|
|
* Write event to all given relays.
|
|
|
|
*/
|
2023-03-28 14:34:01 +00:00
|
|
|
broadcastAll: (ev: RawEvent | undefined, relays: string[]) => {
|
2023-02-10 19:23:52 +00:00
|
|
|
if (ev) {
|
|
|
|
for (const k of relays) {
|
|
|
|
System.WriteOnceToRelay(k, ev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2023-02-07 20:04:50 +00:00
|
|
|
muted: async (keys: HexKey[], priv: HexKey[]) => {
|
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, EventKind.PubkeyLists);
|
|
|
|
ev.tags.push(["d", Lists.Muted]);
|
2023-02-09 12:26:54 +00:00
|
|
|
keys.forEach(p => {
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.tags.push(["p", p]);
|
2023-02-07 20:04:50 +00:00
|
|
|
});
|
|
|
|
let content = "";
|
|
|
|
if (priv.length > 0) {
|
2023-02-09 12:26:54 +00:00
|
|
|
const ps = priv.map(p => ["p", p]);
|
2023-02-07 20:04:50 +00:00
|
|
|
const plaintext = JSON.stringify(ps);
|
|
|
|
if (hasNip07 && !privKey) {
|
2023-02-09 12:26:54 +00:00
|
|
|
content = await barrierNip07(() => window.nostr.nip04.encrypt(pubKey, plaintext));
|
2023-02-07 20:04:50 +00:00
|
|
|
} else if (privKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
content = await EventExt.encryptData(plaintext, pubKey, privKey);
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
2023-01-19 18:00:56 +00:00
|
|
|
}
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.content = content;
|
2023-02-07 20:04:50 +00:00
|
|
|
return await signEvent(ev);
|
2023-02-13 15:49:19 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
pinned: async (notes: HexKey[]) => {
|
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, EventKind.NoteLists);
|
|
|
|
ev.tags.push(["d", Lists.Pinned]);
|
2023-02-13 15:49:19 +00:00
|
|
|
notes.forEach(n => {
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.tags.push(["e", n]);
|
2023-02-13 15:49:19 +00:00
|
|
|
});
|
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
bookmarked: async (notes: HexKey[]) => {
|
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, EventKind.NoteLists);
|
|
|
|
ev.tags.push(["d", Lists.Bookmarked]);
|
2023-02-13 15:49:19 +00:00
|
|
|
notes.forEach(n => {
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.tags.push(["e", n]);
|
2023-02-13 15:49:19 +00:00
|
|
|
});
|
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
tags: async (tags: string[]) => {
|
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, EventKind.TagLists);
|
|
|
|
ev.tags.push(["d", Lists.Followed]);
|
2023-02-13 15:49:19 +00:00
|
|
|
tags.forEach(t => {
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.tags.push(["t", t]);
|
2023-02-13 15:49:19 +00:00
|
|
|
});
|
|
|
|
return await signEvent(ev);
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
metadata: async (obj: UserMetadata) => {
|
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, EventKind.SetMetadata);
|
|
|
|
ev.content = JSON.stringify(obj);
|
2023-02-07 20:04:50 +00:00
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
2023-04-10 14:55:25 +00:00
|
|
|
note: async (msg: string, extraTags?: Array<Array<string>>, kind?: EventKind) => {
|
2023-02-07 20:04:50 +00:00
|
|
|
if (pubKey) {
|
2023-04-10 14:55:25 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, kind ?? EventKind.TextNote);
|
2023-02-07 20:04:50 +00:00
|
|
|
processContent(ev, msg);
|
2023-03-27 22:58:29 +00:00
|
|
|
if (extraTags) {
|
|
|
|
for (const et of extraTags) {
|
|
|
|
ev.tags.push(et);
|
|
|
|
}
|
|
|
|
}
|
2023-02-07 20:04:50 +00:00
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
2023-04-05 17:07:42 +00:00
|
|
|
/**
|
|
|
|
* Create a zap request event for a given target event/profile
|
|
|
|
* @param amount Millisats amout!
|
|
|
|
* @param author Author pubkey to tag in the zap
|
|
|
|
* @param note Note Id to tag in the zap
|
|
|
|
* @param msg Custom message to be included in the zap
|
|
|
|
* @param extraTags Any extra tags to include on the zap request event
|
|
|
|
* @returns
|
|
|
|
*/
|
2023-04-05 15:10:14 +00:00
|
|
|
zap: async (amount: number, author: HexKey, note?: HexKey, msg?: string, extraTags?: Array<Array<string>>) => {
|
2023-02-07 20:04:50 +00:00
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, EventKind.ZapRequest);
|
2023-02-07 20:04:50 +00:00
|
|
|
if (note) {
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.tags.push(["e", note]);
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.tags.push(["p", author]);
|
2023-02-28 16:07:20 +00:00
|
|
|
const relayTag = ["relays", ...Object.keys(relays).map(a => a.trim())];
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.tags.push(relayTag);
|
|
|
|
ev.tags.push(["amount", amount.toString()]);
|
2023-04-05 15:10:14 +00:00
|
|
|
ev.tags.push(...(extraTags ?? []));
|
2023-02-07 20:04:50 +00:00
|
|
|
processContent(ev, msg || "");
|
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Reply to a note
|
|
|
|
*/
|
2023-04-10 14:55:25 +00:00
|
|
|
reply: async (replyTo: TaggedRawEvent, msg: string, extraTags?: Array<Array<string>>, kind?: EventKind) => {
|
2023-02-07 20:04:50 +00:00
|
|
|
if (pubKey) {
|
2023-04-10 14:55:25 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, kind ?? EventKind.TextNote);
|
2023-01-15 19:40:47 +00:00
|
|
|
|
2023-03-28 14:34:01 +00:00
|
|
|
const thread = EventExt.extractThread(ev);
|
2023-02-07 20:04:50 +00:00
|
|
|
if (thread) {
|
2023-03-28 14:34:01 +00:00
|
|
|
if (thread.root || thread.replyTo) {
|
|
|
|
ev.tags.push(["e", thread.root?.Event ?? thread.replyTo?.Event ?? "", "", "root"]);
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.tags.push(["e", replyTo.id, replyTo.relays[0] ?? "", "reply"]);
|
2023-01-15 19:40:47 +00:00
|
|
|
|
2023-02-07 20:04:50 +00:00
|
|
|
// dont tag self in replies
|
2023-03-28 14:34:01 +00:00
|
|
|
if (replyTo.pubkey !== pubKey) {
|
|
|
|
ev.tags.push(["p", replyTo.pubkey]);
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
2023-01-15 19:40:47 +00:00
|
|
|
|
2023-03-28 14:34:01 +00:00
|
|
|
for (const pk of thread.pubKeys) {
|
2023-02-07 20:04:50 +00:00
|
|
|
if (pk === pubKey) {
|
|
|
|
continue; // dont tag self in replies
|
2023-01-15 19:40:47 +00:00
|
|
|
}
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.tags.push(["p", pk]);
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
|
|
|
} else {
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.tags.push(["e", replyTo.id, "", "reply"]);
|
2023-02-07 20:04:50 +00:00
|
|
|
// dont tag self in replies
|
2023-03-28 14:34:01 +00:00
|
|
|
if (replyTo.pubkey !== pubKey) {
|
|
|
|
ev.tags.push(["p", replyTo.pubkey]);
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
processContent(ev, msg);
|
2023-03-27 22:58:29 +00:00
|
|
|
if (extraTags) {
|
|
|
|
for (const et of extraTags) {
|
|
|
|
ev.tags.push(et);
|
|
|
|
}
|
|
|
|
}
|
2023-02-07 20:04:50 +00:00
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
2023-03-28 14:34:01 +00:00
|
|
|
react: async (evRef: RawEvent, content = "+") => {
|
2023-02-07 20:04:50 +00:00
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, EventKind.Reaction);
|
|
|
|
ev.content = content;
|
|
|
|
ev.tags.push(["e", evRef.id]);
|
|
|
|
ev.tags.push(["p", evRef.pubkey]);
|
2023-02-07 20:04:50 +00:00
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
saveRelays: async () => {
|
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, EventKind.ContactList);
|
|
|
|
ev.content = JSON.stringify(relays);
|
2023-02-07 19:47:57 +00:00
|
|
|
for (const pk of follows) {
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.tags.push(["p", pk]);
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
2023-01-15 19:40:47 +00:00
|
|
|
|
2023-02-07 20:04:50 +00:00
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
2023-02-10 19:23:52 +00:00
|
|
|
saveRelaysSettings: async () => {
|
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, EventKind.Relays);
|
2023-02-10 19:23:52 +00:00
|
|
|
for (const [url, settings] of Object.entries(relays)) {
|
|
|
|
const rTag = ["r", url];
|
|
|
|
if (settings.read && !settings.write) {
|
|
|
|
rTag.push("read");
|
|
|
|
}
|
|
|
|
if (settings.write && !settings.read) {
|
|
|
|
rTag.push("write");
|
|
|
|
}
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.tags.push(rTag);
|
2023-02-10 19:23:52 +00:00
|
|
|
}
|
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
2023-02-09 12:26:54 +00:00
|
|
|
addFollow: async (pkAdd: HexKey | HexKey[], newRelays?: Record<string, RelaySettings>) => {
|
2023-02-07 20:04:50 +00:00
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, EventKind.ContactList);
|
|
|
|
ev.content = JSON.stringify(newRelays ?? relays);
|
2023-02-07 19:47:57 +00:00
|
|
|
const temp = new Set(follows);
|
2023-02-07 20:04:50 +00:00
|
|
|
if (Array.isArray(pkAdd)) {
|
2023-02-09 12:26:54 +00:00
|
|
|
pkAdd.forEach(a => temp.add(a));
|
2023-02-07 20:04:50 +00:00
|
|
|
} else {
|
|
|
|
temp.add(pkAdd);
|
|
|
|
}
|
2023-02-07 19:47:57 +00:00
|
|
|
for (const pk of temp) {
|
2023-02-07 20:04:50 +00:00
|
|
|
if (pk.length !== 64) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.tags.push(["p", pk.toLowerCase()]);
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
2023-01-15 19:40:47 +00:00
|
|
|
|
2023-02-07 20:04:50 +00:00
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
removeFollow: async (pkRemove: HexKey) => {
|
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, EventKind.ContactList);
|
|
|
|
ev.content = JSON.stringify(relays);
|
2023-02-07 19:47:57 +00:00
|
|
|
for (const pk of follows) {
|
2023-02-07 20:04:50 +00:00
|
|
|
if (pk === pkRemove || pk.length !== 64) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.tags.push(["p", pk]);
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
2023-01-15 19:40:47 +00:00
|
|
|
|
2023-02-07 20:04:50 +00:00
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Delete an event (NIP-09)
|
|
|
|
*/
|
|
|
|
delete: async (id: u256) => {
|
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, EventKind.Deletion);
|
|
|
|
ev.tags.push(["e", id]);
|
2023-02-07 20:04:50 +00:00
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
2023-02-07 19:47:57 +00:00
|
|
|
* Repost a note (NIP-18)
|
2023-02-07 20:04:50 +00:00
|
|
|
*/
|
2023-03-28 14:34:01 +00:00
|
|
|
repost: async (note: TaggedRawEvent) => {
|
2023-02-07 20:04:50 +00:00
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, EventKind.Repost);
|
|
|
|
ev.tags.push(["e", note.id, ""]);
|
|
|
|
ev.tags.push(["p", note.pubkey]);
|
2023-02-07 20:04:50 +00:00
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
2023-03-28 14:34:01 +00:00
|
|
|
decryptDm: async (note: RawEvent): Promise<string | undefined> => {
|
2023-02-07 20:04:50 +00:00
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
if (note.pubkey !== pubKey && !note.tags.some(a => a[1] === pubKey)) {
|
2023-02-07 20:04:50 +00:00
|
|
|
return "<CANT DECRYPT>";
|
|
|
|
}
|
|
|
|
try {
|
2023-04-13 18:43:43 +00:00
|
|
|
const otherPubKey = note.pubkey === pubKey ? unwrap(note.tags.find(a => a[0] === "p")?.[1]) : note.pubkey;
|
2023-02-07 20:04:50 +00:00
|
|
|
if (hasNip07 && !privKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
return await barrierNip07(() => window.nostr.nip04.decrypt(otherPubKey, note.content));
|
2023-02-07 20:04:50 +00:00
|
|
|
} else if (privKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
return await EventExt.decryptDm(note.content, privKey, otherPubKey);
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
|
|
|
} catch (e) {
|
2023-02-07 19:47:57 +00:00
|
|
|
console.error("Decryption failed", e);
|
2023-02-07 20:04:50 +00:00
|
|
|
return "<DECRYPTION FAILED>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
sendDm: async (content: string, to: HexKey) => {
|
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, EventKind.DirectMessage);
|
|
|
|
ev.content = content;
|
|
|
|
ev.tags.push(["p", to]);
|
2023-01-15 19:40:47 +00:00
|
|
|
|
2023-02-07 20:04:50 +00:00
|
|
|
try {
|
|
|
|
if (hasNip07 && !privKey) {
|
2023-02-09 12:26:54 +00:00
|
|
|
const cx: string = await barrierNip07(() => window.nostr.nip04.encrypt(to, content));
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.content = cx;
|
2023-02-07 20:04:50 +00:00
|
|
|
return await signEvent(ev);
|
|
|
|
} else if (privKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
ev.content = await EventExt.encryptData(content, to, privKey);
|
2023-02-07 20:04:50 +00:00
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
console.error("Encryption failed", e);
|
2023-01-15 19:40:47 +00:00
|
|
|
}
|
2023-02-07 20:04:50 +00:00
|
|
|
}
|
|
|
|
},
|
2023-02-18 20:36:42 +00:00
|
|
|
newKey: () => {
|
|
|
|
const privKey = secp.utils.bytesToHex(secp.utils.randomPrivateKey());
|
|
|
|
const pubKey = secp.utils.bytesToHex(secp.schnorr.getPublicKey(privKey));
|
|
|
|
return {
|
|
|
|
privateKey: privKey,
|
|
|
|
publicKey: pubKey,
|
|
|
|
};
|
|
|
|
},
|
2023-03-30 18:21:33 +00:00
|
|
|
generic: async (content: string, kind: EventKind, tags?: Array<Array<string>>) => {
|
2023-02-13 15:29:25 +00:00
|
|
|
if (pubKey) {
|
2023-03-28 14:34:01 +00:00
|
|
|
const ev = EventExt.forPubKey(pubKey, kind);
|
|
|
|
ev.content = content;
|
2023-03-30 18:21:33 +00:00
|
|
|
ev.tags = tags ?? [];
|
2023-02-13 15:29:25 +00:00
|
|
|
return await signEvent(ev);
|
|
|
|
}
|
|
|
|
},
|
2023-02-07 20:04:50 +00:00
|
|
|
};
|
2023-02-13 15:29:25 +00:00
|
|
|
|
|
|
|
return useMemo(() => ret, [pubKey, relays, follows]);
|
2023-01-15 19:40:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let isNip07Busy = false;
|
|
|
|
|
2023-02-07 19:47:57 +00:00
|
|
|
export const barrierNip07 = async <T>(then: () => Promise<T>): Promise<T> => {
|
2023-02-07 20:04:50 +00:00
|
|
|
while (isNip07Busy) {
|
|
|
|
await delay(10);
|
|
|
|
}
|
|
|
|
isNip07Busy = true;
|
|
|
|
try {
|
|
|
|
return await then();
|
|
|
|
} finally {
|
|
|
|
isNip07Busy = false;
|
|
|
|
}
|
2023-01-27 17:35:55 +00:00
|
|
|
};
|