GithubHelp home page GithubHelp logo

lnurl-node's Introduction

lnurl-node

Build Status

Node.js implementation of lnurl. The purpose of this project is to provide an easy and flexible lnurl server that you can run as a stand-alone process (via CLI) or integrated with your own custom node.js application (via API).

Optionally, your lnurl server can authorize other applications (offline or otherwise). Possible use-cases include offline Lightning Network ATMs (e.g. Bleskomat), static QR codes for receiving donations, authentication mechanism for web sites or web services (login / registration / 2FA).

This project attempts to maintain backwards compatibility for any features, methods, options, hooks, and events which are documented here.

Specification Support

The LNURL specification is divided into separate documents called "LUDs". These documents can be found in the lnurl-rfc repository.

The following is a list of LUDs which this module already (or plans to) support:

Installation

If you wish to use this module as a CLI tool, install it globally via npm:

npm install -g lnurl

Add to your application via npm:

npm install lnurl --save

This will install lnurl and add it to your application's package.json file.

Command-line interface

This section assumes that you have lnurl installed globally and that it is available on your current user's PATH.

CLI: help

To view the help menu:

lnurl --help

CLI: encode

Encode a URL:

lnurl encode "https://service.com/api?q=3fc3645b439ce8e7f2553a69e5267081d96dcd340693afabe04be7b0ccd178df"

Expected output:

lnurl1dp68gurn8ghj7um9wfmxjcm99e3k7mf0v9cxj0m385ekvcenxc6r2c35xvukxefcv5mkvv34x5ekzd3ev56nyd3hxqurzepexejxxepnxscrvwfnv9nxzcn9xq6xyefhvgcxxcmyxymnserxfq5fns

This command also accepts piped input. For example:

echo -n "https://service.com/api?q=3fc3645b439ce8e7f2553a69e5267081d96dcd340693afabe04be7b0ccd178df" \
	| lnurl encode

CLI: decode

Decode an lnurl:

lnurl decode "lnurl1dp68gurn8ghj7um9wfmxjcm99e3k7mf0v9cxj0m385ekvcenxc6r2c35xvukxefcv5mkvv34x5ekzd3ev56nyd3hxqurzepexejxxepnxscrvwfnv9nxzcn9xq6xyefhvgcxxcmyxymnserxfq5fns"

Expected output:

https://service.com/api?q=3fc3645b439ce8e7f2553a69e5267081d96dcd340693afabe04be7b0ccd178df

This command also accepts piped input. For example:

echo -n "lnurl1dp68gurn8ghj7um9wfmxjcm99e3k7mf0v9cxj0m385ekvcenxc6r2c35xvukxefcv5mkvv34x5ekzd3ev56nyd3hxqurzepexejxxepnxscrvwfnv9nxzcn9xq6xyefhvgcxxcmyxymnserxfq5fns" \
	| lnurl decode

CLI: generateNewUrl

To generate a new lnurl that a client application can then use:

lnurl generateNewUrl \
	--host "localhost" \
	--port "3000" \
	--endpoint "/lnurl" \
	--store.backend "knex" \
	--store.config '{"client":"postgres","connection":{"host":"127.0.0.1","user":"postgres","password":"example","database":"lnurl_example"}}' \
	--tag "withdrawRequest" \
	--params '{"minWithdrawable":10000,"maxWithdrawable":10000,"defaultDescription":""}'

See Tags and Parameters for a full list of possible tags and params.

Alternatively, a configuration file can be used:

lnurl generateNewUrl \
	--configFile ./config.json \
	--tag "withdrawRequest" \
	--params '{"minWithdrawable":10000,"maxWithdrawable":10000,"defaultDescription":""}'

Example output:

{
	"encoded": "lnurl1dp68gup69uhkcmmrv9kxsmmnwsarxvpsxqhkcmn4wfkr7ufavvexxvpk893rswpjxcmnvctyvgexzen9xvmkycnxv33rvdtrvy6xzv3ex43xzve5vvexgwfj8yenxvm9xaskzdmpxuexywt9893nqvcly0lgs",
	"secret": "c2c069b882676adb2afe37bbfdb65ca4a295ba34c2d929333e7aa7a72b9e9c03",
	"url": "http://localhost:3000/lnurl?q=c2c069b882676adb2afe37bbfdb65ca4a295ba34c2d929333e7aa7a72b9e9c03"
}

It is possible to set the number of uses allowed for the new URL:

lnurl generateNewUrl \
	--configFile ./config.json \
	--tag "withdrawRequest" \
	--params '{"minWithdrawable":10000,"maxWithdrawable":10000,"defaultDescription":""}' \
	--uses 3

Set --uses equal to 0 to allow the URL to be used an unlimited number of times.

For a list of available options:

lnurl generateNewUrl --help

It is also possible to generate lnurls in other ways:

CLI: server

Start an lnurl application server with the following command:

lnurl server \
	--host "localhost" \
	--port "3000" \
	--lightning.backend "dummy" \
	--lightning.config '{}'
  • The example above uses the "dummy" LN backend. For details about how to connect to a real LN backend, see Supported Lightning Network Backends
  • By default the lnurl server stores data in memory - which is fine for development and testing. But once you plan to run it in production, it is recommended that you use a proper data store - see Configuring Data Store.
  • To enable debugging messages, see the Debugging section of this readme.

Alternatively, a configuration file can be used:

lnurl server --configFile ./config.json

To print all available options for the server command:

lnurl server --help

API

encode

encode(url)

Encode a url as a bech32-encoded string.

Usage:

const lnurl = require('lnurl');
const encoded = lnurl.encode('https://service.com/api?q=3fc3645b439ce8e7f2553a69e5267081d96dcd340693afabe04be7b0ccd178df');
console.log(encoded);

Expected output:

"lnurl1dp68gurn8ghj7um9wfmxjcm99e3k7mf0v9cxj0m385ekvcenxc6r2c35xvukxefcv5mkvv34x5ekzd3ev56nyd3hxqurzepexejxxepnxscrvwfnv9nxzcn9xq6xyefhvgcxxcmyxymnserxfq5fns"

decode

decode(url)

Decode a bech32-encoded lnurl.

Usage:

const lnurl = require('lnurl');
const decoded = lnurl.decode('lnurl1dp68gurn8ghj7um9wfmxjcm99e3k7mf0v9cxj0m385ekvcenxc6r2c35xvukxefcv5mkvv34x5ekzd3ev56nyd3hxqurzepexejxxepnxscrvwfnv9nxzcn9xq6xyefhvgcxxcmyxymnserxfq5fns');
console.log(decoded);

Expected output:

"https://service.com/api?q=3fc3645b439ce8e7f2553a69e5267081d96dcd340693afabe04be7b0ccd178df"

createServer

createServer([options])

Create and initialize an instance of the lnurl server.

Usage:

const lnurl = require('lnurl');
const server = lnurl.createServer({
	host: 'localhost',
	port: 3000,
	auth: {
		apiKeys: [
			{
				id: '46f8cab814de07a8a65f',
				key: 'ee7678f6fa5ab9cf3aa23148ef06553edd858a09639b3687113a5d5cdb5a2a67',
				encoding: 'hex',
			},
		],
	},
	lightning: {
		backend: 'dummy',
		config: {},
	},
});
  • The example above uses the "dummy" LN backend. For details about how to connect to a real LN backend, see Supported Lightning Network Backends
  • By default the lnurl server stores data in memory - which is fine for development and testing. But once you plan to run it in production, it is recommended that you use a proper data store - see Configuring Data Store.
  • To enable debugging messages, see the Debugging section of this readme.

createServer: options

Below is the full list of options that can be passed to the createServer method.

{
	// The host for the web server:
	host: 'localhost',
	// The port for the web server:
	port: 3000,
	// Whether or not to start listening when the server is created:
	listen: true,
	// The URL where the server is externally reachable (e.g "https://your-lnurl-server.com"):
	url: null,
	// The URI path of the web API end-point:
	endpoint: '/lnurl',
	// See list of possible LN backends here:
	// https://github.com/chill117/lnurl-node#supported-lightning-network-backends
	lightning: {
		// The name of the LN backend to use:
		backend: 'dummy',
		// Configuration options to pass to LN backend:
		config: {},
	},
	store: {
		// Name of store backend ('knex', 'memory'):
		backend: 'memory',
		// Configuration options to pass to store:
		config: {},
	},
	payRequest: {
		// A number greater than 0 indicates the maximum length of comments.
		// Setting this to 0 ignores comments.
		//
		// Note that there is a generally accepted limit (2000 characters)
		// to the length of URLs; see:
		// https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers/417184#417184
		//
		// Since comments are sent as a query parameter to the callback URL,
		// this limit should be set to a maximum of 1000 to be safe.
		commentAllowed: 500,
		// Default metadata to be sent in response object:
		metadata: '[["text/plain", "lnurl-node"]]',
	},
}

generateNewUrl

generateNewUrl(tag, params)

To generate a new lnurl that a client application can then use:

const tag = 'payRequest';
const params = {
	minSendable: 10000,
	maxSendable: 200000,
	metadata: '[["text/plain", "lnurl-node"]]',
	commentAllowed: 500,
};
server.generateNewUrl(tag, params).then(result => {
	const { encoded, secret, url } = result;
	console.log({ encoded, secret, url });
}).catch(error => {
	console.error(error);
});

Expected output:

{
	"encoded": "lnurl1dp68gup69uhkcmmrv9kxsmmnwsarxvpsxqhkcmn4wfkr7ufavvexxvpk893rswpjxcmnvctyvgexzen9xvmkycnxv33rvdtrvy6xzv3ex43xzve5vvexgwfj8yenxvm9xaskzdmpxuexywt9893nqvcly0lgs",
	"secret": "c2c069b882676adb2afe37bbfdb65ca4a295ba34c2d929333e7aa7a72b9e9c03",
	"url": "http://localhost:3000/lnurl?q=c2c069b882676adb2afe37bbfdb65ca4a295ba34c2d929333e7aa7a72b9e9c03"
}

See Tags and Parameters for a full list of possible tags and params.

It is possible to set the number of uses allowed for the new URL:

const tag = 'payRequest';
const params = {
	minSendable: 10000,
	maxSendable: 200000,
	metadata: '[["text/plain", "lnurl-node"]]',
	commentAllowed: 500,
};
const options = {
	uses: 3,
};
server.generateNewUrl(tag, params, options).then(result => {
	const { encoded, secret, url } = result;
	console.log({ encoded, secret, url });
}).catch(error => {
	console.error(error);
});

Set uses equal to 0 to allow the URL to be used an unlimited number of times.

It is also possible to generate lnurls in other ways:

Tags and Parameters

Below you will find all tags and their associated params.

channelRequest:

name type notes
localAmt integer (sats) > 0
pushAmt integer (sats) <= localAmt

login:

none

payRequest:

name type notes
minSendable integer (msats) > 0
maxSendable integer (msats) >= minSendable
metadata string stringified JSON
commentAllowed integer character limit for comments (max. 1000), set to 0 to disallow comments

withdrawRequest:

name type notes
minWithdrawable integer (msats) > 0
maxWithdrawable integer (msats) >= minWithdrawable
defaultDescription string

Hooks

It is possible to further customize your lnurl server by using hooks to run custom application code at key points in the server application flow.

How to use a hook:

const lnurl = require('lnurl');
const server = lnurl.createServer();
const { HttpError } = require('lnurl/lib');

// The callback signature can vary depending upon the hook used:
server.bindToHook('HOOK', function(arg1, arg2, arg3, next) {
	// Fail the request by calling next with an error:
	next(new Error('Your custom error message'));
	// Use the HttpError constructor to pass the error to the response object:
	next(new HttpError('Custom error sent in the response object', 400/* status code */));
	// Or call next without any arguments to continue with the request:
	next();
});

Hook: error

This hook is called when any request fails with an error.

Override the existing error with a new error:

server.bindToHook('error', function(error, req, res, next) {
	// Call next with a new error which will be passed to the default error handler:
	next(new HttpError('A new error message', 400));
});

Continue with the existing error:

server.bindToHook('error', function(error, req, res, next) {
	// Call next with no arguments to let the error pass-thru to the default error handler:
	next();
});

Make a custom response:

server.bindToHook('error', function(error, req, res, next) {
	// Use the response object to make a custom response:
	res.status(200).json({ message: 'custom error handling' });
	// Do not call next in this case.
});

Hook: status

This hook is called when a request is received at the web server's /status end-point.

Example OK status response:

server.bindToHook('status', function(req, res, next) {
	// Call next() with no arguments to continue with the normal status flow.
	next();
});

Example failed status response:

server.bindToHook('status', function(req, res, next) {
	// Or, call next with an error to fail the request:
	next(new HttpError('Service temporarily unavailable', 503));
});

Hook: url:process

This hook is called when a request is received at the web server's LNURL end-point.

Example modifying the request object:

server.bindToHook('url:process', function(req, res, next) {
	req.query.defaultDescription = 'custom default description';
	next();// Call next() with no arguments to continue the request.
});

Example rejecting the request:

server.bindToHook('url:process', function(req, res, next) {
	// Call next() with an error to fail the request:
	next(new HttpError('Failed check', 400));
});

Hook: login

login

The lnurl-auth subprotocol allows users to login/authenticate with your service. You can use the login hook as shown here to execute your own custom code whenever there is a successful login/authentication attempt for your server.

server.bindToHook('login', function(key, next) {
	// This code is executed when the lnurl-auth checks have passed (e.g valid signature provided).
	// `key` is the public linking key which has just authenticated.
	// Perform asynchronous code such as database calls here.
	// Call next() without any arguments to continue with the request:
	next();
});

Hook: channelRequest:validate

Hook: payRequest:validate

Hook: withdrawRequest:validate

channelRequest:validate payRequest:validate withdrawRequest:validate

These hooks are called when validating the parameters provided when creating a new URL. For example, when calling server.generateNewUrl(tag, params).

server.bindToHook('channelRequest:validate', function(params, next) {
	// Throw an error to prevent the creation of the new URL:
	next(new Error('Invalid params!'));
	// Call next() without any arguments to continue with the creation of the new URL:
	next();
});

Hook: channelRequest:info

Hook: payRequest:info

Hook: withdrawRequest:info

channelRequest:info payRequest:info withdrawRequest:info

These hooks are called when the initial request is made to the LNURL end-point. The initial request occurs when a wallet app first scans a QR code containing an LNURL. The wallet app makes the initial request for more information about the tag and other parameters associated with the LNURL it just scanned.

server.bindToHook('channelRequest:info', function(secret, params, next) {
	// `secret` is the k1 value that when hashed gives the unique `hash`
	//  associated with an LNURL in the data store.
	// `params` are the parameters provided when the URL was created.
	// Throw an error to fail the request:
	next(new HttpError('Custom error sent in the response object', 400/* status code */));
	// Call next() without any arguments to continue with the request:
	next();
});

Hook: channelRequest:action

Hook: payRequest:action

Hook: withdrawRequest:action

channelRequest:action payRequest:action withdrawRequest:action

These hooks are called when the second request is made to the LNURL end-point. This request occurs when the wallet app wants to complete the action associated with the LNURL it scanned and made an initial request for previously.

  • channelRequest:action - Wallet app sends its node ID and whether or not to make the channel private:
    • remoteid - remote node ID (public key) to which the server should open a channel
    • private - 0 or 1
  • payRequest:action - Wallet sends the amount it wants to pay and an optional comment:
    • amount - amount the server should use when generating a new invoice
  • withdrawRequest:action - Wallet sends a bolt11 invoice that the server should pay:
    • pr - bolt11 invoice
server.bindToHook('channelRequest:action', function(secret, params, next) {
	// `secret` is the k1 value that when hashed gives the unique `hash`
	//  associated with an LNURL in the data store.
	// `params` are the parameters provided when the URL was created plus
	// the parameters provided in the request to the server.
	// Throw an error to fail the request:
	next(new HttpError('Custom error sent in the response object', 400/* status code */));
	// Call next() without any arguments to continue with the request:
	next();
});

Note that these hooks are executed before the server calls the LN backend method. So if an error is thrown here, a channel will not be opened; a new invoice will not be generated; the provided invoice will not be paid.

Events

The server object extends from the event emitter class. It is possible to listen for events as follows:

const lnurl = require('lnurl');
const server = lnurl.createServer();

server.on('EVENT', function(event) {
	// The event object varies depending upon the event type.
});

Event: login

This event is emitted after a successful login attempt.

server.on('login', function(event) {
	const { key, hash } = event;
	// `key` - the public key as provided by the LNURL wallet app
	// `hash` - the hash of the secret for the LNURL used to login
});

Event: channelRequest:action:processed

This event is emitted after a successful call to the LN backend's openChannel method.

server.on('channelRequest:action:processed', function(event) {
	const { secret, params, result } = event;
	// `result` is the non-normalized response object from the LN backend
	// So this will vary depending upon the backend used.
});

Event: payRequest:action:processed

This event is emitted after a successful call to the LN backend's addInvoice method.

server.on('payRequest:action:processed', function(event) {
	const { secret, params, result } = event;
	const { id, invoice } = result;
	// `id` - non-standard reference ID for the new invoice, can be NULL if none provided
	// `invoice` - bolt11 invoice
});

Event: withdrawRequest:action:processed

This event is emitted after a successful call to the LN backend's payInvoice method.

server.on('withdrawRequest:action:processed', function(event) {
	const { secret, params, result } = event;
	const { id } = result;
	// `id` - non-standard reference ID for the payment, can be NULL if none provided
});

Event: channelRequest:action:failed

This event is emitted after a failed call to the LN backend's openChannel method.

server.on('channelRequest:action:failed', function(event) {
	const { secret, params, error } = event;
	// `error` - error from the LN backend
});

Event: payRequest:action:failed

This event is emitted after a failed call to the LN backend's addInvoice method.

server.on('payRequest:action:failed', function(event) {
	const { secret, params, error } = event;
	// `error` - error from the LN backend
});

Event: withdrawRequest:action:failed

This event is emitted after a failed call to the LN backend's payInvoice method.

server.on('withdrawRequest:action:failed', function(event) {
	const { secret, params, error } = event;
	// `error` - error from the LN backend
});

Supported Lightning Network Backends

See lightning-backends for a list of supported Lightning Network backends and their corresponding configuration options.

Configuring Data Store

By default the lnurl server will store data in memory - which is not ideal for several reasons. It is strongly recommended that you configure a proper data store for your server. This module supports PostgreSQL.

PostgreSQL

To use PostgreSQL as your data store you will need to install the postgres module and knex wherever you are running your lnurl server:

npm install knex pg

Then you can run your server via the API as follows:

const lnurl = require('lnurl');
const server = lnurl.createServer({
	// ...
	store: {
		backend: 'knex',
		config: {
			client: 'postgres',
			connection: {
				host: '127.0.0.1',
				user: 'lnurl_server',
				password: '',
				database: 'lnurl_server',
			},
		},
	},
	// ...
});

Or via the CLI:

lnurl server \
	--store.backend="knex" \
	--store.config='{"client":"postgres","connection":{"host":"127.0.0.1","user":"lnurl_server","password":"","database":"lnurl_server"}}'

Debugging

This module uses debug to output debug messages to the console. To output all debug messages, run your node app with the DEBUG environment variable:

DEBUG=lnurl* node your-app.js

Or if using the CLI interface:

DEBUG=lnurl* lnurl server

Tests

To run all tests:

npm test

Changelog

See CHANGELOG.md

License

This software is MIT licensed:

A short, permissive software license. Basically, you can do whatever you want as long as you include the original copyright and license notice in any copy of the software/source. There are many variations of this license in use.

lnurl-node's People

Contributors

asoltys avatar bassim avatar chill117 avatar chrischo-h avatar fiatjaf avatar miguelmedeiros avatar nchabra avatar nicolasburtey avatar prusnak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lnurl-node's Issues

Callback configuration missing

I have configured, a lnurl-node with lnd on backend.

When i access lnurl, looks only this: callback | "http://IP_ADDRESS:7744/lnurl"

How can we configure callback ?
Its not necessary ?

LNPAY and Coinos lightning backends are getting invalid response from the server.

Hey @chill117 !
Thanks for this awesome repo!
I had a great experience configuring my LNUrl Node! ❤️

But I've found a bug when I tried to create a server with LNPay and Coinos Lightning backend integrations.

Let me describe this issue for you:

When I create a new LNURL, the LNPay and CoinOs backend only accepts the amount parameter in sats instead of milisats.
Se when I create a LNURL with the amount: ?amount=1000 referring to 1000 milisats = 1 sat
The backend respond me with an LN invoice with 1000 sats instead of 1 sat.

LNPay and CoinOS APIs are working with the amount unit in sats and your repo is sending the amount in milisats.

Version

v0.19.0

Steps to reproduce

  • Generate a new LNURL
  • Scan the LNURL with a compatible wallet
  • Choose the amount of sats
  • You will get an error.

Expected behaviour

  • Generate a new LNURL
  • Scan the LNURL with a compatible wallet
  • Choose the amount of sats
  • Get a response with payment sent

Screenshots

You can reproduce this error with Z Bot (Discord bot):
image

“uses” with signed URLs?

I noticed before the "uses" concept was introduced a signed url could only be used once. I recently upgraded and now it appears signed urls (in my case withdrawals) can be used an unlimited number of times. Is it possible to specify "uses" for signed urls?

BTW thank you for creating this awesome project 😀

CLI: Add new command to generate new LNURL (w/ server's config)

Example:

lnurl generateNewUrl \
        --configFile ./config.json \
        --tag "channelRequest" \
        --params '{"localAmt":2000,"pushAmt":0}'

Alternative:

lnurl generateNewUrl \
        --url "https://ln.server/u" \
        --store.backend "redis" \
        --store.config '{}' \
        --tag "channelRequest" \
        --params '{"localAmt":2000,"pushAmt":0}'

"uses" in signed URL more than one time

const options = {
    baseUrl: '<my-domain>',
    encode: false,
    uses: 10,
    shorten: true
};

I created lnurl with option uses, but lnurl can be used only for first time, then I got bad request error by wallet (tested by blue wallet). Got error message that maximum ussage of lnurl was already reached.
Storage that I use is sql3.

Any recomendation to create lnurl for more than one use? thanks for help

Connect multiple LND nodes for same LNUrl server

Hi I have 3 LND Nodes running and want to configure LNUrl for those, so is there any possibility I can use same LNURL server and connect to all 3 nodes, or do i need to run 3 different LNUrl servers ?

lnd open channel error: expected funding_txid_str, got funding_txid_bytes

I'm trying to fulfill an openChannel request with lnd and it looks like lnurl-node expects to get back an object with "funding_txid_str" and "output_index" but I'm getting back "funding_txid_bytes" instead:

{
funding_txid_bytes: 'ZWfJcPATOwRKugph5xzjIFVGt4z+WC6sxaxxaazjf2g=',
output_index: 0
}

This is with lnd v0.10.1

I tried going back to lnd v0.9.0 to see if maybe the output had changed recently but still got bytes on that version (and no output_index).

c-lightning support

c-lightning provides a JSON-RPC interface. The following commands can be used to instruct c-lightning to perform necessary actions on behalf of lnurl-server:

The last requirement is for the lnurl-server to know c-lightning's node URI. Since there is no JSON-RPC command for this, then it will have to be a required option when configuring the lnurl-server with c-lightning.

Error when running with config file

Steps to reproduce:

  1. install lnurl locally npm install lnurl (without -g)
  2. create config file as per documentation
  3. run ./node_modules/.bin/lnurl server --configFile ./config.json
  4. observe the following error:
internal/validators.js:124
    throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
    ^

TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
    at validateString (internal/validators.js:124:11)
    at Object.join (path.js:1148:7)
    at Server.prepareStore (/home/bitcoin/node_modules/lnurl/lib/Server.js:580:25)
    at new Server (/home/bitcoin/node_modules/lnurl/lib/Server.js:34:20)
    at Object.createServer (/home/bitcoin/node_modules/lnurl/index.js:7:10)
    at Command.<anonymous> (/home/bitcoin/node_modules/lnurl/cli.js:269:9)
    at Command.listener [as _actionHandler] (/home/bitcoin/node_modules/commander/lib/command.js:466:17)
    at /home/bitcoin/node_modules/commander/lib/command.js:1170:65
    at Command._chainOrCall (/home/bitcoin/node_modules/commander/lib/command.js:1088:12)
    at Command._parseCommand (/home/bitcoin/node_modules/commander/lib/command.js:1170:27) {
  code: 'ERR_INVALID_ARG_TYPE'
}

Oddly enough, this works when I specify options from config file manually on the command line. 🤷

I am using NodeJS 14.x

lnurl-pay: Handle "fromnodes" according to specification

Investigate LN node support for handling "fromnodes" from the lnurl-pay spec:

fromnodes - an optional parameter with value set to comma separated nodeIds if payer wishes a service to provide payment routes starting from specified LN nodeIds

It might not be possible to do this via the APIs provided by every LN node.

New, refactored middleware hooks

There is currently only the "middleware:signedLnurl:afterCheckSignature" hook. Leave this hook for backwards compatibility, but add a new one (with a better name) in the same place in the middleware chain.

Add new hooks:

  • "status" - executed on requests to the /status end-point
  • "url:signed" - executed on valid, signed URL requests
  • "url:process" - executed on requests to the /lnurl (or custom "endpoint" config) - before the default URL checking is done

lnurl-withdraw: "use" incorrectly recorded even in case of payment failure

During the lnurl-withdraw flow, if there is an error from the payment (lnurl-server -> LN node) the server still records that attempt as a "use". In the case that there is only one use, the server responds with following error:

{"status":"ERROR","reason":"Maximum number of uses already reached"}

This is without a payment ever having been sent via LN.

Host & Port for production server.

Hi @chill117, when I tried to host my server on production, the host and port (removed or not) will be localhost. Therefore, my lnurl server does not run on production (local development works fine).

// The host for the web server:
host: 'localhost',
// The port for the web server:
port: 3000,
// The protocol to use for the web server:
protocol: 'http',

LUD-16: Lightning Address

Add support for LUD-16 Lightning Address

Possible new server options:

{
	lightningAddress: {
		// Whether or not to accept payments to any user.
		// Setting this to FALSE will reject payments if a user was not found.
		catchAll: true,
		// Optionally define an array of users for which to accept payments.
		// "username" must be unique.
		users: [
			// { username: 'example' },
			// { username: 'another-user' },
		],
	},
}

Pass entire params object to login hook

I ran into a situation where I wanted to access the k1 secret of the login request in the login hook so I could add a new linkingKey to an existing user's account, identified by the secret they had generated. So I modified your code to pass in the entire params object instead of just the linking key:

asoltys@73260c8

It's a breaking API change but I wonder if you would consider adding it upstream?

Missing tests

Command-line interface:

  • lnurl server command:
    • --configFile option

Planned v1.0.0 release

Create backwards-compatible v0.22 release; deprecate the following:

  • mysql and sqlite3 data stores
  • built-in signed URL support

Create v1.0.0 release with the following breaking changes:

  • Remove support for mysql and sqlite3 data stores
  • Remove built-in signed URL support - this can be done via hooks plus methods provided by lnurl-offline-node

Auth in serverless

It is possible to use LNURL Auth in Lambda or Worker environment? So without running server, just with Request & Reponse handlers.

LndBackend should not require cert

I'm using an LND backend connected to a Voltage server, which does not require providing a cert. Unfortunately, I'm currently getting an error at startup saying the lightning.config.cert is a required field.

Looking at the LndBackend (lib/lightning/lnd.js) class in my node_modules, I see the cert is listed as a required field, but when I check a similar file in the underlying lightning-backends-node, it looks like it's configured correctly, implying that I'm pulling a different class somehow.

I'm wondering where the LndBackend is pulled from and how it can be replaced.

Automated integration tests for LN backends

  • Add a new job to "CI" GitHub action for running LN backend integration tests
    • Use GitHub actions secrets for tokens and other sensitive information needed by tests
  • Create integration tests for LN backends
    • Pass tokens, invoices, payment hashes, preimages, etc as environment variables

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.