Skip to main content

rustauth_plugins/phone_number/
errors.rs

1use http::StatusCode;
2use rustauth_core::api::{ApiErrorResponse, ApiResponse};
3use rustauth_core::error::RustAuthError;
4use rustauth_core::plugin::PluginErrorCode;
5
6pub const PHONE_NUMBER_ERROR_CODES: &[(&str, &str)] = &[
7    ("INVALID_PHONE_NUMBER", "Invalid phone number"),
8    ("PHONE_NUMBER_EXIST", "Phone number already exists"),
9    ("PHONE_NUMBER_NOT_EXIST", "phone number isn't registered"),
10    (
11        "INVALID_PHONE_NUMBER_OR_PASSWORD",
12        "Invalid phone number or password",
13    ),
14    ("UNEXPECTED_ERROR", "Unexpected error"),
15    ("OTP_NOT_FOUND", "OTP not found"),
16    ("OTP_EXPIRED", "OTP expired"),
17    ("INVALID_OTP", "Invalid OTP"),
18    ("PHONE_NUMBER_NOT_VERIFIED", "Phone number not verified"),
19    (
20        "PHONE_NUMBER_CANNOT_BE_UPDATED",
21        "Phone number cannot be updated",
22    ),
23    ("SEND_OTP_NOT_IMPLEMENTED", "sendOTP not implemented"),
24    ("TOO_MANY_ATTEMPTS", "Too many attempts"),
25];
26
27macro_rules! error_code_fn {
28    ($name:ident, $code:literal, $message:literal) => {
29        pub fn $name() -> PluginErrorCode {
30            PluginErrorCode::new($code, $message)
31        }
32    };
33}
34
35error_code_fn!(
36    invalid_phone_number,
37    "INVALID_PHONE_NUMBER",
38    "Invalid phone number"
39);
40error_code_fn!(
41    phone_number_exists,
42    "PHONE_NUMBER_EXIST",
43    "Phone number already exists"
44);
45error_code_fn!(
46    phone_number_not_exists,
47    "PHONE_NUMBER_NOT_EXIST",
48    "phone number isn't registered"
49);
50error_code_fn!(
51    invalid_phone_number_or_password,
52    "INVALID_PHONE_NUMBER_OR_PASSWORD",
53    "Invalid phone number or password"
54);
55error_code_fn!(unexpected_error, "UNEXPECTED_ERROR", "Unexpected error");
56error_code_fn!(otp_not_found, "OTP_NOT_FOUND", "OTP not found");
57error_code_fn!(otp_expired, "OTP_EXPIRED", "OTP expired");
58error_code_fn!(invalid_otp, "INVALID_OTP", "Invalid OTP");
59error_code_fn!(
60    phone_number_not_verified,
61    "PHONE_NUMBER_NOT_VERIFIED",
62    "Phone number not verified"
63);
64error_code_fn!(
65    phone_number_cannot_be_updated,
66    "PHONE_NUMBER_CANNOT_BE_UPDATED",
67    "Phone number cannot be updated"
68);
69error_code_fn!(
70    send_otp_not_implemented,
71    "SEND_OTP_NOT_IMPLEMENTED",
72    "sendOTP not implemented"
73);
74error_code_fn!(too_many_attempts, "TOO_MANY_ATTEMPTS", "Too many attempts");
75
76pub(crate) fn error_response(
77    status: StatusCode,
78    error: PluginErrorCode,
79) -> Result<ApiResponse, RustAuthError> {
80    json_response(
81        status,
82        &ApiErrorResponse {
83            code: error.code,
84            message: error.message,
85            original_message: None,
86        },
87        Vec::new(),
88    )
89}
90
91pub(crate) fn json_response<T>(
92    status: StatusCode,
93    body: &T,
94    cookies: Vec<rustauth_core::cookies::Cookie>,
95) -> Result<ApiResponse, RustAuthError>
96where
97    T: serde::Serialize,
98{
99    let body = serde_json::to_vec(body).map_err(|error| RustAuthError::Api(error.to_string()))?;
100    let mut response = http::Response::builder()
101        .status(status)
102        .header(http::header::CONTENT_TYPE, "application/json")
103        .body(body)
104        .map_err(|error| RustAuthError::Api(error.to_string()))?;
105    for cookie in cookies {
106        response.headers_mut().append(
107            http::header::SET_COOKIE,
108            http::HeaderValue::from_str(&serialize_cookie(&cookie))
109                .map_err(|error| RustAuthError::Cookie(error.to_string()))?,
110        );
111    }
112    Ok(response)
113}
114
115fn serialize_cookie(cookie: &rustauth_core::cookies::Cookie) -> String {
116    let mut value = format!("{}={}", cookie.name, cookie.value);
117    if let Some(max_age) = cookie.attributes.max_age {
118        value.push_str(&format!("; Max-Age={max_age}"));
119    }
120    if let Some(domain) = &cookie.attributes.domain {
121        value.push_str(&format!("; Domain={domain}"));
122    }
123    if let Some(path) = &cookie.attributes.path {
124        value.push_str(&format!("; Path={path}"));
125    }
126    if cookie.attributes.http_only.unwrap_or(false) {
127        value.push_str("; HttpOnly");
128    }
129    if cookie.attributes.secure.unwrap_or(false) {
130        value.push_str("; Secure");
131    }
132    if let Some(same_site) = &cookie.attributes.same_site {
133        value.push_str("; SameSite=");
134        value.push_str(same_site);
135    }
136    value
137}