tdm_server_rust/utils/
cos_sts.rs1use cos_rust_sdk::sts::{GetCredentialsRequest, Policy, Statement, StsClient};
18use std::collections::HashMap;
19
20#[derive(Debug, Clone)]
25pub struct TempCredentials {
26 pub tmp_secret_id: String,
28 pub tmp_secret_key: String,
30 pub session_token: String,
32}
33
34pub fn extract_app_id(bucket: &str) -> crate::error::ApiResult<String> {
50 bucket
51 .rsplit_once('-')
52 .map(|(_, app_id)| app_id.to_string())
53 .ok_or_else(|| crate::error::AppError::Oss {
54 code: None,
55 msg: format!("Bucket 名称格式错误: {bucket}"),
56 })
57}
58
59pub fn build_put_policy(
74 bucket: &str,
75 region: &str,
76 object_key: &str,
77 max_bytes: u64,
78) -> crate::error::ApiResult<Policy> {
79 let app_id = extract_app_id(bucket)?;
80 let resource = format!("qcs::cos:{region}:uid/{app_id}:{bucket}/{object_key}");
81 let mut condition = HashMap::new();
82 condition.insert(
83 "cos:content-length".to_string(),
84 serde_json::json!(max_bytes),
85 );
86 Ok(Policy {
87 version: "2.0".into(),
88 statement: vec![Statement {
89 effect: "allow".into(),
90 action: vec!["name/cos:PutObject".into()],
91 resource: vec![resource],
92 condition: Some(HashMap::from([(
93 "numeric_less_than_equal".into(),
94 condition,
95 )])),
96 }],
97 })
98}
99
100pub fn build_get_policy(
110 bucket: &str,
111 region: &str,
112 object_key: &str,
113) -> crate::error::ApiResult<Policy> {
114 let app_id = extract_app_id(bucket)?;
115 let resource = format!("qcs::cos:{region}:uid/{app_id}:{bucket}/{object_key}");
116 Ok(Policy {
117 version: "2.0".into(),
118 statement: vec![Statement {
119 effect: "allow".into(),
120 action: vec!["name/cos:GetObject".into()],
121 resource: vec![resource],
122 condition: None,
123 }],
124 })
125}
126
127pub async fn get_federation_token(
152 secret_id: &str,
153 secret_key: &str,
154 region: &str,
155 policy: Policy,
156 duration_secs: u64,
157) -> crate::error::ApiResult<TempCredentials> {
158 if secret_id.is_empty() || secret_key.is_empty() {
159 return Err(crate::error::AppError::Oss {
160 code: None,
161 msg: "腾讯云 SecretId/SecretKey 未配置".into(),
162 });
163 }
164 let client = StsClient::new(
165 secret_id.trim().to_string(),
166 secret_key.trim().to_string(),
167 region.to_string(),
168 );
169 let creds = client
170 .get_credentials(GetCredentialsRequest {
171 policy,
172 duration_seconds: Some(duration_secs as u32),
173 name: Some("cos-sts-rust".into()),
174 })
175 .await
176 .map_err(|e| crate::error::AppError::Oss {
177 code: None,
178 msg: format!("STS 失败: {e}"),
179 })?;
180 Ok(TempCredentials {
181 tmp_secret_id: creds.tmp_secret_id,
182 tmp_secret_key: creds.tmp_secret_key,
183 session_token: creds.token,
184 })
185}