Is the code open somewhere?

Reply to this note

Please Login to reply.

Discussion

😅 the code that does the sending is a complete mess and has a non-public info in it. I’ll try to clean it up and open the source for it. Need to parameterize some of the non-public (but not a high value secret or anything) info.

t-y Fishcake

This took me way longer than I would have liked, but here is the working Typescript code that makes those god damn GW DMs.

// Create DM event

export async function creatNIP17DMEvent(

fromSk: string,

toNpub: string,

dm: string[],

): Promise> {

const skBuff = hexToBytes(fromSk)

const events: Array = []

while (dm.length > 0) {

const msg = dm.shift()

if (msg)

events.push(createNip17Wraps(msg, toNpub, skBuff))

}

return events

}

function getNow(): number {

return Math.floor(Date.now() / 1000)

}

function getRandomNow(): number {

return getNow() - Math.floor(Math.random() * 172800)

}

function nip44Encrypt(rumor: Rumor, privateKey: Uint8Array, publicKey: string): string {

const key = nip44.v2.utils.getConversationKey(privateKey, publicKey)

return nip44.v2.encrypt(JSON.stringify(rumor), key)

}

function createWrap(event: Event, recipientPublicKey: string): Event {

// Get random secret key to wrap the event

const randomSK = generateSecretKey()

return finalizeEvent({

kind: 1059, // Gift wrapped event

content: nip44Encrypt(event, randomSK, recipientPublicKey),

created_at: getRandomNow(),

tags: [["p", recipientPublicKey]]

}, randomSK) as Event

}

function createSeal(event: Rumor, privateKey: Uint8Array, recipientPublicKey: string): Event {

return finalizeEvent({

kind: 13, // Seal

content: nip44Encrypt(event, privateKey, recipientPublicKey),

created_at: getRandomNow(),

tags: []

}, privateKey)

}

function createRumor(message: string, senderPubkey: string, receiverPubkey: string): Rumor {

const rumor = {

kind: 14, // As per specs, should be Kind 14 event

content: message,

pubkey: senderPubkey,

created_at: getNow(),

tags: [["p", receiverPubkey]],

} as Rumor

rumor.id = getEventHash(rumor)

return rumor

}

function createNip17Wraps(message: string, recipientPublicKey: string, senderSk: Uint8Array): Event {

const senderPubkey = getPublicKey(senderSk)

return createWrap(

createSeal(

createRumor(message, senderPubkey, recipientPublicKey),

senderSk, recipientPublicKey),

recipientPublicKey)

}

One fix for types:

function nip44Encrypt(rumor: Rumor | VerifiedEvent, privateKey: Uint8Array, publicKey: string): string {

const key = nip44.v2.utils.getConversationKey(privateKey, publicKey)

return nip44.v2.encrypt(JSON.stringify(rumor), key)

}

It does not have any impact, just cosmetics

It works! :)

Yeah! I do suggest to make a clear documentation about how it should be done, I will contribute if needed. It is super confusing now and no single NIP to look at 🫂😭

Maybe send a PR with some of this code to nostr-tools?

I should add nip40 expiration to the wrap too I think, if the event is OTP

Great idea