File size: 3,487 Bytes
2d2e8fb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.lib import colors
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Preformatted
from reportlab.lib.enums import TA_LEFT
import io
import html
import re

def generate_pdf(technique_id: str, red_output: str, blue_output: str) -> bytes:
    buffer = io.BytesIO()
    doc = SimpleDocTemplate(buffer, pagesize=A4,
                           rightMargin=inch, leftMargin=inch,
                           topMargin=inch, bottomMargin=inch)
    
    styles = getSampleStyleSheet()
    styles.add(ParagraphStyle(name='CustomTitle',
                              fontSize=20, spaceAfter=20,
                              textColor=colors.HexColor('#1a1a2e'),
                              fontName='Helvetica-Bold'))
    styles.add(ParagraphStyle(name='SectionTitle',
                              fontSize=14, spaceAfter=10, spaceBefore=20,
                              textColor=colors.HexColor('#c0392b'),
                              fontName='Helvetica-Bold'))
    styles.add(ParagraphStyle(name='BlueSectionTitle',
                              fontSize=14, spaceAfter=10, spaceBefore=20,
                              textColor=colors.HexColor('#2980b9'),
                              fontName='Helvetica-Bold'))
    styles.add(ParagraphStyle(name='CodeStyle',
                              fontSize=8, fontName='Courier',
                              backColor=colors.HexColor('#f4f4f4'),
                              leftIndent=10, rightIndent=10,
                              spaceAfter=10))

    story = []
    
    # Title
    story.append(Paragraph("AegisOps AI Purple Team Report", styles['CustomTitle']))
    story.append(Paragraph(f"Technique: {html.escape(str(technique_id))}", styles['Normal']))
    story.append(Spacer(1, 20))

    # Red Team section
    story.append(Paragraph("Red Team Attack Simulation", styles['SectionTitle']))
    _parse_markdown_to_pdf(red_output, story, styles)
    
    story.append(Spacer(1, 20))
    
    # Blue Team section
    story.append(Paragraph("Blue Team Defense Report", styles['BlueSectionTitle']))
    _parse_markdown_to_pdf(blue_output, story, styles)

    doc.build(story)
    buffer.seek(0)
    return buffer.getvalue()

def _parse_markdown_to_pdf(text: str, story: list, styles):
    # Split on code blocks
    parts = re.split(r'```(?:\w+)?\n?', text)
    in_code = False
    for part in parts:
        if in_code:
            story.append(Preformatted(part.strip(), styles['CodeStyle']))
        else:
            for line in part.split('\n'):
                line = line.strip()
                if not line:
                    story.append(Spacer(1, 6))
                elif line.startswith('### '):
                    story.append(Paragraph(html.escape(line[4:]), styles['Heading3']))
                elif line.startswith('## '):
                    story.append(Paragraph(html.escape(line[3:]), styles['Heading2']))
                elif line.startswith('# '):
                    story.append(Paragraph(html.escape(line[2:]), styles['Heading1']))
                elif line.startswith('- ') or line.startswith('* '):
                    story.append(Paragraph(f"• {html.escape(line[2:])}", styles['Normal']))
                else:
                    story.append(Paragraph(html.escape(line), styles['Normal']))
        in_code = not in_code