Skip to content

Commit 3bfb754

Browse files
committed
Merges API and Manager to IntelMQ project.
1 parent d14611c commit 3bfb754

File tree

167 files changed

+102325
-22
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

167 files changed

+102325
-22
lines changed

.github/workflows/codespell.yml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,13 @@ on:
1818
jobs:
1919
codespell:
2020
name: Find and notify about common misspellings
21-
runs-on: ubuntu-20.04
21+
runs-on: ubuntu-latest
2222
# This should not fail the whole workflow run
2323
continue-on-error: true
2424

2525
steps:
26-
- name: Checkout repository
27-
uses: actions/checkout@v3
28-
- name: Install codespell
29-
run: pip install "codespell==2.2.4"
30-
- name: Run codespell
31-
run: /home/runner/.local/bin/codespell
26+
- name: "Checkout repository"
27+
uses: actions/checkout@v3
28+
29+
- name: "Check codespell"
30+
uses: codespell-project/actions-codespell@v2

.github/workflows/unittests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ jobs:
6262
run: bash .github/workflows/scripts/setup-full.sh
6363

6464
- name: Install test dependencies
65-
run: pip install pytest-cov Cerberus requests_mock coverage
65+
run: pip install pytest-cov Cerberus requests_mock coverage httpx pycodestyle
6666

6767
- name: Install dependencies
6868
if: ${{ matrix.type == 'basic' }}

contrib/malware_name_mapping/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Additional optional rules
2525

2626
### Malpedia rules
2727

28-
The rules imported from Malpedia can be used optionally with the flag `--include-malpedia`. Note, that this data is CC BY-NC-SA 3.0 and not CC0, so any comercial usage, including usage in commercial organizations, is not allowed.
28+
The rules imported from Malpedia can be used optionally with the flag `--include-malpedia`. Note, that this data is CC BY-NC-SA 3.0 and not CC0, so any commercial usage, including usage in commercial organizations, is not allowed.
2929

3030
### MISP galaxy rules
3131

debian/changelog

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,6 @@ intelmq (1.0.0~dev4~alpha2) UNRELEASED; urgency=low
451451
intelmq (1.0.0~dev4~alpha1) UNRELEASED; urgency=low
452452

453453
* source package automatically created by stdeb 0.8.5,
454-
with a bunch of manual tweeking.
454+
with a bunch of manual tweaking.
455455

456456
-- Sascha Wilde <[email protected]> Wed, 23 Mar 2016 18:44:26 +0000

docs/overview.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ intelmq-mailgen](https://github.com/Intevation/intelmq-mailgen)
9292

9393
A web application helping CERTs to enable members of their constituency to self-administrate how they get warnings related to their network objects (IP addresses, IP ranges, autonomous systems, domains). *tuency* is developed by [Intevation](https://intevation.de/) for [CERT.at](https://cert.at).
9494

95-
If features organizational hierarchies, contact roles, self-administration and network objects per organization (Autonomous systems, network ranges, (sub)domains, RIPE organization handles). A network object claiming and approval process prevents abuse. An hierarchical rule-system on the network objects allow fine-grained settings. The tagging system for contacts and organization complement the contact-management features of the portal. Authentication is based on keycloak, which enables the re-use of the user accounts in the portal. The integrated API enables IntelMQ to query the portal for the right abuse contact and notification settings with the `intelmq.bots.experts.tuency.expert` expert bot.
95+
If features organizational hierarchies, contact roles, self-administration and network objects per organization (Autonomous systems, network ranges, (sub)domains, RIPE organization handles). A network object claiming and approval process prevents abuse. An hierarchical rule-system on the network objects allow fine-grained settings. The tagging system for contacts and organization complement the contact-management features of the portal. Authentication is based on keycloak, which enables the reuse of the user accounts in the portal. The integrated API enables IntelMQ to query the portal for the right abuse contact and notification settings with the `intelmq.bots.experts.tuency.expert` expert bot.
9696

9797
![Tuency Netobjects Overview](https://gitlab.com/intevation/tuency/tuency/-/raw/64b95ec0/docs/images/netobjects.png)
9898

intelmq/__main__.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import argparse
2+
import getpass
3+
import sys
4+
5+
import uvicorn
6+
7+
from intelmq.api.config import Config
8+
from intelmq.api.session import SessionStore
9+
from intelmq.lib import utils
10+
11+
12+
def server_start(host: str = None, port: int = None, debug: bool = False, *args, **kwargs):
13+
server_settings = utils.get_server_settings()
14+
host = host if host is not None else server_settings.get("host", "0.0.0.0")
15+
port = int(port) if port is not None else int(server_settings.get("port", 8080))
16+
17+
return uvicorn.run(
18+
"intelmq.server:app",
19+
host=host,
20+
reload=debug,
21+
port=port,
22+
workers=1,
23+
)
24+
25+
26+
def server_adduser(username: str, password: str = None, *args, **kwargs):
27+
api_config: Config = Config()
28+
29+
if api_config.session_store is None:
30+
print("Could not add user- no session store configured in configuration!", file=sys.stderr)
31+
exit(1)
32+
33+
session_store = SessionStore(str(api_config.session_store), api_config.session_duration)
34+
password = getpass.getpass() if password is None else password
35+
session_store.add_user(username, password)
36+
print(f"Added user {username} to intelmq session file.")
37+
38+
39+
def main():
40+
parser = argparse.ArgumentParser(prog="intelmq", usage="intelmq [OPTIONS] COMMAND")
41+
parser.set_defaults(func=(lambda *_, **__: parser.print_help())) # wrapper to accept args and kwargs
42+
parser._optionals.title = "Options"
43+
parser.add_argument("--version", action="store_true", help="print version and exit", default=None)
44+
commands = parser.add_subparsers(metavar="", title="Commands")
45+
46+
# intelmq server
47+
srv_parser = commands.add_parser("server", help="server subcommands", usage="intelmq server [COMMAND]")
48+
srv_parser.set_defaults(func=(lambda *_, **__: srv_parser.print_help())) # wrapper to accept args and kwargs
49+
srv_parser._optionals.title = "Options"
50+
srv_subcommands = srv_parser.add_subparsers(metavar="", title="Commands")
51+
52+
# intelmq server start
53+
srv_start = srv_subcommands.add_parser("start", help="start the server", usage="intelmq server start [OPTIONS]")
54+
srv_start.set_defaults(func=server_start)
55+
srv_start._optionals.title = "Options"
56+
srv_start.add_argument("--debug", action="store_true", dest="debug", default=None)
57+
srv_start.add_argument("--host", type=str, dest="host")
58+
srv_start.add_argument("--port", type=int, dest="port")
59+
60+
# intelmq server adduser
61+
srv_adduser = srv_subcommands.add_parser("adduser", help="adds new user", usage="intelmq server adduser [OPTIONS]")
62+
srv_adduser.set_defaults(func=server_adduser)
63+
srv_adduser._optionals.title = "Options"
64+
srv_adduser.add_argument('--username', required=True, help='The username of the account.', type=str)
65+
srv_adduser.add_argument('--password', required=False, help='The password of the account.', type=str)
66+
67+
args = parser.parse_args()
68+
return args.func(**vars(args))
69+
70+
71+
if __name__ == "__main__":
72+
main()

intelmq/api/__init__.py

Whitespace-only changes.

intelmq/api/config.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"""Configuration for IntelMQ Manager
2+
3+
SPDX-FileCopyrightText: 2020 Intevation GmbH <https://intevation.de>
4+
SPDX-License-Identifier: AGPL-3.0-or-later
5+
6+
Funding: of initial version by SUNET
7+
Author(s):
8+
* Bernhard Herzog <[email protected]>
9+
"""
10+
11+
from typing import List, Optional
12+
from pathlib import Path
13+
from intelmq.lib import utils
14+
15+
16+
class Config:
17+
18+
"""Configuration settings for IntelMQ Manager"""
19+
20+
intelmq_ctl_cmd: List[str] = ["sudo", "-u", "intelmq", "/usr/local/bin/intelmqctl"]
21+
22+
allowed_path: Path = Path("/opt/intelmq/var/lib/bots/")
23+
24+
session_store: Optional[Path] = None
25+
26+
session_duration: int = 24 * 3600
27+
28+
allow_origins: List[str] = ['*']
29+
30+
enable_webgui: bool = True
31+
32+
host: str = "0.0.0.0"
33+
34+
port: int = 8080
35+
36+
def __init__(self):
37+
server_settings = utils.get_server_settings()
38+
39+
if "intelmq_ctl_cmd" in server_settings:
40+
self.intelmq_ctl_cmd = server_settings["intelmq_ctl_cmd"]
41+
42+
if "allowed_path" in server_settings:
43+
self.allowed_path = Path(server_settings["allowed_path"])
44+
45+
if "session_store" in server_settings:
46+
self.session_store = Path(server_settings["session_store"])
47+
48+
if "session_duration" in server_settings:
49+
self.session_duration = int(server_settings["session_duration"])
50+
51+
if "allow_origins" in server_settings:
52+
self.allow_origins = server_settings['allow_origins']
53+
54+
if "enable_webgui" in server_settings:
55+
self.enable_webgui = server_settings["enable_webgui"]
56+
57+
if "host" in server_settings:
58+
self.host = server_settings["host"]
59+
60+
if "port" in server_settings:
61+
self.host = server_settings["port"]

intelmq/api/dependencies.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"""Dependencies of the API endpoints, in the FastAPI style
2+
3+
SPDX-FileCopyrightText: 2022 CERT.at GmbH <https://cert.at>
4+
SPDX-License-Identifier: AGPL-3.0-or-later
5+
"""
6+
7+
import typing
8+
from typing import Generic, Optional, TypeVar
9+
10+
from fastapi import Depends, Header, HTTPException, Response, status
11+
12+
import intelmq.api.config
13+
import intelmq.api.session as session
14+
15+
T = TypeVar("T")
16+
17+
18+
class OneTimeDependency(Generic[T]):
19+
"""Allows one-time explicit initialization of the dependency,
20+
and then returning it on every usage.
21+
22+
It emulates the previous behavior that used global variables"""
23+
24+
def __init__(self) -> None:
25+
self._value: Optional[T] = None
26+
27+
def initialize(self, value: T) -> None:
28+
self._value = value
29+
30+
def __call__(self) -> Optional[T]:
31+
return self._value
32+
33+
34+
api_config = OneTimeDependency[intelmq.api.config.Config]()
35+
session_store = OneTimeDependency[session.SessionStore]()
36+
37+
38+
def cached_response(max_age: int):
39+
"""Adds the cache headers to the response"""
40+
def _cached_response(response: Response):
41+
response.headers["cache-control"] = f"max-age={max_age}"
42+
return _cached_response
43+
44+
45+
def token_authorization(authorization: typing.Union[str, None] = Header(default=None),
46+
session: session.SessionStore = Depends(session_store)):
47+
if session is not None:
48+
if not authorization or not session.verify_token(authorization):
49+
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail={
50+
"Authentication Required":
51+
"Please provide valid Token verification credentials"
52+
})
53+
54+
55+
def startup(config: intelmq.api.config.Config):
56+
"""A starting point to one-time initialization of necessary dependencies. This needs to
57+
be called by the application on the startup."""
58+
api_config.initialize(config)
59+
session_file = config.session_store
60+
if session_file is not None:
61+
session_store.initialize(session.SessionStore(str(session_file),
62+
config.session_duration))

intelmq/api/exceptions.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""Exception handlers for API
2+
3+
SPDX-FileCopyrightText: 2022 CERT.at GmbH <https://cert.at>
4+
SPDX-License-Identifier: AGPL-3.0-or-later
5+
"""
6+
7+
from fastapi import FastAPI, Request, status
8+
from fastapi.responses import JSONResponse
9+
from starlette.exceptions import HTTPException as StarletteHTTPException
10+
11+
import intelmq.api.runctl as runctl
12+
13+
14+
def ctl_error_handler(request: Request, exc: runctl.IntelMQCtlError):
15+
return JSONResponse(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=exc.error_dict)
16+
17+
18+
def handle_generic_error(request: Request, exc: StarletteHTTPException):
19+
return JSONResponse(status_code=exc.status_code, content={"error": exc.detail})
20+
21+
22+
def register(app: FastAPI):
23+
"""A hook to register handlers in the app. Need to be called before startup"""
24+
app.add_exception_handler(runctl.IntelMQCtlError, ctl_error_handler)
25+
app.add_exception_handler(StarletteHTTPException, handle_generic_error)

0 commit comments

Comments
 (0)