diff --git a/docker/Dockerfile.bots b/docker/Dockerfile.bots index fc2ec693c..a989a105c 100644 --- a/docker/Dockerfile.bots +++ b/docker/Dockerfile.bots @@ -1,4 +1,4 @@ -FROM python:3.7-alpine3.14 AS build_shared +FROM python:3.12-alpine3.18 AS build_shared WORKDIR /build_shared/ @@ -8,7 +8,7 @@ RUN python -m build -FROM python:3.7-alpine3.14 AS production +FROM python:3.12-alpine3.18 AS production WORKDIR /app/ diff --git a/docker/Dockerfile.collectors b/docker/Dockerfile.collectors index a77621c42..edc46df14 100644 --- a/docker/Dockerfile.collectors +++ b/docker/Dockerfile.collectors @@ -1,4 +1,4 @@ -FROM python:3.7-alpine3.14 AS build_shared +FROM python:3.12-alpine3.18 AS build_shared WORKDIR /build_shared/ @@ -8,7 +8,7 @@ RUN python -m build -FROM python:3.7-alpine3.14 AS production +FROM python:3.12-alpine3.18 AS production WORKDIR /app/ diff --git a/docker/Dockerfile.presenters b/docker/Dockerfile.presenters index 8f1b61026..27737392e 100644 --- a/docker/Dockerfile.presenters +++ b/docker/Dockerfile.presenters @@ -1,4 +1,4 @@ -FROM python:3.7-alpine3.14 AS build_shared +FROM python:3.12-alpine3.18 AS build_shared WORKDIR /build_shared/ @@ -8,7 +8,7 @@ RUN python -m build -FROM python:3.7-alpine3.14 AS production +FROM python:3.12-alpine3.18 AS production WORKDIR /app/ @@ -20,59 +20,15 @@ RUN \ apk add --no-cache \ libpng \ libjpeg \ - wkhtmltopdf + py3-gobject3 \ + pango # install fonts RUN \ apk add --no-cache \ msttcorefonts-installer \ fontconfig \ - font-noto \ - font-noto-adlam \ - font-noto-adlamunjoined \ - font-noto-arabic \ - font-noto-armenian \ - font-noto-avestan \ - font-noto-bamum \ - font-noto-bengali \ - font-noto-buhid \ - font-noto-carian \ - font-noto-chakma \ - font-noto-cherokee \ - font-noto-cypriot \ - font-noto-deseret \ - font-noto-devanagari \ - font-noto-ethiopic \ - font-noto-extra \ - font-noto-georgian \ - font-noto-glagolitic \ - font-noto-gothic \ - font-noto-gujarati \ - font-noto-gurmukhi \ - font-noto-hebrew \ - font-noto-kannada \ - font-noto-kayahli \ - font-noto-khmer \ - font-noto-lao \ - font-noto-lisu \ - font-noto-malayalam \ - font-noto-mandaic \ - font-noto-myanmar \ - font-noto-nko \ - font-noto-olchiki \ - font-noto-oldturkic \ - font-noto-oriya \ - font-noto-osage \ - font-noto-osmanya \ - font-noto-shavian \ - font-noto-sinhala \ - font-noto-tamil \ - font-noto-telugu \ - font-noto-thaana \ - font-noto-thai \ - font-noto-tibetan \ - font-noto-tifinagh \ - font-noto-vai \ + font-noto-all \ terminus-font \ ttf-opensans \ font-bakoma \ diff --git a/docker/Dockerfile.publishers b/docker/Dockerfile.publishers index 5ee5a7ead..c4f50e78c 100644 --- a/docker/Dockerfile.publishers +++ b/docker/Dockerfile.publishers @@ -1,4 +1,4 @@ -FROM python:3.9-alpine3.17 AS build_shared +FROM python:3.12-alpine3.18 AS build_shared WORKDIR /build_shared/ @@ -8,7 +8,7 @@ RUN python -m build -FROM python:3.9-alpine3.17 AS production +FROM python:3.12-alpine3.18 AS production WORKDIR /app/ @@ -25,9 +25,9 @@ RUN pip install --no-cache-dir ./custom_packages/taranis_ng_shared-*.whl && rm - COPY ./src/publishers/requirements.txt /app/requirements.txt RUN apk add --no-cache \ - swig\ + swig \ libmagic \ - gnupg + gnupg RUN \ apk add --no-cache --virtual .build-deps build-base \ diff --git a/src/bots/managers/auth_manager.py b/src/bots/managers/auth_manager.py index c7d94a288..24b59d938 100644 --- a/src/bots/managers/auth_manager.py +++ b/src/bots/managers/auth_manager.py @@ -1,11 +1,16 @@ +"""Authorization manager for the API. + +Returns: + wrapper: Wrapper function for the API endpoints. +""" from functools import wraps from flask import request import os import ssl -api_key = os.getenv('API_KEY') +api_key = os.getenv("API_KEY") -if os.getenv('SSL_VERIFICATION') == "False": +if os.getenv("SSL_VERIFICATION") == "False": try: _create_unverified_https_context = ssl._create_unverified_context except AttributeError: @@ -15,11 +20,18 @@ def api_key_required(fn): + """Check for API key in the request header. + + Arguments: + fn -- The function to be decorated. + Returns: + wrapper: Wrapper function for the API endpoints. + """ + @wraps(fn) def wrapper(*args, **kwargs): - - if not request.headers.has_key('Authorization') or request.headers['Authorization'] != ('Bearer ' + api_key): - return {'error': 'not authorized'}, 401 + if "Authorization" not in request.headers.keys() or request.headers["Authorization"] != ("Bearer " + api_key): + return {"error": "not authorized"}, 401 else: return fn(*args, **kwargs) diff --git a/src/bots/requirements.txt b/src/bots/requirements.txt index 4139b7a7e..bc21d0327 100644 --- a/src/bots/requirements.txt +++ b/src/bots/requirements.txt @@ -1,26 +1,13 @@ -certifi==2019.11.28 -Flask==1.1.4 -Flask-Cors==3.0.10 -Flask-RESTful==0.3.7 -gevent==21.8.0 -greenlet==1.1.1 -gunicorn==20.0.4 -idna==2.8 -marshmallow==3.18.0 +Flask==3.0.0 +Flask-Cors==4.0.0 +Flask-RESTful==0.3.10 +gevent==23.9.1 +gunicorn==21.2.0 +marshmallow==3.20.1 marshmallow-enum==1.5.1 -Jinja2==2.11.3 -MarkupSafe==1.1.0 -oauthlib==3.1.0 +oauthlib==3.2.2 PySocks==1.7.1 -python-dateutil==2.8.1 -python-dotenv==0.10.5 -pytz==2019.3 -requests==2.26.0 -requests-oauthlib==1.3.0 -schedule==0.6.0 -six==1.14.0 -sseclient-py==1.7 -tweepy==3.8.0 -urllib3==1.26.7 -Werkzeug==0.16.0 -zipp==3.1.0 +python-dotenv==1.0.0 +requests==2.31.0 +schedule==1.2.1 +sseclient-py==1.8.0 diff --git a/src/collectors/collectors/rss_collector.py b/src/collectors/collectors/rss_collector.py index 35412c9c7..7c2fa62be 100644 --- a/src/collectors/collectors/rss_collector.py +++ b/src/collectors/collectors/rss_collector.py @@ -1,3 +1,4 @@ +"""RSS collector module.""" import datetime import hashlib import uuid @@ -17,13 +18,19 @@ class RSSCollector(BaseCollector): + """RSS collector class. + + Arguments: + BaseCollector -- Base collector class. + """ + type = "RSS_COLLECTOR" name = "RSS Collector" description = "Collector for gathering data from RSS feeds" parameters = [ Parameter(0, "FEED_URL", "Feed URL", "Full url for RSS feed", ParameterType.STRING), - Parameter(0, "USER_AGENT", "User agent", "Type of user agent", ParameterType.STRING) + Parameter(0, "USER_AGENT", "User agent", "Type of user agent", ParameterType.STRING), ] parameters.extend(BaseCollector.parameters) @@ -31,45 +38,52 @@ class RSSCollector(BaseCollector): news_items = [] def collect(self, source): + """Collect data from RSS feed. - feed_url = source.parameter_values['FEED_URL'] - interval = source.parameter_values['REFRESH_INTERVAL'] + Arguments: + source -- Source object. + """ + feed_url = source.parameter_values["FEED_URL"] + # interval = source.parameter_values["REFRESH_INTERVAL"] - log_manager.log_collector_activity('rss', source.name, 'Starting collector for url: {}'.format(feed_url)) + log_manager.log_collector_activity("rss", source.name, "Starting collector for url: {}".format(feed_url)) - user_agent = source.parameter_values['USER_AGENT'] + user_agent = source.parameter_values["USER_AGENT"] if user_agent: feedparser.USER_AGENT = user_agent - user_agent_headers = {'User-Agent': user_agent} + # user_agent_headers = {"User-Agent": user_agent} else: - user_agent_headers = { } + # user_agent_headers = {} + pass # use system proxy proxy_handler = None opener = urllib.request.urlopen - if 'PROXY_SERVER' in source.parameter_values: - proxy_server = source.parameter_values['PROXY_SERVER'] + if "PROXY_SERVER" in source.parameter_values: + proxy_server = source.parameter_values["PROXY_SERVER"] # disable proxy - do not use system proxy - if proxy_server == 'none': + if proxy_server == "none": proxy_handler = urllib.request.ProxyHandler({}) else: proxy = re.search(r"^(http|https|socks4|socks5)://([a-zA-Z0-9\-\.\_]+):(\d+)/?$", proxy_server) if proxy: scheme, host, port = proxy.groups() # classic HTTP/HTTPS proxy - if scheme in ['http', 'https']: - proxy_handler = urllib.request.ProxyHandler({ - 'http': '{}://{}:{}'.format(scheme, host, port), - 'https': '{}://{}:{}'.format(scheme, host, port), - 'ftp': '{}://{}:{}'.format(scheme, host, port) - }) + if scheme in ["http", "https"]: + proxy_handler = urllib.request.ProxyHandler( + { + "http": "{}://{}:{}".format(scheme, host, port), + "https": "{}://{}:{}".format(scheme, host, port), + "ftp": "{}://{}:{}".format(scheme, host, port), + } + ) # socks4 proxy - elif scheme == 'socks4': + elif scheme == "socks4": proxy_handler = SocksiPyHandler(socks.SOCKS4, host, int(port)) # socks5 proxy - elif scheme == 'socks5': + elif scheme == "socks5": proxy_handler = SocksiPyHandler(socks.SOCKS5, host, int(port)) # use proxy in urllib @@ -78,63 +92,72 @@ def collect(self, source): try: if proxy_handler: - feed = feedparser.parse(feed_url, handlers = [proxy_handler]) + feed = feedparser.parse(feed_url, handlers=[proxy_handler]) else: feed = feedparser.parse(feed_url) - log_manager.log_collector_activity('rss', source.name, 'RSS returned feed with {} entries'.format(len(feed['entries']))) + log_manager.log_collector_activity("rss", source.name, "RSS returned feed with {} entries".format(len(feed["entries"]))) news_items = [] - for feed_entry in feed['entries']: - - for key in ['author', 'published', 'title', 'description', 'link']: - if not feed_entry.has_key(key): - feed_entry[key] = '' + for feed_entry in feed["entries"]: + for key in ["author", "published", "title", "description", "link"]: + if key not in feed_entry.keys(): + feed_entry[key] = "" - limit = BaseCollector.history(interval) - published = feed_entry['published'] - published = dateparser.parse(published, settings={'DATE_ORDER': 'DMY'}) + # limit = BaseCollector.history(interval) + published = feed_entry["published"] + published = dateparser.parse(published, settings={"DATE_ORDER": "DMY"}) # if published > limit: TODO: uncomment after testing, we need some initial data now - link_for_article = feed_entry['link'] + link_for_article = feed_entry["link"] if not link_for_article: log_manager.log_collector_activity("rss", source.name, "Skipping (empty link)") continue - log_manager.log_collector_activity('rss', source.name, 'Processing entry [{}]'.format(link_for_article)) + log_manager.log_collector_activity("rss", source.name, "Processing entry [{}]".format(link_for_article)) - html_content = '' + html_content = "" request = urllib.request.Request(link_for_article) - request.add_header('User-Agent', user_agent) + request.add_header("User-Agent", user_agent) with opener(request) as response: html_content = response.read() - soup = BeautifulSoup(html_content, features='html.parser') + soup = BeautifulSoup(html_content, features="html.parser") - content = '' + content = "" if html_content: - content_text = [p.text.strip() for p in soup.findAll('p')] - replaced_str = '\xa0' + content_text = [p.text.strip() for p in soup.findAll("p")] + replaced_str = "\xa0" if replaced_str: - content = [w.replace(replaced_str, ' ') for w in content_text] - content = ' '.join(content) - - for_hash = feed_entry['author'] + feed_entry['title'] + feed_entry['link'] - - news_item = NewsItemData(uuid.uuid4(), hashlib.sha256(for_hash.encode()).hexdigest(), - feed_entry['title'], feed_entry['description'], feed_url, feed_entry['link'], - feed_entry['published'], feed_entry['author'], datetime.datetime.now(), - content, source.id, []) + content = [w.replace(replaced_str, " ") for w in content_text] + content = " ".join(content) + + for_hash = feed_entry["author"] + feed_entry["title"] + feed_entry["link"] + + news_item = NewsItemData( + uuid.uuid4(), + hashlib.sha256(for_hash.encode()).hexdigest(), + feed_entry["title"], + feed_entry["description"], + feed_url, + feed_entry["link"], + feed_entry["published"], + feed_entry["author"], + datetime.datetime.now(), + content, + source.id, + [], + ) news_items.append(news_item) BaseCollector.publish(news_items, source) except Exception as error: - log_manager.log_collector_activity('rss', source.name, 'RSS collection exceptionally failed') + log_manager.log_collector_activity("rss", source.name, "RSS collection exceptionally failed") BaseCollector.print_exception(source, error) log_manager.log_debug(traceback.format_exc()) diff --git a/src/collectors/managers/auth_manager.py b/src/collectors/managers/auth_manager.py index c7d94a288..28d4ce145 100644 --- a/src/collectors/managers/auth_manager.py +++ b/src/collectors/managers/auth_manager.py @@ -1,11 +1,16 @@ +"""Authorization manager for the API. + +Returns: + wrapper: Wrapper function for the API endpoints. +""" from functools import wraps from flask import request import os import ssl -api_key = os.getenv('API_KEY') +api_key = os.getenv("API_KEY") -if os.getenv('SSL_VERIFICATION') == "False": +if os.getenv("SSL_VERIFICATION") == "False": try: _create_unverified_https_context = ssl._create_unverified_context except AttributeError: @@ -15,11 +20,19 @@ def api_key_required(fn): + """Check for API key in the request header. + + Arguments: + fn -- The function to be decorated. + + Returns: + wrapper: Wrapper function for the API endpoints. + """ + @wraps(fn) def wrapper(*args, **kwargs): - - if not request.headers.has_key('Authorization') or request.headers['Authorization'] != ('Bearer ' + api_key): - return {'error': 'not authorized'}, 401 + if "Authorization" not in request.headers.keys() or request.headers["Authorization"] != ("Bearer " + api_key): + return {"error": "not authorized"}, 401 else: return fn(*args, **kwargs) diff --git a/src/collectors/requirements.txt b/src/collectors/requirements.txt index 4352be63b..d7b1d1d38 100644 --- a/src/collectors/requirements.txt +++ b/src/collectors/requirements.txt @@ -1,30 +1,19 @@ -beautifulsoup4==4.8.1 -bleach==4.1.0 -certifi==2021.10.8 -feedparser==5.2.1 -Flask==1.1.4 -Flask-Cors==3.0.10 -Flask-RESTful==0.3.7 -gevent==21.8.0 -greenlet==1.1.1 -gunicorn==20.0.4 -lxml==4.6.5 -marshmallow==3.18.0 +beautifulsoup4==4.12.2 +bleach==6.1.0 +dateparser==1.2.0 +feedparser==6.0.10 +Flask==3.0.0 +Flask-Cors==4.0.0 +Flask-RESTful==0.3.10 +gevent==23.9.1 +gunicorn==21.2.0 +marshmallow==3.20.1 marshmallow-enum==1.5.1 -Jinja2==2.11.3 -MarkupSafe==1.1.0 -pyslack==0.5.0 PySocks==1.7.1 -python-dateutil==2.8.1 -python-dotenv==0.10.5 -pytz==2019.3 -requests==2.26.0 -schedule==0.6.0 -selenium==4.0.0 -six==1.14.0 -slackclient==1.0.7 -soupsieve==1.9.5 -tweepy==3.8.0 -Werkzeug==0.16.0 -zipp==3.1.0 -dateparser==1.1.1 +python-dateutil==2.8.2 +python-dotenv==1.0.0 +requests==2.31.0 +schedule==1.2.1 +selenium==4.15.2 +slackclient==1.3.2 +tweepy==4.14.0 diff --git a/src/presenters/managers/auth_manager.py b/src/presenters/managers/auth_manager.py index c7d94a288..24b59d938 100644 --- a/src/presenters/managers/auth_manager.py +++ b/src/presenters/managers/auth_manager.py @@ -1,11 +1,16 @@ +"""Authorization manager for the API. + +Returns: + wrapper: Wrapper function for the API endpoints. +""" from functools import wraps from flask import request import os import ssl -api_key = os.getenv('API_KEY') +api_key = os.getenv("API_KEY") -if os.getenv('SSL_VERIFICATION') == "False": +if os.getenv("SSL_VERIFICATION") == "False": try: _create_unverified_https_context = ssl._create_unverified_context except AttributeError: @@ -15,11 +20,18 @@ def api_key_required(fn): + """Check for API key in the request header. + + Arguments: + fn -- The function to be decorated. + Returns: + wrapper: Wrapper function for the API endpoints. + """ + @wraps(fn) def wrapper(*args, **kwargs): - - if not request.headers.has_key('Authorization') or request.headers['Authorization'] != ('Bearer ' + api_key): - return {'error': 'not authorized'}, 401 + if "Authorization" not in request.headers.keys() or request.headers["Authorization"] != ("Bearer " + api_key): + return {"error": "not authorized"}, 401 else: return fn(*args, **kwargs) diff --git a/src/presenters/presenters/pdf_presenter.py b/src/presenters/presenters/pdf_presenter.py index 260340da6..fdad204a1 100644 --- a/src/presenters/presenters/pdf_presenter.py +++ b/src/presenters/presenters/pdf_presenter.py @@ -1,96 +1,97 @@ +"""PDF Presenter. + +Returns: + dict: mime type and base64 encoded data of the generated PDF document +""" import datetime import os import tempfile from base64 import b64encode import jinja2 -import pdfkit +from weasyprint import HTML from .base_presenter import BasePresenter from shared.schema.parameter import Parameter, ParameterType class PDFPresenter(BasePresenter): + """PDF Presenter class. + + Args: + BasePresenter (class): Base presenter class + """ + type = "PDF_PRESENTER" name = "PDF Presenter" description = "Presenter for generating PDF documents" - parameters = [ - Parameter(0, "HEADER_TEMPLATE_PATH", "Header template path", "Path of header template file", - ParameterType.STRING), - Parameter(0, "BODY_TEMPLATE_PATH", "Body template path", "Path of body template file", - ParameterType.STRING), - Parameter(0, "FOOTER_TEMPLATE_PATH", "Footer template path", "Path of footer template file", - ParameterType.STRING) - ] + parameters = [Parameter(0, "PDF_TEMPLATE_PATH", "Template path", "Path of header template file", ParameterType.STRING)] parameters.extend(BasePresenter.parameters) def generate(self, presenter_input): + """Generate PDF document. + + Args: + presenter_input (_type_): Parameters from settings + Returns: + dict: mime type and base64 encoded data of the generated PDF document + """ try: temporary_directory = tempfile.gettempdir() + "/" - output_body_html = temporary_directory + 'pdf_body.html' - output_pdf = temporary_directory + 'pdf_report__' + datetime.datetime.now().strftime( - "%d-%m-%Y_%H:%M") + '.pdf' + output_html = temporary_directory + "pdf_body.html" + output_pdf = temporary_directory + "pdf_report__" + datetime.datetime.now().strftime("%d-%m-%Y_%H:%M") + ".pdf" - pdf_header_template = presenter_input.parameter_values_map['HEADER_TEMPLATE_PATH'] - pdf_footer_template = presenter_input.parameter_values_map['FOOTER_TEMPLATE_PATH'] - head, tail = os.path.split(presenter_input.parameter_values_map['BODY_TEMPLATE_PATH']) + head, tail = os.path.split(presenter_input.parameter_values_map["PDF_TEMPLATE_PATH"]) input_data = BasePresenter.generate_input_data(presenter_input) env = jinja2.Environment(loader=jinja2.FileSystemLoader(head)) env.filters["strfdate"] = BasePresenter._filter_datetime - body = env.get_template(tail) - output_text = body.render(data=input_data) - with open(output_body_html, 'w') as output_file: + pdf = env.get_template(tail) + output_text = pdf.render(data=input_data) + with open(output_html, "w") as output_file: output_file.write(output_text) if not os.path.exists(temporary_directory): os.mkdir(temporary_directory) - options = { - 'dpi': 500, - 'page-size': 'A4', - 'margin-top': '1.55in', - 'margin-right': '0.75in', - 'margin-bottom': '1.55in', - 'margin-left': '0.75in', - 'encoding': "UTF-8", - 'header-html': pdf_header_template, - 'footer-html': pdf_footer_template, - 'custom-header': [ - ('Accept-Encoding', 'gzip') - ], - 'no-outline': None, - 'enable-local-file-access': None - } - - pdfkit.from_file(input=output_body_html, output_path=output_pdf, options=options) - - encoding = 'UTF-8' + # options = { + # 'dpi': 500, + # 'page-size': 'A4', + # 'margin-top': '1.55in', + # 'margin-right': '0.75in', + # 'margin-bottom': '1.55in', + # 'margin-left': '0.75in', + # 'encoding': "UTF-8", + # 'header-html': pdf_header_template, + # 'footer-html': pdf_footer_template, + # 'custom-header': [ + # ('Accept-Encoding', 'gzip') + # ], + # 'no-outline': None, + # 'enable-local-file-access': None + # } + HTML(output_html).write_pdf(output_pdf) + + encoding = "UTF-8" file = output_pdf - with open(file, 'rb') as open_file: + with open(file, "rb") as open_file: byte_content = open_file.read() base64_bytes = b64encode(byte_content) data = base64_bytes.decode(encoding) - presenter_output = { - 'mime_type': 'application/pdf', - 'data': data - } + presenter_output = {"mime_type": "application/pdf", "data": data} - os.remove(output_body_html) + os.remove(output_html) os.remove(file) return presenter_output except Exception as error: BasePresenter.print_exception(self, error) - presenter_output = { - 'mime_type': 'text/plain', - 'data': b64encode(("TEMPLATING ERROR\n"+str(error)).encode()).decode('UTF-8') - } + presenter_output = {"mime_type": "text/plain", "data": b64encode(("TEMPLATING ERROR\n" + str(error)).encode()).decode("UTF-8")} return presenter_output diff --git a/src/presenters/requirements.txt b/src/presenters/requirements.txt index 7d4b125d3..bebd77dd8 100644 --- a/src/presenters/requirements.txt +++ b/src/presenters/requirements.txt @@ -1,17 +1,10 @@ -Flask==1.1.4 -Flask-Cors==3.0.10 -Flask-RESTful==0.3.7 -gevent==21.8.0 -greenlet==1.1.1 -gunicorn==20.0.4 -Jinja2==2.11.3 -MarkupSafe==1.1.0 -marshmallow==3.18.0 +Flask==3.0.0 +Flask-Cors==4.0.0 +Flask-RESTful==0.3.10 +gevent==23.9.1 +gunicorn==21.2.0 +Jinja2==3.1.2 +marshmallow==3.20.1 marshmallow-enum==1.5.1 -pdfkit==0.6.1 -PyJWT==1.7.1 -python-dotenv==0.10.5 -pytz==2019.3 -PyYAML==6.0.1 -six==1.14.0 -Werkzeug==0.16.0 +python-dotenv==1.0.0 +weasyprint==60.1 diff --git a/src/presenters/templates/pdf_body_template.html b/src/presenters/templates/pdf_body_template.html deleted file mode 100644 index 888292da2..000000000 --- a/src/presenters/templates/pdf_body_template.html +++ /dev/null @@ -1,239 +0,0 @@ - - -
- -CONFIDENTIALITY, DISTRIBUTION, SEVERITY | -|||||
---|---|---|---|---|---|
- Confidentiality
- |
-
-
-
-
- |
-
-
-
-
- |
-
-
-
-
- |
-
-
-
-
- |
-
-
-
-
- |
-
- TLP
- |
- - {% if report_item.attrs.tlp == 'CLEAR' or report_item.attrs.tlp == 'WHITE' %} - TLP:CLEAR - {% endif %} - {% if report_item.attrs.tlp == 'GREEN' %} - TLP:GREEN - {% endif %} - {% if report_item.attrs.tlp == 'AMBER' %} - TLP:AMBER - {% endif %} - {% if report_item.attrs.tlp == 'AMBER+STRICT' %} - TLP:AMBER+STRICT - {% endif %} - {% if report_item.attrs.tlp == 'RED' %} - TLP:RED - {% endif %} - | -||||
- CVSS vector
- |
-
- {{ report_item.attrs.cvss|e }}
- |
DESCRIPTION | -
---|
- {{ report_item.attrs.description|e }} - | -
PUBLISHED | -
---|
- {{ report_item.attrs.exposure_date }} - | -
UPDATED | -
---|
- {{ report_item.attrs.update_date }} - | -
CVE | -
---|
- {% if report_item.attrs.cve %}
- {% for i in report_item.attrs.cve %}
- {{ i|e }}
- {% endfor %}
- {% endif %}
- |
-
IMPACT | -
---|
- {% if report_item.attrs.impact %}
- {% for i in report_item.attrs.impact %}
- {{ i|e }}
- {% endfor %}
- {% endif %}
- |
-
IOC | -
---|
- {% if report_item.attrs.ioc %}
- {% for i in report_item.attrs.ioc %}
- {{ i|e }}
- {% endfor %}
- {% endif %}
- |
-
AFFECTED SYSTEMS | -
---|
- {% if report_item.attrs.affected_systems %}
- {% for i in report_item.attrs.affected_systems %}
- {{ i|e }}
- {% endfor %}
- {% endif %}
- |
-
RECOMMENDATIONS | -
---|
- {{ report_item.attrs.recommendations }} - | -
LINKS | -
---|
-
{{ i|e }}
- {% endfor %}
- {% endif %}
- |
-
Created by Taranis NG | -Repo: github.com/SK-CERT/Taranis-NG | -Company name | -
OSINT analysis tool | -E-mail: sk-cert@nbu.gov.sk | -Company address | -
for CSIRT community | -Web: www.sk-cert.sk | -City name | -
- | VULNERABILITY REPORT | -No: SW1234-ER/2 | -