diff --git a/pyrobird/src/pyrobird/cli/serve/__init__.py b/pyrobird/src/pyrobird/cli/serve/__init__.py index 2e09854..ab95e07 100644 --- a/pyrobird/src/pyrobird/cli/serve/__init__.py +++ b/pyrobird/src/pyrobird/cli/serve/__init__.py @@ -1,86 +1,21 @@ -import sys -from flask import Flask, render_template, send_from_directory - -# Created by: Dmitry Romanov, 2024 -# This file is part of Firebird Event Display and is licensed under the LGPLv3. -# See the LICENSE file in the project root for full license information. -import yaml -import os -import click -from rich import inspect -import fnmatch -from importlib import resources -from pyrobird.cern_root import ensure_pyroot_importable, tgeo_delete_node, tgeo_process_file - import logging -from importlib import resources -import yaml import click +import pyrobird.server # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) -from flask import Flask, send_file, request, abort - -app = Flask(__name__, static_folder='dist') - - -@app.route('/download/') -def download_file(filename): - # Ensure the path is safe and only files within a certain directory can be accessed - # For example, let's say you store your files in a 'files' directory within the server root - safe_path = filename - base_path = '' - if base_path: - safe_path = os.path.join(base_path, filename) - safe_path = os.path.abspath(safe_path) # Resolve any path traversal attempts - - if not safe_path.startswith(base_path): - # Security check failed - abort(404) - - if os.path.exists(safe_path) and os.path.isfile(safe_path): - return send_file(safe_path, as_attachment=True) - else: - abort(404) - -# Check for the filename argument -if len(sys.argv) < 2: - print("Usage: python app.py ") - sys.exit(1) - -file_path = sys.argv[1] - -@app.route('/') -def index(): - return render_template('index.html', file_path=file_path) - -@app.route('/') -def static_file(path): - return send_from_directory('dist', path) - @click.command() +@click.option("--unsecure-files", "unsecure_files", is_flag=True, show_default=True, default=False, help="Allow unrestricted files download in a system") @click.pass_context -def serve(ctx): +def serve(ctx, unsecure_files): """ Operations with database (create tables, erase everything, etc) """ - app.run(debug=True) - - # # assert isinstance(ctx, click.Context) - # # context = ctx.obj - # # assert isinstance(context, CasdmAppContext) - # # if not context.connection_str: - # # ctx.fail("ERROR(!) Connection string is not set. Needs it to connect to BD") - # # # click.echo(, err=True) - # # # click.echo(ctx.get_help()) - # - # if ctx.invoked_subcommand is None: - # print("No command was specified") - + pyrobird.server.run(debug=True, config={"ALLOW_UNRESTRICTED_DOWNLOAD": unsecure_files}) if __name__ == '__main__': - app.run(debug=True) \ No newline at end of file + pyrobird.server.run(debug=True) \ No newline at end of file diff --git a/pyrobird/src/pyrobird/server/__init__.py b/pyrobird/src/pyrobird/server/__init__.py new file mode 100644 index 0000000..e772411 --- /dev/null +++ b/pyrobird/src/pyrobird/server/__init__.py @@ -0,0 +1,73 @@ +# Created by: Dmitry Romanov, 2024 +# This file is part of Firebird Event Display and is licensed under the LGPLv3. +# See the LICENSE file in the project root for full license information. + +import os +import logging +from csv import excel + +import werkzeug.exceptions +from flask import render_template, send_from_directory, Flask, send_file, abort, Config +from pandas.io.common import file_exists + +# Configure logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +server_dir = os.path.abspath(os.path.dirname(__file__)) +static_dir = os.path.join(server_dir, "static") +app = Flask(__name__, static_folder='static') +app.config.update() + + +@app.route('/download/') +def download_file(filename): + # Ensure the path is safe and only files within a certain directory can be accessed + # For example, let's say you store your files in a 'files' directory within the server root + safe_path = filename + base_path = '' + if base_path: + safe_path = os.path.join(base_path, filename) + safe_path = os.path.abspath(safe_path) # Resolve any path traversal attempts + + if not safe_path.startswith(base_path): + # Security check failed + abort(404) + + if os.path.exists(safe_path) and os.path.isfile(safe_path): + return send_file(safe_path, as_attachment=True) + else: + abort(404) + + +@app.route('/') +def index(): + return static_file("index.html") + + +@app.route('/') +def static_file(path): + + if app.debug: + print("Serve path:") + print(" Server dir :", server_dir) + print(" Static dir :", static_dir) + print(" path :", path) + + try: + return send_from_directory(static_dir, path) + except werkzeug.exceptions.NotFound as ex: + if app.debug: + print("File is not found, assuming it is SPA and serving index.html") + return send_from_directory(static_dir, "index.html") + + +def run(config=None, host=None, port=None, debug=True, load_dotenv=True): + if config: + if isinstance(config, Config) or isinstance(config, map): + app.config.from_mapping(config) + else: + app.config.from_object(config) + + app.run(host=host, port=port, debug=debug, load_dotenv=load_dotenv) diff --git a/pyrobird/src/pyrobird/server/static/.gitignore b/pyrobird/src/pyrobird/server/static/.gitignore new file mode 100644 index 0000000..6ce5ebc --- /dev/null +++ b/pyrobird/src/pyrobird/server/static/.gitignore @@ -0,0 +1,3 @@ +# It is assumed that static content is copied here from frontend build +# Thus we ignore everything in this folder +* \ No newline at end of file