use clap::Parser as _;
use secrecy::{ExposeSecret as _, SecretString};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, clap::Parser)]
#[clap(
name = "sl_map_web_register",
about = "Emulate the LSL registration object against a local sl-map-web instance.",
author = clap::crate_authors!(),
version = clap::crate_version!()
)]
struct Args {
#[clap(long, env = "SL_MAP_WEB_URL")]
server_url: String,
#[clap(
long,
env = "SL_MAP_WEB_LSL_REGISTRATION_BEARER_TOKEN",
hide_env_values = true,
value_parser = parse_secret_string,
)]
bearer_token: SecretString,
#[clap(long)]
agent_key: Uuid,
#[clap(long)]
legacy_name: String,
#[clap(long)]
username: String,
}
#[derive(Debug, Serialize)]
struct RegisterRequest {
agent_key: Uuid,
legacy_name: String,
username: String,
}
#[derive(Debug, Deserialize)]
struct RegisterResponse {
set_password_url: String,
expires_at: String,
}
#[derive(thiserror::Error, Debug)]
enum Error {
#[error("HTTP error: {0}")]
Http(#[from] reqwest::Error),
#[error("server returned HTTP {status}: {body}")]
Status {
status: reqwest::StatusCode,
body: String,
},
}
fn main() {
if let Err(err) = run() {
eprintln!("{err}");
std::process::exit(1);
}
}
fn parse_secret_string(s: &str) -> Result<SecretString, std::convert::Infallible> {
Ok(SecretString::from(s.to_owned()))
}
fn run() -> Result<(), Error> {
let args = Args::parse();
let url = format!(
"{}/api/auth/register",
args.server_url.trim_end_matches('/')
);
let body = RegisterRequest {
agent_key: args.agent_key,
legacy_name: args.legacy_name,
username: args.username,
};
let client = reqwest::blocking::Client::new();
let response = client
.post(&url)
.bearer_auth(args.bearer_token.expose_secret())
.json(&body)
.send()?;
let status = response.status();
if !status.is_success() {
let body = response.text().unwrap_or_default();
return Err(Error::Status { status, body });
}
let parsed: RegisterResponse = response.json()?;
println!("set-password URL: {}", parsed.set_password_url);
println!("expires at: {}", parsed.expires_at);
Ok(())
}