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() endpoints = EndpointFilter(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 dashboard(request: HttpRequest) -> HttpResponse: engagements = get_authorized_engagements(Permissions.Engagement_View).distinct() findings = get_authorized_findings(Permissions.Finding_View).distinct() findings = findings.filter(duplicate=False) engagement_count = engagements.filter(active=True).count() today = timezone.now().date() date_range = [today - timedelta(days=6), today] # 7 days (6 days plus today) finding_count = findings\ .filter(created__date__range=date_range)\ .count() mitigated_count = findings\ .filter(mitigated__date__range=date_range)\ .count() accepted_count = findings\ .filter(risk_acceptance__created__date__range=date_range)\ .count() severity_count_all = get_severities_all(findings) severity_count_by_month = get_severities_by_month(findings, today) punchcard, ticks = get_punchcard_data(findings, today - relativedelta(weeks=26), 26) if user_has_configuration_permission(request.user, 'dojo.view_engagement_survey', 'staff'): unassigned_surveys = Answered_Survey.objects.filter(assignee_id__isnull=True, completed__gt=0, ) \ .filter(Q(engagement__isnull=True) | Q(engagement__in=engagements)) else: unassigned_surveys = None if request.user.is_superuser and not settings.FEATURE_CONFIGURATION_AUTHORIZATION: message = '''Legacy authorization for changing configurations based on staff users will be removed with version 2.12.0 / 5. July 2022. If you have set `FEATURE_CONFIGURATION_AUTHORIZATION` to `False` in your local configuration, remove this local setting and start using the new authorization.''' messages.add_message(request, messages.WARNING, message, extra_tags='alert-warning') add_breadcrumb(request=request, clear=True) return render(request, 'dojo/dashboard.html', { 'engagement_count': engagement_count, 'finding_count': finding_count, 'mitigated_count': mitigated_count, 'accepted_count': accepted_count, 'critical': severity_count_all['Critical'], 'high': severity_count_all['High'], 'medium': severity_count_all['Medium'], 'low': severity_count_all['Low'], 'info': severity_count_all['Info'], 'by_month': severity_count_by_month, 'punchcard': punchcard, 'ticks': ticks, 'surveys': unassigned_surveys, })
def dashboard(request: HttpRequest) -> HttpResponse: engagements = get_authorized_engagements( Permissions.Engagement_View).distinct() findings = get_authorized_findings(Permissions.Finding_View).distinct() findings = findings.filter(duplicate=False) engagement_count = engagements.filter(active=True).count() today = timezone.now().date() date_range = [today - timedelta(days=6), today] # 7 days (6 days plus today) finding_count = findings\ .filter(created__date__range=date_range)\ .count() mitigated_count = findings\ .filter(mitigated__date__range=date_range)\ .count() accepted_count = findings\ .filter(risk_acceptance__created__date__range=date_range)\ .count() severity_count_all = get_severities_all(findings) severity_count_by_month = get_severities_by_month(findings, today) punchcard, ticks = get_punchcard_data(findings, today - relativedelta(weeks=26), 26) if request.user.is_staff: unassigned_surveys = Answered_Survey.objects.filter(assignee_id__isnull=True, completed__gt=0, ) \ .filter(Q(engagement__isnull=True) | Q(engagement__in=engagements)) else: unassigned_surveys = None add_breadcrumb(request=request, clear=True) return render( request, 'dojo/dashboard.html', { 'engagement_count': engagement_count, 'finding_count': finding_count, 'mitigated_count': mitigated_count, 'accepted_count': accepted_count, 'critical': severity_count_all['Critical'], 'high': severity_count_all['High'], 'medium': severity_count_all['Medium'], 'low': severity_count_all['Low'], 'info': severity_count_all['Info'], 'by_month': severity_count_by_month, 'punchcard': punchcard, 'ticks': ticks, 'surveys': unassigned_surveys, })
def components(request): add_breadcrumb(title='Components', top_level=True, request=request) separator = ', ' # Get components ordered by component_name and concat component versions to the same row component_query = get_authorized_findings(Permissions.Finding_View) if connection.vendor == 'postgresql': component_query = component_query.values("component_name").order_by( 'component_name').annotate(component_version=StringAgg( 'component_version', delimiter=separator, distinct=True)) else: component_query = component_query.values("component_name").order_by( 'component_name') component_query = component_query.annotate( component_version=Sql_GroupConcat( 'component_version', separator=separator, distinct=True)) # Append counts component_query = component_query.annotate( total=Count('id')).order_by('component_name') component_query = component_query.annotate( active=Count('id', filter=Q(active=True))) component_query = component_query.annotate( duplicate=(Count('id', filter=Q(duplicate=True)))) component_query = component_query.order_by( '-total') # Default sort by total descending comp_filter = ComponentFilter(request.GET, queryset=component_query) result = get_page_items(request, comp_filter.qs, 25) # Filter out None values for auto-complete component_words = component_query.exclude( component_name__isnull=True).values_list('component_name', flat=True) return render( request, 'dojo/components.html', { 'filter': comp_filter, 'result': result, 'component_words': sorted(set(component_words)) })
def product_findings_report(request): findings = get_authorized_findings(Permissions.Finding_View) return generate_report(request, findings)
def finding_querys(prod_type, request): findings_query = Finding.objects.filter( verified=True, severity__in=('Critical', 'High', 'Medium', 'Low', 'Info') ).select_related( 'reporter', 'test', 'test__engagement__product', 'test__engagement__product__prod_type', ).prefetch_related( 'risk_acceptance_set', 'test__engagement__risk_acceptance', 'test__test_type', ) findings_query = get_authorized_findings(Permissions.Finding_View, findings_query, request.user) active_findings_query = Finding.objects.filter( verified=True, active=True, severity__in=('Critical', 'High', 'Medium', 'Low', 'Info') ).select_related( 'reporter', 'test', 'test__engagement__product', 'test__engagement__product__prod_type', ).prefetch_related( 'risk_acceptance_set', 'test__engagement__risk_acceptance', 'test__test_type', ) active_findings_query = get_authorized_findings(Permissions.Finding_View, active_findings_query, request.user) findings = MetricsFindingFilter(request.GET, queryset=findings_query) active_findings = MetricsFindingFilter(request.GET, queryset=active_findings_query) findings_qs = queryset_check(findings) active_findings_qs = queryset_check(active_findings) if not findings_qs and not findings_query: findings = findings_query active_findings = active_findings_query findings_qs = findings if isinstance(findings, QuerySet) else findings.qs active_findings_qs = active_findings if isinstance(active_findings, QuerySet) else active_findings.qs messages.add_message(request, messages.ERROR, 'All objects have been filtered away. Displaying all objects', extra_tags='alert-danger') try: start_date = findings_qs.earliest('date').date start_date = datetime(start_date.year, start_date.month, start_date.day, tzinfo=timezone.get_current_timezone()) end_date = findings_qs.latest('date').date end_date = datetime(end_date.year, end_date.month, end_date.day, tzinfo=timezone.get_current_timezone()) except: start_date = timezone.now() end_date = timezone.now() if len(prod_type) > 0: findings_closed = Finding.objects.filter(mitigated__date__range=[start_date, end_date], test__engagement__product__prod_type__in=prod_type).prefetch_related( 'test__engagement__product') # capture the accepted findings in period accepted_findings = Finding.objects.filter(risk_accepted=True, date__range=[start_date, end_date], test__engagement__product__prod_type__in=prod_type). \ prefetch_related('test__engagement__product') accepted_findings_counts = Finding.objects.filter(risk_accepted=True, date__range=[start_date, end_date], test__engagement__product__prod_type__in=prod_type). \ prefetch_related('test__engagement__product') else: findings_closed = Finding.objects.filter(mitigated__date__range=[start_date, end_date]).prefetch_related( 'test__engagement__product') accepted_findings = Finding.objects.filter(risk_accepted=True, date__range=[start_date, end_date]). \ prefetch_related('test__engagement__product') accepted_findings_counts = Finding.objects.filter(risk_accepted=True, date__range=[start_date, end_date]). \ prefetch_related('test__engagement__product') findings_closed = get_authorized_findings(Permissions.Finding_View, findings_closed, request.user) accepted_findings = get_authorized_findings(Permissions.Finding_View, accepted_findings, request.user) accepted_findings_counts = get_authorized_findings(Permissions.Finding_View, accepted_findings_counts, request.user) accepted_findings_counts = severity_count(accepted_findings_counts, 'aggregate', 'severity') r = relativedelta(end_date, start_date) months_between = (r.years * 12) + r.months # include current month months_between += 1 weeks_between = int(ceil((((r.years * 12) + r.months) * 4.33) + (r.days / 7))) if weeks_between <= 0: weeks_between += 2 monthly_counts = get_period_counts(active_findings_qs, findings_qs, findings_closed, accepted_findings, months_between, start_date, relative_delta='months') weekly_counts = get_period_counts(active_findings_qs, findings_qs, findings_closed, accepted_findings, weeks_between, start_date, relative_delta='weeks') top_ten = get_authorized_products(Permissions.Product_View) top_ten = top_ten.filter(engagement__test__finding__verified=True, engagement__test__finding__false_p=False, engagement__test__finding__duplicate=False, engagement__test__finding__out_of_scope=False, engagement__test__finding__mitigated__isnull=True, engagement__test__finding__severity__in=( 'Critical', 'High', 'Medium', 'Low'), prod_type__in=prod_type) top_ten = severity_count(top_ten, 'annotate', 'engagement__test__finding__severity').order_by('-critical', '-high', '-medium', '-low')[:10] return { 'all': findings, 'closed': findings_closed, 'accepted': accepted_findings, 'accepted_count': accepted_findings_counts, 'top_ten': top_ten, 'monthly_counts': monthly_counts, 'weekly_counts': weekly_counts, 'weeks_between': weeks_between, 'start_date': start_date, 'end_date': end_date, }
def simple_search(request): ip_addresses = [] dashes = [] query = [] tests = None findings = None finding_templates = None products = None tagged_tests = None tagged_findings = None tagged_products = None tagged_endpoints = None tagged_engagements = None tagged_finding_templates = None engagements = None endpoints = None languages = None app_analysis = None clean_query = '' cookie = False terms = '' form = SimpleSearchForm() original_clean_query = "" findings_filter = None title_words = None component_words = None paged_generic = None # if request.method == 'GET' and "query" in request.GET: if request.method == 'GET': form = SimpleSearchForm(request.GET) if form.is_valid(): cookie = True clean_query = form.cleaned_data['query'] or '' original_clean_query = clean_query operators, keywords = parse_search_query(clean_query) search_tags = "tag" in operators or "test-tag" in operators or "engagement-tag" in operators or "product-tag" in operators or \ "tags" in operators or "test-tags" in operators or "engagement-tags" in operators or "product-tags" in operators or \ "not-tag" in operators or "not-test-tag" in operators or "not-engagement-tag" in operators or "not-product-tag" in operators or \ "not-tags" in operators or "not-test-tags" in operators or "not-engagement-tags" in operators or "not-product-tags" in operators search_cve = "cve" in operators search_finding_id = "id" in operators search_findings = "finding" in operators or search_cve or search_finding_id or search_tags or not operators search_finding_templates = "template" in operators or search_tags or not ( operators or search_finding_id or search_cve) search_tests = "test" in operators or search_tags or not ( operators or search_finding_id or search_cve) search_engagements = "engagement" in operators or search_tags or not ( operators or search_finding_id or search_cve) search_products = "product" in operators or search_tags or not ( operators or search_finding_id or search_cve) search_endpoints = "endpoint" in operators or search_tags or not ( operators or search_finding_id or search_cve) search_languages = "language" in operators or search_tags or not ( operators or search_finding_id or search_cve) search_technologies = "technology" in operators or search_tags or not ( operators or search_finding_id or search_cve) authorized_findings = get_authorized_findings( Permissions.Finding_View) authorized_tests = get_authorized_tests(Permissions.Test_View) authorized_engagements = get_authorized_engagements( Permissions.Engagement_View) authorized_products = get_authorized_products( Permissions.Product_View) authorized_endpoints = get_authorized_endpoints( Permissions.Endpoint_View) authorized_finding_templates = Finding_Template.objects.all() # TODO better get findings in their own query and match on id. that would allow filtering on additional fields such cve, prod_id, etc. findings = authorized_findings tests = authorized_tests engagements = authorized_engagements products = authorized_products endpoints = authorized_endpoints findings_filter = None title_words = None component_words = None keywords_query = ' '.join(keywords) if search_finding_id: logger.debug('searching finding id') findings = authorized_findings findings = findings.filter(id=operators['id'][0]) elif search_findings: logger.debug('searching findings') findings_filter = OpenFindingFilter(request.GET, queryset=findings, user=request.user, pid=None, prefix='finding') # setting initial values for filters is not supported and discouraged: https://django-filter.readthedocs.io/en/stable/guide/tips.html#using-initial-values-as-defaults # we could try to modify request.GET before generating the filter, but for now we'll leave it as is title_words = get_words_for_field(Finding, 'title') component_words = get_words_for_field(Finding, 'component_name') findings = findings_filter.qs findings = apply_tag_filters(findings, operators) findings = apply_endpoint_filter(findings, operators) findings = apply_cve_filter(findings, operators) findings = perform_keyword_search_for_operator( findings, operators, 'finding', keywords_query) else: findings = None findings_filter = None component_words = None # prefetch after watson to avoid inavlid query errors due to watson not understanding prefetching if findings is not None: # check for None to avoid query execution logger.debug('prefetching findings') findings = get_page_items(request, findings, 25) findings.object_list = prefetch_for_findings( findings.object_list) # some over the top tag displaying happening... findings.object_list = findings.object_list.prefetch_related( 'test__engagement__product__tags') tag = operators['tag'] if 'tag' in operators else keywords tags = operators['tags'] if 'tags' in operators else keywords not_tag = operators[ 'not-tag'] if 'not-tag' in operators else keywords not_tags = operators[ 'not-tags'] if 'not-tags' in operators else keywords if search_tags and tag or tags or not_tag or not_tags: logger.debug('searching tags') Q1, Q2, Q3, Q4 = Q(), Q(), Q(), Q() if tag: tag = ','.join(tag) # contains needs a single value Q1 = Q(tags__name__contains=tag) if tags: Q2 = Q(tags__name__in=tags) if not_tag: not_tag = ','.join( not_tag) # contains needs a single value Q3 = Q(tags__name__contains=not_tag) if not_tags: Q4 = Q(tags__name__in=not_tags) tagged_findings = authorized_findings.filter(Q1 | Q2).exclude( Q3 | Q4).distinct()[:max_results].prefetch_related('tags') tagged_finding_templates = authorized_finding_templates.filter( Q1 | Q2).exclude(Q3 | Q4).distinct()[:max_results] tagged_tests = authorized_tests.filter(Q1 | Q2).exclude( Q3 | Q4).distinct()[:max_results].prefetch_related('tags') tagged_engagements = authorized_engagements.filter( Q1 | Q2).exclude( Q3 | Q4).distinct()[:max_results].prefetch_related('tags') tagged_products = authorized_products.filter(Q1 | Q2).exclude( Q3 | Q4).distinct()[:max_results].prefetch_related('tags') tagged_endpoints = authorized_endpoints.filter( Q1 | Q2).exclude( Q3 | Q4).distinct()[:max_results].prefetch_related('tags') else: tagged_findings = None tagged_finding_templates = None tagged_tests = None tagged_engagements = None tagged_products = None tagged_endpoints = None tagged_results = tagged_findings or tagged_finding_templates or tagged_tests or tagged_engagements or tagged_products or tagged_endpoints if search_finding_templates: logger.debug('searching finding templates') finding_templates = authorized_finding_templates finding_templates = apply_tag_filters(finding_templates, operators) if keywords_query: watson_results = watson.filter(finding_templates, keywords_query) finding_templates = finding_templates.filter( id__in=[watson.id for watson in watson_results]) finding_templates = finding_templates[:max_results] else: finding_templates = None if search_tests: logger.debug('searching tests') tests = authorized_tests tests = apply_tag_filters(tests, operators) if keywords_query: watson_results = watson.filter(tests, keywords_query) tests = tests.filter( id__in=[watson.id for watson in watson_results]) tests = tests.prefetch_related('engagement', 'engagement__product', 'test_type', 'tags', 'engagement__tags', 'engagement__product__tags') tests = tests[:max_results] else: tests = None if search_engagements: logger.debug('searching engagements') engagements = authorized_engagements engagements = apply_tag_filters(engagements, operators) if keywords_query: watson_results = watson.filter(engagements, keywords_query) engagements = engagements.filter( id__in=[watson.id for watson in watson_results]) engagements = engagements.prefetch_related( 'product', 'product__tags', 'tags') engagements = engagements[:max_results] else: engagements = None if search_products: logger.debug('searching products') products = authorized_products products = apply_tag_filters(products, operators) if keywords_query: watson_results = watson.filter(products, keywords_query) products = products.filter( id__in=[watson.id for watson in watson_results]) products = products.prefetch_related('tags') products = products[:max_results] else: products = None if search_endpoints: logger.debug('searching endpoint') endpoints = authorized_endpoints endpoints = apply_tag_filters(endpoints, operators) endpoints = endpoints.filter( Q(host__icontains=keywords_query) | Q(path__icontains=keywords_query) | Q(protocol__icontains=keywords_query) | Q(query__icontains=keywords_query) | Q(fragment__icontains=keywords_query)) endpoints = prefetch_for_endpoints(endpoints) endpoints = endpoints[:max_results] else: endpoints = None if search_languages: logger.debug('searching languages') languages = Languages.objects.filter( language__language__icontains=keywords_query) languages = languages.prefetch_related('product', 'product__tags') languages = languages[:max_results] else: languages = None if search_technologies: logger.debug('searching technologies') app_analysis = App_Analysis.objects.filter( name__icontains=keywords_query) app_analysis = app_analysis[:max_results] else: app_analysis = None # make sure watson only searches in authorized model instances if keywords_query: logger.debug('searching generic') logger.debug('going generic with: %s', keywords_query) generic = watson.search( keywords_query, models=( authorized_findings, authorized_tests, authorized_engagements, authorized_products, authorized_endpoints, authorized_finding_templates, App_Analysis)).prefetch_related('object')[:max_results] else: generic = None # paging doesn't work well with django_watson # paged_generic = get_page_items(request, generic, 25) # generic = get_page_items(request, generic, 25) # generic = watson.search(original_clean_query)[:50].prefetch_related('object') # generic = watson.search("qander document 'CVE-2019-8331'")[:10].prefetch_related('object') # generic = watson.search("'CVE-2020-6754'")[:10].prefetch_related('object') # generic = watson.search(" 'ISEC-433'")[:10].prefetch_related('object') logger.debug('all searched') else: logger.debug(form.errors) form = SimpleSearchForm() add_breadcrumb(title="Simple Search", top_level=True, request=request) activetab = 'findings' if findings \ else 'products' if products \ else 'engagements' if engagements else \ 'tests' if tests else \ 'endpoint' if endpoints else \ 'tagged' if tagged_results else \ 'generic' response = render( request, 'dojo/simple_search.html', { 'clean_query': original_clean_query, 'languages': languages, 'app_analysis': app_analysis, 'tests': tests, 'findings': findings, 'finding_templates': finding_templates, 'filtered': findings_filter, 'title_words': title_words, 'component_words': component_words, 'products': products, 'tagged_tests': tagged_tests, 'tagged_findings': tagged_findings, 'tagged_finding_templates': tagged_finding_templates, 'tagged_products': tagged_products, 'tagged_endpoints': tagged_endpoints, 'tagged_engagements': tagged_engagements, 'engagements': engagements, 'endpoints': endpoints, 'name': 'Simple Search', 'metric': False, 'user': request.user, 'form': form, 'activetab': activetab, 'show_product_column': True, 'generic': generic }) if cookie: response.set_cookie("highlight", value=keywords_query, max_age=None, expires=None, path='/', secure=True, httponly=False) else: response.delete_cookie("highlight", path='/') return response '''