Muted words: phase 1
This commit is contained in:
@ -25,6 +25,7 @@ enum EventKind {
|
||||
Badge = 30009, // NIP-58
|
||||
ProfileBadges = 30008, // NIP-58
|
||||
LongFormTextNote = 30023, // NIP-23
|
||||
AppData = 30_078, // NIP-78
|
||||
LiveEvent = 30311, // NIP-102
|
||||
UserStatus = 30315, // NIP-38
|
||||
ZapstrTrack = 31337,
|
||||
|
@ -3,11 +3,13 @@ import * as utils from "@noble/curves/abstract/utils";
|
||||
import { unwrap, getPublicKey, unixNow } from "@snort/shared";
|
||||
|
||||
import {
|
||||
decodeEncryptionPayload,
|
||||
EventKind,
|
||||
EventSigner,
|
||||
FullRelaySettings,
|
||||
HexKey,
|
||||
Lists,
|
||||
MessageEncryptorVersion,
|
||||
NostrEvent,
|
||||
NostrLink,
|
||||
NotSignedNostrEvent,
|
||||
@ -24,6 +26,7 @@ import { EventBuilder } from "./event-builder";
|
||||
import { EventExt } from "./event-ext";
|
||||
import { findTag } from "./utils";
|
||||
import { Nip7Signer } from "./impl/nip7";
|
||||
import { base64 } from "@scure/base";
|
||||
|
||||
type EventBuilderHook = (ev: EventBuilder) => EventBuilder;
|
||||
|
||||
@ -269,6 +272,23 @@ export class EventPublisher {
|
||||
return await this.#sign(eb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic decryption using NIP-23 payload scheme
|
||||
*/
|
||||
async decryptGeneric(content: string, from: string) {
|
||||
const pl = decodeEncryptionPayload(content);
|
||||
switch(pl.v) {
|
||||
case MessageEncryptorVersion.Nip4: {
|
||||
const nip4Payload = `${base64.encode(pl.ciphertext)}?iv=${base64.encode(pl.nonce)}`;
|
||||
return await this.#signer.nip4Decrypt(nip4Payload, from);
|
||||
}
|
||||
case MessageEncryptorVersion.XChaCha20: {
|
||||
return await this.#signer.nip44Decrypt(content, from);
|
||||
}
|
||||
}
|
||||
throw new Error("Not supported version");
|
||||
}
|
||||
|
||||
async decryptDm(note: NostrEvent) {
|
||||
if (note.kind === EventKind.SealedRumor) {
|
||||
const unseal = await this.unsealRumor(note);
|
||||
|
@ -6,6 +6,7 @@ import { NostrEvent, ReqFilter, TaggedNostrEvent } from "./nostr";
|
||||
import { ProfileLoaderService } from "./profile-cache";
|
||||
import { RelayCache } from "./gossip-model";
|
||||
import { QueryOptimizer } from "./query-optimizer";
|
||||
import { base64 } from "@scure/base";
|
||||
|
||||
export * from "./nostr-system";
|
||||
export { default as EventKind } from "./event-kind";
|
||||
@ -136,3 +137,25 @@ export interface MessageEncryptor {
|
||||
encryptData(plaintext: string, sharedSecet: Uint8Array): Promise<MessageEncryptorPayload> | MessageEncryptorPayload;
|
||||
decryptData(payload: MessageEncryptorPayload, sharedSecet: Uint8Array): Promise<string> | string;
|
||||
}
|
||||
|
||||
export function decodeEncryptionPayload(p: string) {
|
||||
if (p.startsWith("{") && p.endsWith("}")) {
|
||||
const pj = JSON.parse(p) as { v: number; nonce: string; ciphertext: string };
|
||||
return {
|
||||
v: pj.v,
|
||||
nonce: base64.decode(pj.nonce),
|
||||
ciphertext: base64.decode(pj.ciphertext),
|
||||
} as MessageEncryptorPayload;
|
||||
} else {
|
||||
const buf = base64.decode(p);
|
||||
return {
|
||||
v: buf[0],
|
||||
nonce: buf.subarray(1, 25),
|
||||
ciphertext: buf.subarray(25),
|
||||
} as MessageEncryptorPayload;
|
||||
}
|
||||
}
|
||||
|
||||
export function encodeEncryptionPayload(p: MessageEncryptorPayload) {
|
||||
return base64.encode(new Uint8Array([p.v, ...p.nonce, ...p.ciphertext]));
|
||||
}
|
@ -3,7 +3,7 @@ import { getPublicKey } from "@snort/shared";
|
||||
import { EventExt } from "./event-ext";
|
||||
import { Nip4WebCryptoEncryptor } from "./impl/nip4";
|
||||
import { XChaCha20Encryptor } from "./impl/nip44";
|
||||
import { MessageEncryptorPayload, MessageEncryptorVersion } from "./index";
|
||||
import { MessageEncryptorVersion, decodeEncryptionPayload, encodeEncryptionPayload } from "./index";
|
||||
import { NostrEvent } from "./nostr";
|
||||
import { base64 } from "@scure/base";
|
||||
|
||||
@ -74,11 +74,11 @@ export class PrivateKeySigner implements EventSigner {
|
||||
const enc = new XChaCha20Encryptor();
|
||||
const shared = enc.getSharedSecret(this.#privateKey, key);
|
||||
const data = enc.encryptData(content, shared);
|
||||
return this.#encodePayload(data);
|
||||
return encodeEncryptionPayload(data);
|
||||
}
|
||||
|
||||
async nip44Decrypt(content: string, otherKey: string) {
|
||||
const payload = this.#decodePayload(content);
|
||||
const payload = decodeEncryptionPayload(content);
|
||||
if (payload.v !== MessageEncryptorVersion.XChaCha20) throw new Error("Invalid payload version");
|
||||
|
||||
const enc = new XChaCha20Encryptor();
|
||||
@ -86,28 +86,6 @@ export class PrivateKeySigner implements EventSigner {
|
||||
return enc.decryptData(payload, shared);
|
||||
}
|
||||
|
||||
#decodePayload(p: string) {
|
||||
if (p.startsWith("{") && p.endsWith("}")) {
|
||||
const pj = JSON.parse(p) as { v: number; nonce: string; ciphertext: string };
|
||||
return {
|
||||
v: pj.v,
|
||||
nonce: base64.decode(pj.nonce),
|
||||
ciphertext: base64.decode(pj.ciphertext),
|
||||
} as MessageEncryptorPayload;
|
||||
} else {
|
||||
const buf = base64.decode(p);
|
||||
return {
|
||||
v: buf[0],
|
||||
nonce: buf.subarray(1, 25),
|
||||
ciphertext: buf.subarray(25),
|
||||
} as MessageEncryptorPayload;
|
||||
}
|
||||
}
|
||||
|
||||
#encodePayload(p: MessageEncryptorPayload) {
|
||||
return base64.encode(new Uint8Array([p.v, ...p.nonce, ...p.ciphertext]));
|
||||
}
|
||||
|
||||
sign(ev: NostrEvent): Promise<NostrEvent> {
|
||||
EventExt.sign(ev, this.#privateKey);
|
||||
return Promise.resolve(ev);
|
||||
|
Reference in New Issue
Block a user