merge changes

This commit is contained in:
Alex Bosworth 2022-04-20 10:10:32 -07:00
parent a3192e2f97
commit 7dc460eba0
No known key found for this signature in database
GPG key ID: E80D2F3F311FD87E
2 changed files with 27 additions and 57 deletions

View file

@ -1,26 +1,30 @@
const {bech32} = require('bech32');
const {decode} = bech32;
const asLnurl = n => n.substring(n.startsWith('lightning:') ? 10 : 0);
const bech32CharLimit = 2000;
const emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
const isOnion = n => /onion/.test(n);
const {decode} = bech32;
const isEmail = n => /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/.test(n);
const isOnion = n => /.onion$/.test(n);
const isUsername = n => /^[a-z0-9_.]*$/.test(n);
const join = arr => arr.join('');
const parseEmail = email => email.split('@');
const prefix = 'lnurl';
const sslProtocol = 'https://';
const testEmail = n => emailPattern.test(n);
const testUsername = n => /^[a-z0-9_.]*$/.test(n);
const urlString = '/.well-known/lnurlp/';
const wordsAsUtf8 = n => Buffer.from(bech32.fromWords(n)).toString('utf8');
/** Parse lnurl or lightning address
/** Parse lnurl or LUD-16 lightning address
{
url: <Lnurl or Lightning Address String>
}
@throws
<Error>
@returns
{
url: <Callback Url>
url: <Callback Url String>
}
*/
module.exports = ({url}) => {
@ -28,42 +32,28 @@ module.exports = ({url}) => {
throw new Error('ExpectedLnurlOrLightningAddressToParse');
}
// Check if its a valid email address
if (!!testEmail(url)) {
const [username, domain] = url.split('@');
// Exit early when the URL looks like an email, indicating lightning address
if (!!isEmail(url)) {
const [username, domain] = parseEmail(url);
// Check if the user name is valid
if (!testUsername(username)) {
if (!isUsername(username)) {
throw new Error('ExpectedValidUsernameInLightningAddress');
}
// Because of restrictions on the HTTP request library, disallow onion URLs
if (!!isOnion(domain)) {
throw new Error('ExpectedValidClearnetLightningAddress');
throw new Error('LnurlOnionUrlsCurrentlyUnsupported');
}
const callbackUrl = [
sslProtocol,
domain,
urlString,
username,
];
return callbackUrl.join('');
return {url: join([sslProtocol, domain, urlString, username])};
}
// Check for lnurl is valid
try {
decode(asLnurl(url), bech32CharLimit);
} catch (err) {
throw new Error(400, 'FailedToDecodeLnurl', {err});
}
if (decode(asLnurl(url), bech32CharLimit).prefix !== prefix) {
throw new Error(400, 'ExpectedLnUrlPrefix');
throw new Error('ExpectedLnurlPrefix');
}
const {words} = decode(asLnurl(url), bech32CharLimit);
return wordsAsUtf8(words);
}
return {url: wordsAsUtf8(words)};
};

View file

@ -1,7 +1,6 @@
const {createHash} = require('crypto');
const asyncAuto = require('async/auto');
const {bech32} = require('bech32');
const {getNodeAlias} = require('ln-sync');
const moment = require('moment');
const {returnResult} = require('asyncjs-util');
@ -10,10 +9,6 @@ const {parsePaymentRequest} = require('ln-service');
const parseUrl = require('./parse_url');
const {pay} = require('./../network');
const asLnurl = n => n.substring(n.startsWith('lightning:') ? 10 : 0);
const bech32CharLimit = 2000;
const {decode} = bech32;
const emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
const errorStatus = 'ERROR';
const {isArray} = Array;
const isNumber = n => !isNaN(n);
@ -24,11 +19,9 @@ const minMinSendable = 1;
const mtokensAsTokens = n => Math.floor(n / 1000);
const {parse} = JSON;
const payRequestTag = 'payRequest';
const prefix = 'lnurl';
const {round} = Math;
const sha256 = n => createHash('sha256').update(n).digest().toString('hex');
const sslProtocol = 'https:';
const testEmail = n => emailPattern.test(n);
const textPlain = 'text/plain';
const tokensAsBigUnit = tokens => (tokens / 1e8).toFixed(8);
const tokensAsMillitokens = n => n * 1000;
@ -64,16 +57,10 @@ module.exports = (args, cbk) => {
return cbk([400, 'ExpectedUrlToGetPaymentRequestFromLnurl']);
}
if (!testEmail(args.lnurl)) {
try {
decode(asLnurl(args.lnurl), bech32CharLimit);
} catch (err) {
return cbk([400, 'FailedToDecodeLnurlOrLightningAddressToPay']);
}
}
if (!testEmail(args.lnurl) && decode(asLnurl(args.lnurl), bech32CharLimit).prefix !== prefix) {
return cbk([400, 'ExpectedLnUrlPrefixToPay']);
try {
parseUrl({url: args.lnurl});
} catch (err) {
return cbk([400, err.message]);
}
if (!args.lnd) {
@ -103,16 +90,9 @@ module.exports = (args, cbk) => {
return cbk();
},
// Get the call back url
getCallBackUrl: ['validate', ({}, cbk) => {
const url = parseUrl({url: args.lnurl});
return cbk(null, url);
}],
// Get accepted terms from the encoded url
getTerms: ['getCallBackUrl', ({getCallBackUrl}, cbk) => {
const url = getCallBackUrl;
getTerms: ['validate', ({}, cbk) => {
const {url} = parseUrl({url: args.lnurl});
return args.request({url, json: true}, (err, r, json) => {
if (!!err) {