diff --git a/libs/gl-client-py/glclient/__init__.py b/libs/gl-client-py/glclient/__init__.py index 7108a7ec6..dbde842d6 100644 --- a/libs/gl-client-py/glclient/__init__.py +++ b/libs/gl-client-py/glclient/__init__.py @@ -64,11 +64,10 @@ def is_running(self) -> bool: class Scheduler(object): - def __init__(self, node_id: bytes, network: str, creds: Optional[Credentials] = None): - self.node_id = node_id + def __init__(self, network: str, creds: Optional[Credentials] = None): self.network = network self.creds = creds if creds is not None else native.Credentials() - self.inner = native.Scheduler(node_id, network, self.creds) + self.inner = native.Scheduler(network, self.creds) def schedule(self) -> schedpb.NodeInfoResponse: res = self.inner.schedule() @@ -99,7 +98,7 @@ def node(self) -> "Node": res = self.inner.node() info = schedpb.NodeInfoResponse.FromString(bytes(res)) return Node( - node_id=self.node_id, + node_id=self.creds.node_id(), grpc_uri=info.grpc_uri, creds=self.creds, ) diff --git a/libs/gl-client-py/glclient/glclient.pyi b/libs/gl-client-py/glclient/glclient.pyi index 3bfd16c98..ba515a3dc 100644 --- a/libs/gl-client-py/glclient/glclient.pyi +++ b/libs/gl-client-py/glclient/glclient.pyi @@ -27,6 +27,7 @@ class Credentials: def from_path(path: str) -> Credentials: ... @staticmethod def from_parts(cert: bytes, key: bytes, ca: bytes, rune: str) -> Credentials: ... + def node_id(self) -> bytes: ... def upgrade(self, scheduler: Scheduler, signer: Signer) -> Credentials: ... def to_bytes(self) -> bytes: ... @@ -47,7 +48,7 @@ class Signer: class Scheduler: - def __init__(self, node_id: bytes, network: str, creds: Optional[Credentials]): ... + def __init__(self, network: str, creds: Optional[Credentials]): ... def register(self, signer: Signer, invite_code: Optional[str]) -> bytes: ... def recover(self, signer: Signer) -> bytes: ... def authenticate(self, creds: Credentials): ... diff --git a/libs/gl-client-py/src/credentials.rs b/libs/gl-client-py/src/credentials.rs index 2c67b5879..4430ba50d 100644 --- a/libs/gl-client-py/src/credentials.rs +++ b/libs/gl-client-py/src/credentials.rs @@ -1,7 +1,7 @@ use crate::runtime::exec; use crate::scheduler::Scheduler; use crate::signer::Signer; -use gl_client::credentials::{self, RuneProvider, TlsConfigProvider}; +use gl_client::credentials::{self, NodeIdProvider, RuneProvider, TlsConfigProvider}; use pyo3::exceptions::PyValueError; use pyo3::prelude::*; use pyo3::types::PyBytes; @@ -12,7 +12,7 @@ pub type PyCredentials = UnifiedCredentials where T: TlsConfigProvider, - R: TlsConfigProvider + RuneProvider + Clone, + R: TlsConfigProvider + RuneProvider + NodeIdProvider + Clone, { Nobody(T), Device(R), @@ -21,7 +21,7 @@ where impl UnifiedCredentials where T: TlsConfigProvider, - R: TlsConfigProvider + RuneProvider + Clone, + R: TlsConfigProvider + RuneProvider + NodeIdProvider + Clone, { pub fn ensure_nobody(&self) -> Result<()> { if let Self::Nobody(_) = self { @@ -47,7 +47,7 @@ where impl TlsConfigProvider for UnifiedCredentials where T: TlsConfigProvider, - R: TlsConfigProvider + RuneProvider + Clone, + R: TlsConfigProvider + RuneProvider + NodeIdProvider + Clone, { fn tls_config(&self) -> gl_client::tls::TlsConfig { match self { @@ -60,18 +60,33 @@ where impl RuneProvider for UnifiedCredentials where T: TlsConfigProvider, - R: TlsConfigProvider + RuneProvider + Clone, + R: TlsConfigProvider + RuneProvider + NodeIdProvider + Clone, { fn rune(&self) -> String { match self { UnifiedCredentials::Nobody(_) => panic!( - "can not provide rune from nobody credentials! something really bad happended." + "can not provide rune from nobody credentials! something really bad happened." ), UnifiedCredentials::Device(d) => d.rune(), } } } +impl NodeIdProvider for UnifiedCredentials +where + T: TlsConfigProvider, + R: TlsConfigProvider + RuneProvider + NodeIdProvider + Clone, +{ + fn node_id(&self) -> credentials::Result> { + match self { + UnifiedCredentials::Nobody(_) => panic!( + "can not provide node_id from nobody credentials! something really bad happened." + ), + UnifiedCredentials::Device(d) => d.node_id(), + } + } +} + #[pyclass] #[derive(Clone)] pub struct Credentials { @@ -110,7 +125,8 @@ impl Credentials { #[staticmethod] pub fn from_parts(cert: &[u8], key: &[u8], ca: &[u8], rune: &str) -> Self { - let inner = UnifiedCredentials::Device(gl_client::credentials::Device::with(cert, key, ca, rune)); + let inner = + UnifiedCredentials::Device(gl_client::credentials::Device::with(cert, key, ca, rune)); Self { inner } } @@ -150,6 +166,10 @@ impl Credentials { pub fn ensure_nobody(&self) -> Result<()> { self.inner.ensure_nobody() } + + pub fn node_id(&self) -> Result> { + Ok(self.inner.node_id()?) + } } type Result = std::result::Result; diff --git a/libs/gl-client-py/src/scheduler.rs b/libs/gl-client-py/src/scheduler.rs index a17f4ec8d..b63acfc2b 100644 --- a/libs/gl-client-py/src/scheduler.rs +++ b/libs/gl-client-py/src/scheduler.rs @@ -3,7 +3,7 @@ use crate::runtime::exec; use crate::Signer; use anyhow::{anyhow, Result}; use gl_client::bitcoin::Network; -use gl_client::credentials::RuneProvider; +use gl_client::credentials::{NodeIdProvider, RuneProvider}; use gl_client::credentials::TlsConfigProvider; use gl_client::pb; use gl_client::scheduler; @@ -15,7 +15,7 @@ use pyo3::prelude::*; pub enum UnifiedScheduler where T: TlsConfigProvider, - R: TlsConfigProvider + RuneProvider + Clone, + R: TlsConfigProvider + RuneProvider + NodeIdProvider + Clone, { Unauthenticated(scheduler::Scheduler), Authenticated(scheduler::Scheduler), @@ -24,7 +24,7 @@ where impl UnifiedScheduler where T: TlsConfigProvider, - R: TlsConfigProvider + RuneProvider + Clone, + R: TlsConfigProvider + RuneProvider + NodeIdProvider + Clone, { pub fn is_authenticated(&self) -> Result<()> { if let Self::Authenticated(_) = self { @@ -72,7 +72,7 @@ where impl UnifiedScheduler where T: TlsConfigProvider, - R: TlsConfigProvider + RuneProvider + Clone, + R: TlsConfigProvider + RuneProvider + NodeIdProvider + Clone, { async fn export_node(&self) -> Result { let s = self.authenticated_scheduler()?; @@ -137,25 +137,23 @@ where #[pyclass] pub struct Scheduler { - node_id: Vec, pub inner: UnifiedScheduler, } #[pymethods] impl Scheduler { #[new] - fn new(node_id: Vec, network: &str, creds: Credentials) -> PyResult { + fn new(network: &str, creds: Credentials) -> PyResult { let network: Network = network .parse() .map_err(|_| PyValueError::new_err("Error parsing the network"))?; - let id = node_id.clone(); let uri = gl_client::utils::scheduler_uri(); let inner = match creds.inner { crate::credentials::UnifiedCredentials::Nobody(_) => { let scheduler = exec(async move { - gl_client::scheduler::Scheduler::with(id, network, creds.inner.clone(), uri) + gl_client::scheduler::Scheduler::with(network, creds.inner.clone(), uri) .await }) .map_err(|e| PyValueError::new_err(e.to_string()))?; @@ -163,7 +161,7 @@ impl Scheduler { } crate::credentials::UnifiedCredentials::Device(_) => { let scheduler = exec(async move { - gl_client::scheduler::Scheduler::with(id, network, creds.inner.clone(), uri) + gl_client::scheduler::Scheduler::with(network, creds.inner.clone(), uri) .await }) .map_err(|e| PyValueError::new_err(e.to_string()))?; @@ -171,7 +169,7 @@ impl Scheduler { } }; - Ok(Scheduler { node_id, inner }) + Ok(Scheduler { inner }) } fn register(&self, signer: &Signer, invite_code: Option) -> PyResult> { @@ -198,7 +196,6 @@ impl Scheduler { )) })?; Ok(Scheduler { - node_id: self.node_id.clone(), inner: s, }) } diff --git a/libs/gl-client-py/tests/fixtures.py b/libs/gl-client-py/tests/fixtures.py index 6b03a5148..0749b65f5 100644 --- a/libs/gl-client-py/tests/fixtures.py +++ b/libs/gl-client-py/tests/fixtures.py @@ -27,7 +27,7 @@ def sclient(signer, creds): registration and recovery, but no mTLS certificate yet. """ network = "regtest" - return Scheduler(signer.node_id(), network=network, creds=creds) + return Scheduler(network=network, creds=creds) @pytest.fixture diff --git a/libs/gl-client-py/tests/test_creds.py b/libs/gl-client-py/tests/test_creds.py index aa630d3a3..5aee6f445 100644 --- a/libs/gl-client-py/tests/test_creds.py +++ b/libs/gl-client-py/tests/test_creds.py @@ -21,7 +21,7 @@ def test_upgrade_credentials(scheduler, sclient, signer): c = Credentials.from_bytes(creds).upgrade( Scheduler( - node_id=signer.node_id(), network="regtest", creds=screds + network="regtest", creds=screds ).inner, signer.inner, ) diff --git a/libs/gl-client-py/tests/test_scheduler.py b/libs/gl-client-py/tests/test_scheduler.py index c18f1bc5f..06ebe0505 100644 --- a/libs/gl-client-py/tests/test_scheduler.py +++ b/libs/gl-client-py/tests/test_scheduler.py @@ -8,7 +8,7 @@ def test_connect(scheduler, creds): """Test that we can connect to the scheduler.""" sig = Signer(b"\x00" * 32, network="regtest", creds=creds) node_id = sig.node_id() - s = Scheduler(node_id, network="regtest", creds=creds) + s = Scheduler(network="regtest", creds=creds) with pytest.raises(ValueError): s.recover(sig) diff --git a/libs/gl-client/src/credentials.rs b/libs/gl-client/src/credentials.rs index a68fcfeca..878e2c743 100644 --- a/libs/gl-client/src/credentials.rs +++ b/libs/gl-client/src/credentials.rs @@ -2,6 +2,7 @@ use crate::{ scheduler::Scheduler, signer::Signer, tls::{self, TlsConfig}, + utils::get_node_id_from_tls_config, }; /// Credentials is a collection of all relevant keys and attestations /// required to authenticate a device and authorize a command on the node. @@ -40,15 +41,20 @@ pub enum Error { FetchDefaultNobodyCredentials(#[source] anyhow::Error), } -type Result = std::result::Result; +pub type Result = std::result::Result; pub trait TlsConfigProvider: Send + Sync { fn tls_config(&self) -> TlsConfig; } + pub trait RuneProvider { fn rune(&self) -> String; } +pub trait NodeIdProvider { + fn node_id(&self) -> Result>; +} + /// A helper struct to combine the Tls certificate and the corresponding private /// key. #[derive(Clone, Debug)] @@ -177,31 +183,30 @@ impl Device { /// Asynchronously upgrades the credentials using the provided scheduler and /// signer, potentially involving network operations or other async tasks. - pub async fn upgrade(mut self, scheduler: &Scheduler, signer: &Signer) -> Result + pub async fn upgrade(mut self, _scheduler: &Scheduler, signer: &Signer) -> Result where T: TlsConfigProvider, { use Error::*; - // For now, upgrade is covered by recover - let res = scheduler - .recover(signer) - .await - .map_err(|e| UpgradeCredentialsError(e.to_string()))?; - let mut data = model::Data::try_from(&res.creds[..]) + self.version = CRED_VERSION; + + if self.rune.is_empty() { + let node_id = self + .node_id() + .map_err(|e| UpgradeCredentialsError(e.to_string()))?; + + let alt = runeauth::Alternative::new( + "pubkey".to_string(), + runeauth::Condition::Equal, + hex::encode(node_id), + false, + ) .map_err(|e| UpgradeCredentialsError(e.to_string()))?; - data.version = CRED_VERSION; - if let Some(cert) = data.cert { - self.cert = cert - } - if let Some(key) = data.key { - self.key = key - } - if let Some(ca) = data.ca { - self.ca = ca - } - if let Some(rune) = data.rune { - self.rune = rune + + self.rune = signer + .create_rune(None, vec![vec![&alt.encode()]]) + .map_err(|e| UpgradeCredentialsError(e.to_string()))?; }; Ok(self) } @@ -217,6 +222,7 @@ impl TlsConfigProvider for Device { fn tls_config(&self) -> TlsConfig { tls::TlsConfig::with(&self.cert, &self.key, &self.ca) } + } impl RuneProvider for Device { @@ -225,6 +231,16 @@ impl RuneProvider for Device { } } +impl NodeIdProvider for Device { + fn node_id(&self) -> Result> { + get_node_id_from_tls_config(&self.tls_config()).map_err(|_e| { + Error::GetFromIdentityError( + "node_id could not be retrieved from the certificate".to_string(), + ) + }) + } +} + impl From for Vec { fn from(value: Device) -> Self { let data: model::Data = value.into(); diff --git a/libs/gl-client/src/lib.rs b/libs/gl-client/src/lib.rs index e665eb511..612e65e13 100644 --- a/libs/gl-client/src/lib.rs +++ b/libs/gl-client/src/lib.rs @@ -46,13 +46,7 @@ pub mod tls; pub mod export; /// Tools to interact with a node running on greenlight. -pub mod utils { - - pub fn scheduler_uri() -> String { - std::env::var("GL_SCHEDULER_GRPC_URI") - .unwrap_or_else(|_| "https://scheduler.gl.blckstrm.com".to_string()) - } -} +pub mod utils; pub mod credentials; diff --git a/libs/gl-client/src/scheduler.rs b/libs/gl-client/src/scheduler.rs index 1d1593872..28aec6cac 100644 --- a/libs/gl-client/src/scheduler.rs +++ b/libs/gl-client/src/scheduler.rs @@ -1,10 +1,10 @@ -use crate::credentials::{self, RuneProvider, TlsConfigProvider}; +use crate::credentials::{self, RuneProvider, NodeIdProvider, TlsConfigProvider}; use crate::node::{self, GrpcClient}; use crate::pb::scheduler::scheduler_client::SchedulerClient; use crate::tls::{self}; use crate::utils::scheduler_uri; use crate::{pb, signer::Signer}; -use anyhow::{anyhow, Result}; +use anyhow::{Result}; use lightning_signer::bitcoin::Network; use log::debug; use runeauth; @@ -16,7 +16,6 @@ type Client = SchedulerClient; /// different implementations depending on the implementations #[derive(Clone)] pub struct Scheduler { - node_id: Vec, client: Client, network: Network, grpc_uri: String, @@ -42,12 +41,12 @@ where /// let node_id = vec![0, 1, 2, 3]; /// let network = Network::Regtest; /// let creds = Nobody::new(); - /// let scheduler = Scheduler::new(node_id, network, creds).await.unwrap(); + /// let scheduler = Scheduler::new(network, creds).await.unwrap(); /// # } /// ``` - pub async fn new(node_id: Vec, network: Network, creds: Creds) -> Result> { + pub async fn new(network: Network, creds: Creds) -> Result> { let grpc_uri = scheduler_uri(); - Self::with(node_id, network, creds, grpc_uri).await + Self::with(network, creds, grpc_uri).await } /// Creates a new scheduler client with the provided parameters and @@ -66,11 +65,10 @@ where /// let network = Network::Regtest; /// let creds = Nobody::new(); /// let uri = "https://example.com".to_string(); - /// let scheduler = Scheduler::with(node_id, network, creds, uri).await.unwrap(); + /// let scheduler = Scheduler::with(network, creds, uri).await.unwrap(); /// # } /// ``` pub async fn with( - node_id: Vec, network: Network, creds: Creds, uri: impl Into, @@ -90,7 +88,6 @@ where Ok(Scheduler { client, - node_id, network, creds, grpc_uri: uri, @@ -117,7 +114,7 @@ impl Scheduler { /// let node_id = vec![0, 1, 2, 3]; /// let network = Network::Regtest; /// let creds = Nobody::new(); - /// let scheduler = Scheduler::new(node_id.clone(), network, creds.clone()).await.unwrap(); + /// let scheduler = Scheduler::new(network, creds.clone()).await.unwrap(); /// let secret = vec![0, 0, 0, 0]; /// let signer = Signer::new(secret, network, creds).unwrap(); // Create or obtain a signer instance /// let registration_response = scheduler.register(&signer, None).await.unwrap(); @@ -147,7 +144,7 @@ impl Scheduler { .clone() .get_challenge(pb::scheduler::ChallengeRequest { scope: pb::scheduler::ChallengeScope::Register as i32, - node_id: self.node_id.clone(), + node_id: signer.node_id(), }) .await? .into_inner(); @@ -156,7 +153,7 @@ impl Scheduler { let signature = signer.sign_challenge(challenge.challenge.clone())?; let device_cert = tls::generate_self_signed_device_cert( - &hex::encode(self.node_id.clone()), + &hex::encode(signer.node_id()), "default", vec!["localhost".into()], ); @@ -173,7 +170,7 @@ impl Scheduler { .client .clone() .register(pb::scheduler::RegistrationRequest { - node_id: self.node_id.clone(), + node_id: signer.node_id(), bip32_key: signer.bip32_ext_key(), network: self.network.to_string(), challenge: challenge.challenge, @@ -245,7 +242,7 @@ impl Scheduler { /// let node_id = vec![0, 1, 2, 3]; /// let network = Network::Regtest; /// let creds = Nobody::new(); - /// let scheduler = Scheduler::new(node_id.clone(), network, creds.clone()).await.unwrap(); + /// let scheduler = Scheduler::new(network, creds.clone()).await.unwrap(); /// let secret = vec![0, 0, 0, 0]; /// let signer = Signer::new(secret, network, creds).unwrap(); // Create or obtain a signer instance /// let recovery_response = scheduler.recover(&signer).await.unwrap(); @@ -257,7 +254,7 @@ impl Scheduler { .clone() .get_challenge(pb::scheduler::ChallengeRequest { scope: pb::scheduler::ChallengeScope::Recover as i32, - node_id: self.node_id.clone(), + node_id: signer.node_id(), }) .await? .into_inner(); @@ -265,7 +262,7 @@ impl Scheduler { let signature = signer.sign_challenge(challenge.challenge.clone())?; let name = format!("recovered-{}", hex::encode(&challenge.challenge[0..8])); let device_cert = tls::generate_self_signed_device_cert( - &hex::encode(self.node_id.clone()), + &hex::encode(signer.node_id()), &name, vec!["localhost".into()], ); @@ -276,7 +273,7 @@ impl Scheduler { .client .clone() .recover(pb::scheduler::RecoveryRequest { - node_id: self.node_id.clone(), + node_id: signer.node_id(), challenge: challenge.challenge, signature, csr: device_csr.into_bytes(), @@ -344,7 +341,7 @@ impl Scheduler { /// let node_id = vec![0, 1, 2, 3]; /// let network = Network::Regtest; /// let creds = Nobody::new(); - /// let scheduler_unauthed = Scheduler::new(node_id.clone(), network, creds.clone()).await.unwrap(); + /// let scheduler_unauthed = Scheduler::new(network, creds.clone()).await.unwrap(); /// let secret = vec![0, 0, 0, 0]; /// let signer = Signer::new(secret, network, creds).unwrap(); // Create or obtain a signer instance /// let registration_response = scheduler_unauthed.register(&signer, None).await.unwrap(); @@ -368,7 +365,6 @@ impl Scheduler { let client = SchedulerClient::new(channel); Ok(Scheduler { - node_id: self.node_id.clone(), client, network: self.network, creds, @@ -380,7 +376,7 @@ impl Scheduler { impl Scheduler where - Creds: TlsConfigProvider + RuneProvider + Clone, + Creds: TlsConfigProvider + RuneProvider + NodeIdProvider + Clone, { /// Schedules a node at the scheduler service. Once a node is /// scheduled one can access it through the node client. @@ -395,7 +391,7 @@ where /// let node_id = vec![0, 1, 2, 3]; /// let network = Network::Regtest; /// let creds = Device::from_path("my/path/to/credentials.glc"); - /// let scheduler = Scheduler::new(node_id.clone(), network, creds.clone()).await.unwrap(); + /// let scheduler = Scheduler::new(network, creds.clone()).await.unwrap(); /// let info = scheduler.schedule().await.unwrap(); /// let node_client: Client = Node::new(node_id, creds).unwrap().connect(info.grpc_uri).await.unwrap(); /// # } @@ -405,7 +401,7 @@ where .client .clone() .schedule(pb::scheduler::ScheduleRequest { - node_id: self.node_id.clone(), + node_id: self.creds.node_id()?, }) .await?; Ok(res.into_inner()) @@ -425,7 +421,7 @@ where /// let node_id = vec![0, 1, 2, 3]; /// let network = Network::Regtest; /// let creds = Device::from_path("my/path/to/credentials.glc"); - /// let scheduler = Scheduler::new(node_id.clone(), network, creds.clone()).await.unwrap(); + /// let scheduler = Scheduler::new(network, creds.clone()).await.unwrap(); /// let node_client: Client = scheduler.node().await.unwrap(); /// # } /// ``` @@ -433,14 +429,8 @@ where where T: GrpcClient, { - let cert_node_id = self.get_node_id_from_tls_config()?; - - if cert_node_id != self.node_id { - return Err(anyhow!("The node_id defined on the Credential's certificate does not match the node_id the scheduler was initialized with\nExpected {}, got {}", hex::encode(&self.node_id), hex::encode(&cert_node_id))); - } - let res = self.schedule().await?; - node::Node::new(self.node_id.clone(), self.creds.clone())? + node::Node::new(self.creds.node_id()?, self.creds.clone())? .connect(res.grpc_uri) .await } @@ -450,7 +440,7 @@ where .client .clone() .get_node_info(pb::scheduler::NodeInfoRequest { - node_id: self.node_id.clone(), + node_id: self.creds.node_id()?, wait: wait, }) .await? @@ -479,7 +469,7 @@ where &self, uri: String, ) -> Result { - let node_id = self.get_node_id_from_tls_config()?; + let node_id = self.creds.node_id()?; let res = self .client .clone() @@ -491,7 +481,7 @@ where pub async fn list_outgoing_webhooks( &self, ) -> Result { - let node_id = self.get_node_id_from_tls_config()?; + let node_id = self.creds.node_id()?; let res = self .client .clone() @@ -501,7 +491,7 @@ where } pub async fn delete_webhooks(&self, webhook_ids: Vec) -> Result { - let node_id = self.get_node_id_from_tls_config()?; + let node_id = self.creds.node_id()?; let res = self .client .clone() @@ -517,7 +507,7 @@ where &self, webhook_id: i64, ) -> Result { - let node_id = self.get_node_id_from_tls_config()?; + let node_id = self.creds.node_id()?; let res = self .client .clone() @@ -528,58 +518,4 @@ where .await?; Ok(res.into_inner()) } - - fn get_node_id_from_tls_config(&self) -> Result> { - let tls_config = self.creds.tls_config(); - let subject_common_name = match &tls_config.x509_cert { - Some(x) => match x.subject_common_name() { - Some(cn) => cn, - None => { - return Err(anyhow!( - "Failed to parse the subject common name in the provided x509 certificate" - )) - } - }, - None => { - return Err(anyhow!( - "The certificate could not be parsed in the x509 format" - )) - } - }; - - let split_subject_common_name = subject_common_name.split("/").collect::>(); - - assert!(split_subject_common_name[1] == "users"); - Ok(hex::decode(split_subject_common_name[2]) - .expect("Failed to parse the node_id from the TlsConfig to bytes")) - } -} - -#[cfg(test)] -mod tests { - use crate::credentials::Device; - - use super::*; - - #[tokio::test] - async fn test_node_returns_error_on_node_id_mismatch() { - let cert_node_id: [u8; 32] = rand::random(); - let device_cert = tls::generate_self_signed_device_cert( - &hex::encode(cert_node_id.clone()), - "default".into(), - vec!["localhost".into()], - ); - - let device_crt = device_cert.serialize_pem().unwrap(); - let device_key = device_cert.serialize_private_key_pem(); - - let creds = Device::with(device_crt, device_key, String::new(), ""); - - let scheduler_node_id: [u8; 32] = rand::random(); - let sched = Scheduler::new(scheduler_node_id.to_vec(), Network::Bitcoin, creds) - .await - .unwrap(); - - assert!(sched.node::().await.is_err_and(|e| e.to_string().contains("The node_id defined on the Credential's certificate does not match the node_id the scheduler was initialized with"))); - } -} +} \ No newline at end of file diff --git a/libs/gl-client/src/util.rs b/libs/gl-client/src/util.rs index fead0f6dc..c9bd4f8c7 100644 --- a/libs/gl-client/src/util.rs +++ b/libs/gl-client/src/util.rs @@ -1,33 +1,24 @@ - - - - - -pub fn is_feature_bit_enabled(bitmap : &[u8], index : usize) -> bool { +pub fn is_feature_bit_enabled(bitmap: &[u8], index: usize) -> bool { let n_bytes = bitmap.len(); - let (byte_index, bit_index ) = (index / 8, index % 8); + let (byte_index, bit_index) = (index / 8, index % 8); // The index doesn't fit in the byte-array if byte_index >= n_bytes { - return false + return false; } let selected_byte = bitmap[n_bytes - 1 - byte_index]; let bit_mask = 1u8 << (bit_index); - - return (selected_byte & bit_mask) != 0 + return (selected_byte & bit_mask) != 0; } - - #[cfg(test)] mod test { use super::*; - fn to_bitmap(feature_hex_string : &str) -> Result, String> { - hex::decode(&feature_hex_string) - .map_err(|x| x.to_string()) + fn to_bitmap(feature_hex_string: &str) -> Result, String> { + hex::decode(&feature_hex_string).map_err(|x| x.to_string()) } #[test] @@ -53,21 +44,21 @@ mod test { assert!(is_feature_bit_enabled(&feature_bitmap_07, 7)); // Check that other bits are disabled - assert!(! is_feature_bit_enabled(&feature_bitmap_01, 0)); - assert!(! is_feature_bit_enabled(&feature_bitmap_01, 2)); - assert!(! is_feature_bit_enabled(&feature_bitmap_01, 3)); - assert!(! is_feature_bit_enabled(&feature_bitmap_01, 4)); - assert!(! is_feature_bit_enabled(&feature_bitmap_01, 5)); - assert!(! is_feature_bit_enabled(&feature_bitmap_01, 6)); - assert!(! is_feature_bit_enabled(&feature_bitmap_01, 7)); - assert!(! is_feature_bit_enabled(&feature_bitmap_01, 8)); - assert!(! is_feature_bit_enabled(&feature_bitmap_01, 9)); - - assert!(! is_feature_bit_enabled(&feature_bitmap_01, 1000)); + assert!(!is_feature_bit_enabled(&feature_bitmap_01, 0)); + assert!(!is_feature_bit_enabled(&feature_bitmap_01, 2)); + assert!(!is_feature_bit_enabled(&feature_bitmap_01, 3)); + assert!(!is_feature_bit_enabled(&feature_bitmap_01, 4)); + assert!(!is_feature_bit_enabled(&feature_bitmap_01, 5)); + assert!(!is_feature_bit_enabled(&feature_bitmap_01, 6)); + assert!(!is_feature_bit_enabled(&feature_bitmap_01, 7)); + assert!(!is_feature_bit_enabled(&feature_bitmap_01, 8)); + assert!(!is_feature_bit_enabled(&feature_bitmap_01, 9)); + + assert!(!is_feature_bit_enabled(&feature_bitmap_01, 1000)); } #[test] - fn test_lsps_option_enabled_bitmap() { + fn test_lsps_option_enabled_bitmap() { // Copied from LSPS0 // This set bit number 729 let data = "0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; @@ -77,7 +68,7 @@ mod test { assert!(is_feature_bit_enabled(&bitmap, 729)); // Check that the expected bit is disabled - assert!(! is_feature_bit_enabled(&bitmap, 728)); - assert!(! is_feature_bit_enabled(&bitmap, 730)); + assert!(!is_feature_bit_enabled(&bitmap, 728)); + assert!(!is_feature_bit_enabled(&bitmap, 730)); } -} \ No newline at end of file +} diff --git a/libs/gl-client/src/utils.rs b/libs/gl-client/src/utils.rs new file mode 100644 index 000000000..7795938c1 --- /dev/null +++ b/libs/gl-client/src/utils.rs @@ -0,0 +1,31 @@ +use anyhow::{anyhow, Result}; +use crate::tls::TlsConfig; + +pub fn scheduler_uri() -> String { + std::env::var("GL_SCHEDULER_GRPC_URI") + .unwrap_or_else(|_| "https://scheduler.gl.blckstrm.com".to_string()) +} + +pub fn get_node_id_from_tls_config(tls_config: &TlsConfig) -> Result> { + let subject_common_name = match &tls_config.x509_cert { + Some(x) => match x.subject_common_name() { + Some(cn) => cn, + None => { + return Err(anyhow!( + "Failed to parse the subject common name in the provided x509 certificate" + )) + } + }, + None => { + return Err(anyhow!( + "The certificate could not be parsed in the x509 format" + )) + } + }; + + let split_subject_common_name = subject_common_name.split("/").collect::>(); + + assert!(split_subject_common_name[1] == "users"); + Ok(hex::decode(split_subject_common_name[2]) + .expect("Failed to parse the node_id from the TlsConfig to bytes")) +} \ No newline at end of file diff --git a/libs/gl-testing/gltesting/clients.py b/libs/gl-testing/gltesting/clients.py index 0e2f9306c..c4b18deb1 100644 --- a/libs/gl-testing/gltesting/clients.py +++ b/libs/gl-testing/gltesting/clients.py @@ -100,7 +100,7 @@ def creds(self) -> glclient.Credentials: def scheduler(self, authenticate: bool = False) -> glclient.Scheduler: """Return a scheduler stub configured with our identity if configured.""" - scheduler = glclient.Scheduler(self.node_id, network=NETWORK, creds=self.creds()) + scheduler = glclient.Scheduler(network=NETWORK, creds=self.creds()) if authenticate: scheduler.authenticate(creds=self.creds()) return scheduler