Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 10 additions & 17 deletions src/headers/lnurl_auth_jwt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,13 @@ use bitcoin::hashes::hex::FromHex;
use bitcoin::hashes::sha256;
use bitcoin::hashes::{Hash, HashEngine, Hmac, HmacEngine};
use bitcoin::secp256k1::{Message, Secp256k1, SignOnly};
use bitcoin::Network;
use bitcoin::PrivateKey;
use serde::Deserialize;
use std::collections::HashMap;
use std::sync::RwLock;
use std::time::{Duration, SystemTime};
use url::Url;

// Derivation index of the parent extended private key as defined by LUD-05.
const PARENT_DERIVATION_INDEX: u32 = 138;
// Derivation index of the hashing private key as defined by LUD-05.
const HASHING_DERIVATION_INDEX: u32 = 0;
// The JWT token will be refreshed by the given amount before its expiry.
Expand Down Expand Up @@ -61,24 +58,20 @@ pub struct LnurlAuthToJwtProvider {
impl LnurlAuthToJwtProvider {
/// Creates a new JWT provider based on LNURL Auth.
///
/// The LNURL Auth keys are derived from a seed according to LUD-05.
/// The user is free to choose a consistent seed, such as a hardened derivation from the wallet
/// master key or otherwise for compatibility reasons.
/// The LNURL Auth keys are derived as children from a hardened parent key,
/// following [LUD-05](https://github.com/lnurl/luds/blob/luds/05.md).
/// The hardened parent extended key is given here as an argument, and is suggested to be the
/// `m/138'` derivation from the wallet master key as in the specification.
/// However, users are free to choose a consistent hardened derivation path.
///
/// The LNURL with the challenge will be retrieved by making a request to the given URL.
/// The JWT token will be returned in response to the signed LNURL request under a token field.
/// The given set of headers will be used for LNURL requests, and will also be returned together
/// with the JWT authorization header for VSS requests.
pub fn new(
seed: &[u8], url: String, default_headers: HashMap<String, String>,
parent_key: Xpriv, url: String, default_headers: HashMap<String, String>,
) -> Result<LnurlAuthToJwtProvider, VssHeaderProviderError> {
let engine = Secp256k1::signing_only();
let master =
Xpriv::new_master(Network::Testnet, seed).map_err(VssHeaderProviderError::from)?;
let child_number = ChildNumber::from_hardened_idx(PARENT_DERIVATION_INDEX)
.map_err(VssHeaderProviderError::from)?;
let parent_key = master
.derive_priv(&engine, &vec![child_number])
.map_err(VssHeaderProviderError::from)?;
let default_headermap = get_headermap(&default_headers)?;
let client = reqwest::Client::builder()
.default_headers(default_headermap)
Expand Down Expand Up @@ -297,13 +290,13 @@ mod test {
#[test]
fn test_sign_lnurl() {
let engine = Secp256k1::signing_only();
let seed: [u8; 32] =
let parent_key_bytes: [u8; 32] =
FromHex::from_hex("abababababababababababababababababababababababababababababababab")
.unwrap();
let master = Xpriv::new_master(Network::Testnet, &seed).unwrap();
let parent_key = Xpriv::new_master(Network::Testnet, &parent_key_bytes).unwrap();
let signed = sign_lnurl(
&engine,
&master,
&parent_key,
"https://example.com/path?tag=login&k1=e2af6254a8df433264fa23f67eb8188635d15ce883e8fc020989d5f82ae6f11e",
)
.unwrap();
Expand Down
5 changes: 4 additions & 1 deletion tests/lnurl_auth_jwt_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
mod lnurl_auth_jwt_tests {
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
use base64::Engine;
use bitcoin::bip32::Xpriv;
use bitcoin::Network;
use mockito::Matcher;
use serde_json::json;
use std::collections::HashMap;
Expand Down Expand Up @@ -34,8 +36,9 @@ mod lnurl_auth_jwt_tests {
// Initialize LNURL Auth JWT provider connecting to the mock server.
let addr = mockito::server_address();
let base_url = format!("http://localhost:{}", addr.port());
let parent_key = Xpriv::new_master(Network::Testnet, &[0; 32]).unwrap();
let lnurl_auth_jwt =
LnurlAuthToJwtProvider::new(&[0; 32], base_url.clone(), HashMap::new()).unwrap();
LnurlAuthToJwtProvider::new(parent_key, base_url.clone(), HashMap::new()).unwrap();
{
// First request will be provided with an expired JWT token.
let k1 = "0000000000000000000000000000000000000000000000000000000000000000";
Expand Down