Add helpful clock drift message for timestamp auth errors

This commit is contained in:
Russell Ballestrini 2025-12-28 14:36:00 -05:00
parent a4f9bfa377
commit ae8f9ee8c8
8 changed files with 79 additions and 8 deletions

11
un.go
View file

@ -209,7 +209,16 @@ func apiRequest(endpoint, method string, data map[string]interface{}, publicKey,
} }
if resp.StatusCode >= 400 { if resp.StatusCode >= 400 {
fmt.Fprintf(os.Stderr, "%sError: HTTP %d - %s%s\n", Red, resp.StatusCode, string(body), Reset) if resp.StatusCode == 401 && strings.Contains(strings.ToLower(string(body)), "timestamp") {
fmt.Fprintf(os.Stderr, "%sError: Request timestamp expired (must be within 5 minutes of server time)%s\n", Red, Reset)
fmt.Fprintf(os.Stderr, "%sYour computer's clock may have drifted.%s\n", Yellow, Reset)
fmt.Fprintf(os.Stderr, "%sCheck your system time and sync with NTP if needed:%s\n", Yellow, Reset)
fmt.Fprintf(os.Stderr, " Linux: sudo ntpdate -s time.nist.gov\n")
fmt.Fprintf(os.Stderr, " macOS: sudo sntp -sS time.apple.com\n")
fmt.Fprintf(os.Stderr, " Windows: w32tm /resync\n")
} else {
fmt.Fprintf(os.Stderr, "%sError: HTTP %d - %s%s\n", Red, resp.StatusCode, string(body), Reset)
}
os.Exit(1) os.Exit(1)
} }

11
un.js
View file

@ -162,7 +162,16 @@ function apiRequest(endpoint, method = "GET", data = null, publicKey = null, sec
resolve(responseBody); resolve(responseBody);
} }
} else { } else {
console.error(`${RED}Error: HTTP ${res.statusCode} - ${responseBody}${RESET}`); if (res.statusCode === 401 && responseBody.toLowerCase().includes('timestamp')) {
console.error(`${RED}Error: Request timestamp expired (must be within 5 minutes of server time)${RESET}`);
console.error(`${YELLOW}Your computer's clock may have drifted.${RESET}`);
console.error(`${YELLOW}Check your system time and sync with NTP if needed:${RESET}`);
console.error(` Linux: sudo ntpdate -s time.nist.gov`);
console.error(` macOS: sudo sntp -sS time.apple.com`);
console.error(` Windows: w32tm /resync`);
} else {
console.error(`${RED}Error: HTTP ${res.statusCode} - ${responseBody}${RESET}`);
}
process.exit(1); process.exit(1);
} }
}); });

11
un.lua
View file

@ -185,7 +185,16 @@ local function api_request(endpoint, method, data, keys)
end end
if not http_code or tonumber(http_code) < 200 or tonumber(http_code) >= 300 then if not http_code or tonumber(http_code) < 200 or tonumber(http_code) >= 300 then
io.stderr:write(RED .. "Error: HTTP " .. (http_code or "000") .. " - " .. response .. RESET .. "\n") if http_code == "401" and response:lower():find("timestamp") then
io.stderr:write(RED .. "Error: Request timestamp expired (must be within 5 minutes of server time)" .. RESET .. "\n")
io.stderr:write(YELLOW .. "Your computer's clock may have drifted." .. RESET .. "\n")
io.stderr:write(YELLOW .. "Check your system time and sync with NTP if needed:" .. RESET .. "\n")
io.stderr:write(" Linux: sudo ntpdate -s time.nist.gov\n")
io.stderr:write(" macOS: sudo sntp -sS time.apple.com\n")
io.stderr:write(" Windows: w32tm /resync\n")
else
io.stderr:write(RED .. "Error: HTTP " .. (http_code or "000") .. " - " .. response .. RESET .. "\n")
end
os.exit(1) os.exit(1)
end end

11
un.php
View file

@ -162,7 +162,16 @@ function api_request($endpoint, $method = 'GET', $data = null, $keys = null) {
curl_close($ch); curl_close($ch);
if ($http_code < 200 || $http_code >= 300) { if ($http_code < 200 || $http_code >= 300) {
fwrite(STDERR, RED . "Error: HTTP $http_code - $response" . RESET . "\n"); if ($http_code === 401 && stripos($response, 'timestamp') !== false) {
fwrite(STDERR, RED . "Error: Request timestamp expired (must be within 5 minutes of server time)" . RESET . "\n");
fwrite(STDERR, YELLOW . "Your computer's clock may have drifted." . RESET . "\n");
fwrite(STDERR, YELLOW . "Check your system time and sync with NTP if needed:" . RESET . "\n");
fwrite(STDERR, " Linux: sudo ntpdate -s time.nist.gov\n");
fwrite(STDERR, " macOS: sudo sntp -sS time.apple.com\n");
fwrite(STDERR, " Windows: w32tm /resync\n");
} else {
fwrite(STDERR, RED . "Error: HTTP $http_code - $response" . RESET . "\n");
}
exit(1); exit(1);
} }

11
un.pl
View file

@ -153,7 +153,16 @@ sub api_request {
my $response = $ua->request($request); my $response = $ua->request($request);
unless ($response->is_success) { unless ($response->is_success) {
print STDERR "${RED}Error: HTTP ", $response->code, " - ", $response->content, "${RESET}\n"; if ($response->code == 401 && $response->content =~ /timestamp/i) {
print STDERR "${RED}Error: Request timestamp expired (must be within 5 minutes of server time)${RESET}\n";
print STDERR "${YELLOW}Your computer's clock may have drifted.${RESET}\n";
print STDERR "${YELLOW}Check your system time and sync with NTP if needed:${RESET}\n";
print STDERR " Linux: sudo ntpdate -s time.nist.gov\n";
print STDERR " macOS: sudo sntp -sS time.apple.com\n";
print STDERR " Windows: w32tm /resync\n";
} else {
print STDERR "${RED}Error: HTTP ", $response->code, " - ", $response->content, "${RESET}\n";
}
exit 1; exit 1;
} }

10
un.py
View file

@ -181,7 +181,15 @@ def api_request(endpoint, method="GET", data=None, public_key=None, secret_key=N
return json.loads(resp.read().decode('utf-8')) return json.loads(resp.read().decode('utf-8'))
except urllib.error.HTTPError as e: except urllib.error.HTTPError as e:
error_body = e.read().decode('utf-8') if e.fp else str(e) error_body = e.read().decode('utf-8') if e.fp else str(e)
print(f"{RED}Error: HTTP {e.code} - {error_body}{RESET}", file=sys.stderr) if e.code == 401 and 'timestamp' in error_body.lower():
print(f"{RED}Error: Request timestamp expired (must be within 5 minutes of server time){RESET}", file=sys.stderr)
print(f"{YELLOW}Your computer's clock may have drifted.{RESET}", file=sys.stderr)
print("Check your system time and sync with NTP if needed:", file=sys.stderr)
print(" Linux: sudo ntpdate -s time.nist.gov", file=sys.stderr)
print(" macOS: sudo sntp -sS time.apple.com", file=sys.stderr)
print(" Windows: w32tm /resync", file=sys.stderr)
else:
print(f"{RED}Error: HTTP {e.code} - {error_body}{RESET}", file=sys.stderr)
sys.exit(1) sys.exit(1)
except urllib.error.URLError as e: except urllib.error.URLError as e:
print(f"{RED}Error: {e.reason}{RESET}", file=sys.stderr) print(f"{RED}Error: {e.reason}{RESET}", file=sys.stderr)

11
un.rb
View file

@ -150,7 +150,16 @@ def api_request(endpoint, method: 'GET', data: nil, keys:)
response = http.request(request) response = http.request(request)
unless response.is_a?(Net::HTTPSuccess) unless response.is_a?(Net::HTTPSuccess)
warn "#{RED}Error: HTTP #{response.code} - #{response.body}#{RESET}" if response.code == '401' && response.body.downcase.include?('timestamp')
warn "#{RED}Error: Request timestamp expired (must be within 5 minutes of server time)#{RESET}"
warn "#{YELLOW}Your computer's clock may have drifted.#{RESET}"
warn "#{YELLOW}Check your system time and sync with NTP if needed:#{RESET}"
warn " Linux: sudo ntpdate -s time.nist.gov"
warn " macOS: sudo sntp -sS time.apple.com"
warn " Windows: w32tm /resync"
else
warn "#{RED}Error: HTTP #{response.code} - #{response.body}#{RESET}"
end
exit 1 exit 1
end end

11
un.sh
View file

@ -190,7 +190,16 @@ api_request() {
local body=$(echo "$response" | head -n-1) local body=$(echo "$response" | head -n-1)
if [[ "$http_code" -lt 200 || "$http_code" -ge 300 ]]; then if [[ "$http_code" -lt 200 || "$http_code" -ge 300 ]]; then
echo -e "${RED}Error: HTTP $http_code - $body${RESET}" >&2 if [[ "$http_code" == "401" ]] && echo "$body" | grep -qi "timestamp"; then
echo -e "${RED}Error: Request timestamp expired (must be within 5 minutes of server time)${RESET}" >&2
echo -e "${YELLOW}Your computer's clock may have drifted.${RESET}" >&2
echo -e "${YELLOW}Check your system time and sync with NTP if needed:${RESET}" >&2
echo -e " Linux: sudo ntpdate -s time.nist.gov" >&2
echo -e " macOS: sudo sntp -sS time.apple.com" >&2
echo -e " Windows: w32tm /resync" >&2
else
echo -e "${RED}Error: HTTP $http_code - $body${RESET}" >&2
fi
exit 1 exit 1
fi fi