diff --git a/intelmq/app/server.py b/intelmq/app/server.py index 1c46f2505..34cec9679 100644 --- a/intelmq/app/server.py +++ b/intelmq/app/server.py @@ -5,8 +5,10 @@ """ import os +import pathlib from fastapi import FastAPI +from fastapi.staticfiles import StaticFiles from fastapi.middleware.cors import CORSMiddleware from intelmq.version import __version__ @@ -15,6 +17,7 @@ from intelmq.app.config import config from intelmq.app.api.router import router as api_router +from intelmq.app.webgui.router import router as web_router app = FastAPI( title="IntelMQ", @@ -32,4 +35,9 @@ def init_app(): app.include_router(api_router, prefix="/api/v1") +if config.enable_webgui: + static_files = pathlib.Path(__file__).parent / "webgui" / "static" + app.mount("/static", StaticFiles(directory=static_files), name="static") + app.include_router(web_router) + intelmq.app.api.exceptions.register(app) diff --git a/intelmq/app/webgui/__init__.py b/intelmq/app/webgui/__init__.py index f1e51caf6..e69de29bb 100644 --- a/intelmq/app/webgui/__init__.py +++ b/intelmq/app/webgui/__init__.py @@ -1,10 +0,0 @@ -"""Python __init__ file that provides the path to the module - -SPDX-FileCopyrightText: 2020 IntelMQ Team -SPDX-License-Identifier: AGPL-3.0-or-later - -""" -import pathlib -from .version import __version__, __version_info__ # noqa - -path = pathlib.Path(__file__).parent diff --git a/intelmq/app/webgui/build.py b/intelmq/app/webgui/build.py deleted file mode 100644 index 04e15c2fb..000000000 --- a/intelmq/app/webgui/build.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Build statically rendered files. - -SPDX-FileCopyrightText: 2021 Birger Schacht , Mikk Margus Möll , Sebastian Wagner -SPDX-License-Identifier: AGPL-3.0-or-later -""" -import argparse -import pathlib -import shutil -from mako.lookup import TemplateLookup - - -def render_page(pagename: str, **template_args) -> str: - template_dir = pathlib.Path(__file__).parent / 'templates' - template_lookup = TemplateLookup(directories=[template_dir], default_filters=["h"], input_encoding='utf8') - template = template_lookup.get_template(f'{pagename}.mako') - - return template.render(pagename=pagename, **template_args) - - -def buildhtml(outputdir: pathlib.Path = pathlib.Path('html')): - outputdir.mkdir(parents=True, exist_ok=True) - - htmlfiles = ["configs", "management", "monitor", "check", "about", "index"] - for filename in htmlfiles: - print(f"Rendering {filename}.html") - html = render_page(filename) - outputdir.joinpath(f"{filename}.html").write_text(html) - - staticfiles = ["css", "images", "js", "plugins", "less"] - for filename in staticfiles: - print(f"Copying {filename} recursively") - src = pathlib.Path(__file__).parent / 'static' / filename - dst = outputdir / filename - if dst.exists(): - shutil.rmtree(dst) - shutil.copytree(src, dst) - - print('rendering dynvar.js') - rendered = render_page('dynvar', allowed_path='/opt/intelmq/var/lib/bots/', controller_cmd='intelmq') - outputdir.joinpath('js/dynvar.js').write_text(rendered) - - -def main(): - parser = argparse.ArgumentParser( - prog='intelmq-manager-build', - description='Build statically rendered files for intelmq-manager.', - epilog='This command renders and saves all files required for IntelMQ Manager at the given directory, which can be served by Webservers statically', - formatter_class=argparse.RawDescriptionHelpFormatter, - ) - - parser.add_argument('--output-dir', '-o', default='html', - type=pathlib.Path, - help='The destination directory, will be created if needed.') - args = parser.parse_args() - buildhtml(outputdir=args.output_dir) - - -if __name__ == '__main__': - main() diff --git a/intelmq/app/webgui/router.py b/intelmq/app/webgui/router.py new file mode 100644 index 000000000..add8c4d14 --- /dev/null +++ b/intelmq/app/webgui/router.py @@ -0,0 +1,101 @@ +# SPDX-FileCopyrightText: 2023 IntelMQ Team +# SPDX-License-Identifier: AGPL-3.0-or-later + +import collections +import pathlib + +from fastapi import APIRouter, Request +from fastapi.responses import HTMLResponse +from fastapi.templating import Jinja2Templates + +from intelmq.app.config import config + +SHOW_LOGIN = True if config.session_store else False + +router = APIRouter(default_response_class=HTMLResponse) +templates_dir = pathlib.Path(__file__).parent / "templates" +templates = Jinja2Templates(directory=templates_dir) +Page = collections.namedtuple("Page", ["name", "title", "url", "icon_url"]) + + +def get_pages(request: Request): + return [ + Page( + name="configs", + title="Configuration", + url=request.url_for('get_configuration'), + icon_url=request.url_for('static', path='images/configuration.png'), + ), + Page( + name="management", + title="Management", + url=request.url_for('get_management'), + icon_url=request.url_for('static', path='images/management.png'), + ), + Page( + name="monitor", + title="Monitor", + url=request.url_for('get_monitor'), + icon_url=request.url_for('static', path='images/monitor.png'), + ), + Page( + name="check", + title="Check", + url=request.url_for('get_check'), + icon_url=request.url_for('static', path='images/check.png'), + ), + Page( + name="about", + title="About", + url=request.url_for('get_about'), + icon_url=request.url_for('static', path='images/about.png'), + ) + ] + + +@router.get("/", include_in_schema=False) +async def get_index(request: Request): + return templates.TemplateResponse("index.html", { + "request": request, + "pages": get_pages(request) + }) + + +@router.get("/configuration", include_in_schema=False) +async def get_configuration(request: Request): + return templates.TemplateResponse("configuration.html", { + "request": request, + "pages": get_pages(request) + }) + + +@router.get("/management", include_in_schema=False) +def get_management(request: Request): + return templates.TemplateResponse("management.html", { + "request": request, + "pages": get_pages(request) + }) + + +@router.get("/monitor", include_in_schema=False) +def get_monitor(request: Request): + return templates.TemplateResponse("monitor.html", { + "request": request, + "pages": get_pages(request) + }) + + +@router.get("/check", include_in_schema=False) +def get_check(request: Request): + return templates.TemplateResponse("check.html", { + "request": request, + "pages": get_pages(request) + }) + + +@router.get("/about", include_in_schema=False) +def get_about(request: Request): + return templates.TemplateResponse("about.html", { + "request": request, + "pages": get_pages(request) + }) diff --git a/intelmq/app/webgui/static/images/config.png b/intelmq/app/webgui/static/images/configuration.png similarity index 100% rename from intelmq/app/webgui/static/images/config.png rename to intelmq/app/webgui/static/images/configuration.png diff --git a/intelmq/app/webgui/static/images/botnet.png b/intelmq/app/webgui/static/images/management.png similarity index 100% rename from intelmq/app/webgui/static/images/botnet.png rename to intelmq/app/webgui/static/images/management.png diff --git a/intelmq/app/webgui/static/js/about.js b/intelmq/app/webgui/static/js/about.js index c18470de5..13b36b466 100644 --- a/intelmq/app/webgui/static/js/about.js +++ b/intelmq/app/webgui/static/js/about.js @@ -5,14 +5,10 @@ function get_versions() { let intelmq_version_element = document.getElementById('intelmq-version'); - let intelmq_api_version_element = document.getElementById('intelmq-api-version'); - let intelmq_manager_version_element = document.getElementById('intelmq-manager-version'); authenticatedGetJson(managementUrl('version')) .done(function (data) { intelmq_version_element.innerHTML = data.intelmq; - intelmq_api_version_element.innerHTML = data['intelmq-api']; - intelmq_manager_version_element.innerHTML = '3.2.0'; }) .fail(function (jqxhr, textStatus, error) { let err = `${textStatus}, ${error}`; diff --git a/intelmq/app/webgui/static/js/configs.js b/intelmq/app/webgui/static/js/configs.js index 8dd3b1ea3..aa744dca5 100644 --- a/intelmq/app/webgui/static/js/configs.js +++ b/intelmq/app/webgui/static/js/configs.js @@ -30,7 +30,7 @@ var documentation = null; var span = null; var table = null; var disabledKeys = ['group', 'name', 'module']; -var $manipulation, $saveButton; // jQuery of Vis control panel; elements reseted with network +var $manipulation, $saveButton; // jQuery of Vis control panel; elements reset with network var node = null; var $EDIT_DEFAULT_BUTTON = $("#editDefaults"); @@ -544,7 +544,7 @@ function saveData(data, callback) { saveFormData(); - // check inputs beeing valid + // check inputs being valid if (node.bot_id === '' && node.group === '') { show_error('fields id and group must not be empty!'); return; @@ -740,7 +740,7 @@ function draw() { initNetwork(); if (window.location.hash) { let node = window.location.hash.substr(1); - setTimeout(() => { // doesnt work immediately, I don't know why. Maybe a js guru would bind to visjs onready if that exists or sth. + setTimeout(() => { // doesn't work immediately, I don't know why. Maybe a js guru would bind to visjs onready if that exists or sth. try { fitNode(node); } catch (e) { diff --git a/intelmq/app/webgui/static/js/intelmq-manager.js b/intelmq/app/webgui/static/js/intelmq-manager.js deleted file mode 100644 index b9b952ca3..000000000 --- a/intelmq/app/webgui/static/js/intelmq-manager.js +++ /dev/null @@ -1,29 +0,0 @@ -/* intelmq-manager.js javascript file for intelmq-manager - * - * SPDX-FileCopyrightText: 2020 IntelMQ Team - * SPDX-License-Identifier: AGPL-3.0-or-later - * - * Do not change this file! If you want to customize the settings, - * create a 'var.js' file and define the custom settings there with - * var VARIABLENAME = value - */ - -/* - * ROOT points to the URI of the API service. - * Set this for example to `https://intelmq.organization.tld/` - * By default ROOT points to the host the manager runs on, but the path '/intelmq' - */ -'use strict'; - -var arr = window.location.href.split('/'); -var ROOT = ROOT ?? `${arr[0]}//${arr[2]}/intelmq`; - -/* - * If there are multiple versions of the API, they can be defined here - */ -var API_V1 = ROOT + '/v1/api/' - -/* - * use a specific version when accessing the API variable - */ -var API = API_V1 diff --git a/intelmq/app/webgui/static/js/static.js b/intelmq/app/webgui/static/js/static.js index 4fc6c8e7c..432bf772b 100644 --- a/intelmq/app/webgui/static/js/static.js +++ b/intelmq/app/webgui/static/js/static.js @@ -76,7 +76,7 @@ var LOAD_X_LOG_LINES = 30; var MESSAGE_LENGTH = 200; -var MONITOR_BOT_URL = "monitor.html?bot_id={0}"; +var MONITOR_BOT_URL = "monitor?bot_id={0}"; var page_is_exiting = false; diff --git a/intelmq/app/webgui/templates/about.mako b/intelmq/app/webgui/templates/about.html similarity index 90% rename from intelmq/app/webgui/templates/about.mako rename to intelmq/app/webgui/templates/about.html index 242610d37..bb52ce3a6 100644 --- a/intelmq/app/webgui/templates/about.mako +++ b/intelmq/app/webgui/templates/about.html @@ -1,8 +1,11 @@ -## SPDX-FileCopyrightText: 2020 IntelMQ Team -## SPDX-License-Identifier: AGPL-3.0-or-later +{#SPDX-FileCopyrightText: 2020 IntelMQ Team #} +{#SPDX-License-Identifier: AGPL-3.0-or-later#} -<%inherit file="base.mako" /> +{% extends "base.html" %} +{% block title %}About{% endblock %} + +{% block content %}
@@ -51,8 +54,6 @@

Version

- -
IntelMQ
IntelMQ API
IntelMQ Manager
@@ -63,3 +64,8 @@

Debugging

+{% endblock %} + +{% block javascript %} + +{% endblock %} diff --git a/intelmq/app/webgui/templates/base.html b/intelmq/app/webgui/templates/base.html new file mode 100644 index 000000000..3a2eeea5f --- /dev/null +++ b/intelmq/app/webgui/templates/base.html @@ -0,0 +1,162 @@ +{#SPDX-FileCopyrightText: 2020 IntelMQ Team #} +{#SPDX-License-Identifier: AGPL-3.0-or-later#} + + + + + + + + + + + + IntelMQ - {% block title %}{% endblock %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + +
+ {% block content %} + {% endblock %} +
+ + + + + + + + + + + + + + + + {% block javascript %} + {% endblock %} + +
+
+ + + + + +
+
+ + + \ No newline at end of file diff --git a/intelmq/app/webgui/templates/base.mako b/intelmq/app/webgui/templates/base.mako deleted file mode 100644 index a36aff559..000000000 --- a/intelmq/app/webgui/templates/base.mako +++ /dev/null @@ -1,181 +0,0 @@ -## SPDX-FileCopyrightText: 2020 IntelMQ Team -## SPDX-License-Identifier: AGPL-3.0-or-later - -<%! - import collections - - Page = collections.namedtuple("Page", ["name", "title", "icon", "libraries"]) - pages = [Page("configs", "Configuration", "config.png", - ["plugins/vis.js/vis.js", - "js/runtime.js", - "js/positions.js", - "js/defaults.js", - "js/network-configuration.js", - "js/configs.js", - ]), - Page("management", "Management", "botnet.png", - ["js/runtime.js", "js/management.js"]), - Page("monitor", "Monitor", "monitor.png", - ["js/runtime.js", - "js/defaults.js", - "js/monitor.js"]), - Page("check", "Check", "check.png", ["js/check.js"]), - Page("about", "About", "about.png", ["js/about.js"])] - - common_libraries = [ - "js/dynvar.js", - "js/var.js", - "js/intelmq-manager.js", - "js/static.js", - "js/sb-admin-2.js", - ## XX this don't have to be on every page: - "plugins/dataTables/jquery.dataTables.js", - "plugins/dataTables/dataTables.bootstrap.js", - ] - - page_map = {page.name: page for page in pages} - page_map["index"] = Page("index", "", "", []) -%> - - - - - - - - - - - - - IntelMQ Manager - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - ${next.body()} - - - - - - - - - - - % for lib in common_libraries + page_map[pagename].libraries: - - % endfor - ?> - -
-
-
- - - - - -
-
- - diff --git a/intelmq/app/webgui/templates/check.mako b/intelmq/app/webgui/templates/check.html similarity index 66% rename from intelmq/app/webgui/templates/check.mako rename to intelmq/app/webgui/templates/check.html index 0d027e177..8e49226aa 100644 --- a/intelmq/app/webgui/templates/check.mako +++ b/intelmq/app/webgui/templates/check.html @@ -1,8 +1,11 @@ -## SPDX-FileCopyrightText: 2020 IntelMQ Team -## SPDX-License-Identifier: AGPL-3.0-or-later +{#SPDX-FileCopyrightText: 2020 IntelMQ Team #} +{#SPDX-License-Identifier: AGPL-3.0-or-later#} -<%inherit file="base.mako" /> +{% extends "base.html" %} +{% block title %}Check{% endblock %} + +{% block content %}
@@ -22,3 +25,8 @@

Check output

+{% endblock %} + +{% block javascript %} + +{% endblock %} \ No newline at end of file diff --git a/intelmq/app/webgui/templates/configs.mako b/intelmq/app/webgui/templates/configuration.html similarity index 87% rename from intelmq/app/webgui/templates/configs.mako rename to intelmq/app/webgui/templates/configuration.html index 61e0c4e80..cc057d0ab 100644 --- a/intelmq/app/webgui/templates/configs.mako +++ b/intelmq/app/webgui/templates/configuration.html @@ -1,8 +1,11 @@ -## SPDX-FileCopyrightText: 2020 IntelMQ Team -## SPDX-License-Identifier: AGPL-3.0-or-later +{#SPDX-FileCopyrightText: 2020 IntelMQ Team #} +{#SPDX-License-Identifier: AGPL-3.0-or-later#} -<%inherit file="base.mako" /> +{% extends "base.html" %} +{% block title %}Configuration{% endblock %} + +{% block content %} +{% endblock %} + +{% block javascript %} + + + + + + +{% endblock %} \ No newline at end of file diff --git a/intelmq/app/webgui/templates/dynvar.mako b/intelmq/app/webgui/templates/dynvar.mako deleted file mode 100644 index cb4f692c1..000000000 --- a/intelmq/app/webgui/templates/dynvar.mako +++ /dev/null @@ -1,5 +0,0 @@ -## SPDX-FileCopyrightText: 2021 Mikk Margus Möll -## SPDX-License-Identifier: AGPL-3.0-or-later - -var ALLOWED_PATH = "${allowed_path}"; -var CONTROLLER_CMD = "${controller_cmd}"; diff --git a/intelmq/app/webgui/templates/index.mako b/intelmq/app/webgui/templates/index.html similarity index 67% rename from intelmq/app/webgui/templates/index.mako rename to intelmq/app/webgui/templates/index.html index 91d8ebc0a..d46c5b0a8 100644 --- a/intelmq/app/webgui/templates/index.mako +++ b/intelmq/app/webgui/templates/index.html @@ -1,17 +1,19 @@ -## SPDX-FileCopyrightText: 2020 IntelMQ Team -## SPDX-License-Identifier: AGPL-3.0-or-later +{#SPDX-FileCopyrightText: 2020 IntelMQ Team #} +{#SPDX-License-Identifier: AGPL-3.0-or-later#} -<%inherit file="base.mako" /> +{% extends "base.html" %} +{% block title %}Home{% endblock %} +{% block content %}
- Logo - IntelMQ Manager + Logo + IntelMQ
@@ -20,9 +22,9 @@
- +
- +

Configuration

To either change the currently deployed configuration or to create a new one in a graphical fashion.

@@ -32,9 +34,9 @@

Configuration

- +
- +

Management

This is where you go to start/stop your bots or check on their status.

@@ -44,9 +46,9 @@

Management

- +
- +

Monitor

This feature is meant to allow you to check on the overall status of your botnet. You can read the bot logs, see how the queues are behaving and other features that allow you to have a better overview of the overall health of the system.

@@ -60,9 +62,9 @@

Monitor

- +
- +

Check

Check IntelMQ is running properly.

@@ -72,9 +74,9 @@

Check

- +
- +

About

To learn more about the project's goals and contributors.

@@ -88,3 +90,5 @@

About

+{% endblock %} + diff --git a/intelmq/app/webgui/templates/management.mako b/intelmq/app/webgui/templates/management.html similarity index 89% rename from intelmq/app/webgui/templates/management.mako rename to intelmq/app/webgui/templates/management.html index 3830ad8ce..33f9d0e33 100644 --- a/intelmq/app/webgui/templates/management.mako +++ b/intelmq/app/webgui/templates/management.html @@ -1,9 +1,11 @@ -## SPDX-FileCopyrightText: 2020 IntelMQ Team -## SPDX-License-Identifier: AGPL-3.0-or-later +{#SPDX-FileCopyrightText: 2020 IntelMQ Team #} +{#SPDX-License-Identifier: AGPL-3.0-or-later#} -<%inherit file="base.mako" /> +{% extends "base.html" %} - +{% block title %}Management{% endblock %} + +{% block content %}
@@ -74,3 +76,9 @@

Individual Bot Status:

+{% endblock %} + +{% block javascript %} + + +{% endblock %} diff --git a/intelmq/app/webgui/templates/monitor.mako b/intelmq/app/webgui/templates/monitor.html similarity index 92% rename from intelmq/app/webgui/templates/monitor.mako rename to intelmq/app/webgui/templates/monitor.html index 06ca50208..69f4ec87d 100644 --- a/intelmq/app/webgui/templates/monitor.mako +++ b/intelmq/app/webgui/templates/monitor.html @@ -1,8 +1,11 @@ -## SPDX-FileCopyrightText: 2020 IntelMQ Team -## SPDX-License-Identifier: AGPL-3.0-or-later +{#SPDX-FileCopyrightText: 2020 IntelMQ Team #} +{#SPDX-License-Identifier: AGPL-3.0-or-later#} -<%inherit file="base.mako" /> +{% extends "base.html" %} +{% block title %}Monitor{% endblock %} + +{% block content %}
+{% endblock %} + +{% block javascript %} + + + +{% endblock %} + diff --git a/intelmq/app/webgui/version.py b/intelmq/app/webgui/version.py deleted file mode 100644 index d0f244d03..000000000 --- a/intelmq/app/webgui/version.py +++ /dev/null @@ -1,7 +0,0 @@ -""" Version file for intelmq-manager - -SPDX-FileCopyrightText: 2020-2021 Intelmq Team , 2022-2023 Intevation GmbH -SPDX-License-Identifier: AGPL-3.0-or-later -""" -__version_info__ = (3, 2, 0) -__version__ = '.'.join(map(str, __version_info__))