Skip to content

Commit

Permalink
Merge pull request #370 from GhostManager/hotfix/holiday-bugs
Browse files Browse the repository at this point in the history
Holiday Bug Fixes
  • Loading branch information
chrismaddalena authored Dec 13, 2023
2 parents 6bd74d2 + 3078819 commit c33041b
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 70 deletions.
5 changes: 5 additions & 0 deletions ghostwriter/modules/notifications_slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ def craft_burned_msg(
self,
domain: str,
categories: str,
scanners: str,
burned_explanation: str,
) -> list:
"""
Expand Down Expand Up @@ -316,6 +317,10 @@ def craft_burned_msg(
"type": "mrkdwn",
"text": f"*Categories:*\n{categories}",
},
{
"type": "mrkdwn",
"text": f"*Flagged as Malicious By:*\n{scanners}",
},
],
},
{
Expand Down
19 changes: 15 additions & 4 deletions ghostwriter/modules/review.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ def check_domain_status(self):
# Ignore any expired domains because we don't control them anymore
if domain.is_expired() is False:
domain_categories = {}
malicious_scans = []
bad_categories = []
burned_explanations = []
lab_results[domain.id] = {}
Expand Down Expand Up @@ -216,10 +217,19 @@ def check_domain_status(self):
if "last_analysis_stats" in vt_results["data"]:
analysis_stats = vt_results["data"]["last_analysis_stats"]
if analysis_stats["malicious"] > 0:
for scanner, result in vt_results["data"]["last_analysis_results"].items():
if result["result"] == "malicious":
malicious_scans.append(scanner)
burned = True
burned_explanations.append("A VirusTotal scanner has flagged the domain as malicious.")
burned_explanations.append(
"{} VirusTotal scanner(s) ({}) flagged the domain as malicious.".format(
analysis_stats["malicious"],
", ".join(malicious_scans),
)
)
logger.warning(
"A VirusTotal scanner has flagged the %s as malicious",
"%s VirusTotal scanners flagged the %s as malicious",
analysis_stats["malicious"],
domain_name,
)

Expand All @@ -234,17 +244,18 @@ def check_domain_status(self):
)
)
logger.warning(
"There are %s VirusTotal community votes flagging the the domain as malicious",
"There are %s VirusTotal community votes flagging the the domain as malicious.",
votes["malicious"],
)

else:
lab_results[domain.id]["vt_results"] = "none"
logger.warning("Did not receive results for %s from VirusTotal", domain_name)
logger.warning("Did not receive results for %s from VirusTotal.", domain_name)

# Assemble the dictionary to return for this domain
lab_results[domain.id]["burned"] = burned
lab_results[domain.id]["categories"] = domain_categories
lab_results[domain.id]["scanners"] = malicious_scans
lab_results[domain.id]["warnings"]["messages"] = warnings
lab_results[domain.id]["warnings"]["total"] = len(warnings)
if burned:
Expand Down
44 changes: 0 additions & 44 deletions ghostwriter/rolodex/templates/rolodex/project_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -1870,50 +1870,6 @@ <h4>Project Notes</h4>

prepareTodoList();
});

{% comment %} Create a new project point of contact from a client contact {% endcomment %}
$(document).ready(function () {
$('#id_client_contact').change(function () {
let option =$(this).val();
if(option === -1) {
$('#assign-btn').prop('disabled', true);
} else {
$('#assign-btn').prop('disabled',false);
}
});
$('#assign-project-contact-form').submit(function (e) {
e.preventDefault();
let url = $(this).attr('action');
let $contact = $('#id_client_contact')
let contactId = $contact.val();
let csrftoken = $('input[name=csrfmiddlewaretoken]').val();
if ($contact.val() === '') {
contactId = -1
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader('X-CSRFToken', csrftoken);
}
}
});
$.ajax({
url: url,
type: 'POST',
dataType: 'json',
data: {
'contact': contactId,
'csrfmiddlewaretoken': csrftoken,
},
success: function (data) {
if (data['message']) {
displayToastTop({type: data['result'], string: data['message'], title: 'Contacts Update'});
}
update_project_contacts();
},
});
});
});
</script>

{% comment %} Generate modals for displaying the scope lists {% endcomment %}
Expand Down
46 changes: 46 additions & 0 deletions ghostwriter/rolodex/templates/snippets/project_contacts_table.html
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,49 @@ <h4>Project Points of Contacts</h4>
</div>
</form>
</div>

<script>
{% comment %} Create a new project point of contact from a client contact {% endcomment %}
$(document).ready(function () {
$('#id_client_contact').change(function () {
let option = $(this).val();
if (option === -1) {
$('#assign-btn').prop('disabled', true);
} else {
$('#assign-btn').prop('disabled', false);
}
});
$('#assign-project-contact-form').submit(function (e) {
e.preventDefault();
let url = $(this).attr('action');
let $contact = $('#id_client_contact')
let contactId = $contact.val();
let csrftoken = $('input[name=csrfmiddlewaretoken]').val();
if ($contact.val() === '') {
contactId = -1
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader('X-CSRFToken', csrftoken);
}
}
});
$.ajax({
url: url,
type: 'POST',
dataType: 'json',
data: {
'contact': contactId,
'csrfmiddlewaretoken': csrftoken,
},
success: function (data) {
if (data['message']) {
displayToastTop({type: data['result'], string: data['message'], title: 'Contacts Update'});
}
update_project_contacts();
},
});
});
});
</script>
35 changes: 35 additions & 0 deletions ghostwriter/rolodex/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -828,3 +828,38 @@ def test_invalid_contact_id(self):
response = self.client_mgr.post(self.uri, {"contact": -1})
self.assertEqual(response.status_code, 200)
self.assertJSONEqual(force_str(response.content), data)


class ProjectDetailViewTests(TestCase):
"""Collection of tests for :view:`rolodex.ProjectDetailView`."""

@classmethod
def setUpTestData(cls):
cls.user = UserFactory(password=PASSWORD)
cls.user_mgr = UserFactory(password=PASSWORD, role="manager")
cls.project = ProjectFactory()
cls.uri = reverse("rolodex:project_detail", kwargs={"pk": cls.project.pk})

def setUp(self):
self.client = Client()
self.client_auth = Client()
self.client_mgr = Client()
self.assertTrue(self.client_auth.login(username=self.user.username, password=PASSWORD))
self.assertTrue(self.client_mgr.login(username=self.user_mgr.username, password=PASSWORD))

def test_view_uri_exists_at_desired_location(self):
response = self.client_mgr.get(self.uri)
self.assertEqual(response.status_code, 200)

def test_view_requires_login_and_permissions(self):
response = self.client.get(self.uri)
self.assertEqual(response.status_code, 302)

response = self.client_mgr.get(self.uri)
self.assertEqual(response.status_code, 200)

response = self.client_auth.get(self.uri)
self.assertEqual(response.status_code, 302)
ProjectAssignmentFactory(project=self.project, operator=self.user)
response = self.client_auth.get(self.uri)
self.assertEqual(response.status_code, 200)
33 changes: 14 additions & 19 deletions ghostwriter/rolodex/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,22 @@ def update_project_contacts(request, pk):
if not verify_access(request.user, project_instance):
return ForbiddenJsonResponse()

contacts = ClientContact.objects.filter(client=project_instance.client)
for contact in contacts:
if (
ProjectContact.objects.filter(
name=contact.name,
email=contact.email,
phone=contact.phone,
project=project_instance,
).count()
> 0
):
contacts = contacts.exclude(id=contact.id)

html = render_to_string(
"snippets/project_contacts_table.html",
{"project": project_instance},
{"project": project_instance, "client_contacts": contacts},
)
return HttpResponse(html)

Expand Down Expand Up @@ -1439,24 +1452,6 @@ def handle_no_permission(self):
messages.error(self.request, "You do not have permission to access that.")
return redirect("home:dashboard")

def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)

contacts = ClientContact.objects.filter(client=self.object.client)
for contact in contacts:
if (
ProjectContact.objects.filter(
name=contact.name,
email=contact.email,
phone=contact.phone,
project=self.object,
).count()
> 0
):
contacts = contacts.exclude(id=contact.id)
ctx["client_contacts"] = contacts
return ctx


class ProjectCreate(RoleBasedAccessControlMixin, CreateView):
"""
Expand Down
16 changes: 13 additions & 3 deletions ghostwriter/shepherd/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,9 @@ def release_domains(no_action=False):
# Check if tomorrow is the end date
if date.today() == warning_date:
release_me = False
message = "Your domain, {}, will be released tomorrow! Modify the project's end date as needed.".format(
domain.name
message = "Reminder: your project is ending soon and your domain, {}, will be released when it does. If your project is still ending after EOB on {}, you don't need to do anything!".format(
domain.name,
release_date,
)
if slack.enabled:
err = slack.send_msg(message, slack_channel)
Expand Down Expand Up @@ -392,10 +393,19 @@ def check_domains(domain_id=None):
if lab_results[k]["burned"]:
domain_qs.health_status = HealthStatus.objects.get(health_status="Burned")
change = "burned"
pretty_categories = []
for vendor, category in lab_results[k]["categories"].items():
pretty_categories.append(f"{vendor}: {category}")

scanners = "N/A"
if lab_results[k]["scanners"]:
scanners = "\n".join(lab_results[k]["scanners"])

if slack.enabled:
blocks = slack.craft_burned_msg(
v["domain"],
lab_results[k]["categories"],
"\n".join(pretty_categories),
scanners,
lab_results[k]["burned_explanation"],
)
if slack.enabled:
Expand Down

0 comments on commit c33041b

Please sign in to comment.