Java
172 lines · 6,227 bytes
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
public class LibreAuth {
public String name;
public String ownerid;
public String version;
public String url;
public String sessionid;
public String enckey;
public String hash;
public LibreAuth(String name, String ownerid, String version, String url) {
this.name = name;
this.ownerid = ownerid;
this.version = version;
this.url = url.endsWith("/") ? url : url + "/";
}
public Map<String, Object> init() throws Exception {
if (enckey == null || enckey.isEmpty()) {
enckey = randomHex(18).substring(0, 35);
}
Map<String, String> data = base();
data.put("type", "init");
data.put("ver", version);
data.put("enckey", enckey);
if (hash != null && !hash.isEmpty()) data.put("hash", hash);
Map<String, Object> res = req(data);
if (!Boolean.TRUE.equals(res.get("success"))) {
throw new Exception(String.valueOf(res.get("message")));
}
sessionid = String.valueOf(res.get("sessionid"));
return res;
}
public Map<String, Object> login(String user, String pass, String hwid) throws Exception {
Map<String, String> data = base();
data.put("type", "login");
data.put("username", user);
data.put("pass", pass);
data.put("hwid", hwid == null ? "" : hwid);
return auth(data);
}
public Map<String, Object> license(String key, String hwid) throws Exception {
Map<String, String> data = base();
data.put("type", "license");
data.put("key", key);
data.put("hwid", hwid == null ? "" : hwid);
return auth(data);
}
public Map<String, Object> register(String user, String pass, String key, String hwid) throws Exception {
Map<String, String> data = base();
data.put("type", "register");
data.put("username", user);
data.put("pass", pass);
data.put("key", key);
data.put("hwid", hwid == null ? "" : hwid);
return auth(data);
}
private Map<String, Object> auth(Map<String, String> data) throws Exception {
Map<String, Object> res = req(data);
if (!Boolean.TRUE.equals(res.get("success"))) {
throw new Exception(String.valueOf(res.get("message")));
}
Object info = res.get("info");
if (info instanceof Map) return (Map<String, Object>) info;
return res;
}
private Map<String, String> base() {
Map<String, String> data = new LinkedHashMap<>();
data.put("name", name);
data.put("ownerid", ownerid);
if (sessionid != null && !sessionid.isEmpty()) data.put("sessionid", sessionid);
return data;
}
@SuppressWarnings("unchecked")
private Map<String, Object> req(Map<String, String> data) throws Exception {
String body = encode(data);
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
try (OutputStream os = conn.getOutputStream()) {
os.write(body.getBytes(StandardCharsets.UTF_8));
}
if (conn.getResponseCode() == 429) throw new Exception("Rate limited");
InputStream stream = conn.getResponseCode() >= 400 ? conn.getErrorStream() : conn.getInputStream();
String raw = readStream(stream);
return parseJson(raw);
}
private static String encode(Map<String, String> data) throws UnsupportedEncodingException {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> e : data.entrySet()) {
if (sb.length() > 0) sb.append('&');
sb.append(URLEncoder.encode(e.getKey(), "UTF-8"));
sb.append('=');
sb.append(URLEncoder.encode(e.getValue(), "UTF-8"));
}
return sb.toString();
}
private static String readStream(InputStream in) throws IOException {
if (in == null) return "{}";
ByteArrayOutputStream buf = new ByteArrayOutputStream();
byte[] tmp = new byte[4096];
int n;
while ((n = in.read(tmp)) != -1) buf.write(tmp, 0, n);
return buf.toString(StandardCharsets.UTF_8.name());
}
@SuppressWarnings("unchecked")
private static Map<String, Object> parseJson(String raw) {
raw = raw.trim();
Map<String, Object> out = new LinkedHashMap<>();
if (!raw.startsWith("{")) return out;
raw = raw.substring(1, raw.length() - 1).trim();
if (raw.isEmpty()) return out;
for (String part : splitTop(raw)) {
int c = part.indexOf(':');
if (c < 1) continue;
String k = strip(part.substring(0, c));
String v = strip(part.substring(c + 1));
if (v.startsWith("{")) {
out.put(k, parseJson("{" + v + "}"));
} else {
out.put(k, v);
}
}
return out;
}
private static List<String> splitTop(String s) {
List<String> parts = new ArrayList<>();
int depth = 0, start = 0;
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (ch == '{') depth++;
else if (ch == '}') depth--;
else if (ch == ',' && depth == 0) {
parts.add(s.substring(start, i));
start = i + 1;
}
}
parts.add(s.substring(start));
return parts;
}
private static String strip(String s) {
s = s.trim();
if (s.startsWith("\"") && s.endsWith("\"")) return s.substring(1, s.length() - 1);
return s;
}
private static String randomHex(int len) {
Random r = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < len; i++) sb.append(Integer.toHexString(r.nextInt(16)));
return sb.toString();
}
}