Upload app.py
Browse files
app.py
CHANGED
|
@@ -56,19 +56,20 @@ app.add_middleware(
|
|
| 56 |
|
| 57 |
# 允許的來源網址清單
|
| 58 |
ALLOWED_ORIGINS = [
|
| 59 |
-
#
|
| 60 |
-
"https://script.google.com/a/macros/apps.dfes.ntpc.edu.tw",
|
| 61 |
-
"https://script.googleusercontent.com", # GAS 實際執行網域
|
| 62 |
-
# 一般網頁來源
|
| 63 |
"https://www.dfes.ntpc.edu.tw",
|
| 64 |
"https://www.dfes.ntpc.edu.tw/"
|
| 65 |
]
|
| 66 |
|
| 67 |
-
#
|
| 68 |
-
#
|
|
|
|
| 69 |
|
| 70 |
-
#
|
| 71 |
-
|
|
|
|
|
|
|
|
|
|
| 72 |
|
| 73 |
# 掛載靜態文件(如果存在)
|
| 74 |
if os.path.exists("static"):
|
|
@@ -96,29 +97,14 @@ def _is_origin_allowed(request: Request) -> bool:
|
|
| 96 |
|
| 97 |
print(f"請求來源檢查 - Origin: {origin}, Referer: {referer}, User-Agent: {user_agent}")
|
| 98 |
|
| 99 |
-
#
|
| 100 |
-
# GAS 請求的特徵:
|
| 101 |
-
# 1. Origin 通常包含 script.googleusercontent.com
|
| 102 |
-
# 2. 或者沒有 Origin/Referer 標頭(沙箱環境)
|
| 103 |
-
# 3. User-Agent 通常是標準的瀏覽器標頭
|
| 104 |
-
|
| 105 |
-
# 檢查是否為 GAS 的 Origin
|
| 106 |
-
if origin and "script.googleusercontent.com" in origin:
|
| 107 |
-
print("✅ 檢測到 Google Apps Script Origin")
|
| 108 |
-
return True
|
| 109 |
-
|
| 110 |
-
# 檢查是否為 GAS 的 Referer
|
| 111 |
-
if referer and "script.googleusercontent.com" in referer:
|
| 112 |
-
print("✅ 檢測到 Google Apps Script Referer")
|
| 113 |
-
return True
|
| 114 |
-
|
| 115 |
-
# 檢查其他允許的來源(一般網頁)
|
| 116 |
if origin:
|
| 117 |
for allowed_origin in ALLOWED_ORIGINS:
|
| 118 |
if origin.startswith(allowed_origin):
|
| 119 |
print(f"✅ Origin 匹配: {origin} 匹配 {allowed_origin}")
|
| 120 |
return True
|
| 121 |
|
|
|
|
| 122 |
if referer:
|
| 123 |
for allowed_origin in ALLOWED_ORIGINS:
|
| 124 |
if referer.startswith(allowed_origin):
|
|
@@ -126,20 +112,27 @@ def _is_origin_allowed(request: Request) -> bool:
|
|
| 126 |
return True
|
| 127 |
|
| 128 |
# 檢查是否為 GAS 沙箱環境(沒有 Origin/Referer 但有標準瀏覽器 User-Agent)
|
| 129 |
-
# 這種情況下,我們需要通過其他方式驗證
|
| 130 |
if not origin and not referer and "mozilla" in user_agent.lower():
|
| 131 |
-
# 檢查是否有 GAS 特有的標頭或特徵
|
| 132 |
-
# 可以通過檢查特定的請求標頭來驗證
|
| 133 |
print("⚠️ 檢測到可能的 GAS 沙箱請求")
|
| 134 |
|
| 135 |
-
# 檢查是否有
|
| 136 |
-
|
| 137 |
-
if
|
| 138 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
return True
|
| 140 |
|
| 141 |
-
|
| 142 |
-
print("⚠️
|
| 143 |
return True
|
| 144 |
|
| 145 |
# 允許來自 Hugging Face Spaces 的直接調用
|
|
@@ -216,20 +209,23 @@ async def gas_verify(request: Request):
|
|
| 216 |
"current_status": "✅ 請求已通過驗證" if is_gas else "❌ 請求被拒絕"
|
| 217 |
},
|
| 218 |
"gas_usage_example": {
|
| 219 |
-
"description": "在 GAS 中使用此 API 的範例",
|
| 220 |
"code": """
|
| 221 |
// 在 Google Apps Script 中
|
| 222 |
const response = UrlFetchApp.fetch('https://your-api-url/tts', {
|
| 223 |
method: 'POST',
|
| 224 |
headers: {
|
| 225 |
'Content-Type': 'application/json',
|
| 226 |
-
'x-
|
|
|
|
| 227 |
},
|
| 228 |
payload: JSON.stringify({
|
| 229 |
text: '要轉換的文字',
|
| 230 |
voice: 'zh-TW-HsiaoChenNeural'
|
| 231 |
})
|
| 232 |
});
|
|
|
|
|
|
|
| 233 |
"""
|
| 234 |
}
|
| 235 |
}
|
|
@@ -384,4 +380,4 @@ async def delete_audio_file(file_id: str):
|
|
| 384 |
|
| 385 |
if __name__ == "__main__":
|
| 386 |
import uvicorn
|
| 387 |
-
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
| 56 |
|
| 57 |
# 允許的來源網址清單
|
| 58 |
ALLOWED_ORIGINS = [
|
| 59 |
+
"https://script.google.com/a/macros/apps.dfes.ntpc.edu.tw", # 特定組織的 GAS
|
|
|
|
|
|
|
|
|
|
| 60 |
"https://www.dfes.ntpc.edu.tw",
|
| 61 |
"https://www.dfes.ntpc.edu.tw/"
|
| 62 |
]
|
| 63 |
|
| 64 |
+
# 注意:GAS 實際執行時會使用 script.googleusercontent.com
|
| 65 |
+
# 但我們無法從該網址判斷是否來自特定組織
|
| 66 |
+
# 因此主要依賴於沙箱環境檢測
|
| 67 |
|
| 68 |
+
# 允許的組織標識(用於 GAS 驗證)
|
| 69 |
+
ALLOWED_ORGANIZATIONS = [
|
| 70 |
+
"apps.dfes.ntpc.edu.tw", # 大豐國小組織
|
| 71 |
+
"dfes.ntpc.edu.tw" # 大豐國小網域
|
| 72 |
+
]
|
| 73 |
|
| 74 |
# 掛載靜態文件(如果存在)
|
| 75 |
if os.path.exists("static"):
|
|
|
|
| 97 |
|
| 98 |
print(f"請求來源檢查 - Origin: {origin}, Referer: {referer}, User-Agent: {user_agent}")
|
| 99 |
|
| 100 |
+
# 檢查 Origin 標頭
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
if origin:
|
| 102 |
for allowed_origin in ALLOWED_ORIGINS:
|
| 103 |
if origin.startswith(allowed_origin):
|
| 104 |
print(f"✅ Origin 匹配: {origin} 匹配 {allowed_origin}")
|
| 105 |
return True
|
| 106 |
|
| 107 |
+
# 檢查 Referer 標頭(備用檢查)
|
| 108 |
if referer:
|
| 109 |
for allowed_origin in ALLOWED_ORIGINS:
|
| 110 |
if referer.startswith(allowed_origin):
|
|
|
|
| 112 |
return True
|
| 113 |
|
| 114 |
# 檢查是否為 GAS 沙箱環境(沒有 Origin/Referer 但有標準瀏覽器 User-Agent)
|
|
|
|
| 115 |
if not origin and not referer and "mozilla" in user_agent.lower():
|
|
|
|
|
|
|
| 116 |
print("⚠️ 檢測到可能的 GAS 沙箱請求")
|
| 117 |
|
| 118 |
+
# 檢查是否有組織標識標頭
|
| 119 |
+
org_header = request.headers.get("x-organization")
|
| 120 |
+
if org_header:
|
| 121 |
+
for allowed_org in ALLOWED_ORGANIZATIONS:
|
| 122 |
+
if allowed_org in org_header.lower():
|
| 123 |
+
print(f"✅ 組織驗證通過: {org_header}")
|
| 124 |
+
return True
|
| 125 |
+
print(f"❌ 組織驗證失敗: {org_header}")
|
| 126 |
+
return False
|
| 127 |
+
|
| 128 |
+
# 檢查是否有自定義驗證標頭
|
| 129 |
+
custom_header = request.headers.get("x-dfes-verified")
|
| 130 |
+
if custom_header == "true":
|
| 131 |
+
print("✅ 自定義驗證標頭通過")
|
| 132 |
return True
|
| 133 |
|
| 134 |
+
print("⚠️ 沒有組織驗證標頭,暫時允許請求")
|
| 135 |
+
print("⚠️ 建議在 GAS 中添加 'x-organization' 或 'x-dfes-verified' 標頭")
|
| 136 |
return True
|
| 137 |
|
| 138 |
# 允許來自 Hugging Face Spaces 的直接調用
|
|
|
|
| 209 |
"current_status": "✅ 請求已通過驗證" if is_gas else "❌ 請求被拒絕"
|
| 210 |
},
|
| 211 |
"gas_usage_example": {
|
| 212 |
+
"description": "在 GAS 中使用此 API 的範例(建議添加組織驗證)",
|
| 213 |
"code": """
|
| 214 |
// 在 Google Apps Script 中
|
| 215 |
const response = UrlFetchApp.fetch('https://your-api-url/tts', {
|
| 216 |
method: 'POST',
|
| 217 |
headers: {
|
| 218 |
'Content-Type': 'application/json',
|
| 219 |
+
'x-organization': 'apps.dfes.ntpc.edu.tw', // 組織標識
|
| 220 |
+
'x-dfes-verified': 'true' // 自定義驗證標頭
|
| 221 |
},
|
| 222 |
payload: JSON.stringify({
|
| 223 |
text: '要轉換的文字',
|
| 224 |
voice: 'zh-TW-HsiaoChenNeural'
|
| 225 |
})
|
| 226 |
});
|
| 227 |
+
|
| 228 |
+
// 注意:添加這些標頭可以確保只有大豐國小的 GAS 才能使用 API
|
| 229 |
"""
|
| 230 |
}
|
| 231 |
}
|
|
|
|
| 380 |
|
| 381 |
if __name__ == "__main__":
|
| 382 |
import uvicorn
|
| 383 |
+
uvicorn.run(app, host="0.0.0.0", port=7860)
|