ohmyapi commited on
Commit
4a30e4d
·
verified ·
1 Parent(s): 03e51a9

Create cleanup_tokens.sh

Browse files
Files changed (1) hide show
  1. cleanup_tokens.sh +184 -0
cleanup_tokens.sh ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+ #
3
+ # cleanup_tokens.sh - Remove invalid/unavailable auth tokens via CLIProxyAPI Management API
4
+ #
5
+ # Runs periodically to clean up expired or failed OAuth tokens from the auth store.
6
+ # Tokens with status != "ready", unavailable=true, or known error statuses will be deleted.
7
+ #
8
+ # Required environment variables:
9
+ # MANAGEMENT_PASSWORD - CLIProxyAPI management API password (required)
10
+ #
11
+ # Optional environment variables:
12
+ # FEISHU_WEBHOOK_URL - Feishu (Lark) bot webhook URL for notifications
13
+ # e.g. https://open.feishu.cn/open-apis/bot/v2/hook/xxxx
14
+ # If not set, no notifications will be sent.
15
+ # CLEANUP_NOTIFY_ON_EMPTY - Set to "true" to send a notification even when
16
+ # no invalid tokens were found (default: false)
17
+ #
18
+ # The service always runs on localhost:7860 in this HuggingFace deployment.
19
+ #
20
+
21
+ API_BASE="http://localhost:7860/v0/management"
22
+ LOG_PREFIX="[cleanup_tokens] $(date '+%Y-%m-%d %H:%M:%S')"
23
+ TMP_FILE="/tmp/auth_files_$$.json"
24
+ TMP_NAMES="/tmp/auth_names_$$.txt"
25
+
26
+ cleanup_tmp() {
27
+ rm -f "$TMP_FILE" "$TMP_NAMES"
28
+ }
29
+ trap cleanup_tmp EXIT
30
+
31
+ # Send a notification to Feishu webhook
32
+ # Usage: notify_feishu "title" "content"
33
+ notify_feishu() {
34
+ if [ -z "$FEISHU_WEBHOOK_URL" ]; then
35
+ return 0
36
+ fi
37
+ TITLE="$1"
38
+ CONTENT="$2"
39
+ PAYLOAD=$(jq -n \
40
+ --arg title "$TITLE" \
41
+ --arg content "$CONTENT" \
42
+ '{
43
+ msg_type: "post",
44
+ content: {
45
+ post: {
46
+ zh_cn: {
47
+ title: $title,
48
+ content: [[{"tag": "text", "text": $content}]]
49
+ }
50
+ }
51
+ }
52
+ }')
53
+ curl -s -X POST \
54
+ -H "Content-Type: application/json" \
55
+ -d "$PAYLOAD" \
56
+ "$FEISHU_WEBHOOK_URL" > /dev/null 2>&1
57
+ }
58
+
59
+ if [ -z "$MANAGEMENT_PASSWORD" ]; then
60
+ echo "${LOG_PREFIX} ERROR: MANAGEMENT_PASSWORD not set, skipping cleanup"
61
+ exit 1
62
+ fi
63
+
64
+ echo "${LOG_PREFIX} Starting invalid token cleanup..."
65
+
66
+ # Fetch all auth files
67
+ HTTP_STATUS=$(curl -s -o "$TMP_FILE" -w "%{http_code}" \
68
+ -H "Authorization: Bearer ${MANAGEMENT_PASSWORD}" \
69
+ "${API_BASE}/auth-files" 2>/dev/null)
70
+
71
+ if [ "$HTTP_STATUS" != "200" ]; then
72
+ MSG="API returned HTTP ${HTTP_STATUS}. Service may not be ready."
73
+ echo "${LOG_PREFIX} ERROR: ${MSG}"
74
+ cat "$TMP_FILE" 2>/dev/null
75
+ notify_feishu "❌ Token 清理失败" "$(date '+%Y-%m-%d %H:%M:%S')
76
+ 错误:${MSG}"
77
+ exit 1
78
+ fi
79
+
80
+ if ! jq empty "$TMP_FILE" 2>/dev/null; then
81
+ echo "${LOG_PREFIX} ERROR: Invalid JSON response from API"
82
+ notify_feishu "❌ Token 清理失败" "$(date '+%Y-%m-%d %H:%M:%S')
83
+ 错误:API 返回了无效的 JSON 响应"
84
+ exit 1
85
+ fi
86
+
87
+ TOTAL=$(jq '.files | length' "$TMP_FILE")
88
+ echo "${LOG_PREFIX} Total auth files found: ${TOTAL}"
89
+
90
+ if [ "$TOTAL" -eq 0 ]; then
91
+ echo "${LOG_PREFIX} No auth files found, nothing to clean up."
92
+ exit 0
93
+ fi
94
+
95
+ # Extract names of tokens to delete:
96
+ # - unavailable=true AND runtime_only=false (can only delete file-based tokens)
97
+ # - OR status is one of: error, expired, invalid, failed, unauthorized, quota_exceeded
98
+ jq -r '
99
+ .files[] |
100
+ select(.runtime_only != true) |
101
+ select(
102
+ .unavailable == true or
103
+ (.status != null and (.status == "error" or .status == "expired" or
104
+ .status == "invalid" or .status == "failed" or
105
+ .status == "unauthorized" or .status == "quota_exceeded"))
106
+ ) |
107
+ .name
108
+ ' "$TMP_FILE" > "$TMP_NAMES"
109
+
110
+ TO_DELETE=$(wc -l < "$TMP_NAMES" | tr -d ' ')
111
+ echo "${LOG_PREFIX} Tokens to delete: ${TO_DELETE}"
112
+
113
+ if [ "$TO_DELETE" -eq 0 ]; then
114
+ echo "${LOG_PREFIX} All tokens are healthy, no cleanup needed."
115
+ if [ "${CLEANUP_NOTIFY_ON_EMPTY}" = "true" ]; then
116
+ notify_feishu "✅ Token 清理完成" "$(date '+%Y-%m-%d %H:%M:%S')
117
+ 共 ${TOTAL} 个 token,全部健康,无需清理。"
118
+ fi
119
+ exit 0
120
+ fi
121
+
122
+ # Build a detail list for the notification
123
+ DETAIL_LIST=""
124
+ while IFS= read -r NAME; do
125
+ STATUS=$(jq -r --arg n "$NAME" '.files[] | select(.name == $n) | .status // "unknown"' "$TMP_FILE")
126
+ UNAVAIL=$(jq -r --arg n "$NAME" '.files[] | select(.name == $n) | .unavailable' "$TMP_FILE")
127
+ echo "${LOG_PREFIX} - ${NAME} (status=${STATUS}, unavailable=${UNAVAIL})"
128
+ DETAIL_LIST="${DETAIL_LIST} • ${NAME} [${STATUS}]
129
+ "
130
+ done < "$TMP_NAMES"
131
+
132
+ # Delete each invalid token
133
+ DELETED=0
134
+ ERRORS=0
135
+ ERROR_LIST=""
136
+
137
+ while IFS= read -r NAME; do
138
+ if [ -z "$NAME" ]; then
139
+ continue
140
+ fi
141
+
142
+ # URL-encode the name (handles @ and . in email-based filenames)
143
+ ENCODED_NAME=$(printf '%s' "$NAME" | sed 's/@/%40/g' | sed 's/ /%20/g')
144
+
145
+ DEL_STATUS=$(curl -s -o /tmp/del_resp_$$.json -w "%{http_code}" \
146
+ -X DELETE \
147
+ -H "Authorization: Bearer ${MANAGEMENT_PASSWORD}" \
148
+ "${API_BASE}/auth-files?name=${ENCODED_NAME}" 2>/dev/null)
149
+
150
+ if [ "$DEL_STATUS" = "200" ]; then
151
+ echo "${LOG_PREFIX} DELETED: ${NAME}"
152
+ DELETED=$((DELETED + 1))
153
+ else
154
+ DEL_ERR=$(cat /tmp/del_resp_$$.json 2>/dev/null)
155
+ echo "${LOG_PREFIX} ERROR deleting ${NAME} (HTTP ${DEL_STATUS}): ${DEL_ERR}"
156
+ ERRORS=$((ERRORS + 1))
157
+ ERROR_LIST="${ERROR_LIST} • ${NAME} (HTTP ${DEL_STATUS})
158
+ "
159
+ fi
160
+ rm -f /tmp/del_resp_$$.json
161
+ done < "$TMP_NAMES"
162
+
163
+ echo "${LOG_PREFIX} Cleanup done. Deleted: ${DELETED}, Errors: ${ERRORS}"
164
+
165
+ # Send Feishu notification with summary
166
+ if [ "$ERRORS" -gt 0 ]; then
167
+ NOTIFY_TITLE="⚠️ Token 清理完成(有错误)"
168
+ NOTIFY_BODY="$(date '+%Y-%m-%d %H:%M:%S')
169
+ 共 ${TOTAL} 个 token,清理 ${TO_DELETE} 个失效 token。
170
+
171
+ 已删除(${DELETED} 个):
172
+ ${DETAIL_LIST}
173
+ 删除失败(${ERRORS} 个):
174
+ ${ERROR_LIST}"
175
+ else
176
+ NOTIFY_TITLE="🧹 Token 清理完成"
177
+ NOTIFY_BODY="$(date '+%Y-%m-%d %H:%M:%S')
178
+ 共 ${TOTAL} 个 token,成功清理 ${DELETED} 个失效 token。
179
+
180
+ 已删除:
181
+ ${DETAIL_LIST}"
182
+ fi
183
+
184
+ notify_feishu "$NOTIFY_TITLE" "$NOTIFY_BODY"