mirror of
https://github.com/jackeilles/xygt.git
synced 2024-11-23 23:32:38 +01:00
kinda working??? cant pass a string through curl:(
This commit is contained in:
parent
ff9fb826e8
commit
e582c74363
9 changed files with 289 additions and 0 deletions
1
.flaskenv
Normal file
1
.flaskenv
Normal file
|
@ -0,0 +1 @@
|
|||
FLASK_APP=main.py
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -6,6 +6,8 @@ __pycache__/
|
|||
# C extensions
|
||||
*.so
|
||||
|
||||
.vscode/
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
|
@ -158,3 +160,6 @@ cython_debug/
|
|||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# xygt Files
|
||||
data/
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
This repository hosts all of the code for the file hosting site 'xygt.cc'.
|
||||
|
||||
## About
|
||||
xygt.cc is a simple, anonymous, temporary file-hosting service, designed with Python and Flask.
|
||||
|
||||
This uses MongoDB by default for the file index, user database, and the URL shortening DB, I'm **not** adding support for SQL.
|
||||
|
||||
## Website
|
||||
You can access the site on [https://xygt.cc](https://xygt.cc).
|
||||
|
||||
|
|
5
app/__init__.py
Normal file
5
app/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
from app import routes
|
82
app/routes.py
Normal file
82
app/routes.py
Normal file
|
@ -0,0 +1,82 @@
|
|||
from app import app, worker
|
||||
from config import Config, Errors
|
||||
from flask import render_template, request, send_file
|
||||
import os
|
||||
import io
|
||||
import random
|
||||
import magic
|
||||
|
||||
@app.route('/', methods=["GET", "POST"])
|
||||
def index():
|
||||
|
||||
# Check for a GET or POST request
|
||||
if request.method == "GET":
|
||||
return render_template('index.html')
|
||||
|
||||
elif request.method == "POST":
|
||||
|
||||
# Before anything else, we want to take the IP if the logging is enabled
|
||||
if Config.ipLogEnabled == True:
|
||||
ip = request.remote_addr
|
||||
else:
|
||||
# If not then return a 0
|
||||
ip = 0
|
||||
|
||||
# Init variables before they're passed
|
||||
userid = request.form.get("userid") if request.form.get("userid") else None
|
||||
filename = request.form.get("filename") if request.form.get("filename") else None
|
||||
retention = request.form.get("retention") if request.form.get("retention") else None
|
||||
id = request.form.get("filename") if Config.files.find_one({"id": filename}) is None else None
|
||||
|
||||
# We got a file or a url?
|
||||
if 'file' in request.files:
|
||||
|
||||
# Grab the file and store it, this is a FileStorage object
|
||||
file = request.files['file']
|
||||
|
||||
# Call the function to upload the file, this will return either HTTP Status codes or a 200 with a URL.
|
||||
result, status = worker.uploadFile(file, ip, userid, filename, id, retention)
|
||||
|
||||
result = "https://xygt.cc/{}".format(result)
|
||||
|
||||
return result, status
|
||||
|
||||
elif 'url' in request.form:
|
||||
result, status = worker.shortURL(url, ip, userid, id, retention)
|
||||
|
||||
@app.route('/<id>')
|
||||
def getData(id):
|
||||
|
||||
# Does it exist in the files DB?
|
||||
if Config.files.find_one({"id": id}) is not None:
|
||||
data = Config.files.find_one({"id": id})
|
||||
|
||||
with open(os.path.join(Config.fileDir, id), "rb") as f:
|
||||
file = f.read()
|
||||
|
||||
# Get MIME type from file, if fails then use magic
|
||||
try:
|
||||
mimetype = data["mimetype"]
|
||||
except KeyError:
|
||||
mimetype = magic.from_buffer(file, mime=True)
|
||||
|
||||
# Return the file with the correct MIME type
|
||||
return send_file(io.BytesIO(file), mimetype=mimetype)
|
||||
|
||||
# If not then check the URL Shortening DB
|
||||
elif Config.url.find_one({"id": id}) is not None:
|
||||
data = Config.url.find_one({"id": id})
|
||||
|
||||
return redirect(data["url"])
|
||||
|
||||
else:
|
||||
return random.choice(Errors.file404)
|
||||
|
||||
@app.route('/<id>/info')
|
||||
def getInfo(id):
|
||||
|
||||
return worker.idInfo(id)
|
||||
|
||||
@app.route('/teapot')
|
||||
def teapot():
|
||||
return 'I\'m a teapot. 418.', 418
|
1
app/templates/index.html
Normal file
1
app/templates/index.html
Normal file
|
@ -0,0 +1 @@
|
|||
Under Construction - No frontend available yet.
|
111
app/worker.py
Normal file
111
app/worker.py
Normal file
|
@ -0,0 +1,111 @@
|
|||
from config import disallowedMimeTypes, Errors, Config
|
||||
import secrets
|
||||
import magic
|
||||
import datetime
|
||||
import random
|
||||
import time
|
||||
import os
|
||||
|
||||
def uploadFile(file, ip, userid, filename, id, retention):
|
||||
|
||||
# Is the MIME and file size good?
|
||||
if file.content_type not in disallowedMimeTypes:
|
||||
if file.content_length <= Config.maxFileSize:
|
||||
# We're going to check whether the id variable has been filled
|
||||
|
||||
while True: # Loop to find an available file ID
|
||||
id = randomHex() # Prevent conflicts if 2 of the same get made
|
||||
if Config.files.find_one({'id': id}) is None:
|
||||
filename = id
|
||||
break
|
||||
|
||||
if userid == None:
|
||||
userid = 0
|
||||
elif Config.users.find_one({'userid': userid}) == None:
|
||||
userid = 0
|
||||
|
||||
# Calculate retention before the file is written, we'll grab the filesize here as it's needed for the equation.
|
||||
fileSize = round(float(file.content_length) / 1024, 2)
|
||||
|
||||
if retention == None:
|
||||
retention = (Config.minretention+(-Config.maxretention + Config.minretention)*pow((fileSize / Config.maxFileSize -1), 3))
|
||||
elif retention > (Config.minretention+(-Config.maxretention + Config.minretention)*pow((fileSize / Config.maxFileSize -1), 3)):
|
||||
retention = (Config.minretention+(-Config.maxretention + Config.minretention)*pow((fileSize / Config.maxFileSize -1), 3))
|
||||
|
||||
if file.
|
||||
# Create the file
|
||||
with open(f"{os.path.abspath(Config.fileDir)}/{filename}", "wb") as f:
|
||||
f.write(file.read())
|
||||
|
||||
date = time.mktime(datetime.datetime.now().timetuple())
|
||||
|
||||
# Create the dictionary that we'll insert into the db
|
||||
data = {
|
||||
'id': id,
|
||||
'filename': filename,
|
||||
'filesize': fileSize,
|
||||
'retention': round(retention * 86400), # Convert to seconds
|
||||
'userid': userid,
|
||||
'ip': ip,
|
||||
'date': date,
|
||||
'expiry': date + round(retention * 86400)
|
||||
}
|
||||
|
||||
# Add the data and verify its there.
|
||||
Config.files.insert_one(data)
|
||||
print(Config.files.find_one({"id": id}))
|
||||
|
||||
return id, 200
|
||||
else:
|
||||
return random.choice(Errors.fileTooLarge), 400
|
||||
else:
|
||||
return random.choice(Errors.fileTypeNotAllowed), 400
|
||||
|
||||
def shortenURL(url, ip, userid, id, retention):
|
||||
# We're going to check whether the id variable has been filled
|
||||
# If not then we'll generate one. (The ID variable will be the same as the filename if not rejected earlier.)
|
||||
if id == None:
|
||||
while True: # Loop to find an available file ID
|
||||
id = randomHex() # Prevent conflicts if 2 of the same get made
|
||||
if Config.files.find_one({'id': id}) is None:
|
||||
filename = id
|
||||
break
|
||||
|
||||
if userid == None:
|
||||
userid = 0
|
||||
elif Config.users.find_one({'userid': userid}) == None:
|
||||
userid = 0
|
||||
|
||||
if retention == None:
|
||||
retention = 14
|
||||
elif retention > 365:
|
||||
retention = 365
|
||||
|
||||
data = {
|
||||
"id": id,
|
||||
"url": url,
|
||||
"userid": userid,
|
||||
"retention": retention,
|
||||
"ip": ip
|
||||
}
|
||||
|
||||
Config.url.insert_one(data)
|
||||
print(Config.url.find_one({"id": data["id"]}))
|
||||
|
||||
return id
|
||||
|
||||
def idInfo(id):
|
||||
# Check files and url for the ID
|
||||
if Config.files.find_one({"id": id}) is not None:
|
||||
check = Config.files.find_one({"id": id}, {'_id': False}, {"ip": False})
|
||||
# "ip": False removes the IP from the returned data.
|
||||
# If it's not there then check url
|
||||
elif Config.url.find_one({"id": id}) is not None:
|
||||
check = Config.url.find_one({"id": id}, {'_id': False}, {"ip": False})
|
||||
|
||||
# Return the mongodb info about the file, removing IP if its present
|
||||
return check
|
||||
|
||||
def randomHex():
|
||||
hexRand = ''.join(secrets.choice('0123456789abcdef') for _ in range(6))
|
||||
return hexRand
|
75
config.py
Normal file
75
config.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
import os
|
||||
from pymongo import MongoClient
|
||||
|
||||
class Config:
|
||||
# MongoDB init stuff
|
||||
client = MongoClient("mongodb://localhost:27017/")
|
||||
db = client["xygt"]
|
||||
files = db["file"]
|
||||
url = db["url"]
|
||||
users = db["users"]
|
||||
|
||||
# Basic configs
|
||||
maxFileSize = 256
|
||||
premMaxFileSize = 512
|
||||
maxretention = 365
|
||||
minretention = 7
|
||||
fileDir = "./data"
|
||||
ipLogEnabled = False
|
||||
|
||||
quotes = {
|
||||
"Anon /g/": "Biometrics are shit, you lose a limb and you're fucked.",
|
||||
"Jack": "i named it xygt because it sounds cool lmao",
|
||||
"Cow": "Does this server run Gentoo? (no it doesn't)",
|
||||
"uname -a": "Linux xygt 6.1.0-12-arm64 #1 SMP Debian 6.1.52-1 (2023-09-07) aarch64 GNU/Linux",
|
||||
"Luna": "shit you moth",
|
||||
"Maze": "Mein Gott Leute, meine Mama hat mir einfach erlaubt dass ich Cola trinken darf! Wie cool ist das bitte? Jetzt zocke ich Fortnite und trinke Cola! YIPPEE!",
|
||||
}
|
||||
|
||||
disallowedMimeTypes = [
|
||||
"application/x-dosexec",
|
||||
"application/java-archive",
|
||||
"application/java-vm"
|
||||
]
|
||||
|
||||
class Errors:
|
||||
file404 = [
|
||||
"The file you seek does not exist...",
|
||||
"Nope, can't find it.",
|
||||
"AVE FOOKIN LOST IT",
|
||||
"My shitty filehost can't find this, sorry lmao",
|
||||
"Your file could not be found.",
|
||||
"You fucked up somewhere, this link doesn't work.",
|
||||
"If someone gave you this link, go shout at them, it's broken.",
|
||||
"404.",
|
||||
"The file isn't in our db, so it's probably expired or just never existed in the first place."
|
||||
]
|
||||
|
||||
fileTooLarge = [
|
||||
"Too big, nah.",
|
||||
"File size goes over the limit, you're not uploading this"
|
||||
"Your file is too large, get it under 256mb first.",
|
||||
"I don't know what the hell you're trying to upload but it's over 256mb, so no.",
|
||||
"Your file is over 256mb, remember, we don't store your files forever!",
|
||||
"File is too big, 265mb is the limit.",
|
||||
"nuh uh, too big"
|
||||
]
|
||||
|
||||
fileTypeNotAllowed = [
|
||||
"Nice try idiot. You're not uploading that onto my server.",
|
||||
"No executables allowed, NO EXCEPTIONS.",
|
||||
"So bud... what you trying to do there? You can't upload executables you know.",
|
||||
"Nah, not getting that on here today.",
|
||||
"Stop trying to upload executables, goddamnit.",
|
||||
"Executables can suck my dick, you're not uploading that"
|
||||
"nuh uh (executables not allowed)"
|
||||
]
|
||||
|
||||
def file404Error():
|
||||
return random.choice(self.file404.items())
|
||||
|
||||
def fileTooLargeError():
|
||||
return random.choice(self.fileTooLarge.items())
|
||||
|
||||
def fileTypeNotAllowedError():
|
||||
return random.choice(self.fileTypeNotAllowed.items())
|
4
requirements.txt
Normal file
4
requirements.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
flask
|
||||
flask-dotenv
|
||||
pymongo
|
||||
python-magic
|
Loading…
Reference in a new issue