@@ -3,7 +3,19 @@ import wrap from './lib/promise-wrap'
33
44const debug = require ( 'debug' ) ( 'lightning-charge' )
55
6- module . exports = ( app , payListen , model , auth ) => {
6+ module . exports = ( app , payListen , model , auth , ln ) => async {
7+ // check if method invoicewithdescriptionhash exists
8+ let help = await ln . help ( )
9+ let foundCommand
10+ for ( let i = 0 ; i < help . help . length ; i ++ ) {
11+ let command = help . help [ i ] . command
12+ if ( command . slice ( 0 , 26 ) !== 'invoicewithdescriptionhash' ) continue
13+ foundCommand = true
14+ break
15+ }
16+ if ( ! foundCommand ) return
17+
18+ // define routes
719 const {
820 newInvoice, listInvoicesByLnurlPayEndpoint
921 , getLnurlPayEndpoint, listLnurlPayEndpoints
@@ -26,67 +38,85 @@ module.exports = (app, payListen, model, auth) => {
2638 addBech32Lnurl ( req , await setLnurlPayEndpoint ( req . params . id , req . body ) )
2739 ) ) )
2840
29- app . delete ( '/endpoint/:id' , auth , wrap ( async ( req , res ) =>
30- res . status ( 200 ) . send ( await delLnurlPayEndpoint ( req . params . id ) ) ) )
41+ app . delete ( '/endpoint/:id' , auth , wrap ( async ( req , res ) => {
42+ const deletedRows = await delLnurlPayEndpoint ( req . params . id )
43+ if ( deletedRows ) res . status ( 204 )
44+ else res . status ( 404 )
45+ } ) )
3146
32- app . get ( '/endpoint/:id' , auth , wrap ( async ( req , res ) =>
33- res . status ( 200 ) . send (
34- addBech32Lnurl ( req , await getLnurlPayEndpoint ( req . params . id ) )
35- ) ) )
47+ app . get ( '/endpoint/:id' , auth , wrap ( async ( req , res ) => {
48+ const endpoint = await getLnurlPayEndpoint ( req . params . id )
49+ if ( endpoint ) res . status ( 200 ) . send ( addBech32Lnurl ( req , endpoint ) )
50+ else res . status ( 404 )
51+ } ) )
3652
3753 app . get ( '/endpoint/:id/invoices' , auth , wrap ( async ( req , res ) =>
3854 res . send ( await listInvoicesByLnurlPayEndpoint ( req . params . id ) ) ) )
3955
4056 // this is the actual endpoint users will hit
4157 app . get ( '/lnurl/:id' , wrap ( async ( req , res ) => {
42- const lnurlpay = await getLnurlPayEndpoint ( req . params . id )
58+ const endpoint = await getLnurlPayEndpoint ( req . params . id )
59+
60+ if ( ! endpoint ) {
61+ res . status ( 404 )
62+ return
63+ }
4364
4465 res . status ( 200 ) . send ( {
4566 tag : 'payRequest'
46- , minSendable : lnurlpay . min
47- , maxSendable : lnurlpay . max
48- , metadata : makeMetadata ( lnurlpay )
49- , commentAllowed : lnurlpay . comment
67+ , minSendable : endpoint . min
68+ , maxSendable : endpoint . max
69+ , metadata : makeMetadata ( endpoint )
70+ , commentAllowed : endpoint . comment_length
5071 , callback : `https://${ req . hostname } /lnurl/${ lnurlpay . id } /callback`
5172 } )
5273 } ) )
5374
5475 app . get ( '/lnurl/:id/callback' , wrap ( async ( req , res ) => {
55- const lnurlpay = await getLnurlPayEndpoint ( req . params . id )
76+ const endpoint = await getLnurlPayEndpoint ( req . params . id )
77+ const amount = + req . query . amount
5678
57- if ( req . query . amount > lnurlpay . max )
58- return res . send ( { status : 'ERROR' , reason : 'amount too large' } )
59- if ( req . query . amount < lnurlpay . min )
60- return res . send ( { status : 'ERROR' , reason : 'amount too small' } )
79+ if ( ! amount )
80+ return res . send ( { status : 'ERROR' , reason : `invalid amount '${ req . query . amount } '` } )
81+ if ( amount > endpoint . max )
82+ return res . send ( { status : 'ERROR' , reason : `amount must be smaller than ${ Math . floor ( endpoint . max / 1000 ) } sat` } )
83+ if ( amount < endpoint . min )
84+ return res . send ( { status : 'ERROR' , reason : `amount must be greater than ${ Math . ceil ( endpoint . min / 1000 ) } sat` } )
6185
6286 let invoiceMetadata = { ...req . query }
6387 delete invoiceMetadata . amount
6488 delete invoiceMetadata . fromnodes
6589 delete invoiceMetadata . nonce
66- invoiceMetadata = { ...lnurlpay . metadata , ...invoiceMetadata }
90+ invoiceMetadata = { ...endpoint . metadata , ...invoiceMetadata }
91+
92+ // enforce comment length
93+ invoiceMetadata . comment =
94+ ( comment . comment && req . query . comment )
95+ ? ( '' + req . query . comment ) . substr ( 0 , endpoint . comment )
96+ : undefined
6797
6898 const invoice = await newInvoice ( {
69- descriptionHash : require ( 'crypto' )
99+ description_hash : require ( 'crypto' )
70100 . createHash ( 'sha256' )
71101 . update ( makeMetadata ( lnurlpay ) )
72102 . digest ( 'hex' )
73103 , msatoshi : req . query . amount
74104 , metadata : invoiceMetadata
75- , webhook : lnurlpay . webhook
76- , lnurlpay_endpoint : lnurlpay . id
105+ , webhook : endpoint . webhook
106+ , lnurlpay_endpoint : endpoint . id
77107 } )
78108
79109 let successAction
80- if ( lnurlpay . success_url ) {
110+ if ( endpoint . success_url ) {
81111 successAction = {
82112 tag : 'url'
83- , url : lnurlpay . success_url
84- , description : lnurlpay . success_text || ''
113+ , url : endpoint . success_url
114+ , description : endpoint . success_text || ''
85115 }
86- } else if ( lnurlpay . success_value ) {
116+ } else if ( lnurlpay . success_secret ) {
87117 // not implemented yet
88- } else if ( lnurlpay . success_text ) {
89- successAction = { tag : 'message' , message : lnurlpay . success_text }
118+ } else if ( endpoint . success_text ) {
119+ successAction = { tag : 'message' , message : endpoint . success_text }
90120 }
91121
92122 res . status ( 200 ) . send ( {
@@ -98,18 +128,18 @@ module.exports = (app, payListen, model, auth) => {
98128 } ) )
99129}
100130
101- function makeMetadata ( lnurlpay ) {
102- const text = lnurlpay . text
103-
104- const meta = [ [ 'text/plain' , text ] ]
105- . concat ( lnurlpay . image ? [ 'image/png;base64' , lnurlpay . image ] : [ ] )
106-
107- return JSON . stringify ( meta )
131+ function makeMetadata ( endpoint ) {
132+ return JSON . stringify (
133+ [ [ 'text/plain' , endpoint . text ] ]
134+ . concat ( endpoint . image ? [ 'image/png;base64' , endpoint . image ] : [ ] )
135+ . concat ( JSON . parse ( endpoint . other_metadata || [ ] ) )
136+ )
108137}
109138
110139function addBech32Lnurl ( req , lnurlpay ) {
111- const hostname = req . hostname || req . params . hostname
112- const url = `https://${ hostname } /lnurl/${ lnurlpay . id } `
140+ let base = process . env . URL || `https://${ req . hostname } `
141+ base = base [ base . length - 1 ] === '/' ? base . slice ( 0 , - 1 ) : base
142+ const url = `${ base } /lnurl/${ lnurlpay . id } `
113143 const words = bech32 . toWords ( Buffer . from ( url ) )
114144 lnurlpay . bech32 = bech32 . encode ( 'lnurl' , words , 2500 ) . toUpperCase ( )
115145 return lnurlpay
0 commit comments