diff --git a/etc/nginx/sites-available/sample-onion-fileshare.conf b/etc/nginx/sites-available/sample-onion-fileshare.conf new file mode 100755 index 00000000..4794a12d --- /dev/null +++ b/etc/nginx/sites-available/sample-onion-fileshare.conf @@ -0,0 +1,11 @@ +server { + listen TARGET; + server_name ONION_HOSTNAME; + + access_log /var/log/nginx/access_SERVICE.log; + error_log /var/log/nginx/error_SERVICE.log; + + location / { + proxy_pass http://unix:/var/run/tfs_SERVICE.sock; + } +} diff --git a/lib/fileshare/README.md b/lib/fileshare/README.md new file mode 100644 index 00000000..72ca1f7c --- /dev/null +++ b/lib/fileshare/README.md @@ -0,0 +1,69 @@ +# TorBox FileSharing +A web-client used to share files in the TorBox Project. + +## Installation +###### Note: Instructions are exclusive for TorBox Project. + +### Requirements +**TFS** was developed using Python 3.9, so it is recommended to use this version or higher. + +Dependencies: +- Flask +- Flask_compress +- Flask_CORS +- click + +To install dependencies, run + +```sudo pip install -r requirements.txt``` + +## Usage +To allow download and upload to one of your directories, simply run + +```./tfs -fp /path/to/shared/dir``` + +For more options see + +``` +Usage: tfs [OPTIONS] + +Options: + -n, --name TEXT Onion Service Name + -od, --onion-domain TEXT Onion domain where TFS will be published + -fp, --file-path TEXT Path to share + --dev BOOLEAN Run in development mode (Default: 0) + --help Show this message and exit. + +``` + +### Manage permissions + +Permissions are managed by a file inside the shared directory called `.access` +which must contain a list of subdirectories of the shared directory and their +permissions, separated by a semicolon, in the following format: + +``` +/path/to/directory;rw +/path/to/another/directory;r +``` + +Where: + +- `r` stands for read-only (can download files) +- `w` stands for write (can upload files +- `x` stands for excecute (can list files) +- `rw` stands for read and write (can upload and download files) +- `rx` stands for read and execute (can list and download files) + +By default, all directories are set to `rx` permissions. + +Permissions will make the directory appear in the web-client, and will allow +users to download and upload files to it. + +## Development + +To run TFS in development mode, simply run + +```./tfs -n test -od test -fp /path/to/directory --dev 1``` + + diff --git a/lib/fileshare/main.py b/lib/fileshare/main.py index 97d43776..c478dc9b 100644 --- a/lib/fileshare/main.py +++ b/lib/fileshare/main.py @@ -15,11 +15,11 @@ ONION_DOMAIN = os.environ.get('ONION_DOMAIN') DOWNLOADS_PATH = os.environ.get('MEDIA_ROOT') -BASE_PATH = Path(os.path.dirname(os.path.abspath(__file__))) +BASE_DIR = Path(os.path.dirname(os.path.abspath(__file__))) app = Flask( __name__, static_url_path='/assets', - static_folder=BASE_PATH / "webclient/dist/assets/" + static_folder=BASE_DIR / "webclient/dist/assets" ) CORS(app, origins=ONION_DOMAIN) Compress(app) @@ -140,7 +140,7 @@ def download_folder(): # webclient index.html located in webclient/dist @app.route('/') def index(): - return send_from_directory(BASE_PATH / "webclient/dist", 'index.html') + return send_from_directory(BASE_DIR / "webclient/dist", 'index.html') def main(): diff --git a/lib/fileshare/requirements.txt b/lib/fileshare/requirements.txt index d48ada2c..fc1c11b8 100644 --- a/lib/fileshare/requirements.txt +++ b/lib/fileshare/requirements.txt @@ -1,13 +1,5 @@ -blinker==1.7.0 -Brotli==1.1.0 click==8.1.7 Flask==3.0.0 Flask-Compress==1.14 Flask-Cors==4.0.0 -importlib-metadata==6.9.0 -itsdangerous==2.1.2 -Jinja2==3.1.2 -MarkupSafe==2.1.3 -Werkzeug==3.0.1 -zipp==3.17.0 diff --git a/lib/fileshare/tfs b/lib/fileshare/tfs index 6165fbf9..bcca4c9c 100755 --- a/lib/fileshare/tfs +++ b/lib/fileshare/tfs @@ -65,21 +65,51 @@ def main(name, onion_domain, file_path, dev): def run_webserver(instance_name, dev=True): + from main import app, BASE_DIR if dev: # Dev - from main import main as dev_main - - dev_main() - + app.run(debug=True) quit() else: - # TODO: Production: run flask for production - - # Remove pid file - try: - os.remove(settings.BASE_DIR / f"pid/{instance_name}.pid") - except: - pass + import atexit + from gunicorn.app.base import BaseApplication + + def stop_webserver(): + # Remove pid file in case it exists + try: + os.remove(BASE_DIR / f"pid/{instance_name}.pid") + except: # noqa + pass + + quit() + + class TFSApp(BaseApplication): + def load_config(self): + self.cfg.set("bind", f"unix:/tmp/tfs_{instance_name}.sock") + self.cfg.set("workers", 2) + self.cfg.set("loglevel", "error") + # self.cfg.set("loglevel", "debug") # dev + # self.cfg.set("bind", f"0.0.0.0:8888") # dev + + def load(self): + return app + + def run(self): + pid = os.getpid() + pid_file = BASE_DIR / f"pid/{instance_name}.pid" + with open(pid_file, "w") as f: + f.write(str(pid)) + atexit.register(stop_webserver) + + super().run() + + # Remove pid file + try: + os.remove(BASE_DIR / f"pid/{instance_name}.pid") + except: # noqa + pass + + TFSApp(app).run() if __name__ == "__main__":