Example #1
0
 def gradient(self, gradient):
     try:
         loadChecker(type(self).__name__, gradient, ['colors', 'minValue', 'maxValue'], "gradient")
         self.__gradient = Gradient(gradient['colors'], gradient['minValue'], gradient['maxValue'])
     except MissingParameters as e:
         handler(type(self).__name__, 'Gradient {} is missing parameters: '
                                      '{}. Skipping.'
                 .format(gradient, e))
Example #2
0
 def gradient(self, gradient):
     try:
         self.__gradient = Gradient(gradient['colors'],
                                    gradient['minValue'],
                                    gradient['maxValue'])
     except KeyError as e:
         handler(
             type(self).__name__, 'Gradient is missing parameters: {}. '
             'Unable to load.'.format(e))
Example #3
0
    def _build_headers(self,
                       name,
                       config,
                       desc=None,
                       filters=None,
                       gradient=None):
        """
            Internal - build the header blocks for the svg

            :param name: The name of the layer being exported
            :param config: SVG Config object
            :param desc: Description of the layer being exported
            :param filters: Any filters applied to the layer being exported
            :param gradient: Gradient information included with the layer
            :return: Instantiated SVG header
        """
        max_x = convertToPx(config.width, config.unit)
        max_y = convertToPx(config.height, config.unit)
        header_height = convertToPx(config.headerHeight, config.unit)
        ff = config.font
        d = draw.Drawing(max_x, max_y, origin=(0, -max_y), displayInline=False)
        psych = 0
        overlay = None
        if config.showHeader:
            border = convertToPx(config.border, config.unit)
            root = G(tx=border, ty=border, style='font-family: {}'.format(ff))

            header = G()
            root.append(header)
            b1 = G()
            header.append(b1)

            header_count = 0
            if config.showAbout:
                header_count += 1
            if config.showFilters:
                header_count += 1
            if config.showLegend and gradient is not False and config.legendDocked:
                header_count += 1

            operation_x = (max_x - border) - (1.5 * border *
                                              (header_count - 1))
            if header_count > 0:
                header_width = operation_x / header_count
                if config.showAbout:
                    if desc is not None:
                        g = SVG_HeaderBlock().build(height=header_height,
                                                    width=header_width,
                                                    label='about',
                                                    t1text=name,
                                                    t2text=desc,
                                                    config=config)
                    else:
                        g = SVG_HeaderBlock().build(height=header_height,
                                                    width=header_width,
                                                    label='about',
                                                    t1text=name,
                                                    config=config)
                    b1.append(g)
                    psych += 1
                if config.showFilters:
                    fi = filters
                    if fi is None:
                        fi = Filter()
                        fi.platforms = ["Windows", "Linux", "macOS"]
                        fi.stages = ["act"]
                    g2 = SVG_HeaderBlock().build(height=header_height,
                                                 width=header_width,
                                                 label='filters',
                                                 t1text=', '.join(
                                                     fi.platforms),
                                                 t2text=fi.stages[0],
                                                 config=config)
                    b2 = G(tx=operation_x / header_count * psych +
                           1.5 * border * psych)
                    header.append(b2)
                    b2.append(g2)
                    psych += 1
                if config.showLegend and gradient is not False:
                    gr = gradient
                    if gr is None:
                        gr = Gradient(colors=["#ff6666", "#ffe766", "#8ec843"],
                                      minValue=1,
                                      maxValue=100)
                    colors = []
                    div = round(
                        (gr.maxValue - gr.minValue) / (len(gr.colors) * 2 - 1))
                    for i in range(0, len(gr.colors) * 2 - 1):
                        colors.append(
                            (gr.compute_color(int(gr.minValue + div * i)),
                             gr.minValue + div * i))
                    colors.append((gr.compute_color(gr.maxValue), gr.maxValue))
                    if config.legendDocked:
                        b3 = G(tx=operation_x / header_count * psych +
                               1.5 * border * psych)
                        g3 = SVG_HeaderBlock().build(height=header_height,
                                                     width=header_width,
                                                     label='legend',
                                                     variant='graphic',
                                                     colors=colors,
                                                     config=config)
                        header.append(b3)
                        b3.append(g3)
                        psych += 1
                    else:
                        adjusted_height = convertToPx(config.legendHeight,
                                                      config.unit)
                        adjusted_width = convertToPx(config.legendWidth,
                                                     config.unit)
                        g3 = SVG_HeaderBlock().build(height=adjusted_height,
                                                     width=adjusted_width,
                                                     label='legend',
                                                     variant='graphic',
                                                     colors=colors,
                                                     config=config)
                        lx = convertToPx(config.legendX, config.unit)
                        if not lx:
                            lx = max_x - adjusted_width - convertToPx(
                                config.border, config.unit)
                        ly = convertToPx(config.legendY, config.unit)
                        if not ly:
                            ly = max_y - adjusted_height - convertToPx(
                                config.border, config.unit)
                        overlay = G(tx=lx, ty=ly)
                        if (ly + adjusted_height) > max_y or (
                                lx + adjusted_width) > max_x:
                            print(
                                "[WARNING] - Floating legend will render partly out of view..."
                            )
                        overlay.append(g3)
            d.append(root)
        return d, psych, overlay
Example #4
0
 def __init__(self, gradient):
     self.grade = gradient
     if self.grade == None:
         self.grade = Gradient(colors=["#ff6666", "#ffe766", "#8ec843"], minValue=1, maxValue=100)
Example #5
0
class SVG_Technique:
    def __init__(self, gradient):
        self.grade = gradient
        if self.grade == None:
            self.grade = Gradient(colors=["#ff6666", "#ffe766", "#8ec843"], minValue=1, maxValue=100)

    def build(self, offset, technique, height, width, tBC, subtechniques=[], mode=(True, False), tactic=None,
              colors=[]):
        """
            Build a SVG Technique block

            :param offset: Current offset to build the block at (so it fits in the column)
            :param technique: The technique to build a block for
            :param height: The height of the technique block
            :param width: The width of the technique block
            :param tBC: The hex code of the technique block's border
            :param subtechniques: List of any visible subtechniques for this technique
            :param mode: Display mode (Show Name, Show ID)
            :param tactic: The corresponding tactic
            :param colors: List of all default color values if no score can be found
            :return: The newly created SVG technique block
        """
        g = G(ty=offset)
        c = self._com_color(technique, tactic, colors)
        t = dict(name=self._disp(technique.name, technique.id, mode), id=technique.id,
                 color=tuple(int(c[i:i+2], 16) for i in (0, 2, 4)))
        tech, text = self._block(t, height, width, tBC=tBC)
        g.append(tech)
        g.append(text)
        new_offset = height
        for entry in subtechniques:
            gp = G(tx=width/5, ty=new_offset)
            g.append(gp)
            c = self._com_color(entry, tactic, colors)
            st = dict(name=self._disp(entry.name, entry.id, mode), id=entry.id,
                     color=tuple(int(c[i:i + 2], 16) for i in (0, 2, 4)))
            subtech, subtext = self._block(st, height, width - width/5, tBC=tBC)
            gp.append(subtech)
            gp.append(subtext)
            new_offset = new_offset + height
        if len(subtechniques):
            g.append(draw.Lines(width/16, -height,
                                width/8, -height * 2,
                                width/8, -height * (len(subtechniques) + 1),
                                width/5, -height * (len(subtechniques) + 1),
                                width/5, -height,
                       close=True,
                       fill=tBC,
                       stroke=tBC))
        return g, offset + new_offset

    @staticmethod
    def _block(technique, height, width, tBC):
        """
            INTERNAL: Build a technique block element

            :param technique: Technique data dictionary
            :param height: Block height
            :param width: Block width
            :param tBC: Block border color
            :return: Block object, fit text object
        """
        tech = Cell(height, width, technique['color'], ctype=technique['id'], tBC=tBC)

        fs, patch_text = _optimalFontSize(technique['name'], width, height)
        adjusted = "\n".join(patch_text)

        lines = adjusted.count('\n')

        y = height / 2
        if lines > 0:
            y = (height - (lines * fs)) / 2 + height/10 #padding
        else:
            y = y + fs / 4

        hls = colorsys.rgb_to_hls(technique['color'][0], technique['color'][1], technique['color'][2])
        fill = None
        if hls[1] < 127.5:
            fill = 'white'

        text = Text(adjusted.encode('utf-8').decode('ascii', 'backslashreplace'), fs, '', x=4, y=y, fill=fill)
        return tech, text

    def _com_color(self, technique, tactic, colors=[]):
        """
            INTERNAL: Retrieve hex color for a block

            :param technique: Technique object
            :param tactic: What tactic the technique falls under
            :param colors: Default technique color data
            :return: Hex color code
        """
        c = 'FFFFFF'
        if technique.score:
            c = self.grade.compute_color(technique.score)[1:]
        else:
            for x in colors:
                if x[0] == technique.id and (x[1] == tactic or not x[1]):
                    c = x[2][1:]
        return c

    @staticmethod
    def _disp(name, id, mode):
        """
            INTERNAL: Generate technique display form

            :param name: The name of the technique
            :param id: The ID of the technique
            :param mode: Which mode to use
            :return: Target display string for the technique
        """
        p1 = name
        p2 = id
        if not mode[0]:
            p1 = ''
        if not mode[1]:
            p2 = ''
        out = ': '.join([p2, p1])
        if out.startswith(': '):
            return p1
        return out
    def _build_headers(self,
                       name,
                       config,
                       domain='Enterprise',
                       version='8',
                       desc=None,
                       filters=None,
                       gradient=None):
        """
            Internal - build the header blocks for the svg

            :param name: The name of the layer being exported
            :param config: SVG Config object
            :param domain: The layer's domain
            :param version: The layer's version
            :param desc: Description of the layer being exported
            :param filters: Any filters applied to the layer being exported
            :param gradient: Gradient information included with the layer
            :return: Instantiated SVG header
        """
        max_x = convertToPx(config.width, config.unit)
        max_y = convertToPx(config.height, config.unit)
        header_height = convertToPx(config.headerHeight, config.unit)
        ff = config.font
        d = draw.Drawing(max_x, max_y, origin=(0, -max_y), displayInline=False)
        psych = 0
        overlay = None
        if config.showHeader:
            border = convertToPx(config.border, config.unit)
            root = G(tx=border, ty=border, style='font-family: {}'.format(ff))

            header = G()
            root.append(header)
            b1 = G()
            header.append(b1)

            header_count = 0
            showAgg = False
            if config.showAbout:
                header_count += 1
            if config.showFilters:
                header_count += 1
            if config.showDomain:
                header_count += 1
            if config.showLegend and gradient is not False and config.legendDocked:
                header_count += 1
            if self.lhandle.layout:
                if self.lhandle.layout.showAggregateScores:
                    showAgg = True
                    header_count += 1
                if config.showFilters:
                    header_count -= 1

            operation_x = (max_x - border) - (1.5 * border *
                                              (header_count - 1)) - border
            if header_count > 0:
                header_width = operation_x / header_count
                if config.showAbout:
                    if desc is not None:
                        g = SVG_HeaderBlock().build(height=header_height,
                                                    width=header_width,
                                                    label='about',
                                                    t1text=name,
                                                    t2text=desc,
                                                    config=config)
                    else:
                        g = SVG_HeaderBlock().build(height=header_height,
                                                    width=header_width,
                                                    label='about',
                                                    t1text=name,
                                                    config=config)
                    b1.append(g)
                    psych += 1
                if config.showDomain:
                    if domain.startswith('mitre-'):
                        domain = domain[6:].capitalize()
                    if domain.endswith('-attack'):
                        domain = domain[:-7].capitalize()
                    tag = domain + ' ATT&CK v' + version
                    if config.showFilters and showAgg:
                        fi = filters
                        if fi is None:
                            fi = Filter()
                            fi.platforms = ["Windows", "Linux", "macOS"]
                        gD = SVG_HeaderBlock().build(
                            height=header_height,
                            width=header_width,
                            label='domain & platforms',
                            t1text=tag,
                            t2text=', '.join(fi.platforms),
                            config=config)
                    else:
                        gD = SVG_HeaderBlock().build(height=header_height,
                                                     width=header_width,
                                                     label='domain',
                                                     t1text=tag,
                                                     config=config)
                    bD = G(tx=operation_x / header_count * psych +
                           1.5 * border * psych)
                    header.append(bD)
                    bD.append(gD)
                    psych += 1
                if config.showFilters and not showAgg:
                    fi = filters
                    if fi is None:
                        fi = Filter()
                        fi.platforms = ["Windows", "Linux", "macOS"]
                    g2 = SVG_HeaderBlock().build(height=header_height,
                                                 width=header_width,
                                                 label='filters',
                                                 t1text=', '.join(
                                                     fi.platforms),
                                                 config=config)
                    b2 = G(tx=operation_x / header_count * psych +
                           1.5 * border * psych)
                    header.append(b2)
                    b2.append(g2)
                    psych += 1
                if showAgg:
                    t1 = f"showing aggregate scores using the {self.lhandle.layout.aggregateFunction} " \
                         f"aggregate function"
                    stub = "does not include"
                    if self.lhandle.layout.countUnscored:
                        stub = "includes"
                    t2 = f"{stub} unscored techniques as having a score of 0"
                    gA = SVG_HeaderBlock().build(height=header_height,
                                                 width=header_width,
                                                 label='aggregate',
                                                 t1text=t1,
                                                 t2text=t2,
                                                 config=config)
                    bA = G(tx=operation_x / header_count * psych +
                           1.5 * border * psych)
                    header.append(bA)
                    bA.append(gA)
                    psych += 1
                if config.showLegend and gradient is not False:
                    gr = gradient
                    if gr is None:
                        gr = Gradient(colors=["#ff6666", "#ffe766", "#8ec843"],
                                      minValue=1,
                                      maxValue=100)
                    colors = []
                    div = round(
                        (gr.maxValue - gr.minValue) / (len(gr.colors) * 2 - 1))
                    for i in range(0, len(gr.colors) * 2 - 1):
                        colors.append(
                            (gr.compute_color(int(gr.minValue + div * i)),
                             gr.minValue + div * i))
                    colors.append((gr.compute_color(gr.maxValue), gr.maxValue))
                    if config.legendDocked:
                        b3 = G(tx=operation_x / header_count * psych +
                               1.5 * border * psych)
                        g3 = SVG_HeaderBlock().build(height=header_height,
                                                     width=header_width,
                                                     label='legend',
                                                     variant='graphic',
                                                     colors=colors,
                                                     config=config)
                        header.append(b3)
                        b3.append(g3)
                        psych += 1
                    else:
                        adjusted_height = convertToPx(config.legendHeight,
                                                      config.unit)
                        adjusted_width = convertToPx(config.legendWidth,
                                                     config.unit)
                        g3 = SVG_HeaderBlock().build(height=adjusted_height,
                                                     width=adjusted_width,
                                                     label='legend',
                                                     variant='graphic',
                                                     colors=colors,
                                                     config=config)
                        lx = convertToPx(config.legendX, config.unit)
                        if not lx:
                            lx = max_x - adjusted_width - convertToPx(
                                config.border, config.unit)
                        ly = convertToPx(config.legendY, config.unit)
                        if not ly:
                            ly = max_y - adjusted_height - convertToPx(
                                config.border, config.unit)
                        overlay = G(tx=lx, ty=ly)
                        if (ly + adjusted_height) > max_y or (
                                lx + adjusted_width) > max_x:
                            print(
                                "[WARNING] - Floating legend will render partly out of view..."
                            )
                        overlay.append(g3)
            d.append(root)
        return d, psych, overlay