1use chrono::prelude::*;
2use crypto::hmac::Hmac;
3use crypto::mac::Mac;
4use crypto::sha1::Sha1;
5use rand::seq::SliceRandom;
6
7pub fn oauth2_authorization_header(bearer_token: &str) -> String {
8 format!("Bearer {}", bearer_token)
9}
10
11pub fn oauth1_authorization_header(
12 consumer_key: &str,
13 consumer_secret: &str,
14 access_token: &str,
15 access_token_secret: &str,
16 method: &str,
17 uri: &str,
18 options: &Vec<(&str, &str)>,
19) -> String {
20 let res = calc_oauth_header(
21 &format!("{}&{}", consumer_secret, access_token_secret),
22 consumer_key,
23 &vec![("oauth_token", access_token)],
24 method,
25 uri,
26 options,
27 );
28 format!("OAuth {}", res)
29}
30
31pub fn calc_oauth_header(
32 sign_key: &str,
33 consumer_key: &str,
34 header_options: &Vec<(&str, &str)>,
35 method: &str,
36 uri: &str,
37 options: &Vec<(&str, &str)>,
38) -> String {
39 let mut param0: Vec<(&str, String)> = vec![
40 ("oauth_consumer_key", String::from(consumer_key)),
41 ("oauth_nonce", nonce()),
42 ("oauth_signature_method", String::from("HMAC-SHA1")),
43 ("oauth_timestamp", timestamp()),
44 ("oauth_version", String::from("1.0")),
45 ];
46 for header_option in header_options {
47 param0.push((header_option.0, encode(header_option.1)));
48 }
49 let mut param1 = param0.clone();
50 for option in options {
51 param1.push((option.0, encode(option.1)));
52 }
53 param1.sort();
54 let parameter = make_query(¶m1, "&");
55 let base = format!("{}&{}&{}", method, encode(uri), encode(¶meter));
56 let mut param2 = param0.clone();
57 param2.push(("oauth_signature", encode(&sign(&base, sign_key))));
58 make_query(¶m2, ", ")
59}
60
61const BASE_STR: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
62
63fn nonce() -> String {
64 let mut rng = &mut rand::thread_rng();
65 String::from_utf8(
66 BASE_STR
67 .as_bytes()
68 .choose_multiple(&mut rng, 32)
69 .cloned()
70 .collect(),
71 )
72 .unwrap()
73}
74
75fn timestamp() -> String {
76 format!("{}", Utc::now().timestamp())
77}
78
79pub fn encode(s: &str) -> String {
80 url::form_urlencoded::byte_serialize(s.as_bytes()).collect::<String>().replace('+', "%20").replace('*', "%2A").replace("%7E", "~")
82}
83
84fn sign(base: &str, key: &str) -> String {
85 let mut hmac = Hmac::new(Sha1::new(), key.as_bytes());
86 hmac.input(base.as_bytes());
87 base64::encode(hmac.result().code())
88}
89
90fn make_query(list: &Vec<(&str, String)>, separator: &str) -> String {
91 let mut result = String::from("");
92 for item in list {
93 if "" != result {
94 result.push_str(separator);
95 }
96 result.push_str(&format!("{}={}", item.0, item.1));
97 }
98 result
99}
100
101#[cfg(test)]
102mod tests {
103 #[test]
104 fn it_oauth2_authorization_header() {
105 assert_eq!("Bearer abc", crate::oauth2_authorization_header("abc"));
106 println!(
107 "{}",
108 crate::oauth1_authorization_header(
109 "a",
110 "b",
111 "c",
112 "d",
113 "GET",
114 "http://localhost",
115 &vec![]
116 )
117 );
118 }
119}