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))
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))
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
def __init__(self, gradient): self.grade = gradient if self.grade == None: self.grade = Gradient(colors=["#ff6666", "#ffe766", "#8ec843"], minValue=1, maxValue=100)
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