Skip to content

自定义报告模版

使用变量 & 执行js代码

模版中使用 {{.....}} 作为命令分隔符。您可以在模板中添加变量,如:{{reportName}}{{testBasis[0]}}{{vulList[0].vulName}},也可以通过exec标志来执行js运算。

以下表达式将在您的浏览器中运行:

javascript
{{exec
    myFun = () => Math.random()
}}

For循环:

javascript
{{FOR t IN testBasis}}
{{$t}}
{{END-FOR t}}

在列表中使用:

javascript
----------------------------------------------------------
| 名称                          | 备注                     |
----------------------------------------------------------
| {{FOR t IN target}}          |                         |
----------------------------------------------------------
| {{$t[0]}}                    | {{$t[1]}}               |
----------------------------------------------------------
| {{END-FOR t}}                |                         |
----------------------------------------------------------

If判断:

javascript
{{IF supplierType === 'company'}}
{{supplierCompanyName}}
{{END-IF}}

默认参数

系统默认提供如下参数供模版调用:

点击展开参数
参数名描述类型
reportId报告编号string
reportName报告名称string
projectName项目名称string
systemName系统名称string
testTime测试时间string[]
reportTime编写报告时间string
retestTime复测时间 [仅复测]string
testGroup测试成员string
author作者string
dangerLevel威胁等级'高危'|'中危'|'低危'
summary测试总结string
target目标[string[]]
customerCompanyName提测方公司名称string
customerName提测方联系人string
customerPhone提测方联系电话string
customerEmail提测方联系邮箱string
customerAddress提测方联系地址string
supplierType测试方主体类型'company'|'personal'
supplierCompanyName测试方公司名称string
supplierCompanyAddress测试方公司联系地址string
supplierName测试方联系人string
supplierPhone测试方联系电话string
supplierEmail测试方联系邮箱string
testTools测试工具[string[]]
testBasis测试依据[string]
vulList漏洞列表[]
vulListIndexObj根据类型的漏洞列表索引{}
coverSignature封面测试主体名称string
vulHighRiskSum高危漏洞数量int
vulMediumRiskSum中危漏洞数量int
vulLowRiskSum低危漏洞数量int
vulRetestHighRiskSum高危漏洞复测后剩余数量 [仅复测]int
vulRetestMediumRiskSum中危漏洞复测后剩余数量 [仅复测]int
vulRetestLowRiskSum低危漏洞复测后剩余数量 [仅复测]int
vulHighRiskList高危漏洞列表[]
vulMediumRiskList中危漏洞列表[]
vulLowRiskList低危漏洞列表[]
vulTypeObj全部漏洞类型{}

自动目录

如果您需要在模版中插入目录,并且在报告导出后的第一次打开自动更新,需要在上传模版前进行如下操作:

  1. 在文档中插入常规目录
  2. 使用如下Python脚本对文档进行修剪

脚本用法:

shell
python3 -m pip install lxml # 安装XML解析依赖
python3 docx-tidy.py ~/Desktop/xxx.docx # 对docx进行修剪
点击展开脚本代码:docx-tidy.py

下载脚本

python
import io
import os
import sys
import zipfile
from typing import IO
from lxml import etree


def tidy_setting(setting_content: IO[bytes]) -> str:
    tree = etree.parse(setting_content)
    root = tree.getroot()
    namespaces = {
        'w': root.nsmap['w'],
    }
    update_fields_elem = tree.xpath('/w:settings/w:updateFields', namespaces=namespaces)
    if not update_fields_elem:
        settings_elem = tree.xpath('/w:settings', namespaces=namespaces)[0]
        update_fields_elem = etree.Element('{' + namespaces['w'] + '}updateFields')
        update_fields_elem.set('{' + namespaces['w'] + '}val', 'true')
        settings_elem.append(update_fields_elem)
        return etree.tostring(tree, xml_declaration=True, encoding='UTF-8', standalone='yes').decode()
    return ""


def tidy_document(document_content: IO[bytes]) -> str:
    tree = etree.parse(document_content)
    root = tree.getroot()
    namespaces = {
        'w': root.nsmap['w'],
    }
    hyperlink_fields_elem = tree.xpath('//w:hyperlink', namespaces=namespaces)
    if hyperlink_fields_elem:
        for hyperlink in hyperlink_fields_elem:
            hyperlink.getparent().remove(hyperlink)
        return etree.tostring(tree, xml_declaration=True, encoding='UTF-8', standalone='yes').decode()
    return ""


if __name__ == '__main__':
    docx_path = ''
    if docx_path == "":
        if len(sys.argv) == 2:
            docx_path = sys.argv[1]
        else:
            print("请指定文件")
            exit()
    if not os.path.isfile(docx_path):
        print("文件不存在")
        exit()
    with zipfile.ZipFile(docx_path) as z:
        with io.BytesIO() as i:
            i.write(z.read('word/settings.xml'))
            i.seek(0)
            new_setting_content = tidy_setting(i)
        with io.BytesIO() as i:
            i.write(z.read('word/document.xml'))
            i.seek(0)
            new_document_content = tidy_document(i)
        with io.BytesIO() as buffer:
            with zipfile.ZipFile(buffer, 'w') as mem_zip:
                for item in z.infolist():
                    if item.filename == 'word/settings.xml' and new_setting_content != "":
                        mem_zip.writestr(item, new_setting_content)
                    elif item.filename == 'word/document.xml' and new_document_content != "":
                        mem_zip.writestr(item, new_document_content)
                    else:
                        mem_zip.writestr(item, z.read(item.filename))
            with open(docx_path, 'wb') as output_file:
                output_file.write(buffer.getvalue())
    print('Done')