Skip to content

Instantly share code, notes, and snippets.

@SpiralAPI
Last active January 6, 2024 18:17
Show Gist options
  • Save SpiralAPI/41f655ebca7fc8acae0a2117eafcc942 to your computer and use it in GitHub Desktop.
Save SpiralAPI/41f655ebca7fc8acae0a2117eafcc942 to your computer and use it in GitHub Desktop.
Queue-based Discord Webhook Proxy (Designed for roblox)
# Made by SpiralAPI
# This system automatically ratelimits all requests, with the downside of not returning errors when there is an issue with your Webhook Data.
# Workaround: Don't switch your proxy to this one until you are certain that it is functional.
# If you do use this, I highly suggest hosting this alongside Nginx and UWSGI. Your welcome!
# edit: this is pretty old, it works but theres better ways to do it
# //IMPORTS
from flask import Flask, request, jsonify
import redis
import requests
import validators
from urllib.parse import urlparse
from threading import Thread
import json
import re
from time import sleep
# //Variables
app = Flask(__name__)
client = redis.Redis() # you must setup your own redis server! https://developer.redis.com/develop/python/#step-1-run-a-redis-server
RobloxIPs = ["103.140.28.0", "128.116.0.0", "128.116.2.0", "128.116.3.0", "128.116.4.0", "128.116.6.0", "128.116.8.0", "128.116.11.0", "128.116.13.0", "128.116.14.0", "128.116.15.0", "128.116.16.0", "128.116.17.0", "128.116.18.0", "128.116.19.0", "128.116.20.0", "128.116.23.0", "128.116.24.0", "128.116.25.0", "128.116.26.0", "128.116.27.0", "128.116.28.0", "128.116.29.0", "128.116.34.0", "128.116.35.0", "128.116.36.0", "128.116.37.0", "128.116.38.0", "128.116.39.0", "128.116.40.0", "128.116.41.0", "128.116.42.0", "128.116.43.0", "128.116.44.0", "128.116.45.0", "128.116.46.0", "128.116.49.0", "128.116.50.0", "128.116.51.0", "128.116.58.0", "128.116.59.0", "128.116.60.0", "128.116.62.0", "128.116.65.0", "128.116.67.0", "128.116.69.0", "128.116.70.0", "128.116.71.0", "128.116.72.0", "128.116.73.0", "128.116.74.0", "128.116.75.0", "128.116.76.0", "128.116.77.0", "128.116.78.0", "128.116.80.0", "128.116.81.0", "128.116.82.0", "128.116.83.0", "128.116.84.0", "128.116.85.0", "128.116.87.0", "128.116.88.0", "128.116.89.0", "128.116.95.0", "128.116.97.0", "128.116.99.0", "128.116.101.0", "128.116.102.0", "128.116.104.0", "128.116.105.0", "128.116.112.0", "128.116.114.0", "128.116.115.0", "128.116.116.0", "128.116.117.0", "128.116.118.0", "128.116.119.0", "128.116.120.0", "128.116.121.0", "128.116.122.0", "128.116.123.0", "128.116.124.0", "128.116.126.0", "128.116.127.0", "141.193.3.0", "205.201.62.0", "209.206.40.0", "209.206.40.0", "209.206.42.0", "209.206.43.0", "209.206.44.0"]
# //FUNCTIONS
def detect_special_character(pass_string): # special character detection. i got this off of stack overflow i think
regex= re.compile('[@_!#$%^&*()<>?/\|}{~:]')
if(regex.search(pass_string) == None):
res = False
else:
res = True
return(res)
def processQueue():
while True:
task = client.blpop("discord_queue") # pops (retrives + deletes from list) the most recent object in the redis queue
data = json.loads(task[1]) # turn in to a python object
webhook_data = data["value"]
webhook_url = data["webhook_url"]
try:
req = requests.post(webhook_url, json=webhook_data) # sends the webhook with all data provided
if req.status_code == 200:
return jsonify({"response": "Success."}), 200
except requests.exceptions.RequestException as error:
return jsonify({"response": error}), 500
sleep(1/30) # important so that there aren't ratelimits!
# //APP FUNCTIONALITY
@app.route('/api', defaults={'path': ''}) # opens a new path "/api"
@app.route('/<path:path>', methods=["POST", "GET"]) # allows any path to follow "/api", for example "/api/hello" would work
def proxy(path):
webhookUrl = "https://discord.com/" + path
if not validators.url(webhookUrl) or detect_special_character(webhookUrl) and not urlparse(webhookUrl).hostname == "discord.com" and urlparse(webhookUrl).scheme:
jsonify({"response": "Webhook URL Invalid."}), 400 # checks to make sure the webhook url is valid
if not request.remote_addr in RobloxIPs: # i added this to prevent external use from NON roblox ip's however its not needed
return jsonify({"response": "Access denied. Make sure you are using this service on a ROBLOX server."}), 401
if request.method == "POST": # the main usage. when posting to your servers endpoint it will run
data2 = {}
data = request.get_json()
data2["webhook_url"] = webhookUrl
data2["value"] = data
if data2 and "webhook_url" in data2:
client.rpush("discord_queue", json.dumps(data2)) # adds all webhook data in to the redis queue where it is then processed
return webhookUrl
elif request.method == "GET": # i dont really see any reason why you'd need this but i added it anyways
try:
resp = requests.get(webhookUrl)
return resp.json()
except:
return jsonify({"response": "Error returning webhook info."}), 500
# //STARTUP
queue_thread = Thread(target=processQueue) # starts a new thread that executes the processQueue function
queue_thread.start()
app.run("0.0.0.0", 1050) # run your flask app.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment