Files
osmap_cli/osmap-embed.sh
T

610 lines
19 KiB
Bash

#!/usr/bin/env bash
# ==============================================================================
# OSMAP KAI Embed Token & Map Navigator CLI
# ==============================================================================
# Automates token management (obtain, validate, cache, revoke) and provides
# access to OSMAP KAI protected embed map routes.
# ==============================================================================
set -e
# Color definitions
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
YELLOW='\033[1;33m'
BOLD='\033[1m'
NC='\033[0m' # No Color
# Default values
DEFAULT_ENV="live"
DEFAULT_APP_ID="IrSIcf06QRwUCmsRCZ0JvsVibSfuPUG4"
DEFAULT_APP_SECRET="Z8tPOBHGbwWu9TrIddRqkiDFDymtiPAhMNbSz6aUOOTkqdZoQYuTWXTra5m2mPQa"
CONFIG_FILE=".osmap_credentials"
CACHE_DIR="${HOME}/.cache/osmap"
mkdir -p "$CACHE_DIR"
# Route Definitions: "Route_Key|Display_Name|Path"
ROUTES=(
"executive|Executive Map|/executive"
"rolling|Rolling Map|/rolling"
"iris-jpl|IRIS JPL|/iris-jpl"
"iris-jpl-v2|IRIS JPL (v2)|/v2/iris-jpl"
"accelerometer|Executive Accelerometer|/executive/accelerometer"
"genset|Genset Monitoring|/genset"
"managerial|Managerial / Asset View|/managerial"
"fatigue|Fatigue Monitoring|/fatigue"
"sigap-tracker|SIGAP Tracker|/sigap-tracker"
"sigap-dashboard|SIGAP Dashboard|/sigap-dashboard"
"railway-cargo-system|Railway Cargo System (RCS)|/railway-cargo-system"
)
# Helper: Resolve Base URL
get_base_url() {
local env_name="$1"
case "$env_name" in
live)
echo "https://live.osmap.id"
;;
beta)
echo "https://beta.osmap.id"
;;
staging)
echo "https://staging.osmap.id"
;;
demo)
echo "https://demo.osmap.id"
;;
local)
echo "http://localhost:8000"
;;
http://*|https://*)
echo "$env_name"
;;
*)
echo "https://${env_name}"
;;
esac
}
# Helper: Copy to Clipboard
copy_to_clipboard() {
local text="$1"
if command -v pbcopy >/dev/null 2>&1; then
echo -n "$text" | pbcopy
return 0
elif command -v clip.exe >/dev/null 2>&1; then
printf "%s" "$text" | clip.exe
return 0
elif command -v clip >/dev/null 2>&1; then
printf "%s" "$text" | clip
return 0
elif command -v wl-copy >/dev/null 2>&1; then
echo -n "$text" | wl-copy
return 0
elif command -v xclip >/dev/null 2>&1; then
echo -n "$text" | xclip -selection clipboard
return 0
elif command -v xsel >/dev/null 2>&1; then
echo -n "$text" | xsel --clipboard --input
return 0
elif command -v powershell.exe >/dev/null 2>&1; then
printf "%s" "$text" | powershell.exe -NoProfile -Command "Set-Clipboard" >/dev/null 2>&1
return 0
fi
return 1
}
# Helper: Open URL in Browser
open_url() {
local url="$1"
if command -v open >/dev/null 2>&1; then
open "$url"
elif command -v xdg-open >/dev/null 2>&1; then
xdg-open "$url" >/dev/null 2>&1 &
elif command -v start >/dev/null 2>&1; then
start "$url"
else
echo -e "${YELLOW}Could not detect browser launcher. Please open the URL manually.${NC}"
fi
}
# Helper: Load Credentials
load_credentials() {
# 1. Check CLI args / Env vars
APP_ID="${APP_ID:-$OSMAP_APP_ID}"
APP_SECRET="${APP_SECRET:-$OSMAP_APP_SECRET}"
# 2. Check local config file
if [[ -z "$APP_ID" || -z "$APP_SECRET" ]] && [[ -f "$CONFIG_FILE" ]]; then
# shellcheck disable=SC1090
source "$CONFIG_FILE"
APP_ID="${APP_ID:-$OSMAP_APP_ID}"
APP_SECRET="${APP_SECRET:-$OSMAP_APP_SECRET}"
fi
# 3. Check .env in current directory
if [[ -z "$APP_ID" || -z "$APP_SECRET" ]] && [[ -f ".env" ]]; then
local env_app_id
local env_app_secret
env_app_id=$(grep -E "^OSMAP_APP_ID=" .env | cut -d '=' -f2- | tr -d '"' | tr -d "'" || true)
env_app_secret=$(grep -E "^OSMAP_APP_SECRET=" .env | cut -d '=' -f2- | tr -d '"' | tr -d "'" || true)
APP_ID="${APP_ID:-$env_app_id}"
APP_SECRET="${APP_SECRET:-$env_app_secret}"
fi
# 4. Fallback to built-in default credentials
APP_ID="${APP_ID:-$DEFAULT_APP_ID}"
APP_SECRET="${APP_SECRET:-$DEFAULT_APP_SECRET}"
}
# Helper: Safe Read from TTY when piped (e.g. curl ... | bash)
read_input() {
if [[ -t 0 ]]; then
read "$@"
elif [[ -e /dev/tty ]]; then
read "$@" < /dev/tty
else
read "$@"
fi
}
# Helper: Prompt Credentials if missing
ensure_credentials() {
load_credentials
if [[ -z "$APP_ID" ]]; then
echo -e "${CYAN}Please enter your OSMAP App ID:${NC}"
read_input -r -p "App ID: " APP_ID
fi
if [[ -z "$APP_SECRET" ]]; then
echo -e "${CYAN}Please enter your OSMAP App Secret:${NC}"
read_input -r -s -p "App Secret: " APP_SECRET
echo ""
fi
if [[ -z "$APP_ID" || -z "$APP_SECRET" ]]; then
echo -e "${RED}Error: App ID and App Secret are required.${NC}" >&2
exit 1
fi
}
# Helper: Save credentials to config
save_credentials() {
echo "OSMAP_APP_ID=\"$APP_ID\"" > "$CONFIG_FILE"
echo "OSMAP_APP_SECRET=\"$APP_SECRET\"" >> "$CONFIG_FILE"
chmod 600 "$CONFIG_FILE"
echo -e "${GREEN}Credentials saved to ${CONFIG_FILE}${NC}"
}
# Cache management
get_cache_file() {
local env_sanitized
env_sanitized=$(echo "$BASE_URL" | sed 's/[^a-zA-Z0-9]/_/g')
echo "${CACHE_DIR}/token_${env_sanitized}.json"
}
# Step 3 per doc: Check token if valid
validate_token() {
local token="$1"
local endpoint="${BASE_URL}/api/apps/validate-token"
local response
response=$(curl -s --location "$endpoint" \
--header 'Content-Type: application/json' \
--data "{\"token\":\"$token\"}" 2>/dev/null || echo '{"success":false}')
local is_valid
is_valid=$(echo "$response" | jq -r '.success // false' 2>/dev/null || echo "false")
if [[ "$is_valid" == "true" ]]; then
return 0
else
return 1
fi
}
# Step 2 per doc: Get token through app_id and app_secret
fetch_new_token() {
ensure_credentials
local endpoint="${BASE_URL}/api/apps/token"
echo -e "${CYAN}Requesting new embed token from ${endpoint}...${NC}" >&2
local payload
payload=$(jq -n \
--arg app_id "$APP_ID" \
--arg app_secret "$APP_SECRET" \
'{app_id: $app_id, app_secret: $app_secret}')
local response
response=$(curl -s --location "$endpoint" \
--header 'Content-Type: application/json' \
--data "$payload")
local is_success
is_success=$(echo "$response" | jq -r '.success // false' 2>/dev/null || echo "false")
if [[ "$is_success" != "true" ]]; then
local error_msg
error_msg=$(echo "$response" | jq -r '.message // "Failed to obtain token"' 2>/dev/null || echo "$response")
echo -e "${RED}Authentication Error:${NC} $error_msg" >&2
exit 1
fi
local access_token
access_token=$(echo "$response" | jq -r '.access_token')
# Save to cache
local cache_file
cache_file=$(get_cache_file)
echo "$response" > "$cache_file"
chmod 600 "$cache_file"
echo "$access_token"
}
# Step 1-5 Flow: Get valid token (cached or fresh)
get_valid_token() {
local cache_file
cache_file=$(get_cache_file)
local token=""
if [[ -f "$cache_file" ]]; then
token=$(jq -r '.access_token // empty' "$cache_file" 2>/dev/null || true)
fi
if [[ -n "$token" ]]; then
# Validate existing token
if validate_token "$token"; then
echo "$token"
return 0
fi
fi
# Token missing or invalid -> fetch fresh token
fetch_new_token
}
# Revoke Tokens
revoke_tokens() {
ensure_credentials
local endpoint="${BASE_URL}/api/apps/revoke-tokens"
local payload
payload=$(jq -n \
--arg app_id "$APP_ID" \
--arg app_secret "$APP_SECRET" \
'{app_id: $app_id, app_secret: $app_secret}')
echo -e "${CYAN}Revoking tokens at ${endpoint}...${NC}"
local response
response=$(curl -s --location "$endpoint" \
--header 'Content-Type: application/json' \
--data "$payload")
echo "$response" | jq .
# Clear local cache
local cache_file
cache_file=$(get_cache_file)
rm -f "$cache_file"
echo -e "${GREEN}Local cache cleared.${NC}"
}
# Register App
register_app() {
local endpoint="${BASE_URL}/api/apps/register"
echo -e "${BOLD}${CYAN}=== Register New App ===${NC}"
read -r -p "App Name: " app_name
read -r -p "Allowed Domains (comma-separated, e.g. demo.osmap.id,localhost): " allowed_domains_raw
# Convert comma-separated string to JSON array
local domains_json
domains_json=$(echo "$allowed_domains_raw" | jq -R 'split(",") | map(gsub("^[ \t]+|[ \t]+$"; ""))')
local payload
payload=$(jq -n \
--arg app_name "$app_name" \
--argjson domains "$domains_json" \
'{app_name: $app_name, allowed_domains: $domains}')
echo -e "${CYAN}Sending registration request to ${endpoint}...${NC}"
local response
response=$(curl -s --location "$endpoint" \
--header 'Content-Type: application/json' \
--data "$payload")
echo "$response" | jq .
local success
success=$(echo "$response" | jq -r '.success // false' 2>/dev/null || echo "false")
if [[ "$success" == "true" ]]; then
local new_app_id
local new_app_secret
new_app_id=$(echo "$response" | jq -r '.app_id // empty')
new_app_secret=$(echo "$response" | jq -r '.app_secret // empty')
echo ""
read -r -p "Do you want to save these credentials to ${CONFIG_FILE}? (y/N): " save_confirm
if [[ "$save_confirm" =~ ^[Yy]$ ]]; then
APP_ID="$new_app_id"
APP_SECRET="$new_app_secret"
save_credentials
fi
fi
}
# Print single URL
display_and_handle_url() {
local name="$1"
local path="$2"
local token="$3"
local auto_open="$4"
local full_url="${BASE_URL}${path}?token=${token}"
echo ""
echo -e "${BOLD}${GREEN}Map:${NC} ${name}"
echo -e "${BOLD}${CYAN}URL:${NC} ${full_url}"
echo ""
if copy_to_clipboard "$full_url"; then
echo -e "${GREEN}✓ Copied URL to clipboard!${NC}"
fi
if [[ "$auto_open" == "true" ]]; then
echo -e "${CYAN}Opening in browser...${NC}"
open_url "$full_url"
fi
}
# Print all URLs
print_all_urls() {
local token="$1"
echo ""
echo -e "${BOLD}${CYAN}=== OSMAP All Embed URLs (${TARGET_ENV}) ===${NC}"
echo ""
printf "%-30s | %s\n" "Map Feature" "Complete Embed URL"
printf "%-30s-+-%s\n" "------------------------------" "------------------------------------------------------------"
for item in "${ROUTES[@]}"; do
IFS="|" read -r key name path <<< "$item"
local url="${BASE_URL}${path}?token=${token}"
printf "%-30s | %s\n" "$name" "$url"
done
echo ""
}
# Interactive Menu
show_interactive_menu() {
local token="$1"
while true; do
echo ""
echo -e "${BOLD}${CYAN}╔════════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}${CYAN}║ OSMAP KAI Embed Map Navigator ║${NC}"
echo -e "${BOLD}${CYAN}╠════════════════════════════════════════════════════════════════╣${NC}"
echo -e "${CYAN}║ Target Environment:${NC} ${BOLD}${YELLOW}${BASE_URL}${NC}"
echo -e "${BOLD}${CYAN}╚════════════════════════════════════════════════════════════════╝${NC}"
echo ""
local index=1
for item in "${ROUTES[@]}"; do
IFS="|" read -r key name path <<< "$item"
printf " ${BOLD}%2d)${NC} %-32s ${CYAN}%s${NC}\n" "$index" "$name" "$path"
((index++))
done
echo ""
printf " ${BOLD}%2d)${NC} %s\n" "$index" "Display All URLs Table"
((index++))
printf " ${BOLD}%2d)${NC} %s\n" "$index" "Copy Raw Token"
((index++))
printf " ${BOLD}%2d)${NC} %s\n" "$index" "Switch Environment (live / beta / local / demo / custom)"
((index++))
printf " ${BOLD} 0)${NC} %s\n" "Exit"
echo ""
read_input -r -p "Select an option [0-$((index-1))]: " choice
if [[ "$choice" == "0" || "$choice" == "q" || "$choice" == "exit" ]]; then
echo -e "${GREEN}Goodbye!${NC}"
exit 0
fi
if [[ "$choice" -ge 1 && "$choice" -le ${#ROUTES[@]} ]]; then
local selected_item="${ROUTES[$((choice-1))]}"
IFS="|" read -r key name path <<< "$selected_item"
display_and_handle_url "$name" "$path" "$token" "false"
read_input -r -p "Open this URL in your default browser? (Y/n): " open_choice
if [[ "$open_choice" =~ ^[Nn]$ ]]; then
:
else
open_url "${BASE_URL}${path}?token=${token}"
fi
elif [[ "$choice" -eq $(( ${#ROUTES[@]} + 1 )) ]]; then
print_all_urls "$token"
elif [[ "$choice" -eq $(( ${#ROUTES[@]} + 2 )) ]]; then
if copy_to_clipboard "$token"; then
echo -e "${GREEN}✓ Access Token copied to clipboard:${NC} $token"
else
echo -e "${YELLOW}Could not detect clipboard tool. Here is the token:${NC}"
echo "$token"
fi
elif [[ "$choice" -eq $(( ${#ROUTES[@]} + 3 )) ]]; then
echo ""
read_input -r -p "Enter environment [live, beta, staging, demo, local, or URL]: " new_env
if [[ -n "$new_env" ]]; then
TARGET_ENV="$new_env"
BASE_URL=$(get_base_url "$TARGET_ENV")
echo -e "${CYAN}Validating token for ${BASE_URL}...${NC}"
token=$(get_valid_token)
fi
else
echo -e "${RED}Invalid selection.${NC}"
fi
done
}
# Help / Usage
show_help() {
cat << EOF
OSMAP Embed CLI Tool
Usage:
./osmap-embed.sh [route|command] [options]
Commands & Short-names:
interactive Launch interactive selection menu (default)
all Display all embed URLs with token
token Print current valid token only
validate Check if cached token is still valid
revoke Revoke current app tokens
register Register a new application
Routes:
executive /executive
rolling /rolling
iris-jpl /iris-jpl
iris-jpl-v2 /v2/iris-jpl
accelerometer /executive/accelerometer
genset /genset
managerial /managerial
fatigue /fatigue
sigap-tracker /sigap-tracker
sigap-dashboard /sigap-dashboard
railway-cargo-system /railway-cargo-system
Options:
-e, --env <env> Environment: live (default), beta, staging, demo, local, or custom URL
--app-id <id> Override App ID
--app-secret <secret> Override App Secret
-o, --open Automatically open the generated URL in browser
-c, --copy Copy URL to clipboard
--save Save provided App ID / Secret to .osmap_credentials
-h, --help Show this help message
Examples:
./osmap-embed.sh
./osmap-embed.sh managerial --env live --open
./osmap-embed.sh all --env beta
./osmap-embed.sh token --env live
EOF
}
# ------------------------------------------------------------------------------
# Argument Parsing
# ------------------------------------------------------------------------------
TARGET_ENV="$DEFAULT_ENV"
COMMAND_OR_ROUTE=""
AUTO_OPEN="false"
AUTO_COPY="false"
DO_SAVE="false"
while [[ $# -gt 0 ]]; do
case "$1" in
-e|--env)
TARGET_ENV="$2"
shift 2
;;
--app-id)
APP_ID="$2"
shift 2
;;
--app-secret)
APP_SECRET="$2"
shift 2
;;
-o|--open)
AUTO_OPEN="true"
shift
;;
-c|--copy)
AUTO_COPY="true"
shift
;;
--save)
DO_SAVE="true"
shift
;;
-h|--help)
show_help
exit 0
;;
*)
if [[ -z "$COMMAND_OR_ROUTE" ]]; then
COMMAND_OR_ROUTE="$1"
fi
shift
;;
esac
done
BASE_URL=$(get_base_url "$TARGET_ENV")
if [[ "$DO_SAVE" == "true" && -n "$APP_ID" && -n "$APP_SECRET" ]]; then
save_credentials
fi
# Route / Command Execution
case "$COMMAND_OR_ROUTE" in
register)
register_app
exit 0
;;
revoke)
revoke_tokens
exit 0
;;
validate)
cache_file=$(get_cache_file)
if [[ -f "$cache_file" ]]; then
token=$(jq -r '.access_token // empty' "$cache_file")
if [[ -n "$token" ]] && validate_token "$token"; then
echo -e "${GREEN}✓ Cached token is VALID for ${BASE_URL}${NC}"
echo "Token: $token"
exit 0
fi
fi
echo -e "${RED}✗ No valid cached token found for ${BASE_URL}${NC}"
exit 1
;;
token)
token=$(get_valid_token)
echo "$token"
exit 0
;;
all)
token=$(get_valid_token)
print_all_urls "$token"
exit 0
;;
"")
token=$(get_valid_token)
show_interactive_menu "$token"
;;
*)
# Match against routes
matched=false
token=$(get_valid_token)
for item in "${ROUTES[@]}"; do
IFS="|" read -r key name path <<< "$item"
if [[ "$COMMAND_OR_ROUTE" == "$key" || "$COMMAND_OR_ROUTE" == "${path#/}" ]]; then
display_and_handle_url "$name" "$path" "$token" "$AUTO_OPEN"
matched=true
break
fi
done
if [[ "$matched" == "false" ]]; then
echo -e "${RED}Unknown command or route:${NC} $COMMAND_OR_ROUTE"
echo "Run './osmap-embed.sh --help' for available routes."
exit 1
fi
;;
esac