Compare commits

...
109 Commits
Author SHA1 Message Date
writegr a5fdff61ff chore: fix some typos (#4564)
Signed-off-by: writegr <wellweek@outlook.com>
2024-04-18 12:24:40 +08:00
zhengkunwang 4832081b82 fix: 解决文件上传权限错误的问题 (#4563) 2024-04-18 03:18:07 +00:00
ssongliu ef5a13f87f fix: 解决本地备份账号路径获取错误的问题 (#4560) 2024-04-18 02:36:06 +00:00
老广 e2bc8e800a docs: add projects to other readme (#4561) 2024-04-18 10:26:00 +08:00
老广 85a397949e Update README.md
Add our other projects
2024-04-17 17:08:35 +08:00
ssongliu 5cfdcedf9a fix: 解决容器日志缺失的问题 (#4549) 2024-04-17 08:52:07 +00:00
ssongliu c5bb8dab8c fix: 解决复制导致的快照失败问题 (#4547) 2024-04-17 07:28:07 +00:00
zhengkunwang f1421ba7f9 style: 修改文件编辑器配置样式 (#4535) 2024-04-16 18:59:30 +08:00
ssongliu 9e44db53a7 pref: 调整部分界面的高度问题 (#4534) 2024-04-16 18:59:14 +08:00
zhengkunwang 4814a76c47 style: 修改 openresty 的端口提示 (#4532) 2024-04-16 15:58:51 +08:00
ssongliu 2ec4b2561c feat: 修改服务初始化操作逻辑 (#4530) 2024-04-16 14:44:07 +08:00
wanghe 4efe7240ad Update tyops-check.yml 2024-04-16 13:57:03 +08:00
ssongliu ed13136221 feat: 增加许可证解绑功能 (#4522) 2024-04-15 18:37:05 +08:00
ssongliu 735fc75e35 feat: 登陆时加载许可证状态 (#4520) 2024-04-15 18:06:38 +08:00
xuwei-fit2cloud b8a52ae707 chore: 添加拼写检查Action 2024-04-15 17:58:36 +08:00
John Bro 2501a9f78a fix: 修复容器未指定 IP 编辑显示报错问题 (#4519) 2024-04-15 07:12:10 +00:00
Langel 5a8d6db43e feat: 增加菜单标签页功能 (#3267) (#4510) 2024-04-15 15:10:24 +08:00
ssongliu a3312331d2 feat: 解决登录页授权 IP 跳转失败的问题 (#4517) 2024-04-15 07:10:10 +00:00
zhengkunwang fbd0e836d7 fix:解决新建文件夹部分权限无法创建的问题 (#4515) 2024-04-15 07:08:10 +00:00
Craftsman 4935d88301 typos: Modify wrong words (#4518) 2024-04-15 15:05:00 +08:00
zhengkunwang 8625979cc3 feat: 修改 supervisor 名称限制 (#4513) 2024-04-15 03:56:10 +00:00
zhengkunwang c77742e72e fix: 解决安装应用时候,原始 docker-compose.yml 的 deploy 字段下内容会被自动覆写的问题 (#4512)
Refs https://github.com/1Panel-dev/1Panel/issues/4340
2024-04-15 03:54:09 +00:00
John Bro 43a6b4b735 feat: 容器创建支持指定 IP 地址 (#4489)
#### What this PR does / why we need it?

#### Summary of your change

#### Please indicate you've done the following:

- [ ] Made sure tests are passing and test coverage is added if needed.
- [ ] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/).
- [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.
2024-04-13 11:56:07 +00:00
mobeicanyue f4ee534101 fix typos (#4503) 2024-04-13 19:49:17 +08:00
ssongliu c055a07e57 fix: 解决概览页 CPU 核心过多导致的显示问题 (#4490)
Refs #3966
2024-04-13 11:44:07 +00:00
ssongliu 62bead5c50 fix: 修改登录页跳转问题 (#4487) 2024-04-12 08:20:07 +00:00
zhengkunwang 9edafc13a3 feat: 修改中国地区名称 (#4485) 2024-04-12 04:30:07 +00:00
zhengkunwang e6ccf8be1f fix: 解决文件搜索目录包含回收站目录能进入的问题 (#4484) 2024-04-12 04:08:06 +00:00
ssongliu 222089d56a fix: 修改系统版本比较方法 (#4483) 2024-04-12 03:04:06 +00:00
zhengkunwang 96e48847d0 fix: 解决特殊字符下文件放入回收站失败的问题 (#4480) 2024-04-11 11:08:11 +00:00
zhengkunwang 38b0c42555 feat: 增加回收站文件夹限制 (#4479) 2024-04-11 11:06:10 +00:00
zhengkunwang 2eae8274f6 fix: 创建文件增加非法字符校验 (#4478) 2024-04-11 10:32:11 +00:00
ssongliu 0de79e537e fix: 修改高级功能菜单 LOGO (#4477) 2024-04-11 10:30:11 +00:00
zhengkunwang e37b87d63e fix: 解决安装应用时 deploy 字段被覆盖的问题 (#4476) 2024-04-11 10:28:11 +00:00
ssongliu 37a0329d4a fix: 解决登录页跳转错误的问题 (#4474) 2024-04-11 09:16:10 +00:00
ssongliu e037b69f52 fix: 解决登录页跳转错误的问题 (#4470) 2024-04-11 15:53:22 +08:00
zhengkunwang 34498392dc style(waf): 修改网站图标位置 (#4469) 2024-04-11 07:00:13 +00:00
ssongliu 1687b99526 feat: 增加 GPU 监控 (#4468) 2024-04-11 06:16:10 +00:00
ssongliu 0bf6db1cf8 fix: 解决僵尸进程的问题 (#4464) 2024-04-10 14:18:08 +00:00
ssongliu 0cd06803e2 fix: 监控数据迁移增加数据长度判断 (#4454) 2024-04-10 06:06:08 +00:00
guangwu 45f6a415de fix: close resource (#4456) 2024-04-10 14:05:07 +08:00
John Bro 3e3f0d9452 feat: 未认证设置状态下系统跳转页面功能实现 (#4444)
#### What this PR does / why we need it?

#### Summary of your change

#### Please indicate you've done the following:

- [ ] Made sure tests are passing and test coverage is added if needed.
- [ ] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/).
- [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.
2024-04-09 14:46:09 +00:00
zhengkunwang 35785f1e40 feat: 增加文件修改权限的超时时间 (#4448)
Refs https://github.com/1Panel-dev/1Panel/issues/4291
2024-04-09 09:34:09 +00:00
zhengkunwang 437d6eb0fd feat: 网站名称支持带端口 (#4446)
Refs https://github.com/1Panel-dev/1Panel/issues/3726
2024-04-09 09:32:10 +00:00
zhengkunwang 1e2c85e771 feat: 文本编辑器记住上次设置 (#4445)
Refs https://github.com/1Panel-dev/1Panel/issues/4397
Refs https://github.com/1Panel-dev/1Panel/issues/4266
2024-04-09 09:30:09 +00:00
zhengkunwang ef075df3fe feat: 进程守护名称支持-_等字符 (#4442)
Refs https://github.com/1Panel-dev/1Panel/issues/4303
2024-04-09 08:38:09 +00:00
zhengkunwang 1e22769c8b feat: 文件上传权限优化 (#4441)
Refs https://github.com/1Panel-dev/1Panel/issues/4362
2024-04-09 08:36:09 +00:00
zhengkunwang 0751326b46 feat: 优化文件创建 (#4440) 2024-04-09 07:34:08 +00:00
zhengkunwang db4973cfde fix: 解决读取 block 文件报错的问题 (#4439) 2024-04-09 06:28:09 +00:00
zhengkunwang 0b47d692b8 fix: 解决 upstream 配置报错的问题 (#4438)
Refs https://github.com/1Panel-dev/1Panel/issues/4258
2024-04-09 06:16:09 +00:00
zhengkunwang 672ef66be8 fix: 解决 docker-compose 文件错误导致的异常 (#4431) 2024-04-08 09:54:07 +00:00
ssongliu 7ab005540b fix: 切换菜单设置接口 (#4429) 2024-04-08 09:48:08 +00:00
clonefetch 7c928735cd chore: remove repetitive word (#4430)
Signed-off-by: clonefetch <c0217@outlook.com>
2024-04-08 17:47:17 +08:00
zhengkunwang 9ec1610f34 feat: 增加一些翻译 (#4428) 2024-04-08 09:06:08 +00:00
ssongliu 4f2a340212 fix: 修改监控相关接口 (#4427) 2024-04-08 08:52:07 +00:00
ssongliu e69fd3b388 pref: 优化 OSS 连接检测错误信息 (#4426) 2024-04-08 06:44:07 +00:00
ssongliu 6991c773da feat: 监控数据使用独立数据库 (#4424) 2024-04-08 05:48:07 +00:00
ssongliu 9b88979b69 fix: 解决替换根目录失败的问题 (#4420) 2024-04-07 23:21:15 +08:00
ssongliu 7c9608727d fix: 解决升级失败的问题 (#4419) 2024-04-07 14:09:46 +00:00
ssongliu 62828c464e fix: 解决文件保存失败一直处于加载中的问题 (#4418) 2024-04-07 21:38:59 +08:00
ssongliu f1ed051135 feat: 增加概览页跳转方式 (#4417) 2024-04-07 09:29:46 +00:00
zhengkunwang 33a0c2ba30 feat: 删除网站适配防篡改 (#4415) 2024-04-07 09:25:46 +00:00
ssongliu 494da3c209 fix: 修改 xpack 依赖 (#4414) 2024-04-07 08:29:46 +00:00
wanghe 646fc4e678 Update .gitattributes 2024-04-07 11:59:42 +08:00
ssongliu cdbe24a523 fix: 修改升级等过程中复制方式 (#4402) 2024-04-06 14:32:10 +00:00
maninhill 10012c6148 chore:更新 README 2024-04-04 08:28:43 +08:00
zhengkunwang bb4fd69f3a fix: 解决没有 xpack 打包报错的问题 (#4400) 2024-04-03 09:40:07 +00:00
John Broandzhoujunhong 6ff0f14841 fix: 专业版菜单选择显示前端优化 (#4399)
Co-authored-by: zhoujunhong <1298308460@qq.com>
2024-04-03 17:27:55 +08:00
ssongliu 1088034a5c feat: 计划任务容器中执行增加 Command 选项 (#4398)
Refs #4363
2024-04-03 08:50:07 +00:00
zhengkunwang 8a011b1cf9 feat: 优化文件上传体验 (#4396) 2024-04-03 08:40:07 +00:00
Node e3eebc938a 提升文件上传体验 (#4393)
* 上传文件支持覆盖被占用的文件且上传失败时不影响原文件,增加强制覆盖选项

* 原文件存在时,保持同样的文件权限

* 制表符更新
2024-04-03 14:37:22 +08:00
John Bro 08da7802c6 feat: 专业版菜单隐藏控制功能实现 (#4392) 2024-04-03 14:11:12 +08:00
ssongliu 79ca1b4d6b pref: 专业版界面增加图标显示 (#4391) 2024-04-02 09:16:46 +00:00
ssongliu 47119e508b fix: 解决容器挂载卷回显失败的问题 (#4389)
Refs #4387
2024-04-02 09:14:45 +00:00
ssongliu 13bb5e0d30 pref: 优化界面设置提示信息 (#4382) 2024-04-01 10:52:06 +00:00
zhengkunwang 218c165c26 feat: 删除部分 .gitignore (#4380) 2024-04-01 09:52:07 +00:00
zhengkunwang d6006d34c0 feat: 修改 WAF 专业版提示 (#4377) 2024-04-01 08:38:08 +00:00
ssongliu 810ea03ac1 pref: 优化 Xpack 错误信息 (#4376) 2024-04-01 08:28:07 +00:00
ssongliu e046315616 pref: 修改描述信息 (#4375) 2024-04-01 08:00:08 +00:00
zhengkunwang 0a7f1eb286 fix: 处理时序攻击漏洞 (#4373) 2024-04-01 07:52:07 +00:00
wanghe-fit2cloud b0411b2df6 feat: 增加构建标签 2024-04-01 15:22:51 +08:00
ssongliu 471b7d9657 style: 调整 Logo 样式 (#4357) 2024-03-29 09:24:07 +00:00
ssongliu 1527c63d37 feat: 同步数据库中界面设置数据 (#4355) 2024-03-29 07:50:06 +00:00
zhengkunwang 0ebeeaebd6 fix: 解决 WAF 首次安装创建网站没有生效的问题 (#4354) 2024-03-29 07:04:06 +00:00
zhengkunwang 1ae5bef40d feat: 调整 waf 配置文件生成顺序 (#4339) 2024-03-28 08:10:07 +00:00
zhengkunwang 9b9fe5444d feat: 创建网站增加 waf 关联 (#4333) 2024-03-27 10:36:08 +00:00
ssongliu a5d853c61a fix: 解决界面设置无法上传大图片的问题 (#4332) 2024-03-27 10:34:07 +00:00
zhengkunwang 6610a3debe fix: 解决前端打包报错问题 (#4331) 2024-03-27 10:26:07 +00:00
zhengkunwang 6b244b2b03 feat: 删除旧版本 WAF 配置 (#4327) 2024-03-27 07:42:07 +00:00
刘瑞斌 0b26d70927 chore: 增加 JetBrains Toolbox 图标 (#4325) 2024-03-27 13:47:05 +08:00
ssongliu 18faed79f3 style: 调整 Xpack 界面样式与菜单位置 (#4323) 2024-03-27 03:32:07 +00:00
zhengkunwang b0cc1248f0 feat: 删除 xpack 的翻译 (#4322) 2024-03-27 03:24:06 +00:00
ssongliu 8013c7fd96 fix: 修改 Xpack 路由路径 (#4317) 2024-03-26 09:40:07 +00:00
ssongliu 306082d625 feat: 完善界面设置功能 (#4316) 2024-03-26 08:44:07 +00:00
刘瑞斌 821b8dfe63 chore: 去掉某些字体 (#4315) 2024-03-26 16:15:58 +08:00
ssongliu 8d88ed812c fix: 修改 License 状态判断 (#4309) 2024-03-26 06:08:07 +00:00
zhengkunwang aa93a6d373 feat: 删除 plugins 目录 (#4311) 2024-03-26 06:00:07 +00:00
ssongliu b4e8c8503c feat: 调整 License 导入样式 (#4305) 2024-03-25 22:49:39 +08:00
zhengkunwang 4de733e084 feat: 优化网站目录显示 (#4301)
Refs https://github.com/1Panel-dev/1Panel/issues/4280
2024-03-25 09:58:07 +00:00
ssongliu 6c67dc6ed4 feat: 完善 License 导入错误显示 (#4297) 2024-03-25 07:12:07 +00:00
ssongliu ba6991bfb6 feat: 增加 License 导入界面 (#4295) 2024-03-25 04:20:07 +00:00
zhengkunwang 33309d2d93 feat(waf): 优化配置文件读取方式 (#4288) 2024-03-23 14:04:06 +00:00
zhengkunwang 1b2208a4d0 feat(waf): 增加 IP 组功能 (#4277) 2024-03-22 10:58:08 +00:00
刘瑞斌 e3fb97fc8c ci: 替换过时的组件 (#4273) 2024-03-22 14:33:48 +08:00
an4er 1ff5bf85e9 fix: 解决命令注入waf被绕过的问题 (#4268) 2024-03-22 14:18:47 +08:00
wanghe-fit2cloud 062b2f2ae6 chore: 修改同步仓库地址 2024-03-22 14:17:40 +08:00
wanghe-fit2cloud 44445aca93 chore: 修改使用手册显示信息 2024-03-21 22:36:32 +08:00
dependabot[bot] 94de830637 chore(deps): bump github.com/docker/docker (#4256)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 25.0.3+incompatible to 25.0.5+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v25.0.3...v25.0.5)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-21 18:54:22 +08:00
Shang Yuanchun 9160726127 解决部分操作系统上 platformVersion 为空导致的显示问题 (#4259)
* fix: 解决部分操作系统上 platformVersion 为空导致的显示问题

例如archlinux,显示的是:arch-

* fix: 修改表达式 (#4259)
2024-03-21 18:54:13 +08:00
247 changed files with 4533 additions and 8557 deletions
+5 -1
View File
@@ -1 +1,5 @@
*.ts linguist-language=Go
*.ts linguist-language=Go
*.js linguist-language=Go
*.css linguist-language=Go
*.scss linguist-language=Go
*.html linguist-language=Go
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
name: 为 PR 添加标签
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: actions-ecosystem/action-add-labels@v1
with:
github_token: ${{ secrets.GITHUBTOKEN }}
+1 -1
View File
@@ -9,7 +9,7 @@ jobs:
uses: Yikun/hub-mirror-action@master
with:
src: 'github/1Panel-dev'
dst: 'gitee/fit2cloud-xlab'
dst: 'gitee/fit2cloud-feizhiyun'
dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
dst_token: ${{ secrets.GITEE_TOKEN }}
static_list: "1Panel"
+13
View File
@@ -0,0 +1,13 @@
name: Typos Check
on: pull_request
jobs:
run:
name: Spell Check with Typos
runs-on: ubuntu-latest
steps:
- name: Checkout Actions Repository
uses: actions/checkout@v2
- name: Check spelling
uses: crate-ci/typos@master
+4 -6
View File
@@ -16,7 +16,8 @@ build/1panel
*.factorypath
# IntelliJ IDEA
.idea
.idea/*
!.idea/icon.png
*.iws
*.iml
*.ipr
@@ -41,11 +42,7 @@ frontend/src/xpack
backend/xpack
backend/router/entry_xpack.go
backend/server/init_xpack.go
plugins/openresty/waf/db
plugins/openresty/waf/data
plugins/openresty/waf/sites
plugins/openresty/waf/conf/websites.json
backend/utils/xpack/xpack_xpack.go
.history/
dist/
@@ -55,3 +52,4 @@ install.sh
quick_start.sh
cmd/server/fileList.txt
.fileList.txt
1Panel.code-workspace
+1
View File
@@ -13,6 +13,7 @@ builds:
- main: ./cmd/server/main.go
binary: 1panel
flags:
- -tags=xpack
- -trimpath
ldflags:
- -w -s
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

+9
View File
@@ -19,6 +19,8 @@
- **安全可靠**:基于容器管理并部署应用,实现最小的漏洞暴露面,同时提供防火墙和日志审计等功能;
- **一键备份**:支持一键备份和恢复,用户可以将数据备份到各类云端存储介质,永不丢失。
1Panel 三分钟速览:https://www.bilibili.com/video/BV1Mt421n7LZ/
## UI 展示
![UI展示](https://resource.fit2cloud.com/1panel/img/overview.png)
@@ -56,6 +58,13 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
[![Star History Chart](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](https://star-history.com/#1Panel-dev/1Panel&Date)
## 我们的其他明星项目
- [JumpServer](https://github.com/jumpserver/jumpserver/) - 广受欢迎的开源堡垒机
- [DataEase](https://github.com/dataease/dataease/) - 人人可用的开源数据可视化分析工具
- [MeterSphere](https://github.com/metersphere/metersphere/) - 一站式开源自动化测试平台
- [Halo](https://github.com/halo-dev/halo/) - 强大易用的开源建站工具
## FOSSA Status
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2F1Panel-dev%2F1Panel?ref=badge_large)
-6
View File
@@ -3,9 +3,6 @@
如果您发现安全问题,请直接联系我们:
- wanghe@fit2cloud.com
- zhengkun@fit2cloud.com
- support@fit2cloud.com
- 400-052-0755
感谢您的支持!
@@ -14,8 +11,5 @@
All security bugs should be reported to the contact as below:
- wanghe@fit2cloud.com
- zhengkun@fit2cloud.com
- support@fit2cloud.com
- +86 400-052-0755
Thanks for your support!
+1 -1
View File
@@ -137,7 +137,7 @@ func (b *BaseApi) GetAppDetailByID(c *gin.Context) {
// @Accept json
// @Success 200 {object} response.IgnoredApp
// @Security ApiKeyAuth
// @Router /apps/ingored [get]
// @Router /apps/ignored [get]
func (b *BaseApi) GetIgnoredApp(c *gin.Context) {
res, err := appService.GetIgnoredApp()
if err != nil {
+9
View File
@@ -121,6 +121,15 @@ func (b *BaseApi) CheckIsSafety(c *gin.Context) {
helper.SuccessWithData(c, status)
}
func (b *BaseApi) GetResponsePage(c *gin.Context) {
pageCode, err := authService.GetResponsePage()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, pageCode)
}
// @Tags Auth
// @Summary Check System isDemo
// @Description 判断是否为demo环境
+67 -8
View File
@@ -301,28 +301,83 @@ func (b *BaseApi) UploadFiles(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
files := form.File["file"]
uploadFiles := form.File["file"]
paths := form.Value["path"]
overwrite := true
if ow, ok := form.Value["overwrite"]; ok {
if len(ow) != 0 {
parseBool, _ := strconv.ParseBool(ow[0])
overwrite = parseBool
}
}
if len(paths) == 0 || !strings.Contains(paths[0], "/") {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error paths in request"))
return
}
dir := path.Dir(paths[0])
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
info, err := os.Stat(dir)
if err != nil && os.IsNotExist(err) {
mode, err := files.GetParentMode(dir)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
if err = os.MkdirAll(dir, mode); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, fmt.Errorf("mkdir %s failed, err: %v", dir, err))
return
}
}
info, err = os.Stat(dir)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
mode := info.Mode()
fileOp := files.NewFileOp()
success := 0
failures := make(buserr.MultiErr)
for _, file := range files {
if err := c.SaveUploadedFile(file, path.Join(paths[0], file.Filename)); err != nil {
for _, file := range uploadFiles {
dstFilename := path.Join(paths[0], file.Filename)
dstDir := path.Dir(dstFilename)
if !fileOp.Stat(dstDir) {
if err = fileOp.CreateDir(dstDir, mode); err != nil {
e := fmt.Errorf("create dir [%s] failed, err: %v", path.Dir(dstFilename), err)
failures[file.Filename] = e
global.LOG.Error(e)
continue
}
}
tmpFilename := dstFilename + ".tmp"
if err := c.SaveUploadedFile(file, tmpFilename); err != nil {
_ = os.Remove(tmpFilename)
e := fmt.Errorf("upload [%s] file failed, err: %v", file.Filename, err)
failures[file.Filename] = e
global.LOG.Error(e)
continue
}
dstInfo, statErr := os.Stat(dstFilename)
if overwrite {
_ = os.Remove(dstFilename)
}
err = os.Rename(tmpFilename, dstFilename)
if err != nil {
_ = os.Remove(tmpFilename)
e := fmt.Errorf("upload [%s] file failed, err: %v", file.Filename, err)
failures[file.Filename] = e
global.LOG.Error(e)
continue
}
if statErr == nil {
_ = os.Chmod(dstFilename, dstInfo.Mode())
} else {
_ = os.Chmod(dstFilename, mode)
}
success++
}
if success == 0 {
@@ -539,16 +594,20 @@ func (b *BaseApi) Size(c *gin.Context) {
func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int) error {
op := files.NewFileOp()
dstDir = strings.TrimSpace(dstDir)
mode, _ := files.GetParentMode(dstDir)
if mode == 0 {
mode = 0755
}
if _, err := os.Stat(dstDir); err != nil && os.IsNotExist(err) {
if err = op.CreateDir(dstDir, os.ModePerm); err != nil {
if err = op.CreateDir(dstDir, mode); err != nil {
return err
}
}
targetFile, err := os.Create(filepath.Join(dstDir, fileName))
targetFile, err := os.OpenFile(filepath.Join(dstDir, fileName), os.O_RDWR|os.O_CREATE, mode)
if err != nil {
return err
}
defer targetFile.Close()
for i := 0; i < chunkCount; i++ {
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", fileName, i))
+34 -3
View File
@@ -15,6 +15,13 @@ import (
"github.com/shirou/gopsutil/v3/net"
)
// @Tags Monitor
// @Summary Load monitor datas
// @Description 获取监控数据
// @Param request body dto.MonitorSearch true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/monitor/search [post]
func (b *BaseApi) LoadMonitor(c *gin.Context) {
var req dto.MonitorSearch
if err := helper.CheckBindAndValidate(&req, c); err != nil {
@@ -28,7 +35,7 @@ func (b *BaseApi) LoadMonitor(c *gin.Context) {
var backdatas []dto.MonitorData
if req.Param == "all" || req.Param == "cpu" || req.Param == "memory" || req.Param == "load" {
var bases []model.MonitorBase
if err := global.DB.
if err := global.MonitorDB.
Where("created_at > ? AND created_at < ?", req.StartTime, req.EndTime).
Find(&bases).Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
@@ -45,7 +52,7 @@ func (b *BaseApi) LoadMonitor(c *gin.Context) {
}
if req.Param == "all" || req.Param == "io" {
var bases []model.MonitorIO
if err := global.DB.
if err := global.MonitorDB.
Where("created_at > ? AND created_at < ?", req.StartTime, req.EndTime).
Find(&bases).Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
@@ -62,7 +69,7 @@ func (b *BaseApi) LoadMonitor(c *gin.Context) {
}
if req.Param == "all" || req.Param == "network" {
var bases []model.MonitorNetwork
if err := global.DB.
if err := global.MonitorDB.
Where("name = ? AND created_at > ? AND created_at < ?", req.Info, req.StartTime, req.EndTime).
Find(&bases).Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
@@ -80,6 +87,30 @@ func (b *BaseApi) LoadMonitor(c *gin.Context) {
helper.SuccessWithData(c, backdatas)
}
// @Tags Monitor
// @Summary Clean monitor datas
// @Description 清空监控数据
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/monitor/clean [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"清空监控数据","formatEN":"clean monitor datas"}
func (b *BaseApi) CleanMonitor(c *gin.Context) {
if err := global.MonitorDB.Exec("DELETE FROM monitor_bases").Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
if err := global.MonitorDB.Exec("DELETE FROM monitor_ios").Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
if err := global.MonitorDB.Exec("DELETE FROM monitor_networks").Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) GetNetworkOptions(c *gin.Context) {
netStat, _ := net.IOCounters(true)
var options []string
+22 -24
View File
@@ -60,6 +60,28 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
// @Tags System Setting
// @Summary Update system setting
// @Description 隐藏高级功能菜单
// @Accept json
// @Param request body dto.SettingUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/menu/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"隐藏高级功能菜单","formatEN":"Hide advanced feature menu."}
func (b *BaseApi) UpdateMenu(c *gin.Context) {
var req dto.SettingUpdate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := settingService.Update(req.Key, req.Value); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags System Setting
// @Summary Update system password
// @Description 更新系统登录密码
@@ -227,30 +249,6 @@ func (b *BaseApi) LoadBaseDir(c *gin.Context) {
helper.SuccessWithData(c, global.CONF.System.DataDir)
}
// @Tags System Setting
// @Summary Clean monitor datas
// @Description 清空监控数据
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/monitor/clean [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"清空监控数据","formatEN":"clean monitor datas"}
func (b *BaseApi) CleanMonitor(c *gin.Context) {
if err := global.DB.Exec("DELETE FROM monitor_bases").Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
if err := global.DB.Exec("DELETE FROM monitor_ios").Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
if err := global.DB.Exec("DELETE FROM monitor_networks").Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags System Setting
// @Summary Load mfa info
// @Description 获取 mfa 信息
+9 -9
View File
@@ -102,7 +102,7 @@ func (b *BaseApi) RedisWsSsh(c *gin.Context) {
if wshandleError(wsConn, err) {
return
}
defer killBash(redisConf.ContainerName, commands, pidMap)
defer killBash(redisConf.ContainerName, pidMap)
defer slave.Close()
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, false)
@@ -170,7 +170,7 @@ func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
if wshandleError(wsConn, err) {
return
}
defer killBash(containerID, command, pidMap)
defer killBash(containerID, pidMap)
defer slave.Close()
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave, true)
@@ -221,26 +221,26 @@ func loadMapFromDockerTop(containerID string) map[string]string {
lines := strings.Split(stdout, "\n")
for _, line := range lines {
parts := strings.Fields(line)
if len(parts) != 2 {
if len(parts) == 0 {
continue
}
pidMap[parts[0]] = parts[1]
pidMap[parts[0]] = strings.Join(parts, " ")
}
return pidMap
}
func killBash(containerID, comm string, pidMap map[string]string) {
func killBash(containerID string, pidMap map[string]string) {
sudo := cmd.SudoHandleCmd()
newPidMap := loadMapFromDockerTop(containerID)
for pid, command := range newPidMap {
for pid, newCmd := range newPidMap {
isOld := false
for pid2 := range pidMap {
if pid == pid2 {
for pid2, oldCmd := range pidMap {
if pid == pid2 && oldCmd == newCmd {
isOld = true
break
}
}
if !isOld && command == comm {
if !isOld {
_, _ = cmd.Execf("%s kill -9 %s", sudo, pid)
}
}
+1 -64
View File
@@ -305,69 +305,6 @@ func (b *BaseApi) CreateWebsiteCheck(c *gin.Context) {
helper.SuccessWithData(c, data)
}
// @Tags Website WAF
// @Summary Load websit waf conf
// @Description 获取网站 waf 配置
// @Accept json
// @Param request body request.WebsiteWafReq true "request"
// @Success 200 {object} response.WebsiteWafConfig
// @Security ApiKeyAuth
// @Router /websites/waf/config [post]
func (b *BaseApi) GetWebsiteWafConfig(c *gin.Context) {
var req request.WebsiteWafReq
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
data, err := websiteService.GetWafConfig(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
// @Tags Website WAF
// @Summary Update website waf conf
// @Description 更新 网站 waf 配置
// @Accept json
// @Param request body request.WebsiteWafUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/waf/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"WAF 配置修改 [domain]","formatEN":"WAF conf update [domain]"}
func (b *BaseApi) UpdateWebsiteWafConfig(c *gin.Context) {
var req request.WebsiteWafUpdate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := websiteService.UpdateWafConfig(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Website WAF
// @Summary Update website waf file
// @Description 更新 网站 waf 配置文件
// @Accept json
// @Param request body request.WebsiteWafUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/waf/file/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"WAF 配置文件修改 [domain]","formatEN":"WAF conf file update [domain]"}
func (b *BaseApi) UpdateWebsiteWafFile(c *gin.Context) {
var req request.WebsiteWafFileUpdate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := websiteService.UpdateWafFile(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Website Nginx
// @Summary Update website nginx conf
// @Description 更新 网站 nginx 配置
@@ -433,7 +370,7 @@ func (b *BaseApi) ChangeDefaultServer(c *gin.Context) {
}
// @Tags Website
// @Summary Load websit php conf
// @Summary Load website php conf
// @Description 获取网站 php 配置
// @Accept json
// @Param id path integer true "request"
+3
View File
@@ -48,6 +48,8 @@ type ContainerOperate struct {
Name string `json:"name" validate:"required"`
Image string `json:"image" validate:"required"`
Network string `json:"network"`
Ipv4 string `json:"ipv4"`
Ipv6 string `json:"ipv6"`
PublishAllPorts bool `json:"publishAllPorts"`
ExposedPorts []PortHelper `json:"exposedPorts"`
Tty bool `json:"tty"`
@@ -98,6 +100,7 @@ type ContainerStats struct {
}
type VolumeHelper struct {
Type string `json:"type"`
SourceDir string `json:"sourceDir"`
ContainerDir string `json:"containerDir"`
Mode string `json:"mode"`
+3
View File
@@ -8,6 +8,7 @@ type CronjobCreate struct {
Spec string `json:"spec" validate:"required"`
Script string `json:"script"`
Command string `json:"command"`
ContainerName string `json:"containerName"`
AppID string `json:"appID"`
Website string `json:"website"`
@@ -28,6 +29,7 @@ type CronjobUpdate struct {
Spec string `json:"spec" validate:"required"`
Script string `json:"script"`
Command string `json:"command"`
ContainerName string `json:"containerName"`
AppID string `json:"appID"`
Website string `json:"website"`
@@ -70,6 +72,7 @@ type CronjobInfo struct {
Spec string `json:"spec"`
Script string `json:"script"`
Command string `json:"command"`
ContainerName string `json:"containerName"`
AppID string `json:"appID"`
Website string `json:"website"`
+17
View File
@@ -69,6 +69,8 @@ type DashboardCurrent struct {
NetBytesSent uint64 `json:"netBytesSent"`
NetBytesRecv uint64 `json:"netBytesRecv"`
GPUData []GPUInfo `json:"gpuData"`
ShotTime time.Time `json:"shotTime"`
}
@@ -86,3 +88,18 @@ type DiskInfo struct {
InodesFree uint64 `json:"inodesFree"`
InodesUsedPercent float64 `json:"inodesUsedPercent"`
}
type GPUInfo struct {
Index uint `json:"index"`
ProductName string `json:"productName"`
GPUUtil string `json:"gpuUtil"`
Temperature string `json:"temperature"`
PerformanceState string `json:"performanceState"`
PowerUsage string `json:"powerUsage"`
PowerDraw string `json:"powerDraw"`
MaxPowerLimit string `json:"maxPowerLimit"`
MemoryUsage string `json:"memoryUsage"`
MemUsed string `json:"memUsed"`
MemTotal string `json:"memTotal"`
FanSpeed string `json:"fanSpeed"`
}
+1 -1
View File
@@ -131,7 +131,7 @@ type MysqlStatus struct {
}
type MysqlVariables struct {
BinlogCachSize string `json:"binlog_cache_size"`
BinlogCacheSize string `json:"binlog_cache_size"`
InnodbBufferPoolSize string `json:"innodb_buffer_pool_size"`
InnodbLogBufferSize string `json:"innodb_log_buffer_size"`
JoinBufferSize string `json:"join_buffer_size"`
+1 -1
View File
@@ -22,7 +22,7 @@ type FileCreate struct {
Path string `json:"path" validate:"required"`
Content string `json:"content"`
IsDir bool `json:"isDir"`
Mode int64 `json:"mode" validate:"required"`
Mode int64 `json:"mode"`
IsLink bool `json:"isLink"`
IsSymlink bool `json:"isSymlink"`
LinkPath string `json:"linkPath"`
+6 -18
View File
@@ -69,24 +69,12 @@ type WebsiteOp struct {
Operate string `json:"operate"`
}
type WebsiteWafReq struct {
WebsiteID uint `json:"websiteId" validate:"required"`
Key string `json:"key" validate:"required"`
Rule string `json:"rule" validate:"required"`
}
type WebsiteRedirectUpdate struct {
WebsiteID uint `json:"websiteId" validate:"required"`
Key string `json:"key" validate:"required"`
Enable bool `json:"enable"`
}
type WebsiteWafUpdate struct {
WebsiteID uint `json:"websiteId" validate:"required"`
Key string `json:"key" validate:"required"`
Enable bool `json:"enable"`
}
type WebsiteRecover struct {
WebsiteName string `json:"websiteName" validate:"required"`
Type string `json:"type" validate:"required"`
@@ -207,12 +195,12 @@ type WebsiteRedirectReq struct {
WebsiteID uint `json:"websiteId" validate:"required"`
}
type WebsiteWafFileUpdate struct {
WebsiteID uint `json:"websiteID" validate:"required"`
Content string `json:"content" validate:"required"`
Type string `json:"type" validate:"required,oneof=cc ip_white ip_block url_white url_block cookie_block args_check post_check ua_check file_ext_block user_agent"`
}
type WebsiteCommonReq struct {
ID uint `json:"id" validate:"required"`
}
type WafWebsite struct {
Key string `json:"key"`
Domains []string `json:"domains"`
Host []string `json:"host"`
}
-5
View File
@@ -31,11 +31,6 @@ type WebsiteNginxConfig struct {
Params []NginxParam `json:"params"`
}
type WebsiteWafConfig struct {
Enable bool `json:"enable"`
Content string `json:"content"`
}
type WebsiteHTTPS struct {
Enable bool `json:"enable"`
HttpConfig string `json:"httpConfig"`
+3
View File
@@ -19,6 +19,7 @@ type SettingInfo struct {
BindAddress string `json:"bindAddress"`
PanelName string `json:"panelName"`
Theme string `json:"theme"`
MenuTabs string `json:"menuTabs"`
Language string `json:"language"`
DefaultNetwork string `json:"defaultNetwork"`
LastCleanTime string `json:"lastCleanTime"`
@@ -54,6 +55,8 @@ type SettingInfo struct {
FileRecycleBin string `json:"fileRecycleBin"`
SnapshotIgnore string `json:"snapshotIgnore"`
XpackHideMenu string `json:"xpackHideMenu"`
NoAuthSetting string `json:"noAuthSetting"`
}
type SettingUpdate struct {
+1
View File
@@ -9,6 +9,7 @@ type Cronjob struct {
Type string `gorm:"type:varchar(64);not null" json:"type"`
Spec string `gorm:"type:varchar(64);not null" json:"spec"`
Command string `gorm:"type:varchar(64)" json:"command"`
ContainerName string `gorm:"type:varchar(64)" json:"containerName"`
Script string `gorm:"longtext" json:"script"`
Website string `gorm:"type:varchar(64)" json:"website"`
+6 -6
View File
@@ -68,20 +68,20 @@ func (u *SettingRepo) Update(key, value string) error {
}
func (u *SettingRepo) CreateMonitorBase(model model.MonitorBase) error {
return global.DB.Create(&model).Error
return global.MonitorDB.Create(&model).Error
}
func (u *SettingRepo) BatchCreateMonitorIO(ioList []model.MonitorIO) error {
return global.DB.CreateInBatches(ioList, len(ioList)).Error
return global.MonitorDB.CreateInBatches(ioList, len(ioList)).Error
}
func (u *SettingRepo) BatchCreateMonitorNet(ioList []model.MonitorNetwork) error {
return global.DB.CreateInBatches(ioList, len(ioList)).Error
return global.MonitorDB.CreateInBatches(ioList, len(ioList)).Error
}
func (u *SettingRepo) DelMonitorBase(timeForDelete time.Time) error {
return global.DB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorBase{}).Error
return global.MonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorBase{}).Error
}
func (u *SettingRepo) DelMonitorIO(timeForDelete time.Time) error {
return global.DB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorIO{}).Error
return global.MonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorIO{}).Error
}
func (u *SettingRepo) DelMonitorNet(timeForDelete time.Time) error {
return global.DB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorNetwork{}).Error
return global.MonitorDB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorNetwork{}).Error
}
+19 -11
View File
@@ -5,6 +5,8 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
"github.com/docker/docker/api/types/container"
"math"
"net/http"
"os"
@@ -37,7 +39,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/utils/compose"
composeV2 "github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/1Panel-dev/1Panel/backend/utils/files"
dockerTypes "github.com/docker/docker/api/types"
"github.com/pkg/errors"
)
@@ -364,6 +365,7 @@ func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete b
}
_ = websiteRepo.DeleteAll(ctx)
_ = websiteDomainRepo.DeleteAll(ctx)
xpack.RemoveTamper("")
case constant.AppMysql, constant.AppMariaDB:
_ = mysqlRepo.Delete(ctx, mysqlRepo.WithByMysqlName(install.Name))
case constant.AppPostgresql:
@@ -693,8 +695,8 @@ func handleMap(params map[string]interface{}, envParams map[string]string) {
strArray[i] = strings.ToLower(fmt.Sprintf("%v", t[i]))
}
envParams[k] = strings.Join(strArray, ",")
default:
envParams[k] = t.(string)
case map[string]interface{}:
handleMap(t, envParams)
}
}
}
@@ -827,7 +829,7 @@ func checkContainerNameIsExist(containerName, appDir string) (bool, error) {
if err != nil {
return false, err
}
var options dockerTypes.ContainerListOptions
var options container.ListOptions
list, err := client.ContainerList(context.Background(), options)
if err != nil {
return false, err
@@ -1225,14 +1227,20 @@ func addDockerComposeCommonParam(composeMap map[string]interface{}, serviceName
return buserr.New(constant.ErrFileParse)
}
serviceValue := service.(map[string]interface{})
deploy := map[string]interface{}{
"resources": map[string]interface{}{
"limits": map[string]interface{}{
"cpus": "${CPUS}",
"memory": "${MEMORY_LIMIT}",
},
},
deploy := map[string]interface{}{}
if de, ok := serviceValue["deploy"]; ok {
deploy = de.(map[string]interface{})
}
resource := map[string]interface{}{}
if res, ok := deploy["resources"]; ok {
resource = res.(map[string]interface{})
}
resource["limits"] = map[string]interface{}{
"cpus": "${CPUS}",
"memory": "${MEMORY_LIMIT}",
}
deploy["resources"] = resource
serviceValue["deploy"] = deploy
ports, ok := serviceValue["ports"].([]interface{})
+13 -3
View File
@@ -1,6 +1,7 @@
package service
import (
"crypto/hmac"
"strconv"
"github.com/1Panel-dev/1Panel/backend/app/dto"
@@ -19,6 +20,7 @@ type AuthService struct{}
type IAuthService interface {
CheckIsSafety(code string) (string, error)
GetResponsePage() (string, error)
VerifyCode(code string) (bool, error)
Login(c *gin.Context, info dto.Login, entrance string) (*dto.UserLoginInfo, error)
LogOut(c *gin.Context) error
@@ -42,7 +44,7 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login, entrance string) (*d
if err != nil {
return nil, constant.ErrAuth
}
if info.Password != pass || nameSetting.Value != info.Name {
if !hmac.Equal([]byte(info.Password), []byte(pass)) || nameSetting.Value != info.Name {
return nil, constant.ErrAuth
}
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
@@ -78,7 +80,7 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin, entrance strin
if err != nil {
return nil, err
}
if info.Password != pass || nameSetting.Value != info.Name {
if !hmac.Equal([]byte(info.Password), []byte(pass)) || nameSetting.Value != info.Name {
return nil, constant.ErrAuth
}
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
@@ -168,7 +170,7 @@ func (u *AuthService) VerifyCode(code string) (bool, error) {
if err != nil {
return false, err
}
return setting.Value == code, nil
return hmac.Equal([]byte(setting.Value), []byte(code)), nil
}
func (u *AuthService) CheckIsSafety(code string) (string, error) {
@@ -184,3 +186,11 @@ func (u *AuthService) CheckIsSafety(code string) (string, error) {
}
return "unpass", nil
}
func (u *AuthService) GetResponsePage() (string, error) {
pageCode, err := settingRepo.Get(settingRepo.WithByKey("NoAuthSetting"))
if err != nil {
return "", err
}
return pageCode.Value, nil
}
+118 -93
View File
@@ -29,6 +29,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/client"
@@ -87,7 +88,9 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
if err != nil {
return 0, nil, err
}
options := types.ContainerListOptions{All: true}
options := container.ListOptions{
All: true,
}
if len(req.Filters) != 0 {
options.Filters = filters.NewArgs()
options.Filters.Add("label", req.Filters)
@@ -216,7 +219,7 @@ func (u *ContainerService) List() ([]string, error) {
if err != nil {
return nil, err
}
containers, err := client.ContainerList(context.Background(), types.ContainerListOptions{All: true})
containers, err := client.ContainerList(context.Background(), container.ListOptions{All: true})
if err != nil {
return nil, err
}
@@ -237,7 +240,7 @@ func (u *ContainerService) ContainerListStats() ([]dto.ContainerListStats, error
if err != nil {
return nil, err
}
list, err := client.ContainerList(context.Background(), types.ContainerListOptions{All: true})
list, err := client.ContainerList(context.Background(), container.ListOptions{All: true})
if err != nil {
return nil, err
}
@@ -376,14 +379,14 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error {
return err
}
global.LOG.Infof("new container info %s has been made, now start to create", req.Name)
container, err := client.ContainerCreate(ctx, config, hostConf, networkConf, &v1.Platform{}, req.Name)
con, err := client.ContainerCreate(ctx, config, hostConf, networkConf, &v1.Platform{}, req.Name)
if err != nil {
_ = client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
_ = client.ContainerRemove(ctx, req.Name, container.RemoveOptions{RemoveVolumes: true, Force: true})
return err
}
global.LOG.Infof("create container %s successful! now check if the container is started and delete the container information if it is not.", req.Name)
if err := client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}); err != nil {
_ = client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
if err := client.ContainerStart(ctx, con.ID, container.StartOptions{}); err != nil {
_ = client.ContainerRemove(ctx, req.Name, container.RemoveOptions{RemoveVolumes: true, Force: true})
return fmt.Errorf("create successful but start failed, err: %v", err)
}
return nil
@@ -410,6 +413,18 @@ func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.Contai
break
}
}
networkSettings := oldContainer.NetworkSettings
bridgeNetworkSettings := networkSettings.Networks[data.Network]
if bridgeNetworkSettings.IPAMConfig != nil {
ipv4Address := bridgeNetworkSettings.IPAMConfig.IPv4Address
data.Ipv4 = ipv4Address
ipv6Address := bridgeNetworkSettings.IPAMConfig.IPv6Address
data.Ipv6 = ipv6Address
} else {
data.Ipv4 = bridgeNetworkSettings.IPAddress
}
data.Cmd = oldContainer.Config.Cmd
data.OpenStdin = oldContainer.Config.OpenStdin
data.Tty = oldContainer.Config.Tty
@@ -442,7 +457,7 @@ func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.Contai
if oldContainer.HostConfig.Memory != 0 {
data.Memory = float64(oldContainer.HostConfig.Memory) / 1024 / 1024
}
data.Volumes = loadVolumeBinds(oldContainer.HostConfig.Binds)
data.Volumes = loadVolumeBinds(oldContainer.Mounts)
return &data, nil
}
@@ -471,7 +486,7 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
}
}
if err := client.ContainerRemove(ctx, req.ContainerID, types.ContainerRemoveOptions{Force: true}); err != nil {
if err := client.ContainerRemove(ctx, req.ContainerID, container.RemoveOptions{Force: true}); err != nil {
return err
}
@@ -482,13 +497,13 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
}
global.LOG.Infof("new container info %s has been update, now start to recreate", req.Name)
container, err := client.ContainerCreate(ctx, config, hostConf, networkConf, &v1.Platform{}, req.Name)
con, err := client.ContainerCreate(ctx, config, hostConf, networkConf, &v1.Platform{}, req.Name)
if err != nil {
reCreateAfterUpdate(req.Name, client, oldContainer.Config, oldContainer.HostConfig, oldContainer.NetworkSettings)
return fmt.Errorf("update container failed, err: %v", err)
}
global.LOG.Infof("update container %s successful! now check if the container is started.", req.Name)
if err := client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}); err != nil {
if err := client.ContainerStart(ctx, con.ID, container.StartOptions{}); err != nil {
return fmt.Errorf("update successful but start failed, err: %v", err)
}
@@ -523,18 +538,18 @@ func (u *ContainerService) ContainerUpgrade(req dto.ContainerUpgrade) error {
break
}
}
if err := client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{Force: true}); err != nil {
if err := client.ContainerRemove(ctx, req.Name, container.RemoveOptions{Force: true}); err != nil {
return err
}
global.LOG.Infof("new container info %s has been update, now start to recreate", req.Name)
container, err := client.ContainerCreate(ctx, config, hostConf, &networkConf, &v1.Platform{}, req.Name)
con, err := client.ContainerCreate(ctx, config, hostConf, &networkConf, &v1.Platform{}, req.Name)
if err != nil {
reCreateAfterUpdate(req.Name, client, oldContainer.Config, oldContainer.HostConfig, oldContainer.NetworkSettings)
return fmt.Errorf("upgrade container failed, err: %v", err)
}
global.LOG.Infof("upgrade container %s successful! now check if the container is started.", req.Name)
if err := client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}); err != nil {
if err := client.ContainerStart(ctx, con.ID, container.StartOptions{}); err != nil {
return fmt.Errorf("upgrade successful but start failed, err: %v", err)
}
@@ -566,7 +581,7 @@ func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error
global.LOG.Infof("start container %s operation %s", item, req.Operation)
switch req.Operation {
case constant.ContainerOpStart:
err = client.ContainerStart(ctx, item, types.ContainerStartOptions{})
err = client.ContainerStart(ctx, item, container.StartOptions{})
case constant.ContainerOpStop:
err = client.ContainerStop(ctx, item, container.StopOptions{})
case constant.ContainerOpRestart:
@@ -578,7 +593,7 @@ func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error
case constant.ContainerOpUnpause:
err = client.ContainerUnpause(ctx, item)
case constant.ContainerOpRemove:
err = client.ContainerRemove(ctx, item, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
err = client.ContainerRemove(ctx, item, container.RemoveOptions{RemoveVolumes: true, Force: true})
}
}
return err
@@ -612,7 +627,7 @@ func (u *ContainerService) ContainerLogClean(req dto.OperationWithName) error {
_ = os.Remove(file)
}
if err := client.ContainerStart(ctx, containerItem.ID, types.ContainerStartOptions{}); err != nil {
if err := client.ContainerStart(ctx, containerItem.ID, container.StartOptions{}); err != nil {
return err
}
return nil
@@ -623,22 +638,26 @@ func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, containerType,
if cmd.CheckIllegal(container, since, tail) {
return buserr.New(constant.ErrCmdIllegal)
}
command := fmt.Sprintf("docker logs %s", container)
commandName := "docker"
commandArg := []string{"logs", container}
if containerType == "compose" {
command = fmt.Sprintf("docker-compose -f %s logs", container)
commandName = "docker-compose"
commandArg = []string{"-f", container, "logs"}
}
if tail != "0" {
command += " --tail " + tail
commandArg = append(commandArg, "--tail")
commandArg = append(commandArg, tail)
}
if since != "all" {
command += " --since " + since
commandArg = append(commandArg, "--since")
commandArg = append(commandArg, since)
}
if follow {
command += " -f"
commandArg = append(commandArg, "-f")
}
command += " 2>&1"
cmd := exec.Command("bash", "-c", command)
if !follow {
cmd := exec.Command(commandName, commandArg...)
cmd.Stderr = cmd.Stdout
stdout, _ := cmd.CombinedOutput()
if !utf8.Valid(stdout) {
return errors.New("invalid utf8")
@@ -649,50 +668,53 @@ func (u *ContainerService) ContainerLogs(wsConn *websocket.Conn, containerType,
return nil
}
cmd := exec.Command(commandName, commandArg...)
stdout, err := cmd.StdoutPipe()
if err != nil {
return err
}
if err := cmd.Start(); err != nil {
return err
}
defer func() {
_ = cmd.Process.Signal(syscall.SIGTERM)
_ = cmd.Wait()
}()
var exitCh chan struct{}
if follow {
go func() {
_, wsData, _ := wsConn.ReadMessage()
if string(wsData) == "close conn" {
exitCh <- struct{}{}
}
}()
return err
}
cmd.Stderr = cmd.Stdout
if err := cmd.Start(); err != nil {
_ = cmd.Process.Signal(syscall.SIGTERM)
return err
}
exitCh := make(chan struct{})
go func() {
_, wsData, _ := wsConn.ReadMessage()
if string(wsData) == "close conn" {
_ = cmd.Process.Signal(syscall.SIGTERM)
exitCh <- struct{}{}
}
}()
buffer := make([]byte, 1024)
for {
select {
case <-exitCh:
return nil
default:
n, err := stdout.Read(buffer)
if err != nil {
if err == io.EOF {
return err
go func() {
buffer := make([]byte, 1024)
for {
select {
case <-exitCh:
return
default:
n, err := stdout.Read(buffer)
if err != nil {
if err == io.EOF {
return
}
global.LOG.Errorf("read bytes from log failed, err: %v", err)
continue
}
if !utf8.Valid(buffer[:n]) {
continue
}
if err = wsConn.WriteMessage(websocket.TextMessage, buffer[:n]); err != nil {
global.LOG.Errorf("send message with log to ws failed, err: %v", err)
return
}
global.LOG.Errorf("read bytes from log failed, err: %v", err)
continue
}
if !utf8.Valid(buffer[:n]) {
continue
}
if err = wsConn.WriteMessage(websocket.TextMessage, buffer[:n]); err != nil {
global.LOG.Errorf("send message with log to ws failed, err: %v", err)
return err
}
}
}
}()
_ = cmd.Wait()
return nil
}
func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error) {
@@ -735,7 +757,7 @@ func (u *ContainerService) LoadContainerLogs(req dto.OperationWithNameAndType) s
if err != nil {
return ""
}
options := types.ContainerListOptions{All: true}
options := container.ListOptions{All: true}
options.Filters = filters.NewArgs()
options.Filters.Add("label", fmt.Sprintf("%s=%s", composeProjectLabel, req.Name))
containers, err := cli.ContainerList(context.Background(), options)
@@ -976,8 +998,21 @@ func loadConfigInfo(isCreate bool, req dto.ContainerOperate, oldContainer *types
case "host", "none", "bridge":
hostConf.NetworkMode = container.NetworkMode(req.Network)
}
networkConf.EndpointsConfig = map[string]*network.EndpointSettings{req.Network: {}}
if req.Ipv4 != "" || req.Ipv6 != "" {
networkConf.EndpointsConfig = map[string]*network.EndpointSettings{
req.Network: {
IPAMConfig: &network.EndpointIPAMConfig{
IPv4Address: req.Ipv4,
IPv6Address: req.Ipv6,
},
}}
} else {
networkConf.EndpointsConfig = map[string]*network.EndpointSettings{req.Network: {}}
}
} else {
if req.Ipv4 != "" || req.Ipv6 != "" {
return nil, nil, nil, fmt.Errorf("Please set up the network")
}
networkConf = network.NetworkingConfig{}
}
@@ -994,10 +1029,19 @@ func loadConfigInfo(isCreate bool, req dto.ContainerOperate, oldContainer *types
hostConf.MemorySwap = 0
hostConf.PortBindings = portMap
hostConf.Binds = []string{}
hostConf.Mounts = []mount.Mount{}
config.Volumes = make(map[string]struct{})
for _, volume := range req.Volumes {
config.Volumes[volume.ContainerDir] = struct{}{}
hostConf.Binds = append(hostConf.Binds, fmt.Sprintf("%s:%s:%s", volume.SourceDir, volume.ContainerDir, volume.Mode))
if volume.Type == "volume" {
hostConf.Mounts = append(hostConf.Mounts, mount.Mount{
Type: mount.Type(volume.Type),
Source: volume.SourceDir,
Target: volume.ContainerDir,
})
config.Volumes[volume.ContainerDir] = struct{}{}
} else {
hostConf.Binds = append(hostConf.Binds, fmt.Sprintf("%s:%s:%s", volume.SourceDir, volume.ContainerDir, volume.Mode))
}
}
return &config, &hostConf, &networkConf, nil
}
@@ -1018,46 +1062,27 @@ func reCreateAfterUpdate(name string, client *client.Client, config *container.C
global.LOG.Errorf("recreate after container update failed, err: %v", err)
return
}
if err := client.ContainerStart(ctx, oldContainer.ID, types.ContainerStartOptions{}); err != nil {
if err := client.ContainerStart(ctx, oldContainer.ID, container.StartOptions{}); err != nil {
global.LOG.Errorf("restart after container update failed, err: %v", err)
}
global.LOG.Errorf("recreate after container update successful")
}
func loadVolumeBinds(binds []string) []dto.VolumeHelper {
func loadVolumeBinds(binds []types.MountPoint) []dto.VolumeHelper {
var datas []dto.VolumeHelper
for _, bind := range binds {
parts := strings.Split(bind, ":")
var volumeItem dto.VolumeHelper
if len(parts) > 3 {
continue
volumeItem.Type = string(bind.Type)
if bind.Type == "volume" {
volumeItem.SourceDir = bind.Name
} else {
volumeItem.SourceDir = bind.Source
}
volumeItem.SourceDir = parts[0]
if len(parts) == 1 {
volumeItem.ContainerDir = parts[0]
volumeItem.ContainerDir = bind.Destination
volumeItem.Mode = "ro"
if bind.RW {
volumeItem.Mode = "rw"
}
if len(parts) == 2 {
switch parts[1] {
case "r", "ro":
volumeItem.ContainerDir = parts[0]
volumeItem.Mode = "ro"
case "rw":
volumeItem.ContainerDir = parts[0]
volumeItem.Mode = "rw"
default:
volumeItem.ContainerDir = parts[1]
volumeItem.Mode = "rw"
}
}
if len(parts) == 3 {
volumeItem.ContainerDir = parts[1]
if parts[2] == "r" {
volumeItem.Mode = "ro"
} else {
volumeItem.Mode = parts[2]
}
}
datas = append(datas, volumeItem)
}
return datas
+2 -2
View File
@@ -4,6 +4,7 @@ import (
"bufio"
"errors"
"fmt"
"github.com/docker/docker/api/types/container"
"io"
"os"
"os/exec"
@@ -20,7 +21,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/compose"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"golang.org/x/net/context"
)
@@ -40,7 +40,7 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
return 0, nil, err
}
options := types.ContainerListOptions{All: true}
options := container.ListOptions{All: true}
options.Filters = filters.NewArgs()
options.Filters.Add("label", composeProjectLabel)
+1
View File
@@ -265,6 +265,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
upMap["name"] = req.Name
upMap["spec"] = spec
upMap["script"] = req.Script
upMap["command"] = req.Command
upMap["container_name"] = req.ContainerName
upMap["app_id"] = req.AppID
upMap["website"] = req.Website
+4 -4
View File
@@ -326,7 +326,7 @@ func handleBackupLogs(targetDir, fileName string) error {
if len(logFiles) != 0 {
for i := 0; i < len(logFiles); i++ {
if !logFiles[i].IsDir() {
_ = cpBinary([]string{path.Join(itemDir, logFiles[i].Name())}, dirItem)
_ = common.CopyFile(path.Join(itemDir, logFiles[i].Name()), dirItem)
}
}
}
@@ -335,7 +335,7 @@ func handleBackupLogs(targetDir, fileName string) error {
if len(logFiles2) != 0 {
for i := 0; i < len(logFiles2); i++ {
if !logFiles2[i].IsDir() {
_ = cpBinary([]string{path.Join(itemDir2, logFiles2[i].Name())}, dirItem)
_ = common.CopyFile(path.Join(itemDir2, logFiles2[i].Name()), dirItem)
}
}
}
@@ -354,7 +354,7 @@ func handleBackupLogs(targetDir, fileName string) error {
if len(systemLogFiles) != 0 {
for i := 0; i < len(systemLogFiles); i++ {
if !systemLogFiles[i].IsDir() {
_ = cpBinary([]string{path.Join(systemLogDir, systemLogFiles[i].Name())}, systemDir)
_ = common.CopyFile(path.Join(systemLogDir, systemLogFiles[i].Name()), systemDir)
}
}
}
@@ -370,7 +370,7 @@ func handleBackupLogs(targetDir, fileName string) error {
if len(loginLogFiles) != 0 {
for i := 0; i < len(loginLogFiles); i++ {
if !loginLogFiles[i].IsDir() && (strings.HasPrefix(loginLogFiles[i].Name(), "secure") || strings.HasPrefix(loginLogFiles[i].Name(), "auth.log")) {
_ = cpBinary([]string{path.Join("/var/log", loginLogFiles[i].Name())}, loginDir)
_ = common.CopyFile(path.Join("/var/log", loginLogFiles[i].Name()), loginDir)
}
}
}
+21 -1
View File
@@ -2,6 +2,7 @@ package service
import (
"context"
"encoding/json"
"fmt"
"os"
"path"
@@ -38,7 +39,11 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
_ = cronjobRepo.UpdateRecords(record.ID, map[string]interface{}{"records": record.Records})
script := cronjob.Script
if len(cronjob.ContainerName) != 0 {
script = fmt.Sprintf("docker exec %s %s", cronjob.ContainerName, cronjob.Script)
command := "sh"
if len(cronjob.Command) != 0 {
command = cronjob.Command
}
script = fmt.Sprintf("docker exec %s %s -c \"%s\"", cronjob.ContainerName, command, strings.ReplaceAll(cronjob.Script, "\"", "\\\""))
}
err = u.handleShell(cronjob.Type, cronjob.Name, script, record.Records)
u.removeExpiredLog(*cronjob)
@@ -271,6 +276,21 @@ func loadClientMap(backupAccounts string) (map[string]cronjobUploadHelper, error
if account.BackupPath != "/" {
pathItem = strings.TrimPrefix(account.BackupPath, "/")
}
if target == constant.Local {
varMap := make(map[string]interface{})
if err := json.Unmarshal([]byte(account.Vars), &varMap); err != nil {
return nil, err
}
if _, ok := varMap["dir"]; !ok {
return nil, errors.New("load local backup dir failed")
}
baseDir, ok := varMap["dir"].(string)
if ok {
pathItem = baseDir
} else {
return nil, fmt.Errorf("error type dir: %T", varMap["dir"])
}
}
clients[target] = cronjobUploadHelper{
client: client,
backupPath: pathItem,
+21
View File
@@ -11,6 +11,8 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/copier"
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/disk"
"github.com/shirou/gopsutil/v3/host"
@@ -154,6 +156,7 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
currentInfo.SwapMemoryUsedPercent = swapInfo.UsedPercent
currentInfo.DiskData = loadDiskInfo()
currentInfo.GPUData = loadGPUInfo()
if ioOption == "all" {
diskInfo, _ := disk.IOCounters()
@@ -289,3 +292,21 @@ func loadDiskInfo() []dto.DiskInfo {
})
return datas
}
func loadGPUInfo() []dto.GPUInfo {
list := xpack.LoadGpuInfo()
if len(list) == 0 {
return nil
}
var data []dto.GPUInfo
for _, gpu := range list {
var dataItem dto.GPUInfo
if err := copier.Copy(&dataItem, &gpu); err != nil {
continue
}
dataItem.PowerUsage = dataItem.PowerDraw + " / " + dataItem.MaxPowerLimit
dataItem.MemoryUsage = dataItem.MemUsed + " / " + dataItem.MemTotal
data = append(data, dataItem)
}
return data
}
+22 -9
View File
@@ -116,22 +116,32 @@ func (f *FileService) GetFileTree(op request.FileOption) ([]response.FileTree, e
}
func (f *FileService) Create(op request.FileCreate) error {
if files.IsInvalidChar(op.Path) {
return buserr.New("ErrInvalidChar")
}
fo := files.NewFileOp()
if fo.Stat(op.Path) {
return buserr.New(constant.ErrFileIsExit)
}
if op.IsDir {
return fo.CreateDir(op.Path, fs.FileMode(op.Mode))
} else {
if op.IsLink {
if !fo.Stat(op.LinkPath) {
return buserr.New(constant.ErrLinkPathNotFound)
}
return fo.LinkFile(op.LinkPath, op.Path, op.IsSymlink)
mode := op.Mode
if mode == 0 {
fileInfo, err := os.Stat(filepath.Dir(op.Path))
if err == nil {
mode = int64(fileInfo.Mode().Perm())
} else {
return fo.CreateFile(op.Path)
mode = 0755
}
}
if op.IsDir {
return fo.CreateDir(op.Path, fs.FileMode(mode))
}
if op.IsLink {
if !fo.Stat(op.LinkPath) {
return buserr.New(constant.ErrLinkPathNotFound)
}
return fo.LinkFile(op.LinkPath, op.Path, op.IsSymlink)
}
return fo.CreateFileWithMode(op.Path, fs.FileMode(mode))
}
func (f *FileService) Delete(op request.FileDelete) error {
@@ -236,6 +246,9 @@ func (f *FileService) SaveContent(edit request.FileEdit) error {
}
func (f *FileService) ChangeName(req request.FileRename) error {
if files.IsInvalidChar(req.NewName) {
return buserr.New("ErrInvalidChar")
}
fo := files.NewFileOp()
return fo.Rename(req.OldName, req.NewName)
}
+9 -7
View File
@@ -7,6 +7,8 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"io"
"os"
"path"
@@ -43,7 +45,7 @@ func NewIImageService() IImageService {
}
func (u *ImageService) Page(req dto.SearchWithPage) (int64, interface{}, error) {
var (
list []types.ImageSummary
list []image.Summary
records []dto.ImageInfo
backDatas []dto.ImageInfo
)
@@ -51,11 +53,11 @@ func (u *ImageService) Page(req dto.SearchWithPage) (int64, interface{}, error)
if err != nil {
return 0, nil, err
}
list, err = client.ImageList(context.Background(), types.ImageListOptions{})
list, err = client.ImageList(context.Background(), image.ListOptions{})
if err != nil {
return 0, nil, err
}
containers, _ := client.ContainerList(context.Background(), types.ContainerListOptions{All: true})
containers, _ := client.ContainerList(context.Background(), container.ListOptions{All: true})
if len(req.Info) != 0 {
length, count := len(list), 0
for count < length {
@@ -104,11 +106,11 @@ func (u *ImageService) ListAll() ([]dto.ImageInfo, error) {
if err != nil {
return nil, err
}
list, err := client.ImageList(context.Background(), types.ImageListOptions{})
list, err := client.ImageList(context.Background(), image.ListOptions{})
if err != nil {
return nil, err
}
containers, _ := client.ContainerList(context.Background(), types.ContainerListOptions{All: true})
containers, _ := client.ContainerList(context.Background(), container.ListOptions{All: true})
for _, image := range list {
size := formatFileSize(image.Size)
records = append(records, dto.ImageInfo{
@@ -124,14 +126,14 @@ func (u *ImageService) ListAll() ([]dto.ImageInfo, error) {
func (u *ImageService) List() ([]dto.Options, error) {
var (
list []types.ImageSummary
list []image.Summary
backDatas []dto.Options
)
client, err := docker.NewDockerClient()
if err != nil {
return nil, err
}
list, err = client.ImageList(context.Background(), types.ImageListOptions{})
list, err = client.ImageList(context.Background(), image.ListOptions{})
if err != nil {
return nil, err
}
-9
View File
@@ -385,15 +385,6 @@ func updateRecoverStatus(id uint, isRecover bool, interruptStep, status, message
}
}
func cpBinary(src []string, dst string) error {
global.LOG.Debugf(fmt.Sprintf("\\cp -f %s %s", strings.Join(src, " "), dst))
stdout, err := cmd.Exec(fmt.Sprintf("\\cp -f %s %s", strings.Join(src, " "), dst))
if err != nil {
return fmt.Errorf("cp file failed, stdout: %v, err: %v", stdout, err)
}
return nil
}
func (u *SnapshotService) handleUnTar(sourceDir, targetDir string) error {
if _, err := os.Stat(targetDir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(targetDir, os.ModePerm); err != nil {
+10 -2
View File
@@ -43,7 +43,15 @@ func snapPanel(snap snapHelper, targetDir string) {
defer snap.Wg.Done()
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"panel": constant.Running})
status := constant.StatusDone
if err := cpBinary([]string{"/usr/local/bin/1panel", "/usr/local/bin/1pctl", "/etc/systemd/system/1panel.service"}, targetDir); err != nil {
if err := common.CopyFile("/usr/local/bin/1panel", path.Join(targetDir, "1panel")); err != nil {
status = err.Error()
}
if err := common.CopyFile("/usr/local/bin/1pctl", targetDir); err != nil {
status = err.Error()
}
if err := common.CopyFile("/etc/systemd/system/1panel.service", targetDir); err != nil {
status = err.Error()
}
snap.Status.Panel = status
@@ -59,7 +67,7 @@ func snapDaemonJson(snap snapHelper, targetDir string) {
return
}
_ = snapshotRepo.UpdateStatus(snap.Status.ID, map[string]interface{}{"daemon_json": constant.Running})
if err := cpBinary([]string{"/etc/docker/daemon.json"}, path.Join(targetDir, "daemon.json")); err != nil {
if err := common.CopyFile("/etc/docker/daemon.json", targetDir); err != nil {
status = err.Error()
}
snap.Status.DaemonJson = status
+6 -7
View File
@@ -13,6 +13,7 @@ import (
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/pkg/errors"
)
@@ -88,7 +89,7 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b
}
if req.IsNew || snap.InterruptStep == "1PanelBinary" {
if err := recoverPanel(path.Join(snapFileDir, "1panel/1panel"), "/usr/local/bin/1panel"); err != nil {
if err := recoverPanel(path.Join(snapFileDir, "1panel/1panel"), "/usr/local/bin"); err != nil {
updateRecoverStatus(snap.ID, isRecover, "1PanelBinary", constant.StatusFailed, err.Error())
return
}
@@ -96,7 +97,7 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b
req.IsNew = true
}
if req.IsNew || snap.InterruptStep == "1PctlBinary" {
if err := recoverPanel(path.Join(snapFileDir, "1panel/1pctl"), "/usr/local/bin/1pctl"); err != nil {
if err := recoverPanel(path.Join(snapFileDir, "1panel/1pctl"), "/usr/local/bin"); err != nil {
updateRecoverStatus(snap.ID, isRecover, "1PctlBinary", constant.StatusFailed, err.Error())
return
}
@@ -104,7 +105,7 @@ func (u *SnapshotService) HandleSnapshotRecover(snap model.Snapshot, isRecover b
req.IsNew = true
}
if req.IsNew || snap.InterruptStep == "1PanelService" {
if err := recoverPanel(path.Join(snapFileDir, "1panel/1panel.service"), "/etc/systemd/system/1panel.service"); err != nil {
if err := recoverPanel(path.Join(snapFileDir, "1panel/1panel.service"), "/etc/systemd/system"); err != nil {
updateRecoverStatus(snap.ID, isRecover, "1PanelService", constant.StatusFailed, err.Error())
return
}
@@ -235,10 +236,8 @@ func recoverPanel(src string, dst string) error {
if _, err := os.Stat(src); err != nil {
return fmt.Errorf("file is not found in %s, err: %v", src, err)
}
global.LOG.Debugf(fmt.Sprintf("\\cp -f %s %s", src, dst))
stdout, err := cmd.Exec(fmt.Sprintf("\\cp -f %s %s", src, dst))
if err != nil {
return fmt.Errorf("cp file failed, stdout: %v, err: %v", stdout, err)
if err := common.CopyFile(src, dst); err != nil {
return fmt.Errorf("cp file failed, err: %v", err)
}
return nil
}
+8 -9
View File
@@ -43,7 +43,7 @@ func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) {
global.LOG.Infof("load latest version failed, err: %v", err)
return nil, err
}
if !common.CompareVersion(string(latestVersion), currentVersion.Value) {
if !common.ComparePanelVersion(string(latestVersion), currentVersion.Value) {
return nil, err
}
upgrade.LatestVersion = latestVersion
@@ -130,13 +130,13 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
}
global.LOG.Info("backup original data successful, now start to upgrade!")
if err := cpBinary([]string{tmpDir + "/1panel"}, "/usr/local/bin/1panel"); err != nil {
if err := common.CopyFile(path.Join(tmpDir, "1panel"), "/usr/local/bin"); err != nil {
global.LOG.Errorf("upgrade 1panel failed, err: %v", err)
u.handleRollback(originalDir, 1)
return
}
if err := cpBinary([]string{tmpDir + "/1pctl"}, "/usr/local/bin/1pctl"); err != nil {
if err := common.CopyFile(path.Join(tmpDir, "1pctl"), "/usr/local/bin"); err != nil {
global.LOG.Errorf("upgrade 1pctl failed, err: %v", err)
u.handleRollback(originalDir, 2)
return
@@ -147,7 +147,7 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
return
}
if err := cpBinary([]string{tmpDir + "/1panel.service"}, "/etc/systemd/system/1panel.service"); err != nil {
if err := common.CopyFile(path.Join(tmpDir, "1panel.service"), "/etc/systemd/system"); err != nil {
global.LOG.Errorf("upgrade 1panel.service failed, err: %v", err)
u.handleRollback(originalDir, 3)
return
@@ -181,24 +181,23 @@ func (u *UpgradeService) handleBackup(fileOp files.FileOp, originalDir string) e
}
func (u *UpgradeService) handleRollback(originalDir string, errStep int) {
dbPath := global.CONF.System.DbPath + "/1Panel.db"
_ = settingRepo.Update("SystemStatus", "Free")
if err := cpBinary([]string{originalDir + "/1Panel.db"}, dbPath); err != nil {
if err := common.CopyFile(path.Join(originalDir, "1Panel.db"), global.CONF.System.DbPath); err != nil {
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
}
if err := cpBinary([]string{originalDir + "/1panel"}, "/usr/local/bin/1panel"); err != nil {
if err := common.CopyFile(path.Join(originalDir, "1panel"), "/usr/local/bin"); err != nil {
global.LOG.Errorf("rollback 1pctl failed, err: %v", err)
}
if errStep == 1 {
return
}
if err := cpBinary([]string{originalDir + "/1pctl"}, "/usr/local/bin/1pctl"); err != nil {
if err := common.CopyFile(path.Join(originalDir, "1pctl"), "/usr/local/bin"); err != nil {
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
}
if errStep == 2 {
return
}
if err := cpBinary([]string{originalDir + "/1panel.service"}, "/etc/systemd/system/1panel.service"); err != nil {
if err := common.CopyFile(path.Join(originalDir, "1panel.service"), "/etc/systemd/system"); err != nil {
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
}
}
+122 -84
View File
@@ -61,6 +61,7 @@ type IWebsiteService interface {
UpdateWebsite(req request.WebsiteUpdate) error
DeleteWebsite(req request.WebsiteDelete) error
GetWebsite(id uint) (response.WebsiteDTO, error)
CreateWebsiteDomain(create request.WebsiteDomainCreate) ([]model.WebsiteDomain, error)
GetWebsiteDomain(websiteId uint) ([]model.WebsiteDomain, error)
DeleteWebsiteDomain(domainId uint) error
@@ -75,10 +76,6 @@ type IWebsiteService interface {
ChangeDefaultServer(id uint) error
PreInstallCheck(req request.WebsiteInstallCheckReq) ([]response.WebsitePreInstallCheck, error)
GetWafConfig(req request.WebsiteWafReq) (response.WebsiteWafConfig, error)
UpdateWafConfig(req request.WebsiteWafUpdate) error
UpdateWafFile(req request.WebsiteWafFileUpdate) (err error)
GetPHPConfig(id uint) (*response.PHPConfig, error)
UpdatePHPConfig(req request.WebsitePHPConfigUpdate) error
UpdatePHPConfigFile(req request.WebsitePHPFileUpdate) error
@@ -182,8 +179,6 @@ func (w WebsiteService) GetWebsites() ([]response.WebsiteDTO, error) {
}
func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error) {
primaryDomainArray := strings.Split(create.PrimaryDomain, ":")
primaryDomain := primaryDomainArray[0]
alias := create.Alias
if common.ContainsChinese(alias) {
alias, err = common.PunycodeEncode(alias)
@@ -217,7 +212,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
defaultDate, _ := time.Parse(constant.DateLayout, constant.DefaultDate)
website := &model.Website{
PrimaryDomain: primaryDomain,
PrimaryDomain: create.PrimaryDomain,
Type: create.Type,
Alias: alias,
Remark: create.Remark,
@@ -327,12 +322,16 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
case constant.RuntimeNode:
website.Proxy = fmt.Sprintf("127.0.0.1:%d", runtime.Port)
}
}
if err = configDefaultNginx(website, domains, appInstall, runtime); err != nil {
return err
}
if err = createWafConfig(website, domains); err != nil {
return err
}
tx, ctx := helper.GetTxAndContext()
defer tx.Rollback()
if err = websiteRepo.Create(ctx, website); err != nil {
@@ -425,17 +424,18 @@ func (w WebsiteService) DeleteWebsite(req request.WebsiteDelete) error {
if err != nil {
return err
}
if err := delNginxConfig(website, req.ForceDelete); err != nil {
if err = delNginxConfig(website, req.ForceDelete); err != nil {
return err
}
if err = delWafConfig(website, req.ForceDelete); err != nil {
return err
}
if checkIsLinkApp(website) && req.DeleteApp {
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
if !reflect.DeepEqual(model.AppInstall{}, appInstall) {
if err := deleteAppInstall(appInstall, true, req.ForceDelete, true); err != nil && !req.ForceDelete {
appInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
if appInstall.ID > 0 {
if err = deleteAppInstall(appInstall, true, req.ForceDelete, true); err != nil && !req.ForceDelete {
return err
}
}
@@ -494,6 +494,53 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
return nil, err
}
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return nil, err
}
wafDataPath := path.Join(nginxInstall.GetPath(), "1pwaf", "data")
fileOp := files.NewFileOp()
if fileOp.Stat(wafDataPath) {
websitesConfigPath := path.Join(wafDataPath, "conf", "sites.json")
content, err := fileOp.GetContent(websitesConfigPath)
if err != nil {
return nil, err
}
var websitesArray []request.WafWebsite
if content != nil {
if err := json.Unmarshal(content, &websitesArray); err != nil {
return nil, err
}
}
for index, wafWebsite := range websitesArray {
if wafWebsite.Key == website.Alias {
wafSite := request.WafWebsite{
Key: website.Alias,
Domains: wafWebsite.Domains,
Host: wafWebsite.Host,
}
for _, domain := range domainModels {
wafSite.Domains = append(wafSite.Domains, domain.Domain)
if domain.Port != 80 && domain.Port != 443 {
wafSite.Host = append(wafSite.Host, domain.Domain+":"+string(rune(domain.Port)))
}
}
if len(wafSite.Host) == 0 {
wafSite.Host = []string{}
}
websitesArray[index] = wafSite
break
}
}
websitesContent, err := json.Marshal(websitesArray)
if err != nil {
return nil, err
}
if err := fileOp.SaveFileWithByte(websitesConfigPath, websitesContent, 0644); err != nil {
return nil, err
}
}
return domainModels, websiteDomainRepo.BatchCreate(context.TODO(), domainModels)
}
@@ -523,6 +570,7 @@ func (w WebsiteService) DeleteWebsiteDomain(domainId uint) error {
if oldDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(webSiteDomain.WebsiteID), websiteDomainRepo.WithDomain(webSiteDomain.Domain)); len(oldDomains) == 1 {
domains = append(domains, webSiteDomain.Domain)
}
if len(ports) > 0 || len(domains) > 0 {
stringBinds := make([]string, len(ports))
for i := 0; i < len(ports); i++ {
@@ -533,6 +581,63 @@ func (w WebsiteService) DeleteWebsiteDomain(domainId uint) error {
}
}
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
}
wafDataPath := path.Join(nginxInstall.GetPath(), "1pwaf", "data")
fileOp := files.NewFileOp()
if fileOp.Stat(wafDataPath) {
websitesConfigPath := path.Join(wafDataPath, "conf", "sites.json")
content, err := fileOp.GetContent(websitesConfigPath)
if err != nil {
return err
}
var websitesArray []request.WafWebsite
var newWebsitesArray []request.WafWebsite
if content != nil {
if err := json.Unmarshal(content, &websitesArray); err != nil {
return err
}
}
for _, wafWebsite := range websitesArray {
if wafWebsite.Key == website.Alias {
wafSite := wafWebsite
oldDomains := wafSite.Domains
var newDomains []string
for _, domain := range oldDomains {
if domain == webSiteDomain.Domain {
continue
}
newDomains = append(newDomains, domain)
}
wafSite.Domains = newDomains
oldHostArray := wafSite.Host
var newHostArray []string
for _, host := range oldHostArray {
if host == webSiteDomain.Domain+":"+string(rune(webSiteDomain.Port)) {
continue
}
newHostArray = append(newHostArray, host)
}
wafSite.Host = newHostArray
if len(wafSite.Host) == 0 {
wafSite.Host = []string{}
}
newWebsitesArray = append(newWebsitesArray, wafSite)
} else {
newWebsitesArray = append(newWebsitesArray, wafWebsite)
}
}
websitesContent, err := json.Marshal(newWebsitesArray)
if err != nil {
return err
}
if err = fileOp.SaveFileWithByte(websitesConfigPath, websitesContent, 0644); err != nil {
return err
}
}
return websiteDomainRepo.DeleteBy(context.TODO(), commonRepo.WithByID(domainId))
}
@@ -852,56 +957,6 @@ func (w WebsiteService) PreInstallCheck(req request.WebsiteInstallCheckReq) ([]r
return nil, nil
}
func (w WebsiteService) GetWafConfig(req request.WebsiteWafReq) (response.WebsiteWafConfig, error) {
var res response.WebsiteWafConfig
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
if err != nil {
return res, nil
}
res.Enable = true
if req.Key != "" {
params, err := getNginxParamsByKeys(constant.NginxScopeServer, []string{"set"}, &website)
if err != nil {
return res, nil
}
for _, param := range params {
if param.Params[0] == req.Key {
res.Enable = len(param.Params) > 1 && param.Params[1] == "on"
break
}
}
}
nginxFull, err := getNginxFull(&website)
if err != nil {
return res, nil
}
filePath := path.Join(nginxFull.SiteDir, "sites", website.Alias, "waf", "rules", req.Rule+".json")
content, err := os.ReadFile(filePath)
if err != nil {
return res, nil
}
res.Content = string(content)
return res, nil
}
func (w WebsiteService) UpdateWafConfig(req request.WebsiteWafUpdate) error {
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
if err != nil {
return err
}
updateValue := "on"
if !req.Enable {
updateValue = "off"
}
return updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{
{Name: "set", Params: []string{req.Key, updateValue}},
}, &website)
}
func (w WebsiteService) UpdateNginxConfigFile(req request.WebsiteNginxUpdate) error {
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {
@@ -1899,7 +1954,7 @@ func (w WebsiteService) UpdateAntiLeech(req request.NginxAntiLeechUpdate) (err e
Parameters: []string{"off"},
})
validDir := &components.Directive{
Name: "valid_referers",
Name: "valid_referrers",
Parameters: []string{},
}
if req.NoneRef {
@@ -1968,7 +2023,7 @@ func (w WebsiteService) GetAntiLeech(id uint) (*response.NginxAntiLeechRes, erro
}
lDirectives := location.GetBlock().GetDirectives()
for _, lDir := range lDirectives {
if lDir.GetName() == "valid_referers" {
if lDir.GetName() == "valid_referrers" {
res.Enable = true
params := lDir.GetParameters()
for _, param := range params {
@@ -2339,23 +2394,6 @@ func (w WebsiteService) UpdateRedirectFile(req request.NginxRedirectUpdate) (err
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
}
func (w WebsiteService) UpdateWafFile(req request.WebsiteWafFileUpdate) (err error) {
var (
website model.Website
nginxInstall model.AppInstall
)
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
if err != nil {
return err
}
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return
}
rulePath := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "waf", "rules", fmt.Sprintf("%s.json", req.Type))
return files.NewFileOp().WriteFile(rulePath, strings.NewReader(req.Content), 0755)
}
func (w WebsiteService) LoadWebsiteDirConfig(req request.WebsiteCommonReq) (*response.WebsiteDirConfig, error) {
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {
+143 -5
View File
@@ -1,7 +1,9 @@
package service
import (
"encoding/json"
"fmt"
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
"log"
"os"
"path"
@@ -197,7 +199,7 @@ func createWebsiteFolder(nginxInstall model.AppInstall, website *model.Website,
}
}
}
return fileOp.CopyDir(path.Join(nginxFolder, "www", "common", "waf", "rules"), path.Join(siteFolder, "waf"))
return nil
}
func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, appInstall *model.AppInstall, runtime *model.Runtime) error {
@@ -233,12 +235,8 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
server.UpdateServerName(serverNames)
siteFolder := path.Join("/www", "sites", website.Alias)
commonFolder := path.Join("/www", "common")
server.UpdateDirective("access_log", []string{path.Join(siteFolder, "log", "access.log")})
server.UpdateDirective("error_log", []string{path.Join(siteFolder, "log", "error.log")})
server.UpdateDirective("access_by_lua_file", []string{path.Join(commonFolder, "waf", "access.lua")})
server.UpdateDirective("set", []string{"$RulePath", path.Join(siteFolder, "waf", "rules")})
server.UpdateDirective("set", []string{"$logdir", path.Join(siteFolder, "log")})
rootIndex := path.Join("/www/sites", website.Alias, "index")
switch website.Type {
@@ -285,6 +283,99 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
return nil
}
func createWafConfig(website *model.Website, domains []model.WebsiteDomain) error {
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
}
wafDataPath := path.Join(nginxInstall.GetPath(), "1pwaf", "data")
fileOp := files.NewFileOp()
if !fileOp.Stat(wafDataPath) {
return nil
}
websitesConfigPath := path.Join(wafDataPath, "conf", "sites.json")
content, err := fileOp.GetContent(websitesConfigPath)
if err != nil {
return err
}
var websitesArray []request.WafWebsite
if len(content) != 0 {
if err := json.Unmarshal(content, &websitesArray); err != nil {
return err
}
}
wafWebsite := request.WafWebsite{
Key: website.Alias,
Domains: make([]string, 0),
Host: make([]string, 0),
}
for _, domain := range domains {
wafWebsite.Domains = append(wafWebsite.Domains, domain.Domain)
if domain.Port != 80 && domain.Port != 443 {
wafWebsite.Host = append(wafWebsite.Host, domain.Domain+":"+string(rune(domain.Port)))
}
}
websitesArray = append(websitesArray, wafWebsite)
websitesContent, err := json.Marshal(websitesArray)
if err != nil {
return err
}
if err := fileOp.SaveFileWithByte(websitesConfigPath, websitesContent, 0644); err != nil {
return err
}
var (
sitesDir = path.Join(wafDataPath, "sites")
defaultConfigPath = path.Join(wafDataPath, "conf", "siteConfig.json")
defaultRuleDir = path.Join(wafDataPath, "rules")
websiteDir = path.Join(sitesDir, website.Alias)
)
defaultConfigContent, err := fileOp.GetContent(defaultConfigPath)
if err != nil {
return err
}
if !fileOp.Stat(websiteDir) {
if err = fileOp.CreateDir(websiteDir, 0755); err != nil {
return err
}
}
defer func() {
if err != nil {
_ = fileOp.DeleteDir(websiteDir)
}
}()
if err = fileOp.SaveFileWithByte(path.Join(websiteDir, "config.json"), defaultConfigContent, 0644); err != nil {
return err
}
websiteRuleDir := path.Join(websiteDir, "rules")
if !fileOp.Stat(websiteRuleDir) {
if err := fileOp.CreateDir(websiteRuleDir, 0755); err != nil {
return err
}
}
defaultRulesName := []string{"acl", "args", "cookie", "defaultUaBlack", "defaultUrlBlack", "fileExt", "header", "methodWhite"}
for _, ruleName := range defaultRulesName {
srcPath := path.Join(defaultRuleDir, ruleName+".json")
if err = fileOp.Copy(srcPath, websiteRuleDir); err != nil {
return err
}
}
if err = opNginx(nginxInstall.ContainerName, constant.NginxCheck); err != nil {
return err
}
if err = opNginx(nginxInstall.ContainerName, constant.NginxReload); err != nil {
return err
}
return nil
}
func delNginxConfig(website model.Website, force bool) error {
nginxApp, err := appRepo.GetFirst(appRepo.WithKey(constant.AppOpenresty))
if err != nil {
@@ -310,6 +401,7 @@ func delNginxConfig(website model.Website, force bool) error {
}
sitePath := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name, "www", "sites", website.Alias)
if fileOp.Stat(sitePath) {
xpack.RemoveTamper(website.Alias)
_ = fileOp.DeleteDir(sitePath)
}
@@ -322,6 +414,52 @@ func delNginxConfig(website model.Website, force bool) error {
return nil
}
func delWafConfig(website model.Website, force bool) error {
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
}
wafDataPath := path.Join(nginxInstall.GetPath(), "1pwaf", "data")
fileOp := files.NewFileOp()
if !fileOp.Stat(wafDataPath) {
return nil
}
websitesConfigPath := path.Join(wafDataPath, "conf", "sites.json")
content, err := fileOp.GetContent(websitesConfigPath)
if err != nil {
return err
}
var websitesArray []request.WafWebsite
var newWebsiteArray []request.WafWebsite
if len(content) > 0 {
if err = json.Unmarshal(content, &websitesArray); err != nil {
return err
}
}
for _, wafWebsite := range websitesArray {
if wafWebsite.Key != website.Alias {
newWebsiteArray = append(newWebsiteArray, wafWebsite)
}
}
websitesContent, err := json.Marshal(newWebsiteArray)
if err != nil {
return err
}
if err := fileOp.SaveFileWithByte(websitesConfigPath, websitesContent, 0644); err != nil {
return err
}
_ = fileOp.DeleteDir(path.Join(wafDataPath, "sites", website.Alias))
if err := opNginx(nginxInstall.ContainerName, constant.NginxReload); err != nil {
if force {
return nil
}
return err
}
return nil
}
func addListenAndServerName(website model.Website, ports []int, domains []string) error {
nginxFull, err := getNginxFull(&website)
if err != nil {
+7 -3
View File
@@ -47,10 +47,14 @@ func WithDetail(Key string, detail interface{}, err error) BusinessError {
}
func WithErr(Key string, err error) BusinessError {
paramMap := map[string]interface{}{}
if err != nil {
paramMap["err"] = err
}
return BusinessError{
Msg: Key,
Detail: "",
Err: err,
Msg: Key,
Map: paramMap,
Err: err,
}
}
+1 -1
View File
@@ -22,7 +22,7 @@ type System struct {
Entrance string `mapstructure:"entrance"`
IsDemo bool `mapstructure:"is_demo"`
AppRepo string `mapstructure:"app_repo"`
ChangeUserInfo bool `mapstructure:"change_user_info"`
ChangeUserInfo string `mapstructure:"change_user_info"`
OneDriveID string `mapstructure:"one_drive_id"`
OneDriveSc string `mapstructure:"one_drive_sc"`
}
+13
View File
@@ -18,6 +18,8 @@ const (
CodeErrDomain = 409
CodeErrInternalServer = 500
CodeErrHeader = 406
CodeErrXpack = 410
)
// internal
@@ -43,6 +45,9 @@ var (
ErrNameIsExist = "ErrNameIsExist"
ErrDemoEnvironment = "ErrDemoEnvironment"
ErrCmdIllegal = "ErrCmdIllegal"
ErrXpackNotFound = "ErrXpackNotFound"
ErrXpackNotActive = "ErrXpackNotActive"
ErrXpackOutOfDate = "ErrXpackOutOfDate"
)
// app
@@ -150,3 +155,11 @@ var (
var (
ErrNotExistUser = "ErrNotExistUser"
)
// license
var (
ErrLicense = "ErrLicense"
ErrLicenseCheck = "ErrLicenseCheck"
ErrLicenseSave = "ErrLicenseSave"
ErrLicenseSync = "ErrLicenseSync"
)
+8 -7
View File
@@ -13,13 +13,14 @@ import (
)
var (
DB *gorm.DB
LOG *logrus.Logger
CONF configs.ServerConfig
VALID *validator.Validate
SESSION *psession.PSession
CACHE *badger_db.Cache
Viper *viper.Viper
DB *gorm.DB
MonitorDB *gorm.DB
LOG *logrus.Logger
CONF configs.ServerConfig
VALID *validator.Validate
SESSION *psession.PSession
CACHE *badger_db.Cache
Viper *viper.Viper
Cron *cron.Cron
MonitorCronID cron.EntryID
+17 -2
View File
@@ -74,6 +74,7 @@ ErrFileDownloadDir: "Download folder not supported"
ErrCmdNotFound: "{{ .name}} command does not exist, please install this command on the host first"
ErrSourcePathNotFound: "Source directory does not exist"
ErrFavoriteExist: "This path has been collected"
ErrInvalidChar: "Illegal characters are prohibited"
#website
ErrDomainIsExist: "Domain is already exist"
@@ -144,7 +145,7 @@ ErrNodeModulesNotFound: "The node_modules folder does not exist! Please edit the
#setting
ErrBackupInUsed: "The backup account is already being used in a cronjob and cannot be deleted."
ErrBackupCheck: "Backup account test connection failed {{ .err}}"
ErrOSSConn: "Unable to successfully request the latest version. Please check if the server can connect to the external network environment."
ErrOSSConn: "Unable to retrieve the latest version, please check if the server can connect to the external network."
ErrEntrance: "Security entrance information error. Please check and try again!"
#tool
@@ -171,4 +172,18 @@ ErrBanAction: "Setting failed, the current {{ .name }} service is unavailable, p
ErrScope: "Modification of this configuration is not supported"
ErrStateChange: "State modification failed"
ErrRuleExist: "Rule is Exist"
ErrRuleNotExist: "Rule is not Exist"
ErrRuleNotExist: "Rule is not Exist"
ErrParseIP: "IP format error"
ErrDefaultIP: "default is a reserved name, please change it to another name"
ErrGroupInUse: "The IP group is used by the black/white list and cannot be deleted"
ErrGroupExist: "IP group name already exists"
ErrIPRange: "Wrong IP range"
#license
ErrLicense: "License format error, please check and try again!"
ErrLicenseCheck: "License verification failed, please check and try again!"
ErrLicenseSave: "Failed to save license information, error {{ .err }}, please try again!"
ErrLicenseSync: "Failed to sync license information, no license information detected in the database!"
ErrXpackNotFound: "This section is a professional edition feature, please import the license first in Panel Settings-License interface"
ErrXpackNotActive: "This section is a professional edition feature, please synchronize the license status first in Panel Settings-License interface"
ErrXpackOutOfDate: "The current license has expired, please re-import the license in Panel Settings-License interface"
+16 -1
View File
@@ -23,6 +23,7 @@ ErrTypePortRange: '連接埠範圍需要在 1-65535 之間'
Success: "成功"
Failed: "失敗"
SystemRestart: "系統重啟導致任務中斷"
ErrInvalidChar: "禁止使用非法字元"
#app
ErrPortInUsed: "{{ .detail }} 端口已被佔用!"
@@ -145,7 +146,7 @@ ErrNodeModulesNotFound: "node_modules 文件夾不存在!請編輯運行環境
#setting
ErrBackupInUsed: "該備份帳號已在計劃任務中使用,無法刪除"
ErrBackupCheck: "備份帳號測試連接失敗 {{ .err}}"
ErrOSSConn: "無法成功請求最新版本,請檢查伺服器是否能夠連接到外部網絡環境。"
ErrOSSConn: "無法獲取最新版本,請確認伺服器是否能夠連接外部網路。"
ErrEntrance: "安全入口信息錯誤,請檢查後重試!"
#tool
@@ -173,3 +174,17 @@ ErrScope: "不支援修改此配置"
ErrStateChange: "狀態修改失敗"
ErrRuleExist: "規則名稱已存在"
ErrRuleNotExist: "規則不存在"
ErrParseIP: "IP 格式錯誤"
ErrDefaultIP: "default 為保留名稱,請更換其他名稱"
ErrGroupInUse: "IP 群組被黑/白名單使用,無法刪除"
ErrGroupExist: "IP 群組名稱已存在"
ErrIPRange: "IP 範圍錯誤"
#license
ErrLicense: "許可證格式錯誤,請檢查後重試!"
ErrLicenseCheck: "許可證校驗失敗,請檢查後重試!"
ErrLicenseSave: "許可證信息保存失敗,錯誤 {{ .err }}, 請重試!"
ErrLicenseSync: "許可證信息同步失敗,資料庫中未檢測到許可證信息!"
ErrXpackNotFound: "該部分為專業版功能,請先在 面板設置-許可證 界面導入許可證"
ErrXpackNotActive: "該部分為專業版功能,請先在 面板設置-許可證 界面同步許可證狀態"
ErrXpackOutOfDate: "當前許可證已過期,請重新在 面板設置-許可證 界面導入許可證"
+18 -2
View File
@@ -74,6 +74,7 @@ ErrFileDownloadDir: "不支持下载文件夹"
ErrCmdNotFound: "{{ .name}} 命令不存在,请先在宿主机安装此命令"
ErrSourcePathNotFound: "源目录不存在"
ErrFavoriteExist: "已收藏此路径"
ErrInvalidChar: "禁止使用非法字符"
#website
ErrDomainIsExist: "域名已存在"
@@ -144,7 +145,7 @@ ErrNodeModulesNotFound: "node_modules 文件夹不存在!请编辑运行环境
#setting
ErrBackupInUsed: "该备份账号已在计划任务中使用,无法删除"
ErrBackupCheck: "备份账号测试连接失败 {{ .err}}"
ErrOSSConn: "无法成功请求最新版本,请检查服务器是否能够连接到外部网络环境。"
ErrOSSConn: "无法获取最新版本,请确认服务器是否能够连接外部网络。"
ErrEntrance: "安全入口信息错误,请检查后重试!"
#tool
@@ -171,4 +172,19 @@ ErrBanAction: "设置失败,当前 {{ .name }} 服务不可用,请检查后
ErrScope: "不支持修改此配置"
ErrStateChange: "状态修改失败"
ErrRuleExist: "规则名称已存在"
ErrRuleNotExist: "规则不存在"
ErrRuleNotExist: "规则不存在"
ErrParseIP: "IP 格式错误"
ErrDefaultIP: "default 为保留名称,请更换其他名称"
ErrGroupInUse: "IP 组被黑/白名单使用,无法删除"
ErrGroupExist: "IP 组名称已存在"
ErrIPRange: "IP 范围错误"
#license
ErrLicense: "许可证格式错误,请检查后重试!"
ErrLicenseCheck: "许可证校验失败,请检查后重试!"
ErrLicenseSave: "许可证信息保存失败,错误 {{ .err }},请重试!"
ErrLicenseSync: "许可证信息同步失败,数据库中未检测到许可证信息!"
ErrXpackNotFound: "该部分为专业版功能,请先在 面板设置-许可证 界面导入许可证"
ErrXpackNotActive: "该部分为专业版功能,请先在 面板设置-许可证 界面同步许可证状态"
ErrXpackOutOfDate: "当前许可证已过期,请重新在 面板设置-许可证 界面导入许可证"
+35 -1
View File
@@ -4,6 +4,7 @@ import (
"fmt"
"log"
"os"
"path"
"time"
"github.com/1Panel-dev/1Panel/backend/global"
@@ -34,6 +35,7 @@ func Init() {
Colorful: false,
},
)
initMonitorDB(newLogger)
db, err := gorm.Open(sqlite.Open(fullPath), &gorm.Config{
DisableForeignKeyConstraintWhenMigrating: true,
@@ -45,7 +47,7 @@ func Init() {
_ = db.Exec("PRAGMA journal_mode = WAL;")
sqlDB, dbError := db.DB()
if dbError != nil {
panic(err)
panic(dbError)
}
sqlDB.SetConnMaxIdleTime(10)
sqlDB.SetMaxOpenConns(100)
@@ -54,3 +56,35 @@ func Init() {
global.DB = db
global.LOG.Info("init db successfully")
}
func initMonitorDB(newLogger logger.Interface) {
if _, err := os.Stat(global.CONF.System.DbPath); err != nil {
if err := os.MkdirAll(global.CONF.System.DbPath, os.ModePerm); err != nil {
panic(fmt.Errorf("init db dir failed, err: %v", err))
}
}
fullPath := path.Join(global.CONF.System.DbPath, "monitor.db")
if _, err := os.Stat(fullPath); err != nil {
if _, err := os.Create(fullPath); err != nil {
panic(fmt.Errorf("init db file failed, err: %v", err))
}
}
db, err := gorm.Open(sqlite.Open(fullPath), &gorm.Config{
DisableForeignKeyConstraintWhenMigrating: true,
Logger: newLogger,
})
if err != nil {
panic(err)
}
sqlDB, dbError := db.DB()
if dbError != nil {
panic(dbError)
}
sqlDB.SetConnMaxIdleTime(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
global.MonitorDB = db
global.LOG.Info("init monitor db successfully")
}
+40 -15
View File
@@ -4,6 +4,7 @@ import (
"encoding/base64"
"encoding/json"
"os"
"strings"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/app/repo"
@@ -57,21 +58,7 @@ func Init() {
global.LOG.Fatalf("init service before start failed, err: %v", err)
}
if global.CONF.System.ChangeUserInfo {
if err := settingRepo.Update("UserName", common.RandStrAndNum(10)); err != nil {
global.LOG.Fatalf("init username before start failed, err: %v", err)
}
pass, _ := encrypt.StringEncrypt(common.RandStrAndNum(10))
if err := settingRepo.Update("Password", pass); err != nil {
global.LOG.Fatalf("init password before start failed, err: %v", err)
}
if err := settingRepo.Update("SecurityEntrance", common.RandStrAndNum(10)); err != nil {
global.LOG.Fatalf("init entrance before start failed, err: %v", err)
}
sudo := cmd.SudoHandleCmd()
_, _ = cmd.Execf("%s sed -i '/CHANGE_USER_INFO=true/d' /usr/local/bin/1pctl", sudo)
}
handleUserInfo(global.CONF.System.ChangeUserInfo, settingRepo)
handleCronjobStatus()
handleSnapStatus()
@@ -173,3 +160,41 @@ func loadLocalDir() {
}
global.LOG.Errorf("error type dir: %T", varMap["dir"])
}
func handleUserInfo(tags string, settingRepo repo.ISettingRepo) {
if len(tags) == 0 {
return
}
if tags == "all" {
if err := settingRepo.Update("UserName", common.RandStrAndNum(10)); err != nil {
global.LOG.Fatalf("init username before start failed, err: %v", err)
}
pass, _ := encrypt.StringEncrypt(common.RandStrAndNum(10))
if err := settingRepo.Update("Password", pass); err != nil {
global.LOG.Fatalf("init password before start failed, err: %v", err)
}
if err := settingRepo.Update("SecurityEntrance", common.RandStrAndNum(10)); err != nil {
global.LOG.Fatalf("init entrance before start failed, err: %v", err)
}
return
}
if strings.Contains(global.CONF.System.ChangeUserInfo, "username") {
if err := settingRepo.Update("UserName", common.RandStrAndNum(10)); err != nil {
global.LOG.Fatalf("init username before start failed, err: %v", err)
}
}
if strings.Contains(global.CONF.System.ChangeUserInfo, "password") {
pass, _ := encrypt.StringEncrypt(common.RandStrAndNum(10))
if err := settingRepo.Update("Password", pass); err != nil {
global.LOG.Fatalf("init password before start failed, err: %v", err)
}
}
if strings.Contains(global.CONF.System.ChangeUserInfo, "entrance") {
if err := settingRepo.Update("SecurityEntrance", common.RandStrAndNum(10)); err != nil {
global.LOG.Fatalf("init entrance before start failed, err: %v", err)
}
}
sudo := cmd.SudoHandleCmd()
_, _ = cmd.Execf("%s sed -i '/CHANGE_USER_INFO=%v/d' /usr/local/bin/1pctl", sudo, global.CONF.System.ChangeUserInfo)
}
+6
View File
@@ -75,6 +75,12 @@ func Init() {
migrations.AddSnapshotIgnore,
migrations.AddDatabaseIsDelete,
migrations.AddXpackHideMenu,
migrations.AddCronjobCommand,
migrations.NewMonitorDB,
migrations.AddNoAuthSetting,
migrations.UpdateXpackHideMenu,
migrations.AddMenuTabsSetting,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)
+113
View File
@@ -2,6 +2,7 @@ package migrations
import (
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/go-gormigrate/gormigrate/v2"
"gorm.io/gorm"
)
@@ -25,3 +26,115 @@ var AddDatabaseIsDelete = &gormigrate.Migration{
return nil
},
}
var AddXpackHideMenu = &gormigrate.Migration{
ID: "20240328-add-xpack-hide-menu",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "XpackHideMenu", Value: "{\"id\":\"1\",\"label\":\"/xpack\",\"isCheck\":true,\"title\":\"xpack.menu\",\"children\":[{\"id\":\"2\",\"title\":\"xpack.waf.name\",\"path\":\"/xpack/waf/dashboard\",\"label\":\"Dashboard\",\"isCheck\":true},{\"id\":\"3\",\"title\":\"xpack.tamper.tamper\",\"path\":\"/xpack/tamper\",\"label\":\"Tamper\",\"isCheck\":true},{\"id\":\"4\",\"title\":\"xpack.setting.setting\",\"path\":\"/xpack/setting\",\"label\":\"XSetting\",\"isCheck\":true}]}"}).Error; err != nil {
return err
}
return nil
},
}
var AddCronjobCommand = &gormigrate.Migration{
ID: "20240403-add-cronjob-command",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Cronjob{}); err != nil {
return err
}
return nil
},
}
var NewMonitorDB = &gormigrate.Migration{
ID: "20240408-new-monitor-db",
Migrate: func(tx *gorm.DB) error {
var (
bases []model.MonitorBase
ios []model.MonitorIO
networks []model.MonitorNetwork
)
_ = tx.Find(&bases).Error
_ = tx.Find(&ios).Error
_ = tx.Find(&networks).Error
if err := global.MonitorDB.AutoMigrate(&model.MonitorBase{}, &model.MonitorIO{}, &model.MonitorNetwork{}); err != nil {
return err
}
_ = global.MonitorDB.Exec("DELETE FROM monitor_bases").Error
_ = global.MonitorDB.Exec("DELETE FROM monitor_ios").Error
_ = global.MonitorDB.Exec("DELETE FROM monitor_networks").Error
if len(bases) != 0 {
for i := 0; i <= len(bases)/200; i++ {
var itemData []model.MonitorBase
if 200*(i+1) <= len(bases) {
itemData = bases[200*i : 200*(i+1)]
} else {
itemData = bases[200*i:]
}
if err := global.MonitorDB.Create(&itemData).Error; err != nil {
return err
}
}
}
if len(ios) != 0 {
for i := 0; i <= len(ios)/200; i++ {
var itemData []model.MonitorIO
if 200*(i+1) <= len(ios) {
itemData = ios[200*i : 200*(i+1)]
} else {
itemData = ios[200*i:]
}
if err := global.MonitorDB.Create(&itemData).Error; err != nil {
return err
}
}
}
if len(networks) != 0 {
for i := 0; i <= len(networks)/200; i++ {
var itemData []model.MonitorNetwork
if 200*(i+1) <= len(networks) {
itemData = networks[200*i : 200*(i+1)]
} else {
itemData = networks[200*i:]
}
if err := global.MonitorDB.Create(&itemData).Error; err != nil {
return err
}
}
}
return nil
},
}
var AddNoAuthSetting = &gormigrate.Migration{
ID: "20240328-add-no-auth-setting",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "NoAuthSetting", Value: "200"}).Error; err != nil {
return err
}
return nil
},
}
var UpdateXpackHideMenu = &gormigrate.Migration{
ID: "20240411-update-xpack-hide-menu",
Migrate: func(tx *gorm.DB) error {
if err := tx.Model(&model.Setting{}).Where("key", "XpackHideMenu").Updates(map[string]interface{}{"value": "{\"id\":\"1\",\"label\":\"/xpack\",\"isCheck\":true,\"title\":\"xpack.menu\",\"children\":[{\"id\":\"2\",\"title\":\"xpack.waf.name\",\"path\":\"/xpack/waf/dashboard\",\"label\":\"Dashboard\",\"isCheck\":true},{\"id\":\"3\",\"title\":\"xpack.tamper.tamper\",\"path\":\"/xpack/tamper\",\"label\":\"Tamper\",\"isCheck\":true},{\"id\":\"4\",\"title\":\"xpack.gpu.gpu\",\"path\":\"/xpack/gpu\",\"label\":\"GPU\",\"isCheck\":true},{\"id\":\"5\",\"title\":\"xpack.setting.setting\",\"path\":\"/xpack/setting\",\"label\":\"XSetting\",\"isCheck\":true}]}"}).Error; err != nil {
return err
}
return nil
},
}
var AddMenuTabsSetting = &gormigrate.Migration{
ID: "20240415-add-menu-tabs-setting",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "MenuTabs", Value: "disable"}).Error; err != nil {
return err
}
return nil
},
}
+6 -1
View File
@@ -2,6 +2,9 @@ package router
import (
"fmt"
"net/http"
v1 "github.com/1Panel-dev/1Panel/backend/app/api/v1"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/i18n"
"github.com/1Panel-dev/1Panel/backend/middleware"
@@ -12,7 +15,6 @@ import (
"github.com/gin-gonic/gin"
swaggerfiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
"net/http"
)
var (
@@ -21,6 +23,7 @@ var (
func setWebStatic(rootRouter *gin.RouterGroup) {
rootRouter.StaticFS("/public", http.FS(web.Favicon))
rootRouter.Static("/api/v1/images", "./uploads")
rootRouter.Use(func(c *gin.Context) {
c.Next()
})
@@ -61,6 +64,8 @@ func Routers() *gin.Engine {
PublicGroup.GET("/health", func(c *gin.Context) {
c.JSON(200, "ok")
})
baseApi := v1.ApiGroupApp.BaseApi
PublicGroup.GET("/api/v1/respagecode", baseApi.GetResponsePage)
PublicGroup.Use(gzip.Gzip(gzip.DefaultCompression))
setWebStatic(PublicGroup)
}
+4 -4
View File
@@ -96,7 +96,7 @@ func Init() {
global.CONF.System.Username = username
global.CONF.System.Password = password
global.CONF.System.Entrance = entrance
global.CONF.System.ChangeUserInfo = loadChange()
global.CONF.System.ChangeUserInfo = loadChangeInfo()
global.Viper = v
}
@@ -112,10 +112,10 @@ func loadParams(param string) string {
return info
}
func loadChange() bool {
func loadChangeInfo() string {
stdout, err := cmd.Exec("grep '^CHANGE_USER_INFO=' /usr/bin/1pctl | cut -d'=' -f2")
if err != nil {
return false
return ""
}
return stdout == "true\n"
return strings.ReplaceAll(stdout, "\n", "")
}
-1
View File
@@ -6,7 +6,6 @@ func commonGroups() []CommonRouter {
&DashboardRouter{},
&HostRouter{},
&ContainerRouter{},
&MonitorRouter{},
&LogRouter{},
&FileRouter{},
&ToolboxRouter{},
+5
View File
@@ -35,6 +35,11 @@ func (s *HostRouter) InitRouter(Router *gin.RouterGroup) {
hostRouter.POST("/firewall/update/addr", baseApi.UpdateAddrRule)
hostRouter.POST("/firewall/update/description", baseApi.UpdateFirewallDescription)
hostRouter.POST("/monitor/search", baseApi.LoadMonitor)
hostRouter.POST("/monitor/clean", baseApi.CleanMonitor)
hostRouter.GET("/monitor/netoptions", baseApi.GetNetworkOptions)
hostRouter.GET("/monitor/iooptions", baseApi.GetIOOptions)
hostRouter.GET("/ssh/conf", baseApi.LoadSSHConf)
hostRouter.POST("/ssh/search", baseApi.GetSSHInfo)
hostRouter.POST("/ssh/update", baseApi.UpdateSSH)
-23
View File
@@ -1,23 +0,0 @@
package router
import (
v1 "github.com/1Panel-dev/1Panel/backend/app/api/v1"
"github.com/1Panel-dev/1Panel/backend/middleware"
"github.com/gin-gonic/gin"
)
type MonitorRouter struct{}
func (s *MonitorRouter) InitRouter(Router *gin.RouterGroup) {
monitorRouter := Router.Group("monitors").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
baseApi := v1.ApiGroupApp.BaseApi
{
monitorRouter.POST("/search", baseApi.LoadMonitor)
monitorRouter.GET("/netoptions", baseApi.GetNetworkOptions)
monitorRouter.GET("/iooptions", baseApi.GetIOOptions)
}
}
+1 -1
View File
@@ -23,13 +23,13 @@ func (s *SettingRouter) InitRouter(Router *gin.RouterGroup) {
settingRouter.GET("/search/available", baseApi.GetSystemAvailable)
settingRouter.POST("/update", baseApi.UpdateSetting)
settingRouter.GET("/interface", baseApi.LoadInterfaceAddr)
settingRouter.POST("/menu/update", baseApi.UpdateMenu)
settingRouter.POST("/bind/update", baseApi.UpdateBindInfo)
settingRouter.POST("/port/update", baseApi.UpdatePort)
settingRouter.POST("/ssl/update", baseApi.UpdateSSL)
settingRouter.GET("/ssl/info", baseApi.LoadFromCert)
settingRouter.POST("/ssl/download", baseApi.DownloadSSL)
settingRouter.POST("/password/update", baseApi.UpdatePassword)
settingRouter.POST("/monitor/clean", baseApi.CleanMonitor)
settingRouter.POST("/mfa", baseApi.LoadMFA)
settingRouter.POST("/mfa/bind", baseApi.MFABind)
-4
View File
@@ -39,10 +39,6 @@ func (a *WebsiteRouter) InitRouter(Router *gin.RouterGroup) {
groupRouter.GET("/:id/https", baseApi.GetHTTPSConfig)
groupRouter.POST("/:id/https", baseApi.UpdateHTTPSConfig)
groupRouter.POST("/waf/config", baseApi.GetWebsiteWafConfig)
groupRouter.POST("/waf/update", baseApi.UpdateWebsiteWafConfig)
groupRouter.POST("/waf/file/update", baseApi.UpdateWebsiteWafFile)
groupRouter.GET("/php/config/:id", baseApi.GetWebsitePHPConfig)
groupRouter.POST("/php/config", baseApi.UpdateWebsitePHPConfig)
groupRouter.POST("/php/update", baseApi.UpdatePHPFile)
+5 -7
View File
@@ -6,7 +6,7 @@ import (
"path"
"path/filepath"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
)
type localClient struct {
@@ -54,9 +54,8 @@ func (c localClient) Upload(src, target string) (bool, error) {
}
}
stdout, err := cmd.Execf("\\cp -f %s %s", src, path.Join(c.dir, target))
if err != nil {
return false, fmt.Errorf("cp file failed, stdout: %v, err: %v", stdout, err)
if err := common.CopyFile(src, target); err != nil {
return false, fmt.Errorf("cp file failed, err: %v", err)
}
return true, nil
}
@@ -73,9 +72,8 @@ func (c localClient) Download(src, target string) (bool, error) {
}
}
stdout, err := cmd.Execf("\\cp -f %s %s", localPath, target)
if err != nil {
return false, fmt.Errorf("cp file failed, stdout: %v, err: %v", stdout, err)
if err := common.CopyFile(localPath, target); err != nil {
return false, fmt.Errorf("cp file failed, err: %v", err)
}
return true, nil
}
@@ -120,10 +120,12 @@ func (m minIoClient) Download(src, target string) (bool, error) {
if err != nil {
return false, err
}
defer object.Close()
localFile, err := os.Create(target)
if err != nil {
return false, err
}
defer localFile.Close()
if _, err = io.Copy(localFile, object); err != nil {
return false, err
}
+1 -1
View File
@@ -178,7 +178,7 @@ func CheckIllegal(args ...string) bool {
if strings.Contains(arg, "&") || strings.Contains(arg, "|") || strings.Contains(arg, ";") ||
strings.Contains(arg, "$") || strings.Contains(arg, "'") || strings.Contains(arg, "`") ||
strings.Contains(arg, "(") || strings.Contains(arg, ")") || strings.Contains(arg, "\"") ||
strings.Contains(arg, "\n") || strings.Contains(arg, "\r") {
strings.Contains(arg, "\n") || strings.Contains(arg, "\r") || strings.Contains(arg, ">") {
return true
}
}
+61
View File
@@ -6,6 +6,8 @@ import (
"io"
mathRand "math/rand"
"net"
"os"
"path"
"reflect"
"regexp"
"sort"
@@ -43,6 +45,35 @@ func CompareVersion(version1, version2 string) bool {
return false
}
func ComparePanelVersion(version1, version2 string) bool {
if version1 == version2 {
return false
}
version1s := strings.Split(version1, ".")
version2s := strings.Split(version2, ".")
if len(version2s) > len(version1s) {
for i := 0; i < len(version2s)-len(version1s); i++ {
version1s = append(version1s, "0")
}
}
if len(version1s) > len(version2s) {
for i := 0; i < len(version1s)-len(version2s); i++ {
version2s = append(version2s, "0")
}
}
n := min(len(version1s), len(version2s))
for i := 0; i < n; i++ {
if version1s[i] == version2s[i] {
continue
} else {
return version1s[i] > version2s[i]
}
}
return true
}
func extractNumbers(version string) []string {
var numbers []string
start := -1
@@ -82,6 +113,36 @@ func GetSortedVersions(versions []string) []string {
return versions
}
func CopyFile(src, dst string) error {
source, err := os.Open(src)
if err != nil {
return err
}
defer source.Close()
if path.Base(src) != path.Base(dst) {
dst = path.Join(dst, path.Base(src))
}
if _, err := os.Stat(path.Dir(dst)); err != nil {
if os.IsNotExist(err) {
_ = os.MkdirAll(path.Dir(dst), os.ModePerm)
}
}
target, err := os.OpenFile(dst+"_temp", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
if err != nil {
return err
}
defer target.Close()
if _, err = io.Copy(target, source); err != nil {
return err
}
if err = os.Rename(dst+"_temp", dst); err != nil {
return err
}
return nil
}
func IsCrossVersion(version1, version2 string) bool {
version1s := strings.Split(version1, ".")
version2s := strings.Split(version2, ".")
+27 -9
View File
@@ -54,7 +54,17 @@ func (f FileOp) GetContent(dst string) ([]byte, error) {
}
func (f FileOp) CreateDir(dst string, mode fs.FileMode) error {
return f.Fs.MkdirAll(dst, mode)
if err := f.Fs.MkdirAll(dst, mode); err != nil {
return err
}
modStr := fmt.Sprintf("%o", mode)
modeInt, err := strconv.ParseInt(modStr, 10, 64)
if err != nil {
modeInt = 0755
}
return f.ChmodR(dst, modeInt, true)
}
func (f FileOp) CreateFile(dst string) error {
@@ -64,6 +74,14 @@ func (f FileOp) CreateFile(dst string) error {
return nil
}
func (f FileOp) CreateFileWithMode(dst string, mode fs.FileMode) error {
file, err := f.Fs.OpenFile(dst, os.O_CREATE, mode)
if err != nil {
return err
}
return file.Close()
}
func (f FileOp) LinkFile(source string, dst string, isSymlink bool) error {
if isSymlink {
osFs := afero.OsFs{}
@@ -149,7 +167,7 @@ func (f FileOp) ChownR(dst string, uid string, gid string, sub bool) error {
if cmd.HasNoPasswordSudo() {
cmdStr = fmt.Sprintf("sudo %s", cmdStr)
}
if msg, err := cmd.ExecWithTimeOut(cmdStr, 2*time.Second); err != nil {
if msg, err := cmd.ExecWithTimeOut(cmdStr, 10*time.Second); err != nil {
if msg != "" {
return errors.New(msg)
}
@@ -166,7 +184,7 @@ func (f FileOp) ChmodR(dst string, mode int64, sub bool) error {
if cmd.HasNoPasswordSudo() {
cmdStr = fmt.Sprintf("sudo %s", cmdStr)
}
if msg, err := cmd.ExecWithTimeOut(cmdStr, 2*time.Second); err != nil {
if msg, err := cmd.ExecWithTimeOut(cmdStr, 10*time.Second); err != nil {
if msg != "" {
return errors.New(msg)
}
@@ -314,7 +332,7 @@ func (f FileOp) Cut(oldPaths []string, dst, name string, cover bool) error {
coverFlag = "-f"
}
cmdStr := fmt.Sprintf(`mv %s "%s" "%s"`, coverFlag, p, dstPath)
cmdStr := fmt.Sprintf(`mv %s '%s' '%s'`, coverFlag, p, dstPath)
if err := cmd.ExecCmd(cmdStr); err != nil {
return err
}
@@ -323,7 +341,7 @@ func (f FileOp) Cut(oldPaths []string, dst, name string, cover bool) error {
}
func (f FileOp) Mv(oldPath, dstPath string) error {
cmdStr := fmt.Sprintf(`mv "%s" "%s"`, oldPath, dstPath)
cmdStr := fmt.Sprintf(`mv '%s' '%s'`, oldPath, dstPath)
if err := cmd.ExecCmd(cmdStr); err != nil {
return err
}
@@ -377,13 +395,13 @@ func (f FileOp) CopyAndReName(src, dst, name string, cover bool) error {
if name != "" && !cover {
dstPath = filepath.Join(dst, name)
}
return cmd.ExecCmd(fmt.Sprintf(`cp -rf "%s" "%s"`, src, dstPath))
return cmd.ExecCmd(fmt.Sprintf(`cp -rf '%s' '%s'`, src, dstPath))
} else {
dstPath := filepath.Join(dst, name)
if cover {
dstPath = dst
}
return cmd.ExecCmd(fmt.Sprintf(`cp -f "%s" "%s"`, src, dstPath))
return cmd.ExecCmd(fmt.Sprintf(`cp -f '%s' '%s'`, src, dstPath))
}
}
@@ -396,12 +414,12 @@ func (f FileOp) CopyDir(src, dst string) error {
if err = f.Fs.MkdirAll(dstDir, srcInfo.Mode()); err != nil {
return err
}
return cmd.ExecCmd(fmt.Sprintf(`cp -rf "%s" "%s"`, src, dst+"/"))
return cmd.ExecCmd(fmt.Sprintf(`cp -rf '%s' '%s'`, src, dst+"/"))
}
func (f FileOp) CopyFile(src, dst string) error {
dst = filepath.Clean(dst) + string(filepath.Separator)
return cmd.ExecCmd(fmt.Sprintf(`cp -f "%s" "%s"`, src, dst+"/"))
return cmd.ExecCmd(fmt.Sprintf(`cp -f '%s' '%s'`, src, dst+"/"))
}
func (f FileOp) GetDirSize(path string) (float64, error) {
+14 -12
View File
@@ -311,20 +311,22 @@ func (f *FileInfo) listChildren(option FileOption) error {
}
func (f *FileInfo) getContent() error {
if f.Size <= 10*1024*1024 {
afs := &afero.Afero{Fs: f.Fs}
cByte, err := afs.ReadFile(f.Path)
if err != nil {
return nil
}
if len(cByte) > 0 && DetectBinary(cByte) {
return buserr.New(constant.ErrFileCanNotRead)
}
f.Content = string(cByte)
return nil
} else {
if IsBlockDevice(f.FileMode) {
return buserr.New(constant.ErrFileCanNotRead)
}
if f.Size > 10*1024*1024 {
return buserr.New("ErrFileToLarge")
}
afs := &afero.Afero{Fs: f.Fs}
cByte, err := afs.ReadFile(f.Path)
if err != nil {
return nil
}
if len(cByte) > 0 && DetectBinary(cByte) {
return buserr.New(constant.ErrFileCanNotRead)
}
f.Content = string(cByte)
return nil
}
func DetectBinary(buf []byte) bool {
+36
View File
@@ -2,6 +2,7 @@ package files
import (
"bufio"
"fmt"
"github.com/spf13/afero"
"io"
"net/http"
@@ -9,6 +10,7 @@ import (
"os/user"
"path/filepath"
"strconv"
"strings"
"sync"
)
@@ -16,6 +18,10 @@ func IsSymlink(mode os.FileMode) bool {
return mode&os.ModeSymlink != 0
}
func IsBlockDevice(mode os.FileMode) bool {
return mode&os.ModeDevice != 0 && mode&os.ModeCharDevice == 0
}
func GetMimeType(path string) string {
file, err := os.Open(path)
if err != nil {
@@ -113,3 +119,33 @@ func ReadFileByLine(filename string, page, pageSize int) ([]string, bool, error)
return lines, isEndOfFile, nil
}
func GetParentMode(path string) (os.FileMode, error) {
absPath, err := filepath.Abs(path)
if err != nil {
return 0, err
}
for {
fileInfo, err := os.Stat(absPath)
if err == nil {
return fileInfo.Mode() & os.ModePerm, nil
}
if !os.IsNotExist(err) {
return 0, err
}
parentDir := filepath.Dir(absPath)
if parentDir == absPath {
return 0, fmt.Errorf("no existing directory found in the path: %s", path)
}
absPath = parentDir
}
}
func IsInvalidChar(name string) bool {
if strings.Contains(name, "&") {
return true
}
return false
}
+1 -1
View File
@@ -61,7 +61,7 @@ func NewParserFromLexer(lexer *lexer) *Parser {
parser.directiveWrappers = map[string]func(*components.Directive) components.IDirective{
"server": func(directive *components.Directive) components.IDirective {
return parser.wrapServer(directive)
return parser.parseUpstreamServer(directive)
},
}
-79
View File
@@ -1,79 +0,0 @@
package ps
import (
"fmt"
"strconv"
"testing"
"time"
"github.com/shirou/gopsutil/v3/host"
"github.com/shirou/gopsutil/v3/process"
)
func TestPs(t *testing.T) {
processes, err := process.Processes()
if err != nil {
panic(err)
}
for _, pro := range processes {
var (
name string
parentID int32
userName string
status string
startTime string
numThreads int32
numConnections int
cpuPercent float64
//mem string
rss string
ioRead string
ioWrite string
)
name, _ = pro.Name()
parentID, _ = pro.Ppid()
userName, _ = pro.Username()
array, err := pro.Status()
if err == nil {
status = array[0]
}
createTime, err := pro.CreateTime()
if err == nil {
t := time.Unix(createTime/1000, 0)
startTime = t.Format("2006-1-2 15:04:05")
}
numThreads, _ = pro.NumThreads()
connections, err := pro.Connections()
if err == nil && len(connections) > 0 {
numConnections = len(connections)
}
cpuPercent, _ = pro.CPUPercent()
menInfo, err := pro.MemoryInfo()
if err == nil {
rssF := float64(menInfo.RSS) / 1048576
rss = fmt.Sprintf("%.2f", rssF)
}
ioStat, err := pro.IOCounters()
if err == nil {
ioWrite = strconv.FormatUint(ioStat.WriteBytes, 10)
ioRead = strconv.FormatUint(ioStat.ReadBytes, 10)
}
cmdLine, err := pro.Cmdline()
if err == nil {
fmt.Println(cmdLine)
}
ss, err := pro.Terminal()
if err == nil {
fmt.Println(ss)
}
fmt.Printf("Name: %s PId: %v ParentID: %v Username: %v status:%s startTime: %s numThreads: %v numConnections:%v cpuPercent:%v rss:%s MB IORead: %s IOWrite: %s \n",
name, pro.Pid, parentID, userName, status, startTime, numThreads, numConnections, cpuPercent, rss, ioRead, ioWrite)
}
users, err := host.Users()
if err == nil {
fmt.Println(users)
}
}
-457
View File
@@ -1,457 +0,0 @@
package ssl
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/json"
"encoding/pem"
"fmt"
"github.com/go-acme/lego/v4/providers/dns/cloudflare"
"os"
"path"
"testing"
"time"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"gopkg.in/yaml.v3"
"github.com/go-acme/lego/v4/acme/api"
"github.com/go-acme/lego/v4/certcrypto"
"github.com/go-acme/lego/v4/certificate"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/lego"
"github.com/go-acme/lego/v4/registration"
"log"
)
type AppList struct {
Version string `json:"version"`
Tags []Tag `json:"tags"`
Items []AppDefine `json:"items"`
}
type NewAppDefine struct {
Name string `yaml:"name"`
Tags []string `yaml:"tags"`
Title string `yaml:"title"`
Type string `yaml:"type"`
Description string `yaml:"description"`
AdditionalProperties AppDefine `yaml:"additionalProperties"`
}
type NewAppConfig struct {
AdditionalProperties map[string]interface{} `yaml:"additionalProperties"`
}
type AppDefine struct {
Key string `json:"key" yaml:"key"`
Name string `json:"name" yaml:"name"`
Tags []string `json:"tags" yaml:"tags"`
Versions []string `json:"versions" yaml:"-"`
ShortDescZh string `json:"shortDescZh" yaml:"shortDescZh"`
ShortDescEn string `json:"shortDescEn" yaml:"shortDescEn"`
Type string `json:"type" yaml:"type"`
CrossVersionUpdate bool `json:"crossVersionUpdate" yaml:"crossVersionUpdate"`
Limit int `json:"limit" yaml:"limit"`
Recommend int `json:"recommend" yaml:"recommend"`
Website string `json:"website" yaml:"website"`
Github string `json:"github" yaml:"github"`
Document string `json:"document" yaml:"document"`
}
type Tag struct {
Key string `json:"key" yaml:"key"`
Name string `json:"name" yaml:"name"`
}
func getTagName(key string, tags []Tag) string {
result := "应用"
for _, tag := range tags {
if tag.Key == key {
return tag.Name
}
}
return result
}
func TestAppToV2(t *testing.T) {
oldDir := "/Users/wangzhengkun/projects/github.com/1Panel-dev/appstore/apps"
newDir := "/Users/wangzhengkun/projects/github.com/1Panel-dev/appstore/apps_new"
listJsonDir := path.Join(oldDir, "list.json")
fileOp := files.NewFileOp()
content, err := fileOp.GetContent(listJsonDir)
if err != nil {
panic(err)
}
appList := &AppList{}
if err = json.Unmarshal(content, appList); err != nil {
panic(err)
}
for _, appDefine := range appList.Items {
newAppDefine := &NewAppDefine{
Name: appDefine.Name,
Tags: []string{getTagName(appDefine.Tags[0], appList.Tags)},
Type: getTagName(appDefine.Tags[0], appList.Tags),
Title: appDefine.ShortDescZh,
Description: appDefine.ShortDescZh,
AdditionalProperties: appDefine,
}
yamlContent, err := yaml.Marshal(newAppDefine)
if err != nil {
panic(err)
}
oldAppDir := oldDir + "/" + appDefine.Key
newAppDir := newDir + "/" + appDefine.Key
if !fileOp.Stat(newAppDir) {
if err := fileOp.CreateDir(newAppDir, 0755); err != nil {
panic(err)
}
}
// logo
oldLogoPath := oldAppDir + "/metadata/logo.png"
if err := fileOp.CopyFile(oldLogoPath, newAppDir); err != nil {
panic(err)
}
for _, version := range appDefine.Versions {
oldVersionDir := oldAppDir + "/versions/" + version
if err := fileOp.CopyDir(oldVersionDir, newAppDir); err != nil {
panic(err)
}
oldConfigPath := oldVersionDir + "/config.json"
configContent, err := fileOp.GetContent(oldConfigPath)
if err != nil {
panic(err)
}
var result map[string]interface{}
if err := json.Unmarshal(configContent, &result); err != nil {
panic(err)
}
newConfigD := &NewAppConfig{}
newConfigD.AdditionalProperties = result
configYamlByte, err := yaml.Marshal(newConfigD)
if err != nil {
panic(err)
}
newVersionDir := newAppDir + "/" + version
if err := fileOp.WriteFile(newVersionDir+"/data.yml", bytes.NewReader(configYamlByte), 0755); err != nil {
panic(err)
}
if err := fileOp.WriteFile(newAppDir+"/data.yml", bytes.NewReader(yamlContent), 0755); err != nil {
panic(err)
}
_ = fileOp.DeleteFile(newVersionDir + "/config.json")
oldReadMefile := newVersionDir + "/README.md"
_ = fileOp.Cut([]string{oldReadMefile}, newAppDir, "", false)
_ = fileOp.DeleteFile(oldReadMefile)
}
}
}
func TestCreatePrivate(t *testing.T) {
priKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
derStream := x509.MarshalPKCS1PrivateKey(priKey)
block := &pem.Block{
Type: "privateKey",
Bytes: derStream,
}
file, err := os.Create("private.key")
if err != nil {
return
}
if err = pem.Encode(file, block); err != nil {
return
}
}
func TestSSL(t *testing.T) {
priKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Fatalf("Failed to generate private key: %v", err)
}
myUser := AcmeUser{
Email: "you2@yours.com",
Key: priKey,
}
config := lego.NewConfig(&myUser)
//config.CADirURL = "https://acme-v02.api.letsencrypt.org/directory"
config.CADirURL = "https://acme-staging-v02.api.letsencrypt.org/directory"
config.CADirURL = "https://acme.zerossl.com/v2/DV90"
config.UserAgent = "acm_go/0.0.1"
config.Certificate.KeyType = certcrypto.RSA2048
//config.HTTPClient = httpClient
client, err := lego.NewClient(config)
if err != nil {
panic(err)
}
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
if err != nil {
panic(err)
}
myUser.Registration = reg
//获取证书
//certificates, err := client.Certificate.Get("https://acme-v02.api.letsencrypt.org/acme/cert/049cb98a8b3ea5a73f08dcdcf89263af8323", true)
//if err != nil {
// panic(err)
//}
//certificates, err = client.Certificate.Renew(*certificates, true, true, "")
//if err != nil {
// panic(err)
//}
//申请证书
ewDomain := "tuxpanel.com"
request := certificate.ObtainRequest{
Domains: []string{ewDomain},
// 证书链
Bundle: true,
}
err = client.Challenge.SetDNS01Provider(&manualDnsProvider{}, dns01.AddDNSTimeout(6*time.Minute))
if err != nil {
panic(err)
}
core, err := api.New(config.HTTPClient, config.UserAgent, config.CADirURL, reg.URI, priKey)
if err != nil {
panic(err)
}
order, err := core.Orders.New([]string{ewDomain})
if err != nil {
panic(err)
}
auth, err := core.Authorizations.Get(order.Authorizations[0])
if err != nil {
panic(err)
}
domain := challenge.GetTargetedDomain(auth)
chlng, err := challenge.FindChallenge(challenge.DNS01, auth)
if err != nil {
panic(err)
}
keyAuth, err := core.GetKeyAuthorization(chlng.Token)
if err != nil {
panic(err)
}
fqdn, value := dns01.GetRecord(domain, keyAuth)
fmt.Println("fqdn", fqdn, value)
//
//keyAuth, err := client.Challenge.core.GetKeyAuthorization(chlng.Token)
//if err != nil {
// panic(err)
//}
//
//httpProvider, err := webroot.NewHTTPProvider("/opt/1Panel/data/apps/nginx/nginx-1/www/wwwroot")
//if err != nil {
// panic(err)
//}
//
//err = client.Challenge.SetHTTP01Provider(httpProvider)
//if err != nil {
// panic(err)
//}
//err = client.Challenge.SetTLSALPN01Provider(tlsalpn01.NewProviderServer("43.142.178.16", "443"))
//if err != nil {
// panic(err)
//}
certificates, err := client.Certificate.Obtain(request)
if err != nil {
panic(err)
}
fmt.Println("---private---")
fmt.Println(string(certificates.PrivateKey))
fmt.Println("---.pem---")
fmt.Println(string(certificates.Certificate))
fmt.Println("---.domain---")
fmt.Println(certificates.Domain)
fmt.Println("---.certUrl---")
fmt.Println(certificates.CertURL)
fmt.Println("---.csr---")
fmt.Println(certificates.CSR)
fmt.Println("---.cert string---")
fmt.Println(string(certificates.IssuerCertificate))
cer1, _ := pem.Decode(certificates.Certificate)
cert, err := x509.ParseCertificate(cer1.Bytes)
if err != nil {
panic(err)
}
fmt.Println(cert)
cer2, _ := pem.Decode(certificates.IssuerCertificate)
cert2, err := x509.ParseCertificate(cer2.Bytes)
if err != nil {
panic(err)
}
fmt.Println(cert2)
}
func generateCSR(privateKey crypto.PrivateKey, domain string) ([]byte, error) {
// 创建证书请求的模板
template := x509.CertificateRequest{
Subject: pkix.Name{
CommonName: domain,
},
SignatureAlgorithm: x509.ECDSAWithSHA256,
}
// 生成 CSR
csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &template, privateKey)
if err != nil {
return nil, err
}
// 将 CSR 编码为 PEM 格式
csrPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csrBytes})
// 这里可以将 CSR 写入文件或者返回
err = os.WriteFile("csr.pem", csrPEM, 0644)
if err != nil {
return nil, err
}
return csrPEM, nil
}
func TestZeroSSL(t *testing.T) {
domain := "1panel.store"
acmeServer := "https://acme.zerossl.com/v2/DV90"
//acmeServer = "https://api.test4.buypass.no/acme/directory"
//
//acmeServer = "https://api.buypass.com/acme/directory"
priKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Fatalf("Failed to generate private key: %v", err)
}
user := AcmeUser{
Email: "zhengkunwang123@sina.com",
Key: priKey,
}
//logFile, err := os.OpenFile("/opt/1panel/ssl.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
//if err != nil {
// log.Fatalf("Failed to open log file: %v", err)
//}
//defer logFile.Close()
//
//logger := log.New(logFile, "", log.LstdFlags)
//legoLogger.Logger = logger
config := lego.NewConfig(&user)
// 设置ACME服务器URL
config.CADirURL = acmeServer
config.Certificate.KeyType = certcrypto.RSA2048
config.UserAgent = "acm_go/0.0.1"
// 创建ACME客户端
client, err := lego.NewClient(config)
if err != nil {
log.Fatal(err)
}
// ZeroSSl
kid := ""
hmacEncoded := ""
eabOptions := registration.RegisterEABOptions{
TermsOfServiceAgreed: true,
Kid: kid,
HmacEncoded: hmacEncoded,
}
reg, err := client.Registration.RegisterWithExternalAccountBinding(eabOptions)
if err != nil {
log.Fatal(err)
}
// ZeroSSl
//reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
//if err != nil {
// log.Fatal(err)
//}
user.Registration = reg
cloudflareConfig := cloudflare.NewDefaultConfig()
cloudflareConfig.AuthEmail = ""
cloudflareConfig.AuthKey = ""
p, err := cloudflare.NewDNSProviderConfig(cloudflareConfig)
if err != nil {
log.Fatal(err)
}
if err := client.Challenge.SetDNS01Provider(p, dns01.AddDNSTimeout(3*time.Minute)); err != nil {
log.Fatal(err)
}
// 申请证书
pk, err := certcrypto.GeneratePrivateKey(certcrypto.EC256)
if err != nil {
return
}
request := certificate.ObtainRequest{
Domains: []string{domain},
Bundle: true,
PrivateKey: pk,
}
certificates, err := client.Certificate.Obtain(request)
if err != nil {
log.Fatal(err)
}
// 保存证书
err = os.WriteFile("certificate.crt", certificates.Certificate, 0644)
if err != nil {
log.Fatal(err)
}
err = os.WriteFile("private.key", certificates.PrivateKey, 0644)
if err != nil {
log.Fatal(err)
}
}
func TestGetEABCre(t *testing.T) {
res, err := getZeroSSLEabCredentials("zen@11.com")
if err != nil {
panic(err)
}
fmt.Printf("%v", res)
}
+9
View File
@@ -0,0 +1,9 @@
//go:build !xpack
package xpack
func RemoveTamper(website string) {}
func LoadGpuInfo() []interface{} {
return nil
}
+5 -13
View File
@@ -8,7 +8,7 @@ import (
"strings"
cmdUtils "github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/pkg/errors"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/spf13/cobra"
)
@@ -43,19 +43,19 @@ var restoreCmd = &cobra.Command{
tmpPath = path.Join(upgradeDir, tmpPath, "original")
fmt.Printf("(0/4) 开始从 %s 目录回滚 1Panel 服务及数据... \n", tmpPath)
if err := cpBinary(path.Join(tmpPath, "1panel"), "/usr/local/bin/1panel"); err != nil {
if err := common.CopyFile(path.Join(tmpPath, "1panel"), "/usr/local/bin"); err != nil {
return err
}
fmt.Println("(1/4) 1panel 二进制回滚成功")
if err := cpBinary(path.Join(tmpPath, "1pctl"), "/usr/local/bin/1pctl"); err != nil {
if err := common.CopyFile(path.Join(tmpPath, "1pctl"), "/usr/local/bin"); err != nil {
return err
}
fmt.Println("(2/4) 1panel 脚本回滚成功")
if err := cpBinary(path.Join(tmpPath, "1panel.service"), "/etc/systemd/system/1panel.service"); err != nil {
if err := common.CopyFile(path.Join(tmpPath, "1panel.service"), "/etc/systemd/system"); err != nil {
return err
}
fmt.Println("(3/4) 1panel 服务回滚成功")
if err := cpBinary(path.Join(tmpPath, "1Panel.db"), path.Join(baseDir, "1panel", "db", "1Panel.db")); err != nil {
if err := common.CopyFile(path.Join(tmpPath, "1Panel.db"), path.Join(baseDir, "1panel", "db")); err != nil {
return err
}
fmt.Printf("(4/4) 1panel 数据回滚成功 \n\n")
@@ -87,11 +87,3 @@ func loadRestorePath(upgradeDir string) (string, error) {
})
return folders[0], nil
}
func cpBinary(src string, dst string) error {
stderr, err := cmdUtils.Exec(fmt.Sprintf("\\cp -f %s %s", src, dst))
if err != nil {
return errors.New(stderr)
}
return nil
}
+8
View File
@@ -59,6 +59,14 @@ func getSettingByKey(db *gorm.DB, key string) string {
return setting.Value
}
type LoginLog struct{}
func isDefault(db *gorm.DB) bool {
logCount := int64(0)
_ = db.Model(&LoginLog{}).Where("status = ?", "Success").Count(&logCount).Error
return logCount == 0
}
func setSettingByKey(db *gorm.DB, key, value string) error {
return db.Model(&setting{}).Where("key = ?", key).Updates(map[string]interface{}{"value": value}).Error
}
+12 -1
View File
@@ -3,6 +3,8 @@ package cmd
import (
"fmt"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
"github.com/spf13/cobra"
)
@@ -23,6 +25,15 @@ var userinfoCmd = &cobra.Command{
return fmt.Errorf("init my db conn failed, err: %v \n", err)
}
user := getSettingByKey(db, "UserName")
pass := "********"
if isDefault(db) {
encryptSetting := getSettingByKey(db, "EncryptKey")
pass = getSettingByKey(db, "Password")
if len(encryptSetting) == 16 {
global.CONF.System.EncryptKey = encryptSetting
pass, _ = encrypt.StringDecrypt(pass)
}
}
port := getSettingByKey(db, "ServerPort")
ssl := getSettingByKey(db, "SSL")
entrance := getSettingByKey(db, "SecurityEntrance")
@@ -38,7 +49,7 @@ var userinfoCmd = &cobra.Command{
fmt.Printf("面板地址: %s://%s:%s/%s \n", protocol, address, port, entrance)
fmt.Println("面板用户: ", user)
fmt.Println("面板密码: ", "********")
fmt.Println("面板密码: ", pass)
fmt.Println("提示:修改密码可执行命令:1pctl update password")
return nil
},
+210 -215
View File
@@ -156,7 +156,7 @@ const docTemplate = `{
}
}
},
"/apps/ingored": {
"/apps/ignored": {
"get": {
"security": [
{
@@ -8097,6 +8097,62 @@ const docTemplate = `{
}
}
},
"/hosts/monitor/clean": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "清空监控数据",
"tags": [
"Monitor"
],
"summary": "Clean monitor datas",
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [],
"formatEN": "clean monitor datas",
"formatZH": "清空监控数据",
"paramKeys": []
}
}
},
"/hosts/monitor/search": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取监控数据",
"tags": [
"Monitor"
],
"summary": "Load monitor datas",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.MonitorSearch"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/hosts/search": {
"post": {
"security": [
@@ -9158,6 +9214,28 @@ const docTemplate = `{
}
}
},
"/runtimes/sync": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "同步运行环境状态",
"consumes": [
"application/json"
],
"tags": [
"Runtime"
],
"summary": "Sync runtime status",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/runtimes/update": {
"post": {
"security": [
@@ -9901,6 +9979,46 @@ const docTemplate = `{
}
}
},
"/settings/menu/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "隐藏高级功能菜单",
"consumes": [
"application/json"
],
"tags": [
"System Setting"
],
"summary": "Update system setting",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.SettingUpdate"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [],
"formatEN": "Hide advanced feature menu.",
"formatZH": "隐藏高级功能菜单",
"paramKeys": []
}
}
},
"/settings/mfa": {
"post": {
"security": [
@@ -9977,32 +10095,6 @@ const docTemplate = `{
}
}
},
"/settings/monitor/clean": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "清空监控数据",
"tags": [
"System Setting"
],
"summary": "Clean monitor datas",
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [],
"formatEN": "clean monitor datas",
"formatZH": "清空监控数据",
"paramKeys": []
}
}
},
"/settings/password/update": {
"post": {
"security": [
@@ -12940,7 +13032,7 @@ const docTemplate = `{
"tags": [
"Website"
],
"summary": "Load websit php conf",
"summary": "Load website php conf",
"parameters": [
{
"type": "integer",
@@ -13918,144 +14010,6 @@ const docTemplate = `{
"paramKeys": []
}
}
},
"/websites/waf/config": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取网站 waf 配置",
"consumes": [
"application/json"
],
"tags": [
"Website WAF"
],
"summary": "Load websit waf conf",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteWafReq"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.WebsiteWafConfig"
}
}
}
}
},
"/websites/waf/file/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "更新 网站 waf 配置文件",
"consumes": [
"application/json"
],
"tags": [
"Website WAF"
],
"summary": "Update website waf file",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteWafUpdate"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [
{
"db": "websites",
"input_column": "id",
"input_value": "websiteId",
"isList": false,
"output_column": "primary_domain",
"output_value": "domain"
}
],
"bodyKeys": [
"websiteId"
],
"formatEN": "WAF conf file update [domain]",
"formatZH": "WAF 配置文件修改 [domain]",
"paramKeys": []
}
}
},
"/websites/waf/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "更新 网站 waf 配置",
"consumes": [
"application/json"
],
"tags": [
"Website WAF"
],
"summary": "Update website waf conf",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteWafUpdate"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [
{
"db": "websites",
"input_column": "id",
"input_value": "websiteId",
"isList": false,
"output_column": "primary_domain",
"output_value": "domain"
}
],
"bodyKeys": [
"websiteId"
],
"formatEN": "WAF conf update [domain]",
"formatZH": "WAF 配置修改 [domain]",
"paramKeys": []
}
}
}
},
"definitions": {
@@ -14930,6 +14884,9 @@ const docTemplate = `{
"backupAccounts": {
"type": "string"
},
"command": {
"type": "string"
},
"containerName": {
"type": "string"
},
@@ -15001,6 +14958,9 @@ const docTemplate = `{
"backupAccounts": {
"type": "string"
},
"command": {
"type": "string"
},
"containerName": {
"type": "string"
},
@@ -15234,6 +15194,12 @@ const docTemplate = `{
"$ref": "#/definitions/dto.DiskInfo"
}
},
"gpuData": {
"type": "array",
"items": {
"$ref": "#/definitions/dto.GPUInfo"
}
},
"ioCount": {
"type": "integer"
},
@@ -15817,6 +15783,47 @@ const docTemplate = `{
}
}
},
"dto.GPUInfo": {
"type": "object",
"properties": {
"fanSpeed": {
"type": "string"
},
"gpuUtil": {
"type": "string"
},
"index": {
"type": "integer"
},
"maxPowerLimit": {
"type": "string"
},
"memTotal": {
"type": "string"
},
"memUsed": {
"type": "string"
},
"memoryUsage": {
"type": "string"
},
"performanceState": {
"type": "string"
},
"powerDraw": {
"type": "string"
},
"powerUsage": {
"type": "string"
},
"productName": {
"type": "string"
},
"temperature": {
"type": "string"
}
}
},
"dto.GenerateLoad": {
"type": "object",
"required": [
@@ -16324,6 +16331,34 @@ const docTemplate = `{
}
}
},
"dto.MonitorSearch": {
"type": "object",
"required": [
"param"
],
"properties": {
"endTime": {
"type": "string"
},
"info": {
"type": "string"
},
"param": {
"type": "string",
"enum": [
"all",
"cpu",
"memory",
"load",
"io",
"network"
]
},
"startTime": {
"type": "string"
}
}
},
"dto.MysqlDBCreate": {
"type": "object",
"required": [
@@ -17800,6 +17835,9 @@ const docTemplate = `{
"monitorStoreDays": {
"type": "string"
},
"noAuthSetting": {
"type": "string"
},
"ntpSite": {
"type": "string"
},
@@ -17844,6 +17882,9 @@ const docTemplate = `{
},
"weChatVars": {
"type": "string"
},
"xpackHideMenu": {
"type": "string"
}
}
},
@@ -18090,6 +18131,9 @@ const docTemplate = `{
},
"sourceDir": {
"type": "string"
},
"type": {
"type": "string"
}
}
},
@@ -18921,7 +18965,6 @@ const docTemplate = `{
"request.FileCreate": {
"type": "object",
"required": [
"mode",
"path"
],
"properties": {
@@ -20777,43 +20820,6 @@ const docTemplate = `{
}
}
},
"request.WebsiteWafReq": {
"type": "object",
"required": [
"key",
"rule",
"websiteId"
],
"properties": {
"key": {
"type": "string"
},
"rule": {
"type": "string"
},
"websiteId": {
"type": "integer"
}
}
},
"request.WebsiteWafUpdate": {
"type": "object",
"required": [
"key",
"websiteId"
],
"properties": {
"enable": {
"type": "boolean"
},
"key": {
"type": "string"
},
"websiteId": {
"type": "integer"
}
}
},
"response.AppDTO": {
"type": "object",
"properties": {
@@ -21493,17 +21499,6 @@ const docTemplate = `{
"type": "string"
}
}
},
"response.WebsiteWafConfig": {
"type": "object",
"properties": {
"content": {
"type": "string"
},
"enable": {
"type": "boolean"
}
}
}
}
}`
+210 -215
View File
@@ -149,7 +149,7 @@
}
}
},
"/apps/ingored": {
"/apps/ignored": {
"get": {
"security": [
{
@@ -8090,6 +8090,62 @@
}
}
},
"/hosts/monitor/clean": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "清空监控数据",
"tags": [
"Monitor"
],
"summary": "Clean monitor datas",
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [],
"formatEN": "clean monitor datas",
"formatZH": "清空监控数据",
"paramKeys": []
}
}
},
"/hosts/monitor/search": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取监控数据",
"tags": [
"Monitor"
],
"summary": "Load monitor datas",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.MonitorSearch"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/hosts/search": {
"post": {
"security": [
@@ -9151,6 +9207,28 @@
}
}
},
"/runtimes/sync": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "同步运行环境状态",
"consumes": [
"application/json"
],
"tags": [
"Runtime"
],
"summary": "Sync runtime status",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/runtimes/update": {
"post": {
"security": [
@@ -9894,6 +9972,46 @@
}
}
},
"/settings/menu/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "隐藏高级功能菜单",
"consumes": [
"application/json"
],
"tags": [
"System Setting"
],
"summary": "Update system setting",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.SettingUpdate"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [],
"formatEN": "Hide advanced feature menu.",
"formatZH": "隐藏高级功能菜单",
"paramKeys": []
}
}
},
"/settings/mfa": {
"post": {
"security": [
@@ -9970,32 +10088,6 @@
}
}
},
"/settings/monitor/clean": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "清空监控数据",
"tags": [
"System Setting"
],
"summary": "Clean monitor datas",
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [],
"bodyKeys": [],
"formatEN": "clean monitor datas",
"formatZH": "清空监控数据",
"paramKeys": []
}
}
},
"/settings/password/update": {
"post": {
"security": [
@@ -12933,7 +13025,7 @@
"tags": [
"Website"
],
"summary": "Load websit php conf",
"summary": "Load website php conf",
"parameters": [
{
"type": "integer",
@@ -13911,144 +14003,6 @@
"paramKeys": []
}
}
},
"/websites/waf/config": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取网站 waf 配置",
"consumes": [
"application/json"
],
"tags": [
"Website WAF"
],
"summary": "Load websit waf conf",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteWafReq"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.WebsiteWafConfig"
}
}
}
}
},
"/websites/waf/file/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "更新 网站 waf 配置文件",
"consumes": [
"application/json"
],
"tags": [
"Website WAF"
],
"summary": "Update website waf file",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteWafUpdate"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [
{
"db": "websites",
"input_column": "id",
"input_value": "websiteId",
"isList": false,
"output_column": "primary_domain",
"output_value": "domain"
}
],
"bodyKeys": [
"websiteId"
],
"formatEN": "WAF conf file update [domain]",
"formatZH": "WAF 配置文件修改 [domain]",
"paramKeys": []
}
}
},
"/websites/waf/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "更新 网站 waf 配置",
"consumes": [
"application/json"
],
"tags": [
"Website WAF"
],
"summary": "Update website waf conf",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteWafUpdate"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [
{
"db": "websites",
"input_column": "id",
"input_value": "websiteId",
"isList": false,
"output_column": "primary_domain",
"output_value": "domain"
}
],
"bodyKeys": [
"websiteId"
],
"formatEN": "WAF conf update [domain]",
"formatZH": "WAF 配置修改 [domain]",
"paramKeys": []
}
}
}
},
"definitions": {
@@ -14923,6 +14877,9 @@
"backupAccounts": {
"type": "string"
},
"command": {
"type": "string"
},
"containerName": {
"type": "string"
},
@@ -14994,6 +14951,9 @@
"backupAccounts": {
"type": "string"
},
"command": {
"type": "string"
},
"containerName": {
"type": "string"
},
@@ -15227,6 +15187,12 @@
"$ref": "#/definitions/dto.DiskInfo"
}
},
"gpuData": {
"type": "array",
"items": {
"$ref": "#/definitions/dto.GPUInfo"
}
},
"ioCount": {
"type": "integer"
},
@@ -15810,6 +15776,47 @@
}
}
},
"dto.GPUInfo": {
"type": "object",
"properties": {
"fanSpeed": {
"type": "string"
},
"gpuUtil": {
"type": "string"
},
"index": {
"type": "integer"
},
"maxPowerLimit": {
"type": "string"
},
"memTotal": {
"type": "string"
},
"memUsed": {
"type": "string"
},
"memoryUsage": {
"type": "string"
},
"performanceState": {
"type": "string"
},
"powerDraw": {
"type": "string"
},
"powerUsage": {
"type": "string"
},
"productName": {
"type": "string"
},
"temperature": {
"type": "string"
}
}
},
"dto.GenerateLoad": {
"type": "object",
"required": [
@@ -16317,6 +16324,34 @@
}
}
},
"dto.MonitorSearch": {
"type": "object",
"required": [
"param"
],
"properties": {
"endTime": {
"type": "string"
},
"info": {
"type": "string"
},
"param": {
"type": "string",
"enum": [
"all",
"cpu",
"memory",
"load",
"io",
"network"
]
},
"startTime": {
"type": "string"
}
}
},
"dto.MysqlDBCreate": {
"type": "object",
"required": [
@@ -17793,6 +17828,9 @@
"monitorStoreDays": {
"type": "string"
},
"noAuthSetting": {
"type": "string"
},
"ntpSite": {
"type": "string"
},
@@ -17837,6 +17875,9 @@
},
"weChatVars": {
"type": "string"
},
"xpackHideMenu": {
"type": "string"
}
}
},
@@ -18083,6 +18124,9 @@
},
"sourceDir": {
"type": "string"
},
"type": {
"type": "string"
}
}
},
@@ -18914,7 +18958,6 @@
"request.FileCreate": {
"type": "object",
"required": [
"mode",
"path"
],
"properties": {
@@ -20770,43 +20813,6 @@
}
}
},
"request.WebsiteWafReq": {
"type": "object",
"required": [
"key",
"rule",
"websiteId"
],
"properties": {
"key": {
"type": "string"
},
"rule": {
"type": "string"
},
"websiteId": {
"type": "integer"
}
}
},
"request.WebsiteWafUpdate": {
"type": "object",
"required": [
"key",
"websiteId"
],
"properties": {
"enable": {
"type": "boolean"
},
"key": {
"type": "string"
},
"websiteId": {
"type": "integer"
}
}
},
"response.AppDTO": {
"type": "object",
"properties": {
@@ -21486,17 +21492,6 @@
"type": "string"
}
}
},
"response.WebsiteWafConfig": {
"type": "object",
"properties": {
"content": {
"type": "string"
},
"enable": {
"type": "boolean"
}
}
}
}
}
+137 -140
View File
@@ -584,6 +584,8 @@ definitions:
type: string
backupAccounts:
type: string
command:
type: string
containerName:
type: string
dbName:
@@ -632,6 +634,8 @@ definitions:
type: string
backupAccounts:
type: string
command:
type: string
containerName:
type: string
dbName:
@@ -791,6 +795,10 @@ definitions:
items:
$ref: '#/definitions/dto.DiskInfo'
type: array
gpuData:
items:
$ref: '#/definitions/dto.GPUInfo'
type: array
ioCount:
type: integer
ioReadBytes:
@@ -1186,6 +1194,33 @@ definitions:
- type
- vars
type: object
dto.GPUInfo:
properties:
fanSpeed:
type: string
gpuUtil:
type: string
index:
type: integer
maxPowerLimit:
type: string
memTotal:
type: string
memUsed:
type: string
memoryUsage:
type: string
performanceState:
type: string
powerDraw:
type: string
powerUsage:
type: string
productName:
type: string
temperature:
type: string
type: object
dto.GenerateLoad:
properties:
encryptionMode:
@@ -1528,6 +1563,26 @@ definitions:
- interval
- secret
type: object
dto.MonitorSearch:
properties:
endTime:
type: string
info:
type: string
param:
enum:
- all
- cpu
- memory
- load
- io
- network
type: string
startTime:
type: string
required:
- param
type: object
dto.MysqlDBCreate:
properties:
database:
@@ -2526,6 +2581,8 @@ definitions:
type: string
monitorStoreDays:
type: string
noAuthSetting:
type: string
ntpSite:
type: string
panelName:
@@ -2556,6 +2613,8 @@ definitions:
type: string
weChatVars:
type: string
xpackHideMenu:
type: string
type: object
dto.SettingUpdate:
properties:
@@ -2717,6 +2776,8 @@ definitions:
type: string
sourceDir:
type: string
type:
type: string
type: object
files.FileInfo:
properties:
@@ -3283,7 +3344,6 @@ definitions:
sub:
type: boolean
required:
- mode
- path
type: object
request.FileDeCompress:
@@ -4517,31 +4577,6 @@ definitions:
- id
- user
type: object
request.WebsiteWafReq:
properties:
key:
type: string
rule:
type: string
websiteId:
type: integer
required:
- key
- rule
- websiteId
type: object
request.WebsiteWafUpdate:
properties:
enable:
type: boolean
key:
type: string
websiteId:
type: integer
required:
- key
- websiteId
type: object
response.AppDTO:
properties:
createdAt:
@@ -4990,13 +5025,6 @@ definitions:
version:
type: string
type: object
response.WebsiteWafConfig:
properties:
content:
type: string
enable:
type: boolean
type: object
host: localhost
info:
contact: {}
@@ -5092,7 +5120,7 @@ paths:
summary: Get app detail by id
tags:
- App
/apps/ingored:
/apps/ignored:
get:
consumes:
- application/json
@@ -10130,6 +10158,41 @@ paths:
summary: Create group
tags:
- Firewall
/hosts/monitor/clean:
post:
description: 清空监控数据
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Clean monitor datas
tags:
- Monitor
x-panel-log:
BeforeFunctions: []
bodyKeys: []
formatEN: clean monitor datas
formatZH: 清空监控数据
paramKeys: []
/hosts/monitor/search:
post:
description: 获取监控数据
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.MonitorSearch'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Load monitor datas
tags:
- Monitor
/hosts/search:
post:
consumes:
@@ -10791,6 +10854,19 @@ paths:
summary: List runtimes
tags:
- Runtime
/runtimes/sync:
post:
consumes:
- application/json
description: 同步运行环境状态
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Sync runtime status
tags:
- Runtime
/runtimes/update:
post:
consumes:
@@ -11263,6 +11339,32 @@ paths:
summary: Load system address
tags:
- System Setting
/settings/menu/update:
post:
consumes:
- application/json
description: 隐藏高级功能菜单
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.SettingUpdate'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Update system setting
tags:
- System Setting
x-panel-log:
BeforeFunctions: []
bodyKeys: []
formatEN: Hide advanced feature menu.
formatZH: 隐藏高级功能菜单
paramKeys: []
/settings/mfa:
post:
consumes:
@@ -11311,23 +11413,6 @@ paths:
formatEN: bind mfa
formatZH: mfa 绑定
paramKeys: []
/settings/monitor/clean:
post:
description: 清空监控数据
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Clean monitor datas
tags:
- System Setting
x-panel-log:
BeforeFunctions: []
bodyKeys: []
formatEN: clean monitor datas
formatZH: 清空监控数据
paramKeys: []
/settings/password/update:
post:
consumes:
@@ -13197,7 +13282,7 @@ paths:
$ref: '#/definitions/response.PHPConfig'
security:
- ApiKeyAuth: []
summary: Load websit php conf
summary: Load website php conf
tags:
- Website
/websites/php/update:
@@ -13810,92 +13895,4 @@ paths:
formatEN: Update website [primaryDomain]
formatZH: 更新网站 [primaryDomain]
paramKeys: []
/websites/waf/config:
post:
consumes:
- application/json
description: 获取网站 waf 配置
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/request.WebsiteWafReq'
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.WebsiteWafConfig'
security:
- ApiKeyAuth: []
summary: Load websit waf conf
tags:
- Website WAF
/websites/waf/file/update:
post:
consumes:
- application/json
description: 更新 网站 waf 配置文件
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/request.WebsiteWafUpdate'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Update website waf file
tags:
- Website WAF
x-panel-log:
BeforeFunctions:
- db: websites
input_column: id
input_value: websiteId
isList: false
output_column: primary_domain
output_value: domain
bodyKeys:
- websiteId
formatEN: WAF conf file update [domain]
formatZH: WAF 配置文件修改 [domain]
paramKeys: []
/websites/waf/update:
post:
consumes:
- application/json
description: 更新 网站 waf 配置
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/request.WebsiteWafUpdate'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Update website waf conf
tags:
- Website WAF
x-panel-log:
BeforeFunctions:
- db: websites
input_column: id
input_value: websiteId
isList: false
output_column: primary_domain
output_value: domain
bodyKeys:
- websiteId
formatEN: WAF conf update [domain]
formatZH: WAF 配置修改 [domain]
paramKeys: []
swagger: "2.0"
@@ -16,22 +16,6 @@ server {
access_log /www/sites/domain/log/access.log;
error_log /www/sites/domain/log/error.log;
access_by_lua_file /www/common/waf/access.lua;
set $RulePath /www/sites/domain/waf/rules;
set $logdir /www/sites/domain/waf/log;
set $redirect on;
set $attackLog on;
set $CCDeny off;
set $urlWhiteAllow off;
set $urlBlockDeny off;
set $argsDeny off;
set $postDeny off;
set $cookieDeny off;
set $fileExtDeny off;
set $ipBlockDeny off;
set $ipWhiteAllow off;
location ^~ /.well-known/acme-challenge {
allow all;
root /usr/share/nginx/html;
+8
View File
@@ -54,6 +54,14 @@ If you discover any security issues, please contact us through:
- Email: support@fit2cloud.com
- Phone: 400-052-0755
## Our Other Star Projects
- [JumpServer](https://github.com/jumpserver/jumpserver/) - A popular open-source PAM system
- [DataEase](https://github.com/dataease/dataease/) - An open-source data visualization and analysis tool for everyone
- [MeterSphere](https://github.com/metersphere/metersphere/) - An all-in-one open-source automated testing platform
- [Halo](https://github.com/halo-dev/halo/) - A powerful and user-friendly open-source website building tool
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](https://star-history.com/#1Panel-dev/1Panel&Date)
+7
View File
@@ -54,6 +54,13 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
- メール: support@fit2cloud.com
- 電話番号: 400-052-0755
## その他の主要プロジェクト
- [JumpServer](https://github.com/jumpserver/jumpserver/) - 人気のあるオープンソースのバスチョンホスト管理ツール
- [DataEase](https://github.com/dataease/dataease/) - 誰でも利用できるオープンソースのデータ可視化および分析ツール
- [MeterSphere](https://github.com/metersphere/metersphere/) - オールインワンのオープンソース自動化テストプラットフォーム
- [Halo](https://github.com/halo-dev/halo/) - 強力で使いやすいオープンソースのウェブサイト構築ツール
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](https://star-history.com/#1Panel-dev/1Panel&Date)
+7
View File
@@ -52,6 +52,13 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
- 郵箱:support@fit2cloud.com
- 電話:400-052-0755
## 我們的其他明星專案
- [JumpServer](https://github.com/jumpserver/jumpserver/) - 受歡迎的開源堡壘機管理工具
- [DataEase](https://github.com/dataease/dataease/) - 開源的數據可視化和分析工具,適用於所有人
- [MeterSphere](https://github.com/metersphere/metersphere/) - 一站式開源自動化測試平台
- [Halo](https://github.com/halo-dev/halo/) - 強大且易於使用的開源網站建設工具
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](https://star-history.com/#1Panel-dev/1Panel&Date)
-1
View File
@@ -2,7 +2,6 @@
<html>
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/public/favicon.png" />
<meta name="robots" content="noindex,nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<title>loading...</title>
+5 -3
View File
@@ -42,9 +42,6 @@ class RequestHttp {
this.service.interceptors.response.use(
(response: AxiosResponse) => {
const { data } = response;
if (response.headers['x-csrf-token']) {
globalStore.setCsrfToken(response.headers['x-csrf-token']);
}
if (data.code == ResultEnum.OVERDUE || data.code == ResultEnum.FORBIDDEN) {
globalStore.setLogStatus(false);
router.push({
@@ -73,6 +70,11 @@ class RequestHttp {
});
return Promise.reject(data);
}
if (data.code == ResultEnum.ERRXPACK) {
globalStore.isProductPro = false;
window.location.reload();
return Promise.reject(data);
}
if (data.code == ResultEnum.ERRGLOBALLOADDING) {
globalStore.setGlobalLoading(true);
globalStore.setLoadingText(data.message);
+3 -1
View File
@@ -27,6 +27,8 @@ export namespace Container {
imageInput: boolean;
forcePull: boolean;
network: string;
ipv4: string;
ipv6: string;
cmdStr: string;
entrypointStr: string;
memoryItem: number;
@@ -56,10 +58,10 @@ export namespace Container {
protocol: string;
}
export interface Volume {
type: string;
sourceDir: string;
containerDir: string;
mode: string;
isVolume: boolean;
}
export interface ContainerInfo {
containerID: string;
+2
View File
@@ -9,6 +9,8 @@ export namespace Cronjob {
specObjs: Array<SpecObj>;
script: string;
isCustom: boolean;
command: string;
inContainer: boolean;
containerName: string;
appID: string;
+12
View File
@@ -59,6 +59,8 @@ export namespace Dashboard {
diskData: Array<DiskInfo>;
gpuData: Array<GPUInfo>;
netBytesSent: number;
netBytesRecv: number;
@@ -78,4 +80,14 @@ export namespace Dashboard {
inodesFree: number;
inodesUsedPercent: number;
}
export interface GPUInfo {
index: number;
productName: string;
gpuUtil: string;
temperature: string;
performanceState: string;
powerUsage: string;
memoryUsage: string;
fanSpeed: string;
}
}
+1 -1
View File
@@ -55,7 +55,7 @@ export namespace File {
export interface FileCreate {
path: string;
isDir: boolean;
mode: number;
mode?: number;
isLink?: boolean;
isSymlink?: boolean;
linkPath?: boolean;
+12
View File
@@ -116,6 +116,18 @@ export namespace Host {
rules: Array<RulePort>;
}
export interface MonitorData {
param: string;
date: Array<Date>;
value: Array<any>;
}
export interface MonitorSearch {
param: string;
info: string;
startTime: Date;
endTime: Date;
}
export interface SSHInfo {
autoStart: boolean;
status: string;
-13
View File
@@ -1,13 +0,0 @@
export namespace Monitor {
export interface MonitorData {
param: string;
date: Array<Date>;
value: Array<any>;
}
export interface MonitorSearch {
param: string;
info: string;
startTime: Date;
endTime: Date;
}
}
+11
View File
@@ -16,6 +16,7 @@ export namespace Setting {
panelName: string;
theme: string;
menuTabs: string;
language: string;
defaultNetwork: string;
lastCleanTime: string;
@@ -46,6 +47,8 @@ export namespace Setting {
weChatVars: string;
dingVars: string;
snapshotIgnore: string;
xpackHideMenu: string;
noAuthSetting: string;
}
export interface SettingUpdate {
key: string;
@@ -140,4 +143,12 @@ export namespace Setting {
latestVersion: string;
releaseNote: string;
}
export interface License {
licenseName: string;
assigneeName: string;
productPro: string;
trial: boolean;
status: string;
}
}
-23
View File
@@ -258,29 +258,6 @@ export namespace Website {
appName: string;
}
export interface WafReq {
websiteId: number;
key: string;
rule: string;
}
export interface WafRes {
enable: boolean;
content: string;
}
export interface WafUpdate {
enable: boolean;
websiteId: number;
key: string;
}
export interface WafFileUpdate {
websiteId: number;
type: string;
content: string;
}
export interface DelReq {
id: number;
}
+4
View File
@@ -21,6 +21,10 @@ export const checkIsSafety = (code: string) => {
return http.get<string>(`/auth/issafety?code=${code}`);
};
export const getResponsePage = () => {
return http.get<string>(`/respagecode`);
};
export const checkIsDemo = () => {
return http.get<boolean>('/auth/demo');
};
+14
View File
@@ -101,6 +101,20 @@ export const batchOperateRule = (params: Host.BatchRule) => {
return http.post(`/hosts/firewall/batch`, params, TimeoutEnum.T_60S);
};
// monitors
export const loadMonitor = (param: Host.MonitorSearch) => {
return http.post<Array<Host.MonitorData>>(`/hosts/monitor/search`, param);
};
export const getNetworkOptions = () => {
return http.get<Array<string>>(`/hosts/monitor/netoptions`);
};
export const getIOOptions = () => {
return http.get<Array<string>>(`/hosts/monitor/iooptions`);
};
export const cleanMonitors = () => {
return http.post(`/hosts/monitor/clean`, {});
};
// ssh
export const getSSHInfo = () => {
return http.post<Host.SSHInfo>(`/hosts/ssh/search`);
-14
View File
@@ -1,14 +0,0 @@
import http from '@/api';
import { Monitor } from '../interface/monitor';
export const loadMonitor = (param: Monitor.MonitorSearch) => {
return http.post<Array<Monitor.MonitorData>>(`/monitors/search`, param);
};
export const getNetworkOptions = () => {
return http.get<Array<string>>(`/monitors/netoptions`);
};
export const getIOOptions = () => {
return http.get<Array<string>>(`/monitors/iooptions`);
};
+20 -4
View File
@@ -6,6 +6,22 @@ import { Backup } from '../interface/backup';
import { Setting } from '../interface/setting';
import { TimeoutEnum } from '@/enums/http-enum';
export const UploadFileData = (params: FormData) => {
return http.upload('/licenses/upload', params);
};
export const getLicense = () => {
return http.get<Setting.License>(`/licenses/get`);
};
export const syncLicense = () => {
return http.post(`/licenses/sync`);
};
export const unbindLicense = () => {
return http.post(`/licenses/unbind`);
};
export const getSettingInfo = () => {
return http.post<Setting.SettingInfo>(`/settings/search`);
};
@@ -17,6 +33,10 @@ export const updateSetting = (param: Setting.SettingUpdate) => {
return http.post(`/settings/update`, param);
};
export const updateMenu = (param: Setting.SettingUpdate) => {
return http.post(`/settings/menu/update`, param);
};
export const updatePassword = (param: Setting.PasswordUpdate) => {
return http.post(`/settings/password/update`, param);
};
@@ -54,10 +74,6 @@ export const syncTime = (ntpSite: string) => {
return http.post<string>(`/settings/time/sync`, { ntpSite: ntpSite });
};
export const cleanMonitors = () => {
return http.post(`/settings/monitor/clean`, {});
};
export const loadMFA = (param: Setting.MFARequest) => {
return http.post<Setting.MFAInfo>(`/settings/mfa`, param);
};
-12
View File
@@ -144,18 +144,6 @@ export const PreCheck = (req: Website.CheckReq) => {
return http.post<Website.CheckRes[]>(`/websites/check`, req);
};
export const GetWafConfig = (req: Website.WafReq) => {
return http.post<Website.WafRes>(`/websites/waf/config`, req);
};
export const UpdateWafEnable = (req: Website.WafUpdate) => {
return http.post<any>(`/websites/waf/update`, req);
};
export const UpdateWafFile = (req: Website.WafFileUpdate) => {
return http.post<any>(`/websites/waf/file/update`, req);
};
export const UpdateNginxFile = (req: Website.NginxUpdate) => {
return http.post<any>(`/websites/nginx/update`, req);
};
+64 -4
View File
@@ -1,9 +1,9 @@
@font-face {
font-family: "panel"; /* Project id 3575356 */
src: url('iconfont.woff2?t=1701341406915') format('woff2'),
url('iconfont.woff?t=1701341406915') format('woff'),
url('iconfont.ttf?t=1701341406915') format('truetype'),
url('iconfont.svg?t=1701341406915#panel') format('svg');
src: url('iconfont.woff2?t=1712830223091') format('woff2'),
url('iconfont.woff?t=1712830223091') format('woff'),
url('iconfont.ttf?t=1712830223091') format('truetype'),
url('iconfont.svg?t=1712830223091#panel') format('svg');
}
.panel {
@@ -14,6 +14,66 @@
-moz-osx-font-smoothing: grayscale;
}
.p-xpack:before {
content: "\e604";
}
.p-gpu-2:before {
content: "\e6d8";
}
.p-gpu-1:before {
content: "\e623";
}
.p-waf-4:before {
content: "\e608";
}
.p-waf-1:before {
content: "\e62a";
}
.p-waf-2:before {
content: "\e682";
}
.p-waf-3:before {
content: "\e666";
}
.p-setting-1:before {
content: "\e626";
}
.p-setting-2:before {
content: "\e630";
}
.p-setting-3:before {
content: "\e617";
}
.p-tamper-4:before {
content: "\e7c3";
}
.p-tamper-2:before {
content: "\e610";
}
.p-tamper-3:before {
content: "\ec4d";
}
.p-tamper-1:before {
content: "\e687";
}
.p-tongji:before {
content: "\e856";
}
.p-webdav:before {
content: "\e622";
}
File diff suppressed because one or more lines are too long
+105
View File
@@ -5,6 +5,111 @@
"css_prefix_text": "p-",
"description": "",
"glyphs": [
{
"icon_id": "3722144",
"name": "钻石",
"font_class": "xpack",
"unicode": "e604",
"unicode_decimal": 58884
},
{
"icon_id": "640495",
"name": "详细信息",
"font_class": "gpu-2",
"unicode": "e6d8",
"unicode_decimal": 59096
},
{
"icon_id": "6176565",
"name": "监控",
"font_class": "gpu-1",
"unicode": "e623",
"unicode_decimal": 58915
},
{
"icon_id": "8229531",
"name": "ACL策略",
"font_class": "waf-4",
"unicode": "e608",
"unicode_decimal": 58888
},
{
"icon_id": "8765146",
"name": "地图",
"font_class": "waf-1",
"unicode": "e62a",
"unicode_decimal": 58922
},
{
"icon_id": "16563651",
"name": "8-4限制区域",
"font_class": "waf-2",
"unicode": "e682",
"unicode_decimal": 59010
},
{
"icon_id": "17064153",
"name": "拦截",
"font_class": "waf-3",
"unicode": "e666",
"unicode_decimal": 58982
},
{
"icon_id": "899647",
"name": "欢迎页",
"font_class": "setting-1",
"unicode": "e626",
"unicode_decimal": 58918
},
{
"icon_id": "1114667",
"name": "图标",
"font_class": "setting-2",
"unicode": "e630",
"unicode_decimal": 58928
},
{
"icon_id": "12010559",
"name": "注册网站",
"font_class": "setting-3",
"unicode": "e617",
"unicode_decimal": 58903
},
{
"icon_id": "435944",
"name": "日志",
"font_class": "tamper-4",
"unicode": "e7c3",
"unicode_decimal": 59331
},
{
"icon_id": "5799978",
"name": "扫描",
"font_class": "tamper-2",
"unicode": "e610",
"unicode_decimal": 58896
},
{
"icon_id": "5961299",
"name": "安全",
"font_class": "tamper-3",
"unicode": "ec4d",
"unicode_decimal": 60493
},
{
"icon_id": "28131805",
"name": "完整性检查",
"font_class": "tamper-1",
"unicode": "e687",
"unicode_decimal": 59015
},
{
"icon_id": "5838475",
"name": "统计",
"font_class": "tongji",
"unicode": "e856",
"unicode_decimal": 59478
},
{
"icon_id": "23044673",
"name": "webdav",
+30
View File
@@ -14,6 +14,36 @@
/>
<missing-glyph />
<glyph glyph-name="xpack" unicode="&#58884;" d="M971.527 503.922L839.149 726.406c-5.729 11.652-17.836 20.114-32.248 20.114H217.227v-0.442c-12.134 0-24.007-5.962-30.647-17.394L54.201 506.903c-10.077-14.177-8.931-33.836 3.645-46.178l428.043-428.499 1.133-0.456c13.943-13.722 36.362-13.722 50.306 0l428.707 428.955h-0.222c11.43 11.431 14.412 29.267 5.714 43.197zM760.032 674.968l-85.743-140.632a47.989 47.989 0 0 1-3.789 0.164c-2.771 0-5.48-0.25-8.12-0.706l-98.988 141.174h196.64z m-132.05-166.793c-0.136-0.271-0.273-0.541-0.404-0.815H401.421a47.213 47.213 0 0 1-2.563 4.683l113.537 161.311 115.587-165.179zM460.736 674.968l-98.403-140.636a48.105 48.105 0 0 1-3.833 0.167c-2.775 0-5.49-0.251-8.135-0.708l-86.504 141.176h196.875z m-234.605-19.45l89.842-147.361c-0.132-0.265-0.267-0.528-0.394-0.796h-178.16l88.712 148.157zM154.799 464.37h161.928c6.511-11.994 18.04-20.861 31.767-23.805l98.051-267.719L154.799 464.37z m357.597-345.475L390.021 451.478a47.675 47.675 0 0 1 10.252 12.892h228.454a47.625 47.625 0 0 1 6.843-9.55L512.396 118.89499999999998z m64.939 53.951l97.977 266.896c15.992 1.609 29.644 11.149 36.962 24.628h156.364L577.335 172.846zM713.422 507.36a47.323 47.323 0 0 1-2.727 4.938l87.756 143.22 88.022-148.158H713.422z" horiz-adv-x="1024" />
<glyph glyph-name="gpu-2" unicode="&#59096;" d="M392.585795 223.71443399999998l-93.230358 0c-14.145162 0-25.611308-11.466146-25.611308-25.611308s11.467169-25.611308 25.611308-25.611308l93.230358 0c14.145162 0 25.611308 11.466146 25.611308 25.611308S406.729933 223.71443399999998 392.585795 223.71443399999998zM392.585795 103.84434599999997l-93.230358 0c-14.145162 0-25.611308-11.466146-25.611308-25.611308s11.467169-25.611308 25.611308-25.611308l93.230358 0c14.145162 0 25.611308 11.466146 25.611308 25.611308S406.729933 103.84434599999997 392.585795 103.84434599999997zM392.585795 330.26312199999995l-93.230358 0c-14.145162 0-25.611308-11.466146-25.611308-25.611308s11.467169-25.611308 25.611308-25.611308l93.230358 0c14.145162 0 25.611308 11.466146 25.611308 25.611308S406.729933 330.26312199999995 392.585795 330.26312199999995zM473.523175 304.65181399999994c0-14.145162 11.467169-25.611308 25.611308-25.611308l226.416729 0c14.145162 0 25.611308 11.466146 25.611308 25.611308s-11.466146 25.611308-25.611308 25.611308l-226.416729 0C484.990345 330.26312199999995 473.523175 318.796976 473.523175 304.65181399999994zM852.245729 471.110987c-54.019311 71.51887-226.167043 271.164886-294.330492 347.954807-2.820232 3.175319-6.088672 5.656837-9.639544 7.385201l-2.437515 2.849908-9.704013 0c-0.049119 0-0.097214 0.004093-0.146333 0.004093-0.039909 0-0.079818-0.004093-0.12075-0.004093L213.635123 829.300902c-15.878642 0-32.363082-6.886851-45.228087-18.896372-13.467733-12.571317-21.190625-29.167297-21.190625-45.533033L147.216411 5.710303999999951c0-16.116049 7.467065-32.885991 20.48659-46.007847 13.072737-13.175067 29.815049-20.732184 45.933145-20.732184l602.350774 0c16.676821 0 33.07428 8.121981 44.989657 22.281469 10.622942 12.624529 16.714683 28.828582 16.714683 44.457538L877.691261 441.366545 852.245729 471.110987zM559.654858 734.350366l239.987816-280.545534L563.927161 453.804832c-2.067079 3.163039-4.272303 9.214872-4.272303 13.115716L559.654858 734.350366zM826.467623 5.710303999999951c0-7.726985-7.185656-15.516392-10.480702-15.516392L213.635123-9.806087000000048c-5.396917 0-15.196097 10.005888-15.196097 15.516392L198.439026 764.87252c0 4.66423 8.933463 13.205766 15.196097 13.205766l294.79712 0 0-311.158762c0-26.295899 18.24555-64.339354 51.235918-64.339354l266.799462 0L826.467623 5.710303999999951zM430.875866 634.92696L297.690518 634.92696c-14.145162 0-25.611308-11.467169-25.611308-25.611308l0-133.186372c0-14.145162 11.467169-25.612331 25.611308-25.612331l133.185348 0c14.145162 0 25.611308 11.467169 25.611308 25.612331L456.487174 609.314629C456.487174 623.45979 445.021028 634.92696 430.875866 634.92696zM405.264559 501.739565l-81.962733 0 0 81.963757 81.962733 0L405.264559 501.739565zM725.551212 223.71443399999998l-226.416729 0c-14.145162 0-25.611308-11.466146-25.611308-25.611308s11.467169-25.611308 25.611308-25.611308l226.416729 0c14.145162 0 25.611308 11.466146 25.611308 25.611308S739.697397 223.71443399999998 725.551212 223.71443399999998zM725.551212 103.84434599999997l-226.416729 0c-14.145162 0-25.611308-11.466146-25.611308-25.611308s11.467169-25.611308 25.611308-25.611308l226.416729 0c14.145162 0 25.611308 11.466146 25.611308 25.611308S739.697397 103.84434599999997 725.551212 103.84434599999997z" horiz-adv-x="1024" />
<glyph glyph-name="gpu-1" unicode="&#58915;" d="M838.22 139.59000000000003H187.78a89.1 89.1 0 0 0-89.1 89.1V697.46a89.1 89.1 0 0 0 89.1 89.1h650.44a89.1 89.1 0 0 0 89.1-89.1v-468.77a89.1 89.1 0 0 0-89.1-89.1zM852 224.64999999999998V701.5a9 9 0 0 1-9 8.95H183a9 9 0 0 1-9-8.95v-476.85a9 9 0 0 1 9-8.94h660a9 9 0 0 1 9 8.94zM287.01 63.48000000000002m37.86 0l376.26 0q37.86 0 37.86-37.86l0-0.39q0-37.86-37.86-37.86l-376.26 0q-37.86 0-37.86 37.86l0 0.39q0 37.86 37.86 37.86ZM249.34 558.22m31.68 0l11.97 0q31.68 0 31.68-31.68l0-203.04q0-31.68-31.68-31.68l-11.97 0q-31.68 0-31.68 31.68l0 203.04q0 31.68 31.68 31.68ZM400 444.05m37.67 0l-0.01 0q37.67 0 37.67-37.67l0-76.89q0-37.67-37.67-37.67l0.01 0q-37.67 0-37.67 37.67l0 76.89q0 37.67 37.67 37.67ZM550.67 634.3299999999999m37.67 0l-0.01 0q37.67 0 37.67-37.67l0-267.17q0-37.67-37.67-37.67l0.01 0q-37.67 0-37.67 37.67l0 267.17q0 37.67 37.67 37.67ZM701.33 482.11m37.67 0l-0.01 0q37.67 0 37.67-37.67l0-114.94q0-37.67-37.67-37.67l0.01 0q-37.67 0-37.67 37.67l0 114.94q0 37.67 37.67 37.67Z" horiz-adv-x="1024" />
<glyph glyph-name="waf-4" unicode="&#58888;" d="M136.533333 759.466667h546.133334v-68.266667H136.533333zM136.533333 622.933333h546.133334v-68.266666H136.533333zM136.533333 486.4h546.133334v-68.266667H136.533333zM136.533333 349.866667h68.266667v-68.266667H136.533333zM136.533333 213.33333300000004h68.266667v-68.266666H136.533333zM466.261333 55.63733300000001h68.266667L546.133333 8.53333299999997h43.690667l-68.266667 204.8H477.866667l-68.266667-204.8h43.008z m30.037334 105.130667a81.92 81.92 0 0 1 0 17.066667 84.650667 84.650667 0 0 1 0-17.749334l21.162666-68.266666H477.866667zM691.541333 8.53333299999997a115.370667 115.370667 0 0 1 53.248 10.922667v38.912a84.650667 84.650667 0 0 0-45.738666-12.970667 53.248 53.248 0 0 0-42.325334 17.749334 68.266667 68.266667 0 0 0-15.701333 47.104 68.266667 68.266667 0 0 0 16.384 48.469333 55.296 55.296 0 0 0 43.690667 18.432 79.872 79.872 0 0 0 43.008-11.605333v40.96a121.514667 121.514667 0 0 1-45.738667 7.509333 92.842667 92.842667 0 0 1-68.266667-30.037333 108.544 108.544 0 0 1-27.989333-76.458667 101.034667 101.034667 0 0 1 24.576-68.266667 86.698667 86.698667 0 0 1 64.853333-30.72zM887.466667 44.03200000000004h-69.632V213.33333300000004h-40.277334v-204.8H887.466667v35.498667zM819.2 349.866667V896H0v-1024h1024V349.866667zM68.266667-59.733333000000016V827.733333h682.666666v-477.866666H273.066667v-409.6z m887.466666 0H341.333333V281.6h614.4z" horiz-adv-x="1024" />
<glyph glyph-name="waf-1" unicode="&#58922;" d="M1017.6 6.399999999999977c-6.4 12.8-6.4 19.2-6.4 19.2l-121.6 236.8-6.4 6.4-6.4 6.4c-12.8 19.2-25.6 44.8-57.6 44.8h-128c-19.2 0-25.6-12.8-25.6-25.6s12.8-25.6 25.6-25.6h128s6.4-6.4 12.8-19.2l6.4-6.4 121.6-217.6s-6.4-6.4-12.8-6.4h-870.4s-6.4 0-6.4 6.4l128 217.6s6.4 6.4 6.4 12.8 6.4 6.4 0 6.4h115.2c19.2 0 25.6 12.8 25.6 25.6s-12.8 25.6-25.6 25.6h-115.2c-32 0-44.8-19.2-51.2-32l-6.4-6.4s-6.4-6.4-6.4-12.8l-134.4-230.4v-12.8c0-38.4 32-64 70.4-64h870.4c32-6.4 70.4 12.8 70.4 51.2zM512 492.8c70.4 0 128 57.6 128 128s-57.6 128-128 128-128-57.6-128-128 57.6-128 128-128z m0 198.4c38.4 0 70.4-32 70.4-70.4-6.4-38.4-38.4-70.4-70.4-70.4-38.4 0-70.4 32-70.4 70.4 0 38.4 32 70.4 70.4 70.4zM441.6 211.20000000000005c25.6-32 44.8-44.8 70.4-44.8s44.8 12.8 70.4 44.8c70.4 76.8 160 185.6 192 307.2 25.6 83.2 6.4 172.8-44.8 249.6-51.2 64-134.4 102.4-217.6 102.4-96 0-172.8-38.4-230.4-102.4-51.2-64-64-160-32-249.6 25.6-83.2 89.6-192 192-307.2z m-115.2 524.8c32 51.2 96 76.8 179.2 76.8 64 0 128-32 166.4-83.2 44.8-57.6 64-134.4 44.8-198.4-32-115.2-115.2-217.6-185.6-281.6l-25.6-25.6s-6.4 6.4-6.4 12.8c-6.4 6.4-6.4 12.8-12.8 12.8l-12.8 12.8c-44.8 51.2-140.8 166.4-172.8 275.2-19.2 70.4-12.8 140.8 25.6 198.4z" horiz-adv-x="1024" />
<glyph glyph-name="waf-2" unicode="&#59010;" d="M458.752 857.6C360.96 857.6 281.6 778.24 281.6 680.448c0-23.04 12.8-79.872 98.304-201.216 29.184-41.472 58.88-78.848 78.848-102.912 19.968 24.064 49.664 61.44 78.848 102.912 85.504 121.344 98.304 178.176 98.304 201.216 0 97.792-79.36 177.152-177.152 177.152z m0-257.024c-50.176 0-91.136 40.96-91.136 91.136s40.96 91.136 91.136 91.136 91.136-40.96 91.136-91.136-40.96-91.136-91.136-91.136zM417.28 161.27999999999997H141.312v286.72h132.096v61.44H129.024c-27.136 0-49.152-22.016-49.152-49.152V148.48000000000002c0-27.136 22.016-49.152 49.152-49.152H419.84c-2.048 14.336-3.072 28.672-3.072 43.52 0 6.144 0 12.288 0.512 18.432zM837.632 460.288c0 27.136-22.016 49.152-49.152 49.152h-138.752v-61.44h126.464V430.08c21.504-4.608 41.984-11.776 61.44-20.992v51.2zM381.952 371.20000000000005H227.328v-133.12h205.312c6.144 17.408 13.824 34.304 22.528 50.176l-73.216 82.944zM711.168 314.88c94.72 0 171.52-76.8 171.52-171.52s-76.8-171.52-171.52-171.52-171.52 76.8-171.52 171.52 76.8 171.52 171.52 171.52m0 61.44c-128.512 0-232.96-104.448-232.96-232.96s104.448-232.96 232.96-232.96 232.96 104.448 232.96 232.96-104.448 232.96-232.96 232.96zM526.40768 42.94143999999994l334.90944 261.6064 37.82144-48.41984-334.90944-261.6064z" horiz-adv-x="1024" />
<glyph glyph-name="waf-3" unicode="&#58982;" d="M818.869708 193.34349299999997h-185.924226a38.390594 38.390594 0 1 1 0-75.07494h185.924226a38.390594 38.390594 0 1 1 0 75.07494zM198.136454 623.8868990000001h441.634022a42.656216 42.656216 0 0 1 45.499964 38.049344 49.139961 49.139961 0 0 1-45.499964 45.499964H198.07958a42.656216 42.656216 0 0 1-38.049345-45.499964 35.944971 35.944971 0 0 1 38.049345-38.049344z m152.311129-319.807869H198.136454a42.656216 42.656216 0 0 1-38.049344-45.499964 35.944971 35.944971 0 0 1 38.049344-38.049345h144.689885a35.944971 35.944971 0 0 1 38.049344 38.049345c0 22.749982-7.621244 45.499964-30.484975 45.499964zM548.429299 463.954527a35.944971 35.944971 0 0 1-38.049344 38.049344H205.473324a38.10622 38.10622 0 0 1 0-76.155564h304.565381c23.091232-7.564369 38.333719 15.299363 38.333719 38.163095zM806.072843 431.080803V779.553649a97.313047 97.313047 0 0 1-58.069328 94.412425A65.918072 65.918072 0 0 1 697.157305 895.749181H116.35027A105.73054 105.73054 0 0 1 29.21784 859.46296 109.199913 109.199913 0 0 1 0.154738 779.553649v-675.21946a126.717399 126.717399 0 0 1 29.063102-87.13243 109.199913 109.199913 0 0 1 79.624936-29.063102h341.249727a33.214973 33.214973 0 0 1 36.286221 29.063102c21.783108-21.783108 36.286221-43.566215 58.069329-65.349323A280.507276 280.507276 0 0 1 740.723521-128 283.521648 283.521648 0 0 1 1023.903919 155.18039899999997a287.616645 287.616645 0 0 1-217.831076 275.900404z m138.20614-275.900404a202.929838 202.929838 0 0 0-203.555462-203.555463 230.571066 230.571066 0 0 0-145.201759 58.069329 205.375461 205.375461 0 0 0 145.201759 348.529721 207.764209 207.764209 0 0 0 203.555462-203.043587z m-486.678986-87.132431h-341.249727c-7.279994 0-21.783108 7.279994-29.063102 7.279994-7.507494 7.109369-7.507494 14.503113-7.507494 29.006227V779.553649a43.679965 43.679965 0 0 0 7.279994 29.063102 43.679965 43.679965 0 0 0 29.290602 7.507494h573.583916c7.279994 0 14.503113-7.279994 21.783108-7.279994a37.708095 37.708095 0 0 0 14.503113-29.063102V431.080803a284.374773 284.374773 0 0 1-268.62041-275.900404 513.410214 513.410214 0 0 1 14.616863-87.132431h-14.616863z" horiz-adv-x="1024" />
<glyph glyph-name="setting-1" unicode="&#58918;" d="M586.587654-76.34850100000006l0 299.434215c0 3.973192 0 7.585185 0 10.835979 0.361199 11.197178 0.361199 21.310758-2.528395 24.200353-1.444797 1.444797-5.05679 3.250794-14.447972 3.250794l-114.861376 0c-9.391182 0-13.003175-1.805996-14.447972-3.250794-3.250794-3.250794-2.889594-13.003175-2.528395-24.200353 0-3.250794 0-6.862787 0-10.835979l0-299.434215L282.096649-76.34850100000006c-65.015873 0-118.112169 58.514286-118.112169 130.392945l0 263.314286L123.891358 317.35873000000004c-31.424339 0-55.985891 15.17037-67.905467 41.17672-9.391182 21.310758-7.223986 57.069489 26.728748 92.828219l341.694533 355.420106c23.116755 24.200353 54.179894 37.203527 87.410229 37.203527 33.230335 0 64.293474-13.364374 87.410229-37.203527l341.694533-355.420106c34.313933-35.397531 36.119929-71.156261 26.728748-92.467019-5.417989-12.280776-23.116755-41.17672-67.905467-41.17672l-40.093122 0L859.654321 54.40564400000005c0-71.87866-53.096296-130.392945-118.112169-130.392945L586.587654-75.987302zM741.903351 0.22574999999994816c24.922751 0 41.537919 28.173545 41.537919 54.179894L783.44127 393.932981l104.747795 0c-1.083598 1.805996-2.167196 3.611993-3.611993 4.695591l-341.694533 355.058907c-8.668783 9.029982-19.504762 14.086772-29.979541 14.086772 0 0-0.361199 0-0.361199 0-11.197178 0-22.755556-5.05679-31.424339-14.086772l-341.694533-355.058907c-1.444797-1.444797-2.528395-2.889594-3.611993-4.695591l104.747795 0L240.55873 54.40564400000005c0-26.367549 16.615168-54.179894 41.537919-54.179894L361.199295 0.22574999999994816l0 223.221164c0 77.296649 30.70194 114.500176 93.189418 114.500176l114.861376 0c62.848677 0 93.550617-37.564727 93.550617-114.500176L662.800705 0.22574999999994816 741.903351 0.22574999999994816z" horiz-adv-x="1024" />
<glyph glyph-name="setting-2" unicode="&#58928;" d="M437.996 198.481L437.996 198.481 437.996 309.278 327.195 309.278c-61.187 0-110.797-49.61-110.797-110.797 0-61.195 49.61-110.797 110.797-110.797C388.387 87.68399999999997 437.996 137.28599999999994 437.996 198.481L437.996 198.481 437.996 198.481 437.996 198.481zM493.395 198.481c0-91.789-74.411-166.195-166.2-166.195C235.41 32.285999999999945 161 106.69200000000001 161 198.481c0 91.789 74.41 166.195 166.195 166.195l110.801 0 55.399 0 0-55.398L493.395 198.481 493.395 198.481 493.395 198.481zM585.723 198.481L585.723 309.278 696.52 309.278c61.195 0 110.796-49.61 110.796-110.797 0-61.195-49.601-110.797-110.796-110.797C635.332 87.68399999999997 585.723 137.28599999999994 585.723 198.481L585.723 198.481 585.723 198.481zM530.324 198.481c0-91.789 74.41-166.195 166.196-166.195 91.789 0 166.199 74.406 166.199 166.195 0 91.789-74.41 166.195-166.199 166.195L585.723 364.67600000000004l-55.399 0 0-55.398L530.324 198.481 530.324 198.481 530.324 198.481zM437.996 567.8050000000001l0-110.801L327.195 457.004c-61.187 0-110.797 49.61-110.797 110.801 0 61.188 49.61 110.797 110.797 110.797C388.387 678.602 437.996 628.9929999999999 437.996 567.8050000000001L437.996 567.8050000000001 437.996 567.8050000000001zM493.395 567.8050000000001c0 91.785-74.411 166.195-166.2 166.195C235.41 734 161 659.59 161 567.8050000000001c0-91.789 74.41-166.199 166.195-166.199l110.801 0 55.399 0 0 55.398L493.395 567.8050000000001 493.395 567.8050000000001 493.395 567.8050000000001zM585.723 567.8050000000001l0-110.801L696.52 457.004c61.195 0 110.796 49.61 110.796 110.801 0 61.188-49.601 110.797-110.796 110.797C635.332 678.602 585.723 628.9929999999999 585.723 567.8050000000001L585.723 567.8050000000001 585.723 567.8050000000001zM530.324 567.8050000000001L530.324 567.8050000000001C530.324 659.59 604.734 734 696.52 734c91.789 0 166.199-74.41 166.199-166.195 0-91.789-74.41-166.199-166.199-166.199L585.723 401.606l-55.399 0 0 55.398L530.324 567.8050000000001 530.324 567.8050000000001 530.324 567.8050000000001zM530.324 567.8050000000001" horiz-adv-x="1024" />
<glyph glyph-name="setting-3" unicode="&#58903;" d="M827.5 118.60000000000002c60.5 71.8 97 164.4 97 265.4 0 227.4-185.1 412.5-412.5 412.5S99.5 611.4 99.5 384 284.6-28.5 512-28.5c121 0 230 52.4 305.5 135.6l2.7-1.5 7.3 13zM512 534.8c28.7 0 57.2 1.8 85.4 5.3 10.1-47.5 16-97.1 17.2-147.9H415.5c1.2 50.5 7 99.9 17 147.2 26.2-3.1 52.8-4.6 79.5-4.6z m-70.1 43.8C458.8 641 483.4 699 515 750c31.5-50.8 56-108.5 72.9-170.7-25.1-2.9-50.4-4.4-75.9-4.4-23.6 0-46.9 1.2-70.1 3.7z m212.8-186.4c-1.2 52.7-7.2 104.4-17.6 154 61.3 11.3 120.3 30.9 174.9 58.3 44-59.7 70.7-133 72.4-212.3H654.7z m-279.3 0H139.7c1.7 79.3 28.4 152.6 72.4 212.3 56.4-28.3 117.3-48.3 180.7-59.4-10.4-49.2-16.2-100.5-17.4-152.9z m0-40.1c1.1-46.8 6-93 14.5-137.8-60.7-10.9-119.2-30-173.4-56.7-42.1 54.8-69.3 121.7-75.5 194.4h234.4z m40.1 0h199.1c-1.1-45.1-5.9-89.6-14.2-132.5-29.1 3.7-58.6 5.7-88.4 5.7-27.7 0-55.2-1.7-82.4-4.9-8.3 42.6-13 86.8-14.1 131.7z m239.2 0H883c-6.2-72.7-33.4-139.6-75.5-194.4-52.5 25.8-108.9 44.5-167.5 55.6 8.6 45 13.6 91.6 14.7 138.8z m131 284.2c-49.5-23.9-102.7-41-157.9-51-16 60.5-38.9 117.3-68.1 168.1 88.9-11.5 168.1-54.3 226-117.1zM470.8 754.1c-29.6-51.4-52.8-108.7-68.9-169.9-57.3 9.8-112.4 27.3-163.7 52.1 59.4 64.3 141.1 107.7 232.6 117.8zM243.5 126.20000000000005c48.7 22.9 100.8 39.3 154.8 48.9 13.8-56.8 33.5-110.6 58.6-159.4-83.2 12.4-157.6 52.4-213.4 110.5z m261.2-114.5c-29 50.7-51.3 108.1-66.5 169.2 24.4 2.8 49 4.2 73.8 4.2 26.8 0 53.5-1.6 79.7-4.9-15.1-60.8-37.5-117.9-66.3-168.4-4.5-0.2-8.9-0.2-13.4-0.2-2.4 0-4.9 0-7.3 0.1z m68.9 5c24.7 48.3 44.2 101.4 57.9 157.4 52-9.7 102.1-25.8 149-47.9-54.3-56.5-126.3-96-206.9-109.5z" horiz-adv-x="1024" />
<glyph glyph-name="tamper-4" unicode="&#59331;" d="M781.824 552.5333330000001L242.133333 552.5333330000001c-11.797333 0-21.354667-9.557333-21.354667-21.354667 0-11.797333 9.557333-21.354667 21.354667-21.354667l539.690667 0c11.84 0 21.376 9.578667 21.376 21.354667C803.2 542.954667 793.664 552.5333330000001 781.824 552.5333330000001zM242.133333 362.624l441.578667 0c11.84 0 21.376 9.6 21.376 21.376s-9.536 21.354667-21.376 21.354667L242.133333 405.354667c-11.797333 0-21.354667-9.557333-21.354667-21.354667S230.336 362.624 242.133333 362.624zM781.824 258.218667L242.133333 258.218667c-11.797333 0-21.354667-9.557333-21.354667-21.376 0-11.84 9.557333-21.376 21.354667-21.376l539.690667 0c11.84 0 21.376 9.536 21.376 21.376C803.2 248.64 793.664 258.218667 781.824 258.218667zM683.712 110.99733300000003L242.133333 110.99733300000003c-11.797333 0-21.354667-9.557333-21.354667-21.376 0-11.84 9.557333-21.354667 21.354667-21.354667l441.578667 0c11.84 0 21.376 9.514667 21.376 21.354667C705.088 101.44000000000005 695.552 110.99733300000003 683.712 110.99733300000003zM781.824 773.333333l-35.008 0c-12.906667 28.864-41.770667 49.088-75.370667 49.088l-66.922667 0C594.794667 864.490667 556.949333 896 512 896c-45.034667 0-82.816-31.509333-92.544-73.578667l-66.922667 0c-33.621333 0-62.485333-20.224-75.413333-49.088l-23.765333 0c-95.765333 0-179.776-78.762667-179.776-168.554667L73.578667 40.53333299999997c0-89.749333 84.010667-168.533333 179.776-168.533333l528.469333 0c92.906667 0 168.576 75.626667 168.554667 168.533333L950.378667 604.778667C950.4 697.7280000000001 874.773333 773.333333 781.824 773.333333zM352.533333 779.690667l85.888 0c11.776 0 21.354667 9.557333 21.354667 21.354667 0 28.778667 23.445333 52.224 52.224 52.224 28.8 0 52.202667-23.424 52.202667-52.224 0-11.797333 9.536-21.354667 21.333333-21.354667l85.909333 0c21.994667 0 39.957333-17.92 39.957333-39.978667 0-22.037333-17.962667-39.978667-39.957333-39.978667l-318.933333 0c-22.058667 0-39.978667 17.941333-39.978667 39.978667C312.554667 761.770667 330.517333 779.690667 352.533333 779.690667zM907.648 40.53333299999997c0-69.376-56.448-125.802667-125.802667-125.802667L253.354667-85.26933299999996c-73.002667 0-137.045333 58.794667-137.045333 125.802667L116.309333 604.778667c0 67.029333 64.042667 125.824 137.045333 125.824l17.386667 0c4.608-41.28 39.317333-73.6 81.770667-73.6l318.933333 0c42.453333 0 77.141333 32.32 81.749333 73.6l28.629333 0c69.376 0 125.802667-56.448 125.802667-125.824L907.626667 40.53333299999997z" horiz-adv-x="1024" />
<glyph glyph-name="tamper-2" unicode="&#58896;" d="M512 266.66666699999996a117.333333 117.333333 0 1 0 117.333333 117.333333 117.546667 117.546667 0 0 0-117.333333-117.333333z m0 213.333333a96 96 0 1 1 96-96 96 96 0 0 1-96 96zM512 106.66666699999996a277.333333 277.333333 0 1 0 277.333333 277.333333 277.333333 277.333333 0 0 0-277.333333-277.333333z m0 533.333333a256 256 0 1 1 256-256 256 256 0 0 1-256 256zM512-53.33333300000004A437.333333 437.333333 0 1 0 949.333333 384 437.76 437.76 0 0 0 512-53.33333300000004z m0 853.333333A416 416 0 1 1 928 384 416.426667 416.426667 0 0 1 512 800zM85.333333 394.666667h853.333334v-21.333334H85.333333zM501.333333 810.666667h21.333334v-853.333334h-21.333334zM293.76 548.48m-34.56 0a34.56 34.56 0 1 1 69.12 0 34.56 34.56 0 1 1-69.12 0ZM778.666667 384m-34.56 0a34.56 34.56 0 1 1 69.12 0 34.56 34.56 0 1 1-69.12 0Z" horiz-adv-x="1024" />
<glyph glyph-name="tamper-3" unicode="&#60493;" d="M867.584 735.808c-149.632 16.928-262.208 57.408-334.592 120.352l-19.04 16.544-20.544-14.656C379.968 777.056 267.776 736 160 736H128v-448c0-137.344 121.088-261.92 370.208-380.864l13.088-6.24 13.344 5.728C771.072 12.480000000000018 896 140.76800000000003 896 288V732.576l-28.416 3.232zM832 288c0-116.8-107.392-223.36-319.328-316.8C299.872 74.976 192 181.53599999999994 192 288V673.024c104.672 6.784 211.584 46.688 318.496 118.944C587.232 733.472 695.168 694.4639999999999 832 675.744V288zM359.776 427.328a32 32 0 1 1-47.968-42.4l121.792-137.824c12.608-14.24 30.176-21.568 47.904-21.568a64.384 64.384 0 0 1 49.696 23.52l197.6 242.72a32 32 0 0 1-49.632 40.416l-197.6-242.688-121.792 137.824z" horiz-adv-x="1024" />
<glyph glyph-name="tamper-1" unicode="&#59015;" d="M499.2 128c-147.2 0-268.8 121.6-268.8 268.8 0 147.2 121.6 268.8 268.8 268.8 147.2 0 268.8-121.6 268.8-268.8 0-150.4-121.6-268.8-268.8-268.8z m0 486.4c-121.6 0-220.8-99.2-220.8-220.8s99.2-220.8 220.8-220.8 220.8 99.2 220.8 220.8-99.2 220.8-220.8 220.8zM800 70.39999999999998c-6.4 0-12.8 3.2-16 6.4l-105.6 105.6c-9.6 9.6-9.6 25.6 0 35.2 9.6 9.6 25.6 9.6 35.2 0l105.6-105.6c9.6-9.6 9.6-25.6 0-35.2-6.4-3.2-12.8-6.4-19.2-6.4z m-288 233.6h-102.4c-12.8 0-22.4 9.6-22.4 22.4 0 12.8 9.6 22.4 22.4 22.4H512c12.8 0 22.4-9.6 22.4-22.4 3.2-12.8-9.6-22.4-22.4-22.4z m73.6 134.4h-176c-12.8 0-22.4 9.6-22.4 22.4 0 12.8 9.6 22.4 22.4 22.4h176c12.8 0 22.4-9.6 22.4-22.4 3.2-9.6-6.4-22.4-22.4-22.4zM512 896C230.4 896 0 665.6 0 384s230.4-512 512-512c67.2 0 134.4 12.8 195.2 38.4 6.4 3.2 16 6.4 22.4 9.6 6.4 3.2 12.8 9.6 16 16 3.2 6.4 3.2 16 0 22.4-6.4 16-25.6 19.2-38.4 12.8l-19.2-9.6c-54.4-22.4-112-35.2-172.8-35.2C262.4-70.39999999999998 57.6 134.39999999999998 57.6 384S262.4 838.4 512 838.4 966.4 633.6 966.4 384c0-48-6.4-99.2-22.4-144-6.4-16-9.6-28.8-16-44.8-3.2-6.4-3.2-16 0-22.4 3.2-6.4 9.6-12.8 16-16 6.4-3.2 16-3.2 22.4 0 6.4 3.2 12.8 9.6 16 16 6.4 16 12.8 32 19.2 51.2 19.2 51.2 25.6 108.8 25.6 163.2C1024 665.6 793.6 896 512 896z" horiz-adv-x="1027" />
<glyph glyph-name="tongji" unicode="&#59478;" d="M157.538462 29.538462h787.692307v-78.769231H78.769231V817.230769h78.769231v-787.692307z m78.76923 374.153846h78.769231v-315.076923h-78.769231V403.692308z m177.23077 118.153846h78.76923v-433.230769h-78.76923V521.846154z m177.230769-118.153846h78.769231v-315.076923h-78.769231V403.692308z m177.230769 157.538461h78.769231v-472.615384h-78.769231V561.230769z m-470.468923-13.075692l-43.697231 65.536L452.923077 746.417231l173.784615-115.849846 154.505846 137.334153 52.322462-58.88-199.936-177.723076L452.923077 651.736615l-155.392-103.581538z" horiz-adv-x="1024" />
<glyph glyph-name="webdav" unicode="&#58914;" d="M512 846.451613c255.405419 0 462.451613-207.046194 462.451613-462.451613S767.405419-78.45161299999995 512-78.45161299999995 49.548387 128.59458099999995 49.548387 384 256.594581 846.451613 512 846.451613z m0-66.064516C293.07871 780.387097 115.612903 602.92129 115.612903 384s177.465806-396.387097 396.387097-396.387097 396.387097 177.465806 396.387097 396.387097S730.92129 780.387097 512 780.387097zM332.122839 565.677419a33.032258 33.032258 0 0 0 32.090838-25.236645l54.618839-224.916645 57.575226 225.296516A33.032258 33.032258 0 0 0 508.416 565.677419h17.061161a33.032258 33.032258 0 0 0 32.008258-24.856774l57.575226-225.296516 54.618839 224.916645A33.032258 33.032258 0 0 0 701.786839 565.677419h12.684387a29.217032 29.217032 0 0 0 28.110451-37.194322l-85.80129-302.146065A33.032258 33.032258 0 0 0 625.003355 202.322581h-19.059613a33.032258 33.032258 0 0 0-32.008258 24.87329L517.169548 450.064516 459.974194 227.14632300000005A33.032258 33.032258 0 0 0 427.982452 202.322581h-19.555097a33.032258 33.032258 0 0 0-31.777032 24.047484l-85.371871 302.113032A29.233548 29.233548 0 0 0 319.438452 565.677419h12.684387z" horiz-adv-x="1024" />
<glyph glyph-name="xiangqing" unicode="&#58999;" d="M512 654.27010918m-77.34417915 0a77.34417915 77.34417915 0 1 1 154.6883583 0 77.34417915 77.34417915 0 1 1-154.6883583 0ZM512 384m-77.34417915 0a77.34417915 77.34417915 0 1 1 154.6883583 0 77.34417915 77.34417915 0 1 1-154.6883583 0ZM512 113.72989082000004m-77.34417915 0a77.34417915 77.34417915 0 1 1 154.6883583 0 77.34417915 77.34417915 0 1 1-154.6883583 0Z" horiz-adv-x="1024" />

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 90 KiB

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