Compare commits

...

229 Commits

Author SHA1 Message Date
dundunHa
119a1a4e81 feat: release v3.13.2 2023-11-24 12:40:05 +08:00
delong.wang
2cd5efa28c feat: remove privileged tag in compose.yml 2023-11-23 16:02:55 +08:00
dundunHa
bec86edbd6 feat: change compose 2023-11-23 15:56:16 +08:00
delong.wang
35df06a11b fix: typo in document 2023-11-23 14:00:30 +08:00
dundunHa
741ead2838 feat: release v3.13.1 2023-11-23 12:17:19 +08:00
delong.wang
c6243e5107 feat: update blazehttp 2023-11-21 12:16:56 +08:00
delong.wang
533e92aa05 feat: add tips in not found page 2023-11-17 17:45:09 +08:00
delong.wang
6665b93d64 feat: scale blocking page's footer font size, from 10px to 12px 2023-11-17 17:41:37 +08:00
dundunHa
151f111073 feat: release v3.12.2 2023-11-17 12:37:05 +08:00
dundunHa
ff4be6263e feat: release v3.12.1 2023-11-16 17:51:34 +08:00
dundunHa
584d43dca1 feat: release v3.12.0 2023-11-16 16:51:50 +08:00
delong.wang
3b9c7cd477 fix(test): zip testcases package during compile 2023-11-14 16:08:30 +08:00
delong.wang
1ab06110c6 fix(fe): missing install count 2023-11-10 17:27:18 +08:00
delong.wang
babf43282c chore: update version to 3.11.1 2023-11-09 21:16:20 +08:00
dundunHa
ae05e6bdc7 feat: release v3.11.0 2023-11-09 18:04:27 +08:00
delong.wang
210005584a fix: add blazehttp tools to docker image 2023-11-09 13:06:30 +08:00
delong.wang
cc09295b0f feat(doc): update 3.10.3 change log 2023-11-06 17:03:06 +08:00
delong.wang
6177b4bef0 feat: upgrade version to 3.10.3 2023-11-06 16:29:49 +08:00
delong.wang
7efa85996a feat: add dockerfile for whole site 2023-11-04 18:17:11 +08:00
yrluke
ad03d47fce Update setup.sh 2023-11-03 17:31:09 +08:00
dundunHa
e725a162ba feat: release v3.10.1 2023-11-03 12:22:07 +08:00
dundunHa
abd8ad79cd feat: release v3.10.0 2023-11-02 16:44:21 +08:00
Lorna0
21a30a034e Update 2bug-report.yaml
add input "version"
2023-10-27 15:15:45 +08:00
dundunHa
de2c3391bb chore: change 3.9.0 doc 2023-10-26 18:59:09 +08:00
dundunHa
9d08f8961c chore: change 3.9.0 doc 2023-10-26 18:43:46 +08:00
dundunHa
c22afe94fe feat: release v3.9.0 2023-10-26 18:23:17 +08:00
delong.wang
d6322d70b3 Merge pull request #409 from phxa1/chore-upgrade-sh
chore(upgrade.sh): check env installed by collie
2023-10-26 03:03:20 -05:00
phxa1
271f910ea2 chore(upgrade.sh): check env installed by collie 2023-10-26 14:54:47 +08:00
dundunHa
36c31c69e1 feat: release v3.8.2 2023-10-19 17:25:45 +08:00
dundunHa
cc1c6615ee feat: release v3.8.1 2023-10-19 16:58:51 +08:00
dundunHa
049227cc47 feat: release v3.7.3 2023-10-16 17:45:28 +08:00
dundunHa
513e162f88 feat: release v3.7.2 2023-10-13 18:00:44 +08:00
dundunHa
e014bdcdd3 feat: release v3.7.1 2023-10-13 16:47:48 +08:00
dundunHa
bacef0218f feat: release v3.7.0 2023-10-13 14:40:37 +08:00
delong.wang
5c6fdc2a20 fix(fe): add min page height, avoid footer cover on content 2023-10-11 16:38:19 +08:00
yrluke
53bece8dd9 feat: update the detail 2023-10-09 21:02:55 +08:00
yrluke
f6785a8c1b feat: v3.6.4 2023-10-09 20:58:04 +08:00
dundunHa
8aaa49a3ae feat: release v3.6.3 2023-10-09 16:07:43 +08:00
dundunHa
12acaac561 feat: release v3.5.1 2023-09-26 11:15:43 +08:00
yrluke
e2c97a21ec feat: add the redis url to redis 2023-09-25 18:57:37 +08:00
Lorna0
44c010d6ca Update 2bug-report.yaml
复现方式改为必填
2023-09-22 18:30:38 +08:00
dundunHa
2617f11206 feat: release v3.5.0 2023-09-21 18:19:36 +08:00
dundunHa
b0b45adab9 feat: rec_version is v3.4.1 2023-09-15 17:19:20 +08:00
dundunHa
5b69470712 feat: release v3.4.1 2023-09-15 17:03:40 +08:00
dundunHa
000f1200f5 feat: release v3.4.0 2023-09-14 17:17:57 +08:00
delong.wang
990bdfb0e4 feat(fe): change brand text color in block page 2023-09-14 14:55:19 +08:00
delong.wang
ce4e3537fe feat(fe): consistence block page style 2023-09-14 14:18:34 +08:00
delong.wang
be9ff24b77 Merge pull request #312 from toto2134/main
feat: Add not found page when host not match
2023-09-14 14:13:14 +08:00
TAT
86003359c3 Merge pull request #1 from toto2134/toto2134-patch-page
feat(fe): add page when host is not match
2023-09-14 13:57:25 +08:00
TAT
6d47fcb5c9 feat(fe): add page when host is not match 2023-09-14 12:59:57 +08:00
delong.wang
bd86f3961e feat(fe): update block page styles 2023-09-14 12:33:30 +08:00
delong.wang
0f8f7fcdb2 feat(fe): update limited page title 2023-09-14 11:11:42 +08:00
yrluke
a535d5c2b5 feat: update the dns to list 2023-09-12 15:23:48 +08:00
delong.wang
3649008951 fix(websiet): node 20.6 version can't compile docs 2023-09-07 17:54:04 +08:00
dundunHa
1706e76c47 chore: rec_version -> v3.3.0 2023-09-07 17:28:29 +08:00
dundunHa
6781fad27d Merge pull request #300 from dundunHa/main
feat: release v3.3.0
2023-09-07 16:46:23 +08:00
dundunHa
ddf2707bb1 feat: release v3.3.0 2023-09-07 16:44:46 +08:00
zclaiqcc
2edc7a0c2e Merge pull request #285 from YueWey/main
feat(): check IS flag in both lscpu and cpuinfo file
2023-09-05 18:15:30 +08:00
lele.wei
e8858f123c feat(): check IS flag in both lscpu and cpuinfo file 2023-09-04 18:41:47 +08:00
dundunHa
1f271aabc8 Merge pull request #270 from dundunHa/main
feat: release v3.2.0
2023-08-31 18:44:05 +08:00
dundunHa
ced0a4d7d8 feat: release v3.2.0 2023-08-31 18:43:30 +08:00
dundunHa
567d457e68 Merge pull request #265 from dundunHa/main
fix: update install doc,faq
2023-08-30 18:50:52 +08:00
dundunHa
1c3d2c28ba fix: update install doc,faq 2023-08-30 18:41:06 +08:00
Monster
fd20efde48 增加了网站监控的说明文档 2023-08-29 15:40:41 +08:00
yrluke
f0fd9a5051 Update version.json 2023-08-28 18:41:58 +08:00
yrluke
8417fdffb0 feat: v3.1.1 2023-08-28 18:35:14 +08:00
Monster
14a00affa4 Merge branch 'main' of github.com:chaitin/safeline into main 2023-08-25 15:54:26 +08:00
Monster
0a1b1df300 更换17群的二维码 2023-08-25 15:54:10 +08:00
zclaiqcc
3dfed03f73 feat: new wechat group qr code 2023-08-25 15:51:41 +08:00
zclaiqcc
bcc44c71c4 fix: add seccomp.json 2023-08-25 12:17:48 +08:00
zclaiqcc
ce9c4e847a fix: faq 2023-08-25 11:54:03 +08:00
zclaiqcc
a3c87f4a9b feat: release v3.1.0 2023-08-25 11:11:37 +08:00
delong.wang
42b463e317 feat: add permenent redirect links 2023-08-24 11:08:46 +08:00
zclaiqcc
0a1ae23970 feat: add cpu ssse3 check and info 2023-08-22 17:34:04 +08:00
zclaiqcc
33e21284c4 feat: remove links 2023-08-18 19:39:46 +08:00
zclaiqcc
550bc01b4d feat: remove links 2023-08-18 19:36:53 +08:00
赵昶
0f4fc83848 Merge branch 'update-docs-config' into 'main'
docs: update guide-config

See merge request chang.zhao/safeline-ce!7
2023-08-18 11:21:55 +00:00
Lorna0
5cecf1ff6b 修改查询端口监听情况的命令 2023-08-18 19:11:13 +08:00
Lorna0
6e419416b9 调整了一点文字描述细节和顺序 2023-08-18 19:09:01 +08:00
Lorna0
e46e4668a2 typo 2023-08-18 19:01:09 +08:00
Lorna0
7f360e7b3c 增加未部署雷池时的访问方式,简化了一点文字描述 2023-08-18 18:58:35 +08:00
Lorna0
9e39f29044 删去之前的 常见问题排查-网站无法访问、常见问题排查-配置问题 2023-08-18 18:54:32 +08:00
zclaiqcc
858ad57fdb feat: release v3.0.1 2023-08-18 18:43:20 +08:00
Lorna0
897ae3cf94 找一个客户端执行->在客户端执行 2023-08-18 18:34:43 +08:00
Lorna0
7169046f19 基本原理->工作原理 2023-08-18 18:29:26 +08:00
Lorna0
762347b476 docs: update guide-config
- 合并 常见问题排查-网站无法访问、常见问题排查-配置问题 的内容
- 增加 部署在单独服务器、部署在网站服务器 的简单示例
- 调整若干文字描述细节
2023-08-18 18:29:26 +08:00
zclaiqcc
2e9f937736 feat: release safeline v3.0.0 2023-08-18 12:38:40 +08:00
zclaiqcc
5690509887 feat: release v3.0.0 2023-08-18 12:21:11 +08:00
zclaiqcc
8ed04c780d feat: add SafeLine framework 2023-08-18 11:42:37 +08:00
zclaiqcc
377d5da59c feat: pre-release 3.0.0 2023-08-17 19:54:41 +08:00
zclaiqcc
2fb6b487c4 feat: add faq 2023-08-17 19:14:33 +08:00
yrluke
6aac65e1e7 feat: add the file extend 2023-08-16 15:20:28 +08:00
yrluke
32c69668a4 Create 00-about3 2023-08-16 14:52:22 +08:00
Monster
5049af2ce0 更换微信二维码 2023-08-16 11:26:50 +08:00
yrluke
4fd4d6632f feat: use the dns to enable threat info 2023-08-11 17:19:12 +08:00
delong.wang
1f183c80ff fix(fe): homepage style 2023-08-11 14:29:27 +08:00
Lorna0
f1fe10d312 Merge pull request #210 from chaitin/Lorna0-Update-issue-template
Update issue template: add some hits in feature-request issue
2023-08-10 18:18:35 +08:00
Lorna0
f5a888f655 Update 1feature-request.yaml 2023-08-10 18:11:50 +08:00
delong.wang
9dc5cf4ba2 feat: rename docs folder 2023-08-10 17:31:27 +08:00
zclaiqcc
5b172b7e74 docs: reword changelog 2023-08-10 17:24:53 +08:00
zclaiqcc
fad2178670 style: pretty format 2023-08-10 17:06:00 +08:00
zclaiqcc
c886e2ec96 feat: release v2.6.0 2023-08-10 17:00:53 +08:00
zclaiqcc
0e0e212fab style: pretty format 2023-08-10 17:00:53 +08:00
delong.wang
51b9e6d740 feat: remove github link in nav bar 2023-08-10 16:29:35 +08:00
Monster
f9080246c8 升级脚本里的 wget 换成 curl 2023-08-10 16:22:52 +08:00
delong.wang
05c8ef5bdd feat: remove soft link 2023-08-10 15:45:26 +08:00
delong.wang
15d3d333fa fix: upload missing files 2023-08-10 15:15:09 +08:00
delong.wang
c1932eb469 feat: remove homepage (use website instead) 2023-08-10 14:50:14 +08:00
delong.wang
09b4ed5bb7 feat(docs): update docs 2023-08-10 12:44:13 +08:00
delong.wang
e37f42d300 fix: update image.tar download link 2023-08-09 15:20:43 +08:00
delong.wang
d3ff29342a fix: update image.tar download link 2023-08-09 15:18:36 +08:00
delong.wang
490b1a1aff feat(website): mobile mode show menu button 2023-08-08 16:47:59 +08:00
yrluke
24606b6a92 feat: change the subnet prefix in docs 2023-08-07 18:28:08 +08:00
yrluke
327306ae2e feat: update the download command and subnet 2023-08-07 18:18:09 +08:00
delong.wang
2c9d1cf420 feat(site): config website, remove edit link 2023-08-07 16:14:40 +08:00
delong.wang
2be17bbdf3 feat: rename event field from 'EventId' to 'ID' 2023-08-07 13:16:59 +08:00
delong.wang
f992b0e38c feat: order doc files 2023-08-07 12:11:35 +08:00
delong.wang
bd6ee24eb1 fix: search panel disappear 2023-08-07 10:16:31 +08:00
delong.wang
366a64530e feat(doc): adjust ui of detection page 2023-08-03 18:53:39 +08:00
zclaiqcc
45a175957e feat: remove dup info of offline upgrade 2023-08-03 18:22:57 +08:00
zclaiqcc
d390b609a4 feat: release v2.5.0 2023-08-03 18:13:38 +08:00
delong.wang
4c9488091e Merge pull request #190 from chaitin/website
feat: new version of website
2023-08-02 15:51:15 +08:00
delong.wang
45987efeea feat: new version of website 2023-08-02 15:34:07 +08:00
zclaiqcc
7c8e4f2585 feat: release v2.4.0 2023-07-27 15:43:15 +08:00
delong.wang
f9f4facbb8 feat(fe): add new intercepted page 2023-07-26 16:55:46 +08:00
yrluke
ad5a3f55af feat: release v2.3.2 2023-07-24 19:06:54 +08:00
Monster
09f5831e43 Merge branch 'main' of github.com:chaitin/safeline into main 2023-07-21 11:51:13 +08:00
Monster
56a7b66650 解决了升级脚本无法识别老版本 compose,雷池已停止,手动改过 compose 的多种问题 2023-07-21 11:43:04 +08:00
zclaiqcc
111d332609 style: pretty changelog 2023-07-21 11:12:01 +08:00
Monster
5405b5659e update qrcode 2023-07-20 21:10:59 +08:00
zclaiqcc
b7aa1c7dc6 feat: release v2.3.1 2023-07-20 18:44:45 +08:00
zclaiqcc
6ad19f8688 feat: release v2.3.1 2023-07-20 18:08:49 +08:00
zclaiqcc
8cde19b479 feat: release v2.3.0 2023-07-20 17:15:49 +08:00
zclaiqcc
21d8b0ecb2 feat: downgrade redis to 7.0.10
due to https://github.com/redis/redis/issues/12362
2023-07-20 17:15:32 +08:00
zclaiqcc
e93451de32 feat: config mario & detector & pg url in compose env 2023-07-20 16:50:26 +08:00
Monster
14716a090b add yanshi 2023-07-20 15:19:03 +08:00
Monster
b3afe35fe3 fix yanshi 2023-07-20 15:18:30 +08:00
Monster
20361064a2 add about us link 2023-07-20 15:15:47 +08:00
yrluke
c7dc059d0c fix: remove useless title 2023-07-19 14:57:11 +08:00
yrluke
99d71f815b feat: add the fluentd config into other 2023-07-19 14:53:21 +08:00
yrluke
3e5d2eeac2 Merge pull request #163 from chaitin/fix-typo
fix: fix the typo
2023-07-17 16:59:19 +08:00
yrluke
dd296eb982 fix: fix the typo 2023-07-17 16:58:34 +08:00
zclaiqcc
24c3dfab38 feat: update wechat qr code 2023-07-17 12:51:28 +08:00
zclaiqcc
61f2f2ce9c feat: add faq for online services addr 2023-07-14 23:24:35 +08:00
zclaiqcc
d7546aa1e5 feat: add faq for online services addr 2023-07-14 23:21:48 +08:00
zclaiqcc
d280cc5ae2 fix: typo 2023-07-14 19:29:23 +08:00
zclaiqcc
eec026e5c7 feat: release v2.2.0 2023-07-14 15:43:34 +08:00
Lorna0
779f735117 Merge pull request #155 from chaitin/Update-issue-template-enable-blank-issues
Update issue template: enable blank issues
2023-07-14 12:16:25 +08:00
Lorna0
e120b28880 Update issue template: enable blank issues
用于添加一些置顶的 issue
2023-07-14 12:16:03 +08:00
Lorna0
05dd6386dd Merge pull request #153 from chaitin/add-github-issue-template
add some comments to github issue template
2023-07-13 17:43:54 +08:00
Lorna0
523abc1ecc add some comments to github issue template 2023-07-13 17:42:57 +08:00
yrluke
e7f0dc33b8 Merge pull request #152 from chaitin/add-github-issue-template
add github issue template
2023-07-13 16:44:58 +08:00
Lorna0
7e917e2ac9 add github issue template 2023-07-13 16:41:24 +08:00
naocanmonster
538c9e0008 fix find compose path 2023-07-12 19:09:08 +08:00
Monster
e4d404388b about chaitin 2023-07-12 15:58:23 +08:00
zclaiqcc
4a6056d081 fix: offline installation doc 2023-07-12 14:33:35 +08:00
delong.wang
ea86defc8b fix: https://github.com/chaitin/safeline/security/dependabot/57 2023-07-07 15:26:47 +08:00
zclaiqcc
4e53b91d8b feat: release v2.1.2 2023-07-07 13:37:47 +08:00
zclaiqcc
67275f6906 feat: release v2.1.1 2023-07-06 20:16:45 +08:00
zclaiqcc
77761d86fe feat: release v2.1.0 2023-07-06 18:17:08 +08:00
zclaiqcc
0871d652fe feat: add faq for customizing nginx config 2023-07-06 15:25:24 +08:00
zclaiqcc
d4220cffe2 feat: add faq for customizing nginx config 2023-07-05 18:04:56 +08:00
zclaiqcc
ccd940cc54 feat: add faq for customizing nginx config 2023-07-05 18:01:15 +08:00
Monster
5ffaddc1c6 安装时不要重启 docker 服务 2023-07-04 20:47:15 +08:00
yrluke
d73d13a22c Update faq_other.md 2023-07-04 15:26:17 +08:00
Monster
d3026154a1 once more fix the compose command 2023-06-30 15:57:31 +08:00
Monster
a415b027e8 Merge branch 'main' of github.com:chaitin/safeline into main 2023-06-30 15:34:41 +08:00
Monster
2d994d0e53 once more fix the compose command 2023-06-30 15:34:28 +08:00
zclaiqcc
f22673226d feat: release v2.0.1 2023-06-30 14:52:47 +08:00
Monster
e4d59c7dd6 fix compose path 2023-06-30 13:38:14 +08:00
Monster
61f5843da9 修改安装脚本里不识别 docker-compose 的问题 2023-06-30 11:51:52 +08:00
Monster
086a484f39 路径识别的问题刚才没修好,重修了一次 2023-06-29 15:21:33 +08:00
Monster
f40f12c782 修复了升级脚本不识别非默认路径的问题 2023-06-29 14:36:10 +08:00
yrluke
3f95bef0f4 Merge pull request #116 from yrluke/update_detail
doc: update detail
2023-06-29 12:26:47 +08:00
rui.yan
fd391fa5b1 doc: update detail 2023-06-29 12:26:02 +08:00
zclaiqcc
c709c52211 feat: update challenge docs 2023-06-29 11:54:34 +08:00
yrluke
57554a6ca1 Merge pull request #114 from yrluke/version2
doc: add 2.0
2023-06-29 11:14:32 +08:00
yrluke
437a4b24af Merge branch 'main' into version2 2023-06-29 11:14:25 +08:00
rui.yan
94f17bfe39 doc: add 2.0 2023-06-29 11:12:17 +08:00
zclaiqcc
ff91bd8f3c feat: release v2.0.0 2023-06-28 19:58:17 +08:00
Monster
0bf5de39c9 安装 docker 后加了自动启动的步骤 2023-06-28 10:51:23 +08:00
Monster
9783578c33 修改了测试文档里的路径错误 2023-06-28 10:44:17 +08:00
naocanmonster
061104d31f 调整安装脚本,在运行出错的时候提示文档信息 2023-06-27 23:21:33 +08:00
Monster
9aacbc14f3 fix gif 2023-06-27 16:57:53 +08:00
Monster
91e10ec19a change gif to 2.0 2023-06-27 16:39:44 +08:00
delong.wang
200dfb9ba2 fix(fe): my sample panel height overflow the screen 2023-06-27 10:58:00 +08:00
naocanmonster
5e2e75b6e2 删了几行没用的脚本 2023-06-26 23:37:32 +08:00
naocanmonster
2b8cadb7a4 修改了教程里的安装命令 2023-06-26 23:28:25 +08:00
naocanmonster
d99ef04cf3 加上了几个子模块 2023-06-26 22:49:23 +08:00
naocanmonster
d5a8819db5 更新官网关于升级的文档 2023-06-26 22:46:07 +08:00
Monster
e98fa14b6f 修改了 readme 里的安装文档 2023-06-26 21:03:02 +08:00
Monster
4f45333677 修改了升级脚本 2023-06-26 20:58:30 +08:00
naocanmonster
9fc53e2732 Merge pull request #106 from chaitin/new_setup_script
修改了安装脚本
2023-06-26 18:18:29 +08:00
naocanmonster
a3393f1eb3 Update README.md 2023-06-26 17:31:44 +08:00
naocanmonster
db1ef55b30 修改了安装脚本 2023-06-26 16:03:18 +08:00
Monster
e5d2670577 又改了改 readme 2023-06-25 18:30:05 +08:00
Monster
fc45502a6a Merge branch 'main' of github.com:chaitin/safeline into main 2023-06-25 18:20:02 +08:00
Monster
dee5019888 修改 readme 2023-06-25 18:18:38 +08:00
zclaiqcc
51e750845a fix: md link 2023-06-25 17:37:59 +08:00
naocanmonster
d0a1620f57 给轮播图加了个有色边框 2023-06-25 16:48:23 +08:00
zclaiqcc
151b64da27 feat: release v1.10.0 2023-06-21 17:06:45 +08:00
delong.wang
90eaac3cd1 feat(blockpage): use svg instead of png 2023-06-21 16:34:41 +08:00
delong.wang
13401133a4 feat(blockpage): add new maintaining page 2023-06-21 15:05:31 +08:00
naocanmonster
c262369fd7 修改了配置源 IP 相关的文档 2023-06-21 12:01:19 +08:00
zclaiqcc
b8bd25968d feat: add redis image to manually upgrade instruction 2023-06-20 17:56:02 +08:00
naocanmonster
32c6821d36 修改雷池到离线安装文档 2023-06-20 13:01:29 +08:00
naocanmonster
498d116245 修改了官网文档里的两个错别字 2023-06-19 14:56:33 +08:00
naocanmonster
9d6742fab6 给社区版网站增加搜索关键字 2023-06-19 13:42:19 +08:00
yrluke
a79ff303d5 Merge pull request #101 from yrluke/add_access_log
Add access log
2023-06-16 16:48:41 +08:00
rui.yan
138e075946 doc: update detail 2023-06-16 16:47:09 +08:00
naocanmonster
567dbcd6ec 修改了文档里对千万错别字 2023-06-16 16:47:03 +08:00
rui.yan
26cab99562 doc: remove mac or windows 2023-06-16 16:46:22 +08:00
naocanmonster
ded344cd7f 修改了 changelog 标题对问题 2023-06-16 16:21:34 +08:00
yrluke
49b3c8d5d4 Merge pull request #100 from yrluke/add_access_log
doc: fix detail
2023-06-16 16:18:48 +08:00
rui.yan
f1699505da doc: fix detail 2023-06-16 16:18:19 +08:00
delong.wang
1f998ce2ea feat: change new theme icon 2023-06-16 14:50:41 +08:00
delong.wang
e5f932adff feat(fe): change theme main color 2023-06-16 14:41:04 +08:00
naocanmonster
37f72ba51f 换了新版本的截图 2023-06-16 14:17:52 +08:00
zclaiqcc
1a8c175c48 feat: release v1.9.0 2023-06-16 12:43:03 +08:00
yrluke
18ab2f1010 Merge pull request #99 from yrluke/add_access_log
doc: add the server_name index
2023-06-14 17:22:46 +08:00
rui.yan
3bde97627d doc: add the server_name index 2023-06-14 17:22:21 +08:00
yrluke
478a22015d Merge pull request #97 from yrluke/add_access_log
foc: copy the method
2023-06-13 21:13:44 +08:00
rui.yan
0768508060 foc: copy the method 2023-06-13 21:11:40 +08:00
yrluke
a8e2b1b248 Merge pull request #96 from yrluke/add_access_log
doc: more detail
2023-06-13 17:17:46 +08:00
rui.yan
d8183bd8d8 doc: more detail 2023-06-13 17:16:05 +08:00
yrluke
13f6265498 Merge pull request #95 from yrluke/add_access_log
doc: update the doc
2023-06-13 17:03:24 +08:00
rui.yan
60e155b230 doc: update the doc 2023-06-13 17:02:56 +08:00
zclaiqcc
a57188692f feat: release v1.8.2 2023-06-12 10:57:03 +08:00
zclaiqcc
f07ed2b30d feat: add clean instruction for old images 2023-06-12 10:57:03 +08:00
264 changed files with 31031 additions and 11039 deletions

5
.dockerignore Normal file
View File

@@ -0,0 +1,5 @@
website/node_modules
website/build
website/.docusaurus
blazehttp/.github

View File

@@ -0,0 +1,30 @@
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

42
.github/ISSUE_TEMPLATE/2bug-report.yaml vendored Normal file
View File

@@ -0,0 +1,42 @@
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

14
.github/ISSUE_TEMPLATE/3other.yaml vendored Normal file
View File

@@ -0,0 +1,14 @@
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: 反馈内容

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
blank_issues_enabled: Ture
contact_links:
- name: 绕过反馈
url: https://stack.chaitin.com/security-challenge/safeline/index
about: Waf 绕过可在 CT Stack 安全挑战赛提交细节

2
.gitignore vendored
View File

@@ -1,2 +1,4 @@
*.Zone.Identifier
.DS_Store
*.zip
*.tar

9
.gitmodules vendored Normal file
View File

@@ -0,0 +1,9 @@
[submodule "blazehttp"]
path = blazehttp
url = https://github.com/chaitin/blazehttp
[submodule "lua-resty-t1k"]
path = lua-resty-t1k
url = https://github.com/chaitin/lua-resty-t1k
[submodule "plugins"]
path = plugins
url = https://github.com/chaitin/safeline-open-platform

View File

@@ -1,9 +1,451 @@
SAFELINE-CE CHANGELOG
===
# SAFELINE-CE CHANGELOG
## [Unreleased]
- 告警
## [3.13.2] - 2023-11-24
### 修复
- 修复了 safeline-fvm-manager 容器的健康检查错误结果
## [3.13.1] - 2023-11-23**
### 新增
- 人机验证的二次验证,从数字验证码改为旋转图片,网站用户体验更好
### 优化
- 修复 社区恶意 IP 情报 每日定时更新后,控制台上 “更新时间” 未相应更新的问题
- 日志详情 “已拦截” “已放行” 图案改为英文,适配国际化
- 域名不匹配时,返回的拦截页面补充更多提示
- 优化一些界面细节
## [3.12.2] - 2023-11-17
### 修复
- 修复重启 docker (包括雷池升级)后,站点通用配置和拦截页面附加说明没有被正确载入的问题 [#438](https://github.com/chaitin/SafeLine/issues/438) [#446](https://github.com/chaitin/SafeLine/issues/446)
## [3.12.1] - 2023-11-16
### 新增
- 登录过程输入完 6 位验证码自动登录([#335](https://github.com/chaitin/SafeLine/issues/335)
- 统计 PV 和 UV 用的 cookie 默认添加 HttpOnly 属性,在 HTTPS 下自动添加 Secure 属性
### 优化
- 修复证书在添加一段时间后,证书类型统一变成 “上传已有证书” ,编辑时也看不到证书内容的问题。(免费证书需要手动再切换到免费证书申请一下,后续才能自动续期。只影响列表管理,不影响网站上的证书)
- 开启 “强制 HTTPS” 时HSTS 删去 preload 参数,并改为只在 https 端口下返回 [#407](https://github.com/chaitin/SafeLine/issues/407)
- 修复添加、编辑站点有时出现 “Service abnormal” 异常的问题
- 修复 “申请免费证书” 类型的证书,在证书列表上显示成 “上传已有证书” 的问题
- 优化一些样式交互细节
### [3.11.1] - 2023-11-09
#### 修复
- 修复证书列表页面域名列显示不正确问题
## [3.11.0] - 2023-11-09
### 新增
- 站点详情新增站点的 favicon、标题和编辑按钮
### 优化
- 优化 “强制 HTTPS” 中 HSTS 的参数细节([#407](https://github.com/chaitin/SafeLine/issues/407)
- 修复英文模式下事件列表文字错位问题
- 修复添加、编辑站点有时出现 “Service abnormal” 异常的问题
- 优化站点 “运行模式” 的展示和交互
- 优化一些界面交互和提示文字
## [3.10.3] - 2023-11-06
- 修复部分证书无法编辑,提示 “密钥内容解析错误” 的问题
- 修复升级或重启后,站点证书引用成历史证书的问题
- 修复编辑证书有时必须填写私钥的问题
## [3.10.1] - 2023-11-03
### 修复
- 修复无法修改 通用配置-其他-拦截页面附加说明 的问题
## [3.10.0] - 2023-11-02
### 新增
- 在证书管理创建证书时,支持直接粘贴证书与私钥内容([#77](https://github.com/chaitin/SafeLine/issues/77)
### 优化
- 人机验证的客户端文件从 138k 减小到 78k提高加载速度
- 人机验证 cookie 改为 httpOnly 模式,避免在 JavaScript 运行时泄露
- 人机验证防止简单绕过 [#405](https://github.com/chaitin/SafeLine/issues/405)
- 修复站点详情中,资源 “今日请求” 的总和大于站点 “今日请求总量” 的问题([#410](https://github.com/chaitin/SafeLine/issues/410)
## [3.9.0] - 2023-10-26
### 优化
- 人机验证页面增加响应头 Cache-Control向下游声明不希望被缓存避免被 CDN 缓存导致不断重复验证([#402](https://github.com/chaitin/SafeLine/issues/402)
- 修复人机验证在 iframe 中会不断重复验证的问题([#397](https://github.com/chaitin/SafeLine/issues/397)
- 修复人机验证在 alook 浏览器中页面空白的问题([#393](https://github.com/chaitin/SafeLine/issues/393)
- 修复添加、编辑站点有时出现 “Service abnormal” 异常的问题
- 修复申请免费证书时,无法填写多个域名的问题
- 修复编辑站点时,域名无法设为空的问题
- 升级过程增加安装方式检查,通过牧云助手安装的,需要通过牧云助手升级,避免故障
## [3.8.2] - 2023-10-19
### 新增
- “通用漏洞规则” 的攻击日志中,新增 “命中规则”,方便管理员了解具体的拦截原因:
### 优化
- 修复 acme 未记录好邮箱,导致无法自动续签的问题。**旧版本已申请的证书,升级后需要再次编辑补全一下邮箱地址,才能自动续签**
- 修复雷池重启后,已通过人机验证的页面会一直反复进行人机验证的问题
- 修复某个站点关闭 ssl 之后,还会错误地显示在证书管理的 “使用站点” 中的问题
- 优化安卓手机的人机验证效果,现在不会总是弹出验证码识别了
- 修复证书管理-编辑证书时,弹窗没有正常回填已有配置的问题
- 优化 攻击事件->原始日志 默认的筛选条件([#288](https://github.com/chaitin/SafeLine/issues/288)
- 优化一些 UI 交互细节
## [3.7.3] - 2023-10-16
### 修复
- 修复获取上游服务器的 favicon 和标题失败时,可能导致站点管理无法配置站点的问题
- 修复 IP 组中的网段解析错误,导致匹配结果不正确的问题
## [3.7.2] - 2023-10-13
### 优化
- 修复无法更新威胁情报 IP 的问题
- 修复编辑人机验证配置时不回显的问题
## [3.7.1] - 2023-10-13
### 新增
- 人机验证增加 **二次验证码验证**,在自动验证失败时进行,减少误拦
### 优化
- 优化人机验证
- 简化配置,不再区分交互、非交互
- 区分站点,验证通过的结果只能在一个站点(按域名或 IP 区分)上生效了
- 降低算力要求,解决部分移动端验证时间过长的问题
- 配置站点时,“上游服务器” 的服务器地址部分支持填写主机名,例如 http://localhost:8080
- 站点的运行模式为 “观察” 时,黑名单、限频、人机 改为**都不拦截**。其中黑名单会记录 “放行” 的日志;限频会持续计入统计,但限制结果不会对观察中的站点生效
- 修复证书管理中,泛域名的证书显示 “域名不匹配” 问题([#368](https://github.com/chaitin/SafeLine/issues/368)
- 更新检测引擎版本,降低误报
- 优化若干提示文字和样式细节
## [3.6.4] - 2023-10-09
### 修复
- 修复了多个域名申请免费证书失败的问题
- 修复了有时候不能创建 HTTP 站点的问题
- 修复证书管理中,“使用站点” 不全的问题
- 修复证书管理中,泛域名证书的使用站点始终提示 “域名不匹配” 的问题
## [3.6.3] - 2023-10-09
### 新增
- 新增申请免费证书。只要域名已经指向雷池,就可以在界面上直接申请证书了
- 证书管理新增 “使用站点”,并且会自动检查站点和证书的域名是否一致
### 优化
- 优化站点配置证书的流程,现在所有证书都在证书管理配置,方便统一查看
- 雷池控制台证书的配置移动到了 “通用配置” -> “其他” 中,更符合直觉
- 修复某些情况下采集不到站点 favicon 的问题
- 修复采集站点标题的时候,会把英文大写转成小写的问题
- 修复站点详情中,删除文件夹的操作不会生效的问题
- 修复站点详情中,资源的 今日请求 / 近 30 日请求 始终为 0 的问题
## [3.5.1] - 2023-09-26
### 优化:
- 修复站点详情中,今日请求量一直为 0 的问题
- 修复获取站点 favicon 时没有尝试默认路径,导致某些站点获取不到的问题
- 修复小概率出现无法对站点进行任何操作的问题(不影响已配置站点的防护)
## [3.5.0] - 2023-09-21
### 新增
- 人机验证新增每个规则的 “今日验证情况”,方便判断规则配置的效果:
### 优化
- 站点列表新增 “资源数”,方便判断判断资源管理情况
- 优化 攻击事件->原始日志 默认的筛选条件([#288](https://github.com/chaitin/SafeLine/issues/288)
- 修复自动采集的站点 favicon 有时候显示不出来的问题([#316](https://github.com/chaitin/SafeLine/issues/316)
- 修复自动采集的站点标题有时候显示成乱码的问题
- 修复站点详情的 “今日请求总量” 有时候不显示最新值的问题
- 优化一些界面样式交互细节
## [3.4.1] - 2023-09-15
### 优化
- 修复请求上游服务器的 title 和 icon 时间过长导致站点相关功能异常的问题
- 修复站点列表中站点标题的优先显示顺序,先显示“备注”,如果没有“备注”再显示网页的“标题”
## [3.4.0] - 2023-09-14
### 新增
- “防护站点” 新增站点的标题和 Favicon每天更新一次管理起来更加清晰
- 站点详情新增“采集设置”,支持设置不记录的路径前缀和类型
### 优化
- 限频后封禁的拦截页面改为 “请求频率过高,已被拦截”,与语义分析和黑名单的拦截页面区分开,方便管理员确认拦截原因
- 修复有时候无法正常通过路径搜索日志的问题
- 修复限频中,同时配置人机验证、直接封禁两类限制结果时,直接封禁有时候不会被触发的问题
- 修复黑名单拦截的请求也会触发限频,导致限频日志中出现很多 “已限制请求数” 为 0 的记录的问题
- 优化界面的一些样式交互
## [3.3.0] - 2023-09-07
### 新增
- 支持设置拦截页面附加说明([#192](https://github.com/chaitin/SafeLine/issues/192)
- 频率限制新增 “人机验证” 的限制方式([#226](https://github.com/chaitin/SafeLine/issues/226)
### 优化
- 当网站域名不匹配的时候,返回 “网站不存在” ,提示更清晰([#58](https://github.com/chaitin/SafeLine/issues/58)
- 修复 攻击事件->原始日志 的 “攻击地址” 中显示额外的转义符的问题
- 修复站点详情中 “今日总请求量” 和站点列表的 “今日访问量” 不一致的问题([#279](https://github.com/chaitin/SafeLine/issues/279)
- 频率限制后直接封禁的拦截状态码改为 429和普通拦截 403 区分开,方便排查拦截原因
- 加强后台登录安全性(感谢微信交流 20 群「千年之狐」提供的建议)
- 优化安装/升级时 CPU ssse3 指令集的检查方式([#273](https://github.com/chaitin/SafeLine/issues/273)
- 优化界面样式交互,修复一些已知问题
## [3.2.0] - 2023-08-31
### 新增
- 证书管理支持上传 PKCS1、PKCS8、ECC 私钥格式的证书([#257](https://github.com/chaitin/SafeLine/issues/257)
- 站点详情新增近 30 天请求数,支持批量删除
### 优化
- 优化站点详情页面,提高加载速度、优化界面样式和逻辑
- 限频的生效阈值由 “超过 xx 次” 改为 “达到 xx 次”([#245](https://github.com/chaitin/SafeLine/issues/245)
- 修复频率限制所拦截的请求,没有被计入站点列表的 “今日访问/拦截量” 的问题
- 修复证书管理的证书有时候无法正常删除的问题([#268](https://github.com/chaitin/SafeLine/issues/268)
- 修复证书管理中,有时候一个证书内会解析出几个重复的域名的问题
- 去掉对 docker 的 seccomp 特性的依赖([#255](https://github.com/chaitin/SafeLine/issues/255)
- 优化大量界面样式、交互和操作提示细节
## [3.1.1] - 2023-08-28
### 优化
- 修复创建站点时直接上传 SSL 证书显示创建失败的问题
## [3.1.0] - 2023-08-25
### 新增
- 新增证书管理。自动判断域名与过期状态,配置站点时可以直接选择([#111](https://github.com/chaitin/SafeLine/issues/111)),还可以修改管理后台的证书([#201](https://github.com/chaitin/SafeLine/issues/201)
- 新增系统信息
### 优化
- 修复站点详情全局只支持 250 个资源的问题。现在是每个站点各支持 250 个
- 修复站点详情中,路径太长样式会错位的问题
- 修复站点从维护切换成其他状态时,微信会缓存维护页面的问题([#221](https://github.com/chaitin/SafeLine/issues/221)
- 修复手机和平板上不能输入动态口令的问题([#234](https://github.com/chaitin/SafeLine/issues/234)
- 优化导航栏和若干 UI 交互细节
## [3.0.1] - 2023-08-18
- 更新底层语义分析引擎,加强基础防护能力
- 修复站点详情中,不同域名的资源会重复记录问题
- 修复攻击事件有小概率时间排序错误的问题
- 修复关闭再打开频率限制时,配置不会重置到默认值的问题
- 修复首次创建站点且配置 SSL 端口的情况下提示“端口被占用”的问题
## [3.0.0] - 2023-08-18
### 新增
- 新增站点详情,能自动从流量中记录网站资源,一览资源的存活、访问情况
- PS. 考虑机器资源消耗问题,当前版本每个站点下最多记录 250 个资源
- 站点支持输入多个域名、端口([#162](https://github.com/chaitin/safeline/issues/162)
- 通用配置中新增 “站点通用配置”,支持一键开启:
- 强制 HTTPS[#67](https://github.com/chaitin/safeline/issues/67)
- 使用 HTTP/2[#161](https://github.com/chaitin/safeline/issues/161)
- 监听 IPv6[#166](https://github.com/chaitin/safeline/issues/166)
- 传递客户端连接的 Host 和协议,方便后续服务器处理
### 优化
- 优化限频配置的默认值
- 增加 HTTP 497 错误重定向。当以 HTTP 协议访问 HTTPS 端口时,将重定向到 HTTPS[#186](https://github.com/chaitin/safeline/issues/186)
- 默认拒绝 IP 和其他非指定域名的访问。如果需要通过 IP 访问站点,可以给站点添加一个 "\*" 域名([#58](https://github.com/chaitin/safeline/issues/58)
- 优化若干 UI 交互细节和文字提示
## [2.6.0] - 2023-08-10
### 新增
- 新增高频攻击封禁,即多次攻击后自动封禁 IP ([#29](https://github.com/chaitin/safeline/issues/29))
- 频率限制日志显示封禁 IP 的地理位置 ([#198](https://github.com/chaitin/safeline/issues/198))
### 优化
- 攻击检测的原始日志支持搜索端口 ([#193](https://github.com/chaitin/safeline/issues/193))
- 修复编辑站点后,“维护模式” 会失效的问题
- 修改默认占用的网段,避免跟腾讯云默认网段冲突 ([#40](https://github.com/chaitin/safeline/issues/40))
- 优化安装脚本 ([#194](https://github.com/chaitin/safeline/issues/194)),优化界面一些 UI 交互、错误提示
## [2.5.0] - 2023-08-03
### 新增
- 请求频率限制([#29](https://github.com/chaitin/safeline/issues/29)
### 优化
- 支持筛选攻击检测日志的 ID[#74](https://github.com/chaitin/safeline/issues/74)),优化筛选的交互
- 证书支持 .cer 格式([#181](https://github.com/chaitin/safeline/issues/181)
- 优化人机校验页面,适配移动端([#184](https://github.com/chaitin/safeline/issues/184)
- 界面增加一些配置提示:添加站点时 “域名” 的格式、黑白名单/人机验证中匹配条件的生效逻辑
## [2.4.0] - 2023-07-27
### 新增
- IP 组支持注释 [#143](https://github.com/chaitin/safeline/issues/143)
### 优化
- 优化编辑 IP 组和相关规则时的性能
- 优化一些界面 UI 交互细节
## [2.3.2] - 2023-07-24
### 修复
- 修复了攻击事件 - 原始日志中,请求报文没有格式化的问题
- 优化了一些已知问题
## [2.3.1] - 2023-07-20
### 新增
- 检测日志升级为**攻击事件** ,自动聚合同一攻击 IP 短时间内的所有攻击日志,方便管理员进行监控和处置
- 日志支持按时间([#102](https://github.com/chaitin/safeline/issues/102))、动作筛选
### 修复
- 修复添加/编辑站点时,上传证书处未翻译中文的问题
- 修复数据统计中,“访问来源地区” 小概率出现的部分地区显示不正确的问题
## [2.2.0] - 2023-07-14
### 新增
- IP 组中新增长亭社区恶意 IP 情报,内容来自社区版共享的攻击 IP每日自动更新
### 优化
- 升级核心检测引擎,修复一些绕过和误报
- 管理界面增加浏览器版本检查,如果版本过旧,会提示升级浏览器
- 优化一些界面的 UI 交互细节
- 修复一些中英文翻译的问题
## [2.1.2] - 2023-07-07
- 修复了日志详情中防护策略模块没有翻译的问题
## [2.1.1] - 2023-07-06
- 修复了防护策略模块没有翻译的问题
## [2.1.0] - 2023-07-06
### 新增
- 添加/编辑站点时,自动检查端口占用情况,避免保存后配置不生效
- 支持自定义站点的 nginx conf详情可见[官网文档](https://waf-ce.chaitin.cn/posts/faq_other#%E8%87%AA%E5%AE%9A%E4%B9%89%E7%AB%99%E7%82%B9-nginx-conf)
- [站点列表支持按域名、端口或访问量进行排序](https://github.com/chaitin/safeline/issues/14)
- [绑定 TOTP 密钥时,支持直接复制密钥;登录时的 6 位动态密码输入框,支持粘贴](https://github.com/chaitin/safeline/issues/30)
### 优化
- [黑白名单和人机验证列表中,可以鼠标悬浮查看 “复合条件” 的具体内容](https://github.com/chaitin/safeline/issues/120)
- 修复人机验证列表中,“源 IP 不属于 IP 组” 的规则IP 组名称显示成了 id 的问题
- [优化人机验证启用/禁用交互](https://github.com/chaitin/safeline/issues/130)
- [优化描述文字](https://github.com/chaitin/safeline/issues/122)
- 优化一些界面 UI 交互、提示文字
- 修复一些已知问题
## [2.0.1] - 2023-06-30
- 调整了人机验证的策略,降低误拦的情况
- 修复了人机验证启动/禁用规则不会自动刷新状态的问题
- 修复其他一些已知问题
## [2.0.0] - 2023-06-29
### 新增
- 人机验证
- 支持嵌入式部署,可以通过 [t1k 协议](https://github.com/chaitin/lua-resty-t1k) 直接把流量转发到雷池进行检测
- 把日志详情中的源 IP 加入到 IP 组时,支持调整 IP 为任意 IP 或网段
### 优化
- 日志列表按照时间和 ID 排序,防止出现小范围的时间乱序
- 转发流量时,自动设置请求头 X-Forwarded-Proto适配更多代理场景
- 优化界面 UI修复其他一些已知问题
## [1.10.0] - 2023-06-21
### 新增
- 防护站点新增 “运行模式”,可以一键将站点设为 观察 或 维护 模式了
### 优化
- 修复了站点列表没有分页器的问题
- 修复了窗口水平滚动时导航栏会错位的问题
- 修复了黑白名单配置 “不属于 IP 组” 的条件时,列表显示组 ID而未显示组名称的问题
- 优化了界面的 UI 与交互
## [1.9.0] - 2023-06-16
### 新增
- 界面 UI 改造,信息层级更清晰
- 黑白名单支持添加 源 IP - 不属于 IP 组 的条件
### 优化
- 检测日志的路由进一步完善
- 数据统计页面更加紧凑,现在可以在 1920\*1080 的屏幕上完全显示了
- 黑白名单的展示优化
- 修复 通用配置-防护模块配置 中,“批量配置为” 按钮有时候不生效的问题
- 修复一些已知问题
## [1.8.2] - 2023-06-12
- 修复了「30 天访问情况」和「30 天拦截情况」显示相同数据的问题
## [1.8.1] - 2023-06-09
@@ -26,23 +468,27 @@ SAFELINE-CE CHANGELOG
## [1.7.1] - 2023-06-05
### 修复
- 部分情况下无法打开日志详情页面的问题
- 部分情况下页面查询数量只有 10 条的问题
## [1.7.0] - 2023-06-01
### 新增
- 新增 “IP 组” 功能,可以快速配置大量 IP 的黑/白名单了
- 防护策略增加 “仅观察” 配置
- 防护策略增加 “批量配置为” 按钮,可以快速切换所有模块的防护策略
### 优化
- 自定义规则列表增加翻页
- 优化规则生效顺序,现在会优先执行完所有白名单,再执行黑名单
## [1.6.0] - 2023-05-25
### 新增
- 自定义规则支持匹配 Header 和 Body
- 检测日志支持按域名搜索
- 支持命令行清理检测日志和统计信息
@@ -54,11 +500,13 @@ SAFELINE-CE CHANGELOG
## [1.5.0] - 2023-05-18
### 新增
- 支持 i18n
- 数据统计新增 “今日请求错误情况”
- 检测日志的筛选条件现在会显示在 URL方便保存
### 优化
- 修复自定义规则的编辑表单,有时候会丢失编辑中数据的问题
- 修复 Safari 浏览器上的一些显示问题
- 修复 Payload 中存在非 Unicode 编码时,检测日志会入库失败的问题(不影响拦截)
@@ -67,25 +515,30 @@ SAFELINE-CE CHANGELOG
## [1.4.0] - 2023-05-12
### 新增
- 自定义规则支持匹配域名
- 支持在一条自定义规则内,设置多个匹配条件
- 站点列表新增 “今日访问 / 拦截量”
### 优化
- 优化交互和提示文案、修复已知问题
## [1.3.0] - 2023-05-05
### 新增
- 支持按照源 IP、攻击类型、URL 筛选检测日志
### 修复
- 修复 dashboard 在部分低版本浏览器下的兼容问题
- 修复按源 IP 添加自定义规则时,添加不了 /8 和更大的网段的问题
## [1.2.0] - 2023-04-27
### 新增
- 新增了数据统计页面,可以直观的看到流量大小
- 支持配置源 IP 提取方式,解决了源 IP 获取不对的问题
- 支持自定义检测策略,可以动态调整检测引擎
@@ -93,10 +546,12 @@ SAFELINE-CE CHANGELOG
## [1.1.0] - 2023-04-20
### 新增
- 支持根据 IP 和 URL 特征配置黑白名单
- 默认开启高防模式
### 优化
- 支持在日志详情中展示响应报文
- 服务器时间不准导致 TOTP 无法登录时增加了提示语
- 修复了上游服务器填 HTTPS 时端口解析不正确的问题
@@ -110,4 +565,4 @@ SAFELINE-CE CHANGELOG
- OTP 登录
- 攻击检测日志
- 默认防护策略
- 默认防护策略

75
Dockerfile Normal file
View File

@@ -0,0 +1,75 @@
FROM node:20.5-alpine
RUN apk update
RUN apk add nginx tini
RUN echo -e " \n\
server { \n\
listen 80; \n\
\n\
location /api/count { \n\
proxy_pass https://rivers-telemetry.chaitin.cn:10086; \n\
} \n\
location /api/exist { \n\
proxy_pass https://rivers-telemetry.chaitin.cn:10086; \n\
} \n\
location /blazehttp { \n\
root /app/; \n\
try_files \$uri =404; \n\
} \n\
location /release { \n\
root /app/; \n\
try_files \$uri =404; \n\
} \n\
location / { \n\
rewrite /posts/guide_introduction /docs/ permanent; \n\
rewrite /posts/guide_install /docs/guide/install permanent; \n\
rewrite /docs/上手指南/guide_install /docs/guide/install permanent; \n\
rewrite /posts/guide_login /docs/guide/login permanent; \n\
rewrite /docs/上手指南/guide_login /docs/guide/login permanent; \n\
rewrite /posts/guide_config /docs/guide/config permanent; \n\
rewrite /docs/上手指南/guide_config /docs/guide/config permanent; \n\
rewrite /posts/guide_test /docs/guide/test permanent; \n\
rewrite /docs/上手指南/guide_test /docs/guide/test permanent; \n\
rewrite /posts/guide_upgrade /docs/guide/upgrade permanent; \n\
rewrite /docs/上手指南/guide_upgrade /docs/guide/upgrade permanent; \n\
rewrite /posts/faq_install /docs/faq/install permanent; \n\
rewrite /docs/常见问题排查/faq_install /docs/faq/install permanent; \n\
rewrite /posts/faq_login /docs/faq/login permanent; \n\
rewrite /docs/常见问题排查/faq_login /docs/faq/login permanent; \n\
rewrite /posts/faq_access /docs/guide/config permanent; \n\
rewrite /docs/常见问题排查/faq_access /docs/guide/config permanent; \n\
rewrite /posts/faq_config /docs/faq/config permanent; \n\
rewrite /docs/常见问题排查/faq_config /docs/faq/config permanent; \n\
rewrite /posts/faq_other /docs/faq/other permanent; \n\
rewrite /docs/常见问题排查/faq_other /docs/faq/other permanent; \n\
rewrite /posts/about_syntaxanalysis /docs/about/syntaxanalysis permanent; \n\
rewrite /docs/关于雷池/about_syntaxanalysis /docs/about/syntaxanalysis permanent; \n\
rewrite /posts/about_challenge /docs/about/challenge permanent; \n\
rewrite /docs/关于雷池/about_challenge /docs/about/challenge permanent; \n\
rewrite /posts/about_changelog /docs/about/changelog permanent; \n\
rewrite /docs/关于雷池/about_changelog /docs/about/changelog permanent; \n\
rewrite /posts/about_chaitin /docs/about/chaitin permanent; \n\
rewrite /docs/关于雷池/about_chaitin /docs/about/chaitin permanent; \n\
rewrite /docs/faq/access /docs/guide/config permanent; \n\
rewrite /docs/faq/config /docs/guide/config permanent; \n\
proxy_pass http://127.0.0.1:3000; \n\
} \n\
} \n\
" > /etc/nginx/http.d/default.conf
RUN sed -i 's/access_log/access_log off; #/' /etc/nginx/nginx.conf
RUN nginx -t
COPY release /app/release
# 需要提前编译 blaze
# cd blaze; ./build.sh
# 创建 testcase 压缩文件
# zip -r ./build/testcases.zip testcases
COPY blazehttp/build /app/blazehttp
COPY website /app
WORKDIR /app
RUN npm ci
RUN npm run build
CMD nginx; tini -- npm run serve

6
FAQ.md
View File

@@ -14,7 +14,7 @@ refers also: [https://stackoverflow.com/questions/66514436/difference-between-do
### ERROR: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
As shown, you shall start docker first. Try `systemctl start docker` or manually start your `Docker Desktop` for MacOS/Windows users.
As shown, you shall start docker first. Try `systemctl start docker`.
### docker not found, unable to deploy
@@ -76,9 +76,9 @@ TOTP is calculated and verified according to time. So check your server time.
### ERROR: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
如描述,你需要启动 docker daemon 才能执行相关的命令。尝试 `systemctl start docker` 或者手动启动 `Docker Desktop` MacOS 或者 Windows 用户)
如描述,你需要启动 docker daemon 才能执行相关的命令。尝试 `systemctl start docker`
As shown, you shall start docker first. Try `systemctl start docker` or manually start your docker desktop for MacOS/Windows users.
As shown, you shall start docker first. Try `systemctl start docker`.
### docker not found, unable to deploy

144
README.md
View File

@@ -1,8 +1,7 @@
<p align="center">
<img src="https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_logo.png" width="120">
<img src="https://waf-ce.chaitin.cn/images/403.svg" width="120">
</p>
<h1 align="center">SafeLine Community Edition</h1>
<h3 align="center">Keep hackers at bay</h3>
<h1 align="center">雷池 - 广受好评的社区 WAF</h1>
<br>
<p align="center">
<img src="https://img.shields.io/badge/SafeLine-BEST_WAF-blue">
@@ -12,101 +11,108 @@
<img src="https://img.shields.io/github/stars/chaitin/safeline?style=social">
</p>
<p align="center"> <a href="https://waf-ce.chaitin.cn/">Official Website</a> </p>
<p align="center"> English | <a href="README_CN.md">中文文档</a> </p>
<p align="center">
<a href="https://waf-ce.chaitin.cn/">官方网站</a> |
<a href="https://demo.waf-ce.chaitin.cn:9443/dashboard">在线 Demo</a> |
<a href="https://waf-ce.chaitin.cn/posts/guide_introduction">技术文档</a> |
<a href="README_EN.md">For English</a>
</p>
A simple and easy to use WAF tool. Built on [Chaitin Technology](https://www.chaitin.cn/en/)'s ace 🤖Intelligent Semantic Analysis algorithm🤖, designed for the community.
一款足够简单、足够好用、足够强的免费 WAF。基于业界领先的语义引擎检测技术作为反向代理接入保护你的网站不受黑客攻击。
## ✨ Demo
核心检测能力由智能语义分析算法驱动,专为社区而生,不让黑客越雷池半步。
### 🔥🔥🔥 Online Demo: https://demo.waf-ce.chaitin.cn:9443/
<img src="https://waf-ce.chaitin.cn/images/album/0.png" />
There is a simple http server, listened on `http://127.0.0.1:8889`, can be used as for testing.
<h4 align="center">相关源码仓库</h4>
<p align="center">
<a href="https://github.com/chaitin/yanshi">语义分析自动机引擎</a> |
<a href="https://github.com/chaitin/safeline-open-platform">流量分析插件</a> |
<a href="https://github.com/chaitin/lua-resty-t1k">T1K 协议</a> |
<a href="https://github.com/chaitin/blazehttp">测试工具</a>
</p>
![](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_detect_log.gif)
## 相关特性
![](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_website.gif)
#### 便捷性
## 🚀 Installation
采用容器化部署一条命令即可完成安装0 成本上手。安全配置开箱即用,无需人工维护,可实现安全躺平式管理。
### 1. Make sure [Docker](https://docs.docker.com/engine/install/) and [Compose V2](https://docs.docker.com/compose/install/) are installed correctly on the machine
```shell
docker info # >= 20.10.6
docker compose version # >= 2.0.0
#### 安全性
首创业内领先的智能语义分析算法,精准检测、低误报、难绕过。语义分析算法无规则,面对未知特征的 0day 攻击不再手足无措。
#### 高性能
无规则引擎,线性安全检测算法,平均请求检测延迟在 1 毫秒级别。并发能力强,单核轻松检测 2000+ TPS只要硬件足够强可支撑的流量规模无上限。
#### 高可用
流量处理引擎基于 Nginx 开发,性能与稳定性均可得到保障。内置完善的健康检查机制,服务可用性高达 99.99%。
## 🚀 安装
### 配置需求
- 操作系统Linux
- 指令架构x86_64
- 软件依赖Docker 20.10.6 版本以上
- 软件依赖Docker Compose 2.0.0 版本以上
- 最小化环境1 核 CPU / 1 GB 内存 / 10 GB 磁盘
### 一键安装
```
bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)"
```
### 2. Setup and deploy
> 更多安装方式请参考 <a href="https://waf-ce.chaitin.cn/posts/guide_install">安装雷池</a>
```shell
mkdir -p safeline && cd safeline
# setup
curl -kfLsS https://waf-ce.chaitin.cn/release/latest/setup.sh | bash
## 🕹️ 快速使用
# launch
sudo docker compose up -d
```
### 登录
#### Upgrade
浏览器打开后台管理页面 `https://<waf-ip>:9443`。根据界面提示,使用 **支持 TOTP 的认证软件** 扫描二维码,然后输入动态口令登录:
**WARN: SafeLine will be restarted and your traffic will be unavailable for a short period of time. You may need to choose a proper time for upgration.**
![login.gif](https://waf-ce.chaitin.cn/images/gif/login.gif)
```shell
curl -kfLsS https://waf-ce.chaitin.cn/release/latest/upgrade.sh | bash
### 配置防护站点
# replace with `docker-compose` if necessary.
docker compose down && docker compose pull && docker compose up -d
```
雷池以反向代理方式接入,优先于网站服务器接收流量,对流量中的攻击行为进行检测和清洗,将清洗过后的流量转发给网站服务器。
## 🕹️ Quick Start
![config.gif](https://waf-ce.chaitin.cn/images/gif/config_site.gif)
### 1. Login
<font color=grey>💡 TIPS: 添加后,执行 `curl -H "Host: <域名>" http://<WAF IP>:<端口>` 应能获取到业务网站的响应。</font>
Open admin page `https://<waf-ip>:9443` and scan qrcode with any authenticator Apps that support TOTP, enter the code to login.
### 测试效果
![safeline_login.gif](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_login.gif)
使用以下方式尝试模拟黑客攻击,看看雷池的防护效果如何
### 2. Create website
- 浏览器访问 `http://<IP或域名>:<端口>/?id=1%20AND%201=1`
- 浏览器访问 `http://<IP或域名>:<端口>/?a=<script>alert(1)</script>`
![safeline_website.gif](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_website.gif)
![log.gif](https://waf-ce.chaitin.cn/images/gif/detect_log.gif)
<font color=grey>💡 TIPS: After creating websiteexecute `curl -H "Host: <Domain>" http://<WAF IP>:<Port>` to check if you can get correct response from web server.</font>
> 如果你需要进行深度测试,请参考 <a href="https://waf-ce.chaitin.cn/posts/guide_test">测试防护效果</a>
### 3. Deploy your website to SafeLine
### FAQ
- If your website is hosted by DNS, just modify your DNS record to WAF
- If your website is behind any reverse-proxy like nginx, you can modify your nginx conf and set upstream to WAF
- [安装问题](https://waf-ce.chaitin.cn/posts/faq_install)
- [登录问题](https://waf-ce.chaitin.cn/posts/faq_login)
- [网站无法访问](https://waf-ce.chaitin.cn/posts/faq_access)
- [配置问题](https://waf-ce.chaitin.cn/posts/faq_config)
- [其他问题](https://waf-ce.chaitin.cn/posts/faq_other)
### 4. Protected!👌
## 🏘️ 联系我们
Try these:
1. 可以通过 GitHub Issue 直接进行 Bug 反馈和功能建议
2. 可以扫描下方二维码加入雷池社区版用户讨论群
- `http://<IP or Domain>:<Port>/webshell.php`
- `http://<IP or Domain>:<Port>/?id=1%20AND%201=1`
- `http://<IP or Domain>:<Port>/?a=<script>alert(1)</script>`
## 📖 FAQ
Please refer to our [FAQ](FAQ.md) first if you have any questions.
For examples:
- [docker compose or docker-compose?](FAQ.md#docker-compose-or-docker-compose)
- [website configurations](FAQ.md#站点配置问题)
- [website not working / not correctly response](FAQ.md#配置完成之后还是没有成功访问到上游服务器)
## 🏘️ Contact Us
1. You can make bug feedback and feature suggestions directly through GitHub Issues.
2. By scanning the QR code below (use wechat or qq), you can join the discussion group of SafeLine users for detailed discussions.
<img src="https://waf-ce.chaitin.cn/images/wechat-light.png" width="30%" />
## ✨ CTStack
<img src="https://ctstack-oss.oss-cn-beijing.aliyuncs.com/CT%20Stack-2.png" width="30%" />
SafeLine has already joined [CTStack](https://stack.chaitin.com/tool/detail?id=717) community.
<img src="https://waf-ce.chaitin.cn/images/wechat-230825.png" width="30%" />
## Star History <a name="star-history"></a>
<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>
<img width="500" alt="Star History Chart" src="https://api.star-history.com/svg?repos=chaitin/safeline&type=Date">
</a>

View File

@@ -1,141 +0,0 @@
<p align="center">
<img src="https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_logo.png" width="120">
</p>
<h1 align="center">雷池 SafeLine 社区版</h1>
<h3 align="center">不让黑客越雷池半步</h3>
<br>
<p align="center">
<img src="https://img.shields.io/badge/SafeLine-BEST_WAF-blue">
<img src="https://img.shields.io/github/release/chaitin/safeline.svg?color=blue" />
<img src="https://img.shields.io/github/release-date/chaitin/safeline.svg?color=blue&label=update" />
<img src="https://img.shields.io/docker/v/chaitin/safeline-mgt-api?color=blue">
<img src="https://img.shields.io/github/stars/chaitin/safeline?style=social">
</p>
<p align="center"> <a href="https://waf-ce.chaitin.cn/">官方网站</a> </p>
<p align="center"> 中文文档 | <a href="README.md">English</a> </p>
一款简单、好用的 WAF 工具。基于[长亭科技](https://www.chaitin.cn)王牌的 🤖️智能语义分析算法🤖️ 打造,专为社区设计。
## ✨ Demo
### 🔥🔥🔥 体验地址https://demo.waf-ce.chaitin.cn:9443/
有一台运行在环境上 `http://127.0.0.1:8889` 的服务可以作为上游服务器测试使用。
![](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_detect_log.gif)
![](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_website.gif)
## 🚀 安装
### 1. 确保机器上正确安装 [Docker](https://docs.docker.com/engine/install/) 和 [Compose V2](https://docs.docker.com/compose/install/)
```shell
docker info # >= 20.10.6
docker compose version # >= 2.0.0
```
### 2. 部署安装
```shell
mkdir -p safeline && cd safeline
# 下载并执行 setup
curl -kfLsS https://waf-ce.chaitin.cn/release/latest/setup.sh | bash
# 运行
sudo docker compose up -d
```
#### 升级
##### 自动一键更新
**WARN: 雷池 SafeLine 服务会重启,流量会中断一小段时间,根据业务情况选择合适的时间来执行升级操作。**
```shell
# 请到 compose.yaml 同级目录下执行下面脚本
curl -kfLsS https://waf-ce.chaitin.cn/release/latest/upgrade.sh | bash
```
**有部分环境的默认 SafeLine 安装路径是在 `/data/safeline-ce`,安装之后可能会发现需要重新绑定 OTP、配置丢失等情况可以修改 .env 的 `SAFELINE_DIR` 变量,指向 `/data/safeline-ce`**
##### 手动更新镜像
**适用于 docker hub 拉取镜像失败的场景,手动更新镜像,注意还是要执行 `upgrade.sh` 来处理 `.env` 的更新,否则有可能会因为缺少参数而启动失败。**
###### 1. 在一台能够从 docker hub 拉取镜像的机器上执行
```shell
# 拉取镜像
docker pull chaitin/safeline-tengine:latest
docker pull chaitin/safeline-mgt-api:latest
docker pull chaitin/safeline-mario:latest
docker pull chaitin/safeline-detector:latest
docker pull postgres:15.2
# 打包镜像
docker save -o image.tar chaitin/safeline-tengine:latest chaitin/safeline-mgt-api:latest chaitin/safeline-mario:latest chaitin/safeline-detector:latest postgres:15.2
# 传输到 SafeLine 要部署的目标服务器
# scp image.tar <target-server>:/root/
```
###### 2. 在目标服务器 load 镜像
```shell
docker load -i image.tar
curl -kfLsS https://waf-ce.chaitin.cn/release/latest/upgrade.sh | bash
```
## 🕹️ 快速使用
### 1. 登录
浏览器打开后台管理页面 `https://<waf-ip>:9443`。根据界面提示,使用 **支持 TOTP 的认证软件** 扫描二维码,然后输入动态口令登录:
![safeline_login.gif](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_login.gif)
### 2. 添加站点
![safeline_website.gif](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_website.gif)
<font color=grey>💡 TIPS: 添加后,执行 `curl -H "Host: <域名>" http://<WAF IP>:<端口>` 应能获取到业务网站的响应。</font>
### 3. 将网站流量切到雷池
- 若网站通过域名访问,则可将域名的 DNS 解析指向雷池所在设备
- 若网站前有 nginx 、负载均衡等代理设备,则可将雷池部署在代理设备和业务服务器之间,然后将代理设备的 upstream 指向雷池
### 4. 开始防护👌
试试这些攻击方式:
- 浏览器访问 `http://<IP或域名>:<端口>/webshell.php`
- 浏览器访问 `http://<IP或域名>:<端口>/?id=1%20AND%201=1`
- 浏览器访问 `http://<IP或域名>:<端口>/?a=<script>alert(1)</script>`
## 📖 FAQ
有任何问题请先查阅我们的 [FAQ 文档](FAQ.md)。
比如:
- [docker compose or docker-compose?](FAQ.md#docker-compose-还是-docker-compose)
- [站点如何配置](FAQ.md#站点配置问题)
- [配置完成之后,还是没有成功访问到上游服务器](FAQ.md#配置完成之后还是没有成功访问到上游服务器)
## 🏘️ 联系我们
1. 您可以通过 GitHub Issue 直接进行 Bug 反馈和功能建议。
2. 扫描下方二维码可以加入雷池社区版用户讨论群进行详细讨论
<img src="https://waf-ce.chaitin.cn/images/wechat-light.png" width="30%" />
## ✨ CTStack
<img src="https://ctstack-oss.oss-cn-beijing.aliyuncs.com/CT%20Stack-2.png" width="30%" />
雷池 SafeLine 现已加入 [CTStack](https://stack.chaitin.com/tool/detail?id=717) 社区
## Star History <a name="star-history"></a>
<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>

112
README_EN.md Normal file
View File

@@ -0,0 +1,112 @@
<p align="center">
<img src="https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_logo.png" width="120">
</p>
<h1 align="center">SafeLine Community Edition</h1>
<h3 align="center">Keep hackers at bay</h3>
<br>
<p align="center">
<img src="https://img.shields.io/badge/SafeLine-BEST_WAF-blue">
<img src="https://img.shields.io/github/release/chaitin/safeline.svg?color=blue" />
<img src="https://img.shields.io/github/release-date/chaitin/safeline.svg?color=blue&label=update" />
<img src="https://img.shields.io/docker/v/chaitin/safeline-mgt-api?color=blue">
<img src="https://img.shields.io/github/stars/chaitin/safeline?style=social">
</p>
<p align="center"> <a href="https://waf-ce.chaitin.cn/">Official Website</a> </p>
<p align="center"> English | <a href="README_CN.md">中文文档</a> </p>
A simple and easy to use WAF tool. Built on [Chaitin Technology](https://www.chaitin.cn/en/)'s ace 🤖Intelligent Semantic Analysis algorithm🤖, designed for the community.
## ✨ Demo
### 🔥🔥🔥 Online Demo: https://demo.waf-ce.chaitin.cn:9443/
There is a simple http server, listened on `http://127.0.0.1:8889`, can be used as for testing.
![](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_detect_log.gif)
![](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_website.gif)
## 🚀 Installation
### 1. Make sure [Docker](https://docs.docker.com/engine/install/) and [Compose V2](https://docs.docker.com/compose/install/) are installed correctly on the machine
```shell
docker info # >= 20.10.6
docker compose version # >= 2.0.0
```
### 2. Setup and deploy
```shell
mkdir -p safeline && cd safeline
# setup
curl -kfLsS https://waf-ce.chaitin.cn/release/latest/setup.sh | bash
# launch
sudo docker compose up -d
```
#### Upgrade
**WARN: SafeLine will be restarted and your traffic will be unavailable for a short period of time. You may need to choose a proper time for upgration.**
```shell
curl -kfLsS https://waf-ce.chaitin.cn/release/latest/upgrade.sh | bash
# delete the old used image layers if necessary.
docker rmi $(docker images | grep "safeline" | grep "none" | awk '{print $3}')
```
## 🕹️ Quick Start
### 1. Login
Open admin page `https://<waf-ip>:9443` and scan qrcode with any authenticator Apps that support TOTP, enter the code to login.
![safeline_login.gif](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_login.gif)
### 2. Create website
![safeline_website.gif](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_website.gif)
<font color=grey>💡 TIPS: After creating websiteexecute `curl -H "Host: <Domain>" http://<WAF IP>:<Port>` to check if you can get correct response from web server.</font>
### 3. Deploy your website to SafeLine
- If your website is hosted by DNS, just modify your DNS record to WAF
- If your website is behind any reverse-proxy like nginx, you can modify your nginx conf and set upstream to WAF
### 4. Protected!👌
Try these:
- `http://<IP or Domain>:<Port>/webshell.php`
- `http://<IP or Domain>:<Port>/?id=1%20AND%201=1`
- `http://<IP or Domain>:<Port>/?a=<script>alert(1)</script>`
## 📖 FAQ
Please refer to our [FAQ](FAQ.md) first if you have any questions.
For examples:
- [docker compose or docker-compose?](FAQ.md#docker-compose-or-docker-compose)
- [website configurations](FAQ.md#站点配置问题)
- [website not working / not correctly response](FAQ.md#配置完成之后还是没有成功访问到上游服务器)
## 🏘️ Contact Us
1. You can make bug feedback and feature suggestions directly through GitHub Issues.
2. By scanning the QR code below (use wechat or qq), you can join the discussion group of SafeLine users for detailed discussions.
<img src="https://waf-ce.chaitin.cn/images/wechat-230825.png" width="30%" />
## ✨ CTStack
<img src="https://ctstack-oss.oss-cn-beijing.aliyuncs.com/CT%20Stack-2.png" width="30%" />
SafeLine has already joined [CTStack](https://stack.chaitin.com/tool/detail?id=717) community.
## Star History <a name="star-history"></a>
<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>

1
blazehttp Submodule

Submodule blazehttp added at 23e8b59cd2

View File

@@ -26,7 +26,7 @@
width: 100%;
background: white;
font-size: 12px;
min-height: 450px;
min-height: 480px;
position: relative;
}
@@ -44,12 +44,19 @@
margin-bottom: 1.5rem;
font-size: 20px;
line-height: 1.6;
color: #333;
color: black;
}
.intercepted-tips {
margin: 8px 0;
font-size: 14px;
color: rgba(0, 0, 0, 0.7);
}
.intercepted-item {
margin: 8px 0;
color: #666;
font-size: 12px;
color: rgba(0, 0, 0, 0.3);
}
.footer {
@@ -57,8 +64,8 @@
bottom: 32px;
left: 0;
width: 100%;
color: #a8a8a8;
font-size: 10px;
color: rgba(0, 0, 0, 0.3);
font-size: 12px;
text-align: center;
}
.footer-waflink {
@@ -81,7 +88,6 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<title>编组 12</title>
<defs>
<linearGradient
x1="50%"
@@ -155,71 +161,60 @@
</filter>
</defs>
<g
id="页面-1"
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<g id="编组-12" transform="translate(49.000000, 38.000000)">
<g transform="translate(49.000000, 38.000000)">
<path
d="M292.40836,59.04 C290.927217,51.9634286 285.002646,46.6971429 277.761503,46.368 C222.13636,44.8868571 176.385503,16.5805714 157.953503,3.08571429 C152.358074,-1.02857143 144.95236,-1.02857143 139.356931,3.08571429 C120.431217,16.5805714 75.1740742,44.8868571 19.5489314,46.368 C12.4723599,46.6971429 6.21864565,51.9634286 4.90207422,59.04 C-3.98478292,103.474286 -19.2899258,254.057143 148.902074,324 C316.60036,253.892571 300.966074,103.474286 292.40836,59.04 Z"
id="路径"
fill="url(#linearGradient-1)"
fill-rule="nonzero"
></path>
<path
d="M292.40836,59.04 C290.927217,51.9634286 285.002646,46.6971429 277.761503,46.368 C222.13636,44.8868571 176.385503,16.5805714 157.953503,3.08571429 C152.358074,-1.02857143 144.95236,-1.02857143 139.356931,3.08571429 C120.431217,16.5805714 75.1740742,44.8868571 19.5489314,46.368 C12.4723599,46.6971429 6.21864565,51.9634286 4.90207422,59.04 C-3.98478292,103.474286 -19.2899258,254.057143 148.902074,324 C316.60036,253.892571 300.966074,103.474286 292.40836,59.04 Z"
id="路径"
fill="url(#linearGradient-1)"
fill-rule="nonzero"
filter="url(#filter-2)"
></path>
<path
d="M149,261.4 C205.553958,261.4 251.4,215.553958 251.4,159 C251.4,131.275004 240.381593,106.123494 222.484813,87.6855068 C209.900749,96.0964568 185.81512,106.024178 175.564259,100.853688 C166.334879,96.1984273 157.476591,88.4505652 148.989396,77.610101 C142.047769,88.5334102 134.670586,95.5517221 126.857848,98.6650367 C120.689419,101.123107 98.2592604,102.915695 75.4419467,87.761039 C57.5883513,106.192154 46.6,131.312844 46.6,159 C46.6,215.553958 92.4460416,261.4 149,261.4 Z"
id="椭圆形备份-26"
fill="url(#linearGradient-3)"
></path>
<g
id="编组-5备份-6"
transform="translate(91.771423, 102.101722)"
fill="#FFFFFF"
>
<polygon
id="路径-130备份-29"
transform="translate(57.217971, 95.920999) rotate(-180.000000) translate(-57.217971, -95.920999) "
points="56.6651511 64.9496372 -7.57241738e-17 97.1108413 50.6084036 126.892361 68.8016729 117.264704 34.3433228 97.1108413 56.6651511 84.5503086 96.9001091 107.376711 96.9001091 114.88399 114.435942 125.435553 114.435942 97.1108413"
></polygon>
<polygon
id="路径-130备份-30"
transform="translate(57.217971, 30.971362) rotate(-360.000000) translate(-57.217971, -30.971362) "
points="56.6651511 2.84217094e-14 -7.57241738e-17 32.1612041 50.6084036 61.9427239 68.8016729 52.3150668 34.3433228 32.1612041 56.6651511 19.6006714 96.9001091 42.4270741 96.9001091 49.9343528 114.435942 60.4859155 114.435942 32.1612041"
></polygon>
<polygon
id="路径-130备份-29"
opacity="0.40499442"
transform="translate(57.217971, 95.920999) rotate(-180.000000) translate(-57.217971, -95.920999) "
points="56.6651511 64.9496372 -7.57241738e-17 97.1108413 50.6084036 126.892361 68.8016729 117.264704 34.3433228 97.1108413 56.6651511 84.5503086 96.9001091 107.376711 96.9001091 114.88399 114.435942 125.435553 114.435942 97.1108413"
></polygon>
<polygon
id="路径-130备份-30"
opacity="0.40499442"
transform="translate(57.217971, 30.971362) rotate(-360.000000) translate(-57.217971, -30.971362) "
points="56.6651511 4.8316906e-13 -7.57241738e-17 32.1612041 50.6084036 61.9427239 68.8016729 52.3150668 34.3433228 32.1612041 56.6651511 19.6006714 96.9001091 42.4270741 96.9001091 49.9343528 114.435942 60.4859155 114.435942 32.1612041"
></polygon>
</g>
<g
id="长亭logo备份-18"
transform="translate(72.200000, 45.222222)"
fill-rule="nonzero"
>
<g id="编组-7">
<g>
<path
d="M96.7632666,18.0061837 C96.7632666,18.0061837 79.3862969,15.2966085 76.7907961,0 C74.1952953,15.2966085 56.8183256,18.0061837 56.8183256,18.0061837 C39.1836466,20.8694936 30.6424242,7.60987058 30.6424242,7.60987058 C39.0363842,30.6893013 53.7258141,29.862977 53.7258141,29.862977 L99.8741859,29.862977 C99.8741859,29.862977 114.563616,30.6700845 122.957576,7.60987058 C122.957576,7.60987058 114.416353,20.8694936 96.7816744,18.0061837 L96.7632666,18.0061837 Z"
id="路径"
fill="#27B876"
></path>
<g id="路径">
<g>
<use
fill="black"
fill-opacity="1"
@@ -235,6 +230,7 @@
</svg>
</div>
<div class="intercepted">请求存在威胁,已被拦截</div>
<div class="intercepted-tips" id="intercepted-tips"></div>
<div class="intercepted-item" id="EventID"></div>
<div class="intercepted-item" id="TYPE"></div>
<div class="intercepted-item">拦截时间: <span id="now"></span></div>
@@ -287,7 +283,7 @@
/**
* 以后引擎按此约定插入新参数:
* <!-- event_id: ****** type: A anymore: **** -->
* event_id: ****** type: A anymore: ****
*/
try {
@@ -305,7 +301,7 @@
console.log(e);
}
if (event_id) {
document.getElementById("EventID").innerText = "EventID: " + event_id;
document.getElementById("EventID").innerText = "ID: " + event_id;
}
if (type) {
document.getElementById("TYPE").innerText = "TYPE: " + type;

282
blockpage/limited.html Normal file
View File

@@ -0,0 +1,282 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>访问频率过高,本次请求已被拦截</title>
<link
rel="shortcut icon"
href="data:image/png;base64,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"
/>
<style>
html {
height: 100%;
}
body {
margin: 0;
height: 100%;
}
.container {
text-align: center;
word-break: keep-all;
height: 100%;
width: 100%;
background: white;
font-size: 12px;
min-height: 450px;
position: relative;
}
.content {
width: 100%;
height: 100%;
}
.logo {
text-align: center;
}
.intercepted {
margin-top: 3.5rem;
margin-bottom: 1.5rem;
font-size: 20px;
line-height: 1.6;
color: black;
}
.intercepted-tips {
margin: 8px 0;
font-size: 14px;
color: rgba(0, 0, 0, 0.7);
}
.intercepted-item {
margin: 8px 0;
color: rgba(0, 0, 0, 0.3);
}
.footer {
position: absolute;
bottom: 32px;
left: 0;
width: 100%;
color: rgba(0, 0, 0, 0.3);
font-size: 12px;
text-align: center;
}
.footer-waflink {
color: #27b876;
text-decoration: none;
}
</style>
</head>
<body>
<div class="container">
<table class="content">
<tr>
<td>
<div class="logo">
<svg
width="200px"
height="200px"
viewBox="0 0 396 407"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<defs>
<linearGradient
x1="50%"
y1="0%"
x2="50%"
y2="100%"
id="linearGradient-1"
>
<stop stop-color="#4B4B4B" offset="0%"></stop>
<stop stop-color="#000000" offset="100%"></stop>
</linearGradient>
<filter
x="-3.0%"
y="-2.8%"
width="106.1%"
height="105.6%"
filterUnits="objectBoundingBox"
id="filter-2"
>
<feGaussianBlur
stdDeviation="3"
in="SourceGraphic"
></feGaussianBlur>
</filter>
<linearGradient
x1="50%"
y1="0%"
x2="50%"
y2="100%"
id="linearGradient-3"
>
<stop
stop-color="#24BC43"
stop-opacity="0.8"
offset="0%"
></stop>
<stop
stop-color="#3ACBAB"
stop-opacity="0.7"
offset="100%"
></stop>
</linearGradient>
<path
d="M110.049657,49.667649 C110.049657,49.667649 81.1358702,46.2263115 76.8,26.7636364 C72.4880848,46.2263115 43.5503431,49.667649 43.5503431,49.667649 C14.2053649,53.3001718 0,36.4567369 0,36.4567369 C13.941859,65.8036979 38.4,64.7712967 38.4,64.7712967 L115.2,64.7712967 C115.2,64.7712967 139.634186,65.8036979 153.6,36.4567369 C153.6,36.4567369 139.394635,53.3192904 110.049657,49.667649 Z"
id="path-4"
></path>
<filter
x="-16.9%"
y="-57.9%"
width="133.9%"
height="236.8%"
filterUnits="objectBoundingBox"
id="filter-5"
>
<feOffset
dx="0"
dy="4"
in="SourceAlpha"
result="shadowOffsetOuter1"
></feOffset>
<feGaussianBlur
stdDeviation="8"
in="shadowOffsetOuter1"
result="shadowBlurOuter1"
></feGaussianBlur>
<feColorMatrix
values="0 0 0 0 0 0 0 0 0 0.490319293 0 0 0 0 0.292243323 0 0 0 1 0"
type="matrix"
in="shadowBlurOuter1"
></feColorMatrix>
</filter>
</defs>
<g
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<g transform="translate(49.000000, 38.000000)">
<path
d="M292.40836,59.04 C290.927217,51.9634286 285.002646,46.6971429 277.761503,46.368 C222.13636,44.8868571 176.385503,16.5805714 157.953503,3.08571429 C152.358074,-1.02857143 144.95236,-1.02857143 139.356931,3.08571429 C120.431217,16.5805714 75.1740742,44.8868571 19.5489314,46.368 C12.4723599,46.6971429 6.21864565,51.9634286 4.90207422,59.04 C-3.98478292,103.474286 -19.2899258,254.057143 148.902074,324 C316.60036,253.892571 300.966074,103.474286 292.40836,59.04 Z"
fill="url(#linearGradient-1)"
fill-rule="nonzero"
></path>
<path
d="M292.40836,59.04 C290.927217,51.9634286 285.002646,46.6971429 277.761503,46.368 C222.13636,44.8868571 176.385503,16.5805714 157.953503,3.08571429 C152.358074,-1.02857143 144.95236,-1.02857143 139.356931,3.08571429 C120.431217,16.5805714 75.1740742,44.8868571 19.5489314,46.368 C12.4723599,46.6971429 6.21864565,51.9634286 4.90207422,59.04 C-3.98478292,103.474286 -19.2899258,254.057143 148.902074,324 C316.60036,253.892571 300.966074,103.474286 292.40836,59.04 Z"
fill="url(#linearGradient-1)"
fill-rule="nonzero"
filter="url(#filter-2)"
></path>
<path
d="M149,261.4 C205.553958,261.4 251.4,215.553958 251.4,159 C251.4,131.275004 240.381593,106.123494 222.484813,87.6855068 C209.900749,96.0964568 185.81512,106.024178 175.564259,100.853688 C166.334879,96.1984273 157.476591,88.4505652 148.989396,77.610101 C142.047769,88.5334102 134.670586,95.5517221 126.857848,98.6650367 C120.689419,101.123107 98.2592604,102.915695 75.4419467,87.761039 C57.5883513,106.192154 46.6,131.312844 46.6,159 C46.6,215.553958 92.4460416,261.4 149,261.4 Z"
fill="url(#linearGradient-3)"
></path>
<g
transform="translate(91.771423, 102.101722)"
fill="#FFFFFF"
>
<polygon
transform="translate(57.217971, 95.920999) rotate(-180.000000) translate(-57.217971, -95.920999) "
points="56.6651511 64.9496372 -7.57241738e-17 97.1108413 50.6084036 126.892361 68.8016729 117.264704 34.3433228 97.1108413 56.6651511 84.5503086 96.9001091 107.376711 96.9001091 114.88399 114.435942 125.435553 114.435942 97.1108413"
></polygon>
<polygon
transform="translate(57.217971, 30.971362) rotate(-360.000000) translate(-57.217971, -30.971362) "
points="56.6651511 2.84217094e-14 -7.57241738e-17 32.1612041 50.6084036 61.9427239 68.8016729 52.3150668 34.3433228 32.1612041 56.6651511 19.6006714 96.9001091 42.4270741 96.9001091 49.9343528 114.435942 60.4859155 114.435942 32.1612041"
></polygon>
<polygon
opacity="0.40499442"
transform="translate(57.217971, 95.920999) rotate(-180.000000) translate(-57.217971, -95.920999) "
points="56.6651511 64.9496372 -7.57241738e-17 97.1108413 50.6084036 126.892361 68.8016729 117.264704 34.3433228 97.1108413 56.6651511 84.5503086 96.9001091 107.376711 96.9001091 114.88399 114.435942 125.435553 114.435942 97.1108413"
></polygon>
<polygon
opacity="0.40499442"
transform="translate(57.217971, 30.971362) rotate(-360.000000) translate(-57.217971, -30.971362) "
points="56.6651511 4.8316906e-13 -7.57241738e-17 32.1612041 50.6084036 61.9427239 68.8016729 52.3150668 34.3433228 32.1612041 56.6651511 19.6006714 96.9001091 42.4270741 96.9001091 49.9343528 114.435942 60.4859155 114.435942 32.1612041"
></polygon>
</g>
<g
transform="translate(72.200000, 45.222222)"
fill-rule="nonzero"
>
<g>
<path
d="M96.7632666,18.0061837 C96.7632666,18.0061837 79.3862969,15.2966085 76.7907961,0 C74.1952953,15.2966085 56.8183256,18.0061837 56.8183256,18.0061837 C39.1836466,20.8694936 30.6424242,7.60987058 30.6424242,7.60987058 C39.0363842,30.6893013 53.7258141,29.862977 53.7258141,29.862977 L99.8741859,29.862977 C99.8741859,29.862977 114.563616,30.6700845 122.957576,7.60987058 C122.957576,7.60987058 114.416353,20.8694936 96.7816744,18.0061837 L96.7632666,18.0061837 Z"
fill="#27B876"
></path>
<g>
<use
fill="black"
fill-opacity="1"
filter="url(#filter-5)"
xlink:href="#path-4"
></use>
<use fill="#27B876" xlink:href="#path-4"></use>
</g>
</g>
</g>
</g>
</g>
</svg>
</div>
<div id="intercepted" class="intercepted">
请求频率过高,存在威胁,已被拦截
</div>
<div class="intercepted-tips" id="intercepted-tips"></div>
<div class="intercepted-item">
<span id="intercepted-at">拦截时间</span>: <span id="now"></span>
</div>
</td>
</tr>
</table>
<div id="footer" class="footer">
安全检测能力由
<a class="footer-waflink" href="https://waf-ce.chaitin.cn"
>长亭雷池 WAF</a
>
驱动
</div>
</div>
<script>
// 显示当前时间
function timestring() {
var d = new Date();
function p(d) {
return d < 10 ? "0" + d : d;
}
return (
d.getFullYear() +
"-" +
p(d.getMonth() + 1) +
"-" +
p(d.getDate()) +
" " +
p(d.getHours()) +
":" +
p(d.getMinutes())
);
}
document.getElementById("now").innerText = timestring();
</script>
<script>
if (navigator.language.startsWith("en")) {
document.title = "Requested too frequently";
document.getElementById("intercepted").innerText =
"Requested too frequently, please try again later";
document.getElementById("intercepted-at").innerText = "Intercepted at";
document.getElementById("footer").style.display = "none";
}
</script>
</body>
</html>

212
blockpage/maintaining.html Normal file
View File

@@ -0,0 +1,212 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>网站维护中</title>
<style>
html {
height: 100%;
}
body {
margin: 0;
height: 100%;
}
.container {
text-align: center;
word-break: keep-all;
height: 100%;
width: 100%;
background: white;
font-size: 12px;
min-height: 450px;
position: relative;
}
.content {
width: 100%;
height: 100%;
}
.logo {
text-align: center;
}
.intercepted {
margin-top: 3.5rem;
margin-bottom: 1.5rem;
font-size: 20px;
line-height: 1.6;
color: #333;
}
.intercepted-item {
margin: 8px 0;
color: #666;
}
.footer {
position: absolute;
bottom: 32px;
left: 0;
width: 100%;
color: rgba(0, 0, 0, 0.3);
font-size: 12px;
text-align: center;
}
.footer-waflink {
color: #27b876;
text-decoration: none;
}
</style>
</head>
<body>
<div class="container">
<table class="content">
<tr>
<td>
<div class="logo">
<svg
width="300px"
height="112px"
viewBox="0 0 300 112"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<title>编组 65</title>
<defs>
<linearGradient
x1="50%"
y1="0%"
x2="50%"
y2="100%"
id="linearGradient-1"
>
<stop
stop-color="#0FC6C2"
stop-opacity="0.1"
offset="0%"
></stop>
<stop
stop-color="#0FC6C2"
stop-opacity="0"
offset="100%"
></stop>
</linearGradient>
<linearGradient
x1="50%"
y1="0%"
x2="50%"
y2="100%"
id="linearGradient-2"
>
<stop stop-color="#A9D6D3" offset="0%"></stop>
<stop stop-color="#8EC6C4" offset="100%"></stop>
</linearGradient>
<linearGradient
x1="17.048305%"
y1="8.1635079%"
x2="76.1348779%"
y2="89.9397366%"
id="linearGradient-3"
>
<stop stop-color="#ECF7F7" offset="0%"></stop>
<stop stop-color="#CEEFEE" offset="100%"></stop>
</linearGradient>
</defs>
<g
id="问脉"
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<g id="编组-65" transform="translate(0.000000, 0.656106)">
<path
d="M158.105468,46.4305012 C230.638275,48.8882768 280.048484,89.2493521 291.411562,97.5896283 C298.986948,103.149812 301.288867,107.707461 298.317319,111.262574 L0,111.262574 C57.0484407,66.4026752 109.750263,44.7919842 158.105468,46.4305012 Z"
id="路径-14备份"
fill="url(#linearGradient-1)"
opacity="0.6"
></path>
<path
d="M133.744707,59.2516792 C128.220216,62.212914 142.271748,72.3438938 152.603912,72.3438938 C162.936076,72.3438938 170.384509,66.1002168 166.415224,63.7091176 C162.445939,61.3180184 139.269199,56.2904444 133.744707,59.2516792 Z"
id="路径-23备份"
fill="#CEEEED"
></path>
<g
id="维护备份"
transform="translate(125.841376, 4.000000)"
fill="url(#linearGradient-2)"
fill-rule="nonzero"
>
<path
d="M53.4407915,17.8309532 C49.850381,20.6412105 45.048111,20.2807339 42.738148,17.0275722 C40.428185,13.7744105 41.4704292,8.83897736 45.0608397,6.02872002 L48.4302392,3.3908402 C50.2893442,1.93421992 49.6588911,0.00928311389 46.813125,0.241953931 C43.8131226,0.486558233 40.8354442,1.6843377 38.3140089,3.66074708 C34.2763868,6.82838427 31.8308675,11.6191742 31.8089552,16.4041942 L3.55036904,38.5271177 C-0.0421309333,41.3487126 -1.07876034,46.2575577 1.22851314,49.522012 C2.33804924,51.0840803 4.09016048,52.0468265 6.09769574,52.1975197 C8.105231,52.3482129 10.2029338,51.6744483 11.9272901,50.3251027 L40.1897428,28.2024695 C43.7454976,29.2914901 47.8019094,28.7846954 51.4034487,26.8014661 C55.004988,24.8182368 57.8332485,21.5339069 59.2220045,17.7221341 C60.2487908,14.9244912 58.6731626,13.7367433 56.810191,15.1930733 L53.4407915,17.8309532 Z M5.56827104,46.1206895 C4.79626286,45.0334702 5.14228458,43.3949223 6.34222301,42.4557247 C7.541301,41.5714856 9.09674694,41.7145817 9.85296424,42.7787018 C10.6091815,43.842822 10.2920189,45.4421908 9.13710773,46.3885799 C7.9371693,47.3277774 6.34027921,47.2079088 5.56827104,46.1206895 Z M13.7446583,12.4428814 L20.5888502,22.087378 L24.9316389,18.6903037 L18.087447,9.04580702 L16.9394989,5.05163029 L11.6667257,0 L7.32393706,3.39707438 L10.4272492,10.147387 L13.7446583,12.4428814 Z M38.1657743,33.2576704 C37.8311845,33.2325548 37.4815663,33.3450613 37.1943929,33.5702592 L30.6813074,38.6699737 C30.0831963,39.1405877 29.9105495,39.9581375 30.2943314,40.5024561 L40.1788997,54.4239027 C41.7237519,56.5943835 44.9213986,56.8344109 47.3165731,54.9596835 C49.7156141,53.0852463 50.4093292,49.8002347 48.8653128,47.6257961 L38.976878,33.7040592 C38.7922954,33.4434496 38.5003642,33.282786 38.1657743,33.2576704 Z"
id="形状"
></path>
</g>
<g
id="维护备份-2"
transform="translate(123.841376, 0.000000)"
fill="url(#linearGradient-3)"
fill-rule="nonzero"
>
<path
d="M53.4407915,17.8309532 C49.850381,20.6412105 45.048111,20.2807339 42.738148,17.0275722 C40.428185,13.7744105 41.4704292,8.83897736 45.0608397,6.02872002 L48.4302392,3.3908402 C50.2893442,1.93421992 49.6588911,0.00928311389 46.813125,0.241953931 C43.8131226,0.486558233 40.8354442,1.6843377 38.3140089,3.66074708 C34.2763868,6.82838427 31.8308675,11.6191742 31.8089552,16.4041942 L3.55036904,38.5271177 C-0.0421309333,41.3487126 -1.07876034,46.2575577 1.22851314,49.522012 C2.33804924,51.0840803 4.09016048,52.0468265 6.09769574,52.1975197 C8.105231,52.3482129 10.2029338,51.6744483 11.9272901,50.3251027 L40.1897428,28.2024695 C43.7454976,29.2914901 47.8019094,28.7846954 51.4034487,26.8014661 C55.004988,24.8182368 57.8332485,21.5339069 59.2220045,17.7221341 C60.2487908,14.9244912 58.6731626,13.7367433 56.810191,15.1930733 L53.4407915,17.8309532 Z M5.56827104,46.1206895 C4.79626286,45.0334702 5.14228458,43.3949223 6.34222301,42.4557247 C7.541301,41.5714856 9.09674694,41.7145817 9.85296424,42.7787018 C10.6091815,43.842822 10.2920189,45.4421908 9.13710773,46.3885799 C7.9371693,47.3277774 6.34027921,47.2079088 5.56827104,46.1206895 Z M13.7446583,12.4428814 L20.5888502,22.087378 L24.9316389,18.6903037 L18.087447,9.04580702 L16.9394989,5.05163029 L11.6667257,0 L7.32393706,3.39707438 L10.4272492,10.147387 L13.7446583,12.4428814 Z M38.1657743,33.2576704 C37.8311845,33.2325548 37.4815663,33.3450613 37.1943929,33.5702592 L30.6813074,38.6699737 C30.0831963,39.1405877 29.9105495,39.9581375 30.2943314,40.5024561 L40.1788997,54.4239027 C41.7237519,56.5943835 44.9213986,56.8344109 47.3165731,54.9596835 C49.7156141,53.0852463 50.4093292,49.8002347 48.8653128,47.6257961 L38.976878,33.7040592 C38.7922954,33.4434496 38.5003642,33.282786 38.1657743,33.2576704 Z"
id="形状"
></path>
</g>
</g>
</g>
</svg>
</div>
<div class="intercepted" id="intercepted">
网站维护中,暂时无法访问
</div>
<div class="intercepted-item"><span id="now"></span></div>
</td>
</tr>
</table>
<div class="footer" id="footer">
安全检测能力由
<a class="footer-waflink" href="https://waf-ce.chaitin.cn"
>长亭雷池 WAF</a
>
驱动
</div>
</div>
<script>
// 显示当前时间
function timestring() {
var d = new Date();
function p(d) {
return d < 10 ? "0" + d : d;
}
return (
d.getFullYear() +
"-" +
p(d.getMonth() + 1) +
"-" +
p(d.getDate()) +
" " +
p(d.getHours()) +
":" +
p(d.getMinutes())
);
}
document.getElementById("now").innerText = timestring();
</script>
<script>
if (navigator.language.startsWith("en")) {
document.title = "Site is Maintaining";
document.getElementById("intercepted").innerText =
"The site is on maintaining, please try again later";
document.getElementById("footer").style.display = "none";
}
</script>
</body>
</html>

240
blockpage/not_found.html Normal file
View File

@@ -0,0 +1,240 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>您访问的网站不存在</title>
<link
rel="shortcut icon"
href="data:image/png;base64,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"
/>
<style>
html {
height: 100%;
}
body {
margin: 0;
height: 100%;
}
.container {
text-align: center;
word-break: keep-all;
height: 100%;
width: 100%;
background: white;
font-size: 12px;
min-height: 450px;
position: relative;
}
.content {
width: 100%;
height: 100%;
}
.logo {
text-align: center;
}
.intercepted {
margin-top: 3.5rem;
margin-bottom: 1.5rem;
font-size: 20px;
line-height: 1.6;
color: black;
}
.intercepted-item {
margin: 8px 0;
font-size: 12px;
color: rgba(0, 0, 0, 0.3);
}
.footer {
position: absolute;
bottom: 32px;
left: 0;
width: 100%;
color: rgba(0, 0, 0, 0.3);
font-size: 12px;
text-align: center;
}
.footer-waflink {
color: #27b876;
text-decoration: none;
}
</style>
</head>
<body>
<div class="container">
<table class="content">
<tr>
<td>
<div class="logo">
<svg
width="200px"
height="200px"
viewBox="0 0 396 407"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<defs>
<linearGradient
x1="50%"
y1="0%"
x2="50%"
y2="100%"
id="linearGradient-1"
>
<stop stop-color="#4B4B4B" offset="0%"></stop>
<stop stop-color="#000000" offset="100%"></stop>
</linearGradient>
<filter
x="-3.0%"
y="-2.8%"
width="106.1%"
height="105.6%"
filterUnits="objectBoundingBox"
id="filter-2"
>
<feGaussianBlur
stdDeviation="3"
in="SourceGraphic"
></feGaussianBlur>
</filter>
<linearGradient
x1="50%"
y1="0%"
x2="50%"
y2="100%"
id="linearGradient-3"
>
<stop
stop-color="#24BC43"
stop-opacity="0.8"
offset="0%"
></stop>
<stop
stop-color="#3ACBAB"
stop-opacity="0.7"
offset="100%"
></stop>
</linearGradient>
<path
d="M110.049657,49.667649 C110.049657,49.667649 81.1358702,46.2263115 76.8,26.7636364 C72.4880848,46.2263115 43.5503431,49.667649 43.5503431,49.667649 C14.2053649,53.3001718 0,36.4567369 0,36.4567369 C13.941859,65.8036979 38.4,64.7712967 38.4,64.7712967 L115.2,64.7712967 C115.2,64.7712967 139.634186,65.8036979 153.6,36.4567369 C153.6,36.4567369 139.394635,53.3192904 110.049657,49.667649 Z"
id="path-4"
></path>
<filter
x="-16.9%"
y="-57.9%"
width="133.9%"
height="236.8%"
filterUnits="objectBoundingBox"
id="filter-5"
>
<feOffset
dx="0"
dy="4"
in="SourceAlpha"
result="shadowOffsetOuter1"
></feOffset>
<feGaussianBlur
stdDeviation="8"
in="shadowOffsetOuter1"
result="shadowBlurOuter1"
></feGaussianBlur>
<feColorMatrix
values="0 0 0 0 0 0 0 0 0 0.490319293 0 0 0 0 0.292243323 0 0 0 1 0"
type="matrix"
in="shadowBlurOuter1"
></feColorMatrix>
</filter>
</defs>
<g
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<g transform="translate(49.000000, 38.000000)">
<path
d="M292.40836,59.04 C290.927217,51.9634286 285.002646,46.6971429 277.761503,46.368 C222.13636,44.8868571 176.385503,16.5805714 157.953503,3.08571429 C152.358074,-1.02857143 144.95236,-1.02857143 139.356931,3.08571429 C120.431217,16.5805714 75.1740742,44.8868571 19.5489314,46.368 C12.4723599,46.6971429 6.21864565,51.9634286 4.90207422,59.04 C-3.98478292,103.474286 -19.2899258,254.057143 148.902074,324 C316.60036,253.892571 300.966074,103.474286 292.40836,59.04 Z"
fill="url(#linearGradient-1)"
fill-rule="nonzero"
></path>
<path
d="M292.40836,59.04 C290.927217,51.9634286 285.002646,46.6971429 277.761503,46.368 C222.13636,44.8868571 176.385503,16.5805714 157.953503,3.08571429 C152.358074,-1.02857143 144.95236,-1.02857143 139.356931,3.08571429 C120.431217,16.5805714 75.1740742,44.8868571 19.5489314,46.368 C12.4723599,46.6971429 6.21864565,51.9634286 4.90207422,59.04 C-3.98478292,103.474286 -19.2899258,254.057143 148.902074,324 C316.60036,253.892571 300.966074,103.474286 292.40836,59.04 Z"
fill="url(#linearGradient-1)"
fill-rule="nonzero"
filter="url(#filter-2)"
></path>
<path
d="M149,261.4 C205.553958,261.4 251.4,215.553958 251.4,159 C251.4,131.275004 240.381593,106.123494 222.484813,87.6855068 C209.900749,96.0964568 185.81512,106.024178 175.564259,100.853688 C166.334879,96.1984273 157.476591,88.4505652 148.989396,77.610101 C142.047769,88.5334102 134.670586,95.5517221 126.857848,98.6650367 C120.689419,101.123107 98.2592604,102.915695 75.4419467,87.761039 C57.5883513,106.192154 46.6,131.312844 46.6,159 C46.6,215.553958 92.4460416,261.4 149,261.4 Z"
fill="url(#linearGradient-3)"
></path>
<g
transform="translate(91.771423, 102.101722)"
fill="#FFFFFF"
>
<polygon
transform="translate(57.217971, 95.920999) rotate(-180.000000) translate(-57.217971, -95.920999) "
points="56.6651511 64.9496372 -7.57241738e-17 97.1108413 50.6084036 126.892361 68.8016729 117.264704 34.3433228 97.1108413 56.6651511 84.5503086 96.9001091 107.376711 96.9001091 114.88399 114.435942 125.435553 114.435942 97.1108413"
></polygon>
<polygon
transform="translate(57.217971, 30.971362) rotate(-360.000000) translate(-57.217971, -30.971362) "
points="56.6651511 2.84217094e-14 -7.57241738e-17 32.1612041 50.6084036 61.9427239 68.8016729 52.3150668 34.3433228 32.1612041 56.6651511 19.6006714 96.9001091 42.4270741 96.9001091 49.9343528 114.435942 60.4859155 114.435942 32.1612041"
></polygon>
<polygon
opacity="0.40499442"
transform="translate(57.217971, 95.920999) rotate(-180.000000) translate(-57.217971, -95.920999) "
points="56.6651511 64.9496372 -7.57241738e-17 97.1108413 50.6084036 126.892361 68.8016729 117.264704 34.3433228 97.1108413 56.6651511 84.5503086 96.9001091 107.376711 96.9001091 114.88399 114.435942 125.435553 114.435942 97.1108413"
></polygon>
<polygon
opacity="0.40499442"
transform="translate(57.217971, 30.971362) rotate(-360.000000) translate(-57.217971, -30.971362) "
points="56.6651511 4.8316906e-13 -7.57241738e-17 32.1612041 50.6084036 61.9427239 68.8016729 52.3150668 34.3433228 32.1612041 56.6651511 19.6006714 96.9001091 42.4270741 96.9001091 49.9343528 114.435942 60.4859155 114.435942 32.1612041"
></polygon>
</g>
<g
transform="translate(72.200000, 45.222222)"
fill-rule="nonzero"
>
<g>
<path
d="M96.7632666,18.0061837 C96.7632666,18.0061837 79.3862969,15.2966085 76.7907961,0 C74.1952953,15.2966085 56.8183256,18.0061837 56.8183256,18.0061837 C39.1836466,20.8694936 30.6424242,7.60987058 30.6424242,7.60987058 C39.0363842,30.6893013 53.7258141,29.862977 53.7258141,29.862977 L99.8741859,29.862977 C99.8741859,29.862977 114.563616,30.6700845 122.957576,7.60987058 C122.957576,7.60987058 114.416353,20.8694936 96.7816744,18.0061837 L96.7632666,18.0061837 Z"
fill="#27B876"
></path>
<g>
<use
fill="black"
fill-opacity="1"
filter="url(#filter-5)"
xlink:href="#path-4"
></use>
<use fill="#27B876" xlink:href="#path-4"></use>
</g>
</g>
</g>
</g>
</g>
</svg>
</div>
<div class="intercepted">您访问的网站不存在</div>
<div class="intercepted-item">当前域名可能有误,请检查配置</div>
</td>
</tr>
</table>
<div class="footer">
安全检测能力由
<a class="footer-waflink" href="https://waf-ce.chaitin.cn"
>长亭雷池 WAF</a
>
驱动
</div>
</div>
</body>
</html>

View File

@@ -1,3 +0,0 @@
{
"extends": "next/core-web-vitals"
}

35
homepage/.gitignore vendored
View File

@@ -1,35 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

View File

@@ -1,2 +0,0 @@
build:
npm i && npm run build

View File

@@ -1,35 +0,0 @@
const isProduction = process.env.NODE_ENV == "production";
const isDevelopment = process.env.NODE_ENV == "development";
const prodConfig = {
output: "export",
};
const devConfig = {
async rewrites() {
return [
{
source: "/api/poc/:path*",
destination: "https://waf-ce.chaitin.cn/api/poc/:path*",
},
{
source: "/api/count",
destination: "https://waf-ce.chaitin.cn/api/count",
},
];
},
};
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: false,
images: { unoptimized: true },
};
Object.assign(
nextConfig,
isProduction && prodConfig,
isDevelopment && devConfig
);
module.exports = nextConfig;

File diff suppressed because it is too large Load Diff

View File

@@ -1,41 +0,0 @@
{
"name": "blog",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"icon": "node ./script/downLoadIcon.js"
},
"dependencies": {
"@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6",
"@jsdevtools/rehype-toc": "^3.0.2",
"@mui/icons-material": "^5.11.16",
"@mui/lab": "5.0.0-alpha.128",
"@mui/material": "^5.12.0",
"@types/node": "18.15.11",
"@types/react": "18.0.35",
"@types/react-dom": "18.0.11",
"ahooks": "^3.7.6",
"axios": "^1.3.6",
"countup.js": "2.6.2",
"eslint": "8.38.0",
"eslint-config-next": "13.3.0",
"github-slugger": "^2.0.0",
"gray-matter": "^4.0.3",
"highlight.js": "11.8.0",
"next": "13.3.0",
"next-mdx-remote": "^4.4.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-responsive-carousel": "^3.2.23",
"remark-external-links": "^9.0.1",
"remark-gfm": "^3.0.1",
"remark-prism": "^1.3.6",
"remark-slug": "^7.0.1",
"typescript": "5.0.4"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 989 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 595 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 686 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 412 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="61px" height="68px" viewBox="0 0 61 68" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 4备份 4</title>
<defs>
<linearGradient x1="50%" y1="-1.15518706e-11%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#744BE4" offset="0%"></stop>
<stop stop-color="#E44BD3" offset="99.9153191%"></stop>
</linearGradient>
<linearGradient x1="9.5%" y1="7.78543896e-13%" x2="90.5%" y2="100%" id="linearGradient-2">
<stop stop-color="#FFFFFF" offset="0%"></stop>
<stop stop-color="#8F00FE" offset="100%"></stop>
</linearGradient>
<path d="M25.4341763,6.37416481 L15.0880707,0.440979948 C14.1181233,-0.146993316 12.8787461,-0.146993316 11.8549127,0.440979948 L1.61657901,6.37416481 C0.646631602,6.96213807 0,7.97772828 0,9.15367481 L0,20.9131403 C0,22.0356347 0.592745625,23.1046771 1.61657901,23.6926503 L11.8549127,29.5723831 C12.3398864,29.8396437 12.932632,30 13.4714917,30 C14.0103514,30 14.603097,29.8396437 15.0880707,29.5723831 L25.3264044,23.6391982 C26.2963518,23.051225 26.9429834,22.0356347 26.9429834,20.9131403 L26.9968694,9.15367481 C27.0507554,7.97772825 26.4041238,6.90868595 25.4341763,6.37416481 Z" id="path-3"></path>
<filter x="-103.7%" y="-60.0%" width="307.4%" height="286.7%" filterUnits="objectBoundingBox" id="filter-4">
<feMorphology radius="0.5" operator="dilate" in="SourceAlpha" result="shadowSpreadOuter1"></feMorphology>
<feOffset dx="0" dy="10" in="shadowSpreadOuter1" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="7.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"></feComposite>
<feColorMatrix values="0 0 0 0 0.560784314 0 0 0 0 0 0 0 0 0 0.996078431 0 0 0 0.24 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
</defs>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-4备份-4" transform="translate(1.000000, 0.000000)">
<g id="编组-3备份" fill="#D8D8D8" fill-opacity="0">
<rect id="矩形" x="0" y="0" width="60" height="60"></rect>
</g>
<rect id="矩形" fill-opacity="0" fill="#D8D8D8" x="0" y="0" width="60" height="60"></rect>
<path d="M24.4561176,11.7839344 L17.5587138,7.79637281 C16.9120822,7.40120906 16.0858307,7.40120906 15.4032751,7.79637281 L8.57771934,11.7839344 C7.93108773,12.1790981 7.5,12.8616537 7.5,13.6519812 L7.5,21.5552563 C7.5,22.3096599 7.89516375,23.0281394 8.57771934,23.4233032 L15.4032751,27.3749408 C15.7265909,27.5545606 16.1217547,27.6623326 16.4809945,27.6623326 C16.8402342,27.6623326 17.235398,27.5545606 17.5587138,27.3749408 L24.3842696,23.3873792 C25.0309012,22.9922155 25.4619889,22.3096599 25.4619889,21.5552563 L25.4979129,13.6519812 C25.5338369,12.8616537 25.1027492,12.1431741 24.4561176,11.7839344 Z" id="路径" fill="url(#linearGradient-1)" fill-rule="nonzero"></path>
<g id="编组-13备份-4" transform="translate(15.000000, 12.000000)" fill-rule="nonzero">
<g id="路径">
<use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-3"></use>
<use stroke="url(#linearGradient-2)" stroke-width="1" fill-opacity="0.3" fill="#8F00FE" xlink:href="#path-3"></use>
</g>
</g>
<path d="M34.3321474,21.1810911 C34.9778424,20.8082989 35.8034894,21.0295304 36.1762816,21.6752254 C36.5490739,22.3209205 36.3278424,23.1465675 35.6821474,23.5193597 L35.6821474,23.5193597 L29.778,26.928 L29.7786864,33.4502254 C29.7786864,34.1958098 29.1742708,34.8002254 28.4286864,34.8002254 C27.683102,34.8002254 27.0786864,34.1958098 27.0786864,33.4502254 L27.078,26.927 L21.1752254,23.5193597 C20.5295304,23.1465675 20.3082989,22.3209205 20.6810911,21.6752254 C21.0538833,21.0295304 21.8795304,20.8082989 22.5252254,21.1810911 L28.429,24.589 Z" id="形状结合" fill="#FFFFFF"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

View File

@@ -1 +0,0 @@
../../../../compose.yaml

View File

@@ -1 +0,0 @@
../../../../setup.sh

View File

@@ -1 +0,0 @@
../../../../upgrade.sh

View File

@@ -1 +0,0 @@
../../../../version.json

View File

@@ -1,19 +0,0 @@
const fs = require("fs");
const path = require("path");
const Axios = require("axios");
async function downloadFile(url) {
const iconPath = path.resolve(__dirname, "../src/static/fonts/iconfont.js");
const writer = fs.createWriteStream(iconPath);
const response = await Axios({
url: "https:" + url,
method: "GET",
responseType: "stream",
});
response.data.pipe(writer);
writer.on("finish", () => console.log("下载成功"));
writer.on("error", (err) => console.log(err));
}
let argument = process.argv.splice(2);
downloadFile(argument[0]);

View File

@@ -1,42 +0,0 @@
export { submitSampleSet, getSampleSet, getSampleSetResult, getSampleDetail };
const BASE_API = "/api/poc/";
function submitSampleSet(data: {
pocs: Array<{ content: string; tag: string }>;
record_it: boolean;
}) {
return fetch(BASE_API + "list", {
method: "POST",
headers: { "Content-Type": "application/json" },
mode: "cors",
// credentials: "include",
body: JSON.stringify(data),
}).then((res) => res.json());
}
function getSampleSet(id: string) {
return fetch(BASE_API + "list?id=" + id).then((res) => res.json());
}
function getSampleDetail(id: string) {
return fetch(BASE_API + "detail?id=" + id).then((res) => res.json());
}
async function getSampleSetResult(id: string, timeout: number = 60) {
const startAt = new Date().getTime();
const isTimeout = () => new Date().getTime() - startAt > timeout * 1000;
const maxRetry = 20;
for (let i = 0; i < maxRetry; i++) {
const res = await fetch(BASE_API + "results?id=" + id).then((res) =>
res.json()
);
if (res.code == 0 && res.data.data) {
return { data: res.data.data, timeout: false };
}
if (isTimeout()) break;
await new Promise((r) => setTimeout(r, 2000));
}
return { data: [], timeout: true };
}

View File

@@ -1,13 +0,0 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from 'next'
type Data = {
name: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
res.status(200).json({ name: 'John Doe' })
}

View File

@@ -1,5 +0,0 @@
export { getSetupCount };
function getSetupCount() {
return fetch("/api/count").then((res) => res.json());
}

View File

@@ -1,68 +0,0 @@
import React, { type FC, useEffect, useRef, useState } from "react";
import { Box, type SxProps, Tooltip } from "@mui/material";
interface EllipsisProps {
children: React.ReactNode;
sx?: SxProps;
}
const Ellipsis: FC<EllipsisProps> = (props) => {
const { children, sx } = props;
const content = useRef<HTMLSpanElement>(null);
const [ellipsis, setEllipsis] = useState<boolean>(false);
//判断文字内容是否超出div宽度
const onResize = () => {
if (content.current) {
setEllipsis(
(content.current.parentNode! as HTMLDivElement).offsetWidth <
content.current.offsetWidth
);
}
};
useEffect(() => {
onResize();
}, [children]);
return (
<>
<Box
sx={{
width: "100%",
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
...sx,
}}
>
<Tooltip
title={ellipsis ? children : null}
arrow
followCursor
componentsProps={{
tooltip: {
sx: {
color: "text.primary",
backgroundColor: "background.paper0",
boxShadow: " 0px 0px 20px 0px rgba(0,0,0,0.1)",
padding: "16px",
lineHeight: "24px",
maxWidth: "500px",
fontSize: "14px",
},
},
arrow: { sx: { color: "background.paper0" } },
}}
>
<Box ref={content} component="span" sx={{ maxWidth: "100%" }}>
{children as React.ReactElement}
</Box>
</Tooltip>
</Box>
</>
);
};
export default Ellipsis;

View File

@@ -1,58 +0,0 @@
import { Grid, Box } from "@mui/material";
import Link from "next/link";
const LINK_LIST = [
{
name: "北京长亭科技有限公司",
url: "https://chaitin.cn/",
},
{
name: "CT Stack 安全社区",
url: "https://stack.chaitin.cn/",
},
{
name: "长亭百川云平台",
url: "https://rivers.chaitin.cn/",
},
{
name: "长亭 GitHub 主页",
url: "https://github.com/chaitin",
},
{
name: "长亭 B 站主页",
url: "https://space.bilibili.com/521870525",
},
{
name: "长亭合作伙伴论坛",
url: "https://bbs.chaitin.cn/",
},
];
const FriendlyLinks = () => {
return (
<Grid container>
{LINK_LIST.map((item) => (
<Grid item xs={6} sm={4} md={3} key={item.name}>
<Box
component={Link}
target="_blank"
href={item.url}
sx={{
color: "rgba(0,0,0,0.7)",
fontSize: "14px",
lineHeight: "24px",
"&:hover": {
color: "primary.main",
},
}}
>
{item.name}
</Box>
</Grid>
))}
</Grid>
);
};
export default FriendlyLinks;

View File

@@ -1,255 +0,0 @@
import { type FC, useEffect, useRef, useState } from "react";
import { Ellipsis } from "@/components";
import { useRouter } from "next/router";
import { Box } from "@mui/material";
import Link from "next/link";
import { useDebounceFn, useThrottleFn } from "ahooks";
import { slug } from "github-slugger";
interface MarkdownNavbarProps {
containerId?: string;
source: string;
}
interface Heading {
dataId: string;
listNo: string;
offsetTop: number;
}
interface Nav {
index: number;
level: number;
text: string;
listNo: string;
}
const MarkdownNavbar: FC<MarkdownNavbarProps> = (props) => {
const router = useRouter();
let { containerId, source } = props;
let container: HTMLElement;
if (typeof window !== "undefined") {
container =
(containerId && document.getElementById(containerId)) || document.body;
}
const [currentListNo, setCurrentListNo] = useState<string>("");
const [navStructure, setNavStructure] = useState<Nav[]>([]);
const scrollEventLock = useRef(false);
const timer = useRef<any>();
const trimArrZero = (arr: number[]) => {
let start, end;
for (start = 0; start < arr.length; start++) {
if (arr[start]) {
break;
}
}
for (end = arr.length - 1; end >= 0; end--) {
if (arr[end]) {
break;
}
}
return arr.slice(start, end + 1);
};
const getHeadingList = (navStructure: Nav[]) => {
const headingList: Heading[] = [];
navStructure.forEach((t) => {
const curHeading = document.getElementById(slug(t.text));
if (curHeading) {
headingList.push({
dataId: `heading-${t.index}`,
listNo: t.listNo,
offsetTop: curHeading.offsetTop - 179,
});
}
});
return headingList;
};
const initHeadingsId = (navStructure: any[]) => {
navStructure.forEach((t) => {
const headings = document.querySelectorAll(`h${t.level}`);
const curHeading = Array.prototype.slice
.apply(headings)
.find(
(h) =>
h.innerText.trim() === t.text.trim() &&
(!h.dataset || !h.dataset.id)
);
if (curHeading) {
curHeading.dataset.id = `heading-${t.index}`;
}
});
};
const getNavStructure: (source: string) => Nav[] = (source) => {
const contentWithoutCode = source
.replace(/```[^`\n]*\n+[^```]+```\n+/g, "")
.replace(/^[^#]+\n/g, "")
.replace(/(?:[^\n#]+)#+\s([^#\n]+)\n*/g, "") // 匹配行内出现 # 号的情况
.replace(/^#\s[^#\n]*\n+/, "")
.replace(/`([^`\n]+)`/g, "$1")
.replace(/\*\*?([^*\n]+)\*\*?/g, "$1")
.replace(/__?([^_\n]+)__?/g, "$1")
.trim();
const pattOfTitle = /#+\s([^#\n]+)\n*/g;
const matchResult = contentWithoutCode.match(pattOfTitle);
if (!matchResult) {
return [];
}
const navData = matchResult.map((r, i) => ({
index: i,
level: r.match(/^#+/g)![0].length,
text: r.replace(pattOfTitle, "$1"),
listNo: "",
}));
let maxLevel = 0;
navData.forEach((t) => {
if (t.level > maxLevel) {
maxLevel = t.level;
}
});
let matchStack = [];
for (let i = 0; i < navData.length; i++) {
const t = navData[i];
const { level } = t;
while (
matchStack.length &&
matchStack[matchStack.length - 1].level > level
) {
matchStack.pop();
}
if (matchStack.length === 0) {
const arr = new Array(maxLevel).fill(0);
arr[level - 1] += 1;
matchStack.push({
level,
arr,
});
t.listNo = trimArrZero(arr).join(".");
continue;
}
const arr: number[] = matchStack[matchStack.length - 1].arr;
const newArr = arr.slice();
newArr[level - 1] += 1;
matchStack.push({
level,
arr: newArr,
});
t.listNo = trimArrZero(newArr).join(".");
}
return navData;
};
const refreshNav = (source: string) => {
// TODO: 只需要 2 3 级标题
const navStructure = getNavStructure(source).filter((nav) =>
[2, 3].includes(nav.level)
);
setNavStructure(navStructure);
let hash = router.asPath.split("#")[1];
let listNo = navStructure[0]?.listNo;
if (hash) {
const hashText = decodeURIComponent(hash);
let findNav = navStructure.find((nav) => hashText === slug(nav.text));
if (findNav) {
listNo = findNav.listNo;
const target = document.getElementById(hashText);
if (target) {
target.scrollIntoView({ behavior: "smooth" });
scrollEventLock.current = true;
setTimeout(() => {
scrollEventLock.current = false;
}, 500);
}
}
}
setCurrentListNo(listNo);
initHeadingsId(navStructure);
setTimeout(() => {
container?.addEventListener(
"scroll",
() => winScroll(getHeadingList(navStructure)),
false
);
});
};
const { run: winScroll } = useThrottleFn(
(headingList: Heading[]) => {
clearTimeout(timer.current);
if (scrollEventLock.current) return;
var curHeading: Heading | null = null;
headingList.forEach((h) => {
if (h.offsetTop <= container.scrollTop) {
curHeading = h;
}
});
if (curHeading) {
timer.current = setTimeout(() => {
setCurrentListNo(curHeading!.listNo);
});
}
},
{ wait: 300 }
);
const { run: scrollToTarget } = useDebounceFn(
(dataId: string) => {
const target = document.querySelector(`[data-id="${dataId}"]`);
if (target) {
target.scrollIntoView({ behavior: "smooth" });
scrollEventLock.current = true;
setTimeout(() => {
scrollEventLock.current = false;
}, 500);
}
},
{ wait: 0 }
);
useEffect(() => {
refreshNav(source);
return () => {
container?.removeEventListener("scroll", winScroll, false);
};
}, [source]);
const tBlocks = navStructure.map((t, index) => {
const cls = `title-anchor title-level${t.level}`;
const anchor = slug(t.text);
return (
<Box
className={cls}
component={Link}
href={`#${anchor}`}
style={{ width: "100%" }}
key={`title_anchor_${Math.random().toString(36).substring(2)}`}
>
<Ellipsis
sx={{
"&:hover": {
color: "primary.main",
},
color: currentListNo === t.listNo ? "primary.main" : "inherit",
}}
>
{t.text}
</Ellipsis>
</Box>
);
});
return <div className={`markdown-navigation`}>{tBlocks}</div>;
};
export default MarkdownNavbar;

View File

@@ -1,46 +0,0 @@
import React, { type FC } from "react";
import ErrorIcon from "@mui/icons-material/Error";
import { Box } from "@mui/material";
import { ThemeProvider } from "@/components";
import Modal, { type ModalProps } from "./Modal";
export interface ConfirmDialogProps extends ModalProps {
content?: React.ReactNode;
width?: string;
}
const ConfirmDialog: FC<ConfirmDialogProps> = (props) => {
const { title = "提示", content, width = "480px", ...rest } = props;
return (
<ThemeProvider>
<Modal
title={
<Box
sx={{
display: "flex",
alignItems: "center",
lineHeight: "22px",
color: "text.main",
fontWeight: 500,
}}
>
<ErrorIcon
sx={{ color: "#FFBF00", mr: "16px", fontSize: "24px" }}
/>
{title}
</Box>
}
closable={false}
{...rest}
sx={{ width }}
>
<Box sx={{ color: "text.main", pl: "40px" }}>{content}</Box>
</Modal>
</ThemeProvider>
);
};
export default ConfirmDialog;

View File

@@ -1,61 +0,0 @@
import { useMemo, useEffect, useState } from "react";
import {
ThemeProvider as MUIThemeProvider,
useMediaQuery,
} from "@mui/material";
import { useLocalStorageState } from "ahooks";
import themes from "../../themes";
import ThemeContext, { type ThemeMode } from "../../themes/themeContext";
interface ThemeProviderProps {
children?: React.ReactNode;
}
const ThemeProvider: React.FC<ThemeProviderProps> = ({ children }) => {
// const [mode, setMode] = useLocalStorageState<ThemeMode>("themeMode", {
// defaultValue: "system",
// });
const [mode, setMode] = useState<ThemeMode>("light");
const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
const theme = useMemo(() => {
let newMode = mode;
if (mode === "system") {
newMode = prefersDarkMode ? "dark" : "light";
}
return themes(newMode as "dark" | "light");
}, [mode, prefersDarkMode]);
const themeMode = useMemo(() => {
return {
mode,
setThemeMode: (mode: ThemeMode) => {
setMode(mode);
},
};
}, [mode]);
useEffect(() => {
const bodyStyle = document.body.style;
const body = document.body;
let newMode = mode;
if (mode === "system") {
newMode = prefersDarkMode ? "dark" : "light";
}
body.className = newMode;
// @ts-ignore
bodyStyle.backgroundColor = theme.palette.background.paper0;
bodyStyle.color = theme.palette.text.primary;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [theme]);
return (
<ThemeContext.Provider value={themeMode}>
<MUIThemeProvider theme={theme}>{children}</MUIThemeProvider>
</ThemeContext.Provider>
);
};
export default ThemeProvider;

View File

@@ -1,107 +0,0 @@
const BuiltinAttackSamples = [
`
POST /doUpload.action HTTP/1.1
Host: localhost:8080
Content-Length: 1000000000
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryXd004BVJN9pBYBL2
------WebKitFormBoundaryXd004BVJN9pBYBL2
Content-Disposition: form-data; name="upload"; filename="ok"
<%eval request("sb")%>
------WebKitFormBoundaryXd004BVJN9pBYBL2--
`,
`GET /fe/Channel/25545911?tabNum=cat%20%2Fetc%2Fhosts HTTP/1.1
Host: monster
User-Agent: Chrome`,
`GET /scripts/%2e%2e/%2e/Windows/System32/cmd.exe?/c+dir+c HTTP/1.1
Host: a.cn
User-Agent: Chrome
Cookie: 2333;`,
`GET /?s=/../../../etc/login\0.img HTTP/1.1
Host: monster
User-Agent: Chrome`,
`POST / HTTP/1.1
Host: monster
User-Agent: Chrome
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary4JGjXRl94NnI4Og7
------WebKitFormBoundary4JGjXRl94NnI4Og7
Content-Disposition: form-data; name="file"; filename="hack.asp%00.png"
Content-Type: application/octet-stream
<%@codepage=65000%><%response.codepage=65001:eval(request("key"))%>
------WebKitFormBoundary4JGjXRl94NnI4Og7--"`,
`GET /?s=%ac%ed%00%05%73%72%00%1a%63%6f%6d%2e%63%74%2e%61%72%61%6c%65%69%69%2e%74%65%73%74%2e%50%65%72%73%6f%6e%00%00%00%00%00%00%00%01%02%00%08%49%00%03%61%61%61%43%00%03%63%63%63%42%00%03%64%64%64%5a%00%03%65%65%65%4a%00%03%66%66%66%46%00%03%67%67%67%44%00%03%68%68%68%4c%00%03%62%62%62%74%00%12%4c%6a%61%76%61%2f%6c%61%6e%67%2f%53%74%72%69%6e%67%3b%78%70%00%00%00%01%00%62%65%01%00%00%00%00%00%00%00%01%3f%80%00%00%40%00%00%00%00%00%00%00%74%00%03%61%61%61 HTTP/1.1
Host: monster
User-Agent: Chrome`,
`GET / HTTP/1.1
Host: a.cn
Content-Type: a
Origin: b
User-Agent: c
X-Forwarded-For: d
Cookie: FOOID=1;
A: AAAAAAAAA
Referer: %{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='ifconfig').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}`,
`GET / HTTP/1.1
Host: monster
User-Agent: Chrome
Content-Type: application/x-www-form-urlencoded
Content-Length: 55
<?php echo $a; ?>`,
`GET / HTTP/1.1
Host: monster
User-Agent: Chrome
Content-Type: application/x-www-form-urlencoded
Content-Length: 55
a=O:9:"FileClass":1:{s:8:"filename";s:10:"config.php";}`,
`GET / HTTP/1.1
Host: monster
User-Agent: () { :;}; echo; echo $(/bin/ls -al)
Referer: Chrome
Cookie: 2333;`,
`GET /somepath?q=1'%20or%201=1 HTTP/1.1`,
`GET /hello?content=hello&user=ftp://a.com HTTP/1.1
Host: www.baidu.com
User-Agent: Chrome
Referer: http://www.qq.com/abc.html`,
`GET /?flag=%7B%7Bconfig.__class__.__init__.__globals__%5B'os'%5D.popen('id').read()%7D%7D HTTP/1.1
Host: 1.2.3.4
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:97.0) Gecko/20100101 Firefox/97.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close`,
`POST / HTTP/1.1
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/fruits">
<xsl:value-of select="system-property('xsl:vendor')"/>
</xsl:template>
</xsl:stylesheet>`,
`GET /somepath?q=<script>alert('XSS')</script> HTTP/1.1`,
`POST / HTTP/1.1
<?xml version="1.0"?>
<!DOCTYPE data [
<!ELEMENT data (#ANY)>
<!ENTITY file SYSTEM "file:///etc/passwd">
]>
<data>&file;</data>`,
];
const BuiltinNonAttackSamples = [
`GET / HTTP/1.1
Host: 1.2.3.4`,
`POST / HTTP/1.1
name=haha&submit=submit`,
];
export { BuiltinAttackSamples, BuiltinNonAttackSamples };

View File

@@ -1,3 +0,0 @@
.detection-samples-accordion::before {
display: none;
}

View File

@@ -1,6 +0,0 @@
export { default as ThemeProvider } from "./ThemeProvider";
export { default as Icon } from "./Icon";
export { default as Message } from "./Message";
export { default as MarkdownNavbar } from "./MarkdownNavbar";
export { default as Modal } from "./Modal";
export { default as Ellipsis } from "./Ellipsis";

View File

@@ -1,259 +0,0 @@
import React, { useMemo } from "react";
import { useRouter } from "next/router";
import Image from "next/image";
import Link from "next/link";
import {
AppBar,
Box,
CssBaseline,
Divider,
Drawer,
IconButton,
List,
ListItem,
ListItemButton,
ListItemText,
Toolbar,
Typography,
Button,
alpha,
} from "@mui/material";
import MenuIcon from "@mui/icons-material/Menu";
interface Props {
/**
* Injected by the documentation to work in an iframe.
* You won't need it on your project.
*/
window?: () => Window;
}
const drawerWidth = 240;
export default function DrawerAppBar(props: Props) {
const { window } = props;
const router = useRouter();
const { pathname, asPath } = router;
const [mobileOpen, setMobileOpen] = React.useState(false);
const handleDrawerToggle = () => {
setMobileOpen((prevState) => !prevState);
};
const drawer = (
<Box onClick={handleDrawerToggle} sx={{ textAlign: "center" }}>
<Typography
variant="h6"
component="div"
sx={{
flexGrow: 1,
display: "flex",
alignItems: "center",
my: 2,
ml: 2,
}}
onClick={() => router.push("/")}
>
<Image
src="/images/logo.png"
alt="Logo"
width={120}
height={34}
priority
/>
<Image
src="/images/safeline.png"
alt="Logo"
width={34}
height={34}
style={{ marginLeft: "24px" }}
priority
/>
</Typography>
<Divider />
<List>
<ListItem disablePadding>
<ListItemButton
sx={{ textAlign: "center" }}
selected={pathname === "/"}
component={Link}
href="/"
>
<ListItemText primary="主页" />
</ListItemButton>
</ListItem>
<ListItem disablePadding>
<ListItemButton
sx={{ textAlign: "center" }}
selected={pathname.startsWith("/posts/")}
component={Link}
href="/posts/guide_introduction/"
>
<ListItemText primary="技术文档" />
</ListItemButton>
</ListItem>
<ListItem disablePadding>
<ListItemButton
sx={{ textAlign: "center" }}
component={Link}
href="https://www.bilibili.com/medialist/detail/ml2342694989"
target="_blank"
>
<ListItemText primary="教学视频" />
</ListItemButton>
</ListItem>
<ListItem disablePadding>
<ListItemButton
sx={{ textAlign: "center" }}
component={Link}
href="https://demo.waf-ce.chaitin.cn:9443/"
target="_blank"
>
<ListItemText primary="演示环境" />
</ListItemButton>
</ListItem>
</List>
</Box>
);
const container =
window !== undefined ? () => window().document.body : undefined;
return (
<Box
sx={{
display: "flex",
}}
>
<CssBaseline />
<AppBar
component="nav"
sx={{
backgroundColor: "#0F1935",
boxShadow: "none",
color: "text.primary",
pr: "0 !important",
}}
>
<Toolbar sx={{ display: "flex", justifyContent: "space-between" }}>
<Typography
variant="h6"
component="div"
sx={{
display: "flex",
alignItems: "center",
}}
onClick={() => router.push("/")}
>
<Image
src="/images/logo.png"
alt="Logo"
width={120}
height={34}
priority
/>
<Image
src="/images/403.svg"
alt="Logo"
width={34}
height={34}
style={{ marginLeft: "24px" }}
priority
/>
</Typography>
<IconButton
color="inherit"
onClick={handleDrawerToggle}
sx={{ display: { sm: "none", color: "#fff" } }}
>
<MenuIcon />
</IconButton>
<Box
sx={{
display: { xs: "none", sm: "block" },
".MuiButtonBase-root": {
ml: "16px",
},
"a.MuiBox-root": {
mr: 5,
"&:hover": {
color: "primary.main",
},
},
}}
>
<Box
sx={{
color: pathname === "/" ? "primary.main" : "#fff",
}}
component={Link}
href="/"
>
</Box>
<Box
sx={{
color: pathname.startsWith("/posts/") ? "primary.main" : "#fff",
}}
component={Link}
href="/posts/guide_introduction/"
>
</Box>
<Box
sx={{
color: pathname.startsWith("/detection")
? "primary.main"
: "#fff",
}}
component={Link}
href="/detection"
>
</Box>
<Box
sx={{
color: "#fff",
}}
component={Link}
href="https://www.bilibili.com/medialist/detail/ml2342694989"
target="_blank"
>
</Box>
<Button
sx={{ ml: "0 !important" }}
component={Link}
variant="contained"
href="https://demo.waf-ce.chaitin.cn:9443/"
target="_blank"
>
</Button>
</Box>
</Toolbar>
</AppBar>
<Box component="nav">
<Drawer
container={container}
variant="temporary"
open={mobileOpen}
onClose={handleDrawerToggle}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
sx={{
display: { xs: "block", sm: "none" },
"& .MuiDrawer-paper": {
boxSizing: "border-box",
width: drawerWidth,
},
}}
>
{drawer}
</Drawer>
</Box>
</Box>
);
}

View File

@@ -1,43 +0,0 @@
import { type FC } from "react";
import Head from "next/head";
import { Box } from "@mui/material";
import Header from "./Header";
interface IProps {
redirect?: string;
children?: React.ReactNode;
}
const MainLayout: FC<IProps> = ({ children }) => {
return (
<>
<Head>
<title> WAF </title>
<meta
name="description"
content="长亭雷池 Web 应用防火墙 | 长亭雷池 WAF"
/>
<meta name="keywords" content="WAF,雷池,长亭,社区版" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/images/safeline.png" />
</Head>
<Box
sx={{
position: "relative",
flex: 1,
display: "flex",
flexDirection: "column",
height: "100vh",
}}
>
<Header />
<Box component="main" sx={{ flexGrow: 1 }}>
{children}
</Box>
</Box>
</>
);
};
export default MainLayout;

View File

@@ -1,159 +0,0 @@
import { type FC, useState } from "react";
import Link from "next/link";
import { useRouter } from "next/router";
import ExpandLess from "@mui/icons-material/ExpandLess";
import ExpandMore from "@mui/icons-material/ExpandMore";
import {
Box,
Collapse,
AppBar,
List,
ListItemIcon,
ListItemText,
ListSubheader,
ListItem,
} from "@mui/material";
import { type GroupItem } from "@/utils/posts";
interface SideLayoutProps {
list: GroupItem[];
children?: React.ReactNode;
}
const SideLayout: FC<SideLayoutProps> = ({ children, list }) => {
const router = useRouter();
const { asPath } = router;
const [open, setOpen] = useState(false);
const handleClick = () => {
setOpen(!open);
};
return (
<Box sx={{ display: { xs: "block", sm: "flex" }, height: "100%" }}>
<Box
sx={{
position: "fixed",
top: 0,
left: 0,
width: 240,
pt: "80px",
pb: 3,
height: "100%",
overflow: "auto",
backgroundColor: "#f8f9fc",
// boxShadow: "inset 0px 0px 16px 0px rgba(0, 145, 255, 1)",
display: { xs: "none", sm: "block" },
borderRight: "1px solid hsla(210, 18%, 87%, 1)",
"&::-webkit-scrollbar": {
display: "none",
},
}}
>
{list.map((group) => (
<Box sx={{ pl: "40px", lineHeight: "32px" }} key={group.title}>
<Box sx={{ color: "text.auxiliary", mb: "6px", mt: "20px" }}>
{group.title}
</Box>
{group.list.map((nav) => (
<Box
key={nav.title}
component={Link}
href={`/posts/${nav.id}`}
sx={{
fontSize: "16px",
display: "block",
textDecoration: "none",
color: asPath.startsWith(`/posts/${nav.id}`)
? "primary.main"
: "inherit",
fontWeight: asPath.startsWith(`/posts/${nav.id}`) ? 700 : 400,
"&:hover": {
color: "primary.main",
},
}}
>
{nav.title}
</Box>
))}
</Box>
))}
</Box>
<AppBar
sx={{
top: 72,
backgroundColor: "#fff",
display: {
xs: "block",
sm: "none",
boxShadow: "0 12px 25px -12px rgba(93,99,112, 0.2)",
},
}}
>
<ListItem onClick={handleClick}>
<ListItemIcon>{open ? <ExpandLess /> : <ExpandMore />}</ListItemIcon>
<ListItemText primary="目录" sx={{ color: "#000" }} />
</ListItem>
<Collapse in={open} timeout="auto" unmountOnExit>
<List
sx={{
width: "100%",
bgcolor: "background.paper",
position: "relative",
overflow: "auto",
maxHeight: 300,
"& ul": { padding: 0 },
}}
subheader={<li />}
>
{list.map((group) => (
<li key={`section-${group.title}`}>
<ul>
<ListSubheader sx={{ color: "text.auxiliary" }}>
{group.title}
</ListSubheader>
{group.list.map((nav) => (
<ListItem
key={nav.title}
onClick={() => {
router.push(`/posts/${nav.id}`);
handleClick();
}}
sx={{
color: asPath.startsWith(`/posts/${nav.id}`)
? "primary.main"
: "text.primary",
fontWeight: asPath.startsWith(`/posts/${nav.id}`)
? 700
: 400,
}}
>
<ListItemText primary={nav.title} />
</ListItem>
))}
</ul>
</li>
))}
</List>
</Collapse>
</AppBar>
<Box
sx={{
pt: { xs: 18, sm: 13 },
pb: 3,
px: 3,
flexGrow: 1,
height: "100%",
width: { xs: "100%", sm: "calc(100% - 240px)" },
marginLeft: { xs: 0, sm: "240px" },
backgroundColor: "#F8F9FC",
}}
>
{children}
</Box>
</Box>
);
};
export default SideLayout;

View File

@@ -1,35 +0,0 @@
import "@/styles/globals.css";
import "@/styles/markdown.css";
import type { AppProps } from "next/app";
import { ThemeProvider } from "@/components";
import MainLayout from "@/layout/MainLayout";
import type { ReactElement, ReactNode } from "react";
import type { NextPage } from "next";
import Script from "next/script";
import "@/components/detection/detection.css"
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
getLayout?: (page: ReactElement) => ReactNode;
};
type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout;
};
export default function App({ Component, pageProps }: AppPropsWithLayout) {
const getLayout = Component.getLayout || ((page) => page);
return (
<>
{process.env.NODE_ENV === "production" && (
<Script
type="text/javascript"
src="https://v1.cnzz.com/z_stat.php?id=1281262430&web_id=1281262430"
/>
)}
<ThemeProvider>
<MainLayout>{getLayout(<Component {...pageProps} />)}</MainLayout>
</ThemeProvider>
</>
);
}

View File

@@ -1,13 +0,0 @@
import { Html, Head, Main, NextScript } from "next/document";
export default function Document() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}

View File

@@ -1,117 +0,0 @@
import { useEffect, useState } from "react";
import Container from "@mui/material/Container";
import Result from "@/components/detection/Result";
import { useRouter } from "next/router";
import "highlight.js/styles/a11y-light.css";
import { getSampleSet, getSampleSetResult } from "@/api/detection";
import { Message } from "@/components";
import type {
RecordSamplesType,
ResultRowsType,
} from "@/components/detection/types";
import Grid from "@mui/material/Grid";
import SampleList from "@/components/detection/SampleList";
import { Typography } from "@mui/material";
import Head from "next/head";
export default Detection;
function Detection() {
const router = useRouter();
const [samples, setSamples] = useState<RecordSamplesType>([]);
const [result, setResult] = useState<ResultRowsType>([]);
useEffect(() => {
// useRouter 中获取 参数会有延迟,所以先判断有没有 id 参数
const realSetId =
new URLSearchParams(location.search).get("id") || "default";
const setId = (router.query.id as string) || "default";
if (setId !== realSetId) return;
// 查询样本集合
getSampleSet(setId).then((res) => {
if (res.code != 0) {
Message.error("测试集合 " + setId + ": " + res.msg);
return;
}
if (!res.data.data) {
Message.error("测试集合 " + setId + ": 获取结果为空");
return;
}
setSamples(
res.data.data?.map((i: any) => ({
id: i.id,
summary: i.summary,
size: i.length,
isAttack: i.tag == "black",
}))
);
});
// 查询样本集合结果
getSampleSetResult(setId).then(({ data, timeout }) => {
if (timeout) {
Message.error("获取检测集结果超时");
return;
}
setResult(
data.map((i: any) => ({
engine: i.engine,
version: i.version,
detectionRate: percent(i.recall),
failedRate: percent(i.fdr),
accuracy: percent(i.accuracy),
cost: i.elapsed > 0 ? i.elapsed + " 毫秒" : "小于 1 毫秒",
}))
);
});
}, [router.query.id]);
const handleSetId = (id: string) => {
router.push({
pathname: router.pathname,
query: { id },
});
};
return (
<>
<Head>
<title> - WAF </title>
</Head>
<Container sx={{ mb: 2 }}>
<div style={{ height: "100px" }}></div>
<SampleList value={samples} onSetIdChange={handleSetId} />
<Result rows={result} />
<Grid
container
spacing={2}
sx={{ mt: 3, mb: 3, color: "text.auxiliary" }}
>
<Grid item md={3}>
<Typography>TP: 正确识别到攻击样本的数量</Typography>
<br />
<Typography> = TP / (TP + FN)</Typography>
</Grid>
<Grid item md={3}>
<Typography>TN: 正确识别到普通样本的数量</Typography>
<br />
<Typography> = FP / (TP + FP)</Typography>
</Grid>
<Grid item md={3}>
<Typography>FP: 将普通样本误报为攻击的数量</Typography>
<br />
<Typography> = (TP + TN) / (TP + TN + FP + FN)</Typography>
</Grid>
<Grid item md={3}>
<Typography>FN: 未识别到攻击样本的数量</Typography>
</Grid>
</Grid>
</Container>
</>
);
}
function percent(v: number) {
return Math.round(v * 10000) / 100 + "%";
}

View File

@@ -1,276 +0,0 @@
import Image from "next/image";
import Link from "next/link";
import { Box, Grid, Button, Typography, Container, Stack } from "@mui/material";
import { Carousel } from "react-responsive-carousel";
import Version from "@/components/Home/Version";
import FriendlyLinks from "@/components/Home/FriendlyLinks";
import Features from "@/components/Home/Features";
import Title from "@/components/Home/Title";
import { getSetupCount } from "@/api/home";
// import countUpModule from "countup.js";
import "react-responsive-carousel/lib/styles/carousel.min.css";
import { useState, useEffect, useRef } from "react";
const IMAGE_LIST = [
{
name: "可视化仪表盘",
url: "/images/album/0.png",
},
{
name: "登录页",
url: "/images/album/5.png",
},
{
name: "攻击检测列表",
url: "/images/album/1.png",
},
{
name: "攻击检测详情",
url: "/images/album/2.png",
},
{
name: "防护站点列表",
url: "/images/album/3.png",
},
{
name: "自定义规则列表",
url: "/images/album/3.png",
},
{
name: "攻击阻断页面",
url: "/images/album/block.png",
},
];
export default function Home() {
const totalRef = useRef(null);
const initTotal = async (n: number) => {
const countUpModule = await import("countup.js");
const anim = new countUpModule.CountUp(totalRef.current!, Math.max(0, n), {
duration: 2,
});
anim.start();
};
useEffect(() => {
getSetupCount().then((d) => {
initTotal(d.total);
});
});
return (
<Box sx={{ backgroundColor: "#F8F9FC" }}>
<Box sx={{ pt: 16, pb: 18, backgroundColor: "#0F1935", color: "#fff" }}>
<Container maxWidth="lg">
<Box sx={{ display: { xs: "block", sm: "flex" }, flexWrap: "wrap" }}>
<Grid container sx={{ flex: 1 }}>
<Grid item xs={12}>
<Typography variant="h3" sx={{ pb: 3 }}>
Web {" "}
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="subtitle1" sx={{ pb: 3 }}>
10
<Box component="span" color="primary.main" sx={{ px: 1 }}>
</Box>
</Typography>
</Grid>
<Grid container item xs={12} spacing={2}>
<Button
variant="contained"
component={Link}
target="_blank"
sx={{
width: { xs: "100%", sm: "auto" },
ml: { xs: 2, sm: 2 },
mb: { xs: 2, sm: 0 },
}}
href="https://stack.chaitin.com/tool/detail?id=717"
>
使
</Button>
<Button
variant="contained"
color="neutral"
component={Link}
target="_blank"
sx={{
textTransform: "none",
backgroundColor: "#fff",
color: "#000",
ml: { xs: 2, sm: 2 },
mb: { xs: 2, sm: 0 },
width: { xs: "100%", sm: "auto" },
"&:hover": {
fontWeight: "500",
},
}}
href="https://github.com/chaitin/safeline"
startIcon={
<Image
src="/images/github.png"
alt="Logo"
width={16}
height={16}
priority
/>
}
>
GitHub
</Button>
<Button
variant="contained"
color="neutral"
sx={{
backgroundColor: "#fff",
color: "#000",
ml: { xs: 2, sm: 2 },
width: { xs: "100%", sm: "auto" },
}}
component={Link}
href="/#groupchat"
startIcon={
<Image
src="/images/wechat-logo.png"
alt="Logo"
width={16}
height={16}
priority
/>
}
>
</Button>
</Grid>
</Grid>
<Box
sx={{
display: "flex",
justifyContent: { xs: "center", sm: "right" },
pt: { xs: 3, sm: 0 },
ml: { xs: 0, sm: 3 },
}}
>
<Image
src="/images/403.svg"
alt="Logo"
width={196}
height={196}
priority
/>
</Box>
</Box>
</Container>
</Box>
<Container sx={{ mt: -10, color: "#000", pb: 3 }}>
<Features />
</Container>
<Container>
<Stack sx={{ pt: 15 }} spacing={3} alignItems="center">
<Title title="装机量" />
<Typography
sx={{
color: "primary.main",
fontSize: "96px",
letterSpacing: "10px",
}}
ref={totalRef}
>-</Typography>
</Stack>
</Container>
<Container
sx={{
color: "#000",
".carousel .control-dots .dot": {
backgroundColor: "#000",
},
".carousel .control-prev.control-arrow": {
padding: "20px",
borderRadius: "12px 0 0 12px",
},
".carousel .control-next.control-arrow": {
padding: "20px",
borderRadius: "0 12px 12px 0",
},
".carousel .control-prev.control-arrow:before": {
borderRightColor: "rgba(0,0,0,0.5)",
},
".carousel .control-next.control-arrow:before": {
borderLeftColor: "rgba(0,0,0,0.5)",
},
".carousel .slide .legend": {
width: "30%",
marginLeft: "-15%",
},
}}
>
<Stack sx={{ pt: 15 }} spacing={6} alignItems="center">
<Title title="产品展示" />
<Box sx={{ boxShadow: "0 12px 25px -12px rgba(93,99,112, 0.2)" }}>
<Carousel
interval={2000}
infiniteLoop
autoPlay
showStatus={false}
showThumbs={false}
>
{IMAGE_LIST.map((item) => (
<Box
key={item.url}
sx={{
borderRadius: "12px",
overflow: "hidden",
}}
>
<Box component="img" src={item.url} alt={item.name} />
<Box
className="legend"
sx={{
opacity: "0.40 !important",
py: "4px !important",
borderRadius: "4px !important",
}}
>
<Typography variant="h6" sx={{ fontSize: "14px" }}>
{item.name}
</Typography>
</Box>
</Box>
))}
</Carousel>
</Box>
</Stack>
</Container>
<Container sx={{ color: "#000", pb: 3 }}>
<Stack sx={{ pt: 15 }} spacing={3} alignItems="center">
<Title title="版本对比" />
<Version />
</Stack>
<Stack sx={{ pt: 15 }} id="groupchat" spacing={6} alignItems="center">
<Title title="加入讨论组" />
<Image
src="/images/wechat-light.png"
alt="wechat"
width={300}
height={300}
priority
/>
</Stack>
<Box sx={{ pt: 12 }}>
<FriendlyLinks />
</Box>
<Stack sx={{ pt: 6, color: "rgba(0,0,0,0.5)", textAlign: "center" }}>
© 2023 ICP 19035216
11010802020947
</Stack>
</Container>
</Box>
);
}

View File

@@ -1,103 +0,0 @@
import { type GetStaticProps } from "next";
import { useRef } from "react";
import { Box } from "@mui/material";
import Head from "next/head";
import SideLayout from "@/layout/SideLayout";
import { MarkdownNavbar } from "@/components";
import { MDXRemote, MDXRemoteProps } from "next-mdx-remote";
import {
getPostsIds,
getPostsGroup,
getPostData,
type GroupItem,
} from "@/utils/posts";
interface PostsProps {
group: GroupItem[];
postData: MDXRemoteProps;
content: string;
headTitle: string;
// tocElement: any;
}
const Posts: React.FC<PostsProps> = ({
group,
postData,
content,
headTitle,
// tocElement,
}) => {
const domRef = useRef<HTMLElement>();
return (
<SideLayout list={group}>
<Head>
<title>{headTitle}</title>
</Head>
<Box
id="markdown-body-warp"
sx={{
display: "flex",
height: "calc(100vh - 128px)",
overflow: "auto",
justifyContent: "space-between",
// "&::-webkit-scrollbar": {
// display: "none",
// },
}}
>
<Box
ref={domRef}
id="markdown-body"
className="markdown-body"
sx={{ width: { xs: "100%", sm: "77%" } }}
>
<MDXRemote {...postData} />
</Box>
<Box
sx={{
display: { xs: "none", sm: "block" },
width: "20%",
position: "sticky",
top: 0,
}}
>
<MarkdownNavbar source={content} containerId="markdown-body-warp" />
</Box>
</Box>
</SideLayout>
);
};
export async function getStaticPaths() {
const paths = getPostsIds();
return {
paths,
fallback: false,
};
}
export const getStaticProps: GetStaticProps<PostsProps> = async ({
params,
}) => {
const { postData, content } = await getPostData(params?.id as string);
const group = getPostsGroup();
let idToTextMap: Record<string, string> = {};
group.forEach((g) => {
g.list.forEach((nav) => {
idToTextMap[nav.id] = nav.title;
});
});
return {
props: {
group,
content,
postData,
headTitle: idToTextMap[params?.id as string] + " - 长亭雷池 WAF 社区版",
},
};
};
export default Posts;

View File

@@ -1,8 +0,0 @@
---
title: "社区版 vs 企业版"
group:
title: "关于雷池"
order: 3
order: 1
---
# 社区版 vs 企业版

View File

@@ -1,118 +0,0 @@
---
title: "版本更新记录"
group: "关于雷池"
order: 3
---
# 版本更新记录
[版本升级方法](https://waf-ce.chaitin.cn/posts/guide_upgrade)
## [1.8.1] - 2023-06-09
- 修复了「全部请求」和「仅拦截」数据一样的问题
## [1.8.0] - 2023-06-09
### 新增
- 数据统计页面增加访问来源地区、流量统计,更好把控网站运营情况
![](/images/docs/about_changelog/map.png)
### 优化
- 更新语义引擎版本,优化了一大批检测逻辑,降低误报
- 优化了部分操作提示信息:
- IP 组正在使用时,无法被删除的提示
- 未创建 IP 组时,在黑白名单中无法选择属于 IP 组的提示
- 添加站点时,域名格式错误的提示
## [1.7.1] - 2023-06-05
### 修复
- 部分情况下无法打开日志详情页面的问题
- 部分情况下页面查询数量只有 10 条的问题
## [1.7.0] - 2023-06-01
### 新增
- 新增 “IP 组” 功能,可以快速配置大量 IP 的黑/白名单了
- 防护策略增加 “仅观察” 配置
- 防护策略增加 “批量配置为” 按钮,可以快速切换所有模块的防护策略
### 优化
- 自定义规则列表增加翻页
- 优化规则生效顺序,现在会优先执行完所有白名单,再执行黑名单
## [1.6.0] - 2023-05-25
### 新增
- 自定义规则支持匹配 Header 和 Body
- 检测日志支持按域名搜索
- 支持命令行清理检测日志和统计信息
## [1.5.1] - 2023-05-18
- 修复了自定义规则切换白名单之后,无法创建/编辑的问题
## [1.5.0] - 2023-05-18
### 新增
- 支持 i18n
- 数据统计新增 “今日请求错误情况”
- 检测日志的筛选条件现在会显示在 URL方便保存
### 优化
- 修复自定义规则的编辑表单,有时候会丢失编辑中数据的问题
- 修复 Safari 浏览器上的一些显示问题
- 修复 Payload 中存在非 Unicode 编码时,检测日志会入库失败的问题(不影响拦截)
- 修复新增的 “HTTP 请求走私” 攻击类型会被错误地展示成 “未知” 攻击类型的问题
## [1.4.0] - 2023-05-12
### 新增
- 自定义规则支持匹配域名
- 支持在一条自定义规则内,设置多个匹配条件
- 站点列表新增 “今日访问 / 拦截量”
### 优化
- 优化交互和提示文案、修复已知问题
## [1.3.0] - 2023-05-05
### 新增
- 支持按照源 IP、攻击类型、URL 筛选检测日志
### 修复
- 修复 dashboard 在部分低版本浏览器下的兼容问题
- 修复按源 IP 添加自定义规则时,添加不了 /8 和更大的网段的问题
## [1.2.0] - 2023-04-27
### 新增
- 新增了数据统计页面,可以直观的看到流量大小
- 支持配置源 IP 提取方式,解决了源 IP 获取不对的问题
- 支持自定义检测策略,可以动态调整检测引擎
## [1.1.0] - 2023-04-20
### 新增
- 支持根据 IP 和 URL 特征配置黑白名单
- 默认开启高防模式
### 优化
- 支持在日志详情中展示响应报文
- 服务器时间不准导致 TOTP 无法登录时增加了提示语
- 修复了上游服务器填 HTTPS 时端口解析不正确的问题
- 优化了 SSL 上传逻辑,体验更好
## [1.0.0] - 2023-04-13
- 站点配置
## [0.9.0] - 2023-03-20
- OTP 登录
- 攻击检测日志
- 默认防护策略

View File

@@ -1,24 +0,0 @@
---
title: "网站无法访问"
group: "常见问题排查"
order: 3
---
# 网站无法访问
为了方便讨论问题, 我们假设:
在没有 SafeLine 的时候,假设小明的域名 `xiaoming.com` 通过 DNS 解析到自己主机 `192.168.1.111`,上面在 `:8888` 端口监听了自己的服务(网站/博客/靶场)等等。
小明通过 `http://xiaoming.com:8888` 或者 `192.168.1.111:8888` 来访问自己的服务。
## 如果返回502
![DNS.png](/images/docs/tengine_502.png)
如果出现类似相应,请检查上游服务器地址是否配置正确或者雷池是否能够访问能访问到上游服务器
## 请求返回缓慢
1. 首先检查服务器负载情况
2. 检查雷池服务器与上游服务器的网络状况,检查命令`curl -H "Host: <SafeLine-IP>" -vv -o /dev/null -s -w 'time_namelookup: %{time_namelookup}\ntime_connect: %{time_connect}\ntime_starttransfer: %{time_starttransfer}\ntime_total: %{time_total}\n' http://xiaoming.com:8888` <br/>
如果 `time_namelookup` 时间过大请检查dns server配置
如果 `time_connect` 时间过大,请检查与上游服务器之间的网络状态
如果 `time_starttransfer` 时间过大,请检查上游服务器状态,是否出现资源过载情况

View File

@@ -1,77 +0,0 @@
---
title: "配置问题"
group: "常见问题排查"
order: 10
---
# 配置问题
## 站点配置问题
在没有 SafeLine 的时候,假设小明的域名 `xiaoming.com` 通过 DNS 解析到自己主机 `192.168.1.111`,上面在 `:8888` 端口监听了自己的服务(网站/博客/靶场)等等。
小明通过 `http://xiaoming.com:8888` 或者 `192.168.1.111:8888` 来访问自己的服务。
### 我该如何配置?/ 域名填什么?/ 端口怎么写?/ 上游服务器是什么?
目前社区版 SafeLine 支持的是反向代理的方式接入站点,也就是类似于一台 nginx 服务。这时候小明需要做的就是让流量先抵达 SafeLine然后经过 SafeLine 检测之后,再转发给自己原先的业务。
小明只需要按照如下方式创建站点即可:
- `xiaoming.com` 填入页面的「域名」
- `:7777` 填入「端口」;或者别的任意非 `:8888``:9443`(被 SafeLine 后台管理页面占用)端口
- `http://192.168.1.111:8888` 填入「上游服务器」
创建之后,就可以通过 `http://xiaoming.com:7777` 或者 `192.168.1.111:7777` 访问自己的服务了,这时候请求到 `http://xiaoming.com:7777` 的流量都会被 SafeLine 检测。经过 SafeLine 过滤后,安全的流量会被透传到原先的 `:8888` 业务服务器(即上游服务器)。
**注:直接访问 `http://xiaoming.com:8888` 的流量,仍然不会被 SafeLine 检测,因为流量并没有经过 SafeLine而是绕过 SafeLine 直接打到了上游服务器上**
**如果按照如上配置,还是无法成功访问到我的上游服务器,接着往下看,尝试逐项进行问题排查。**
## 配置完成之后,还是没有成功访问到上游服务器
下面例子都还按照上面小明的环境情况介绍。
#### 1. netstat/ss/lsof 查看端口占用情况
先确认下 `0.0.0.0:7777` 端口是否有服务在监听。SafeLine 使用 Tengine 来作为代理服务,所以正常来说,应该有一个 nginx 进程监听在 `:7777` 端口。如果没有的话,可能是 SafeLine 的问题,请通过社群或者 Github issue 提交反馈。
如果有的话,继续往下排查。
#### 2. 是否是被非 SafeLine 的 nginx 监听
基于第一步,已经能确认 `:7777` 是被某个 nginx 进程监听了,但是并不能确认是被 SafeLine 自己的 nginx 监听。排查是否自己原先有 nginx conf 中配置了 server 监听 `:7777`。如果有的话,手动解决冲突。要么修改自己原先的 nginx conf要么修改 SafeLine 的站点配置。
也可以直接通过 `docker logs -f safeline-tengine` 确认 SafeLine 是否有 nginx 报错说端口冲突。
*常见的情况就是自己原先有一个服务监听在 `:80`SafeLine 上配置了站点也监听 `:80` 端口,就产生了冲突。*
如果没有的话,继续往下排查。
#### 3. 是否被防火墙拦截
有操作系统本身的防火墙,还有可能是云服务商的防火墙。根据实际情况逐项排查,配置开放端口的 TCP 访问。
出现如下情况,可能就是被中间某防火墙拦截了:
1.`192.168.1.111` 上 curl -vv `127.0.0.1:7777` 能访问到业务,有 HTTP 返回码。
2. 在本机 curl -vv `192.168.1.111:7777` 不通,没有 HTTP 响应;`telnet 192.168.1.111 7777` 返回 `Unable to connect to remote host: Connection refused`
#### 4. SafeLine 是否能访问到上游服务器
小明的情况是 SafeLine 和业务在同一台机器,一般不会有不同机器之间的网络问题,但是也建议在 SafeLine 部署的机器上测试一下。如果是两台机器的情况下,需要考虑是否互相之间能正常通信。
直接 `curl -H "Host: <SafeLine-IP>" -vv http://xiaoming.com:8888` 测一下是否能访问到。如果不行,需要自行排查为什么 SafeLine 的机器没法访问到。
注:这里需要 -H 指定 Host `Host: <SafeLine-IP>` 进行连通性测试。收到比较多的反馈,在 WAF 上直接配置上游服务器为 HTTPS 的域名,比如 `https://xiaoming.com`。实际场景是希望先测试 WAF 能力正常后再把域名解析切到 WAF 进行上线。这种本地测试的场景,需要修改本机 host`xiaoming.com` 解析到 `SafeLine-IP`,否则可能会无法成功代理。因为 SafeLine 向上游服务器转发时,代理请求中的 Host 使用的是原始 HTTP 请求中的 Host此时需要自行判断上游业务服务器能够正确处理该代理请求例如上游业务服务器在 Host 没有匹配自己的站点名称时,是否能够处理)
#### 5. 其他情况
如果执行了 1-4
1. 确认有 nginx 进程监听了 SafeLine 机器的 `0.0.0.0:7777` 端口
2. 确认 SafeLine tengine 无端口冲突报错
3. 确认主机和云服务商的防火墙都没有限制 `:7777` 端口的 TCP 访问
4. 确认在 SafeLine 上能访问到「上游服务器」
问题还是没有解决,可能是 SafeLine 产品的问题,请通过社群或者 Github issue 提交反馈。

View File

@@ -1,39 +0,0 @@
---
title: "其他问题"
group: "常见问题排查"
order: 10
---
# 其他问题
### 为什么我的检测日志中的攻击IP显示的是负载均衡的IP
因为雷池的源 IP 获取方式默认为**从 Socket 中获取**,如需更改请至 通用配置 -> 源 IP 获取方式 处更改
![get_source_ip.png](/images/docs/get_source_ip.png)
### 如何清理数据库中的统计信息和检测日志
***注意:该操作会清除所有日志信息,且不可恢复***
```shell
docker exec -it safeline-mgt-api cleanlogs
```
### 如何记录所有访问雷池的请求
默认情况下雷池是并不会保存请求记录的,如果需要保存请求记录,可以修改**resources/nginx/nginx.conf**
![config_access_log.png](/images/docs/config_access_log.png)
如图所示去掉文件第99行的注释删除第100行的内容保存后运行命令检查配置文件
```shell
docker exec safeline-tengine nginx -t
```
检查应显示
```shell
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
```
最后应用配置文件
```shell
docker exec safeline-tengine nginx -s reload
```
配置生效后,访问日志将会保存至**logs/nginx**
***注意:该操作会会加快对硬盘的消耗,请定时清理访问日志***

View File

@@ -1,7 +0,0 @@
---
title: "防护不生效"
group: "常见问题排查"
order: 4
---
# 防护不生效

View File

@@ -1,26 +0,0 @@
---
title: "配置防护站点"
group: "上手指南"
order: 4
---
# 配置防护站点
![safeline_website.gif](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_website.gif)
💡 TIPS: 添加后,执行 `curl -H "Host: <域名>" http://<WAF IP>:<端口>` 应能获取到业务网站的响应。
## 将网站流量切到雷池
- 若网站通过域名访问,则可将域名的 DNS 解析指向雷池所在设备
![DNS.png](/images/docs/DNS.png)
- 若网站前有 nginx 、负载均衡等代理设备,则可将雷池部署在代理设备和业务服务器之间,然后将代理设备的 upstream 指向雷池
![DNS.png](/images/docs/LoadBlance.png)
## 如何配置https
![safeline_https_website.gif](/images/docs/safeline_https_website.gif)
## 测试防护效果
[测试防护效果](/posts/guide_test)

View File

@@ -1,141 +0,0 @@
---
title: "安装雷池"
group: "上手指南"
order: 2
---
# 安装雷池
## 配置需求
- 操作系统Linux
- 指令架构x86_64
- 软件依赖Docker 20.10.6 版本以上
- 软件依赖Docker Compose 2.0.0 版本以上
- 最小化环境1 核 CPU / 1 GB 内存 / 10 GB 磁盘
可以逐行执行以下命令来确认服务器配置
```shell
uname -m # 查看指令架构
docker version # 查看 Docker 版本
docker compose version # 查看 Docker Compose 版本
docker-compose version # 同上(兼容老版本 Docker Compose
cat /proc/cpuinfo # 查看 CPU 信息
cat /proc/meminfo # 查看内存信息
df -h # 查看磁盘信息
```
有三种安装方式供选择
- [在线安装](#在线安装) : 推荐安装方式
- [离线安装](#离线安装) : 服务器无法联网时选择
- [一键安装](#使用牧云助手安装) : 最简单的安装方式
## 在线安装
***如果服务器可以访问互联网环境,推荐使用在线安装方式***
### 在线安装 Docker
> 如果已经安装 Docker 和 Docker Compose可跳过这一步直接进入 [在线安装雷池](#在线安装雷池)
执行以下命令来安装 Docker 和 Docker Compose
```bash
curl -fsSLk https://get.docker.com/ | bash
```
安装命令结束后,可以执行以下命令来确认 Docker 和 Docker Compose 是否安装成功
```
docker version # 查看 Docker 版本
docker compose version # 查看 Docker Compose 版本
```
### 在线安装雷池
执行以下命令创建并进入雷池安装目录
```
mkdir -p safeline # 创建 safeline 目录
cd safeline # 进入 safeline 目录
```
执行以下命令,将会自动下载镜像,并完成环境的初始化
```
curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh | bash
```
执行以下命令启动雷池
```
docker compose up -d
```
经过以上步骤,你的雷池已经安装好了,下一步请参考 [登录雷池](/posts/guide_login)
## 离线安装
如果你的服务器无法连接互联网环境,可以使用离线安装方式
> 这里忽略 Docker 安装的过程
首先,你要找一台能够访问互联网的服务器,执行以下命令拉取镜像,打包到 image.tar 文件中
```
docker pull chaitin/safeline-tengine:latest
docker pull chaitin/safeline-mgt-api:latest
docker pull chaitin/safeline-mario:latest
docker pull chaitin/safeline-detector:latest
docker pull postgres:15.2
docker pull redis:7.0.11
docker save -o image.tar chaitin/safeline-tengine:latest chaitin/safeline-mgt-api:latest chaitin/safeline-mario:latest chaitin/safeline-detector:latest postgres:15.2 redis:7.0.11
```
将 image.tar 文件传输到需要安装雷池的服务器上,执行以下命令加载镜像
```
docker load -i image.tar
```
执行以下命令创建并进入雷池安装目录
```
mkdir -p safeline # 创建 safeline 目录
cd safeline # 进入 safeline 目录
```
下载 [编排脚本](https://waf-ce.chaitin.cn/release/latest/compose.yaml) 并传输到 safeline 目录中
执行以下命令,生成雷池运行所需的相关环境变量
```
echo "SAFELINE_DIR=$(pwd)" > .env
echo "IMAGE_TAG=latest" >> .env
echo "MGT_PORT=9443" >> .env
echo "POSTGRES_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 </dev/urandom | head -c 32)" >> .env
echo "SUBNET_PREFIX=169.254.0" >> .env
```
执行以下命令启动雷池
```
docker compose up -d
```
经过以上步骤,你的雷池已经安装好了,下一步请参考 [登录雷池](/posts/guide_login)
## 使用牧云助手安装
也可以使用 [牧云主机管理助手](https://collie.chaitin.cn/) 进行一键安装
![](/images/docs/guide_install/collie_apps.png)
参考视频教程 [用 “白嫖的云主机” 一键安装 “开源的Web防火墙”](https://www.bilibili.com/video/BV1sh4y1t7Pk/)
## 常见安装问题
请参考 [安装问题](/posts/faq_install)

View File

@@ -1,11 +0,0 @@
---
title: "登录雷池"
group: "上手指南"
order: 3
---
# 登录雷池
浏览器打开后台管理页面 `https://<waf-ip>:9443`。根据界面提示,使用 **支持 TOTP 的认证软件** 扫描二维码,然后输入动态口令登录:
![safeline_login.gif](https://ctstack-oss.oss-cn-beijing.aliyuncs.com/veinmind/safeline-assets/safeline_login.gif)

View File

@@ -1,94 +0,0 @@
---
title: "测试防护效果"
group: "上手指南"
order: 5
---
# 测试防护效果
## 确认网站可以正常访问
根据雷池 WAF 配置的网站参数访问你的网站
打开浏览器访问 `http://<IP或域名>:<端口>/`
> 网站协议默认是 http勾选 ssl 则为 https
> 主机名可以是雷池的 IP也可以是网站的域名确保域名已经解析到雷池
> 端口是你在雷池页面中配置的网站端口
若网站访问不正常,请参考 [网站无法访问](/posts/faq_access)
## 尝试手动模拟攻击
打开浏览器,访问以下地址即可模拟出对应的攻击:
- 模拟 SQL 注入,请访问 `http://<IP或域名>:<端口>/?id=1%20AND%201=1`
- 模拟 XSS请访问 `http://<IP或域名>:<端口>/?html=<script>alert(1)</script>`
通过浏览器,你将会看到雷池已经发现并阻断了攻击请求。
若请求没有被阻断,请参考 [防护不生效](/posts/faq_protection)
## 自动化测试防护效果
两条请求当然无法完整的测试雷池的防护效果,可以使用 blazehttp 自动化工具进行批量测试
#### 下载测试工具
- [Windows 版本](/blazehttp/blazehttp_windows.exe)
- [Mac 版本(x64)](/blazehttp/blazehttp_mac_x64)
- [Mac 版本(M1)](/blazehttp/blazehttp_mac_m1)
- [Linux 版本(x64)](/blazehttp/blazehttp_linux_x64)
- [Linux 版本(ARM)](/blazehttp/blazehttp_linux_arm64)
- [源码仓库](https://github.com/chaitin/blazehttp)
#### 准备测试样本
- [测试样本](/blazehttp/testcases.zip)
下载请求样本后解压到 `testcases` 目录
#### 开始测试
1. 将测试工具 `blazehttp` 和测试样本 `testcases` 放在同一个目录下
2. 进入对应的目录
3. 使用以下请求开始测试
```
./blazehttp -t http://<IP或域名>:<端口> -g './testcases/*.http'
```
#### 测试效果展示
```
# 测试请求
./blazehttp -t http://192.168.0.1:8080 -g './testcases/*.http'
sending 100% |██████████████████████████████████████████| (18/18, 86 it/s)
Total http file: 18, success: 18 failed: 0
Stat http response code
Status code: 403 hit: 16
Status code: 200 hit: 2
Stat http request tag
tag: sqli hit: 1
tag: black hit: 16
tag: file_include hit: 1
tag: file_upload hit: 1
tag: java_unserialize hit: 1
tag: php_unserialize hit: 1
tag: cmdi hit: 1
tag: ssrf hit: 1
tag: xslti hit: 1
tag: xss hit: 1
tag: xxe hit: 1
tag: asp_code hit: 1
tag: white hit: 2
tag: ognl hit: 1
tag: shellshock hit: 1
tag: ssti hit: 1
tag: directory_traversal hit: 1
tag: php_code hit: 1
```

View File

@@ -1,46 +0,0 @@
---
title: "升级雷池"
group: "上手指南"
order: 6
---
# 升级雷池
## 自动一键更新
**WARN: 雷池 SafeLine 服务会重启,流量会中断一小段时间,根据业务情况选择合适的时间来执行升级操作。**
```shell
# 请到 compose.yaml 同级目录下执行下面脚本
curl -kfLsS https://waf-ce.chaitin.cn/release/latest/upgrade.sh | bash
```
**有部分环境的默认 SafeLine 安装路径是在 `/data/safeline-ce`,安装之后可能会发现需要重新绑定 OTP、配置丢失等情况可以修改 .env 的 `SAFELINE_DIR` 变量,指向 `/data/safeline-ce`**
## 手动更新镜像
适用于 docker hub 拉取镜像失败的场景,手动更新镜像,注意还是要执行 `upgrade.sh` 来处理 `.env` 的更新,否则有可能会因为缺少参数而启动失败。
### 1. 在一台能够从 docker hub 拉取镜像的机器上执行
```shell
# 拉取镜像
docker pull chaitin/safeline-tengine:latest
docker pull chaitin/safeline-mgt-api:latest
docker pull chaitin/safeline-mario:latest
docker pull chaitin/safeline-detector:latest
docker pull postgres:15.2
# 打包镜像
docker save -o image.tar chaitin/safeline-tengine:latest chaitin/safeline-mgt-api:latest chaitin/safeline-mario:latest chaitin/safeline-detector:latest postgres:15.2
# 传输到 SafeLine 要部署的目标服务器
# scp image.tar <target-server>:/root/
```
### 2. 在目标服务器 load 镜像
```shell
docker load -i image.tar
curl -kfLsS https://waf-ce.chaitin.cn/release/latest/upgrade.sh | bash
```

View File

@@ -1,352 +0,0 @@
/*
1. Use a more-intuitive box-sizing model.
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
/*
2. Remove default margin
*/
* {
margin: 0;
}
/*
3. Allow percentage-based heights in the application
*/
html,
body {
height: 100%;
}
/*
Typographic tweaks!
4. Add accessible line-height
5. Improve text rendering
*/
body {
line-height: 1.5;
scrollbar-width: 5px;
scrollbar-color: #9b9b9b #363636;
}
/*
6. Improve media defaults
*/
img,
picture,
video,
canvas,
svg {
display: block;
max-width: 100%;
}
/*
7. Remove built-in form typography styles
*/
input,
button,
textarea,
select {
font: inherit;
}
/*
8. Avoid text overflows
*/
p,
h1,
h2,
h3,
h4,
h5,
h6 {
overflow-wrap: break-word;
}
/*
9. Create a root stacking context
*/
#root,
#__next {
isolation: isolate;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Ping Fang SC', 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a,
a:link,
a:visited,
a:hover,
a:active {
text-decoration: none;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
@keyframes fadeIn {
0% {
opacity: 0;
}
50% {
opacity: 0;
}
51% {
opacity: 1;
}
100% {
opacity: 1;
}
}
@keyframes wings {
50% {
transform: translateY(-40px);
}
100% {
transform: translateY(0px);
}
}
@keyframes blink {
50% {
opacity: 0.6;
}
100% {
opacity: 1;
}
}
@keyframes bounce {
0%,
20%,
53%,
to {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
transform: translateZ(0);
}
40%,
43% {
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
transform: translate3d(0, -5px, 0);
}
70% {
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
transform: translate3d(0, -7px, 0);
}
80% {
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
transform: translateZ(0);
}
90% {
transform: translate3d(0, -2px, 0);
}
}
@keyframes slideY {
0%,
50%,
100% {
transform: translateY(0px);
}
25% {
transform: translateY(-10px);
}
75% {
transform: translateY(10px);
}
}
@keyframes slideX {
0%,
50%,
100% {
transform: translateX(0px);
}
25% {
transform: translateX(-10px);
}
75% {
transform: translateX(10px);
}
}
@keyframes scale {
0% {
transform: scale(1.5) rotate(90deg);
opacity: 0;
}
100% {
transform: scale(1) rotate(0);
opacity: 1;
}
}
.dark ::-webkit-scrollbar {
width: 5px;
/* 纵向滚动条*/
height: 5px;
/* 横向滚动条 */
background-color: #363636;
border-radius: 10px;
}
/*定义滚动条轨道 内阴影*/
.dark ::-webkit-scrollbar-track {
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
background-color: #363636;
border-radius: 10px;
}
/*定义滑块 内阴影*/
.dark ::-webkit-scrollbar-thumb {
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
background-color: #9b9b9b;
border-radius: 10px;
}
.light ::-webkit-scrollbar {
width: 5px;
/* 纵向滚动条*/
height: 5px;
/* 横向滚动条 */
border-radius: 10px;
}
/*定义滚动条轨道 内阴影*/
.light ::-webkit-scrollbar-track {
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
background-color: #afafaf;
border-radius: 10px;
}
/*定义滑块 内阴影*/
.light ::-webkit-scrollbar-thumb {
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0);
background-color: #666;
border-radius: 10px;
}
/* @font-face {
font-family: 'HYXIAOBOZHEZHITIJ';
src: url('../fonts/HYXIAOBOZHEZHITIJ.TTF');
font-weight: normal;
font-style: normal;
} */
/* @font-face {
font-family: 'Mono-Bold';
src: url('../fonts/JetBrainsMono-Bold.ttf');
font-weight: normal;
font-style: normal;
} */
.markdown-navigation {
font-size: 14px;
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Helvetica", "Arial", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif;
width: 100%;
overflow: hidden;
border-left: 2px solid #E9E9E9;
padding-left: 15px;
}
.markdown-navigation .title-anchor {
display: block;
color: #bbb;
transition: all 0.2s;
margin: 0.8em 0;
/* font-weight: lighter; */
line-height: 2em;
padding-right: 1.8em;
cursor: pointer;
}
.markdown-navigation .title-anchor:hover,
.markdown-navigation .title-anchor.active {
background-color: #f8f8f8;
text-decoration: inherit;
}
.markdown-navigation .title-anchor.active {
color: #007fff;
}
.markdown-navigation .title-anchor small {
/* margin: 0 0.8em; */
margin-right: 0.8em;
}
.markdown-navigation .title-level1 {
display: none;
color: #000;
font-size: 1.2em;
padding-left: 0em;
font-weight: normal;
}
.markdown-navigation .title-level2 {
color: #000;
font-size: 1em;
/* padding-left: 2em; */
font-weight: normal;
}
.markdown-navigation .title-level3 {
color: #666;
font-size: 0.8em;
/* padding-left: 3em; */
font-weight: normal;
}
.markdown-navigation .title-level4 {
color: #222;
font-size: 0.72em;
/* padding-left: 4em; */
}
.markdown-navigation .title-level5 {
color: #999;
font-size: 0.72em;
/* padding-left: 5em; */
}
.markdown-navigation .title-level6 {
color: #bbb;
font-size: 0.72em;
/* padding-left: 6em; */
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,182 +0,0 @@
export const dark = {
primary: {
main: '#7267EF',
contrastText: '#fff',
},
secondary: {
lighter: '#D6E4FF',
light: '#84A9FF',
main: '#2196F3',
dark: '#1939B7',
darker: '#091A7A',
contrastText: '#fff',
},
info: {
lighter: '#D0F2FF',
light: '#74CAFF',
main: '#1890FF',
dark: '#0C53B7',
darker: '#04297A',
contrastText: '#fff',
},
success: {
lighter: '#E9FCD4',
light: '#AAF27F',
main: '#02BFA5',
dark: '#229A16',
darker: '#08660D',
contrastText: 'rgba(0,0,0,0.7)',
},
warning: {
lighter: '#FFF7CD',
light: '#FFE16A',
main: '#FFBF00',
dark: '#B78103',
darker: '#7A4F01',
contrastText: 'rgba(0,0,0,0.7)',
},
neutral: {
main: '#232C59',
contrastText: 'rgba(255, 255, 255, 0.60)',
},
error: {
lighter: '#FFE7D9',
light: '#FFA48D',
main: '#FF1844',
dark: '#B72136',
darker: '#7A0C2E',
contrastText: '#fff',
},
text: {
primary: '#fff',
secondary: 'rgba(255,255,255,0.7)',
auxiliary: 'rgba(255,255,255,0.5)',
slave: 'rgba(255,255,255,0.05)',
disabled: 'rgba(255,255,255,0.15)',
inversePrimary: '#000',
inverseAuxiliary: 'rgba(255,255,255,0.5)',
inverseDisabled: 'rgba(255,255,255,0.15)',
},
divider: '#38405D',
background: {
paper0: '#111936',
paper: '#1A223F',
paper2: '#212A46',
default: 'rgba(255,255,255,0.6)',
disabled: '#2E375F',
chip: '#232D4F',
circle: '#3B476A',
},
common: {},
shadowColor: '#0B1233',
table: {
head: {
backgroundColor: '#232D4F',
color: 'rgba(255,255,255,0.7)',
},
row: {
hoverColor: '#212A46',
},
cell: {
borderColor: '#232D4F',
},
},
charts: {
color: ['#7267EF', '#02BFA5'],
},
} as const
export const light = {
primary: {
main: '#7635DC',
contrastText: '#fff',
},
secondary: {
lighter: '#D6E4FF',
light: '#84A9FF',
main: '#3366FF',
dark: '#1939B7',
darker: '#091A7A',
contrastText: '#fff',
},
info: {
lighter: '#D0F2FF',
light: '#74CAFF',
main: '#1890FF',
dark: '#0C53B7',
darker: '#04297A',
contrastText: '#fff',
},
success: {
lighter: '#E9FCD4',
light: '#AAF27F',
main: '#02BFA5',
mainShadow: '#02BFA5',
dark: '#229A16',
darker: '#08660D',
contrastText: 'rgba(0,0,0,0.7)',
},
warning: {
lighter: '#FFF7CD',
light: '#FFE16A',
main: '#FFBF00',
dark: '#B78103',
darker: '#7A4F01',
contrastText: 'rgba(0,0,0,0.7)',
},
neutral: {
main: '#F4F6F8',
contrastText: 'rgba(0, 0, 0, 0.60)',
},
error: {
lighter: '#FFE7D9',
light: '#FFA48D',
main: '#FF1844',
dark: '#B72136',
darker: '#7A0C2E',
contrastText: '#fff',
},
divider: '#E3E8EF',
text: {
primary: '#000',
secondary: 'rgba(0,0,0,0.7)',
auxiliary: 'rgba(0,0,0,0.5)',
slave: 'rgba(0,0,0,0.05)',
disabled: 'rgba(0,0,0,0.15)',
inversePrimary: '#fff',
inverseAuxiliary: 'rgba(255,255,255,0.5)',
inverseDisabled: 'rgba(255,255,255,0.15)',
},
background: {
paper0: '#fff',
paper: '#fff',
paper2: '#f6f8fa',
default: '#fff',
chip: '#F4F6F8',
circle: '#E6E8EC',
},
shadowColor: 'rgba(145,158,171,0.2)',
table: {
head: {
backgroundColor: '#F4F6F8',
color: 'rgba(0,0,0,0.7)',
},
row: {
hoverColor: '#F9FAFB',
},
cell: {
borderColor: '#F3F4F5',
},
},
charts: {
color: ['#673AB7', '#02BFA5'],
},
}
export type Color = typeof dark

View File

@@ -1,204 +0,0 @@
import { type Color } from './color'
export default function componentStyleOverrides(color: Color) {
return {
MuiButton: {
styleOverrides: {
root: ({ ownerState, theme }: any) => {
return {
boxShadow: 'none',
'&:hover': {
boxShadow: 'none',
...(ownerState.color === 'neutral' && {
color: color.primary.main,
fontWeight: 700,
}),
},
}
},
},
},
MuiLoadingButton: {
styleOverrides: {
root: ({ ownerState, theme }: any) => {
return {
// position: 'relative',
// ...(ownerState.loading && {
// backgroundImage: 'linear-gradient(263deg, #3892EE 0%, #2E7AE9 100%)',
// boxShadow: '0px 2px 8px 0px rgba(133,190,245,0.5)',
// '&.MuiLoadingButton-loading': {
// color: '#fff',
// },
// '&:before': {
// content: "''",
// position: 'absolute',
// top: '-1px',
// right: '-1px',
// bottom: '-1px',
// left: '-1px',
// zIndex: 1,
// background: '#fff',
// opacity: 0.35,
// transition: 'opacity .2s',
// pointerEvents: 'none',
// },
// }),
}
},
},
},
MuiListItemButton: {
styleOverrides: {
root: {
// paddingTop: '10px',
// paddingBottom: '10px',
// borderRadius: '8px',
// '&.Mui-selected': {
// color: theme.menuSelected,
// backgroundColor: theme.menuSelectedBack,
// '&:hover': {
// backgroundColor: theme.menuSelectedBack,
// },
// '& .MuiListItemIcon-root': {
// color: theme.menuSelected,
// },
// },
// '&:hover': {
// backgroundColor: 'transparent',
// color: theme.menuSelected,
// '& .MuiListItemIcon-root': {
// color: theme.menuSelected,
// },
// },
},
},
},
MuiListItemIcon: {
styleOverrides: {
root: {
// minWidth: '36px',
},
},
},
MuiFormControlLabel: {
styleOverrides: {
root: {
// marginRight: '24px',
},
},
},
MuiInputBase: {
styleOverrides: {
root: {
// '.MuiInputBase-colorPrimary&:hover:not(.Mui-disabled):before': {
// borderColor: theme.colors?.primaryMain,
// },
},
},
},
MuiFormControl: {
styleOverrides: {
root: {
'.MuiFormLabel-asterisk': {
color: color.error.main,
},
},
},
},
MuiTableRow: {
styleOverrides: {
root: {
'&:hover': {
'.MuiTableCell-root': {
// backgroundColor: color.table.row.hoverColor,
},
},
},
},
},
MuiTableBody: {
styleOverrides: {
root: {
'.MuiTableRow-root:hover': {
'.MuiTableCell-root': {
backgroundColor: color.table.row.hoverColor,
},
},
},
},
},
MuiTableCell: {
styleOverrides: {
root: {
background: color.background.paper,
lineHeight: 1.5,
fontSize: '14px',
paddingTop: '24px',
paddingBottom: '24px',
borderColor: color.table.cell.borderColor,
paddingLeft: 0,
'&:first-of-type': {
paddingLeft: '32px',
},
},
head: {
backgroundColor: color.table.head.backgroundColor,
color: color.table.head.color,
fontSize: '12px',
height: '24px',
paddingTop: 0,
paddingBottom: 0,
},
},
},
MuiMenu: {
defaultProps: {
elevation: 0,
},
},
MuiPaper: {
defaultProps: {
elevation: 1,
},
styleOverrides: {
root: ({ ownerState }: any) => {
return {
...(ownerState.elevation === 0 && {
backgroundColor: color.background.paper0,
}),
...(ownerState.elevation === 2 && {
backgroundColor: color.background.paper2,
}),
backgroundImage: 'none',
}
},
},
},
MuiChip: {
styleOverrides: {
root: {
borderRadius: '4px'
},
},
},
MuiAppBar: {
defaultProps: {
elevation: 1,
},
},
MuiOutlinedInput: {
styleOverrides: {
root: {
'&:hover .MuiOutlinedInput-notchedOutline': {
borderColor: color.primary.main,
},
'& .MuiOutlinedInput-notchedOutline': {
borderColor: color.divider,
},
},
},
},
}
}

View File

@@ -1,59 +0,0 @@
import { zhCN } from "@mui/material/locale";
import { createTheme } from "@mui/material/styles";
import * as colors from "./color";
import { type Color } from "./color";
import componentStyleOverrides from "./componentStyleOverrides";
import themePalette from "./palette";
import shadows from "./shadows";
import themeTypography from "./typography";
declare module "@mui/material/styles" {
interface Palette {
neutral: Palette["primary"];
}
// allow configuration using `createTheme`
interface PaletteOptions {
neutral: PaletteOptions["primary"];
}
}
declare module "@mui/material/Button" {
interface ButtonPropsColorOverrides {
neutral: true;
}
}
export const theme = (mode: "light" | "dark") => {
const color: Color = colors[mode] as Color;
const themeOptions = {
palette: themePalette(color, mode),
shadows: shadows(color),
breakpoints: {
values: {
xs: 0,
sm: 680,
md: 900,
lg: 1200,
xl: 1536,
},
},
mixins: {
toolbar: {
minHeight: "48px",
padding: "16px",
"@media (min-width: 600px)": {
minHeight: "48px",
},
},
},
typography: themeTypography(color),
};
const themes = createTheme(themeOptions as any, zhCN);
themes.components = componentStyleOverrides(color);
return themes;
};
export default theme;

View File

@@ -1,23 +0,0 @@
import { type Color } from './color'
import { type ThemeMode } from './themeContext'
export default function themePalette(color: Color, mode: Omit<ThemeMode, 'system'>) {
return {
mode,
common: { black: '#000', white: '#fff' },
primary: color.primary,
secondary: color.secondary,
info: color.info,
success: color.success,
warning: color.warning,
error: color.error,
neutral: color.neutral,
divider: color.divider,
text: color.text,
background: color.background,
shadowColor: color.shadowColor,
charts: color.charts,
action: {
selectedOpacity: 0.1,
},
}
}

View File

@@ -1,30 +0,0 @@
import { type Color } from './color'
export default function shadows(color: Color) {
return [
`0px 12px 24px -4px ${color.shadowColor},0px 0px 2px 0px ${color.shadowColor}`,
`0px 12px 24px -4px ${color.shadowColor},0px 0px 2px 0px ${color.shadowColor}`,
`0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.12),0px 1px 5px 0px rgba(0,0,0,0.12)`,
`0px 3px 3px -2px rgba(0,0,0,0.2),0px 3px 4px 0px rgba(0,0,0,0.12),0px 1px 8px 0px rgba(0,0,0,0.12)`,
`0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.12),0px 1px 10px 0px rgba(0,0,0,0.12)`,
`0px 3px 5px -1px rgba(0,0,0,0.2),0px 5px 8px 0px rgba(0,0,0,0.12),0px 1px 14px 0px rgba(0,0,0,0.12)`,
`0px 3px 5px -1px rgba(0,0,0,0.2),0px 6px 10px 0px rgba(0,0,0,0.12),0px 1px 18px 0px rgba(0,0,0,0.12)`,
`0px 4px 5px -2px rgba(0,0,0,0.2),0px 7px 10px 1px rgba(0,0,0,0.12),0px 2px 16px 1px rgba(0,0,0,0.12)`,
`0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.12),0px 3px 14px 2px rgba(0,0,0,0.12)`,
`0px 5px 6px -3px rgba(0,0,0,0.2),0px 9px 12px 1px rgba(0,0,0,0.12),0px 3px 16px 2px rgba(0,0,0,0.12)`,
`0px 6px 6px -3px rgba(0,0,0,0.2),0px 10px 14px 1px rgba(0,0,0,0.12),0px 4px 18px 3px rgba(0,0,0,0.12)`,
`0px 6px 7px -4px rgba(0,0,0,0.2),0px 11px 15px 1px rgba(0,0,0,0.12),0px 4px 20px 3px rgba(0,0,0,0.12)`,
`0px 7px 8px -4px rgba(0,0,0,0.2),0px 12px 17px 2px rgba(0,0,0,0.12),0px 5px 22px 4px rgba(0,0,0,0.12)`,
`0px 7px 8px -4px rgba(0,0,0,0.2),0px 13px 19px 2px rgba(0,0,0,0.12),0px 5px 24px 4px rgba(0,0,0,0.12)`,
`0px 7px 9px -4px rgba(0,0,0,0.2),0px 14px 21px 2px rgba(0,0,0,0.12),0px 5px 26px 4px rgba(0,0,0,0.12)`,
`0px 8px 9px -5px rgba(0,0,0,0.2),0px 15px 22px 2px rgba(0,0,0,0.12),0px 6px 28px 5px rgba(0,0,0,0.12)`,
`0px 8px 10px -5px rgba(0,0,0,0.2),0px 16px 24px 2px rgba(0,0,0,0.12),0px 6px 30px 5px rgba(0,0,0,0.12)`,
`0px 8px 11px -5px rgba(0,0,0,0.2),0px 17px 26px 2px rgba(0,0,0,0.12),0px 6px 32px 5px rgba(0,0,0,0.12)`,
`0px 9px 11px -5px rgba(0,0,0,0.2),0px 18px 28px 2px rgba(0,0,0,0.12),0px 7px 34px 6px rgba(0,0,0,0.12)`,
`0px 9px 12px -6px rgba(0,0,0,0.2),0px 19px 29px 2px rgba(0,0,0,0.12),0px 7px 36px 6px rgba(0,0,0,0.12)`,
`0px 10px 13px -6px rgba(0,0,0,0.2),0px 20px 31px 3px rgba(0,0,0,0.12),0px 8px 38px 7px rgba(0,0,0,0.12)`,
`0px 10px 13px -6px rgba(0,0,0,0.2),0px 21px 33px 3px rgba(0,0,0,0.12),0px 8px 40px 7px rgba(0,0,0,0.12)`,
`0px 10px 14px -6px rgba(0,0,0,0.2),0px 22px 35px 3px rgba(0,0,0,0.12),0px 8px 42px 7px rgba(0,0,0,0.12)`,
`0px 11px 14px -7px rgba(0,0,0,0.2),0px 23px 36px 3px rgba(0,0,0,0.12),0px 9px 44px 8px rgba(0,0,0,0.12)`,
`0px 11px 15px -7px rgba(0,0,0,0.2),0px 24px 38px 3px rgba(0,0,0,0.12),0px 9px 46px 8px rgba(0,0,0,0.12)`,
]
}

View File

@@ -1,6 +0,0 @@
import { createContext } from 'react'
export type ThemeMode = 'dark' | 'light' | 'system'
const ThemeContext = createContext({ mode: 'dark' as ThemeMode, setThemeMode: (mode: ThemeMode) => {} })
export default ThemeContext

View File

@@ -1,8 +0,0 @@
export default function themeTypography(color: any) {
return {
fontFamily: 'inherit',
body1: {
fontSize: '14px',
},
}
}

View File

@@ -1,16 +0,0 @@
export * from "./render";
export { sampleLength, sizeLength, sampleSummary };
function sampleLength(s: string) {
const l = new Blob([s]).size;
return l > 1024 * 2 ? Math.round(l / 1024) + "KB" : l + "B";
}
function sizeLength(l: number) {
return l > 1024 * 2 ? Math.round(l / 1024) + "KB" : l + "B";
}
function sampleSummary(s: string) {
return s.split("\n").slice(0, 2).join(" ").slice(0, 60);
}

View File

@@ -1,134 +0,0 @@
import fs from "fs";
import path from "path";
import matter from "gray-matter";
import { serialize } from "next-mdx-remote/serialize";
// import prism from "remark-prism";
import slug from "remark-slug";
import remarkGfm from "remark-gfm";
import externalLinks from "remark-external-links";
const postsDir = path.join(process.cwd(), "./src/static/md/");
const fileNames = fs.readdirSync(postsDir);
export const getPostsIds = () => {
return fileNames.map((fileName) => ({
params: { id: fileName.replace(/\.md$/, "") },
}));
};
type Group = string | { title: string; order?: number };
export interface NavItem {
title: string;
group: Group;
order?: number;
id: string;
}
export interface GroupItem {
title: string;
order?: number;
list: NavItem[];
}
export const sortComparer = <
T extends { order?: number; id?: string; title: string }
>(
a: T,
b: T
) => {
return (
("order" in a && "order" in b ? a.order! - b.order! : 0) ||
("id" in a && "id" in b ? a.id!.localeCompare(b.id!) : 0) ||
(a.title ? a.title.localeCompare(b.title) : -1)
);
};
const dealWithData: (data: NavItem[]) => GroupItem[] = (data) => {
let list: GroupItem[] = [];
let cache: { [key: string]: NavItem } = {};
data.forEach((ele) => {
let groupTitle: string, groupOrder: number | undefined;
if (typeof ele.group === "object") {
groupTitle = ele.group.title;
groupOrder = ele.group.order;
} else if (typeof ele.group === "string") {
groupTitle = ele.group;
}
if (!cache[groupTitle!]) {
let group: GroupItem = {
title: groupTitle!,
list: [ele],
};
if (groupOrder) group.order = groupOrder;
list.push(group);
cache[groupTitle!] = ele;
} else {
const cur = list.find((item) => item.title === groupTitle);
if (groupOrder && cur) {
cur.order = groupOrder;
}
cur?.list.push(ele);
}
});
return list.sort(sortComparer).map((group) => ({
...group,
list: group.list.sort(sortComparer),
}));
};
export const getPostsGroup = () => {
const dataList: NavItem[] = fileNames.map((fileName) => {
// 去除文件名的md后缀使其作为文章id使用
const id = fileName.replace(/\.md$/, "");
// 获取md文件路径
const fullPath = path.join(postsDir, fileName);
// 读取md文件内容
const fileContents = fs.readFileSync(fullPath, "utf8");
// 使用matter提取md文件元数据{data:{//元数据},content:'内容'}
const matterResult = matter(fileContents);
return {
id,
...(matterResult.data as Omit<NavItem, "id">),
};
});
return dealWithData(dataList);
};
export async function getPostData(id: string) {
// 文章路径
const fullPath = path.join(postsDir, `${id}.md`);
// const toc = require("@jsdevtools/rehype-toc");
// 读取文章内容
const fileContents = fs.readFileSync(fullPath, "utf8");
// 使用matter解析markdown元数据和内容
const matterResult = await matter(fileContents);
// let tocElement;
const res = await serialize(matterResult.content, {
mdxOptions: {
remarkPlugins: [externalLinks, remarkGfm, slug],
// rehypePlugins: [
// [
// toc,
// {
// headings: ["h1", "h2", "h3", "h4"],
// customizeTOC: (tocAll: any) => {
// tocElement = tocAll;
// return false;
// },
// },
// ],
// ],
},
});
// console.log(tocElement, "tocElement--");
return { postData: res, content: matterResult.content };
}

View File

@@ -1,22 +0,0 @@
import ReactDOM, { type Root } from 'react-dom/client'
const MARK = '__ct_react_root__'
type ContainerType = (Element | DocumentFragment) & {
[MARK]?: Root
}
export function render(node: React.ReactElement, container: ContainerType) {
const root = container[MARK] || ReactDOM.createRoot(container)
root.render(node)
container[MARK] = root
}
export async function unmount(container: ContainerType) {
return Promise.resolve().then(() => {
container[MARK]?.unmount()
delete container[MARK]
})
}

View File

@@ -1,23 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}

1
homepage/type.d.ts vendored
View File

@@ -1 +0,0 @@
declare module "remark-prism";

1
lua-resty-t1k Submodule

Submodule lua-resty-t1k added at 6446166301

1
plugins Submodule

Submodule plugins added at 209e7c0e00

19
release/ipgroup/README.md Normal file
View File

@@ -0,0 +1,19 @@
# 雷池内置 IP 组
### 国家 IP 库
定期手动更新,数据来源 https://ipv4.fetus.jp/tw
### 爬虫 IP 库
##### cloudflare
官方 https://www.cloudflare.com/ips-v4
##### 360
http://www.so.com/help/spider_ip.html
##### 百度
没有爬虫 IP 池,官方推荐的判断方法 https://ziyuan.baidu.com/college/articleinfo?id=1198

View File

@@ -0,0 +1,26 @@
# http://www.so.com/help/spider_ip.html
180.153.232.0/24
180.153.234.0/24
180.153.236.0/24
180.163.220.0/24
42.236.101.0/24
42.236.102.0/24
42.236.103.0/24
42.236.10.0/24
42.236.12.0/24
42.236.13.0/24
42.236.14.0/24
42.236.15.0/24
42.236.16.0/24
42.236.17.0/24
42.236.46.0/24
42.236.48.0/24
42.236.49.0/24
42.236.50.0/24
42.236.51.0/24
42.236.52.0/24
42.236.53.0/24
42.236.54.0/24
42.236.55.0/24
42.236.99.0/24

View File

@@ -0,0 +1,17 @@
# sync from https://www.cloudflare.com/ips-v4
173.245.48.0/20
103.21.244.0/22
103.22.200.0/22
103.31.4.0/22
141.101.64.0/18
108.162.192.0/18
190.93.240.0/20
188.114.96.0/20
197.234.240.0/22
198.41.128.0/17
162.158.0.0/15
104.16.0.0/13
104.24.0.0/14
172.64.0.0/13
131.0.72.0/22

6163
release/ipgroup/geo/cn.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -30,11 +30,11 @@ services:
redis:
container_name: safeline-redis
restart: always
image: redis:7.0.11
image: redis:7.0.10
volumes:
- ${SAFELINE_DIR}/resources/redis/data:/data
- /etc/localtime:/etc/localtime:ro
command: redis-server --appendonly yes --requirepass ${POSTGRES_PASSWORD}
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
networks:
safeline-ce:
ipv4_address: ${SUBNET_PREFIX}.3
@@ -56,8 +56,18 @@ services:
environment:
- MANAGEMENT_RESOURCES_DIR=/resources/management
- NGINX_RESOURCES_DIR=/resources/nginx
- DATABASE_URL=postgres://safeline-ce:${POSTGRES_PASSWORD}@127.0.0.1/safeline-ce
- DATABASE_URL=postgres://safeline-ce:${POSTGRES_PASSWORD}@safeline-postgres/safeline-ce
- MARIO_URL=http://safeline-mario:3335
- FVM_MANAGER_URL=safeline-fvm-manager:9004
- REDIS_URL=redis://:${REDIS_PASSWORD}@safeline-redis:6379/0
- MANAGEMENT_LOGS_DIR=/logs/management
dns:
- 119.29.29.29
- 223.5.5.5
- 180.76.76.76
- 1.2.4.8
- 114.114.114.114
- 8.8.8.8
networks:
safeline-ce:
ipv4_address: ${SUBNET_PREFIX}.4
@@ -90,7 +100,7 @@ services:
- LOG_DIR=/logs/mario
- GOGC=100
- DATABASE_URL=postgres://safeline-ce:${POSTGRES_PASSWORD}@safeline-postgres/safeline-ce
- REDIS_URL=redis://:${POSTGRES_PASSWORD}@safeline-redis:6379/0
- REDIS_URL=redis://:${REDIS_PASSWORD}@safeline-redis:6379/0
networks:
safeline-ce:
ipv4_address: ${SUBNET_PREFIX}.6
@@ -109,7 +119,23 @@ services:
- ${SAFELINE_DIR}/resources/cache:/usr/local/nginx/cache
- /etc/resolv.conf:/etc/resolv.conf
environment:
- REDIS_URL=redis://:${REDIS_PASSWORD}@${SUBNET_PREFIX}.3:6379/0
- MGT_ADDR=${SUBNET_PREFIX}.4:9002
ulimits:
nofile: 131072
network_mode: host
network_mode: host
fvm-manager:
container_name: safeline-fvm-manager
restart: always
image: chaitin/safeline-fvm-manager:${IMAGE_TAG}
environment:
- FVM_LOGS_DIR=/logs/management
- DETECTOR_URL=http://safeline-detector:8001
volumes:
- /etc/localtime:/etc/localtime:ro
- ${SAFELINE_DIR}/logs:/logs
networks:
safeline-ce:
ipv4_address: ${SUBNET_PREFIX}.8
cap_drop:
- net_raw

1578
release/latest/seccomp.json Normal file

File diff suppressed because it is too large Load Diff

223
release/latest/setup.sh Executable file
View File

@@ -0,0 +1,223 @@
#!/bin/bash
echo "
____ __ _ _
/ ___| __ _ / _| ___ | | (_) _ __ ___
\___ \ / _\` | | |_ / _ \ | | | | | '_ \ / _ \\
___) | | (_| | | _| | __/ | |___ | | | | | | | __/
|____/ \__,_| |_| \___| |_____| |_| |_| |_| \___|
"
qrcode() {
echo "█████████████████████████████████████████"
echo "█████████████████████████████████████████"
echo "████ ▄▄▄▄▄ █▀ █▀▀██▀▄▀▀▄▀▄▀▄██ ▄▄▄▄▄ ████"
echo "████ █ █ █▀ ▄ █▀▄▄▀▀ ▄█▄ ▀█ █ █ ████"
echo "████ █▄▄▄█ █▀█ █▄█▄▀▀▄▀▄ ▀▀▄▄█ █▄▄▄█ ████"
echo "████▄▄▄▄▄▄▄█▄█▄█ █▄▀ █ ▀▄▀ █▄█▄▄▄▄▄▄▄████"
echo "████▄ ▄▄ █▄▄ ▄█▄▄▄▄▀▄▀▀▄██ ▄▄▀▄█▄▀ ▀████"
echo "████▄ ▄▀▄ ▄▀▄ ▀ ▄█▀ ▀▄ █▀▀ ▀█▀▄██▄▀▄█████"
echo "█████ ▀▄█ ▄ ▄▄▀▄▀▀█▄▀▄▄▀▄▀▄ ▄ ▀▄▄▄█▀▀████"
echo "████ █▀▄▀ ▄▀▄▄▀█▀ ▄▄ █▄█▀▀▄▀▀█▄█▄█▀▄█████"
echo "████ █ ▀ ▄▀▀ ██▄█▄▄▄▄▄▀▄▀▀▀▄▄▀█▄▀█ ▀████"
echo "████ █ ▀▄ ▄██▀▀ ▄█▀ ▀███▄ ▀▄▀▄▄ ▄▀▄█████"
echo "████▀▄▄█ ▄▀▄▀ ▄▀▀▀▄▀▄▀ ▄▀▄ ▄▀ ▄▀█ ▀████"
echo "████ █ █ █▄▀ █▄█▀ ▄▄███▀▀▀▄█▀▄ ▀ ▀▄█████"
echo "████▄███▄█▄▄▀▄ █▄█▄▄▄▄▀▀▄█▀▀ ▄▄▄ ▀█ ████"
echo "████ ▄▄▄▄▄ █▄▀█ ▄█▀▄ █▀█▄ ▀ █▄█ ▀▄▀████"
echo "████ █ █ █ █▄▀▀▀▄▄▄▀▀▀▀▀▀ ▄▄ ▀█ ████"
echo "████ █▄▄▄█ █ ▀█▀ ▄▄▄▄ ▀█ ▀▀▄▀ ▀▀ ▀██████"
echo "████▄▄▄▄▄▄▄█▄▄██▄█▄▄█▄██▄██▄▄█▄▄█▄█▄█████"
echo "█████████████████████████████████████████"
echo "█████████████████████████████████████████"
echo
echo "微信扫描上方二维码加入雷池项目讨论组"
}
command_exists() {
command -v "$1" 2>&1
}
space_left() {
dir="$1"
while [ ! -d "$dir" ]; do
dir=`dirname "$dir"`;
done
echo `df -h "$dir" --output='avail' | tail -n 1`
}
start_docker() {
systemctl start docker && systemctl enable docker
}
confirm() {
echo -e -n "\033[34m[SafeLine] $* \033[1;36m(Y/n)\033[0m"
read -n 1 -s opt
[[ "$opt" == $'\n' ]] || echo
case "$opt" in
'y' | 'Y' ) return 0;;
'n' | 'N' ) return 1;;
*) confirm "$1";;
esac
}
info() {
echo -e "\033[37m[SafeLine] $*\033[0m"
}
warning() {
echo -e "\033[33m[SafeLine] $*\033[0m"
}
abort() {
qrcode
echo -e "\033[31m[SafeLine] $*\033[0m"
exit 1
}
trap 'onexit' INT
onexit() {
echo
abort "用户手动结束安装"
}
# CPU ssse3 指令集检查
support_ssse3=1
lscpu | grep ssse3 > /dev/null 2>&1
if [ $? -ne "0" ]; then
echo "not found info in lscpu"
support_ssse3=0
fi
cat /proc/cpuinfo | grep ssse3 > /dev/null 2>&1
if [ $support_ssse3 -eq "0" -a $? -ne "0" ]; then
abort "雷池需要运行在支持 ssse3 指令集的 CPU 上,虚拟机请自行配置开启 CPU ssse3 指令集支持"
fi
safeline_path='/data/safeline'
if [ -z "$BASH" ]; then
abort "请用 bash 执行本脚本,请参考最新的官方技术文档 https://waf-ce.chaitin.cn/"
fi
if [ ! -t 0 ]; then
abort "STDIN 不是标准的输入设备,请参考最新的官方技术文档 https://waf-ce.chaitin.cn/"
fi
if [ "$#" -ne "0" ]; then
abort "当前脚本无需任何参数,请参考最新的官方技术文档 https://waf-ce.chaitin.cn/"
fi
if [ "$EUID" -ne "0" ]; then
abort "请以 root 权限运行"
fi
info "脚本调用方式确认正常"
if [ -z `command_exists docker` ]; then
warning "缺少 Docker 环境"
if confirm "是否需要自动安装 Docker"; then
curl -sSLk https://get.docker.com/ | bash
if [ $? -ne "0" ]; then
abort "Docker 安装失败"
fi
info "Docker 安装完成"
else
abort "中止安装"
fi
fi
info "发现 Docker 环境: '`command -v docker`'"
start_docker
docker version > /dev/null 2>&1
if [ $? -ne "0" ]; then
abort "Docker 服务工作异常"
fi
info "Docker 工作状态正常"
compose_command="docker compose"
if $compose_command version; then
info "发现 Docker Compose Plugin"
else
warning "未发现 Docker Compose Plugin"
compose_command="docker-compose"
if [ -z `command_exists "docker-compose"` ]; then
warning "未发现 docker-compose 组件"
if confirm "是否需要自动安装 Docker Compose Plugin"; then
curl -sSLk https://get.docker.com/ | bash
if [ $? -ne "0" ]; then
abort "Docker Compose Plugin 安装失败"
fi
info "Docker Compose Plugin 安装完成"
compose_command="docker compose"
else
abort "中止安装"
fi
else
info "发现 docker-compose 组件: '`command -v docker-compose`'"
fi
fi
while true; do
echo -e -n "\033[34m[SafeLine] 雷池安装目录 (留空则为 '$safeline_path'): \033[0m"
read input_path
[[ -z "$input_path" ]] && input_path=$safeline_path
if [[ ! $input_path == /* ]]; then
warning "'$input_path' 不是合法的绝对路径"
continue
fi
if [ -f "$input_path" ] || [ -d "$input_path" ]; then
warning "'$input_path' 路径已经存在,请换一个"
continue
fi
safeline_path=$input_path
if confirm "目录 '$safeline_path' 当前剩余存储空间为 `space_left \"$safeline_path\"` ,雷池至少需要 5G是否确定"; then
break
fi
done
mkdir -p "$safeline_path"
if [ $? -ne "0" ]; then
abort "创建安装目录 '$safeline_path' 失败"
fi
info "创建安装目录 '$safeline_path' 成功"
cd "$safeline_path"
curl -sS -k "https://waf-ce.chaitin.cn/release/latest/compose.yaml" -o compose.yaml
if [ $? -ne "0" ]; then
abort "下载 compose.yaml 脚本失败"
fi
info "下载 compose.yaml 脚本成功"
touch ".env"
if [ $? -ne "0" ]; then
abort "创建 .env 脚本失败"
fi
info "创建 .env 脚本成功"
echo "SAFELINE_DIR=$safeline_path" >> .env
echo "IMAGE_TAG=latest" >> .env
echo "MGT_PORT=9443" >> .env
echo "POSTGRES_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 </dev/urandom | head -c 32)" >> .env
echo "REDIS_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 </dev/urandom | head -c 32)" >> .env
echo "SUBNET_PREFIX=172.22.222" >> .env
info "即将开始下载 Docker 镜像"
$compose_command up -d
if [ $? -ne "0" ]; then
abort "启动 Docker 容器失败"
fi
qrcode
warning "雷池 WAF 社区版安装成功,请访问以下地址访问控制台"
warning "https://0.0.0.0:9443/"

233
release/latest/upgrade.sh Executable file
View File

@@ -0,0 +1,233 @@
#! /bin/bash
echo "
____ __ _ _
/ ___| __ _ / _| ___ | | (_) _ __ ___
\___ \ / _\` | | |_ / _ \ | | | | | '_ \ / _ \\
___) | | (_| | | _| | __/ | |___ | | | | | | | __/
|____/ \__,_| |_| \___| |_____| |_| |_| |_| \___|
"
echo $1
qrcode() {
echo
echo "█████████████████████████████████████████"
echo "█████████████████████████████████████████"
echo "████ ▄▄▄▄▄ █▀ █▀▀██▀▄▀▀▄▀▄▀▄██ ▄▄▄▄▄ ████"
echo "████ █ █ █▀ ▄ █▀▄▄▀▀ ▄█▄ ▀█ █ █ ████"
echo "████ █▄▄▄█ █▀█ █▄█▄▀▀▄▀▄ ▀▀▄▄█ █▄▄▄█ ████"
echo "████▄▄▄▄▄▄▄█▄█▄█ █▄▀ █ ▀▄▀ █▄█▄▄▄▄▄▄▄████"
echo "████▄ ▄▄ █▄▄ ▄█▄▄▄▄▀▄▀▀▄██ ▄▄▀▄█▄▀ ▀████"
echo "████▄ ▄▀▄ ▄▀▄ ▀ ▄█▀ ▀▄ █▀▀ ▀█▀▄██▄▀▄█████"
echo "█████ ▀▄█ ▄ ▄▄▀▄▀▀█▄▀▄▄▀▄▀▄ ▄ ▀▄▄▄█▀▀████"
echo "████ █▀▄▀ ▄▀▄▄▀█▀ ▄▄ █▄█▀▀▄▀▀█▄█▄█▀▄█████"
echo "████ █ ▀ ▄▀▀ ██▄█▄▄▄▄▄▀▄▀▀▀▄▄▀█▄▀█ ▀████"
echo "████ █ ▀▄ ▄██▀▀ ▄█▀ ▀███▄ ▀▄▀▄▄ ▄▀▄█████"
echo "████▀▄▄█ ▄▀▄▀ ▄▀▀▀▄▀▄▀ ▄▀▄ ▄▀ ▄▀█ ▀████"
echo "████ █ █ █▄▀ █▄█▀ ▄▄███▀▀▀▄█▀▄ ▀ ▀▄█████"
echo "████▄███▄█▄▄▀▄ █▄█▄▄▄▄▀▀▄█▀▀ ▄▄▄ ▀█ ████"
echo "████ ▄▄▄▄▄ █▄▀█ ▄█▀▄ █▀█▄ ▀ █▄█ ▀▄▀████"
echo "████ █ █ █ █▄▀▀▀▄▄▄▀▀▀▀▀▀ ▄▄ ▀█ ████"
echo "████ █▄▄▄█ █ ▀█▀ ▄▄▄▄ ▀█ ▀▀▄▀ ▀▀ ▀██████"
echo "████▄▄▄▄▄▄▄█▄▄██▄█▄▄█▄██▄██▄▄█▄▄█▄█▄█████"
echo "█████████████████████████████████████████"
echo "█████████████████████████████████████████"
echo
echo "微信扫描上方二维码加入雷池项目讨论组"
}
command_exists() {
command -v "$1" 2>&1
}
space_left() {
dir="$1"
while [ ! -d "$dir" ]; do
dir=`dirname "$dir"`;
done
echo `df -h "$dir" --output='avail' | tail -n 1`
}
confirm() {
echo -e -n "\033[34m[SafeLine] $* \033[1;36m(Y/n)\033[0m"
read -n 1 -s opt
[[ "$opt" == $'\n' ]] || echo
case "$opt" in
'y' | 'Y' ) return 0;;
'n' | 'N' ) return 1;;
*) confirm "$1";;
esac
}
info() {
echo -e "\033[37m[SafeLine] $*\033[0m"
}
warning() {
echo -e "\033[33m[SafeLine] $*\033[0m"
}
abort() {
qrcode
echo -e "\033[31m[SafeLine] $*\033[0m"
exit 1
}
trap 'onexit' INT
onexit() {
echo
abort "用户手动结束升级"
}
# CPU ssse3 指令集检查
support_ssse3=1
lscpu | grep ssse3 > /dev/null 2>&1
if [ $? -ne "0" ]; then
echo "not found info in lscpu"
support_ssse3=0
fi
cat /proc/cpuinfo | grep ssse3 > /dev/null 2>&1
if [ $support_ssse3 -eq "0" -a $? -ne "0" ]; then
abort "雷池需要运行在支持 ssse3 指令集的 CPU 上,虚拟机请自行配置开启 CPU ssse3 指令集支持"
fi
if [ -z "$BASH" ]; then
abort "请用 bash 执行本脚本, 请参考最新的官方技术文档 https://waf-ce.chaitin.cn/"
fi
if [ ! -t 0 ]; then
abort "STDIN 不是标准的输入设备, 请参考最新的官方技术文档 https://waf-ce.chaitin.cn/"
fi
if [ "$#" -ne "0" ]; then
abort "当前脚本无需任何参数, 请参考最新的官方技术文档 https://waf-ce.chaitin.cn/"
fi
if [ "$EUID" -ne "0" ]; then
abort "请以 root 权限运行"
fi
info "脚本调用方式确认正常"
if [ -z `command_exists docker` ]; then
warning "缺少 Docker 环境"
if confirm "是否需要自动安装 Docker"; then
curl -sSLk https://get.docker.com/ | bash
if [ $? -ne "0" ]; then
abort "Docker 安装失败"
fi
info "Docker 安装完成"
else
abort "中止安装"
fi
fi
info "发现 Docker 环境: '`command -v docker`'"
docker version > /dev/null 2>&1
if [ $? -ne "0" ]; then
abort "Docker 服务工作异常"
fi
info "Docker 工作状态正常"
compose_command="docker compose"
if $compose_command version; then
info "发现 Docker Compose Plugin"
else
warning "未发现 Docker Compose Plugin"
compose_command="docker-compose"
if [ -z `command_exists "docker-compose"` ]; then
warning "未发现 docker-compose 组件"
if confirm "是否需要自动安装 Docker Compose Plugin"; then
curl -sSLk https://get.docker.com/ | bash
if [ $? -ne "0" ]; then
abort "Docker Compose Plugin 安装失败"
fi
info "Docker Compose Plugin 安装完成"
compose_command="docker compose"
else
abort "中止安装"
fi
else
info "发现 docker-compose 组件: '`command -v docker-compose`'"
fi
fi
container_id=`docker ps --filter ancestor=chaitin/safeline-mgt-api --format '{{.ID}}'`
mount_path=`docker inspect --format '{{range .Mounts}}{{if eq .Destination "/logs"}}{{.Source}}{{end}}{{end}}' $container_id`
safeline_path=`dirname $mount_path`
while [ -z "$safeline_path" ]; do
echo -e -n "\033[34m[SafeLine] 未发现正在运行的雷池,请输入雷池安装路径 (留空则为 '`pwd`'): \033[0m"
read input_path
[[ -z "$input_path" ]] && input_path=`pwd`
if [[ ! $input_path == /* ]]; then
warning "'$input_path' 不是合法的绝对路径"
continue
fi
safeline_path=$input_path
done
cd "$safeline_path"
grep COLLIE .env > /dev/null 2>&1
if [ $? -eq "0" ]; then
abort "检测到你的环境通过牧云主机助手安装,请使用牧云主机助手-应用市场进行升级."
fi
compose_name=`ls docker-compose.yaml compose.yaml 2>/dev/null`
compose_path=$safeline_path/$compose_name
if [ -f "$compose_path" ]; then
info "发现位于 '$safeline_path' 的雷池环境"
else
abort "没有发现位于 $safeline_path 的雷池环境"
fi
mv $compose_name $compose_name.old
curl "https://waf-ce.chaitin.cn/release/latest/compose.yaml" -sSLk -o $compose_name
if [ $? -ne "0" ]; then
abort "下载 compose.yaml 脚本失败"
fi
info "下载 compose.yaml 脚本成功"
sed -i "s/IMAGE_TAG=.*/IMAGE_TAG=latest/g" ".env"
grep "SAFELINE_DIR" ".env" > /dev/null || echo "SAFELINE_DIR=$(pwd)" >> ".env"
grep "IMAGE_TAG" ".env" > /dev/null || echo "IMAGE_TAG=latest" >> ".env"
grep "MGT_PORT" ".env" > /dev/null || echo "MGT_PORT=9443" >> ".env"
grep "POSTGRES_PASSWORD" ".env" > /dev/null || echo "POSTGRES_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 </dev/urandom | head -c 32)" >> ".env"
grep "REDIS_PASSWORD" ".env" > /dev/null || echo "REDIS_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 </dev/urandom | head -c 32)" >> ".env"
grep "SUBNET_PREFIX" ".env" > /dev/null || echo "SUBNET_PREFIX=172.22.222" >> ".env"
info "升级 .env 脚本成功"
info "即将开始下载新版本 Docker 镜像"
$compose_command pull
if [ $? -ne "0" ]; then
abort "下载新版本 Docker 镜像失败"
fi
info "下载新版本 Docker 镜像成功"
info "即将开始替换 Docker 容器"
$compose_command down && $compose_command up -d
if [ $? -ne "0" ]; then
abort "替换 Docker 容器失败"
fi
info "雷池升级成功"
qrcode
warning "雷池 WAF 社区版安装成功, 请访问以下地址访问控制台"
warning "https://0.0.0.0:9443/"

View File

@@ -0,0 +1,4 @@
{
"latest_version": "v3.13.2",
"rec_version": "v3.8.2"
}

View File

@@ -1,46 +0,0 @@
#! /bin/bash
set -eE
abort()
{
echo $1
exit 1
}
echo "
____ __ _ _
/ ___| __ _ / _| ___ | | (_) _ __ ___
\___ \ / _\` | | |_ / _ \ | | | | | '_ \ / _ \\
___) | | (_| | | _| | __/ | |___ | | | | | | | __/
|____/ \__,_| |_| \___| |_____| |_| |_| |_| \___|
"
if [[ "$#" -ne "0" ]]; then
echo "Usage: run "$0" to set up Safeline CE at current working directory."
exit 0
fi
command -v docker > /dev/null || abort "docker not found, unable to deploy"
compose_plugin=true
compose_command="docker compose"
docker --help | grep compose | grep v2 > /dev/null || compose_plugin=false || compose_command="docker-compose"
if [[ "x${compose_plugin}" = "xfalse" ]]; then
command -v docker-compose > /dev/null && docker-compose --version | grep v2 > /dev/null || abort "docker compose v2 not found, unable to deploy"
fi
COMPOSE_YAML="compose.yaml"
wget https://waf-ce.chaitin.cn/release/latest/compose.yaml --no-check-certificate -O ${COMPOSE_YAML}
ENV_FILE=".env"
if [[ ! -f ${ENV_FILE} ]]; then
echo "SAFELINE_DIR=$(pwd)" >> .env
echo "IMAGE_TAG=latest" >> .env
echo "MGT_PORT=9443" >> .env
echo "POSTGRES_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 </dev/urandom | head -c 32)" >> .env
echo "SUBNET_PREFIX=169.254.0" >> .env
fi
echo "Setup success!"
echo "Run '$compose_command up -d' to start SafeLine."
echo "And then visit https://<SafeLine-IP>:9443."

View File

@@ -1,42 +0,0 @@
#! /bin/bash
set -eE
abort()
{
echo $1
exit 1
}
echo "
____ __ _ _
/ ___| __ _ / _| ___ | | (_) _ __ ___
\___ \ / _\` | | |_ / _ \ | | | | | '_ \ / _ \\
___) | | (_| | | _| | __/ | |___ | | | | | | | __/
|____/ \__,_| |_| \___| |_____| |_| |_| |_| \___|
"
if [[ "$#" -ne "0" ]]; then
echo "Usage: run "$0" to set up Safeline CE at current working directory."
exit 0
fi
command -v docker > /dev/null || abort "docker not found, unable to deploy"
compose_plugin=true
compose_command="docker compose"
docker --help | grep compose | grep v2 > /dev/null || compose_plugin=false || compose_command="docker-compose"
if [[ "x${compose_plugin}" = "xfalse" ]]; then
command -v docker-compose > /dev/null && docker-compose --version | grep v2 > /dev/null || abort "docker compose v2 not found, unable to deploy"
fi
COMPOSE_YAML="compose.yaml"
wget https://waf-ce.chaitin.cn/release/latest/compose.yaml --no-check-certificate -O ${COMPOSE_YAML}
ENV_FILE=".env"
sed -i "s/IMAGE_TAG=.*/IMAGE_TAG=latest/g" ${ENV_FILE}
grep "SAFELINE_DIR" ${ENV_FILE} > /dev/null || echo "SAFELINE_DIR=$(pwd)" >> ${ENV_FILE}
grep "SUBNET_PREFIX" ${ENV_FILE} > /dev/null || echo "SUBNET_PREFIX=169.254.0" >> ${ENV_FILE}
$compose_command pull && $compose_command down && $compose_command up -d
echo "Upgrade success!"

View File

@@ -1,4 +0,0 @@
{
"latest_version": "v1.8.1",
"rec_version": "v1.7.1"
}

Some files were not shown because too many files have changed in this diff Show More