├── .gitignore ├── LICENSE ├── PackerFuzzer.py ├── README.md ├── config.ini ├── doc ├── dict │ ├── password.dic │ └── username.dic ├── kiwi │ ├── README.en.md │ └── demo-terminal.png ├── lang.ini └── template │ ├── en.docx │ ├── es.docx │ ├── fr.docx │ ├── html │ ├── en.html │ ├── es.html │ ├── fr.html │ ├── ja.html │ ├── res │ │ ├── OverlayScrollbars.min.css │ │ ├── adminlte.min.css │ │ ├── adminlte.min.js │ │ ├── all.min.css │ │ ├── bootstrap.bundle.min.js │ │ ├── css │ │ ├── dataTables.bootstrap4.min.css │ │ ├── dataTables.bootstrap4.min.js │ │ ├── fa-brands-400.eot │ │ ├── fa-brands-400.svg │ │ ├── fa-brands-400.ttf │ │ ├── fa-brands-400.woff │ │ ├── fa-brands-400.woff2 │ │ ├── fa-regular-400.eot │ │ ├── fa-regular-400.svg │ │ ├── fa-regular-400.ttf │ │ ├── fa-regular-400.woff │ │ ├── fa-regular-400.woff2 │ │ ├── fa-solid-900.eot │ │ ├── fa-solid-900.svg │ │ ├── fa-solid-900.ttf │ │ ├── fa-solid-900.woff │ │ ├── fa-solid-900.woff2 │ │ ├── images.jpeg │ │ ├── index.js │ │ ├── ionicons.min.css │ │ ├── jquery-ui.min.js │ │ ├── jquery.dataTables.min.js │ │ ├── jquery.min.js │ │ └── jquery.overlayScrollbars.min.js │ └── zh.html │ ├── ja.docx │ └── zh.docx ├── ext ├── __init__.py ├── demo.py └── waf_ban.py ├── lib ├── ApiCollect.py ├── CheckPacker.py ├── Controller.py ├── CreateReport.py ├── Database.py ├── DownloadJs.py ├── FuzzParam.py ├── LoadExtensions.py ├── ParseJs.py ├── PostApiText.py ├── PostDataText.py ├── Recoverspilt.py ├── TestProxy.py ├── __init__.py ├── common │ ├── CreatLog.py │ ├── __init__.py │ ├── banner.py │ ├── beautyJS.py │ ├── cmdline.py │ ├── groupBy.py │ ├── readConfig.py │ ├── utils.py │ └── webRequest.py ├── getApiResponse.py ├── getApiText.py ├── reports │ ├── CreatHtml.py │ ├── CreatPdf.py │ ├── CreatTxt.py │ ├── CreatWord.py │ ├── __init__.py │ ├── creat_api.py │ ├── creat_suggest.py │ ├── creat_tree.py │ └── creat_vuln_detail.py ├── vuln │ ├── BacTest.py │ ├── CorsTest.py │ ├── InfoTest.py │ ├── PasswordTest.py │ ├── SqlTest.py │ ├── UnauthTest.py │ ├── UploadTest.py │ └── __init__.py └── vulnTest.py ├── logs └── README.MD ├── reports └── README.MD ├── requirements.txt └── tmp └── README.MD /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.pyc 4 | .DS_Store 5 | main.db 6 | lib/test.py 7 | 8 | tmp/*.lock 9 | tmp/*/* 10 | reports/*.docx 11 | reports/*.html 12 | reports/*.pdf 13 | reports/*.txt 14 | reports/res/ 15 | 16 | # Distribution / packaging 17 | .Python 18 | env/ 19 | build/ 20 | develop-eggs/ 21 | dist/ 22 | downloads/ 23 | eggs/ 24 | .eggs/ 25 | lib64/ 26 | parts/ 27 | sdist/ 28 | var/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | .idea/ 33 | 34 | # PyInstaller 35 | # Usually these files are written by a python script from a template 36 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 37 | *.manifest 38 | *.spec 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .coverage 48 | .coverage.* 49 | .cache 50 | nosetests.xml 51 | coverage.xml 52 | *,cover 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | -------------------------------------------------------------------------------- /PackerFuzzer.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | # -*- encoding: utf-8 -*- 3 | 4 | from lib.Controller import Project 5 | from lib.TestProxy import testProxy 6 | from lib.common.banner import RandomBanner 7 | from lib.common.cmdline import CommandLines 8 | from lib.common.readConfig import ReadConfig 9 | 10 | 11 | class Program(): 12 | def __init__(self,options): 13 | self.options = options 14 | 15 | def check(self): 16 | url = self.options.url 17 | t = Project(url,self.options) 18 | t.parseStart() 19 | 20 | 21 | if __name__ == '__main__': 22 | cmd = CommandLines().cmd() 23 | testProxy(cmd,1) 24 | PackerFuzzer = Program(cmd) 25 | PackerFuzzer.check() 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Packer Fuzzer

2 | 3 |

一款针对Webpack等前端打包工具所构造的网站进行快速、高效安全检测的扫描工具

4 | 5 |

6 | Packer-Fuzzer 7 | Packer-Fuzzer 8 | Packer-Fuzzer 9 | Packer-Fuzzer 10 | Packer-Fuzzer 11 |

由Poc-Sir、KpLi0rn、Liucy、RachesseHS、Lupin-III荣誉出品
12 |
Click here for the English version
13 |

14 | 15 | 16 |

17 | DEMO 18 |

19 | 20 | 21 | 22 | ## 👮🏻‍♀️ 免责声明 23 | 24 | 由于传播、利用Packer Fuzzer工具(下简称本工具)提供的检测功能而造成的**任何直接或者间接的后果及损失**,均由使用者本人负责,Packer Fuzzer开发团队(下简称本团队)**不为此承担任何责任**。 25 | 26 | 本工具会根据使用者检测结果**自动生成**扫描结果报告,本报告内容及其他衍生内容均**不能代表**本团队的立场及观点。 27 | 28 | 请在使用本工具时遵循使用者以及目标系统所在国当地的**相关法律法规**,一切**未授权测试均是不被允许的**。若出现相关违法行为,我们将**保留追究**您法律责任的权利,并**全力配合**相关机构展开调查。 29 | 30 | 31 | 32 | ## 🏝 介是个嘛 33 | 34 | 随着WEB前端打包工具的流行,您在日常渗透测试、安全服务中是否遇到越来越多以`Webpack打包器`为代表的网站?这类打包器会将整站的API和API参数打包在一起供Web集中调用,这也便于我们快速发现网站的功能和API清单,但往往这些打包器所生成的JS文件数量异常之多并且总JS代码量异常庞大(多达上万行),这给我们的手工测试带来了极大的不便,Packer Fuzzer软件应运而生。 35 | 36 | 本工具支持自动模糊提取对应目标站点的API以及API对应的参数内容,并支持对:未授权访问、敏感信息泄露、CORS、SQL注入、水平越权、弱口令、任意文件上传七大漏洞进行模糊高效的快速检测。在扫描结束之后,本工具还支持自动生成扫描报告,您可以选择便于分析的HTML版本以及较为正规的doc、pdf、txt版本。 37 | 38 | 而且您完全不用担心因为国际化带来的语言问题,本工具附带五大主流语言语言包(包括报告模板):简体中文、法语、西班牙语、英语、日语(根据翻译准确度排序),由我们非常~~不~~专业的团队翻译。 39 | 40 | > 注:目前第一版工具只对Webpack打包器的规则做了优化,其他打包器规则敬请期待。 41 | 42 | 43 | 44 | ## 🎸 安装环境 45 | 46 | 1. 本工具使用Python3语言开发,在运行本工具之前请确保您装有`Python3.X`软件及`pip3`软件。若您未安装相关环境,可通过如下指引安装:[https://www.runoob.com/python3/python3-install.html](https://www.runoob.com/python3/python3-install.html) 47 | 48 | MacOS用户可使用如下命令快速安装: 49 | 50 | ```bash 51 | brew install python3 #会自动安装pip3 52 | ``` 53 | 54 | Ubuntu用户可使用如下命令快速安装: 55 | 56 | ```bash 57 | sudo apt-get install -y python3 && sudo apt install -y python3-pip 58 | ``` 59 | 60 | CentOS用户可使用如下命令快速安装: 61 | 62 | ```bash 63 | sudo yum -y install epel-release && sudo yum install python3 && yum install -y python3-setuptools && easy_install pip 64 | ``` 65 | 66 | 2. 本工具将会通过`node_vm2`运行原生`NodeJS`代码,故我们推荐您安装`NodeJS`环境(不推荐其他JS运行环境,可能会导致解析失败)。若您未安装相关环境,可通过如下指引安装:[https://www.runoob.com/nodejs/nodejs-install-setup.html](https://www.runoob.com/nodejs/nodejs-install-setup.html) 67 | 68 | MacOS用户可使用如下命令快速安装: 69 | 70 | ```bash 71 | brew install node 72 | ``` 73 | 74 | Ubuntu用户可使用如下命令快速安装: 75 | 76 | ```bash 77 | sudo apt-get install nodejs && sudo apt-get install npm 78 | ``` 79 | 80 | CentOS用户可使用如下命令快速安装: 81 | 82 | ```bash 83 | sudo yum -y install nodejs 84 | ``` 85 | 86 | 3. 请使用如下命令一键安装本工具所需要的Python运行库: 87 | 88 | ```bash 89 | pip3 install -r requirements.txt 90 | ``` 91 | 92 | 93 | 94 | ## 🦁 参数介绍 95 | 96 | 您可以使用`python3 PackerFuzzer.py [options]`命令来运行本工具,`options`内容表述如下: 97 | 98 | - -h(--help) 99 | 100 | 帮助命令,无需附加参数,查看本工具支持的全部参数及其对应简介; 101 | 102 | - -u(--url) 103 | 104 | 要扫描的网站网址路径,为必填选项,例如:`-u https://demo.poc-sir.com`; 105 | 106 | - -c(--cookie) 107 | 108 | 附加cookies内容,可为空,若填写则将全局传入,例如:`-c "POC=666;SIR=233"`; 109 | 110 | - -d(--head) 111 | 112 | 附加HTTP头部内容,可为空,若填写则将全局传入,默认为`Cache-Control:no-cache`,例如:`-d "Token:3VHJ32HF0"`; 113 | 114 | - -l(--lang) 115 | 116 | 语言选项,当为空时自动选择系统对应语言选项,若无对应语言包则自动切换至英文界面。可供选择的语言包有:简体中文(zh)、法语(fr)、西班牙语(es)、英语(en)、日语(ja),例如:`-l zh`; 117 | 118 | - -t(--type) 119 | 120 | 分为基础版和高级版,当为空时默认使用基础版。高级版将会对所有API进行重新扫描并模糊提取API对应的参数,并进行:SQL注入漏洞、水平越权漏洞、弱口令漏洞、任意文件上传漏洞的检测。可使用`adv`选项进入高级版,例如:`-t adv`; 121 | 122 | - -p(--proxy) 123 | 124 | 全局代理,可为空,若填写则全局使用代理IP,例如:`-p https://hack.cool:8080`; 125 | 126 | - -j(--js) 127 | 128 | 附加JS文件,可为空,当您认为还有其他JS文件需要本工具分析时,可使用此选项,例如:`-j https://demo.poc-sir.com/js/index.js,https://demo.poc-sir.com/js/vue.js`; 129 | 130 | - -b(--base) 131 | 132 | 指定API中间部分(例如某API为:https://demo.poc-sir.com/v1_api/login 时,则其basedir为:v1_api),可为空,当您认为本工具自动提取的basedir不准确时,可使用此选项,例如:`-b v1_api`; 133 | 134 | - -r(--report) 135 | 136 | 指定生成的报告格式,当为空时默认生成HTML和DOC格式的报告。可供选择的报告格式有:html、doc、pdf、txt,例如:`-r html,pdf`; 137 | 138 | - -e(--ext) 139 | 140 | 是否开启扩展插件选项,本工具支持用户自我编写插件并存入`ext`目录(如何编写请参考对应目录下`demo.py`文件)。默认为关闭状态,当用户使用`on`命令开启时,本工具将会自动执行对应目录下的插件,例如:`-e on`; 141 | 142 | - -f(--flag) 143 | 144 | SSL连接安全选项,当为空时默认关闭状态,在此状态下将会阻止一切不安全的连接。若您希望忽略SSL安全状态,您可使用`1`命令开启,将会忽略一切证书错误,例如:`-f 1`; 145 | 146 | - -s(--silent) 147 | 148 | 静默选项,一旦开启则一切询问YES或NO的操作都将自动设置为YES,并且参数后的内容便是本次扫描报告的名称(自定义报告名),可用于无人值守、批量操作、插件调用等模式,例如:`-s Scan_Task_777`。 149 | 150 | - --st(--sendtype) 151 | 152 | 请求方式选项,目前本选项支持POST和GET参数,一旦开启则将会使用对应的请求方式扫描所有的API,若不开启将会通过HTTP状态码来进行智能请求。 153 | 154 | - --ct(--contenttype) 155 | 156 | Content-Type选项,可通过此选项自定义扫描时的HTTP请求头中的Content-Type参数内容,若不开启将会通过HTTP状态码来进行智能请求。 157 | 158 | - --pd(--postdata) 159 | 160 | POST内容选项,可通过此选项自定义扫描时的POST请求内容(所有的扫描都将会使用此内容,仅对POST场景有效),若不开启将会通过HTTP状态码来进行智能请求。 161 | 162 | - --ah(--apihost) 163 | 164 | Api域名选项,可通过此选项自定义扫描时所有的API请求域名,例如:api部分(从JS中提取到的API路径)为`/v1/info`,扫描的url(-u --url参数传入内容,扫描的网页)为`http://exp.com/`,当apihost参数传入`https://pocsir.com:777/`则此时的API为`https://pocsir.com:777/v1/info`而不是`http://exp.com/v1/info`,用于api与前端不同域名或服务器等场景。 165 | 166 | - --fe(--fileext) 167 | 168 | Api扩展名选项,可通过此选项对所有API都添加特定的扩展名,以便应对在提取API时出现扩展名提取缺失的情况,例如:当提取到的API为`https://pocsir.com:777/v1/info`时,传入`--fe .json`则工具将会自动将API转化成`https://pocsir.com:777/v1/info.json`进行扫描及检测。 169 | 170 | 171 | 172 | ## 🎯 使用技巧 173 | 174 | - 当您遇到假卡死或者扫描器因为意外的错误而被中断时,您无需过于担心。您可以直接在tmp目录下找到对应缓存文件夹内的以`.db`结尾的Sqlite数据库文件,当您打开之后您可以看见对应项目的所有实时结果均保存在此数据库内,您可以直接通过缓存数据库分析当前的扫描结果; 175 | - 我们推荐您通过自定义`baseurl`的方式来提高API拼接成功率,减少发包次数。找寻`baseurl`并不难,您只需要在对应目标站点中触发任何一个API并稍加观察缺失部分即可快速寻找到; 176 | - 我们不推荐您在较大、较复杂的站点中使用本工具的高级模式,因为在一些情况下高级模式会耗费异常大量的时间去不停地在后台做正则匹配,从而使本工具陷入假卡死的状态; 177 | - 当您遇到A站点的API均在B站点时:您可以直接使用本工具的`--ah(--apihost)`命令来自定义API服务器地址; 178 | - 当您遇到在Windows环境下无法创建、读取数据库时,您可以右键点击`使用管理员身份运行`。当您在Linux/Mac下时请也注意权限问题,推荐使用`sudo`命令。 179 | 180 | 181 | 182 | ## 📝 意见交流 183 | 184 | 您可以直接在Github仓库中提交ISSUE:[https://github.com/rtcatc/Packer-Fuzzer/issues](https://github.com/rtcatc/Packer-Fuzzer/issues) 185 | 186 | 如果您认为具体目标不宜直接公开,您可以给我们发送邮件:admin[at]hackinn.com 187 | 188 | 在提交时,为了便于我们判断,请附上`logs`目录中对应的日志文件,谢谢您的配合! 189 | 190 | 与此同时您可以扫描左下方群聊二维码加入我们的微信讨论群(受微信限制,此方式暂不可用),或者您可以扫描右边“天下大木头(KpLi0rn)”的个人二维码备注“Packer Fuzzer”由他拉您入群聊: 191 | 192 |

193 | QR-code 194 | QR-code 195 |

196 | 197 | 198 | 199 | ## 🍻 贡献名单 200 | 201 |

202 | Poc Sir Poc Sir 203 |       204 | KpLi0rn KpLi0rn 205 |       206 | Liucy Liucy 207 |       208 | RachesseHS RachesseHS 209 |

210 | 211 | 212 | 213 | ## 👑 更新记录 214 | 215 | - v1.0 2020/09/30 216 | 217 | 1. 开天辟地,懂的自然懂. 218 | 219 | - v1.1 2020/11/21 220 | 221 | 1. 修复了一些Windows系统下的兼容性问题; 222 | 223 | 2. 改进了全局证书校验忽略的部分; 224 | 225 | 3. 修复了多处可能会导致扫描器产生严重错误的bug. 226 | 227 | - v1.2 2021/01/21 228 | 229 | 1. 增加前端打包器识别功能和资产树显示功能; 230 | 231 | 2. 优化了异步提取规则并新增了两类API识别规则; 232 | 233 | 3. 修复了报告及数据库无法正确生成的bug; 234 | 235 | 4. 增加了静默模式,便于批量测试或多平台联动; 236 | 237 | 5. 紧急修复了一个可能会导致任意命令执行的漏洞。 238 | 239 | - v1.3 2021/04/23 240 | 241 | 1. 修复了若干可能导致检测异常的Bug; 242 | 243 | 2. 将PyExecJS替换为相对安全的node_vm2; 244 | 245 | 3. 优化了终端显示界面,增加了新的交互提示; 246 | 247 | 4. 优化了BaseDir的处理模式,使其更加人性化。 248 | 249 | - v1.4 2022/06/19 250 | 251 | 1. 修复了若干会导致扫描器异常运行的Bug; 252 | 253 | 2. 移除废弃的python扩展内容; 254 | 255 | 3. 优化了HTML报告,现可显示API返回内容长度,并可进行排序; 256 | 257 | 4. 添加了POST和GET请求切换机制; 258 | 259 | 5. 添加了Content-Type请求头的自定义功能; 260 | 261 | 6. 添加了POST请求时的数据内容自定义功能; 262 | 263 | 7. 添加了自定义Api服务器地址的功能。 264 | -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | [blacklist] 2 | filename = jquery.js,flexible.js,data-set.js,monitor.js,honeypot.js,angular.js 3 | domain = api.map.baidu.com,alipayobjects.com 4 | apiExts = *,+,=,{,},[,],(,),<,>,@,#,",',@,:,?,!, ,^,\,(,),.docx,.xlsx,.jpeg,.jpg,.bmp,.png,.svg,.vue,.js,.doc,.ppt,.pptx,.mp3,.png,.doc,.pptx,.xls,.mp4,.gif,.css,.eot,.otf,.ttf,.woff2,.woff 5 | 6 | [vulnTest] 7 | resultFilter = 未登录,请登录,重新登录,登录失效,权限鉴定失败,未授权,鉴权失败,unauth,状态失效,没有登录,会话超时,token???,login_failure,token can not be null,need token,Need Access Token,Access Token Is Null,have not Access-Token,token is empty,登录失败,凭证失效,未认证,认证失败,未发现认证,登录无效,令牌错误,token is error,token error,error token,登录超时,登录无效,会话已过期,会话过期,会话无效,无效凭据,无效会话,Invalid token,invalid token,is invalid,code 401,令牌无,令牌为空,令牌不能为空,null token,need token,需要令牌,控制器不存在 8 | unauth_not_sure = 系统繁忙,系统错误,系统异常,服务器繁忙,参数错误,异常错误,服务端发生异常,服务端异常,安全异常,cookie错误,参数为空,拒绝访问,执行错误,权限错误,未知异常,未知错误,非法访问,访问异常,无权限,没有操作权限,没权限,code 500 9 | login = 登录成功,login success,密码正确,成功登录,auth success,login ok 10 | 11 | [infoTest] 12 | info = REDIS_PM§§§Redis Password,APP_KEY§§§Third APP Key,password§§§Password Info,BEGIN RSA PRIVATE KEY§§§RSA PRIVATE KEY,email§§§email address,AccessKeyId§§§Access Key Id,AccessKeySecret§§§Access Key Secret,accesskey§§§Access Key,accesstoken§§§Access Token,client_id§§§Client id,client_secret§§§Client secret,secretkey§§§Secret Key,token§§§token,access_key§§§Access Key,access_token§§§Access Token,secret§§§secret Key,APP_SECRET§§§APP Secret,MQTT§§§MQTT,appSecret§§§App Secret 13 | infoFilter =s is not a,password,mail 14 | 15 | [FuzzerParam] 16 | param = success,post,get 17 | default = id,num,number,code,type,flag 18 | 19 | [vuln] 20 | passwordtest_list = login.do,signin,login,user,admin 21 | passworduser_list = userCode,username,name,user,nickname 22 | passwordpass_list = userPass,password,pass,code 23 | uploadtest_list = upload,file,doc,pic,update 24 | upload_fail = 上传失败,不允许,不合法,非法,禁止,fail,失败,错误 25 | upload_success = 上传成功,php,asp,jsp,success,200,成功,已上传 26 | -------------------------------------------------------------------------------- /doc/dict/password.dic: -------------------------------------------------------------------------------- 1 | 123456 2 | test 3 | admin 4 | admin888 5 | test123 6 | -------------------------------------------------------------------------------- /doc/dict/username.dic: -------------------------------------------------------------------------------- 1 | root 2 | test 3 | admin 4 | -------------------------------------------------------------------------------- /doc/kiwi/demo-terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rtcatc/Packer-Fuzzer/bd7c98009e7df6aaa32daa86676ad6887388929c/doc/kiwi/demo-terminal.png -------------------------------------------------------------------------------- /doc/template/en.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rtcatc/Packer-Fuzzer/bd7c98009e7df6aaa32daa86676ad6887388929c/doc/template/en.docx -------------------------------------------------------------------------------- /doc/template/es.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rtcatc/Packer-Fuzzer/bd7c98009e7df6aaa32daa86676ad6887388929c/doc/template/es.docx -------------------------------------------------------------------------------- /doc/template/fr.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rtcatc/Packer-Fuzzer/bd7c98009e7df6aaa32daa86676ad6887388929c/doc/template/fr.docx -------------------------------------------------------------------------------- /doc/template/html/res/css: -------------------------------------------------------------------------------- 1 | /* cyrillic-ext */ 2 | @font-face { 3 | font-family: 'Source Sans Pro'; 4 | font-style: italic; 5 | font-weight: 400; 6 | src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7qsDJB9cme_xc.woff2) format('woff2'); 7 | unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; 8 | } 9 | /* cyrillic */ 10 | @font-face { 11 | font-family: 'Source Sans Pro'; 12 | font-style: italic; 13 | font-weight: 400; 14 | src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7jsDJB9cme_xc.woff2) format('woff2'); 15 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 16 | } 17 | /* greek-ext */ 18 | @font-face { 19 | font-family: 'Source Sans Pro'; 20 | font-style: italic; 21 | font-weight: 400; 22 | src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7rsDJB9cme_xc.woff2) format('woff2'); 23 | unicode-range: U+1F00-1FFF; 24 | } 25 | /* greek */ 26 | @font-face { 27 | font-family: 'Source Sans Pro'; 28 | font-style: italic; 29 | font-weight: 400; 30 | src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7ksDJB9cme_xc.woff2) format('woff2'); 31 | unicode-range: U+0370-03FF; 32 | } 33 | /* vietnamese */ 34 | @font-face { 35 | font-family: 'Source Sans Pro'; 36 | font-style: italic; 37 | font-weight: 400; 38 | src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7osDJB9cme_xc.woff2) format('woff2'); 39 | unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; 40 | } 41 | /* latin-ext */ 42 | @font-face { 43 | font-family: 'Source Sans Pro'; 44 | font-style: italic; 45 | font-weight: 400; 46 | src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7psDJB9cme_xc.woff2) format('woff2'); 47 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 48 | } 49 | /* latin */ 50 | @font-face { 51 | font-family: 'Source Sans Pro'; 52 | font-style: italic; 53 | font-weight: 400; 54 | src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7nsDJB9cme.woff2) format('woff2'); 55 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 56 | } 57 | /* cyrillic-ext */ 58 | @font-face { 59 | font-family: 'Source Sans Pro'; 60 | font-style: normal; 61 | font-weight: 300; 62 | src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmhdu3cOWxy40.woff2) format('woff2'); 63 | unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; 64 | } 65 | /* cyrillic */ 66 | @font-face { 67 | font-family: 'Source Sans Pro'; 68 | font-style: normal; 69 | font-weight: 300; 70 | src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwkxdu3cOWxy40.woff2) format('woff2'); 71 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 72 | } 73 | /* greek-ext */ 74 | @font-face { 75 | font-family: 'Source Sans Pro'; 76 | font-style: normal; 77 | font-weight: 300; 78 | src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmxdu3cOWxy40.woff2) format('woff2'); 79 | unicode-range: U+1F00-1FFF; 80 | } 81 | /* greek */ 82 | @font-face { 83 | font-family: 'Source Sans Pro'; 84 | font-style: normal; 85 | font-weight: 300; 86 | src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwlBdu3cOWxy40.woff2) format('woff2'); 87 | unicode-range: U+0370-03FF; 88 | } 89 | /* vietnamese */ 90 | @font-face { 91 | font-family: 'Source Sans Pro'; 92 | font-style: normal; 93 | font-weight: 300; 94 | src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmBdu3cOWxy40.woff2) format('woff2'); 95 | unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; 96 | } 97 | /* latin-ext */ 98 | @font-face { 99 | font-family: 'Source Sans Pro'; 100 | font-style: normal; 101 | font-weight: 300; 102 | src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmRdu3cOWxy40.woff2) format('woff2'); 103 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 104 | } 105 | /* latin */ 106 | @font-face { 107 | font-family: 'Source Sans Pro'; 108 | font-style: normal; 109 | font-weight: 300; 110 | src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwlxdu3cOWxw.woff2) format('woff2'); 111 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 112 | } 113 | /* cyrillic-ext */ 114 | @font-face { 115 | font-family: 'Source Sans Pro'; 116 | font-style: normal; 117 | font-weight: 400; 118 | src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNa7lujVj9_mf.woff2) format('woff2'); 119 | unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; 120 | } 121 | /* cyrillic */ 122 | @font-face { 123 | font-family: 'Source Sans Pro'; 124 | font-style: normal; 125 | font-weight: 400; 126 | src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qPK7lujVj9_mf.woff2) format('woff2'); 127 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 128 | } 129 | /* greek-ext */ 130 | @font-face { 131 | font-family: 'Source Sans Pro'; 132 | font-style: normal; 133 | font-weight: 400; 134 | src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNK7lujVj9_mf.woff2) format('woff2'); 135 | unicode-range: U+1F00-1FFF; 136 | } 137 | /* greek */ 138 | @font-face { 139 | font-family: 'Source Sans Pro'; 140 | font-style: normal; 141 | font-weight: 400; 142 | src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qO67lujVj9_mf.woff2) format('woff2'); 143 | unicode-range: U+0370-03FF; 144 | } 145 | /* vietnamese */ 146 | @font-face { 147 | font-family: 'Source Sans Pro'; 148 | font-style: normal; 149 | font-weight: 400; 150 | src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qN67lujVj9_mf.woff2) format('woff2'); 151 | unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; 152 | } 153 | /* latin-ext */ 154 | @font-face { 155 | font-family: 'Source Sans Pro'; 156 | font-style: normal; 157 | font-weight: 400; 158 | src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNq7lujVj9_mf.woff2) format('woff2'); 159 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 160 | } 161 | /* latin */ 162 | @font-face { 163 | font-family: 'Source Sans Pro'; 164 | font-style: normal; 165 | font-weight: 400; 166 | src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7lujVj9w.woff2) format('woff2'); 167 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 168 | } 169 | /* cyrillic-ext */ 170 | @font-face { 171 | font-family: 'Source Sans Pro'; 172 | font-style: normal; 173 | font-weight: 700; 174 | src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmhdu3cOWxy40.woff2) format('woff2'); 175 | unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; 176 | } 177 | /* cyrillic */ 178 | @font-face { 179 | font-family: 'Source Sans Pro'; 180 | font-style: normal; 181 | font-weight: 700; 182 | src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwkxdu3cOWxy40.woff2) format('woff2'); 183 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 184 | } 185 | /* greek-ext */ 186 | @font-face { 187 | font-family: 'Source Sans Pro'; 188 | font-style: normal; 189 | font-weight: 700; 190 | src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmxdu3cOWxy40.woff2) format('woff2'); 191 | unicode-range: U+1F00-1FFF; 192 | } 193 | /* greek */ 194 | @font-face { 195 | font-family: 'Source Sans Pro'; 196 | font-style: normal; 197 | font-weight: 700; 198 | src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlBdu3cOWxy40.woff2) format('woff2'); 199 | unicode-range: U+0370-03FF; 200 | } 201 | /* vietnamese */ 202 | @font-face { 203 | font-family: 'Source Sans Pro'; 204 | font-style: normal; 205 | font-weight: 700; 206 | src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmBdu3cOWxy40.woff2) format('woff2'); 207 | unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; 208 | } 209 | /* latin-ext */ 210 | @font-face { 211 | font-family: 'Source Sans Pro'; 212 | font-style: normal; 213 | font-weight: 700; 214 | src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmRdu3cOWxy40.woff2) format('woff2'); 215 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 216 | } 217 | /* latin */ 218 | @font-face { 219 | font-family: 'Source Sans Pro'; 220 | font-style: normal; 221 | font-weight: 700; 222 | src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(https://fonts.gstatic.com/s/sourcesanspro/v13/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdu3cOWxw.woff2) format('woff2'); 223 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 224 | } 225 | -------------------------------------------------------------------------------- /doc/template/html/res/dataTables.bootstrap4.min.css: -------------------------------------------------------------------------------- 1 | table.dataTable{clear:both;margin-top:6px !important;margin-bottom:6px !important;max-width:none !important;border-collapse:separate !important;border-spacing:0}table.dataTable td,table.dataTable th{-webkit-box-sizing:content-box;box-sizing:content-box}table.dataTable td.dataTables_empty,table.dataTable th.dataTables_empty{text-align:center}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}div.dataTables_wrapper div.dataTables_length label{font-weight:normal;text-align:left;white-space:nowrap}div.dataTables_wrapper div.dataTables_length select{width:auto;display:inline-block}div.dataTables_wrapper div.dataTables_filter{text-align:right}div.dataTables_wrapper div.dataTables_filter label{font-weight:normal;white-space:nowrap;text-align:left}div.dataTables_wrapper div.dataTables_filter input{margin-left:0.5em;display:inline-block;width:auto}div.dataTables_wrapper div.dataTables_info{padding-top:0.85em;white-space:nowrap}div.dataTables_wrapper div.dataTables_paginate{margin:0;white-space:nowrap;text-align:right}div.dataTables_wrapper div.dataTables_paginate ul.pagination{margin:2px 0;white-space:nowrap;justify-content:flex-end}div.dataTables_wrapper div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:1em 0}table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting{padding-right:30px}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;position:relative}table.dataTable thead .sorting:before,table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:before,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:before,table.dataTable thead .sorting_desc_disabled:after{position:absolute;bottom:0.9em;display:block;opacity:0.3}table.dataTable thead .sorting:before,table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_desc:before,table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_desc_disabled:before{right:1em;content:"\2191"}table.dataTable thead .sorting:after,table.dataTable thead .sorting_asc:after,table.dataTable thead .sorting_desc:after,table.dataTable thead .sorting_asc_disabled:after,table.dataTable thead .sorting_desc_disabled:after{right:0.5em;content:"\2193"}table.dataTable thead .sorting_asc:before,table.dataTable thead .sorting_desc:after{opacity:1}table.dataTable thead .sorting_asc_disabled:before,table.dataTable thead .sorting_desc_disabled:after{opacity:0}div.dataTables_scrollHead table.dataTable{margin-bottom:0 !important}div.dataTables_scrollBody table{border-top:none;margin-top:0 !important;margin-bottom:0 !important}div.dataTables_scrollBody table thead .sorting:before,div.dataTables_scrollBody table thead .sorting_asc:before,div.dataTables_scrollBody table thead .sorting_desc:before,div.dataTables_scrollBody table thead .sorting:after,div.dataTables_scrollBody table thead .sorting_asc:after,div.dataTables_scrollBody table thead .sorting_desc:after{display:none}div.dataTables_scrollBody table tbody tr:first-child th,div.dataTables_scrollBody table tbody tr:first-child td{border-top:none}div.dataTables_scrollFoot>.dataTables_scrollFootInner{box-sizing:content-box}div.dataTables_scrollFoot>.dataTables_scrollFootInner>table{margin-top:0 !important;border-top:none}@media screen and (max-width: 767px){div.dataTables_wrapper div.dataTables_length,div.dataTables_wrapper div.dataTables_filter,div.dataTables_wrapper div.dataTables_info,div.dataTables_wrapper div.dataTables_paginate{text-align:center}}table.dataTable.table-sm>thead>tr>th{padding-right:20px}table.dataTable.table-sm .sorting:before,table.dataTable.table-sm .sorting_asc:before,table.dataTable.table-sm .sorting_desc:before{top:5px;right:0.85em}table.dataTable.table-sm .sorting:after,table.dataTable.table-sm .sorting_asc:after,table.dataTable.table-sm .sorting_desc:after{top:5px}table.table-bordered.dataTable th,table.table-bordered.dataTable td{border-left-width:0}table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable th:last-child,table.table-bordered.dataTable td:last-child,table.table-bordered.dataTable td:last-child{border-right-width:0}table.table-bordered.dataTable tbody th,table.table-bordered.dataTable tbody td{border-bottom-width:0}div.dataTables_scrollHead table.table-bordered{border-bottom-width:0}div.table-responsive>div.dataTables_wrapper>div.row{margin:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:first-child{padding-left:0}div.table-responsive>div.dataTables_wrapper>div.row>div[class^="col-"]:last-child{padding-right:0} 2 | -------------------------------------------------------------------------------- /doc/template/html/res/dataTables.bootstrap4.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | DataTables Bootstrap 4 integration 3 | ©2011-2017 SpryMedia Ltd - datatables.net/license 4 | */ 5 | (function(b){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(a){return b(a,window,document)}):"object"===typeof exports?module.exports=function(a,d){a||(a=window);if(!d||!d.fn.dataTable)d=require("datatables.net")(a,d).$;return b(d,a,a.document)}:b(jQuery,window,document)})(function(b,a,d,m){var f=b.fn.dataTable;b.extend(!0,f.defaults,{dom:"<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>><'row'<'col-sm-12'tr>><'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", 6 | renderer:"bootstrap"});b.extend(f.ext.classes,{sWrapper:"dataTables_wrapper dt-bootstrap4",sFilterInput:"form-control form-control-sm",sLengthSelect:"custom-select custom-select-sm form-control form-control-sm",sProcessing:"dataTables_processing card",sPageButton:"paginate_button page-item"});f.ext.renderer.pageButton.bootstrap=function(a,h,r,s,j,n){var o=new f.Api(a),t=a.oClasses,k=a.oLanguage.oPaginate,u=a.oLanguage.oAria.paginate||{},e,g,p=0,q=function(d,f){var l,h,i,c,m=function(a){a.preventDefault(); 7 | !b(a.currentTarget).hasClass("disabled")&&o.page()!=a.data.action&&o.page(a.data.action).draw("page")};l=0;for(h=f.length;l", 8 | {"class":t.sPageButton+" "+g,id:0===r&&"string"===typeof c?a.sTableId+"_"+c:null}).append(b("",{href:"#","aria-controls":a.sTableId,"aria-label":u[c],"data-dt-idx":p,tabindex:a.iTabIndex,"class":"page-link"}).html(e)).appendTo(d),a.oApi._fnBindAction(i,{action:c},m),p++)}},i;try{i=b(h).find(d.activeElement).data("dt-idx")}catch(v){}q(b(h).empty().html('