#!/bin/bash set -euo pipefail # Get the directory where this script is located SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" USERNAME=$(secret-mgr get-username --key git) KC_PASS=$(secret-mgr get-secret --key keycloak) GITEA_PASS=$(secret-mgr get-secret --key git) if [[ -z "$USERNAME" || -z "$KC_PASS" || -z "$GITEA_PASS" ]]; then echo "[ERROR] Missing required credentials in secret-mgr" >&2 exit 1 fi sql_escape() { printf '%s' "$1" | sed "s/'/''/g" } WORKDIR="/tmp" COOKIES_FILE="$WORKDIR/${USERNAME}_oidc_cookies.txt" KC_LOGIN_HTML="$WORKDIR/${USERNAME}_kc_login.html" KC_POST_LOGIN_HTML="$WORKDIR/${USERNAME}_kc_post_login.html" KC_POST_LOGIN_LOG="$WORKDIR/${USERNAME}_kc_post_login.log" GITEA_CALLBACK_HTML="$WORKDIR/${USERNAME}_gitea_after_callback.html" GITEA_LINK_HTML="$WORKDIR/${USERNAME}_gitea_link_account.html" GITEA_LINK_RESP_HTML="$WORKDIR/${USERNAME}_gitea_link_signin.html" GITEA_LINK_RESP_LOG="$WORKDIR/${USERNAME}_gitea_link_signin.log" OIDC_URL="https://git.hangman-lab.top/user/oauth2/hangman-lab" ESCAPED_USERNAME=$(sql_escape "$USERNAME") cleanup() { "$SCRIPT_DIR/external-login-ctrl" --disable >/dev/null 2>&1 || true if [[ -n "${ORIG_LOGIN_TYPE:-}" && -n "${ORIG_LOGIN_SOURCE:-}" ]]; then ssh root@vps.git " set -euo pipefail . /root/git-kc/.env docker exec -i git-kc-mysql mysql -uroot -p\"\$MYSQL_ROOT_PASSWORD\" giteadb -e \"UPDATE user SET login_type=${ORIG_LOGIN_TYPE}, login_source=${ORIG_LOGIN_SOURCE}, login_name=${ORIG_LOGIN_NAME_SQL:-NULL} WHERE name='${ESCAPED_USERNAME}';\" " >/dev/null 2>&1 || true fi rm -f "$COOKIES_FILE" "$KC_LOGIN_HTML" "$KC_POST_LOGIN_HTML" "$KC_POST_LOGIN_LOG" \ "$GITEA_CALLBACK_HTML" "$GITEA_LINK_HTML" "$GITEA_LINK_RESP_HTML" "$GITEA_LINK_RESP_LOG" } trap cleanup EXIT rm -f "$COOKIES_FILE" "$KC_LOGIN_HTML" "$KC_POST_LOGIN_HTML" "$KC_POST_LOGIN_LOG" \ "$GITEA_CALLBACK_HTML" "$GITEA_LINK_HTML" "$GITEA_LINK_RESP_HTML" "$GITEA_LINK_RESP_LOG" # Capture original login fields so we can restore them exactly. ORIG_STATE=$(ssh root@vps.git " set -euo pipefail . /root/git-kc/.env docker exec -i git-kc-mysql mysql -N -B -uroot -p\"\$MYSQL_ROOT_PASSWORD\" giteadb -e \"SELECT login_type, login_source, COALESCE(login_name, '__NULL__') FROM user WHERE name='${ESCAPED_USERNAME}' LIMIT 1;\" ") if [[ -z "$ORIG_STATE" ]]; then echo "[ERROR] User not found in Gitea DB: $USERNAME" >&2 exit 1 fi IFS=$'\t' read -r ORIG_LOGIN_TYPE ORIG_LOGIN_SOURCE ORIG_LOGIN_NAME <<< "$ORIG_STATE" if [[ "$ORIG_LOGIN_NAME" == "__NULL__" ]]; then ORIG_LOGIN_NAME_SQL="NULL" else ORIG_LOGIN_NAME_SQL="'$(sql_escape "$ORIG_LOGIN_NAME")'" fi "$SCRIPT_DIR/external-login-ctrl" --enable echo "[INFO] 通过 OIDC 入口触发跳转,获取 Keycloak 登录页..." curl -s -L -c "$COOKIES_FILE" "$OIDC_URL" -o "$KC_LOGIN_HTML" KC_LOGIN_URL=$(perl -ne ' if(/
/){ if(/action="([^"]+)"/){ my $u=$1; $u=~s/&/&/g; print $u; exit } } ' "$KC_LOGIN_HTML") if [[ -z "${KC_LOGIN_URL:-}" ]]; then echo "[ERROR] 未找到 kc-form-login 表单的 action URL" >&2 exit 1 fi echo "[INFO] 登录 Keycloak..." curl -v "$KC_LOGIN_URL" \ -b "$COOKIES_FILE" -c "$COOKIES_FILE" \ --data-urlencode "username=$USERNAME" \ --data-urlencode "password=$KC_PASS" \ -d "credentialId=" \ -o "$KC_POST_LOGIN_HTML" \ 2>"$KC_POST_LOGIN_LOG" || true GITEA_CALLBACK_URL=$(grep -i "location: https://git.hangman-lab.top" "$KC_POST_LOGIN_LOG" | sed -E 's/.*location: (https:[^\r]+).*/\1/i' | tail -n1) if [[ -z "${GITEA_CALLBACK_URL:-}" ]]; then echo "[ERROR] 登录后未发现返回 Gitea 的 callback URL" >&2 exit 1 fi echo "[INFO] 调用 Gitea 回调..." curl -s -L -b "$COOKIES_FILE" -c "$COOKIES_FILE" "$GITEA_CALLBACK_URL" -o "$GITEA_CALLBACK_HTML" echo "[INFO] 访问 Gitea Link Account 页面..." curl -s -b "$COOKIES_FILE" "https://git.hangman-lab.top/user/link_account" -o "$GITEA_LINK_HTML" CSRF_TOKEN=$(perl -ne 'if(/name="_csrf" value="([^"]+)"/){print $1; exit}' "$GITEA_LINK_HTML" || true) if [[ -z "${CSRF_TOKEN:-}" ]]; then echo "[ERROR] 未能从 Link Account 页面解析出 _csrf" >&2 exit 1 fi echo "[INFO] 临时将 login_type 改为本地登录..." ssh root@vps.git " set -euo pipefail . /root/git-kc/.env docker exec -i git-kc-mysql mysql -uroot -p\"\$MYSQL_ROOT_PASSWORD\" giteadb -e \"UPDATE user SET login_type=0, login_source=0, login_name=NULL WHERE name='${ESCAPED_USERNAME}';\" " echo "[INFO] 提交 link_account_signin..." curl -v "https://git.hangman-lab.top/user/link_account_signin" \ -b "$COOKIES_FILE" -c "$COOKIES_FILE" \ --data-urlencode "_csrf=$CSRF_TOKEN" \ --data-urlencode "user_name=$USERNAME" \ --data-urlencode "password=$GITEA_PASS" \ -o "$GITEA_LINK_RESP_HTML" \ 2>"$GITEA_LINK_RESP_LOG" || true echo "[INFO] 恢复原始登录方式..." ssh root@vps.git " set -euo pipefail . /root/git-kc/.env docker exec -i git-kc-mysql mysql -uroot -p\"\$MYSQL_ROOT_PASSWORD\" giteadb -e \"UPDATE user SET login_type=${ORIG_LOGIN_TYPE}, login_source=${ORIG_LOGIN_SOURCE}, login_name=${ORIG_LOGIN_NAME_SQL} WHERE name='${ESCAPED_USERNAME}';\" " unset ORIG_LOGIN_TYPE ORIG_LOGIN_SOURCE ORIG_LOGIN_NAME ORIG_LOGIN_NAME_SQL echo "[DONE] Keycloak 账号关联完成"