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
|
# C extensions
|
||||||
*.so
|
*.so
|
||||||
|
|
||||||
|
.vscode/
|
||||||
|
|
||||||
# Distribution / packaging
|
# Distribution / packaging
|
||||||
.Python
|
.Python
|
||||||
build/
|
build/
|
||||||
|
@ -158,3 +160,6 @@ cython_debug/
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
# 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.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
#.idea/
|
||||||
|
|
||||||
|
# xygt Files
|
||||||
|
data/
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
|
|
||||||
This repository hosts all of the code for the file hosting site 'xygt.cc'.
|
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
|
## Website
|
||||||
You can access the site on [https://xygt.cc](https://xygt.cc).
|
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