summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--rust/Cargo.toml2
-rw-r--r--rust/src/collaboration/remote.rs50
-rw-r--r--rust/tests/data_buffer.rs4
4 files changed, 42 insertions, 15 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 7fea9b14..8e08425f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -358,6 +358,7 @@ dependencies = [
"log",
"rayon",
"rstest",
+ "serde_json",
"serial_test",
"tempfile",
"thiserror 2.0.11",
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index aecffb99..16743cd9 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -18,6 +18,8 @@ log = { version = "0.4", features = ["std"] }
rayon = { version = "1.10", optional = true }
binaryninjacore-sys = { path = "binaryninjacore-sys" }
thiserror = "2.0"
+# Parts of the collaboration and workflow APIs consume and produce JSON.
+serde_json = "1.0"
[dev-dependencies]
rstest = "0.24"
diff --git a/rust/src/collaboration/remote.rs b/rust/src/collaboration/remote.rs
index 7b5828ef..c1ad6678 100644
--- a/rust/src/collaboration/remote.rs
+++ b/rust/src/collaboration/remote.rs
@@ -1,15 +1,17 @@
+use super::{sync, GroupId, RemoteGroup, RemoteProject, RemoteUser};
use binaryninjacore_sys::*;
+use std::env::VarError;
use std::ffi::c_void;
use std::ptr::NonNull;
-use super::{sync, GroupId, RemoteGroup, RemoteProject, RemoteUser};
-
use crate::binary_view::BinaryView;
use crate::database::Database;
use crate::enterprise;
use crate::progress::{NoProgressCallback, ProgressCallback};
use crate::project::Project;
use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
+use crate::secrets_provider::CoreSecretsProvider;
+use crate::settings::Settings;
use crate::string::{BnString, IntoCStr};
#[repr(transparent)]
@@ -185,20 +187,22 @@ impl Remote {
/// Use [Remote::connect_with_opts] if you cannot otherwise automatically connect using enterprise.
///
/// WARNING: This is currently **not** thread safe, if you try and connect/disconnect to a remote on
- /// multiple threads you will be subject to race conditions. To avoid this wrap the [`Remote`] in
- /// a synchronization primitive, and pass that to your threads. Or don't try and connect on multiple threads.
+ /// multiple threads, you will be subject to race conditions. To avoid this, wrap the [`Remote`] in
+ /// a synchronization primitive and pass that to your threads. Or don't try and connect on multiple threads.
pub fn connect(&self) -> Result<(), ()> {
- // TODO: implement SecretsProvider
if self.is_enterprise()? && enterprise::is_server_authenticated() {
self.connect_with_opts(ConnectionOptions::from_enterprise()?)
} else {
- // TODO: Make this error instead.
- let username =
- std::env::var("BN_ENTERPRISE_USERNAME").expect("No username for connection!");
- let password =
- std::env::var("BN_ENTERPRISE_PASSWORD").expect("No password for connection!");
- let connection_opts = ConnectionOptions::new_with_password(username, password);
- self.connect_with_opts(connection_opts)
+ // Try to load from env vars.
+ match ConnectionOptions::from_env_variables() {
+ Ok(connection_opts) => self.connect_with_opts(connection_opts),
+ Err(_) => {
+ // Try to load from the enterprise secrets provider.
+ let secrets_connection_opts =
+ ConnectionOptions::from_secrets_provider(&self.address())?;
+ self.connect_with_opts(secrets_connection_opts)
+ }
+ }
}
}
@@ -870,11 +874,31 @@ impl ConnectionOptions {
// TODO: Check if enterprise is initialized and error if not.
let username = enterprise::server_username();
let token = enterprise::server_token();
+ Ok(Self::new_with_token(username, token))
+ }
+
+ /// Retrieves the [`ConnectionOptions`] for the given address.
+ ///
+ /// NOTE: Uses the secret's provider specified by the setting "enterprise.secretsProvider".
+ pub fn from_secrets_provider(address: &str) -> Result<Self, ()> {
+ let secrets_provider_name = Settings::new().get_string("enterprise.secretsProvider");
+ let provider = CoreSecretsProvider::by_name(&secrets_provider_name).ok_or(())?;
+ let cred_data_str = provider.get_data(address);
+ if cred_data_str.is_empty() {
+ return Err(());
+ }
+ let cred_data: serde_json::Value = serde_json::from_str(&cred_data_str).map_err(|_| ())?;
+ let username = cred_data["username"].as_str().ok_or(())?;
+ let token = cred_data["token"].as_str().ok_or(())?;
Ok(Self::new_with_token(
username.to_string(),
token.to_string(),
))
}
- // TODO: from_secrets_provider
+ pub fn from_env_variables() -> Result<Self, VarError> {
+ let username = std::env::var("BN_ENTERPRISE_USERNAME")?;
+ let password = std::env::var("BN_ENTERPRISE_PASSWORD")?;
+ Ok(ConnectionOptions::new_with_password(username, password))
+ }
}
diff --git a/rust/tests/data_buffer.rs b/rust/tests/data_buffer.rs
index 8480ae71..1e095d19 100644
--- a/rust/tests/data_buffer.rs
+++ b/rust/tests/data_buffer.rs
@@ -13,7 +13,7 @@ fn get_slice() {
#[test]
fn set_len_write() {
let mut data = DataBuffer::default();
- assert_eq!(data.get_data(), &[]);
+ assert!(data.get_data().is_empty());
unsafe { data.set_len(DUMMY_DATA_0.len()) };
assert_eq!(data.len(), DUMMY_DATA_0.len());
let mut contents = DUMMY_DATA_0.to_vec();
@@ -29,7 +29,7 @@ fn set_len_write() {
assert_eq!(data.get_data(), &DUMMY_DATA_0[..13]);
data.clear();
- assert_eq!(data.get_data(), &[]);
+ assert!(data.get_data().is_empty());
}
#[test]