From 06b1533c226627950b57dc7c71a2d9baede85707 Mon Sep 17 00:00:00 2001 From: Cara Salter Date: Tue, 28 Jun 2022 16:45:16 -0400 Subject: auth: Login command and user authentication --- .envrc | 1 - Cargo.lock | 43 ++++++++++++++++++++++++++++++++++++++ Cargo.toml | 9 ++++++++ src/main.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 120 insertions(+), 2 deletions(-) delete mode 100644 .envrc diff --git a/.envrc b/.envrc deleted file mode 100644 index 3550a30..0000000 --- a/.envrc +++ /dev/null @@ -1 +0,0 @@ -use flake diff --git a/Cargo.lock b/Cargo.lock index d9ccd96..fa9359e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -173,6 +173,26 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "either" version = "1.6.1" @@ -838,6 +858,17 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -1038,9 +1069,12 @@ dependencies = [ "color-eyre", "eyre", "reqwest", + "serde", + "serde_json", "solarlib", "tabular", "thiserror", + "xdg", ] [[package]] @@ -1521,3 +1555,12 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] + +[[package]] +name = "xdg" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4583db5cbd4c4c0303df2d15af80f0539db703fa1c68802d4cbbd2dd0f88f6" +dependencies = [ + "dirs", +] diff --git a/Cargo.toml b/Cargo.toml index 29629f2..7cf3e27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,9 @@ eyre = "0.6" tabular = "0.2" +xdg = "2" +serde_json = "1" + [dependencies.solarlib] git = "https://git.carathe.dev/solard/solarlib" branch = "master" @@ -29,3 +32,9 @@ features = [ "blocking", "json" ] + +[dependencies.serde] +version = "1" +features = [ + "derive" +] diff --git a/src/main.rs b/src/main.rs index e629d0d..70fd438 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,15 @@ +use std::fs; use std::process::Command; use clap::Parser; mod errors; use errors::CliError; +use reqwest::header; use tabular::{row, Table}; use reqwest::{blocking::Client, StatusCode}; use solarlib::planet::{Planet, Memory, CpuCount}; use solarlib::star::NewPlanet; +use serde::{Serialize, Deserialize}; /// Manage solard and homeworld instances #[derive(Parser)] @@ -19,6 +22,11 @@ struct Args { action: Action } +#[derive(Serialize, Deserialize)] +struct ServerConfig { + pub token: String +} + #[derive(clap::Subcommand)] enum Action { /// List planets on the server @@ -60,13 +68,33 @@ enum Action { /// The Sha256 hash of the ship ship: String + }, + + /// Goes through the first-time authentication process to create a token that expires after one + /// year, storing it in the process. + Login { + key: String } } fn main() { color_eyre::install().unwrap(); let args = Args::parse(); - let client = reqwest::blocking::Client::new(); + let xdg_dirs = xdg::BaseDirectories::with_profile("solarctl", args.server.clone()).unwrap(); + + let mut headers = header::HeaderMap::new(); + + if let Some(p) = xdg_dirs.find_config_file("config.json") { + let c = fs::read_to_string(p).unwrap(); + if let Ok(cfg) = serde_json::from_str::(&c) { + headers.insert(header::AUTHORIZATION, header::HeaderValue::from_str(&cfg.token).unwrap()); + } + + } else { + println!("No config file found! You will need to authenticate with the `login` subcommand"); + } + + let client = reqwest::blocking::ClientBuilder::new().default_headers(headers).build().unwrap(); let root = args.server.clone(); @@ -91,6 +119,9 @@ fn main() { }, Action::Create { max_mem, max_cpus, disk_size_mb, name, ship } => { create(root, client, max_mem, max_cpus, disk_size_mb, name, ship).unwrap(); + }, + Action::Login { key } => { + login(root, client, key); } }; } @@ -233,3 +264,39 @@ fn create(s: String, c: Client, mem: u64, cpus: u64, disk_size: u64, name: Strin Ok(()) } + +fn login(s: String, c: Client, k: String) -> Result<(), CliError> { + let url = format!("http://{}/auth/begin?key={}", s, k); + + println!("Obtaining token..."); + let res = c.post(url).send()?; + + match res.status() { + StatusCode::OK => { + let token = res.text()?; + let xdg_dirs = xdg::BaseDirectories::with_profile("solarctl", s).unwrap(); + + if let Some(p) = xdg_dirs.find_config_file("config.json") { + let cfg = ServerConfig { + token + }; + + fs::write(p, serde_json::to_string_pretty(&cfg).unwrap()).unwrap(); + + } else { + let p = xdg_dirs.place_config_file("config.json").unwrap(); + let cfg = ServerConfig { + token + }; + + fs::write(p, serde_json::to_string_pretty(&cfg).unwrap()).unwrap(); + } + + }, + _ => { + return Err(CliError::Cli(format!("Could not authenticate: {}", res.text()?))); + } + }; + + Ok(()) +} -- cgit v1.2.3