Skip to content

Commit 8cd670f

Browse files
authored
Merge pull request #637 from benthecarman/lnurl-auth
Add LNURL-auth support
2 parents 399cb65 + 343d570 commit 8cd670f

File tree

8 files changed

+347
-4
lines changed

8 files changed

+347
-4
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ bdk_esplora = { version = "0.22.0", default-features = false, features = ["async
5656
bdk_electrum = { version = "0.23.0", default-features = false, features = ["use-rustls-ring"]}
5757
bdk_wallet = { version = "2.3.0", default-features = false, features = ["std", "keys-bip39"]}
5858

59-
bitreq = { version = "0.3", default-features = false, features = ["async-https"] }
59+
bitreq = { version = "0.3", default-features = false, features = ["async-https", "json-using-serde"] }
6060
rustls = { version = "0.23", default-features = false }
6161
rusqlite = { version = "0.31.0", features = ["bundled"] }
6262
bitcoin = "0.32.7"

bindings/ldk_node.udl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ interface Node {
9393
UnifiedPayment unified_payment();
9494
LSPS1Liquidity lsps1_liquidity();
9595
[Throws=NodeError]
96+
void lnurl_auth(string lnurl);
97+
[Throws=NodeError]
9698
void connect(PublicKey node_id, SocketAddress address, boolean persist);
9799
[Throws=NodeError]
98100
void disconnect(PublicKey node_id);
@@ -208,6 +210,9 @@ enum NodeError {
208210
"InvalidBlindedPaths",
209211
"AsyncPaymentServicesDisabled",
210212
"HrnParsingFailed",
213+
"LnurlAuthFailed",
214+
"LnurlAuthTimeout",
215+
"InvalidLnurl",
211216
};
212217

213218
typedef dictionary NodeStatus;

src/builder.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ use crate::io::{
6868
use crate::liquidity::{
6969
LSPS1ClientConfig, LSPS2ClientConfig, LSPS2ServiceConfig, LiquiditySourceBuilder,
7070
};
71+
use crate::lnurl_auth::LnurlAuth;
7172
use crate::logger::{log_error, LdkLogger, LogLevel, LogWriter, Logger};
7273
use crate::message_handler::NodeCustomMessageHandler;
7374
use crate::payment::asynchronous::om_mailbox::OnionMessageMailbox;
@@ -1762,6 +1763,8 @@ fn build_with_store_internal(
17621763
None
17631764
};
17641765

1766+
let lnurl_auth = Arc::new(LnurlAuth::new(xprv, Arc::clone(&logger)));
1767+
17651768
let (stop_sender, _) = tokio::sync::watch::channel(());
17661769
let (background_processor_stop_sender, _) = tokio::sync::watch::channel(());
17671770
let is_running = Arc::new(RwLock::new(false));
@@ -1807,6 +1810,7 @@ fn build_with_store_internal(
18071810
scorer,
18081811
peer_store,
18091812
payment_store,
1813+
lnurl_auth,
18101814
is_running,
18111815
node_metrics,
18121816
om_mailbox,

src/config.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ pub(crate) const EXTERNAL_PATHFINDING_SCORES_SYNC_TIMEOUT_SECS: u64 = 5;
107107
// The timeout after which we abort a parsing/looking up an HRN resolution.
108108
pub(crate) const HRN_RESOLUTION_TIMEOUT_SECS: u64 = 5;
109109

110+
// The timeout after which we abort an LNURL-auth operation.
111+
pub(crate) const LNURL_AUTH_TIMEOUT_SECS: u64 = 15;
112+
110113
#[derive(Debug, Clone)]
111114
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
112115
/// Represents the configuration of an [`Node`] instance.

src/error.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,12 @@ pub enum Error {
131131
AsyncPaymentServicesDisabled,
132132
/// Parsing a Human-Readable Name has failed.
133133
HrnParsingFailed,
134+
/// LNURL-auth authentication failed.
135+
LnurlAuthFailed,
136+
/// LNURL-auth authentication timed out.
137+
LnurlAuthTimeout,
138+
/// The provided lnurl is invalid.
139+
InvalidLnurl,
134140
}
135141

136142
impl fmt::Display for Error {
@@ -213,6 +219,9 @@ impl fmt::Display for Error {
213219
Self::HrnParsingFailed => {
214220
write!(f, "Failed to parse a human-readable name.")
215221
},
222+
Self::LnurlAuthFailed => write!(f, "LNURL-auth authentication failed."),
223+
Self::LnurlAuthTimeout => write!(f, "LNURL-auth authentication timed out."),
224+
Self::InvalidLnurl => write!(f, "The provided lnurl is invalid."),
216225
}
217226
}
218227
}

src/io/vss_store.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use vss_client::util::storable_builder::{EntropySource, StorableBuilder};
4343

4444
use crate::entropy::NodeEntropy;
4545
use crate::io::utils::check_namespace_key_validity;
46+
use crate::lnurl_auth::LNURL_AUTH_HARDENED_CHILD_INDEX;
4647

4748
type CustomRetryPolicy = FilteredRetryPolicy<
4849
JitteredRetryPolicy<
@@ -68,7 +69,6 @@ impl_writeable_tlv_based_enum!(VssSchemaVersion,
6869
);
6970

7071
const VSS_HARDENED_CHILD_INDEX: u32 = 877;
71-
const VSS_LNURL_AUTH_HARDENED_CHILD_INDEX: u32 = 138;
7272
const VSS_SCHEMA_VERSION_KEY: &str = "vss_schema_version";
7373

7474
// We set this to a small number of threads that would still allow to make some progress if one
@@ -902,7 +902,7 @@ impl VssStoreBuilder {
902902
let lnurl_auth_xprv = vss_xprv
903903
.derive_priv(
904904
&secp_ctx,
905-
&[ChildNumber::Hardened { index: VSS_LNURL_AUTH_HARDENED_CHILD_INDEX }],
905+
&[ChildNumber::Hardened { index: LNURL_AUTH_HARDENED_CHILD_INDEX }],
906906
)
907907
.map_err(|_| VssStoreBuildError::KeyDerivationFailed)?;
908908

src/lib.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ pub mod graph;
9696
mod hex_utils;
9797
pub mod io;
9898
pub mod liquidity;
99+
mod lnurl_auth;
99100
pub mod logger;
100101
mod message_handler;
101102
pub mod payment;
@@ -126,7 +127,8 @@ pub use builder::NodeBuilder as Builder;
126127
use chain::ChainSource;
127128
use config::{
128129
default_user_config, may_announce_channel, AsyncPaymentsRole, ChannelConfig, Config,
129-
NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
130+
LNURL_AUTH_TIMEOUT_SECS, NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL,
131+
RGS_SYNC_INTERVAL,
130132
};
131133
use connection::ConnectionManager;
132134
pub use error::Error as NodeError;
@@ -154,6 +156,7 @@ pub use lightning_invoice;
154156
pub use lightning_liquidity;
155157
pub use lightning_types;
156158
use liquidity::{LSPS1Liquidity, LiquiditySource};
159+
use lnurl_auth::LnurlAuth;
157160
use logger::{log_debug, log_error, log_info, log_trace, LdkLogger, Logger};
158161
use payment::asynchronous::om_mailbox::OnionMessageMailbox;
159162
use payment::asynchronous::static_invoice_store::StaticInvoiceStore;
@@ -224,6 +227,7 @@ pub struct Node {
224227
scorer: Arc<Mutex<Scorer>>,
225228
peer_store: Arc<PeerStore<Arc<Logger>>>,
226229
payment_store: Arc<PaymentStore>,
230+
lnurl_auth: Arc<LnurlAuth>,
227231
is_running: Arc<RwLock<bool>>,
228232
node_metrics: Arc<RwLock<NodeMetrics>>,
229233
om_mailbox: Option<Arc<OnionMessageMailbox>>,
@@ -1009,6 +1013,26 @@ impl Node {
10091013
))
10101014
}
10111015

1016+
/// Authenticates the user via [LNURL-auth] for the given LNURL string.
1017+
///
1018+
/// [LNURL-auth]: https://github.com/lnurl/luds/blob/luds/04.md
1019+
pub fn lnurl_auth(&self, lnurl: String) -> Result<(), Error> {
1020+
let auth = Arc::clone(&self.lnurl_auth);
1021+
self.runtime.block_on(async move {
1022+
let res = tokio::time::timeout(
1023+
Duration::from_secs(LNURL_AUTH_TIMEOUT_SECS),
1024+
auth.authenticate(&lnurl),
1025+
)
1026+
.await;
1027+
1028+
match res {
1029+
Ok(Ok(())) => Ok(()),
1030+
Ok(Err(e)) => Err(e),
1031+
Err(_) => Err(Error::LnurlAuthTimeout),
1032+
}
1033+
})
1034+
}
1035+
10121036
/// Returns a liquidity handler allowing to request channels via the [bLIP-51 / LSPS1] protocol.
10131037
///
10141038
/// [bLIP-51 / LSPS1]: https://github.com/lightning/blips/blob/master/blip-0051.md

0 commit comments

Comments
 (0)