import os from datetime import datetime from flask import current_app as app import re import sys import json import stat import time import sqlite3 from .misc import * from .crypt import * def get_db(): db = sqlite3.connect(os.getenv("FLASK_DB"), timeout=5) c = db.cursor() return db, c def db_store_file(token, name, expires, max_dl): db, c = get_db() c.execute( """ insert into files(token,name,added,expires,downloads,max_downloads) values (?,?,?,?,?,?) """, (token, name, int(time.time()), expires, 0, max_dl), ) if c.rowcount > 0: db.commit() return def db_get_file(token, name): db, c = get_db() return db.execute( """ SELECT added,expires,downloads,max_downloads FROM files WHERE token = ? AND name = ? """, (token, name), ).fetchone() def db_get_files(): db, c = get_db() return db.execute( """ SELECT token,name,added,expires,downloads,max_downloads FROM files WHERE expires > ? and downloads < max_downloads """, (time.time(),), ) def db_delete_file(token, name): db, c = get_db() c.execute( """ DELETE FROM files WHERE token = ? and name = ? """, (token, name), ) if c.rowcount > 0: db.commit() def db_add_download(token, name): db, c = get_db() c.execute( """ UPDATE files SET downloads = downloads + 1 WHERE token = ? AND name = ? """, (token, name), ) if c.rowcount > 0: db.commit() return def file_autoremove(): db, c = get_db() rows = db.execute( """ select token, name from files where expires > ? or downloads >= max_downloads """, (int(time.time()),), ) deleted_tokens = [] for row in rows: try: os.remove(os.path.join(os.getenv("DATAFOLDER"), row[0], row[1])) except FileNotFoundError: pass try: os.rmdir(os.path.join(os.getenv("DATAFOLDER"), row[0])) except FileNotFoundError: pass deleted_tokens.append(row[0]) if len(deleted_tokens) > 0: db, c = get_db() for token in deleted_tokens: c.execute( """ DELETE FROM files WHERE token = ? """, (token,), ) db.commit() return def file_age(path): now = datetime.now() then = datetime.fromtimestamp(os.stat(path).st_mtime) diff = now - then return ( diff, "%03d d %s" % (diff.days, datetime.utcfromtimestamp(diff.seconds).strftime("%H:%M:%S")), ) def file_details(token, name): full_path = os.path.join(os.getenv("FLASK_DATAFOLDER"), token, name) try: s = os.stat(full_path) db_stat = db_get_file(token, name) if db_stat: added, expires, downloads, max_dl = db_stat else: return {} return { "size": file_size_MB(s.st_size), "hsize": file_size_human(s.st_size, HTML=False), "added": file_date_human(added), "name": name, "url": f"{app.config['PUBLIC_URL']}/dl/{token}/{name}", "expires": file_date_human(expires), "downloaded": downloads, "max-dl": max_dl, } except FileNotFoundError: return {} def file_list(): files = list(db_get_files()) details = [] maxlen = 4 for file in files: maxlen = max(maxlen, len(file[1])) details = [] details.append( "Added/Expiry DL/MaxDL URL" ) details.append("=" * 75) for file in files: details.append( " ".join(( str(file[2]),str(file[3]),str(file[4]),str(file[5]), f"{app.config['PUBLIC_URL']}/dl/{file[0]}/{file[1]}" )) ) return details def get_expiring_file(ehash): connection = apsw.Connection(app.config["SQLITE_FILE"]) cursor = connection.cursor() for row in cursor.execute( "SELECT file, expires FROM expiring WHERE hash = ?", (ehash,) ): return row[0], row[1] return None, None def get_script_url(public_url, share, end_point, token="[TOKEN]"): cmd = None doc = None if get_or_none("direct_links", share) and end_point == "download": end_point = "direct" url = "%s/script/%s/%s/%s" % (public_url, end_point, share["name"], token) if end_point in ("download", "direct"): cmd = "curl -s %s | bash /dev/stdin [-f]" % (url,) doc = "Download all files in the share. -f to force overwrite existing files." if end_point == "client": cmd = "python <( curl -s %s )" % (url,) doc = "Console client to download and upload files." if end_point == "upload_split": cmd = ( "curl -s %s | python - [-s split_size_in_Mb] file_to_upload.ext [second.file.ext]" % (url,) ) doc = "Upload files to the share. -s to set splitting size." if end_point == "flip": cmd = "curl -s %s > flip && ./flip" % (url,) doc = "Use the share as a command line clipboard" return {"cmd": cmd, "doc": doc} def set_expiring_file(share, filename, expires): connection = apsw.Connection(app.config["SQLITE_FILE"]) cursor = connection.cursor() while True: ehash = random_expiring_hash() matches = len( list(cursor.execute("SELECT file FROM expiring WHERE hash = ?", (ehash,))) ) if matches == 0: break cursor.execute( "INSERT INTO expiring (hash, file, expires) VALUES (?,?,?)", (ehash, filename, expires), ) return "/".join((app.config["PUBLIC_URL"], "e", ehash, os.path.basename(filename))) def remove_expiring_file(share, filename): connection = apsw.Connection(app.config["SQLITE_FILE"]) cursor = connection.cursor() cursor.execute("DELETE FROM expiring WHERE file = ?", (filename,))