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 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
//! Bindings to the [Authy TOTP service api](https://www.twilio.com/docs/api/authy/authy-totp). //! //! Much of the documentation for this module comes from the Authy TOTP service //! documentation. use std::fmt::{self, Display}; use serde_json; use std::collections::HashMap; use error::AuthyError; use client::{Client, Status}; const PREFIX: &'static str = "protected"; /// Returned when creating a new authy user. #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct UserNew { /// This id is unique per API KEY and should be stored in your database. pub id: u32, } /// Returned when requesting the status of an authy user. #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct UserStatus { /// The authy id for the user. #[serde(rename = "authy_id")] pub id: u32, /// true when the user has used a valid code before. pub confirmed: bool, /// true when the Authy Mobile/Desktop App was registered. pub registered: bool, /// Has the account been marked for deletion pub account_disabled: bool, /// The country code listed for the user. pub country_code: u16, /// The last 4 of the phone number registered to the account. pub phone_number: String, /// (Unknown, API documentation doesn't list) pub has_hard_token: bool, /// List of devices, options are: android, android_tablet, ios, authy_chrome, sms. pub devices: Vec<String>, } /// Returned when sending a verification code to a user via SMS or Call. #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct PhoneCall { /// The phone number used to send the message. pub cellphone: String, /// The name of the most recent device used by the user. This is only /// returned when the SMS was ignored. pub device: Option<String>, /// True if the request was ignored. pub ignored: Option<bool>, } #[derive(Debug, Clone, Eq, PartialEq)] pub enum ActivityType { PasswordReset, Banned, Unbanned, CookieLogin, } impl Display for ActivityType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ActivityType::PasswordReset => write!(f, "password_reset"), ActivityType::Banned => write!(f, "banned"), ActivityType::Unbanned => write!(f, "unbanned"), ActivityType::CookieLogin => write!(f, "cookie_login"), } } } #[deprecated] /// Please use `create`. pub fn new(client: &Client, email: &str, country_code: u16, phone: &str, send_instructions: bool) -> Result<(Status, UserNew), AuthyError> { create(client, email, country_code, phone, send_instructions) } /// Creates a new Authy user. /// /// Before you can secure a user's login you need to create an Authy user. /// Authy requires you send an email, phone number and country code for each /// Authy user. In response you get an Authy ID which you must then store with /// your user's profile in your own application. /// /// Note: You need to store the unchanging authy_id against the user profile /// in your database or directory: You will use this ID every time you are /// verifying the user's token. For privacy reasons, your users can change /// their phone number registered with Authy without your knowledge by using /// the Authy mobile or desktop app or the Authy.com phone change security /// review. Their Authy ID may be used for other services as well. /// /// A user can have multiple e-mails but only one cellphone. Two separate api /// calls to register a user with the same cellphone and different e-mails will /// return the same authy_id and store both emails for that Authy user. /// /// Please see the Authy documentation for more details: /// https://www.twilio.com/docs/api/authy/authy-totp#enabling-two-factor /// /// Example: /// /// ```rust,ignore /// let mut c = Client::new(API_URL, API_KEY); /// let (status, user) = user::new(&c, "user@domain.com", 54, "317-338-9302", false).expect("User to be created"); /// /// println!("My new authy user is: {}", user.id); /// ``` pub fn create(client: &Client, email: &str, country_code: u16, phone: &str, send_instructions: bool) -> Result<(Status, UserNew), AuthyError> { let mut params: Vec<(String, String)> = vec![]; params.push(("user[email]".into(), email.into())); params.push(("user[cellphone]".into(), phone.into())); params.push(("user[country_code]".into(), country_code.to_string())); if send_instructions { params.push(("send_install_link_via_sms".into(), "true".into())); } let (status, res) = client.post(PREFIX, "users/new", None, Some(params))?; let user = serde_json::from_value(res["user"].clone())?; Ok((status, user)) } /// Deletes an Authy user. /// /// If you want to remove users from your application you can use the delete /// API. Note, deleting a user will NOT immediately disable token /// verifications, as a 24 hour delay is typical before the user is permanently /// removed from the application. If you need to immediately disable a user and /// have not built this functionality into your user management system, the /// Authy dashboard "Delete user" function can be used, and after approving the /// email confirmation, 2FA for the user will be immediately disabled. /// /// Please see the Authy documentation for more details: /// https://www.twilio.com/docs/api/authy/authy-totp#deleting-user pub fn delete(client: &Client, id: u32) -> Result<Status, AuthyError> { let (status, _) = client.post(PREFIX, &format!("users/{}/delete", id), None, None)?; Ok(status) } /// Status of an Authy user. /// /// This will return various details of an Authy user such as their /// registration status, their country code, and the last 4 of their phone /// number. /// /// Please see the Authy documentation for more details: /// https://www.twilio.com/docs/api/authy/authy-totp#user-status pub fn status(client: &Client, id: u32) -> Result<(Status, UserStatus), AuthyError> { let (status, res) = client.get(PREFIX, &format!("users/{}/status", id), None)?; let user_status = serde_json::from_value(res["status"].clone())?; Ok((status, user_status)) } /// Verify an authentication token. /// /// To verify a token simply pass in the token that the user entered and the /// authy id of the user (which should have stored in your database when you /// registered the user above). Authy will use HTTP status codes for the /// response. /// /// To prevent user from being locked out, until the user successfully logs /// in once using Authy this call will return 200 (valid token). If you wish /// to verify token regardless, see below to see how to force verification. /// HTTP 200 means valid token and HTTP 401 means invalid token /// /// Please see the Authy documentation for more details: /// https://www.twilio.com/docs/api/authy/authy-totp#verifying-a-token pub fn verify(client: &Client, id: u32, token: &str) -> Result<Status, AuthyError> { let (status, _) = client.get(PREFIX, &format!("verify/{token}/{id}", token = token, id = id), None)?; Ok(status) } fn phone(client: &Client, kind: &str, id: u32, force: bool, action: Option<&str>, action_message: Option<&str>) -> Result<(Status, PhoneCall), AuthyError> { let mut params: Vec<(String, String)> = vec![]; params.push(("force".into(), force.to_string())); if let Some(action) = action { params.push(("action".into(), action.into())); } if let Some(action_message) = action_message { params.push(("action_message".into(), action_message.into())); } let (status, res) = client.get(PREFIX, &format!("{}/{}", kind, id), Some(params))?; let sms = serde_json::from_value(res)?; Ok((status, sms)) } /// Send token to user via SMS. /// /// Once an Authy ID has been generated for a user, you can provide a /// two-factor stage to a login. If the user downloads and installs the Authy /// smartphone application, it will generate the codes required. However, for /// users that don't own a smartphone, Authy allows you to use text messages /// to send the one time passcode. By default this call will be ignored if the /// user has downloaded and registered the Authy smartphone application /// against their phone number. However you can override this behavior. /// /// Custom Actions /// /// You can pass `action` and `action_message` (optional) to send a code that /// is only valid for the given action. This is useful if you require codes to /// perform different actions on your app. When using this option you have to /// pass the same action when verifying the code. /// /// Please see the Authy documentation for more details: /// https://www.twilio.com/docs/api/authy/authy-totp#requesting-sms-codes pub fn sms(client: &Client, id: u32, force: bool, action: Option<&str>, action_message: Option<&str>) -> Result<(Status, PhoneCall), AuthyError> { phone(client, "sms", id, force, action, action_message) } /// Send token to user via phone call. /// /// For users that don't own a smartphone, and are having trouble with SMS /// Tokens, Authy allows you to use phone calls instead. This call will be /// ignored if the user is using the Authy Mobile app. /// /// Custom Actions /// /// You can pass `action` and `action_message` (optional) to send a code that /// is only valid for the given action. This is useful if you require codes to /// perform different actions on your app. When using this option you have to /// pass the same action when verifying the code. /// /// Please see the Authy documentation for more details: /// https://www.twilio.com/docs/api/authy/authy-totp#phone-call-tokens pub fn call(client: &Client, id: u32, force: bool, action: Option<&str>, action_message: Option<&str>) -> Result<(Status, PhoneCall), AuthyError> { phone(client, "call", id, force, action, action_message) } /// Register user activity with authy. /// /// Optionally you can register some of the activities that your user do on /// your application. This helps us to identify fraudulent behaviours. For /// example if you register that a user reset his password and then he tries to /// change his phone with Authy we can know that something weird is happening. /// /// Please see the Authy documentation for more details: /// https://www.twilio.com/docs/api/authy/authy-totp#register-user-activities pub fn register_activity(client: &Client, id: u32, data: Option<&HashMap<&str, String>>, activity_type: ActivityType, user_ip: &str) -> Result<Status, AuthyError> { let mut params: Vec<(String, String)> = vec![]; params.push(("type".into(), activity_type.to_string())); params.push(("user_ip".into(), user_ip.into())); if let Some(data) = data { for (k, v) in data { params.push((format!("data[{}]", k), v.clone())); } } let (status, _) = client.post(PREFIX, &format!("users/{}/register_activity", id), None, Some(params))?; Ok(status) }