diff --git a/chatops/python/docbuilder.py b/chatops/python/docbuilder.py index 8c51651..1fc461b 100644 --- a/chatops/python/docbuilder.py +++ b/chatops/python/docbuilder.py @@ -23,6 +23,7 @@ from __future__ import print_function import argparse import os +import random import subprocess from subprocess import PIPE import sys @@ -32,7 +33,7 @@ import textwrap GITREV = 'GITREV' # Magic tag which gets replaced by the git short commit hash OFFERTE = 'generate_offerte.xsl' # XSL for generating waivers WAIVER = 'waiver_' # prefix for waivers -EXECSUMMARY = 'execsummary' # generating an executive summary instead of a report +EXECSUMMARY = 'execsummary' # generating an executive summary instead of a report def parse_arguments(): @@ -56,9 +57,12 @@ the Free Software Foundation, either version 3 of the License, or help='overwrite output file if it already exists') parser.add_argument('-date', action='store', help='the invoice date') - parser.add_argument('-execsummary', action='store_true', + parser.add_argument('--execsummary', action='store_true', help="""create an executive summary as well as a report (true/false). Default: false """) + parser.add_argument('--pw', action='store_true', + help="""password-protect the pdf. + Default: false """) parser.add_argument('--fop-config', action='store', default='/etc/docbuilder/fop.xconf', help="""fop configuration file (default @@ -106,7 +110,7 @@ the Free Software Foundation, either version 3 of the License, or else: verboseprint = lambda *a: None verboseerror = lambda *a: None - return vars(parser.parse_args()) + return vars(args) def print_output(stdout, stderr): @@ -138,6 +142,13 @@ def change_tag(fop): print('[-] could not execute git - is git installed ?') +def generate_pw(): + s = "abcdefghijklmnopqrstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()?" + length = 12 + p = "".join(random.sample(s, length)) + return(p) + + def to_fo(options): """ Creates a fo output file based on a XML file. @@ -171,6 +182,9 @@ def to_pdf(options): """ cmd = [options['fop_binary'], '-c', options['fop_config'], options['fop'], options['output']] + if options['pw']: + pw = generate_pw() + cmd = cmd + ['-u', pw] try: verboseprint('Converting {0} to {1}'.format(options['fop'], options['output'])) @@ -180,6 +194,8 @@ def to_pdf(options): print_output(stdout, stderr) if result == 0: print('[+] Succesfully built ' + options['output']) + if options['pw']: + print('\n[+] Password for this pdf is ' + pw) except OSError as exception: print_exit('[-] ERR: {0}'.format(exception.strerror), exception.errno) return result == 0 @@ -234,7 +250,7 @@ def main(): except OSError as exception: print_exit('[-] ERR: {0}'.format(exception.strerror), exception.errno) - if options['execsummary'] == True: # we're generating a summary as well as a report + if options['execsummary']: # we're generating a summary as well as a report report_output = options['output'] verboseprint('generating additional executive summary') output_dir = os.path.dirname(options['output']) @@ -260,4 +276,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/chatops/python/pentext_id.py b/chatops/python/pentext_id.py index c0425c6..e208a6d 100644 --- a/chatops/python/pentext_id.py +++ b/chatops/python/pentext_id.py @@ -123,7 +123,7 @@ def locate_id(findings, args): Show finding corresponding to an identifier """ try: - print("{0:2d} {1}".format(args.id, findings[args.id-1])) + print("{0:2d} {1}".format(args.id, findings[args.id - 1])) except IndexError: logging.error('Finding %s could not be located', args.id) diff --git a/chatops/python/validate_report.py b/chatops/python/validate_report.py index 5ea5603..30d6c56 100644 --- a/chatops/python/validate_report.py +++ b/chatops/python/validate_report.py @@ -51,7 +51,7 @@ VOCABULARY = 'project-vocabulary.txt' # Snippets may contain XML fragments without the proper entities EXAMPLEDIR = 'examples/' SNIPPETDIR = 'snippets/' -STATUS = 25 # loglevel for 'generic' status messages +STATUS = 25 # loglevel for 'generic' status messages TEMPLATEDIR = 'templates/' OFFERTE = '/offerte.xml' REPORT = '/report.xml' @@ -68,12 +68,12 @@ class LogFormatter(logging.Formatter): # STATUS = (25) generic status messages # WARNING = (30) warning messages (= errors in validation) # ERROR = (40) error messages (= program errors) - FORMATS = {logging.DEBUG :"DEBUG: %(module)s: %(lineno)d: %(message)s", - logging.INFO : "[*] %(message)s", - STATUS : "[+] %(message)s", - logging.WARN : "[-] %(message)s", - logging.ERROR : "ERROR: %(message)s", - 'DEFAULT' : "%(message)s"} + FORMATS = {logging.DEBUG: "DEBUG: %(module)s: %(lineno)d: %(message)s", + logging.INFO: "[*] %(message)s", + STATUS: "[+] %(message)s", + logging.WARN: "[-] %(message)s", + logging.ERROR: "ERROR: %(message)s", + 'DEFAULT': "%(message)s"} def format(self, record): self._fmt = self.FORMATS.get(record.levelno, self.FORMATS['DEFAULT']) @@ -213,7 +213,8 @@ def validate_files(filenames, options): if 'scans' in xml_type: scans.append(filename) for master in masters: - result = validate_master(master, findings, non_findings, scans, options) and result + result = validate_master( + master, findings, non_findings, scans, options) and result return result @@ -241,10 +242,12 @@ def validate_xml(filename, options): try: with open(filename, 'rb') as xml_file: xml.sax.parse(xml_file, xml.sax.ContentHandler()) - tree = ElementTree.parse(filename, ElementTree.XMLParser(strip_cdata=False)) - tree.xinclude() # Include everything + tree = ElementTree.parse( + filename, ElementTree.XMLParser(strip_cdata=False)) + tree.xinclude() # Include everything type_result, xml_type = validate_type(tree, filename, options) - result = validate_long_lines(tree, filename, options) and result and type_result + result = validate_long_lines( + tree, filename, options) and result and type_result if options['edit'] and not result: open_editor(filename) except (xml.sax.SAXException, ElementTree.ParseError) as exception: @@ -326,12 +329,13 @@ def validate_type(tree, filename, options): print('[-] threatLevel is not Low, Moderate, High, Elevated or Extreme: {0} {1}'. format(filename, root.attrib[attribute])) result = False - if attribute == 'type' and (options['capitalization'] and not \ + if attribute == 'type' and (options['capitalization'] and not is_capitalized(root.attrib[attribute])): print('[A] Type missing capitalization (expected {0}, read {1})'. format(capitalize(root.attrib[attribute]), root.attrib[attribute])) - root.attrib[attribute] = titlecase(root.attrib[attribute], callback=abbreviations) + root.attrib[attribute] = titlecase( + root.attrib[attribute], callback=abbreviations) fix = True if attribute == 'status' and root.attrib[attribute] not in \ ('new', 'unresolved', 'not_retested', 'resolved'): @@ -347,16 +351,18 @@ def validate_type(tree, filename, options): logging.warning('Empty tag in %s: %s', filename, tag) result = False continue - if tag == 'title' and (options['capitalization'] and \ + if tag == 'title' and (options['capitalization'] and not is_capitalized(root.find(tag).text)): print('[A] Title missing capitalization in {0} (expected {1}, read {2})'. format(filename, titlecase(root.find(tag).text, callback=abbreviations).strip(), root.find(tag).text.strip())) - root.find(tag).text = titlecase(root.find(tag).text, callback=abbreviations) + root.find(tag).text = titlecase( + root.find(tag).text, callback=abbreviations) fix = True all_text = get_all_text(root.find(tag)) if tag == 'description' and all_text.strip()[-1] != '.': - print('[A] Description missing final dot in {0}: {1}'.format(filename, all_text)) + print('[A] Description missing final dot in {0}: {1}'.format( + filename, all_text)) root.find(tag).text = all_text.strip() + '.' fix = True if fix: @@ -395,7 +401,8 @@ def validate_long_lines(tree, filename, options): print('cutted line {0}'.format(line)) line = line[cutpoint:] fixed_text += fixed_line.encode('utf-8') - print('[A] can be fixed (breaking at {0}): {1}'.format(cutpoint, fixed_line)) + print('[A] can be fixed (breaking at {0}): {1}'.format( + cutpoint, fixed_line)) fixed_text += line + '\n' if fix and options['auto_fix']: print('[+] Automatically fixed {0}'.format(filename)) @@ -418,11 +425,12 @@ def validate_master(filename, findings, non_findings, scans, options): try: xmltree = ElementTree.parse(filename, ElementTree.XMLParser(strip_cdata=False)) - xmltree.xinclude() # include all stuff + xmltree.xinclude() # include all stuff if not find_keyword(xmltree, 'TODO', filename): print('[-] Keyword checks failed for {0}'.format(filename)) result = False - logging.info('Performing cross check on findings, non-findings and scans...') + logging.info( + 'Performing cross check on findings, non-findings and scans...') for finding in findings: if not cross_check_file(filename, finding): print('[A] Cross check failed for finding {0}'.format(finding)) @@ -430,7 +438,8 @@ def validate_master(filename, findings, non_findings, scans, options): result = False for non_finding in non_findings: if not cross_check_file(filename, non_finding): - logging.warning('Cross check failed for non-finding %s', non_finding) + logging.warning( + 'Cross check failed for non-finding %s', non_finding) include_nonfindings.append(non_finding) result = False if result: @@ -468,7 +477,8 @@ def cross_check_file(filename, external): result = True report_text = report_string(filename) if report_text.find(external) == -1: - logging.warning('Could not find a reference in %s to %s', filename, external) + logging.warning( + 'Could not find a reference in %s to %s', filename, external) result = False return result @@ -477,16 +487,19 @@ def add_include(filename, identifier, findings): """ Adds XML include based on the identifier ('findings' or 'nonFindings'). """ - tree = ElementTree.parse(filename, ElementTree.XMLParser(strip_cdata=False)) + tree = ElementTree.parse( + filename, ElementTree.XMLParser(strip_cdata=False)) root = tree.getroot() for section in tree.iter('section'): if section.attrib['id'] == identifier: finding_section = section if finding_section is not None: for finding in findings: - new_finding = ElementTree.XML(''.format(finding)) + new_finding = ElementTree.XML( + ''.format(finding)) finding_section.append(new_finding) - tree.write(filename, encoding="utf-8", xml_declaration=True, pretty_print=True) + tree.write(filename, encoding="utf-8", + xml_declaration=True, pretty_print=True) def close_file(filename): @@ -501,8 +514,10 @@ def close_file(filename): f = open(fileout, 'w') f.write(newdata) f.close() - tree = ElementTree.parse(filename, ElementTree.XMLParser(strip_cdata=False)) - tree.write(filename, encoding="utf-8", xml_declaration=True, pretty_print=True) + tree = ElementTree.parse( + filename, ElementTree.XMLParser(strip_cdata=False)) + tree.write(filename, encoding="utf-8", + xml_declaration=True, pretty_print=True) def find_keyword(xmltree, keyword, filename): @@ -517,7 +532,8 @@ def find_keyword(xmltree, keyword, filename): section = 'in {0}'.format(tag.attrib['id']) if tag.text: if keyword in tag.text: - logging.warning('%s found in %s %s', keyword, filename, section) + logging.warning('%s found in %s %s', + keyword, filename, section) result = False return result @@ -566,7 +582,8 @@ def main(): else: logging.warning('Validation failed') if options['spelling'] and options['learn']: - logging.log(STATUS, 'Don\'t forget to check the vocabulary file %s', VOCABULARY) + logging.log( + STATUS, 'Don\'t forget to check the vocabulary file %s', VOCABULARY) if __name__ == "__main__":