1use crate::types::XError;
2use oauth1_request::signature_method::hmac_sha1::HmacSha1;
3use oauth1_request::{Credentials as OAuthCredentials, Token as OAuthToken};
4use reqwest::Request;
5
6#[derive(Debug, Clone)]
8pub struct Credentials {
9 pub app_key: String,
11 pub app_secret: String,
13 pub access_token: String,
15 pub access_secret: String,
17}
18
19impl Credentials {
20 pub fn new(
22 app_key: impl Into<String>,
23 app_secret: impl Into<String>,
24 access_token: impl Into<String>,
25 access_secret: impl Into<String>,
26 ) -> Self {
27 Self {
28 app_key: app_key.into(),
29 app_secret: app_secret.into(),
30 access_token: access_token.into(),
31 access_secret: access_secret.into(),
32 }
33 }
34
35 pub fn validate(&self) -> Result<(), XError> {
37 if self.app_key.is_empty()
38 || self.app_secret.is_empty()
39 || self.access_token.is_empty()
40 || self.access_secret.is_empty()
41 {
42 return Err(XError::AuthenticationFailed(
43 "All credentials must be non-empty".to_string(),
44 ));
45 }
46 Ok(())
47 }
48}
49
50#[derive(Clone)]
52pub struct OAuth {
53 credentials: Credentials,
54}
55
56impl OAuth {
57 pub fn new(credentials: Credentials) -> Result<Self, XError> {
59 credentials.validate()?;
60 Ok(Self { credentials })
61 }
62
63 pub fn sign_request(&self, request: &mut Request) -> Result<(), XError> {
65 let method = request.method().as_str();
66 let url = request.url().as_str();
67
68 let client = OAuthCredentials::new(&self.credentials.app_key, &self.credentials.app_secret);
70 let token_creds = OAuthCredentials::new(
71 &self.credentials.access_token,
72 &self.credentials.access_secret,
73 );
74 let token = OAuthToken::new(client, token_creds);
75
76 let auth_header = oauth1_request::authorize(method, url, &(), &token, HmacSha1::new());
78
79 request.headers_mut().insert(
81 "Authorization",
82 auth_header.parse().map_err(|e| {
83 XError::OAuthError(format!("Failed to parse authorization header: {}", e))
84 })?,
85 );
86
87 Ok(())
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn test_credentials_new() {
97 let creds = Credentials::new("key", "secret", "token", "token_secret");
98 assert_eq!(creds.app_key, "key");
99 assert_eq!(creds.app_secret, "secret");
100 assert_eq!(creds.access_token, "token");
101 assert_eq!(creds.access_secret, "token_secret");
102 }
103
104 #[test]
105 fn test_credentials_validate_success() {
106 let creds = Credentials::new("key", "secret", "token", "token_secret");
107 assert!(creds.validate().is_ok());
108 }
109
110 #[test]
111 fn test_credentials_validate_empty() {
112 let creds = Credentials::new("", "secret", "token", "token_secret");
113 assert!(creds.validate().is_err());
114 }
115}