Skip to content

Commit c79287b

Browse files
committed
Consult secrets provider when trying to connect to a remote in Rust API
1 parent 0646d94 commit c79287b

File tree

4 files changed

+42
-15
lines changed

4 files changed

+42
-15
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ log = { version = "0.4", features = ["std"] }
1818
rayon = { version = "1.10", optional = true }
1919
binaryninjacore-sys = { path = "binaryninjacore-sys" }
2020
thiserror = "2.0"
21+
# Parts of the collaboration and workflow APIs consume and produce JSON.
22+
serde_json = "1.0"
2123

2224
[dev-dependencies]
2325
rstest = "0.24"

rust/src/collaboration/remote.rs

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1+
use super::{sync, GroupId, RemoteGroup, RemoteProject, RemoteUser};
12
use binaryninjacore_sys::*;
3+
use std::env::VarError;
24
use std::ffi::c_void;
35
use std::ptr::NonNull;
46

5-
use super::{sync, GroupId, RemoteGroup, RemoteProject, RemoteUser};
6-
77
use crate::binary_view::BinaryView;
88
use crate::database::Database;
99
use crate::enterprise;
1010
use crate::progress::{NoProgressCallback, ProgressCallback};
1111
use crate::project::Project;
1212
use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
13+
use crate::secrets_provider::CoreSecretsProvider;
14+
use crate::settings::Settings;
1315
use crate::string::{BnString, IntoCStr};
1416

1517
#[repr(transparent)]
@@ -185,20 +187,22 @@ impl Remote {
185187
/// Use [Remote::connect_with_opts] if you cannot otherwise automatically connect using enterprise.
186188
///
187189
/// WARNING: This is currently **not** thread safe, if you try and connect/disconnect to a remote on
188-
/// multiple threads you will be subject to race conditions. To avoid this wrap the [`Remote`] in
189-
/// a synchronization primitive, and pass that to your threads. Or don't try and connect on multiple threads.
190+
/// multiple threads, you will be subject to race conditions. To avoid this, wrap the [`Remote`] in
191+
/// a synchronization primitive and pass that to your threads. Or don't try and connect on multiple threads.
190192
pub fn connect(&self) -> Result<(), ()> {
191-
// TODO: implement SecretsProvider
192193
if self.is_enterprise()? && enterprise::is_server_authenticated() {
193194
self.connect_with_opts(ConnectionOptions::from_enterprise()?)
194195
} else {
195-
// TODO: Make this error instead.
196-
let username =
197-
std::env::var("BN_ENTERPRISE_USERNAME").expect("No username for connection!");
198-
let password =
199-
std::env::var("BN_ENTERPRISE_PASSWORD").expect("No password for connection!");
200-
let connection_opts = ConnectionOptions::new_with_password(username, password);
201-
self.connect_with_opts(connection_opts)
196+
// Try to load from env vars.
197+
match ConnectionOptions::from_env_variables() {
198+
Ok(connection_opts) => self.connect_with_opts(connection_opts),
199+
Err(_) => {
200+
// Try to load from the enterprise secrets provider.
201+
let secrets_connection_opts =
202+
ConnectionOptions::from_secrets_provider(&self.address())?;
203+
self.connect_with_opts(secrets_connection_opts)
204+
}
205+
}
202206
}
203207
}
204208

@@ -870,11 +874,31 @@ impl ConnectionOptions {
870874
// TODO: Check if enterprise is initialized and error if not.
871875
let username = enterprise::server_username();
872876
let token = enterprise::server_token();
877+
Ok(Self::new_with_token(username, token))
878+
}
879+
880+
/// Retrieves the [`ConnectionOptions`] for the given address.
881+
///
882+
/// NOTE: Uses the secret's provider specified by the setting "enterprise.secretsProvider".
883+
pub fn from_secrets_provider(address: &str) -> Result<Self, ()> {
884+
let secrets_provider_name = Settings::new().get_string("enterprise.secretsProvider");
885+
let provider = CoreSecretsProvider::by_name(&secrets_provider_name).ok_or(())?;
886+
let cred_data_str = provider.get_data(address);
887+
if cred_data_str.is_empty() {
888+
return Err(());
889+
}
890+
let cred_data: serde_json::Value = serde_json::from_str(&cred_data_str).map_err(|_| ())?;
891+
let username = cred_data["username"].as_str().ok_or(())?;
892+
let token = cred_data["token"].as_str().ok_or(())?;
873893
Ok(Self::new_with_token(
874894
username.to_string(),
875895
token.to_string(),
876896
))
877897
}
878898

879-
// TODO: from_secrets_provider
899+
pub fn from_env_variables() -> Result<Self, VarError> {
900+
let username = std::env::var("BN_ENTERPRISE_USERNAME")?;
901+
let password = std::env::var("BN_ENTERPRISE_PASSWORD")?;
902+
Ok(ConnectionOptions::new_with_password(username, password))
903+
}
880904
}

rust/tests/data_buffer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fn get_slice() {
1313
#[test]
1414
fn set_len_write() {
1515
let mut data = DataBuffer::default();
16-
assert_eq!(data.get_data(), &[]);
16+
assert!(data.get_data().is_empty());
1717
unsafe { data.set_len(DUMMY_DATA_0.len()) };
1818
assert_eq!(data.len(), DUMMY_DATA_0.len());
1919
let mut contents = DUMMY_DATA_0.to_vec();
@@ -29,7 +29,7 @@ fn set_len_write() {
2929
assert_eq!(data.get_data(), &DUMMY_DATA_0[..13]);
3030

3131
data.clear();
32-
assert_eq!(data.get_data(), &[]);
32+
assert!(data.get_data().is_empty());
3333
}
3434

3535
#[test]

0 commit comments

Comments
 (0)