Skip to content

Commit b0fd70a

Browse files
Merge pull request #2398 from valentijnscholten/my-1.6.0
1.6.0 bugfix PRs
2 parents 9b4178f + 54d0f02 commit b0fd70a

22 files changed

+92918
-700
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ Quarterly.txt
9393
components/*
9494
!components/package.json
9595
!components/yarn.lock
96-
dojo/static/*
96+
# dojo/static/*
9797
!dojo/static/dojo/*
9898
dojo/media
9999
/static

docker/entrypoint-integration-tests.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,22 @@ fi
1313

1414
# Run available unittests with a simple setup
1515
echo "Running Product type integration tests"
16+
# All available Integrationtest Scripts are activated below
17+
# If successsful, A successs message is printed and the script continues
18+
# If any script is unsuccesssful a failure message is printed and the test script
19+
# Exits with status code of 1
20+
21+
function fail() {
22+
echo "Error: $1 test failed\n"
23+
exit 1
24+
}
25+
26+
function success() {
27+
echo "Success: $1 test passed\n"
28+
}
29+
30+
test="Product type integration tests"
31+
echo "Running: $test"
1632
if python3 tests/Product_type_unit_test.py ; then
1733
echo "Success: Product type integration tests passed"
1834
else

dojo/engagement/views.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,6 @@ def import_scan_results(request, eid=None, pid=None):
522522
cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter(
523523
engagement=engagement).order_by('cred_id')
524524

525-
526525
if form.is_valid():
527526
# Allows for a test to be imported with an engagement created on the fly
528527
if engagement is None:
@@ -692,6 +691,7 @@ def import_scan_results(request, eid=None, pid=None):
692691

693692
create_notification(
694693
event='results_added',
694+
initiator=request.user,
695695
title=str(finding_count) + " findings for " + engagement.product.name,
696696
finding_count=finding_count,
697697
test=t,

dojo/finding/views.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,24 +1037,22 @@ def edit_finding(request, fid):
10371037
enabled = finding.test.engagement.product.jira_pkey_set.first().push_all_issues
10381038
jform = JIRAFindingForm(enabled=enabled, prefix='jiraform')
10391039

1040-
gform = None
10411040
try:
10421041
jissue = JIRA_Issue.objects.get(finding=finding)
10431042
enabled = True
10441043
except:
10451044
enabled = False
1046-
pass
10471045

10481046
try:
10491047
gissue = GITHUB_Issue.objects.get(finding=finding)
1050-
enabled = True
1048+
github_enabled = True
10511049
except:
1052-
enabled = False
1053-
pass
1050+
github_enabled = False
10541051

1055-
if get_system_setting('enable_github') and GITHUB_PKey.objects.filter(
1056-
product=finding.test.engagement.product) != 0:
1057-
gform = GITHUBFindingForm(enabled=enabled, prefix='githubform')
1052+
gform = None
1053+
if get_system_setting('enable_github'):
1054+
if GITHUB_PKey.objects.filter(product=finding.test.engagement.product).exclude(git_conf_id=None):
1055+
gform = GITHUBFindingForm(enabled=github_enabled, prefix='githubform')
10581056

10591057
if request.method == 'POST':
10601058
form = FindingForm(request.POST, instance=finding, template=False)
@@ -1128,7 +1126,7 @@ def edit_finding(request, fid):
11281126

11291127
if 'githubform-push_to_github' in request.POST:
11301128
gform = GITHUBFindingForm(
1131-
request.POST, prefix='githubform', enabled=enabled)
1129+
request.POST, prefix='githubform', enabled=github_enabled)
11321130
if gform.is_valid():
11331131
if GITHUB_Issue.objects.filter(finding=new_finding).exists():
11341132
update_external_issue_task.delay(
@@ -2148,7 +2146,7 @@ def finding_bulk_update_all(request, pid=None):
21482146
logger.info('push selected findings to github')
21492147
finds = Finding.objects.filter(id__in=finding_to_update)
21502148
for finding in finds:
2151-
print('will push to github finding: ' + str(finding))
2149+
print('will push to GitHub finding: ' + str(finding))
21522150
old_status = finding.status()
21532151
if form.cleaned_data['push_to_github']:
21542152
if GITHUB_Issue.objects.filter(finding=finding).exists():

dojo/github.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ def add_external_issue_github(find, prod, eng):
109109
eng = Engagement.objects.get(test=find.test)
110110
prod = Product.objects.get(engagement=eng)
111111
github_product_key = GITHUB_PKey.objects.get(product=prod)
112-
github_conf = github_product_key.git_conf
113-
logger.debug('Create issue with github profile: ' + str(github_conf) + ' on product: ' + str(github_product_key))
112+
github_conf = github_product_key.git_conf_id
113+
logger.info('Create issue with github profile: ' + str(github_conf) + ' on product: ' + str(github_product_key))
114114

115115
try:
116116
g = Github(github_conf.api_key)

dojo/models.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,14 +1806,10 @@ def save(self, dedupe_option=True, false_history=False, rules_option=True,
18061806
if rules_option:
18071807
from dojo.tasks import async_rules
18081808
from dojo.utils import sync_rules
1809-
try:
1810-
if self.reporter.usercontactinfo.block_execution:
1811-
sync_rules(self, *args, **kwargs)
1812-
else:
1813-
async_rules(self, *args, **kwargs)
1814-
except UserContactInfo.DoesNotExist:
1809+
if hasattr(self.reporter, 'usercontactinfo') and self.reporter.usercontactinfo.block_execution:
1810+
sync_rules(self, *args, **kwargs)
1811+
else:
18151812
async_rules(self, *args, **kwargs)
1816-
pass
18171813
from dojo.utils import calculate_grade
18181814
calculate_grade(self.test.engagement.product)
18191815
# Assign the numerical severity for correct sorting order

dojo/notifications/helper.py

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
import requests
2+
import logging
3+
from django.core.mail import EmailMessage
4+
from dojo.models import Notifications, Dojo_User, Alerts, UserContactInfo
5+
from django.template.loader import render_to_string
6+
from django.db.models import Q, Count, Prefetch
7+
from django.urls import reverse
8+
9+
logger = logging.getLogger(__name__)
10+
11+
12+
def create_notification(event=None, *args, **kwargs):
13+
# System notifications
14+
try:
15+
system_notifications = Notifications.objects.get(user=None)
16+
except Exception:
17+
system_notifications = Notifications()
18+
19+
logger.debug('creating system notifications')
20+
process_notifications(event, system_notifications, *args, **kwargs)
21+
22+
if 'recipients' in kwargs:
23+
# mimic existing code so that when recipients is specified, no other personal notifications are sent.
24+
logger.debug('creating notifications for recipients')
25+
for recipient_notifications in Notifications.objects.filter(user__username__in=kwargs['recipients'], user__is_active=True):
26+
# kwargs.update({'user': recipient_notifications.user})
27+
process_notifications(event, recipient_notifications, *args, **kwargs)
28+
else:
29+
# Personal but global notifications
30+
# only retrieve users which have at least one notification type enabled for this event type.
31+
logger.debug('creating personal notifications')
32+
33+
product = None
34+
if 'product' in kwargs:
35+
product = kwargs.get('product')
36+
37+
if not product and 'engagement' in kwargs:
38+
product = kwargs['engagement'].product
39+
40+
if not product and 'test' in kwargs:
41+
product = kwargs['test'].engagement.product
42+
43+
# get users with either global notifications, or a product specific noditiciation
44+
users = Dojo_User.objects.filter(is_active=True).prefetch_related(Prefetch(
45+
"notifications_set",
46+
queryset=Notifications.objects.filter(Q(product_id=product) | Q(product__isnull=True)),
47+
to_attr="applicable_notifications"
48+
)).annotate(applicable_notifications_count=Count('notifications__id', filter=Q(notifications__product_id=product) | Q(notifications__product__isnull=True))).filter(applicable_notifications_count__gt=0)
49+
50+
for user in users:
51+
# send notifications to user after merging possible multiple notifications records (i.e. personal global + personal product)
52+
# kwargs.update({'user': user})
53+
process_notifications(event, Notifications.merge_notifications_list(user.applicable_notifications), *args, **kwargs)
54+
55+
56+
def create_description(event, *args, **kwargs):
57+
if "description" not in kwargs.keys():
58+
if event == 'product_added':
59+
kwargs["description"] = "Product " + kwargs['title'] + " has been created successfully."
60+
else:
61+
kwargs["description"] = "Event " + str(event) + " has occured."
62+
63+
return kwargs["description"]
64+
65+
66+
def create_notification_message(event, user, notification_type, *args, **kwargs):
67+
template = 'notifications/%s.tpl' % event.replace('/', '')
68+
kwargs.update({'type': notification_type})
69+
kwargs.update({'user': user})
70+
71+
try:
72+
notification = render_to_string(template, kwargs)
73+
except Exception as e:
74+
logger.exception(e)
75+
create_description(event)
76+
notification = render_to_string('notifications/other.tpl', kwargs)
77+
78+
return notification
79+
80+
81+
def process_notifications(event, notifications=None, *args, **kwargs):
82+
from dojo.utils import get_system_setting
83+
84+
if not notifications:
85+
logger.warn('no notifications!')
86+
return
87+
88+
sync = 'initiator' in kwargs and hasattr(kwargs['initiator'], 'usercontactinfo') and kwargs['initiator'].usercontactinfo.block_execution
89+
90+
logger.debug('sync: %s', sync)
91+
logger.debug('sending notifications ' + ('synchronously' if sync else 'asynchronously'))
92+
logger.debug(vars(notifications))
93+
94+
slack_enabled = get_system_setting('enable_slack_notifications')
95+
hipchat_enabled = get_system_setting('enable_hipchat_notifications')
96+
mail_enabled = get_system_setting('enable_mail_notifications')
97+
98+
from dojo.tasks import send_slack_notification_task, send_alert_notification_task, send_hipchat_notification_task, send_mail_notification_task
99+
100+
if slack_enabled and 'slack' in getattr(notifications, event):
101+
if not sync:
102+
send_slack_notification_task.delay(event, notifications.user, *args, **kwargs)
103+
else:
104+
send_slack_notification(event, notifications.user, *args, **kwargs)
105+
106+
if hipchat_enabled and 'hipchat' in getattr(notifications, event):
107+
if not sync:
108+
send_hipchat_notification_task.delay(event, notifications.user, *args, **kwargs)
109+
else:
110+
send_hipchat_notification(event, notifications.user, *args, **kwargs)
111+
112+
if mail_enabled and 'mail' in getattr(notifications, event):
113+
if not sync:
114+
send_mail_notification_task.delay(event, notifications.user, *args, **kwargs)
115+
else:
116+
send_mail_notification(event, notifications.user, *args, **kwargs)
117+
118+
print(getattr(notifications, event, None))
119+
if 'alert' in getattr(notifications, event, None):
120+
if not sync:
121+
send_alert_notification_task.delay(event, notifications.user, *args, **kwargs)
122+
else:
123+
send_alert_notification(event, notifications.user, *args, **kwargs)
124+
125+
126+
def send_slack_notification(event, user=None, *args, **kwargs):
127+
from dojo.utils import get_system_setting, get_slack_user_id
128+
if user is not None:
129+
if hasattr(user, 'usercontactinfo') and user.usercontactinfo.slack_username is not None:
130+
slack_user_id = user.usercontactinfo.slack_user_id
131+
if user.usercontactinfo.slack_user_id is None:
132+
# Lookup the slack userid
133+
slack_user_id = get_slack_user_id(
134+
user.usercontactinfo.slack_username)
135+
slack_user_save = UserContactInfo.objects.get(user_id=user.id)
136+
slack_user_save.slack_user_id = slack_user_id
137+
slack_user_save.save()
138+
139+
channel = '@%s' % slack_user_id
140+
else:
141+
# user has no slack username, skip
142+
return
143+
else:
144+
channel = get_system_setting('slack_channel')
145+
146+
try:
147+
res = requests.request(
148+
method='POST',
149+
url='https://slack.com/api/chat.postMessage',
150+
data={
151+
'token': get_system_setting('slack_token'),
152+
'channel': channel,
153+
'username': get_system_setting('slack_username'),
154+
'text': create_notification_message(event, user, 'slack', *args, **kwargs)
155+
})
156+
except Exception as e:
157+
logger.exception(e)
158+
log_alert(e, *args, **kwargs)
159+
pass
160+
161+
162+
def send_hipchat_notification(event, user=None, *args, **kwargs):
163+
from dojo.utils import get_system_setting
164+
if user:
165+
# HipChat doesn't seem to offer direct message functionality, so no HipChat PM functionality here...
166+
return
167+
168+
try:
169+
# We use same template for HipChat as for slack
170+
res = requests.request(
171+
method='POST',
172+
url='https://%s/v2/room/%s/notification?auth_token=%s' %
173+
(get_system_setting('hipchat_site'),
174+
get_system_setting('hipchat_channel'),
175+
get_system_setting('hipchat_token')),
176+
data={
177+
'message': create_notification_message(event, 'slack', *args, **kwargs),
178+
'message_format': 'text'
179+
})
180+
except Exception as e:
181+
logger.exception(e)
182+
log_alert(e, *args, **kwargs)
183+
pass
184+
185+
186+
def send_mail_notification(event, user=None, *args, **kwargs):
187+
from dojo.utils import get_system_setting
188+
189+
if user:
190+
address = user.email
191+
else:
192+
address = get_system_setting('mail_notifications_to')
193+
194+
subject = '%s notification' % get_system_setting('team_name')
195+
if 'title' in kwargs:
196+
subject += ': %s' % kwargs['title']
197+
try:
198+
email = EmailMessage(
199+
subject,
200+
create_notification_message(event, user, 'mail', *args, **kwargs),
201+
get_system_setting('mail_notifications_from'),
202+
[address],
203+
headers={"From": "{}".format(get_system_setting('mail_notifications_from'))}
204+
)
205+
email.content_subtype = 'html'
206+
logger.debug('sending email alert')
207+
# logger.info(create_notification_message(event, 'mail'))
208+
email.send(fail_silently=False)
209+
210+
except Exception as e:
211+
logger.exception(e)
212+
log_alert(e, *args, **kwargs)
213+
pass
214+
215+
216+
def send_alert_notification(event, user=None, *args, **kwargs):
217+
icon = kwargs.get('icon', 'info-circle')
218+
alert = Alerts(
219+
user_id=user,
220+
title=kwargs.get('title'),
221+
description=create_notification_message(event, user, 'alert', *args, **kwargs),
222+
url=kwargs.get('url', reverse('alerts')),
223+
icon=icon,
224+
source=Notifications._meta.get_field(event).verbose_name.title())
225+
alert.save()
226+
227+
228+
def log_alert(e, *args, **kwargs):
229+
users = Dojo_User.objects.filter(is_superuser=True)
230+
for user in users:
231+
alert = Alerts(
232+
user_id=user,
233+
url=kwargs.get('url', reverse('alerts')),
234+
title='Notification issue',
235+
description="%s" % e,
236+
icon="exclamation-triangle",
237+
source="Notifications")
238+
alert.save()

0 commit comments

Comments
 (0)