|
5 | 5 | // http://opensource.org/licenses/MIT>, at your option. You may not use this file except in |
6 | 6 | // accordance with one or both of these licenses. |
7 | 7 |
|
| 8 | +#![allow(dead_code)] |
| 9 | + |
8 | 10 | use std::collections::{hash_map, HashMap}; |
9 | 11 | use std::future::Future; |
10 | 12 | use std::panic::RefUnwindSafe; |
@@ -350,3 +352,111 @@ pub(crate) fn do_test_store<K: KVStoreSync + Sync>(store_0: &K, store_1: &K) { |
350 | 352 | // Make sure everything is persisted as expected after close. |
351 | 353 | check_persisted_data!(persister_0_max_pending_updates * 2 * EXPECTED_UPDATES_PER_PAYMENT + 1); |
352 | 354 | } |
| 355 | + |
| 356 | +#[cfg(all(feature = "test_utils", jwt_auth_test))] |
| 357 | +mod jwt_auth { |
| 358 | + use super::*; |
| 359 | + |
| 360 | + use std::time::SystemTime; |
| 361 | + |
| 362 | + use jsonwebtoken::{encode, Algorithm, EncodingKey, Header}; |
| 363 | + use serde::{Deserialize, Serialize}; |
| 364 | + |
| 365 | + // Private key for testing purposes solely. |
| 366 | + const VSS_PRIVATE_PEM: &str = include_str!("../../tests/fixtures/vss_jwt_rsa_prv.pem"); |
| 367 | + |
| 368 | + #[derive(Serialize, Deserialize)] |
| 369 | + struct TestClaims { |
| 370 | + sub: String, |
| 371 | + iat: i64, |
| 372 | + nbf: i64, |
| 373 | + exp: i64, |
| 374 | + } |
| 375 | + |
| 376 | + pub fn generate_test_jwt(private_pem: &str, user_id: &str) -> String { |
| 377 | + let now = |
| 378 | + SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs() as i64; |
| 379 | + |
| 380 | + let claims = |
| 381 | + TestClaims { sub: user_id.to_owned(), iat: now, nbf: now, exp: now + (60 * 10) }; |
| 382 | + |
| 383 | + let encoding_key = EncodingKey::from_rsa_pem(private_pem.as_bytes()) |
| 384 | + .expect("Failed to create EncodingKey"); |
| 385 | + |
| 386 | + encode(&Header::new(Algorithm::RS256), &claims, &encoding_key).unwrap() |
| 387 | + } |
| 388 | + |
| 389 | + pub fn get_fixed_headers() -> HashMap<String, String> { |
| 390 | + let token = generate_test_jwt(VSS_PRIVATE_PEM, "test"); |
| 391 | + let mut headers = HashMap::new(); |
| 392 | + headers.insert("Authorization".to_string(), format!("Bearer {}", token)); |
| 393 | + return headers; |
| 394 | + } |
| 395 | +} |
| 396 | + |
| 397 | +#[cfg(all(feature = "test_utils", sig_auth_test))] |
| 398 | +mod sig_auth { |
| 399 | + use super::*; |
| 400 | + |
| 401 | + use std::time::SystemTime; |
| 402 | + use std::time::UNIX_EPOCH; |
| 403 | + |
| 404 | + use bitcoin::hashes::sha256::Hash; |
| 405 | + use bitcoin::hashes::Hash as _; |
| 406 | + use bitcoin::secp256k1::{self, SecretKey}; |
| 407 | + |
| 408 | + use crate::hex_utils; |
| 409 | + |
| 410 | + // Must match vss-server's SignatureAuthorizer constant. |
| 411 | + // See: https://github.com/lightningdevkit/vss-server/blob/main/rust/auth-impls/src/signature.rs#L21 |
| 412 | + const SIGNING_CONSTANT: &'static [u8] = |
| 413 | + b"VSS Signature Authorizer Signing Salt Constant.................."; |
| 414 | + |
| 415 | + fn build_auth_token(secret_key: &SecretKey) -> String { |
| 416 | + let secp = secp256k1::Secp256k1::new(); |
| 417 | + let pubkey = secret_key.public_key(&secp); |
| 418 | + let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); |
| 419 | + |
| 420 | + let mut bytes_to_sign = Vec::new(); |
| 421 | + bytes_to_sign.extend_from_slice(SIGNING_CONSTANT); |
| 422 | + bytes_to_sign.extend_from_slice(&pubkey.serialize()); |
| 423 | + bytes_to_sign.extend_from_slice(format!("{now}").as_bytes()); |
| 424 | + |
| 425 | + let hash = Hash::hash(&bytes_to_sign); |
| 426 | + let msg = secp256k1::Message::from_digest(hash.to_byte_array()); |
| 427 | + let sig = secp.sign_ecdsa(&msg, &secret_key); |
| 428 | + |
| 429 | + format!("{pubkey:x}{}{now}", hex_utils::to_string(&sig.serialize_compact())) |
| 430 | + } |
| 431 | + |
| 432 | + pub fn get_fixed_headers() -> HashMap<String, String> { |
| 433 | + let secret_key = SecretKey::from_slice(&[42; 32]).unwrap(); |
| 434 | + let token = build_auth_token(&secret_key); |
| 435 | + let mut headers = HashMap::new(); |
| 436 | + headers.insert("Authorization".to_string(), token); |
| 437 | + return headers; |
| 438 | + } |
| 439 | +} |
| 440 | + |
| 441 | +/// Returns a hashmap of fixed headers, where, depending on configuration, |
| 442 | +/// corresponds to valid headers for no-op, signature-based, or jwt-based |
| 443 | +/// authorizers on vss-server. |
| 444 | +pub fn get_fixed_headers() -> HashMap<String, String> { |
| 445 | + #[cfg(noop_auth_test)] |
| 446 | + { |
| 447 | + HashMap::new() |
| 448 | + } |
| 449 | + |
| 450 | + #[cfg(all(jwt_auth_test, feature = "test_utils"))] |
| 451 | + { |
| 452 | + jwt_auth::get_fixed_headers() |
| 453 | + } |
| 454 | + |
| 455 | + #[cfg(all(feature = "test_utils", sig_auth_test))] |
| 456 | + { |
| 457 | + sig_auth::get_fixed_headers() |
| 458 | + } |
| 459 | + |
| 460 | + #[cfg(not(any(noop_auth_test, all(jwt_auth_test, feature = "test_utils"), sig_auth_test)))] |
| 461 | + HashMap::new() |
| 462 | +} |
0 commit comments