Migrate to API v3

This commit is contained in:
Andrey Golovizin 2024-03-09 15:58:37 +01:00
parent 4946ec2228
commit 33a60aa4c9
3 changed files with 44 additions and 54 deletions

View file

@ -9,14 +9,20 @@ use crate::keys::Key;
const BASE_URL: &str = "https://api.azirevpn.com"; const BASE_URL: &str = "https://api.azirevpn.com";
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub(crate) struct CheckResult { pub(crate) struct CheckResponse {
pub status: String,
pub data: CheckData,
}
#[derive(Serialize, Deserialize, Debug)]
pub(crate) struct CheckData {
pub connected: bool, pub connected: bool,
pub ip: String, // XXX pub ip: String, // XXX
pub location: Option<String>, pub location: Option<String>,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub(crate) struct Locations { pub(crate) struct LocationsResponse {
pub status: String, pub status: String,
pub locations: Vec<Location>, pub locations: Vec<Location>,
} }
@ -41,46 +47,47 @@ impl Location {
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub(crate) struct Addresses { pub(crate) struct AddressResponse {
pub status: String, pub status: String,
pub ipv4: WireguardConfigIpv4, pub data: AddressData,
pub ipv6: WireguardConfigIpv6, }
#[derive(Serialize, Deserialize, Debug)]
pub(crate) struct AddressData {
pub ipv4_address: Ipv4Addr,
pub ipv4_netmask: u8,
pub ipv6_address: Ipv6Addr,
pub ipv6_netmask: u8,
pub dns: Vec<IpAddr>, pub dns: Vec<IpAddr>,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub(crate) struct WireguardConfigIpv4 { pub(crate) struct AddIpRequest<'a> {
pub address: Ipv4Addr, pub key: &'a str,
pub netmask: u8,
}
#[derive(Serialize, Deserialize, Debug)]
pub(crate) struct WireguardConfigIpv6 {
pub address: Ipv6Addr,
pub netmask: u8,
} }
pub(crate) fn check() -> anyhow::Result<CheckResult> { pub(crate) fn check() -> anyhow::Result<CheckData> {
let url = format!("{}/v1/check", BASE_URL); let url = format!("{}/v3/check", BASE_URL);
let response: CheckResult = ureq::get(&url).call()?.into_json()?; let response: CheckResponse = ureq::get(&url).call()?.into_json()?;
debug!("response = {:?}", &response); debug!("response = {:?}", &response);
Ok(response) Ok(response.data)
} }
pub(crate) fn get_locations() -> anyhow::Result<Locations> { pub(crate) fn get_locations() -> anyhow::Result<Vec<Location>> {
let url = format!("{}/v2/locations", BASE_URL); let url = format!("{}/v3/locations", BASE_URL);
let response: Locations = ureq::get(&url).call()?.into_json()?; let response: LocationsResponse = ureq::get(&url).call()?.into_json()?;
debug!("response = {:?}", &response); debug!("response = {:?}", &response);
Ok(response) Ok(response.locations)
} }
pub(crate) fn add_ip(username: &str, token: &str, public_key: &Key) -> anyhow::Result<Addresses> { pub(crate) fn add_ip(token: &str, public_key: &Key) -> anyhow::Result<AddressData> {
let url = format!("{}/v2/ip/add", BASE_URL); let url = format!("{}/v3/ips", BASE_URL);
let response: Addresses = ureq::post(&url) let authorization = format!("Bearer {token}");
.send_form(&[ let request = AddIpRequest {
("username", username), key: &public_key.to_base64(),
("token", token), };
("key", &public_key.to_base64()), let response: AddressResponse = ureq::post(&url)
])? .set("Authorization", &authorization)
.send_json(&request)?
.into_json()?; .into_json()?;
debug!("response = {:?}", &response); debug!("response = {:?}", &response);
Ok(response) Ok(response.data)
} }

View file

@ -43,10 +43,6 @@ impl MachineConfig {
Ok(()) Ok(())
} }
pub(crate) fn username(&self) -> anyhow::Result<String> {
Ok(std::fs::read_to_string(self.username_path())?)
}
pub(crate) fn token(&self) -> anyhow::Result<String> { pub(crate) fn token(&self) -> anyhow::Result<String> {
Ok(std::fs::read_to_string(self.token_path())?) Ok(std::fs::read_to_string(self.token_path())?)
} }
@ -60,11 +56,6 @@ impl MachineConfig {
Key::try_from_base64(key_data.trim_end()) Key::try_from_base64(key_data.trim_end())
} }
pub(crate) fn save_username(&self, username: &str) -> anyhow::Result<()> {
std::fs::write(self.username_path(), username)?;
Ok(())
}
pub(crate) fn save_token(&self, token: &str) -> anyhow::Result<()> { pub(crate) fn save_token(&self, token: &str) -> anyhow::Result<()> {
std::fs::write(self.token_path(), token)?; std::fs::write(self.token_path(), token)?;
Ok(()) Ok(())
@ -80,10 +71,6 @@ impl MachineConfig {
&self.path &self.path
} }
fn username_path(&self) -> PathBuf {
self.path().join("username")
}
fn token_path(&self) -> PathBuf { fn token_path(&self) -> PathBuf {
self.path().join("token") self.path().join("token")
} }

View file

@ -31,7 +31,6 @@ struct Opts {
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
struct LoginOpts { struct LoginOpts {
username: String,
token: String, token: String,
} }
@ -79,7 +78,6 @@ fn main() -> Result<(), anyhow::Error> {
fn login(opts: &Opts, login_opts: &LoginOpts) -> Result<(), anyhow::Error> { fn login(opts: &Opts, login_opts: &LoginOpts) -> Result<(), anyhow::Error> {
let machine_config = config::MachineConfig::new(opts.machine.as_ref())?; let machine_config = config::MachineConfig::new(opts.machine.as_ref())?;
machine_config.save_username(&login_opts.username)?;
machine_config.save_token(&login_opts.token)?; machine_config.save_token(&login_opts.token)?;
Ok(()) Ok(())
} }
@ -109,7 +107,7 @@ fn list_locations(opts: &Opts) -> Result<(), anyhow::Error> {
if opts.json { if opts.json {
println!("{}", serde_json::to_string(&locations)?); println!("{}", serde_json::to_string(&locations)?);
} else { } else {
for (i, location) in locations.locations.iter().enumerate() { for (i, location) in locations.iter().enumerate() {
if i > 0 { if i > 0 {
println!() println!()
}; };
@ -128,16 +126,14 @@ fn get_config(opts: &Opts, config_opts: &ConfigOpts) -> Result<(), anyhow::Error
let machine_config = MachineConfig::new(opts.machine.as_ref())?; let machine_config = MachineConfig::new(opts.machine.as_ref())?;
let locations = api::get_locations()?; let locations = api::get_locations()?;
let location = locations let location = locations
.locations
.iter() .iter()
.find(|location| location.name == config_opts.location) .find(|location| location.name == config_opts.location)
.ok_or_else(|| anyhow::anyhow!("no such location: {}", config_opts.location))?; .ok_or_else(|| anyhow::anyhow!("no such location: {}", config_opts.location))?;
debug!("location = {:?}", &location); debug!("location = {:?}", &location);
let keys = get_keys(&machine_config)?; let keys = get_keys(&machine_config)?;
debug!("keys = {:?}", &keys); debug!("keys = {:?}", &keys);
let username = machine_config.username()?;
let token = machine_config.token()?; let token = machine_config.token()?;
let addresses = api::add_ip(&username, &token, &keys.public_key)?; let addresses = api::add_ip(&token, &keys.public_key)?;
write_config( write_config(
&mut std::io::stdout().lock(), &mut std::io::stdout().lock(),
@ -152,17 +148,17 @@ fn write_config(
output: &mut dyn Write, output: &mut dyn Write,
config_opts: &ConfigOpts, config_opts: &ConfigOpts,
location: &api::Location, location: &api::Location,
config: &api::Addresses, config: &api::AddressData,
keys: &WireguardKeyPair, keys: &WireguardKeyPair,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
writeln!(output, "[Interface]")?; writeln!(output, "[Interface]")?;
writeln!(output, "PrivateKey = {}", &keys.private_key.to_base64())?; writeln!(output, "PrivateKey = {}", &keys.private_key.to_base64())?;
let allowed_addresses = if config_opts.no_ipv6 { let allowed_addresses = if config_opts.no_ipv6 {
vec![IpAddr::V4(config.ipv4.address)] vec![IpAddr::V4(config.ipv4_address)]
} else { } else {
vec![ vec![
IpAddr::V4(config.ipv4.address), IpAddr::V4(config.ipv4_address),
IpAddr::V6(config.ipv6.address), IpAddr::V6(config.ipv6_address),
] ]
}; };
write_list(output, "Address = ", allowed_addresses)?; write_list(output, "Address = ", allowed_addresses)?;