From d3a4efc173f28fcd83f6811df4548c9272414e1b Mon Sep 17 00:00:00 2001 From: KINDNICK Date: Thu, 30 Apr 2026 18:23:51 +0900 Subject: [PATCH] v2.3.3: fix Discord webhook always failing (Cloudflare blocks Python UA) Cloudflare protects Discord webhook endpoints and rejects requests with the default Python urllib User-Agent ('Python-urllib/3.x') with HTTP 403 + 'error code 1010'. Add a browser-like User-Agent header to the request. The onboarding wizard's 'Send Test Message' button (and clock-in/out push messages) now succeed. Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 10 ++++++++++ core/version.py | 2 +- utils/discord_webhook.py | 9 ++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d538c9a..61a1d58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +## [2.3.3] — 2026-04-30 + +### Fixed +- **Discord 웹훅 항상 실패하던 문제** (Cloudflare error 1010 / 403 Forbidden) + - 원인: Python 기본 User-Agent(`Python-urllib/3.x`)를 Discord/Cloudflare가 + 봇으로 인식해 차단 + - 수정: `utils/discord_webhook.py`에 브라우저 UA 헤더 추가 + (`Mozilla/5.0 (Windows NT 10.0; Win64; x64) ClockOutCalculator/2.3`) + - 이제 온보딩 위저드의 "테스트 메시지 보내기" + 출퇴근/휴식 push 모두 정상 동작 + ## [2.3.2] — 2026-04-30 ### Fixed diff --git a/core/version.py b/core/version.py index f1a3b5f..9097ce3 100644 --- a/core/version.py +++ b/core/version.py @@ -4,4 +4,4 @@ 릴리스 시 이 값을 올린 후 git tag → push. CHANGELOG.md의 최상단 항목과 일치시킬 것. """ -__version__ = '2.3.2' +__version__ = '2.3.3' diff --git a/utils/discord_webhook.py b/utils/discord_webhook.py index ed4ef77..72835a2 100644 --- a/utils/discord_webhook.py +++ b/utils/discord_webhook.py @@ -10,6 +10,10 @@ import urllib.error from datetime import datetime from typing import Optional, List +# Discord/Cloudflare는 Python 기본 UA(Python-urllib/3.x)를 봇으로 차단(error 1010). +# 일반 브라우저 UA로 위장해야 통과. +USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ClockOutCalculator/2.3' + # Discord embed 색상 (decimal) COLOR_GREEN = 0x57F287 COLOR_BLUE = 0x5865F2 @@ -49,7 +53,10 @@ def send(webhook_url: str, title: str, description: str, data = json.dumps(payload, ensure_ascii=False).encode('utf-8') req = urllib.request.Request( webhook_url, data=data, - headers={'Content-Type': 'application/json; charset=utf-8'}, + headers={ + 'Content-Type': 'application/json; charset=utf-8', + 'User-Agent': USER_AGENT, + }, method='POST', ) try: