obscuravpn_api/
check.rs

1use serde::{Deserialize, Serialize};
2use url::Url;
3
4#[derive(Debug, Serialize, Deserialize, Clone)]
5pub struct Check {
6    // The requesting IP is an implicit parameter.
7}
8
9#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
10#[non_exhaustive]
11pub enum IpType {
12    Mullvad,
13
14    /// We don't know about this IP address.
15    Unknown,
16
17    /// Catch-all, never returned but let's old clients parse new responses.
18    ///
19    /// This means the server could identify the IP but the client doesn't know about this new type.
20    #[serde(other)]
21    Other,
22}
23
24#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
25pub struct CheckResult {
26    /// The user is using an exit that may be Obscura traffic.
27    ///
28    /// Either way the user is not coming from an unknown IP range.
29    pub is_safe: bool,
30
31    pub ip: String,
32    pub ip_type: IpType,
33}
34
35impl Check {
36    pub fn to_request(&self, base_url: impl AsRef<str>) -> anyhow::Result<http::Request<()>> {
37        let url = Url::parse(base_url.as_ref())?.join("check")?;
38        Ok(http::Request::get(url.as_str()).body(())?)
39    }
40}
41
42#[test]
43fn check_err_json() {
44    assert_eq!(
45        serde_json::to_string(&CheckResult {
46            is_safe: true,
47            ip: "10.0.1.2".into(),
48            ip_type: IpType::Mullvad
49        })
50        .unwrap(),
51        r#"{"is_safe":true,"ip":"10.0.1.2","ip_type":"Mullvad"}"#,
52    );
53
54    assert_eq!(
55        serde_json::from_str::<CheckResult>(
56            r#"
57            {
58                "is_safe": false,
59                "ip": "10.9.8.7",
60                "ip_type": "Unknown"
61            }
62        "#
63        )
64        .unwrap(),
65        CheckResult {
66            is_safe: false,
67            ip: "10.9.8.7".into(),
68            ip_type: IpType::Unknown
69        }
70    );
71
72    assert_eq!(
73        serde_json::from_str::<CheckResult>(
74            r#"
75            {
76                "is_safe": false,
77                "ip": "127.0.0.1",
78                "ip_type": "NewValue"
79            }
80        "#
81        )
82        .unwrap(),
83        CheckResult {
84            is_safe: false,
85            ip: "127.0.0.1".into(),
86            ip_type: IpType::Other
87        }
88    );
89}