Compare commits

...
Sign in to create a new pull request.

62 commits
dev ... main

Author SHA1 Message Date
姚凯
53a955b439 fix: environment 2024-12-19 19:49:20 +08:00
姚凯
c3f064fa4c fix: insufficient-disk-capacity argument 2024-12-09 18:24:34 +08:00
姚凯
233ac9547c fix: clean image when uninstall 2024-12-09 10:54:54 +08:00
姚凯
5d73a333d0 feat: add restart 2024-12-06 18:05:13 +08:00
姚凯
e443cd47c0 fix: add more info 2024-12-06 16:18:48 +08:00
姚凯
2f61ebaf85 feat: add repair 2024-12-06 14:37:41 +08:00
姚凯
9fe9ff3ef1 fix: typo 2024-12-05 19:19:36 +08:00
姚凯
a75123c86d feat: add uninstall 2024-12-05 19:19:36 +08:00
xiaobing.wang
599a6903a9 feat: 7.3.0 2024-12-05 18:50:55 +08:00
xiaobing.wang
bf87488eff feat: 7.3.0 2024-12-05 18:37:14 +08:00
姚凯
c2c3fe32fb fix: remove captcha_output 2024-12-05 17:51:24 +08:00
姚凯
a18cc16b33 fix: add more log 2024-12-05 16:23:07 +08:00
xbingW
3efdd3fff5
Update manage.py 2024-12-05 15:33:25 +08:00
xbingW
9d156c65ba
Merge pull request #1100 from dhsifss/main
feat: add upgrade
2024-12-05 14:38:40 +08:00
姚凯
8f575dc232 feat: add upgrade 2024-11-27 10:25:49 +08:00
xiaobing.wang
e44e88c136 feat: 7.2.0 2024-11-15 00:38:59 +08:00
safe1ine
3f8187ae6c
Create manage.py
new installer
2024-11-14 17:37:26 +08:00
xiaobing.wang
de7307fbda feat: add release 2024-11-12 22:55:55 +08:00
xiaobing.wang
2685813f4d fix: chaos 2024-10-31 18:30:19 +08:00
xbingW
78912d064e
Merge pull request #1095 from dhsifss/main
feat: support arm
2024-10-31 17:22:21 +08:00
姚凯
e1e801cec8 feat: support arm 2024-10-31 17:21:36 +08:00
xbingW
f851033a7a
Merge pull request #1085 from dhsifss/main
refactor: remove bridge
2024-10-17 19:29:37 +08:00
姚凯
82a2e4473a refactor: remove bridge 2024-10-11 18:13:20 +08:00
xiaobing.wang
c6f5467000 feat: 6.10.2 2024-09-27 14:38:47 +08:00
xiaobing.wang
2c7f0f94c5 feat: 6.9.0 2024-09-12 19:09:15 +08:00
safe1ine
e2672c93e2
Update README.md 2024-08-26 21:06:46 +08:00
xiaobing.wang
4e033ed5f3 feat: update traefik sdk 2024-08-09 11:37:49 +08:00
xiaobing.wang
d060377caa feat: add env for 6.4.0 2024-08-01 21:02:57 +08:00
xiaobing.wang
07900ac11d feat: Why is it needed is required 2024-07-31 11:38:45 +08:00
xiaobing.wang
cf62e2c07e fix: compose env 2024-07-29 15:21:59 +08:00
safe1ine
e63799dd78
Merge pull request #1001 from safe1ine/main
add chinese readme
2024-07-23 23:48:42 +08:00
safe1ine
da209259cd
Delete CN directory 2024-07-23 23:47:59 +08:00
safe1ine
3d9420095b
Merge branch 'chaitin:main' into main 2024-07-23 23:47:20 +08:00
safe1ine
86689954c0
Update README.md 2024-07-23 23:45:47 +08:00
safe1ine
b3238a462d
Create README_CN.md 2024-07-23 23:45:01 +08:00
safe1ine
b087450844
Create CN README.md 2024-07-23 23:42:35 +08:00
safe1ine
3c2ebf308b
Merge pull request #999 from safe1ine/main
change readme
2024-07-23 17:56:31 +08:00
safe1ine
9476db4119
Merge branch 'main' into main 2024-07-23 17:56:14 +08:00
naocanmonster
35acf92d5b change readme 2024-07-23 17:49:22 +08:00
safe1ine
b776a2a598
Update README.md 2024-07-22 18:47:57 +08:00
safe1ine
afc47d4faa
Update README.md 2024-07-22 18:13:04 +08:00
safe1ine
3a20f0a8f5
Add files via upload 2024-07-22 18:11:53 +08:00
safe1ine
325e169d7d
Update README.md 2024-07-22 16:56:52 +08:00
safe1ine
2a549cae19
Add files via upload 2024-07-22 16:56:03 +08:00
safe1ine
5917c2f184
Update README.md 2024-07-22 16:20:09 +08:00
safe1ine
1b642fd9c4
Update README.md 2024-07-22 16:18:19 +08:00
safe1ine
82a1cacd30
Update README.md 2024-07-22 16:06:48 +08:00
safe1ine
61302eb183
Update README.md 2024-07-22 14:49:55 +08:00
safe1ine
8a22751ade
Update README.md 2024-07-19 19:05:57 +08:00
safe1ine
9c76cdd002
Update README.md 2024-07-19 19:05:06 +08:00
safe1ine
70c3820e5a
Update README.md 2024-07-16 10:16:54 +08:00
safe1ine
0bda186500
Update README.md 2024-07-12 16:04:59 +08:00
xiaobing.wang
135bf69301 chore: update template 2024-07-10 16:04:30 +08:00
xiaobing.wang
d05cfc3ef8 chore: update template 2024-07-10 16:02:38 +08:00
xiaobing.wang
259d955117 chore: update template 2024-07-10 15:59:15 +08:00
xiaobing.wang
9736a5a9f3 chore: update template 2024-07-10 15:58:30 +08:00
xiaobing.wang
8234d91cc3 chore: update dep 2024-07-10 15:52:06 +08:00
xiaobing.wang
e6e01d9b74 chore: rename md 2024-07-05 16:39:18 +08:00
xiaobing.wang
952f45ad91 feat: ingress 1.0.3 2024-07-05 15:07:58 +08:00
xiaobing.wang
663ffc2205 feat: kong 1.0.2 2024-07-05 11:45:12 +08:00
xiaobing.wang
8d4a2de07e feat: lua t1k 1.1.5 2024-07-05 11:22:38 +08:00
xbingW
3f0d660442
Merge pull request #976 from chaitin/dev
Dev
2024-07-04 17:55:43 +08:00
83 changed files with 4163 additions and 331 deletions

View file

@ -1,30 +0,0 @@
name: 功能建议
# Feature request
description: 新功能或现有能力的优化建议
title: "[建议] "
body:
- type: markdown
attributes:
value: |
提示:创建前请搜索一下是否有重复问题。一个 issue 尽量只描述一个问题。简洁、准确的描述有助于集中大家的意见,推进问题尽快解决
# Please check for duplicate issue first.
# 尽量描述需求的背景、原始问题,避免出现 X-Y 问题,参考: https://coolshell.cn/articles/10804.html
- type: textarea
id: problem
attributes:
label: 背景与遇到的问题
# Background and the problem that frustrates you
placeholder: |
例如我的业务有xxx特性当我在使用xxx功能的时候会遇到xxx情况...
validations:
required: false
- type: textarea
id: solution
attributes:
label: 建议的解决方案
# Describe the solution you'd like
placeholder: |
例如建议增加xxx功能将xxx改为xxx...
validations:
required: false

View file

@ -1,42 +0,0 @@
name: Bug
description: 明确的软件故障或缺陷
# Create a report to help us improve
title: "[Bug] "
body:
- type: markdown
attributes:
value: |
提示:提问前请先搜索一下是否存在重复问题
# Please check for duplicate issue first.
- type: textarea
id: Description
attributes:
label: 问题描述
# Describe the bug
validations:
required: false
- type: input
id: version
attributes:
label: 版本号
placeholder: 3.0.0
validations:
required: true
- type: textarea
id: Reproduce
attributes:
label: 复现方法
# To Reproduce
placeholder: |
1. ...
2. ...
validations:
required: true
- type: textarea
id: Expected
attributes:
label: 期望的结果
# Expected behavior. Descript what you expected to happen.
validations:
required: true

View file

@ -1,14 +0,0 @@
name: 其他问题与反馈
description: 文档、部署失败等其他问题。
body:
- type: markdown
attributes:
value: |
提示:创建前请先搜索一下是否存在重复问题
# Please check for duplicate issue first.
# 尽量描述需求的背景、原始问题,避免出现 X-Y 问题,参考: https://coolshell.cn/articles/10804.html
# 提問的智慧: https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md
- type: textarea
id: content
attributes:
label: 反馈内容

45
.github/ISSUE_TEMPLATE/bug-report.yaml vendored Normal file
View file

@ -0,0 +1,45 @@
name: Bug
description: Report a bug
# Create a report to help us improve
title: "[Bug] "
body:
- type: markdown
attributes:
value: |
Please search the [open issues](https://github.com/chaitin/SafeLine/issues) and [discussion](https://github.com/chaitin/SafeLine/discussions) for duplicate issue first.
The more information you share, the faster we can identify and fix the bug.
# Please check for duplicate issue first.
- type: textarea
id: Description
attributes:
label: What happened?
# Describe the bug
validations:
required: false
- type: textarea
id: Reproduce
attributes:
label: How we reproduce?
description: |
Reports cannot be reproduced will Most likely be closed.
# To Reproduce
value: |
1. ...
2. ...
3. ...
- type: textarea
id: Expected
attributes:
label: Expected behavior
# placeholder: |
# Descript what you expected to happen.
# Expected behavior. Descript what you expected to happen.
- type: textarea
id: Errorlog
attributes:
label: Error log
placeholder: |
Paste the error logs if any.
# Expected behavior. Descript what you expected to happen.

View file

@ -1,5 +1,11 @@
blank_issues_enabled: Ture
blank_issues_enabled: false
contact_links:
- name: Discord
url: https://discord.gg/wyshSVuvxC
about: Ask questions and discuss with other SafeLine users in real time.
- name: Home page 官网
url: https://waf.chaitin.com/
about: Get feature descriptions, technical documentation and more information. 获取功能描述、技术文档和更多信息。
- name: 绕过反馈
url: https://stack.chaitin.com/security-challenge/safeline/index
about: Waf 绕过可在 CT Stack 安全挑战赛提交细节
about: Waf 绕过可在 CT Stack 安全挑战赛提交细节

View file

@ -0,0 +1,28 @@
name: Suggestion
# Feature request
description: New feature or improvements.
title: "[Suggestion] "
body:
- type: markdown
attributes:
value: |
Please search the [open issues](https://github.com/chaitin/SafeLine/issues) and [discussion](https://github.com/chaitin/SafeLine/discussions) for duplicate issue first.
Please rise only one suggestion in an issue.
- type: textarea
id: solution
attributes:
label: What would you like to be added or improved?
# Describe the solution you'd like
# placeholder: |
#
- type: textarea
id: problem
attributes:
label: Why is it needed?
# Background and the specific problem that frustrates you
placeholder: |
Background and the problem that frustrates you
validations:
required: true

12
.github/ISSUE_TEMPLATE/other.yaml vendored Normal file
View file

@ -0,0 +1,12 @@
name: Other
description: Other issues such as Doc
body:
- type: markdown
attributes:
value: |
Please search the [open issues](https://github.com/chaitin/SafeLine/issues) and [discussion](https://github.com/chaitin/SafeLine/discussions) for duplicate issue first.
Please rise only one suggestion in an issue.
- type: textarea
id: content
attributes:
label: Content

View file

209
README.md
View file

@ -1,35 +1,34 @@
# SafeLine, make your webserver secure
<img src="/images/403.svg" align="right" width="200" />
SafeLine is a web security gateway to protect your websites from attacks and exploits.
It defenses for all of web attacks, such as sql injection, code injection, os command injection, CRLF injection, ldap injection, xpath injection, rce, xss, xxe, ssrf, path traversal, backdoor, bruteforce, http-flood, bot abused and so on.
<p align="left">
<a target="_blank" href="https://waf.chaitin.com/">🏠Home</a> &nbsp; | &nbsp;
<a target="_blank" href="https://docs.waf.chaitin.com/">📖Documentation</a> &nbsp; | &nbsp;
<a target="_blank" href="https://demo.waf.chaitin.com:9443/dashboard">🔍Live Demo</a> &nbsp; | &nbsp;
<a target="_blank" href="https://waf-ce.chaitin.cn/">中文版</a>
<p align="center">
<img src="/images/banner.png" width="400" />
</p>
<p align="left">
<a target="_blank" href="https://discord.gg/wyshSVuvxC"><img src="https://img.shields.io/badge/Discord-5865F2?style=flat&logo=discord&logoColor=white"></a> &nbsp;
<a target="_blank" href="https://x.com/safeline_waf"><img src="https://img.shields.io/badge/X-000000?style=flat&logo=x&logoColor=white"></a> &nbsp;
<a target="_blank" href="https://t.me/safeline_waf"><img src="https://img.shields.io/badge/Telegram-2CA5E0?style=flat&logo=telegram&logoColor=white"></a> &nbsp;
<a target="_blank" href="/images/wechat-230825.png"><img src="https://img.shields.io/badge/WeChat-07C160?style=flat&logo=wechat&logoColor=white"></a>
<h4 align="center">
SafeLine - Make your web apps secure
</h4>
<p align="center">
<a target="_blank" href="https://waf.chaitin.com/">🏠 Website</a> &nbsp; | &nbsp;
<a target="_blank" href="https://docs.waf.chaitin.com/">📖 Docs</a> &nbsp; | &nbsp;
<a target="_blank" href="https://demo.waf.chaitin.com:9443/">🔍 Live Demo</a> &nbsp; | &nbsp;
<a target="_blank" href="https://discord.gg/SVnZGzHFvn">🙋‍♂️ Discord</a> &nbsp; | &nbsp;
<a target="_blank" href="/README_CN.md">中文版</a>
</p>
# Screenshots
## 👋 INTRODUCTION
<img src="./images/safeline_en.png" width=600 />
SafeLine is a self-hosted **`WAF(Web Application Firewall)`** to protect your web apps from attacks and exploits.
# How It Works
A web application firewall helps protect web apps by filtering and monitoring HTTP traffic between a web application and the Internet. It typically protects web apps from attacks such as `SQL injection`, `XSS`, `code injection`, `os command injection`, `CRLF injection`, `ldap injection`, `xpath injection`, `RCE`, `XXE`, `SSRF`, `path traversal`, `backdoor`, `bruteforce`, `http-flood`, `bot abused`, among others.
<img src="/images/safeline-as-proxy.png" align="right" width=400 />
#### 💡 How It Works
SafeLine is developed based on nginx, it serves as a reverse proxy middleware to detect and cleans web attacks, its core capabilities include:
<img src="/images/how-it-works.png" width="800" />
By deploying a WAF in front of a web application, a shield is placed between the web application and the Internet. While a proxy server protects a client machines identity by using an intermediary, a WAF is a type of reverse-proxy, protecting the server from exposure by having clients pass through the WAF before reaching the server.
A WAF protects your web apps by filtering, monitoring, and blocking any malicious HTTP/S traffic traveling to the web application, and prevents any unauthorized data from leaving the app. It does this by adhering to a set of policies that help determine what traffic is malicious and what traffic is safe. Just as a proxy server acts as an intermediary to protect the identity of a client, a WAF operates in similar fashion but acting as an reverse proxy intermediary that protects the web app server from a potentially malicious client.
its core capabilities include:
- Defenses for web attacks
- Proactive bot abused defense
@ -37,107 +36,93 @@ SafeLine is developed based on nginx, it serves as a reverse proxy middleware to
- IP-based rate limiting
- Web Access Control List
# Installation
#### ⚡️ Screenshots
**中国大陆用户安装国际版可能会导致无法连接云服务,请查看** [中文版安装文档](https://docs.waf-ce.chaitin.cn/zh/%E4%B8%8A%E6%89%8B%E6%8C%87%E5%8D%97/%E5%AE%89%E8%A3%85%E9%9B%B7%E6%B1%A0)
| <img src="./images/screenshot-1.png" width=370 /> | <img src="./images/screenshot-2.png" width=370 /> |
| ------------------------------------------------- | ------------------------------------------------- |
| <img src="./images/screenshot-3.png" width=370 /> | <img src="./images/screenshot-4.png" width=370 /> |
## Automatic Deploy
Get [Live Demo](https://demo.waf.chaitin.com:9443/)
> 👍Recommended
## 🔥 FEATURES
Use the following command to start the automated installation of SafeLine. (This process requires root privileges)
List of the main features as follows:
```bash
bash -c "$(curl -fsSLk https://waf.chaitin.com/release/latest/setup.sh)"
```
- **`Block Web Attacks`**
- It defenses for all of web attacks, such as `SQL injection`, `XSS`, `code injection`, `os command injection`, `CRLF injection`, `XXE`, `SSRF`, `path traversal` and so on.
- **`Rate Limiting`**
- Defend your web apps against `DoS attacks`, `bruteforce attempts`, `traffic surges`, and other types of abuse by throttling traffic that exceeds defined limits.
- **`Anti-Bot Challenge`**
- Anti-Bot challenges to protect your website from `bot attacks`, humen users will be allowed, crawlers and bots will be blocked.
- **`Authentication Challenge`**
- When authentication challenge turned on, visitors need to enter the password, otherwise they will be blocked.
- **`Dynamic Protection`**
- When dynamic protection turned on, html and js codes in your web server will be dynamically encrypted by each time you visit.
After the command is executed, it means the installation is successfully. Please go to "Use Web UI" directly.
#### 🧩 Showcases
| | Legitimate User | Malicious User |
| ----------------------------- | --------------------------------------------------- | ---------------------------------------------------------------- |
| **`Block Web Attacks`** | <img src="./images/skeleton.png" width=270 /> | <img src="./images/blocked-for-attack-detected.png" width=270 /> |
| **`Rate Limiting`** | <img src="./images/skeleton.png" width=270 /> | <img src="./images/blocked-for-access-too-fast.png" width=270 /> |
| **`Anti-Bot Challenge`** | <img src="./images/captcha-1.gif" width=270 /> | <img src="./images/captcha-2.gif" width=270 /> |
| **`Auth Challenge`** | <img src="./images/auth-1.gif" width=270 /> | <img src="./images/auth-2.gif" width=270 /> |
| **`HTML Dynamic Protection`** | <img src="./images/dynamic-html-1.png" width=270 /> | <img src="./images/dynamic-html-2.png" width=270 /> |
| **`JS Dynamic Protection`** | <img src="./images/dynamic-js-1.png" width=270 /> | <img src="./images/dynamic-js-2.png" width=270 /> |
## 🚀 Quickstart
> [!WARNING]
> 中国大陆用户安装国际版可能会导致无法连接云服务,请查看 [中文版安装文档](https://docs.waf-ce.chaitin.cn/zh/%E4%B8%8A%E6%89%8B%E6%8C%87%E5%8D%97/%E5%AE%89%E8%A3%85%E9%9B%B7%E6%B1%A0)
#### 📦 Installing
Information on how to install SafeLine can be found in the [Install Guide](https://docs.waf.chaitin.com/en/tutorials/install)
#### ⚙️ Protecting Web Apps
to see [Configuration](https://docs.waf.chaitin.com/en/tutorials/Configuration)
## 📋 More Informations
#### Effect Evaluation
| Metric | ModSecurity, Level 1 | CloudFlare, Free | SafeLine, Balance | SafeLine, Strict |
| ----------------- | -------------------- | -------------------- | ---------------------- | --------------------- |
| Total Samples | 33669 | 33669 | 33669 | 33669 |
| **Detection** | 69.74% | 10.70% | 71.65% | **76.17%** |
| **False Positive**| 17.58% | 0.07% | **0.07%** | 0.22% |
| **Accuracy** | 82.20% | 98.40% | **99.45%** | 99.38% |
## Mannually Deploy
#### Is SafeLine Production-Ready?
to see [Documentation](https://docs.waf.chaitin.com/en/tutorials/install)
Yes, SafeLine is production-ready.
# Usage
- Over 180,000 installations worldwide
- Protecting over 1,000,000 Websites
- Handling over 30,000,000,000 HTTP Requests Daily
## Login
#### 🙋‍♂️ Community
Open the web console page `https://<safeline-ip>:9443/` in the browser, then you will see below.
Join our [Discord](https://discord.gg/SVnZGzHFvn) to get community support, the core team members are identified by the STAFF role in Discord.
<img width="400" src="/images/login.png">
- channel [#feedback](https://discord.com/channels/1243085666485534830/1243120292822253598): for new features discussion.
- channel [#FAQ](https://discord.com/channels/1243085666485534830/1263761679619981413): for FAQ.
- channel [#general](https://discord.com/channels/1243085666485534830/1243115843919806486): for any other questions.
Execute the following command to get administrator account
Several contact options exist for our community, the primary one being Discord. These are in addition to GitHub issues for creating a new issue.
```bash
docker exec safeline-mgt /app/mgt-cli reset-admin --once
```
After the command is successfully executed, you will see the following content
> Please must remember this content
```text
[SafeLine] Initial usernameadmin
[SafeLine] Initial password**********
[SafeLine] Done
```
Enter the password in the previous step and you will successfully logged into SafeLine.
## Protecting a website
Log into the SafeLine Web Admin Console, go to the "Site" -> "Website" page and click the "Add Site" button in the upper right corner.
<img src="/images/add-site-1.png" width=800>
In the next dialog box, enter the information to the original website.
- **Domain**: domain name of your original website, or hostname, or ip address, for example: `www.chaitin.com`
- **Port**: port that SafeLine will listen, such as 80 or 443. (for `https` websites, please check the `SSL` option)
- **Upstream**: real address of your original website, through which SafeLine will forward traffic to it
After completing the above settings, please resolve the domain name you just entered to the IP address of the server where SafeLine is located.
<img src="/images/add-site-2.png" width=400>
Then you can access the website protected by the SafeLine through the domain name like this.
<img src="/images/safeline-as-proxy-2.png" width=400>
## Try to attack your website
Now, your website is protected by SafeLine, lets try tp attack it and see what happens.
If https://chaitin.com is a website protected by SafeLine, here are some test cases for common attacks:
- SQL Injection: `https://chaitin.com/?id=1+and+1=2+union+select+1`
- XSS: `https://chaitin.com/?id=<img+src=x+onerror=alert()>`
- Path Traversal: `https://chaitin.com/?id=../../../../etc/passwd`
- Code Injection: `https://chaitin.com/?id=phpinfo();system('id')`
- XXE: `https://chaitin.com/?id=<?xml+version="1.0"?><!DOCTYPE+foo+SYSTEM+"">`
Replace `chaitin.com` in the above cases with your website domain name and try to access it.
<img src="/images/blocked.png" width=400>
Check the web console of SafeLine to see the attack list
<img src="/images/log-list.png" width=800>
To view the specific details of the attack, click "detail"
<img src="/images/log-detail.png" width=600>
## Star History
<a href="https://github.com/chaitin/safeline/stargazers">
<img width="500" alt="Star History Chart" src="https://api.star-history.com/svg?repos=chaitin/safeline&type=Date">
</a>
## Related Repo
<p >
<a href="https://github.com/chaitin/yanshi">Automaton Generator</a> |
<a href="https://github.com/chaitin/safeline-open-platform">Lua Plugin</a> |
<a href="https://github.com/chaitin/lua-resty-t1k">T1K Protocol</a> |
<a href="https://github.com/chaitin/blazehttp">WAF Test Tool</a>
<p align="left">
<a target="_blank" href="https://discord.gg/SVnZGzHFvn"><img src="https://img.shields.io/badge/Discord-5865F2?style=flat&logo=discord&logoColor=white"></a> &nbsp;
<a target="_blank" href="https://x.com/safeline_waf"><img src="https://img.shields.io/badge/X.com-000000?style=flat&logo=x&logoColor=white"></a> &nbsp;
<a target="_blank" href="/images/wechat.png"><img src="https://img.shields.io/badge/WeChat-07C160?style=flat&logo=wechat&logoColor=white"></a>
</p>
#### 💪 PRO Edition
Coming soon!
#### 📝 License
See [LICENSE](/LICENSE.md) for details.

115
README_CN.md Normal file
View file

@ -0,0 +1,115 @@
<p align="center">
<img src="/images/banner.png" width="400" />
</p>
<h4 align="center">
SafeLine - 雷池 - 不让黑客越过半步
</h4>
<p align="center">
<a target="_blank" href="https://waf-ce.chaitin.cn/">🏠 官网</a> &nbsp; | &nbsp;
<a target="_blank" href="https://docs.waf-ce.chaitin.cn/">📖 文档</a> &nbsp; | &nbsp;
<a target="_blank" href="https://demo.waf-ce.chaitin.cn:9443/">🔍 演示环境</a> &nbsp; | &nbsp;
<a target="_blank" href="/images/wechat.png">🙋‍♂️ 社区微信群</a> &nbsp; | &nbsp;
<a target="_blank" href="https://github.com/chaitin/SafeLine">国际版</a>
</p>
## 👋 项目介绍
SafeLine中文名 "雷池",是一款简单好用, 效果突出的 **`Web 应用防火墙(WAF)`**,可以保护 Web 服务不受黑客攻击。
雷池通过过滤和监控 Web 应用与互联网之间的 HTTP 流量来保护 Web 服务。可以保护 Web 服务免受 `SQL 注入``XSS``代码注入``命令注入``CRLF 注入``ldap 注入``xpath 注入``RCE``XXE``SSRF``路径遍历``后门``暴力破解``CC``爬虫` 等攻击。
#### 💡 工作原理
<img src="/images/how-it-works.png" width="800" />
雷池通过阻断流向 Web 服务的恶意 HTTP 流量来保护 Web 服务。雷池作为反向代理接入网络,通过在 Web 服务前部署雷池,可在 Web 服务和互联网之间设置一道屏障。
雷池的核心功能如下:
- 防护 Web 攻击
- 防爬虫, 防扫描
- 前端代码动态加密
- 基于源 IP 的访问速率限制
- HTTP 访问控制
#### ⚡️ 项目截图
| <img src="./images/screenshot-1.png" width=370 /> | <img src="./images/screenshot-2.png" width=370 /> |
| ------------------------------------------------- | ------------------------------------------------- |
| <img src="./images/screenshot-3.png" width=370 /> | <img src="./images/screenshot-4.png" width=370 /> |
查看 [演示环境](https://demo.waf-ce.chaitin.cn:9443/)
## 🔥 核心能力
对于你的网站而言, 雷池可以实现如下效果:
- **`阻断 Web 攻击`**
- 可以防御所有的 Web 攻击,例如 `SQL 注入``XSS``代码注入``操作系统命令注入``CRLF 注入``XXE``SSRF``路径遍历` 等等。
- **`限制访问频率`**
- 限制用户的访问速率,让 Web 服务免遭 `CC 攻击``暴力破解``流量激增` 和其他类型的滥用。
- **`人机验证`**
- 互联网上有来自真人用户的流量,但更多的是由爬虫, 漏洞扫描器, 蠕虫病毒, 漏洞利用程序等自动化程序发起的流量,开启雷池的人机验证功能后真人用户会被放行,恶意爬虫将会被阻断。
- **`身份认证`**
- 雷池的 "身份认证" 功能可以很好的解决 "未授权访问" 漏洞,当用户访问您的网站时,需要输入您配置的用户名和密码信息,不持有认证信息的用户将被拒之门外。
- **`动态防护`**
- 在用户浏览到的网页内容不变的情况下,将网页赋予动态特性,对 HTML 和 JavaScript 代码进行动态加密,确保每次访问时这些代码都以随机且独特的形态呈现。
#### 🧩 核心能力展示
| | Legitimate User | Malicious User |
| ----------------------------- | --------------------------------------------------- | ---------------------------------------------------------------- |
| **`阻断 Web 攻击`** | <img src="./images/skeleton.png" width=270 /> | <img src="./images/blocked-for-attack-detected.png" width=270 /> |
| **`限制访问频率`** | <img src="./images/skeleton.png" width=270 /> | <img src="./images/blocked-for-access-too-fast.png" width=270 /> |
| **`人机验证`** | <img src="./images/captcha-1.gif" width=270 /> | <img src="./images/captcha-2.gif" width=270 /> |
| **`身份认证`** | <img src="./images/auth-1.gif" width=270 /> | <img src="./images/auth-2.gif" width=270 /> |
| **`HTML 动态防护`** | <img src="./images/dynamic-html-1.png" width=270 /> | <img src="./images/dynamic-html-2.png" width=270 /> |
| **`JS 动态防护`** | <img src="./images/dynamic-js-1.png" width=270 /> | <img src="./images/dynamic-js-2.png" width=270 /> |
## 🚀 上手指南
#### 📦 安装
查看 [安装雷池](https://docs.waf-ce.chaitin.cn/zh/%E4%B8%8A%E6%89%8B%E6%8C%87%E5%8D%97/%E5%AE%89%E8%A3%85%E9%9B%B7%E6%B1%A0)
#### ⚙️ 配置防护站点
查看 [快速配置](https://docs.waf-ce.chaitin.cn/zh/%E4%B8%8A%E6%89%8B%E6%8C%87%E5%8D%97/%E5%BF%AB%E9%80%9F%E9%85%8D%E7%BD%AE)
## 📋 更多信息
#### 防护效果测试
| Metric | ModSecurity, Level 1 | CloudFlare | 雷池, 平衡 | 雷池, 严格 |
| ----------------- | -------------------- | -------------------- | ---------------------- | --------------------- |
| 样本数量 | 33669 | 33669 | 33669 | 33669 |
| **检出率** | 69.74% | 10.70% | 71.65% | **76.17%** |
| **误报率** | 17.58% | 0.07% | **0.07%** | 0.22% |
| **准确率** | 82.20% | 98.40% | **99.45%** | 99.38% |
#### 雷池可以投入生产使用吗
是的,已经有不少用户将雷池投入生产使用,截至目前
- 全球累计装机量已超过 18 万台
- 防护的网站数量超过 100 万个
- 每天清洗 HTTP 请求超过 300 亿次
#### 🙋‍♂️ 用户社区
欢迎加入雷池 [社区微信群](/images/wechat.png) 进行技术交流。
也可以加入雷池 [Discord](https://discord.gg/SVnZGzHFvn) 来获取更多社区支持。
<p align="left">
<a target="_blank" href="/images/wechat.png"><img src="https://img.shields.io/badge/WeChat-07C160?style=flat&logo=wechat&logoColor=white"></a>
<a target="_blank" href="https://discord.gg/SVnZGzHFvn"><img src="https://img.shields.io/badge/Discord-5865F2?style=flat&logo=discord&logoColor=white"></a> &nbsp;
<a target="_blank" href="https://x.com/safeline_waf"><img src="https://img.shields.io/badge/X.com-000000?style=flat&logo=x&logoColor=white"></a> &nbsp;
</p>
#### 💪 专业版
查看 [社区版 vs 专业版](https://waf-ce.chaitin.cn/version)

View file

@ -14,7 +14,7 @@ services:
postgres:
container_name: safeline-pg
restart: always
image: ${IMAGE_PREFIX}/safeline-postgres:15.2
image: ${IMAGE_PREFIX}/safeline-postgres${ARCH_SUFFIX}:15.2
volumes:
- ${SAFELINE_DIR}/resources/postgres/data:/var/lib/postgresql/data
- /etc/localtime:/etc/localtime:ro
@ -30,18 +30,18 @@ services:
mgt:
container_name: safeline-mgt
restart: always
image: ${IMAGE_PREFIX}/safeline-mgt-g:${IMAGE_TAG:?image tag required}
image: ${IMAGE_PREFIX}/safeline-mgt${REGION}${ARCH_SUFFIX}${RELEASE}:${IMAGE_TAG:?image tag required}
volumes:
- /etc/localtime:/etc/localtime:ro
- ${SAFELINE_DIR}/resources/mgt:/app/data
- ${SAFELINE_DIR}/logs/nginx:/app/log/nginx:z
- ${SAFELINE_DIR}/resources/sock:/app/sock
- /var/run:/app/run
ports:
- ${MGT_PORT:-9443}:1443
healthcheck:
test: curl -k -f https://localhost:1443/api/open/health
environment:
- MGT_READ_ONLY=true
- MGT_NO_AUTH=true
- MGT_PG=postgres://safeline-ce:${POSTGRES_PASSWORD}@safeline-pg/safeline-ce?sslmode=disable
depends_on:
- postgres
@ -56,7 +56,7 @@ services:
detect:
container_name: safeline-detector
restart: always
image: ${IMAGE_PREFIX}/safeline-detector-g:${IMAGE_TAG}
image: ${IMAGE_PREFIX}/safeline-detector${REGION}${ARCH_SUFFIX}${RELEASE}:${IMAGE_TAG}
volumes:
- ${SAFELINE_DIR}/resources/detector:/resources/detector
- ${SAFELINE_DIR}/logs/detector:/logs/detector
@ -66,50 +66,35 @@ services:
networks:
safeline-ce:
ipv4_address: ${SUBNET_PREFIX}.5
mario:
container_name: safeline-mario
restart: always
image: ${IMAGE_PREFIX}/safeline-mario-g:${IMAGE_TAG}
volumes:
- ${SAFELINE_DIR}/resources/mario:/resources/mario
- ${SAFELINE_DIR}/logs/mario:/logs/mario
- /etc/localtime:/etc/localtime:ro
environment:
- LOG_DIR=/logs/mario
- GOGC=100
- DATABASE_URL=postgres://safeline-ce:${POSTGRES_PASSWORD}@safeline-pg/safeline-ce
logging:
options:
max-size: "100m"
max-file: "5"
networks:
safeline-ce:
ipv4_address: ${SUBNET_PREFIX}.6
tengine:
container_name: safeline-tengine
restart: always
image: ${IMAGE_PREFIX}/safeline-tengine-g:${IMAGE_TAG}
image: ${IMAGE_PREFIX}/safeline-tengine${REGION}${ARCH_SUFFIX}${RELEASE}:${IMAGE_TAG}
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/resolv.conf:/etc/resolv.conf:ro
- ${SAFELINE_DIR}/resources/nginx:/etc/nginx
- ${SAFELINE_DIR}/resources/detector:/resources/detector
- ${SAFELINE_DIR}/resources/chaos:/resources/chaos
- ${SAFELINE_DIR}/logs/nginx:/var/log/nginx:z
- ${SAFELINE_DIR}/resources/cache:/usr/local/nginx/cache
- ${SAFELINE_DIR}/resources/sock:/app/sock
environment:
- TCD_MGT_API=https://${SUBNET_PREFIX}.4:1443/api/open/publish/server
- TCD_SNSERVER=${SUBNET_PREFIX}.5:8000
# deprecated
- SNSERVER_ADDR=${SUBNET_PREFIX}.5:8000
- CHAOS_ADDR=${SUBNET_PREFIX}.10
ulimits:
nofile: 131072
network_mode: host
luigi:
container_name: safeline-luigi
restart: always
image: ${IMAGE_PREFIX}/safeline-luigi-g:${IMAGE_TAG}
image: ${IMAGE_PREFIX}/safeline-luigi${REGION}${ARCH_SUFFIX}${RELEASE}:${IMAGE_TAG}
environment:
- MGT_IP=${SUBNET_PREFIX}.4
- LUIGI_PG=postgres://safeline-ce:${POSTGRES_PASSWORD}@safeline-pg/safeline-ce?sslmode=disable
volumes:
- /etc/localtime:/etc/localtime:ro
- ${SAFELINE_DIR}/resources/luigi:/app/data
@ -126,7 +111,7 @@ services:
fvm:
container_name: safeline-fvm
restart: always
image: ${IMAGE_PREFIX}/safeline-fvm-g:${IMAGE_TAG}
image: ${IMAGE_PREFIX}/safeline-fvm${REGION}${ARCH_SUFFIX}${RELEASE}:${IMAGE_TAG}
volumes:
- /etc/localtime:/etc/localtime:ro
logging:
@ -136,39 +121,19 @@ services:
networks:
safeline-ce:
ipv4_address: ${SUBNET_PREFIX}.8
bridge:
container_name: safeline-bridge
restart: always
image: ${IMAGE_PREFIX}/safeline-bridge-g:${IMAGE_TAG}
command:
- /app/bridge
- serve
- -n
- unix
- -a
- /app/run/safeline.sock
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run:/app/run
logging:
options:
max-size: "100m"
max-file: "5"
networks:
safeline-ce:
ipv4_address: ${SUBNET_PREFIX}.9
depends_on:
- mgt
chaos:
container_name: safeline-chaos
restart: always
image: ${IMAGE_PREFIX}/safeline-chaos-g:${IMAGE_TAG}
image: ${IMAGE_PREFIX}/safeline-chaos${REGION}${ARCH_SUFFIX}${RELEASE}:${IMAGE_TAG}
logging:
options:
max-size: "100m"
max-file: "10"
environment:
- DB_ADDR=postgres://safeline-ce:${POSTGRES_PASSWORD}@safeline-pg/safeline-ce?sslmode=disable
volumes:
- ${SAFELINE_DIR}/resources/sock:/app/sock
- ${SAFELINE_DIR}/resources/chaos:/app/chaos
networks:
safeline-ce:
ipv4_address: ${SUBNET_PREFIX}.10
ipv4_address: ${SUBNET_PREFIX}.10

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

BIN
images/auth-1.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
images/auth-2.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
images/banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

BIN
images/captcha-1.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 KiB

BIN
images/captcha-2.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 806 KiB

BIN
images/dynamic-html-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

BIN
images/dynamic-html-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

BIN
images/dynamic-js-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

BIN
images/dynamic-js-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

BIN
images/how-it-works.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

View file

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 557 KiB

BIN
images/screenshot-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
images/screenshot-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

BIN
images/screenshot-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

BIN
images/screenshot-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

BIN
images/skeleton.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

View file

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View file

@ -1,24 +1,20 @@
module chaitin.cn/patronus/safeline-2/management/tcontrollerd
go 1.18
go 1.21
toolchain go1.21.3
require (
chaitin.cn/dev/go/errors v0.0.0-20210324055134-dc5247602af6
chaitin.cn/dev/go/log v0.0.0-20221220104336-05125760b10c
chaitin.cn/dev/go/settings v0.0.0-20221220104336-05125760b10c
github.com/robfig/cron/v3 v3.0.1
github.com/sirupsen/logrus v1.4.2
google.golang.org/grpc v1.39.0-dev
google.golang.org/protobuf v1.28.1
github.com/sirupsen/logrus v1.9.3
google.golang.org/grpc v1.65.0
)
require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.1 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
gopkg.in/yaml.v2 v2.2.7 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
)

View file

@ -1,4 +1,3 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
chaitin.cn/dev/go/errors v0.0.0-20200717101723-df6132d53dc8/go.mod h1:u+ZD0shdyUt0UG9XfCgD1R5mSqXpTVoO5rwQXQeo3Eo=
chaitin.cn/dev/go/errors v0.0.0-20210324055134-dc5247602af6 h1:1Qa9ABk907/9ZrOLbbRcS8Fqq9VhjAF/mLjbSP1qAJY=
chaitin.cn/dev/go/errors v0.0.0-20210324055134-dc5247602af6/go.mod h1:u+ZD0shdyUt0UG9XfCgD1R5mSqXpTVoO5rwQXQeo3Eo=
@ -6,6 +5,7 @@ chaitin.cn/dev/go/log v0.0.0-20221220104336-05125760b10c h1:Xn9IYkxmnpDcEpV+7JIR
chaitin.cn/dev/go/log v0.0.0-20221220104336-05125760b10c/go.mod h1:xJIYwUoA2TX5mNg/RBrEPyE251BPwj+70/mM7UIhoxg=
chaitin.cn/dev/go/settings v0.0.0-20221220104336-05125760b10c h1:tXsraF7o9iUsQY6IwpDJusc6OFhB7iv/bBTfgR3MPUU=
chaitin.cn/dev/go/settings v0.0.0-20221220104336-05125760b10c/go.mod h1:fUvtmpG8Z8Zf5aciadL9a/vn5SB3knG7pdNJixDplPg=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@ -31,6 +31,7 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@ -48,12 +49,14 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -65,6 +68,7 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -72,11 +76,14 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@ -95,6 +102,7 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.39.0-dev h1:K4VkkiYp4LCvQiW6OiGglzm5nO4Zyryf7pHhzP15cmI=
google.golang.org/grpc v1.39.0-dev/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -108,10 +116,12 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View file

@ -1,61 +1,59 @@
module chaitin.cn/patronus/safeline-2/management/webserver
go 1.18
go 1.21
toolchain go1.21.3
require (
chaitin.cn/dev/go/errors v0.0.0-20210324055134-dc5247602af6
chaitin.cn/dev/go/log v0.0.0-20221220104336-05125760b10c
chaitin.cn/dev/go/settings v0.0.0-20221220104336-05125760b10c
github.com/gin-contrib/sessions v0.0.5
github.com/gin-gonic/gin v1.9.0
github.com/gin-gonic/gin v1.10.0
github.com/pquerna/otp v1.4.0
github.com/robfig/cron/v3 v3.0.1
github.com/rogpeppe/go-internal v1.10.0
github.com/sirupsen/logrus v1.4.2
google.golang.org/grpc v1.54.0
google.golang.org/protobuf v1.28.1
google.golang.org/grpc v1.65.0
gorm.io/datatypes v1.1.1
gorm.io/driver/postgres v1.5.0
gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11
gorm.io/driver/postgres v1.5.9
gorm.io/gorm v1.25.10
)
require (
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/bytedance/sonic v1.8.0 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.11.2 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/go-sql-driver/mysql v1.7.0 // indirect
github.com/goccy/go-json v0.10.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/gorilla/context v1.1.1 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/gorilla/sessions v1.2.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.3.0 // indirect
github.com/jackc/pgx/v5 v5.5.5 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.9 // indirect
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/driver/mysql v1.4.7 // indirect
)

View file

@ -10,9 +10,13 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBW
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA=
github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@ -23,6 +27,7 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8=
github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
@ -30,15 +35,18 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU=
github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@ -54,6 +62,7 @@ github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.3.0 h1:/NQi8KHMpKWHInxXesC8yD4DhkXPrVhmnwYkjp9AmBA=
github.com/jackc/pgx/v5 v5.3.0/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
@ -64,6 +73,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -77,16 +88,20 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
@ -102,6 +117,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -111,18 +127,23 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU=
github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
@ -130,6 +151,7 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -143,6 +165,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@ -152,6 +176,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
@ -163,6 +189,7 @@ google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY7
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
@ -185,9 +212,12 @@ gorm.io/driver/mysql v1.4.7 h1:rY46lkCspzGHn7+IYsNpSfEv9tA+SU4SkkB+GFX125Y=
gorm.io/driver/mysql v1.4.7/go.mod h1:SxzItlnT1cb6e1e4ZRpgJN2VYtcqJgqnHxWr4wsP8oc=
gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U=
gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A=
gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU=
gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11 h1:9qNbmu21nNThCNnF5i2R3kw2aL27U8ZwbzccNjOmW0g=
gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

1261
scripts/manage.py Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,20 @@
package = "ingress-nginx-safeline"
version = "1.0.3-1"
source = {
url = "git://github.com/xbingW/ingress-nginx-safeline.git"
}
description = {
summary = "Ingress-Nginx plugin for Chaitin SafeLine Web Application Firewall",
homepage = "https://github.com/xbingW/ingress-nginx-safeline",
license = "Apache License 2.0",
maintainer = "Xiaobing Wang <xiaobing.wang@chaitin.com>"
}
dependencies = {
"lua-resty-t1k >= 1.1.5"
}
build = {
type = "builtin",
modules = {
["safeline.main"] = "lib/safeline/main.lua"
}
}

View file

@ -0,0 +1,21 @@
package = "kong-safeline"
version = "1.0.2-1"
source = {
url = "git://github.com/xbingW/kong-safeline.git"
}
description = {
summary = "Kong plugin for Chaitin SafeLine Web Application Firewall",
homepage = "https://github.com/xbingW/kong-safeline",
license = "Apache License 2.0",
maintainer = "Xiaobing Wang <xiaobing.wang@chaitin.com>"
}
dependencies = {
"lua-resty-t1k >= 1.1.5"
}
build = {
type = "builtin",
modules = {
["kong.plugins.safeline.handler"] = "kong/plugins/safeline/handler.lua",
["kong.plugins.safeline.schema"] = "kong/plugins/safeline/schema.lua"
}
}

View file

@ -16,6 +16,7 @@ local byte = string.byte
local char = string.char
local fmt = string.format
local sub = string.sub
local concat = table.concat
local ngx = ngx
local nlog = ngx.log
@ -88,6 +89,13 @@ local function get_remote_addr(remote_addr_var, remote_addr_idx)
return addr or ngx_var.remote_addr
end
local function parse_v(v)
if type(v) == "table" then
return concat(v, ", ")
end
return tostring(v)
end
local function build_header()
local http_version = ngx_req.http_version()
if http_version < 2.0 then
@ -101,13 +109,10 @@ local function build_header()
end
local buf = buffer:new()
buf:add(ngx_req.get_method())
buf:add(" ")
buf:add(ngx_var.request_uri)
buf:add(fmt(" HTTP/%.1f\r\n", http_version))
buf:add(fmt("%s %s HTTP/%.1f\r\n", ngx_req.get_method(), ngx_var.request_uri, http_version))
for k, v in pairs(headers) do
buf:add(k .. ": " .. v .. "\r\n")
buf:add(fmt("%s: %s\r\n", k, parse_v(v)))
end
buf:add("\r\n")

View file

@ -0,0 +1,32 @@
package = "lua-resty-t1k"
version = "1.1.5-0"
source = {
url = "git://github.com/chaitin/lua-resty-t1k",
tag = "v1.1.5"
}
description = {
summary = "Lua implementation of the T1K protocol for Chaitin SafeLine Web Application Firewall",
detailed = [[
Check https://waf-ce.chaitin.cn/ for more information about Chaitin SafeLine Web Application Firewall.
]],
homepage = "https://github.com/chaitin/lua-resty-t1k",
license = "Apache License 2.0",
maintainer = "Xudong Wang <xudong.wang@chaitin.com>"
}
build = {
type = "builtin",
modules = {
["resty.t1k"] = "lib/resty/t1k.lua",
["resty.t1k.buffer"] = "lib/resty/t1k/buffer.lua",
["resty.t1k.constants"] = "lib/resty/t1k/constants.lua",
["resty.t1k.file"] = "lib/resty/t1k/file.lua",
["resty.t1k.filter"] = "lib/resty/t1k/filter.lua",
["resty.t1k.handler"] = "lib/resty/t1k/handler.lua",
["resty.t1k.log"] = "lib/resty/t1k/log.lua",
["resty.t1k.request"] = "lib/resty/t1k/request.lua",
["resty.t1k.utils"] = "lib/resty/t1k/utils.lua",
["resty.t1k.uuid"] = "lib/resty/t1k/uuid.lua",
},
}

View file

@ -1,7 +1,7 @@
displayName: Chaitin Safeline WAF
type: middleware
import: github.com/xbingW/traefik-safeline
import: github.com/chaitin/traefik-safeline
summary: 'Traefik plugin to proxy requests to safeline waf.t serves as a reverse proxy access to protect your website from network attacks that including OWASP attacks, zero-day attacks, web crawlers, vulnerability scanning, vulnerability exploit, http flood and so on.'

View file

@ -29,7 +29,7 @@ The following declaration (given here in YAML) defines a plugin:
experimental:
plugins:
safeline:
moduleName: github.com/xbingW/traefik-safeline
moduleName: github.com/chaitin/traefik-safeline
version: v1.0.0
```

View file

@ -1,5 +1,7 @@
module github.com/xbingW/traefik-safeline
module github.com/chaitin/traefik-safeline
go 1.17
require github.com/xbingW/t1k v1.2.1
require golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
require github.com/chaitin/t1k-go v1.5.0

View file

@ -2,12 +2,13 @@ package traefik_safeline
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"sync"
"github.com/xbingW/t1k"
t1k "github.com/chaitin/t1k-go"
)
// Package example a example plugin.
@ -15,61 +16,84 @@ import (
// Config the plugin configuration.
type Config struct {
// Addr is the address for the detector
Addr string `yaml:"addr"`
// Get ip from header, if not set, get ip from remote addr
IpHeader string `yaml:"ipHeader"`
// When ip_header has multiple ip, use this to get the ip
//
//for example, X-Forwarded-For: ip1, ip2, ip3
// when ip_last_index is 0, the client ip is ip3
// when ip_last_index is 1, the client ip is ip2
// when ip_last_index is 2, the client ip is ip1
IPRightIndex uint `yaml:"ipRightIndex"`
Addr string `yaml:"addr"`
PoolSize int `yaml:"pool_size"`
}
// CreateConfig creates the default plugin configuration.
func CreateConfig() *Config {
return &Config{
Addr: "",
IpHeader: "",
IPRightIndex: 0,
Addr: "",
PoolSize: 100,
}
}
// Safeline a plugin.
type Safeline struct {
next http.Handler
server *t1k.Server
name string
config *Config
logger *log.Logger
mu sync.Mutex
}
// New created a new plugin.
func New(ctx context.Context, next http.Handler, config *Config, name string) (http.Handler, error) {
logger := log.New(os.Stdout, "safeline", log.LstdFlags)
logger.Printf("config: %+v", config)
return &Safeline{
next: next,
name: name,
config: config,
logger: log.New(os.Stdout, "safeline", log.LstdFlags),
logger: logger,
}, nil
}
func (s *Safeline) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
d := t1k.NewDetector(t1k.Config{
Addr: s.config.Addr,
IpHeader: s.config.IpHeader,
IPRightIndex: s.config.IPRightIndex,
})
resp, err := d.DetectorRequest(req)
if err != nil {
s.logger.Printf("Failed to detect request: %v", err)
func (s *Safeline) initServer() error {
if s.server != nil {
return nil
}
if resp != nil && !resp.Allowed() {
rw.WriteHeader(resp.StatusCode())
if err := json.NewEncoder(rw).Encode(resp.BlockMessage()); err != nil {
s.logger.Printf("Failed to encode block message: %v", err)
s.mu.Lock()
defer s.mu.Unlock()
if s.server == nil {
server, err := t1k.NewWithPoolSize(s.config.Addr, s.config.PoolSize)
if err != nil {
return err
}
s.server = server
}
return nil
}
func (s *Safeline) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
defer func() {
if r := recover(); r != nil {
s.logger.Printf("panic: %s", r)
}
}()
if err := s.initServer(); err != nil {
s.logger.Printf("error in initServer: %s", err)
s.next.ServeHTTP(rw, req)
return
}
rw.Header().Set("X-Chaitin-waf", "safeline")
result, err := s.server.DetectHttpRequest(req)
if err != nil {
s.logger.Printf("error in detection: \n%+v\n", err)
s.next.ServeHTTP(rw, req)
return
}
if result.Blocked() {
rw.WriteHeader(result.StatusCode())
msg := fmt.Sprintf(`{"code": %d, "success":false, "message": "blocked by Chaitin SafeLine Web Application Firewall", "event_id": "%s"}`,
result.StatusCode(),
result.EventID(),
)
_, _ = rw.Write([]byte(msg))
return
}
s.next.ServeHTTP(rw, req)
//rw.WriteHeader(http.StatusForbidden)
//_, _ = rw.Write([]byte("Inject by safeline\n"))
}

201
sdk/traefik/vendor/github.com/chaitin/t1k-go/License generated vendored Normal file
View file

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2023 Beijing Chaitin Technology Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -0,0 +1,5 @@
# t1k-go
Go implementation of the T1K protocol for [Chaitin/SafeLine](https://github.com/chaitin/safeline) Web Application Firewall.

101
sdk/traefik/vendor/github.com/chaitin/t1k-go/conn.go generated vendored Normal file
View file

@ -0,0 +1,101 @@
package t1k
import (
"net"
"net/http"
"github.com/chaitin/t1k-go/detection"
"github.com/chaitin/t1k-go/t1k"
"github.com/chaitin/t1k-go/misc"
)
type conn struct {
socket net.Conn
server *Server
failing bool
}
func makeConn(socket net.Conn, server *Server) *conn {
return &conn{
socket: socket,
server: server,
failing: false,
}
}
func (c *conn) onErr(err error) {
if err != nil {
// re-open socket to recover from possible error state
c.socket.Close()
sock, errConnect := c.server.socketFactory()
if errConnect != nil {
c.failing = true
return
}
c.socket = sock
}
}
func (c *conn) Close() {
if c.socket == nil {
return
}
c.socket.Close()
}
func (c *conn) DetectRequestInCtx(dc *detection.DetectionContext) (*detection.Result, error) {
ret, err := DetectRequestInCtx(c.socket, dc)
c.onErr(err)
return ret, err
}
func (c *conn) DetectResponseInCtx(dc *detection.DetectionContext) (*detection.Result, error) {
ret, err := DetectResponseInCtx(c.socket, dc)
c.onErr(err)
return ret, misc.ErrorWrap(err, "")
}
func (c *conn) Detect(dc *detection.DetectionContext) (*detection.Result, *detection.Result, error) {
retReq, retRsp, err := Detect(c.socket, dc)
c.onErr(err)
return retReq, retRsp, misc.ErrorWrap(err, "")
}
func (c *conn) DetectHttpRequest(req *http.Request) (*detection.Result, error) {
ret, err := DetectHttpRequest(c.socket, req)
c.onErr(err)
return ret, err
}
func (c *conn) DetectRequest(req detection.Request) (*detection.Result, error) {
ret, err := DetectRequest(c.socket, req)
c.onErr(err)
return ret, err
}
func (c *conn) Heartbeat() {
err := DoHeartbeat(c.socket)
c.onErr(err)
}
func (c *conn) WriteSection(sec t1k.Section) error {
err := t1k.WriteSection(sec, c.socket)
return misc.ErrorWrap(err, "")
}
func (c *conn) ReadSection() (t1k.Section, error) {
sec, err := t1k.ReadSection(c.socket)
if err != nil {
return nil, misc.ErrorWrap(err, "")
}
return sec, nil
}
func (c *conn) ReadFullSection() (t1k.Section, error) {
sec, err := t1k.ReadFullSection(c.socket)
if err != nil {
return nil, misc.ErrorWrap(err, "")
}
return sec, nil
}

253
sdk/traefik/vendor/github.com/chaitin/t1k-go/detect.go generated vendored Normal file
View file

@ -0,0 +1,253 @@
package t1k
import (
"bytes"
"fmt"
"io"
"net/http"
"github.com/chaitin/t1k-go/detection"
"github.com/chaitin/t1k-go/t1k"
"github.com/chaitin/t1k-go/misc"
)
func writeDetectionRequest(w io.Writer, req detection.Request) error {
{
data, err := req.Header()
if err != nil {
return err
}
sec := t1k.MakeSimpleSection(t1k.TAG_HEADER|t1k.MASK_FIRST, data)
err = t1k.WriteSection(sec, w)
if err != nil {
return err
}
}
{
bodySize, bodyReadCloser, err := req.Body()
if err == nil {
defer bodyReadCloser.Close()
sec := t1k.MakeReaderSection(t1k.TAG_BODY, bodySize, bodyReadCloser)
err = t1k.WriteSection(sec, w)
if err != nil {
return err
}
}
}
{
data, err := req.Extra()
if err != nil {
return err
}
sec := t1k.MakeSimpleSection(t1k.TAG_EXTRA, data)
err = t1k.WriteSection(sec, w)
if err != nil {
return err
}
}
{
sec := t1k.MakeSimpleSection(t1k.TAG_VERSION|t1k.MASK_LAST, []byte("Proto:2\n"))
err := t1k.WriteSection(sec, w)
if err != nil {
return err
}
}
return nil
}
func writeDetectionResponse(w io.Writer, rsp detection.Response) error {
{
data, err := rsp.RequestHeader()
if err != nil {
return misc.ErrorWrap(err, "")
}
sec := t1k.MakeSimpleSection(t1k.TAG_HEADER|t1k.MASK_FIRST, data)
err = t1k.WriteSection(sec, w)
if err != nil {
return misc.ErrorWrap(err, "")
}
}
{
data, err := rsp.Header()
if err != nil {
return misc.ErrorWrap(err, "")
}
sec := t1k.MakeSimpleSection(t1k.TAG_RSP_HEADER, data)
err = t1k.WriteSection(sec, w)
if err != nil {
return misc.ErrorWrap(err, "")
}
}
{
bodySize, bodyReadCloser, err := rsp.Body()
if err == nil {
defer bodyReadCloser.Close()
sec := t1k.MakeReaderSection(t1k.TAG_RSP_BODY, bodySize, bodyReadCloser)
err = t1k.WriteSection(sec, w)
if err != nil {
return err
}
}
}
{
data, err := rsp.Extra()
if err != nil {
return misc.ErrorWrap(err, "")
}
sec := t1k.MakeSimpleSection(t1k.TAG_RSP_EXTRA, data)
err = t1k.WriteSection(sec, w)
if err != nil {
return misc.ErrorWrap(err, "")
}
}
{
sec := t1k.MakeSimpleSection(t1k.TAG_VERSION, []byte("Proto:2\n"))
err := t1k.WriteSection(sec, w)
if err != nil {
return misc.ErrorWrap(err, "")
}
}
{
data, err := rsp.T1KContext()
if err != nil {
return misc.ErrorWrap(err, "")
}
sec := t1k.MakeSimpleSection(t1k.TAG_CONTEXT|t1k.MASK_LAST, data)
err = t1k.WriteSection(sec, w)
if err != nil {
return misc.ErrorWrap(err, "")
}
}
return nil
}
func readDetectionResult(r io.Reader) (*detection.Result, error) {
var ret detection.Result
parseSection := func(sec t1k.Section) error {
var buf bytes.Buffer
err := sec.WriteBody(&buf)
if err != nil {
return misc.ErrorWrap(err, "")
}
tag := sec.Header().Tag.Strip()
switch tag {
case t1k.TAG_HEADER:
if len(buf.Bytes()) != 1 {
return fmt.Errorf("len(T1K_HEADER) != 1")
}
ret.Head = buf.Bytes()[0]
case t1k.TAG_BODY:
ret.Body = buf.Bytes()
case t1k.TAG_ALOG:
ret.Alog = buf.Bytes()
case t1k.TAG_EXTRA_HEADER:
ret.ExtraHeader = buf.Bytes()
case t1k.TAG_EXTRA_BODY:
ret.ExtraBody = buf.Bytes()
case t1k.TAG_CONTEXT:
ret.T1KContext = buf.Bytes()
case t1k.TAG_COOKIE:
ret.Cookie = buf.Bytes()
case t1k.TAG_WEB_LOG:
ret.WebLog = buf.Bytes()
}
return nil
}
sec, err := t1k.ReadFullSection(r)
if err != nil {
return nil, misc.ErrorWrap(err, "")
}
if !sec.Header().Tag.IsFirst() {
return nil, fmt.Errorf("first section IsFirst != true, middle of another msg or corrupt stream, with <%x>", sec.Header().Tag)
}
for {
err = parseSection(sec)
if err != nil {
return nil, misc.ErrorWrap(err, "")
}
if sec.Header().Tag.IsLast() {
break
}
sec, err = t1k.ReadSection(r)
if err != nil {
return nil, misc.ErrorWrap(err, "")
}
}
return &ret, nil
}
func doDetectRequest(s io.ReadWriter, req detection.Request) (*detection.Result, error) {
err := writeDetectionRequest(s, req)
if err != nil {
return nil, misc.ErrorWrap(err, "")
}
ret, err := readDetectionResult(s)
if err != nil {
return nil, misc.ErrorWrap(err, "")
}
ret.Objective = detection.RO_REQUEST
return ret, nil
}
func doDetectResponse(s io.ReadWriter, rsp detection.Response) (*detection.Result, error) {
err := writeDetectionResponse(s, rsp)
if err != nil {
return nil, misc.ErrorWrap(err, "")
}
ret, err := readDetectionResult(s)
if err != nil {
return nil, misc.ErrorWrap(err, "")
}
ret.Objective = detection.RO_RESPONSE
return ret, nil
}
func DetectRequestInCtx(s io.ReadWriter, dc *detection.DetectionContext) (*detection.Result, error) {
ret, err := doDetectRequest(s, dc.Request)
if err != nil {
return nil, err
}
dc.ProcessResult(ret)
return ret, nil
}
func DetectResponseInCtx(s io.ReadWriter, dc *detection.DetectionContext) (*detection.Result, error) {
ret, err := doDetectResponse(s, dc.Response)
if err != nil {
return nil, misc.ErrorWrap(err, "")
}
dc.ProcessResult(ret)
return ret, nil
}
func Detect(s io.ReadWriter, dc *detection.DetectionContext) (*detection.Result, *detection.Result, error) {
var reqResult *detection.Result
var rspResult *detection.Result
if dc.Request != nil {
ret, err := doDetectRequest(s, dc.Request)
if err != nil {
return nil, nil, misc.ErrorWrap(err, "")
}
reqResult = ret
dc.ProcessResult(reqResult)
}
if dc.Response != nil {
ret, err := doDetectResponse(s, dc.Response)
if err != nil {
return nil, nil, misc.ErrorWrap(err, "")
}
rspResult = ret
dc.ProcessResult(rspResult)
}
return reqResult, rspResult, nil
}
func DetectHttpRequest(s io.ReadWriter, req *http.Request) (*detection.Result, error) {
dc, _ := detection.MakeContextWithRequest(req)
return doDetectRequest(s, detection.MakeHttpRequestInCtx(req, dc))
}
func DetectRequest(s io.ReadWriter, req detection.Request) (*detection.Result, error) {
return doDetectRequest(s, req)
}

View file

@ -0,0 +1,88 @@
package detection
import (
"errors"
"net/http"
"github.com/chaitin/t1k-go/misc"
)
type DetectionContext struct {
UUID string
Scheme string
ProxyName string
RemoteAddr string
Protocol string
RemotePort uint16
LocalAddr string
LocalPort uint16
ReqBeginTime int64
RspBeginTime int64
T1KContext []byte
Request Request
Response Response
}
func New() *DetectionContext {
return &DetectionContext{
UUID: misc.GenUUID(),
Scheme: "http",
ProxyName: "go-sdk",
RemoteAddr: "127.0.0.1",
RemotePort: 30001,
LocalAddr: "127.0.0.1",
LocalPort: 80,
Protocol: "HTTP/1.1",
}
}
func MakeContextWithRequest(req *http.Request) (*DetectionContext, error) {
if req == nil {
return nil, errors.New("nil http.request or response")
}
wrapReq := &HttpRequest{
req: req,
}
// ignore GetRemoteIP error,not sure request record remote ip
remoteIP, _ := wrapReq.GetRemoteIP()
remotePort, _ := wrapReq.GetRemotePort()
localAddr, err := wrapReq.GetUpstreamAddress()
if err != nil {
return nil, err
}
localPort, err := wrapReq.GetUpstreamPort()
if err != nil {
return nil, err
}
scheme := "http"
if req.TLS != nil {
scheme = "https"
}
context := &DetectionContext{
UUID: misc.GenUUID(),
Scheme: scheme,
ProxyName: "go-sdk",
RemoteAddr: remoteIP,
RemotePort: remotePort,
LocalAddr: localAddr,
LocalPort: localPort,
ReqBeginTime: misc.Now(),
Request: wrapReq,
Protocol: req.Proto,
}
wrapReq.dc = context
return context, nil
}
func (dc *DetectionContext) ProcessResult(r *Result) {
if r.Objective == RO_REQUEST {
dc.T1KContext = r.T1KContext
}
}

View file

@ -0,0 +1,93 @@
package detection
import (
"fmt"
"github.com/chaitin/t1k-go/misc"
)
func MakeRequestExtra(
scheme string,
proxyName string,
remoteAddr string,
remotePort uint16,
localAddr string,
localPort uint16,
uuid string,
hasRspIfOK string,
hasRspIfBlock string,
reqBeginTime int64,
) []byte {
format := "Scheme:%s\n" +
"ProxyName:%s\n" +
"RemoteAddr:%s\n" +
"RemotePort:%d\n" +
"LocalAddr:%s\n" +
"LocalPort:%d\n" +
"UUID:%s\n" +
"HasRspIfOK:%s\n" +
"HasRspIfBlock:%s\n" +
"ReqBeginTime:%d\n"
return []byte(fmt.Sprintf(
format,
scheme,
proxyName,
remoteAddr,
remotePort,
localAddr,
localPort,
uuid,
hasRspIfOK,
hasRspIfBlock,
reqBeginTime,
))
}
func MakeResponseExtra(
scheme string,
proxyName string,
remoteAddr string,
remotePort uint16,
localAddr string,
localPort uint16,
uuid string,
rspBeginTime int64,
) []byte {
format := "Scheme:%s\n" +
"ProxyName:%s\n" +
"RemoteAddr:%s\n" +
"RemotePort:%d\n" +
"LocalAddr:%s\n" +
"LocalPort:%d\n" +
"UUID:%s\n" +
"RspBeginTime:%d\n"
return []byte(fmt.Sprintf(
format,
scheme,
proxyName,
remoteAddr,
remotePort,
localAddr,
localPort,
uuid,
rspBeginTime,
))
}
func PlaceholderRequestExtra(uuid string) []byte {
return MakeRequestExtra("http", "go-sdk", "127.0.0.1", 30001, "127.0.0.1", 80, uuid, "n", "n", misc.Now())
}
func GenRequestExtra(dc *DetectionContext) []byte {
hasRsp := "u"
if dc.Response != nil {
hasRsp = "y"
}
return MakeRequestExtra(dc.Scheme, dc.ProxyName, dc.RemoteAddr, dc.RemotePort, dc.LocalAddr, dc.LocalPort, dc.UUID, hasRsp, hasRsp, dc.ReqBeginTime)
}
func GenResponseExtra(dc *DetectionContext) []byte {
return MakeResponseExtra(dc.Scheme, dc.ProxyName, dc.RemoteAddr, dc.RemotePort, dc.LocalAddr, dc.LocalPort, dc.UUID, dc.RspBeginTime)
}

View file

@ -0,0 +1,132 @@
package detection
import (
"bytes"
"errors"
"fmt"
"io"
"net"
"net/http"
"strconv"
"github.com/chaitin/t1k-go/misc"
)
type Request interface {
Header() ([]byte, error)
Body() (uint32, io.ReadCloser, error)
Extra() ([]byte, error)
}
type HttpRequest struct {
req *http.Request
dc *DetectionContext // this is optional
}
func MakeHttpRequest(req *http.Request) *HttpRequest {
return &HttpRequest{
req: req,
}
}
func MakeHttpRequestInCtx(req *http.Request, dc *DetectionContext) *HttpRequest {
ret := &HttpRequest{
req: req,
dc: dc,
}
dc.Request = ret
if dc.ReqBeginTime == 0 {
dc.ReqBeginTime = misc.Now()
}
return ret
}
func (r *HttpRequest) GetUpstreamAddress() (string, error) {
if r.req.Host == "" {
return "", errors.New("empty Host in request")
}
host, _, err := net.SplitHostPort(r.req.Host)
if err != nil {
return r.req.Host, nil // OK; there probably was no port
}
return host, nil
}
func (r *HttpRequest) GetUpstreamPort() (uint16, error) {
_, port, err := net.SplitHostPort(r.req.Host)
if err != nil {
if r.req.TLS != nil {
return 443, nil
} else {
return 80, nil
}
}
if portNum, err := strconv.Atoi(port); err == nil {
return uint16(portNum), nil
}
return 0, errors.New("wrong value of port")
}
func (r *HttpRequest) GetRemoteIP() (string, error) {
host, _, err := net.SplitHostPort(r.req.RemoteAddr)
if err != nil {
return r.req.RemoteAddr, nil
}
return host, nil
}
func (r *HttpRequest) GetRemotePort() (uint16, error) {
_, port, _ := net.SplitHostPort(r.req.RemoteAddr)
if portNum, err := strconv.Atoi(port); err == nil {
return uint16(portNum), nil
}
return 0, errors.New("wrong value of port")
}
func (r *HttpRequest) Header() ([]byte, error) {
var buf bytes.Buffer
proto := r.req.Proto
if r.dc != nil {
if r.dc.Protocol != "" {
proto = r.dc.Protocol
} else {
r.dc.Protocol = proto
}
}
startLine := fmt.Sprintf("%s %s %s\r\n", r.req.Method, r.req.URL.RequestURI(), proto)
_, err := buf.Write([]byte(startLine))
if err != nil {
return nil, err
}
_, err = buf.Write([]byte(fmt.Sprintf("Host: %s\r\n", r.req.Host)))
if err != nil {
return nil, err
}
err = r.req.Header.Write(&buf)
if err != nil {
return nil, err
}
_, err = buf.Write([]byte("\r\n"))
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func (r *HttpRequest) Body() (uint32, io.ReadCloser, error) {
bodyBytes, err := io.ReadAll(r.req.Body)
if err != nil {
return 0, nil, err
}
r.req.Body = io.NopCloser(bytes.NewReader(bodyBytes))
return uint32(len(bodyBytes)), io.NopCloser(bytes.NewReader(bodyBytes)), nil
}
func (r *HttpRequest) Extra() ([]byte, error) {
if r.dc == nil {
return PlaceholderRequestExtra(misc.GenUUID()), nil
}
return GenRequestExtra(r.dc), nil
}

View file

@ -0,0 +1,72 @@
package detection
import (
"bytes"
"fmt"
"io"
"net/http"
"github.com/chaitin/t1k-go/misc"
)
type Response interface {
RequestHeader() ([]byte, error)
Header() ([]byte, error)
Body() (uint32, io.ReadCloser, error)
Extra() ([]byte, error)
T1KContext() ([]byte, error)
}
type HttpResponse struct {
rsp *http.Response
dc *DetectionContext // this is a must-have
}
func MakeHttpResponseInCtx(rsp *http.Response, dc *DetectionContext) *HttpResponse {
ret := &HttpResponse{
rsp: rsp,
dc: dc,
}
dc.Response = ret
dc.RspBeginTime = misc.Now()
return ret
}
func (r *HttpResponse) RequestHeader() ([]byte, error) {
return r.dc.Request.Header()
}
func (r *HttpResponse) Header() ([]byte, error) {
var buf bytes.Buffer
statusLine := fmt.Sprintf("HTTP/1.1 %s\n", r.rsp.Status)
_, err := buf.Write([]byte(statusLine))
if err != nil {
return nil, err
}
err = r.rsp.Header.Write(&buf)
if err != nil {
return nil, err
}
_, err = buf.Write([]byte("\r\n"))
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func (r *HttpResponse) Body() (uint32, io.ReadCloser, error) {
bodyBytes, err := io.ReadAll(r.rsp.Body)
if err != nil {
return 0, nil, misc.ErrorWrapf(err, "get body size %d", len(bodyBytes))
}
r.rsp.Body = io.NopCloser(bytes.NewReader(bodyBytes))
return uint32(len(bodyBytes)), io.NopCloser(bytes.NewReader(bodyBytes)), nil
}
func (r *HttpResponse) Extra() ([]byte, error) {
return GenResponseExtra(r.dc), nil
}
func (r *HttpResponse) T1KContext() ([]byte, error) {
return r.dc.T1KContext, nil
}

View file

@ -0,0 +1,76 @@
package detection
import (
"log"
"net/http"
"regexp"
"strconv"
)
type ResultObjective int
const (
RO_REQUEST ResultObjective = 0
RO_RESPONSE ResultObjective = 1
)
type Result struct {
Objective ResultObjective
Head byte
Body []byte
Alog []byte
ExtraHeader []byte
ExtraBody []byte
T1KContext []byte
Cookie []byte
WebLog []byte
}
func (r *Result) Passed() bool {
return r.Head == '.'
}
func (r *Result) Blocked() bool {
return !r.Passed()
}
func (r *Result) StatusCode() int {
str := string(r.Body)
if str == "" {
return http.StatusForbidden
}
code, err := strconv.Atoi(str)
if err != nil {
log.Printf("t1k convert status code failed: %v", err)
return http.StatusForbidden
}
return code
}
func (r *Result) BlockMessage() map[string]interface{} {
return map[string]interface{}{
"status": r.StatusCode(),
"success": false,
"message": "blocked by Chaitin SafeLine Web Application Firewall",
"event_id": r.EventID(),
}
}
func (r *Result) EventID() string {
extra := string(r.ExtraBody)
if extra == "" {
return ""
}
// <!-- event_id: e1impksyjq0gl92le6odi0fnobi270cj -->
re, err := regexp.Compile(`<\!--\s*event_id:\s*([a-zA-Z0-9]+)\s*-->\s*`)
if err != nil {
log.Printf("t1k compile regexp failed: %v", err)
return ""
}
matches := re.FindStringSubmatch(extra)
if len(matches) < 2 {
log.Printf("t1k regexp not match event id: %s", extra)
return ""
}
return matches[1]
}

View file

@ -0,0 +1,17 @@
package t1k
import (
"io"
"github.com/chaitin/t1k-go/t1k"
)
func DoHeartbeat(s io.ReadWriter) error {
h := t1k.MakeHeader(t1k.MASK_FIRST|t1k.MASK_LAST, 0)
_, err := s.Write(h.Serialize())
if err != nil {
return err
}
_, err = readDetectionResult(s)
return err
}

View file

@ -0,0 +1,81 @@
package misc
import (
"fmt"
"io"
"os"
)
var asciiPrintableMap map[byte]bool
func init() {
asciiPrintableMap = make(map[byte]bool)
for i := 0; i < 256; i++ {
asciiPrintableMap[byte(i)] = false
}
s := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ "
for _, ch := range []byte(s) {
asciiPrintableMap[ch] = true
}
}
func isAsciiPrintable(b byte) bool {
return asciiPrintableMap[b]
}
func DumpHex(w io.Writer, b []byte) error {
lines := len(b) / 16
for i := 0; i < lines; i += 1 {
srep := ""
for j := 0; j < 16; j += 1 {
it := b[16*i+j]
_, err := w.Write([]byte(fmt.Sprintf("%02x ", it)))
if err != nil {
return err
}
if isAsciiPrintable(it) {
srep += string([]byte{it})
} else {
srep += "."
}
}
_, err := w.Write([]byte("| " + srep + "\n"))
if err != nil {
return err
}
}
remain := len(b) - 16*lines
srep := ""
j := 0
for ; j < remain; j += 1 {
it := b[16*lines+j]
_, err := w.Write([]byte(fmt.Sprintf("%02x ", it)))
if err != nil {
return err
}
if isAsciiPrintable(it) {
srep += string([]byte{it})
} else {
srep += "."
}
}
for ; j < 16; j++ {
_, err := w.Write([]byte(" "))
if err != nil {
return err
}
srep += " "
}
_, err := w.Write([]byte("| " + srep + "\n"))
if err != nil {
return err
}
return nil
}
func PrintHex(b []byte) {
err := DumpHex(os.Stdout, b)
if err != nil {
fmt.Printf("error in PrintHex() : %s\n", err.Error())
}
}

View file

@ -0,0 +1,58 @@
package misc
import (
"fmt"
"golang.org/x/xerrors"
)
type wrapError struct {
message string
next error
frame xerrors.Frame
}
func (e *wrapError) Unwrap() error {
return e.next
}
func (e *wrapError) Error() string {
if e.next == nil {
return e.message
}
return fmt.Sprintf("%s: %v", e.message, e.next)
}
func (e *wrapError) Format(f fmt.State, c rune) {
xerrors.FormatError(e, f, c)
}
func (e *wrapError) FormatError(p xerrors.Printer) error {
p.Print(e.message)
if p.Detail() {
e.frame.Format(p)
}
return e.next
}
func wrap(err error, message string, skip int) error {
if err == nil {
return nil
}
return &wrapError{
message: message,
next: err,
frame: xerrors.Caller(skip),
}
}
// Wrap returns a error annotating `err` with `message` and the caller's frame.
// Wrap returns nil if `err` is nil.
func ErrorWrap(err error, message string) error {
return wrap(err, message, 2)
}
// Wrapf returns a error annotating `err` with `message` formatted and the caller's frame.
func ErrorWrapf(err error, message string, args ...interface{}) error {
return wrap(err, fmt.Sprintf(message, args...), 2)
}

View file

@ -0,0 +1,17 @@
package misc
import (
"encoding/hex"
)
var (
rng *MT19937 = NewMT19937()
)
func GenUUID() string {
u := make([]byte, 16)
rng.RandBytes(u)
u[6] = (u[6] | 0x40) & 0x4F
u[8] = (u[8] | 0x80) & 0xBF
return hex.EncodeToString(u)
}

View file

@ -0,0 +1,102 @@
package misc
import (
"crypto/rand"
"encoding/binary"
"sync"
"time"
)
const (
n = 312
m = 156
seedMask = 170298
hiMask uint64 = 0xffffffff80000000
loMask uint64 = 0x000000007fffffff
matrixA uint64 = 0xB5026F5AA96619E9
)
type MT19937 struct {
state []uint64
index int
mut sync.Mutex
}
func NewMT19937WithSeed(seed int64) *MT19937 {
mt := &MT19937{
state: make([]uint64, n),
index: n,
}
mt.mut.Lock()
defer mt.mut.Unlock()
mt.state[0] = uint64(seed)
for i := uint64(1); i < n; i++ {
mt.state[i] = 6364136223846793005*(mt.state[i-1]^(mt.state[i-1]>>62)) + i
}
return mt
}
func NewMT19937() *MT19937 {
var seed int64
b := make([]byte, 8)
if _, err := rand.Read(b); err == nil {
seed = int64(binary.LittleEndian.Uint64(b[:]))
}
seed = seed ^ time.Now().UnixNano() ^ seedMask
return NewMT19937WithSeed(seed)
}
func (mt *MT19937) Uint64() uint64 {
mt.mut.Lock()
defer mt.mut.Unlock()
x := mt.state
if mt.index >= n {
for i := 0; i < n-m; i++ {
y := (x[i] & hiMask) | (x[i+1] & loMask)
x[i] = x[i+m] ^ (y >> 1) ^ ((y & 1) * matrixA)
}
for i := n - m; i < n-1; i++ {
y := (x[i] & hiMask) | (x[i+1] & loMask)
x[i] = x[i+(m-n)] ^ (y >> 1) ^ ((y & 1) * matrixA)
}
y := (x[n-1] & hiMask) | (x[0] & loMask)
x[n-1] = x[m-1] ^ (y >> 1) ^ ((y & 1) * matrixA)
mt.index = 0
}
y := x[mt.index]
y ^= (y >> 29) & 0x5555555555555555
y ^= (y << 17) & 0x71D67FFFEDA60000
y ^= (y << 37) & 0xFFF7EEE000000000
y ^= (y >> 43)
mt.index++
return y
}
func (mt *MT19937) RandBytes(p []byte) {
for len(p) >= 8 {
val := mt.Uint64()
p[0] = byte(val)
p[1] = byte(val >> 8)
p[2] = byte(val >> 16)
p[3] = byte(val >> 24)
p[4] = byte(val >> 32)
p[5] = byte(val >> 40)
p[6] = byte(val >> 48)
p[7] = byte(val >> 56)
p = p[8:]
}
if len(p) > 0 {
val := mt.Uint64()
for i := 0; i < len(p); i++ {
p[i] = byte(val)
val >>= 8
}
}
}

View file

@ -0,0 +1,9 @@
package misc
import (
"time"
)
func Now() int64 {
return time.Now().UnixNano() / 1e3
}

184
sdk/traefik/vendor/github.com/chaitin/t1k-go/server.go generated vendored Normal file
View file

@ -0,0 +1,184 @@
package t1k
import (
"log"
"net"
"net/http"
"os"
"sync"
"time"
"github.com/chaitin/t1k-go/detection"
"github.com/chaitin/t1k-go/misc"
)
const (
DEFAULT_POOL_SIZE = 8
HEARTBEAT_INTERVAL = 20
)
type Server struct {
socketFactory func() (net.Conn, error)
poolCh chan *conn
poolSize int
count int
closeCh chan struct{}
logger *log.Logger
mu sync.Mutex
}
func (s *Server) newConn() error {
s.mu.Lock()
defer s.mu.Unlock()
sock, err := s.socketFactory()
if err != nil {
return err
}
s.count += 1
s.poolCh <- makeConn(sock, s)
return nil
}
func (s *Server) GetConn() (*conn, error) {
if s.count < s.poolSize {
for i := 0; i < (s.poolSize - s.count); i++ {
err := s.newConn()
if err != nil {
return nil, err
}
}
}
c := <-s.poolCh
return c, nil
}
func (s *Server) PutConn(c *conn) {
s.mu.Lock()
defer s.mu.Unlock()
if c.failing {
s.count -= 1
c.Close()
} else {
s.poolCh <- c
}
}
func (s *Server) broadcastHeartbeat() {
l := len(s.poolCh)
for i := 0; i < l; i++ {
select {
case c := <-s.poolCh:
c.Heartbeat()
s.PutConn(c)
default:
return
}
}
}
func (s *Server) runHeartbeatCo() {
for {
timer := time.NewTimer(HEARTBEAT_INTERVAL * time.Second)
select {
case <-s.closeCh:
return
case <-timer.C:
}
s.broadcastHeartbeat()
}
}
func NewFromSocketFactoryWithPoolSize(socketFactory func() (net.Conn, error), poolSize int) (*Server, error) {
ret := &Server{
socketFactory: socketFactory,
poolCh: make(chan *conn, poolSize),
poolSize: poolSize,
closeCh: make(chan struct{}),
logger: log.New(os.Stdout, "snserver", log.LstdFlags),
mu: sync.Mutex{},
}
for i := 0; i < poolSize; i++ {
err := ret.newConn()
if err != nil {
return nil, err
}
}
go ret.runHeartbeatCo()
return ret, nil
}
func NewFromSocketFactory(socketFactory func() (net.Conn, error)) (*Server, error) {
return NewFromSocketFactoryWithPoolSize(socketFactory, DEFAULT_POOL_SIZE)
}
func NewWithPoolSize(addr string, poolSize int) (*Server, error) {
return NewFromSocketFactoryWithPoolSize(func() (net.Conn, error) {
return net.Dial("tcp", addr)
}, poolSize)
}
func New(addr string) (*Server, error) {
return NewWithPoolSize(addr, DEFAULT_POOL_SIZE)
}
func (s *Server) DetectRequestInCtx(dc *detection.DetectionContext) (*detection.Result, error) {
c, err := s.GetConn()
if err != nil {
return nil, err
}
defer s.PutConn(c)
return c.DetectRequestInCtx(dc)
}
func (s *Server) DetectResponseInCtx(dc *detection.DetectionContext) (*detection.Result, error) {
c, err := s.GetConn()
if err != nil {
return nil, misc.ErrorWrap(err, "")
}
defer s.PutConn(c)
return c.DetectResponseInCtx(dc)
}
func (s *Server) Detect(dc *detection.DetectionContext) (*detection.Result, *detection.Result, error) {
c, err := s.GetConn()
if err != nil {
return nil, nil, misc.ErrorWrap(err, "")
}
reqResult, rspResult, err := c.Detect(dc)
if err == nil {
s.PutConn(c)
}
return reqResult, rspResult, err
}
func (s *Server) DetectHttpRequest(req *http.Request) (*detection.Result, error) {
c, err := s.GetConn()
if err != nil {
return nil, err
}
defer s.PutConn(c)
return c.DetectHttpRequest(req)
}
func (s *Server) DetectRequest(req detection.Request) (*detection.Result, error) {
c, err := s.GetConn()
if err != nil {
return nil, err
}
defer s.PutConn(c)
return c.DetectRequest(req)
}
// blocks until all pending detection is completed
func (s *Server) Close() {
close(s.closeCh)
for i := 0; i < s.count; i++ {
c, err := s.GetConn()
if err != nil {
return
}
c.Close()
}
}

View file

@ -0,0 +1,35 @@
package t1k
import (
"encoding/binary"
)
const (
T1K_HEADER_SIZE uint64 = 5
)
type Header struct {
Tag Tag
Size uint32
}
func MakeHeader(tag Tag, size uint32) Header {
return Header{
Tag: tag,
Size: size,
}
}
func (h Header) Serialize() []byte {
b := make([]byte, 5)
b[0] = byte(uint8(h.Tag))
binary.LittleEndian.PutUint32(b[1:], h.Size)
return b
}
func DeserializeHeader(b []byte) Header {
return MakeHeader(
Tag(uint8(b[0])),
binary.LittleEndian.Uint32(b[1:]),
)
}

View file

@ -0,0 +1,95 @@
package t1k
import (
"bytes"
"io"
"github.com/chaitin/t1k-go/misc"
)
type Section interface {
Header() Header
WriteBody(io.Writer) error
}
type SimpleSection struct {
tag Tag
body []byte
}
func MakeSimpleSection(tag Tag, body []byte) *SimpleSection {
return &SimpleSection{
tag: tag,
body: body,
}
}
func (msg *SimpleSection) Header() Header {
return MakeHeader(msg.tag, uint32(len(msg.body)))
}
func (msg *SimpleSection) WriteBody(w io.Writer) error {
_, err := w.Write(msg.body)
return err
}
type ReaderSection struct {
tag Tag
size uint32
reader io.Reader
}
func MakeReaderSection(tag Tag, size uint32, reader io.Reader) *ReaderSection {
return &ReaderSection{
tag: tag,
size: size,
reader: reader,
}
}
func (msg *ReaderSection) Header() Header {
return MakeHeader(msg.tag, msg.size)
}
func (msg *ReaderSection) WriteBody(w io.Writer) error {
_, err := io.CopyN(w, msg.reader, int64(msg.size))
return misc.ErrorWrap(err, "")
}
func WriteSection(s Section, w io.Writer) error {
h := s.Header()
_, err := w.Write(h.Serialize())
if err != nil {
return misc.ErrorWrap(err, "")
}
return s.WriteBody(w)
}
// returns a *ReaderSection, must call its WriteBody
// before next call to r
func ReadSection(r io.Reader) (Section, error) {
bHeader := make([]byte, T1K_HEADER_SIZE)
_, err := io.ReadFull(r, bHeader)
if err != nil {
return nil, err
}
h := DeserializeHeader(bHeader)
bodyReader := io.LimitReader(r, int64(h.Size))
return MakeReaderSection(h.Tag, h.Size, bodyReader), nil
}
// returns a *SimpleSection
func ReadFullSection(r io.Reader) (Section, error) {
bHeader := make([]byte, T1K_HEADER_SIZE)
_, err := io.ReadFull(r, bHeader)
if err != nil {
return nil, misc.ErrorWrap(err, "")
}
h := DeserializeHeader(bHeader)
var buf bytes.Buffer
_, err = io.CopyN(&buf, r, int64(h.Size))
if err != nil {
return nil, misc.ErrorWrap(err, "")
}
return MakeSimpleSection(h.Tag, buf.Bytes()), nil
}

View file

@ -0,0 +1,39 @@
package t1k
type Tag uint8
const (
TAG_HEADER Tag = 0x01
TAG_BODY Tag = 0x02
TAG_EXTRA Tag = 0x03
TAG_RSP_HEADER Tag = 0x11
TAG_RSP_BODY Tag = 0x12
TAG_RSP_EXTRA Tag = 0x13
TAG_VERSION Tag = 0x20
TAG_ALOG Tag = 0x21
TAG_STAT Tag = 0x22
TAG_EXTRA_HEADER Tag = 0x23
TAG_EXTRA_BODY Tag = 0x24
TAG_CONTEXT Tag = 0x25
TAG_COOKIE Tag = 0x26
TAG_WEB_LOG Tag = 0x27
TAG_USER_DATA Tag = 0x28
TAG_BOT_QUERY Tag = 0x29
TAG_BOT_BODY Tag = 0x30
MASK_TAG Tag = 0x3f
MASK_FIRST Tag = 0x40
MASK_LAST Tag = 0x80
)
func (t Tag) IsFirst() bool {
return !(0 == (t & MASK_FIRST))
}
func (t Tag) IsLast() bool {
return !(0 == (t & MASK_LAST))
}
func (t Tag) Strip() Tag {
return t & MASK_TAG
}

27
sdk/traefik/vendor/golang.org/x/xerrors/LICENSE generated vendored Normal file
View file

@ -0,0 +1,27 @@
Copyright (c) 2019 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

22
sdk/traefik/vendor/golang.org/x/xerrors/PATENTS generated vendored Normal file
View file

@ -0,0 +1,22 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

2
sdk/traefik/vendor/golang.org/x/xerrors/README generated vendored Normal file
View file

@ -0,0 +1,2 @@
This repository holds the transition packages for the new Go 1.13 error values.
See golang.org/design/29934-error-values.

193
sdk/traefik/vendor/golang.org/x/xerrors/adaptor.go generated vendored Normal file
View file

@ -0,0 +1,193 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xerrors
import (
"bytes"
"fmt"
"io"
"reflect"
"strconv"
)
// FormatError calls the FormatError method of f with an errors.Printer
// configured according to s and verb, and writes the result to s.
func FormatError(f Formatter, s fmt.State, verb rune) {
// Assuming this function is only called from the Format method, and given
// that FormatError takes precedence over Format, it cannot be called from
// any package that supports errors.Formatter. It is therefore safe to
// disregard that State may be a specific printer implementation and use one
// of our choice instead.
// limitations: does not support printing error as Go struct.
var (
sep = " " // separator before next error
p = &state{State: s}
direct = true
)
var err error = f
switch verb {
// Note that this switch must match the preference order
// for ordinary string printing (%#v before %+v, and so on).
case 'v':
if s.Flag('#') {
if stringer, ok := err.(fmt.GoStringer); ok {
io.WriteString(&p.buf, stringer.GoString())
goto exit
}
// proceed as if it were %v
} else if s.Flag('+') {
p.printDetail = true
sep = "\n - "
}
case 's':
case 'q', 'x', 'X':
// Use an intermediate buffer in the rare cases that precision,
// truncation, or one of the alternative verbs (q, x, and X) are
// specified.
direct = false
default:
p.buf.WriteString("%!")
p.buf.WriteRune(verb)
p.buf.WriteByte('(')
switch {
case err != nil:
p.buf.WriteString(reflect.TypeOf(f).String())
default:
p.buf.WriteString("<nil>")
}
p.buf.WriteByte(')')
io.Copy(s, &p.buf)
return
}
loop:
for {
switch v := err.(type) {
case Formatter:
err = v.FormatError((*printer)(p))
case fmt.Formatter:
v.Format(p, 'v')
break loop
default:
io.WriteString(&p.buf, v.Error())
break loop
}
if err == nil {
break
}
if p.needColon || !p.printDetail {
p.buf.WriteByte(':')
p.needColon = false
}
p.buf.WriteString(sep)
p.inDetail = false
p.needNewline = false
}
exit:
width, okW := s.Width()
prec, okP := s.Precision()
if !direct || (okW && width > 0) || okP {
// Construct format string from State s.
format := []byte{'%'}
if s.Flag('-') {
format = append(format, '-')
}
if s.Flag('+') {
format = append(format, '+')
}
if s.Flag(' ') {
format = append(format, ' ')
}
if okW {
format = strconv.AppendInt(format, int64(width), 10)
}
if okP {
format = append(format, '.')
format = strconv.AppendInt(format, int64(prec), 10)
}
format = append(format, string(verb)...)
fmt.Fprintf(s, string(format), p.buf.String())
} else {
io.Copy(s, &p.buf)
}
}
var detailSep = []byte("\n ")
// state tracks error printing state. It implements fmt.State.
type state struct {
fmt.State
buf bytes.Buffer
printDetail bool
inDetail bool
needColon bool
needNewline bool
}
func (s *state) Write(b []byte) (n int, err error) {
if s.printDetail {
if len(b) == 0 {
return 0, nil
}
if s.inDetail && s.needColon {
s.needNewline = true
if b[0] == '\n' {
b = b[1:]
}
}
k := 0
for i, c := range b {
if s.needNewline {
if s.inDetail && s.needColon {
s.buf.WriteByte(':')
s.needColon = false
}
s.buf.Write(detailSep)
s.needNewline = false
}
if c == '\n' {
s.buf.Write(b[k:i])
k = i + 1
s.needNewline = true
}
}
s.buf.Write(b[k:])
if !s.inDetail {
s.needColon = true
}
} else if !s.inDetail {
s.buf.Write(b)
}
return len(b), nil
}
// printer wraps a state to implement an xerrors.Printer.
type printer state
func (s *printer) Print(args ...interface{}) {
if !s.inDetail || s.printDetail {
fmt.Fprint((*state)(s), args...)
}
}
func (s *printer) Printf(format string, args ...interface{}) {
if !s.inDetail || s.printDetail {
fmt.Fprintf((*state)(s), format, args...)
}
}
func (s *printer) Detail() bool {
s.inDetail = true
return s.printDetail
}

View file

@ -0,0 +1 @@
issuerepo: golang/go

23
sdk/traefik/vendor/golang.org/x/xerrors/doc.go generated vendored Normal file
View file

@ -0,0 +1,23 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package xerrors implements functions to manipulate errors.
//
// This package is based on the Go 2 proposal for error values:
//
// https://golang.org/design/29934-error-values
//
// These functions were incorporated into the standard library's errors package
// in Go 1.13:
// - Is
// - As
// - Unwrap
//
// Also, Errorf's %w verb was incorporated into fmt.Errorf.
//
// Use this package to get equivalent behavior in all supported Go versions.
//
// No other features of this package were included in Go 1.13, and at present
// there are no plans to include any of them.
package xerrors // import "golang.org/x/xerrors"

33
sdk/traefik/vendor/golang.org/x/xerrors/errors.go generated vendored Normal file
View file

@ -0,0 +1,33 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xerrors
import "fmt"
// errorString is a trivial implementation of error.
type errorString struct {
s string
frame Frame
}
// New returns an error that formats as the given text.
//
// The returned error contains a Frame set to the caller's location and
// implements Formatter to show this information when printed with details.
func New(text string) error {
return &errorString{text, Caller(1)}
}
func (e *errorString) Error() string {
return e.s
}
func (e *errorString) Format(s fmt.State, v rune) { FormatError(e, s, v) }
func (e *errorString) FormatError(p Printer) (next error) {
p.Print(e.s)
e.frame.Format(p)
return nil
}

190
sdk/traefik/vendor/golang.org/x/xerrors/fmt.go generated vendored Normal file
View file

@ -0,0 +1,190 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xerrors
import (
"fmt"
"strings"
"unicode"
"unicode/utf8"
"golang.org/x/xerrors/internal"
)
const percentBangString = "%!"
// Errorf formats according to a format specifier and returns the string as a
// value that satisfies error.
//
// The returned error includes the file and line number of the caller when
// formatted with additional detail enabled. If the last argument is an error
// the returned error's Format method will return it if the format string ends
// with ": %s", ": %v", or ": %w". If the last argument is an error and the
// format string ends with ": %w", the returned error implements an Unwrap
// method returning it.
//
// If the format specifier includes a %w verb with an error operand in a
// position other than at the end, the returned error will still implement an
// Unwrap method returning the operand, but the error's Format method will not
// return the wrapped error.
//
// It is invalid to include more than one %w verb or to supply it with an
// operand that does not implement the error interface. The %w verb is otherwise
// a synonym for %v.
//
// Note that as of Go 1.13, the fmt.Errorf function will do error formatting,
// but it will not capture a stack backtrace.
func Errorf(format string, a ...interface{}) error {
format = formatPlusW(format)
// Support a ": %[wsv]" suffix, which works well with xerrors.Formatter.
wrap := strings.HasSuffix(format, ": %w")
idx, format2, ok := parsePercentW(format)
percentWElsewhere := !wrap && idx >= 0
if !percentWElsewhere && (wrap || strings.HasSuffix(format, ": %s") || strings.HasSuffix(format, ": %v")) {
err := errorAt(a, len(a)-1)
if err == nil {
return &noWrapError{fmt.Sprintf(format, a...), nil, Caller(1)}
}
// TODO: this is not entirely correct. The error value could be
// printed elsewhere in format if it mixes numbered with unnumbered
// substitutions. With relatively small changes to doPrintf we can
// have it optionally ignore extra arguments and pass the argument
// list in its entirety.
msg := fmt.Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...)
frame := Frame{}
if internal.EnableTrace {
frame = Caller(1)
}
if wrap {
return &wrapError{msg, err, frame}
}
return &noWrapError{msg, err, frame}
}
// Support %w anywhere.
// TODO: don't repeat the wrapped error's message when %w occurs in the middle.
msg := fmt.Sprintf(format2, a...)
if idx < 0 {
return &noWrapError{msg, nil, Caller(1)}
}
err := errorAt(a, idx)
if !ok || err == nil {
// Too many %ws or argument of %w is not an error. Approximate the Go
// 1.13 fmt.Errorf message.
return &noWrapError{fmt.Sprintf("%sw(%s)", percentBangString, msg), nil, Caller(1)}
}
frame := Frame{}
if internal.EnableTrace {
frame = Caller(1)
}
return &wrapError{msg, err, frame}
}
func errorAt(args []interface{}, i int) error {
if i < 0 || i >= len(args) {
return nil
}
err, ok := args[i].(error)
if !ok {
return nil
}
return err
}
// formatPlusW is used to avoid the vet check that will barf at %w.
func formatPlusW(s string) string {
return s
}
// Return the index of the only %w in format, or -1 if none.
// Also return a rewritten format string with %w replaced by %v, and
// false if there is more than one %w.
// TODO: handle "%[N]w".
func parsePercentW(format string) (idx int, newFormat string, ok bool) {
// Loosely copied from golang.org/x/tools/go/analysis/passes/printf/printf.go.
idx = -1
ok = true
n := 0
sz := 0
var isW bool
for i := 0; i < len(format); i += sz {
if format[i] != '%' {
sz = 1
continue
}
// "%%" is not a format directive.
if i+1 < len(format) && format[i+1] == '%' {
sz = 2
continue
}
sz, isW = parsePrintfVerb(format[i:])
if isW {
if idx >= 0 {
ok = false
} else {
idx = n
}
// "Replace" the last character, the 'w', with a 'v'.
p := i + sz - 1
format = format[:p] + "v" + format[p+1:]
}
n++
}
return idx, format, ok
}
// Parse the printf verb starting with a % at s[0].
// Return how many bytes it occupies and whether the verb is 'w'.
func parsePrintfVerb(s string) (int, bool) {
// Assume only that the directive is a sequence of non-letters followed by a single letter.
sz := 0
var r rune
for i := 1; i < len(s); i += sz {
r, sz = utf8.DecodeRuneInString(s[i:])
if unicode.IsLetter(r) {
return i + sz, r == 'w'
}
}
return len(s), false
}
type noWrapError struct {
msg string
err error
frame Frame
}
func (e *noWrapError) Error() string {
return fmt.Sprint(e)
}
func (e *noWrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
func (e *noWrapError) FormatError(p Printer) (next error) {
p.Print(e.msg)
e.frame.Format(p)
return e.err
}
type wrapError struct {
msg string
err error
frame Frame
}
func (e *wrapError) Error() string {
return fmt.Sprint(e)
}
func (e *wrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
func (e *wrapError) FormatError(p Printer) (next error) {
p.Print(e.msg)
e.frame.Format(p)
return e.err
}
func (e *wrapError) Unwrap() error {
return e.err
}

34
sdk/traefik/vendor/golang.org/x/xerrors/format.go generated vendored Normal file
View file

@ -0,0 +1,34 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xerrors
// A Formatter formats error messages.
type Formatter interface {
error
// FormatError prints the receiver's first error and returns the next error in
// the error chain, if any.
FormatError(p Printer) (next error)
}
// A Printer formats error messages.
//
// The most common implementation of Printer is the one provided by package fmt
// during Printf (as of Go 1.13). Localization packages such as golang.org/x/text/message
// typically provide their own implementations.
type Printer interface {
// Print appends args to the message output.
Print(args ...interface{})
// Printf writes a formatted string.
Printf(format string, args ...interface{})
// Detail reports whether error detail is requested.
// After the first call to Detail, all text written to the Printer
// is formatted as additional detail, or ignored when
// detail has not been requested.
// If Detail returns false, the caller can avoid printing the detail at all.
Detail() bool
}

56
sdk/traefik/vendor/golang.org/x/xerrors/frame.go generated vendored Normal file
View file

@ -0,0 +1,56 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xerrors
import (
"runtime"
)
// A Frame contains part of a call stack.
type Frame struct {
// Make room for three PCs: the one we were asked for, what it called,
// and possibly a PC for skipPleaseUseCallersFrames. See:
// https://go.googlesource.com/go/+/032678e0fb/src/runtime/extern.go#169
frames [3]uintptr
}
// Caller returns a Frame that describes a frame on the caller's stack.
// The argument skip is the number of frames to skip over.
// Caller(0) returns the frame for the caller of Caller.
func Caller(skip int) Frame {
var s Frame
runtime.Callers(skip+1, s.frames[:])
return s
}
// location reports the file, line, and function of a frame.
//
// The returned function may be "" even if file and line are not.
func (f Frame) location() (function, file string, line int) {
frames := runtime.CallersFrames(f.frames[:])
if _, ok := frames.Next(); !ok {
return "", "", 0
}
fr, ok := frames.Next()
if !ok {
return "", "", 0
}
return fr.Function, fr.File, fr.Line
}
// Format prints the stack as error detail.
// It should be called from an error's Format implementation
// after printing any other error detail.
func (f Frame) Format(p Printer) {
if p.Detail() {
function, file, line := f.location()
if function != "" {
p.Printf("%s\n ", function)
}
if file != "" {
p.Printf("%s:%d\n", file, line)
}
}
}

View file

@ -0,0 +1,8 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package internal
// EnableTrace indicates whether stack information should be recorded in errors.
var EnableTrace = true

112
sdk/traefik/vendor/golang.org/x/xerrors/wrap.go generated vendored Normal file
View file

@ -0,0 +1,112 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xerrors
import (
"reflect"
)
// A Wrapper provides context around another error.
type Wrapper interface {
// Unwrap returns the next error in the error chain.
// If there is no next error, Unwrap returns nil.
Unwrap() error
}
// Opaque returns an error with the same error formatting as err
// but that does not match err and cannot be unwrapped.
func Opaque(err error) error {
return noWrapper{err}
}
type noWrapper struct {
error
}
func (e noWrapper) FormatError(p Printer) (next error) {
if f, ok := e.error.(Formatter); ok {
return f.FormatError(p)
}
p.Print(e.error)
return nil
}
// Unwrap returns the result of calling the Unwrap method on err, if err implements
// Unwrap. Otherwise, Unwrap returns nil.
//
// Deprecated: As of Go 1.13, use errors.Unwrap instead.
func Unwrap(err error) error {
u, ok := err.(Wrapper)
if !ok {
return nil
}
return u.Unwrap()
}
// Is reports whether any error in err's chain matches target.
//
// An error is considered to match a target if it is equal to that target or if
// it implements a method Is(error) bool such that Is(target) returns true.
//
// Deprecated: As of Go 1.13, use errors.Is instead.
func Is(err, target error) bool {
if target == nil {
return err == target
}
isComparable := reflect.TypeOf(target).Comparable()
for {
if isComparable && err == target {
return true
}
if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
return true
}
// TODO: consider supporing target.Is(err). This would allow
// user-definable predicates, but also may allow for coping with sloppy
// APIs, thereby making it easier to get away with them.
if err = Unwrap(err); err == nil {
return false
}
}
}
// As finds the first error in err's chain that matches the type to which target
// points, and if so, sets the target to its value and returns true. An error
// matches a type if it is assignable to the target type, or if it has a method
// As(interface{}) bool such that As(target) returns true. As will panic if target
// is not a non-nil pointer to a type which implements error or is of interface type.
//
// The As method should set the target to its value and return true if err
// matches the type to which target points.
//
// Deprecated: As of Go 1.13, use errors.As instead.
func As(err error, target interface{}) bool {
if target == nil {
panic("errors: target cannot be nil")
}
val := reflect.ValueOf(target)
typ := val.Type()
if typ.Kind() != reflect.Ptr || val.IsNil() {
panic("errors: target must be a non-nil pointer")
}
if e := typ.Elem(); e.Kind() != reflect.Interface && !e.Implements(errorType) {
panic("errors: *target must be interface or implement error")
}
targetType := typ.Elem()
for err != nil {
if reflect.TypeOf(err).AssignableTo(targetType) {
val.Elem().Set(reflect.ValueOf(err))
return true
}
if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
return true
}
err = Unwrap(err)
}
return false
}
var errorType = reflect.TypeOf((*error)(nil)).Elem()

View file

@ -1,6 +1,10 @@
# github.com/xbingW/t1k v1.2.1
# github.com/chaitin/t1k-go v1.5.0
## explicit; go 1.17
github.com/xbingW/t1k
github.com/xbingW/t1k/pkg/datetime
github.com/xbingW/t1k/pkg/rand
github.com/xbingW/t1k/pkg/t1k
github.com/chaitin/t1k-go
github.com/chaitin/t1k-go/detection
github.com/chaitin/t1k-go/misc
github.com/chaitin/t1k-go/t1k
# golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028
## explicit; go 1.18
golang.org/x/xerrors
golang.org/x/xerrors/internal