diff --git a/api/resolvers/wallet.js b/api/resolvers/wallet.js index 246f97ec..b6fcdb17 100644 --- a/api/resolvers/wallet.js +++ b/api/resolvers/wallet.js @@ -4,6 +4,7 @@ import serialize from './serial' import { decodeCursor, LIMIT, nextCursorEncoded } from '../../lib/cursor' import lnpr from 'bolt11' import { SELECT } from './item' +import { lnurlPayDescriptionHash } from '../../lib/lnurl' export async function getInvoice (parent, { id }, { me, models }) { if (!me) { @@ -230,6 +231,19 @@ export default { throw new Error(res2.reason) } + // decode invoice + let decoded + try { + decoded = await decodePaymentRequest({ lnd, request: res2.pr }) + } catch (error) { + console.log(error) + throw new Error('could not decode invoice') + } + + if (decoded.description_hash !== lnurlPayDescriptionHash(res1.metadata)) { + throw new Error('description hash does not match') + } + // take pr and createWithdrawl return await createWithdrawal(parent, { invoice: res2.pr, maxFee }, { me, models, lnd }) } diff --git a/lib/lnurl.js b/lib/lnurl.js index d986d38e..f08c2879 100644 --- a/lib/lnurl.js +++ b/lib/lnurl.js @@ -16,6 +16,10 @@ export function lnurlPayMetadataString (username) { ]]) } -export function lnurlPayDescriptionHash (username) { - return createHash('sha256').update(lnurlPayMetadataString(username)).digest('hex') +export function lnurlPayDescriptionHashForUser (username) { + return lnurlPayDescriptionHash(lnurlPayMetadataString(username)) +} + +export function lnurlPayDescriptionHash (data) { + return createHash('sha256').update(data).digest('hex') } diff --git a/pages/api/lnurlp/[username]/index.js b/pages/api/lnurlp/[username]/index.js index 567a8307..1e0c1b00 100644 --- a/pages/api/lnurlp/[username]/index.js +++ b/pages/api/lnurlp/[username]/index.js @@ -8,7 +8,7 @@ export default async ({ query: { username } }, res) => { } return res.status(200).json({ - callback: `https://stacker.news/api/lnurlp/${username}/pay`, // The URL from LN SERVICE which will accept the pay request parameters + callback: `${process.env.PUBLIC_URL}/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: lnurlPayMetadataString(username), // Metadata json which must be presented as raw string here, this is required to pass signature verification at a later step diff --git a/pages/api/lnurlp/[username]/pay.js b/pages/api/lnurlp/[username]/pay.js index c21b64f7..a3c045fc 100644 --- a/pages/api/lnurlp/[username]/pay.js +++ b/pages/api/lnurlp/[username]/pay.js @@ -1,7 +1,7 @@ import models from '../../../../api/models' import lnd from '../../../../api/lnd' import { createInvoice } from 'ln-service' -import { lnurlPayDescriptionHash } from '../../../../lib/lnurl' +import { lnurlPayDescriptionHashForUser } from '../../../../lib/lnurl' import serialize from '../../../../api/resolvers/serial' export default async ({ query: { username, amount } }, res) => { @@ -17,7 +17,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 = lnurlPayDescriptionHash(username) + const descriptionHash = lnurlPayDescriptionHashForUser(username) try { const invoice = await createInvoice({ description,