finished project - working
This commit is contained in:
Binary file not shown.
BIN
server/__pycache__/preview.cpython-311.pyc
Normal file
BIN
server/__pycache__/preview.cpython-311.pyc
Normal file
Binary file not shown.
BIN
server/__pycache__/rename.cpython-311.pyc
Normal file
BIN
server/__pycache__/rename.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
140
server/app.py
140
server/app.py
@@ -1,10 +1,13 @@
|
|||||||
from flask import Flask, request, render_template, redirect, url_for, session, send_from_directory
|
from flask import Flask, request, render_template, redirect, url_for, session, send_from_directory, jsonify, send_file
|
||||||
from flask_talisman import Talisman
|
from flask_talisman import Talisman
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
import os
|
import os
|
||||||
from security import validate_user
|
from security import validate_user
|
||||||
from data_handler import save_link, save_file, retrieve_uploads, handle_download, get_file_path
|
from data_handler import save_link, save_file, retrieve_uploads, handle_download, get_file_path
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from zipfile import ZipFile
|
||||||
|
from preview import generate_preview # Import the preview module
|
||||||
|
from rename import rename_file # Import the rename module
|
||||||
|
|
||||||
app = Flask(__name__, template_folder='../templates')
|
app = Flask(__name__, template_folder='../templates')
|
||||||
app.secret_key = os.urandom(24)
|
app.secret_key = os.urandom(24)
|
||||||
@@ -35,6 +38,8 @@ def login_required(f):
|
|||||||
def ensure_login():
|
def ensure_login():
|
||||||
if 'username' not in session and request.endpoint not in ('login', 'static'):
|
if 'username' not in session and request.endpoint not in ('login', 'static'):
|
||||||
return redirect(url_for('login'))
|
return redirect(url_for('login'))
|
||||||
|
elif request.endpoint == 'login' and 'username' in session:
|
||||||
|
session.clear()
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
@login_required
|
@login_required
|
||||||
@@ -69,15 +74,18 @@ def upload_link():
|
|||||||
save_link(uploader, link)
|
save_link(uploader, link)
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
@app.route('/upload/file', methods=['POST'])
|
@app.route('/upload/files', methods=['POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def upload_file():
|
def upload_files():
|
||||||
if 'file' not in request.files:
|
if 'files' not in request.files:
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
file = request.files['file']
|
files = request.files.getlist('files')
|
||||||
uploader = session['username']
|
uploader = session['username']
|
||||||
save_file(uploader, file)
|
|
||||||
|
for file in files:
|
||||||
|
save_file(uploader, file)
|
||||||
|
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
@app.route('/uploads')
|
@app.route('/uploads')
|
||||||
@@ -104,14 +112,12 @@ def view_uploads():
|
|||||||
def download_link(link_id):
|
def download_link(link_id):
|
||||||
upload = handle_download(link_id)
|
upload = handle_download(link_id)
|
||||||
|
|
||||||
if upload[2] == 'link':
|
if upload and upload[2] == 'link':
|
||||||
link_content = upload[3]
|
link_content = upload[3]
|
||||||
|
|
||||||
x = 1
|
x = 1
|
||||||
while os.path.exists(os.path.join(DOWNLOADS_DIRECTORY, f"link_{x}.txt")):
|
while os.path.exists(os.path.join(DOWNLOADS_DIRECTORY, f"link_{x}.txt")):
|
||||||
x += 1
|
x += 1
|
||||||
filename = f"link_{x}.txt"
|
filename = f"link_{x}.txt"
|
||||||
|
|
||||||
filepath = os.path.join(DOWNLOADS_DIRECTORY, filename)
|
filepath = os.path.join(DOWNLOADS_DIRECTORY, filename)
|
||||||
with open(filepath, 'w') as f:
|
with open(filepath, 'w') as f:
|
||||||
f.write(link_content)
|
f.write(link_content)
|
||||||
@@ -119,7 +125,6 @@ def download_link(link_id):
|
|||||||
response = send_from_directory(DOWNLOADS_DIRECTORY, filename, as_attachment=True)
|
response = send_from_directory(DOWNLOADS_DIRECTORY, filename, as_attachment=True)
|
||||||
|
|
||||||
handle_download(link_id, delete_only=True)
|
handle_download(link_id, delete_only=True)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
return "Link Not found", 404
|
return "Link Not found", 404
|
||||||
|
|
||||||
@@ -137,13 +142,9 @@ def download_all_links():
|
|||||||
for link in links:
|
for link in links:
|
||||||
f.write(link[3] + "\n")
|
f.write(link[3] + "\n")
|
||||||
|
|
||||||
# Serve the combined links file from the Downloads directory
|
|
||||||
response = send_from_directory(DOWNLOADS_DIRECTORY, filename, as_attachment=True)
|
response = send_from_directory(DOWNLOADS_DIRECTORY, filename, as_attachment=True)
|
||||||
|
|
||||||
# Now delete all the link entries from the database after serving
|
|
||||||
for link in links:
|
for link in links:
|
||||||
handle_download(link[0], delete_only=True)
|
handle_download(link[0], delete_only=True)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
return redirect(url_for('view_uploads'))
|
return redirect(url_for('view_uploads'))
|
||||||
@@ -153,23 +154,22 @@ def download_all_links():
|
|||||||
def download(upload_id):
|
def download(upload_id):
|
||||||
upload = handle_download(upload_id)
|
upload = handle_download(upload_id)
|
||||||
|
|
||||||
if not upload:
|
if upload and upload[2] == 'file':
|
||||||
print(f"Error: No upload found with ID {upload_id}")
|
|
||||||
return "The requested file does not exist or you do not have permission to access it.", 404
|
|
||||||
|
|
||||||
if upload[2] == 'file':
|
|
||||||
file_path = get_file_path(upload[3])
|
file_path = get_file_path(upload[3])
|
||||||
print(f"Trying to download file: {file_path}")
|
|
||||||
|
|
||||||
if not os.path.isfile(file_path):
|
if not os.path.isfile(file_path):
|
||||||
print(f"Error: File not found at {file_path}")
|
return redirect(url_for('view_uploads'), code=404)
|
||||||
return "File not found", 404
|
|
||||||
|
response = send_from_directory(
|
||||||
response = send_from_directory(os.path.dirname(file_path), os.path.basename(file_path), as_attachment=True)
|
directory=os.path.dirname(file_path),
|
||||||
|
path=os.path.basename(file_path),
|
||||||
|
as_attachment=True,
|
||||||
|
#download_name=os.path.basename(file_path) # Ensures the download retains the current name
|
||||||
|
download_name=upload[3]
|
||||||
|
)
|
||||||
|
|
||||||
handle_download(upload_id, delete_only=True)
|
handle_download(upload_id, delete_only=True)
|
||||||
|
return response
|
||||||
return response
|
return "The requested file does not exist or you do not have permission to access it.", 404
|
||||||
|
|
||||||
@app.route('/delete_link/<int:link_id>', methods=['GET'])
|
@app.route('/delete_link/<int:link_id>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@@ -183,6 +183,88 @@ def delete_file(file_id):
|
|||||||
handle_download(file_id, delete_only=True)
|
handle_download(file_id, delete_only=True)
|
||||||
return redirect(url_for('view_uploads'))
|
return redirect(url_for('view_uploads'))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
# Add routes for downloading all photos
|
||||||
app.run(host='0.0.0.0', port=5000, ssl_context='adhoc')
|
@app.route('/download_all_photos', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def download_all_photos():
|
||||||
|
photos = [upload for upload in retrieve_uploads() if upload[2] == 'file' and upload[3].lower().endswith(('.jpg', '.jpeg', '.png', '.gif'))]
|
||||||
|
|
||||||
|
if photos:
|
||||||
|
zip_filename = f"photos_{datetime.now().strftime('%m-%d-%Y')}.zip"
|
||||||
|
zip_filepath = os.path.join(DOWNLOADS_DIRECTORY, zip_filename)
|
||||||
|
|
||||||
|
# Create a zip file containing all photos
|
||||||
|
with ZipFile(zip_filepath, 'w') as zipf:
|
||||||
|
for photo in photos:
|
||||||
|
file_path = get_file_path(photo[3])
|
||||||
|
zipf.write(file_path, os.path.basename(file_path))
|
||||||
|
handle_download(photo[0], delete_only=True) # Delete each photo entry
|
||||||
|
|
||||||
|
return send_from_directory(DOWNLOADS_DIRECTORY, zip_filename, as_attachment=True)
|
||||||
|
else:
|
||||||
|
return redirect(url_for('view_uploads'))
|
||||||
|
|
||||||
|
# Add similar routes for videos and misc
|
||||||
|
@app.route('/download_all_videos', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def download_all_videos():
|
||||||
|
videos = [upload for upload in retrieve_uploads() if upload[2] == 'file' and upload[3].lower().endswith(('.mp4', '.mkv', '.avi'))]
|
||||||
|
|
||||||
|
if videos:
|
||||||
|
zip_filename = f"videos_{datetime.now().strftime('%m-%d-%Y')}.zip"
|
||||||
|
zip_filepath = os.path.join(DOWNLOADS_DIRECTORY, zip_filename)
|
||||||
|
|
||||||
|
with ZipFile(zip_filepath, 'w') as zipf:
|
||||||
|
for video in videos:
|
||||||
|
file_path = get_file_path(video[3])
|
||||||
|
zipf.write(file_path, os.path.basename(file_path))
|
||||||
|
handle_download(video[0], delete_only=True) # Delete each video entry
|
||||||
|
|
||||||
|
return send_from_directory(DOWNLOADS_DIRECTORY, zip_filename, as_attachment=True)
|
||||||
|
else:
|
||||||
|
return redirect(url_for('view_uploads'))
|
||||||
|
|
||||||
|
@app.route('/download_all_misc', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def download_all_misc():
|
||||||
|
misc_files = [upload for upload in retrieve_uploads() if upload[2] == 'file' and upload not in videos + photos]
|
||||||
|
|
||||||
|
if misc_files:
|
||||||
|
zip_filename = f"misc_{datetime.now().strftime('%m-%d-%Y')}.zip"
|
||||||
|
zip_filepath = os.path.join(DOWNLOADS_DIRECTORY, zip_filename)
|
||||||
|
|
||||||
|
with ZipFile(zip_filepath, 'w') as zipf:
|
||||||
|
for item in misc_files:
|
||||||
|
file_path = get_file_path(item[3])
|
||||||
|
zipf.write(file_path, os.path.basename(file_path))
|
||||||
|
handle_download(item[0], delete_only=True) # Delete each misc entry
|
||||||
|
|
||||||
|
return send_from_directory(DOWNLOADS_DIRECTORY, zip_filename, as_attachment=True)
|
||||||
|
else:
|
||||||
|
return redirect(url_for('view_uploads'))
|
||||||
|
|
||||||
|
# Route to handle file renaming
|
||||||
|
@app.route('/rename/<int:upload_id>', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def rename(upload_id):
|
||||||
|
data = request.get_json() # Expecting JSON data from the frontend
|
||||||
|
new_name = data.get('new_name', '').strip()
|
||||||
|
|
||||||
|
if not new_name:
|
||||||
|
return jsonify({"error": "New name not provided"}), 400
|
||||||
|
|
||||||
|
success, message = rename_file(upload_id, new_name)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
return jsonify({"success": True}), 200
|
||||||
|
else:
|
||||||
|
return jsonify({"error": message}), 400
|
||||||
|
|
||||||
|
# Route to handle file previews
|
||||||
|
@app.route('/preview/<int:upload_id>', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def preview(upload_id):
|
||||||
|
return generate_preview(upload_id)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run(host='0.0.0.0', port=5000, debug=True, ssl_context='adhoc')
|
||||||
|
|||||||
@@ -4,19 +4,23 @@ from functools import wraps
|
|||||||
import os
|
import os
|
||||||
from security import validate_user
|
from security import validate_user
|
||||||
from data_handler import save_link, save_file, retrieve_uploads, handle_download, get_file_path
|
from data_handler import save_link, save_file, retrieve_uploads, handle_download, get_file_path
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
app = Flask(__name__, template_folder='../templates')
|
app = Flask(__name__, template_folder='../templates')
|
||||||
app.secret_key = os.urandom(24) # Generate a more secure secret key
|
app.secret_key = os.urandom(24)
|
||||||
talisman = Talisman(app, content_security_policy={
|
talisman = Talisman(app, content_security_policy={
|
||||||
'default-src': ["'self'"],
|
'default-src': ["'self'"],
|
||||||
'script-src': ["'self'", "'unsafe-inline'"] # Allow inline scripts
|
'script-src': ["'self'", "'unsafe-inline'"]
|
||||||
})
|
})
|
||||||
|
|
||||||
UPLOAD_DIRECTORY = "../assets"
|
UPLOAD_DIRECTORY = "../assets"
|
||||||
if not os.path.exists(UPLOAD_DIRECTORY):
|
if not os.path.exists(UPLOAD_DIRECTORY):
|
||||||
os.makedirs(UPLOAD_DIRECTORY)
|
os.makedirs(UPLOAD_DIRECTORY)
|
||||||
|
|
||||||
# Login required decorator
|
DOWNLOADS_DIRECTORY = os.path.expanduser("~/Downloads")
|
||||||
|
if not os.path.exists(DOWNLOADS_DIRECTORY):
|
||||||
|
os.makedirs(DOWNLOADS_DIRECTORY)
|
||||||
|
|
||||||
def login_required(f):
|
def login_required(f):
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def decorated_function(*args, **kwargs):
|
def decorated_function(*args, **kwargs):
|
||||||
@@ -65,15 +69,18 @@ def upload_link():
|
|||||||
save_link(uploader, link)
|
save_link(uploader, link)
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
@app.route('/upload/file', methods=['POST'])
|
@app.route('/upload/files', methods=['POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def upload_file():
|
def upload_files():
|
||||||
if 'file' not in request.files:
|
if 'files' not in request.files:
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
file = request.files['file']
|
files = request.files.getlist('files')
|
||||||
uploader = session['username']
|
uploader = session['username']
|
||||||
save_file(uploader, file)
|
|
||||||
|
for file in files:
|
||||||
|
save_file(uploader, file)
|
||||||
|
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
@app.route('/uploads')
|
@app.route('/uploads')
|
||||||
@@ -81,7 +88,6 @@ def upload_file():
|
|||||||
def view_uploads():
|
def view_uploads():
|
||||||
uploads = retrieve_uploads()
|
uploads = retrieve_uploads()
|
||||||
|
|
||||||
# Categorizing uploads
|
|
||||||
links = [upload for upload in uploads if upload[2] == 'link']
|
links = [upload for upload in uploads if upload[2] == 'link']
|
||||||
videos = [upload for upload in uploads if upload[2] == 'file' and upload[3].lower().endswith(('.mp4', '.mkv', '.avi'))]
|
videos = [upload for upload in uploads if upload[2] == 'file' and upload[3].lower().endswith(('.mp4', '.mkv', '.avi'))]
|
||||||
photos = [upload for upload in uploads if upload[2] == 'file' and upload[3].lower().endswith(('.jpg', '.jpeg', '.png', '.gif'))]
|
photos = [upload for upload in uploads if upload[2] == 'file' and upload[3].lower().endswith(('.jpg', '.jpeg', '.png', '.gif'))]
|
||||||
@@ -99,24 +105,23 @@ def view_uploads():
|
|||||||
@app.route('/download_link/<int:link_id>', methods=['GET'])
|
@app.route('/download_link/<int:link_id>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def download_link(link_id):
|
def download_link(link_id):
|
||||||
uploader = session['username']
|
upload = handle_download(link_id)
|
||||||
upload = handle_download(link_id, uploader)
|
|
||||||
|
|
||||||
if upload[2] == 'link':
|
if upload and upload[2] == 'link':
|
||||||
link_content = upload[3]
|
link_content = upload[3]
|
||||||
|
|
||||||
# Create a unique filename
|
|
||||||
x = 1
|
x = 1
|
||||||
while os.path.exists(f"link_{x}.txt"):
|
while os.path.exists(os.path.join(DOWNLOADS_DIRECTORY, f"link_{x}.txt")):
|
||||||
x += 1
|
x += 1
|
||||||
filename = f"link_{x}.txt"
|
filename = f"link_{x}.txt"
|
||||||
|
filepath = os.path.join(DOWNLOADS_DIRECTORY, filename)
|
||||||
# Save the link content to the file
|
with open(filepath, 'w') as f:
|
||||||
with open(filename, 'w') as f:
|
|
||||||
f.write(link_content)
|
f.write(link_content)
|
||||||
|
|
||||||
# Serve the file
|
response = send_from_directory(DOWNLOADS_DIRECTORY, filename, as_attachment=True)
|
||||||
return send_from_directory(directory=os.getcwd(), filename=filename, as_attachment=True)
|
|
||||||
|
handle_download(link_id, delete_only=True)
|
||||||
|
return response
|
||||||
|
return "Link Not found", 404
|
||||||
|
|
||||||
@app.route('/download_all_links', methods=['GET'])
|
@app.route('/download_all_links', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@@ -124,26 +129,48 @@ def download_all_links():
|
|||||||
links = [upload for upload in retrieve_uploads() if upload[2] == 'link']
|
links = [upload for upload in retrieve_uploads() if upload[2] == 'link']
|
||||||
|
|
||||||
if len(links) > 1:
|
if len(links) > 1:
|
||||||
with open("links_data.txt", 'w') as f:
|
current_date = datetime.now().strftime("%m-%d-%Y")
|
||||||
|
filename = f"links_{current_date}.txt"
|
||||||
|
|
||||||
|
links_file_path = os.path.join(DOWNLOADS_DIRECTORY, filename)
|
||||||
|
with open(links_file_path, 'w') as f:
|
||||||
for link in links:
|
for link in links:
|
||||||
f.write(link[3] + "\n")
|
f.write(link[3] + "\n")
|
||||||
|
|
||||||
return send_from_directory(directory=os.getcwd(), filename="links_data.txt", as_attachment=True)
|
response = send_from_directory(DOWNLOADS_DIRECTORY, filename, as_attachment=True)
|
||||||
|
for link in links:
|
||||||
|
handle_download(link[0], delete_only=True)
|
||||||
|
return response
|
||||||
else:
|
else:
|
||||||
return redirect(url_for('view_uploads'))
|
return redirect(url_for('view_uploads'))
|
||||||
|
|
||||||
@app.route('/download/<int:upload_id>', methods=['GET'])
|
@app.route('/download/<int:upload_id>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def download(upload_id):
|
def download(upload_id):
|
||||||
uploader = session['username']
|
upload = handle_download(upload_id)
|
||||||
upload = handle_download(upload_id, uploader)
|
|
||||||
|
if upload and upload[2] == 'file':
|
||||||
if upload[2] == 'link':
|
|
||||||
return f"<a href='{upload[3]}' target='_blank'>{upload[3]}</a>"
|
|
||||||
elif upload[2] == 'file':
|
|
||||||
# Integrate get_file_path here
|
|
||||||
file_path = get_file_path(upload[3])
|
file_path = get_file_path(upload[3])
|
||||||
return send_from_directory(os.path.dirname(file_path), os.path.basename(file_path), as_attachment=True)
|
if not os.path.isfile(file_path):
|
||||||
|
return "File not found", 404
|
||||||
|
|
||||||
|
response = send_from_directory(os.path.dirname(file_path), os.path.basename(file_path), as_attachment=True)
|
||||||
|
handle_download(upload_id, delete_only=True)
|
||||||
|
return response
|
||||||
|
|
||||||
|
return "The requested file does not exist or you do not have permission to access it.", 404
|
||||||
|
|
||||||
|
@app.route('/delete_link/<int:link_id>', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def delete_link(link_id):
|
||||||
|
handle_download(link_id, delete_only=True)
|
||||||
|
return redirect(url_for('view_uploads'))
|
||||||
|
|
||||||
|
@app.route('/delete_file/<int:file_id>', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def delete_file(file_id):
|
||||||
|
handle_download(file_id, delete_only=True)
|
||||||
|
return redirect(url_for('view_uploads'))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(host='0.0.0.0', port=5000, ssl_context='adhoc')
|
app.run(host='0.0.0.0', port=5000, ssl_context='adhoc')
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
# server/db_setup.py
|
# server/db_setup.py
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import os
|
||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
|
|
||||||
DATABASE = 'transfer_service.db'
|
DATABASE = 'transfer_service.db'
|
||||||
|
|
||||||
def initialize_db():
|
def initialize_db():
|
||||||
with closing(sqlite3.connect(DATABASE)) as conn, conn, closing(conn.cursor()) as c:
|
with closing(sqlite3.connect(DATABASE)) as conn, conn, closing(conn.cursor()) as c:
|
||||||
# Create users table
|
# Create users table with salt
|
||||||
c.execute('''
|
c.execute('''
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
username TEXT UNIQUE NOT NULL,
|
username TEXT UNIQUE NOT NULL,
|
||||||
password TEXT NOT NULL,
|
password TEXT NOT NULL,
|
||||||
|
salt TEXT NOT NULL,
|
||||||
login_attempts INTEGER DEFAULT 0
|
login_attempts INTEGER DEFAULT 0
|
||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
@@ -28,21 +30,66 @@ def initialize_db():
|
|||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
# Check if the 'salt' column exists in the users table and add it if missing
|
||||||
|
c.execute("PRAGMA table_info(users)")
|
||||||
|
columns = [column[1] for column in c.fetchall()]
|
||||||
|
if 'salt' not in columns:
|
||||||
|
c.execute("ALTER TABLE users ADD COLUMN salt TEXT")
|
||||||
|
update_existing_users_with_salts() # Update existing users with salts
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
|
def generate_salt():
|
||||||
|
return os.urandom(16).hex()
|
||||||
|
|
||||||
|
def hash_password(password, salt):
|
||||||
|
return hashlib.sha256((password + salt).encode()).hexdigest()
|
||||||
|
|
||||||
|
def update_existing_users_with_salts():
|
||||||
|
"""
|
||||||
|
Updates existing users to include a unique salt and rehashes their passwords.
|
||||||
|
"""
|
||||||
|
with closing(sqlite3.connect(DATABASE)) as conn, closing(conn.cursor()) as c:
|
||||||
|
c.execute('SELECT id, password FROM users')
|
||||||
|
users = c.fetchall()
|
||||||
|
|
||||||
|
for user_id, password in users:
|
||||||
|
salt = generate_salt()
|
||||||
|
hashed_password = hash_password(password, salt)
|
||||||
|
c.execute('UPDATE users SET password = ?, salt = ? WHERE id = ?', (hashed_password, salt, user_id))
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
print("Updated existing users with salts.")
|
||||||
|
|
||||||
def add_user(username, password):
|
def add_user(username, password):
|
||||||
hashed_password = hashlib.sha256(password.encode()).hexdigest()
|
# Generate a unique salt for each user
|
||||||
|
salt = os.urandom(16)
|
||||||
|
hashed_password = hashlib.sha256(salt + password.encode()).hexdigest()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with closing(sqlite3.connect(DATABASE)) as conn, conn, closing(conn.cursor()) as c:
|
with closing(sqlite3.connect(DATABASE)) as conn, conn, closing(conn.cursor()) as c:
|
||||||
c.execute('INSERT INTO users (username, password) VALUES (?, ?)', (username, hashed_password))
|
c.execute('INSERT INTO users (username, password, salt) VALUES (?, ?, ?)', (username, hashed_password, salt))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
print(f"User '{username}' added successfully.")
|
print(f"User '{username}' added successfully.")
|
||||||
except sqlite3.IntegrityError:
|
except sqlite3.IntegrityError:
|
||||||
print(f"User '{username}' already exists.")
|
print(f"User '{username}' already exists.")
|
||||||
|
|
||||||
|
def delete_user(username):
|
||||||
|
"""
|
||||||
|
Deletes a user from the database based on the provided username.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with closing(sqlite3.connect(DATABASE)) as conn, conn, closing(conn.cursor()) as c:
|
||||||
|
c.execute('DELETE FROM users WHERE username = ?', (username,))
|
||||||
|
conn.commit()
|
||||||
|
print(f"User '{username}' deleted successfully.")
|
||||||
|
except sqlite3.Error as e:
|
||||||
|
print(f"Error deleting user '{username}': {e}")
|
||||||
|
|
||||||
def get_user(username):
|
def get_user(username):
|
||||||
with closing(sqlite3.connect(DATABASE)) as conn, closing(conn.cursor()) as c:
|
with closing(sqlite3.connect(DATABASE)) as conn, closing(conn.cursor()) as c:
|
||||||
c.execute('SELECT username, password, login_attempts FROM users WHERE username = ?', (username,))
|
# Select only password, salt, and login_attempts
|
||||||
|
c.execute('SELECT password, salt, login_attempts FROM users WHERE username = ?', (username,))
|
||||||
return c.fetchone()
|
return c.fetchone()
|
||||||
|
|
||||||
def reset_login_attempts(username):
|
def reset_login_attempts(username):
|
||||||
@@ -70,8 +117,17 @@ def delete_upload(upload_id):
|
|||||||
c.execute('DELETE FROM uploads WHERE id = ?', (upload_id,))
|
c.execute('DELETE FROM uploads WHERE id = ?', (upload_id,))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
|
def update_upload_filename(upload_id, new_name):
|
||||||
|
with closing(sqlite3.connect(DATABASE)) as conn, closing(conn.cursor()) as c:
|
||||||
|
c.execute('UPDATE uploads SET content = ? WHERE id = ?', (new_name, upload_id))
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
initialize_db()
|
initialize_db()
|
||||||
|
|
||||||
# Example of initializing users (only run manually)
|
# Example of initializing users (only run manually)
|
||||||
# add_user('iphone_user', 'your_secure_password')
|
# add_user('iphone_user', 'your_secure_password')
|
||||||
# add_user('laptop_user', 'your_secure_password')
|
# add_user('laptop_user', 'your_secure_password')
|
||||||
|
# Example of deleting user
|
||||||
|
# delete_user('iphone_user')
|
||||||
|
# delete_user('laptop_user')
|
||||||
|
|||||||
37
server/preview.py
Normal file
37
server/preview.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# preview.py
|
||||||
|
import os
|
||||||
|
from flask import send_file, jsonify
|
||||||
|
import sqlite3
|
||||||
|
import mimetypes
|
||||||
|
|
||||||
|
UPLOAD_DIRECTORY = "../assets"
|
||||||
|
|
||||||
|
def generate_preview(upload_id):
|
||||||
|
conn = sqlite3.connect('transfer_service.db')
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
c.execute('SELECT file_type, content FROM uploads WHERE id = ?', (upload_id,))
|
||||||
|
upload = c.fetchone()
|
||||||
|
|
||||||
|
if not upload:
|
||||||
|
conn.close()
|
||||||
|
return jsonify({"error": "File not found"}), 404
|
||||||
|
|
||||||
|
file_type, filename = upload
|
||||||
|
file_path = os.path.join(UPLOAD_DIRECTORY, filename)
|
||||||
|
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
return jsonify({"error": "File not found"}), 404
|
||||||
|
|
||||||
|
# Detect the MIME type
|
||||||
|
mime_type, _ = mimetypes.guess_type(filename)
|
||||||
|
|
||||||
|
# Handle different file types for preview
|
||||||
|
if file_type == "link":
|
||||||
|
return jsonify({"link": filename}), 200
|
||||||
|
|
||||||
|
# Send the file with the correct MIME type
|
||||||
|
if file_type == "file" and filename.lower().endswith(('.jpg', '.jpeg', '.png', '.gif')):
|
||||||
|
return send_file(file_path, mimetype='image/jpeg', download_name=os.path.basename(file_path))
|
||||||
|
|
||||||
|
return jsonify({"error": "Preview not supported for this file type"}), 400
|
||||||
40
server/rename.py
Normal file
40
server/rename.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# rename.py
|
||||||
|
import os
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
UPLOAD_DIRECTORY = "../assets"
|
||||||
|
DATABASE = 'transfer_service.db' # Define the DATABASE path
|
||||||
|
|
||||||
|
def rename_file(upload_id, new_name):
|
||||||
|
conn = sqlite3.connect(DATABASE)
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
# Retrieve the upload record based on the ID
|
||||||
|
c.execute('SELECT * FROM uploads WHERE id = ?', (upload_id,))
|
||||||
|
upload = c.fetchone()
|
||||||
|
|
||||||
|
if not upload:
|
||||||
|
conn.close()
|
||||||
|
return False, "File not found in database"
|
||||||
|
|
||||||
|
old_filename = upload[3]
|
||||||
|
old_path = os.path.join(UPLOAD_DIRECTORY, old_filename)
|
||||||
|
new_path = os.path.join(UPLOAD_DIRECTORY, new_name)
|
||||||
|
|
||||||
|
if os.path.exists(new_path):
|
||||||
|
conn.close()
|
||||||
|
return False, "A file with the new name already exists"
|
||||||
|
|
||||||
|
# Rename the file in the filesystem
|
||||||
|
try:
|
||||||
|
os.rename(old_path, new_path)
|
||||||
|
except OSError as e:
|
||||||
|
conn.close()
|
||||||
|
return False, f"Error renaming file: {e}"
|
||||||
|
|
||||||
|
# Update the filename in the database
|
||||||
|
c.execute('UPDATE uploads SET content = ? WHERE id = ?', (new_name, upload_id))
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return True, "File renamed successfully"
|
||||||
@@ -1,40 +1,79 @@
|
|||||||
# server/security.py
|
import os # Import for generating random salts
|
||||||
from flask import request, session
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
from flask import request
|
||||||
from db_setup import get_user, increment_login_attempts, reset_login_attempts
|
from db_setup import get_user, increment_login_attempts, reset_login_attempts
|
||||||
|
|
||||||
MAX_ATTEMPTS = 3
|
MAX_ATTEMPTS = 3
|
||||||
|
|
||||||
|
def generate_salt():
|
||||||
|
"""
|
||||||
|
Generates a 16-byte random salt.
|
||||||
|
"""
|
||||||
|
return os.urandom(16)
|
||||||
|
|
||||||
|
def hash_password(password, salt):
|
||||||
|
# Convert the salt to bytes if it's a string
|
||||||
|
if isinstance(salt, str):
|
||||||
|
salt = salt.encode()
|
||||||
|
return hashlib.sha256(salt + password.encode()).hexdigest()
|
||||||
|
|
||||||
def validate_user(username, password):
|
def validate_user(username, password):
|
||||||
|
"""
|
||||||
|
Validates the user's credentials against stored data.
|
||||||
|
"""
|
||||||
user_data = get_user(username)
|
user_data = get_user(username)
|
||||||
if not user_data:
|
if not user_data:
|
||||||
|
print(f"User '{username}' does not exist.")
|
||||||
return False, "User does not exist."
|
return False, "User does not exist."
|
||||||
|
|
||||||
stored_username, stored_password, login_attempts = user_data
|
stored_password, salt, login_attempts = user_data
|
||||||
|
|
||||||
|
# Check if the maximum login attempts have been reached
|
||||||
if login_attempts >= MAX_ATTEMPTS:
|
if login_attempts >= MAX_ATTEMPTS:
|
||||||
|
print(f"User '{username}' has exceeded max login attempts.")
|
||||||
return False, "Maximum login attempts exceeded. Please contact the administrator."
|
return False, "Maximum login attempts exceeded. Please contact the administrator."
|
||||||
|
|
||||||
hashed_password = hashlib.sha256(password.encode()).hexdigest()
|
# Hash the provided password with the salt
|
||||||
|
hashed_password = hash_password(password, salt)
|
||||||
|
print(f"Provided hash: {hashed_password}, Stored hash: {stored_password}")
|
||||||
|
|
||||||
if hashed_password == stored_password:
|
if hashed_password == stored_password:
|
||||||
reset_login_attempts(username)
|
reset_login_attempts(username)
|
||||||
|
print(f"User '{username}' logged in successfully.")
|
||||||
return True, "Login successful."
|
return True, "Login successful."
|
||||||
else:
|
else:
|
||||||
increment_login_attempts(username)
|
increment_login_attempts(username)
|
||||||
return False, f"Invalid credentials. {MAX_ATTEMPTS - login_attempts - 1} attempt(s) remaining."
|
remaining_attempts = MAX_ATTEMPTS - login_attempts - 1
|
||||||
|
print(f"Invalid credentials for '{username}'. {remaining_attempts} attempt(s) remaining.")
|
||||||
|
return False, f"Invalid credentials. {remaining_attempts} attempt(s) remaining."
|
||||||
|
|
||||||
def identify_uploader():
|
def identify_uploader():
|
||||||
|
"""
|
||||||
|
Identifies the uploader's device information from the request headers.
|
||||||
|
"""
|
||||||
device_info = get_device_info()
|
device_info = get_device_info()
|
||||||
if "iPhone" in device_info['user_agent']:
|
user_agent = device_info['user_agent']
|
||||||
return f"Uploaded by iPhone (IP: {device_info['ip']})"
|
|
||||||
|
if "iPhone" in user_agent:
|
||||||
|
device_type = "iPhone"
|
||||||
|
elif "Android" in user_agent:
|
||||||
|
device_type = "Android"
|
||||||
|
elif "Windows" in user_agent:
|
||||||
|
device_type = "Windows PC"
|
||||||
|
elif "Mac" in user_agent:
|
||||||
|
device_type = "Mac"
|
||||||
|
elif "Linux" in user_agent:
|
||||||
|
device_type = "Linux Machine"
|
||||||
else:
|
else:
|
||||||
return f"Uploaded by {device_info['isa']} {device_info['os']} (IP: {device_info['ip']})"
|
device_type = "Unknown Device"
|
||||||
|
|
||||||
|
return f"Uploaded by {device_type} (IP: {device_info['ip']})"
|
||||||
|
|
||||||
def get_device_info():
|
def get_device_info():
|
||||||
user_agent = request.headers.get('User-Agent', 'Unknown')
|
"""
|
||||||
|
Extracts device information from the request.
|
||||||
|
"""
|
||||||
return {
|
return {
|
||||||
"ip": request.remote_addr,
|
"ip": request.remote_addr or "Unknown IP",
|
||||||
"user_agent": user_agent,
|
"user_agent": request.headers.get('User-Agent', 'Unknown'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user