Last active
September 27, 2025 00:03
-
-
Save gsj1377/29be655f01246a9b1810c3492193e543 to your computer and use it in GitHub Desktop.
Offcloud IP Management Script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Offcloud IP Management Script | |
| # | |
| # This script automates adding the current public IP to your Offcloud account. | |
| # It requires curl and jq to be installed. | |
| # --- Configuration --- | |
| # IMPORTANT: Hardcoding credentials is not secure. | |
| # Consider using environment variables or a secrets management tool. | |
| EMAIL="<offcloud-email>" | |
| PASSWORD="<offcloud-password>" | |
| BASE_URL="https://offcloud.com" | |
| COOKIE_JAR="/tmp/offcloud_cookies.txt" | |
| HOST="" # hostname-linked-to-home-dynamic-ip | |
| IPS="" # example IPS="1.1.1.1;8.8.8.8" | |
| # --- Helper Functions --- | |
| # Function to print messages | |
| log() { | |
| echo -e "[$(date +'%Y-%m-%d %H:%M:%S')] $1" >&2 | |
| } | |
| # Function to validate an IP address | |
| is_valid_ip() { | |
| local ip=$1 | |
| local stat=1 | |
| if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then | |
| OIFS=$IFS | |
| IFS='.' | |
| ip=($ip) | |
| IFS=$OIFS | |
| [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]] | |
| stat=$? | |
| fi | |
| return $stat | |
| } | |
| # Function to get the current public IP | |
| get_current_ip() { | |
| local IP | |
| IP=$(curl -s https://api.ipify.org) | |
| if [ -z "$IP" ]; then | |
| log "β Failed to get IP from ipify.org, trying httpbin.org..." | |
| IP=$(curl -s https://httpbin.org/ip | jq -r '.origin') | |
| fi | |
| if [ -z "$IP" ]; then | |
| log "β Could not determine public IP address." | |
| return 1 | |
| fi | |
| echo "$IP" | |
| } | |
| # Function to get the IP of a given host | |
| get_host_ip() { | |
| local HOSTNAME=$1 | |
| local IP | |
| IP=$(dig +short "$HOSTNAME" 2>/dev/null || true) | |
| if [ -z "$IP" ]; then | |
| log "β οΈ Could not resolve IP for $HOSTNAME." | |
| fi | |
| echo "$IP" | |
| } | |
| # Function to log in to Offcloud | |
| login() { | |
| LOGIN_URL="$BASE_URL/api/login" | |
| LOGIN_PAYLOAD=$(cat <<EOF | |
| { | |
| "username": "$EMAIL", | |
| "password": "$PASSWORD" | |
| } | |
| EOF | |
| ) | |
| HTTP_RESPONSE=$(curl -s -w "\n%{http_code}" \ | |
| -X POST "$LOGIN_URL" \ | |
| -H "Content-Type: application/json;charset=utf-8" \ | |
| -c "$COOKIE_JAR" \ | |
| --data "$LOGIN_PAYLOAD") | |
| HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed '$d') | |
| HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tail -n 1) | |
| if [ "$HTTP_STATUS" -ne 200 ]; then | |
| log "β Login failed with status code $HTTP_STATUS." | |
| log " Response: $HTTP_BODY" | |
| exit 1 | |
| fi | |
| USER_ID=$(echo "$HTTP_BODY" | jq -r '.userId') | |
| if [ "$USER_ID" != "null" ] && [ -n "$USER_ID" ]; then | |
| log "β Login successful. User ID: $USER_ID" | |
| else | |
| ERROR_MSG=$(echo "$HTTP_BODY" | jq -r '.error // "Unknown error"') | |
| log "β Login failed: $ERROR_MSG" | |
| exit 1 | |
| fi | |
| } | |
| # Function to get currently registered IPs | |
| get_registered_ips() { | |
| IPS_URL="$BASE_URL/account/registered-ips" | |
| HTTP_RESPONSE=$(curl -s -w "\n%{http_code}" \ | |
| -X POST "$IPS_URL" \ | |
| -H "Content-Type: application/json;charset=utf-8" \ | |
| -b "$COOKIE_JAR") | |
| HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed '$d') | |
| HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tail -n 1) | |
| if [ "$HTTP_STATUS" -ne 200 ]; then | |
| log "β Failed to get registered IPs. Status: $HTTP_STATUS" | |
| log " Response: $HTTP_BODY" | |
| REGISTERED_IPS="" | |
| return 1 | |
| fi | |
| local ips=$(echo "$HTTP_BODY" | jq -r '.data[].ip') | |
| local valid_ips=() | |
| for ip in $ips; do | |
| if is_valid_ip "$ip"; then | |
| valid_ips+=("$ip") | |
| else | |
| log "β οΈ Found invalid IP in registered list: $ip" | |
| fi | |
| done | |
| REGISTERED_IPS=("${valid_ips[@]}") | |
| log "β Found registered IPs: \n$(printf "%s\n" "${REGISTERED_IPS[@]}")" | |
| } | |
| # Function to add an IP address | |
| add_ip() { | |
| local IP_TO_ADD=$1 | |
| log "π Adding IP address $IP_TO_ADD..." | |
| ADD_IP_URL="$BASE_URL/account/ip/add" | |
| ADD_PAYLOAD=$(cat <<EOF | |
| { | |
| "ip": "$IP_TO_ADD" | |
| } | |
| EOF | |
| ) | |
| HTTP_RESPONSE=$(curl -s -w "\n%{http_code}" \ | |
| -X POST "$ADD_IP_URL" \ | |
| -H "Content-Type: application/json;charset=utf-8" \ | |
| -b "$COOKIE_JAR" \ | |
| --data "$ADD_PAYLOAD") | |
| HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed '$d') | |
| HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tail -n 1) | |
| if [ "$HTTP_STATUS" -eq 200 ]; then | |
| log "β Server accepted request to add IP: $IP_TO_ADD" | |
| else | |
| log "β Failed to add IP address. Status: $HTTP_STATUS" | |
| log " Response: $HTTP_BODY" | |
| return 1 | |
| fi | |
| } | |
| # Function to remove an IP address | |
| remove_ip() { | |
| local IP_TO_REMOVE=$1 | |
| log "π Removing IP address $IP_TO_REMOVE..." | |
| REMOVE_IP_URL="$BASE_URL/account/ip/remove" | |
| REMOVE_PAYLOAD=$(cat <<EOF | |
| { | |
| "ip": "$IP_TO_REMOVE" | |
| } | |
| EOF | |
| ) | |
| HTTP_RESPONSE=$(curl -s -w "\n%{http_code}" \ | |
| -X POST "$REMOVE_IP_URL" \ | |
| -H "Content-Type: application/json;charset=utf-8" \ | |
| -b "$COOKIE_JAR" \ | |
| --data "$REMOVE_PAYLOAD") | |
| HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed '$d') | |
| HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tail -n 1) | |
| if [ "$HTTP_STATUS" -eq 200 ]; then | |
| log "β Server accepted request to remove IP: $IP_TO_REMOVE" | |
| else | |
| log "β Failed to remove IP address. Status: $HTTP_STATUS" | |
| log " Response: $HTTP_BODY" | |
| return 1 | |
| fi | |
| } | |
| # Function to remove all IPs except the ones we want to manage | |
| remove_other_ips() { | |
| log "π§Ή Removing all other IP addresses..." | |
| for IP_TO_CHECK in "${REGISTERED_IPS[@]}"; do | |
| if ! is_valid_ip "$IP_TO_CHECK"; then | |
| log "β οΈ Skipping invalid IP in registered list: $IP_TO_CHECK" | |
| continue | |
| fi | |
| SHOULD_KEEP=false | |
| for IP_TO_KEEP in "${IPS_TO_MANAGE[@]}"; do | |
| if [ "$IP_TO_CHECK" == "$IP_TO_KEEP" ]; then | |
| SHOULD_KEEP=true | |
| break | |
| fi | |
| done | |
| if [ "$SHOULD_KEEP" == "false" ]; then | |
| remove_ip "$IP_TO_CHECK" | |
| fi | |
| done | |
| } | |
| # --- Main Script --- | |
| # Clean up cookie jar on exit | |
| trap 'rm -f "$COOKIE_JAR"' EXIT | |
| main() { | |
| log "π Offcloud IP Manager" | |
| log "==============================" | |
| # 1. Login to Offcloud | |
| login | |
| # 2. Get registered IPs | |
| get_registered_ips | |
| # 3. Define list of IPs to manage | |
| declare -a IPS_TO_MANAGE | |
| # Add current public IP | |
| CURRENT_IP=$(get_current_ip) | |
| if [ -n "$CURRENT_IP" ]; then | |
| log "β Public IP is: $CURRENT_IP" | |
| IPS_TO_MANAGE+=("$CURRENT_IP") | |
| else | |
| log "β οΈ Could not get current public IP. Skipping." | |
| fi | |
| # Add IP for the specified host | |
| HOST_IP=$(get_host_ip "$HOST") | |
| if [ -n "$HOST_IP" ]; then | |
| log "β IP for $HOST is: $HOST_IP" | |
| IPS_TO_MANAGE+=("$HOST_IP") | |
| else | |
| log "β οΈ Could not get IP for $HOST. Skipping." | |
| fi | |
| # Add static IPs from IPS variable | |
| if [ -n "$IPS" ]; then | |
| log "βΉοΈ Processing static IPs from configuration..." | |
| for IP in $(echo $IPS | tr ";" " "); do | |
| if is_valid_ip "$IP"; then | |
| log "β Adding static IP: $IP" | |
| IPS_TO_MANAGE+=("$IP") | |
| else | |
| log "β οΈ Invalid static IP found: $IP. Skipping." | |
| fi | |
| done | |
| fi | |
| # Remove duplicate IPs | |
| IPS_TO_MANAGE=($(printf "%s\n" "${IPS_TO_MANAGE[@]}" | sort -u)) | |
| if [ ${#IPS_TO_MANAGE[@]} -eq 0 ]; then | |
| log "β No valid IPs to manage. Exiting." | |
| exit 1 | |
| fi | |
| log "βΉοΈ IPs to manage: ${IPS_TO_MANAGE[*]}" | |
| # 4. Add any missing IPs | |
| for IP_TO_CHECK in "${IPS_TO_MANAGE[@]}"; do | |
| if [[ " ${REGISTERED_IPS[*]} " =~ " ${IP_TO_CHECK} " ]]; then | |
| log "β IP address $IP_TO_CHECK is already registered." | |
| else | |
| log "βΉοΈ IP address $IP_TO_CHECK is not registered. Adding it..." | |
| add_ip "$IP_TO_CHECK" | |
| fi | |
| done | |
| # 5. Verify that all required IPs are now registered | |
| log "π Verifying all IPs after additions..." | |
| sleep 5 # Give the server a moment to process the changes | |
| get_registered_ips # Refresh the list of registered IPs | |
| VERIFICATION_FAILED=false | |
| for IP_TO_VERIFY in "${IPS_TO_MANAGE[@]}"; do | |
| if [[ " ${REGISTERED_IPS[*]} " =~ " ${IP_TO_VERIFY} " ]]; then | |
| log "β Verification successful for IP: $IP_TO_VERIFY" | |
| else | |
| log "β Verification failed for IP: $IP_TO_VERIFY" | |
| VERIFICATION_FAILED=true | |
| fi | |
| done | |
| if $VERIFICATION_FAILED; then | |
| log "β One or more IPs could not be verified." | |
| log " Current registered IPs: $REGISTERED_IPS" | |
| exit 1 | |
| else | |
| log "π All required IPs are successfully registered." | |
| fi | |
| # 6. Remove any other IPs | |
| remove_other_ips | |
| get_registered_ips # Refresh the list of registered IPs | |
| } | |
| main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment