LibreAuth SDK Docs
Nut.exe
Rust 84 lines · 2,765 bytes
use reqwest::blocking::Client;
use serde_json::{json, Value};
use std::collections::HashMap;

pub struct LibreAuth {
    pub name: String,
    pub owner_id: String,
    pub version: String,
    pub url: String,
    pub session_id: Option<String>,
    pub enckey: Option<String>,
}

impl LibreAuth {
    pub fn new(name: &str, owner_id: &str, version: &str, url: &str) -> Self {
        Self {
            name: name.to_string(),
            owner_id: owner_id.to_string(),
            version: version.to_string(),
            url: format!("{}/", url.trim_end_matches('/')),
            session_id: None,
            enckey: None,
        }
    }

    pub fn init(&mut self) -> Result<Value, String> {
        let enc: String = (0..35).map(|_| format!("{:x}", rand::random::<u8>() % 16)).collect();
        self.enckey = Some(enc.clone());
        let res = self.req(&[
            ("type", "init"),
            ("ver", &self.version),
            ("enckey", &enc),
        ])?;
        if !res["success"].as_bool().unwrap_or(false) {
            return Err(res["message"].as_str().unwrap_or("init failed").to_string());
        }
        self.session_id = Some(res["sessionid"].as_str().unwrap_or("").to_string());
        Ok(res)
    }

    pub fn login(&self, user: &str, pass: &str, hwid: &str) -> Result<Value, String> {
        self.auth(&[
            ("type", "login"),
            ("username", user),
            ("pass", pass),
            ("hwid", hwid),
        ])
    }

    pub fn license(&self, key: &str, hwid: &str) -> Result<Value, String> {
        self.auth(&[("type", "license"), ("key", key), ("hwid", hwid)])
    }

    pub fn token(&self, token: &str, hwid: &str) -> Result<Value, String> {
        self.auth(&[("type", "token"), ("token", token), ("hwid", hwid)])
    }

    fn auth(&self, extra: &[(&str, &str)]) -> Result<Value, String> {
        let res = self.req(extra)?;
        if !res["success"].as_bool().unwrap_or(false) {
            return Err(res["message"].as_str().unwrap_or("auth failed").to_string());
        }
        Ok(res["info"].clone())
    }

    fn req(&self, extra: &[(&str, &str)]) -> Result<Value, String> {
        let client = Client::new();
        let mut form: HashMap<&str, &str> = HashMap::new();
        form.insert("name", &self.name);
        form.insert("ownerid", &self.owner_id);
        if let Some(ref sid) = self.session_id {
            form.insert("sessionid", sid);
        }
        for (k, v) in extra {
            form.insert(k, v);
        }
        let resp = client.post(&self.url).form(&form).send().map_err(|e| e.to_string())?;
        if resp.status().as_u16() == 429 {
            return Err("Rate limited".into());
        }
        resp.json().map_err(|e| e.to_string())
    }
}