#!/usr/bin/env bash
# check-cert-expiry.sh —— 检查 TLS 证书剩余天数
#
# 用法：
#   bash check-cert-expiry.sh example.com:443 [--warn 30]
#   bash check-cert-expiry.sh --file /path/to/server.crt [--warn 30]
#
# 退出码：0 = 全部高于阈值；1 = 有证书低于阈值；2 = 参数或读取失败
# 说明：按原样提供，不附带任何保证。先在测试环境验证再用。

set -uo pipefail

warn=30
target=""
file=""

while [ $# -gt 0 ]; do
  case "$1" in
    --warn) warn="${2:-30}"; shift 2 ;;
    --file) file="${2:-}"; shift 2 ;;
    -h|--help) sed -n '2,10p' "$0"; exit 0 ;;
    *) target="$1"; shift ;;
  esac
done

if ! [[ "$warn" =~ ^[0-9]+$ ]]; then
  echo "错误：--warn 必须是整数" >&2
  exit 2
fi

get_notafter() {
  # $1 = 目标；输出 notAfter（UTC 字符串）
  local t="$1" host port
  if [ -n "$file" ]; then
    openssl x509 -in "$file" -noout -enddate 2>/dev/null | cut -d= -f2
    return
  fi
  host="${t%%:*}"
  port="${t##*:}"
  [ "$host" = "$t" ] && port=443
  openssl s_client -servername "$host" -connect "${host}:${port}" </dev/null 2>/dev/null \
    | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2
}

if [ -z "$file" ] && [ -z "$target" ]; then
  echo "错误：需要 <host>[:port] 或 --file <crt>" >&2
  exit 2
fi

notafter="$(get_notafter "${file:-$target}")"
if [ -z "$notafter" ]; then
  echo "失败：读不到证书（$([ -n "$file" ] && echo "$file" || echo "$target")）" >&2
  exit 2
fi

end_epoch=$(date -u -d "$notafter" +%s 2>/dev/null) || {
  echo "失败：无法解析到期时间 '$notafter'" >&2; exit 2; }
now_epoch=$(date -u +%s)
days=$(( (end_epoch - now_epoch) / 86400 ))

name="${file:-$target}"
printf '%-40s 到期 %s  UTC  剩余 %s 天\n' "$name" "$notafter" "$days"

if [ "$days" -lt 0 ]; then
  echo "!! 证书已过期" >&2
  exit 1
fi
if [ "$days" -lt "$warn" ]; then
  echo "!! 低于阈值 ${warn} 天" >&2
  exit 1
fi
exit 0
