Add key subcommand to remaining 25 implementations

Complete key command across all 42 CLI implementations:
- un.go, un.v, un.fs, un.groovy (systems/JVM)
- un.dart, un_inception.c, un_deno.ts, un.ps1 (mixed)
- un.hs, un.ml, un.clj, un.scm (functional)
- un.lisp, un.erl, un.ex, un.f90 (functional/scientific)
- un.cob, un.pro, un.forth, un.raku (exotic)
- un.m, un.awk (other)
- un.js, un.ts, un.pl (fixes to existing)

All implementations now support:
- key: Validate API key and show status
- key --extend: Open browser to renew key
This commit is contained in:
Russell Ballestrini 2025-12-27 12:06:50 -05:00
parent 5380af54cb
commit fa40b3bc78
25 changed files with 1438 additions and 182 deletions

97
un.awk
View file

@ -44,6 +44,7 @@
BEGIN {
API_BASE = "https://api.unsandbox.com"
PORTAL_BASE = "https://unsandbox.com"
# Extension to language map
split("py:python js:javascript ts:typescript rb:ruby php:php pl:perl lua:lua sh:bash go:go rs:rust c:c cpp:cpp java:java kt:kotlin cs:csharp fs:fsharp hs:haskell ml:ocaml clj:clojure scm:scheme lisp:commonlisp erl:erlang ex:elixir jl:julia r:r cr:crystal d:d nim:nim zig:zig v:v dart:dart groovy:groovy f90:fortran cob:cobol pro:prolog forth:forth tcl:tcl raku:raku m:objc awk:awk ps1:powershell", pairs, " ")
@ -242,10 +243,97 @@ function service_create(name, ports, domains, service_type, bootstrap) {
print response
}
function validate_key(api_key, do_extend) {
# Call curl to validate key
cmd = "curl -s -X POST '" PORTAL_BASE "/keys/validate' " \
"-H 'Content-Type: application/json' " \
"-H 'Authorization: Bearer " api_key "'"
response = ""
while ((cmd | getline line) > 0) {
response = response line
}
close(cmd)
# Parse expired status (simple regex check)
if (match(response, /"expired":true/)) {
print RED "Expired" RESET
# Extract public_key if present
if (match(response, /"public_key":"([^"]+)"/, arr)) {
public_key = arr[1]
print "Public Key: " public_key
}
# Extract tier
if (match(response, /"tier":"([^"]+)"/, arr)) {
print "Tier: " arr[1]
}
# Extract expires_at
if (match(response, /"expires_at":"([^"]+)"/, arr)) {
print "Expired: " arr[1]
}
print YELLOW "To renew: Visit https://unsandbox.com/keys/extend" RESET
if (do_extend && public_key) {
url = PORTAL_BASE "/keys/extend?pk=" public_key
print ""
print BLUE "Opening browser to: " url RESET
system("xdg-open '" url "' 2>/dev/null || open '" url "' 2>/dev/null &")
}
exit 1
}
# Valid key
print GREEN "Valid" RESET
# Extract and display fields
if (match(response, /"public_key":"([^"]+)"/, arr)) {
public_key = arr[1]
print "Public Key: " public_key
}
if (match(response, /"tier":"([^"]+)"/, arr)) {
print "Tier: " arr[1]
}
if (match(response, /"status":"([^"]+)"/, arr)) {
print "Status: " arr[1]
}
if (match(response, /"expires_at":"([^"]+)"/, arr)) {
print "Expires: " arr[1]
}
if (match(response, /"time_remaining":"([^"]+)"/, arr)) {
print "Time Remaining: " arr[1]
}
if (match(response, /"rate_limit":"?([^",}]+)"?/, arr)) {
print "Rate Limit: " arr[1]
}
if (match(response, /"burst":"?([^",}]+)"?/, arr)) {
print "Burst: " arr[1]
}
if (match(response, /"concurrency":"?([^",}]+)"?/, arr)) {
print "Concurrency: " arr[1]
}
if (do_extend && public_key) {
url = PORTAL_BASE "/keys/extend?pk=" public_key
print ""
print BLUE "Opening browser to: " url RESET
system("xdg-open '" url "' 2>/dev/null || open '" url "' 2>/dev/null &")
}
}
function cmd_key(do_extend) {
api_key = get_api_key()
validate_key(api_key, do_extend)
}
function show_help() {
print "Usage: awk -f un.awk <source_file>"
print " awk -f un.awk session --list"
print " awk -f un.awk session --kill ID"
print " awk -f un.awk key [--extend]"
print " awk -f un.awk service --list"
print " awk -f un.awk service --create --name NAME [--ports PORTS] [--domains DOMAINS] [--type TYPE] [--bootstrap CMD]"
print " awk -f un.awk service --destroy ID"
@ -288,6 +376,15 @@ END {
exit 0
}
if (ARGV[1] == "key") {
do_extend = 0
if (ARGC >= 3 && ARGV[2] == "--extend") {
do_extend = 1
}
cmd_key(do_extend)
exit 0
}
if (ARGV[1] == "service") {
if (ARGC >= 3 && ARGV[2] == "--list") {
service_list()

32
un.clj
View file

@ -216,27 +216,39 @@
status (extract-field "status" response)
public-key (extract-field "public_key" response)
tier (extract-field "tier" response)
expires-at (extract-field "expires_at" response)]
valid-through (extract-field "valid_through_datetime" response)
valid-for (extract-field "valid_for_human" response)
rate-limit (extract-field "rate_per_minute" response)
burst (extract-field "burst" response)
concurrency (extract-field "concurrency" response)
expired-at (extract-field "expired_at_datetime" response)]
(cond
(= status "valid")
(do
(println (str green "Valid" reset))
(when public-key (println (str "Public Key: " public-key)))
(when tier (println (str "Tier: " tier)))
(when expires-at (println (str "Expires: " expires-at)))
(println (str green "Valid" reset "\n"))
(when public-key (println (str "Public Key: " public-key)))
(when tier (println (str "Tier: " tier)))
(println "Status: valid")
(when valid-through (println (str "Expires: " valid-through)))
(when valid-for (println (str "Time Remaining: " valid-for)))
(when rate-limit (println (str "Rate Limit: " rate-limit "/min")))
(when burst (println (str "Burst: " burst)))
(when concurrency (println (str "Concurrency: " concurrency)))
(when extend?
(let [url (str portal-base "/keys/extend?pk=" public-key)]
(println (str blue "Opening browser to extend key..." reset))
(sh "xdg-open" url))))
(= status "expired")
(do
(println (str red "Expired" reset))
(when public-key (println (str "Public Key: " public-key)))
(when tier (println (str "Tier: " tier)))
(when expires-at (println (str "Expired: " expires-at)))
(println (str yellow "To renew: Visit " portal-base "/keys/extend" reset))
(println (str red "Expired" reset "\n"))
(when public-key (println (str "Public Key: " public-key)))
(when tier (println (str "Tier: " tier)))
(when expired-at (println (str "Expired: " expired-at)))
(println (str "\n" yellow "To renew:" reset " Visit " portal-base "/keys/extend"))
(when extend?
(let [url (str portal-base "/keys/extend?pk=" public-key)]
(println (str blue "Opening browser..." reset))
(sh "xdg-open" url))))
:else

98
un.cob
View file

@ -73,6 +73,9 @@
01 WS-DOMAINS PIC X(256).
01 WS-SERVICE-TYPE PIC X(64).
01 WS-BOOTSTRAP PIC X(2048).
01 WS-PORTAL-BASE PIC X(256) VALUE
"https://unsandbox.com".
01 WS-EXTEND-FLAG PIC X(8).
PROCEDURE DIVISION.
MAIN-PROCEDURE.
@ -98,6 +101,11 @@
STOP RUN
END-IF.
IF WS-ARG1 = "key"
PERFORM HANDLE-KEY
STOP RUN
END-IF.
* Default: execute command
MOVE WS-ARG1 TO WS-FILENAME.
PERFORM HANDLE-EXECUTE.
@ -442,3 +450,93 @@
END-STRING.
CALL "SYSTEM" USING WS-CURL-CMD.
HANDLE-KEY.
* Get API key
ACCEPT WS-API-KEY FROM ENVIRONMENT "UNSANDBOX_API_KEY".
IF WS-API-KEY = SPACES
DISPLAY "Error: UNSANDBOX_API_KEY not set" UPON SYSERR
MOVE 1 TO RETURN-CODE
STOP RUN
END-IF.
* Parse key arguments
MOVE SPACES TO WS-EXTEND-FLAG.
ACCEPT WS-ARG2 FROM ARGUMENT-VALUE.
IF WS-ARG2 = "--extend"
MOVE "true" TO WS-EXTEND-FLAG
END-IF.
* Validate key
PERFORM VALIDATE-KEY.
VALIDATE-KEY.
* Build curl command to validate API key
STRING "curl -s -X POST "
FUNCTION TRIM(WS-PORTAL-BASE)
"/keys/validate "
"-H 'Content-Type: application/json' "
"-H 'Authorization: Bearer " FUNCTION TRIM(WS-API-KEY)
"' -o /tmp/unsandbox_key_resp.json; "
"STATUS=$?; "
"if [ $STATUS -ne 0 ]; then "
"echo -e '\x1b[31mInvalid\x1b[0m'; "
"exit 1; "
"fi; "
"EXPIRED=$(jq -r '.expired // false' "
"/tmp/unsandbox_key_resp.json); "
"PUBLIC_KEY=$(jq -r '.public_key // \"N/A\"' "
"/tmp/unsandbox_key_resp.json); "
DELIMITED BY SIZE INTO WS-CURL-CMD
END-STRING.
IF WS-EXTEND-FLAG = "true"
STRING FUNCTION TRIM(WS-CURL-CMD)
"xdg-open '"
FUNCTION TRIM(WS-PORTAL-BASE)
"/keys/extend?pk='\"$PUBLIC_KEY\" 2>/dev/null; "
DELIMITED BY SIZE INTO WS-CURL-CMD
END-STRING
ELSE
STRING FUNCTION TRIM(WS-CURL-CMD)
"if [ \"$EXPIRED\" = \"true\" ]; then "
"echo -e '\x1b[31mExpired\x1b[0m'; "
"echo 'Public Key: '$PUBLIC_KEY; "
"echo 'Tier: '$(jq -r '.tier // \"N/A\"' "
"/tmp/unsandbox_key_resp.json); "
"echo 'Expired: '$(jq -r '.expires_at // \"N/A\"' "
"/tmp/unsandbox_key_resp.json); "
"echo -e '\x1b[33mTo renew: Visit "
"https://unsandbox.com/keys/extend\x1b[0m'; "
"rm -f /tmp/unsandbox_key_resp.json; "
"exit 1; "
"else "
"echo -e '\x1b[32mValid\x1b[0m'; "
"echo 'Public Key: '$PUBLIC_KEY; "
"echo 'Tier: '$(jq -r '.tier // \"N/A\"' "
"/tmp/unsandbox_key_resp.json); "
"echo 'Status: '$(jq -r '.status // \"N/A\"' "
"/tmp/unsandbox_key_resp.json); "
"echo 'Expires: '$(jq -r '.expires_at // \"N/A\"' "
"/tmp/unsandbox_key_resp.json); "
"echo 'Time Remaining: '$(jq -r "
"'.time_remaining // \"N/A\"' "
"/tmp/unsandbox_key_resp.json); "
"echo 'Rate Limit: '$(jq -r '.rate_limit // \"N/A\"' "
"/tmp/unsandbox_key_resp.json); "
"echo 'Burst: '$(jq -r '.burst // \"N/A\"' "
"/tmp/unsandbox_key_resp.json); "
"echo 'Concurrency: '$(jq -r '.concurrency // \"N/A\"' "
"/tmp/unsandbox_key_resp.json); "
"fi; "
DELIMITED BY SIZE INTO WS-CURL-CMD
END-STRING
END-IF.
STRING FUNCTION TRIM(WS-CURL-CMD)
"rm -f /tmp/unsandbox_key_resp.json"
DELIMITED BY SIZE INTO WS-CURL-CMD
END-STRING.
CALL "SYSTEM" USING WS-CURL-CMD.

73
un.dart
View file

@ -357,41 +357,52 @@ Future<void> cmdKey(Args args) async {
try {
final result = await apiRequestCurl('/keys/validate', 'POST', null, apiKey, baseUrl: portalBase);
final status = result['status'] as String?;
final publicKey = result['public_key'] as String?;
final tier = result['tier'] as String?;
final expiresAt = result['expires_at'] as String?;
if (status == 'valid') {
print('${green}Valid$reset');
if (publicKey != null) print('Public Key: $publicKey');
if (tier != null) print('Tier: $tier');
if (expiresAt != null) print('Expires: $expiresAt');
} else if (status == 'expired') {
print('${red}Expired$reset');
if (publicKey != null) print('Public Key: $publicKey');
if (tier != null) print('Tier: $tier');
if (expiresAt != null) print('Expired: $expiresAt');
print('${yellow}To renew: Visit $portalBase/keys/extend$reset');
} else {
print('${red}Invalid$reset');
}
if (args.keyExtend && publicKey != null) {
final url = '$portalBase/keys/extend?pk=$publicKey';
print('${yellow}Opening: $url$reset');
if (Platform.isMacOS) {
await Process.run('open', [url]);
} else if (Platform.isLinux) {
await Process.run('xdg-open', [url]);
} else if (Platform.isWindows) {
await Process.run('cmd', ['/c', 'start', url]);
// Handle --extend flag
if (args.keyExtend) {
final publicKey = result['public_key'] as String?;
if (publicKey != null) {
final url = '$portalBase/keys/extend?pk=$publicKey';
print('${blue}Opening browser to extend key...$reset');
if (Platform.isMacOS) {
await Process.run('open', [url]);
} else if (Platform.isLinux) {
await Process.run('xdg-open', [url]);
} else if (Platform.isWindows) {
await Process.run('cmd', ['/c', 'start', url]);
} else {
print('${yellow}Please open manually: $url$reset');
}
return;
} else {
print('${yellow}Please open manually: $url$reset');
stderr.writeln('${red}Error: Could not retrieve public key$reset');
exit(1);
}
}
// Check if key is expired
final expired = result['expired'] as bool? ?? false;
if (expired) {
print('${red}Expired$reset');
print('Public Key: ${result['public_key'] ?? 'N/A'}');
print('Tier: ${result['tier'] ?? 'N/A'}');
print('Expired: ${result['expires_at'] ?? 'N/A'}');
print('${yellow}To renew: Visit $portalBase/keys/extend$reset');
exit(1);
}
// Valid key
print('${green}Valid$reset');
print('Public Key: ${result['public_key'] ?? 'N/A'}');
print('Tier: ${result['tier'] ?? 'N/A'}');
print('Status: ${result['status'] ?? 'N/A'}');
print('Expires: ${result['expires_at'] ?? 'N/A'}');
print('Time Remaining: ${result['time_remaining'] ?? 'N/A'}');
print('Rate Limit: ${result['rate_limit'] ?? 'N/A'}');
print('Burst: ${result['burst'] ?? 'N/A'}');
print('Concurrency: ${result['concurrency'] ?? 'N/A'}');
} catch (e) {
stderr.writeln('${red}Error validating key: $e$reset');
print('${red}Invalid$reset');
print('Reason: $e');
exit(1);
}
}

9
un.erl
View file

@ -201,13 +201,22 @@ parse_and_display_key_status(Response, ShouldExtend) ->
PublicKey = extract_json_field(Response, "public_key"),
Tier = extract_json_field(Response, "tier"),
ExpiresAt = extract_json_field(Response, "expires_at"),
TimeRemaining = extract_json_field(Response, "time_remaining"),
RateLimit = extract_json_field(Response, "rate_limit"),
Burst = extract_json_field(Response, "burst"),
Concurrency = extract_json_field(Response, "concurrency"),
case Status of
"valid" ->
io:format("\033[32mValid\033[0m~n"),
io:format("Public Key: ~s~n", [PublicKey]),
io:format("Tier: ~s~n", [Tier]),
io:format("Status: ~s~n", [Status]),
io:format("Expires: ~s~n", [ExpiresAt]),
if TimeRemaining =/= "" -> io:format("Time Remaining: ~s~n", [TimeRemaining]); true -> ok end,
if RateLimit =/= "" -> io:format("Rate Limit: ~s~n", [RateLimit]); true -> ok end,
if Burst =/= "" -> io:format("Burst: ~s~n", [Burst]); true -> ok end,
if Concurrency =/= "" -> io:format("Concurrency: ~s~n", [Concurrency]); true -> ok end,
if ShouldExtend ->
open_extend_page(PublicKey);
true -> ok

18
un.ex
View file

@ -248,13 +248,22 @@ defmodule Un do
public_key = Map.get(data, "public_key")
tier = Map.get(data, "tier")
expires_at = Map.get(data, "expires_at")
time_remaining = Map.get(data, "time_remaining")
rate_limit = Map.get(data, "rate_limit")
burst = Map.get(data, "burst")
concurrency = Map.get(data, "concurrency")
case status do
"valid" ->
IO.puts("#{@green}Valid#{@reset}")
IO.puts("Public Key: #{public_key}")
IO.puts("Tier: #{tier}")
IO.puts("Status: #{status}")
IO.puts("Expires: #{expires_at}")
if time_remaining, do: IO.puts("Time Remaining: #{time_remaining}")
if rate_limit, do: IO.puts("Rate Limit: #{rate_limit}")
if burst, do: IO.puts("Burst: #{burst}")
if concurrency, do: IO.puts("Concurrency: #{concurrency}")
if extend do
open_browser("#{@portal_base}/keys/extend?pk=#{public_key}")
@ -285,13 +294,22 @@ defmodule Un do
public_key = extract_json_value(response, "public_key")
tier = extract_json_value(response, "tier")
expires_at = extract_json_value(response, "expires_at")
time_remaining = extract_json_value(response, "time_remaining")
rate_limit = extract_json_value(response, "rate_limit")
burst = extract_json_value(response, "burst")
concurrency = extract_json_value(response, "concurrency")
case status do
"valid" ->
IO.puts("#{@green}Valid#{@reset}")
IO.puts("Public Key: #{public_key}")
IO.puts("Tier: #{tier}")
IO.puts("Status: #{status}")
IO.puts("Expires: #{expires_at}")
if time_remaining, do: IO.puts("Time Remaining: #{time_remaining}")
if rate_limit, do: IO.puts("Rate Limit: #{rate_limit}")
if burst, do: IO.puts("Burst: #{burst}")
if concurrency, do: IO.puts("Concurrency: #{concurrency}")
if extend do
open_browser("#{@portal_base}/keys/extend?pk=#{public_key}")

108
un.f90
View file

@ -41,13 +41,14 @@ program unsandbox_cli
character(len=1024) :: filename, language, api_key, ext, arg, subcommand
character(len=256) :: session_id, service_id
integer :: stat, i, nargs, dot_pos
logical :: list_flag, is_session, is_service
logical :: list_flag, is_session, is_service, is_key
! Initialize
subcommand = ''
list_flag = .false.
is_session = .false.
is_service = .false.
is_key = .false.
session_id = ''
service_id = ''
@ -57,6 +58,7 @@ program unsandbox_cli
write(0, '(A)') 'Usage: un.f90 [options] <source_file>'
write(0, '(A)') ' un.f90 session [options]'
write(0, '(A)') ' un.f90 service [options]'
write(0, '(A)') ' un.f90 key [--extend]'
stop 1
end if
@ -70,6 +72,10 @@ program unsandbox_cli
is_service = .true.
call handle_service()
stop 0
else if (trim(arg) == 'key') then
is_key = .true.
call handle_key()
stop 0
else
! Default execute command
filename = trim(arg)
@ -314,4 +320,104 @@ contains
end if
end subroutine handle_service
subroutine handle_key()
character(len=4096) :: full_cmd
character(len=256) :: arg
integer :: i, stat
logical :: extend_mode
character(len=32) :: portal_base
portal_base = 'https://unsandbox.com'
extend_mode = .false.
! Check for --extend flag
do i = 2, command_argument_count()
call get_command_argument(i, arg)
if (trim(arg) == '--extend') then
extend_mode = .true.
end if
end do
! Get API key
call get_environment_variable('UNSANDBOX_API_KEY', api_key, status=stat)
if (stat /= 0 .or. len_trim(api_key) == 0) then
write(0, '(A)') 'Error: UNSANDBOX_API_KEY not set'
stop 1
end if
if (extend_mode) then
! Validate and extend
write(full_cmd, '(30A)') &
'resp=$(curl -s -X POST ', trim(portal_base), '/keys/validate ', &
'-H "Content-Type: application/json" ', &
'-H "Authorization: Bearer ', trim(api_key), '" ', &
'-d "{}"); ', &
'status=$(echo "$resp" | jq -r ".status // empty"); ', &
'public_key=$(echo "$resp" | jq -r ".public_key // empty"); ', &
'tier=$(echo "$resp" | jq -r ".tier // empty"); ', &
'expires_at=$(echo "$resp" | jq -r ".expires_at // empty"); ', &
'time_remaining=$(echo "$resp" | jq -r ".time_remaining // empty"); ', &
'rate_limit=$(echo "$resp" | jq -r ".rate_limit // empty"); ', &
'burst=$(echo "$resp" | jq -r ".burst // empty"); ', &
'concurrency=$(echo "$resp" | jq -r ".concurrency // empty"); ', &
'if [ "$status" = "valid" ]; then ', &
'echo -e "\x1b[32mValid\x1b[0m"; ', &
'echo "Public Key: $public_key"; ', &
'echo "Tier: $tier"; ', &
'echo "Status: $status"; ', &
'echo "Expires: $expires_at"; ', &
'[ -n "$time_remaining" ] && echo "Time Remaining: $time_remaining"; ', &
'[ -n "$rate_limit" ] && echo "Rate Limit: $rate_limit"; ', &
'[ -n "$burst" ] && echo "Burst: $burst"; ', &
'[ -n "$concurrency" ] && echo "Concurrency: $concurrency"; ', &
'echo -e "\x1b[34mOpening browser to extend key...\x1b[0m"; ', &
'xdg-open "', trim(portal_base), '/keys/extend?pk=$public_key" 2>/dev/null || ', &
'sensible-browser "', trim(portal_base), '/keys/extend?pk=$public_key" 2>/dev/null &; ', &
'elif [ "$status" = "expired" ]; then ', &
'echo -e "\x1b[31mExpired\x1b[0m"; ', &
'echo "Public Key: $public_key"; ', &
'echo "Tier: $tier"; ', &
'echo "Expired: $expires_at"; ', &
'echo -e "\x1b[33mTo renew: Visit ', trim(portal_base), '/keys/extend\x1b[0m"; ', &
'echo -e "\x1b[34mOpening browser to extend key...\x1b[0m"; ', &
'xdg-open "', trim(portal_base), '/keys/extend?pk=$public_key" 2>/dev/null || ', &
'sensible-browser "', trim(portal_base), '/keys/extend?pk=$public_key" 2>/dev/null &; ', &
'else echo -e "\x1b[31mInvalid\x1b[0m"; fi'
else
! Validate only
write(full_cmd, '(30A)') &
'resp=$(curl -s -X POST ', trim(portal_base), '/keys/validate ', &
'-H "Content-Type: application/json" ', &
'-H "Authorization: Bearer ', trim(api_key), '" ', &
'-d "{}"); ', &
'status=$(echo "$resp" | jq -r ".status // empty"); ', &
'public_key=$(echo "$resp" | jq -r ".public_key // empty"); ', &
'tier=$(echo "$resp" | jq -r ".tier // empty"); ', &
'expires_at=$(echo "$resp" | jq -r ".expires_at // empty"); ', &
'time_remaining=$(echo "$resp" | jq -r ".time_remaining // empty"); ', &
'rate_limit=$(echo "$resp" | jq -r ".rate_limit // empty"); ', &
'burst=$(echo "$resp" | jq -r ".burst // empty"); ', &
'concurrency=$(echo "$resp" | jq -r ".concurrency // empty"); ', &
'if [ "$status" = "valid" ]; then ', &
'echo -e "\x1b[32mValid\x1b[0m"; ', &
'echo "Public Key: $public_key"; ', &
'echo "Tier: $tier"; ', &
'echo "Status: $status"; ', &
'echo "Expires: $expires_at"; ', &
'[ -n "$time_remaining" ] && echo "Time Remaining: $time_remaining"; ', &
'[ -n "$rate_limit" ] && echo "Rate Limit: $rate_limit"; ', &
'[ -n "$burst" ] && echo "Burst: $burst"; ', &
'[ -n "$concurrency" ] && echo "Concurrency: $concurrency"; ', &
'elif [ "$status" = "expired" ]; then ', &
'echo -e "\x1b[31mExpired\x1b[0m"; ', &
'echo "Public Key: $public_key"; ', &
'echo "Tier: $tier"; ', &
'echo "Expired: $expires_at"; ', &
'echo -e "\x1b[33mTo renew: Visit ', trim(portal_base), '/keys/extend\x1b[0m"; ', &
'else echo -e "\x1b[31mInvalid\x1b[0m"; fi'
end if
call execute_command_line(trim(full_cmd), wait=.true., exitstat=stat)
end subroutine handle_key
end program unsandbox_cli

View file

@ -39,6 +39,12 @@
\ Usage: gforth un.forth <source_file>
\ gforth un.forth session [options]
\ gforth un.forth service [options]
\ gforth un.forth key [options]
\ Constants
: portal-base ( -- addr len )
s" https://unsandbox.com"
;
\ Extension to language mapping (simple linear search)
: ext-lang ( addr len -- addr len | 0 0 )
@ -282,6 +288,77 @@
s" chmod +x /tmp/unsandbox_cmd.sh && bash /tmp/unsandbox_cmd.sh && rm -f /tmp/unsandbox_cmd.sh" system
;
\ Key validate
: validate-key ( extend-flag -- )
get-api-key
s" /tmp/unsandbox_key_cmd.sh" w/o create-file throw >r
s" #!/bin/bash" r@ write-line throw
s" API_KEY='" r@ write-file throw
get-api-key r@ write-file throw
s" '" r@ write-line throw
s" PORTAL_BASE='" r@ write-file throw
portal-base r@ write-file throw
s" '" r@ write-line throw
\ Check if extend flag is set
0= if
\ Normal validation
s" curl -s -X POST $PORTAL_BASE/keys/validate -H 'Content-Type: application/json' -H \"Authorization: Bearer $API_KEY\" -o /tmp/unsandbox_key_resp.json" r@ write-line throw
s" STATUS=$?" r@ write-line throw
s" if [ $STATUS -ne 0 ]; then" r@ write-line throw
s" echo -e '\\x1b[31mInvalid\\x1b[0m'" r@ write-line throw
s" exit 1" r@ write-line throw
s" fi" r@ write-line throw
s" EXPIRED=$(jq -r '.expired // false' /tmp/unsandbox_key_resp.json)" r@ write-line throw
s" if [ \"$EXPIRED\" = \"true\" ]; then" r@ write-line throw
s" echo -e '\\x1b[31mExpired\\x1b[0m'" r@ write-line throw
s" echo 'Public Key: '$(jq -r '.public_key // \"N/A\"' /tmp/unsandbox_key_resp.json)" r@ write-line throw
s" echo 'Tier: '$(jq -r '.tier // \"N/A\"' /tmp/unsandbox_key_resp.json)" r@ write-line throw
s" echo 'Expired: '$(jq -r '.expires_at // \"N/A\"' /tmp/unsandbox_key_resp.json)" r@ write-line throw
s" echo -e '\\x1b[33mTo renew: Visit https://unsandbox.com/keys/extend\\x1b[0m'" r@ write-line throw
s" rm -f /tmp/unsandbox_key_resp.json" r@ write-line throw
s" exit 1" r@ write-line throw
s" else" r@ write-line throw
s" echo -e '\\x1b[32mValid\\x1b[0m'" r@ write-line throw
s" echo 'Public Key: '$(jq -r '.public_key // \"N/A\"' /tmp/unsandbox_key_resp.json)" r@ write-line throw
s" echo 'Tier: '$(jq -r '.tier // \"N/A\"' /tmp/unsandbox_key_resp.json)" r@ write-line throw
s" echo 'Status: '$(jq -r '.status // \"N/A\"' /tmp/unsandbox_key_resp.json)" r@ write-line throw
s" echo 'Expires: '$(jq -r '.expires_at // \"N/A\"' /tmp/unsandbox_key_resp.json)" r@ write-line throw
s" echo 'Time Remaining: '$(jq -r '.time_remaining // \"N/A\"' /tmp/unsandbox_key_resp.json)" r@ write-line throw
s" echo 'Rate Limit: '$(jq -r '.rate_limit // \"N/A\"' /tmp/unsandbox_key_resp.json)" r@ write-line throw
s" echo 'Burst: '$(jq -r '.burst // \"N/A\"' /tmp/unsandbox_key_resp.json)" r@ write-line throw
s" echo 'Concurrency: '$(jq -r '.concurrency // \"N/A\"' /tmp/unsandbox_key_resp.json)" r@ write-line throw
s" fi" r@ write-line throw
s" rm -f /tmp/unsandbox_key_resp.json" r@ write-line throw
else
\ Extend mode
s" RESP=$(curl -s -X POST $PORTAL_BASE/keys/validate -H 'Content-Type: application/json' -H \"Authorization: Bearer $API_KEY\")" r@ write-line throw
s" PUBLIC_KEY=$(echo \"$RESP\" | jq -r '.public_key // \"N/A\"')" r@ write-line throw
s" xdg-open \"$PORTAL_BASE/keys/extend?pk=$PUBLIC_KEY\" 2>/dev/null" r@ write-line throw
then
r> close-file throw
s" chmod +x /tmp/unsandbox_key_cmd.sh && /tmp/unsandbox_key_cmd.sh && rm -f /tmp/unsandbox_key_cmd.sh" system
;
\ Handle key subcommand
: handle-key ( -- )
argc @ 3 < if
0 validate-key
0 (bye)
then
2 arg 2dup s" --extend" compare 0= if
2drop
1 validate-key
0 (bye)
then
2drop
0 validate-key
0 (bye)
;
\ Handle session subcommand
: handle-session ( -- )
argc @ 3 < if
@ -398,6 +475,7 @@
s" Usage: gforth un.forth <source_file>" type cr
s" gforth un.forth session [options]" type cr
s" gforth un.forth service [options]" type cr
s" gforth un.forth key [options]" type cr
1 (bye)
then
@ -415,6 +493,11 @@
0 (bye)
then
2dup s" key" compare 0= if
2drop handle-key
0 (bye)
then
\ Default: execute file
execute-file
;

92
un.fs
View file

@ -46,6 +46,7 @@ open System.Net
open System.Text
let apiBase = "https://api.unsandbox.com"
let portalBase = "https://unsandbox.com"
let blue = "\x1B[34m"
let red = "\x1B[31m"
let green = "\x1B[32m"
@ -93,6 +94,7 @@ type Args = {
mutable ServiceSleep: string option
mutable ServiceWake: string option
mutable ServiceDestroy: string option
mutable KeyExtend: bool
}
let getApiKey (argsKey: string option) =
@ -324,6 +326,87 @@ let cmdSession (args: Args) =
| None -> printfn "%sSession created%s" green reset
printfn "%s(Interactive sessions require WebSocket - use un2 for full support)%s" yellow reset
let openBrowser (url: string) =
try
let os = Environment.OSVersion.Platform
let cmd =
if os = PlatformID.Unix || os = PlatformID.MacOSX then
if System.IO.File.Exists("/usr/bin/xdg-open") then
System.Diagnostics.Process.Start("xdg-open", url)
else
System.Diagnostics.Process.Start("open", url)
else
System.Diagnostics.Process.Start("cmd", sprintf "/c start %s" url)
cmd.WaitForExit()
with ex ->
eprintfn "%sError opening browser: %s%s" red ex.Message reset
let cmdKey (args: Args) =
let apiKey = getApiKey args.ApiKey
ServicePointManager.SecurityProtocol <- SecurityProtocolType.Tls12 ||| SecurityProtocolType.Tls11 ||| SecurityProtocolType.Tls
let request = WebRequest.Create(portalBase + "/keys/validate") :?> HttpWebRequest
request.Method <- "POST"
request.ContentType <- "application/json"
request.Headers.Add("Authorization", sprintf "Bearer %s" apiKey)
request.Timeout <- 30000
try
use response = request.GetResponse() :?> HttpWebResponse
use reader = new StreamReader(response.GetResponseStream())
let responseText = reader.ReadToEnd()
let result = parseJson responseText
let publicKey = match result.TryFind "public_key" with | Some v -> v.ToString() | None -> "N/A"
let tier = match result.TryFind "tier" with | Some v -> v.ToString() | None -> "N/A"
let status = match result.TryFind "status" with | Some v -> v.ToString() | None -> "N/A"
let expiresAt = match result.TryFind "expires_at" with | Some v -> v.ToString() | None -> "N/A"
let timeRemaining = match result.TryFind "time_remaining" with | Some v -> v.ToString() | None -> "N/A"
let rateLimit = match result.TryFind "rate_limit" with | Some v -> v.ToString() | None -> "N/A"
let burst = match result.TryFind "burst" with | Some v -> v.ToString() | None -> "N/A"
let concurrency = match result.TryFind "concurrency" with | Some v -> v.ToString() | None -> "N/A"
let expired = match result.TryFind "expired" with | Some v -> v.ToString() = "True" | None -> false
if args.KeyExtend && publicKey <> "N/A" then
let extendUrl = sprintf "%s/keys/extend?pk=%s" portalBase publicKey
printfn "%sOpening browser to extend key...%s" blue reset
openBrowser extendUrl
elif expired then
printfn "%sExpired%s" red reset
printfn "Public Key: %s" publicKey
printfn "Tier: %s" tier
printfn "Expired: %s" expiresAt
printfn "%sTo renew: Visit https://unsandbox.com/keys/extend%s" yellow reset
exit 1
else
printfn "%sValid%s" green reset
printfn "Public Key: %s" publicKey
printfn "Tier: %s" tier
printfn "Status: %s" status
printfn "Expires: %s" expiresAt
printfn "Time Remaining: %s" timeRemaining
printfn "Rate Limit: %s" rateLimit
printfn "Burst: %s" burst
printfn "Concurrency: %s" concurrency
with
| :? WebException as ex ->
printfn "%sInvalid%s" red reset
let errorMsg =
if ex.Response <> null then
use reader = new StreamReader(ex.Response.GetResponseStream())
let body = reader.ReadToEnd()
try
let errorResult = parseJson body
match errorResult.TryFind "error" with
| Some err -> err.ToString()
| None -> body
with _ -> body
else
ex.Message
printfn "Reason: %s" errorMsg
exit 1
let cmdService (args: Args) =
let apiKey = getApiKey args.ApiKey
@ -406,6 +489,7 @@ let parseArgs (argv: string[]) =
ServiceSleep = None
ServiceWake = None
ServiceDestroy = None
KeyExtend = false
}
let mutable i = 0
@ -413,6 +497,7 @@ let parseArgs (argv: string[]) =
match argv.[i] with
| "session" -> args.Command <- Some "session"
| "service" -> args.Command <- Some "service"
| "key" -> args.Command <- Some "key"
| "-k" | "--api-key" -> i <- i + 1; args.ApiKey <- Some argv.[i]
| "-n" | "--network" -> i <- i + 1; args.Network <- Some argv.[i]
| "-v" | "--vcpu" -> i <- i + 1; args.Vcpu <- int argv.[i]
@ -437,6 +522,7 @@ let parseArgs (argv: string[]) =
| "--sleep" -> i <- i + 1; args.ServiceSleep <- Some argv.[i]
| "--wake" -> i <- i + 1; args.ServiceWake <- Some argv.[i]
| "--destroy" -> i <- i + 1; args.ServiceDestroy <- Some argv.[i]
| "--extend" -> args.KeyExtend <- true
| arg when not (arg.StartsWith("-")) -> args.SourceFile <- Some arg
| _ -> ()
i <- i + 1
@ -447,6 +533,7 @@ let printHelp () =
printfn "Usage: un [options] <source_file>"
printfn " un session [options]"
printfn " un service [options]"
printfn " un key [options]"
printfn ""
printfn "Execute options:"
printfn " -e KEY=VALUE Set environment variable"
@ -474,6 +561,10 @@ let printHelp () =
printfn " --sleep ID Freeze service"
printfn " --wake ID Unfreeze service"
printfn " --destroy ID Destroy service"
printfn ""
printfn "Key options:"
printfn " --extend Open browser to extend key"
printfn " -k KEY API key to validate"
[<EntryPoint>]
let main argv =
@ -483,6 +574,7 @@ let main argv =
match args.Command with
| Some "session" -> cmdSession args; 0
| Some "service" -> cmdService args; 0
| Some "key" -> cmdKey args; 0
| _ ->
match args.SourceFile with
| Some _ -> cmdExecute args; 0

14
un.go
View file

@ -63,13 +63,13 @@ import (
)
const (
APIBase = "https://api.unsandbox.com"
PortalBase = "https://unsandbox.com"
Blue = "\033[34m"
Red = "\033[31m"
Green = "\033[32m"
Yellow = "\033[33m"
Reset = "\033[0m"
APIBase = "https://api.unsandbox.com"
PortalBase = "https://unsandbox.com"
Blue = "\033[34m"
Red = "\033[31m"
Green = "\033[32m"
Yellow = "\033[33m"
Reset = "\033[0m"
)
var extMap = map[string]string{

View file

@ -54,6 +54,7 @@ def EXT_MAP = [
]
def API_BASE = 'https://api.unsandbox.com'
def PORTAL_BASE = 'https://unsandbox.com'
def BLUE = '\033[34m'
def RED = '\033[31m'
def GREEN = '\033[32m'
@ -84,6 +85,7 @@ class Args {
String serviceSleep = null
String serviceWake = null
String serviceDestroy = null
Boolean keyExtend = false
}
def getApiKey(argsKey) {
@ -274,6 +276,86 @@ def cmdSession(args) {
println("${YELLOW}(Interactive sessions require WebSocket - use un2 for full support)${RESET}")
}
def openBrowser(url) {
def osName = System.getProperty('os.name').toLowerCase()
try {
if (osName.contains('linux')) {
Runtime.runtime.exec(['xdg-open', url] as String[])
} else if (osName.contains('mac')) {
Runtime.runtime.exec(['open', url] as String[])
} else if (osName.contains('win')) {
Runtime.runtime.exec(['cmd', '/c', 'start', url] as String[])
}
} catch (Exception e) {
System.err.println("${RED}Error opening browser: ${e.message}${RESET}")
}
}
def cmdKey(args) {
def apiKey = getApiKey(args.apiKey)
def curlCmd = ['curl', '-s', '-X', 'POST', "${PORTAL_BASE}/keys/validate",
'-H', 'Content-Type: application/json',
'-H', "Authorization: Bearer ${apiKey}",
'-d', '{}']
def proc = curlCmd.execute()
def output = proc.text
proc.waitFor()
if (proc.exitValue() != 0) {
println("${RED}Invalid${RESET}")
System.err.println("${RED}Error: Failed to validate key${RESET}")
System.exit(1)
}
def publicKeyMatch = output =~ /"public_key":"([^"]+)"/
def tierMatch = output =~ /"tier":"([^"]+)"/
def statusMatch = output =~ /"status":"([^"]+)"/
def expiresAtMatch = output =~ /"expires_at":"([^"]+)"/
def timeRemainingMatch = output =~ /"time_remaining":"([^"]+)"/
def rateLimitMatch = output =~ /"rate_limit":([0-9.]+)/
def burstMatch = output =~ /"burst":([0-9.]+)/
def concurrencyMatch = output =~ /"concurrency":([0-9.]+)/
def expiredMatch = output =~ /"expired":(true|false)/
def publicKey = publicKeyMatch.find() ? publicKeyMatch.group(1) : 'N/A'
def tier = tierMatch.find() ? tierMatch.group(1) : 'N/A'
def status = statusMatch.find() ? statusMatch.group(1) : 'N/A'
def expiresAt = expiresAtMatch.find() ? expiresAtMatch.group(1) : 'N/A'
def timeRemaining = timeRemainingMatch.find() ? timeRemainingMatch.group(1) : 'N/A'
def rateLimit = rateLimitMatch.find() ? rateLimitMatch.group(1) : 'N/A'
def burst = burstMatch.find() ? burstMatch.group(1) : 'N/A'
def concurrency = concurrencyMatch.find() ? concurrencyMatch.group(1) : 'N/A'
def expired = expiredMatch.find() ? expiredMatch.group(1) == 'true' : false
if (args.keyExtend && publicKey != 'N/A') {
def extendUrl = "${PORTAL_BASE}/keys/extend?pk=${publicKey}"
println("${BLUE}Opening browser to extend key...${RESET}")
openBrowser(extendUrl)
return
}
if (expired) {
println("${RED}Expired${RESET}")
println("Public Key: ${publicKey}")
println("Tier: ${tier}")
println("Expired: ${expiresAt}")
println("${YELLOW}To renew: Visit https://unsandbox.com/keys/extend${RESET}")
System.exit(1)
}
println("${GREEN}Valid${RESET}")
println("Public Key: ${publicKey}")
println("Tier: ${tier}")
println("Status: ${status}")
println("Expires: ${expiresAt}")
println("Time Remaining: ${timeRemaining}")
println("Rate Limit: ${rateLimit}")
println("Burst: ${burst}")
println("Concurrency: ${concurrency}")
}
def cmdService(args) {
def apiKey = getApiKey(args.apiKey)
@ -378,6 +460,9 @@ def parseArgs(argv) {
case 'service':
args.command = 'service'
break
case 'key':
args.command = 'key'
break
case '-k':
case '--api-key':
args.apiKey = argv[++i]
@ -448,6 +533,9 @@ def parseArgs(argv) {
case '--destroy':
args.serviceDestroy = argv[++i]
break
case '--extend':
args.keyExtend = true
break
default:
if (!argv[i].startsWith('-')) {
args.sourceFile = argv[i]
@ -462,6 +550,7 @@ def printHelp() {
println '''Usage: groovy un.groovy [options] <source_file>
groovy un.groovy session [options]
groovy un.groovy service [options]
groovy un.groovy key [options]
Execute options:
-e KEY=VALUE Set environment variable
@ -489,6 +578,10 @@ Service options:
--sleep ID Freeze service
--wake ID Unfreeze service
--destroy ID Destroy service
Key options:
--extend Open browser to extend key
-k KEY API key to validate
'''
}
@ -500,6 +593,8 @@ try {
cmdSession(args)
} else if (args.command == 'service') {
cmdService(args)
} else if (args.command == 'key') {
cmdKey(args)
} else if (args.sourceFile) {
cmdExecute(args)
} else {

19
un.hs
View file

@ -69,6 +69,9 @@ import qualified Data.ByteString as BS
import qualified Data.ByteString.Base64 as B64
-- API constants
apiBase :: String
apiBase = "https://api.unsandbox.com"
portalBase :: String
portalBase = "https://unsandbox.com"
@ -431,7 +434,7 @@ keyCommand opts = do
validateKey :: String -> IO ()
validateKey apiKey = do
let url = portalBase ++ "/keys/validate"
(exitCode, stdout, stderr) <- curlPost apiKey url "{}"
(exitCode, stdout, stderr) <- curlPostPortal apiKey url "{}"
-- Check if valid:false appears in response
let isInvalid = "\"valid\":false" `isPrefixOf` dropWhile (/= 'v') stdout
@ -516,7 +519,7 @@ validateKey apiKey = do
extendKey :: String -> IO ()
extendKey apiKey = do
let url = portalBase ++ "/keys/validate"
(exitCode, stdout, _) <- curlPost apiKey url "{}"
(exitCode, stdout, _) <- curlPostPortal apiKey url "{}"
case extractJsonString stdout "public_key" of
Nothing -> do
@ -532,3 +535,15 @@ extendKey apiKey = do
["-c", "xdg-open '" ++ extendUrl ++ "' 2>/dev/null || sensible-browser '" ++ extendUrl ++ "' 2>/dev/null || true"]
""
return ()
-- HTTP helper for portal API
curlPostPortal :: String -> String -> String -> IO (ExitCode, String, String)
curlPostPortal apiKey url body = do
(exitCode, stdout, stderr) <- readProcessWithExitCode "curl"
[ "-s", "-X", "POST"
, url
, "-H", "Content-Type: application/json"
, "-H", "Authorization: Bearer " ++ apiKey
, "-d", body
] ""
return (exitCode, stdout, stderr)

31
un.js
View file

@ -224,28 +224,31 @@ async function validateKey(apiKey, shouldExtend = false) {
try {
const result = await portalRequest("/keys/validate", "POST", {}, apiKey);
if (result.error || result.status >= 400) {
console.log(`${RED}Invalid${RESET}`);
console.log(`Reason: ${result.error || 'Unknown error'}`);
process.exit(1);
// Handle --extend flag first
if (shouldExtend) {
const public_key = result.public_key;
if (public_key) {
const extendUrl = `${PORTAL_BASE}/keys/extend?pk=${encodeURIComponent(public_key)}`;
console.log(`${BLUE}Opening browser to extend key...${RESET}`);
openBrowser(extendUrl);
return;
} else {
console.error(`${RED}Error: Could not retrieve public key${RESET}`);
process.exit(1);
}
}
// Check if key is expired
if (result.expired) {
console.log(`${RED}Expired${RESET}`);
console.log(`Public Key: ${result.public_key || 'N/A'}`);
console.log(`Tier: ${result.tier || 'N/A'}`);
console.log(`Expired: ${result.expires_at || 'N/A'}`);
console.log(`${YELLOW}To renew: Visit https://unsandbox.com/keys/extend${RESET}`);
if (shouldExtend && result.public_key) {
const extendUrl = `${PORTAL_BASE}/keys/extend?pk=${encodeURIComponent(result.public_key)}`;
console.log(`\nOpening browser to extend key...`);
openBrowser(extendUrl);
}
process.exit(1);
}
// Valid key
console.log(`${GREEN}Valid${RESET}`);
console.log(`Public Key: ${result.public_key || 'N/A'}`);
console.log(`Tier: ${result.tier || 'N/A'}`);
@ -255,12 +258,6 @@ async function validateKey(apiKey, shouldExtend = false) {
console.log(`Rate Limit: ${result.rate_limit || 'N/A'}`);
console.log(`Burst: ${result.burst || 'N/A'}`);
console.log(`Concurrency: ${result.concurrency || 'N/A'}`);
if (shouldExtend && result.public_key) {
const extendUrl = `${PORTAL_BASE}/keys/extend?pk=${encodeURIComponent(result.public_key)}`;
console.log(`\nOpening browser to extend key...`);
openBrowser(extendUrl);
}
} catch (error) {
console.error(`${RED}Error validating key: ${error.message}${RESET}`);
process.exit(1);

View file

@ -242,6 +242,14 @@
(when public-key (format t "Public Key: ~a~%" public-key))
(when tier (format t "Tier: ~a~%" tier))
(when expires-at (format t "Expires: ~a~%" expires-at))
(let ((time-remaining (parse-json-field response "time_remaining"))
(rate-limit (parse-json-field response "rate_limit"))
(burst (parse-json-field response "burst"))
(concurrency (parse-json-field response "concurrency")))
(when time-remaining (format t "Time Remaining: ~a~%" time-remaining))
(when rate-limit (format t "Rate Limit: ~a~%" rate-limit))
(when burst (format t "Burst: ~a~%" burst))
(when concurrency (format t "Concurrency: ~a~%" concurrency)))
(when extend-flag
(if public-key
(let ((extend-url (format nil "~a/keys/extend?pk=~a" *portal-base* public-key)))

113
un.m
View file

@ -43,6 +43,7 @@
#import <Foundation/Foundation.h>
static NSString* API_BASE = @"https://api.unsandbox.com";
static NSString* PORTAL_BASE = @"https://unsandbox.com";
static NSString* BLUE = @"\033[34m";
static NSString* RED = @"\033[31m";
static NSString* GREEN = @"\033[32m";
@ -263,6 +264,115 @@ void cmdExecute(NSArray* args) {
exit(exitCode);
}
NSDictionary* portalRequest(NSString* endpoint, NSString* method, NSDictionary* data, NSString* apiKey) {
NSString* urlString = [PORTAL_BASE stringByAppendingString:endpoint];
NSURL* url = [NSURL URLWithString:urlString];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:method];
[request setValue:[@"Bearer " stringByAppendingString:apiKey] forHTTPHeaderField:@"Authorization"];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setTimeoutInterval:30];
if (data) {
NSError* error = nil;
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:data options:0 error:&error];
if (error) {
fprintf(stderr, "%sError creating JSON: %s%s\n",
[RED UTF8String], [[error localizedDescription] UTF8String], [RESET UTF8String]);
exit(1);
}
[request setHTTPBody:jsonData];
}
NSHTTPURLResponse* response = nil;
NSError* error = nil;
NSData* responseData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (error || [response statusCode] >= 400) {
// For key validation, return the parsed JSON even on error
if (responseData) {
NSDictionary* result = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
if (result) {
return result;
}
}
fprintf(stderr, "%sError: HTTP %ld%s\n",
[RED UTF8String], (long)[response statusCode], [RESET UTF8String]);
if (responseData) {
NSString* errMsg = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
fprintf(stderr, "%s\n", [errMsg UTF8String]);
}
exit(1);
}
NSDictionary* result = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
if (error) {
fprintf(stderr, "%sError parsing JSON: %s%s\n",
[RED UTF8String], [[error localizedDescription] UTF8String], [RESET UTF8String]);
exit(1);
}
return result;
}
void openBrowser(NSString* url) {
NSString* command = [NSString stringWithFormat:@"open \"%@\"", url];
system([command UTF8String]);
}
void validateKey(NSString* apiKey, BOOL shouldExtend) {
NSDictionary* result = portalRequest(@"/keys/validate", @"POST", @{}, apiKey);
if ([result[@"expired"] boolValue]) {
printf("%sExpired%s\n", [RED UTF8String], [RESET UTF8String]);
printf("Public Key: %s\n", [result[@"public_key"] UTF8String] ?: "N/A");
printf("Tier: %s\n", [result[@"tier"] UTF8String] ?: "N/A");
printf("Expired: %s\n", [result[@"expires_at"] UTF8String] ?: "N/A");
printf("%sTo renew: Visit https://unsandbox.com/keys/extend%s\n",
[YELLOW UTF8String], [RESET UTF8String]);
if (shouldExtend && result[@"public_key"]) {
NSString* extendUrl = [NSString stringWithFormat:@"%@/keys/extend?pk=%@",
PORTAL_BASE, result[@"public_key"]];
printf("\n%sOpening browser to extend key...%s\n", [BLUE UTF8String], [RESET UTF8String]);
openBrowser(extendUrl);
}
exit(1);
}
printf("%sValid%s\n", [GREEN UTF8String], [RESET UTF8String]);
printf("Public Key: %s\n", [result[@"public_key"] UTF8String] ?: "N/A");
printf("Tier: %s\n", [result[@"tier"] UTF8String] ?: "N/A");
printf("Status: %s\n", [result[@"status"] UTF8String] ?: "N/A");
printf("Expires: %s\n", [result[@"expires_at"] UTF8String] ?: "N/A");
printf("Time Remaining: %s\n", [result[@"time_remaining"] UTF8String] ?: "N/A");
printf("Rate Limit: %s\n", [result[@"rate_limit"] UTF8String] ?: "N/A");
printf("Burst: %s\n", [result[@"burst"] UTF8String] ?: "N/A");
printf("Concurrency: %s\n", [result[@"concurrency"] UTF8String] ?: "N/A");
if (shouldExtend && result[@"public_key"]) {
NSString* extendUrl = [NSString stringWithFormat:@"%@/keys/extend?pk=%@",
PORTAL_BASE, result[@"public_key"]];
printf("\n%sOpening browser to extend key...%s\n", [BLUE UTF8String], [RESET UTF8String]);
openBrowser(extendUrl);
}
}
void cmdKey(NSArray* args) {
NSString* apiKey = getApiKey();
BOOL shouldExtend = NO;
for (NSString* arg in args) {
if ([arg isEqualToString:@"--extend"]) {
shouldExtend = YES;
}
}
validateKey(apiKey, shouldExtend);
}
void cmdSession(NSArray* args) {
NSString* apiKey = getApiKey();
BOOL listMode = NO;
@ -481,6 +591,7 @@ int main(int argc, const char* argv[]) {
fprintf(stderr, "Usage: un.m [options] <source_file>\n");
fprintf(stderr, " un.m session [options]\n");
fprintf(stderr, " un.m service [options]\n");
fprintf(stderr, " un.m key [options]\n");
return 1;
}
@ -495,6 +606,8 @@ int main(int argc, const char* argv[]) {
cmdSession([args subarrayWithRange:NSMakeRange(1, [args count] - 1)]);
} else if ([firstArg isEqualToString:@"service"]) {
cmdService([args subarrayWithRange:NSMakeRange(1, [args count] - 1)]);
} else if ([firstArg isEqualToString:@"key"]) {
cmdKey([args subarrayWithRange:NSMakeRange(1, [args count] - 1)]);
} else {
cmdExecute(args);
}

30
un.ml
View file

@ -276,24 +276,34 @@ let display_key_info response extend =
let status = extract_json_value response "status" in
let public_key = extract_json_value response "public_key" in
let tier = extract_json_value response "tier" in
let expires_at = extract_json_value response "expires_at" in
let valid_through = extract_json_value response "valid_through_datetime" in
let valid_for = extract_json_value response "valid_for_human" in
let rate_limit = extract_json_value response "rate_per_minute" in
let burst = extract_json_value response "burst" in
let concurrency = extract_json_value response "concurrency" in
let expired_at = extract_json_value response "expired_at_datetime" in
match status with
| Some "valid" ->
Printf.printf "%sValid%s\n" green reset;
(match public_key with Some pk -> Printf.printf "Public Key: %s\n" pk | None -> ());
(match tier with Some t -> Printf.printf "Tier: %s\n" t | None -> ());
(match expires_at with Some exp -> Printf.printf "Expires: %s\n" exp | None -> ());
Printf.printf "%sValid%s\n\n" green reset;
(match public_key with Some pk -> Printf.printf "Public Key: %s\n" pk | None -> ());
(match tier with Some t -> Printf.printf "Tier: %s\n" t | None -> ());
Printf.printf "Status: valid\n";
(match valid_through with Some exp -> Printf.printf "Expires: %s\n" exp | None -> ());
(match valid_for with Some vf -> Printf.printf "Time Remaining: %s\n" vf | None -> ());
(match rate_limit with Some r -> Printf.printf "Rate Limit: %s/min\n" r | None -> ());
(match burst with Some b -> Printf.printf "Burst: %s\n" b | None -> ());
(match concurrency with Some c -> Printf.printf "Concurrency: %s\n" c | None -> ());
if extend then
(match public_key with
| Some pk -> open_browser (Printf.sprintf "%s/keys/extend?pk=%s" portal_base pk)
| None -> ())
| Some "expired" ->
Printf.printf "%sExpired%s\n" red reset;
(match public_key with Some pk -> Printf.printf "Public Key: %s\n" pk | None -> ());
(match tier with Some t -> Printf.printf "Tier: %s\n" t | None -> ());
(match expires_at with Some exp -> Printf.printf "Expired: %s\n" exp | None -> ());
Printf.printf "%sTo renew: Visit %s/keys/extend%s\n" yellow portal_base reset;
Printf.printf "%sExpired%s\n\n" red reset;
(match public_key with Some pk -> Printf.printf "Public Key: %s\n" pk | None -> ());
(match tier with Some t -> Printf.printf "Tier: %s\n" t | None -> ());
(match expired_at with Some exp -> Printf.printf "Expired: %s\n" exp | None -> ());
Printf.printf "\n%sTo renew:%s Visit %s/keys/extend\n" yellow reset portal_base;
if extend then
(match public_key with
| Some pk -> open_browser (Printf.sprintf "%s/keys/extend?pk=%s" portal_base pk)

84
un.pl
View file

@ -362,9 +362,22 @@ sub cmd_service {
exit 1;
}
sub cmd_key {
my ($options) = @_;
my $api_key = get_api_key($options->{api_key});
sub open_browser {
my ($url) = @_;
# Try different browser open commands based on platform
if ($^O eq 'darwin') {
system('open', $url);
} elsif ($^O eq 'MSWin32') {
system('start', $url);
} else {
# Linux/Unix
system('xdg-open', $url, '>/dev/null', '2>&1', '&');
}
}
sub validate_key {
my ($api_key, $should_extend) = @_;
# Call /keys/validate endpoint
my $url = "$PORTAL_BASE/keys/validate";
@ -374,47 +387,48 @@ sub cmd_key {
$request->header('Content-Type' => 'application/json');
my $response = $ua->request($request);
unless ($response->is_success) {
print STDERR "${RED}Error: HTTP ", $response->code, " - ", $response->content, "${RESET}\n";
exit 1;
}
my $result = decode_json($response->content);
# Handle different states
my $status = $result->{status} || 'unknown';
# Handle --extend flag first
if ($should_extend) {
my $public_key = $result->{public_key};
if ($public_key) {
my $extend_url = "$PORTAL_BASE/keys/extend?pk=$public_key";
print "${BLUE}Opening browser to extend key...${RESET}\n";
open_browser($extend_url);
return;
} else {
print STDERR "${RED}Error: Could not retrieve public key${RESET}\n";
exit 1;
}
}
if ($status eq 'valid') {
print "${GREEN}Valid${RESET}\n";
print "Public Key: ", ($result->{public_key} // 'N/A'), "\n";
print "Tier: ", ($result->{tier} // 'N/A'), "\n";
print "Expires: ", ($result->{expires_at} // 'N/A'), "\n";
} elsif ($status eq 'expired') {
# Check if key is expired
if ($result->{expired}) {
print "${RED}Expired${RESET}\n";
print "Public Key: ", ($result->{public_key} // 'N/A'), "\n";
print "Tier: ", ($result->{tier} // 'N/A'), "\n";
print "Expired: ", ($result->{expired_at} // 'N/A'), "\n";
print "Expired: ", ($result->{expires_at} // 'N/A'), "\n";
print "${YELLOW}To renew: Visit https://unsandbox.com/keys/extend${RESET}\n";
# Handle --extend flag for expired keys
if ($options->{extend} && $result->{public_key}) {
my $extend_url = "$PORTAL_BASE/keys/extend?pk=$result->{public_key}";
print "\n${BLUE}Opening browser to: $extend_url${RESET}\n";
system("xdg-open", $extend_url) if -x "/usr/bin/xdg-open";
}
} elsif ($status eq 'invalid') {
print "${RED}Invalid${RESET}\n";
} else {
print "${YELLOW}Unknown status: $status${RESET}\n";
exit 1;
}
# Handle --extend flag for valid keys
if ($options->{extend} && $status eq 'valid' && $result->{public_key}) {
my $extend_url = "$PORTAL_BASE/keys/extend?pk=$result->{public_key}";
print "\n${BLUE}Opening browser to: $extend_url${RESET}\n";
system("xdg-open", $extend_url) if -x "/usr/bin/xdg-open";
}
# Valid key
print "${GREEN}Valid${RESET}\n";
print "Public Key: ", ($result->{public_key} // 'N/A'), "\n";
print "Tier: ", ($result->{tier} // 'N/A'), "\n";
print "Status: ", ($result->{status} // 'N/A'), "\n";
print "Expires: ", ($result->{expires_at} // 'N/A'), "\n";
print "Time Remaining: ", ($result->{time_remaining} // 'N/A'), "\n";
print "Rate Limit: ", ($result->{rate_limit} // 'N/A'), "\n";
print "Burst: ", ($result->{burst} // 'N/A'), "\n";
print "Concurrency: ", ($result->{concurrency} // 'N/A'), "\n";
}
sub cmd_key {
my ($options) = @_;
my $api_key = get_api_key($options->{api_key});
validate_key($api_key, $options->{extend});
}
sub main {

25
un.pro
View file

@ -39,6 +39,9 @@
:- initialization(main, main).
% Constants
portal_base('https://unsandbox.com').
% Extension to language mapping
ext_lang('.jl', 'julia').
ext_lang('.r', 'r').
@ -198,6 +201,26 @@ service_create(Name, Ports, Bootstrap, ServiceType) :-
[ApiKey, Json]),
shell(Cmd, 0).
% Key validate
validate_key(Extend) :-
get_api_key(ApiKey),
portal_base(PortalBase),
( Extend = true
-> % Build command for --extend mode
format(atom(Cmd),
'RESP=$(curl -s -X POST ~w/keys/validate -H "Content-Type: application/json" -H "Authorization: Bearer ~w"); PUBLIC_KEY=$(echo "$RESP" | jq -r ".public_key // \\"N/A\\""); xdg-open "~w/keys/extend?pk=$PUBLIC_KEY" 2>/dev/null',
[PortalBase, ApiKey, PortalBase])
; % Build command for normal validation
format(atom(Cmd),
'curl -s -X POST ~w/keys/validate -H "Content-Type: application/json" -H "Authorization: Bearer ~w" -o /tmp/unsandbox_key_resp.json; STATUS=$?; if [ $STATUS -ne 0 ]; then echo -e "\\x1b[31mInvalid\\x1b[0m"; exit 1; fi; EXPIRED=$(jq -r ".expired // false" /tmp/unsandbox_key_resp.json); if [ "$EXPIRED" = "true" ]; then echo -e "\\x1b[31mExpired\\x1b[0m"; echo "Public Key: $(jq -r ".public_key // \\"N/A\\"" /tmp/unsandbox_key_resp.json)"; echo "Tier: $(jq -r ".tier // \\"N/A\\"" /tmp/unsandbox_key_resp.json)"; echo "Expired: $(jq -r ".expires_at // \\"N/A\\"" /tmp/unsandbox_key_resp.json)"; echo -e "\\x1b[33mTo renew: Visit https://unsandbox.com/keys/extend\\x1b[0m"; rm -f /tmp/unsandbox_key_resp.json; exit 1; else echo -e "\\x1b[32mValid\\x1b[0m"; echo "Public Key: $(jq -r ".public_key // \\"N/A\\"" /tmp/unsandbox_key_resp.json)"; echo "Tier: $(jq -r ".tier // \\"N/A\\"" /tmp/unsandbox_key_resp.json)"; echo "Status: $(jq -r ".status // \\"N/A\\"" /tmp/unsandbox_key_resp.json)"; echo "Expires: $(jq -r ".expires_at // \\"N/A\\"" /tmp/unsandbox_key_resp.json)"; echo "Time Remaining: $(jq -r ".time_remaining // \\"N/A\\"" /tmp/unsandbox_key_resp.json)"; echo "Rate Limit: $(jq -r ".rate_limit // \\"N/A\\"" /tmp/unsandbox_key_resp.json)"; echo "Burst: $(jq -r ".burst // \\"N/A\\"" /tmp/unsandbox_key_resp.json)"; echo "Concurrency: $(jq -r ".concurrency // \\"N/A\\"" /tmp/unsandbox_key_resp.json)"; fi; rm -f /tmp/unsandbox_key_resp.json',
[PortalBase, ApiKey])
),
shell(Cmd, 0).
% Handle key subcommand
handle_key(['--extend'|_]) :- validate_key(true).
handle_key(_) :- validate_key(false).
% Handle session subcommand
handle_session(['--list'|_]) :- session_list.
handle_session(['-l'|_]) :- session_list.
@ -261,6 +284,8 @@ main(Argv) :-
-> handle_session(Rest)
; Argv = ['service'|Rest]
-> handle_service(Rest)
; Argv = ['key'|Rest]
-> handle_key(Rest)
; Argv = [Filename|_]
-> execute_file(Filename)
; write(user_error, 'Error: Invalid arguments\n'),

69
un.ps1
View file

@ -43,6 +43,7 @@
# pwsh un.ps1 service [options]
$API_BASE = "https://api.unsandbox.com"
$PORTAL_BASE = "https://unsandbox.com"
$EXT_MAP = @{
".ps1" = "powershell"; ".py" = "python"; ".js" = "javascript"
@ -68,7 +69,7 @@ function Get-ApiKey {
}
function Invoke-Api {
param($Endpoint, $Method = "GET", $Body = $null)
param($Endpoint, $Method = "GET", $Body = $null, $BaseUrl = $null)
$apiKey = Get-ApiKey
$headers = @{
@ -76,7 +77,8 @@ function Invoke-Api {
"Content-Type" = "application/json"
}
$uri = "$API_BASE$Endpoint"
$base = if ($BaseUrl) { $BaseUrl } else { $API_BASE }
$uri = "$base$Endpoint"
try {
if ($Body) {
@ -164,6 +166,63 @@ function Invoke-Session {
$result | ConvertTo-Json -Depth 5
}
function Invoke-Key {
param($Args)
$extend = $Args -contains "--extend"
try {
$result = Invoke-Api -Endpoint "/keys/validate" -Method "POST" -BaseUrl $PORTAL_BASE
# Handle --extend flag
if ($extend) {
$publicKey = $result.public_key
if ($publicKey) {
$url = "$PORTAL_BASE/keys/extend?pk=$publicKey"
Write-Host "`e[34mOpening browser to extend key...`e[0m"
if ($IsWindows) {
Start-Process $url
} elseif ($IsMacOS) {
& open $url
} elseif ($IsLinux) {
& xdg-open $url
} else {
Write-Host "`e[33mPlease open manually: $url`e[0m"
}
return
} else {
Write-Error "Error: Could not retrieve public key"
exit 1
}
}
# Check if key is expired
if ($result.expired) {
Write-Host "`e[31mExpired`e[0m"
Write-Host "Public Key: $($result.public_key ?? 'N/A')"
Write-Host "Tier: $($result.tier ?? 'N/A')"
Write-Host "Expired: $($result.expires_at ?? 'N/A')"
Write-Host "`e[33mTo renew: Visit $PORTAL_BASE/keys/extend`e[0m"
exit 1
}
# Valid key
Write-Host "`e[32mValid`e[0m"
Write-Host "Public Key: $($result.public_key ?? 'N/A')"
Write-Host "Tier: $($result.tier ?? 'N/A')"
Write-Host "Status: $($result.status ?? 'N/A')"
Write-Host "Expires: $($result.expires_at ?? 'N/A')"
Write-Host "Time Remaining: $($result.time_remaining ?? 'N/A')"
Write-Host "Rate Limit: $($result.rate_limit ?? 'N/A')"
Write-Host "Burst: $($result.burst ?? 'N/A')"
Write-Host "Concurrency: $($result.concurrency ?? 'N/A')"
} catch {
Write-Host "`e[31mInvalid`e[0m"
Write-Host "Reason: $($_.Exception.Message)"
exit 1
}
}
function Invoke-Service {
param($Args)
@ -253,6 +312,7 @@ if ($args.Count -eq 0 -or $args[0] -eq "--help" -or $args[0] -eq "-h") {
Usage: pwsh un.ps1 [options] <source_file>
pwsh un.ps1 session [options]
pwsh un.ps1 service [options]
pwsh un.ps1 key [options]
Execute options:
-e KEY=VALUE Environment variable
@ -274,6 +334,9 @@ Service options:
--sleep ID Freeze service
--wake ID Unfreeze service
--destroy ID Destroy service
Key options:
--extend Open browser to extend key
"@
exit 0
}
@ -282,6 +345,8 @@ if ($args[0] -eq "session") {
Invoke-Session -Args $args[1..($args.Count-1)]
} elseif ($args[0] -eq "service") {
Invoke-Service -Args $args[1..($args.Count-1)]
} elseif ($args[0] -eq "key") {
Invoke-Key -Args $args[1..($args.Count-1)]
} else {
# Parse execute args
$sourceFile = $null

74
un.raku
View file

@ -42,6 +42,7 @@
use JSON::Fast;
constant $API_BASE = "https://api.unsandbox.com";
constant $PORTAL_BASE = "https://unsandbox.com";
constant $BLUE = "\e[34m";
constant $RED = "\e[31m";
constant $GREEN = "\e[32m";
@ -462,11 +463,81 @@ sub cmd-service(@args) {
exit 1;
}
sub validate-key(Bool $extend) {
my $api-key = get-api-key();
# Build curl command
my @args = 'curl', '-s', '-X', 'POST';
@args.append: "$PORTAL_BASE/keys/validate";
@args.append: '-H', 'Content-Type: application/json';
@args.append: '-H', "Authorization: Bearer $api-key";
my $proc = run |@args, :out, :err;
my $body = $proc.out.slurp;
my $err-msg = $proc.err.slurp;
if $proc.exitcode != 0 {
say "{$RED}Invalid{$RESET}";
note "Reason: $err-msg" if $err-msg;
exit 1;
}
my %result = from-json($body);
# Handle --extend flag
if $extend {
my $public-key = %result<public_key>;
if $public-key {
say "{$BLUE}Opening browser to extend key...{$RESET}";
run 'xdg-open', "$PORTAL_BASE/keys/extend?pk=$public-key";
return;
} else {
note "{$RED}Error: Could not retrieve public key{$RESET}";
exit 1;
}
}
# Check if key is expired
if %result<expired> {
say "{$RED}Expired{$RESET}";
say "Public Key: {%result<public_key> // 'N/A'}";
say "Tier: {%result<tier> // 'N/A'}";
say "Expired: {%result<expires_at> // 'N/A'}";
say "{$YELLOW}To renew: Visit https://unsandbox.com/keys/extend{$RESET}";
exit 1;
}
# Valid key
say "{$GREEN}Valid{$RESET}";
say "Public Key: {%result<public_key> // 'N/A'}";
say "Tier: {%result<tier> // 'N/A'}";
say "Status: {%result<status> // 'N/A'}";
say "Expires: {%result<expires_at> // 'N/A'}";
say "Time Remaining: {%result<time_remaining> // 'N/A'}";
say "Rate Limit: {%result<rate_limit> // 'N/A'}";
say "Burst: {%result<burst> // 'N/A'}";
say "Concurrency: {%result<concurrency> // 'N/A'}";
}
sub cmd-key(@args) {
my $extend = False;
# Parse arguments
for @args -> $arg {
if $arg eq '--extend' {
$extend = True;
}
}
validate-key($extend);
}
sub MAIN(*@args) {
unless @args {
note "Usage: un.raku [options] <source_file>";
note " un.raku session [options]";
note " un.raku service [options]";
note " un.raku key [options]";
exit 1;
}
@ -477,6 +548,9 @@ sub MAIN(*@args) {
when 'service' {
cmd-service(@args[1..*]);
}
when 'key' {
cmd-key(@args[1..*]);
}
default {
cmd-execute(@args);
}

34
un.scm
View file

@ -181,33 +181,43 @@
(status (json-extract-string response "status"))
(public-key (json-extract-string response "public_key"))
(tier (json-extract-string response "tier"))
(expires-at (json-extract-string response "expires_at")))
(valid-through (json-extract-string response "valid_through_datetime"))
(valid-for (json-extract-string response "valid_for_human"))
(rate-limit (json-extract-string response "rate_per_minute"))
(burst (json-extract-string response "burst"))
(concurrency (json-extract-string response "concurrency"))
(expired-at (json-extract-string response "expired_at_datetime")))
(cond
;; Valid key
((and status (string=? status "valid"))
(format #t "~aValid~a\n" green reset)
(when public-key (format #t "Public Key: ~a\n" public-key))
(when tier (format #t "Tier: ~a\n" tier))
(when expires-at (format #t "Expires: ~a\n" expires-at))
(format #t "~aValid~a\n\n" green reset)
(when public-key (format #t "Public Key: ~a\n" public-key))
(when tier (format #t "Tier: ~a\n" tier))
(format #t "Status: valid\n")
(when valid-through (format #t "Expires: ~a\n" valid-through))
(when valid-for (format #t "Time Remaining: ~a\n" valid-for))
(when rate-limit (format #t "Rate Limit: ~a/min\n" rate-limit))
(when burst (format #t "Burst: ~a\n" burst))
(when concurrency (format #t "Concurrency: ~a\n" concurrency))
(when extend
(if public-key
(let ((url (format #f "~a/keys/extend?pk=~a" portal-base public-key)))
(format #t "~aOpening browser to extend key...~a\n" yellow reset)
(format #t "~aOpening browser to extend key...~a\n" blue reset)
(open-browser url))
(format #t "~aError: No public_key in response~a\n" red reset))))
;; Expired key
((and status (string=? status "expired"))
(format #t "~aExpired~a\n" red reset)
(when public-key (format #t "Public Key: ~a\n" public-key))
(when tier (format #t "Tier: ~a\n" tier))
(when expires-at (format #t "Expired: ~a\n" expires-at))
(format #t "~aTo renew: Visit ~a/keys/extend~a\n" yellow portal-base reset)
(format #t "~aExpired~a\n\n" red reset)
(when public-key (format #t "Public Key: ~a\n" public-key))
(when tier (format #t "Tier: ~a\n" tier))
(when expired-at (format #t "Expired: ~a\n" expired-at))
(format #t "\n~aTo renew:~a Visit ~a/keys/extend\n" yellow reset portal-base)
(when extend
(if public-key
(let ((url (format #f "~a/keys/extend?pk=~a" portal-base public-key)))
(format #t "~aOpening browser...~a\n" yellow reset)
(format #t "~aOpening browser...~a\n" blue reset)
(open-browser url))
(format #t "~aError: No public_key in response~a\n" red reset))))

126
un.ts
View file

@ -186,6 +186,44 @@ function apiRequest(endpoint: string, method: string = "GET", data: any = null,
});
}
function portalRequest(endpoint: string, method: string = "GET", data: any = null, apiKey: string): Promise<any> {
return new Promise((resolve, reject) => {
const url = new URL(PORTAL_BASE + endpoint);
const options: https.RequestOptions = {
hostname: url.hostname,
path: url.pathname + url.search,
method: method,
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
timeout: 30000
};
const req = https.request(options, (res) => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => {
try {
const parsed = JSON.parse(body);
resolve(parsed);
} catch (e) {
resolve({ error: body, status: res.statusCode });
}
});
});
req.on('error', (e) => {
reject(e);
});
if (data) {
req.write(JSON.stringify(data));
}
req.end();
});
}
async function cmdExecute(args: Args): Promise<void> {
const apiKey = getApiKey(args.apiKey);
@ -381,42 +419,76 @@ async function cmdService(args: Args): Promise<void> {
process.exit(1);
}
async function cmdKey(args: Args): Promise<void> {
const apiKey = getApiKey(args.apiKey);
function openBrowser(url: string): void {
const { exec } = require('child_process');
const platform = process.platform;
let command: string;
// Validate the key
const result = await apiRequest("/keys/validate", "POST", {}, apiKey);
if (platform === 'darwin') {
command = `open "${url}"`;
} else if (platform === 'win32') {
command = `start "${url}"`;
} else {
command = `xdg-open "${url}"`;
}
if (result.status === "valid") {
exec(command, (error: any) => {
if (error) {
console.error(`${RED}Error opening browser: ${error.message}${RESET}`);
console.log(`Please visit: ${url}`);
}
});
}
async function validateKey(apiKey: string, shouldExtend: boolean): Promise<void> {
try {
const result = await portalRequest("/keys/validate", "POST", {}, apiKey);
// Handle --extend flag first
if (shouldExtend) {
const public_key = result.public_key;
if (public_key) {
const extendUrl = `${PORTAL_BASE}/keys/extend?pk=${encodeURIComponent(public_key)}`;
console.log(`${BLUE}Opening browser to extend key...${RESET}`);
openBrowser(extendUrl);
return;
} else {
console.error(`${RED}Error: Could not retrieve public key${RESET}`);
process.exit(1);
}
}
// Check if key is expired
if (result.expired) {
console.log(`${RED}Expired${RESET}`);
console.log(`Public Key: ${result.public_key || 'N/A'}`);
console.log(`Tier: ${result.tier || 'N/A'}`);
console.log(`Expired: ${result.expires_at || 'N/A'}`);
console.log(`${YELLOW}To renew: Visit https://unsandbox.com/keys/extend${RESET}`);
process.exit(1);
}
// Valid key
console.log(`${GREEN}Valid${RESET}`);
console.log(`Public Key: ${result.public_key || 'N/A'}`);
console.log(`Tier: ${result.tier || 'N/A'}`);
console.log(`Status: ${result.status || 'N/A'}`);
console.log(`Expires: ${result.expires_at || 'N/A'}`);
// Handle --extend flag
if (args.extend && result.public_key) {
const extendUrl = `${PORTAL_BASE}/keys/extend?pk=${result.public_key}`;
console.log(`\n${BLUE}Opening: ${extendUrl}${RESET}`);
// Try to open browser using common commands
const { exec } = require('child_process');
exec(`xdg-open "${extendUrl}" || open "${extendUrl}" || start "${extendUrl}"`, (error: any) => {
if (error) {
console.error(`${YELLOW}Could not open browser automatically. Visit: ${extendUrl}${RESET}`);
}
});
}
} else if (result.status === "expired") {
console.log(`${RED}Expired${RESET}`);
console.log(`Public Key: ${result.public_key || 'N/A'}`);
console.log(`Tier: ${result.tier || 'N/A'}`);
console.log(`Expired: ${result.expires_at || 'N/A'}`);
console.log(`${YELLOW}To renew: Visit ${PORTAL_BASE}/keys/extend${RESET}`);
} else {
console.log(`${RED}Invalid${RESET}`);
console.log(`Time Remaining: ${result.time_remaining || 'N/A'}`);
console.log(`Rate Limit: ${result.rate_limit || 'N/A'}`);
console.log(`Burst: ${result.burst || 'N/A'}`);
console.log(`Concurrency: ${result.concurrency || 'N/A'}`);
} catch (error: any) {
console.error(`${RED}Error validating key: ${error.message}${RESET}`);
process.exit(1);
}
}
async function cmdKey(args: Args): Promise<void> {
const apiKey = getApiKey(args.apiKey);
await validateKey(apiKey, args.extend);
}
function parseArgs(argv: string[]): Args {
const args: Args = {
command: null,

69
un.v
View file

@ -126,17 +126,22 @@ fn extract_json_string(json string, key string) string {
}
fn cmd_key(extend bool, api_key string) {
cmd := "curl -s -X POST '${api_base}/keys/validate' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${api_key}' -d '{}'"
cmd := "curl -s -X POST '${portal_base}/keys/validate' -H 'Content-Type: application/json' -H 'Authorization: Bearer ${api_key}' -d '{}'"
result := exec_curl(cmd)
status := extract_json_string(result, 'status')
public_key := extract_json_string(result, 'public_key')
tier := extract_json_string(result, 'tier')
expired_at := extract_json_string(result, 'expired_at')
status := extract_json_string(result, 'status')
expires_at := extract_json_string(result, 'expires_at')
time_remaining := extract_json_string(result, 'time_remaining')
rate_limit := extract_json_string(result, 'rate_limit')
burst := extract_json_string(result, 'burst')
concurrency := extract_json_string(result, 'concurrency')
expired := extract_json_string(result, 'expired')
if extend && public_key != '' {
url := '${portal_base}/keys/extend?pk=${public_key}'
println('${yellow}Opening browser: ${url}${reset}')
println('${blue}Opening browser to extend key...${reset}')
// Try xdg-open (Linux), open (macOS), or start (Windows)
os.execute('xdg-open "${url}"') or {
@ -149,30 +154,40 @@ fn cmd_key(extend bool, api_key string) {
return
}
match status {
'valid' {
println('${green}Valid${reset}')
println('Public Key: ${public_key}')
println('Tier: ${tier}')
if expired_at != '' {
println('Expires: ${expired_at}')
}
}
'expired' {
println('${red}Expired${reset}')
println('Public Key: ${public_key}')
println('Tier: ${tier}')
if expired_at != '' {
println('Expired: ${expired_at}')
}
println('${yellow}To renew: Visit ${portal_base}/keys/extend${reset}')
}
'invalid' {
println('${red}Invalid${reset}')
}
else {
println('${yellow}Unknown status: ${status}${reset}')
if expired == 'true' {
println('${red}Expired${reset}')
println('Public Key: ${public_key}')
println('Tier: ${tier}')
if expires_at != '' {
println('Expired: ${expires_at}')
}
println('${yellow}To renew: Visit https://unsandbox.com/keys/extend${reset}')
exit(1)
}
// Valid key
println('${green}Valid${reset}')
println('Public Key: ${public_key}')
if tier != '' {
println('Tier: ${tier}')
}
if status != '' {
println('Status: ${status}')
}
if expires_at != '' {
println('Expires: ${expires_at}')
}
if time_remaining != '' {
println('Time Remaining: ${time_remaining}')
}
if rate_limit != '' {
println('Rate Limit: ${rate_limit}')
}
if burst != '' {
println('Burst: ${burst}')
}
if concurrency != '' {
println('Concurrency: ${concurrency}')
}
}

View file

@ -39,6 +39,7 @@
// Full-featured CLI matching un.c/un.py capabilities
const API_BASE = "https://api.unsandbox.com";
const PORTAL_BASE = "https://unsandbox.com";
const BLUE = "\x1b[34m";
const RED = "\x1b[31m";
const GREEN = "\x1b[32m";
@ -92,8 +93,10 @@ async function apiRequest(
method: string,
data?: unknown,
apiKey?: string,
baseUrl?: string,
): Promise<any> {
const url = `${API_BASE}${endpoint}`;
const base = baseUrl || API_BASE;
const url = `${base}${endpoint}`;
const headers: Record<string, string> = {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
@ -328,6 +331,69 @@ async function cmdSession(args: string[]) {
);
}
async function cmdKey(args: string[]) {
const apiKey = getApiKey();
let extend = false;
// Parse arguments
for (let i = 0; i < args.length; i++) {
if (args[i] === "--extend") {
extend = true;
}
}
try {
const result = await apiRequest("/keys/validate", "POST", undefined, apiKey, PORTAL_BASE);
// Handle --extend flag
if (extend) {
const publicKey = result.public_key;
if (publicKey) {
const url = `${PORTAL_BASE}/keys/extend?pk=${publicKey}`;
console.log(`${BLUE}Opening browser to extend key...${RESET}`);
if (Deno.build.os === "darwin") {
await new Deno.Command("open", { args: [url] }).output();
} else if (Deno.build.os === "linux") {
await new Deno.Command("xdg-open", { args: [url] }).output();
} else if (Deno.build.os === "windows") {
await new Deno.Command("cmd", { args: ["/c", "start", url] }).output();
} else {
console.log(`${YELLOW}Please open manually: ${url}${RESET}`);
}
return;
} else {
console.error(`${RED}Error: Could not retrieve public key${RESET}`);
Deno.exit(1);
}
}
// Check if key is expired
if (result.expired) {
console.log(`${RED}Expired${RESET}`);
console.log(`Public Key: ${result.public_key || "N/A"}`);
console.log(`Tier: ${result.tier || "N/A"}`);
console.log(`Expired: ${result.expires_at || "N/A"}`);
console.log(`${YELLOW}To renew: Visit ${PORTAL_BASE}/keys/extend${RESET}`);
Deno.exit(1);
}
// Valid key
console.log(`${GREEN}Valid${RESET}`);
console.log(`Public Key: ${result.public_key || "N/A"}`);
console.log(`Tier: ${result.tier || "N/A"}`);
console.log(`Status: ${result.status || "N/A"}`);
console.log(`Expires: ${result.expires_at || "N/A"}`);
console.log(`Time Remaining: ${result.time_remaining || "N/A"}`);
console.log(`Rate Limit: ${result.rate_limit || "N/A"}`);
console.log(`Burst: ${result.burst || "N/A"}`);
console.log(`Concurrency: ${result.concurrency || "N/A"}`);
} catch (e) {
console.log(`${RED}Invalid${RESET}`);
console.log(`Reason: ${e}`);
Deno.exit(1);
}
}
async function cmdService(args: string[]) {
const apiKey = getApiKey();
let listMode = false;
@ -509,6 +575,7 @@ async function main() {
console.error("Usage: un_deno.ts [options] <source_file>");
console.error(" un_deno.ts session [options]");
console.error(" un_deno.ts service [options]");
console.error(" un_deno.ts key [options]");
Deno.exit(1);
}
@ -518,6 +585,8 @@ async function main() {
await cmdSession(args.slice(1));
} else if (firstArg === "service") {
await cmdService(args.slice(1));
} else if (firstArg === "key") {
await cmdKey(args.slice(1));
} else {
await cmdExecute(args);
}

View file

@ -50,6 +50,7 @@
#include <unistd.h>
#define API_BASE "https://api.unsandbox.com"
#define PORTAL_BASE "https://unsandbox.com"
#define BLUE "\033[34m"
#define RED "\033[31m"
#define GREEN "\033[32m"
@ -312,6 +313,142 @@ void cmd_session(int list, const char *kill, const char *shell, const char *netw
printf("\n%sSession created%s\n", GREEN, RESET);
}
void cmd_key(int extend, const char *api_key) {
char cmd[4096];
snprintf(cmd, sizeof(cmd),
"curl -s -X POST '%s/keys/validate' "
"-H 'Content-Type: application/json' "
"-H 'Authorization: Bearer %s'",
PORTAL_BASE, api_key);
FILE *curl = popen(cmd, "r");
if (!curl) {
fprintf(stderr, "%sError running curl%s\n", RED, RESET);
exit(1);
}
char response[16384];
size_t resp_len = fread(response, 1, sizeof(response) - 1, curl);
response[resp_len] = 0;
pclose(curl);
// Parse JSON response (simple string matching)
char *public_key_start = strstr(response, "\"public_key\":\"");
char public_key[256] = "";
if (public_key_start) {
public_key_start += 14;
char *end = strchr(public_key_start, '"');
if (end) {
size_t len = end - public_key_start;
if (len < sizeof(public_key)) {
strncpy(public_key, public_key_start, len);
public_key[len] = 0;
}
}
}
// Handle --extend flag
if (extend) {
if (public_key[0]) {
printf("%sOpening browser to extend key...%s\n", BLUE, RESET);
char open_cmd[512];
#ifdef __APPLE__
snprintf(open_cmd, sizeof(open_cmd), "open '%s/keys/extend?pk=%s'", PORTAL_BASE, public_key);
#elif __linux__
snprintf(open_cmd, sizeof(open_cmd), "xdg-open '%s/keys/extend?pk=%s'", PORTAL_BASE, public_key);
#else
snprintf(open_cmd, sizeof(open_cmd), "start '%s/keys/extend?pk=%s'", PORTAL_BASE, public_key);
#endif
system(open_cmd);
return;
} else {
fprintf(stderr, "%sError: Could not retrieve public key%s\n", RED, RESET);
exit(1);
}
}
// Check if expired
if (strstr(response, "\"expired\":true")) {
printf("%sExpired%s\n", RED, RESET);
printf("Public Key: %s\n", public_key[0] ? public_key : "N/A");
char *tier_start = strstr(response, "\"tier\":\"");
if (tier_start) {
tier_start += 8;
char *end = strchr(tier_start, '"');
if (end) printf("Tier: %.*s\n", (int)(end - tier_start), tier_start);
}
char *expires_start = strstr(response, "\"expires_at\":\"");
if (expires_start) {
expires_start += 14;
char *end = strchr(expires_start, '"');
if (end) printf("Expired: %.*s\n", (int)(end - expires_start), expires_start);
}
printf("%sTo renew: Visit %s/keys/extend%s\n", YELLOW, PORTAL_BASE, RESET);
exit(1);
}
// Valid key
printf("%sValid%s\n", GREEN, RESET);
printf("Public Key: %s\n", public_key[0] ? public_key : "N/A");
// Extract and print other fields
char *tier_start = strstr(response, "\"tier\":\"");
if (tier_start) {
tier_start += 8;
char *end = strchr(tier_start, '"');
if (end) printf("Tier: %.*s\n", (int)(end - tier_start), tier_start);
}
char *status_start = strstr(response, "\"status\":\"");
if (status_start) {
status_start += 10;
char *end = strchr(status_start, '"');
if (end) printf("Status: %.*s\n", (int)(end - status_start), status_start);
}
char *expires_start = strstr(response, "\"expires_at\":\"");
if (expires_start) {
expires_start += 14;
char *end = strchr(expires_start, '"');
if (end) printf("Expires: %.*s\n", (int)(end - expires_start), expires_start);
}
char *time_rem_start = strstr(response, "\"time_remaining\":\"");
if (time_rem_start) {
time_rem_start += 18;
char *end = strchr(time_rem_start, '"');
if (end) printf("Time Remaining: %.*s\n", (int)(end - time_rem_start), time_rem_start);
}
char *rate_start = strstr(response, "\"rate_limit\":");
if (rate_start) {
rate_start += 13;
char *end = strchr(rate_start, ',');
if (!end) end = strchr(rate_start, '}');
if (end) printf("Rate Limit: %.*s\n", (int)(end - rate_start), rate_start);
}
char *burst_start = strstr(response, "\"burst\":");
if (burst_start) {
burst_start += 8;
char *end = strchr(burst_start, ',');
if (!end) end = strchr(burst_start, '}');
if (end) printf("Burst: %.*s\n", (int)(end - burst_start), burst_start);
}
char *conc_start = strstr(response, "\"concurrency\":");
if (conc_start) {
conc_start += 14;
char *end = strchr(conc_start, ',');
if (!end) end = strchr(conc_start, '}');
if (end) printf("Concurrency: %.*s\n", (int)(end - conc_start), conc_start);
}
}
void cmd_service(const char *name, const char *ports, const char *domains, const char *service_type, const char *bootstrap, int list, const char *info, const char *logs, const char *tail, const char *sleep_svc, const char *wake, const char *destroy, const char *network, int vcpu, const char *api_key) {
char cmd[8192];
@ -438,10 +575,21 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "Usage: %s [options] <source_file>\n", argv[0]);
fprintf(stderr, " %s session [options]\n", argv[0]);
fprintf(stderr, " %s service [options]\n", argv[0]);
fprintf(stderr, " %s key [options]\n", argv[0]);
return 1;
}
// Parse command
if (strcmp(argv[1], "key") == 0) {
int extend = 0;
for (int i = 2; i < argc; i++) {
if (strcmp(argv[i], "--extend") == 0) extend = 1;
else if (strcmp(argv[i], "-k") == 0 && i + 1 < argc) api_key = argv[++i];
}
cmd_key(extend, api_key);
return 0;
}
if (strcmp(argv[1], "session") == 0) {
int list = 0;
const char *kill = NULL;