Skip to main content

imgurs_model/model/
authorization.rs

1//! Authentication data
2
3use crate::{
4    error::ErrorMessage,
5    model::{common::AccountID, common::Username},
6};
7use serde::{Deserialize, Serialize};
8use std::convert::TryFrom;
9use std::fmt;
10use time::{serde::timestamp, OffsetDateTime};
11
12/// Client ID
13#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)]
14#[serde(deny_unknown_fields)]
15pub struct ClientID(pub String);
16
17impl TryFrom<String> for ClientID {
18    type Error = ErrorMessage;
19
20    fn try_from(value: String) -> Result<Self, Self::Error> {
21        // TODO: input checks
22
23        if value.is_empty() {
24            return Err(ErrorMessage::new("Invalid length"));
25        }
26
27        Ok(ClientID(value))
28    }
29}
30
31impl fmt::Display for ClientID {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        write!(f, "{}", self.0)
34    }
35}
36
37/// Client secret
38#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)]
39#[serde(deny_unknown_fields)]
40pub struct ClientSecret(pub String);
41
42impl TryFrom<String> for ClientSecret {
43    type Error = ErrorMessage;
44
45    fn try_from(value: String) -> Result<Self, Self::Error> {
46        // TODO: input checks
47
48        if value.is_empty() {
49            return Err(ErrorMessage::new("Invalid length"));
50        }
51
52        Ok(ClientSecret(value))
53    }
54}
55
56impl fmt::Display for ClientSecret {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        write!(f, "{}", self.0)
59    }
60}
61
62/// User access token
63///
64/// Is your secret key used to access the user's data.
65/// It can be thought of the user's password and username combined into one, and is used to access
66/// the user's account.
67/// It expires after 1 month
68#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)]
69#[serde(deny_unknown_fields)]
70pub struct AccessToken(pub String);
71
72impl TryFrom<String> for AccessToken {
73    type Error = ErrorMessage;
74
75    fn try_from(value: String) -> Result<Self, Self::Error> {
76        // TODO: input checks
77
78        if value.is_empty() {
79            return Err(ErrorMessage::new("Invalid length"));
80        }
81
82        Ok(AccessToken(value))
83    }
84}
85
86impl fmt::Display for AccessToken {
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        write!(f, "{}", self.0)
89    }
90}
91
92/// Refresh token
93///
94/// Is used to request new access_tokens.
95/// Since access_tokens expire after 1 month, we need a way to request new ones without going
96/// through the entire authorization step again.
97/// It does not expire.
98#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize)]
99#[serde(deny_unknown_fields)]
100pub struct RefreshToken(pub String);
101
102impl TryFrom<String> for RefreshToken {
103    type Error = ErrorMessage;
104
105    fn try_from(value: String) -> Result<Self, Self::Error> {
106        // TODO: input checks
107
108        if value.is_empty() {
109            return Err(ErrorMessage::new("Invalid length"));
110        }
111
112        Ok(RefreshToken(value))
113    }
114}
115
116impl fmt::Display for RefreshToken {
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        write!(f, "{}", self.0)
119    }
120}
121
122/// Authorization code
123///
124/// Is used for obtaining the the access and refresh tokens.
125/// It's purpose is to be immediately exchanged for an access_token and refresh_token.
126#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
127#[serde(deny_unknown_fields)]
128pub struct AuthorizationCode(pub String);
129
130impl TryFrom<String> for AuthorizationCode {
131    type Error = ErrorMessage;
132
133    fn try_from(value: String) -> Result<Self, Self::Error> {
134        // TODO: input checks
135
136        if value.is_empty() {
137            return Err(ErrorMessage::new("Invalid length"));
138        }
139
140        Ok(AuthorizationCode(value))
141    }
142}
143
144impl fmt::Display for AuthorizationCode {
145    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146        write!(f, "{}", self.0)
147    }
148}
149
150/// PIN code
151///
152/// Is also used for obtaining the the access and refresh tokens, but it's presented to the user so
153/// that they can enter it directly into your app.
154/// It's purpose is to be immediately exchanged for an access_token and refresh_token.
155#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
156#[serde(deny_unknown_fields)]
157pub struct PINCode(pub String);
158
159impl TryFrom<String> for PINCode {
160    type Error = ErrorMessage;
161
162    fn try_from(value: String) -> Result<Self, Self::Error> {
163        // TODO: input checks
164
165        if value.is_empty() {
166            return Err(ErrorMessage::new("Invalid length"));
167        }
168
169        Ok(PINCode(value))
170    }
171}
172
173impl fmt::Display for PINCode {
174    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175        write!(f, "{}", self.0)
176    }
177}
178
179/// Type of the obtained token
180#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
181#[serde(deny_unknown_fields)]
182pub struct TokenType(pub String);
183
184impl fmt::Display for TokenType {
185    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186        write!(f, "{}", self.0)
187    }
188}
189
190/// Authorization API response
191#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
192#[serde(deny_unknown_fields)]
193pub struct AuthorizationResponse {
194    /// Access token
195    pub access_token: AccessToken,
196    /// Account id
197    pub account_id: AccountID,
198    /// Account username
199    pub account_username: Username,
200    /// Access token expiration date
201    #[serde(with = "timestamp")]
202    pub expires_in: OffsetDateTime,
203    /// Refresh token
204    pub refresh_token: RefreshToken,
205    /// TODO: missing from API model
206    pub scope: serde_json::Value,
207    /// Type of the token received
208    pub token_type: TokenType,
209}
210
211/// Refresh token API response
212#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
213#[serde(deny_unknown_fields)]
214pub struct RefreshResponse {
215    /// Access token
216    pub access_token: AccessToken,
217    /// Account id
218    pub account_id: AccountID,
219    /// Account username
220    pub account_username: Username,
221    /// Access token expiration date
222    #[serde(with = "timestamp")]
223    pub expires_in: OffsetDateTime,
224    /// Refresh token
225    pub refresh_token: RefreshToken,
226    /// TODO: missing from API model
227    pub scope: serde_json::Value,
228    /// Type of the token received
229    pub token_type: TokenType,
230}