├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ ├── 1feature-request.yaml │ ├── 2bug-report.yaml │ ├── 3other.yaml │ └── config.yml └── workflows │ └── release-charts.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── Dockerfile ├── FAQ.md ├── LICENSE.md ├── README.md ├── README_EN.md ├── blockpage ├── index.html ├── limited.html ├── maintaining.html └── not_found.html ├── charts └── safeline │ ├── .helmignore │ ├── Chart.yaml │ ├── README.md │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── cache │ │ └── cache-pvc.yaml │ ├── chaos │ │ ├── chaos-dpl.yaml │ │ ├── chaos-pvc.yaml │ │ └── chaos-svc.yaml │ ├── database │ │ ├── database-secret.yaml │ │ ├── database-ss.yaml │ │ └── database-svc.yaml │ ├── detector │ │ ├── detector-dpl.yaml │ │ ├── detector-pvc.yaml │ │ └── detector-svc.yaml │ ├── fvm │ │ ├── fvm-dpl.yaml │ │ └── fvm-svc.yaml │ ├── logs │ │ └── logs-pvc.yaml │ ├── luigi │ │ ├── luigi-dpl.yaml │ │ ├── luigi-pvc.yaml │ │ └── luigi-svc.yaml │ ├── mgt │ │ ├── mgt-dpl.yaml │ │ ├── mgt-pvc.yaml │ │ └── mgt-svc.yaml │ ├── nginx │ │ └── nginx-pvc.yaml │ ├── run │ │ └── run-pvc.yaml │ ├── sock │ │ └── sock-pvc.yaml │ └── tengine │ │ ├── tengine-dpl.yaml │ │ └── tengine-svc.yaml │ └── values.yaml ├── release ├── ipgroup │ ├── README.md │ ├── crawler │ │ ├── 360.txt │ │ └── cloudflare.txt │ └── geo │ │ └── cn.txt └── latest │ ├── compose.yaml │ ├── seccomp.json │ ├── setup.sh │ ├── upgrade.sh │ └── version.json ├── website ├── .gitignore ├── .npmrc ├── README.md ├── babel.config.js ├── blog │ └── 2023-08-04-website.md ├── compose.yml ├── docs │ ├── 01-introduction.md │ ├── 02-guide │ │ ├── 01-install.md │ │ ├── 02-login.md │ │ ├── 03-config.md │ │ ├── 04-test.md │ │ ├── 05-upgrade.md │ │ └── _category_.json │ ├── 03-faq │ │ ├── 01-install.md │ │ ├── 02-login.md │ │ ├── 03-other.md │ │ └── _category_.json │ ├── 04-practice │ │ ├── 00-monitor.md │ │ └── _category_.json │ └── 05-about │ │ ├── 00-changelog.md │ │ ├── 01-syntaxanalysis.md │ │ ├── 02-challenge.md │ │ ├── 03-framework.md │ │ ├── 04-chaitin.md │ │ └── _category_.json ├── docusaurus.config.js ├── package-lock.json ├── package.json ├── sidebars.js ├── src │ ├── api │ │ └── index.ts │ ├── components │ │ ├── Features.tsx │ │ ├── Icon.tsx │ │ ├── Message │ │ │ ├── Alert.tsx │ │ │ ├── Message.tsx │ │ │ └── index.tsx │ │ ├── Modal │ │ │ ├── ConfirmDialog.tsx │ │ │ ├── Modal.tsx │ │ │ ├── confrim.tsx │ │ │ └── index.tsx │ │ ├── Theme.tsx │ │ ├── Title.tsx │ │ ├── Version │ │ │ ├── Consultation.tsx │ │ │ ├── FunctionTable.tsx │ │ │ └── index.tsx │ │ ├── detection │ │ │ ├── Result.tsx │ │ │ ├── SampleCount.tsx │ │ │ ├── SampleList.tsx │ │ │ ├── SampleSteps.tsx │ │ │ ├── SamplesForm.tsx │ │ │ └── types.ts │ │ └── utils.ts │ ├── css │ │ └── custom.css │ ├── pages │ │ ├── detection.tsx │ │ └── index.tsx │ └── theme │ │ └── Footer │ │ └── Copyright │ │ └── index.js ├── static │ ├── .nojekyll │ ├── fonts │ │ └── iconfont.js │ └── images │ │ ├── 403.svg │ │ ├── album │ │ ├── 0.png │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ └── block.png │ │ ├── class.png │ │ ├── docs │ │ ├── DNS.png │ │ ├── LoadBlance.png │ │ ├── Untitled10.png │ │ ├── Untitled11.png │ │ ├── Untitled12.png │ │ ├── Untitled13.png │ │ ├── about_changelog │ │ │ ├── acl_page.png │ │ │ ├── api_assets.png │ │ │ ├── api_assets_collect1.png │ │ │ ├── api_assets_collect2.png │ │ │ ├── cert_create.png │ │ │ ├── cs_statistics.png │ │ │ ├── forbidden_page_ext.png │ │ │ ├── log_detail.png │ │ │ ├── map.png │ │ │ ├── mgt_cert.png │ │ │ ├── mgt_cert_config.png │ │ │ ├── site_config.png │ │ │ ├── website_1.png │ │ │ └── website_2.png │ │ ├── add_challenge.png │ │ ├── challenge.png │ │ ├── config_access_log.png │ │ ├── fake_host.jpg │ │ ├── flow.png │ │ ├── framework.png │ │ ├── get_source_ip.png │ │ ├── guide_config │ │ │ ├── deploy_on_separate_server.png │ │ │ ├── deploy_on_web_server.png │ │ │ ├── deploy_origin.png │ │ │ ├── deploy_with_other_server.png │ │ │ └── tengine_502.png │ │ ├── guide_install │ │ │ └── collie_apps.png │ │ ├── guide_introduction │ │ │ ├── website_with_safeline.png │ │ │ └── website_without_safeline.png │ │ ├── manual.png │ │ ├── practice_monitor │ │ │ ├── gift.png │ │ │ ├── machineid.png │ │ │ └── website.png │ │ ├── safeline_https_website.gif │ │ ├── server_index01.png │ │ └── server_index02.png │ │ ├── favicon.ico │ │ ├── feature.svg │ │ ├── gif │ │ ├── config_site.gif │ │ ├── detect_log.gif │ │ └── login.gif │ │ ├── github.png │ │ ├── logo.png │ │ ├── logo.svg │ │ ├── qq.png │ │ ├── safeline.png │ │ ├── wechat-230717.png │ │ ├── wechat-230825.png │ │ ├── wechat-light.png │ │ ├── wechat-logo.png │ │ └── wechat.png └── tsconfig.json └── yanshi ├── .gitignore ├── Makefile ├── README.md ├── contrib ├── vim │ ├── compiler │ │ └── yanshi.vim │ ├── ftdetect │ │ └── yanshi.vim │ ├── ftplugin │ │ └── yanshi.vim │ ├── syntax │ │ └── yanshi.vim │ └── syntax_checkers │ │ └── yanshi │ │ └── yanshi.vim └── zsh │ └── _yanshi ├── src ├── common.cc ├── common.hh ├── compiler.cc ├── compiler.hh ├── fsa.cc ├── fsa.hh ├── fsa_anno.cc ├── fsa_anno.hh ├── lexer.l ├── lexer_helper.cc ├── lexer_helper.hh ├── loader.cc ├── loader.hh ├── location.cc ├── location.hh ├── main.cc ├── option.cc ├── option.hh ├── parser.y ├── repl.cc ├── repl.hh ├── syntax.cc └── syntax.hh └── unittest ├── determinize_test.cc ├── difference_test.cc ├── intersection_test.cc ├── minimize_test.cc ├── union_test.cc └── unittest_helper.hh /.dockerignore: -------------------------------------------------------------------------------- 1 | website/node_modules 2 | website/build 3 | website/.docusaurus 4 | 5 | blazehttp/.github -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1feature-request.yaml: -------------------------------------------------------------------------------- 1 | name: 功能建议 2 | # Feature request 3 | description: 新功能或现有能力的优化建议 4 | title: "[建议] " 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | 提示:创建前请搜索一下是否有重复问题。一个 issue 尽量只描述一个问题。简洁、准确的描述有助于集中大家的意见,推进问题尽快解决 11 | # Please check for duplicate issue first. 12 | # 尽量描述需求的背景、原始问题,避免出现 X-Y 问题,参考: https://coolshell.cn/articles/10804.html 13 | - type: textarea 14 | id: problem 15 | attributes: 16 | label: 背景与遇到的问题 17 | # Background and the problem that frustrates you 18 | placeholder: | 19 | 例如:我的业务有xxx特性,当我在使用xxx功能的时候,会遇到xxx情况... 20 | validations: 21 | required: false 22 | - type: textarea 23 | id: solution 24 | attributes: 25 | label: 建议的解决方案 26 | # Describe the solution you'd like 27 | placeholder: | 28 | 例如:建议增加xxx功能;将xxx改为xxx... 29 | validations: 30 | required: false 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2bug-report.yaml: -------------------------------------------------------------------------------- 1 | name: Bug 2 | description: 明确的软件故障或缺陷 3 | # Create a report to help us improve 4 | title: "[Bug] " 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | 提示:提问前请先搜索一下是否存在重复问题 11 | # Please check for duplicate issue first. 12 | - type: textarea 13 | id: Description 14 | attributes: 15 | label: 问题描述 16 | # Describe the bug 17 | validations: 18 | required: false 19 | - type: input 20 | id: version 21 | attributes: 22 | label: 版本号 23 | placeholder: 3.0.0 24 | validations: 25 | required: true 26 | - type: textarea 27 | id: Reproduce 28 | attributes: 29 | label: 复现方法 30 | # To Reproduce 31 | placeholder: | 32 | 1. ... 33 | 2. ... 34 | validations: 35 | required: true 36 | - type: textarea 37 | id: Expected 38 | attributes: 39 | label: 期望的结果 40 | # Expected behavior. Descript what you expected to happen. 41 | validations: 42 | required: true 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3other.yaml: -------------------------------------------------------------------------------- 1 | name: 其他问题与反馈 2 | description: 文档、部署失败等其他问题。 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | 提示:创建前请先搜索一下是否存在重复问题 8 | # Please check for duplicate issue first. 9 | # 尽量描述需求的背景、原始问题,避免出现 X-Y 问题,参考: https://coolshell.cn/articles/10804.html 10 | # 提問的智慧: https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md 11 | - type: textarea 12 | id: content 13 | attributes: 14 | label: 反馈内容 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: Ture 2 | contact_links: 3 | - name: 绕过反馈 4 | url: https://stack.chaitin.com/security-challenge/safeline/index 5 | about: Waf 绕过可在 CT Stack 安全挑战赛提交细节 6 | -------------------------------------------------------------------------------- /.github/workflows/release-charts.yml: -------------------------------------------------------------------------------- 1 | name: Release Charts 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | release: 10 | permissions: 11 | contents: write 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | with: 17 | fetch-depth: 0 18 | 19 | - name: Configure Git 20 | run: | 21 | git config user.name "$GITHUB_ACTOR" 22 | git config user.email "$GITHUB_ACTOR@users.noreply.github.com" 23 | 24 | - name: Install Helm 25 | uses: azure/setup-helm@v3 26 | 27 | - name: Run chart-releaser 28 | uses: helm/chart-releaser-action@v1.6.0 29 | env: 30 | CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.Zone.Identifier 2 | .DS_Store 3 | *.zip 4 | *.tar 5 | *.tgz 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "blazehttp"] 2 | path = blazehttp 3 | url = https://github.com/chaitin/blazehttp 4 | [submodule "lua-resty-t1k"] 5 | path = lua-resty-t1k 6 | url = https://github.com/chaitin/lua-resty-t1k 7 | [submodule "plugins"] 8 | path = plugins 9 | url = https://github.com/chaitin/safeline-open-platform 10 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20.5-alpine 2 | 3 | RUN apk update 4 | RUN apk add nginx tini 5 | 6 | RUN echo -e " \n\ 7 | server { \n\ 8 | listen 80; \n\ 9 | \n\ 10 | location /api/count { \n\ 11 | proxy_pass https://rivers-telemetry.chaitin.cn:10086; \n\ 12 | } \n\ 13 | location /api/exist { \n\ 14 | proxy_pass https://rivers-telemetry.chaitin.cn:10086; \n\ 15 | } \n\ 16 | location /blazehttp { \n\ 17 | root /app/; \n\ 18 | try_files \$uri =404; \n\ 19 | } \n\ 20 | location /release { \n\ 21 | root /app/; \n\ 22 | try_files \$uri =404; \n\ 23 | } \n\ 24 | location / { \n\ 25 | rewrite /posts/guide_introduction /docs/ permanent; \n\ 26 | rewrite /posts/guide_install /docs/guide/install permanent; \n\ 27 | rewrite /docs/上手指南/guide_install /docs/guide/install permanent; \n\ 28 | rewrite /posts/guide_login /docs/guide/login permanent; \n\ 29 | rewrite /docs/上手指南/guide_login /docs/guide/login permanent; \n\ 30 | rewrite /posts/guide_config /docs/guide/config permanent; \n\ 31 | rewrite /docs/上手指南/guide_config /docs/guide/config permanent; \n\ 32 | rewrite /posts/guide_test /docs/guide/test permanent; \n\ 33 | rewrite /docs/上手指南/guide_test /docs/guide/test permanent; \n\ 34 | rewrite /posts/guide_upgrade /docs/guide/upgrade permanent; \n\ 35 | rewrite /docs/上手指南/guide_upgrade /docs/guide/upgrade permanent; \n\ 36 | rewrite /posts/faq_install /docs/faq/install permanent; \n\ 37 | rewrite /docs/常见问题排查/faq_install /docs/faq/install permanent; \n\ 38 | rewrite /posts/faq_login /docs/faq/login permanent; \n\ 39 | rewrite /docs/常见问题排查/faq_login /docs/faq/login permanent; \n\ 40 | rewrite /posts/faq_access /docs/guide/config permanent; \n\ 41 | rewrite /docs/常见问题排查/faq_access /docs/guide/config permanent; \n\ 42 | rewrite /posts/faq_config /docs/faq/config permanent; \n\ 43 | rewrite /docs/常见问题排查/faq_config /docs/faq/config permanent; \n\ 44 | rewrite /posts/faq_other /docs/faq/other permanent; \n\ 45 | rewrite /docs/常见问题排查/faq_other /docs/faq/other permanent; \n\ 46 | rewrite /posts/about_syntaxanalysis /docs/about/syntaxanalysis permanent; \n\ 47 | rewrite /docs/关于雷池/about_syntaxanalysis /docs/about/syntaxanalysis permanent; \n\ 48 | rewrite /posts/about_challenge /docs/about/challenge permanent; \n\ 49 | rewrite /docs/关于雷池/about_challenge /docs/about/challenge permanent; \n\ 50 | rewrite /posts/about_changelog /docs/about/changelog permanent; \n\ 51 | rewrite /docs/关于雷池/about_changelog /docs/about/changelog permanent; \n\ 52 | rewrite /posts/about_chaitin /docs/about/chaitin permanent; \n\ 53 | rewrite /docs/关于雷池/about_chaitin /docs/about/chaitin permanent; \n\ 54 | rewrite /docs/faq/access /docs/guide/config permanent; \n\ 55 | rewrite /docs/faq/config /docs/guide/config permanent; \n\ 56 | proxy_pass http://127.0.0.1:3000; \n\ 57 | } \n\ 58 | } \n\ 59 | " > /etc/nginx/http.d/default.conf 60 | RUN sed -i 's/access_log/access_log off; #/' /etc/nginx/nginx.conf 61 | RUN nginx -t 62 | 63 | COPY release /app/release 64 | # 需要提前编译 blaze 65 | # cd blaze; ./build.sh 66 | COPY blazehttp/build /app/blazehttp 67 | 68 | COPY website /app 69 | WORKDIR /app 70 | RUN npm ci 71 | RUN npm run build 72 | 73 | CMD nginx; tini -- npm run serve 74 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ## 软件许可证 2 | 3 | 本许可证(以下简称“许可证”)适用于您所获取的软件(以下简称“软件”),请您在使用本软件前仔细阅读以下条款。使用本软件表示您同意并接受本许可证的条款。 4 | 5 | 1. **版权声明** 6 | 本产品的所有代码、镜像、文件其版权均属于北京长亭科技有限公司。 7 | 8 | 2. **使用许可** 9 | 在遵守本许可证条款的前提下,您有权在单一设备上安装、运行本软件,仅用于个人非商业目的。 10 | 11 | 3. **禁止事项** 12 | 您不得对本软件进行以下行为: 13 | a) 破解、逆向工程、反编译、反汇编等行为; 14 | b) 二次包装、修改、改编、复制、翻译、再许可或制作衍生作品; 15 | c) 用于商业用途或任何盈利活动; 16 | d) 未经授权的传播、分发、出售、出租本软件; 17 | e) 将本软件与侵犯他人知识产权或违反法律法规的内容、行为结合。 18 | 19 | 4. **保留权利** 20 | 本软件的版权归原作者所有,除本许可证明确授权外,所有其他权利均由原作者保留。未经原作者明确授权,您不得行使本许可证未明确授权的其他权利。如超出授权使用,原作者保留追究法律责任的权利。 21 | 22 | 5. **免责声明** 23 | 本软件按“现状”提供,不提供任何形式的保证,包括但不限于对适销性、适用于特定用途、无侵权等方面的保证。原作者对于因使用本软件而造成的任何损失、损害、诉讼等不承担责任。 24 | 25 | 6. **终止条款** 26 | 本许可证自您接受之日起生效,直至终止。如您未遵守本许可证的任何条款,原作者有权随时终止本许可证。一旦许可证终止,您必须停止使用本软件,并销毁您拥有或控制的所有副本。 27 | 28 | 7. **适用法律与争议解决** 29 | 本许可证受原作者所在国家或司法管辖区法律的约束并依据其解释。任何因本许可证引起的或与其相关的争议应通过协商解决。如协商无果,任何一方均可将争议提交原作者所在国家或司法管辖区的有管辖权的法院解决。 30 | 31 | ## License 32 | 33 | This License (hereinafter referred to as "License") applies to the software you have obtained (hereinafter referred to as "Software"). Please read the following terms carefully before using the Software. Using the Software indicates your agreement and acceptance of the terms of this License. 34 | 35 | 1. **Copyright Notice** 36 | All codes, images, and files of this product are copyrighted by Beijing Chaitin Future Technology Co.,Ltd 37 | 38 | 2. **Usage Permission** 39 | Subject to compliance with the terms of this License, you are granted the right to install and run the Software on a single device for personal non-commercial purposes only. 40 | 41 | 3. **Prohibitions** 42 | You shall not engage in the following activities in relation to the Software: 43 | a) Cracking, reverse engineering, decompiling, disassembling, or other similar actions; 44 | b) Repackaging, modifying, adapting, copying, translating, sublicensing, or creating derivative works; 45 | c) Using for commercial purposes or any profit-making activities; 46 | d) Unauthorized dissemination, distribution, sale, or rental of the Software; 47 | e) Combining the Software with content or actions that infringe upon the intellectual property rights of others or violate laws and regulations. 48 | 49 | 4. **Reservation of Rights** 50 | The copyright of the Software belongs to the original author. All other rights not expressly granted in this License are reserved by the original author. You may not exercise any other rights not expressly granted in this License without the explicit authorization of the original author.If used beyond the scope of the authorization, the original author reserves the right to pursue legal liability. 51 | 52 | 5. **Disclaimers** 53 | The Software is provided "as is" without any warranties of any kind, including but not limited to warranties of merchantability, fitness for a particular purpose, or non-infringement. The original author shall not be liable for any loss, damage, litigation, or any other consequences resulting from the use of the Software. 54 | 55 | 6. **Termination** 56 | This License shall be effective upon your acceptance and shall continue in effect until terminated. The original author reserves the right to terminate this License at any time if you fail to comply with any of the terms and conditions of this License. Upon termination, you must cease all use of the Software and destroy all copies in your possession or control. 57 | 58 | 7. **Applicable Law and Dispute Resolution** 59 | This License shall be governed by and construed in accordance with the laws of the country or jurisdiction where the original author is located. Any disputes arising from or in connection with this License shall be resolved through negotiation. In case no settlement can be reached through negotiation, either party may submit the dispute to the competent court of the country or jurisdiction where the original author is located. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 |

雷池 - 广受好评的社区 WAF

5 |
6 |

7 | 8 | 9 | 10 | 11 | 12 |

13 | 14 |

15 | 官方网站 | 16 | 在线 Demo | 17 | 技术文档 | 18 | For English 19 |

20 | 21 | 一款足够简单、足够好用、足够强的免费 WAF。基于业界领先的语义引擎检测技术,作为反向代理接入,保护你的网站不受黑客攻击。 22 | 23 | 核心检测能力由智能语义分析算法驱动,专为社区而生,不让黑客越雷池半步。 24 | 25 | 26 | 27 |

相关源码仓库

28 |

29 | 语义分析自动机引擎 | 30 | 流量分析插件 | 31 | T1K 协议 | 32 | 测试工具 33 |

34 | 35 | ## 相关特性 36 | 37 | #### 便捷性 38 | 39 | 采用容器化部署,一条命令即可完成安装,0 成本上手。安全配置开箱即用,无需人工维护,可实现安全躺平式管理。 40 | 41 | #### 安全性 42 | 43 | 首创业内领先的智能语义分析算法,精准检测、低误报、难绕过。语义分析算法无规则,面对未知特征的 0day 攻击不再手足无措。 44 | 45 | #### 高性能 46 | 47 | 无规则引擎,线性安全检测算法,平均请求检测延迟在 1 毫秒级别。并发能力强,单核轻松检测 2000+ TPS,只要硬件足够强,可支撑的流量规模无上限。 48 | 49 | #### 高可用 50 | 51 | 流量处理引擎基于 Nginx 开发,性能与稳定性均可得到保障。内置完善的健康检查机制,服务可用性高达 99.99%。 52 | 53 | ## 🚀 安装 54 | 55 | ### 配置需求 56 | 57 | - 操作系统:Linux 58 | - 指令架构:x86_64 59 | - 软件依赖:Docker 20.10.6 版本以上 60 | - 软件依赖:Docker Compose 2.0.0 版本以上 61 | - 最小化环境:1 核 CPU / 1 GB 内存 / 10 GB 磁盘 62 | 63 | 64 | ### 一键安装 65 | 66 | ``` 67 | bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" 68 | ``` 69 | 70 | > 更多安装方式请参考 安装雷池 71 | 72 | ## 🕹️ 快速使用 73 | 74 | ### 登录 75 | 76 | 浏览器打开后台管理页面 `https://:9443`。根据界面提示,使用 **支持 TOTP 的认证软件** 扫描二维码,然后输入动态口令登录: 77 | 78 | ![login.gif](https://waf-ce.chaitin.cn/images/gif/login.gif) 79 | 80 | ### 配置防护站点 81 | 82 | 雷池以反向代理方式接入,优先于网站服务器接收流量,对流量中的攻击行为进行检测和清洗,将清洗过后的流量转发给网站服务器。 83 | 84 | ![config.gif](https://waf-ce.chaitin.cn/images/gif/config_site.gif) 85 | 86 | 💡 TIPS: 添加后,执行 `curl -H "Host: <域名>" http://:<端口>` 应能获取到业务网站的响应。 87 | 88 | ### 测试效果 89 | 90 | 使用以下方式尝试模拟黑客攻击,看看雷池的防护效果如何 91 | 92 | - 浏览器访问 `http://:<端口>/?id=1%20AND%201=1` 93 | - 浏览器访问 `http://:<端口>/?a=` 94 | 95 | ![log.gif](https://waf-ce.chaitin.cn/images/gif/detect_log.gif) 96 | 97 | > 如果你需要进行深度测试,请参考 测试防护效果 98 | 99 | ### FAQ 100 | 101 | - [安装问题](https://waf-ce.chaitin.cn/posts/faq_install) 102 | - [登录问题](https://waf-ce.chaitin.cn/posts/faq_login) 103 | - [网站无法访问](https://waf-ce.chaitin.cn/posts/faq_access) 104 | - [配置问题](https://waf-ce.chaitin.cn/posts/faq_config) 105 | - [其他问题](https://waf-ce.chaitin.cn/posts/faq_other) 106 | 107 | ## 🏘️ 联系我们 108 | 109 | 1. 可以通过 GitHub Issue 直接进行 Bug 反馈和功能建议 110 | 2. 可以扫描下方二维码加入雷池社区版用户讨论群 111 | 112 | 113 | 114 | ## Star History 115 | 116 | 117 | Star History Chart 118 | 119 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 |

SafeLine Community Edition

5 |

Keep hackers at bay

6 |
7 |

8 | 9 | 10 | 11 | 12 | 13 |

14 | 15 |

Official Website

16 |

English | 中文文档

17 | 18 | A simple and easy to use WAF tool. Built on [Chaitin Technology](https://www.chaitin.cn/en/)'s ace 🤖️Intelligent Semantic Analysis algorithm🤖️, designed for the community. 19 | 20 | ## ✨ Demo 21 | 22 | ### 🔥🔥🔥 Online Demo: https://demo.waf-ce.chaitin.cn:9443/ 23 | 24 | There is a simple http server, listened on `http://127.0.0.1:8889`, can be used as for testing. 25 | 26 | ![](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_detect_log.gif) 27 | 28 | ![](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_website.gif) 29 | 30 | ## 🚀 Installation 31 | 32 | ### 1. Make sure [Docker](https://docs.docker.com/engine/install/) and [Compose V2](https://docs.docker.com/compose/install/) are installed correctly on the machine 33 | ```shell 34 | docker info # >= 20.10.6 35 | docker compose version # >= 2.0.0 36 | ``` 37 | 38 | ### 2. Setup and deploy 39 | 40 | ```shell 41 | mkdir -p safeline && cd safeline 42 | # setup 43 | curl -kfLsS https://waf-ce.chaitin.cn/release/latest/setup.sh | bash 44 | 45 | # launch 46 | sudo docker compose up -d 47 | ``` 48 | 49 | #### Upgrade 50 | 51 | **WARN: SafeLine will be restarted and your traffic will be unavailable for a short period of time. You may need to choose a proper time for upgration.** 52 | 53 | ```shell 54 | curl -kfLsS https://waf-ce.chaitin.cn/release/latest/upgrade.sh | bash 55 | 56 | # delete the old used image layers if necessary. 57 | docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') 58 | ``` 59 | 60 | ## 🕹️ Quick Start 61 | 62 | ### 1. Login 63 | 64 | Open admin page `https://:9443` and scan qrcode with any authenticator Apps that support TOTP, enter the code to login. 65 | 66 | ![safeline_login.gif](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_login.gif) 67 | 68 | ### 2. Create website 69 | 70 | ![safeline_website.gif](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_website.gif) 71 | 72 | 💡 TIPS: After creating website,execute `curl -H "Host: " http://:` to check if you can get correct response from web server. 73 | 74 | ### 3. Deploy your website to SafeLine 75 | 76 | - If your website is hosted by DNS, just modify your DNS record to WAF 77 | - If your website is behind any reverse-proxy like nginx, you can modify your nginx conf and set upstream to WAF 78 | 79 | ### 4. Protected!👌 80 | 81 | Try these: 82 | 83 | - `http://:/webshell.php` 84 | - `http://:/?id=1%20AND%201=1` 85 | - `http://:/?a=` 86 | 87 | ## 📖 FAQ 88 | 89 | Please refer to our [FAQ](FAQ.md) first if you have any questions. 90 | 91 | For examples: 92 | - [docker compose or docker-compose?](FAQ.md#docker-compose-or-docker-compose) 93 | - [website configurations](FAQ.md#站点配置问题) 94 | - [website not working / not correctly response](FAQ.md#配置完成之后还是没有成功访问到上游服务器) 95 | 96 | ## 🏘️ Contact Us 97 | 98 | 1. You can make bug feedback and feature suggestions directly through GitHub Issues. 99 | 2. By scanning the QR code below (use wechat or qq), you can join the discussion group of SafeLine users for detailed discussions. 100 | 101 | 102 | 103 | ## ✨ CTStack 104 | 105 | 106 | SafeLine has already joined [CTStack](https://stack.chaitin.com/tool/detail?id=717) community. 107 | 108 | ## Star History 109 | 110 | 111 | Star History Chart 112 | 113 | -------------------------------------------------------------------------------- /charts/safeline/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/safeline/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | appVersion: 7.1.0 3 | description: A free WAF that is simple enough, easy to use, and strong enough. Based on the industry's leading semantic engine detection technology, it acts as a reverse proxy access to protect your website from hackers. 4 | home: https://waf-ce.chaitin.cn/ 5 | icon: https://waf-ce.chaitin.cn/images/403.svg 6 | keywords: 7 | - waf 8 | - chaitin 9 | - safeline 10 | maintainers: 11 | - email: admin@jangrui.com 12 | name: Jangrui 13 | name: safeline 14 | sources: 15 | - https://github.com/chaitin/safeline 16 | - https://github.com/jangrui/safeline-helm 17 | version: 7.1.0 18 | -------------------------------------------------------------------------------- /charts/safeline/README.md: -------------------------------------------------------------------------------- 1 | # Helm Chart for SafeLine 2 | 3 | ## Prerequisites 4 | 5 | - Kubernetes cluster storage support RWX. 6 | 7 | ## Installation 8 | 9 | Install the SafeLine helm chart with a release name `safeline`: 10 | ```bash 11 | helm repo add jangrui https://github.com/jangrui/SafeLine --force-update 12 | helm -n safeline upgrade -i safeline jangrui/safeline --create-namespace 13 | ``` 14 | 15 | ## Uninstallation 16 | 17 | To uninstall/delete the `safeline` deployment: 18 | ```bash 19 | helm -n safeline uninstall safeline 20 | ``` 21 | -------------------------------------------------------------------------------- /charts/safeline/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Please wait for several minutes for Safeline deployment to complete. 2 | Then you should be able to visit the Safeline managenment at {{ template "safeline.mgt.api" . }} 3 | For more details, please visit https://github.com/chaitin/SafeLine -------------------------------------------------------------------------------- /charts/safeline/templates/cache/cache-pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- $cache := .Values.persistence.persistentVolumeClaim.cache -}} 2 | {{- if and .Values.persistence.enabled (not $cache.existingClaim) }} 3 | kind: PersistentVolumeClaim 4 | apiVersion: v1 5 | metadata: 6 | name: {{ template "safeline.cache" . }} 7 | annotations: 8 | {{- range $key, $value := $cache.annotations }} 9 | {{ $key }}: {{ $value | quote }} 10 | {{- end }} 11 | {{- if eq .Values.persistence.resourcePolicy "keep" }} 12 | helm.sh/resource-policy: keep 13 | {{- end }} 14 | labels: 15 | {{ include "safeline.labels" . | indent 4 }} 16 | component: cache 17 | spec: 18 | accessModes: 19 | - {{ $cache.accessMode }} 20 | resources: 21 | requests: 22 | storage: {{ $cache.size }} 23 | {{- if .Values.global.persistence.storageClass }} 24 | storageClassName: {{ .Values.global.persistence.storageClass }} 25 | {{- else if $cache.storageClass }} 26 | {{- if eq "-" $cache.storageClass }} 27 | storageClassName: "" 28 | {{- else }} 29 | storageClassName: {{ $cache.storageClass }} 30 | {{- end }} 31 | {{- end }} 32 | {{- end }} 33 | -------------------------------------------------------------------------------- /charts/safeline/templates/chaos/chaos-dpl.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "safeline.chaos" . }} 5 | labels: 6 | {{ include "safeline.labels" . | indent 4 }} 7 | component: chaos 8 | spec: 9 | replicas: {{ .Values.chaos.replicas }} 10 | revisionHistoryLimit: {{ .Values.chaos.revisionHistoryLimit }} 11 | strategy: 12 | {{- if .Values.strategy }} 13 | {{ toYaml .Values.strategy | indent 4 }} 14 | {{- end }} 15 | selector: 16 | matchLabels: 17 | {{ include "safeline.matchLabels" . | indent 6 }} 18 | component: chaos 19 | template: 20 | metadata: 21 | labels: 22 | {{ include "safeline.matchLabels" . | indent 8 }} 23 | component: chaos 24 | annotations: 25 | {{- if .Values.chaos.podAnnotations }} 26 | {{ toYaml .Values.chaos.podAnnotations | indent 8 }} 27 | {{- end }} 28 | spec: 29 | {{- if .Values.chaos.serviceAccountName }} 30 | serviceAccountName: {{ .Values.chaos.serviceAccountName }} 31 | {{- end -}} 32 | {{- with .Values.imagePullSecrets }} 33 | imagePullSecrets: 34 | {{- toYaml . | nindent 8 }} 35 | {{- end }} 36 | automountServiceAccountToken: {{ .Values.chaos.automountServiceAccountToken | default false }} 37 | terminationGracePeriodSeconds: 120 38 | containers: 39 | - name: chaos 40 | image: {{ default .Values.global.image.registry .Values.chaos.image.registry }}/{{ include "safeline.chaos.image.repository" . }}:{{ default .Chart.AppVersion .Values.chaos.image.tag }} 41 | imagePullPolicy: {{ .Values.imagePullPolicy }} 42 | {{- if .Values.chaos.resources }} 43 | resources: 44 | {{ toYaml .Values.chaos.resources | indent 10 }} 45 | {{- end }} 46 | ports: 47 | - name: chaos 48 | containerPort: {{ template "safeline.chaos.port" . }} 49 | volumeMounts: 50 | - name: localtime 51 | mountPath: /etc/localtime 52 | readOnly: true 53 | - mountPath: /app/chaos 54 | name: chaos 55 | volumes: 56 | - name: localtime 57 | hostPath: 58 | path: /etc/localtime 59 | 60 | {{- if .Values.persistence.enabled }} 61 | - name: chaos 62 | persistentVolumeClaim: 63 | claimName: {{ .Values.persistence.persistentVolumeClaim.chaos.existingClaim | default (include "safeline.chaos" .) }} 64 | {{- else -}} 65 | - name: chaos 66 | emptyDir: {} 67 | {{- end -}} 68 | 69 | {{- with .Values.chaos.nodeSelector }} 70 | nodeSelector: 71 | {{ toYaml . | indent 8 }} 72 | {{- end }} 73 | {{- with .Values.chaos.affinity }} 74 | affinity: 75 | {{ toYaml . | indent 8 }} 76 | {{- end }} 77 | {{- with .Values.chaos.tolerations }} 78 | tolerations: 79 | {{ toYaml . | indent 8 }} 80 | {{- end }} 81 | -------------------------------------------------------------------------------- /charts/safeline/templates/chaos/chaos-pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- $chaos := .Values.persistence.persistentVolumeClaim.chaos -}} 2 | {{- if and .Values.persistence.enabled (not $chaos.existingClaim) }} 3 | kind: PersistentVolumeClaim 4 | apiVersion: v1 5 | metadata: 6 | name: {{ template "safeline.chaos" . }} 7 | annotations: 8 | {{- range $key, $value := $chaos.annotations }} 9 | {{ $key }}: {{ $value | quote }} 10 | {{- end }} 11 | {{- if eq .Values.persistence.resourcePolicy "keep" }} 12 | helm.sh/resource-policy: keep 13 | {{- end }} 14 | labels: 15 | {{ include "safeline.labels" . | indent 4 }} 16 | component: chaos 17 | spec: 18 | accessModes: 19 | - {{ $chaos.accessMode }} 20 | resources: 21 | requests: 22 | storage: {{ $chaos.size }} 23 | {{- if .Values.global.persistence.storageClass }} 24 | storageClassName: {{ .Values.global.persistence.storageClass }} 25 | {{- else if $chaos.storageClass }} 26 | {{- if eq "-" $chaos.storageClass }} 27 | storageClassName: "" 28 | {{- else }} 29 | storageClassName: {{ $chaos.storageClass }} 30 | {{- end }} 31 | {{- end }} 32 | {{- end }} 33 | -------------------------------------------------------------------------------- /charts/safeline/templates/chaos/chaos-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: "{{ template "safeline.chaos" . }}" 5 | labels: 6 | {{ include "safeline.labels" . | indent 4 }} 7 | spec: 8 | {{- if or (eq .Values.chaos.service.type "NodePort") (eq .Values.chaos.service.type "LoadBalancer") }} 9 | type: NodePort 10 | {{- end }} 11 | ports: 12 | - name: chaos 13 | protocol: TCP 14 | port: {{ template "safeline.chaos.port" . }} 15 | selector: 16 | {{ include "safeline.matchLabels" . | indent 4 }} 17 | component: chaos 18 | -------------------------------------------------------------------------------- /charts/safeline/templates/database/database-secret.yaml: -------------------------------------------------------------------------------- 1 | {{- if eq .Values.database.type "internal" -}} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: "{{ template "safeline.database" . }}" 6 | labels: 7 | {{ include "safeline.labels" . | indent 4 }} 8 | type: Opaque 9 | data: 10 | POSTGRES_PASSWORD: {{ template "safeline.database.encryptedPassword" . }} 11 | {{- end -}} 12 | -------------------------------------------------------------------------------- /charts/safeline/templates/database/database-ss.yaml: -------------------------------------------------------------------------------- 1 | {{- if eq .Values.database.type "internal" -}} 2 | {{- $database := .Values.persistence.persistentVolumeClaim.database -}} 3 | apiVersion: apps/v1 4 | kind: StatefulSet 5 | metadata: 6 | name: "{{ template "safeline.database" . }}" 7 | labels: 8 | {{ include "safeline.labels" . | indent 4 }} 9 | component: database 10 | spec: 11 | replicas: 1 12 | serviceName: "{{ template "safeline.database" . }}" 13 | selector: 14 | matchLabels: 15 | {{ include "safeline.matchLabels" . | indent 6 }} 16 | component: database 17 | template: 18 | metadata: 19 | labels: 20 | {{ include "safeline.labels" . | indent 8 }} 21 | component: database 22 | annotations: 23 | checksum/secret: {{ include (print $.Template.BasePath "/database/database-secret.yaml") . | sha256sum }} 24 | {{- if .Values.database.podAnnotations }} 25 | {{ toYaml .Values.database.podAnnotations | indent 8 }} 26 | {{- end }} 27 | spec: 28 | {{- if .Values.database.internal.serviceAccountName }} 29 | serviceAccountName: {{ .Values.database.internal.serviceAccountName }} 30 | {{- end -}} 31 | {{- with .Values.imagePullSecrets }} 32 | imagePullSecrets: 33 | {{- toYaml . | nindent 8 }} 34 | {{- end }} 35 | automountServiceAccountToken: {{ .Values.database.internal.automountServiceAccountToken | default false }} 36 | terminationGracePeriodSeconds: 120 37 | containers: 38 | - name: database 39 | image: {{ default .Values.global.image.registry .Values.database.internal.image.registry }}/{{ .Values.database.internal.image.repository }}:{{ .Values.database.internal.image.tag }} 40 | imagePullPolicy: {{ .Values.imagePullPolicy }} 41 | {{- if .Values.database.internal.resources }} 42 | resources: 43 | {{ toYaml .Values.database.internal.resources | indent 10 }} 44 | {{- end }} 45 | envFrom: 46 | - secretRef: 47 | name: "{{ template "safeline.database" . }}" 48 | env: 49 | # - name: PGDATA 50 | # value: "/var/lib/postgresql/data/pgdata" 51 | - name: POSTGRES_USER 52 | value: {{ template "safeline.database.username" . }} 53 | volumeMounts: 54 | - name: database-data 55 | mountPath: /var/lib/postgresql/data 56 | - name: shm-volume 57 | mountPath: /dev/shm 58 | - name: localtime 59 | mountPath: /etc/localtime 60 | readOnly: true 61 | livenessProbe: 62 | exec: 63 | command: 64 | - /bin/sh 65 | - -c 66 | - pg_isready -U safeline-ce -d safeline-ce 67 | initialDelaySeconds: 30 68 | periodSeconds: 10 69 | timeoutSeconds: 5 70 | failureThreshold: 3 71 | readinessProbe: 72 | exec: 73 | command: 74 | - /bin/sh 75 | - -c 76 | - pg_isready -U safeline-ce -d safeline-ce 77 | initialDelaySeconds: 30 78 | periodSeconds: 10 79 | timeoutSeconds: 5 80 | failureThreshold: 3 81 | volumes: 82 | - name: localtime 83 | hostPath: 84 | path: /etc/localtime 85 | - name: shm-volume 86 | emptyDir: 87 | medium: Memory 88 | sizeLimit: {{ .Values.database.internal.shmSizeLimit }} 89 | {{- if not .Values.persistence.enabled }} 90 | - name: "database-data" 91 | emptyDir: {} 92 | {{- else if $database.existingClaim }} 93 | - name: "database-data" 94 | persistentVolumeClaim: 95 | claimName: {{ $database.existingClaim }} 96 | {{- end -}} 97 | 98 | {{- with .Values.database.internal.nodeSelector }} 99 | nodeSelector: 100 | {{ toYaml . | indent 8 }} 101 | {{- end }} 102 | {{- with .Values.database.internal.affinity }} 103 | affinity: 104 | {{ toYaml . | indent 8 }} 105 | {{- end }} 106 | {{- with .Values.database.internal.tolerations }} 107 | tolerations: 108 | {{ toYaml . | indent 8 }} 109 | {{- end }} 110 | {{- if .Values.database.internal.priorityClassName }} 111 | priorityClassName: {{ .Values.database.internal.priorityClassName }} 112 | {{- end }} 113 | {{- if and .Values.persistence.enabled (not $database.existingClaim) }} 114 | volumeClaimTemplates: 115 | - metadata: 116 | name: "database-data" 117 | labels: 118 | {{ include "safeline.labels" . | indent 8 }} 119 | annotations: 120 | {{- range $key, $value := $database.annotations }} 121 | {{ $key }}: {{ $value | quote }} 122 | {{- end }} 123 | spec: 124 | accessModes: [{{ $database.accessMode | quote }}] 125 | {{- if .Values.global.persistence.storageClass }} 126 | storageClassName: "{{ .Values.global.persistence.storageClass }}" 127 | {{- else if $database.storageClass }} 128 | {{- if (eq "-" $database.storageClass) }} 129 | storageClassName: "" 130 | {{- else }} 131 | storageClassName: "{{ $database.storageClass }}" 132 | {{- end }} 133 | {{- end }} 134 | resources: 135 | requests: 136 | storage: {{ $database.size | quote }} 137 | {{- end -}} 138 | {{- end -}} 139 | -------------------------------------------------------------------------------- /charts/safeline/templates/database/database-svc.yaml: -------------------------------------------------------------------------------- 1 | {{- if eq .Values.database.type "internal" -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ template "safeline.database.host" . }} 6 | labels: 7 | {{ include "safeline.labels" . | indent 4 }} 8 | spec: 9 | ports: 10 | - port: 5432 11 | selector: 12 | {{ include "safeline.matchLabels" . | indent 4 }} 13 | component: database 14 | {{- end -}} -------------------------------------------------------------------------------- /charts/safeline/templates/detector/detector-dpl.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "safeline.detector" . }} 5 | labels: 6 | {{ include "safeline.labels" . | indent 4 }} 7 | component: detector 8 | spec: 9 | replicas: {{ .Values.detector.replicas }} 10 | revisionHistoryLimit: {{ .Values.detector.revisionHistoryLimit }} 11 | strategy: 12 | {{- if .Values.strategy }} 13 | {{ toYaml .Values.strategy | indent 4 }} 14 | {{- end }} 15 | selector: 16 | matchLabels: 17 | {{ include "safeline.matchLabels" . | indent 6 }} 18 | component: detector 19 | template: 20 | metadata: 21 | labels: 22 | {{ include "safeline.matchLabels" . | indent 8 }} 23 | component: detector 24 | annotations: 25 | {{- if .Values.detector.podAnnotations }} 26 | {{ toYaml .Values.detector.podAnnotations | indent 8 }} 27 | {{- end }} 28 | spec: 29 | {{- if .Values.detector.serviceAccountName }} 30 | serviceAccountName: {{ .Values.detector.serviceAccountName }} 31 | {{- end -}} 32 | {{- with .Values.imagePullSecrets }} 33 | imagePullSecrets: 34 | {{- toYaml . | nindent 8 }} 35 | {{- end }} 36 | automountServiceAccountToken: {{ .Values.detector.automountServiceAccountToken | default false }} 37 | terminationGracePeriodSeconds: 120 38 | containers: 39 | - name: detector 40 | image: {{ default .Values.global.image.registry .Values.detector.image.registry }}/{{ include "safeline.detector.image.repository" . }}:{{ default .Chart.AppVersion .Values.detector.image.tag }} 41 | imagePullPolicy: {{ .Values.imagePullPolicy }} 42 | ports: 43 | - name: tcd 44 | containerPort: {{ template "safeline.detector.tcd.port" . }} 45 | - name: sns 46 | containerPort: {{ template "safeline.detector.sns.port" . }} 47 | - name: koopa 48 | containerPort: {{ template "safeline.detector.koopa.port" . }} 49 | env: 50 | - name: LOG_DIR 51 | value: /logs/detector 52 | volumeMounts: 53 | - mountPath: /resources/detector 54 | name: detector 55 | - mountPath: /logs 56 | name: logs 57 | - name: localtime 58 | mountPath: /etc/localtime 59 | readOnly: true 60 | volumes: 61 | - name: localtime 62 | hostPath: 63 | path: /etc/localtime 64 | 65 | {{- if .Values.persistence.enabled }} 66 | - name: detector 67 | persistentVolumeClaim: 68 | claimName: {{ .Values.persistence.persistentVolumeClaim.detector.existingClaim | default (include "safeline.detector" .) }} 69 | - name: logs 70 | persistentVolumeClaim: 71 | claimName: {{ .Values.persistence.persistentVolumeClaim.logs.existingClaim | default (include "safeline.logs" .) }} 72 | {{- else -}} 73 | - name: detector 74 | emptyDir: {} 75 | - name: logs 76 | emptyDir: {} 77 | {{- end -}} 78 | 79 | {{- if .Values.detector.resources }} 80 | resources: 81 | {{ toYaml .Values.detector.resources | indent 10 }} 82 | {{- end }} 83 | 84 | {{- with .Values.detector.nodeSelector }} 85 | nodeSelector: 86 | {{ toYaml . | indent 8 }} 87 | {{- end }} 88 | {{- with .Values.detector.affinity }} 89 | affinity: 90 | {{ toYaml . | indent 8 }} 91 | {{- end }} 92 | {{- with .Values.detector.tolerations }} 93 | tolerations: 94 | {{ toYaml . | indent 8 }} 95 | {{- end }} 96 | {{- if .Values.detector.priorityClassName }} 97 | priorityClassName: {{ .Values.detector.priorityClassName }} 98 | {{- end }} 99 | -------------------------------------------------------------------------------- /charts/safeline/templates/detector/detector-pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- $detector := .Values.persistence.persistentVolumeClaim.detector -}} 2 | {{- if and .Values.persistence.enabled (not $detector.existingClaim) }} 3 | kind: PersistentVolumeClaim 4 | apiVersion: v1 5 | metadata: 6 | name: {{ template "safeline.detector" . }} 7 | annotations: 8 | {{- range $key, $value := $detector.annotations }} 9 | {{ $key }}: {{ $value | quote }} 10 | {{- end }} 11 | {{- if eq .Values.persistence.resourcePolicy "keep" }} 12 | helm.sh/resource-policy: keep 13 | {{- end }} 14 | labels: 15 | {{ include "safeline.labels" . | indent 4 }} 16 | component: detector 17 | spec: 18 | accessModes: 19 | - {{ $detector.accessMode }} 20 | resources: 21 | requests: 22 | storage: {{ $detector.size }} 23 | {{- if .Values.global.persistence.storageClass }} 24 | storageClassName: {{ .Values.global.persistence.storageClass }} 25 | {{- else if $detector.storageClass }} 26 | {{- if eq "-" $detector.storageClass }} 27 | storageClassName: "" 28 | {{- else }} 29 | storageClassName: {{ $detector.storageClass }} 30 | {{- end }} 31 | {{- end }} 32 | {{- end }} 33 | -------------------------------------------------------------------------------- /charts/safeline/templates/detector/detector-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "safeline.detector" . }} 5 | labels: 6 | {{ include "safeline.labels" . | indent 4 }} 7 | spec: 8 | ports: 9 | - name: tcd 10 | port: {{ template "safeline.detector.tcd.port" . }} 11 | - name: sns 12 | port: {{ template "safeline.detector.sns.port" . }} 13 | selector: 14 | {{ include "safeline.matchLabels" . | indent 4 }} 15 | component: detector 16 | -------------------------------------------------------------------------------- /charts/safeline/templates/fvm/fvm-dpl.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "safeline.fvm" . }} 5 | labels: 6 | {{ include "safeline.labels" . | indent 4 }} 7 | component: fvm 8 | spec: 9 | replicas: {{ .Values.fvm.replicas }} 10 | revisionHistoryLimit: {{ .Values.fvm.revisionHistoryLimit }} 11 | strategy: 12 | {{- if .Values.strategy }} 13 | {{ toYaml .Values.strategy | indent 4 }} 14 | {{- end }} 15 | selector: 16 | matchLabels: 17 | {{ include "safeline.matchLabels" . | indent 6 }} 18 | component: fvm 19 | template: 20 | metadata: 21 | labels: 22 | {{ include "safeline.matchLabels" . | indent 8 }} 23 | component: fvm 24 | annotations: 25 | {{- if .Values.fvm.podAnnotations }} 26 | {{ toYaml .Values.fvm.podAnnotations | indent 8 }} 27 | {{- end }} 28 | spec: 29 | {{- if .Values.fvm.serviceAccountName }} 30 | serviceAccountName: {{ .Values.fvm.serviceAccountName }} 31 | {{- end -}} 32 | {{- with .Values.imagePullSecrets }} 33 | imagePullSecrets: 34 | {{- toYaml . | nindent 8 }} 35 | {{- end }} 36 | automountServiceAccountToken: {{ .Values.fvm.automountServiceAccountToken | default false }} 37 | terminationGracePeriodSeconds: 120 38 | containers: 39 | - name: fvm 40 | image: {{ default .Values.global.image.registry .Values.fvm.image.registry }}/{{ include "safeline.fvm.image.repository" . }}:{{ default .Chart.AppVersion .Values.fvm.image.tag }} 41 | imagePullPolicy: {{ .Values.imagePullPolicy }} 42 | ports: 43 | - name: api 44 | containerPort: {{ template "safeline.fvm.api.port" . }} 45 | - name: web 46 | containerPort: {{ template "safeline.fvm.web.port" . }} 47 | volumeMounts: 48 | - name: localtime 49 | mountPath: /etc/localtime 50 | readOnly: true 51 | {{- if .Values.fvm.resources }} 52 | resources: 53 | {{ toYaml .Values.fvm.resources | indent 10 }} 54 | {{- end }} 55 | volumes: 56 | - name: localtime 57 | hostPath: 58 | path: /etc/localtime 59 | 60 | {{- with .Values.fvm.nodeSelector }} 61 | nodeSelector: 62 | {{ toYaml . | indent 8 }} 63 | {{- end }} 64 | {{- with .Values.fvm.affinity }} 65 | affinity: 66 | {{ toYaml . | indent 8 }} 67 | {{- end }} 68 | {{- with .Values.fvm.tolerations }} 69 | tolerations: 70 | {{ toYaml . | indent 8 }} 71 | {{- end }} 72 | {{- if .Values.fvm.priorityClassName }} 73 | priorityClassName: {{ .Values.fvm.priorityClassName }} 74 | {{- end }} 75 | -------------------------------------------------------------------------------- /charts/safeline/templates/fvm/fvm-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: "{{ template "safeline.fvm" . }}" 5 | labels: 6 | {{ include "safeline.labels" . | indent 4 }} 7 | spec: 8 | {{- if or (eq .Values.fvm.service.type "NodePort") (eq .Values.fvm.service.type "LoadBalancer") }} 9 | type: NodePort 10 | {{- end }} 11 | ports: 12 | - name: api 13 | protocol: TCP 14 | port: {{ template "safeline.fvm.api.port" . }} 15 | - name: web 16 | protocol: TCP 17 | port: {{ template "safeline.fvm.web.port" . }} 18 | selector: 19 | {{ include "safeline.matchLabels" . | indent 4 }} 20 | component: fvm 21 | -------------------------------------------------------------------------------- /charts/safeline/templates/logs/logs-pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- $logs := .Values.persistence.persistentVolumeClaim.logs -}} 2 | {{- if and .Values.persistence.enabled (not $logs.existingClaim) }} 3 | kind: PersistentVolumeClaim 4 | apiVersion: v1 5 | metadata: 6 | name: {{ template "safeline.logs" . }} 7 | annotations: 8 | {{- range $key, $value := $logs.annotations }} 9 | {{ $key }}: {{ $value | quote }} 10 | {{- end }} 11 | {{- if eq .Values.persistence.resourcePolicy "keep" }} 12 | helm.sh/resource-policy: keep 13 | {{- end }} 14 | labels: 15 | {{ include "safeline.labels" . | indent 4 }} 16 | component: logs 17 | spec: 18 | accessModes: 19 | - {{ $logs.accessMode }} 20 | resources: 21 | requests: 22 | storage: {{ $logs.size }} 23 | {{- if .Values.global.persistence.storageClass }} 24 | storageClassName: {{ .Values.global.persistence.storageClass }} 25 | {{- else if $logs.storageClass }} 26 | {{- if eq "-" $logs.storageClass }} 27 | storageClassName: "" 28 | {{- else }} 29 | storageClassName: {{ $logs.storageClass }} 30 | {{- end }} 31 | {{- end }} 32 | {{- end }} 33 | -------------------------------------------------------------------------------- /charts/safeline/templates/luigi/luigi-dpl.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "safeline.luigi" . }} 5 | labels: 6 | {{ include "safeline.labels" . | indent 4 }} 7 | component: luigi 8 | spec: 9 | replicas: {{ .Values.luigi.replicas }} 10 | revisionHistoryLimit: {{ .Values.luigi.revisionHistoryLimit }} 11 | strategy: 12 | {{- if .Values.strategy }} 13 | {{ toYaml .Values.strategy | indent 4 }} 14 | {{- end }} 15 | selector: 16 | matchLabels: 17 | {{ include "safeline.matchLabels" . | indent 6 }} 18 | component: luigi 19 | template: 20 | metadata: 21 | labels: 22 | {{ include "safeline.matchLabels" . | indent 8 }} 23 | component: luigi 24 | annotations: 25 | {{- if .Values.luigi.podAnnotations }} 26 | {{ toYaml .Values.luigi.podAnnotations | indent 8 }} 27 | {{- end }} 28 | spec: 29 | {{- if .Values.luigi.serviceAccountName }} 30 | serviceAccountName: {{ .Values.luigi.serviceAccountName }} 31 | {{- end -}} 32 | {{- with .Values.imagePullSecrets }} 33 | imagePullSecrets: 34 | {{- toYaml . | nindent 8 }} 35 | {{- end }} 36 | automountServiceAccountToken: {{ .Values.luigi.automountServiceAccountToken | default false }} 37 | terminationGracePeriodSeconds: 120 38 | containers: 39 | - name: luigi 40 | image: {{ default .Values.global.image.registry .Values.luigi.image.registry }}/{{ include "safeline.luigi.image.repository" . }}:{{ default .Chart.AppVersion .Values.luigi.image.tag }} 41 | imagePullPolicy: {{ .Values.imagePullPolicy }} 42 | ports: 43 | - name: luigi 44 | containerPort: {{ template "safeline.luigi.port" . }} 45 | env: 46 | - name: MGT_IP 47 | value: {{ template "safeline.mgt" . }} 48 | - name: LUIGI_PG 49 | value: {{ template "safeline.database.url" . }} 50 | volumeMounts: 51 | - name: localtime 52 | mountPath: /etc/localtime 53 | readOnly: true 54 | - name: luigi 55 | mountPath: /app/data 56 | {{- if .Values.luigi.resources }} 57 | resources: 58 | {{ toYaml .Values.luigi.resources | indent 10 }} 59 | {{- end }} 60 | volumes: 61 | - name: localtime 62 | hostPath: 63 | path: /etc/localtime 64 | {{- if .Values.persistence.enabled }} 65 | - name: luigi 66 | persistentVolumeClaim: 67 | claimName: {{ .Values.persistence.persistentVolumeClaim.luigi.existingClaim | default (include "safeline.luigi" .) }} 68 | {{- else -}} 69 | - name: luigi 70 | emptyDir: {} 71 | {{- end -}} 72 | 73 | {{- with .Values.luigi.nodeSelector }} 74 | nodeSelector: 75 | {{ toYaml . | indent 8 }} 76 | {{- end }} 77 | {{- with .Values.luigi.affinity }} 78 | affinity: 79 | {{ toYaml . | indent 8 }} 80 | {{- end }} 81 | {{- with .Values.luigi.tolerations }} 82 | tolerations: 83 | {{ toYaml . | indent 8 }} 84 | {{- end }} 85 | {{- if .Values.luigi.priorityClassName }} 86 | priorityClassName: {{ .Values.luigi.priorityClassName }} 87 | {{- end }} 88 | -------------------------------------------------------------------------------- /charts/safeline/templates/luigi/luigi-pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- $luigi := .Values.persistence.persistentVolumeClaim.luigi -}} 2 | {{- if and .Values.persistence.enabled (not $luigi.existingClaim) }} 3 | kind: PersistentVolumeClaim 4 | apiVersion: v1 5 | metadata: 6 | name: {{ template "safeline.luigi" . }} 7 | annotations: 8 | {{- range $key, $value := $luigi.annotations }} 9 | {{ $key }}: {{ $value | quote }} 10 | {{- end }} 11 | {{- if eq .Values.persistence.resourcePolicy "keep" }} 12 | helm.sh/resource-policy: keep 13 | {{- end }} 14 | labels: 15 | {{ include "safeline.labels" . | indent 4 }} 16 | component: luigi 17 | spec: 18 | accessModes: 19 | - {{ $luigi.accessMode }} 20 | resources: 21 | requests: 22 | storage: {{ $luigi.size }} 23 | {{- if .Values.global.persistence.storageClass }} 24 | storageClassName: {{ .Values.global.persistence.storageClass }} 25 | {{- else if $luigi.storageClass }} 26 | {{- if eq "-" $luigi.storageClass }} 27 | storageClassName: "" 28 | {{- else }} 29 | storageClassName: {{ $luigi.storageClass }} 30 | {{- end }} 31 | {{- end }} 32 | {{- end }} 33 | -------------------------------------------------------------------------------- /charts/safeline/templates/luigi/luigi-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: "{{ template "safeline.luigi" . }}" 5 | labels: 6 | {{ include "safeline.labels" . | indent 4 }} 7 | spec: 8 | {{- if or (eq .Values.luigi.service.type "NodePort") (eq .Values.luigi.service.type "LoadBalancer") }} 9 | type: NodePort 10 | {{- end }} 11 | ports: 12 | - name: luigi 13 | protocol: TCP 14 | port: {{ template "safeline.luigi.port" . }} 15 | selector: 16 | {{ include "safeline.matchLabels" . | indent 4 }} 17 | component: luigi 18 | -------------------------------------------------------------------------------- /charts/safeline/templates/mgt/mgt-dpl.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "safeline.mgt" . }} 5 | labels: 6 | {{ include "safeline.labels" . | indent 4 }} 7 | component: mgt 8 | spec: 9 | replicas: {{ .Values.mgt.replicas }} 10 | revisionHistoryLimit: {{ .Values.mgt.revisionHistoryLimit }} 11 | strategy: 12 | {{- if .Values.strategy }} 13 | {{ toYaml .Values.strategy | indent 4 }} 14 | {{- end }} 15 | selector: 16 | matchLabels: 17 | {{ include "safeline.matchLabels" . | indent 6 }} 18 | component: mgt 19 | template: 20 | metadata: 21 | labels: 22 | {{ include "safeline.matchLabels" . | indent 8 }} 23 | component: mgt 24 | annotations: 25 | {{- if .Values.mgt.podAnnotations }} 26 | {{ toYaml .Values.mgt.podAnnotations | indent 8 }} 27 | {{- end }} 28 | spec: 29 | {{- if .Values.mgt.serviceAccountName }} 30 | serviceAccountName: {{ .Values.mgt.serviceAccountName }} 31 | {{- end -}} 32 | {{- with .Values.imagePullSecrets }} 33 | imagePullSecrets: 34 | {{- toYaml . | nindent 8 }} 35 | {{- end }} 36 | automountServiceAccountToken: {{ .Values.mgt.automountServiceAccountToken | default false }} 37 | terminationGracePeriodSeconds: 120 38 | containers: 39 | - name: mgt 40 | image: {{ default .Values.global.image.registry .Values.mgt.image.registry }}/{{ include "safeline.mgt.image.repository" . }}:{{ default .Chart.AppVersion .Values.mgt.image.tag }} 41 | imagePullPolicy: {{ .Values.imagePullPolicy }} 42 | ports: 43 | - name: web 44 | containerPort: {{ template "safeline.mgt.web.port" . }} 45 | - name: api 46 | containerPort: {{ template "safeline.mgt.api.port" . }} 47 | - name: tcd 48 | containerPort: {{ template "safeline.mgt.tcd.port" . }} 49 | env: 50 | - name: MGT_PG 51 | value: {{ template "safeline.database.url" . }} 52 | - name: TCD_TASK_ADDRESS 53 | value: {{ template "safeline.tengine" . }}:{{ template "safeline.tengine.tcd.port" . }} 54 | volumeMounts: 55 | - name: localtime 56 | mountPath: /etc/localtime 57 | readOnly: true 58 | - mountPath: /app/data 59 | name: mgt 60 | - mountPath: /app/sock 61 | name: sock 62 | - mountPath: /app/log 63 | name: logs 64 | livenessProbe: 65 | httpGet: 66 | scheme: HTTPS 67 | port: 1443 68 | path: /api/open/health 69 | initialDelaySeconds: 30 70 | periodSeconds: 10 71 | timeoutSeconds: 5 72 | successThreshold: 1 73 | failureThreshold: 3 74 | readinessProbe: 75 | httpGet: 76 | scheme: HTTPS 77 | port: 1443 78 | path: /api/open/health 79 | initialDelaySeconds: 5 80 | periodSeconds: 5 81 | timeoutSeconds: 1 82 | successThreshold: 1 83 | failureThreshold: 3 84 | {{- if .Values.mgt.resources }} 85 | resources: 86 | {{ toYaml .Values.mgt.resources | indent 10 }} 87 | {{- end }} 88 | volumes: 89 | - name: localtime 90 | hostPath: 91 | path: /etc/localtime 92 | {{- if .Values.persistence.enabled }} 93 | - name: mgt 94 | persistentVolumeClaim: 95 | claimName: {{ .Values.persistence.persistentVolumeClaim.mgt.existingClaim | default (include "safeline.mgt" .) }} 96 | - name: sock 97 | persistentVolumeClaim: 98 | claimName: {{ .Values.persistence.persistentVolumeClaim.sock.existingClaim | default (include "safeline.sock" .) }} 99 | - name: logs 100 | persistentVolumeClaim: 101 | claimName: {{ .Values.persistence.persistentVolumeClaim.logs.existingClaim | default (include "safeline.logs" .) }} 102 | {{- else -}} 103 | - name: mgt 104 | emptyDir: {} 105 | - name: sock 106 | emptyDir: {} 107 | - name: logs 108 | emptyDir: {} 109 | {{- end -}} 110 | 111 | {{- with .Values.mgt.nodeSelector }} 112 | nodeSelector: 113 | {{ toYaml . | indent 8 }} 114 | {{- end }} 115 | {{- with .Values.mgt.affinity }} 116 | affinity: 117 | {{ toYaml . | indent 8 }} 118 | {{- end }} 119 | {{- with .Values.mgt.tolerations }} 120 | tolerations: 121 | {{ toYaml . | indent 8 }} 122 | {{- end }} 123 | {{- if .Values.mgt.priorityClassName }} 124 | priorityClassName: {{ .Values.mgt.priorityClassName }} 125 | {{- end }} 126 | -------------------------------------------------------------------------------- /charts/safeline/templates/mgt/mgt-pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- $mgt := .Values.persistence.persistentVolumeClaim.mgt -}} 2 | {{- if and .Values.persistence.enabled (not $mgt.existingClaim) }} 3 | kind: PersistentVolumeClaim 4 | apiVersion: v1 5 | metadata: 6 | name: {{ template "safeline.mgt" . }} 7 | annotations: 8 | {{- range $key, $value := $mgt.annotations }} 9 | {{ $key }}: {{ $value | quote }} 10 | {{- end }} 11 | {{- if eq .Values.persistence.resourcePolicy "keep" }} 12 | helm.sh/resource-policy: keep 13 | {{- end }} 14 | labels: 15 | {{ include "safeline.labels" . | indent 4 }} 16 | component: mgt 17 | spec: 18 | accessModes: 19 | - {{ $mgt.accessMode }} 20 | resources: 21 | requests: 22 | storage: {{ $mgt.size }} 23 | {{- if .Values.global.persistence.storageClass }} 24 | storageClassName: {{ .Values.global.persistence.storageClass }} 25 | {{- else if $mgt.storageClass }} 26 | {{- if eq "-" $mgt.storageClass }} 27 | storageClassName: "" 28 | {{- else }} 29 | storageClassName: {{ $mgt.storageClass }} 30 | {{- end }} 31 | {{- end }} 32 | {{- end }} 33 | -------------------------------------------------------------------------------- /charts/safeline/templates/mgt/mgt-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: "{{ template "safeline.mgt" . }}" 5 | labels: 6 | {{ include "safeline.labels" . | indent 4 }} 7 | spec: 8 | {{- if or (eq .Values.mgt.service.type "NodePort") (eq .Values.mgt.service.type "LoadBalancer") }} 9 | type: NodePort 10 | {{- end }} 11 | ports: 12 | - name: web 13 | port: {{ template "safeline.mgt.web.port" . }} 14 | {{- if or (eq .Values.mgt.service.type "NodePort") (eq .Values.mgt.service.type "LoadBalancer") }} 15 | nodePort: {{ .Values.mgt.service.web.nodePort }} 16 | {{- end }} 17 | - name: api 18 | protocol: TCP 19 | port: {{ template "safeline.mgt.api.port" .}} 20 | - name: tcd 21 | protocol: TCP 22 | port: {{ template "safeline.mgt.tcd.port" .}} 23 | selector: 24 | {{ include "safeline.matchLabels" . | indent 4 }} 25 | component: mgt 26 | -------------------------------------------------------------------------------- /charts/safeline/templates/nginx/nginx-pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- $nginx := .Values.persistence.persistentVolumeClaim.nginx -}} 2 | {{- if and .Values.persistence.enabled (not $nginx.existingClaim) }} 3 | kind: PersistentVolumeClaim 4 | apiVersion: v1 5 | metadata: 6 | name: {{ template "safeline.nginx" . }} 7 | annotations: 8 | {{- range $key, $value := $nginx.annotations }} 9 | {{ $key }}: {{ $value | quote }} 10 | {{- end }} 11 | {{- if eq .Values.persistence.resourcePolicy "keep" }} 12 | helm.sh/resource-policy: keep 13 | {{- end }} 14 | labels: 15 | {{ include "safeline.labels" . | indent 4 }} 16 | component: nginx 17 | spec: 18 | accessModes: 19 | - {{ $nginx.accessMode }} 20 | resources: 21 | requests: 22 | storage: {{ $nginx.size }} 23 | {{- if .Values.global.persistence.storageClass }} 24 | storageClassName: {{ .Values.global.persistence.storageClass }} 25 | {{- else if $nginx.storageClass }} 26 | {{- if eq "-" $nginx.storageClass }} 27 | storageClassName: "" 28 | {{- else }} 29 | storageClassName: {{ $nginx.storageClass }} 30 | {{- end }} 31 | {{- end }} 32 | {{- end }} 33 | -------------------------------------------------------------------------------- /charts/safeline/templates/run/run-pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- $run := .Values.persistence.persistentVolumeClaim.run -}} 2 | {{- if and .Values.persistence.enabled (not $run.existingClaim) }} 3 | kind: PersistentVolumeClaim 4 | apiVersion: v1 5 | metadata: 6 | name: {{ template "safeline.run" . }} 7 | annotations: 8 | {{- range $key, $value := $run.annotations }} 9 | {{ $key }}: {{ $value | quote }} 10 | {{- end }} 11 | {{- if eq .Values.persistence.resourcePolicy "keep" }} 12 | helm.sh/resource-policy: keep 13 | {{- end }} 14 | labels: 15 | {{ include "safeline.labels" . | indent 4 }} 16 | component: run 17 | spec: 18 | accessModes: 19 | - {{ $run.accessMode }} 20 | resources: 21 | requests: 22 | storage: {{ $run.size }} 23 | {{- if .Values.global.persistence.storageClass }} 24 | storageClassName: {{ .Values.global.persistence.storageClass }} 25 | {{- else if $run.storageClass }} 26 | {{- if eq "-" $run.storageClass }} 27 | storageClassName: "" 28 | {{- else }} 29 | storageClassName: {{ $run.storageClass }} 30 | {{- end }} 31 | {{- end }} 32 | {{- end }} 33 | -------------------------------------------------------------------------------- /charts/safeline/templates/sock/sock-pvc.yaml: -------------------------------------------------------------------------------- 1 | {{- $sock := .Values.persistence.persistentVolumeClaim.sock -}} 2 | {{- if and .Values.persistence.enabled (not $sock.existingClaim) }} 3 | kind: PersistentVolumeClaim 4 | apiVersion: v1 5 | metadata: 6 | name: {{ template "safeline.sock" . }} 7 | annotations: 8 | {{- range $key, $value := $sock.annotations }} 9 | {{ $key }}: {{ $value | quote }} 10 | {{- end }} 11 | {{- if eq .Values.persistence.resourcePolicy "keep" }} 12 | helm.sh/resource-policy: keep 13 | {{- end }} 14 | labels: 15 | {{ include "safeline.labels" . | indent 4 }} 16 | component: sock 17 | spec: 18 | accessModes: 19 | - {{ $sock.accessMode }} 20 | resources: 21 | requests: 22 | storage: {{ $sock.size }} 23 | {{- if .Values.global.persistence.storageClass }} 24 | storageClassName: {{ .Values.global.persistence.storageClass }} 25 | {{- else if $sock.storageClass }} 26 | {{- if eq "-" $sock.storageClass }} 27 | storageClassName: "" 28 | {{- else }} 29 | storageClassName: {{ $sock.storageClass }} 30 | {{- end }} 31 | {{- end }} 32 | {{- end }} 33 | -------------------------------------------------------------------------------- /charts/safeline/templates/tengine/tengine-dpl.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "safeline.tengine" . }} 5 | labels: 6 | {{ include "safeline.labels" . | indent 4 }} 7 | component: tengine 8 | spec: 9 | replicas: {{ .Values.tengine.replicas }} 10 | revisionHistoryLimit: {{ .Values.tengine.revisionHistoryLimit }} 11 | strategy: 12 | {{- if .Values.strategy }} 13 | {{ toYaml .Values.strategy | indent 4 }} 14 | {{- end }} 15 | selector: 16 | matchLabels: 17 | {{ include "safeline.matchLabels" . | indent 6 }} 18 | component: tengine 19 | template: 20 | metadata: 21 | labels: 22 | {{ include "safeline.matchLabels" . | indent 8 }} 23 | component: tengine 24 | annotations: 25 | {{- if .Values.tengine.podAnnotations }} 26 | {{ toYaml .Values.tengine.podAnnotations | indent 8 }} 27 | {{- end }} 28 | spec: 29 | {{- if .Values.tengine.serviceAccountName }} 30 | serviceAccountName: {{ .Values.tengine.serviceAccountName }} 31 | {{- end -}} 32 | {{- with .Values.imagePullSecrets }} 33 | imagePullSecrets: 34 | {{- toYaml . | nindent 8 }} 35 | {{- end }} 36 | automountServiceAccountToken: {{ .Values.tengine.automountServiceAccountToken | default false }} 37 | terminationGracePeriodSeconds: 120 38 | initContainers: 39 | - name: mkdir-nginx-logs-dir 40 | image: {{ default .Values.global.image.registry .Values.tengine.image.registry }}/{{ include "safeline.tengine.image.repository" . }}:{{ default .Chart.AppVersion .Values.tengine.image.tag }} 41 | imagePullPolicy: {{ .Values.imagePullPolicy }} 42 | command: 43 | - sh 44 | - -c 45 | - |- 46 | mkdir -p /var/log/nginx 47 | volumeMounts: 48 | - mountPath: /var/log 49 | name: logs 50 | containers: 51 | - name: tengine 52 | image: {{ default .Values.global.image.registry .Values.tengine.image.registry }}/{{ include "safeline.tengine.image.repository" . }}:{{ default .Chart.AppVersion .Values.tengine.image.tag }} 53 | imagePullPolicy: {{ .Values.imagePullPolicy }} 54 | ports: 55 | - name: health 56 | containerPort: {{ template "safeline.tengine.health.port" . }} 57 | - name: tcd 58 | containerPort: {{ template "safeline.tengine.tcd.port" . }} 59 | - name: http 60 | containerPort: {{ template "safeline.tengine.http.port" . }} 61 | env: 62 | - name: TCD_MGT_API 63 | value: {{ template "safeline.mgt.api" . }} 64 | - name: TCD_SNSERVER 65 | value: {{ template "safeline.detector.tcd" . }} 66 | - name: SNSERVER_ADDR 67 | value: {{ template "safeline.detector.tcd" . }} 68 | - name: TCD_TASK_ADDRESS 69 | value: 0.0.0.0:{{ template "safeline.tengine.tcd.port" . }} 70 | volumeMounts: 71 | - name: localtime 72 | mountPath: /etc/localtime 73 | readOnly: true 74 | - mountPath: /etc/nginx 75 | name: nginx 76 | - mountPath: /resources/detector 77 | name: detector 78 | - mountPath: /resources/chaos 79 | name: chaos 80 | - mountPath: /var/log 81 | name: logs 82 | - mountPath: /usr/local/nginx/cache 83 | name: cache 84 | - mountPath: /app/sock 85 | name: sock 86 | - mountPath: /app/run 87 | name: run 88 | volumes: 89 | - name: localtime 90 | hostPath: 91 | path: /etc/localtime 92 | {{- if .Values.persistence.enabled }} 93 | - name: nginx 94 | persistentVolumeClaim: 95 | claimName: {{ .Values.persistence.persistentVolumeClaim.nginx.existingClaim | default (include "safeline.nginx" .) }} 96 | - name: detector 97 | persistentVolumeClaim: 98 | claimName: {{ .Values.persistence.persistentVolumeClaim.detector.existingClaim | default (include "safeline.detector" .) }} 99 | - name: chaos 100 | persistentVolumeClaim: 101 | claimName: {{ .Values.persistence.persistentVolumeClaim.chaos.existingClaim | default (include "safeline.chaos" .) }} 102 | - name: logs 103 | persistentVolumeClaim: 104 | claimName: {{ .Values.persistence.persistentVolumeClaim.logs.existingClaim | default (include "safeline.logs" .) }} 105 | - name: cache 106 | persistentVolumeClaim: 107 | claimName: {{ .Values.persistence.persistentVolumeClaim.cache.existingClaim | default (include "safeline.cache" .) }} 108 | - name: sock 109 | persistentVolumeClaim: 110 | claimName: {{ .Values.persistence.persistentVolumeClaim.sock.existingClaim | default (include "safeline.sock" .) }} 111 | - name: run 112 | persistentVolumeClaim: 113 | claimName: {{ .Values.persistence.persistentVolumeClaim.run.existingClaim | default (include "safeline.run" .) }} 114 | {{- else -}} 115 | - name: nginx 116 | emptyDir: {} 117 | - name: detector 118 | emptyDir: {} 119 | - name: chaos 120 | emptyDir: {} 121 | - name: logs 122 | emptyDir: {} 123 | - name: cache 124 | emptyDir: {} 125 | - name: sock 126 | emptyDir: {} 127 | - name: run 128 | emptyDir: {} 129 | {{- end -}} 130 | 131 | {{- if .Values.tengine.resources }} 132 | resources: 133 | {{ toYaml .Values.tengine.resources | indent 10 }} 134 | {{- end }} 135 | 136 | {{- with .Values.tengine.nodeSelector }} 137 | nodeSelector: 138 | {{ toYaml . | indent 8 }} 139 | {{- end }} 140 | {{- with .Values.tengine.affinity }} 141 | affinity: 142 | {{ toYaml . | indent 8 }} 143 | {{- end }} 144 | {{- with .Values.tengine.tolerations }} 145 | tolerations: 146 | {{ toYaml . | indent 8 }} 147 | {{- end }} 148 | {{- if .Values.tengine.priorityClassName }} 149 | priorityClassName: {{ .Values.tengine.priorityClassName }} 150 | {{- end }} 151 | -------------------------------------------------------------------------------- /charts/safeline/templates/tengine/tengine-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: "{{ template "safeline.tengine" . }}" 5 | labels: 6 | {{ include "safeline.labels" . | indent 4 }} 7 | spec: 8 | ports: 9 | - name: health 10 | protocol: TCP 11 | port: {{ template "safeline.tengine.health.port" . }} 12 | - name: http 13 | protocol: TCP 14 | port: {{ template "safeline.tengine.http.port" . }} 15 | - name: tcd 16 | protocol: TCP 17 | port: {{ template "safeline.tengine.tcd.port" . }} 18 | selector: 19 | {{ include "safeline.matchLabels" . | indent 4 }} 20 | component: tengine 21 | -------------------------------------------------------------------------------- /release/ipgroup/README.md: -------------------------------------------------------------------------------- 1 | # 雷池内置 IP 组 2 | 3 | ### 国家 IP 库 4 | 5 | 定期手动更新,数据来源 https://ipv4.fetus.jp/tw 6 | 7 | ### 爬虫 IP 库 8 | 9 | ##### cloudflare 10 | 11 | 官方 https://www.cloudflare.com/ips-v4 12 | 13 | ##### 360 14 | 15 | http://www.so.com/help/spider_ip.html 16 | 17 | ##### 百度 18 | 19 | 没有爬虫 IP 池,官方推荐的判断方法 https://ziyuan.baidu.com/college/articleinfo?id=1198 20 | -------------------------------------------------------------------------------- /release/ipgroup/crawler/360.txt: -------------------------------------------------------------------------------- 1 | # http://www.so.com/help/spider_ip.html 2 | 3 | 180.153.232.0/24 4 | 180.153.234.0/24 5 | 180.153.236.0/24 6 | 180.163.220.0/24 7 | 42.236.101.0/24 8 | 42.236.102.0/24 9 | 42.236.103.0/24 10 | 42.236.10.0/24 11 | 42.236.12.0/24 12 | 42.236.13.0/24 13 | 42.236.14.0/24 14 | 42.236.15.0/24 15 | 42.236.16.0/24 16 | 42.236.17.0/24 17 | 42.236.46.0/24 18 | 42.236.48.0/24 19 | 42.236.49.0/24 20 | 42.236.50.0/24 21 | 42.236.51.0/24 22 | 42.236.52.0/24 23 | 42.236.53.0/24 24 | 42.236.54.0/24 25 | 42.236.55.0/24 26 | 42.236.99.0/24 -------------------------------------------------------------------------------- /release/ipgroup/crawler/cloudflare.txt: -------------------------------------------------------------------------------- 1 | # sync from https://www.cloudflare.com/ips-v4 2 | 3 | 173.245.48.0/20 4 | 103.21.244.0/22 5 | 103.22.200.0/22 6 | 103.31.4.0/22 7 | 141.101.64.0/18 8 | 108.162.192.0/18 9 | 190.93.240.0/20 10 | 188.114.96.0/20 11 | 197.234.240.0/22 12 | 198.41.128.0/17 13 | 162.158.0.0/15 14 | 104.16.0.0/13 15 | 104.24.0.0/14 16 | 172.64.0.0/13 17 | 131.0.72.0/22 -------------------------------------------------------------------------------- /release/latest/compose.yaml: -------------------------------------------------------------------------------- 1 | networks: 2 | safeline-ce: 3 | name: safeline-ce 4 | driver: bridge 5 | ipam: 6 | driver: default 7 | config: 8 | - gateway: ${SUBNET_PREFIX:?SUBNET_PREFIX required}.1 9 | subnet: ${SUBNET_PREFIX}.0/24 10 | driver_opts: 11 | com.docker.network.bridge.name: safeline-ce 12 | 13 | services: 14 | postgres: 15 | container_name: safeline-postgres 16 | restart: always 17 | image: postgres:15.2 18 | volumes: 19 | - ${SAFELINE_DIR}/resources/postgres/data:/var/lib/postgresql/data 20 | - /etc/localtime:/etc/localtime:ro 21 | environment: 22 | - POSTGRES_USER=safeline-ce 23 | - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?postgres password required} 24 | networks: 25 | safeline-ce: 26 | ipv4_address: ${SUBNET_PREFIX}.2 27 | cap_drop: 28 | - net_raw 29 | command: [postgres, -c, max_connections=200] 30 | redis: 31 | container_name: safeline-redis 32 | restart: always 33 | image: redis:7.0.10 34 | volumes: 35 | - ${SAFELINE_DIR}/resources/redis/data:/data 36 | - /etc/localtime:/etc/localtime:ro 37 | command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD} 38 | networks: 39 | safeline-ce: 40 | ipv4_address: ${SUBNET_PREFIX}.3 41 | cap_drop: 42 | - net_raw 43 | sysctls: 44 | net.core.somaxconn: "511" 45 | management: 46 | container_name: safeline-mgt-api 47 | restart: always 48 | image: chaitin/safeline-mgt-api:${IMAGE_TAG:?image tag required} 49 | volumes: 50 | - ${SAFELINE_DIR?safeline dir required}/resources/management:/resources/management 51 | - ${SAFELINE_DIR}/resources/nginx:/resources/nginx 52 | - ${SAFELINE_DIR}/logs:/logs 53 | - /etc/localtime:/etc/localtime:ro 54 | ports: 55 | - ${MGT_PORT:-9443}:1443 56 | environment: 57 | - MANAGEMENT_RESOURCES_DIR=/resources/management 58 | - NGINX_RESOURCES_DIR=/resources/nginx 59 | - DATABASE_URL=postgres://safeline-ce:${POSTGRES_PASSWORD}@safeline-postgres/safeline-ce 60 | - MARIO_URL=http://safeline-mario:3335 61 | - DETECTOR_URL=http://safeline-detector:8001 62 | - REDIS_URL=redis://:${REDIS_PASSWORD}@safeline-redis:6379/0 63 | - MANAGEMENT_LOGS_DIR=/logs/management 64 | dns: 65 | - 119.29.29.29 66 | - 223.5.5.5 67 | - 180.76.76.76 68 | - 1.2.4.8 69 | - 114.114.114.114 70 | - 8.8.8.8 71 | networks: 72 | safeline-ce: 73 | ipv4_address: ${SUBNET_PREFIX}.4 74 | cap_drop: 75 | - net_raw 76 | detector: 77 | container_name: safeline-detector 78 | restart: always 79 | image: chaitin/safeline-detector:${IMAGE_TAG} 80 | volumes: 81 | - ${SAFELINE_DIR}/resources/detector:/resources/detector 82 | - ${SAFELINE_DIR}/logs/detector:/logs/detector 83 | - /etc/localtime:/etc/localtime:ro 84 | environment: 85 | - LOG_DIR=/logs/detector 86 | networks: 87 | safeline-ce: 88 | ipv4_address: ${SUBNET_PREFIX}.5 89 | cap_drop: 90 | - net_raw 91 | mario: 92 | container_name: safeline-mario 93 | restart: always 94 | image: chaitin/safeline-mario:${IMAGE_TAG} 95 | volumes: 96 | - ${SAFELINE_DIR}/resources/mario:/resources/mario 97 | - ${SAFELINE_DIR}/logs/mario:/logs/mario 98 | - /etc/localtime:/etc/localtime:ro 99 | environment: 100 | - LOG_DIR=/logs/mario 101 | - GOGC=100 102 | - DATABASE_URL=postgres://safeline-ce:${POSTGRES_PASSWORD}@safeline-postgres/safeline-ce 103 | - REDIS_URL=redis://:${REDIS_PASSWORD}@safeline-redis:6379/0 104 | networks: 105 | safeline-ce: 106 | ipv4_address: ${SUBNET_PREFIX}.6 107 | cap_drop: 108 | - net_raw 109 | tengine: 110 | container_name: safeline-tengine 111 | restart: always 112 | image: chaitin/safeline-tengine:${IMAGE_TAG} 113 | volumes: 114 | - ${SAFELINE_DIR}/resources/nginx:/etc/nginx 115 | - ${SAFELINE_DIR}/resources/management:/resources/management 116 | - ${SAFELINE_DIR}/resources/detector:/resources/detector 117 | - ${SAFELINE_DIR}/logs/nginx:/var/log/nginx 118 | - /etc/localtime:/etc/localtime:ro 119 | - ${SAFELINE_DIR}/resources/cache:/usr/local/nginx/cache 120 | - /etc/resolv.conf:/etc/resolv.conf 121 | environment: 122 | - REDIS_URL=redis://:${REDIS_PASSWORD}@${SUBNET_PREFIX}.3:6379/0 123 | - MGT_ADDR=${SUBNET_PREFIX}.4:9002 124 | ulimits: 125 | nofile: 131072 126 | network_mode: host 127 | -------------------------------------------------------------------------------- /release/latest/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "latest_version": "v3.11.0", 3 | "rec_version": "v3.8.2" 4 | } -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /website/.npmrc: -------------------------------------------------------------------------------- 1 | strict-ssl=false 2 | save-prefix="" 3 | engine-strict=true 4 | registry="https://registry.npmmirror.com" -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | 使用 [Docusaurus 2](https://docusaurus.io/), 作为基础框架。 4 | 5 | ### 开发 6 | 7 | ```sh 8 | # 代码变动后可以自动更新,但是不能 9 | npm start 10 | # 支持搜索功能,但是无法自动更新 11 | npm run preview 12 | ``` 13 | 14 | ### 部署 15 | 16 | 手动本地构建 docker 镜像,然后运行 17 | 18 | ```sh 19 | docker build -t website:latest . 20 | docker run --name site -p 3000:80 -d website:latest 21 | ``` 22 | 23 | ### 链接替换 24 | 25 | 使用 nginx rewrite 把更改地址的链接记录下,运行旧链接访问到新地址 26 | 27 | ```nginx 28 | 29 | location / { 30 | 31 | rewrite /posts/guide_introduction /docs/ permanent; 32 | rewrite /posts/guide_install /docs/guide/install permanent; 33 | rewrite /docs/上手指南/guide_install /docs/guide/install permanent; 34 | 35 | rewrite /posts/guide_login /docs/guide/login permanent; 36 | rewrite /docs/上手指南/guide_login /docs/guide/login permanent; 37 | 38 | rewrite /posts/guide_config /docs/guide/config permanent; 39 | rewrite /docs/上手指南/guide_config /docs/guide/config permanent; 40 | 41 | rewrite /posts/guide_test /docs/guide/test permanent; 42 | rewrite /docs/上手指南/guide_test /docs/guide/test permanent; 43 | 44 | rewrite /posts/guide_upgrade /docs/guide/upgrade permanent; 45 | rewrite /docs/上手指南/guide_upgrade /docs/guide/upgrade permanent; 46 | 47 | rewrite /posts/faq_install /docs/faq/install permanent; 48 | rewrite /docs/常见问题排查/faq_install /docs/faq/install permanent; 49 | 50 | rewrite /posts/faq_login /docs/faq/login permanent; 51 | rewrite /docs/常见问题排查/faq_login /docs/faq/login permanent; 52 | 53 | rewrite /posts/faq_access /docs/guide/config permanent; 54 | rewrite /docs/常见问题排查/faq_access /docs/guide/config permanent; 55 | 56 | rewrite /posts/faq_config /docs/faq/config permanent; 57 | rewrite /docs/常见问题排查/faq_config /docs/faq/config permanent; 58 | 59 | rewrite /posts/faq_other /docs/faq/other permanent; 60 | rewrite /docs/常见问题排查/faq_other /docs/faq/other permanent; 61 | 62 | rewrite /posts/about_syntaxanalysis /docs/about/syntaxanalysis permanent; 63 | rewrite /docs/关于雷池/about_syntaxanalysis /docs/about/syntaxanalysis permanent; 64 | 65 | rewrite /posts/about_challenge /docs/about/challenge permanent; 66 | rewrite /docs/关于雷池/about_challenge /docs/about/challenge permanent; 67 | 68 | rewrite /posts/about_changelog /docs/about/changelog permanent; 69 | rewrite /docs/关于雷池/about_changelog /docs/about/changelog permanent; 70 | 71 | rewrite /posts/about_chaitin /docs/about/chaitin permanent; 72 | rewrite /docs/关于雷池/about_chaitin /docs/about/chaitin permanent; 73 | 74 | rewrite /docs/faq/access /docs/guide/config permanent; 75 | rewrite /docs/faq/config /docs/guide/config permanent; 76 | 77 | proxy_pass http://upstream; 78 | } 79 | ``` -------------------------------------------------------------------------------- /website/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /website/blog/2023-08-04-website.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | 为了支持文档检索,采用 https://docusaurus.io/ 作为新的网站框架。 -------------------------------------------------------------------------------- /website/compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | web: 3 | image: safeline-official:2 4 | ports: 5 | - 80:80 6 | -------------------------------------------------------------------------------- /website/docs/01-introduction.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "雷池简介" 3 | slug: / 4 | --- 5 | 6 | # 雷池简介 7 | 8 | ## 什么是 WAF 9 | 10 | WAF 是 Web Application Firewall 的缩写,也被称为 Web 应用防火墙。区别于传统防火墙,WAF 工作在应用层,对基于 HTTP/HTTPS 协议的 Web 系统有着更好的防护效果,使其免于受到黑客的攻击。 11 | 12 | ## 什么是雷池 13 | 14 | 雷池是长亭科技耗时近 10 年倾情打造的 WAF,核心检测能力由智能语义分析算法驱动。 15 | 16 | Slogan: 不让黑客越雷池半步。 17 | 18 | ## 为什么是雷池 19 | 20 | #### 便捷性 21 | 22 | 采用容器化部署,一条命令即可完成安装,0 成本上手 23 | 24 | 安全配置开箱即用,无需人工维护,可实现安全躺平式管理 25 | 26 | #### 安全性 27 | 28 | 首创业内领先的智能语义分析算法,精准检测、低误报、难绕过 29 | 30 | 语义分析算法无规则,面对未知特征的 0day 攻击不再手足无措 31 | 32 | #### 高性能 33 | 34 | 无规则引擎,线性安全检测算法,平均请求检测延迟在 1 毫秒级别 35 | 36 | 并发能力强,单核轻松检测 2000+ TPS,只要硬件足够强,可支撑的流量规模无上限 37 | 38 | #### 高可用 39 | 40 | 流量处理引擎基于 Nginx 开发,性能与稳定性均可得到保障 41 | 42 | 内置完善的健康检查机制,服务可用性高达 99.99% 43 | 44 | ## WAF 部署架构 45 | 46 | 下图是一个简单的网站流量拓扑,外部用户发出请求,经过网络最终传递到网站服务器。 47 | 48 | 此时,若外部用户中存在恶意用户,那么由恶意用户发出的攻击请求也会经过网络最终传递到网站服务器。 49 | 50 | ![](/images/docs/guide_introduction/website_without_safeline.png) 51 | 52 | 社区版雷池以反向代理方式接入,优先于网站服务器接收流量,对流量中的攻击行为进行检测和清洗,将清洗过后的流量转发给网站服务器。 53 | 54 | 通过以上行为,最终确保外部攻击流量无法触达网站服务器。 55 | 56 | ![](/images/docs/guide_introduction/website_with_safeline.png) 57 | -------------------------------------------------------------------------------- /website/docs/02-guide/01-install.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "安装雷池" 3 | --- 4 | 5 | # 安装雷池 6 | 7 | ## 配置需求 8 | 9 | - 操作系统:Linux 10 | - 指令架构:x86_64 11 | - 软件依赖:Docker 20.10.14 版本以上 12 | - 软件依赖:Docker Compose 2.0.0 版本以上 13 | - 最小化环境:1 核 CPU / 1 GB 内存 / 5 GB 磁盘 14 | 15 | 可以逐行执行以下命令来确认服务器配置 16 | 17 | ```shell 18 | uname -m # 查看指令架构 19 | docker version # 查看 Docker 版本 20 | docker compose version # 查看 Docker Compose 版本 21 | docker-compose version # 同上(兼容老版本 Docker Compose) 22 | cat /proc/cpuinfo # 查看 CPU 信息 23 | cat /proc/meminfo # 查看内存信息 24 | df -h # 查看磁盘信息 25 | 26 | lscpu | grep ssse3 # 确认 CPU 是否支持 ssse3 指令集 27 | ``` 28 | 29 | 有三种安装方式供选择 30 | 31 | - [在线安装](#在线安装) : 推荐安装方式 32 | - [离线安装](#离线安装) : 服务器无法连接 Docker Hub 时选择 33 | - [一键安装](#使用牧云助手安装) : 最简单的安装方式 34 | 35 | ## 在线安装 36 | 37 | **_如果服务器可以访问互联网环境,推荐使用该方式_** 38 | 39 | 执行以下命令,即可开始安装 40 | 41 | ``` 42 | bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" 43 | ``` 44 | 45 | > 如果连接 Docker Hub 网络不稳,导致镜像下载失败,可以采用 [离线安装](#离线安装) 方式 46 | 47 | 经过以上步骤,你的雷池已经安装好了,下一步请参考 [登录雷池](/docs/guide/login) 48 | 49 | ## 离线安装 50 | 51 | 如果你的服务器无法连接互联网环境,或连接 Docker Hub 网络不稳,可以使用镜像包安装方式 52 | 53 | > 这里忽略 Docker 安装的过程 54 | 55 | 首先,下载 [雷池社区版镜像包](https://demo.waf-ce.chaitin.cn/image.tar.gz) 并传输到需要安装雷池的服务器上,执行以下命令加载镜像 56 | 57 | ``` 58 | cat image.tar.gz | gzip -d | docker load 59 | ``` 60 | 61 | 执行以下命令创建并进入雷池安装目录 62 | 63 | ``` 64 | mkdir -p safeline # 创建 safeline 目录 65 | cd safeline # 进入 safeline 目录 66 | ``` 67 | 68 | 下载 [编排脚本](https://waf-ce.chaitin.cn/release/latest/compose.yaml) 并传输到 safeline 目录中 69 | 70 | 执行以下命令,生成雷池运行所需的相关环境变量 71 | 72 | ``` 73 | echo "SAFELINE_DIR=$(pwd)" >> .env 74 | echo "IMAGE_TAG=latest" >> .env 75 | echo "MGT_PORT=9443" >> .env 76 | echo "POSTGRES_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 > .env 77 | echo "REDIS_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 > .env 78 | echo "SUBNET_PREFIX=172.22.222" >> .env 79 | ``` 80 | 81 | 执行以下命令启动雷池 82 | 83 | ``` 84 | docker compose up -d 85 | ``` 86 | 87 | 经过以上步骤,你的雷池已经安装好了,下一步请参考 [登录雷池](/docs/guide/login) 88 | 89 | ## 使用牧云助手安装 90 | 91 | 也可以使用 [牧云主机管理助手](https://collie.chaitin.cn/) 进行一键安装 92 | 93 | ![](/images/docs/guide_install/collie_apps.png) 94 | 95 | 参考视频教程 [用 “白嫖的云主机” 一键安装 “开源的 Web 防火墙”](https://www.bilibili.com/video/BV1sh4y1t7Pk/) 96 | 97 | ## 常见安装问题 98 | 99 | 请参考 [安装问题](/docs/faq/install) 100 | -------------------------------------------------------------------------------- /website/docs/02-guide/02-login.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "登录雷池" 3 | --- 4 | 5 | # 登录雷池 6 | 7 | 浏览器打开后台管理页面 `https://:9443`。根据界面提示,使用 **支持 TOTP 的认证软件或者小程序** 扫描二维码,然后输入动态口令登录: 8 | 9 | ![login.gif](https://waf-ce.chaitin.cn/images/gif/login.gif) 10 | -------------------------------------------------------------------------------- /website/docs/02-guide/03-config.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "配置防护站点" 3 | --- 4 | 5 | # 配置防护站点 6 | 7 | ## 界面操作 8 | ![config_site.gif](https://waf-ce.chaitin.cn/images/gif/config_site.gif) 9 | 10 | 添加后,在客户端执行 `curl -H "Host: <域名>" http://<雷池 IP>:<雷池监听端口>` ,若能获取到业务网站的响应,并且站点上 “今日访问量” 增加,则代表配置成功。 11 | 12 | ## 如何配置域名、端口、上游服务器 13 | ### 工作原理 14 | 15 | 雷池社区版主要以 **反向代理** 的方式工作,类似于一台 nginx 服务。部署时,需要让网站流量先抵达雷池,经过雷池检测和过滤后,再转给原来的网站业务。 16 | 17 | 如果你不了解反向代理的工作原理,可以通过以下几种雷池常见的工作场景,来了解如何配置站点。 18 | 19 | 假设你的网站域名为 `example.com`,如图: 20 | 21 | ![Alt text](/images/docs/guide_config/deploy_origin.png) 22 | 23 | ### 在单独设备上部署雷池(推荐) 24 | 25 | 如果你可以提供一台独立设备部署雷池,那么你需要: 26 | 1. **将网站流量指向雷池**。例如将域名解析到雷池 27 | 2. 禁止网站服务器上,所有除了雷池之外的访问。例如配置防火墙,或者直接把网站服务器放到内网 28 | 29 | 效果大致如下: 30 | 31 | ![Alt text](/images/docs/guide_config/deploy_on_separate_server.png) 32 | 33 | 雷池上相应的站点配置为: 34 | * 域名:公网域名 `example.com` 35 | * 端口:80 或 443/ssl 36 | * 上游服务器:网站服务器的地址 `http://192.168.10.10` 37 | 38 | ### 直接在网站服务器上部署雷池 39 | 40 | 提示:不建议这样部署,因为这样单机的负载更高、设备宕机的概率更大。非纯净的环境还会提高安装失败的概率,故障排查也会比较困难。 41 | 42 | 如果能接受这些风险,雷池也可以直接部署在网站服务器上。你需要: 43 | 1. 将原本监听 80 或 443/ssl 端口的网站服务改到其他端口,**让雷池监听设备的 80 或 443/ssl 端口** 44 | 2. 使网站服务仅允许本机访问。例如配置系统防火墙、Iptables 45 | 46 | 效果大致如图: 47 | 48 | ![Alt text](/images/docs/guide_config/deploy_on_web_server.png) 49 | 50 | 此时雷池上的站点配置为: 51 | * 域名:公网域名 `example.com` 52 | * 端口:80 或 443/ssl 53 | * 上游服务器:`http://127.0.0.1:<网站服务改后的端口>` 54 | 55 | ### 和其他反代设备一起部署的情况 56 | 57 | 雷池作为反代设备,可以在任意位置接入主链路。只要将接入位置的流量指向雷池,并在雷池的 “上游服务器” 处填写请求的下一跳服务器地址即可。例如: 58 | 59 | ![Alt text](/images/docs/guide_config/deploy_with_other_server.png) 60 | 61 | ## 配置后网站无法访问,如何排查 62 | 63 | 如果按照上文指引部署雷池、配置了站点,但网站仍无法访问,建议按照以下步骤排查: 64 | 65 | 1. 明确 “网站无法访问” 的具体表现: 66 | * 如果 `502 Bad Gateway tengine`: 67 | 68 | ![Alt text](/images/docs/guide_config/tengine_502.png) 69 | 70 | 大概率是是雷池的上游服务器配置不正确,或者雷池无法访问到上游服务器。请继续按下面步骤排查,重点排查步骤 6、7 71 | * 如果请求能够返回但是十分缓慢 72 | * 首先确认服务器负载是否正常 73 | * 在客户端执行命令,检查雷池服务器与上游服务器的网络:`curl -H "Host: " -vv -o /dev/null -s -w 'time_namelookup: %{time_namelookup}\ntime_connect: %{time_connect}\ntime_starttransfer: %{time_starttransfer}\ntime_total: %{time_total}\n' http://<上游服务器地址>` 74 | * 如果 time_namelookup 时间过大,请检查 dns server 配置 75 | * 如果 time_connect 时间过大,请检查雷池与上游服务器之间的网络状态 76 | * 如果 time_starttransfer 时间过大,请检查上游服务器状态,是否出现资源过载情况 77 | * 如果不是以上情况,继续下一步 78 | 2. 在客户端执行 `curl -H "Host: <域名>" http://<雷池 IP>:<雷池监听端口>` 。正常情况下,应能获取到业务网站的响应,并且站点的 “今日访问量” +1 79 | * 如果浏览器无法访问,但这一步正常获取到响应,大概率是因为: 80 | * 测试过程中,网站域名还没有切到雷池,浏览器测试时访问的是 `http(s)://<雷池 IP>`,恰好业务服务上有 Host 验证,所以拒绝了该请求。这种情况需要修改本机 host,把域名解析到雷池 IP,再访问 `http(s)://<域名>`,才能准确测试 81 | * 网站业务做了其他一些特殊处理。例如访问后 301 跳转到了其他地址,需要具体排查网站业务的响应内容 82 | * 如果不能获取到响应,继续下一步 83 | 3. 在雷池设备上执行 `curl -H "Host: <域名>" http://<雷池 IP>:<雷池监听端口>`。正常情况下,应能获取到业务网站的响应,并且站点上 “今日访问量” +1 84 | * 如果步骤 2 失败而这里成功,说明客户端到雷池之间的网络存在问题。请排查网络,保证客户端可访问到雷池 85 | * 如果不能获取到响应,继续下一步 86 | 4. 在雷池设备上执行 `curl -H "Host: <域名>" http://127.0.0.1:<雷池监听端口>`。正常情况下,应能获取到业务网站的响应,并且站点的 “今日访问量” +1 87 | * 如果步骤 3 失败而这里成功,且 `telnet <雷池 IP> <雷池监听端口>` 返回 `Unable to connect to remote host: Connection refused`,大概率是被雷池设备上的防火墙拦截了。可能是操作系统本身的防火墙,还有可能是云服务商的防火墙。请根据实际情况逐项排查,开放雷池监听端口的访问 88 | * 如果不能获取到响应,继续下一步 89 | 5. 在雷池设备上执行 `netstat -anp | grep <雷池监听端口>` 确认端口监听情况。正常情况下,应该有一个 nginx 进程监听在 `0.0.0.0:<雷池监听端口>`。没有的话请通过社群或者 Github issue 提交反馈,附上排查过程。有的话继续下一步 90 | 6. 在雷池设备上 `curl -H "Host: <域名>" <上游服务器地址>`。正常情况下,应能获取到业务网站的响应 91 | * 如果步骤 4 失败而这里成功,请通过社群或者 Github issue 提交反馈,附上排查过程 92 | * 如果这步失败,说明雷池和上游服务器之间的网络存在问题。请排查网络,确保雷池可以访问到上游服务器 93 | 94 | 如果排查后问题还是没有解决,请通过社群或者 Github issue 提交反馈,并附上排查的过程和截图。 -------------------------------------------------------------------------------- /website/docs/02-guide/04-test.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "测试防护效果" 3 | --- 4 | 5 | # 测试防护效果 6 | 7 | ## 确认网站可以正常访问 8 | 9 | 根据雷池 WAF 配置的网站参数访问你的网站。 10 | 11 | 打开浏览器访问 `http://:<端口>/`。 12 | 13 | > 网站协议默认是 http,勾选 ssl 则为 https 14 | > 主机名可以是雷池的 IP,也可以是网站的域名(确保域名已经解析到雷池) 15 | > 端口是你在雷池页面中配置的网站端口 16 | 17 | 若网站访问不正常,请参考 [网站无法访问](/docs/02-guide/03-config.md)。 18 | 19 | ## 尝试手动模拟攻击 20 | 21 | 打开浏览器,访问以下地址即可模拟出对应的攻击: 22 | 23 | - 模拟 SQL 注入,请访问 `http://:<端口>/?id=1%20AND%201=1` 24 | - 模拟 XSS,请访问 `http://:<端口>/?html=` 25 | 26 | 通过浏览器,你将会看到雷池已经发现并阻断了攻击请求。 27 | 28 | 若请求没有被阻断,请参考 [防护不生效](/docs/03-faq/03-other.md) 29 | 30 | ## 自动化测试防护效果 31 | 32 | 两条请求当然无法完整的测试雷池的防护效果,可以使用 blazehttp 自动化工具进行批量测试 33 | 34 | #### 下载测试工具 35 | 36 | - [Windows 版本](https://waf-ce.chaitin.cn/blazehttp/blazehttp_windows.exe) 37 | - [Mac 版本(x64)](https://waf-ce.chaitin.cn/blazehttp/blazehttp_mac_x64) 38 | - [Mac 版本(M1)](https://waf-ce.chaitin.cn/blazehttp/blazehttp_mac_m1) 39 | - [Linux 版本(x64)](https://waf-ce.chaitin.cn/blazehttp/blazehttp_linux_x64) 40 | - [Linux 版本(ARM)](https://waf-ce.chaitin.cn/blazehttp/blazehttp_linux_arm64) 41 | - [源码仓库](https://github.com/chaitin/blazehttp) 42 | 43 | #### 准备测试样本 44 | 45 | - [测试样本](https://waf-ce.chaitin.cn/blazehttp/testcases.zip) 46 | 47 | 下载请求样本后解压到 `testcases` 目录 48 | 49 | #### 开始测试 50 | 51 | 1. 将测试工具 `blazehttp` 和测试样本 `testcases` 放在同一个目录下 52 | 2. 进入对应的目录 53 | 3. 使用以下请求开始测试 54 | 55 | ``` 56 | ./blazehttp -t http://:<端口> -g './testcases/**/*.http' 57 | ``` 58 | 59 | #### 测试效果展示 60 | 61 | ``` 62 | # 测试请求 63 | ./blazehttp -t http://192.168.0.1:8080 -g './testcases/**/*.http' 64 | 65 | sending 100% |██████████████████████████████████████████| (18/18, 86 it/s) 66 | Total http file: 18, success: 18 failed: 0 67 | Stat http response code 68 | 69 | Status code: 403 hit: 16 70 | Status code: 200 hit: 2 71 | 72 | Stat http request tag 73 | 74 | tag: sqli hit: 1 75 | tag: black hit: 16 76 | tag: file_include hit: 1 77 | tag: file_upload hit: 1 78 | tag: java_unserialize hit: 1 79 | tag: php_unserialize hit: 1 80 | tag: cmdi hit: 1 81 | tag: ssrf hit: 1 82 | tag: xslti hit: 1 83 | tag: xss hit: 1 84 | tag: xxe hit: 1 85 | tag: asp_code hit: 1 86 | tag: white hit: 2 87 | tag: ognl hit: 1 88 | tag: shellshock hit: 1 89 | tag: ssti hit: 1 90 | tag: directory_traversal hit: 1 91 | tag: php_code hit: 1 92 | ``` 93 | -------------------------------------------------------------------------------- /website/docs/02-guide/05-upgrade.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "升级雷池" 3 | --- 4 | 5 | # 升级雷池 6 | 7 | **注意**: 升级雷池时服务会重启,流量会中断一小段时间,根据业务情况选择合适的时间来执行升级操作。 8 | 9 | ## 在线升级 10 | 11 | 执行以下命令即可进行升级。 12 | 13 | ``` 14 | bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/upgrade.sh)" 15 | ``` 16 | 17 | [可选] 升级成功后,可以执行以下命令删除旧版本 Docke 镜像,以释放磁盘空间。 18 | 19 | ``` 20 | docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}') 21 | ``` 22 | 23 | > 有部分环境的默认 SafeLine 安装路径是在 `/data/safeline-ce`,安装之后可能会发现需要重新绑定 OTP、配置丢失等情况,可以修改 .env 的 `SAFELINE_DIR` 变量,指向 `/data/safeline-ce` 24 | 25 | ## 离线镜像 26 | 27 | 适用于 docker hub 拉取镜像失败的场景,手动更新镜像。 28 | 29 | ``` 30 | # cd /path/to/safeline 31 | 32 | mv compose.yaml compose.yaml.old 33 | wget "https://waf-ce.chaitin.cn/release/latest/compose.yaml" --no-check-certificate -O compose.yaml 34 | 35 | wget "https://waf-ce.chaitin.cn/release/latest/seccomp.json" --no-check-certificate -O seccomp.json 36 | 37 | sed -i "s/IMAGE_TAG=.*/IMAGE_TAG=latest/g" ".env" 38 | 39 | grep "SAFELINE_DIR" ".env" > /dev/null || echo "SAFELINE_DIR=$(pwd)" >> ".env" 40 | grep "IMAGE_TAG" ".env" > /dev/null || echo "IMAGE_TAG=latest" >> ".env" 41 | grep "MGT_PORT" ".env" > /dev/null || echo "MGT_PORT=9443" >> ".env" 42 | grep "POSTGRES_PASSWORD" ".env" > /dev/null || echo "POSTGRES_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 > ".env" 43 | grep "REDIS_PASSWORD" ".env" > /dev/null || echo "REDIS_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 > ".env" 44 | grep "SUBNET_PREFIX" ".env" > /dev/null || echo "SUBNET_PREFIX=172.22.222" >> ".env" 45 | ``` 46 | 47 | 下载 [雷池社区版镜像包](https://demo.waf-ce.chaitin.cn/image.tar.gz) 并传输到需要安装雷池的服务器上,执行以下命令加载镜像 48 | 49 | ``` 50 | docker load -i image.tar.gz 51 | ``` 52 | 53 | 执行以下命令替换 Docker 容器 54 | 55 | ``` 56 | docker compose down 57 | docker compose up -d 58 | ``` 59 | 60 | OK,你已经完成了升级 61 | -------------------------------------------------------------------------------- /website/docs/02-guide/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "上手指南", 3 | "collapsed": false, 4 | "link": { 5 | "type": "generated-index" 6 | } 7 | } -------------------------------------------------------------------------------- /website/docs/03-faq/01-install.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "安装问题" 3 | --- 4 | 5 | # 安装问题 6 | 7 | ## 支不支持 MacOS/Windows 8 | 9 | 不支持,由于雷池所依赖的部分 docker 特性在 MacOS/Windows 上并不生效,所以雷池在 MacOS/Windows 并不能正常工作。 10 | 11 | ## 我能把雷池和业务服务部署到同一台机器中吗? 12 | 13 | 不建议,如放在一起,在流量不变的情况下,机器负载将高于分开部署,增大了资源耗尽的可能性。 14 | 15 | ## docker compose 还是 docker-compose? 16 | 17 | `docker compose`(带空格)是 V2 版本,Go 写的。`docker-compose` 是 V1 版本,Python 写的,已经不维护了。 18 | 19 | 我们推荐使用 V2 版本的 `docker compose`,V1 可能会有兼容性等问题。 20 | 21 | [docker/compose](https://github.com/docker/compose/) 中提到: 22 | 23 | > For a smooth transition from legacy docker-compose 1.xx, please consider installing [compose-switch](https://github.com/docker/compose-switch) to translate `docker-compose ...` commands into Compose V2's `docker compose ....` . Also check V2's `--compatibility` flag. 24 | 25 | 其他参考:[https://stackoverflow.com/questions/66514436/difference-between-docker-compose-and-docker-compose](https://stackoverflow.com/a/66516826) 26 | 27 | ## 镜像下载缓慢甚至连接超时 28 | 29 | 这个是因为 docker hub 默认使用位于美西节点拉取镜像,可以自行配置国内镜像加速源。 30 | 31 | ## ERROR: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? 32 | 33 | 如描述,你需要启动 docker daemon 才能执行相关的命令。尝试 `systemctl start docker`。 34 | 35 | ## docker not found, unable to deploy 36 | 37 | 如描述,你需要安装 `docker`。尝试 `curl -fLsS https://get.docker.com/ | sh` 或者 [Install Docker Engine](https://docs.docker.com/engine/install/)。 38 | 39 | ## docker compose v2 not found, unable to deploy 40 | 41 | 如描述,你需要安装 `docker compose v2`。尝试 `[Install Docker Compose](https://docs.docker.com/compose/install/)`。 42 | 43 | ## `failed to create network safeline-ce` 44 | 45 | safeline-ce 是雷池部署时候创建的 network,出现类似报错,先重启下 dockerd 之后重试。 46 | 47 | ## safeline-tengine 出现 Address already in use 48 | 49 | `docker logs -f safeline-tengine` 容器日志中看到 `Address already in use` 信息。 50 | 51 | 端口冲突,根据报错信息中的端口号,排查是哪个服务占用了,手动处理冲突。 52 | 53 | ## safelint-mgt-api 出现 Operation not permitted 54 | `docker logs -f safelint-mgt-api` 容器日志中看到 `runtime/cgo: pthread_create failed: Operation not permitted` 报错,这个错误一般会在 docker 20.10.9 及以下发生。 55 | 56 | - 最推荐的方式是升级 docker 到最新版本尝试解决这个问题。 57 | - 或您的系统支持配置 seccomp (执行 `grep CONFIG_SECCOMP= /boot/config-$(uname -r)` 输出 `CONFIG_SECCOMP=y` 则为支持), 58 | 则可以在雷池工作目录下载 [seccomp](https://waf-ce.chaitin.cn/release/latest/seccomp.json) 并且编辑 compose.yaml 文件, 59 | 在 management 下加入如下配置项,然后执行 `docker compose down && docker compose up -d` 来尝试解决这个问题: 60 | ```yaml 61 | security_opt: 62 | - seccomp=./seccomp.json 63 | ``` 64 | 65 | ## safeline-postgres 出现 Operation not permitted 66 | 67 | `docker logs -f safeline-postgres` 容器日志中看到 `Operation not permitted` 报错。 68 | 69 | 可能是您的 docker 版本过低,升级 docker 到最新版本尝试一下。 70 | 71 | ## 如何自定义 SafeLine 安装路径? 72 | 73 | 基于最新的 `compose.yaml`,你可以手动修改 `.env` 文件的 `SAFELINE_DIR` 变量。 74 | 75 | ## 如何修改 SafeLine 后台管理的默认端口?本机 `:9443` 已经被别的服务占用了 76 | 77 | 基于最新的 `compose.yaml`,你可以手动添加 `MGT_PORT` 变量到 `.env` 文件。 78 | -------------------------------------------------------------------------------- /website/docs/03-faq/02-login.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "登录问题" 3 | --- 4 | 5 | # 登录问题 6 | 7 | > TOTP (Time-based One-Time Password algorithm) 将密钥与当前时间进行组合,通过哈希算法产生一次性密码,已被采纳为 RFC 6238,被用于许多双因素身份验证系统。 8 | 9 | ## 动态口令错误 10 | 11 | #### 时间不准 12 | 13 | 雷池社区版动态口令认证采用了 TOTP 算法,TOTP 与时间强相关,如果相关设备的时间不准,可能会导致动态口令计算错误。 14 | 15 | 1. 检查手机时间是否准确(或其他 TOTP 扫码设备) 16 | 2. 检查雷池服务器时间是否准确 17 | 18 | #### 动态口令可能已失效 19 | 20 | TOTP 动态口令只有 30 秒的有效期,如果认证失败,请在动态口令刷新后重新尝试。 21 | 22 | ## 重新绑定动态口令 23 | 24 | 登录服务器,打开终端,执行以下命令即可重置动态口令 25 | 26 | ``` 27 | docker exec safeline-mgt-api resetadmin 28 | ``` 29 | 30 | 命令执行完成后打开雷池页面重新绑定即可。 31 | 32 | **注意:重置动态口令后要尽快完成绑定,别被其他人捷足先登了。** 33 | 34 | ## 多人使用 35 | 36 | 如果想多人使用雷池社区版,只需要以下 3 步: 37 | 38 | 1. 重置动态口令(参考 [重置认证](#重置认证)) 39 | 2. 进入登录页面,这时会自动跳转到 TOTP 绑定页面,保存 “绑定二维码”(注意,非 “认证二维码”) 40 | 3. 将 “绑定二维码” 分享给其他人进行绑定,绑定后即可登录(注:“绑定二维码” 无绑定次数限制,无时效限制) 41 | 42 | **注意:保存的 “绑定二维码” 千万别泄漏,任何人得到以后都可以绑定并登录。** 43 | -------------------------------------------------------------------------------- /website/docs/03-faq/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "常见问题排查", 3 | "collapsed": false, 4 | "link": { 5 | "type": "generated-index" 6 | } 7 | } -------------------------------------------------------------------------------- /website/docs/04-practice/00-monitor.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "可用性监控" 3 | --- 4 | 5 | # 网站可用性监控 6 | 7 | 除了对网站的安全防护以外,不少站长还对网站的可用性、稳定性健康监测和敏感内容监测也有强烈需求,有此类需求的站长可以搭配使用 [长亭百川网站监测](https://rivers.chaitin.cn/landing/radar) 产品。 8 | 9 | ### 关于长亭百川网站监测 10 | 11 | [长亭百川网站监测](https://rivers.chaitin.cn/landing/radar) 是一款专门为网站管理员打造的网站监测工具,能够有效监测站点可用性、SSL证书合法性、网站敏感内容等信息。 12 | 13 | 交互界面简洁直观、操作上手轻松、注重用户体验,实时监测每个页面的状态和详细信息,让你对网站运行状态了如指掌。 14 | 15 | ![website.png](https://waf-ce.chaitin.cn/images/docs/practice_monitor/website.png) 16 | 17 | ### 雷池用户福利 18 | 19 | 凡是安装了雷池社区版的用户,可凭借雷池设备码领取长亭网站监控产品 100 元体验金一份 20 | 21 | ![machineid.png](https://waf-ce.chaitin.cn/images/docs/practice_monitor/machineid.png) 22 | 23 | ![gift.png](https://waf-ce.chaitin.cn/images/docs/practice_monitor/gift.png) 24 | 25 | -------------------------------------------------------------------------------- /website/docs/04-practice/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "最佳实践", 3 | "collapsed": false, 4 | "link": { 5 | "type": "generated-index" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /website/docs/05-about/01-syntaxanalysis.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "语义分析检测算法" 3 | --- 4 | 5 | # 语义分析检测算法 6 | 7 | ## 传统规则防护,在当下为什么失灵? 8 | 9 | 当下,Web 应用防火墙大多采用规则匹配方式来识别和阻断攻击流量,但由于 Web 攻击成本低、方式复杂多样、高危漏洞不定期爆发等原因,管理者们在安全运维工作中不得不持续调整防护规则,以保障业务的可用性和安全性。尽管如此,每天依然面临着不少的误报和漏报,影响正常业务运转甚至导致 Web 服务失陷。 10 | 11 | 究其原因,是由于基于规则匹配的攻击识别方法存在先天不足导致的。在乔姆斯基文法体系中,编写匹配规则的正则文法属于 3 型文法,而用于构造攻击 Payload 的程序语言属于 2 型文法,如下图所示: 12 | 13 | ![Untitled](/images/docs/Untitled10.png) 14 | 15 | 从文法表达能力比较,3 型文法包含在 2 型文法之内,基于正则的规则描述无法完全覆盖基于程序语言的攻击 Payload,这也是基于规则匹配识别攻击的 WAF 防护效果低于预期的根本原因。 16 | 17 | ## 雷池的解决之道:算法的革新重构 WAF 18 | 19 | 长亭科技自成立起便深入探索 Web 安全防护的新思路,创新性提出以 “智能语义分析算法” 解决 Web 攻击识别问题,给 WAF 内置 “智能大脑”,使其具备自主识别攻击行为的能力,同时结合机器学习建模,不断增强和完善 “大脑” 的分析能力,不依赖传统的规则库即可满足 Web 应用日常安全防护需求。 20 | 21 | 雷池通过对 Web 请求和返回内容进行智能分析,使 WAF 具备智能判断攻击威胁的能力。智能语义分析算法由词法分析、语法分析、语义分析和威胁模型匹配 4 个步骤组成。 22 | 23 | ![Untitled](/images/docs/Untitled11.png) 24 | 25 | 雷池内置涵盖常用编程语言的编译器,通过对 HTTP 的载荷内容进行深度解码后,按照其语言类型匹配相应语法编译器,进而匹配威胁模型得到威胁评级,阻断或允许访问请求。 26 | 27 | 与规则匹配型威胁检测方式相比,智能语义分析技术具有准确率高、误报率低的特点。以 SQL 注入检测为例: 28 | 29 | ![Untitled](/images/docs/Untitled12.png) 30 | 31 | ![Untitled](/images/docs/Untitled13.png) 32 | 33 | 作为全球范围内第一款以智能语义分析算法为核心引擎能力打造的下一代 WAF,雷池展现出了更多让安全产品 “更聪明” 的可能。除了形成了质变的检测引擎的精准程度,它可以通过插件形式灵活扩展、实现瑞士军刀般的功能增加,可以变形适配、安装部署进各种网络环境,可以跟机器学习等前沿技术更好的融合、增强流量分析的能力等。 34 | -------------------------------------------------------------------------------- /website/docs/05-about/02-challenge.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "人机验证" 3 | --- 4 | 5 | # 人机验证 6 | 7 | 自从雷池社区版发布以来,我们一直密切关注用户对于爬虫和扫描器的反馈和防护需求。 因此,在 2.0 版本中,我们致力于探索与此相关的功能,以满足用户的期望和保护网站的安全。 8 | 9 | ![challenge.png](/images/docs/challenge.png) 10 | 11 | ### 加入人机验证之后的请求处理流程 12 | 13 | ![flow.png](/images/docs/flow.png) 14 | 15 | ### 人机验证如何配置 16 | 17 | 首先,点击位于左边栏的人机验证。之后,点击 **添加人机验证**。 18 | ![add_challenge.png](/images/docs/add_challenge.png) 19 | 在这里我们可以配置是否开启交互式校验以及规则的名称以及规则的触发条件。 20 | 21 | ### 人机验证触发规则 22 | 23 | 1. 规则内的条件之间是并且的关系,即需要全部命中,才会触发 24 | 2. 规则与规则之间是或的关系,则有一个命中,便会触发 25 | 26 | ### 交互与非交互的区别 27 | 28 | 如果选择开启交互,那么用户需要点击页面中间的勾选框开始验证,如果选择非交互,那么将自动开始验证。 29 | ![manual.png](/images/docs/manual.png) 30 | -------------------------------------------------------------------------------- /website/docs/05-about/04-chaitin.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "关于我们" 3 | --- 4 | 5 | # 关于我们 6 | 7 | ## 关于长亭 8 | 9 | 雷池是长亭科技耗时近 10 年倾情打造的 Web 应用防护产品,核心检测能力由智能语义分析算法驱动。 10 | 11 | 北京长亭未来科技有限公司是国际顶尖的网络信息安全公司之一,创始人团队 5 人均为清华博士,并引入阿里云安全核心人才团队。全球首发基于智能语义分析的下一代 Web 应用防火墙产品,目前,公司已形成以攻(安全评估系统)、防(下一代 Web 应用防火墙)、知(安全分析与管理平台)、查(主机安全管理平台)、抓(伪装欺骗系统)为核心的新一代安全防护体系,并提供优质的安全测试及咨询服务,为企业级客户带来智能的全新安全防护思路。 12 | 13 | 长亭专注为企业级用户提供专业的网络信息安全解决方案。2016 年即发布基于人工智能语义分析的下一代 Web 应用防火墙,颠覆了传统依赖规则防护的工作原理,为企业用户带来智能、简单、省心的安全产品及服务。 14 | 15 | 长亭雷池坚持以技术为导向,产品与服务所涉及到的算法与核心技术均领先国际行业前沿标准,不仅颠覆了繁琐耗时的传统工作原理,更将产品性能提升至领先水准,为企业用户带来更快、更精准、更智能的安全防护。 16 | 17 | ## 荣誉 & 资质 18 | 19 | ### 2021 年 20 | 21 | - 入选 IDC《中国硬件 Web 应用防火墙(WAF)市场份额》前四 22 | - 重磅发布《实战攻防-企业红蓝对抗实践指南》 23 | - 荣获 2021 网信自主创新优秀产品 “补天奖” 24 | - 荣膺 CNNVD 2020 年度优秀技术支撑单位 25 | - 10 项虚拟机漏洞获 Oracle 官方致谢 26 | - 入选安全牛第八版中国网络安全行业全景图 27 | - 入选 CCSIP 2021 中国网络安全产业全景图 28 | - 入选嘶吼 2021 网络安全产业链图谱 29 | 30 | ### 2020 年 31 | 32 | - 2020 年金融科技产品创新突出贡献奖 33 | - 2020 年网络安全创新能力 100 强 34 | - 入选数世咨询《蜜罐诱捕能力指南》 35 | - 入选数说安全中国网络安全市场全景图 36 | - Network Products Guide IT World Award 37 | - 2020 年中国人工智能商业落地价值潜力 100 强 38 | - 2020 Application Security and Testing 铜奖 39 | - 入选安全牛《2020 中国网络安全企业 100 强报告》 40 | - 发现并命名幽灵猫(Ghostcat)漏洞 41 | - 联合发布《国家区块链漏洞库-区块链漏洞定级细则》 42 | 43 | ### 2019 年 44 | 45 | - 入选 Forrester《Now Tech:Web Application Firewalls, Q4 2019》报告 46 | - 2019 年关键信息基础设施“盘古奖” 47 | - 荣获《金融电子化》“2019 年度金融科技产品创新突出贡献奖” 48 | - 中国网络安全与信息产业 “金智奖” 2019 年度优秀单位 49 | 50 | ### 2018 年 51 | 52 | - 通过国家保密局涉密信息系统产品认证 53 | - 通信网络安全服务能力一级资质认证 54 | - 中国 IT 思想力奖-金融科技产品创新奖 55 | - TSRC 2017 最佳客户端洞主 & 年度最佳合作伙伴 56 | - 获 Info Security Products Guide 全球卓越奖 57 | - 入选《CIO Advisor》亚太地区 25 家最热门人工智能公司 58 | - 入围 Gartner 2018《Web 应用防火墙魔力象限报告亚太版》 59 | - 2018 年度金融科技优秀产品创新奖 60 | - “2018 年度金牌服务机构” 安全服务奖 61 | 62 | ### 2017 年 63 | 64 | - OWASP 认证雷池(SafeLine)下一代 Web 应用防火墙 65 | - 通过国家测评中心/信息安全服务资质测评单位 66 | - Gartner 魔力象限报告提名 67 | - 再次登上 Black Hat USA 演讲 68 | - 《财富》杂志评选中国创新百强 “人工智能和机器人” 领域全国第一 69 | - 受邀出席世界互联网大会网络安全闭门会 70 | - 阿里巴巴年度优秀生态合作伙伴 71 | - 入选 Cyber Defense Magazine 全球网络安全领导者 Top 25 72 | 73 | ### 2016 年 74 | 75 | - ISO9001 国际质量体系认证 76 | - ISO27001 国际质量体系认证 77 | - 长亭雷池 Web 应用防火墙(增强级)销售许可证 78 | - 国家信息安全漏洞库(CNNVD)二级技术支撑单位资质 79 | - 中国年度最佳产品奖、IT 行业最具影响力企业奖 80 | - 年度特殊贡献奖 81 | - GeekPwn 三周年特别贡献奖 82 | 83 | ### 2015 年 84 | 85 | - 中国国家高新技术企业称号 86 | - 中关村高新技术企业称号 87 | - “最具价值安全问题” 荣誉认证 88 | - 首次登上 Black Hat USA 演讲 89 | -------------------------------------------------------------------------------- /website/docs/05-about/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "关于雷池", 3 | "collapsed": false, 4 | "link": { 5 | "type": "generated-index" 6 | } 7 | } -------------------------------------------------------------------------------- /website/docusaurus.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Note: type annotations allow type checking and IDEs autocompletion 3 | 4 | const lightCodeTheme = require("prism-react-renderer/themes/github"); 5 | const darkCodeTheme = require("prism-react-renderer/themes/dracula"); 6 | 7 | /** @type {import('@docusaurus/types').Config} */ 8 | const config = { 9 | title: "长亭雷池 WAF 社区版", 10 | tagline: "", 11 | favicon: "images/favicon.ico", 12 | 13 | // Set the production url of your site here 14 | url: "https://waf-ce.chaitin.cn/", 15 | // Set the // pathname under which your site is served 16 | // For GitHub pages deployment, it is often '//' 17 | baseUrl: "/", 18 | 19 | // GitHub pages deployment config. 20 | // If you aren't using GitHub pages, you don't need these. 21 | organizationName: "chaitin", // Usually your GitHub org/user name. 22 | projectName: "safeline-ce-site", // Usually your repo name. 23 | 24 | onBrokenLinks: "throw", 25 | onBrokenMarkdownLinks: "warn", 26 | 27 | // Even if you don't use internalization, you can use this field to set useful 28 | // metadata like html lang. For example, if your site is Chinese, you may want 29 | // to replace "en" with "zh-Hans". 30 | i18n: { 31 | defaultLocale: "zh-Hans", 32 | locales: ["zh-Hans"], 33 | }, 34 | 35 | themes: [ 36 | [ 37 | // @ts-ignore 38 | require.resolve("@easyops-cn/docusaurus-search-local"), 39 | /** @type {import("@easyops-cn/docusaurus-search-local").PluginOptions} */ 40 | // @ts-ignore 41 | ({ 42 | // ... Your options. 43 | // `hashed` is recommended as long-term-cache of index file is possible. 44 | hashed: true, 45 | // For Docs using Chinese, The `language` is recommended to set to: 46 | // ``` 47 | language: ["en", "zh"], 48 | // ``` 49 | }), 50 | ], 51 | ], 52 | 53 | presets: [ 54 | [ 55 | "classic", 56 | /** @type {import('@docusaurus/preset-classic').Options} */ 57 | ({ 58 | docs: { 59 | sidebarPath: require.resolve("./sidebars.js"), 60 | // Remove this to remove the "edit this page" links. 61 | // editUrl: "https://github.com/chaitin/safeline/tree/main/website", 62 | }, 63 | blog: { 64 | showReadingTime: true, 65 | // Remove this to remove the "edit this page" links. 66 | // editUrl: "https://github.com/chaitin/safeline/tree/main/website", 67 | }, 68 | theme: { 69 | customCss: require.resolve("./src/css/custom.css"), 70 | }, 71 | }), 72 | ], 73 | ], 74 | 75 | themeConfig: 76 | /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ 77 | ({ 78 | // Replace with your project's social card 79 | image: "images/safeline.png", 80 | navbar: { 81 | title: "", 82 | logo: { alt: "Logo", src: "images/logo.png" }, 83 | items: [ 84 | { to: "/docs", label: "技术文档", position: "right" }, 85 | { to: "/detection", label: "效果对比", position: "right" }, 86 | { 87 | to: "https://www.bilibili.com/medialist/detail/ml2342694989", 88 | label: "教学视频", 89 | position: "right", 90 | }, 91 | { 92 | to: "https://demo.waf-ce.chaitin.cn:9443/dashboard", 93 | label: "演示环境", 94 | position: "right", 95 | }, 96 | ], 97 | }, 98 | 99 | footer: { 100 | style: "dark", 101 | links: [ 102 | { 103 | title: " ", 104 | items: [ 105 | { 106 | label: "北京长亭科技有限公司", 107 | to: "https://www.chaitin.cn/zh/", 108 | }, 109 | { 110 | label: "长亭 B 站主页", 111 | href: "https://space.bilibili.com/521870525", 112 | }, 113 | ], 114 | }, 115 | { 116 | title: " ", 117 | items: [ 118 | { 119 | label: "CT Stack 安全社区", 120 | href: "https://stack.chaitin.cn/", 121 | }, 122 | { 123 | label: "长亭合作伙伴论坛", 124 | href: "https://bbs.chaitin.cn/", 125 | }, 126 | ], 127 | }, 128 | { 129 | title: " ", 130 | items: [ 131 | { 132 | label: "长亭百川云平台", 133 | href: "https://rivers.chaitin.cn/", 134 | }, 135 | { 136 | label: "关于我们", 137 | to: "/docs/about/chaitin", 138 | }, 139 | ], 140 | }, 141 | { 142 | title: " ", 143 | items: [ 144 | { 145 | label: "长亭 GitHub 主页", 146 | href: "https://github.com/chaitin", 147 | }, 148 | ], 149 | }, 150 | ], 151 | copyright: `Copyright © ${new Date().getFullYear()} 152 | 北京长亭未来科技有限公司京 ICP 备 19035216 号京公网安备 11010802020947 号`, 153 | }, 154 | prism: { 155 | theme: lightCodeTheme, 156 | darkTheme: darkCodeTheme, 157 | }, 158 | }), 159 | }; 160 | 161 | module.exports = config; 162 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "website", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "preview": "docusaurus clear; docusaurus build; docusaurus serve", 14 | "write-translations": "docusaurus write-translations", 15 | "write-heading-ids": "docusaurus write-heading-ids", 16 | "typecheck": "tsc" 17 | }, 18 | "dependencies": { 19 | "@docusaurus/core": "2.4.1", 20 | "@docusaurus/preset-classic": "2.4.1", 21 | "@easyops-cn/docusaurus-search-local": "^0.35.0", 22 | "@emotion/react": "11.11.1", 23 | "@emotion/styled": "11.11.0", 24 | "@mdx-js/react": "^1.6.22", 25 | "@mui/icons-material": "5.14.3", 26 | "@mui/lab": "5.0.0-alpha.138", 27 | "@mui/material": "5.14.3", 28 | "clsx": "^1.2.1", 29 | "countup.js": "2.7.0", 30 | "prism-react-renderer": "^1.3.5", 31 | "react": "^17.0.2", 32 | "react-dom": "^17.0.2", 33 | "react-responsive-carousel": "3.2.23" 34 | }, 35 | "devDependencies": { 36 | "@docusaurus/module-type-aliases": "2.4.1", 37 | "@tsconfig/docusaurus": "^1.0.5", 38 | "typescript": "^4.7.4" 39 | }, 40 | "browserslist": { 41 | "production": [ 42 | ">0.5%", 43 | "not dead", 44 | "not op_mini all" 45 | ], 46 | "development": [ 47 | "last 1 chrome version", 48 | "last 1 firefox version", 49 | "last 1 safari version" 50 | ] 51 | }, 52 | "engines": { 53 | "node": ">=16.14" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /website/sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | // @ts-check 13 | 14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 15 | const sidebars = { 16 | // By default, Docusaurus generates a sidebar from the docs folder structure 17 | tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], 18 | 19 | // But you can create a sidebar manually 20 | /* 21 | tutorialSidebar: [ 22 | 'intro', 23 | 'hello', 24 | { 25 | type: 'category', 26 | label: 'Tutorial', 27 | items: ['tutorial-basics/create-a-document'], 28 | }, 29 | ], 30 | */ 31 | }; 32 | 33 | module.exports = sidebars; 34 | -------------------------------------------------------------------------------- /website/src/api/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | submitSampleSet, 3 | getSampleSet, 4 | getSampleSetResult, 5 | getSampleDetail, 6 | getSetupCount, 7 | }; 8 | 9 | // http://localhost:2023 10 | const BASE_API = "/api"; 11 | 12 | function submitSampleSet(data: { 13 | pocs: Array<{ content: string; tag: string }>; 14 | record_it: boolean; 15 | }) { 16 | return fetch(BASE_API + "/poc/list", { 17 | method: "POST", 18 | headers: { "Content-Type": "application/json" }, 19 | mode: "cors", 20 | // credentials: "include", 21 | body: JSON.stringify(data), 22 | }).then((res) => res.json()); 23 | } 24 | 25 | function getSampleSet(id: string) { 26 | return fetch(BASE_API + "/poc/list?id=" + id).then((res) => res.json()); 27 | } 28 | 29 | function getSampleDetail(id: string) { 30 | return fetch(BASE_API + "/poc/detail?id=" + id).then((res) => res.json()); 31 | } 32 | 33 | async function getSampleSetResult(id: string, timeout: number = 60) { 34 | const startAt = new Date().getTime(); 35 | const isTimeout = () => new Date().getTime() - startAt > timeout * 1000; 36 | const maxRetry = 20; 37 | 38 | for (let i = 0; i < maxRetry; i++) { 39 | const res = await fetch(BASE_API + "/poc/results?id=" + id).then((res) => 40 | res.json() 41 | ); 42 | if (res.code == 0 && res.data.data) { 43 | return { data: res.data.data, timeout: false }; 44 | } 45 | if (isTimeout()) break; 46 | await new Promise((r) => setTimeout(r, 2000)); 47 | } 48 | return { data: [], timeout: true }; 49 | } 50 | 51 | function getSetupCount() { 52 | return fetch(BASE_API + "/count").then((res) => res.json()); 53 | } 54 | -------------------------------------------------------------------------------- /website/src/components/Features.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Grid, Box, Typography } from "@mui/material"; 3 | 4 | const FEATURE_LIST = [ 5 | { 6 | title: "便捷", 7 | content: ( 8 | <> 9 | 10 | 采用容器化部署,一条命令即可完成安装,0 成本上手 11 | 12 | 13 | 安全配置开箱即用,无需人工维护,可实现安全躺平式管理 14 | 15 | 16 | ), 17 | }, 18 | { 19 | title: "安全", 20 | content: ( 21 | <> 22 | 23 | 首创业内领先的智能语义分析算法,精准检测、低误报、难绕过 24 | 25 | 26 | 语义分析算法无规则,面对未知特征的 0day 攻击不再手足无措 27 | 28 | 29 | ), 30 | }, 31 | { 32 | title: "高性能", 33 | content: ( 34 | <> 35 | 36 | 无规则引擎,线性安全检测算法,平均请求检测延迟在 1 毫秒级别 37 | 38 | 39 | 并发能力强,单核轻松检测 2000+ 40 | TPS,只要硬件足够强,可支撑的流量规模无上限 41 | 42 | 43 | ), 44 | }, 45 | { 46 | title: "高可用", 47 | content: ( 48 | <> 49 | 50 | 流量处理引擎基于 Nginx 开发,性能与稳定性均可得到保障 51 | 52 | 53 | 内置完善的健康检查机制,服务可用性高达 99.99% 54 | 55 | 56 | ), 57 | }, 58 | ]; 59 | 60 | const Features = () => { 61 | return ( 62 | 72 | 73 | {FEATURE_LIST.map((feature) => ( 74 | 75 | 79 | feature 85 | 86 | {feature.title} 87 | 88 | 89 | 92 | {feature.content} 93 | 94 | 95 | ))} 96 | 97 | 98 | ); 99 | }; 100 | 101 | export default Features; 102 | -------------------------------------------------------------------------------- /website/src/components/Icon.tsx: -------------------------------------------------------------------------------- 1 | import React, { type FC, useEffect } from "react"; 2 | 3 | import { Box, type SxProps } from "@mui/material"; 4 | 5 | interface IconProps { 6 | type: string; 7 | sx?: SxProps; 8 | [propName: string]: any; 9 | } 10 | 11 | const Icon: FC = ({ type, sx, ...restProps }) => { 12 | useEffect(() => { 13 | require("../../static/fonts/iconfont"); 14 | }, []); 15 | return ( 16 | // @ts-ignore 17 | 25 | ); 26 | }; 27 | export default Icon; 28 | -------------------------------------------------------------------------------- /website/src/components/Message/Alert.tsx: -------------------------------------------------------------------------------- 1 | import React, { type FC, useRef, useEffect } from 'react' 2 | 3 | import { Alert as MAlert, type AlertColor } from '@mui/material' 4 | 5 | interface AlertProps { 6 | duration?: number 7 | onClose?(key: React.Key): void 8 | noticeKey: React.Key 9 | content?: React.ReactNode 10 | severity: AlertColor 11 | } 12 | 13 | const Alert: FC = (props) => { 14 | const { duration, severity, content, noticeKey, onClose } = props 15 | const closeTimer = useRef(null) 16 | 17 | const startCloseTimer = () => { 18 | if (duration) { 19 | closeTimer.current = window.setTimeout(() => { 20 | close() 21 | }, duration * 1000) 22 | } 23 | } 24 | 25 | const clearCloseTimer = () => { 26 | if (closeTimer.current) { 27 | clearTimeout(closeTimer.current) 28 | closeTimer.current = null 29 | } 30 | } 31 | 32 | const close = (e?: React.MouseEvent) => { 33 | if (e) { 34 | e.stopPropagation() 35 | } 36 | clearCloseTimer() 37 | if (onClose) { 38 | onClose(noticeKey) 39 | } 40 | } 41 | 42 | useEffect(() => { 43 | startCloseTimer() 44 | return () => { 45 | clearCloseTimer() 46 | } 47 | // eslint-disable-next-line react-hooks/exhaustive-deps 48 | }, []) 49 | 50 | return ( 51 | 52 | {content} 53 | 54 | ) 55 | } 56 | 57 | export default Alert 58 | -------------------------------------------------------------------------------- /website/src/components/Message/Message.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, forwardRef, useImperativeHandle } from "react"; 2 | 3 | import { Snackbar, Box, type AlertColor } from "@mui/material"; 4 | 5 | import { render, unmount } from "@site/src/components/utils"; 6 | 7 | import Alert from "./Alert"; 8 | 9 | export interface Notice { 10 | key?: React.Key; 11 | content?: React.ReactNode; 12 | severity: AlertColor; 13 | onClose?: () => void; 14 | } 15 | 16 | interface MessageProps {} 17 | 18 | let seed = 0; 19 | const now = Date.now(); 20 | 21 | function getUuid() { 22 | const id = seed; 23 | seed += 1; 24 | return `ctMessage_${now}_${id}`; 25 | } 26 | 27 | // eslint-disable-next-line react/display-name 28 | const Message = forwardRef((props, ref) => { 29 | const [notices, setNotices] = useState([]); 30 | const add = (notice: Notice) => { 31 | const key = notice.key ?? getUuid(); 32 | setNotices((state) => { 33 | state.push({ ...notice, key }); 34 | return [...state]; 35 | }); 36 | }; 37 | 38 | const remove = (key: React.Key) => { 39 | setNotices((state) => state.filter((s) => s.key !== key)); 40 | }; 41 | 42 | useImperativeHandle(ref, () => ({ 43 | add, 44 | remove, 45 | })); 46 | 47 | return ( 48 | 49 | 50 | {notices.map((item) => { 51 | const alertProps = { 52 | ...item, 53 | noticeKey: item.key!, 54 | onClose: (noticeKey: React.Key) => { 55 | remove(noticeKey); 56 | }, 57 | }; 58 | return ; 59 | })} 60 | 61 | 62 | ); 63 | }); 64 | 65 | // @ts-ignore 66 | Message.newInstance = (properties: MessageProps, callback) => { 67 | const { ...props } = properties || {}; 68 | const div = document?.createElement("div"); 69 | document.body.appendChild(div); 70 | let called = false; 71 | function ref(notification: any) { 72 | if (called) { 73 | return; 74 | } 75 | called = true; 76 | callback({ 77 | notice(noticeProps: MessageProps) { 78 | notification.add(noticeProps); 79 | }, 80 | removeNotice(key: React.Key) { 81 | notification.remove(key); 82 | }, 83 | component: notification, 84 | destroy() { 85 | unmount(div); 86 | if (div.parentNode) { 87 | div.parentNode.removeChild(div); 88 | } 89 | }, 90 | }); 91 | } 92 | setTimeout(() => { 93 | render(, div); 94 | }); 95 | }; 96 | 97 | export default Message; 98 | -------------------------------------------------------------------------------- /website/src/components/Message/index.tsx: -------------------------------------------------------------------------------- 1 | import type React from "react"; 2 | 3 | import { type AlertColor } from "@mui/material"; 4 | 5 | import Notification from "./Message"; 6 | 7 | type MessageStaticFunctions = Record< 8 | AlertColor, 9 | (context: React.ReactNode, duration?: number) => void 10 | >; 11 | 12 | const Message = {} as MessageStaticFunctions; 13 | 14 | let notification: any = null; 15 | 16 | if (typeof window !== "undefined") { 17 | // @ts-ignore 18 | Notification.newInstance({}, (n: any) => { 19 | notification = n; 20 | }); 21 | 22 | const commonOpen = 23 | (type: AlertColor) => 24 | (content: React.ReactNode, duration: number = 3) => { 25 | notification.notice({ 26 | duration, 27 | severity: type, 28 | content, 29 | }); 30 | }; 31 | 32 | (["success", "warning", "info", "error"] as const).forEach((type) => { 33 | Message[type] = commonOpen(type); 34 | }); 35 | } 36 | 37 | export default Message; 38 | -------------------------------------------------------------------------------- /website/src/components/Modal/ConfirmDialog.tsx: -------------------------------------------------------------------------------- 1 | import React, { type FC } from "react"; 2 | 3 | import ErrorIcon from "@mui/icons-material/Error"; 4 | import { Box } from "@mui/material"; 5 | 6 | import Modal, { type ModalProps } from "./Modal"; 7 | 8 | export interface ConfirmDialogProps extends ModalProps { 9 | content?: React.ReactNode; 10 | width?: string; 11 | } 12 | 13 | const ConfirmDialog: FC = (props) => { 14 | const { title = "提示", content, width = "480px", ...rest } = props; 15 | return ( 16 | 27 | 28 | {title} 29 | 30 | } 31 | closable={false} 32 | {...rest} 33 | sx={{ width }} 34 | > 35 | {content} 36 | 37 | ); 38 | }; 39 | 40 | export default ConfirmDialog; 41 | -------------------------------------------------------------------------------- /website/src/components/Modal/Modal.tsx: -------------------------------------------------------------------------------- 1 | import React, { type FC, useState } from 'react' 2 | 3 | import CloseIcon from '@mui/icons-material/Close' 4 | import { LoadingButton } from '@mui/lab' 5 | import { Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton } from '@mui/material' 6 | 7 | export interface ModalProps { 8 | open?: boolean 9 | title?: React.ReactNode 10 | children?: React.ReactNode 11 | footer?: false | React.ReactNode 12 | okText?: React.ReactNode 13 | cancelText?: React.ReactNode 14 | showCancel?: boolean 15 | okColor?: 'primary' | 'error' 16 | cancelColor?: 'primary' | 'error' 17 | closable?: boolean 18 | onOk?(): void 19 | onClose?(): void 20 | onCancel?(): void 21 | sx?: any 22 | } 23 | 24 | const Modal: FC = (props) => { 25 | const { 26 | open = false, 27 | title, 28 | children, 29 | footer, 30 | okText = '确认', 31 | okColor = 'primary', 32 | cancelColor = 'primary', 33 | showCancel = true, 34 | cancelText = '取消', 35 | onOk, 36 | onClose, 37 | onCancel, 38 | closable = true, 39 | sx = {}, 40 | } = props 41 | const [loading, setLoading] = useState(false) 42 | 43 | const onConfirm = async () => { 44 | setLoading(true) 45 | try { 46 | await onOk?.() 47 | } catch (error) {} 48 | 49 | setLoading(false) 50 | } 51 | 52 | return ( 53 | 66 | {(title || closable) && ( 67 | 78 | {title} 79 | {closable && ( 80 | 86 | 87 | 88 | )} 89 | 90 | )} 91 | 92 | {children} 93 | {footer === false && null} 94 | {footer === undefined && ( 95 | 103 | {showCancel && ( 104 | 107 | )} 108 | 109 | 110 | {okText} 111 | 112 | 113 | )} 114 | {footer && ( 115 | 123 | {footer} 124 | 125 | )} 126 | 127 | ) 128 | } 129 | 130 | export default Modal 131 | -------------------------------------------------------------------------------- /website/src/components/Modal/confrim.tsx: -------------------------------------------------------------------------------- 1 | import { render as reactRender } from "@site/src/components/utils"; 2 | 3 | import ConfirmDialog, { type ConfirmDialogProps } from "./ConfirmDialog"; 4 | 5 | export default function confirm(config: ConfirmDialogProps) { 6 | const container = document.createDocumentFragment(); 7 | const { onCancel: propCancel, onOk: propOk } = config; 8 | const onCancel = async () => { 9 | await propCancel?.(); 10 | close(); 11 | }; 12 | const onOk = async () => { 13 | await propOk?.(); 14 | close(); 15 | }; 16 | let currentConfig = { ...config, open: true, onCancel, onOk } as any; 17 | function render(props: ConfirmDialogProps) { 18 | setTimeout(() => { 19 | reactRender(, container); 20 | }); 21 | } 22 | 23 | function close() { 24 | currentConfig = { 25 | ...currentConfig, 26 | open: false, 27 | }; 28 | render(currentConfig); 29 | } 30 | 31 | render(currentConfig); 32 | } 33 | -------------------------------------------------------------------------------- /website/src/components/Modal/index.tsx: -------------------------------------------------------------------------------- 1 | import { type ConfirmDialogProps } from './ConfirmDialog' 2 | import OriginModal from './Modal' 3 | import confirm from './confrim' 4 | 5 | type ModalStaticFunctions = Record<'confirm', (config: ConfirmDialogProps) => void> 6 | type ModalType = typeof OriginModal 7 | 8 | const Modal = OriginModal as ModalType & ModalStaticFunctions 9 | 10 | Modal.confirm = confirm 11 | 12 | export default Modal 13 | -------------------------------------------------------------------------------- /website/src/components/Title.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Typography, SxProps } from "@mui/material"; 3 | 4 | interface TitleProps { 5 | title: string; 6 | sx?: SxProps; 7 | } 8 | 9 | const Title: React.FC = ({ title, sx }) => { 10 | return ( 11 | 15 | 21 | {title} 22 | 23 | ); 24 | }; 25 | 26 | export default Title; 27 | -------------------------------------------------------------------------------- /website/src/components/Version/Consultation.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useState, useEffect } from "react"; 3 | import Message from "@site/src/components/Message"; 4 | import Modal from "@site/src/components/Modal"; 5 | import { Box, TextField, Typography, Button } from "@mui/material"; 6 | 7 | function Consultation() { 8 | const [text, setText] = useState(""); 9 | const [wrongPhoneNumber, setWrongPhoneNumber] = useState(false); 10 | const [consultOpen, setConsultOpen] = useState(false); 11 | 12 | const consultHandler = () => { 13 | const valid = /^1[3-9]\d{9}$/.test(text); 14 | setWrongPhoneNumber(!valid); 15 | if (!valid) { 16 | Message.error("手机号格式不正确"); 17 | return; 18 | } 19 | fetch("https://leads.chaitin.net/api/trial", { 20 | // fetch('http://116.62.230.26:8999/api/trial', { // 测试用地址 21 | method: "POST", 22 | mode: "cors", 23 | headers: { "Content-Type": "application/json" }, 24 | body: JSON.stringify({ 25 | phone: text, 26 | platform_source: "product-official-site", 27 | product_source: "safeline-ce", 28 | source_detail: "来自雷池社区版官网", 29 | }), 30 | }) 31 | .then((d) => d.json()) 32 | .then((d) => { 33 | if (d.code == 0) { 34 | Message.success("提交成功"); 35 | } else { 36 | Message.error("提交失败"); 37 | } 38 | setConsultOpen(false); 39 | }); 40 | }; 41 | 42 | const textHandler = (v: string) => { 43 | setText(v); 44 | }; 45 | 46 | useEffect(() => { 47 | if (!consultOpen) { 48 | setText(""); 49 | } 50 | }, [consultOpen]); 51 | 52 | return ( 53 | <> 54 | 69 | setConsultOpen(false)} 72 | title="咨询企业版" 73 | okText="提交" 74 | onOk={consultHandler} 75 | sx={{ width: 600 }} 76 | > 77 | 78 |
79 | textHandler(e.target.value)} 90 | /> 91 |
92 | 93 | 我们将在工作时间 2 小时内联系您,您的手机号不会用于其他目的 94 | 95 |
96 |
97 | 98 | ); 99 | } 100 | 101 | export default Consultation; 102 | -------------------------------------------------------------------------------- /website/src/components/Version/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Typography, Box, Button, alpha } from "@mui/material"; 3 | import Title from "@site/src/components/Title"; 4 | import FunctionTable from "./FunctionTable"; 5 | import Consultation from "./Consultation"; 6 | 7 | const FREE_FUNCTION = [ 8 | "智能语义分析检测", 9 | "反向代理接入", 10 | "自定义黑白名单", 11 | "CC 攻击防护", 12 | "智能人机验证", 13 | "可视化安全分析", 14 | ]; 15 | const ENTERPRISE_FUNCTION = [ 16 | "智能语义分析检测", 17 | "串行、旁路均可接入", 18 | "集群式可扩展部署", 19 | "CC 攻击防护", 20 | "精细化引擎调节", 21 | "业务 API 智能建模", 22 | "Bot 管理,恶意 Bot 防护", 23 | "专业技术支持服务", 24 | "漏洞应急服务", 25 | ]; 26 | 27 | const Version = () => { 28 | return ( 29 | <> 30 | 39 | 61 | 62 | 社区版 63 | 64 | 76 | 77 | {FREE_FUNCTION.map((f) => ( 78 | 96 | {f} 97 | 98 | ))} 99 | 100 | 101 | 102 | ({ 104 | width: { xs: "100%", sm: 306 }, 105 | flexShrink: 0, 106 | height: { xs: "auto" }, 107 | px: 3, 108 | py: 2, 109 | border: "1px solid", 110 | borderColor: alpha(theme.palette.primary.main, 0.5), 111 | borderRadius: "12px", 112 | display: "flex", 113 | flexDirection: "column", 114 | alignItems: "center", 115 | "&:hover": { 116 | boxShadow: 117 | "0 36px 70px -10px rgba(61,64,76,.15), 0 18px 20px -10px rgba(61,64,76,.05)", 118 | }, 119 | })} 120 | > 121 | 122 | 企业版 123 | 124 | 125 | 126 | {ENTERPRISE_FUNCTION.map((f) => ( 127 | 145 | {f} 146 | 147 | ))} 148 | 149 | 150 | 151 | 152 | 153 | <FunctionTable /> 154 | </> 155 | ); 156 | }; 157 | 158 | export default Version; 159 | -------------------------------------------------------------------------------- /website/src/components/detection/Result.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import TableContainer from "@mui/material/TableContainer"; 3 | import Box from "@mui/material/Box"; 4 | import Table from "@mui/material/Table"; 5 | import TableRow from "@mui/material/TableRow"; 6 | import TableHead from "@mui/material/TableHead"; 7 | import TableCell from "@mui/material/TableCell"; 8 | import TableBody from "@mui/material/TableBody"; 9 | import Paper from "@mui/material/Paper"; 10 | import Title from "@site/src/components/Title"; 11 | import type { ResultRowsType } from "./types"; 12 | import { Typography } from "@mui/material"; 13 | 14 | export default Result; 15 | 16 | function Result({ rows }: { rows: ResultRowsType }) { 17 | return ( 18 | <Box sx={{ mt: 4 }}> 19 | <Title title="测试结果" sx={{ fontSize: "16px", mb: "16px" }} /> 20 | <TableContainer component={Paper}> 21 | <Table sx={{ minWidth: 650, mb: 0 }}> 22 | <TableHead> 23 | <TableRow sx={{ border: 0 }}> 24 | <TableCell>WAF 类别</TableCell> 25 | <TableCell>版本</TableCell> 26 | <TableCell>检出率</TableCell> 27 | <TableCell>误报率</TableCell> 28 | <TableCell>准确率</TableCell> 29 | <TableCell>平均检测耗时</TableCell> 30 | </TableRow> 31 | </TableHead> 32 | <TableBody> 33 | {rows.map((row, index) => ( 34 | <TableRow key={index}> 35 | <TableCell sx={{ borderLeft: "0", borderRight: "0" }}> 36 | {appendLink(row.engine)} 37 | </TableCell> 38 | <TableCell sx={{ borderLeft: "0", borderRight: "0" }}> 39 | {row.version} 40 | </TableCell> 41 | <TableCell sx={{ borderLeft: "0", borderRight: "0" }}> 42 | {row.detectionRate} 43 | </TableCell> 44 | <TableCell sx={{ borderLeft: "0", borderRight: "0" }}> 45 | {row.failedRate} 46 | </TableCell> 47 | <TableCell sx={{ borderLeft: "0", borderRight: "0" }}> 48 | {row.accuracy} 49 | </TableCell> 50 | <TableCell sx={{ borderLeft: "0", borderRight: "0" }}> 51 | {row.cost} 52 | </TableCell> 53 | </TableRow> 54 | ))} 55 | </TableBody> 56 | </Table> 57 | </TableContainer> 58 | </Box> 59 | ); 60 | } 61 | 62 | function appendLink(engine: string) { 63 | if (engine == "ModSecurity") 64 | return ( 65 | <a href="https://github.com/SpiderLabs/ModSecurity" target="_blank"> 66 | <Typography sx={{ color: "primary.main" }}>{engine}</Typography> 67 | </a> 68 | ); 69 | if (engine == "TADK") 70 | return ( 71 | <a 72 | target="_blank" 73 | href="https://networkbuilders.intel.com/university/course/traffic-analytics-development-kit-tadk" 74 | > 75 | <Typography sx={{ color: "primary.main" }}>{engine}</Typography> 76 | </a> 77 | ); 78 | return engine; 79 | } 80 | -------------------------------------------------------------------------------- /website/src/components/detection/SampleCount.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Typography from "@mui/material/Typography"; 3 | 4 | function SampleCount({ 5 | total, 6 | normal, 7 | attack, 8 | }: { 9 | total: number; 10 | normal: number; 11 | attack: number; 12 | }) { 13 | return ( 14 | <div style={{ display: "flex" }}> 15 | <Typography>共计 {total} 个 HTTP 请求样本,其中 </Typography> 16 | <Typography sx={{ color: "success.main" }}> 17 | 普通样本 {normal} 个 18 | </Typography> 19 | 、 20 | <Typography sx={{ color: "error.main" }}>攻击样本 {attack} 个</Typography> 21 | </div> 22 | ); 23 | } 24 | 25 | export default SampleCount; 26 | -------------------------------------------------------------------------------- /website/src/components/detection/SampleList.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useState } from "react"; 3 | // import hljs from "highlight.js"; 4 | 5 | import { 6 | Box, 7 | Button, 8 | Table, 9 | TableHead, 10 | TableRow, 11 | TableBody, 12 | Typography, 13 | Dialog, 14 | DialogActions, 15 | DialogContent, 16 | } from "@mui/material"; 17 | import Paper from "@mui/material/Paper"; 18 | import Accordion from "@mui/material/Accordion"; 19 | import AccordionSummary from "@mui/material/AccordionSummary"; 20 | import AccordionDetails from "@mui/material/AccordionDetails"; 21 | import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; 22 | import TableCell from "@mui/material/TableCell"; 23 | import Title from "@site/src/components/Title"; 24 | import SampleCount from "./SampleCount"; 25 | import SamplesForm from "./SamplesForm"; 26 | import Message from "@site/src/components/Message"; 27 | import { getSampleDetail } from "@site/src/api"; 28 | import { sizeLength } from "@site/src/components/utils"; 29 | 30 | import type { RecordSamplesType } from "./types"; 31 | 32 | export default SampleList; 33 | 34 | interface SampleListProps { 35 | value: RecordSamplesType; 36 | onSetIdChange: (id: string) => void; 37 | } 38 | 39 | function SampleList({ value, onSetIdChange }: SampleListProps) { 40 | const [open, setOpen] = useState(false); 41 | const [detail, setDetail] = useState(""); 42 | 43 | const handleDetail = (id: string) => async () => { 44 | const res = await getSampleDetail(id); 45 | if (res.code != 0) { 46 | Message.error(res.msg || "获取详情失败"); 47 | return; 48 | } 49 | const text = document.createElement("textarea"); 50 | text.innerHTML = res.data.content; 51 | // const highlighted = hljs.highlight(text.value, { 52 | // language: "http", 53 | // }); 54 | // setDetail(highlighted.value); 55 | setDetail(text.value) 56 | setOpen(true); 57 | }; 58 | 59 | const handleClose = () => { 60 | setDetail(""); 61 | setOpen(false); 62 | }; 63 | 64 | return ( 65 | <> 66 | <Box 67 | sx={{ 68 | display: "flex", 69 | justifyContent: "space-between", 70 | marginBottom: "18px", 71 | alignItems: "center", 72 | }} 73 | > 74 | <Title title="测试样本" sx={{ fontSize: "16px" }} /> 75 | <SamplesForm onSetIdChange={onSetIdChange} /> 76 | </Box> 77 | 78 | <Accordion sx={{ borderRadius: "4px" }}> 79 | <AccordionSummary expandIcon={<ExpandMoreIcon />}> 80 | <SampleCount 81 | total={value.length} 82 | normal={value.filter((i) => !i.isAttack).length} 83 | attack={value.filter((i) => i.isAttack).length} 84 | /> 85 | </AccordionSummary> 86 | <AccordionDetails> 87 | <Table> 88 | <TableHead> 89 | <TableRow sx={{ borderBottom: "0" }}> 90 | <TableCell width={150}>样本类型</TableCell> 91 | <TableCell width={150}>样本大小</TableCell> 92 | <TableCell>摘要</TableCell> 93 | <TableCell width={100}></TableCell> 94 | </TableRow> 95 | </TableHead> 96 | <TableBody> 97 | {value.map((row, index) => { 98 | const text = document.createElement("textarea"); 99 | text.innerHTML = row.summary; 100 | 101 | return ( 102 | <TableRow key={index}> 103 | <TableCell sx={{ borderLeft: "0", borderRight: "0" }}> 104 | {row.isAttack ? ( 105 | <Typography sx={{ color: "error.main" }}> 106 | 攻击样本 107 | </Typography> 108 | ) : ( 109 | <Typography sx={{ color: "success.main" }}> 110 | 普通样本 111 | </Typography> 112 | )} 113 | </TableCell> 114 | <TableCell sx={{ borderLeft: "0", borderRight: "0" }}> 115 | {sizeLength(row.size)} 116 | </TableCell> 117 | <TableCell sx={{ borderLeft: "0", borderRight: "0" }}> 118 | <Typography 119 | noWrap 120 | sx={{ 121 | width: "600px", 122 | fontFamily: 123 | "ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace", 124 | }} 125 | > 126 | {text.value} 127 | </Typography> 128 | </TableCell> 129 | <TableCell sx={{ borderLeft: "0", borderRight: "0" }}> 130 | <Button onClick={handleDetail(row.id)}>详情</Button> 131 | </TableCell> 132 | </TableRow> 133 | ); 134 | })} 135 | </TableBody> 136 | </Table> 137 | </AccordionDetails> 138 | </Accordion> 139 | 140 | <Dialog open={open} onClose={handleClose}> 141 | <DialogContent sx={{ marginBottom: 0 }}> 142 | <Box 143 | component="code" 144 | style={{ whiteSpace: "pre-line", wordBreak: "break-all" }} 145 | dangerouslySetInnerHTML={{ __html: detail }} 146 | /> 147 | </DialogContent> 148 | <DialogActions> 149 | <Button onClick={handleClose}>关闭</Button> 150 | </DialogActions> 151 | </Dialog> 152 | </> 153 | ); 154 | } 155 | -------------------------------------------------------------------------------- /website/src/components/detection/SamplesForm.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useState } from "react"; 3 | import Message from "@site/src/components/Message"; 4 | import { submitSampleSet } from "@site/src/api"; 5 | import CircularProgress from "@mui/material/CircularProgress"; 6 | import CloseIcon from "@mui/icons-material/Close"; 7 | import IconButton from "@mui/material/IconButton"; 8 | import SampleSteps from "./SampleSteps"; 9 | import Button from "@mui/material/Button"; 10 | import Modal from "@mui/material/Modal"; 11 | import Box from "@mui/material/Box"; 12 | import Title from "@site/src/components/Title"; 13 | 14 | export default SamplesForm; 15 | 16 | function SamplesForm({ 17 | onSetIdChange, 18 | }: { 19 | onSetIdChange: (id: string) => void; 20 | }) { 21 | const [open, setOpen] = useState(false); 22 | const [loading, setLoading] = useState(false); 23 | 24 | const testHandler = () => { 25 | setOpen(true); 26 | }; 27 | const closeHandler = () => { 28 | setOpen(false); 29 | }; 30 | 31 | const getSetId = async (content: string, publish: boolean, tag: string) => { 32 | const res = await submitSampleSet({ 33 | pocs: [{ content, tag }], 34 | record_it: publish, 35 | }); 36 | if (res.code != 0) throw res.msg; 37 | if (res.data.total != 1) throw "样本数量错误"; 38 | return res.data.id; 39 | }; 40 | 41 | const submit = async ({ 42 | sample, 43 | publish, 44 | isAttack, 45 | }: { 46 | sample: string; 47 | publish: boolean; 48 | isAttack: boolean; 49 | }) => { 50 | setLoading(true); 51 | try { 52 | const setId = await getSetId( 53 | sample, 54 | publish, 55 | isAttack ? "black" : "white" 56 | ); 57 | onSetIdChange(setId); 58 | } catch (e) { 59 | Message.error(("解析失败: " + e) as string); 60 | } 61 | setOpen(false); 62 | setLoading(false); 63 | }; 64 | 65 | return ( 66 | <> 67 | <Button variant="contained" onClick={testHandler}> 68 | 测试我的样本 69 | </Button> 70 | <Modal open={open} onClose={closeHandler}> 71 | <Box 72 | sx={{ 73 | position: "absolute" as "absolute", 74 | top: "50%", 75 | left: "50%", 76 | transform: "translate(-50%, -50%)", 77 | width: 750, 78 | bgcolor: "background.paper", 79 | boxShadow: 24, 80 | borderRadius: "6px", 81 | p: 3, 82 | }} 83 | > 84 | <Box 85 | sx={{ 86 | display: "flex", 87 | justifyContent: "space-between", 88 | alignItems: "center", 89 | }} 90 | > 91 | {loading && ( 92 | <Box 93 | sx={{ 94 | position: "absolute", 95 | top: "0", 96 | left: "0", 97 | right: "0", 98 | bottom: "0", 99 | display: "flex", 100 | justifyContent: "center", 101 | alignItems: "center", 102 | background: "rgba(0,0,0,0.3)", 103 | }} 104 | > 105 | <CircularProgress /> 106 | </Box> 107 | )} 108 | <Title title="测试我的样本" sx={{ fontSize: "18px", mb: 2 }} /> 109 | <IconButton onClick={closeHandler}> 110 | <CloseIcon fontSize="small" /> 111 | </IconButton> 112 | </Box> 113 | <Box> 114 | <SampleSteps onDetect={submit} /> 115 | </Box> 116 | </Box> 117 | </Modal> 118 | </> 119 | ); 120 | } 121 | -------------------------------------------------------------------------------- /website/src/components/detection/types.ts: -------------------------------------------------------------------------------- 1 | export type RecordSamplesType = Array<{ 2 | id: string; 3 | size: number; 4 | isAttack: boolean; 5 | summary: string; 6 | }>; 7 | 8 | export type SampleDetailType = { 9 | id: string; 10 | size: number; 11 | isAttack: boolean; 12 | raw: string; 13 | summary: string; 14 | }; 15 | 16 | export type ResultRowsType = Array<{ 17 | engine: string; 18 | version: string; 19 | detectionRate: number; 20 | failedRate: number; 21 | accuracy: number; 22 | cost: string; 23 | }>; 24 | -------------------------------------------------------------------------------- /website/src/components/utils.ts: -------------------------------------------------------------------------------- 1 | import ReactDOM, { type Root } from "react-dom"; 2 | 3 | const MARK = "__ct_react_root__"; 4 | 5 | type ContainerType = (Element | DocumentFragment) & { 6 | [MARK]?: Root; 7 | }; 8 | 9 | export function render(node: React.ReactElement, container: ContainerType) { 10 | const root = container[MARK] || container; 11 | 12 | ReactDOM.render(node, root); 13 | 14 | container[MARK] = root; 15 | } 16 | 17 | export async function unmount(container: ContainerType) { 18 | return Promise.resolve().then(() => { 19 | container[MARK]?.unmount(); 20 | delete container[MARK]; 21 | }); 22 | } 23 | 24 | export function sizeLength(l: number) { 25 | return l > 1024 * 2 ? Math.round(l / 1024) + "KB" : l + "B"; 26 | } 27 | 28 | export function sampleLength(s: string) { 29 | const l = new Blob([s]).size; 30 | return l > 1024 * 2 ? Math.round(l / 1024) + "KB" : l + "B"; 31 | } 32 | 33 | export function sampleSummary(s: string) { 34 | return s.split("\n").slice(0, 2).join(" ").slice(0, 60); 35 | } 36 | -------------------------------------------------------------------------------- /website/src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | body { 8 | font-size: 14px; 9 | } 10 | 11 | a:hover { 12 | text-decoration: none; 13 | } 14 | 15 | /* You can override the default Infima variables here. */ 16 | :root { 17 | --ifm-color-primary: #0fc6c2; 18 | --ifm-breadcrumb-color-active: #0fc6c2; 19 | --ifm-menu-color-active: #0fc6c2; 20 | --ifm-link-hover-color: #0fc6c2; 21 | --ifm-footer-link-hover-color: #0fc6c2; 22 | --ifm-navbar-link-hover-color: #0fc6c2; 23 | --ifm-navbar-background-color: #0f1935; 24 | --ifm-navbar-link-color: white; 25 | } 26 | 27 | /* Overriding root Infima variables */ 28 | [data-theme="dark"] { 29 | --ifm-navbar-background-color: #0f1935; 30 | } 31 | 32 | aside.theme-doc-sidebar-container { 33 | width: 240px !important; 34 | } 35 | 36 | .navbar__toggle.clean-btn svg { 37 | color: white; 38 | } 39 | 40 | @media (max-width: 996px) { 41 | :root { 42 | --ifm-menu-color: white; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /website/src/pages/detection.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import Container from "@mui/material/Container"; 3 | import Result from "@site/src/components/detection/Result"; 4 | // import { useRouter } from "next/router"; 5 | import { useLocation } from "@docusaurus/router"; 6 | import { getSampleSet, getSampleSetResult } from "@site/src/api"; 7 | import Message from "@site/src/components/Message"; 8 | import type { 9 | RecordSamplesType, 10 | ResultRowsType, 11 | } from "@site/src/components/detection/types"; 12 | import Grid from "@mui/material/Grid"; 13 | import SampleList from "@site/src/components/detection/SampleList"; 14 | import { Typography } from "@mui/material"; 15 | import Layout from "@theme/Layout"; 16 | import ThemeProvider from "@site/src/components/Theme"; 17 | 18 | export default Detection; 19 | 20 | function Detection() { 21 | // const router = useRouter(); 22 | const location = useLocation(); 23 | const [samples, setSamples] = useState<RecordSamplesType>([]); 24 | const [result, setResult] = useState<ResultRowsType>([]); 25 | 26 | useEffect(() => { 27 | // useRouter 中获取 参数会有延迟,所以先判断有没有 id 参数 28 | const realSetId = 29 | new URLSearchParams(location.search).get("id") || "default"; 30 | // const setId = (router.query.id as string) || "default"; 31 | const setId = "default"; 32 | if (setId !== realSetId) return; 33 | 34 | // 查询样本集合 35 | getSampleSet(setId).then((res) => { 36 | if (res.code != 0) { 37 | Message.error("测试集合 " + setId + ": " + res.msg); 38 | return; 39 | } 40 | if (!res.data.data) { 41 | Message.error("测试集合 " + setId + ": 获取结果为空"); 42 | return; 43 | } 44 | setSamples( 45 | res.data.data?.map((i: any) => ({ 46 | id: i.id, 47 | summary: i.summary, 48 | size: i.length, 49 | isAttack: i.tag == "black", 50 | })) 51 | ); 52 | }); 53 | 54 | // 查询样本集合结果 55 | getSampleSetResult(setId).then(({ data, timeout }) => { 56 | if (timeout) { 57 | Message.error("获取检测集结果超时"); 58 | return; 59 | } 60 | setResult( 61 | data.map((i: any) => ({ 62 | engine: i.engine, 63 | version: i.version, 64 | detectionRate: percent(i.recall), 65 | failedRate: percent(i.fdr), 66 | accuracy: percent(i.accuracy), 67 | cost: i.elapsed > 0 ? i.elapsed + " 毫秒" : "小于 1 毫秒", 68 | })) 69 | ); 70 | }); 71 | }, []); 72 | 73 | const handleSetId = (id: string) => { 74 | // router.push({ 75 | // pathname: router.pathname, 76 | // query: { id }, 77 | // }); 78 | }; 79 | 80 | return ( 81 | <Layout title="效果对比 - 长亭雷池 WAF 社区版"> 82 | <ThemeProvider> 83 | <Container sx={{ mt: 2, mb: 2 }}> 84 | <SampleList value={samples} onSetIdChange={handleSetId} /> 85 | <Result rows={result} /> 86 | <Grid 87 | container 88 | spacing={2} 89 | sx={{ mt: 3, mb: 3, color: "text.auxiliary" }} 90 | > 91 | <Grid item md={3}> 92 | <Typography>TP: 正确识别到攻击样本的数量</Typography> 93 | <br /> 94 | <Typography>检出率 = TP / (TP + FN)</Typography> 95 | </Grid> 96 | <Grid item md={3}> 97 | <Typography>TN: 正确识别到普通样本的数量</Typography> 98 | <br /> 99 | <Typography>误报率 = FP / (TP + FP)</Typography> 100 | </Grid> 101 | <Grid item md={3}> 102 | <Typography>FP: 将普通样本误报为攻击的数量</Typography> 103 | <br /> 104 | <Typography>准确率 = (TP + TN) / (TP + TN + FP + FN)</Typography> 105 | </Grid> 106 | <Grid item md={3}> 107 | <Typography>FN: 未识别到攻击样本的数量</Typography> 108 | </Grid> 109 | </Grid> 110 | </Container> 111 | </ThemeProvider> 112 | </Layout> 113 | ); 114 | } 115 | 116 | function percent(v: number) { 117 | return Math.round(v * 10000) / 100 + "%"; 118 | } 119 | -------------------------------------------------------------------------------- /website/src/theme/Footer/Copyright/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | export default function FooterCopyright({ copyright }) { 3 | return ( 4 | <> 5 | <div 6 | className="footer__copyright" 7 | // Developer provided the HTML, so assume it's safe. 8 | // eslint-disable-next-line react/no-danger 9 | dangerouslySetInnerHTML={{ __html: copyright }} 10 | /> 11 | {/* 自定义组件的目的是为了插入 cnzz 统计代码 */} 12 | {process.env.NODE_ENV == "production" && ( 13 | <script 14 | type="text/javascript" 15 | src="https://v1.cnzz.com/z_stat.php?id=1281262430&web_id=1281262430" 16 | /> 17 | )} 18 | </> 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /website/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/.nojekyll -------------------------------------------------------------------------------- /website/static/fonts/iconfont.js: -------------------------------------------------------------------------------- 1 | window._iconfont_svg_string_4031246='<svg><symbol id="icon-bangzhu1" viewBox="0 0 1024 1024"><path d="M512 953.81818174c244.02272695 0 441.81818174-197.79545479 441.81818174-441.81818174C953.81818174 267.97727305 756.02272695 70.18181826 512 70.18181826 267.97727305 70.18181826 70.18181826 267.97727305 70.18181826 512c0 244.02272695 197.79545479 441.81818174 441.81818174 441.81818174z m0-65.45454522a376.36363653 376.36363653 0 1 1 0-752.72727305 376.36363653 376.36363653 0 0 1 0 752.72727305z" ></path><path d="M544.72727305 590.83181826v-5.56363652a90 90 0 0 1 41.1954539-75.64090869C638.69545479 475.59090869 667.45454521 435.5 667.45454521 389.27272695a155.45454521 155.45454521 0 0 0-310.90909042 0 32.72727305 32.72727305 0 1 0 65.45454521 0 90 90 0 1 1 180 0c0 20.37272695-15.62727305 42.17727305-51.54545479 65.37272784a155.45454521 155.45454521 0 0 0-71.18181826 130.62272695v5.56363652a32.72727305 32.72727305 0 1 0 65.4545461 0z" ></path><path d="M512 716.54545479m-40.90909131 0a40.90909131 40.90909131 0 1 0 81.81818262 0 40.90909131 40.90909131 0 1 0-81.81818262 0Z" ></path></symbol><symbol id="icon-duihao" viewBox="0 0 1024 1024"><path d="M515.2 26.66666666c266.496 0 483.2 216.704 483.2 483.2s-216.704 483.2-483.2 483.2S32 776.36266666 32 509.86666666 248.704 26.66666666 515.2 26.66666666z m202.24 380.16a35.2 35.2 0 0 0-49.728 0L470.784 603.62666666 364.48 497.32266666a35.2 35.2 0 0 0-49.792 49.792l131.2 131.2a35.072 35.072 0 0 0 21.952 10.24h6.016l5.888-1.088a35.008 35.008 0 0 0 16-9.152l221.696-221.76a35.2 35.2 0 0 0 0-49.728z" ></path></symbol><symbol id="icon-chahao" viewBox="0 0 1024 1024"><path d="M515.19999998 26.66666665c266.496 0 483.2 216.704 483.2 483.2s-216.704 483.2-483.2 483.2S31.99999998 776.36266665 31.99999998 509.86666665 248.70399998 26.66666665 515.19999998 26.66666665zM407.61599998 352.49066665a35.2 35.2 0 0 0-49.792 49.792L466.55999998 510.89066665 357.82399998 619.49866665a35.2 35.2 0 1 0 49.792 49.792l108.608-108.672 108.608 108.672a35.2 35.2 0 1 0 49.792-49.792L565.95199998 510.89066665l108.672-108.608a35.2 35.2 0 1 0-49.792-49.792L516.22399998 461.22666665z" ></path></symbol></svg>',function(n){var t=(t=document.getElementsByTagName("script"))[t.length-1],e=t.getAttribute("data-injectcss"),t=t.getAttribute("data-disable-injectsvg");if(!t){var o,a,i,c,d,s=function(t,e){e.parentNode.insertBefore(t,e)};if(e&&!n.__iconfont__svg__cssinject__){n.__iconfont__svg__cssinject__=!0;try{document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")}catch(t){console&&console.log(t)}}o=function(){var t,e=document.createElement("div");e.innerHTML=n._iconfont_svg_string_4031246,(e=e.getElementsByTagName("svg")[0])&&(e.setAttribute("aria-hidden","true"),e.style.position="absolute",e.style.width=0,e.style.height=0,e.style.overflow="hidden",e=e,(t=document.body).firstChild?s(e,t.firstChild):t.appendChild(e))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(o,0):(a=function(){document.removeEventListener("DOMContentLoaded",a,!1),o()},document.addEventListener("DOMContentLoaded",a,!1)):document.attachEvent&&(i=o,c=n.document,d=!1,r(),c.onreadystatechange=function(){"complete"==c.readyState&&(c.onreadystatechange=null,l())})}function l(){d||(d=!0,i())}function r(){try{c.documentElement.doScroll("left")}catch(t){return void setTimeout(r,50)}l()}}(window); -------------------------------------------------------------------------------- /website/static/images/album/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/album/0.png -------------------------------------------------------------------------------- /website/static/images/album/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/album/1.png -------------------------------------------------------------------------------- /website/static/images/album/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/album/2.png -------------------------------------------------------------------------------- /website/static/images/album/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/album/3.png -------------------------------------------------------------------------------- /website/static/images/album/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/album/4.png -------------------------------------------------------------------------------- /website/static/images/album/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/album/5.png -------------------------------------------------------------------------------- /website/static/images/album/block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/album/block.png -------------------------------------------------------------------------------- /website/static/images/class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/class.png -------------------------------------------------------------------------------- /website/static/images/docs/DNS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/DNS.png -------------------------------------------------------------------------------- /website/static/images/docs/LoadBlance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/LoadBlance.png -------------------------------------------------------------------------------- /website/static/images/docs/Untitled10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/Untitled10.png -------------------------------------------------------------------------------- /website/static/images/docs/Untitled11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/Untitled11.png -------------------------------------------------------------------------------- /website/static/images/docs/Untitled12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/Untitled12.png -------------------------------------------------------------------------------- /website/static/images/docs/Untitled13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/Untitled13.png -------------------------------------------------------------------------------- /website/static/images/docs/about_changelog/acl_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/about_changelog/acl_page.png -------------------------------------------------------------------------------- /website/static/images/docs/about_changelog/api_assets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/about_changelog/api_assets.png -------------------------------------------------------------------------------- /website/static/images/docs/about_changelog/api_assets_collect1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/about_changelog/api_assets_collect1.png -------------------------------------------------------------------------------- /website/static/images/docs/about_changelog/api_assets_collect2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/about_changelog/api_assets_collect2.png -------------------------------------------------------------------------------- /website/static/images/docs/about_changelog/cert_create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/about_changelog/cert_create.png -------------------------------------------------------------------------------- /website/static/images/docs/about_changelog/cs_statistics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/about_changelog/cs_statistics.png -------------------------------------------------------------------------------- /website/static/images/docs/about_changelog/forbidden_page_ext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/about_changelog/forbidden_page_ext.png -------------------------------------------------------------------------------- /website/static/images/docs/about_changelog/log_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/about_changelog/log_detail.png -------------------------------------------------------------------------------- /website/static/images/docs/about_changelog/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/about_changelog/map.png -------------------------------------------------------------------------------- /website/static/images/docs/about_changelog/mgt_cert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/about_changelog/mgt_cert.png -------------------------------------------------------------------------------- /website/static/images/docs/about_changelog/mgt_cert_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/about_changelog/mgt_cert_config.png -------------------------------------------------------------------------------- /website/static/images/docs/about_changelog/site_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/about_changelog/site_config.png -------------------------------------------------------------------------------- /website/static/images/docs/about_changelog/website_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/about_changelog/website_1.png -------------------------------------------------------------------------------- /website/static/images/docs/about_changelog/website_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/about_changelog/website_2.png -------------------------------------------------------------------------------- /website/static/images/docs/add_challenge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/add_challenge.png -------------------------------------------------------------------------------- /website/static/images/docs/challenge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/challenge.png -------------------------------------------------------------------------------- /website/static/images/docs/config_access_log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/config_access_log.png -------------------------------------------------------------------------------- /website/static/images/docs/fake_host.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/fake_host.jpg -------------------------------------------------------------------------------- /website/static/images/docs/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/flow.png -------------------------------------------------------------------------------- /website/static/images/docs/framework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/framework.png -------------------------------------------------------------------------------- /website/static/images/docs/get_source_ip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/get_source_ip.png -------------------------------------------------------------------------------- /website/static/images/docs/guide_config/deploy_on_separate_server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/guide_config/deploy_on_separate_server.png -------------------------------------------------------------------------------- /website/static/images/docs/guide_config/deploy_on_web_server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/guide_config/deploy_on_web_server.png -------------------------------------------------------------------------------- /website/static/images/docs/guide_config/deploy_origin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/guide_config/deploy_origin.png -------------------------------------------------------------------------------- /website/static/images/docs/guide_config/deploy_with_other_server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/guide_config/deploy_with_other_server.png -------------------------------------------------------------------------------- /website/static/images/docs/guide_config/tengine_502.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/guide_config/tengine_502.png -------------------------------------------------------------------------------- /website/static/images/docs/guide_install/collie_apps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/guide_install/collie_apps.png -------------------------------------------------------------------------------- /website/static/images/docs/guide_introduction/website_with_safeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/guide_introduction/website_with_safeline.png -------------------------------------------------------------------------------- /website/static/images/docs/guide_introduction/website_without_safeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/guide_introduction/website_without_safeline.png -------------------------------------------------------------------------------- /website/static/images/docs/manual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/manual.png -------------------------------------------------------------------------------- /website/static/images/docs/practice_monitor/gift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/practice_monitor/gift.png -------------------------------------------------------------------------------- /website/static/images/docs/practice_monitor/machineid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/practice_monitor/machineid.png -------------------------------------------------------------------------------- /website/static/images/docs/practice_monitor/website.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/practice_monitor/website.png -------------------------------------------------------------------------------- /website/static/images/docs/safeline_https_website.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/safeline_https_website.gif -------------------------------------------------------------------------------- /website/static/images/docs/server_index01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/server_index01.png -------------------------------------------------------------------------------- /website/static/images/docs/server_index02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/docs/server_index02.png -------------------------------------------------------------------------------- /website/static/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/favicon.ico -------------------------------------------------------------------------------- /website/static/images/feature.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <svg width="61px" height="68px" viewBox="0 0 61 68" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 3 | <title>编组 4备份 4 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /website/static/images/gif/config_site.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/gif/config_site.gif -------------------------------------------------------------------------------- /website/static/images/gif/detect_log.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/gif/detect_log.gif -------------------------------------------------------------------------------- /website/static/images/gif/login.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/gif/login.gif -------------------------------------------------------------------------------- /website/static/images/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/github.png -------------------------------------------------------------------------------- /website/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/logo.png -------------------------------------------------------------------------------- /website/static/images/qq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/qq.png -------------------------------------------------------------------------------- /website/static/images/safeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/safeline.png -------------------------------------------------------------------------------- /website/static/images/wechat-230717.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/wechat-230717.png -------------------------------------------------------------------------------- /website/static/images/wechat-230825.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/wechat-230825.png -------------------------------------------------------------------------------- /website/static/images/wechat-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/wechat-light.png -------------------------------------------------------------------------------- /website/static/images/wechat-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/wechat-logo.png -------------------------------------------------------------------------------- /website/static/images/wechat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jangrui/SafeLine/7bcb09197d93c5b045dd37d58fb456cfcc631b7e/website/static/images/wechat.png -------------------------------------------------------------------------------- /website/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@tsconfig/docusaurus/tsconfig.json", 4 | "compilerOptions": { 5 | "baseUrl": "." 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /yanshi/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.dot 3 | *.output 4 | /build 5 | /src/parser.cc 6 | /src/parser.hh 7 | /src/lexer.cc 8 | /src/lexer.hh 9 | -------------------------------------------------------------------------------- /yanshi/Makefile: -------------------------------------------------------------------------------- 1 | CPPFLAGS := -g3 -std=c++1y -Isrc -I. -DHAVE_READLINE 2 | 3 | ifeq ($(build),release) 4 | BUILD := release 5 | CPPFLAGS += -Os 6 | else 7 | BUILD := build 8 | CPPFLAGS += -fsanitize=undefined,address -DDEBUG 9 | LDLIBS := -lasan -lubsan 10 | endif 11 | 12 | LDLIBS += -licuuc -lreadline 13 | SRC := $(filter-out src/lexer.cc src/parser.cc, $(wildcard src/*.cc)) src/lexer.cc src/parser.cc 14 | OBJ := $(addprefix $(BUILD)/,$(subst src/,,$(SRC:.cc=.o))) 15 | UNITTEST_SRC := $(wildcard unittest/*.cc) 16 | UNITTEST_EXE := $(subst unittest/,,$(UNITTEST_SRC:.cc=)) 17 | 18 | all: $(BUILD)/yanshi # unittest 19 | 20 | unittest: $(addprefix $(BUILD)/unittest/,$(UNITTEST_EXE)) 21 | $(foreach x,$(addprefix $(BUILD)/unittest/,$(UNITTEST_EXE)),$x && ) : 22 | 23 | sinclude $(OBJ:.o=.d) 24 | 25 | # FIXME 26 | $(BUILD)/repl.o: src/lexer.hh 27 | 28 | $(BUILD) $(BUILD)/unittest: 29 | mkdir -p $@ 30 | 31 | $(BUILD)/yanshi: $(OBJ) 32 | $(LINK.cc) $^ $(LDLIBS) -o $@ 33 | 34 | $(BUILD)/%.o: src/%.cc | $(BUILD) 35 | $(CXX) $(CPPFLAGS) -MM -MP -MT $@ -MF $(@:.o=.d) $< 36 | $(COMPILE.cc) $< -o $@ 37 | 38 | $(BUILD)/unittest/%: unittest/%.cc $(wildcard unittest/*.hh) $(filter-out $(BUILD)/main.o,$(OBJ)) | $(BUILD)/unittest 39 | $(CXX) $(CPPFLAGS) -MM -MP -MT $@ -MF $(@:.o=.d) $< 40 | $(LINK.cc) $(filter-out %.hh,$^) $(LDLIBS) -o $@ 41 | 42 | src/lexer.cc src/lexer.hh: src/lexer.l 43 | flex --header-file=src/lexer.hh -o src/lexer.cc $< 44 | 45 | src/parser.cc src/parser.hh: src/parser.y src/common.hh src/location.hh src/option.hh src/syntax.hh 46 | bison --defines=src/parser.hh -o src/parser.cc $< 47 | 48 | $(BUILD)/loader.o: src/parser.hh 49 | $(BUILD)/parser.o: src/lexer.hh 50 | $(BUILD)/lexer.o: src/parser.hh 51 | 52 | clean: 53 | $(RM) -r build release 54 | 55 | distclean: clean 56 | $(RM) src/{lexer,parser}.{cc,hh} 57 | 58 | .PHONY: all clean distclean 59 | -------------------------------------------------------------------------------- /yanshi/contrib/vim/compiler/yanshi.vim: -------------------------------------------------------------------------------- 1 | "if exists('current_compiler') 2 | " finish 3 | "endif 4 | let current_compiler = 'yanshi' 5 | 6 | if exists(':CompilerSet') != 2 7 | command -nargs=* CompilerSet setlocal 8 | endif 9 | CompilerSet errorformat= 10 | \%E%f\ %l:%c-%*\\d\ error\ %m, 11 | \%E%f\ %l-%*\\d:%c-%*\\d\ error\ %m, 12 | \%W%f\ %l:%c-%*\\d\ warning\ %m, 13 | \%W%f\ %l-%*\\d:%c-%*\\d\ warning\ %m, 14 | \%C%.%# 15 | CompilerSet makeprg=yanshi\ -d0\ -c\ $*\ % 16 | -------------------------------------------------------------------------------- /yanshi/contrib/vim/ftdetect/yanshi.vim: -------------------------------------------------------------------------------- 1 | au BufRead,BufNewFile *.yanshi setf yanshi 2 | au BufRead,BufNewFile *.ys setf yanshi 3 | -------------------------------------------------------------------------------- /yanshi/contrib/vim/ftplugin/yanshi.vim: -------------------------------------------------------------------------------- 1 | if exists('b:did_ftplugin') 2 | finish 3 | endif 4 | let b:did_ftplugin = 1 5 | 6 | compiler yanshi 7 | -------------------------------------------------------------------------------- /yanshi/contrib/vim/syntax/yanshi.vim: -------------------------------------------------------------------------------- 1 | if exists('b:current_syntax') 2 | finish 3 | endif 4 | 5 | syn cluster yanshiCommentGroup contains=yanshiTodo 6 | syn include @yanshiCcode syntax/cpp.vim 7 | syn keyword yanshiAction action 8 | syn keyword yanshiMacro semicolon nosemicolon 9 | syn keyword yanshiStorageClass export intact 10 | syn keyword yanshiTodo contained TODO FIXME XXX 11 | syn match yanshiCpp 'c++' 12 | syn match yanshiActionOperator '[>$@%]' 13 | syn match yanshiCall '\^\w\+\(::\w\+\)\?' 14 | syn match yanshiCollapse '!\w\+\(::\w\+\)\?' 15 | syn match yanshiHighOp '[+\*?]' 16 | syn match yanshiIdent '\w\+\(::\w\+\)\?' 17 | syn match yanshiCpp display "^c++\s*" skipwhite nextgroup=yanshiBrace 18 | syn match yanshiImport display "^import\s*" contains=yanshiImported 19 | syn match yanshiLowOp '[-&|]' 20 | syn match yanshiSpecial display contained "\\\(x\x\x\|.\|$\)" 21 | syn region yanshiBrace matchgroup=Delimiter start='{' end='}' fold contains=@yanshiCcode 22 | syn region yanshiBracket start='\[' skip=+\\\\\|\\]+ end=']' 23 | syn region yanshiComment start='/\*' end='\*/' keepend contains=@yanshiCommentGroup,@Spell 24 | syn region yanshiImported display contained start="+" skip=+\\\\\|\\"+ end=+"+ 25 | syn region yanshiLineComment start='#\|//' skip='\\$' end='$' keepend contains=@yanshiCommentGroup,@Spell 26 | syn region yanshiPreprocess start="#define" skip="\\$" end="$" keepend 27 | syn region yanshiQQString start=+"+ skip=+\\.+ end=+"+ contains=yanshiSpecial 28 | syn region yanshiQString start=+'+ skip=+\\.+ end=+'+ 29 | 30 | syn region yanshiDefineStmt start='^\w\+\s*[=:]' end='$' skipnl contains=@yanshiExpr,yanshiComment,yanshiLineComment,yanshiParen0 31 | 32 | syn cluster yanshiExpr contains=yanshiActionOperator,yanshiBrace,yanshiBracket,yanshiCall,yanshiCollapse,yanshiIdent,yanshiHighOp,yanshiLowOp,yanshiQString,yanshiQQString, 33 | sy region yanshiParen0 matchgroup=yanshiParen0 start='(' end=')' contains=@yanshiExpr,yanshiParen1 34 | sy region yanshiParen1 matchgroup=yanshiParen1 start='(' end=')' contains=@yanshiExpr,yanshiParen2 contained 35 | sy region yanshiParen2 matchgroup=yanshiParen2 start='(' end=')' contains=@yanshiExpr,yanshiParen3 contained 36 | sy region yanshiParen3 matchgroup=yanshiParen3 start='(' end=')' contains=@yanshiExpr,yanshiParen4 contained 37 | sy region yanshiParen4 matchgroup=yanshiParen4 start='(' end=')' contains=@yanshiExpr,yanshiParen5 contained 38 | sy region yanshiParen5 matchgroup=yanshiParen5 start='(' end=')' contains=@yanshiExpr,yanshiParen0 contained 39 | hi yanshiParen0 ctermfg=brown guifg=#3bb9ff 40 | hi yanshiParen1 ctermfg=DarkBlue guifg=#f88017 41 | hi yanshiParen2 ctermfg=darkgray guifg=#5efb6e 42 | hi yanshiParen3 ctermfg=darkgreen guifg=#f62817 43 | hi yanshiParen4 ctermfg=darkcyan guifg=#fdd017 44 | hi yanshiParen5 ctermfg=darkmagenta guifg=#faafba 45 | 46 | hi link yanshiIdent Identifier 47 | "TODO color mismatch of {} 48 | "hi link yanshiBrace Statement 49 | "hi link yanshiDefineStmt Statement 50 | hi def link yanshiCall Constant 51 | hi def link yanshiCollapse Constant 52 | hi def link yanshiAction Structure 53 | hi def link yanshiActionOperator Type 54 | hi def link yanshiBracket Function 55 | hi def link yanshiCpp Structure 56 | hi def link yanshiComment Comment 57 | hi def link yanshiHighOp Operator 58 | hi def link yanshiImport Include 59 | hi def link yanshiImported String 60 | hi def link yanshiLineComment Comment 61 | hi def link yanshiLowOp Conditional 62 | hi def link yanshiMacro Macro 63 | hi def link yanshiPreprocess Macro 64 | hi def link yanshiQQString String 65 | hi def link yanshiQString String 66 | hi def link yanshiSpecial SpecialChar 67 | hi def link yanshiStorageClass StorageClass 68 | hi def link yanshiTodo Todo 69 | 70 | let b:current_syntax = 'yanshi' 71 | -------------------------------------------------------------------------------- /yanshi/contrib/vim/syntax_checkers/yanshi/yanshi.vim: -------------------------------------------------------------------------------- 1 | if exists('g:loaded_syntastic_yanshi_yanshi_checker') 2 | finish 3 | endif 4 | let g:loaded_syntastic_yanshi_yanshi_checker = 1 5 | 6 | let s:save_cpo = &cpo 7 | set cpo&vim 8 | 9 | fu! SyntaxCheckers_yanshi_yanshi_GetLocList() dict 10 | let makeprg = self.makeprgBuild({ 'args': '-d0 -c' }) 11 | 12 | let errorformat = 13 | \ '%C %.%#,'. 14 | \ '%E%f %l:%c-%*\d error %m,'. 15 | \ '%E%f %l-%*\d:%c-%*\d error %m,'. 16 | \ '%W%f %l:%c-%*\d warning %m,'. 17 | \ '%W%f %l-%*\d:%c-%*\d warning %m' 18 | 19 | return SyntasticMake({ 20 | \ 'makeprg': makeprg, 21 | \ 'errorformat': errorformat }) 22 | endf 23 | 24 | call g:SyntasticRegistry.CreateAndRegisterChecker({ 25 | \ 'filetype': 'yanshi', 26 | \ 'name': 'yanshi'}) 27 | 28 | let &cpo = s:save_cpo 29 | unlet s:save_cpo 30 | -------------------------------------------------------------------------------- /yanshi/contrib/zsh/_yanshi: -------------------------------------------------------------------------------- 1 | #compdef yanshi 2 | 3 | _arguments \ 4 | '(-b --bytes)'{-b,--bytes}'[make labels range over \[0,256), Unicode literals will be treated as UTF-8 bytes]' \ 5 | '(-c --check)'{-c,--check}'[check syntax & use/def]' \ 6 | '-C[generate C source code (default: C++)]' \ 7 | '(-d --debug)'{-d,--debug}'+[debug level]:level:(0 1 2 3 4 5)' \ 8 | '--dump-action[dump associated actions for each edge]' \ 9 | '--dump-assoc[dump associated AST Expr for each state]' \ 10 | '--dump-automaton[dump automata]' \ 11 | '--dump-embed[dump statistics of EmbedExpr]' \ 12 | '--dump-module[dump module use/def/...]' \ 13 | '--dump-tree[dump AST]' \ 14 | '(-G --graph)'{-G,--graph}'[output a Graphviz dot file]' \ 15 | '(-I --import)'{-I,--import}'=[add to search path for "import"]' \ 16 | '(-i --interactive)'{-i,--interactive}'[interactive mode]' \ 17 | '(-k --keep-inaccessible)'{-k,--keep-inaccessible}'[do not perform accessible/co-accessible]' \ 18 | '(-l --debug-output)'{-l,--debug-output}'=[filename for debug output]:file:_files' \ 19 | '--max-return-stack=[max length of return stack in C generator]:len:' \ 20 | '(-o --output)'{-o,--output}'=[.cc output filename]:file:_files' \ 21 | '(-O --output-header)'{-O,--output-header}'=[.hh output filename]:file:_files' \ 22 | '(-s --substring-grammar)'{-s,--substring-grammar}'[construct regular approximation of the substring grammar. Inner states of nonterminals labeled 'intact' are not connected to start/final]' \ 23 | '(-h --help)'{-h,--help}'[display this help]' \ 24 | '1:file:_files -g "*.{ys,yanshi}"'\ 25 | -------------------------------------------------------------------------------- /yanshi/src/common.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef _GNU_SOURCE 3 | # define _GNU_SOURCE 4 | #endif 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | using std::map; 13 | using std::vector; 14 | 15 | typedef int8_t i8; 16 | typedef int16_t i16; 17 | typedef int32_t i32; 18 | typedef int64_t i64; 19 | typedef uint8_t u8; 20 | typedef uint16_t u16; 21 | typedef uint32_t u32; 22 | typedef uint64_t u64; 23 | typedef unsigned long ulong; 24 | 25 | #ifdef __APPLE__ 26 | #include 27 | extern char*** _NSGetArgv(void); 28 | #define program_invocation_name (((char **)*_NSGetArgv())[0]) 29 | #define program_invocation_short_name (((char **)*_NSGetArgv())[0]) 30 | #endif 31 | 32 | #define LEN(x) (sizeof(x)/sizeof(*x)) 33 | #define ALL(x) (x).begin(), (x).end() 34 | #define REP(i, n) FOR(i, 0, n) 35 | #define FOR(i, a, b) for (typename std::remove_cv::type>::type i = (a); i < (b); i++) 36 | #define ROF(i, a, b) for (typename std::remove_cv::type>::type i = (b); --i >= (a); ) 37 | 38 | #define SGR0 "\x1b[m" 39 | #define RED "\x1b[1;31m" 40 | #define GREEN "\x1b[1;32m" 41 | #define YELLOW "\x1b[1;33m" 42 | #define BLUE "\x1b[1;34m" 43 | #define MAGENTA "\x1b[1;35m" 44 | #define CYAN "\x1b[1;36m" 45 | #define NORMAL_YELLOW "\x1b[33m" 46 | const long MAX_CODEPOINT = 0x10ffff; 47 | extern long action_label_base, action_label, call_label_base, call_label, collapse_label_base, collapse_label; 48 | 49 | void bold(long fd = 1); 50 | void blue(long fd = 1); 51 | void cyan(long fd = 1); 52 | void green(long fd = 1); 53 | void magenta(long fd = 1); 54 | void red(long fd = 1); 55 | void sgr0(long fd = 1); 56 | void yellow(long fd = 1); 57 | void normal_yellow(long fd = 1); 58 | void indent(FILE* f, int d); 59 | 60 | const size_t BUF_SIZE = 512; 61 | 62 | void output_error(bool use_err, const char *format, va_list ap); 63 | void err_msg(const char *format, ...); 64 | void err_exit(int exitno, const char *format, ...); 65 | 66 | long get_long(const char *arg); 67 | 68 | void log_generic(const char *prefix, const char *format, va_list ap); 69 | void log_event(const char *format, ...); 70 | void log_action(const char *format, ...); 71 | void log_status(const char *format, ...); 72 | 73 | extern long debug_level; 74 | extern FILE* debug_file; 75 | #define DP(level, ...) do { \ 76 | if (level <= debug_level) { \ 77 | fprintf(debug_file, "%s:%d ", __FILE__, __LINE__); \ 78 | fprintf(debug_file, __VA_ARGS__);\ 79 | fprintf(debug_file, "\n"); \ 80 | fflush(debug_file); \ 81 | } \ 82 | } while (0) 83 | 84 | template 85 | void emplace_front(vector& a, Args&&... args) 86 | { 87 | a.emplace(a.begin(), args...); 88 | } 89 | 90 | template 91 | void sorted_insert(vector& a, const T& x) 92 | { 93 | a.emplace_back(); 94 | auto it = a.end(); 95 | while (a.begin() != --it && x < it[-1]) 96 | *it = it[-1]; 97 | *it = x; 98 | } 99 | 100 | template 101 | void sorted_emplace(vector& a, Args&&... args) 102 | { 103 | T x{args...}; 104 | a.emplace_back(); 105 | auto it = a.end(); 106 | while (a.begin() != --it && x < it[-1]) 107 | *it = it[-1]; 108 | *it = x; 109 | } 110 | 111 | struct DisjointIntervals 112 | { 113 | typedef std::pair value_type; 114 | std::map to; 115 | template 116 | void emplace(Args&&... args) { 117 | value_type x{args...}; 118 | auto it = to.lower_bound(x.first); 119 | if (it != to.begin() && x.first <= prev(it)->second) 120 | x.first = (--it)->first; 121 | auto it2 = to.upper_bound(x.second); 122 | if (it2 != to.begin() && prev(it2)->first <= x.second && x.second < prev(it2)->second) 123 | x.second = prev(it2)->second; 124 | while (it != it2) 125 | it = to.erase(it); 126 | to.emplace(x); 127 | } 128 | void flip(); 129 | void print(); // XXX 130 | }; 131 | -------------------------------------------------------------------------------- /yanshi/src/compiler.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "fsa_anno.hh" 3 | #include "syntax.hh" 4 | 5 | #include 6 | using std::unordered_map; 7 | 8 | void print_assoc(const FsaAnno& anno); 9 | void print_automaton(const Fsa& fsa); 10 | void compile(DefineStmt*); 11 | bool compile_export(DefineStmt* stmt); 12 | void generate_cxx(Module* mo); 13 | void generate_graphviz(Module* mo); 14 | extern unordered_map compiled; 15 | -------------------------------------------------------------------------------- /yanshi/src/fsa.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | using std::function; 6 | using std::pair; 7 | using std::vector; 8 | 9 | typedef pair Label; 10 | typedef pair Edge; 11 | 12 | const Label epsilon{-1L, 0L}; 13 | 14 | struct Fsa { 15 | long start; 16 | vector finals; // sorted 17 | vector> adj; // sorted 18 | 19 | void check() const; 20 | long n() const { return adj.size(); } 21 | bool is_final(long x) const; 22 | bool has(long u, long c) const; 23 | bool has_call(long u) const; 24 | bool has_call_or_collapse(long u) const; 25 | long transit(long u, long c) const; 26 | void epsilon_closure(vector& src) const; 27 | Fsa operator~() const; 28 | // a -> a 29 | void accessible(const vector* starts, function relate); 30 | // a -> a 31 | void co_accessible(const vector* final, function relate); 32 | // DFA -> DFA -> DFA 33 | Fsa intersect(const Fsa& rhs, function relate) const; 34 | // DFA -> DFA -> DFA 35 | Fsa difference(const Fsa& rhs, function relate) const; 36 | // DFA -> DFA 37 | Fsa distinguish(function&)> relate) const; 38 | // * -> DFA 39 | Fsa determinize(const vector* starts, function&)> relate) const; 40 | }; 41 | -------------------------------------------------------------------------------- /yanshi/src/fsa_anno.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "fsa.hh" 3 | #include "syntax.hh" 4 | 5 | enum class ExprTag { 6 | start = 1, 7 | inner = 2, 8 | final = 4, 9 | }; 10 | 11 | extern inline bool has_start(ExprTag x) { return long(x) & long(ExprTag::start); } 12 | extern inline bool has_inner(ExprTag x) { return long(x) & long(ExprTag::inner); } 13 | extern inline bool has_final(ExprTag x) { return long(x) & long(ExprTag::final); } 14 | 15 | bool operator<(ExprTag x, ExprTag y); 16 | bool assoc_has_expr(vector>& as, const Expr* x); 17 | 18 | struct FsaAnno { 19 | bool deterministic; 20 | Fsa fsa; 21 | vector>> assoc; 22 | void accessible(const vector* starts, vector& mapping); 23 | void add_assoc(Expr& expr); 24 | void complement(ComplementExpr* expr); 25 | void co_accessible(const vector* final, vector& mapping); 26 | void concat(FsaAnno& rhs, ConcatExpr* expr); 27 | void determinize(const vector* starts, vector>* mapping); 28 | void difference(FsaAnno& rhs, DifferenceExpr* expr); 29 | void intersect(FsaAnno& rhs, IntersectExpr* expr); 30 | void minimize(vector>* mapping); 31 | void plus(PlusExpr* expr); 32 | void question(QuestionExpr* expr); 33 | void repeat(RepeatExpr& expr); 34 | void star(StarExpr* expr); 35 | void substring_grammar(); 36 | void union_(FsaAnno& rhs, UnionExpr* expr); 37 | static FsaAnno bracket(BracketExpr& expr); 38 | static FsaAnno call(CallExpr& expr); 39 | static FsaAnno collapse(CollapseExpr& expr); 40 | static FsaAnno dot(DotExpr* expr); 41 | static FsaAnno embed(EmbedExpr& expr); 42 | static FsaAnno epsilon_fsa(EpsilonExpr* expr); 43 | static FsaAnno literal(LiteralExpr& expr); 44 | }; 45 | -------------------------------------------------------------------------------- /yanshi/src/lexer_helper.cc: -------------------------------------------------------------------------------- 1 | #include "common.hh" 2 | 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | char* aprintf(const char* fmt, ...) 8 | { 9 | va_list va; 10 | va_start(va, fmt); 11 | char* r = NULL; 12 | vasprintf(&r, fmt, va); 13 | va_end(va); 14 | return r; 15 | } 16 | -------------------------------------------------------------------------------- /yanshi/src/lexer_helper.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | char* aprintf(const char* fmt, ...) 4 | __attribute__((format(printf, 1, 2))); 5 | -------------------------------------------------------------------------------- /yanshi/src/loader.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "syntax.hh" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | using std::map; 10 | using std::set; 11 | using std::string; 12 | using std::unordered_map; 13 | using std::vector; 14 | 15 | enum ModuleStatus { UNPROCESSED = 0, BAD, GOOD }; 16 | 17 | struct Module { 18 | ModuleStatus status; 19 | LocationFile locfile; 20 | string filename; 21 | Stmt* toplevel; 22 | unordered_map defined; 23 | vector unqualified_import; 24 | unordered_map qualified_import; 25 | unordered_map defined_action; 26 | unordered_map macro; 27 | }; 28 | 29 | Stmt* resolve(Module& mo, const string qualified, const string& ident); 30 | long load(const string& filename); 31 | Module* load_module(long& n_errors, const string& filename); 32 | void unload_all(); 33 | extern Module* main_module; 34 | extern FILE *output, *output_header; 35 | extern map> used_as_call, used_as_collapse, used_as_embed; 36 | -------------------------------------------------------------------------------- /yanshi/src/location.cc: -------------------------------------------------------------------------------- 1 | #include "common.hh" 2 | #include "location.hh" 3 | 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | LocationFile::LocationFile(const string& filename, const string& data) : filename(filename), data(data) 9 | { 10 | // data ends with '\n' 11 | long nlines = count(data.begin(), data.end(), '\n'); 12 | linemap.assign(nlines+1, 0); 13 | long line = 1; 14 | for (long i = 0; i < data.size(); i++) 15 | if (data[i] == '\n') 16 | linemap[line++] = i+1; 17 | } 18 | 19 | void LocationFile::context(const Location& loc) const 20 | { 21 | long line1, col1, line2, col2; 22 | locate(loc, line1, col1, line2, col2); 23 | if (line1 == line2) { 24 | fputs(" ", stderr); 25 | FOR(i, linemap[line1], line1+1 < linemap.size() ? linemap[line1+1] : data.size()) { 26 | if (i == loc.start) 27 | magenta(); 28 | fputc(data[i], stderr); 29 | if (i+1 == loc.end) 30 | sgr0(); 31 | } 32 | } else { 33 | bool first = true; 34 | fputs(" ", stderr); 35 | FOR(i, linemap[line1], linemap[line1+1]) { 36 | if (i == loc.start) 37 | magenta(); 38 | fputc(data[i], stderr); 39 | } 40 | if (line2-line1 < 8) { 41 | FOR(i, linemap[line1+1], linemap[line2]) { 42 | if (first) { first = false; fputs(" ", stderr); } 43 | fputc(data[i], stderr); 44 | if (data[i] == '\n') first = true; 45 | } 46 | } else { 47 | FOR(i, linemap[line1+1], linemap[line1+4]) { 48 | if (first) { first = false; fputs(" ", stderr); } 49 | fputc(data[i], stderr); 50 | if (data[i] == '\n') first = true; 51 | } 52 | fputs(" ........\n", stderr); 53 | FOR(i, linemap[line2-3], linemap[line2]) { 54 | if (first) { first = false; fputs(" ", stderr); } 55 | fputc(data[i], stderr); 56 | if (data[i] == '\n') first = true; 57 | } 58 | } 59 | FOR(i, linemap[line2], line2+1 < linemap.size() ? linemap[line2+1] : data.size()) { 60 | if (first) { first = false; fputs(" ", stderr); } 61 | fputc(data[i], stderr); 62 | if (i+1 == loc.end) 63 | sgr0(); 64 | } 65 | } 66 | } 67 | 68 | void LocationFile::locate(const Location& loc, long& line1, long& col1, long& line2, long& col2) const 69 | { 70 | line1 = upper_bound(ALL(linemap), loc.start) - linemap.begin() - 1; 71 | line2 = upper_bound(ALL(linemap), max(loc.end-1, 0L)) - linemap.begin() - 1; 72 | col1 = loc.start - linemap[line1]; 73 | col2 = loc.end - linemap[line2]; 74 | } 75 | 76 | void LocationFile::report_location(const Location& loc) const 77 | { 78 | long line1, col1, line2, col2; 79 | locate(loc, line1, col1, line2, col2); 80 | yellow(2); 81 | fprintf(stderr, "%s ", filename.c_str()); 82 | cyan(2); 83 | if (line1 == line2) 84 | fprintf(stderr, "%ld:%ld-%ld ", line1+1, col1+1, col2); 85 | else 86 | fprintf(stderr, "%ld-%ld:%ld-%ld ", line1+1, line2+1, col1+1, col2); 87 | } 88 | 89 | void LocationFile::error(const Location& loc, const char* fmt, ...) const 90 | { 91 | report_location(loc); 92 | red(2); 93 | fprintf(stderr, "error "); 94 | va_list va; 95 | va_start(va, fmt); 96 | vfprintf(stderr, fmt, va); 97 | va_end(va); 98 | fputs("\n", stderr); 99 | sgr0(2); 100 | } 101 | 102 | void LocationFile::warning(const Location& loc, const char* fmt, ...) const 103 | { 104 | report_location(loc); 105 | yellow(2); 106 | fprintf(stderr, "warning "); 107 | va_list va; 108 | va_start(va, fmt); 109 | vfprintf(stderr, fmt, va); 110 | va_end(va); 111 | fputs("\n", stderr); 112 | sgr0(2); 113 | } 114 | -------------------------------------------------------------------------------- /yanshi/src/location.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common.hh" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct Location { long start, end; }; 9 | 10 | struct LocationFile { 11 | std::string filename, data; 12 | std::vector linemap; 13 | 14 | LocationFile() = default; 15 | LocationFile(const std::string& filename, const std::string& data); 16 | LocationFile& operator=(const LocationFile&) = default; 17 | void context(const Location& loc) const; 18 | void locate(const Location& loc, long& line1, long& col1, long& line2, long& col2) const; 19 | void report_location(const Location& loc) const; 20 | void error(const Location& loc, const char* fmt, ...) const; 21 | void warning(const Location& loc, const char* fmt, ...) const; 22 | template 23 | void error_context(const Location& loc, const char* fmt, Args&&... args) const { 24 | error(loc, fmt, std::forward(args)...); 25 | context(loc); 26 | } 27 | template 28 | void warning_context(const Location& loc, const char* fmt, Args&&... args) const { 29 | warning(loc, fmt, std::forward(args)...); 30 | context(loc); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /yanshi/src/main.cc: -------------------------------------------------------------------------------- 1 | #include "common.hh" 2 | #include "fsa.hh" 3 | #include "loader.hh" 4 | #include "option.hh" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | using namespace std; 16 | 17 | void print_help(FILE *fh) 18 | { 19 | fprintf(fh, "Usage: %s [OPTIONS] dir\n", program_invocation_short_name); 20 | fputs( 21 | "\n" 22 | "Options:\n" 23 | " -b,--bytes make labels range over [0,256), Unicode literals will be treated as UTF-8 bytes\n" 24 | " -C generate C source code (default: C++)\n" 25 | " --check check syntax & use/def\n" 26 | " --debug debug level\n" 27 | " --debug-output filename for debug output\n" 28 | " --dump-action dump associated actions for each edge\n" 29 | " --dump-assoc dump associated AST Expr for each state\n" 30 | " --dump-automaton dump automata\n" 31 | " --dump-embed dump statistics of EmbedExpr\n" 32 | " --dump-module dump module use/def/...\n" 33 | " --dump-tree dump AST\n" 34 | " --extern-c generate extern \"C\" specifier\n" 35 | " -G,--graph output a Graphviz dot file\n" 36 | " -I,--import add to search path for 'import'\n" 37 | " -i,--interactive interactive mode\n" 38 | " --max-return-stack max length of return stack in C generator (default: 100)\n" 39 | " -k,--keep-inaccessible do not perform accessible/co-accessible\n" 40 | " -S,--standalone generate header and 'main()'\n" 41 | " --substring-grammar construct regular approximation of the substring grammar. Inner states of nonterminals labeled 'intact' are not connected to start/final\n" 42 | " -o,--output .cc output filename\n" 43 | " -O,--output-header .hh output filename\n" 44 | " -h, --help display this help and exit\n" 45 | "\n" 46 | , fh); 47 | exit(fh == stdout ? 0 : EX_USAGE); 48 | } 49 | 50 | int main(int argc, char *argv[]) 51 | { 52 | setlocale(LC_ALL, ""); 53 | int opt; 54 | static struct option long_options[] = { 55 | {"bytes", no_argument, 0, 'b'}, 56 | {"check", required_argument, 0, 'c'}, 57 | {"debug", required_argument, 0, 'd'}, 58 | {"debug-output", required_argument, 0, 'l'}, 59 | {"dump-action", no_argument, 0, 1000}, 60 | {"dump-assoc", no_argument, 0, 1001}, 61 | {"dump-automaton", no_argument, 0, 1002}, 62 | {"dump-embed", no_argument, 0, 1003}, 63 | {"dump-module", no_argument, 0, 1004}, 64 | {"dump-tree", no_argument, 0, 1005}, 65 | {"extern-c", no_argument, 0, 1007}, 66 | {"graph", no_argument, 0, 'G'}, 67 | {"import", required_argument, 0, 'I'}, 68 | {"interactive", no_argument, 0, 'i'}, 69 | {"max-return-stack", required_argument, 0, 1006}, 70 | {"keep-inaccessible", no_argument, 0, 'k'}, 71 | {"standalone", no_argument, 0, 'S'}, 72 | {"substring-grammar", no_argument, 0, 's'}, 73 | {"output", required_argument, 0, 'o'}, 74 | {"output-header", required_argument, 0, 'O'}, 75 | {"help", no_argument, 0, 'h'}, 76 | {0, 0, 0, 0}, 77 | }; 78 | 79 | while ((opt = getopt_long(argc, argv, "bCDcd:GhI:ikl:O:o:Ss", long_options, NULL)) != -1) { 80 | switch (opt) { 81 | case 'b': 82 | opt_bytes = true; 83 | AB = 256; 84 | break; 85 | case 'C': 86 | opt_gen_c = true; 87 | break; 88 | case 'D': 89 | break; 90 | case 'c': 91 | opt_check = true; 92 | break; 93 | case 'd': 94 | debug_level = get_long(optarg); 95 | break; 96 | case 'G': 97 | opt_mode = Mode::graphviz; 98 | break; 99 | case 'h': 100 | print_help(stdout); 101 | break; 102 | case 'I': 103 | opt_include_paths.push_back(string(optarg)); 104 | break; 105 | case 'i': 106 | opt_mode = Mode::interactive; 107 | break; 108 | case 'k': 109 | opt_keep_inaccessible = true; 110 | break; 111 | case 'l': 112 | if (debug_file) 113 | err_exit(EX_USAGE, "multiple '-l'"); 114 | debug_file = fopen(optarg, "w"); 115 | if (! debug_file) 116 | err_exit(EX_OSFILE, "fopen"); 117 | break; 118 | case 'O': 119 | opt_output_header_filename = optarg; 120 | break; 121 | case 'o': 122 | opt_output_filename = optarg; 123 | break; 124 | case 'S': 125 | opt_standalone = true; 126 | break; 127 | case 's': 128 | opt_substring_grammar = true; 129 | break; 130 | case 1000: opt_dump_action = true; break; 131 | case 1001: opt_dump_assoc = true; break; 132 | case 1002: opt_dump_automaton = true; break; 133 | case 1003: opt_dump_embed = true; break; 134 | case 1004: opt_dump_module = true; break; 135 | case 1005: opt_dump_tree = true; break; 136 | case 1006: 137 | opt_max_return_stack = get_long(optarg); 138 | break; 139 | case 1007: opt_gen_extern_c = true; break; 140 | case '?': 141 | print_help(stderr); 142 | break; 143 | } 144 | } 145 | if (! debug_file) 146 | debug_file = stderr; 147 | argc -= optind; 148 | argv += optind; 149 | 150 | long n_errors = load(argc ? argv[0] : "-"); 151 | unload_all(); 152 | fclose(debug_file); 153 | return n_errors ? 2 : 0; 154 | } 155 | -------------------------------------------------------------------------------- /yanshi/src/option.cc: -------------------------------------------------------------------------------- 1 | #include "common.hh" 2 | #include "option.hh" 3 | #include 4 | 5 | bool opt_bytes, opt_check, opt_dump_action, opt_dump_assoc, opt_dump_automaton, opt_dump_embed, opt_dump_module, opt_dump_tree, opt_gen_c, opt_gen_extern_c, opt_keep_inaccessible, opt_standalone, opt_substring_grammar; 6 | 7 | long AB = MAX_CODEPOINT+1, opt_max_return_stack = 100; 8 | long debug_level = 3; 9 | FILE* debug_file; 10 | const char* opt_output_filename = "-"; 11 | const char* opt_output_header_filename; 12 | Mode opt_mode = Mode::cxx; 13 | vector opt_include_paths; 14 | -------------------------------------------------------------------------------- /yanshi/src/option.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | using std::string; 5 | using std::vector; 6 | 7 | extern bool opt_bytes, opt_check, opt_dump_action, opt_dump_assoc, opt_dump_automaton, opt_dump_embed, opt_dump_module, opt_dump_tree, opt_gen_c, opt_gen_extern_c, opt_keep_inaccessible, opt_standalone, opt_substring_grammar; 8 | extern long AB, opt_max_return_stack; 9 | extern const char* opt_output_filename; 10 | extern const char* opt_output_header_filename; 11 | enum class Mode {cxx, graphviz, interactive}; 12 | extern Mode opt_mode; 13 | extern vector opt_include_paths; 14 | -------------------------------------------------------------------------------- /yanshi/src/repl.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "syntax.hh" 3 | 4 | void repl(DefineStmt* stmt); 5 | -------------------------------------------------------------------------------- /yanshi/src/syntax.cc: -------------------------------------------------------------------------------- 1 | #include "syntax.hh" 2 | 3 | void stmt_free(Stmt* stmt) 4 | { 5 | while (stmt) { 6 | auto x = stmt->next; 7 | delete stmt; 8 | stmt = x; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /yanshi/unittest/determinize_test.cc: -------------------------------------------------------------------------------- 1 | #include "fsa.hh" 2 | #include "unittest/unittest_helper.hh" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | const char test[] = 13 | "4 7 2\n" 14 | "2 3 \n" 15 | "0 0 1\n" 16 | "0 -1 2\n" 17 | "1 1 1\n" 18 | "1 1 3\n" 19 | "2 -1 1\n" 20 | "2 0 3\n" 21 | "3 0 2\n" 22 | ; 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | if (argc == 1) { 27 | char filename[] = "/tmp/XXXXXX"; 28 | int fd = mkstemp(filename); 29 | write(fd, test, sizeof test-1); 30 | close(fd); 31 | freopen(filename, "r", stdin); 32 | unlink(filename); 33 | } 34 | 35 | auto relate = [](const vector&) {}; 36 | Fsa fsa = read_nfa().determinize(relate); 37 | print_fsa(fsa); 38 | 39 | if (argc == 1) 40 | return fsa.n() == 4 ? 0 : 1; 41 | } 42 | -------------------------------------------------------------------------------- /yanshi/unittest/difference_test.cc: -------------------------------------------------------------------------------- 1 | #include "fsa.hh" 2 | #include "unittest/unittest_helper.hh" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | const char test[] = 12 | "4 4 1\n" 13 | "3 \n" 14 | "0 0 1\n" 15 | "0 1 2\n" 16 | "1 0 3\n" 17 | "2 1 3\n" 18 | 19 | "4 4 1\n" 20 | "3 \n" 21 | "0 0 1\n" 22 | "0 1 2\n" 23 | "1 1 3\n" 24 | "2 1 3\n" 25 | ; 26 | 27 | int main(int argc, char *argv[]) 28 | { 29 | if (argc == 1) { 30 | char filename[] = "/tmp/XXXXXX"; 31 | int fd = mkstemp(filename); 32 | write(fd, test, sizeof test-1); 33 | close(fd); 34 | freopen(filename, "r", stdin); 35 | unlink(filename); 36 | } 37 | 38 | auto relate = [](long u, long v) {}; 39 | Fsa a = read_dfa(), b = read_dfa(), fsa = a.difference(b, relate); 40 | print_fsa(fsa); 41 | 42 | if (argc == 1) 43 | return 0; // fsa.n() == 4 ? 0 : 1; 44 | } 45 | -------------------------------------------------------------------------------- /yanshi/unittest/intersection_test.cc: -------------------------------------------------------------------------------- 1 | #include "fsa.hh" 2 | #include "unittest/unittest_helper.hh" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | const char test[] = 12 | "4 4 1\n" 13 | "3 \n" 14 | "0 0 1\n" 15 | "0 1 2\n" 16 | "1 0 3\n" 17 | "2 1 3\n" 18 | 19 | "4 4 1\n" 20 | "3 \n" 21 | "0 0 1\n" 22 | "0 1 2\n" 23 | "1 1 3\n" 24 | "2 1 3\n" 25 | ; 26 | 27 | int main(int argc, char *argv[]) 28 | { 29 | if (argc == 1) { 30 | char filename[] = "/tmp/XXXXXX"; 31 | int fd = mkstemp(filename); 32 | write(fd, test, sizeof test-1); 33 | close(fd); 34 | freopen(filename, "r", stdin); 35 | unlink(filename); 36 | } 37 | 38 | auto relate = [](long u, long v) {}; 39 | Fsa a = read_dfa(), b = read_dfa(), fsa = a.intersect(b, relate); 40 | print_fsa(fsa); 41 | 42 | if (argc == 1) 43 | return 0; // fsa.n() == 4 ? 0 : 1; 44 | } 45 | -------------------------------------------------------------------------------- /yanshi/unittest/minimize_test.cc: -------------------------------------------------------------------------------- 1 | #include "fsa.hh" 2 | #include "unittest/unittest_helper.hh" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | const char test[] = 14 | "4 4 1\n" 15 | "3 \n" 16 | "0 0 1\n" 17 | "0 1 2\n" 18 | "1 0 3\n" 19 | "2 0 3\n" 20 | ; 21 | 22 | int main(int argc, char *argv[]) 23 | { 24 | if (argc == 1) { 25 | char filename[] = "/tmp/XXXXXX"; 26 | int fd = mkstemp(filename); 27 | write(fd, test, sizeof test-1); 28 | close(fd); 29 | freopen(filename, "r", stdin); 30 | unlink(filename); 31 | } 32 | 33 | auto relate = [](const vector&) {}; 34 | Fsa fsa = read_dfa().minimize(relate); 35 | print_fsa(fsa); 36 | 37 | if (argc == 1) 38 | return fsa.n() == 3 ? 0 : 1; 39 | } 40 | -------------------------------------------------------------------------------- /yanshi/unittest/union_test.cc: -------------------------------------------------------------------------------- 1 | #include "fsa.hh" 2 | #include "unittest/unittest_helper.hh" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | const char test[] = 14 | "4 4 1\n" 15 | "3 \n" 16 | "0 0 1\n" 17 | "0 1 2\n" 18 | "1 0 3\n" 19 | "2 1 3\n" 20 | 21 | "4 4 1\n" 22 | "3 \n" 23 | "0 0 1\n" 24 | "0 1 2\n" 25 | "1 1 3\n" 26 | "2 1 3\n" 27 | ; 28 | 29 | int main(int argc, char *argv[]) 30 | { 31 | if (argc == 1) { 32 | char filename[] = "/tmp/XXXXXX"; 33 | int fd = mkstemp(filename); 34 | write(fd, test, sizeof test-1); 35 | close(fd); 36 | freopen(filename, "r", stdin); 37 | unlink(filename); 38 | } 39 | 40 | auto relate = [](long u, long v) {}; 41 | Fsa a = read_dfa(), b = read_dfa(), fsa = a.union_(b, relate); 42 | print_fsa(fsa); 43 | 44 | if (argc == 1) 45 | return fsa.n() == 4 ? 0 : 1; 46 | } 47 | -------------------------------------------------------------------------------- /yanshi/unittest/unittest_helper.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common.hh" 3 | #include "fsa.hh" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | static Fsa read_nfa() 13 | { 14 | long n, m, k, u, a, v; 15 | cin >> n >> m >> k; 16 | Fsa r; 17 | r.start = 0; 18 | r.adj.resize(n); 19 | while (k--) { 20 | cin >> u; 21 | r.finals.push_back(u); 22 | } 23 | sort(ALL(r.finals)); 24 | while (m--) { 25 | cin >> u >> a >> v; 26 | if (u < 0 || u >= n) 27 | errx(EX_DATAERR, "%ld: 0 <= u < n", u); 28 | if (a < -1 || a >= 256) 29 | errx(EX_DATAERR, "%ld: -1 <= c < 256", a); 30 | if (v < 0 || v >= n) 31 | errx(EX_DATAERR, "%ld: 0 <= v < n", v); 32 | r.adj[u].emplace_back(a, v); 33 | } 34 | assert(cin.good()); 35 | REP(i, n) 36 | sort(ALL(r.adj[i])); 37 | return r; 38 | } 39 | 40 | static Fsa read_dfa() 41 | { 42 | Fsa r = read_nfa(); 43 | REP(i, r.n()) 44 | if (r.adj[i].size()) { 45 | if (r.adj[i][0].first < 0) 46 | errx(EX_DATAERR, "epsilon edge found for %ld", i); 47 | REP(j, r.adj[i].size()-1) 48 | if (r.adj[i][j].first == r.adj[i][j+1].first) 49 | errx(EX_DATAERR, "duplicate labels %ld found for %ld", r.adj[i][j].first, i); 50 | } 51 | assert(cin.good()); 52 | return r; 53 | } 54 | 55 | static void print_fsa(const Fsa& fsa) 56 | { 57 | printf("finals:"); 58 | for (long i: fsa.finals) 59 | printf(" %ld", i); 60 | puts(""); 61 | puts("edges:"); 62 | REP(i, fsa.n()) { 63 | printf("%ld:", i); 64 | for (auto& x: fsa.adj[i]) 65 | printf(" (%ld,%ld)", x.first, x.second); 66 | puts(""); 67 | } 68 | } 69 | --------------------------------------------------------------------------------