1
This commit is contained in:
commit
885ec7e678
12
Dockerfile.bridge
Normal file
12
Dockerfile.bridge
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN pip install --no-cache-dir flask gunicorn
|
||||||
|
|
||||||
|
COPY app.py .
|
||||||
|
COPY mapping.json .
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["gunicorn", "--bind", "0.0.0.0:3000", "app:app"]
|
||||||
67
app.py
Normal file
67
app.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
from flask import Flask, request, jsonify
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
KUMA_BASE_URL = os.getenv("KUMA_BASE_URL", "http://localhost:3001/api/push")
|
||||||
|
MAPPING_FILE = os.getenv("MAPPING_FILE", "mapping.json")
|
||||||
|
# Shared secret for authentication
|
||||||
|
WEBHOOK_SECRET = os.getenv("WEBHOOK_SECRET", "super-secret-key-change-me")
|
||||||
|
|
||||||
|
def load_mapping():
|
||||||
|
if not os.path.exists(MAPPING_FILE):
|
||||||
|
return {}
|
||||||
|
try:
|
||||||
|
with open(MAPPING_FILE, "r") as f:
|
||||||
|
return json.load(f)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ERROR] Failed to parse {MAPPING_FILE}: {e}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
@app.route("/webhook/ppp", methods=["POST"])
|
||||||
|
def ppp_webhook():
|
||||||
|
# 1. Validate Secret Token in Header
|
||||||
|
auth_header = request.headers.get("X-API-Key")
|
||||||
|
if not auth_header or auth_header != WEBHOOK_SECRET:
|
||||||
|
print(f"[WARN] Unauthorized webhook attempt from IP: {request.remote_addr}")
|
||||||
|
return jsonify({"status": "error", "message": "Unauthorized"}), 401
|
||||||
|
|
||||||
|
data = request.get_json(silent=True) or {}
|
||||||
|
|
||||||
|
user = data.get("user")
|
||||||
|
status = data.get("status")
|
||||||
|
ip = data.get("ip", "0.0.0.0")
|
||||||
|
msg = data.get("msg", "")
|
||||||
|
ping = data.get("ping", 0)
|
||||||
|
|
||||||
|
if not user or not status:
|
||||||
|
return jsonify({"status": "error", "message": "Missing required fields"}), 400
|
||||||
|
|
||||||
|
mapping = load_mapping()
|
||||||
|
token = mapping.get(user)
|
||||||
|
|
||||||
|
if not token:
|
||||||
|
print(f"[WARN] No token found for user: '{user}'")
|
||||||
|
return jsonify({"status": "ignored", "message": f"User '{user}' not mapped."}), 404
|
||||||
|
|
||||||
|
kuma_status = "up" if str(status).lower() == "up" else "down"
|
||||||
|
if not msg:
|
||||||
|
msg = f"PPP status is {kuma_status.upper()} for user '{user}' ({ip})"
|
||||||
|
|
||||||
|
encoded_msg = urllib.parse.quote(msg)
|
||||||
|
kuma_url = f"{KUMA_BASE_URL}/{token}?status={kuma_status}&msg={encoded_msg}&ping={ping}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
req = urllib.request.Request(kuma_url, headers={"User-Agent": "MikroTik-Bridge/1.0"})
|
||||||
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
||||||
|
print(f"[INFO] Forwarded push for '{user}' -> status: {kuma_status}")
|
||||||
|
return jsonify({"status": "success"}), 200
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ERROR] Failed to contact Uptime Kuma: {e}")
|
||||||
|
return jsonify({"status": "error", "message": str(e)}), 500
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(host="0.0.0.0", port=3000)
|
||||||
42
docker-compose-with-uptime.yml
Normal file
42
docker-compose-with-uptime.yml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Uptime Kuma Monitoring Service
|
||||||
|
uptime-kuma:
|
||||||
|
image: louislam/uptime-kuma:1
|
||||||
|
container_name: uptime-kuma
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "3001:3001"
|
||||||
|
volumes:
|
||||||
|
- kuma-data:/app/data
|
||||||
|
networks:
|
||||||
|
- kuma-net
|
||||||
|
|
||||||
|
# MikroTik to Uptime Kuma Python Webhook Bridge
|
||||||
|
mikrotik-bridge:
|
||||||
|
build:
|
||||||
|
context: ./bridge
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: mikrotik-kuma-bridge
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
# Internal Docker network URL pointing to the Uptime Kuma service container
|
||||||
|
- KUMA_BASE_URL=http://uptime-kuma:3001/api/push
|
||||||
|
- MAPPING_FILE=mapping.json
|
||||||
|
volumes:
|
||||||
|
# Mount mapping.json so you can edit tokens on the host without rebuilding the container
|
||||||
|
- ./bridge/mapping.json:/app/mapping.json:ro
|
||||||
|
depends_on:
|
||||||
|
- uptime-kuma
|
||||||
|
networks:
|
||||||
|
- kuma-net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
kuma-net:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
kuma-data:
|
||||||
15
docker-compose.yml
Normal file
15
docker-compose.yml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
services:
|
||||||
|
mikrotik-bridge:
|
||||||
|
build:
|
||||||
|
context: ./
|
||||||
|
dockerfile: Dockerfile.bridge
|
||||||
|
container_name: mikrotik-kuma-bridge
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
- KUMA_BASE_URL=http://uptime-kuma:3001/api/push
|
||||||
|
- MAPPING_FILE=mapping.json
|
||||||
|
- WEBHOOK_SECRET=MySuperSecretToken123!
|
||||||
|
volumes:
|
||||||
|
- ./bridge/mapping.json:/app/mapping.json:ro
|
||||||
6
mapping.json
Normal file
6
mapping.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"john_doe": "A1b2C3d4E5",
|
||||||
|
"branch_office_vpn": "F6g7H8i9J0",
|
||||||
|
"site2site_tunnel": "K1l2M3n4O5",
|
||||||
|
"admin_laptop": "P6q7R8s9T0"
|
||||||
|
}
|
||||||
19
mikrotik-script-examples.rsc
Normal file
19
mikrotik-script-examples.rsc
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# --- Define Local Variables ---
|
||||||
|
:local status "up"
|
||||||
|
:local serverUrl "http://localhost/webhook-test.php"
|
||||||
|
:local apiKey "MySuperSecretToken123!"
|
||||||
|
|
||||||
|
# --- Fetch PPP System Variables safely ---
|
||||||
|
:local u $"user"
|
||||||
|
:local lip $"local-address"
|
||||||
|
:local rip $"remote-address"
|
||||||
|
:local cid $"caller-id"
|
||||||
|
:local iface $"interface"
|
||||||
|
|
||||||
|
:local msg ("PPP session " . $status . " on interface " . $iface)
|
||||||
|
|
||||||
|
# --- Construct JSON Body ---
|
||||||
|
:local jsonBody "{\"user\":\"$u\", \"local_ip\":\"$lip\", \"ip\":\"$rip\", \"caller_id\":\"$cid\", \"interface\":\"$iface\", \"status\":\"$status\", \"msg\":\"$msg\"}"
|
||||||
|
|
||||||
|
# --- Send Webhook ---
|
||||||
|
/tool fetch url=$serverUrl http-method=post http-header-field="Content-Type: application/json,X-API-Key: $apiKey" http-data=$jsonBody keep-result=no
|
||||||
10
testing.sh
Normal file
10
testing.sh
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
curl -X POST http://localhost:3000/webhook/ppp \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "X-API-Key: MySuperSecretToken123!" \
|
||||||
|
-d '{
|
||||||
|
"user": "john_doe",
|
||||||
|
"ip": "10.0.0.5",
|
||||||
|
"status": "up"
|
||||||
|
}'
|
||||||
Loading…
x
Reference in New Issue
Block a user