flockstr/lib/nostr/index.ts
2023-10-20 19:20:18 -04:00

157 lines
4.0 KiB
TypeScript

// import "websocket-polyfill";
import sha256 from "crypto-js/sha256";
import Hex from "crypto-js/enc-hex";
import { getTagValues } from "./utils";
import { sha256 as SHA256 } from "@noble/hashes/sha256";
import { bytesToHex } from "@noble/hashes/utils";
import crypto from "crypto";
import { Buffer } from "buffer";
import { log } from "../utils";
export enum Kind {
Metadata = 0,
Text = 1,
RecommendRelay = 2,
Contacts = 3,
EncryptedDirectMessage = 4,
EventDeletion = 5,
Reaction = 7,
ChannelCreation = 40,
ChannelMetadata = 41,
ChannelMessage = 42,
ChannelHideMessage = 43,
ChannelMuteUser = 44,
ProfileList = 30000,
GenericList = 30001,
}
export type Event = {
id?: string;
sig?: string;
kind: Kind;
tags: string[][];
pubkey: string;
content: string;
created_at: number;
};
export function getHashedKeyName(name: string) {
let eventHash = SHA256(name);
const version = bytesToHex(eventHash);
const alt = sha256(name).toString(Hex);
console.log("VERSION", version, "vs", alt);
console.log("EQUAL?", version === alt);
return version;
}
export namespace NostrService {
export function createEvent(
kind: number,
publicKey: string,
content: string,
tags: string[][],
) {
const event: Event = {
kind: kind,
pubkey: publicKey,
created_at: Math.floor(Date.now() / 1000),
content: content,
tags: tags,
};
event.id = getEventHash(event);
return event;
}
function serializeEvent(evt: Event) {
return JSON.stringify([
0,
evt.pubkey,
evt.created_at,
evt.kind,
evt.tags,
evt.content,
]);
}
function getEventHash(event: Event): string {
return sha256(serializeEvent(event)).toString(Hex);
}
export async function signEvent(event: Event) {
try {
return await window.nostr?.signEvent(event);
} catch (err: any) {
console.error("signing event failed");
}
return event;
}
export function filterBlogEvents(eventArray: Event[]) {
const filteredEvents = eventArray.filter((e1: Event, index: number) => {
if (e1.content === "") {
return false;
}
const title = getTagValues("title", e1.tags);
if (!title || title === "") {
return false;
}
// return eventArray.findIndex((e2: Event) => e2.id === e1.id) === index;
return true;
});
return filteredEvents;
}
}
export function encryptMessage(message: string, password: string) {
try {
const buffer = create32ByteBuffer(password);
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv("aes-256-cbc", buffer, iv);
const encrypted = Buffer.concat([
cipher.update(message, "utf-8"),
cipher.final(),
]);
return encrypted.toString("base64") + "?iv=" + iv.toString("base64");
} catch (e) {
console.error(e);
}
}
// Function to decrypt a hashed message using a passphrase
// Function to decrypt a hashed message using a passphrase
export function decryptMessage(encryptedMessage: string, password: string) {
log("func", "decryptMessage");
try {
const buffer = create32ByteBuffer(password);
// Extract IV from the received message
const [message, ivBase64] = encryptedMessage.split("?iv=");
if (!message || !ivBase64) {
return;
}
const iv = Buffer.from(ivBase64, "base64");
const encryptedText = Buffer.from(message, "base64");
const decipher = crypto.createDecipheriv("aes-256-cbc", buffer, iv);
const decrypted = decipher.update(encryptedText);
return Buffer.concat([decrypted, decipher.final()]).toString();
} catch (e) {
console.error("Error decrypting", e);
}
}
function create32ByteBuffer(inputString: string) {
const hash = crypto.createHash("sha256").update(inputString).digest("hex");
const buffer = Buffer.from(hash, "hex");
return buffer;
}
export function generateRandomString() {
return crypto.randomBytes(32).toString("hex");
}
export function randomId(): string {
return crypto.randomBytes(32).toString("hex").slice(0, 8);
}