1extern crate chrono;
2extern crate sha1;
3
4use std::iter;
5
6use chrono::prelude::*;
7use log::debug;
8use rand::distributions::Alphanumeric;
9use rand::{thread_rng, Rng};
10use reqwest::header::{HeaderMap, HeaderValue};
11use uuid::Uuid;
12
13use crate::hash::HashGenerator;
14use crate::hash::IyziAuthV2Generator;
15use crate::options::Options;
16
17pub const CLIENT_VERSION: &str = env!("CARGO_PKG_VERSION");
18pub const CLIENT_TITLE: &str = env!("CARGO_PKG_NAME");
19
20const AUTHORIZATION: &str = "Authorization";
21const RANDOM_HEADER_NAME: &str = "x-iyzi-rnd";
22const CLIENT_VERSION_HEADER_NAME: &str = "x-iyzi-client-version";
23const RANDOM_STRING_SIZE: usize = 8;
24
25#[derive(Debug, Default, Serialize, Deserialize, PartialEq)]
26#[serde(rename_all = "camelCase")]
27pub struct IyzipayResource {
28 status: Option<String>,
29
30 error_code: Option<String>,
31
32 error_message: Option<String>,
33
34 error_group: Option<String>,
35
36 locale: Option<String>,
37
38 system_time: Option<i64>,
39
40 conversation_id: Option<String>,
41}
42
43impl IyzipayResource {
44 pub fn new() -> IyzipayResource {
45 IyzipayResource::default()
46 }
47
48 pub fn get_http_headers(request: String, options: &Options) -> HeaderMap {
49 let mut headers = HeaderMap::new();
50 let mut rng = thread_rng();
51 let random_alpanumeric: String = iter::repeat(())
52 .map(|()| rng.sample(Alphanumeric))
53 .take(RANDOM_STRING_SIZE)
54 .collect();
55 let random_string = format!(
56 "{}{}",
57 IyzipayResource::get_unix_timestamp_ms(),
58 random_alpanumeric
59 );
60 debug!("Request:{}", request);
61
62 headers.insert(
63 RANDOM_HEADER_NAME,
64 HeaderValue::from_str(random_string.as_str()).unwrap(),
65 );
66 headers.insert(
67 AUTHORIZATION,
68 IyzipayResource::prepare_authorization_header(request, random_string, options),
69 );
70
71 IyzipayResource::put_client_version_header(&mut headers);
72
73 debug!(
74 "Header:{}:{:?}",
75 RANDOM_HEADER_NAME,
76 headers.get(RANDOM_HEADER_NAME).unwrap()
77 );
78 debug!(
79 "Header:{}:{:?}",
80 AUTHORIZATION,
81 headers.get(AUTHORIZATION).unwrap()
82 );
83 debug!(
84 "Header:{}:{:?}",
85 CLIENT_VERSION_HEADER_NAME,
86 headers.get(CLIENT_VERSION_HEADER_NAME).unwrap()
87 );
88 headers
89 }
90
91 pub fn prepare_authorization_header(
92 request: String,
93 random_string: String,
94 options: &Options,
95 ) -> HeaderValue {
96 let auth_str = format!(
97 "{} {}:{}",
98 "IYZWS",
99 options.api_key(),
100 HashGenerator::generate_hash(
101 options.api_key(),
102 options.secret_key(),
103 random_string.as_str(),
104 request.as_str()
105 )
106 );
107 HeaderValue::from_str(auth_str.as_str()).unwrap()
108 }
109
110 pub fn prepare_authorization_header_v2(
111 uri: String,
112 request: String,
113 random_string: String,
114 options: &Options,
115 ) -> HeaderValue {
116 let auth_str = format!(
117 "{} {}",
118 "IYZWSv2",
119 IyziAuthV2Generator::generate_auth_content(
120 uri.as_str(),
121 options.api_key(),
122 options.secret_key(),
123 random_string.as_str(),
124 request.as_str()
125 )
126 );
127 HeaderValue::from_str(auth_str.as_str()).unwrap()
128 }
129
130 pub fn get_http_headers_v2(uri: String, request: String, options: &Options) -> HeaderMap {
131 let mut headers = HeaderMap::new();
132 let random_string = Uuid::new_v4().to_string();
133 headers.insert(
134 AUTHORIZATION,
135 IyzipayResource::prepare_authorization_header_v2(uri, request, random_string, options),
136 );
137 IyzipayResource::put_client_version_header(&mut headers);
138
139 debug!(
140 "Header:{}:{:?}",
141 AUTHORIZATION,
142 headers.get(AUTHORIZATION).unwrap()
143 );
144 debug!(
145 "Header:{}:{:?}",
146 CLIENT_VERSION_HEADER_NAME,
147 headers.get(CLIENT_VERSION_HEADER_NAME).unwrap()
148 );
149
150 headers
151 }
152
153 fn get_unix_timestamp_ms() -> i64 {
154 let now = Utc::now();
155 let seconds: i64 = now.timestamp();
156 let nanoseconds: i64 = now.nanosecond() as i64;
157 (seconds * 1000) + (nanoseconds / 1000 / 1000)
158 }
159
160 fn put_client_version_header(headers: &mut HeaderMap<HeaderValue>) {
161 let client: String = format!("{}-{}", CLIENT_TITLE, CLIENT_VERSION);
162 headers.insert(
163 CLIENT_VERSION_HEADER_NAME,
164 HeaderValue::from_str(client.as_str()).unwrap(),
165 );
166 }
167
168 pub fn set_status<T: Into<String>>(&mut self, status: T) {
169 self.status = Some(status.into());
170 }
171
172 pub fn set_error_code<T: Into<String>>(&mut self, error_code: T) {
173 self.error_code = Some(error_code.into());
174 }
175
176 pub fn set_error_message<T: Into<String>>(&mut self, error_message: T) {
177 self.error_message = Some(error_message.into());
178 }
179
180 pub fn set_error_group<T: Into<String>>(&mut self, error_group: T) {
181 self.error_group = Some(error_group.into());
182 }
183
184 pub fn set_locale<T: Into<String>>(&mut self, locale: T) {
185 self.locale = Some(locale.into());
186 }
187
188 pub fn set_system_time<T: Into<i64>>(&mut self, system_time: T) {
189 self.system_time = Some(system_time.into());
190 }
191
192 pub fn set_conversation_id<T: Into<String>>(&mut self, conversation_id: T) {
193 self.conversation_id = Some(conversation_id.into());
194 }
195
196 pub fn status(&self) -> Option<&String> {
197 self.status.as_ref()
198 }
199 pub fn error_code(&self) -> Option<&String> {
200 self.error_code.as_ref()
201 }
202 pub fn error_message(&self) -> Option<&String> {
203 self.error_message.as_ref()
204 }
205 pub fn error_group(&self) -> Option<&String> {
206 self.error_group.as_ref()
207 }
208 pub fn locale(&self) -> Option<&String> {
209 self.locale.as_ref()
210 }
211 pub fn system_time(&self) -> Option<&i64> {
212 self.system_time.as_ref()
213 }
214 pub fn conversation_id(&self) -> Option<&String> {
215 self.conversation_id.as_ref()
216 }
217}