diff --git a/dojo/filters.py b/dojo/filters.py index 460a21f6b0d..08b84de46a9 100644 --- a/dojo/filters.py +++ b/dojo/filters.py @@ -2881,6 +2881,7 @@ class ReportFindingFilter(FindingTagFilter): queryset=Product_Type.objects.none(), label="Product Type") test__engagement__product__lifecycle = MultipleChoiceFilter(choices=Product.LIFECYCLE_CHOICES, label="Product Lifecycle") + test__engagement = ModelMultipleChoiceFilter(queryset=Engagement.objects.none(), label="Engagement") severity = MultipleChoiceFilter(choices=SEVERITY_CHOICES) active = ReportBooleanFilter() is_mitigated = ReportBooleanFilter() @@ -2901,8 +2902,8 @@ class Meta: model = Finding # exclude sonarqube issue as by default it will show all without checking permissions exclude = ['date', 'cwe', 'url', 'description', 'mitigation', 'impact', - 'references', 'test', 'sonarqube_issue', - 'thread_id', 'notes', 'endpoints', + 'references', 'sonarqube_issue', + 'thread_id', 'notes', 'numerical_severity', 'reporter', 'last_reviewed', 'jira_creation', 'jira_change', 'files'] @@ -2952,6 +2953,8 @@ def __init__(self, *args, **kwargs): if 'test__engagement__product' in self.form.fields: self.form.fields[ 'test__engagement__product'].queryset = get_authorized_products(Permissions.Product_View) + if 'test__engagement' in self.form.fields: + self.form.fields['test__engagement'].queryset = get_authorized_engagements(Permissions.Engagement_View) @property def qs(self): diff --git a/dojo/reports/urls.py b/dojo/reports/urls.py index 31503b6c512..1d02fbbf559 100644 --- a/dojo/reports/urls.py +++ b/dojo/reports/urls.py @@ -23,13 +23,13 @@ re_path(r'^reports/cover$', views.report_cover_page, name='report_cover_page'), re_path(r'^reports/builder$', - views.report_builder, name='report_builder'), + views.ReportBuilder.as_view(), name='report_builder'), re_path(r'^reports/findings$', views.report_findings, name='report_findings'), re_path(r'^reports/endpoints$', views.report_endpoints, name='report_endpoints'), re_path(r'^reports/custom$', - views.custom_report, name='custom_report'), + views.CustomReport.as_view(), name='custom_report'), re_path(r'^reports/quick$', views.QuickReportView.as_view(), name='quick_report'), re_path(r'^reports/csv_export$', diff --git a/dojo/reports/views.py b/dojo/reports/views.py index 3b2d8c193bb..cb7a599f112 100644 --- a/dojo/reports/views.py +++ b/dojo/reports/views.py @@ -3,11 +3,12 @@ import re from datetime import datetime from tempfile import NamedTemporaryFile +from typing import List from dateutil.relativedelta import relativedelta from django.conf import settings from django.core.exceptions import PermissionDenied -from django.http import Http404, HttpResponse, QueryDict +from django.http import Http404, HttpRequest, HttpResponse, QueryDict from django.shortcuts import get_object_or_404, render from django.utils import timezone from django.views import View @@ -30,6 +31,7 @@ PageBreak, ReportOptions, TableOfContents, + Widget, WYSIWYGContent, report_widget_factory, ) @@ -64,75 +66,94 @@ def report_url_resolver(request): return url_resolver + ":" + request.META['SERVER_PORT'] -def report_builder(request): - add_breadcrumb(title="Report Builder", top_level=True, request=request) - findings = get_authorized_findings(Permissions.Finding_View) - findings = ReportFindingFilter(request.GET, queryset=findings) - endpoints = Endpoint.objects.filter(finding__active=True, - finding__verified=True, - finding__false_p=False, - finding__duplicate=False, - finding__out_of_scope=False, - ).distinct() - filter_string_matching = get_system_setting("filter_string_matching", False) - filter_class = EndpointFilterWithoutObjectLookups if filter_string_matching else EndpointFilter - endpoints = filter_class(request.GET, queryset=endpoints, user=request.user) - - in_use_widgets = [ReportOptions(request=request)] - available_widgets = [CoverPage(request=request), - TableOfContents(request=request), - WYSIWYGContent(request=request), - FindingList(request=request, findings=findings), - EndpointList(request=request, endpoints=endpoints), - PageBreak()] - return render(request, - 'dojo/report_builder.html', - {"available_widgets": available_widgets, - "in_use_widgets": in_use_widgets}) - - -def custom_report(request): - # saving the report - form = CustomReportJsonForm(request.POST) - host = report_url_resolver(request) - if form.is_valid(): - selected_widgets = report_widget_factory(json_data=request.POST['json'], request=request, user=request.user, - finding_notes=False, finding_images=False, host=host) - report_format = 'AsciiDoc' - finding_notes = True - finding_images = True - - if 'report-options' in selected_widgets: - options = selected_widgets['report-options'] - report_format = options.report_type - finding_notes = (options.include_finding_notes == '1') - finding_images = (options.include_finding_images == '1') - - selected_widgets = report_widget_factory(json_data=request.POST['json'], request=request, user=request.user, - finding_notes=finding_notes, finding_images=finding_images, host=host) +class ReportBuilder(View): + def get(self, request: HttpRequest) -> HttpResponse: + add_breadcrumb(title="Report Builder", top_level=True, request=request) + return render(request, self.get_template(), self.get_context(request)) + + def get_findings(self, request: HttpRequest): + findings = get_authorized_findings(Permissions.Finding_View) + return ReportFindingFilter(self.request.GET, queryset=findings) + + def get_endpoints(self, request: HttpRequest): + endpoints = Endpoint.objects.filter(finding__active=True, + finding__verified=True, + finding__false_p=False, + finding__duplicate=False, + finding__out_of_scope=False, + ).distinct() + filter_string_matching = get_system_setting("filter_string_matching", False) + filter_class = EndpointFilterWithoutObjectLookups if filter_string_matching else EndpointFilter + return filter_class(request.GET, queryset=endpoints, user=request.user) + + def get_available_widgets(self, request: HttpRequest) -> List[Widget]: + return [ + CoverPage(request=request), + TableOfContents(request=request), + WYSIWYGContent(request=request), + FindingList(request=request, findings=self.get_findings(request)), + EndpointList(request=request, endpoints=self.get_endpoints(request)), + PageBreak()] + + def get_in_use_widgets(self, request): + return [ReportOptions(request=request)] - if report_format == 'AsciiDoc': - widgets = list(selected_widgets.values()) - return render(request, - 'dojo/custom_asciidoc_report.html', - {"widgets": widgets, - "host": host, - "finding_notes": finding_notes, - "finding_images": finding_images, - "user_id": request.user.id}) - elif report_format == 'HTML': - widgets = list(selected_widgets.values()) - return render(request, - 'dojo/custom_html_report.html', - {"widgets": widgets, - "host": "", - "finding_notes": finding_notes, - "finding_images": finding_images, - "user_id": request.user.id}) + def get_template(self): + return 'dojo/report_builder.html' + + def get_context(self, request: HttpRequest) -> dict: + return { + "available_widgets": self.get_available_widgets(request), + "in_use_widgets": self.get_in_use_widgets(request), } + + +class CustomReport(View): + def post(self, request: HttpRequest) -> HttpResponse: + # saving the report + form = self.get_form(request) + if form.is_valid(): + self._set_state(request) + return render(request, self.get_template(), self.get_context()) else: raise PermissionDenied() - else: - raise PermissionDenied() + + def _set_state(self, request: HttpRequest): + self.request = request + self.selected_widgets = self.get_selected_widgets(request) + self.widgets = list(self.selected_widgets.values()) + + def get_selected_widgets(self, request): + selected_widgets = report_widget_factory(json_data=request.POST['json'], request=request, finding_notes=False, + finding_images=False) + + if options := selected_widgets.get('report-options', None): + self.report_format = options.report_type + self.finding_notes = (options.include_finding_notes == '1') + self.finding_images = (options.include_finding_images == '1') + else: + self.report_format = 'AsciiDoc' + self.finding_notes = True + self.finding_images = True + + return report_widget_factory(json_data=request.POST['json'], request=request, finding_notes=self.finding_notes, + finding_images=self.finding_images) + + def get_form(self, request): + return CustomReportJsonForm(request.POST) + + def get_template(self): + if self.report_format == 'AsciiDoc': + return 'dojo/custom_asciidoc_report.html', + elif self.report_format == 'HTML': + return 'dojo/custom_html_report.html' + else: + raise PermissionDenied() + + def get_context(self): + return { + "widgets": self.widgets, + "finding_notes": self.finding_notes, + "finding_images": self.finding_images, } def report_findings(request): diff --git a/dojo/reports/widgets.py b/dojo/reports/widgets.py index 665b7758b49..8eef453bb8c 100644 --- a/dojo/reports/widgets.py +++ b/dojo/reports/widgets.py @@ -247,11 +247,6 @@ class FindingList(Widget): def __init__(self, *args, **kwargs): if 'request' in kwargs: self.request = kwargs.get('request') - if 'user_id' in kwargs: - self.user_id = kwargs.get('user_id') - - if 'host' in kwargs: - self.host = kwargs.get('host') if 'findings' in kwargs: self.findings = kwargs.get('findings') @@ -290,10 +285,8 @@ def __init__(self, *args, **kwargs): def get_asciidoc(self): asciidoc = render_to_string("dojo/custom_asciidoc_report_findings.html", {"findings": self.findings.qs, - "host": self.host, "include_finding_notes": self.finding_notes, - "include_finding_images": self.finding_images, - "user_id": self.user_id}) + "include_finding_images": self.finding_images, }) return mark_safe(asciidoc) def get_html(self): @@ -301,9 +294,7 @@ def get_html(self): {"title": self.title, "findings": self.findings.qs, "include_finding_notes": self.finding_notes, - "include_finding_images": self.finding_images, - "host": self.host, - "user_id": self.user_id}) + "include_finding_images": self.finding_images, }) return mark_safe(html) def get_option_form(self): @@ -323,11 +314,6 @@ class EndpointList(Widget): def __init__(self, *args, **kwargs): if 'request' in kwargs: self.request = kwargs.get('request') - if 'user_id' in kwargs: - self.user_id = kwargs.get('user_id') - - if 'host' in kwargs: - self.host = kwargs.get('host') if 'endpoints' in kwargs: self.endpoints = kwargs.get('endpoints') @@ -363,18 +349,14 @@ def get_html(self): {"title": self.title, "endpoints": self.endpoints.qs, "include_finding_notes": self.finding_notes, - "include_finding_images": self.finding_images, - "host": self.host, - "user_id": self.user_id}) + "include_finding_images": self.finding_images, }) return mark_safe(html) def get_asciidoc(self): asciidoc = render_to_string("dojo/custom_asciidoc_report_endpoints.html", {"endpoints": self.endpoints.qs, - "host": self.host, "include_finding_notes": self.finding_notes, - "include_finding_images": self.finding_images, - "user_id": self.user_id}) + "include_finding_images": self.finding_images, }) return mark_safe(asciidoc) def get_option_form(self): @@ -388,8 +370,7 @@ def get_option_form(self): return mark_safe(html) -def report_widget_factory(json_data=None, request=None, user=None, finding_notes=False, finding_images=False, - host=None): +def report_widget_factory(json_data=None, request=None, finding_notes=False, finding_images=False): selected_widgets = OrderedDict() widgets = json.loads(json_data) for idx, widget in enumerate(widgets): @@ -413,9 +394,8 @@ def report_widget_factory(json_data=None, request=None, user=None, finding_notes filter_string_matching = get_system_setting("filter_string_matching", False) filter_class = EndpointFilterWithoutObjectLookups if filter_string_matching else EndpointFilter endpoints = filter_class(d, queryset=endpoints, user=request.user) - user_id = user.id if user is not None else None endpoints = EndpointList(request=request, endpoints=endpoints, finding_notes=finding_notes, - finding_images=finding_images, host=host, user_id=user_id) + finding_images=finding_images) selected_widgets[list(widget.keys())[0] + '-' + str(idx)] = endpoints @@ -429,11 +409,9 @@ def report_widget_factory(json_data=None, request=None, user=None, finding_notes d[item['name']] = item['value'] findings = ReportFindingFilter(d, queryset=findings) - user_id = user.id if user is not None else None selected_widgets[list(widget.keys())[0] + '-' + str(idx)] = FindingList(request=request, findings=findings, finding_notes=finding_notes, - finding_images=finding_images, - host=host, user_id=user_id) + finding_images=finding_images) if list(widget.keys())[0] == 'wysiwyg-content': wysiwyg_content = WYSIWYGContent(request=request) diff --git a/dojo/templates/base.html b/dojo/templates/base.html index 2f1cace966c..765ec10dc55 100644 --- a/dojo/templates/base.html +++ b/dojo/templates/base.html @@ -372,6 +372,7 @@ {% endif %} + {% block reports_tab %}