def main(): # argparse:只需传入path,无其他开关 parser = argparse.ArgumentParser( prog='AppScan', description='读取AppScan的XML文件,转换成测评能手标准格式,转换结果分别保存至每个原始文件的同目录下。') parser.add_argument('path', nargs='+', help='file path or dir path') args = parser.parse_args() _LOGGER.info('[AppScan] Started.') # 过滤xml并去重 _LOGGER.debug('[AppScan] arg_paths = "{}".'.format(args.path)) target_paths = set() for arg_path in args.path: target_paths = target_paths.union( set(Converter.walk.file(arg_path, ['.xml']))) _LOGGER.debug('[AppScan] target_paths = "{}".'.format(target_paths)) # 调用Converter.xml处理 count = 0 for target_path in target_paths: try: new_root = Converter.xml.read_AppScan(target_path) Converter.xml.write( new_root, os.path.splitext(target_path)[0] + '_converted.xml') count += 1 except Exception as err: _LOGGER.warning( '[AppScan] Conversion failure due to "{}"'.format(err)) _LOGGER.info('[AppScan] Finished with {} converted.'.format(count))
def convert_PDF(src_file_path:str) -> str: ''' 调用Word,将{src_file_path}转换为PDF并存放在同目录。 Args: src_file_path(str): 需转换的文件 Returns: str: 转换完成的文件路径 Raises: ValueError: 如果{src_file_path}不存在或格式非法 OSError: 如果调用Word程序失败 ''' # 校验src_file_path的格式是否有效 if os.path.isfile(src_file_path) and os.path.splitext(src_file_path)[1].lower() == '.pdf': return src_file_path if not os.path.isfile(src_file_path) or os.path.splitext(src_file_path)[1].lower() not in ['.doc', '.docx']: raise ValueError('Invalid word file.') dst_file_path = os.path.splitext(src_file_path)[0] + '.pdf' # 打开并关联Word,处理结束后放在后台不管,必要时会自动复用 _LOGGER.debug('[Converter/document/convert_PDF] Dispatching Word.Application.') try: word = win32com.client.gencache.EnsureDispatch('Word.Application') except: _LOGGER.error('[Converter/document/convert_PDF] Failed to dispatch Word.Application.') raise OSError('Failed to dispatch Word.Application.') # 转换doc文件 _LOGGER.info('[Converter/document/convert_PDF] Converting "{}"'.format(src_file_path)) document = word.Documents.Open(FileName=src_file_path, ReadOnly=True) document.SaveAs2(FileName=dst_file_path, FileFormat=17) # wdFormatPDF=17 document.Close(SaveChanges=0) return dst_file_path
def convert_latest(src_file_path:str) -> str: ''' 调用Word,将{src_file_path}转换最新格式。 Args: src_file_path(str): 需转换的文件 Returns: str: 转换完成的文件路径 Raises: ValueError: 如果{src_file_path}不存在或格式非法 OSError: 如果调用Word程序失败 ''' # 校验src_file_path的格式是否有效 if not os.path.isfile(src_file_path) or os.path.splitext(src_file_path)[1].lower() not in ['.doc', '.docx']: raise ValueError('Invalid word file.') dst_file_path = os.path.splitext(src_file_path)[0] + '.docx' # 打开并关联Word,处理结束后放在后台不管,必要时会自动复用 _LOGGER.debug('[Converter/document/convert_latest] Dispatching Word.Application.') try: word = win32com.client.gencache.EnsureDispatch('Word.Application') except: _LOGGER.error('[Converter/document/convert_latest] Failed to dispatch Word.Application.') raise OSError('Failed to dispatch Word.Application.') # 打开并关联文档 document = word.Documents.Open(FileName=src_file_path) _LOGGER.info('[Converter/document/convert_latest] CompatibilityMode = {}.'.format(document.CompatibilityMode)) # 将word转换为最新文件格式 if document.CompatibilityMode < 15: # CompatibilityMode=11-14(旧版) _LOGGER.info('[Converter/document/convert_latest] Converting "{}".'.format(dst_file_path)) document.Convert() document.Save() document.Close() return dst_file_path
def read_XT17(src_file_path:str) -> dict: ''' 读取{src_file_path}文件,获取项目编号、项目名称、方案日期、撰写人。 Args: src_file_path(str): 读取的文件 Returns: dict: {'code': (str), 'name': (str),'date': (str),'leader': (str)} Raises: ValueError: 如果{src_file_path}不存在或格式非法 ''' # 校验src_file_path的格式是否有效 if not os.path.isfile(src_file_path) or os.path.splitext(src_file_path)[1].lower() not in ['.doc', '.docx']: raise ValueError('Invalid word file.') # 自动转换doc,失败时由convert_latest()抛出异常 if os.path.splitext(src_file_path)[1].lower() == '.doc': src_file_path = convert_latest(src_file_path) ret = {'code': '', 'name': '','date': '','leader': ''} document = Document(src_file_path) # 读项目编号 ## 印象中所有项目编号都能在前几行读到 for paragraph in document.paragraphs[0:5]: re_result = re.search('SHTEC20[0-9]{2}DSYS[0-9]{4}', paragraph.text) if re_result: ret['code'] = re_result[0] break ret['name'] = document.tables[0].cell(0, 1).text.strip() ret['date'] = document.tables[0].cell(3, 1).text.strip() ret['leader'] = document.tables[-5].cell(0, 1).text.strip() _LOGGER.debug('[Converter/document/read_XT17] ret = "{}"'.format(ret)) return ret
def main(): # argparse:传入path parser = argparse.ArgumentParser( prog='XT09', description='读取等保方案文件XT17,根据其中信息自动生成方案审核意见单XT09,并尝试转换PDF。') # 传入no-pdf,关闭自动生成PDF parser.add_argument('-np', '--no-pdf', default=False, action='store_true', help='disable PDF generation') parser.add_argument('path', nargs='+', help='file path or dir path') args = parser.parse_args() _LOGGER.info('[XT09] Started.') # 过滤doc/docx并去重 _LOGGER.debug('[XT09] arg_paths = "{}".'.format(args.path)) target_paths = set() for arg_path in args.path: target_paths = target_paths.union( set(Converter.walk.file(arg_path, ['.doc', '.docx']))) _LOGGER.debug('[XT09] target_paths = "{}".'.format(target_paths)) # 读取自定义字典 customized_advices = [] try: # 字典文件不存在时释放res资源 if not os.path.exists( os.path.join(os.path.dirname(sys.argv[0]), 'AdviceList.txt')): shutil.copy(_RESOURCE_PATH(os.path.join('res', 'AdviceList.txt')), os.path.dirname(sys.argv[0])) # 尝试读取自定义字典文件 with open(os.path.join(os.path.dirname(sys.argv[0]), 'AdviceList.txt'), encoding='utf-8') as f: raw_lines = f.readlines() for raw_line in raw_lines: if not raw_line.lstrip().startswith('#'): customized_advices.append(raw_line.strip()) except: _LOGGER.warning('[XT09] Fail to read "AdviceList.txt".') # 调用Converter.document处理 count = 0 for target_path in target_paths: try: # 读取基本信息,并写入随机审核意见 info = Converter.document.read_XT17(target_path) info['advices'] = Converter.walk.XT09_advices(customized_advices) # 根据读取的信息生成审核意见单,并转换成PDF XT09_file_path = Converter.document.make_XT09( os.path.dirname(target_path), info) if not args.no_pdf: Converter.document.convert_PDF(XT09_file_path) count += 1 except Exception as err: _LOGGER.warning( '[XT09] Generation failure due to "{}"'.format(err)) _LOGGER.info('[XT09] Finished with {} generated.'.format(count))
def XT09_advices(customized_advices: list = []) -> str: ''' 生成XT09的建议。如果自定义建议数量少于四个,则使用内置字典。 Args: customized_advices(list): 自定义建议列表 Returns: str: 生成的建议(按\n换行) ''' # 内置建议字典 advices = [ '封面的项目编号有误。', '方案中的被测单位名称可能有误,请与用户方充分沟通并确认。', '方案页脚的页码和总页码处不正确。', '方案中1.4、4.2等相关章节的段落缩进、字体大小等格式方面有不一致等问题,请通篇查找并修订。', '图1.1的图题描述错误,应为“等级保护测评工作流程图”。', '1.3章节测评过程中的个别年份存在笔误。', '2.2章节内容缺失。', '2.2章节“承载业务情况”的个别信息资产描述与2.4章节相关信息资产表的内容不一致。', '2.4章节信息资产表中个别信息资产的版本及型号未描述完善。', '2.4章节信息资产表中个别栏目为空,且未阐明原因或加以注销。', '3.1.1章节关注的抽选信息资产类别,未在3.1.2章节予以体现完整,例如终端这类信息资产。', '3.1.2章节抽选的信息资产列表中的个别信息资产类别,未在3.1.1章节中体现,存在上下文不一致的情况。', '3.3章节内容缺失。', '4.1章节内容有误。', '5.2章节,应对测试工具的接入点加以补充和完善,并与用户方做充分的沟通,确保扫描和渗透性测试的顺利实施。', '6.2章节扩展安全要求中个别栏目为空,且未阐明原因或加以注销。', '8.1章节“项目组织”中表格内的个别栏目未填写内容,请补充完善。' ] if len(customized_advices) >= 4: advices = customized_advices _LOGGER.info('[Converter/word/get_advices] Using customized advices.') else: _LOGGER.info('[Converter/word/get_advices] Using bulitin advices.') # 随机取2-4个索引 chosen_indexs = random.sample(range(0, len(advices)), random.randint(2, 4)) # 拼接审核意见字符串 seq = 1 chosen_advices = [] for chosen_index in chosen_indexs: chosen_advices.append('{}、{}'.format(seq, advices[chosen_index])) seq += 1 _LOGGER.debug('[Converter/word/get_advices] chosen_advices = "{}".'.format( chosen_advices)) return '\n'.join(chosen_advices)
def merge_PDF(src_file_paths:list=[], dst_dir_path:str='') -> str: ''' 调用PyPDF2,将{src_file_paths}合并,输出到{dst_dir_path}下的output.pdf。 Args: src_file_paths(list): 需合并的文件; dst_dir_path(str): 输出文件的目录,缺省时或目录无效时输出到第一个有效文件所在的目录; Returns: str: 合并完成的文件路径 Raises: ValueError: 如果{src_file_paths}中没有任何有效文件 ''' # 校验src_file_paths中的文件是否有效 valid_file_paths = [] for src_file_path in src_file_paths: if os.path.isfile(src_file_path) and os.path.splitext(src_file_path)[1].lower() == '.pdf': valid_file_paths.append(src_file_path) _LOGGER.debug('[Converter/document/merge_PDF] valid_file_paths = "{}".'.format(valid_file_paths)) # 校验dst_dir_path是否有效 if not dst_dir_path or not os.path.isdir(dst_dir_path): dst_dir_path = os.path.dirname(valid_file_paths[0]) dst_file_path = os.path.join(dst_dir_path, 'output.pdf') # 合并PDF if len(valid_file_paths) == 0: raise ValueError('Not enough PDFs.') elif len(valid_file_paths) == 1: shutil.copy(valid_file_paths[0], dst_file_path) else: merger = PdfFileMerger() for src_file_path in valid_file_paths: _LOGGER.debug('[Converter/document/merge_PDF] Reading "{}".'.format(src_file_path)) with open(src_file_path, 'rb') as f: merger.append(PdfFileReader(f), 'rb') _LOGGER.info('[Converter/document/merge_PDF] Writing "{}".'.format(dst_file_path)) with open(dst_file_path, 'wb') as f: merger.write(f) return dst_file_path
def main(): # argparse:传入path parser = argparse.ArgumentParser(prog='Merge', description='读取所有输入的Word文件,转换后合并PDF。') # 传入preserve,保留合并时产生的临时文件 parser.add_argument('-p', '--preserve', default=False, action='store_true', help='preserve temp PDF') parser.add_argument('path', nargs='+', help='file path or dir path') args = parser.parse_args() preserve = args.preserve _LOGGER.info('[Merge] Started.') # 过滤doc/docx/pdf _LOGGER.debug('[Merge] arg_paths = "{}".'.format(args.path)) # 传入的参数有顺序要求,不能使用set target_paths = [] for arg_path in args.path: target_paths.extend( Converter.walk.file(arg_path, ['.doc', '.docx', '.pdf'])) _LOGGER.debug('[Merge] target_paths = "{}".'.format(target_paths)) # 调用Converter.document处理 temp_PDF_paths = [] try: for target_path in target_paths: temp_PDF_paths.append(Converter.document.convert_PDF(target_path)) Converter.document.merge_PDF(temp_PDF_paths) if not preserve: for temp_PDF_path in set(temp_PDF_paths).difference(target_paths): os.remove(temp_PDF_path) except Exception as err: _LOGGER.warning('[Merge] Merge failure due to "{}"'.format(err)) _LOGGER.info('[Merge] Finished.')
def main(): # 目前本地数据库文件必须位于可执行文件的同目录下 db_file_path = os.path.join(os.path.dirname(sys.argv[0]), 'vulns.sqlite3') # argparse:传入path parser = argparse.ArgumentParser( prog='Nessus', description='读取Nessus的CSV文件,将描述文字翻译成中文,转换结果分别保存至每个原始文件的同目录下。') parser.add_argument('path', nargs='+', help='file path or dir path') args = parser.parse_args() _LOGGER.info('[Nessus] Started.') # 本地数据库无效时,使用服务器版本强制覆盖 if not Converter.sqlite.isvalid_Nessus(db_file_path): _LOGGER.warning('[Nessus] Invalid local DB. Downloading...') Converter.sqlite.update_Nessus(db_file_path) # 过滤csv并去重 _LOGGER.debug('[Nessus] arg_paths = "{}".'.format(args.path)) target_paths = set() for arg_path in args.path: target_paths = target_paths.union( set(Converter.walk.file(arg_path, ['.csv']))) _LOGGER.debug('[Nessus] target_paths = "{}".'.format(target_paths)) # 调用Converter.csv处理 count = 0 for target_path in target_paths: try: rows = Converter.csv.read_Nessus(target_path, db_file_path) Converter.csv.write( rows, os.path.splitext(target_path)[0] + '_converted.csv') count += 1 except Exception as err: _LOGGER.warning( '[Nessus] Conversion failure due to "{}"'.format(err)) _LOGGER.info('[Nessus] Finished with {} converted.'.format(count))