diff --git a/lib/lnurl.js b/lib/lnurl.js index 22486993..2ab17c26 100644 --- a/lib/lnurl.js +++ b/lib/lnurl.js @@ -1,4 +1,4 @@ -import { randomBytes } from 'crypto' +import { randomBytes, createHash } from 'crypto' import { bech32 } from 'bech32' export function lnurlAuth (params) { @@ -15,3 +15,14 @@ export function lnurlAuth (params) { const encodedUrl = bech32.encode('lnurl', words, 1023) return { secret, encodedUrl } } + +export function lnurlPayMetadataString (username) { + return JSON.stringify([[ + 'text/plain', + `Funding @${username} on stacker.news` + ]]) +} + +export function lnurlPayDescriptionHash (username) { + return createHash('sha256').update(lnurlPayMetadataString(username)).digest('hex') +} diff --git a/pages/api/lnurlp/[username]/index.js b/pages/api/lnurlp/[username]/index.js index b7146adc..567a8307 100644 --- a/pages/api/lnurlp/[username]/index.js +++ b/pages/api/lnurlp/[username]/index.js @@ -1,4 +1,5 @@ import models from '../../../../api/models' +import { lnurlPayMetadataString } from '../../../../lib/lnurl' export default async ({ query: { username } }, res) => { const user = await models.user.findUnique({ where: { name: username } }) @@ -10,10 +11,7 @@ export default async ({ query: { username } }, res) => { callback: `https://stacker.news/api/lnurlp/${username}/pay`, // The URL from LN SERVICE which will accept the pay request parameters minSendable: 1000, // Min amount LN SERVICE is willing to receive, can not be less than 1 or more than `maxSendable` maxSendable: Number.MAX_SAFE_INTEGER, - metadata: [[ - 'text/plain', // must always be present - `Funding @${username} on stacker.news` // actual metadata content - ]], // Metadata json which must be presented as raw string here, this is required to pass signature verification at a later step + metadata: lnurlPayMetadataString(username), // Metadata json which must be presented as raw string here, this is required to pass signature verification at a later step tag: 'payRequest' // Type of LNURL }) } diff --git a/pages/api/lnurlp/[username]/pay.js b/pages/api/lnurlp/[username]/pay.js index 6e5f9c4e..4472e55c 100644 --- a/pages/api/lnurlp/[username]/pay.js +++ b/pages/api/lnurlp/[username]/pay.js @@ -1,18 +1,7 @@ import models from '../../../../api/models' import lnd from '../../../../api/lnd' import { createInvoice } from 'ln-service' -import crypto from 'crypto' - -function utf8ByteArray (str) { - const utf8 = unescape(encodeURIComponent(str)) - - const arr = [] - for (let i = 0; i < utf8.length; i++) { - arr.push(utf8.charCodeAt(i)) - } - - return Buffer.from(arr) -} +import { lnurlPayDescriptionHash } from '../../../../lib/lnurl' export default async ({ query: { username, amount } }, res) => { const user = await models.user.findUnique({ where: { name: username } }) @@ -27,10 +16,7 @@ export default async ({ query: { username, amount } }, res) => { // generate invoice const expiresAt = new Date(new Date().setHours(new Date().getHours() + 3)) const description = `${amount} msats for @${user.name} on stacker.news` - const descriptionHash = crypto - .createHash('sha256') - .update(utf8ByteArray(`Funding @${username} on stacker.news`)) - .digest('hex') + const descriptionHash = lnurlPayDescriptionHash(username) try { const invoice = await createInvoice({ description,