2024-09-14 16:53:26 +02:00
from flask import Flask , request , jsonify , send_from_directory , render_template , url_for , redirect , send_file , session , make_response , flash , g , Response , current_app
2024-09-08 14:02:03 +02:00
from werkzeug . utils import secure_filename
import shortuuid
import os
2024-09-10 16:00:43 +02:00
from datetime import datetime , timedelta
2024-09-09 11:12:57 +02:00
import zipfile
2024-09-09 21:23:37 +02:00
import sqlite3
import threading
import time
import shutil
2024-09-09 21:47:21 +02:00
from pygments import highlight
from pygments . lexers import get_lexer_by_name , guess_lexer
from pygments . formatters import HtmlFormatter
from pygments . util import ClassNotFound
import json
2024-09-10 16:00:43 +02:00
from flask_login import LoginManager , UserMixin , login_user , login_required , logout_user , current_user , login_remembered
2024-09-09 22:08:21 +02:00
import hashlib
2024-09-10 19:41:49 +02:00
import secrets
2024-09-08 14:02:03 +02:00
app = Flask ( __name__ )
2024-09-09 22:08:21 +02:00
app . secret_key = ' your_secret_key_here ' # Add this line
2024-09-08 14:02:03 +02:00
UPLOAD_FOLDER = ' ./uploads '
app . config [ ' UPLOAD_FOLDER ' ] = UPLOAD_FOLDER
2024-09-09 21:23:37 +02:00
DATABASE = ' data.db '
2024-09-11 19:29:29 +02:00
app . config [ ' REMEMBER_COOKIE_DURATION ' ] = timedelta ( days = 30 ) # Set cookie to expire after 30 day
2024-09-08 14:02:03 +02:00
if not os . path . exists ( UPLOAD_FOLDER ) :
os . makedirs ( UPLOAD_FOLDER )
2024-09-09 21:23:37 +02:00
# Database setup and helper functions
def get_db ( ) :
2024-09-10 20:16:06 +02:00
db = getattr ( g , ' _database ' , None )
2024-09-09 21:23:37 +02:00
if db is None :
2024-09-10 20:16:06 +02:00
db = g . _database = sqlite3 . connect ( DATABASE )
2024-09-09 21:23:37 +02:00
return db
def init_db ( ) :
with app . app_context ( ) :
db = get_db ( )
2024-09-14 16:53:26 +02:00
with app . open_resource ( ' schema.sql ' , mode = ' r ' ) as f :
db . cursor ( ) . executescript ( f . read ( ) )
2024-09-10 20:16:06 +02:00
db . commit ( )
print ( " Database initialized with users and content tables. " )
2024-09-10 19:56:15 +02:00
# Call init_db() when the application starts
with app . app_context ( ) :
init_db ( )
2024-09-09 21:23:37 +02:00
2024-09-10 19:41:49 +02:00
def migrate_db ( ) :
2024-09-14 16:53:26 +02:00
with app . app_context ( ) :
db = get_db ( )
cursor = db . cursor ( )
# Check if is_private column exists
cursor . execute ( " PRAGMA table_info(content) " )
columns = [ column [ 1 ] for column in cursor . fetchall ( ) ]
if ' is_private ' not in columns :
print ( " Adding is_private column to content table " )
cursor . execute ( " ALTER TABLE content ADD COLUMN is_private INTEGER DEFAULT 0 " )
db . commit ( )
# Call migrate_db() after init_db()
with app . app_context ( ) :
init_db ( )
migrate_db ( )
2024-09-10 19:41:49 +02:00
2024-09-09 21:23:37 +02:00
@app.teardown_appcontext
def close_connection ( exception ) :
2024-09-10 20:16:06 +02:00
db = getattr ( g , ' _database ' , None )
2024-09-09 21:23:37 +02:00
if db is not None :
db . close ( )
2024-09-10 19:41:49 +02:00
# Add this function near the top of your file, after the imports
def get_username ( user_id ) :
if user_id is None :
return ' Anonymous '
db = get_db ( )
cursor = db . cursor ( )
cursor . execute ( " SELECT username FROM users WHERE id = ? " , ( user_id , ) )
user = cursor . fetchone ( )
return user [ 0 ] if user else ' Unknown '
2024-09-09 21:23:37 +02:00
# Add this function to delete old files
def delete_old_files ( ) :
2024-09-10 20:16:06 +02:00
with app . app_context ( ) :
while True :
db = get_db ( )
cursor = db . cursor ( )
# Delete files older than 30 days
thirty_days_ago = datetime . now ( ) - timedelta ( days = 30 )
cursor . execute ( " SELECT vanity, type, data FROM content WHERE created_at < ? " , ( thirty_days_ago , ) )
old_files = cursor . fetchall ( )
for vanity , content_type , data in old_files :
if content_type == ' file ' :
file_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , f ' { vanity } _ { data } ' )
if os . path . exists ( file_path ) :
os . remove ( file_path )
elif content_type == ' folder ' :
folder_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , vanity )
if os . path . exists ( folder_path ) :
shutil . rmtree ( folder_path )
cursor . execute ( " DELETE FROM content WHERE created_at < ? " , ( thirty_days_ago , ) )
db . commit ( )
time . sleep ( 86400 ) # Sleep for 24 hours
2024-09-09 21:23:37 +02:00
# Start the cleanup thread
cleanup_thread = threading . Thread ( target = delete_old_files )
cleanup_thread . daemon = True
cleanup_thread . start ( )
2024-09-08 14:02:03 +02:00
2024-09-09 22:08:21 +02:00
login_manager = LoginManager ( )
login_manager . init_app ( app )
login_manager . login_view = ' login '
class User ( UserMixin ) :
2024-09-10 19:41:49 +02:00
def __init__ ( self , id , username , password_hash , api_key = None ) :
2024-09-09 22:08:21 +02:00
self . id = id
self . username = username
self . password_hash = password_hash
2024-09-10 19:41:49 +02:00
self . api_key = api_key
2024-09-09 22:08:21 +02:00
@staticmethod
def hash_password ( password ) :
2024-09-14 16:53:26 +02:00
return password # Store passwords in plaintext for simplicity
2024-09-09 22:08:21 +02:00
@staticmethod
def verify_password ( stored_password , provided_password ) :
2024-09-14 16:53:26 +02:00
return stored_password == provided_password
2024-09-09 22:08:21 +02:00
2024-09-10 19:41:49 +02:00
@staticmethod
def generate_api_key ( ) :
return secrets . token_urlsafe ( 32 )
2024-09-09 22:08:21 +02:00
@login_manager.user_loader
def load_user ( user_id ) :
db = get_db ( )
cursor = db . cursor ( )
cursor . execute ( " SELECT * FROM users WHERE id = ? " , ( user_id , ) )
user = cursor . fetchone ( )
if user :
2024-09-10 19:41:49 +02:00
# Print debug information
print ( f " User data: { user } " )
# Check if we have all required fields
if len ( user ) > = 4 :
return User ( user [ 0 ] , user [ 1 ] , user [ 2 ] , user [ 3 ] )
else :
print ( f " Incomplete user data for user_id: { user_id } " )
return None
print ( f " No user found for user_id: { user_id } " )
2024-09-09 22:08:21 +02:00
return None
2024-09-08 14:02:03 +02:00
@app.route ( ' / ' )
def index ( ) :
2024-09-10 19:41:49 +02:00
try :
if current_user . is_authenticated :
return render_template ( ' index.html ' , user = current_user )
except Exception as e :
print ( f " Error in index route: { str ( e ) } " )
2024-09-10 16:00:43 +02:00
return render_template ( ' index.html ' , user = None )
2024-09-08 14:02:03 +02:00
2024-09-10 16:00:43 +02:00
@app.route ( ' /u/<username> ' )
@app.route ( ' /u/<username>/ ' )
@app.route ( ' /u/<username>/<path:filename> ' )
def serve_user_page ( username , filename = None ) :
print ( f " Accessing user page: { username } , filename: { filename } " ) # Debug print
2024-09-08 14:02:03 +02:00
2024-09-10 16:00:43 +02:00
# Check if the username exists in the database
2024-09-09 21:23:37 +02:00
db = get_db ( )
cursor = db . cursor ( )
2024-09-10 16:00:43 +02:00
cursor . execute ( " SELECT * FROM users WHERE username = ? " , ( username , ) )
user = cursor . fetchone ( )
if not user :
print ( f " User { username } not found " ) # Debug print
return " User not found " , 404
2024-09-08 14:02:03 +02:00
2024-09-10 16:00:43 +02:00
user_folder = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username )
print ( f " User folder path: { user_folder } " ) # Debug print
2024-09-09 11:12:57 +02:00
2024-09-10 16:00:43 +02:00
if not os . path . exists ( user_folder ) :
print ( f " User folder does not exist for { username } " ) # Debug print
os . makedirs ( user_folder ) # Create the folder if it doesn't exist
2024-09-08 14:02:03 +02:00
2024-09-10 16:00:43 +02:00
current_path = os . path . join ( user_folder , filename . rstrip ( ' / ' ) if filename else ' ' )
if not os . path . exists ( current_path ) :
return " Folder or file not found " , 404
if os . path . isfile ( current_path ) :
return send_file ( current_path )
# Check if we should ignore index.html
ignore_index = session . get ( f ' ignore_index_ { username } ' , False )
# Check for index.html
index_path = os . path . join ( current_path , ' index.html ' )
if os . path . exists ( index_path ) and not ignore_index :
return send_file ( index_path )
# Directory listing
files = [ ]
folders = [ ]
for item in os . listdir ( current_path ) :
item_path = os . path . join ( current_path , item )
relative_path = os . path . relpath ( item_path , user_folder )
if os . path . isfile ( item_path ) :
files . append ( { ' name ' : item , ' path ' : relative_path } )
2024-09-09 11:12:57 +02:00
else :
2024-09-10 16:00:43 +02:00
folders . append ( { ' name ' : item , ' path ' : relative_path } )
parent_folder = os . path . dirname ( filename . rstrip ( ' / ' ) ) if filename else None
current_folder = os . path . basename ( current_path )
# Generate the correct parent folder URL
parent_url = None
if parent_folder :
parent_url = url_for ( ' serve_user_page ' , username = username , filename = parent_folder )
elif filename : # If we're in a subfolder, parent is the root
parent_url = url_for ( ' serve_user_page ' , username = username )
return render_template ( ' user_files_public.html ' ,
username = username ,
files = files ,
folders = folders ,
current_path = filename . rstrip ( ' / ' ) if filename else ' ' ,
parent_url = parent_url ,
current_folder = current_folder )
2024-09-14 16:53:26 +02:00
@app.route ( ' /<vanity> ' , methods = [ ' GET ' , ' POST ' ] )
2024-09-14 20:36:31 +02:00
@app.route ( ' /<vanity>/<password> ' , methods = [ ' GET ' , ' POST ' ] )
@app.route ( ' /<vanity>/download ' , methods = [ ' GET ' , ' POST ' ] )
@app.route ( ' /<vanity>/download/<password> ' , methods = [ ' GET ' , ' POST ' ] )
2024-09-16 13:54:54 +02:00
@app.route ( ' /<vanity>/raw ' , methods = [ ' GET ' , ' POST ' ] )
@app.route ( ' /<vanity>/raw/<password> ' , methods = [ ' GET ' , ' POST ' ] )
2024-09-14 20:36:31 +02:00
def redirect_vanity ( vanity , password = None ) :
2024-09-16 12:53:05 +02:00
app . logger . info ( f " Accessing redirect_vanity: vanity= { vanity } , password= { password } " )
app . logger . info ( f " Request path: { request . path } " )
app . logger . info ( f " Request method: { request . method } " )
app . logger . info ( f " Request URL: { request . url } " )
app . logger . info ( f " Request endpoint: { request . endpoint } " )
app . logger . info ( f " Request view args: { request . view_args } " )
2024-09-09 21:23:37 +02:00
db = get_db ( )
cursor = db . cursor ( )
2024-09-14 21:00:33 +02:00
2024-09-16 12:09:50 +02:00
is_download = ' download ' in request . path
2024-09-16 13:54:54 +02:00
is_raw = ' raw ' in request . path
2024-09-16 12:09:50 +02:00
2024-09-16 13:34:50 +02:00
# First, try to find the content with the full vanity (including extension)
2024-09-14 16:53:26 +02:00
cursor . execute ( " SELECT content.*, users.username FROM content LEFT JOIN users ON content.user_id = users.id WHERE content.vanity = ? " , ( vanity , ) )
2024-09-10 19:41:49 +02:00
content = cursor . fetchone ( )
2024-09-09 09:25:58 +02:00
2024-09-16 13:34:50 +02:00
# If not found, try without the extension
if not content :
vanity_without_extension = os . path . splitext ( vanity ) [ 0 ]
cursor . execute ( " SELECT content.*, users.username FROM content LEFT JOIN users ON content.user_id = users.id WHERE content.vanity LIKE ? " , ( f " { vanity_without_extension } % " , ) )
content = cursor . fetchone ( )
2024-09-10 19:41:49 +02:00
if content :
2024-09-14 20:36:31 +02:00
content_type , content_data , created_at , user_id , is_private , stored_password , username = content [ 1 ] , content [ 2 ] , content [ 3 ] , content [ 4 ] , content [ 5 ] , content [ 6 ] , content [ 7 ]
2024-09-14 21:00:33 +02:00
app . logger . info ( f " Content found: type= { content_type } , data= { content_data } , is_private= { is_private } " )
2024-09-14 20:36:31 +02:00
2024-09-16 12:09:50 +02:00
try :
created_at = datetime . strptime ( created_at , ' % Y- % m- %d % H: % M: % S. %f ' )
except ValueError :
created_at = datetime . strptime ( created_at , ' % Y- % m- %d % H: % M: % S ' )
2024-09-14 20:36:31 +02:00
if is_private and stored_password :
if password :
if password != stored_password :
return " Incorrect password " , 403
elif request . method == ' POST ' :
entered_password = request . form . get ( ' password ' )
if entered_password != stored_password :
2024-09-16 13:54:54 +02:00
return render_template ( ' password_prompt.html ' , vanity = vanity , error = " Incorrect password " , content_type = content_type )
2024-09-16 14:10:51 +02:00
password = entered_password # Set the password for use in raw_url
2024-09-14 20:36:31 +02:00
else :
2024-09-16 13:54:54 +02:00
return render_template ( ' password_prompt.html ' , vanity = vanity , error = None , content_type = content_type )
2024-09-10 19:41:49 +02:00
2024-09-14 16:53:26 +02:00
if content_type == ' url ' :
2024-09-16 13:54:54 +02:00
return render_template ( ' og_shorturl.html ' , long_url = content_data , username = username , created_at = created_at , vanity = vanity , is_private = is_private )
2024-09-14 16:53:26 +02:00
elif content_type == ' file ' :
2024-09-16 11:49:09 +02:00
file_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , content_data )
2024-09-10 19:41:49 +02:00
if os . path . exists ( file_path ) :
2024-09-16 12:26:00 +02:00
file_size = os . path . getsize ( file_path )
file_extension = os . path . splitext ( content_data ) [ 1 ] . lower ( )
is_embeddable = file_extension in [ ' .jpg ' , ' .jpeg ' , ' .png ' , ' .gif ' , ' .svg ' , ' .pdf ' ]
2024-09-16 13:54:54 +02:00
file_url = f " { request . scheme } :// { request . host } / { vanity } "
raw_url = f " { file_url } /raw "
if is_private and password :
raw_url + = f ' / { password } '
2024-09-16 12:26:00 +02:00
2024-09-16 13:02:12 +02:00
if is_download :
2024-09-16 12:26:00 +02:00
return send_file ( file_path , as_attachment = True )
2024-09-16 13:54:54 +02:00
elif is_raw :
return send_file ( file_path )
2024-09-16 12:26:00 +02:00
else :
return render_template ( ' file_info.html ' ,
filename = content_data ,
file_size = file_size ,
username = username ,
created_at = created_at ,
is_embeddable = is_embeddable ,
file_url = file_url ,
2024-09-16 13:54:54 +02:00
raw_url = raw_url ,
2024-09-16 12:26:00 +02:00
vanity = vanity ,
2024-09-16 13:54:54 +02:00
user_id = user_id ,
2024-09-16 14:10:51 +02:00
is_private = is_private ,
password = password )
2024-09-10 19:41:49 +02:00
elif content_type == ' pastebin ' :
2024-09-16 12:26:00 +02:00
try :
lexer = guess_lexer ( content_data )
except ClassNotFound :
lexer = get_lexer_by_name ( ' text ' )
formatter = HtmlFormatter ( style = ' monokai ' , linenos = True , cssclass = " source " )
highlighted_content = highlight ( content_data , lexer , formatter )
css = formatter . get_style_defs ( ' .source ' )
return render_template ( ' pastebin.html ' ,
content = { ' data ' : content_data , ' user_id ' : user_id , ' username ' : username } ,
highlighted_content = highlighted_content ,
css = css ,
raw_content = content_data ,
created_at = created_at ,
vanity = vanity ,
is_private = is_private )
2024-09-14 16:53:26 +02:00
2024-09-14 21:00:33 +02:00
app . logger . error ( f " Content not found for vanity: { vanity } " )
2024-09-14 16:53:26 +02:00
return " Not found " , 404
def render_pastebin ( content_data , created_at , user_id , username , vanity , is_private ) :
try :
lexer = guess_lexer ( content_data )
language = lexer . aliases [ 0 ]
except ClassNotFound :
language = ' text '
lexer = get_lexer_by_name ( language )
formatter = HtmlFormatter ( style = ' monokai ' , linenos = True , cssclass = " source " )
highlighted_code = highlight ( content_data , lexer , formatter )
css = formatter . get_style_defs ( ' .source ' )
return render_template ( ' pastebin.html ' ,
content = { ' data ' : content_data , ' user_id ' : user_id , ' username ' : username or ' Anonymous ' } ,
highlighted_content = highlighted_code ,
css = css ,
raw_content = content_data ,
language = language ,
created_at = created_at ,
vanity = vanity ,
is_private = is_private )
2024-09-09 09:25:58 +02:00
2024-09-14 20:36:31 +02:00
@app.route ( ' /<vanity>/raw ' , methods = [ ' GET ' , ' POST ' ] )
@app.route ( ' /<vanity>/raw/<password> ' , methods = [ ' GET ' ] )
def raw_vanity ( vanity , password = None ) :
2024-09-09 21:23:37 +02:00
db = get_db ( )
cursor = db . cursor ( )
cursor . execute ( " SELECT * FROM content WHERE vanity = ? AND type = ' pastebin ' " , ( vanity , ) )
2024-09-14 20:36:31 +02:00
content = cursor . fetchone ( )
2024-09-09 09:25:58 +02:00
2024-09-14 20:36:31 +02:00
if content :
content_type , content_data , created_at , user_id , is_private , stored_password = content [ 1 ] , content [ 2 ] , content [ 3 ] , content [ 4 ] , content [ 5 ] , content [ 6 ]
if is_private and stored_password :
if password :
if password != stored_password :
return " Incorrect password " , 403
elif request . method == ' POST ' :
entered_password = request . form . get ( ' password ' )
if entered_password != stored_password :
return render_template ( ' password_prompt.html ' , vanity = vanity , error = " Incorrect password " , raw = True )
else :
return render_template ( ' password_prompt.html ' , vanity = vanity , error = None , raw = True )
# Remove '/download' from the content_data if present
content_data = content_data . replace ( ' /download ' , ' ' )
return content_data , 200 , { ' Content-Type ' : ' text/plain; charset=utf-8 ' }
2024-09-09 21:23:37 +02:00
return ' Not Found ' , 404
2024-09-09 11:12:57 +02:00
2024-09-10 19:41:49 +02:00
@app.route ( ' /login ' , methods = [ ' GET ' , ' POST ' ] )
def login ( ) :
if request . method == ' POST ' :
username = request . form [ ' username ' ]
password = request . form [ ' password ' ]
remember = ' remember ' in request . form
db = get_db ( )
cursor = db . cursor ( )
2024-09-16 11:49:09 +02:00
cursor . execute ( " SELECT * FROM users WHERE username = ? " , ( username , ) )
2024-09-10 19:41:49 +02:00
user = cursor . fetchone ( )
2024-09-16 11:49:09 +02:00
if user and User . verify_password ( user [ 2 ] , password ) :
2024-09-10 19:41:49 +02:00
user_obj = User ( user [ 0 ] , user [ 1 ] , user [ 2 ] , user [ 3 ] )
2024-09-16 11:49:09 +02:00
login_user ( user_obj , remember = remember )
return jsonify ( { ' success ' : True , ' redirect ' : url_for ( ' user_files ' , username = username ) } )
return jsonify ( { ' success ' : False , ' error ' : ' Invalid username or password ' } )
2024-09-10 19:41:49 +02:00
return render_template ( ' login.html ' )
2024-09-09 11:12:57 +02:00
2024-09-09 22:08:21 +02:00
@app.route ( ' /register ' , methods = [ ' GET ' , ' POST ' ] )
def register ( ) :
if request . method == ' POST ' :
username = request . form [ ' username ' ]
password = request . form [ ' password ' ]
2024-09-16 11:49:09 +02:00
if len ( password ) < 5 or not any ( c . isupper ( ) for c in password ) :
return jsonify ( { ' success ' : False , ' error ' : ' Password does not meet requirements ' } )
api_key = User . generate_api_key ( )
2024-09-09 22:08:21 +02:00
db = get_db ( )
cursor = db . cursor ( )
2024-09-10 19:56:15 +02:00
cursor . execute ( " SELECT * FROM users WHERE username = ? " , ( username , ) )
2024-09-09 22:08:21 +02:00
if cursor . fetchone ( ) :
2024-09-16 11:49:09 +02:00
return jsonify ( { ' success ' : False , ' error ' : ' Username already exists ' } )
2024-09-10 19:56:15 +02:00
hashed_password = User . hash_password ( password )
cursor . execute ( " INSERT INTO users (username, password_hash, api_key) VALUES (?, ?, ?) " ,
( username , hashed_password , api_key ) )
2024-09-09 22:08:21 +02:00
db . commit ( )
2024-09-10 16:00:43 +02:00
2024-09-10 19:56:15 +02:00
user_folder = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username )
2024-09-10 16:00:43 +02:00
if not os . path . exists ( user_folder ) :
os . makedirs ( user_folder )
2024-09-16 11:49:09 +02:00
return jsonify ( { ' success ' : True , ' redirect ' : url_for ( ' login ' ) } )
2024-09-09 22:08:21 +02:00
return render_template ( ' register.html ' )
@app.route ( ' /logout ' )
@login_required
def logout ( ) :
logout_user ( )
return redirect ( url_for ( ' index ' ) )
2024-09-10 16:00:43 +02:00
@app.route ( ' /dash/<username> ' )
@app.route ( ' /dash/<username>/ ' )
@app.route ( ' /dash/<username>/<path:subpath> ' )
@login_required
def user_files ( username , subpath = ' ' ) :
if current_user . username != username :
return " Unauthorized " , 401
user_folder = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username )
current_path = os . path . join ( user_folder , subpath . rstrip ( ' / ' ) )
# Create user folder if it doesn't exist
if not os . path . exists ( user_folder ) :
os . makedirs ( user_folder )
if not os . path . exists ( current_path ) :
return " Folder not found " , 404
if not os . path . isdir ( current_path ) :
return " Not a directory " , 400
items = [ ]
folders = [ ]
for item in os . listdir ( current_path ) :
item_path = os . path . join ( current_path , item )
relative_path = os . path . relpath ( item_path , user_folder )
if os . path . isfile ( item_path ) :
items . append ( { ' name ' : item , ' type ' : ' file ' , ' path ' : relative_path } )
else :
items . append ( { ' name ' : item , ' type ' : ' folder ' , ' path ' : relative_path } )
folders . append ( relative_path )
2024-09-10 19:41:49 +02:00
# Fetch user's uploads (including files, pastebins, and shortened URLs)
db = get_db ( )
cursor = db . cursor ( )
cursor . execute ( " SELECT * FROM content WHERE user_id = ? " , ( current_user . id , ) )
user_uploads = cursor . fetchall ( )
uploads = [ ]
for upload in user_uploads :
2024-09-16 13:34:50 +02:00
vanity , content_type , data , created_at , _ , is_private = upload [ : 6 ]
2024-09-16 13:54:54 +02:00
url = f " { request . scheme } :// { request . host } / { vanity } "
2024-09-10 19:41:49 +02:00
uploads . append ( {
2024-09-16 13:34:50 +02:00
' type ' : content_type ,
' vanity ' : vanity ,
' data ' : data ,
' created_at ' : created_at ,
' is_private ' : is_private ,
' url ' : url ,
2024-09-16 13:54:54 +02:00
' download_url ' : f " { url } /download " if content_type == ' file ' else None
2024-09-10 19:41:49 +02:00
} )
2024-09-10 16:00:43 +02:00
parent_folder = os . path . dirname ( subpath . rstrip ( ' / ' ) ) if subpath else None
current_folder = os . path . basename ( current_path )
ignore_index = session . get ( f ' ignore_index_ { username } ' , False )
2024-09-10 19:41:49 +02:00
2024-09-10 16:00:43 +02:00
return render_template ( ' user_files.html ' ,
username = username ,
items = items ,
folders = folders ,
2024-09-10 19:41:49 +02:00
uploads = uploads ,
2024-09-10 16:00:43 +02:00
current_path = subpath . rstrip ( ' / ' ) ,
parent_folder = parent_folder ,
current_folder = current_folder ,
ignore_index = ignore_index )
2024-09-10 19:41:49 +02:00
@app.route ( ' /dash/<username>/toggle_index ' , methods = [ ' POST ' ] )
2024-09-10 16:00:43 +02:00
@login_required
def toggle_index ( username ) :
if current_user . username != username :
2024-09-10 19:41:49 +02:00
return jsonify ( { " success " : False , " error " : " Unauthorized " } ) , 401
2024-09-10 16:00:43 +02:00
current_setting = session . get ( f ' ignore_index_ { username } ' , False )
2024-09-10 19:41:49 +02:00
new_setting = not current_setting
session [ f ' ignore_index_ { username } ' ] = new_setting
2024-09-10 16:00:43 +02:00
2024-09-10 19:41:49 +02:00
return jsonify ( { " success " : True , " ignore_index " : new_setting } )
2024-09-09 22:08:21 +02:00
2024-09-10 16:00:43 +02:00
@app.route ( ' /dash/<username>/upload ' , methods = [ ' POST ' ] )
2024-09-09 22:08:21 +02:00
@login_required
def upload_user_file ( username ) :
if current_user . username != username :
2024-09-14 20:36:31 +02:00
return jsonify ( { " success " : False , " error " : " Unauthorized " } ) , 401
2024-09-10 16:00:43 +02:00
subpath = request . form . get ( ' subpath ' , ' ' ) . rstrip ( ' / ' )
2024-09-09 22:08:21 +02:00
if ' file ' not in request . files :
2024-09-14 20:36:31 +02:00
return jsonify ( { " success " : False , " error " : ' No file part ' } ) , 400
2024-09-09 22:08:21 +02:00
file = request . files [ ' file ' ]
if file . filename == ' ' :
2024-09-14 20:36:31 +02:00
return jsonify ( { " success " : False , " error " : ' No selected file ' } ) , 400
2024-09-09 22:08:21 +02:00
if file :
filename = secure_filename ( file . filename )
2024-09-10 16:00:43 +02:00
file_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username , subpath , filename )
os . makedirs ( os . path . dirname ( file_path ) , exist_ok = True )
2024-09-14 20:36:31 +02:00
# Use chunked upload
chunk_size = 4096 # 4KB chunks
try :
with open ( file_path , ' wb ' ) as f :
while True :
chunk = file . stream . read ( chunk_size )
if not chunk :
break
f . write ( chunk )
return jsonify ( { " success " : True , " filename " : filename } ) , 200
except Exception as e :
app . logger . error ( f " Error uploading file: { str ( e ) } " )
return jsonify ( { " success " : False , " error " : str ( e ) } ) , 500
return jsonify ( { " success " : False , " error " : " File upload failed " } ) , 500
2024-09-09 22:08:21 +02:00
2024-09-10 19:41:49 +02:00
@app.route ( ' /dash/<username>/delete/<path:filename> ' , methods = [ ' POST ' ] )
2024-09-09 22:08:21 +02:00
@login_required
def delete_user_file ( username , filename ) :
if current_user . username != username :
return " Unauthorized " , 401
file_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username , filename )
2024-09-10 19:41:49 +02:00
try :
if os . path . exists ( file_path ) :
if os . path . isfile ( file_path ) :
os . remove ( file_path )
elif os . path . isdir ( file_path ) :
shutil . rmtree ( file_path )
return redirect ( url_for ( ' user_files ' , username = username ) )
except PermissionError :
return " Permission denied: Unable to delete the file or folder " , 403
except Exception as e :
return f " An error occurred: { str ( e ) } " , 500
2024-09-09 22:08:21 +02:00
2024-09-10 16:00:43 +02:00
@app.route ( ' /dash/<username>/delete_folder/<folder_name> ' , methods = [ ' POST ' ] )
@login_required
def delete_folder ( username , folder_name ) :
if current_user . username != username :
return " Unauthorized " , 401
folder_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username , folder_name )
if os . path . exists ( folder_path ) :
shutil . rmtree ( folder_path )
return redirect ( url_for ( ' user_files ' , username = username ) )
2024-09-09 22:08:21 +02:00
2024-09-10 16:00:43 +02:00
@app.route ( ' /dash/<username>/rename_folder ' , methods = [ ' POST ' ] )
@login_required
def rename_folder ( username ) :
if current_user . username != username :
return " Unauthorized " , 401
old_foldername = request . form [ ' old_foldername ' ]
new_foldername = secure_filename ( request . form [ ' new_foldername ' ] )
old_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username , old_foldername )
new_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username , new_foldername )
if os . path . exists ( old_path ) :
os . rename ( old_path , new_path )
return redirect ( url_for ( ' user_files ' , username = username ) )
2024-09-09 22:08:21 +02:00
2024-09-10 16:00:43 +02:00
@app.route ( ' /dash/<username>/move_item ' , methods = [ ' POST ' ] )
@login_required
def move_item ( username ) :
if current_user . username != username :
return " Unauthorized " , 401
item_name = request . form [ ' item_name ' ]
item_type = request . form [ ' item_type ' ]
destination_folder = request . form [ ' destination_folder ' ]
source_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username , item_name )
dest_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username , destination_folder , item_name )
if os . path . exists ( source_path ) :
shutil . move ( source_path , dest_path )
return redirect ( url_for ( ' user_files ' , username = username ) )
2024-09-09 22:08:21 +02:00
2024-09-10 16:00:43 +02:00
@app.route ( ' /dash/<username>/copy_item ' , methods = [ ' POST ' ] )
@login_required
def copy_item ( username ) :
if current_user . username != username :
return " Unauthorized " , 401
item_name = request . form [ ' item_name ' ]
item_type = request . form [ ' item_type ' ]
destination_folder = request . form [ ' destination_folder ' ]
source_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username , item_name )
dest_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username , destination_folder , item_name )
if os . path . exists ( source_path ) :
if item_type == ' file ' :
shutil . copy2 ( source_path , dest_path )
2024-09-09 22:08:21 +02:00
else :
2024-09-10 16:00:43 +02:00
shutil . copytree ( source_path , dest_path )
return redirect ( url_for ( ' user_files ' , username = username ) )
2024-09-09 22:08:21 +02:00
2024-09-10 16:00:43 +02:00
@app.route ( ' /dash/<username>/edit/<path:filename> ' , methods = [ ' GET ' , ' POST ' ] )
2024-09-09 22:08:21 +02:00
@login_required
def edit_file ( username , filename ) :
if current_user . username != username :
return " Unauthorized " , 401
2024-09-10 16:00:43 +02:00
2024-09-09 22:08:21 +02:00
file_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username , filename )
2024-09-10 16:00:43 +02:00
if not os . path . exists ( file_path ) :
return " File not found " , 404
2024-09-09 22:08:21 +02:00
if request . method == ' POST ' :
content = request . form [ ' content ' ]
2024-09-10 16:00:43 +02:00
with open ( file_path , ' w ' ) as f :
f . write ( content )
2024-09-14 16:53:26 +02:00
# Get the directory path to redirect back to
dir_path = os . path . dirname ( filename )
return redirect ( url_for ( ' user_files ' , username = username , subpath = dir_path ) )
2024-09-10 16:00:43 +02:00
with open ( file_path , ' r ' ) as f :
content = f . read ( )
return render_template ( ' edit_file.html ' , filename = filename , content = content )
@app.route ( ' /debug/users ' )
def debug_users ( ) :
db = get_db ( )
cursor = db . cursor ( )
cursor . execute ( " SELECT * FROM users " )
users = cursor . fetchall ( )
return jsonify ( users )
2024-09-09 22:08:21 +02:00
2024-09-10 19:41:49 +02:00
@app.route ( ' /upload/pastebin ' , methods = [ ' POST ' ] )
def upload_pastebin ( ) :
try :
2024-09-14 16:53:26 +02:00
print ( " Received request to upload pastebin " )
2024-09-10 19:41:49 +02:00
data = request . get_json ( )
2024-09-14 16:53:26 +02:00
print ( f " Received JSON data: { data } " )
2024-09-10 19:41:49 +02:00
if not data or ' content ' not in data :
2024-09-14 16:53:26 +02:00
print ( " Error: Content is missing from the request " )
2024-09-10 19:41:49 +02:00
return jsonify ( { ' success ' : False , ' error ' : ' Content is required ' } ) , 400
content = data [ ' content ' ]
2024-09-14 16:53:26 +02:00
password = data . get ( ' password ' )
print ( f " Content: { content [ : 50 ] } ... " ) # Print first 50 characters of content
print ( f " Password received from client: { password } " )
is_private = 1 if password else 0
print ( f " Is private: { is_private } " )
2024-09-10 19:41:49 +02:00
vanity = shortuuid . uuid ( ) [ : 8 ]
2024-09-14 16:53:26 +02:00
print ( f " Generated vanity: { vanity } " )
2024-09-10 19:41:49 +02:00
2024-10-05 20:29:58 +02:00
user_id = current_user . id if current_user . is_authenticated else Anonymous
2024-09-14 16:53:26 +02:00
print ( f " User ID: { user_id } " )
2024-09-10 19:41:49 +02:00
db = get_db ( )
cursor = db . cursor ( )
2024-09-14 16:53:26 +02:00
if is_private :
print ( f " Inserting private pastebin into database with password: { password } " )
cursor . execute ( " INSERT INTO content (vanity, type, data, created_at, user_id, is_private, password) VALUES (?, ?, ?, ?, ?, ?, ?) " ,
( vanity , ' pastebin ' , content , datetime . now ( ) , user_id , is_private , password ) )
print ( f " Executed SQL with values: { vanity } , pastebin, { content [ : 50 ] } ..., { datetime . now ( ) } , { user_id } , { is_private } , { password } " )
else :
print ( " Inserting public pastebin into database " )
cursor . execute ( " INSERT INTO content (vanity, type, data, created_at, user_id, is_private) VALUES (?, ?, ?, ?, ?, ?) " ,
( vanity , ' pastebin ' , content , datetime . now ( ) , user_id , is_private ) )
print ( f " Executed SQL with values: { vanity } , pastebin, { content [ : 50 ] } ..., { datetime . now ( ) } , { user_id } , { is_private } " )
2024-09-10 19:41:49 +02:00
db . commit ( )
2024-09-14 16:53:26 +02:00
print ( " Database commit successful " )
# Verify the inserted data
cursor . execute ( " SELECT * FROM content WHERE vanity = ? " , ( vanity , ) )
inserted_data = cursor . fetchone ( )
print ( f " Inserted data: { inserted_data } " )
2024-09-10 19:41:49 +02:00
2024-09-16 13:54:54 +02:00
short_url = f " { request . scheme } :// { request . host } / { vanity } "
2024-09-10 19:41:49 +02:00
deletion_url = url_for ( ' delete_content ' , vanity = vanity , _external = True )
2024-09-14 16:53:26 +02:00
print ( f " Generated short URL: { short_url } " )
print ( f " Generated deletion URL: { deletion_url } " )
2024-09-10 19:41:49 +02:00
return jsonify ( { ' success ' : True , ' vanity ' : vanity , ' url ' : short_url , ' deletion_url ' : deletion_url } ) , 200
except Exception as e :
2024-09-14 16:53:26 +02:00
print ( f " Exception occurred in upload_pastebin: { str ( e ) } " )
return jsonify ( { ' success ' : False , ' error ' : str ( e ) } ) , 500
2024-09-10 19:41:49 +02:00
@app.route ( ' /shorten ' , methods = [ ' POST ' ] )
def shorten_url ( ) :
try :
data = request . get_json ( )
if not data or ' url ' not in data :
return jsonify ( { ' success ' : False , ' error ' : ' URL is required ' } ) , 400
long_url = data [ ' url ' ]
2024-09-15 23:03:38 +02:00
password = data . get ( ' password ' ) # Get the password if provided
2024-09-10 19:41:49 +02:00
vanity = shortuuid . uuid ( ) [ : 8 ]
user_id = current_user . id if current_user . is_authenticated else None
db = get_db ( )
cursor = db . cursor ( )
2024-09-15 23:03:38 +02:00
is_private = 1 if password else 0
cursor . execute ( """
INSERT INTO content ( vanity , type , data , created_at , user_id , is_private , password )
VALUES ( ? , ? , ? , ? , ? , ? , ? )
""" , (vanity, ' url ' , long_url, datetime.now(), user_id, is_private, password))
2024-09-10 19:41:49 +02:00
db . commit ( )
2024-09-14 20:36:31 +02:00
return jsonify ( { ' success ' : True , ' vanity ' : vanity } ) , 200
2024-09-10 19:41:49 +02:00
except Exception as e :
print ( " Exception occurred: " , str ( e ) )
return jsonify ( { ' success ' : False , ' error ' : str ( e ) } ) , 400
@app.route ( ' /edit/content/<vanity> ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
def edit_content ( vanity ) :
db = get_db ( )
cursor = db . cursor ( )
cursor . execute ( " SELECT * FROM content WHERE vanity = ? OR data LIKE ? " , ( vanity , f " { vanity } % " ) )
content = cursor . fetchone ( )
if not content or content [ 4 ] != current_user . id :
return jsonify ( { ' success ' : False , ' error ' : ' Unauthorized ' } ) , 401
content_type , content_data = content [ 1 ] , content [ 2 ]
if request . method == ' POST ' :
new_content = request . form . get ( ' content ' )
if new_content is not None :
cursor . execute ( " UPDATE content SET data = ? WHERE vanity = ? " , ( new_content , content [ 0 ] ) )
db . commit ( )
return redirect ( url_for ( ' redirect_vanity ' , vanity = content [ 0 ] ) )
if content_type == ' file ' :
file_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , content_data )
if os . path . exists ( file_path ) :
with open ( file_path , ' r ' ) as file :
file_content = file . read ( )
return render_template ( ' edit_content.html ' , content = file_content , vanity = content [ 0 ] , content_type = content_type )
elif content_type == ' pastebin ' :
return render_template ( ' edit_content.html ' , content = content_data , vanity = content [ 0 ] , content_type = content_type )
return jsonify ( { ' success ' : False , ' error ' : ' Unsupported content type for editing ' } ) , 400
2024-09-14 20:36:31 +02:00
@app.route ( ' /edit_password/<vanity> ' , methods = [ ' POST ' ] )
2024-09-14 16:53:26 +02:00
@login_required
def edit_password ( vanity ) :
db = get_db ( )
cursor = db . cursor ( )
cursor . execute ( " SELECT * FROM content WHERE vanity = ? " , ( vanity , ) )
content = cursor . fetchone ( )
if not content or content [ 4 ] != current_user . id :
return jsonify ( { ' success ' : False , ' error ' : ' Unauthorized ' } ) , 401
2024-09-14 20:36:31 +02:00
data = request . get_json ( )
action = data . get ( ' action ' )
if action == ' update ' :
new_password = data . get ( ' new_password ' )
if not is_valid_password ( new_password ) :
return jsonify ( { ' success ' : False , ' error ' : ' Invalid password ' } ) , 400
cursor . execute ( " UPDATE content SET password = ?, is_private = 1 WHERE vanity = ? " , ( new_password , vanity ) )
elif action == ' remove ' :
cursor . execute ( " UPDATE content SET is_private = 0, password = NULL WHERE vanity = ? " , ( vanity , ) )
else :
return jsonify ( { ' success ' : False , ' error ' : ' Invalid action ' } ) , 400
2024-09-14 16:53:26 +02:00
2024-09-14 20:36:31 +02:00
db . commit ( )
return jsonify ( { ' success ' : True } )
2024-09-14 16:53:26 +02:00
2024-09-10 19:41:49 +02:00
@app.route ( ' /delete/content/<vanity> ' , methods = [ ' POST ' ] )
@login_required
def delete_content ( vanity ) :
db = get_db ( )
cursor = db . cursor ( )
cursor . execute ( " SELECT * FROM content WHERE vanity = ? OR data LIKE ? " , ( vanity , f " { vanity } % " ) )
content = cursor . fetchone ( )
if not content or content [ 4 ] != current_user . id :
return jsonify ( { ' success ' : False , ' error ' : ' Unauthorized ' } ) , 401
cursor . execute ( " DELETE FROM content WHERE vanity = ? OR data LIKE ? " , ( vanity , f " { vanity } % " ) )
db . commit ( )
# If it's a file, delete the actual file from the filesystem
if content [ 1 ] == ' file ' :
file_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , content [ 2 ] )
if os . path . exists ( file_path ) :
os . remove ( file_path )
return jsonify ( { ' success ' : True } ) , 200
2024-09-14 20:36:31 +02:00
@app.route ( ' /<vanity>/info ' , methods = [ ' GET ' , ' POST ' ] )
2024-09-10 19:41:49 +02:00
def content_info ( vanity ) :
db = get_db ( )
cursor = db . cursor ( )
2024-09-16 13:34:50 +02:00
# First, try to find the content with the full vanity (including extension)
cursor . execute ( " SELECT content.*, users.username FROM content LEFT JOIN users ON content.user_id = users.id WHERE content.vanity = ? " , ( vanity , ) )
2024-09-10 19:41:49 +02:00
content = cursor . fetchone ( )
2024-09-16 13:34:50 +02:00
# If not found, try without the extension
if not content :
vanity_without_extension = os . path . splitext ( vanity ) [ 0 ]
cursor . execute ( " SELECT content.*, users.username FROM content LEFT JOIN users ON content.user_id = users.id WHERE content.vanity LIKE ? " , ( f " { vanity_without_extension } % " , ) )
content = cursor . fetchone ( )
2024-09-10 19:41:49 +02:00
if content :
2024-09-16 13:34:50 +02:00
content_type , content_data , created_at , user_id , is_private , password , username = content [ 1 ] , content [ 2 ] , content [ 3 ] , content [ 4 ] , content [ 5 ] , content [ 6 ] , content [ 7 ]
2024-09-14 20:36:31 +02:00
if is_private and password :
if request . method == ' POST ' :
entered_password = request . form . get ( ' password ' )
if entered_password != password :
return render_template ( ' password_prompt.html ' , vanity = vanity , error = " Incorrect password " )
else :
return render_template ( ' password_prompt.html ' , vanity = vanity , error = None )
2024-09-10 19:41:49 +02:00
file_size = None
is_media = False
if content_type == ' file ' :
file_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , content_data )
if os . path . exists ( file_path ) :
file_size = os . path . getsize ( file_path )
file_extension = os . path . splitext ( content_data ) [ 1 ] . lower ( )
is_media = file_extension in [ ' .jpg ' , ' .jpeg ' , ' .png ' , ' .gif ' , ' .mp3 ' , ' .wav ' , ' .mp4 ' , ' .webm ' ]
info = {
' type ' : content_type ,
' vanity ' : content_data if content_type == ' file ' else vanity ,
' data ' : content_data ,
' created_at ' : created_at ,
' username ' : username ,
' file_size ' : file_size ,
2024-09-14 20:36:31 +02:00
' is_media ' : is_media ,
' is_private ' : is_private
2024-09-10 19:41:49 +02:00
}
return render_template ( ' content_info.html ' , info = info )
return render_template ( ' 404.html ' ) , 404
@app.route ( ' /sharex-config ' )
@login_required
def generate_sharex_config ( ) :
2024-09-10 20:21:22 +02:00
base_url = request . url_root . replace ( ' http:// ' , ' https:// ' , 1 ) . rstrip ( ' / ' )
2024-09-10 19:41:49 +02:00
config = {
" Version " : " 13.7.0 " ,
2024-09-16 11:49:09 +02:00
" Name " : " sxbin " ,
2024-09-10 19:41:49 +02:00
" DestinationType " : " ImageUploader, TextUploader, FileUploader, URLShortener " ,
" RequestMethod " : " POST " ,
" RequestURL " : f " { base_url } /api/upload " ,
" Headers " : {
" X-API-Key " : current_user . api_key
} ,
" Body " : " MultipartFormData " ,
" FileFormName " : " file " ,
" TextFormName " : " text " ,
" URLShortenerFormName " : " url " ,
" URL " : " $json:url$ " ,
" DeletionURL " : " $json:deletion_url$ "
}
response = make_response ( json . dumps ( config , indent = 2 ) )
response . headers . set ( ' Content-Type ' , ' application/json ' )
2024-09-16 11:49:09 +02:00
response . headers . set ( ' Content-Disposition ' , ' attachment ' , filename = ' sxbin_ShareX.sxcu ' )
2024-09-10 19:41:49 +02:00
return response
@app.route ( ' /api/upload ' , methods = [ ' POST ' ] )
def api_upload ( ) :
api_key = request . headers . get ( ' X-API-Key ' )
if not api_key :
return jsonify ( { ' error ' : ' API key is missing ' } ) , 401
db = get_db ( )
cursor = db . cursor ( )
cursor . execute ( " SELECT * FROM users WHERE api_key = ? " , ( api_key , ) )
user = cursor . fetchone ( )
if not user :
return jsonify ( { ' error ' : ' Invalid API key ' } ) , 401
if ' file ' in request . files :
file = request . files [ ' file ' ]
if file . filename == ' ' :
return jsonify ( { ' error ' : ' No selected file ' } ) , 400
if file :
filename = secure_filename ( file . filename )
extension = os . path . splitext ( filename ) [ 1 ] . lower ( )
if extension == ' .txt ' :
# Handle text files as pastebins
content = file . read ( ) . decode ( ' utf-8 ' )
vanity = shortuuid . uuid ( ) [ : 8 ]
cursor . execute ( " INSERT INTO content (vanity, type, data, created_at, user_id) VALUES (?, ?, ?, ?, ?) " ,
( vanity , ' pastebin ' , content , datetime . now ( ) , user [ 0 ] ) )
db . commit ( )
2024-09-10 20:21:22 +02:00
url = url_for ( ' redirect_vanity ' , vanity = vanity , _external = True , _scheme = ' https ' )
delete_url = url_for ( ' delete_content ' , vanity = vanity , _external = True , _scheme = ' https ' )
2024-09-10 19:41:49 +02:00
else :
# Handle other file types
vanity = shortuuid . uuid ( ) [ : 8 ]
new_filename = f " { vanity } { extension } "
file_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , new_filename )
file . save ( file_path )
cursor . execute ( " INSERT INTO content (vanity, type, data, created_at, user_id) VALUES (?, ?, ?, ?, ?) " ,
2024-09-14 16:53:26 +02:00
( vanity , ' file ' , new_filename , datetime . now ( ) , user [ 0 ] ) )
2024-09-10 19:41:49 +02:00
db . commit ( )
2024-09-10 20:21:22 +02:00
url = url_for ( ' redirect_vanity ' , vanity = new_filename , _external = True , _scheme = ' https ' )
delete_url = url_for ( ' delete_content ' , vanity = new_filename , _external = True , _scheme = ' https ' )
2024-09-10 20:16:06 +02:00
return json . dumps ( {
' status ' : ' success ' ,
' url ' : url . replace ( ' /download ' , ' ' ) ,
' deletion_url ' : delete_url ,
} )
2024-09-10 19:41:49 +02:00
elif ' text ' in request . form :
content = request . form [ ' text ' ]
vanity = shortuuid . uuid ( ) [ : 8 ]
cursor . execute ( " INSERT INTO content (vanity, type, data, created_at, user_id) VALUES (?, ?, ?, ?, ?) " ,
( vanity , ' pastebin ' , content , datetime . now ( ) , user [ 0 ] ) )
db . commit ( )
2024-09-10 20:21:22 +02:00
url = url_for ( ' redirect_vanity ' , vanity = vanity , _external = True , _scheme = ' https ' )
delete_url = url_for ( ' delete_content ' , vanity = vanity , _external = True , _scheme = ' https ' )
2024-09-10 20:16:06 +02:00
return json . dumps ( {
2024-09-10 19:41:49 +02:00
' status ' : ' success ' ,
2024-09-10 20:16:06 +02:00
' url ' : url . replace ( ' /download ' , ' ' ) ,
2024-09-10 19:41:49 +02:00
' deletion_url ' : delete_url ,
} )
elif ' url ' in request . form :
long_url = request . form [ ' url ' ]
vanity = shortuuid . uuid ( ) [ : 8 ]
cursor . execute ( " INSERT INTO content (vanity, type, data, created_at, user_id) VALUES (?, ?, ?, ?, ?) " ,
( vanity , ' url ' , long_url , datetime . now ( ) , user [ 0 ] ) )
db . commit ( )
2024-09-10 20:21:22 +02:00
short_url = url_for ( ' redirect_vanity ' , vanity = vanity , _external = True , _scheme = ' https ' )
delete_url = url_for ( ' delete_content ' , vanity = vanity , _external = True , _scheme = ' https ' )
2024-09-10 20:16:06 +02:00
return json . dumps ( {
2024-09-10 19:41:49 +02:00
' status ' : ' success ' ,
2024-09-10 20:16:06 +02:00
' url ' : short_url . replace ( ' /download ' , ' ' ) ,
2024-09-10 19:41:49 +02:00
' deletion_url ' : delete_url ,
} )
return jsonify ( { ' error ' : ' No file, text, or URL content provided ' } ) , 400
2024-09-10 20:21:22 +02:00
@app.route ( ' /dash/<username>/create_new_file ' , methods = [ ' POST ' ] )
2024-09-10 19:41:49 +02:00
@login_required
def create_new_file ( username ) :
if current_user . username != username :
return " Unauthorized " , 401
subpath = request . form . get ( ' subpath ' , ' ' ) . rstrip ( ' / ' )
2024-09-11 19:29:29 +02:00
file_name = request . form [ ' file_name ' ]
2024-09-10 19:41:49 +02:00
file_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username , subpath , file_name )
if not os . path . exists ( file_path ) :
with open ( file_path , ' w ' ) as f :
2024-09-10 20:21:22 +02:00
f . write ( ' ' )
flash ( f " File ' { file_name } ' created successfully. " , ' success ' )
2024-09-10 19:41:49 +02:00
else :
2024-09-10 20:21:22 +02:00
flash ( f " File ' { file_name } ' already exists. " , ' error ' )
2024-09-10 19:41:49 +02:00
return redirect ( url_for ( ' user_files ' , username = username , subpath = subpath ) )
2024-09-11 19:29:29 +02:00
@app.route ( ' /dash/<username>/get_folders ' )
@login_required
def get_folders ( username ) :
if current_user . username != username :
return jsonify ( { ' error ' : ' Unauthorized ' } ) , 401
subpath = request . args . get ( ' path ' , ' ' )
folder_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username , subpath )
if not os . path . exists ( folder_path ) :
return jsonify ( { ' error ' : ' Folder not found ' } ) , 404
folders = [ f for f in os . listdir ( folder_path ) if os . path . isdir ( os . path . join ( folder_path , f ) ) ]
return jsonify ( folders )
@app.route ( ' /dash/<username>/get_folders_and_files ' )
@login_required
def get_folders_and_files ( username ) :
if current_user . username != username :
return jsonify ( { ' error ' : ' Unauthorized ' } ) , 401
subpath = request . args . get ( ' path ' , ' ' )
folder_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username , subpath )
if not os . path . exists ( folder_path ) :
return jsonify ( { ' error ' : ' Folder not found ' } ) , 404
folders = [ ]
files = [ ]
for item in os . listdir ( folder_path ) :
item_path = os . path . join ( folder_path , item )
if os . path . isdir ( item_path ) :
folders . append ( item )
else :
files . append ( item )
return jsonify ( { ' folders ' : folders , ' files ' : files } )
@app.route ( ' /dash/<username>/create_folder ' , methods = [ ' POST ' ] )
@login_required
def create_folder ( username ) :
if current_user . username != username :
return jsonify ( { ' error ' : ' Unauthorized ' } ) , 401
if request . is_json :
data = request . get_json ( )
folder_name = data . get ( ' folder_name ' )
subpath = data . get ( ' subpath ' , ' ' ) . rstrip ( ' / ' )
else :
folder_name = request . form . get ( ' folder_name ' )
subpath = request . form . get ( ' subpath ' , ' ' ) . rstrip ( ' / ' )
if not folder_name :
return jsonify ( { ' error ' : ' Folder name is required ' } ) , 400
folder_path = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username , subpath , folder_name )
if os . path . exists ( folder_path ) :
return jsonify ( { ' error ' : ' Folder already exists ' } ) , 400
try :
os . makedirs ( folder_path )
if request . is_json :
return jsonify ( { ' success ' : True , ' message ' : ' Folder created successfully ' } )
else :
flash ( f " Folder ' { folder_name } ' created successfully. " , ' success ' )
return redirect ( url_for ( ' user_files ' , username = username , subpath = subpath ) )
except Exception as e :
if request . is_json :
return jsonify ( { ' error ' : str ( e ) } ) , 500
else :
flash ( f " Error creating folder: { str ( e ) } " , ' error ' )
return redirect ( url_for ( ' user_files ' , username = username , subpath = subpath ) )
2024-09-14 16:53:26 +02:00
@app.route ( ' /dash/<username>/rename ' , methods = [ ' POST ' ] )
@login_required
def rename_user_file ( username ) :
if current_user . username != username :
return " Unauthorized " , 401
old_filename = request . form [ ' old_filename ' ]
new_filename = secure_filename ( request . form [ ' new_filename ' ] )
item_type = request . form [ ' item_type ' ]
current_path = request . form . get ( ' current_path ' , ' ' ) . rstrip ( ' / ' )
user_folder = os . path . join ( app . config [ ' UPLOAD_FOLDER ' ] , username )
full_current_path = os . path . join ( user_folder , current_path )
old_path = os . path . join ( full_current_path , old_filename )
new_path = os . path . join ( full_current_path , new_filename )
if not os . path . exists ( old_path ) :
flash ( f " The { item_type } ' { old_filename } ' does not exist. " , ' error ' )
return redirect ( url_for ( ' user_files ' , username = username , subpath = current_path ) )
try :
os . rename ( old_path , new_path )
flash ( f " Successfully renamed { item_type } from ' { old_filename } ' to ' { new_filename } ' . " , ' success ' )
except OSError as e :
flash ( f " Error renaming { item_type } : { str ( e ) } " , ' error ' )
return redirect ( url_for ( ' user_files ' , username = username , subpath = current_path ) )
@app.route ( ' /upload/file ' , methods = [ ' POST ' ] )
def upload_file ( ) :
2024-09-16 13:34:50 +02:00
app . logger . info ( " Starting upload_file function " )
app . logger . info ( " Code: if ' file ' not in request.files: " )
2024-09-14 16:53:26 +02:00
if ' file ' not in request . files :
2024-09-16 12:53:05 +02:00
app . logger . error ( " No file part in the request " )
2024-09-14 16:53:26 +02:00
return jsonify ( { ' success ' : False , ' error ' : ' No file part ' } ) , 400
2024-09-16 13:34:50 +02:00
app . logger . info ( " Code: file = request.files[ ' file ' ] " )
2024-09-14 16:53:26 +02:00
file = request . files [ ' file ' ]
2024-09-16 13:34:50 +02:00
app . logger . info ( f " File object: { file } " )
app . logger . info ( " Code: if file.filename == ' ' : " )
2024-09-14 16:53:26 +02:00
if file . filename == ' ' :
2024-09-16 12:53:05 +02:00
app . logger . error ( " No selected file " )
2024-09-14 16:53:26 +02:00
return jsonify ( { ' success ' : False , ' error ' : ' No selected file ' } ) , 400
2024-09-16 13:34:50 +02:00
app . logger . info ( " Code: if file: " )
2024-09-14 16:53:26 +02:00
if file :
try :
2024-09-16 12:53:05 +02:00
app . logger . info ( f " Processing file: { file . filename } " )
2024-09-16 13:34:50 +02:00
app . logger . info ( " Code: filename = secure_filename(file.filename) " )
2024-09-14 16:53:26 +02:00
filename = secure_filename ( file . filename )
2024-09-16 13:34:50 +02:00
app . logger . info ( f " Secure filename: { filename } " )
app . logger . info ( " Code: extension = os.path.splitext(filename)[1].lower() " )
2024-09-14 16:53:26 +02:00
extension = os . path . splitext ( filename ) [ 1 ] . lower ( )
2024-09-16 13:34:50 +02:00
app . logger . info ( f " File extension: { extension } " )
app . logger . info ( " Code: vanity = shortuuid.uuid()[:8] " )
2024-09-14 16:53:26 +02:00
vanity = shortuuid . uuid ( ) [ : 8 ]
2024-09-16 13:34:50 +02:00
app . logger . info ( f " Generated vanity: { vanity } " )
app . logger . info ( " Code: vanity_with_extension = f ' {vanity} {extension} ' " )
2024-09-14 16:53:26 +02:00
vanity_with_extension = f " { vanity } { extension } "
2024-09-16 13:34:50 +02:00
app . logger . info ( f " Vanity with extension: { vanity_with_extension } " )
app . logger . info ( " Code: new_filename = vanity_with_extension " )
2024-09-14 16:53:26 +02:00
new_filename = vanity_with_extension
2024-09-16 13:34:50 +02:00
app . logger . info ( f " New filename: { new_filename } " )
app . logger . info ( " Code: file_path = os.path.join(current_app.config[ ' UPLOAD_FOLDER ' ], new_filename) " )
2024-09-14 16:53:26 +02:00
file_path = os . path . join ( current_app . config [ ' UPLOAD_FOLDER ' ] , new_filename )
2024-09-16 13:34:50 +02:00
app . logger . info ( f " File path: { file_path } " )
2024-09-14 16:53:26 +02:00
2024-09-16 13:34:50 +02:00
app . logger . info ( " Code: file.save(file_path) " )
2024-09-14 16:53:26 +02:00
file . save ( file_path )
2024-09-16 13:34:50 +02:00
app . logger . info ( " File saved successfully " )
2024-09-14 16:53:26 +02:00
2024-09-16 13:34:50 +02:00
app . logger . info ( " Code: user_id = current_user.id if current_user.is_authenticated else None " )
2024-09-14 16:53:26 +02:00
user_id = current_user . id if current_user . is_authenticated else None
2024-09-16 12:53:05 +02:00
app . logger . info ( f " User ID: { user_id } " )
2024-09-14 16:53:26 +02:00
2024-09-16 13:34:50 +02:00
app . logger . info ( " Code: password = request.form.get( ' password ' ) " )
2024-09-14 20:36:31 +02:00
password = request . form . get ( ' password ' )
2024-09-16 13:34:50 +02:00
app . logger . info ( f " Password: { ' Set ' if password else ' Not set ' } " )
app . logger . info ( " Code: is_private = 1 if password else 0 " )
2024-09-14 20:36:31 +02:00
is_private = 1 if password else 0
2024-09-16 12:53:05 +02:00
app . logger . info ( f " Is private: { is_private } " )
2024-09-14 20:36:31 +02:00
2024-09-16 13:34:50 +02:00
app . logger . info ( " Code: db = get_db() " )
2024-09-14 16:53:26 +02:00
db = get_db ( )
2024-09-16 13:34:50 +02:00
app . logger . info ( " Database connection established " )
app . logger . info ( " Code: cursor = db.cursor() " )
2024-09-14 16:53:26 +02:00
cursor = db . cursor ( )
2024-09-16 13:34:50 +02:00
app . logger . info ( " Database cursor created " )
2024-09-16 12:53:05 +02:00
app . logger . info ( " Inserting file info into database " )
2024-09-16 13:34:50 +02:00
app . logger . info ( " Code: vanity_for_db = vanity_with_extension " )
vanity_for_db = vanity_with_extension
app . logger . info ( f " Vanity for DB: { vanity_for_db } " )
app . logger . info ( " Code: cursor.execute(...) " )
2024-09-14 20:36:31 +02:00
cursor . execute ( " INSERT INTO content (vanity, type, data, created_at, user_id, is_private, password) VALUES (?, ?, ?, ?, ?, ?, ?) " ,
2024-09-16 13:34:50 +02:00
( vanity_for_db , ' file ' , new_filename , datetime . now ( ) , user_id , is_private , password ) )
app . logger . info ( " SQL query executed " )
app . logger . info ( " Code: db.commit() " )
2024-09-14 16:53:26 +02:00
db . commit ( )
2024-09-16 13:34:50 +02:00
app . logger . info ( " Database changes committed " )
2024-09-14 16:53:26 +02:00
2024-09-16 13:34:50 +02:00
app . logger . info ( " Code: scheme = ' https ' if request.is_secure else ' http ' " )
2024-09-16 12:53:05 +02:00
scheme = ' https ' if request . is_secure else ' http '
app . logger . info ( f " Using scheme: { scheme } " )
app . logger . info ( " Generating URLs " )
2024-09-16 13:34:50 +02:00
app . logger . info ( " Code: short_url = url_for( ' redirect_vanity ' , vanity=vanity_with_extension, _external=True, _scheme=scheme) " )
2024-09-16 13:54:54 +02:00
short_url = f " { scheme } :// { request . host } / { vanity_with_extension } "
2024-09-16 13:34:50 +02:00
app . logger . info ( f " Generated short URL: { short_url } " )
2024-09-16 12:53:05 +02:00
2024-09-16 13:34:50 +02:00
app . logger . info ( " Code: download_url = short_url + ' /download ' " )
2024-09-16 13:54:54 +02:00
download_url = f " { short_url } /download "
2024-09-16 13:34:50 +02:00
app . logger . info ( f " Generated download URL: { download_url } " )
2024-09-16 12:53:05 +02:00
2024-09-16 13:34:50 +02:00
app . logger . info ( " Code: deletion_url = url_for( ' delete_content ' , vanity=vanity_with_extension, _external=True, _scheme=scheme) " )
2024-09-16 12:53:05 +02:00
deletion_url = url_for ( ' delete_content ' , vanity = vanity_with_extension , _external = True , _scheme = scheme )
2024-09-16 13:34:50 +02:00
app . logger . info ( f " Generated deletion URL: { deletion_url } " )
2024-09-16 12:53:05 +02:00
2024-09-16 13:34:50 +02:00
app . logger . info ( " Preparing JSON response " )
response_data = {
' success ' : True ,
' vanity ' : vanity_with_extension ,
' url ' : short_url ,
' download_url ' : download_url ,
' deletion_url ' : deletion_url ,
' filename ' : new_filename
}
app . logger . info ( f " Response data: { response_data } " )
2024-09-14 16:53:26 +02:00
2024-09-16 13:34:50 +02:00
return jsonify ( response_data )
2024-09-14 16:53:26 +02:00
except Exception as e :
2024-09-14 21:00:33 +02:00
app . logger . error ( f " Error uploading file: { str ( e ) } " )
2024-09-16 13:34:50 +02:00
app . logger . exception ( " Exception traceback: " )
2024-09-14 16:53:26 +02:00
return jsonify ( { ' success ' : False , ' error ' : str ( e ) } ) , 500
2024-09-16 12:53:05 +02:00
app . logger . error ( " Unknown error occurred " )
2024-09-14 16:53:26 +02:00
return jsonify ( { ' success ' : False , ' error ' : ' Unknown error occurred ' } ) , 500
2024-09-14 20:36:31 +02:00
# Add this function to validate passwords
def is_valid_password ( password ) :
banned_passwords = [ ' info ' , ' download ' ]
return password not in banned_passwords
2024-09-16 14:41:26 +02:00
@app.route ( ' /reset_api_key ' , methods = [ ' POST ' ] )
@login_required
def reset_api_key ( ) :
new_api_key = secrets . token_urlsafe ( 32 )
db = get_db ( )
cursor = db . cursor ( )
cursor . execute ( " UPDATE users SET api_key = ? WHERE id = ? " , ( new_api_key , current_user . id ) )
db . commit ( )
return jsonify ( { ' success ' : True , ' new_api_key ' : new_api_key } )
@app.route ( ' /api/docs ' )
def api_docs ( ) :
return render_template ( ' api_docs.html ' )
2024-09-08 14:02:03 +02:00
if __name__ == ' __main__ ' :
2024-09-10 20:16:06 +02:00
# Start the cleanup thread
cleanup_thread = threading . Thread ( target = delete_old_files )
cleanup_thread . daemon = True
cleanup_thread . start ( )
2024-09-11 19:29:29 +02:00
app . run ( host = ' 0.0.0.0 ' , port = 7123 , debug = True )