mirror of
https://github.com/artemium428/tvsignals-to-tg.git
synced 2026-09-15 17:16:21 +00:00
Protect webhook with a secret path token.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
7fd6f38d87
commit
b9a9ed1636
5 changed files with 21 additions and 7 deletions
|
|
@ -1,5 +1,6 @@
|
|||
TELEGRAM_BOT_TOKEN=123456:ABC-DEF
|
||||
TELEGRAM_CHAT_ID=-1001234567890
|
||||
TELEGRAM_MESSAGE_THREAD_ID=1
|
||||
WEBHOOK_SECRET=change-me-to-a-long-random-string
|
||||
HOST=0.0.0.0
|
||||
PORT=8000
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ curl http://127.0.0.1:8000/health
|
|||
|
||||
4. Put HTTPS in front (nginx/Caddy) and point TradingView webhook to:
|
||||
|
||||
`https://your-domain/webhook`
|
||||
`https://your-domain/h/<WEBHOOK_SECRET>`
|
||||
|
||||
Bot must be added to the group/forum and allowed to post in the target topic.
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ Build the JSON inside `alert()`. A continuous one-line string is fine.
|
|||
|
||||
In the TradingView alert dialog:
|
||||
|
||||
- Webhook URL: `https://your-domain/webhook`
|
||||
- Webhook URL: `https://your-domain/h/<WEBHOOK_SECRET>`
|
||||
- Message: only `{{alert_message}}` (do not paste a second JSON next to it)
|
||||
|
||||
On **seq == 1**: store `entry_price = close`, freeze SL/TPs, and `signal_time = time / 1000` (bar open, unix seconds). On **seq > 1**: keep those frozen fields; only refresh `current_price` (= live `close`). Example shape:
|
||||
|
|
@ -147,4 +147,4 @@ For seq >1, profit % is signed vs entry; RR is `|price−entry| / |entry−SL|`
|
|||
## Endpoints
|
||||
|
||||
- `GET /health` → `{"status":"ok"}`
|
||||
- `POST /webhook` → signal payload above
|
||||
- `POST /h/<WEBHOOK_SECRET>` → signal payload above (wrong/missing secret → `404`)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ class Settings(BaseSettings):
|
|||
telegram_bot_token: str
|
||||
telegram_chat_id: str
|
||||
telegram_message_thread_id: int
|
||||
webhook_secret: str
|
||||
host: str = "0.0.0.0"
|
||||
port: int = 8000
|
||||
|
||||
|
|
|
|||
18
app/main.py
18
app/main.py
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import json
|
||||
import logging
|
||||
import secrets
|
||||
from typing import Any
|
||||
|
||||
from fastapi import FastAPI, HTTPException, Request
|
||||
|
|
@ -21,7 +22,13 @@ logging.basicConfig(
|
|||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
app = FastAPI(title="TV Signals → Telegram", version="1.0.0")
|
||||
app = FastAPI(
|
||||
title="TV Signals → Telegram",
|
||||
version="1.0.0",
|
||||
docs_url=None,
|
||||
redoc_url=None,
|
||||
openapi_url=None,
|
||||
)
|
||||
|
||||
|
||||
def _parse_signal_body(raw: bytes) -> SignalPayload:
|
||||
|
|
@ -50,10 +57,13 @@ async def health() -> dict[str, str]:
|
|||
return {"status": "ok"}
|
||||
|
||||
|
||||
@app.post("/webhook")
|
||||
async def webhook(request: Request) -> JSONResponse:
|
||||
signal = _parse_signal_body(await request.body())
|
||||
@app.post("/h/{token}")
|
||||
async def webhook(token: str, request: Request) -> JSONResponse:
|
||||
settings = get_settings()
|
||||
if not secrets.compare_digest(token, settings.webhook_secret):
|
||||
raise HTTPException(status_code=404, detail="Not Found")
|
||||
|
||||
signal = _parse_signal_body(await request.body())
|
||||
caption = format_caption(signal)
|
||||
logger.info(
|
||||
"Signal received: %s %s seq=%s tf=%s",
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ services:
|
|||
sync: false
|
||||
- key: TELEGRAM_MESSAGE_THREAD_ID
|
||||
sync: false
|
||||
- key: WEBHOOK_SECRET
|
||||
sync: false
|
||||
- key: MPLBACKEND
|
||||
value: Agg
|
||||
- key: HOST
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue