1
0
forked from spitkov/sxbin
This commit is contained in:
spitkov 2024-09-10 20:16:06 +02:00
parent 5751297239
commit 5c0d0413ef
2 changed files with 91 additions and 57 deletions

130
app.py
View File

@ -1,4 +1,4 @@
from flask import Flask, request, jsonify, send_from_directory, render_template, url_for, redirect, send_file, session, make_response, flash from flask import Flask, request, jsonify, send_from_directory, render_template, url_for, redirect, send_file, session, make_response, flash, g
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
import shortuuid import shortuuid
import os import os
@ -29,9 +29,9 @@ if not os.path.exists(UPLOAD_FOLDER):
# Database setup and helper functions # Database setup and helper functions
def get_db(): def get_db():
db = getattr(threading.current_thread(), '_database', None) db = getattr(g, '_database', None)
if db is None: if db is None:
db = threading.current_thread()._database = sqlite3.connect(DATABASE) db = g._database = sqlite3.connect(DATABASE)
return db return db
def init_db(): def init_db():
@ -39,16 +39,30 @@ def init_db():
db = get_db() db = get_db()
cursor = db.cursor() cursor = db.cursor()
# Check if users table exists # Create users table
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='users'") cursor.execute('''
if not cursor.fetchone(): CREATE TABLE IF NOT EXISTS users (
# If it doesn't exist, create it id INTEGER PRIMARY KEY AUTOINCREMENT,
with app.open_resource('schema.sql', mode='r') as f: username TEXT UNIQUE NOT NULL,
db.cursor().executescript(f.read()) password_hash TEXT NOT NULL,
db.commit() api_key TEXT
print("Database initialized with users table.") )
else: ''')
print("Users table already exists.")
# Create content table
cursor.execute('''
CREATE TABLE IF NOT EXISTS content (
vanity TEXT PRIMARY KEY,
type TEXT NOT NULL,
data TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
user_id INTEGER,
FOREIGN KEY (user_id) REFERENCES users (id)
)
''')
db.commit()
print("Database initialized with users and content tables.")
# Call init_db() when the application starts # Call init_db() when the application starts
with app.app_context(): with app.app_context():
@ -69,7 +83,7 @@ def migrate_db():
@app.teardown_appcontext @app.teardown_appcontext
def close_connection(exception): def close_connection(exception):
db = getattr(threading.current_thread(), '_database', None) db = getattr(g, '_database', None)
if db is not None: if db is not None:
db.close() db.close()
@ -85,29 +99,30 @@ def get_username(user_id):
# Add this function to delete old files # Add this function to delete old files
def delete_old_files(): def delete_old_files():
while True: with app.app_context():
db = get_db() while True:
cursor = db.cursor() db = get_db()
cursor = db.cursor()
# Delete files older than 30 days # Delete files older than 30 days
thirty_days_ago = datetime.now() - timedelta(days=30) thirty_days_ago = datetime.now() - timedelta(days=30)
cursor.execute("SELECT vanity, type, data FROM content WHERE created_at < ?", (thirty_days_ago,)) cursor.execute("SELECT vanity, type, data FROM content WHERE created_at < ?", (thirty_days_ago,))
old_files = cursor.fetchall() old_files = cursor.fetchall()
for vanity, content_type, data in old_files: for vanity, content_type, data in old_files:
if content_type == 'file': if content_type == 'file':
file_path = os.path.join(app.config['UPLOAD_FOLDER'], f'{vanity}_{data}') file_path = os.path.join(app.config['UPLOAD_FOLDER'], f'{vanity}_{data}')
if os.path.exists(file_path): if os.path.exists(file_path):
os.remove(file_path) os.remove(file_path)
elif content_type == 'folder': elif content_type == 'folder':
folder_path = os.path.join(app.config['UPLOAD_FOLDER'], vanity) folder_path = os.path.join(app.config['UPLOAD_FOLDER'], vanity)
if os.path.exists(folder_path): if os.path.exists(folder_path):
shutil.rmtree(folder_path) shutil.rmtree(folder_path)
cursor.execute("DELETE FROM content WHERE created_at < ?", (thirty_days_ago,)) cursor.execute("DELETE FROM content WHERE created_at < ?", (thirty_days_ago,))
db.commit() db.commit()
time.sleep(86400) # Sleep for 24 hours time.sleep(86400) # Sleep for 24 hours
# Start the cleanup thread # Start the cleanup thread
cleanup_thread = threading.Thread(target=delete_old_files) cleanup_thread = threading.Thread(target=delete_old_files)
@ -236,6 +251,7 @@ def serve_user_page(username, filename=None):
current_folder=current_folder) current_folder=current_folder)
@app.route('/<vanity>') @app.route('/<vanity>')
@app.route('/<vanity>/download')
def redirect_vanity(vanity): def redirect_vanity(vanity):
db = get_db() db = get_db()
cursor = db.cursor() cursor = db.cursor()
@ -248,7 +264,20 @@ def redirect_vanity(vanity):
if content_type == 'file': if content_type == 'file':
file_path = os.path.join(app.config['UPLOAD_FOLDER'], content_data) file_path = os.path.join(app.config['UPLOAD_FOLDER'], content_data)
if os.path.exists(file_path): if os.path.exists(file_path):
return send_file(file_path) if '/download' in request.path:
return send_file(file_path, as_attachment=True)
else:
# Embed the file if it's an image, video, or audio
file_extension = os.path.splitext(content_data)[1].lower()
if file_extension in ['.jpg', '.jpeg', '.png', '.gif', '.svg']:
return send_file(file_path, mimetype=f'image/{file_extension[1:]}')
elif file_extension in ['.mp3', '.wav']:
return send_file(file_path, mimetype=f'audio/{file_extension[1:]}')
elif file_extension in ['.mp4', '.webm']:
return send_file(file_path, mimetype=f'video/{file_extension[1:]}')
else:
# For other file types, send as attachment
return send_file(file_path, as_attachment=True)
else: else:
return "File not found", 404 return "File not found", 404
elif content_type == 'url': elif content_type == 'url':
@ -791,11 +820,6 @@ def api_upload():
url = url_for('redirect_vanity', vanity=vanity, _external=True) url = url_for('redirect_vanity', vanity=vanity, _external=True)
delete_url = url_for('delete_content', vanity=vanity, _external=True) delete_url = url_for('delete_content', vanity=vanity, _external=True)
return jsonify({
'status': 'success',
'url': url,
'deletion_url': delete_url,
})
else: else:
# Handle other file types # Handle other file types
vanity = shortuuid.uuid()[:8] vanity = shortuuid.uuid()[:8]
@ -809,11 +833,12 @@ def api_upload():
url = url_for('redirect_vanity', vanity=new_filename, _external=True) url = url_for('redirect_vanity', vanity=new_filename, _external=True)
delete_url = url_for('delete_content', vanity=new_filename, _external=True) delete_url = url_for('delete_content', vanity=new_filename, _external=True)
return jsonify({
'status': 'success', return json.dumps({
'url': url, 'status': 'success',
'deletion_url': delete_url, 'url': url.replace('/download', ''),
}) 'deletion_url': delete_url,
})
elif 'text' in request.form: elif 'text' in request.form:
content = request.form['text'] content = request.form['text']
vanity = shortuuid.uuid()[:8] vanity = shortuuid.uuid()[:8]
@ -824,9 +849,10 @@ def api_upload():
url = url_for('redirect_vanity', vanity=vanity, _external=True) url = url_for('redirect_vanity', vanity=vanity, _external=True)
delete_url = url_for('delete_content', vanity=vanity, _external=True) delete_url = url_for('delete_content', vanity=vanity, _external=True)
return jsonify({
return json.dumps({
'status': 'success', 'status': 'success',
'url': url, 'url': url.replace('/download', ''),
'deletion_url': delete_url, 'deletion_url': delete_url,
}) })
elif 'url' in request.form: elif 'url' in request.form:
@ -839,9 +865,10 @@ def api_upload():
short_url = url_for('redirect_vanity', vanity=vanity, _external=True) short_url = url_for('redirect_vanity', vanity=vanity, _external=True)
delete_url = url_for('delete_content', vanity=vanity, _external=True) delete_url = url_for('delete_content', vanity=vanity, _external=True)
return jsonify({
return json.dumps({
'status': 'success', 'status': 'success',
'url': short_url, 'url': short_url.replace('/download', ''),
'deletion_url': delete_url, 'deletion_url': delete_url,
}) })
@ -877,4 +904,9 @@ def create_new_file(username):
return redirect(url_for('user_files', username=username, subpath=subpath)) return redirect(url_for('user_files', username=username, subpath=subpath))
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=True,host='0.0.0.0',port=7123) # Start the cleanup thread
cleanup_thread = threading.Thread(target=delete_old_files)
cleanup_thread.daemon = True
cleanup_thread.start()
app.run(debug=True, host='0.0.0.0', port=7123)

View File

@ -49,12 +49,14 @@
{% if info.file_size %} {% if info.file_size %}
<div class="info-item"><strong>File Size:</strong> {{ info.file_size }} bytes</div> <div class="info-item"><strong>File Size:</strong> {{ info.file_size }} bytes</div>
{% endif %} {% endif %}
<a href="{{ url_for('redirect_vanity', vanity=info.vanity)|replace('/download', '') }}" class="btn">View/Embed</a>
<a href="{{ url_for('redirect_vanity', vanity=info.vanity) ~ ('/download' if '/download' not in url_for('redirect_vanity', vanity=info.vanity) else '') }}" class="btn">Download</a>
{% elif info.type == 'url' %} {% elif info.type == 'url' %}
<div class="info-item"><strong>Target URL:</strong> {{ info.data }}</div> <div class="info-item"><strong>Target URL:</strong> {{ info.data }}</div>
{% endif %} <a href="{{ url_for('redirect_vanity', vanity=info.vanity) }}" class="btn">Visit URL</a>
<a href="{{ url_for('redirect_vanity', vanity=info.vanity) }}" class="btn">View Content</a> {% elif info.type == 'pastebin' %}
{% if info.type == 'file' %} <a href="{{ url_for('redirect_vanity', vanity=info.vanity) }}" class="btn">View Pastebin</a>
<a href="{{ url_for('redirect_vanity', vanity=info.vanity) }}/download" class="btn">Download</a> <a href="{{ url_for('raw_vanity', vanity=info.vanity) }}" class="btn">View Raw</a>
{% endif %} {% endif %}
{% if current_user.is_authenticated and current_user.username == info.username %} {% if current_user.is_authenticated and current_user.username == info.username %}
{% if info.type != 'file' or not info.is_media %} {% if info.type != 'file' or not info.is_media %}