tencentcloud_sms_sdk/core/
credential.rs

1//! Credential management for TencentCloud authentication
2
3use crate::error::{Result, TencentCloudError};
4use std::env;
5
6/// TencentCloud credentials for API authentication
7#[derive(Debug, Clone)]
8pub struct Credential {
9    /// Secret ID for authentication
10    pub secret_id: String,
11    /// Secret Key for authentication
12    pub secret_key: String,
13    /// Session token for temporary credentials (optional)
14    pub token: Option<String>,
15}
16
17impl Credential {
18    /// Create a new Credential instance
19    ///
20    /// # Arguments
21    ///
22    /// * `secret_id` - The secret ID for authentication
23    /// * `secret_key` - The secret key for authentication
24    /// * `token` - Optional session token for temporary credentials
25    ///
26    /// # Examples
27    ///
28    /// ```rust
29    /// use tencentcloud_sms_sdk::Credential;
30    ///
31    /// let credential = Credential::new("your_secret_id", "your_secret_key", None);
32    /// ```
33    pub fn new<S: Into<String>>(secret_id: S, secret_key: S, token: Option<S>) -> Self {
34        Self {
35            secret_id: secret_id.into(),
36            secret_key: secret_key.into(),
37            token: token.map(|t| t.into()),
38        }
39    }
40
41    /// Create credentials from environment variables
42    ///
43    /// Reads the following environment variables:
44    /// - `TENCENTCLOUD_SECRET_ID` or `TC_SECRET_ID`
45    /// - `TENCENTCLOUD_SECRET_KEY` or `TC_SECRET_KEY`
46    /// - `TENCENTCLOUD_TOKEN` or `TC_TOKEN` (optional)
47    ///
48    /// # Examples
49    ///
50    /// ```rust,no_run
51    /// use tencentcloud_sms_sdk::Credential;
52    ///
53    /// // Make sure to set environment variables first
54    /// // export TENCENTCLOUD_SECRET_ID=your_secret_id
55    /// // export TENCENTCLOUD_SECRET_KEY=your_secret_key
56    /// let credential = Credential::from_env().unwrap();
57    /// ```
58    pub fn from_env() -> Result<Self> {
59        let secret_id = env::var("TENCENTCLOUD_SECRET_ID")
60            .or_else(|_| env::var("TC_SECRET_ID"))
61            .map_err(|_| {
62                TencentCloudError::auth(
63                    "TENCENTCLOUD_SECRET_ID or TC_SECRET_ID environment variable not found",
64                )
65            })?;
66
67        let secret_key = env::var("TENCENTCLOUD_SECRET_KEY")
68            .or_else(|_| env::var("TC_SECRET_KEY"))
69            .map_err(|_| {
70                TencentCloudError::auth(
71                    "TENCENTCLOUD_SECRET_KEY or TC_SECRET_KEY environment variable not found",
72                )
73            })?;
74
75        let token = env::var("TENCENTCLOUD_TOKEN")
76            .or_else(|_| env::var("TC_TOKEN"))
77            .ok();
78
79        Ok(Self {
80            secret_id,
81            secret_key,
82            token,
83        })
84    }
85
86    /// Validate that the credential has required fields
87    pub fn validate(&self) -> Result<()> {
88        if self.secret_id.is_empty() {
89            return Err(TencentCloudError::auth("Secret ID cannot be empty"));
90        }
91        if self.secret_key.is_empty() {
92            return Err(TencentCloudError::auth("Secret Key cannot be empty"));
93        }
94        Ok(())
95    }
96
97    /// Get the secret ID
98    pub fn secret_id(&self) -> &str {
99        &self.secret_id
100    }
101
102    /// Get the secret key
103    pub fn secret_key(&self) -> &str {
104        &self.secret_key
105    }
106
107    /// Get the session token
108    pub fn token(&self) -> Option<&str> {
109        self.token.as_deref()
110    }
111
112    /// Check if this credential has a session token
113    pub fn has_token(&self) -> bool {
114        self.token.is_some()
115    }
116
117    /// Update the session token
118    pub fn set_token<S: Into<String>>(&mut self, token: Option<S>) {
119        self.token = token.map(|t| t.into());
120    }
121}
122
123impl Default for Credential {
124    fn default() -> Self {
125        Self {
126            secret_id: String::new(),
127            secret_key: String::new(),
128            token: None,
129        }
130    }
131}
132
133#[cfg(test)]
134mod tests {
135    use super::*;
136
137    #[test]
138    fn test_credential_new() {
139        let credential = Credential::new("test_id", "test_key", Some("test_token"));
140        assert_eq!(credential.secret_id, "test_id");
141        assert_eq!(credential.secret_key, "test_key");
142        assert_eq!(credential.token, Some("test_token".to_string()));
143    }
144
145    #[test]
146    fn test_credential_validate() {
147        let credential = Credential::new("test_id", "test_key", None);
148        assert!(credential.validate().is_ok());
149
150        let invalid_credential = Credential::new("", "test_key", None);
151        assert!(invalid_credential.validate().is_err());
152
153        let invalid_credential = Credential::new("test_id", "", None);
154        assert!(invalid_credential.validate().is_err());
155    }
156
157    #[test]
158    fn test_credential_methods() {
159        let mut credential = Credential::new("test_id", "test_key", None);
160
161        assert_eq!(credential.secret_id(), "test_id");
162        assert_eq!(credential.secret_key(), "test_key");
163        assert_eq!(credential.token(), None);
164        assert!(!credential.has_token());
165
166        credential.set_token(Some("new_token"));
167        assert_eq!(credential.token(), Some("new_token"));
168        assert!(credential.has_token());
169    }
170}