594 lines
18 KiB
Bash
594 lines
18 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 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
|
|
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
|
|
copy_to_clipboard "$token"
|
|
echo -e "${GREEN}✓ Access Token copied to clipboard:${NC} $token"
|
|
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
|