Add key subcommand to all 31 implementations

- Validate API keys via portal endpoint
- Show key status, tier, expiration with color-coded output
- Add --extend flag to open browser for key renewal
- Update .gitignore for compiled binaries
- Update README with key command documentation
This commit is contained in:
Russell Ballestrini 2025-12-27 11:50:34 -05:00
parent eb5d4ca8bf
commit 5380af54cb
32 changed files with 3140 additions and 70 deletions

116
Un.java
View file

@ -48,6 +48,7 @@ import java.util.Base64;
public class Un {
private static final String API_BASE = "https://api.unsandbox.com";
private static final String PORTAL_BASE = "https://unsandbox.com";
private static final String BLUE = "\033[34m";
private static final String RED = "\033[31m";
private static final String GREEN = "\033[32m";
@ -78,6 +79,8 @@ public class Un {
cmdSession(parsedArgs);
} else if (parsedArgs.command.equals("service")) {
cmdService(parsedArgs);
} else if (parsedArgs.command.equals("key")) {
cmdKey(parsedArgs);
} else if (parsedArgs.sourceFile != null) {
cmdExecute(parsedArgs);
} else {
@ -307,6 +310,108 @@ public class Un {
System.exit(1);
}
private static void cmdKey(Args args) throws Exception {
String apiKey = getApiKey(args.apiKey);
if (args.keyExtend) {
// First validate to get public_key
Map<String, Object> result = validateKey(apiKey);
String publicKey = (String) result.get("public_key");
if (publicKey == null || publicKey.isEmpty()) {
System.err.println(RED + "Error: Could not retrieve public key" + RESET);
System.exit(1);
}
String extendUrl = PORTAL_BASE + "/keys/extend?pk=" + urlEncode(publicKey);
System.out.println(YELLOW + "Opening browser to extend key:" + RESET);
System.out.println(extendUrl);
// Try to open browser
try {
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("mac")) {
Runtime.getRuntime().exec(new String[]{"open", extendUrl});
} else if (os.contains("nix") || os.contains("nux")) {
Runtime.getRuntime().exec(new String[]{"xdg-open", extendUrl});
} else if (os.contains("win")) {
Runtime.getRuntime().exec(new String[]{"rundll32", "url.dll,FileProtocolHandler", extendUrl});
}
} catch (Exception e) {
// Browser opening failed, URL already printed
}
return;
}
// Default: validate key
Map<String, Object> result = validateKey(apiKey);
Boolean expired = (Boolean) result.get("expired");
String publicKey = (String) result.get("public_key");
String tier = (String) result.get("tier");
String status = (String) result.get("status");
String expiresAt = (String) result.get("expires_at");
String timeRemaining = (String) result.get("time_remaining");
Object rateLimit = result.get("rate_limit");
Object burst = result.get("burst");
Object concurrency = result.get("concurrency");
if (expired != null && expired) {
System.out.println(RED + "Expired" + RESET);
System.out.println("Public Key: " + (publicKey != null ? publicKey : "N/A"));
System.out.println("Tier: " + (tier != null ? tier : "N/A"));
System.out.println("Expired: " + (expiresAt != null ? expiresAt : "N/A"));
System.out.println(YELLOW + "To renew: Visit " + PORTAL_BASE + "/keys/extend" + RESET);
System.exit(1);
}
// Valid key
System.out.println(GREEN + "Valid" + RESET);
System.out.println("Public Key: " + (publicKey != null ? publicKey : "N/A"));
System.out.println("Tier: " + (tier != null ? tier : "N/A"));
System.out.println("Status: " + (status != null ? status : "N/A"));
System.out.println("Expires: " + (expiresAt != null ? expiresAt : "N/A"));
System.out.println("Time Remaining: " + (timeRemaining != null ? timeRemaining : "N/A"));
System.out.println("Rate Limit: " + (rateLimit != null ? rateLimit : "N/A"));
System.out.println("Burst: " + (burst != null ? burst : "N/A"));
System.out.println("Concurrency: " + (concurrency != null ? concurrency : "N/A"));
}
private static Map<String, Object> validateKey(String apiKey) throws Exception {
URL url = new URL(PORTAL_BASE + "/keys/validate");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization", "Bearer " + apiKey);
conn.setRequestProperty("Content-Type", "application/json");
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
int status = conn.getResponseCode();
if (status < 200 || status >= 300) {
String error = readStream(conn.getErrorStream());
// Try to parse error JSON
try {
Map<String, Object> errorJson = parseJson(error);
String reason = (String) errorJson.getOrDefault("error", error);
System.out.println(RED + "Invalid" + RESET);
System.out.println("Reason: " + reason);
} catch (Exception e) {
System.out.println(RED + "Invalid" + RESET);
System.out.println("Reason: " + error);
}
System.exit(1);
}
String response = readStream(conn.getInputStream());
return parseJson(response);
}
private static String urlEncode(String s) {
try {
return URLEncoder.encode(s, "UTF-8");
} catch (UnsupportedEncodingException e) {
return s;
}
}
private static String getApiKey(String argsKey) {
String key = argsKey != null ? argsKey : System.getenv("UNSANDBOX_API_KEY");
if (key == null || key.isEmpty()) {
@ -562,6 +667,9 @@ public class Un {
String serviceSleep = null;
String serviceWake = null;
String serviceDestroy = null;
// Key args
boolean keyExtend = false;
}
private static Args parseArgs(String[] args) {
@ -572,6 +680,8 @@ public class Un {
result.command = "session";
} else if (arg.equals("service")) {
result.command = "service";
} else if (arg.equals("key")) {
result.command = "key";
} else if (arg.equals("-k") || arg.equals("--api-key")) {
result.apiKey = args[++i];
} else if (arg.equals("-n") || arg.equals("--network")) {
@ -613,6 +723,8 @@ public class Un {
result.serviceWake = args[++i];
} else if (arg.equals("--destroy")) {
result.serviceDestroy = args[++i];
} else if (arg.equals("--extend")) {
result.keyExtend = true;
} else if (!arg.startsWith("-")) {
result.sourceFile = arg;
}
@ -624,6 +736,7 @@ public class Un {
System.out.println("Usage: java Un [options] <source_file>");
System.out.println(" java Un session [options]");
System.out.println(" java Un service [options]");
System.out.println(" java Un key [options]");
System.out.println();
System.out.println("Execute options:");
System.out.println(" -e KEY=VALUE Set environment variable");
@ -651,5 +764,8 @@ public class Un {
System.out.println(" --sleep ID Freeze service");
System.out.println(" --wake ID Unfreeze service");
System.out.println(" --destroy ID Destroy service");
System.out.println();
System.out.println("Key options:");
System.out.println(" --extend Open browser to extend key");
}
}