bitwarden_auth/send_access/access_token_response.rs
1use std::fmt::Debug;
2
3use crate::send_access::api::{SendAccessTokenApiErrorResponse, SendAccessTokenApiSuccessResponse};
4
5/// A send access token which can be used to access a send.
6#[derive(serde::Serialize, serde::Deserialize, Clone)]
7#[serde(rename_all = "camelCase", deny_unknown_fields)]
8#[cfg_attr(
9 feature = "wasm",
10 derive(tsify::Tsify),
11 tsify(into_wasm_abi, from_wasm_abi)
12)]
13#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
14#[derive(Debug)]
15pub struct SendAccessTokenResponse {
16 /// The actual token string.
17 pub token: String,
18 /// The timestamp in milliseconds when the token expires.
19 pub expires_at: i64,
20}
21
22impl From<SendAccessTokenApiSuccessResponse> for SendAccessTokenResponse {
23 fn from(response: SendAccessTokenApiSuccessResponse) -> Self {
24 // We want to convert the expires_in from seconds to a millisecond timestamp to have a
25 // concrete time the token will expire as it is easier to build logic around a
26 // concrete time rather than a duration.
27 let expires_at =
28 chrono::Utc::now().timestamp_millis() + (response.expires_in * 1000) as i64;
29
30 SendAccessTokenResponse {
31 token: response.access_token,
32 expires_at,
33 }
34 }
35}
36
37// We're using the full variant of the bitwarden-error macro because we want to keep the contents of
38// SendAccessTokenApiErrorResponse
39#[bitwarden_error::bitwarden_error(full)]
40#[derive(Debug, thiserror::Error)]
41#[serde(tag = "kind", content = "data", rename_all = "lowercase")]
42/// Represents errors that can occur when requesting a send access token.
43/// It includes expected and unexpected API errors.
44pub enum SendAccessTokenError {
45 #[error("Unexpected Error response: {0:?}")]
46 /// Represents an unexpected error that occurred during the request.
47 /// This would typically be a transport-level error, such as network issues or serialization
48 /// problems.
49 Unexpected(UnexpectedIdentityError),
50
51 #[error("Expected error response")]
52 /// Represents an expected error response from the API.
53 Expected(SendAccessTokenApiErrorResponse),
54}
55
56// This is just a utility function so that the ? operator works correctly without manual mapping
57impl From<reqwest::Error> for SendAccessTokenError {
58 fn from(value: reqwest::Error) -> Self {
59 Self::Unexpected(UnexpectedIdentityError(format!("{value:?}")))
60 }
61}
62
63/// Any unexpected error that occurs when making requests to identity. This could be
64/// local/transport/decoding failure from the HTTP client (DNS/TLS/connect/read timeout,
65/// connection reset, or JSON decode failure on a success response) or non-2xx response with an
66/// unexpected body or status. Used when decoding the server's error payload into
67/// `SendAccessTokenApiErrorResponse` fails, or for 5xx responses where no structured error is
68/// available.
69#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
70#[serde(transparent)]
71#[cfg_attr(
72 feature = "wasm",
73 derive(tsify::Tsify),
74 tsify(into_wasm_abi, from_wasm_abi)
75)]
76pub struct UnexpectedIdentityError(pub String);
77
78// Newtype wrapper for unexpected identity errors for uniffi compatibility.
79#[cfg(feature = "uniffi")] // only compile this when uniffi feature is enabled
80uniffi::custom_newtype!(UnexpectedIdentityError, String);