Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Update backend/utils/pdf_generator.py
Browse files- backend/utils/pdf_generator.py +24 -21
backend/utils/pdf_generator.py
CHANGED
|
@@ -4,7 +4,7 @@ import hmac
|
|
| 4 |
import secrets
|
| 5 |
import base64
|
| 6 |
import subprocess
|
| 7 |
-
from typing import
|
| 8 |
import os
|
| 9 |
import sys
|
| 10 |
import re
|
|
@@ -26,12 +26,12 @@ import io
|
|
| 26 |
import html
|
| 27 |
from cryptography import x509
|
| 28 |
from cryptography.hazmat.backends import default_backend
|
| 29 |
-
from reportlab.lib import colors
|
| 30 |
-
from reportlab.lib.pagesizes import letter
|
| 31 |
-
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
| 32 |
-
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak, Image, KeepTogether
|
| 33 |
-
from reportlab.graphics.shapes import Drawing
|
| 34 |
-
from reportlab.graphics.charts.barcharts import VerticalBarChart
|
| 35 |
|
| 36 |
|
| 37 |
def get_ssl_info(url):
|
|
@@ -65,8 +65,8 @@ def get_ssl_info(url):
|
|
| 65 |
}
|
| 66 |
|
| 67 |
# Default getpeercert output
|
| 68 |
-
issuer =
|
| 69 |
-
subject =
|
| 70 |
issuer_str = issuer.get('organizationName', issuer.get('commonName', 'Unknown'))
|
| 71 |
subject_str = subject.get('commonName', 'Unknown')
|
| 72 |
not_after = cert.get('notAfter', 'Unknown')
|
|
@@ -100,7 +100,7 @@ class ReusableImage(Image):
|
|
| 100 |
pass
|
| 101 |
super().draw()
|
| 102 |
|
| 103 |
-
def create_proportional_image(img_source, max_width=180, max_height=170, hAlign='CENTER'):
|
| 104 |
"""
|
| 105 |
Creates a ReportLab ReusableImage object that strictly preserves original aspect ratio
|
| 106 |
and survives multi-pass ReportLab builds.
|
|
@@ -131,8 +131,8 @@ def create_proportional_image(img_source, max_width=180, max_height=170, hAlign=
|
|
| 131 |
except Exception:
|
| 132 |
return ReusableImage(img_source, width=max_width, height=max_height, kind='proportional', hAlign=hAlign)
|
| 133 |
|
| 134 |
-
from reportlab.pdfgen import canvas
|
| 135 |
-
from reportlab.platypus import Flowable
|
| 136 |
|
| 137 |
class PageTrackerCanvas(canvas.Canvas):
|
| 138 |
def __init__(self, *args, **kwargs):
|
|
@@ -142,7 +142,7 @@ class PageTrackerCanvas(canvas.Canvas):
|
|
| 142 |
|
| 143 |
def showPage(self):
|
| 144 |
self.pages.append(dict(self.__dict__))
|
| 145 |
-
self._startPage()
|
| 146 |
|
| 147 |
def save(self):
|
| 148 |
num_pages = len(self.pages)
|
|
@@ -163,7 +163,7 @@ class PageNumberRecorder(Flowable):
|
|
| 163 |
|
| 164 |
def draw(self):
|
| 165 |
if self.page_dict is not None:
|
| 166 |
-
self.page_dict[self.key_name] = self.canv._pageNumber
|
| 167 |
|
| 168 |
def generate_scan_pdf(scan, vulnerabilities):
|
| 169 |
severity_order = {"Critical": 0, "High": 1, "Medium": 2, "Low": 3, "Informational": 4}
|
|
@@ -494,8 +494,8 @@ def generate_scan_pdf(scan, vulnerabilities):
|
|
| 494 |
elements.append(Spacer(1, 10))
|
| 495 |
elements.append(sev_t)
|
| 496 |
|
| 497 |
-
from reportlab.graphics.charts.barcharts import VerticalBarChart
|
| 498 |
-
from reportlab.graphics.shapes import Drawing
|
| 499 |
|
| 500 |
color_map = {
|
| 501 |
"Critical": colors.HexColor("#DC2626"),
|
|
@@ -732,6 +732,9 @@ def generate_scan_pdf(scan, vulnerabilities):
|
|
| 732 |
cert = ssock.getpeercert()
|
| 733 |
version = ssock.version() or "TLSv1.2"
|
| 734 |
|
|
|
|
|
|
|
|
|
|
| 735 |
issuer_tuples = cert.get('issuer', ())
|
| 736 |
issuer_parts = []
|
| 737 |
for group in issuer_tuples:
|
|
@@ -965,7 +968,7 @@ def generate_scan_pdf(scan, vulnerabilities):
|
|
| 965 |
|
| 966 |
|
| 967 |
# --- APPENDIX: REQUIRES MANUAL VERIFICATION (ONLY IF UNCONFIRMED FINDINGS EXIST) ---
|
| 968 |
-
target_findings_list = vulnerabilities if
|
| 969 |
|
| 970 |
unconfirmed_findings = [
|
| 971 |
v for v in (target_findings_list or [])
|
|
@@ -1128,7 +1131,7 @@ def generate_scan_pdf(scan, vulnerabilities):
|
|
| 1128 |
"This report contains sensitive, proprietary vulnerability intelligence regarding the client organization's digital assets. Unauthorized distribution, public exposure, or reproduction of this document without prior written authorization from both the client organization and LarShield is strictly prohibited.")
|
| 1129 |
]
|
| 1130 |
|
| 1131 |
-
content_flowables = [header_table, Spacer(1, 10)]
|
| 1132 |
|
| 1133 |
card_cells = []
|
| 1134 |
for idx, (title, body) in enumerate(disclaimer_items):
|
|
@@ -1159,8 +1162,8 @@ def generate_scan_pdf(scan, vulnerabilities):
|
|
| 1159 |
|
| 1160 |
def header_footer_draw(canvas_obj, doc):
|
| 1161 |
canvas_obj.saveState()
|
| 1162 |
-
if canvas_obj._pageNumber > 2:
|
| 1163 |
-
from reportlab.lib.utils import ImageReader
|
| 1164 |
import pytz
|
| 1165 |
from datetime import datetime
|
| 1166 |
|
|
@@ -1222,7 +1225,7 @@ def generate_scan_pdf(scan, vulnerabilities):
|
|
| 1222 |
gen_time = datetime.now().strftime('%d-%b-%Y %H:%M')
|
| 1223 |
canvas_obj.drawCentredString(letter[0] / 2.0, 30, f"{gen_time}")
|
| 1224 |
|
| 1225 |
-
canvas_obj.drawRightString(letter[0] - 40, 30, f"Page {canvas_obj._pageNumber} of {total_pages[0]}")
|
| 1226 |
|
| 1227 |
canvas_obj.restoreState()
|
| 1228 |
|
|
|
|
| 4 |
import secrets
|
| 5 |
import base64
|
| 6 |
import subprocess
|
| 7 |
+
from typing import Any, cast, List
|
| 8 |
import os
|
| 9 |
import sys
|
| 10 |
import re
|
|
|
|
| 26 |
import html
|
| 27 |
from cryptography import x509
|
| 28 |
from cryptography.hazmat.backends import default_backend
|
| 29 |
+
from reportlab.lib import colors # type: ignore[import]
|
| 30 |
+
from reportlab.lib.pagesizes import letter # type: ignore[import]
|
| 31 |
+
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle # type: ignore[import]
|
| 32 |
+
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak, Image, KeepTogether # type: ignore[import]
|
| 33 |
+
from reportlab.graphics.shapes import Drawing # type: ignore[import]
|
| 34 |
+
from reportlab.graphics.charts.barcharts import VerticalBarChart # type: ignore[import]
|
| 35 |
|
| 36 |
|
| 37 |
def get_ssl_info(url):
|
|
|
|
| 65 |
}
|
| 66 |
|
| 67 |
# Default getpeercert output
|
| 68 |
+
issuer = {k: v for x in cert.get('issuer', []) for k, v in [x[0]]}
|
| 69 |
+
subject = {k: v for x in cert.get('subject', []) for k, v in [x[0]]}
|
| 70 |
issuer_str = issuer.get('organizationName', issuer.get('commonName', 'Unknown'))
|
| 71 |
subject_str = subject.get('commonName', 'Unknown')
|
| 72 |
not_after = cert.get('notAfter', 'Unknown')
|
|
|
|
| 100 |
pass
|
| 101 |
super().draw()
|
| 102 |
|
| 103 |
+
def create_proportional_image(img_source, max_width=180, max_height=170, hAlign: Any = 'CENTER'):
|
| 104 |
"""
|
| 105 |
Creates a ReportLab ReusableImage object that strictly preserves original aspect ratio
|
| 106 |
and survives multi-pass ReportLab builds.
|
|
|
|
| 131 |
except Exception:
|
| 132 |
return ReusableImage(img_source, width=max_width, height=max_height, kind='proportional', hAlign=hAlign)
|
| 133 |
|
| 134 |
+
from reportlab.pdfgen import canvas # type: ignore[import]
|
| 135 |
+
from reportlab.platypus import Flowable # type: ignore[import]
|
| 136 |
|
| 137 |
class PageTrackerCanvas(canvas.Canvas):
|
| 138 |
def __init__(self, *args, **kwargs):
|
|
|
|
| 142 |
|
| 143 |
def showPage(self):
|
| 144 |
self.pages.append(dict(self.__dict__))
|
| 145 |
+
self._startPage() # type: ignore[attr-defined]
|
| 146 |
|
| 147 |
def save(self):
|
| 148 |
num_pages = len(self.pages)
|
|
|
|
| 163 |
|
| 164 |
def draw(self):
|
| 165 |
if self.page_dict is not None:
|
| 166 |
+
self.page_dict[self.key_name] = self.canv._pageNumber # type: ignore[attr-defined]
|
| 167 |
|
| 168 |
def generate_scan_pdf(scan, vulnerabilities):
|
| 169 |
severity_order = {"Critical": 0, "High": 1, "Medium": 2, "Low": 3, "Informational": 4}
|
|
|
|
| 494 |
elements.append(Spacer(1, 10))
|
| 495 |
elements.append(sev_t)
|
| 496 |
|
| 497 |
+
from reportlab.graphics.charts.barcharts import VerticalBarChart # type: ignore[import]
|
| 498 |
+
from reportlab.graphics.shapes import Drawing # type: ignore[import]
|
| 499 |
|
| 500 |
color_map = {
|
| 501 |
"Critical": colors.HexColor("#DC2626"),
|
|
|
|
| 732 |
cert = ssock.getpeercert()
|
| 733 |
version = ssock.version() or "TLSv1.2"
|
| 734 |
|
| 735 |
+
if cert is None:
|
| 736 |
+
raise ValueError("No certificate returned")
|
| 737 |
+
|
| 738 |
issuer_tuples = cert.get('issuer', ())
|
| 739 |
issuer_parts = []
|
| 740 |
for group in issuer_tuples:
|
|
|
|
| 968 |
|
| 969 |
|
| 970 |
# --- APPENDIX: REQUIRES MANUAL VERIFICATION (ONLY IF UNCONFIRMED FINDINGS EXIST) ---
|
| 971 |
+
target_findings_list = vulnerabilities if vulnerabilities is not None else getattr(scan, 'vulnerabilities', [])
|
| 972 |
|
| 973 |
unconfirmed_findings = [
|
| 974 |
v for v in (target_findings_list or [])
|
|
|
|
| 1131 |
"This report contains sensitive, proprietary vulnerability intelligence regarding the client organization's digital assets. Unauthorized distribution, public exposure, or reproduction of this document without prior written authorization from both the client organization and LarShield is strictly prohibited.")
|
| 1132 |
]
|
| 1133 |
|
| 1134 |
+
content_flowables: List[Any] = [header_table, Spacer(1, 10)]
|
| 1135 |
|
| 1136 |
card_cells = []
|
| 1137 |
for idx, (title, body) in enumerate(disclaimer_items):
|
|
|
|
| 1162 |
|
| 1163 |
def header_footer_draw(canvas_obj, doc):
|
| 1164 |
canvas_obj.saveState()
|
| 1165 |
+
if canvas_obj._pageNumber > 2: # type: ignore[attr-defined]
|
| 1166 |
+
from reportlab.lib.utils import ImageReader # type: ignore[import]
|
| 1167 |
import pytz
|
| 1168 |
from datetime import datetime
|
| 1169 |
|
|
|
|
| 1225 |
gen_time = datetime.now().strftime('%d-%b-%Y %H:%M')
|
| 1226 |
canvas_obj.drawCentredString(letter[0] / 2.0, 30, f"{gen_time}")
|
| 1227 |
|
| 1228 |
+
canvas_obj.drawRightString(letter[0] - 40, 30, f"Page {canvas_obj._pageNumber} of {total_pages[0]}") # type: ignore[attr-defined]
|
| 1229 |
|
| 1230 |
canvas_obj.restoreState()
|
| 1231 |
|