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