Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
chrismaddalena committed Sep 18, 2023
2 parents 0a5a147 + f6e4353 commit 1a21699
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 23 deletions.
6 changes: 6 additions & 0 deletions compose/production/postgres/maintenance/restore
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ export PGUSER="${POSTGRES_USER}"
export PGPASSWORD="${POSTGRES_PASSWORD}"
export PGDATABASE="${POSTGRES_DB}"


### It's Required to terminate current connections to delete the database
message_info "Cleaning connections to the database..."

psql -c "REVOKE CONNECT ON DATABASE ${PGDATABASE} FROM public; ALTER database ${POSTGRES_DB} allow_connections = off; SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '${PGDATABASE}';" postgres

message_info "Dropping the database..."
dropdb "${PGDATABASE}"

Expand Down
83 changes: 60 additions & 23 deletions ghostwriter/modules/reportwriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -1325,7 +1325,7 @@ def _parse_html_lists(self, tag, prev_p, num, finding, level=0):
# Return last paragraph created
return p

def _process_text_xml(self, text, finding=None):
def _process_text_xml(self, text, finding=None, p_style=None):
"""
Process the provided text from the specified finding to parse keywords for
evidence placement and formatting for Office XML.
Expand Down Expand Up @@ -1379,7 +1379,7 @@ def _process_text_xml(self, text, finding=None):
p = self.finding_body_shape.text_frame.add_paragraph()
ALIGNMENT = PP_ALIGN
else:
p = self.sacrificial_doc.add_paragraph()
p = self.sacrificial_doc.add_paragraph(style=p_style)
ALIGNMENT = WD_ALIGN_PARAGRAPH

# Check for alignment classes on the ``p`` tag
Expand Down Expand Up @@ -1565,92 +1565,129 @@ def _process_richtext(self, context: dict) -> dict:
Pre-defined template context
"""

def render_subdocument(section, finding):
def render_subdocument(section, finding, p_style=None):
if section:
self.sacrificial_doc = self.word_doc.new_subdoc()
self._process_text_xml(section, finding)
self._process_text_xml(section, finding, p_style)
return self.sacrificial_doc
return None

# Findings
for finding in context["findings"]:

logger.info("Processing %s", finding["title"])
# Create ``RichText()`` object for a colored severity category
finding["severity_rt"] = RichText(finding["severity"], color=finding["severity_color"])
finding["cvss_score_rt"] = RichText(finding["cvss_score"], color=finding["severity_color"])
finding["cvss_vector_rt"] = RichText(finding["cvss_vector"], color=finding["severity_color"])
# Create subdocuments for each finding section
finding["affected_entities_rt"] = render_subdocument(finding["affected_entities"], finding)
finding["description_rt"] = render_subdocument(finding["description"], finding)
finding["impact_rt"] = render_subdocument(finding["impact"], finding)
finding["affected_entities_rt"] = render_subdocument(
finding["affected_entities"], finding, self.report_queryset.docx_template.p_style
)
finding["description_rt"] = render_subdocument(
finding["description"], finding, self.report_queryset.docx_template.p_style
)
finding["impact_rt"] = render_subdocument(
finding["impact"], finding, self.report_queryset.docx_template.p_style
)

# Include a copy of ``mitigation`` as ``recommendation`` to match legacy context
mitigation_section = render_subdocument(finding["mitigation"], finding)
mitigation_section = render_subdocument(
finding["mitigation"], finding, self.report_queryset.docx_template.p_style
)
finding["mitigation_rt"] = mitigation_section
finding["recommendation_rt"] = mitigation_section

finding["replication_steps_rt"] = render_subdocument(finding["replication_steps"], finding)
finding["host_detection_techniques_rt"] = render_subdocument(finding["host_detection_techniques"], finding)
finding["replication_steps_rt"] = render_subdocument(
finding["replication_steps"], finding, self.report_queryset.docx_template.p_style
)
finding["host_detection_techniques_rt"] = render_subdocument(
finding["host_detection_techniques"], finding, self.report_queryset.docx_template.p_style
)
finding["network_detection_techniques_rt"] = render_subdocument(
finding["network_detection_techniques"], finding
finding["network_detection_techniques"], finding, self.report_queryset.docx_template.p_style
)
finding["references_rt"] = render_subdocument(
finding["references"], finding, self.report_queryset.docx_template.p_style
)
finding["references_rt"] = render_subdocument(finding["references"], finding)

# Client Notes
context["client"]["note_rt"] = render_subdocument(context["client"]["note"], finding=None)
context["client"]["address_rt"] = render_subdocument(context["client"]["address"], finding=None)
context["client"]["note_rt"] = render_subdocument(
context["client"]["note"], finding=None, p_style=self.report_queryset.docx_template.p_style
)
context["client"]["address_rt"] = render_subdocument(
context["client"]["address"], finding=None, p_style=self.report_queryset.docx_template.p_style
)

# Project Notes
context["project"]["note_rt"] = render_subdocument(context["project"]["note"], finding=None)
context["project"]["note_rt"] = render_subdocument(
context["project"]["note"], finding=None, p_style=self.report_queryset.docx_template.p_style
)

# Assignments
for assignment in context["team"]:
if isinstance(assignment, dict):
if assignment["note"]:
assignment["note_rt"] = render_subdocument(assignment["note"], finding=None)
assignment["note_rt"] = render_subdocument(
assignment["note"], finding=None, p_style=self.report_queryset.docx_template.p_style
)

# Contacts
for contact in context["client"]["contacts"]:
if isinstance(contact, dict):
if contact["note"]:
contact["note_rt"] = render_subdocument(contact["note"], finding=None)
contact["note_rt"] = render_subdocument(
contact["note"], finding=None, p_style=self.report_queryset.docx_template.p_style
)

# Objectives
for objective in context["objectives"]:
if isinstance(objective, dict):
if objective["description"]:
objective["description_rt"] = render_subdocument(objective["description"], finding=None)
objective["description_rt"] = render_subdocument(
objective["description"], finding=None, p_style=self.report_queryset.docx_template.p_style
)

# Scope Lists
for scope_list in context["scope"]:
if isinstance(scope_list, dict):
if scope_list["description"]:
scope_list["description_rt"] = render_subdocument(scope_list["description"], finding=None)
scope_list["description_rt"] = render_subdocument(
scope_list["description"], finding=None, p_style=self.report_queryset.docx_template.p_style
)

# Targets
for target in context["targets"]:
if isinstance(target, dict):
if target["note"]:
target["note_rt"] = render_subdocument(target["note"], finding=None)
target["note_rt"] = render_subdocument(
target["note"], finding=None, p_style=self.report_queryset.docx_template.p_style
)

# Deconfliction Events
for event in context["deconflictions"]:
if isinstance(event, dict):
if event["description"]:
event["description_rt"] = render_subdocument(event["description"], finding=None)
event["description_rt"] = render_subdocument(
event["description"], finding=None, p_style=self.report_queryset.docx_template.p_style
)

# White Cards
for card in context["whitecards"]:
if isinstance(card, dict):
if card["description"]:
card["description_rt"] = render_subdocument(card["description"], finding=None)
card["description_rt"] = render_subdocument(
card["description"], finding=None, p_style=self.report_queryset.docx_template.p_style
)

# Infrastructure
for asset_type in context["infrastructure"]:
for asset in context["infrastructure"][asset_type]:
if isinstance(asset, dict):
if asset["note"]:
asset["note_rt"] = render_subdocument(asset["note"], finding=None)
asset["note_rt"] = render_subdocument(
asset["note"], finding=None, p_style=self.report_queryset.docx_template.p_style
)

return context

Expand Down
1 change: 1 addition & 0 deletions ghostwriter/reporting/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ class ReportTemplateAdmin(admin.ModelAdmin):
"description",
"client",
"doc_type",
"p_style",
)
},
),
Expand Down
5 changes: 5 additions & 0 deletions ghostwriter/reporting/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,7 @@ def __init__(self, *args, **kwargs):
self.fields["doc_type"].empty_label = "-- Select a Matching Filetype --"
self.fields["client"].empty_label = "-- Attach to a Client (Optional) --"
self.fields["tags"].widget.attrs["placeholder"] = "language:en_US, cvss, ..."
self.fields["p_style"].widget.attrs["placeholder"] = "Style for new paragraph (Optional, Word only)"
# Design form layout with Crispy FormHelper
self.helper = FormHelper()
self.helper.form_method = "post"
Expand All @@ -787,6 +788,10 @@ def __init__(self, *args, **kwargs):
Column("client", css_class="form-group col-md-6 mb-0"),
css_class="form-row",
),
Row(
Column("p_style", css_class="form-group col-md-6 mb-0"),
css_class="form-row",
),
Row(
Column(
SwitchToggle(
Expand Down
18 changes: 18 additions & 0 deletions ghostwriter/reporting/migrations/0037_reporttemplate_p_style.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.2.16 on 2023-04-14 10:13

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('reporting', '0036_reporttemplate_landscape'),
]

operations = [
migrations.AddField(
model_name='reporttemplate',
name='p_style',
field=models.CharField(blank=True, default=None, help_text='Provide the name of the style of new paragraphs. The style must be present in the template. Leave empty to use default Normal style.', max_length=255, null=True, verbose_name='Style of new paragraphs (leave empty for default - Normal)'),
),
]
10 changes: 10 additions & 0 deletions ghostwriter/reporting/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,16 @@ class ReportTemplate(models.Model):
help_text="Select the filetype for this template",
)

p_style = models.CharField(
"Style of new paragraphs - Word only (leave empty for default - Normal)",
max_length=255,
null=True,
blank=True,
default=None,
help_text="Provide the name of the style of new paragraphs. The style must be present in the template. " + \
"Leave empty to use default Normal style (Word only).",
)

class Meta:
ordering = ["doc_type", "client", "name"]
verbose_name = "Report template"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ <h2>{{ reporttemplate.name }}</h2>
<td class="text-left bold">Orientation</td>
<td class="text-center">{% if reporttemplate.landscape %}Landscape{% else %}Portrait{% endif %}</td>
</tr>
<tr>
<td class="text-left bold">Style of new paragraph (Word only)</td>
<td class="text-center">{% if reporttemplate.p_style %}{{ reporttemplate.p_style }}{% else %}Normal{% endif %}</td>
</tr>
</table>
</div>

Expand Down

0 comments on commit 1a21699

Please sign in to comment.