217 lines
8.0 KiB
Bash
Executable File
217 lines
8.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# get-cookie.sh — Holy Crab AI 认证流程
|
||
#
|
||
# 流程:
|
||
# 1. 从后端获取钉钉授权 URL
|
||
# 2. 让用户在浏览器打开,授权后 URL 里会带 authCode
|
||
# 3. AI 把 authCode 贴过来 → 调用 /api/v1/auth/direct-token 换出 session token
|
||
# 4. 存 token 到 ~/.holy_crab_env,后续所有请求自动带 Cookie
|
||
#
|
||
# 用法:
|
||
# bash get-cookie.sh # 交互式
|
||
# bash get-cookie.sh --check # 仅检查 token 是否有效
|
||
# bash get-cookie.sh <authCode> # 直接用 authCode 换 token
|
||
|
||
set -e
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
|
||
COOKIE_FILE="$HOME/.holy_crab_cookie"
|
||
ENV_FILE="$HOME/.holy_crab_env"
|
||
BACKEND="${HC_BACKEND_URL:-http://localhost:8000}"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 工具函数
|
||
# ---------------------------------------------------------------------------
|
||
|
||
save_token() {
|
||
local token="$1"
|
||
echo "HC_SESSION=${token}" > "$ENV_FILE"
|
||
chmod 600 "$ENV_FILE"
|
||
echo "✅ Token 已写入: $ENV_FILE"
|
||
echo ""
|
||
echo "📋 后续 AI 将自动从此文件读取 Cookie,无需任何额外操作。"
|
||
}
|
||
|
||
save_token_raw() {
|
||
local token="$1"
|
||
echo "$token" > "$COOKIE_FILE"
|
||
chmod 600 "$COOKIE_FILE"
|
||
}
|
||
|
||
check_token() {
|
||
local token="$1"
|
||
local http_code
|
||
http_code=$(curl -s -o /dev/null -w "%{http_code}" \
|
||
--max-time 10 \
|
||
-H "Cookie: hc_session=${token}" \
|
||
"$BACKEND/api/v1/auth/me")
|
||
if [ "$http_code" = "200" ]; then
|
||
echo "✅ Token 有效"
|
||
return 0
|
||
else
|
||
echo "❌ Token 无效或已过期 (HTTP $http_code)"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# 从现有文件读 token
|
||
load_existing_token() {
|
||
# 优先 ~/.holy_crab_env
|
||
if [ -f "$ENV_FILE" ]; then
|
||
local val
|
||
val=$(grep -E "^HC_SESSION=" "$ENV_FILE" 2>/dev/null | head -1 | cut -d= -f2- | tr -d '"' | tr -d "'" | xargs)
|
||
[ -n "$val" ] && echo "$val" && return 0
|
||
fi
|
||
# 兜底 ~/.holy_crab_cookie
|
||
if [ -f "$COOKIE_FILE" ]; then
|
||
local val
|
||
val=$(cat "$COOKIE_FILE" | xargs)
|
||
[ -n "$val" ] && echo "$val" && return 0
|
||
fi
|
||
return 1
|
||
}
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Step 1:检查现有 token
|
||
# ---------------------------------------------------------------------------
|
||
|
||
if [ "$1" = "--check" ]; then
|
||
echo ""
|
||
echo "🔍 检查现有 Token..."
|
||
if EXISTING=$(load_existing_token 2>/dev/null); then
|
||
if check_token "$EXISTING"; then
|
||
echo ""
|
||
echo " Token 来自: ${ENV_FILE:-$COOKIE_FILE}"
|
||
exit 0
|
||
fi
|
||
fi
|
||
echo " 未找到有效 Token,需要重新授权。"
|
||
exit 1
|
||
fi
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Step 2:直接用 authCode 换 token
|
||
# ---------------------------------------------------------------------------
|
||
|
||
if [ -n "$1" ] && [ "$1" != "--check" ]; then
|
||
AUTH_CODE="$1"
|
||
echo ""
|
||
echo "🔄 正在用 authCode 换取 session token..."
|
||
RESPONSE=$(curl -s --max-time 20 \
|
||
"$BACKEND/api/v1/auth/direct-token?authCode=${AUTH_CODE}")
|
||
|
||
ERROR=$(echo "$RESPONSE" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('code',''))" 2>/dev/null)
|
||
if [ -n "$ERROR" ]; then
|
||
MSG=$(echo "$RESPONSE" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('msg',''))" 2>/dev/null)
|
||
echo "❌ 换取失败: [$ERROR] $MSG"
|
||
echo " 原始响应: $RESPONSE"
|
||
exit 1
|
||
fi
|
||
|
||
TOKEN=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['token'])" 2>/dev/null)
|
||
USER=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['user'].get('name','?'))" 2>/dev/null)
|
||
EXPIRES=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['expires_at'])" 2>/dev/null)
|
||
|
||
if [ -z "$TOKEN" ]; then
|
||
echo "❌ 响应解析失败,原始响应:"
|
||
echo "$RESPONSE"
|
||
exit 1
|
||
fi
|
||
|
||
echo "✅ 换取成功!"
|
||
echo " 用户:$USER"
|
||
echo " 有效期至:$EXPIRES"
|
||
save_token "$TOKEN"
|
||
echo ""
|
||
echo "🎉 认证完成,AI 现在可以访问 Holy Crab 后端了!"
|
||
exit 0
|
||
fi
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Step 3:交互式引导 — 获取 authCode
|
||
# ---------------------------------------------------------------------------
|
||
|
||
echo ""
|
||
echo "═══════════════════════════════════════════════════════"
|
||
echo " 🔐 Holy Crab · AI 授权流程"
|
||
echo "═══════════════════════════════════════════════════════"
|
||
echo ""
|
||
echo " 本流程分两步:① 获取授权码 ② 换取 Token"
|
||
echo ""
|
||
|
||
# 检查后端是否可达
|
||
if ! curl -s --max-time 5 "$BACKEND/health" > /dev/null 2>&1; then
|
||
echo " ❌ 后端不可达: $BACKEND"
|
||
echo ""
|
||
echo " 请确认:"
|
||
echo " 1. 后端是否已启动?(python3 app.py)"
|
||
echo " 2. HC_BACKEND_URL 是否正确?"
|
||
echo ""
|
||
echo " 当前 BACKEND=$BACKEND"
|
||
echo " 修改方式:export HC_BACKEND_URL=http://服务器IP:8000"
|
||
exit 1
|
||
fi
|
||
echo " ✅ 后端在线: $BACKEND"
|
||
|
||
# 检查现有 token
|
||
if EXISTING=$(load_existing_token 2>/dev/null); then
|
||
if check_token "$EXISTING"; then
|
||
echo ""
|
||
echo " ✅ 已有有效 Token,无需重新授权。"
|
||
echo " Token 来源: ${ENV_FILE:-$COOKIE_FILE}"
|
||
exit 0
|
||
else
|
||
echo " ⚠️ 已有 Token 但已过期,需要重新授权..."
|
||
fi
|
||
fi
|
||
|
||
echo ""
|
||
echo "───────────────────────────────────────────────────────"
|
||
echo " Step 1:在浏览器中完成钉钉授权"
|
||
echo "───────────────────────────────────────────────────────"
|
||
echo ""
|
||
|
||
# 获取钉钉授权 URL
|
||
AUTH_URL_RESP=$(curl -s --max-time 10 "$BACKEND/api/v1/auth/dingtalk/login?redirect=/")
|
||
AUTH_URL=$(echo "$AUTH_URL_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['url'])" 2>/dev/null)
|
||
|
||
if [ -z "$AUTH_URL" ]; then
|
||
echo " ❌ 无法获取钉钉授权 URL(后端可能未配置 DINGTALK_CLIENT_ID)"
|
||
echo " 原始响应: $AUTH_URL_RESP"
|
||
exit 1
|
||
fi
|
||
|
||
echo " 请在浏览器中打开以下链接:"
|
||
echo ""
|
||
echo " $AUTH_URL"
|
||
echo ""
|
||
echo " 操作步骤:"
|
||
echo " 1. 浏览器会自动打开钉钉授权页面"
|
||
echo " 2. 点击「授权登录」"
|
||
echo " 3. 授权成功后,浏览器会跳转到后端页面"
|
||
echo " 4. 此时地址栏 URL 中会有 ?authCode=xxxxx"
|
||
echo " 把 authCode= 后面的那串字符复制下来"
|
||
echo ""
|
||
|
||
# 自动打开浏览器
|
||
if command -v open >/dev/null 2>&1; then
|
||
echo " 正在打开授权页面..."
|
||
open "$AUTH_URL" 2>/dev/null || true
|
||
fi
|
||
|
||
echo ""
|
||
echo "───────────────────────────────────────────────────────"
|
||
echo " Step 2:把 authCode 贴过来"
|
||
echo "───────────────────────────────────────────────────────"
|
||
echo ""
|
||
echo " 复制 authCode 后,运行以下命令(把 YOUR_AUTH_CODE 换成你的值):"
|
||
echo ""
|
||
echo " bash $0 YOUR_AUTH_CODE"
|
||
echo ""
|
||
echo " 或者直接告诉 AI:"
|
||
echo " 【authCode】YOUR_AUTH_CODE"
|
||
echo " AI 会自动帮你完成后续操作。"
|
||
echo ""
|
||
echo "═══════════════════════════════════════════════════════"
|