1use crate::config::ConfigHolder;
18use crate::constant::{HEADER_AUTHORIZATION, HEADER_CONTENT_SHA256, HEADER_CONTENT_TYPE_LOWER, HEADER_HOST, HEADER_HOST_LOWER, HEADER_PREFIX, HEADER_REQUEST_DATE, HEADER_SECURITY_TOKEN, ISO8601_DATE_FORMAT, LONG_DATE_FORMAT, NOT_ALLOWED_REQUEST_HEADER, QUERY_ALGORITHM, QUERY_CREDENTIAL, QUERY_DATE, QUERY_EXPIRES, QUERY_POLICY, QUERY_SECURITY_TOKEN, QUERY_SIGNATURE, QUERY_SIGNED_HEADERS};
19use crate::enumeration::HttpMethodType;
20use crate::error::{GenericError, TosError};
21use crate::http::HttpRequest;
22use crate::internal::{base64, check_bucket, hex, hex_sha256, hmac_sha256, url_encode, url_encode_with_safe, AdditionalContext};
23use arc_swap::ArcSwap;
24use chrono::{DateTime, TimeDelta, Utc};
25use std::collections::HashMap;
26use std::ops::Add;
27use std::sync::Arc;
28use tracing::log::debug;
29
30pub trait SignerAPI {
31 fn pre_signed_url(&self, input: &PreSignedURLInput) -> Result<PreSignedURLOutput, TosError>;
32 fn pre_signed_post_signature(&self, input: &PreSignedPostSignatureInput) -> Result<PreSignedPostSignatureOutput, TosError>;
33 fn pre_signed_policy_url(&self, input: &PreSignedPolicyURLInput) -> Result<PreSignedPolicyURLOutput, TosError>;
34}
35
36#[derive(Debug, Clone, PartialEq, Default)]
37pub struct PreSignedURLInput {
38 pub(crate) http_method: HttpMethodType,
39 pub(crate) bucket: String,
40 pub(crate) key: String,
41 pub(crate) expires: i64,
42 pub(crate) header: HashMap<String, String>,
43 pub(crate) query: HashMap<String, String>,
44 pub(crate) alternative_endpoint: String,
45 pub(crate) is_custom_domain: Option<bool>,
46 pub(crate) is_signed_all_headers: bool,
47}
48
49impl PreSignedURLInput {
50 pub fn new(bucket: impl Into<String>) -> Self {
51 Self {
52 http_method: Default::default(),
53 bucket: bucket.into(),
54 key: "".to_string(),
55 expires: 3600,
56 header: Default::default(),
57 query: Default::default(),
58 alternative_endpoint: "".to_string(),
59 is_custom_domain: None,
60 is_signed_all_headers: false,
61 }
62 }
63
64 pub fn new_with_key(bucket: impl Into<String>, key: impl Into<String>) -> Self {
65 Self {
66 http_method: Default::default(),
67 bucket: bucket.into(),
68 key: key.into(),
69 expires: 3600,
70 header: Default::default(),
71 query: Default::default(),
72 alternative_endpoint: "".to_string(),
73 is_custom_domain: None,
74 is_signed_all_headers: false,
75 }
76 }
77
78 pub fn http_method(&self) -> &HttpMethodType {
79 &self.http_method
80 }
81
82 pub fn bucket(&self) -> &str {
83 &self.bucket
84 }
85
86 pub fn key(&self) -> &str {
87 &self.key
88 }
89
90 pub fn expires(&self) -> i64 {
91 self.expires
92 }
93
94 pub fn header(&self) -> &HashMap<String, String> {
95 &self.header
96 }
97
98 pub fn query(&self) -> &HashMap<String, String> {
99 &self.query
100 }
101
102 pub fn alternative_endpoint(&self) -> &str {
103 &self.alternative_endpoint
104 }
105
106 pub fn is_custom_domain(&self) -> Option<bool> {
107 self.is_custom_domain
108 }
109
110 pub fn is_signed_all_headers(&self) -> bool {
111 self.is_signed_all_headers
112 }
113
114 pub fn set_http_method(&mut self, http_method: impl Into<HttpMethodType>) {
115 self.http_method = http_method.into();
116 }
117
118 pub fn set_bucket(&mut self, bucket: impl Into<String>) {
119 self.bucket = bucket.into();
120 }
121
122 pub fn set_key(&mut self, key: impl Into<String>) {
123 self.key = key.into();
124 }
125
126 pub fn set_expires(&mut self, expires: i64) {
127 self.expires = expires;
128 }
129
130 pub fn set_header(&mut self, header: impl Into<HashMap<String, String>>) {
131 self.header = header.into();
132 }
133
134 pub fn set_query(&mut self, query: impl Into<HashMap<String, String>>) {
135 self.query = query.into();
136 }
137
138 pub fn set_alternative_endpoint(&mut self, alternative_endpoint: impl Into<String>) {
139 self.alternative_endpoint = alternative_endpoint.into();
140 }
141
142 pub fn set_is_custom_domain(&mut self, is_custom_domain: impl Into<bool>) {
143 self.is_custom_domain = Some(is_custom_domain.into());
144 }
145
146 pub fn set_is_signed_all_headers(&mut self, is_signed_all_headers: bool) {
147 self.is_signed_all_headers = is_signed_all_headers;
148 }
149}
150
151#[derive(Debug, Clone, PartialEq, Default)]
152pub struct PreSignedURLOutput {
153 pub(crate) signed_url: String,
154 pub(crate) signed_header: HashMap<String, String>,
155}
156
157impl PreSignedURLOutput {
158 pub fn signed_url(&self) -> &str {
159 &self.signed_url
160 }
161
162 pub fn signed_header(&self) -> &HashMap<String, String> {
163 &self.signed_header
164 }
165}
166
167#[derive(Debug, Clone, PartialEq, Default)]
168pub struct PreSignedPostSignatureInput {
169 pub(crate) bucket: String,
170 pub(crate) key: String,
171 pub(crate) expires: i64,
172 pub(crate) conditions: Vec<PostSignatureCondition>,
173 pub(crate) content_length_range: Option<ContentLengthRange>,
174 pub(crate) multi_values_conditions: Vec<PostSignatureMultiValuesCondition>,
175}
176impl PreSignedPostSignatureInput {
177 pub fn new(bucket: impl Into<String>) -> Self {
178 Self {
179 bucket: bucket.into(),
180 key: "".to_string(),
181 expires: 3600,
182 conditions: vec![],
183 content_length_range: None,
184 multi_values_conditions: vec![],
185 }
186 }
187 pub fn new_with_key(bucket: impl Into<String>, key: impl Into<String>) -> Self {
188 Self {
189 bucket: bucket.into(),
190 key: key.into(),
191 expires: 3600,
192 conditions: vec![],
193 content_length_range: None,
194 multi_values_conditions: vec![],
195 }
196 }
197
198 pub fn bucket(&self) -> &str {
199 &self.bucket
200 }
201
202 pub fn key(&self) -> &str {
203 &self.key
204 }
205
206 pub fn expires(&self) -> i64 {
207 self.expires
208 }
209
210 pub fn conditions(&self) -> &Vec<PostSignatureCondition> {
211 &self.conditions
212 }
213
214 pub fn content_length_range(&self) -> &Option<ContentLengthRange> {
215 &self.content_length_range
216 }
217
218 pub fn multi_values_conditions(&self) -> &Vec<PostSignatureMultiValuesCondition> {
219 &self.multi_values_conditions
220 }
221
222 pub fn set_bucket(&mut self, bucket: impl Into<String>) {
223 self.bucket = bucket.into();
224 }
225
226 pub fn set_key(&mut self, key: impl Into<String>) {
227 self.key = key.into();
228 }
229
230 pub fn set_expires(&mut self, expires: i64) {
231 self.expires = expires;
232 }
233
234 pub fn set_conditions(&mut self, conditions: impl Into<Vec<PostSignatureCondition>>) {
235 self.conditions = conditions.into();
236 }
237
238 pub fn add_condition(&mut self, condition: impl Into<PostSignatureCondition>) {
239 self.conditions.push(condition.into());
240 }
241
242 pub fn set_content_length_range(&mut self, content_length_range: impl Into<ContentLengthRange>) {
243 self.content_length_range = Some(content_length_range.into());
244 }
245
246 pub fn set_multi_values_conditions(&mut self, multi_values_conditions: impl Into<Vec<PostSignatureMultiValuesCondition>>) {
247 self.multi_values_conditions = multi_values_conditions.into();
248 }
249
250 pub fn add_multi_values_condition(&mut self, multi_values_condition: impl Into<PostSignatureMultiValuesCondition>) {
251 self.multi_values_conditions.push(multi_values_condition.into());
252 }
253}
254
255#[derive(Debug, Clone, PartialEq, Default)]
256pub struct PostSignatureCondition {
257 pub(crate) key: String,
258 pub(crate) value: String,
259 pub(crate) operator: Option<String>,
260}
261
262impl PostSignatureCondition {
263 pub fn new(key: impl Into<String>, value: impl Into<String>) -> Self {
264 Self {
265 key: key.into(),
266 value: value.into(),
267 operator: None,
268 }
269 }
270
271 pub fn new_with_operator(key: impl Into<String>, value: impl Into<String>, operator: impl Into<String>) -> Self {
272 Self {
273 key: key.into(),
274 value: value.into(),
275 operator: Some(operator.into()),
276 }
277 }
278
279 pub(crate) fn to_serde_json_value(&self) -> serde_json::Value {
280 match &self.operator {
281 None => {
282 let mut m = serde_json::Map::with_capacity(2);
283 m.insert(self.key.clone(), serde_json::Value::String(self.value.clone()));
284 serde_json::Value::Object(m)
285 }
286 Some(operator) => {
287 let mut v = Vec::with_capacity(3);
288 v.push(serde_json::Value::String(operator.clone()));
289 if !&self.key.starts_with("$") {
290 v.push(serde_json::Value::String(String::from("$") + &self.key));
291 } else {
292 v.push(serde_json::Value::String(self.key.clone()));
293 }
294 v.push(serde_json::Value::String(self.value.clone()));
295 serde_json::Value::Array(v)
296 }
297 }
298 }
299
300 pub fn key(&self) -> &str {
301 &self.key
302 }
303
304 pub fn value(&self) -> &str {
305 &self.value
306 }
307
308 pub fn operator(&self) -> &Option<String> {
309 &self.operator
310 }
311
312 pub fn set_key(&mut self, key: impl Into<String>) {
313 self.key = key.into();
314 }
315
316 pub fn set_value(&mut self, value: impl Into<String>) {
317 self.value = value.into();
318 }
319
320 pub fn set_operator(&mut self, operator: impl Into<String>) {
321 self.operator = Some(operator.into());
322 }
323}
324#[derive(Debug, Clone, PartialEq, Default)]
325pub struct ContentLengthRange {
326 pub(crate) range_start: i64,
327 pub(crate) range_end: i64,
328}
329impl ContentLengthRange {
330 pub fn new(range_start: i64, range_end: i64) -> Self {
331 Self {
332 range_start,
333 range_end,
334 }
335 }
336
337 pub fn range_start(&self) -> i64 {
338 self.range_start
339 }
340
341 pub fn range_end(&self) -> i64 {
342 self.range_end
343 }
344
345 pub fn set_range_start(&mut self, range_start: i64) {
346 self.range_start = range_start;
347 }
348
349 pub fn set_range_end(&mut self, range_end: i64) {
350 self.range_end = range_end;
351 }
352}
353#[derive(Debug, Clone, PartialEq, Default)]
354pub struct PostSignatureMultiValuesCondition {
355 pub(crate) key: String,
356 pub(crate) values: Vec<String>,
357 pub(crate) operator: String,
358}
359
360impl PostSignatureMultiValuesCondition {
361 pub fn new(key: impl Into<String>, values: impl Into<Vec<String>>, operator: impl Into<String>) -> Self {
362 Self {
363 key: key.into(),
364 values: values.into(),
365 operator: operator.into(),
366 }
367 }
368
369 pub(crate) fn to_serde_json_value(&self) -> serde_json::Value {
370 let mut v = Vec::with_capacity(3);
371 v.push(serde_json::Value::String(self.operator.clone()));
372 if !&self.key.starts_with("$") {
373 v.push(serde_json::Value::String(String::from("$") + &self.key));
374 } else {
375 v.push(serde_json::Value::String(self.key.clone()));
376 }
377 let mut values = Vec::with_capacity(self.values.len());
378 for value in self.values.iter() {
379 values.push(serde_json::Value::String(value.clone()));
380 }
381 v.push(serde_json::Value::Array(values));
382 serde_json::Value::Array(v)
383 }
384
385 pub fn key(&self) -> &str {
386 &self.key
387 }
388
389 pub fn values(&self) -> &Vec<String> {
390 &self.values
391 }
392
393 pub fn operator(&self) -> &str {
394 &self.operator
395 }
396
397 pub fn set_key(&mut self, key: impl Into<String>) {
398 self.key = key.into();
399 }
400
401 pub fn set_values(&mut self, values: impl Into<Vec<String>>) {
402 self.values = values.into();
403 }
404
405 pub fn set_operator(&mut self, operator: impl Into<String>) {
406 self.operator = operator.into();
407 }
408}
409
410#[derive(Debug, Clone, PartialEq, Default)]
411pub struct PreSignedPostSignatureOutput {
412 pub(crate) origin_policy: String,
413 pub(crate) policy: String,
414 pub(crate) algorithm: String,
415 pub(crate) credential: String,
416 pub(crate) date: String,
417 pub(crate) signature: String,
418}
419
420impl PreSignedPostSignatureOutput {
421 pub fn origin_policy(&self) -> &str {
422 &self.origin_policy
423 }
424
425 pub fn policy(&self) -> &str {
426 &self.policy
427 }
428
429 pub fn algorithm(&self) -> &str {
430 &self.algorithm
431 }
432
433 pub fn credential(&self) -> &str {
434 &self.credential
435 }
436
437 pub fn date(&self) -> &str {
438 &self.date
439 }
440
441 pub fn signature(&self) -> &str {
442 &self.signature
443 }
444}
445
446#[derive(Debug, Clone, PartialEq, Default)]
447pub struct PreSignedPolicyURLInput {
448 pub(crate) bucket: String,
449 pub(crate) expires: i64,
450 pub(crate) conditions: Vec<PolicySignatureCondition>,
451 pub(crate) alternative_endpoint: String,
452 pub(crate) is_custom_domain: Option<bool>,
453}
454impl PreSignedPolicyURLInput {
455 pub fn new(bucket: impl Into<String>) -> Self {
456 Self {
457 bucket: bucket.into(),
458 expires: 3600,
459 conditions: vec![],
460 alternative_endpoint: "".to_string(),
461 is_custom_domain: None,
462 }
463 }
464
465 pub fn bucket(&self) -> &str {
466 &self.bucket
467 }
468
469 pub fn expires(&self) -> i64 {
470 self.expires
471 }
472
473 pub fn conditions(&self) -> &Vec<PolicySignatureCondition> {
474 &self.conditions
475 }
476
477 pub fn alternative_endpoint(&self) -> &str {
478 &self.alternative_endpoint
479 }
480
481 pub fn is_custom_domain(&self) -> Option<bool> {
482 self.is_custom_domain
483 }
484
485 pub fn set_bucket(&mut self, bucket: impl Into<String>) {
486 self.bucket = bucket.into();
487 }
488
489 pub fn set_expires(&mut self, expires: i64) {
490 self.expires = expires;
491 }
492
493 pub fn add_condition(&mut self, condition: impl Into<PolicySignatureCondition>) {
494 self.conditions.push(condition.into());
495 }
496
497 pub fn set_conditions(&mut self, conditions: impl Into<Vec<PolicySignatureCondition>>) {
498 self.conditions = conditions.into();
499 }
500
501 pub fn set_alternative_endpoint(&mut self, alternative_endpoint: impl Into<String>) {
502 self.alternative_endpoint = alternative_endpoint.into();
503 }
504
505 pub fn set_is_custom_domain(&mut self, is_custom_domain: bool) {
506 self.is_custom_domain = Some(is_custom_domain);
507 }
508}
509
510#[derive(Debug, Clone, PartialEq, Default)]
511pub struct PolicySignatureCondition {
512 pub(crate) key: String,
513 pub(crate) value: String,
514 pub(crate) operator: String,
515}
516impl PolicySignatureCondition {
517 pub fn new(key: impl Into<String>, value: impl Into<String>) -> Self {
518 Self {
519 key: key.into(),
520 value: value.into(),
521 operator: "".to_string(),
522 }
523 }
524
525 pub fn new_with_operator(key: impl Into<String>, value: impl Into<String>, operator: impl Into<String>) -> Self {
526 Self {
527 key: key.into(),
528 value: value.into(),
529 operator: operator.into(),
530 }
531 }
532
533 pub fn key(&self) -> &str {
534 &self.key
535 }
536
537 pub fn value(&self) -> &str {
538 &self.value
539 }
540
541 pub fn operator(&self) -> &str {
542 &self.operator
543 }
544
545 pub fn set_key(&mut self, key: impl Into<String>) {
546 self.key = key.into();
547 }
548
549 pub fn set_value(&mut self, value: impl Into<String>) {
550 self.value = value.into();
551 }
552
553 pub fn set_operator(&mut self, operator: impl Into<String>) {
554 self.operator = operator.into();
555 }
556}
557#[derive(Debug, Clone, Default)]
558pub struct PreSignedPolicyURLOutput {
559 pub(crate) signed_query: String,
560 pub(crate) config_holder: Arc<ConfigHolder>,
561 pub(crate) is_custom_domain: bool,
562 pub(crate) bucket: String,
563 pub(crate) domain: String,
564 pub(crate) schema: String,
565}
566
567impl PreSignedPolicyURLOutput {
568 pub fn signed_query(&self) -> &str {
569 &self.signed_query
570 }
571
572 pub fn get_signed_url_for_list(&self, additional_query: Option<HashMap<impl AsRef<str>, impl AsRef<str>>>) -> String {
573 let mut result = self.config_holder.get_endpoint_with_domain(&self.bucket, "", &self.schema, &self.domain, false, self.is_custom_domain);
574 result.push('?');
575 result.push_str(&self.signed_query);
576 if let Some(additional_query) = additional_query {
577 for (key, value) in additional_query.iter() {
578 result.push('&');
579 result.push_str(key.as_ref());
580 result.push('=');
581 result.push_str(value.as_ref());
582 }
583 }
584 result
585 }
586 pub fn get_signed_url_for_get_or_head(&self, key: impl AsRef<str>, additional_query: Option<HashMap<impl AsRef<str>, impl AsRef<str>>>) -> String {
587 let mut result = self.config_holder.get_endpoint_with_domain(&self.bucket, key.as_ref(), &self.schema, &self.domain, true, self.is_custom_domain);
588 result.push('?');
589 result.push_str(&self.signed_query);
590 if let Some(additional_query) = additional_query {
591 for (key, value) in additional_query.iter() {
592 result.push('&');
593 result.push_str(key.as_ref());
594 result.push('=');
595 result.push_str(value.as_ref());
596 }
597 }
598 result
599 }
600}
601
602pub(crate) fn pre_signed_policy_url(config_holder: &ArcSwap<ConfigHolder>, ak: &str, sk: &str, security_token: &str, input: &PreSignedPolicyURLInput) -> Result<PreSignedPolicyURLOutput, TosError> {
603 let config_holder = config_holder.load();
604 if input.conditions().len() == 0 {
605 return Err(TosError::client_error("empty conditions"));
606 }
607
608 let mut is_custom_domain = config_holder.is_custom_domain;
609 if let Some(x) = input.is_custom_domain() {
610 is_custom_domain = x;
611 }
612 let bucket = input.bucket().trim();
613 if !is_custom_domain {
614 check_bucket(bucket)?;
615 }
616 let schema;
617 let domain;
618 if input.alternative_endpoint() != "" {
619 (schema, domain, _) = config_holder.split_endpoint(input.alternative_endpoint())?;
620 } else {
621 schema = "".to_string();
622 domain = "".to_string();
623 }
624
625 let is_anonymous = ak == "" || sk == "";
626 let mut conditions = Vec::<serde_json::Value>::with_capacity(input.conditions().len() + 1);
627 conditions.push(PostSignatureCondition::new("bucket", input.bucket()).to_serde_json_value());
628 let (long_date, short_date, credential_scope) = calc_date_and_credential_scope(&config_holder.region, None);
629 for condition in input.conditions() {
630 if condition.key() != "key" && condition.key() != "$key" {
631 return Err(TosError::client_error("condition key must be 'key'"));
632 }
633 conditions.push(PostSignatureCondition::new_with_operator(condition.key(), condition.value(), condition.operator()).to_serde_json_value());
634 }
635
636 let mut query = HashMap::with_capacity(7);
637 query.insert(QUERY_ALGORITHM, ALGORITHM.to_string());
638 query.insert(QUERY_DATE, long_date.clone());
639 query.insert(QUERY_EXPIRES, input.expires().to_string());
640 if !is_anonymous {
641 query.insert(QUERY_CREDENTIAL, format!("{}/{}", ak, credential_scope));
642 if security_token != "" {
643 query.insert(QUERY_SECURITY_TOKEN, security_token.to_string());
644 }
645 }
646 match serde_json::to_string(&HashMap::from([("conditions", serde_json::Value::Array(conditions))])) {
647 Err(ex) => Err(TosError::client_error_with_cause("trans json error",
648 GenericError::JsonError(ex.to_string()))),
649 Ok(origin_policy) => {
650 let policy = base64(origin_policy.as_str());
651 query.insert(QUERY_POLICY, policy);
652 let mut query = Some(query);
653 if !is_anonymous {
654 let canonical_request = calc_canonical_request("", &mut query, "", "", "", UNSIGNED_PAYLOAD);
655 let string_to_sign = calc_string_to_sign(&long_date, &credential_scope, &canonical_request);
656 let signature = calc_signature(&string_to_sign, &short_date, &config_holder.region, sk)?;
657 query.as_mut().unwrap().insert(QUERY_SIGNATURE, signature);
658 }
659 let mut signed_query = String::new();
660 if let Some(query) = query.as_ref() {
661 for (idx, kv) in query.iter().enumerate() {
662 signed_query.push_str(url_encode(*kv.0).as_str());
663 signed_query.push('=');
664 signed_query.push_str(kv.1);
665 if idx != query.len() - 1 {
666 signed_query.push('&');
667 }
668 }
669 }
670 Ok(PreSignedPolicyURLOutput {
671 signed_query,
672 config_holder: config_holder.clone(),
673 is_custom_domain,
674 bucket: bucket.to_string(),
675 domain,
676 schema,
677 })
678 }
679 }
680}
681
682pub(crate) fn pre_signed_post_signature(config_holder: &ArcSwap<ConfigHolder>, ak: &str, sk: &str, security_token: &str, input: &PreSignedPostSignatureInput) -> Result<PreSignedPostSignatureOutput, TosError> {
683 let config_holder = config_holder.load();
684 let (long_date, short_date, mut credential) = calc_date_and_credential(ak, &config_holder.region);
685 let mut conditions = Vec::<serde_json::Value>::with_capacity(7 + input.conditions().len() + input.multi_values_conditions().len());
686 conditions.push(PostSignatureCondition::new(QUERY_ALGORITHM, ALGORITHM).to_serde_json_value());
687 conditions.push(PostSignatureCondition::new(QUERY_DATE, long_date.clone()).to_serde_json_value());
688 let is_anonymous = ak == "" || sk == "";
689 if !is_anonymous {
690 conditions.push(PostSignatureCondition::new(QUERY_CREDENTIAL, credential.clone()).to_serde_json_value());
691 if security_token != "" {
692 conditions.push(PostSignatureCondition::new(QUERY_SECURITY_TOKEN, security_token).to_serde_json_value());
693 }
694 }
695
696 let bucket = input.bucket().trim();
697 if bucket != "" {
698 check_bucket(bucket)?;
699 conditions.push(PostSignatureCondition::new("bucket", bucket).to_serde_json_value());
700 }
701 let key = input.key();
702 if key != "" {
703 conditions.push(PostSignatureCondition::new("key", key).to_serde_json_value());
704 }
705 if input.conditions().len() > 0 {
706 for condition in input.conditions() {
707 conditions.push(condition.to_serde_json_value());
708 }
709 }
710 if let Some(content_length_range) = &input.content_length_range {
711 let mut condition = PostSignatureCondition::new(content_length_range.range_start.to_string(), content_length_range.range_end.to_string());
712 condition.set_operator("content-length-range");
713 conditions.push(condition.to_serde_json_value());
714 }
715 if input.multi_values_conditions().len() > 0 {
716 for condition in input.multi_values_conditions() {
717 conditions.push(condition.to_serde_json_value());
718 }
719 }
720 let expiration = Utc::now().add(TimeDelta::new(input.expires(), 0).unwrap()).format(ISO8601_DATE_FORMAT).to_string();
721 let mut origin_policy = HashMap::with_capacity(2);
722 origin_policy.insert("expiration", serde_json::Value::String(expiration));
723 origin_policy.insert("conditions", serde_json::Value::Array(conditions));
724
725 match serde_json::to_string(&origin_policy) {
726 Err(ex) => Err(TosError::client_error_with_cause("trans json error",
727 GenericError::JsonError(ex.to_string()))),
728 Ok(result) => {
729 let origin_policy = result;
730 let policy = base64(origin_policy.as_str());
731 let mut signature = String::new();
732 if is_anonymous {
733 credential = String::new();
734 } else {
735 signature = calc_signature(&policy, &short_date, &config_holder.region, sk)?;
736 }
737 Ok(PreSignedPostSignatureOutput {
738 origin_policy,
739 policy,
740 algorithm: ALGORITHM.to_string(),
741 credential,
742 date: long_date,
743 signature,
744 })
745 }
746 }
747}
748pub(crate) fn pre_signed_url(config_holder: &ArcSwap<ConfigHolder>, ak: &str, sk: &str, security_token: &str, input: &PreSignedURLInput) -> Result<PreSignedURLOutput, TosError> {
749 let config_holder = config_holder.load();
750 let mut is_custom_domain = config_holder.is_custom_domain;
751 if let Some(x) = input.is_custom_domain() {
752 is_custom_domain = x;
753 }
754 let bucket = input.bucket().trim();
755 if !is_custom_domain {
756 check_bucket(bucket)?;
757 }
758 let schema;
759 let domain;
760 if input.alternative_endpoint() != "" {
761 (schema, domain, _) = config_holder.split_endpoint(input.alternative_endpoint())?;
762 } else {
763 schema = "".to_string();
764 domain = "".to_string();
765 }
766
767 let is_anonymous = ak == "" || sk == "";
768 if is_anonymous {
769 let signed_url = config_holder.get_endpoint_with_domain(bucket, input.key(), &schema, &domain, true, is_custom_domain);
770 return Ok(PreSignedURLOutput {
771 signed_url,
772 signed_header: HashMap::default(),
773 });
774 }
775
776 let (long_date, short_date, credential_scope) = calc_date_and_credential_scope(&config_holder.region, None);
777
778 let mut signed_header = HashMap::with_capacity(input.header.len() + 1);
779 for (key, value) in &input.header {
780 signed_header.insert(key.clone(), value.to_string());
781 }
782
783 signed_header.insert(HEADER_HOST.to_string(), config_holder.get_host_with_domain(bucket, &domain, is_custom_domain));
784 let (canonical_headers, signed_headers, mut content_sha256) = calc_canonical_headers(&signed_header, &None, input.is_signed_all_headers);
785
786 let mut query = HashMap::with_capacity(input.query.len() + 7);
787 for (key, value) in &input.query {
788 query.insert(key.as_str(), value.to_string());
789 }
790 let mut expires = input.expires;
791 if expires <= 0 {
792 expires = 3600;
793 }
794 query.insert(QUERY_ALGORITHM, ALGORITHM.to_string());
795 query.insert(QUERY_CREDENTIAL, format!("{}/{}", ak, credential_scope));
796 query.insert(QUERY_DATE, long_date.clone());
797 query.insert(QUERY_EXPIRES, expires.to_string());
798 query.insert(QUERY_SIGNED_HEADERS, signed_headers.clone());
799 if security_token != "" {
800 query.insert(QUERY_SECURITY_TOKEN, security_token.to_string());
801 }
802 if content_sha256 == "" {
803 content_sha256 = UNSIGNED_PAYLOAD.to_string();
804 }
805
806 let mut query = Some(query);
807 let canonical_request = calc_canonical_request(input.http_method.as_str(), &mut query, input.key(), &canonical_headers, &signed_headers, content_sha256.as_str());
808 let string_to_sign = calc_string_to_sign(&long_date, &credential_scope, &canonical_request);
809 let signature = calc_signature(&string_to_sign, &short_date, &config_holder.region, sk)?;
810 query.as_mut().unwrap().insert(QUERY_SIGNATURE, signature);
811 let mut signed_url = config_holder.get_endpoint_with_domain(input.bucket(), input.key(), &schema, &domain, true, is_custom_domain);
812
813 if let Some(query) = query.as_ref() {
814 if query.len() > 0 {
815 signed_url.push('?');
816 for (idx, kv) in query.iter().enumerate() {
817 signed_url.push_str(url_encode(*kv.0).as_str());
818 signed_url.push('=');
819 signed_url.push_str(kv.1);
820 if idx != query.len() - 1 {
821 signed_url.push('&');
822 }
823 }
824 }
825 }
826 Ok(PreSignedURLOutput {
827 signed_url,
828 signed_header,
829 })
830}
831
832pub(crate) const SERVICE_TAG: &str = "tos";
833pub(crate) const REQUEST_TAG: &str = "request";
834pub(crate) const EMPTY_HASH_PAYLOAD: &str = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
835pub(crate) const UNSIGNED_PAYLOAD: &str = "UNSIGNED-PAYLOAD";
836pub(crate) const ALGORITHM: &str = "TOS4-HMAC-SHA256";
837
838pub(crate) fn sign_header<'a, 'c, B>(request: &mut HttpRequest<'c, B>, ak: &str, sk: &str, security_token: &str,
839 config_holder: &ConfigHolder, ac: &AdditionalContext<'a>) -> Result<(), TosError>
840where
841 'a: 'c,
842{
843 let is_anonymous = ak == "" || sk == "";
844 if !is_anonymous && security_token != "" {
845 request.header.insert(HEADER_SECURITY_TOKEN, security_token.to_string());
846 }
847 let (long_date, short_date, credential_scope) = calc_date_and_credential_scope(&config_holder.region, ac.request_date);
848 let bucket = request.bucket;
849 if ac.request_host != "" {
850 request.header.insert(HEADER_HOST, ac.request_host.to_string());
851 } else if ac.is_control_operation {
852 request.header.insert(HEADER_HOST, config_holder.get_host_with_domain(bucket, &config_holder.domain_control, config_holder.is_custom_domain));
853 } else {
854 request.header.insert(HEADER_HOST, config_holder.get_host(bucket));
855 }
856 request.header.insert(HEADER_REQUEST_DATE, long_date.clone());
857 if let Some(request_header) = ac.request_header {
858 if request_header.len() > 0 {
859 for (k, v) in request_header.iter() {
860 if request.header.contains_key(k.as_str()) {
861 continue;
862 }
863
864 if NOT_ALLOWED_REQUEST_HEADER.contains_key(k.to_lowercase().as_str()) {
865 continue;
866 }
867
868 request.header.insert(k, v.to_string());
869 }
870 }
871 }
872
873 if let Some(request_query) = ac.request_query {
874 if request_query.len() > 0 {
875 if request.query.is_none() {
876 request.query = Some(HashMap::with_capacity(request_query.len()));
877 }
878 if let Some(query) = &mut request.query {
879 for (k, v) in request_query.iter() {
880 if query.contains_key(k.as_str()) {
881 continue;
882 }
883 query.insert(k, v.to_string());
884 }
885 }
886 }
887 }
888 let (canonical_headers, signed_headers, _) = calc_canonical_headers(&request.header, &request.meta, false);
889 let canonical_request = calc_canonical_request(request.method.as_str(), &mut request.query, request.key, &canonical_headers, &signed_headers, EMPTY_HASH_PAYLOAD);
890 debug!("canonical_request: {}", canonical_request);
891 if is_anonymous {
892 return Ok(());
893 }
894
895 let string_to_sign = calc_string_to_sign(&long_date, &credential_scope, &canonical_request);
896 debug!("string_to_sign: {}", string_to_sign);
898 let signature = calc_signature(&string_to_sign, &short_date, &config_holder.region, sk)?;
899 let mut authorization = String::with_capacity(ALGORITHM.len() + ak.len() +
902 credential_scope.len() + signed_headers.len() + signature.len() + 64);
903 authorization = authorization + ALGORITHM +
904 " Credential=" + ak + "/" + credential_scope.as_str() +
905 ", SignedHeaders=" + signed_headers.as_str() +
906 ", Signature=" + signature.as_str();
907 request.header.insert(HEADER_AUTHORIZATION, authorization);
909 Ok(())
910}
911
912pub(crate) fn calc_string_to_sign(long_date: &str, credential_scope: &str, canonical_request: &str) -> String {
913 let mut string_to_sign = String::with_capacity(ALGORITHM.len() + long_date.len() + credential_scope.len() + 3);
914 string_to_sign = string_to_sign + ALGORITHM + "\n" + long_date + "\n" + credential_scope + "\n" + hex_sha256(canonical_request).as_str();
915 string_to_sign
917}
918
919pub(crate) fn calc_signature(string_to_sign: &str, short_date: &str, region: &str, sk: &str) -> Result<String, TosError> {
920 let result = hmac_sha256(string_to_sign, hmac_sha256(REQUEST_TAG,
921 hmac_sha256(SERVICE_TAG,
922 hmac_sha256(region,
923 hmac_sha256(short_date, sk)?)?)?)?)?;
924 Ok(hex(result))
926}
927
928pub(crate) fn calc_canonical_request(method: &str, query: &mut Option<HashMap<&str, String>>, key: &str, canonical_headers: &str, signed_headers: &str, content_sha256: &str) -> String {
929 let mut canonical_request = String::with_capacity(key.len() * 2 + 64);
930 if method != "" {
931 canonical_request.push_str(method);
932 canonical_request.push('\n');
933 canonical_request.push('/');
934 }
935 if key != "" {
936 canonical_request.push_str(url_encode_with_safe(key, "/").as_str());
937 }
938
939 if method != "" {
940 canonical_request.push('\n');
941 }
942 if let Some(query) = query.as_mut() {
943 let mut keys = Vec::<&str>::with_capacity(query.len());
944 for key in query.keys() {
945 keys.push(key);
946 }
947 keys.sort();
948 let mut value;
949 let mut encoded_value;
950 for (idx, key) in keys.iter().enumerate() {
951 value = query.get(*key).unwrap();
952 canonical_request.push_str(url_encode(*key).as_str());
953 canonical_request.push('=');
954 if *value != "" {
955 encoded_value = url_encode(value);
956 } else {
957 encoded_value = String::new();
958 }
959 canonical_request.push_str(encoded_value.as_str());
960 if idx != keys.len() - 1 {
961 canonical_request.push('&');
962 }
963 query.insert(*key, encoded_value);
964 }
965 }
966 canonical_request.push('\n');
967
968 if canonical_headers != "" {
969 canonical_request.push_str(canonical_headers);
970 }
971 if method != "" {
972 canonical_request.push('\n');
973 }
974
975 if signed_headers != "" {
976 canonical_request.push_str(signed_headers);
977 }
978 if method != "" {
979 canonical_request.push('\n');
980 }
981
982 canonical_request.push_str(content_sha256);
983 canonical_request
985}
986
987pub(crate) fn calc_date_and_credential(ak: &str, region: &str) -> (String, String, String) {
988 let long_date = Utc::now().format(LONG_DATE_FORMAT).to_string();
989 let short_date = &long_date[0..8];
990 let mut credential_scope = String::with_capacity(ak.len() + short_date.len() + region.len() + SERVICE_TAG.len() + REQUEST_TAG.len() + 4);
991 credential_scope.push_str(ak);
992 credential_scope.push('/');
993 credential_scope.push_str(short_date);
994 credential_scope.push('/');
995 credential_scope.push_str(region);
996 credential_scope.push('/');
997 credential_scope.push_str(SERVICE_TAG);
998 credential_scope.push('/');
999 credential_scope.push_str(REQUEST_TAG);
1000 let short_date = short_date.to_string();
1001 (long_date, short_date, credential_scope)
1002}
1003
1004pub(crate) fn calc_date_and_credential_scope(region: &str, request_date: Option<DateTime<Utc>>) -> (String, String, String) {
1005 let now;
1006 if let Some(request_date) = request_date {
1007 now = request_date;
1008 } else {
1009 now = Utc::now();
1010 }
1011 let long_date = now.format(LONG_DATE_FORMAT).to_string();
1012 let short_date = &long_date[0..8];
1013 let mut credential_scope = String::with_capacity(short_date.len() + region.len() + SERVICE_TAG.len() + REQUEST_TAG.len() + 3);
1014 credential_scope.push_str(short_date);
1015 credential_scope.push('/');
1016 credential_scope.push_str(region);
1017 credential_scope.push('/');
1018 credential_scope.push_str(SERVICE_TAG);
1019 credential_scope.push('/');
1020 credential_scope.push_str(REQUEST_TAG);
1021 let short_date = short_date.to_string();
1022 (long_date, short_date, credential_scope)
1023}
1024
1025pub(crate) fn calc_canonical_headers(header: &HashMap<impl AsRef<str>, String>, meta: &Option<HashMap<String, String>>, is_signed_all_headers: bool) -> (String, String, String) {
1026 let mut all_header: HashMap<String, &str>;
1027 let mut keys;
1028 let mut total_len = 0;
1029 if let Some(m) = meta {
1030 keys = Vec::<String>::with_capacity(header.len() + m.len());
1031 all_header = HashMap::with_capacity(header.len() + m.len());
1032 for (key, value) in m {
1033 let key = key.to_lowercase();
1034 all_header.insert(key.clone(), value);
1035 total_len += key.len();
1036 keys.push(key);
1037 }
1038 } else {
1039 keys = Vec::<String>::with_capacity(header.len());
1040 all_header = HashMap::with_capacity(header.len());
1041 }
1042
1043 for (key, value) in header {
1044 let key = key.as_ref().to_lowercase();
1045 all_header.insert(key.clone(), value);
1046 total_len += key.len();
1047 keys.push(key);
1048 }
1049
1050 keys.sort();
1051 let mut content_sha256 = "".to_string();
1052 let mut signed_headers = String::with_capacity(total_len + keys.len());
1053 let mut canonical_headers = String::with_capacity(total_len * 2 + keys.len() * 2);
1054 for key in keys.iter() {
1055 if !is_signed_all_headers && key != HEADER_HOST_LOWER && key != HEADER_CONTENT_TYPE_LOWER && !key.starts_with(HEADER_PREFIX) {
1056 continue;
1057 }
1058
1059 let val = all_header.get(key.as_str()).unwrap().trim();
1060 if key == HEADER_CONTENT_SHA256 {
1061 content_sha256 = val.to_string();
1062 }
1063
1064 signed_headers.push_str(key);
1065 signed_headers.push(';');
1066 canonical_headers.push_str(key);
1067 canonical_headers.push(':');
1068 canonical_headers.push_str(val);
1069 canonical_headers.push('\n');
1070 }
1071
1072 signed_headers = (&signed_headers[0..signed_headers.len() - 1]).to_string();
1073 (canonical_headers, signed_headers, content_sha256)
1074}