use crate::types::XError;
use oauth1_request::signature_method::hmac_sha1::HmacSha1;
use oauth1_request::{Credentials as OAuthCredentials, Token as OAuthToken};
use reqwest::Request;
#[derive(Debug, Clone)]
pub struct Credentials {
pub app_key: String,
pub app_secret: String,
pub access_token: String,
pub access_secret: String,
}
impl Credentials {
pub fn new(
app_key: impl Into<String>,
app_secret: impl Into<String>,
access_token: impl Into<String>,
access_secret: impl Into<String>,
) -> Self {
Self {
app_key: app_key.into(),
app_secret: app_secret.into(),
access_token: access_token.into(),
access_secret: access_secret.into(),
}
}
pub fn validate(&self) -> Result<(), XError> {
if self.app_key.is_empty()
|| self.app_secret.is_empty()
|| self.access_token.is_empty()
|| self.access_secret.is_empty()
{
return Err(XError::AuthenticationFailed(
"All credentials must be non-empty".to_string(),
));
}
Ok(())
}
}
#[derive(Clone)]
pub struct OAuth {
credentials: Credentials,
}
impl OAuth {
pub fn new(credentials: Credentials) -> Result<Self, XError> {
credentials.validate()?;
Ok(Self { credentials })
}
pub fn sign_request(&self, request: &mut Request) -> Result<(), XError> {
let method = request.method().as_str();
let url = request.url().as_str();
let client = OAuthCredentials::new(&self.credentials.app_key, &self.credentials.app_secret);
let token_creds = OAuthCredentials::new(
&self.credentials.access_token,
&self.credentials.access_secret,
);
let token = OAuthToken::new(client, token_creds);
let auth_header = oauth1_request::authorize(method, url, &(), &token, HmacSha1::new());
request.headers_mut().insert(
"Authorization",
auth_header.parse().map_err(|e| {
XError::OAuthError(format!("Failed to parse authorization header: {}", e))
})?,
);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_credentials_new() {
let creds = Credentials::new("key", "secret", "token", "token_secret");
assert_eq!(creds.app_key, "key");
assert_eq!(creds.app_secret, "secret");
assert_eq!(creds.access_token, "token");
assert_eq!(creds.access_secret, "token_secret");
}
#[test]
fn test_credentials_validate_success() {
let creds = Credentials::new("key", "secret", "token", "token_secret");
assert!(creds.validate().is_ok());
}
#[test]
fn test_credentials_validate_empty() {
let creds = Credentials::new("", "secret", "token", "token_secret");
assert!(creds.validate().is_err());
}
}