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
use std::net::SocketAddr;
use http::StatusCode;
use log::debug;
use serde::{Deserialize, Serialize};
use url::Url;
use crate::HTTP_HEADER_OLLANA_DEVICE_ID;
pub struct Ollana {
client: reqwest::Client,
url: Url,
}
#[derive(Serialize, Deserialize)]
pub struct AuthorizationResponse {
pub device_id: String,
}
impl AuthorizationResponse {
pub fn new(device_id: String) -> Self {
Self { device_id }
}
}
impl Ollana {
pub fn new(socket_addr: SocketAddr) -> anyhow::Result<Self> {
let url = format!("https://{}", socket_addr);
let url = Url::parse(&url).unwrap();
let client = reqwest::ClientBuilder::new()
.use_rustls_tls()
.danger_accept_invalid_certs(true)
.build()?;
Ok(Self { client, url })
}
/// Checks if a device is authorized to access Ollana API.
///
/// This function sends an HTTP POST request to the `/ollana/api/authorize`
/// endpoint with the specified device ID. If the response status code is
/// `UNAUTHORIZED`, it logs the failure and returns `None`. Otherwise, it parses
/// the JSON response as an `AuthorizationResponse` and returns it wrapped in
/// `Some`.
///
/// # Arguments
///
/// * `device_id`: A `String` representing the unique identifier for a device.
///
/// # Returns
///
/// * An `anyhow::Result<Option<AuthorizationResponse>>` indicating success or failure,
/// with an optional authorization response if the request is successful and authorized.
///
pub async fn check_authorization(
&self,
device_id: String,
) -> anyhow::Result<Option<AuthorizationResponse>> {
let mut uri = self.url.clone();
uri.set_path("ollana/api/authorize");
match self
.client
.post(uri)
.header(HTTP_HEADER_OLLANA_DEVICE_ID, &device_id)
.send()
.await?
{
response if response.status() == StatusCode::UNAUTHORIZED => {
let message = response.text().await?;
debug!(
"Ollana authorization failed for device_id {}: {}",
device_id, message
);
Ok(None)
}
response => response
.json::<AuthorizationResponse>()
.await
.map(Some)
.map_err(anyhow::Error::new),
}
}
}