Initial commit

This commit is contained in:
Andrey Golovizin 2021-06-26 13:18:19 +02:00
commit ae9fca20ee
8 changed files with 821 additions and 0 deletions

143
src/main.rs Normal file
View file

@ -0,0 +1,143 @@
use std::io::Write;
use std::net::ToSocketAddrs;
use std::process;
use clap::Clap;
use serde::{Deserialize, Serialize};
const BASE_URL: &str = "https://api.azirevpn.com/v1";
#[derive(Clap, Debug)]
struct Opts {
#[clap(subcommand)]
command: Command,
}
#[derive(Clap, Debug)]
struct GetConfigOpts {
location: String,
username: String,
token: String,
}
#[derive(Clap, Debug)]
enum Command {
List,
GetConfig(GetConfigOpts),
}
#[derive(Serialize, Deserialize, Debug)]
struct Endpoints {
wireguard: String,
}
#[derive(Serialize, Deserialize, Debug)]
struct Location {
name: String,
city: String,
country: String,
iso: String,
endpoints: Endpoints,
}
#[derive(Serialize, Deserialize, Debug)]
struct Locations {
locations: Vec<Location>,
}
#[derive(Serialize, Deserialize, Debug)]
struct WireguardConfig {
status: String,
data: WireguardConfigData,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
struct WireguardConfigData {
public_key: String,
address: String,
endpoint: String,
}
#[derive(Debug)]
struct WireguardKeyPair {
public_key: String,
private_key: String,
}
fn main() -> Result<(), anyhow::Error> {
let opts = Opts::parse();
match opts.command {
Command::List => list()?,
Command::GetConfig(get_config_opts) => get_config(&get_config_opts)?,
}
Ok(())
}
fn list() -> Result<(), anyhow::Error> {
let locations: Locations = get_locations()?;
println!("{:?}", &locations);
Ok(())
}
fn get_locations() -> Result<Locations, anyhow::Error> {
let url = format!("{}/locations", BASE_URL);
let locations: Locations = ureq::get(&url).call()?.into_json()?;
Ok(locations)
}
fn get_config(opts: &GetConfigOpts) -> Result<(), anyhow::Error> {
let locations = get_locations()?;
let location = locations
.locations
.iter()
.find(|location| location.name == opts.location)
.ok_or_else(|| anyhow::anyhow!("no such location"))?;
dbg!(&location);
let keys = generage_keys()?;
dbg!(&keys);
let config: WireguardConfig = ureq::post(&location.endpoints.wireguard)
.send_form(&[
("username", &opts.username),
("token", &opts.token),
("pubkey", &keys.public_key),
])?
.into_json()?;
dbg!(&config);
let mut endpoint_addrs = config.data.endpoint.to_socket_addrs()?;
let endpoint_addr = endpoint_addrs
.next()
.ok_or_else(|| anyhow::anyhow!("no endpoint address received"))?;
dbg!(&endpoint_addr);
println!(
r"[Interface]
PrivateKey = {}
Address = {}
[Peer]
PublicKey = {}
Endpoint = {}
AllowedIPs = 0.0.0.0/0 #, ::/0",
&keys.private_key, &config.data.address, &config.data.public_key, &endpoint_addr
);
Ok(())
}
fn generage_keys() -> Result<WireguardKeyPair, anyhow::Error> {
let privkey = process::Command::new("wg").arg("genkey").output()?.stdout;
let mut pubkey_cmd = process::Command::new("wg")
.arg("pubkey")
.stdin(process::Stdio::piped())
.stdout(process::Stdio::piped())
.spawn()?;
pubkey_cmd
.stdin
.as_mut()
.expect("no stdin")
.write_all(&privkey)?;
let pubkey = pubkey_cmd.wait_with_output()?.stdout;
Ok(WireguardKeyPair {
private_key: String::from_utf8(privkey)?.trim_end().to_string(),
public_key: String::from_utf8(pubkey)?.trim_end().to_string(),
})
}