1use std::fmt::{Debug, Display, Formatter};
2use std::str::FromStr;
3use std::{fmt, net};
4
5use ipnetwork;
6use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
7use thiserror::Error;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct AccountInfo {
11 pub id: String,
12 pub active: bool,
13 pub top_up: Option<TopUp>,
14 pub subscription: Option<Subscription>,
15}
16
17#[derive(Debug, Serialize, Deserialize, Clone)]
18pub struct TopUp {
19 pub credit_expires_at: i64,
20}
21
22#[derive(Debug, Serialize, Deserialize, Clone)]
23pub struct Subscription {
24 status: String,
26 current_period_start: i64,
28 current_period_end: i64,
30 cancel_at_period_end: bool,
32}
33
34impl Subscription {
35 pub fn new(status: String, current_period_start: i64, current_period_end: i64, cancel_at_period_end: bool) -> Self {
36 Self {
37 status,
38 current_period_start,
39 current_period_end,
40 cancel_at_period_end,
41 }
42 }
43}
44
45#[derive(Serialize, Deserialize, Clone, Debug)]
46pub struct OneTunnel {
47 pub id: String,
48 pub status: TunnelStatus,
49 pub config: TunnelConfig,
50 pub relay: OneRelay,
51 pub exit: OneExit,
52}
53
54#[derive(Serialize, Deserialize, Clone, Debug)]
55#[serde(tag = "type", rename_all = "snake_case")]
56pub enum TunnelStatus {
57 Created { when: i64 },
58 Connected { when: i64 },
59 Disconnected { when: i64 },
60}
61
62#[derive(Serialize, Deserialize, Clone, Debug)]
63#[serde(tag = "type", rename_all = "snake_case")]
64pub enum TunnelConfig {
65 UdpPort { client: WgClientConfig, server: WgServerConfig },
66 Obfuscated(ObfuscatedTunnelConfig),
67}
68
69#[derive(Serialize, Deserialize, Clone, Debug)]
70pub struct WgClientConfig {
71 pub wg_pubkey: WgPubkey,
72 pub addresses: Vec<ipnetwork::IpNetwork>,
73}
74
75#[derive(Serialize, Deserialize, Clone, Debug)]
76pub struct WgServerConfig {
77 pub wg_pubkey: WgPubkey,
78 pub endpoints: Vec<net::SocketAddr>,
79 pub dnses: Vec<net::IpAddr>,
80}
81
82#[derive(Serialize, Deserialize, Clone, Debug)]
83pub struct ObfuscatedTunnelConfig {
84 pub client_pubkey: WgPubkey,
85 pub client_ips_v4: Vec<ipnetwork::Ipv4Network>,
86 pub client_ips_v6: Vec<ipnetwork::Ipv6Network>,
87 pub dns: Vec<net::IpAddr>,
88 pub relay_addr_v4: net::SocketAddrV4,
89 pub relay_addr_v6: net::SocketAddrV6,
90 pub relay_cert: String,
91 pub exit_pubkey: WgPubkey,
92}
93
94const WG_PUBKEY_LENGTH: usize = 32;
95#[derive(Deserialize, Clone, Eq, PartialEq)]
96pub struct WgPubkey(#[serde(deserialize_with = "deserialize_base64")] pub [u8; WG_PUBKEY_LENGTH]);
97
98impl std::fmt::Debug for WgPubkey {
99 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
100 use base64::{engine::general_purpose::STANDARD, Engine as _};
101 f.debug_tuple("WgPubKey").field(&STANDARD.encode(self.0)).finish()
102 }
103}
104
105#[derive(Error, Debug)]
106pub enum ParseWgPubkeyError {
107 #[error("expected {} bytes, found {}", WG_PUBKEY_LENGTH, .0)]
108 InvalidLength(usize),
109 #[error("base64 decode err: {:?}", .0)]
110 NotBase64(#[from] base64::DecodeError),
111}
112
113impl FromStr for WgPubkey {
114 type Err = ParseWgPubkeyError;
115 fn from_str(s: &str) -> Result<Self, Self::Err> {
116 use base64::{engine::general_purpose::STANDARD, Engine as _};
117 let decoded = STANDARD.decode(s)?;
118 let bytes = decoded.try_into().map_err(|d: Vec<u8>| ParseWgPubkeyError::InvalidLength(d.len()))?;
119 Ok(WgPubkey(bytes))
120 }
121}
122
123impl Display for WgPubkey {
124 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
125 use base64::{display::Base64Display, engine::general_purpose::STANDARD};
126 Base64Display::new(&self.0, &STANDARD).fmt(f)
127 }
128}
129
130impl Serialize for WgPubkey {
131 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
132 where
133 S: Serializer,
134 {
135 serializer.serialize_str(&self.to_string())
136 }
137}
138
139fn deserialize_base64<'de, D>(deserializer: D) -> Result<[u8; WG_PUBKEY_LENGTH], D::Error>
140where
141 D: Deserializer<'de>,
142{
143 let encoded = String::deserialize(deserializer)?;
144 match WgPubkey::from_str(&encoded) {
145 Ok(pk) => Ok(pk.0),
146 Err(ParseWgPubkeyError::InvalidLength(n)) => {
147 let error_string = format!("a base64 string representing {} bytes", WG_PUBKEY_LENGTH);
148 Err(D::Error::invalid_length(n, &error_string.as_str()))
149 }
150 Err(ParseWgPubkeyError::NotBase64(err)) => Err(D::Error::custom(err)),
151 }
152}
153
154#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
155pub struct OneRelay {
156 pub id: String,
157 pub ip_v4: net::Ipv4Addr,
158 pub ip_v6: net::Ipv6Addr,
159}
160
161#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
162pub struct OneExit {
163 pub id: String,
164 pub country_code: String,
165 pub city_name: String,
166}
167
168#[derive(Serialize, Deserialize, Clone, Debug)]
169pub struct Prices {
170 pub subscription: Vec<Price>,
171 pub top_up: Vec<Price>,
172
173 pub sale: Option<Sale>,
177}
178
179#[derive(Serialize, Deserialize, Clone, Debug)]
180pub struct Price {
181 pub months: u16,
182 pub usd_cents: u32,
183
184 pub regular_usd_cents: u32,
187
188 pub sale: Option<Sale>,
189}
190
191#[derive(Serialize, Deserialize, Clone, Debug)]
192pub struct Sale {
193 pub title: String,
195
196 pub summary: String,
198}
199
200#[test]
201fn serde_wg_enc_dec() {
202 let pk = WgPubkey([
203 197, 50, 1, 3, 154, 219, 161, 75, 231, 31, 136, 109, 161, 216, 219, 233, 238, 189, 237, 8, 203, 17, 27, 117, 52, 0, 120, 153, 154, 169, 240,
204 56,
205 ]);
206
207 let json = "\"xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=\"";
208 let pk_from_json: WgPubkey = serde_json::from_str(json).unwrap();
209 assert_eq!(pk_from_json, pk);
210 let json_from_pk = serde_json::to_string(&pk).unwrap();
211 assert_eq!(json_from_pk, json);
212
213 let base64 = &json[1..json.len() - 1];
214 let pk_from_base64: WgPubkey = base64.parse().unwrap();
215 assert_eq!(pk_from_base64, pk);
216 let base64_from_pk = pk.to_string();
217 assert_eq!(base64_from_pk, base64);
218}
219
220#[derive(Clone, PartialEq, Eq)]
221pub struct AuthToken(String);
222
223impl AuthToken {
224 pub fn as_str(&self) -> &str {
225 &self.0
226 }
227}
228
229impl Debug for AuthToken {
230 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
231 f.debug_tuple("AuthToken").field(&format_args!("_")).finish()
232 }
233}
234
235impl From<String> for AuthToken {
236 fn from(s: String) -> Self {
237 Self(s)
238 }
239}
240
241impl From<AuthToken> for String {
242 fn from(value: AuthToken) -> Self {
243 value.0
244 }
245}