#!/usr/bin/env bash

set -euo pipefail

# Update these two values before running the script.
# On first run, the script creates $HOME/.config/dyn/ddns-key if it does not exist yet.
HOSTNAME="yourhost.example.com"
USERNAME="your-dyn-username"
KEY_FILE="$HOME/.config/dyn/ddns-key"
LOG_FILE="$HOME/.config/dyn/ddns-update.log"
CHECKIP_URL="http://checkip.dyndns.org/"
UPDATE_URL="https://members.dyndns.org/nic/update"
SCRIPT_VERSION="2026-03-24"
USER_AGENT="Dyn Help - Unix cron guide - $SCRIPT_VERSION"

mkdir -p "$HOME/.config/dyn"

for command_name in curl sed head tr date install; do
    if ! command -v "$command_name" >/dev/null 2>&1; then
        printf '%s ERROR required command not found: %s\n' \
            "$(date '+%Y-%m-%d %H:%M:%S')" \
            "$command_name" >> "$LOG_FILE"
        printf 'Required command not found: %s\n' "$command_name" >&2
        exit 1
    fi
done

printf 'Using key file: %s\n' "$KEY_FILE"
printf 'Logging to: %s\n' "$LOG_FILE"
printf 'Sending update for hostname: %s\n' "$HOSTNAME"
printf 'Update endpoint: %s\n' "$UPDATE_URL"
printf '%s START hostname=%s\n' \
    "$(date '+%Y-%m-%d %H:%M:%S')" \
    "$HOSTNAME" >> "$LOG_FILE"

if [[ "$HOSTNAME" == "yourhost.example.com" || "$USERNAME" == "your-dyn-username" ]]; then
    printf '%s ERROR update HOSTNAME and USERNAME in %s before running the script\n' \
        "$(date '+%Y-%m-%d %H:%M:%S')" \
        "$0" >> "$LOG_FILE"
    printf 'Update HOSTNAME and USERNAME in %s before running the script.\n' "$0" >&2
    exit 1
fi

if [[ ! -f "$KEY_FILE" ]]; then
    install -m 600 /dev/null "$KEY_FILE"
    printf '%s ERROR key file not found; created empty file at %s\n' \
        "$(date '+%Y-%m-%d %H:%M:%S')" \
        "$KEY_FILE" >> "$LOG_FILE"
    printf 'Created %s. Paste your Dyn update client key into that file, then run the script again.\n' \
        "$KEY_FILE" >&2
    exit 1
fi

KEY="$(head -n 1 "$KEY_FILE" | tr -d '\r\n')"

if [[ -z "$KEY" ]]; then
    printf '%s ERROR key file is empty\n' "$(date '+%Y-%m-%d %H:%M:%S')" >> "$LOG_FILE"
    exit 1
fi

PUBLIC_IP="$(curl -fsS "$CHECKIP_URL" | sed -n 's/.*Current IP Address: \([0-9.]*\).*/\1/p')"

if [[ -z "$PUBLIC_IP" ]]; then
    printf '%s ERROR could not determine public IP from CheckIP\n' "$(date '+%Y-%m-%d %H:%M:%S')" >> "$LOG_FILE"
    exit 1
fi

printf 'Detected public IP: %s\n' "$PUBLIC_IP"
printf '%s PUBLIC_IP=%s\n' \
    "$(date '+%Y-%m-%d %H:%M:%S')" \
    "$PUBLIC_IP" >> "$LOG_FILE"

RESULT="$(curl -fsS \
    --user "$USERNAME:$KEY" \
    --user-agent "$USER_AGENT" \
    "$UPDATE_URL?hostname=$HOSTNAME&myip=$PUBLIC_IP")"

printf 'Dyn response: %s\n' "$RESULT"

printf '%s RESULT=%s\n' \
    "$(date '+%Y-%m-%d %H:%M:%S')" \
    "$RESULT" >> "$LOG_FILE"
