From c1c69168d7a88601870f581d820d57b9486758ed Mon Sep 17 00:00:00 2001 From: Wim Velzeboer Date: Mon, 21 Sep 2026 14:17:43 +0100 Subject: [PATCH] stuff --- src/lib.rs | 107 +++++++++++++++++++++++++++++----------------------- src/main.rs | 22 +++++++++-- 2 files changed, 78 insertions(+), 51 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5fb1ad1..8c7f756 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,9 +16,7 @@ use rsa::RsaPrivateKey; use serde::{Deserialize, Serialize}; use sha2::Sha256; use std::time::Duration; -use thiserror::Error; use time::OffsetDateTime; -use url::Url; /// The default Salesforce production login URL. @@ -392,6 +390,13 @@ pub struct SalesforceAuthSession { /// Salesforce identity service URL, when returned by Salesforce. pub id: Option, + /// OAuth refresh token, when available. + /// Salesforce organization ID parsed from the identity service URL. + pub org_id: Option, + + /// Salesforce user ID parsed from the identity service URL. + pub user_id: Option, + /// OAuth refresh token, when available. pub refresh_token: Option, @@ -659,54 +664,29 @@ pub async fn authenticate_client_credentials( client_id: &str, client_secret: &str, ) -> Result { - println!("authenticate_client_credentials"); - println!("login url {}", login_url); - println!("client Id {}", client_id); - println!("client secret {}", client_secret); - - let http_client = Client::builder() + let response = Client::builder() .redirect(reqwest::redirect::Policy::none()) .timeout(Duration::from_secs(30)) - .build()?; - let token_url = TokenUrl::new(format!( - "{}/services/oauth2/token", - login_url.trim_end_matches('/') - // "http://localhost:3000" - )) - .map_err(|error| SalesforceAuthError::OAuth2(error.to_string()))?; + .build()? + .post(token_url(login_url)?.url().clone()) + .form(&[ + ("grant_type", "client_credentials"), + ("client_id", client_id), + ("client_secret", client_secret), + ]) + .send() + .await? + .error_for_status()? + .json::() + .await?; - - let oauth_client = BasicClient::new(ClientId::new(client_id.to_string())) - .set_client_secret(ClientSecret::new(client_secret.to_string())) - .set_token_uri(token_url); - - let token_response: StandardTokenResponse = - oauth_client - .exchange_client_credentials() - // .add_scope(Scope::new("api".to_string())) - .request_async(&http_client) - .await - .map_err(|error| SalesforceAuthError::OAuth2(error.to_string()))?; - - let access_token = token_response.access_token().secret().to_string(); - - println!("asfasf {}", client_id); - - - Ok(SalesforceAuthSession { - token: RwLock::new(SalesforceAuthToken { - access_token: "asdf".to_string(), - token_type: Some("Bearer".to_string()), - issued_at: None, - signature: None, - }), - instance_url: login_url.trim_end_matches('/').to_string(), - id: None, - refresh_token: None, - client_id: Some(client_id.to_string()), - client_secret: Some(client_secret.to_string()), - login_url: Some(login_url.to_string()), - }) + to_session( + response, + None, + Some(client_id.to_string()), + Some(client_secret.to_string()), + Some(login_url.to_string()), + ) } /// Authenticates to Salesforce using the JWT bearer flow. @@ -772,6 +752,31 @@ fn salesforce_token_endpoint(login_url: &str) -> String { format!("{}/services/oauth2/token", login_url.trim_end_matches('/')) } +fn parse_salesforce_identity_ids(id_url: Option<&str>) -> (Option, Option) { + let Some(id_url) = id_url else { + return (None, None); + }; + + let segments = id_url + .trim_end_matches('/') + .split('/') + .filter(|segment| !segment.is_empty()) + .collect::>(); + + if segments.len() < 2 { + return (None, None); + } + + let org_id = segments + .get(segments.len() - 2) + .map(|value| (*value).to_string()); + + let user_id = segments + .last() + .map(|value| (*value).to_string()); + + (org_id, user_id) +} fn to_session( response: SalesforceTokenResponse, @@ -784,6 +789,8 @@ fn to_session( .instance_url .ok_or(SalesforceAuthError::MissingRequiredField("instance_url"))?; + let (org_id, user_id) = parse_salesforce_identity_ids(response.id.as_deref()); + Ok(SalesforceAuthSession { token: RwLock::new(SalesforceAuthToken { access_token: response.access_token, @@ -793,6 +800,8 @@ fn to_session( }), instance_url, id: response.id, + org_id, + user_id, refresh_token: response.refresh_token.or(refresh_token), client_id, client_secret, @@ -839,6 +848,8 @@ pub fn authenticate_access_token( }), instance_url: instance_url.trim_end_matches('/').to_string(), id: None, + org_id: None, + user_id: None, refresh_token, client_id, client_secret, @@ -1134,6 +1145,8 @@ async fn fetch_salesforce_token_response_from_access_token( }), instance_url: login_url.trim_end_matches('/').to_string(), id: None, + org_id: None, + user_id: None, refresh_token: None, client_id: None, client_secret: None, diff --git a/src/main.rs b/src/main.rs index 02489a2..1523a40 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,18 +58,32 @@ async fn main() { //Default header headers.insert("Accept", HeaderValue::from_static("application/json")); - + // Get API Versions let response = get_http_client().unwrap() .get(format!("{}/services/data", session.instance_url)) - .headers(headers) + .headers(headers.clone()) .send() .await .unwrap(); - - if response.status().is_success() { println!("SUCCESS Response: {:?}", response.text().await.unwrap()); } else { println!("ERROR Response: {:?}", response.text().await.unwrap()); } + + session.refresh_access_token().await.unwrap(); + + // Get LIMITs Versions + let response = get_http_client().unwrap() + .get(format!("{}/services/data/v67.0/limits", session.instance_url)) + .headers(headers) + .send() + .await + .unwrap(); + if response.status().is_success() { + println!("SUCCESS Response 2: {:?}", response.text().await.unwrap()); + } else { + println!("ERROR Response 2: {:?}", response.text().await.unwrap()); + } + }