Compare commits

...

160 Commits

Author SHA1 Message Date
刘祥超
7e5802dcd1 优化没有网站时的提示 2024-01-21 21:17:42 +08:00
刘祥超
2b6d1c70a8 集群节点列表页增加停用/启用操作 2024-01-21 17:42:56 +08:00
刘祥超
faaef3b353 Dockerfile版本号修改为1.3.3 2024-01-21 16:58:01 +08:00
刘祥超
6ffa1d4a1d 版本号修改为1.3.3 2024-01-21 16:55:55 +08:00
刘祥超
10f0e0dcca 提交components.js 2024-01-21 16:55:31 +08:00
刘祥超
0afad2e192 增加创建本地节点命令 2024-01-21 16:55:22 +08:00
刘祥超
6a1e7266b9 优化缓存文件句柄缓存的文字提示 2024-01-21 14:31:05 +08:00
刘祥超
6ffc552bd8 WAF允许ALLOW动作增加有效范围 2024-01-20 21:23:59 +08:00
刘祥超
8d8245971a WAF策略增加显示页面动作默认设置 2024-01-20 16:17:28 +08:00
刘祥超
a2f730d57e 修复部分内置页面没有<head>标签的问题 2024-01-20 10:15:05 +08:00
刘祥超
bf282c41fd 优化创建策略规则集提示 2024-01-19 11:24:02 +08:00
刘祥超
3e3f7b2cc6 WAF动作默认设置为“显示网页(page)”,减少因错误规则导致的IP封禁 2024-01-19 11:13:01 +08:00
刘祥超
0580e063be 优化网站列表批量操作按钮,防止误操作 2024-01-19 10:56:31 +08:00
刘祥超
2924aad25e 修改版本号为1.3.2.2 2024-01-16 20:59:07 +08:00
刘祥超
39907299cd 提交components.js 2024-01-16 20:58:58 +08:00
刘祥超
77705895d5 优化添加规则界面 2024-01-16 20:42:06 +08:00
刘祥超
3fb85edf0b 提交components.js 2024-01-15 08:51:21 +08:00
刘祥超
0e7a968cac 版本号修改为1.3.2.1 2024-01-15 08:40:14 +08:00
刘祥超
195a9dc771 优化网站设置和路由设置中的左侧菜单 2024-01-14 20:33:07 +08:00
刘祥超
ca227a846a 优化代码 2024-01-13 19:31:52 +08:00
刘祥超
e1057fc76e 字符编码设置增加“强制替换”选项 2024-01-13 16:28:37 +08:00
刘祥超
b5168c3174 优化文字 2024-01-13 15:46:26 +08:00
刘祥超
4ced00de50 修改API节点时提示用户需要重启edge-api进程 2024-01-12 16:44:02 +08:00
刘祥超
750c929506 实现批量删除网站功能 2024-01-11 18:40:29 +08:00
刘祥超
8b46a5a5af 自定义页面跳转支持使用变量 2024-01-11 15:37:31 +08:00
刘祥超
10d606a101 增加带宽相关组件 2024-01-11 15:17:52 +08:00
刘祥超
45d36dadcb 修复“迁移”功能中无法远程修改API节点访问地址的问题 2024-01-09 10:39:09 +08:00
刘祥超
61484d5cb8 增加用户系统文章相关管理 2024-01-09 10:21:05 +08:00
刘祥超
b7775a99ef 优化添加缓存条件和不缓存条件交互 2023-12-28 15:50:19 +08:00
刘祥超
c45ba38ffa 修复参数匹配不区分大小写选项无法保存的问题 2023-12-28 15:31:40 +08:00
刘祥超
e97d9fb8a0 优化可执行文件程序 2023-12-26 09:09:21 +08:00
刘祥超
bb56ec9ec5 修改Dockerfile版本 2023-12-24 17:35:30 +08:00
刘祥超
6d8f659558 版本号修改为1.3.2 2023-12-24 11:14:31 +08:00
刘祥超
7e9047c8fe 优化IP名单管理 2023-12-24 11:05:38 +08:00
刘祥超
b5af560b67 IP名单中可以批量删除最多10000个IP 2023-12-24 10:53:03 +08:00
刘祥超
5622636870 优化请求脚本相关代码 2023-12-23 20:54:37 +08:00
刘祥超
372c276afc 优化英文菜单样式 2023-12-23 09:41:33 +08:00
刘祥超
250b5fdd10 取消“通用设置”菜单 2023-12-22 16:58:16 +08:00
刘祥超
d1fb0bf8b7 优化数据库节点相关文字提示 2023-12-21 17:18:04 +08:00
刘祥超
490c273d36 改进部分文字 2023-12-20 15:06:19 +08:00
刘祥超
0773dbaa28 在网站设置中显示流量相关限制状态 2023-12-19 14:56:05 +08:00
刘祥超
4d04964740 修复缓存条件简单和复杂切换时可能导致复杂条件失效的问题 2023-12-19 09:26:18 +08:00
刘祥超
537e6c9a5e 修复一处编译问题 2023-12-18 10:12:20 +08:00
刘祥超
082a6721f3 版本号修改为1.3.1.2 2023-12-18 08:51:16 +08:00
刘祥超
d515a20129 提升Go模板安全性 2023-12-14 19:57:02 +08:00
刘祥超
a66d3ef61a 更新相关库 2023-12-14 19:53:43 +08:00
刘祥超
3b05b1a933 优化修改网站域名时套餐相关检查 2023-12-13 19:02:12 +08:00
刘祥超
105479ce4b 网站所属用户没有套餐时提示用户 2023-12-13 18:53:08 +08:00
刘祥超
1a950e3aad 非商业版隐藏网站配置复制图标 2023-12-13 18:46:16 +08:00
刘祥超
79fa76e039 缓存设置中可以设置缓存主域名,用来复用多域名下的缓存 2023-12-13 18:33:48 +08:00
刘祥超
9db9a70a68 优化文字 2023-12-13 11:08:35 +08:00
刘祥超
632862c742 优化多语言相关代码 2023-12-13 10:29:50 +08:00
刘祥超
76d0783f6f 切换语言时保存语言设置 2023-12-12 22:39:42 +08:00
刘祥超
fc6a0e9813 切换语言时保存更长时间 2023-12-12 22:28:17 +08:00
刘祥超
038e289057 更新components.js 2023-12-12 22:28:04 +08:00
刘祥超
4b2a4af1e7 优化极验相关代码 2023-12-12 15:00:38 +08:00
刘祥超
0fb2555bea Update en-us.js 2023-12-12 12:11:13 +08:00
刘祥超
bd8a809065 优化英文版样式 2023-12-12 11:54:20 +08:00
刘祥超
fc6fb7dce2 部分菜单实现中英文切换 2023-12-12 11:47:41 +08:00
刘祥超
bacb94abe6 优化WebP相关提示和代码 2023-12-11 11:07:02 +08:00
刘祥超
eb04421412 WebP转换质量转移到WebP策略配置 2023-12-11 10:00:22 +08:00
刘祥超
2fbd5a785e 改进部分表单文字提示 2023-12-10 10:46:50 +08:00
刘祥超
d8ae1525be 管理系统安全设置增加“自定义客户端IP报头” 2023-12-10 10:46:35 +08:00
刘祥超
daaa165d25 优化集群设置--WAF策略选择窗口尺寸 2023-12-10 08:55:12 +08:00
刘祥超
27ea02be5e 优化WAF动作“显示网页”显示 2023-12-09 15:55:17 +08:00
刘祥超
8eac1ef307 优化文字提示 2023-12-08 16:00:48 +08:00
刘祥超
1181974ea5 WAF规则集列表中参数和操作符增加悬停提示 2023-12-08 12:01:36 +08:00
刘祥超
5f57fa0470 WAF规则集列表中参数显示中文 2023-12-08 11:20:32 +08:00
刘祥超
c0ad74ab7b WAF操作符对应的对比值可以不填写 2023-12-07 20:24:26 +08:00
刘祥超
c27905e1cc 优化WAF多行对比值的文字提示 2023-12-07 11:44:37 +08:00
刘祥超
cadb65a85f 业务域名CNAME检查DNS主机地址增加Google公共DNS 2023-12-06 09:42:15 +08:00
刘祥超
b3c152685a 优化检查域名解析文字提示 2023-12-05 11:33:32 +08:00
刘祥超
16ce0726f8 将部分MB、GB...改成MiB、GiB... 2023-12-03 11:41:04 +08:00
刘祥超
5be306e087 将部分MB、GB...改成MiB、GiB... 2023-12-03 11:30:02 +08:00
刘祥超
0d21fc27ab 增加“极验-行为验”验证码集成支持 2023-11-29 16:57:58 +08:00
刘祥超
7deaa678bc 创建集群时默认生成子域名 2023-11-27 11:28:01 +08:00
刘祥超
0d230a9237 <domain-box>组件自动分割单个域名 2023-11-27 10:31:41 +08:00
刘祥超
8453d754f1 添加域名时自动分割用逗号、顿号连接的域名列表 2023-11-27 10:20:54 +08:00
刘祥超
05f77f7a0d 修复go.mod 2023-11-24 10:21:07 +08:00
刘祥超
4334b6f148 修复若干测试用例 2023-11-24 09:13:18 +08:00
刘祥超
72955759d7 更新go.sum 2023-11-24 08:53:40 +08:00
刘祥超
18dc52996d 更新Dockerfile中版本 2023-11-23 17:40:28 +08:00
刘祥超
0b16d09330 版本号修改为1.3.1 2023-11-23 17:26:24 +08:00
刘祥超
027d81a8cd 优化SSH认证sudo设置 2023-11-23 16:12:41 +08:00
刘祥超
d833158784 DNSPod改名为腾讯云DNSPod/DNSPod 支持腾讯云API密钥 2023-11-23 15:14:34 +08:00
刘祥超
75024c9364 优化X-Cache报头设置文字提示 2023-11-22 19:02:18 +08:00
刘祥超
1dd5db3c42 优化第三方域名解析azure dns提示文字 2023-11-22 10:30:29 +08:00
刘祥超
faba80e315 GRPC增加Keepalive参数 2023-11-20 09:56:35 +08:00
刘祥超
1b7dc8eb96 优化下载升级新版本文字提示 2023-11-20 08:25:34 +08:00
刘祥超
7c0af45dd0 更新Dockerfile中版本号 2023-11-19 17:34:15 +08:00
刘祥超
daea270132 更新components.js 2023-11-19 17:33:56 +08:00
刘祥超
a42e3ac4a6 优化CAPTCHA最大失败次数文字提示 2023-11-19 15:43:37 +08:00
刘祥超
c94c526b43 提交components.js 2023-11-19 09:09:50 +08:00
刘祥超
e531787773 集群WAF策略处于非防御模式时在地区封禁页面提示用户 2023-11-18 15:25:14 +08:00
刘祥超
0eda84a99a 修复修改单个WAF动作时名称变为阻止的问题 2023-11-18 08:51:50 +08:00
刘祥超
89b791448a 优化DNS.LA域名解析提示文字 2023-11-17 18:13:54 +08:00
刘祥超
2239328b2e 优化GoDaddy域名解析提示文字 2023-11-17 18:01:50 +08:00
刘祥超
e440a46080 源站支持404内容自动重试其他源站 2023-11-15 19:05:04 +08:00
刘祥超
4a0fec6e35 优化WAF设置中人机识别验证方式 2023-11-15 17:19:29 +08:00
刘祥超
a9b46987bc 更新components.js 2023-11-15 15:13:09 +08:00
刘祥超
6771afead5 WAF人机识别实现点击验证和滑动解锁验证/单个网站可以设置默认的人机识别方式 2023-11-15 15:12:58 +08:00
刘祥超
553fca2981 版本号修改为1.3.0 2023-11-14 14:47:52 +08:00
刘祥超
8ef1e36b8b 优化界面 2023-11-13 17:47:24 +08:00
刘祥超
9e6c49b67c 调教components.js 2023-11-13 17:00:22 +08:00
刘祥超
170632ddbc 增加用户列表菜单 2023-11-13 11:53:30 +08:00
刘祥超
4a74488cac 自定义页面增加例外URL和限制URL设置 2023-11-13 10:45:13 +08:00
刘祥超
5fd6a08988 第三方域名解析支持微软Azure DNS(商业版) 2023-11-12 20:31:16 +08:00
刘祥超
c86b91ead6 自定义页面增加“跳转URL”功能 2023-11-10 16:36:03 +08:00
刘祥超
aeebb763c1 优化自定义页面组件界面 2023-11-10 14:59:53 +08:00
刘祥超
b05630e3e0 优化集群设置 -- 网站设置界面 2023-11-10 11:46:02 +08:00
刘祥超
51905a0ee3 URL跳转中增加例外域名和仅限域名 2023-11-10 11:05:05 +08:00
刘祥超
869ebd59d1 优化Ln节点域名解析选项提示 2023-11-09 17:02:15 +08:00
刘祥超
8a6aedca16 集群设置--DNS设置中增加”解析记录“页面 2023-11-09 16:24:52 +08:00
刘祥超
cf98c3453a 域名解析支持Amazon Route 53(商业版) 2023-11-08 21:17:32 +08:00
刘祥超
1b6f234f39 第三方域名解析增加火山引擎TrafficRoute 2023-11-06 16:21:19 +08:00
刘祥超
26c7f0f566 优化多行消息显示 2023-11-03 16:39:20 +08:00
刘祥超
617ad9b16e 申请ACME证书时防止重复提交 2023-11-03 16:26:20 +08:00
刘祥超
04a6792dbf 删除不需要的文件 2023-11-03 11:00:26 +08:00
刘祥超
f2bf8f2dbf 删除不需要的文件 2023-11-03 10:48:34 +08:00
刘祥超
3aba0abd24 优化硬盘不足提示算法 2023-11-03 09:06:33 +08:00
刘祥超
b56ccc7cef 优化数据看板 2023-10-30 16:44:01 +08:00
刘祥超
aeebf55e60 优化数据看板 2023-10-30 11:33:00 +08:00
刘祥超
9a9e0d25f3 优化数据看板图表排列 2023-10-30 11:30:51 +08:00
刘祥超
6b3033e240 删除不需要的文件 2023-10-27 09:12:19 +08:00
刘祥超
2859a59340 优化界面 2023-10-26 15:13:35 +08:00
刘祥超
45367dd579 将看板中的“服务”文字改为“网站” 2023-10-26 11:35:31 +08:00
刘祥超
fee3fd743f MySQL安装程序支持8.2 2023-10-26 08:33:35 +08:00
刘祥超
ba4cfea47c 优化文字提示 2023-10-25 15:22:13 +08:00
刘祥超
5c11f07f8e 优化域名解析文字提示 2023-10-17 15:53:58 +08:00
刘祥超
ffac080611 将版本号修改为1.2.11 2023-10-17 13:50:03 +08:00
刘祥超
f7a1e60735 更新架构图 2023-10-15 20:32:57 +08:00
刘祥超
f22651821c 更新架构图 2023-10-15 20:19:59 +08:00
刘祥超
b2a5a9ac9b 更新架构图片 2023-10-15 20:13:52 +08:00
刘祥超
245af2bd77 修改Dockfile中的版本号为1.2.10 2023-10-15 14:42:04 +08:00
刘祥超
9dd2b1d35c 删除不需要的代码 2023-10-15 14:34:37 +08:00
刘祥超
bdbfd3e055 提交components.js 2023-10-15 14:30:27 +08:00
刘祥超
1518c03d2b 将版本号修改为1.2.10 2023-10-15 13:34:44 +08:00
刘祥超
45920d4df2 WAF记录IP动作中IP名单允许留空 2023-10-15 09:34:07 +08:00
刘祥超
1c106ac6eb 优化消息通知相关代码 2023-10-14 17:15:45 +08:00
刘祥超
9f4a32b4ac macOS上检测磁盘是否不足时忽略/Developer/相关分区 2023-10-13 09:22:45 +08:00
刘祥超
2565b10491 优化集群设置DNS TTL设置文字提示 2023-10-12 10:29:48 +08:00
刘祥超
34d632a401 删除看板中不需要的版本判断 2023-10-11 17:52:02 +08:00
刘祥超
a9df27c0e1 删除不需要的文件 2023-10-11 17:49:59 +08:00
刘祥超
313011a168 支持批量复制WAF设置 2023-10-09 19:52:39 +08:00
刘祥超
5c595aad83 提交components.js 2023-10-09 17:30:23 +08:00
刘祥超
2c67eac63c 升级时如果unzip命令不存在,则使用自定义解压程序 2023-10-09 17:30:10 +08:00
刘祥超
d20c20cb33 申请证书任务列表区分管理员和用户 2023-10-09 16:18:27 +08:00
刘祥超
fa76f032be 证书列表区分管理员和用户证书 2023-10-09 15:53:02 +08:00
刘祥超
3f74910640 访问日志列表搜索增加请求来源查询语法:referer:example.com 2023-10-08 17:52:48 +08:00
刘祥超
22bd2a57e9 WAF规则对比值长度限制为4096个字符 2023-10-08 16:14:50 +08:00
刘祥超
e45a1d0367 集群设置中增加“自动调节系统参数”选项 2023-10-08 15:08:11 +08:00
刘祥超
ee7acdc6a0 优化<url-pattern-box>组件对输入问号的提示 2023-09-27 15:24:05 +08:00
刘祥超
32264f2700 优化重写规则中目标URL选项说明 2023-09-25 18:02:35 +08:00
刘祥超
249ea32973 网站访问日志未开启时,在访问日志列表显示提醒文字 2023-09-22 16:26:15 +08:00
刘祥超
9c31b69a58 优化“集群设置--网站设置”页面 2023-09-18 17:58:16 +08:00
刘祥超
6e985cf6cc 将全局设置的TCP相关设置移到“集群设置--网站设置”中 2023-09-18 16:55:40 +08:00
刘祥超
0f35b45704 将全局的通用设置--域名审核设置移到“集群设置--网站设置”中 2023-09-18 16:07:57 +08:00
刘祥超
ba9245e724 优化集群设置--网站设置界面 2023-09-18 10:43:56 +08:00
刘祥超
6e806f2822 优化缓存磁盘用量选项提示文字 2023-09-18 10:35:22 +08:00
刘祥超
7c6842a859 修改Dockfile的版本号 2023-09-18 07:40:17 +08:00
324 changed files with 29567 additions and 5354 deletions

View File

@@ -46,7 +46,7 @@
* [开发者指南](https://goedge.cn/docs/Developer/Build.md)
## 架构
![架构](doc/architect-zh.jpg)
![架构](doc/architect-zh.png)
其中的组件源码地址如下:
* [边缘节点](https://github.com/TeaOSLab/EdgeNode)

View File

@@ -11,6 +11,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/nodes"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
_ "github.com/TeaOSLab/EdgeCommon/pkg/langs/messages"
"github.com/iwind/TeaGo/Tea"
_ "github.com/iwind/TeaGo/bootstrap"
@@ -40,7 +41,8 @@ func main() {
Option("demo", "switch to demo mode").
Option("dev", "switch to 'dev' mode").
Option("prod", "switch to 'prod' mode").
Option("upgrade [--url=URL]", "upgrade from official site or an url")
Option("upgrade [--url=URL]", "upgrade from official site or an url").
Option("install-local-node", "install a local node")
app.On("daemon", func() {
nodes.NewAdminNode().Daemon()
@@ -76,7 +78,7 @@ func main() {
fmt.Println("done")
})
app.On("recover", func() {
sock := gosock.NewTmpSock(teaconst.ProcessName)
var sock = gosock.NewTmpSock(teaconst.ProcessName)
if !sock.IsListening() {
fmt.Println("[ERROR]the service not started yet, you should start the service first")
return
@@ -89,7 +91,7 @@ func main() {
fmt.Println("enter recovery mode successfully")
})
app.On("demo", func() {
sock := gosock.NewTmpSock(teaconst.ProcessName)
var sock = gosock.NewTmpSock(teaconst.ProcessName)
if !sock.IsListening() {
fmt.Println("[ERROR]the service not started yet, you should start the service first")
return
@@ -178,6 +180,14 @@ func main() {
log.Println("restarting ...")
app.RunRestart()
})
app.On("install-local-node", func() {
err := nodeutils.InstallLocalNode()
if err != nil {
fmt.Println("[ERROR]" + err.Error())
return
}
fmt.Println("success")
})
app.Run(func() {
var adminNode = nodes.NewAdminNode()
adminNode.Run()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

BIN
doc/architect-zh.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

View File

@@ -1,7 +1,7 @@
FROM --platform=linux/amd64 alpine:latest
LABEL maintainer="goedge.cdn@gmail.com"
ENV TZ "Asia/Shanghai"
ENV VERSION 1.2.8
ENV VERSION 1.3.3
ENV ROOT_DIR /usr/local/goedge
ENV TAR_FILE edge-admin-linux-amd64-plus-v${VERSION}.zip

29
go.mod
View File

@@ -8,16 +8,16 @@ require (
github.com/TeaOSLab/EdgeCommon v0.0.0-00010101000000-000000000000
github.com/cespare/xxhash v1.1.0
github.com/go-sql-driver/mysql v1.5.0
github.com/iwind/TeaGo v0.0.0-20230623080147-cd1e53b4915f
github.com/iwind/TeaGo v0.0.0-20231214114820-1bfb0013bcf6
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4
github.com/miekg/dns v1.1.43
github.com/quic-go/quic-go v0.36.0
github.com/quic-go/quic-go v0.40.0
github.com/shirou/gopsutil/v3 v3.22.5
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/tealeg/xlsx/v3 v3.2.3
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
golang.org/x/crypto v0.10.0
golang.org/x/sys v0.9.0
golang.org/x/crypto v0.16.0
golang.org/x/sys v0.15.0
google.golang.org/grpc v1.45.0
gopkg.in/yaml.v3 v3.0.1
)
@@ -26,29 +26,28 @@ require (
github.com/frankban/quicktest v1.11.3 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/btree v1.0.0 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/pprof v0.0.0-20231203200248-ad67f76aa53d // indirect
github.com/kr/pretty v0.2.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
github.com/onsi/ginkgo/v2 v2.13.2 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
github.com/rogpeppe/fastuuid v1.2.0 // indirect
github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa // indirect
github.com/tdewolff/minify/v2 v2.12.7 // indirect
github.com/tdewolff/parse/v2 v2.6.6 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
golang.org/x/mod v0.11.0 // indirect
golang.org/x/net v0.11.0 // indirect
golang.org/x/text v0.10.0 // indirect
golang.org/x/tools v0.10.0 // indirect
go.uber.org/mock v0.3.0 // indirect
golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.16.0 // indirect
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect

69
go.sum
View File

@@ -41,7 +41,7 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-redis/redis/v8 v8.0.0-beta.7/go.mod h1:FGJAWDWFht1sQ4qxyJHZZbVyvnVcKQN0E3u5/5lRz+g=
@@ -51,8 +51,6 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
@@ -79,17 +77,19 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs=
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA=
github.com/google/pprof v0.0.0-20231203200248-ad67f76aa53d h1:bM3Cipp7U7Sdn0DpYngVaLWFV9yonxQ1IB7ZPQ41OLw=
github.com/google/pprof v0.0.0-20231203200248-ad67f76aa53d/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20230623080147-cd1e53b4915f h1:xo6XmXLtveKcwcZAXV6VMxkWNzy/2dStfHEnyowsGAE=
github.com/iwind/TeaGo v0.0.0-20230623080147-cd1e53b4915f/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s=
github.com/iwind/TeaGo v0.0.0-20231214114820-1bfb0013bcf6 h1:l8MW552d+gLzRd+MAtM/2X+80n/uS5nJAlBTYWHroRI=
github.com/iwind/TeaGo v0.0.0-20231214114820-1bfb0013bcf6/go.mod h1:Ng3xWekHSVy0E/6/jYqJ7Htydm/H+mWIl0AS+Eg3H2M=
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4 h1:VWGsCqTzObdlbf7UUE3oceIpcEKi4C/YBUszQXk118A=
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -112,12 +112,12 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc=
github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
github.com/opentracing/opentracing-go v1.1.1-0.20190913142402-a7454ce5950e/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
@@ -130,12 +130,10 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:Om
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U=
github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/quic-go/quic-go v0.36.0 h1:JIrO7p7Ug6hssFcARjWDiqS2RAKJHCiwPxBAA989rbI=
github.com/quic-go/quic-go v0.36.0/go.mod h1:zPetvwDlILVxt15n3hr3Gf/I3mDf7LpLKPhR4Ez0AZQ=
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.40.0 h1:GYd1iznlKm7dpHD7pOVpUvItgMPo/jrMgDWZhMCecqw=
github.com/quic-go/quic-go v0.40.0/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa h1:2cO3RojjYl3hVTbEvJVqrMaFmORhL6O06qdW42toftk=
@@ -167,21 +165,22 @@ github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYa
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119 h1:YyPWX3jLOtYKulBR6AScGIs74lLrJcgeKRwcbAuQOG4=
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119/go.mod h1:/nuTSlK+okRfR/vnIPqR89fFKonnWPiZymN5ydRJkX8=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opentelemetry.io/otel v0.7.0/go.mod h1:aZMyHG5TqDOXEgH2tyLiXSUKly1jT3yqE9PmrzIeCdo=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No=
golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -190,9 +189,8 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -206,8 +204,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -215,7 +213,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -237,27 +235,24 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -174,6 +174,17 @@ func FindAdminLang(adminId int64) string {
return ""
}
// UpdateAdminLang 修改某个管理员选择的语言
func UpdateAdminLang(adminId int64, langCode string) {
locker.Lock()
defer locker.Unlock()
list, ok := sharedAdminModuleMapping[adminId]
if ok {
list.Lang = langCode
}
}
func FindAdminLangForAction(actionPtr actions.ActionWrapper) (langCode langs.LangCode) {
locker.Lock()
defer locker.Unlock()

View File

@@ -1,9 +1,9 @@
package teaconst
const (
Version = "1.2.9"
Version = "1.3.3"
APINodeVersion = "1.2.9"
APINodeVersion = "1.3.3"
ProductName = "Edge Admin"
ProcessName = "edge-admin"

View File

@@ -14,6 +14,7 @@ import (
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/files"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/maps"
"io"
"os"
"path/filepath"
@@ -63,7 +64,7 @@ func generateComponentsJSFile() error {
} else {
buffer.WriteString("window.REQUEST_COND_COMPONENTS = ")
buffer.Write(typesJSON)
buffer.Write([]byte{'\n', '\n'})
buffer.Write([]byte{';', '\n', '\n'})
}
// 条件操作符
@@ -73,7 +74,7 @@ func generateComponentsJSFile() error {
} else {
buffer.WriteString("window.REQUEST_COND_OPERATORS = ")
buffer.Write(requestOperatorsJSON)
buffer.Write([]byte{'\n', '\n'})
buffer.Write([]byte{';', '\n', '\n'})
}
// 请求变量
@@ -83,7 +84,7 @@ func generateComponentsJSFile() error {
} else {
buffer.WriteString("window.REQUEST_VARIABLES = ")
buffer.Write(requestVariablesJSON)
buffer.Write([]byte{'\n', '\n'})
buffer.Write([]byte{';', '\n', '\n'})
}
// 指标
@@ -93,7 +94,7 @@ func generateComponentsJSFile() error {
} else {
buffer.WriteString("window.METRIC_HTTP_KEYS = ")
buffer.Write(metricHTTPKeysJSON)
buffer.Write([]byte{'\n', '\n'})
buffer.Write([]byte{';', '\n', '\n'})
}
// IP地址阈值项目
@@ -103,7 +104,7 @@ func generateComponentsJSFile() error {
} else {
buffer.WriteString("window.IP_ADDR_THRESHOLD_ITEMS = ")
buffer.Write(ipAddrThresholdItemsJSON)
buffer.Write([]byte{'\n', '\n'})
buffer.Write([]byte{';', '\n', '\n'})
}
// IP地址阈值动作
@@ -113,7 +114,25 @@ func generateComponentsJSFile() error {
} else {
buffer.WriteString("window.IP_ADDR_THRESHOLD_ACTIONS = ")
buffer.Write(ipAddrThresholdActionsJSON)
buffer.Write([]byte{'\n', '\n'})
buffer.Write([]byte{';', '\n', '\n'})
}
// WAF checkpoints
var wafCheckpointsMaps = []maps.Map{}
for _, checkpoint := range firewallconfigs.AllCheckpoints {
wafCheckpointsMaps = append(wafCheckpointsMaps, maps.Map{
"name": checkpoint.Name,
"prefix": checkpoint.Prefix,
"description": checkpoint.Description,
})
}
wafCheckpointsJSON, err := json.Marshal(wafCheckpointsMaps)
if err != nil {
logs.Println("ComponentsAction marshal waf rule checkpoints failed: " + err.Error())
} else {
buffer.WriteString("window.WAF_RULE_CHECKPOINTS = ")
buffer.Write(wafCheckpointsJSON)
buffer.Write([]byte{';', '\n', '\n'})
}
// WAF操作符
@@ -123,7 +142,17 @@ func generateComponentsJSFile() error {
} else {
buffer.WriteString("window.WAF_RULE_OPERATORS = ")
buffer.Write(wafOperatorsJSON)
buffer.Write([]byte{'\n', '\n'})
buffer.Write([]byte{';', '\n', '\n'})
}
// WAF验证码类型
captchaTypesJSON, err := json.Marshal(firewallconfigs.FindAllCaptchaTypes())
if err != nil {
logs.Println("ComponentsAction marshal captcha types failed: " + err.Error())
} else {
buffer.WriteString("window.WAF_CAPTCHA_TYPES = ")
buffer.Write(captchaTypesJSON)
buffer.Write([]byte{';', '\n', '\n'})
}
fp, err := os.OpenFile(filepath.Clean(Tea.PublicFile("/js/components.src.js")), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777)

View File

@@ -20,6 +20,7 @@ import (
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/encoding/gzip"
"google.golang.org/grpc/keepalive"
"google.golang.org/grpc/metadata"
"net"
"net/url"
@@ -280,34 +281,6 @@ func (this *RPCClient) MessageRPC() pb.MessageServiceClient {
return pb.NewMessageServiceClient(this.pickConn())
}
func (this *RPCClient) MessageRecipientGroupRPC() pb.MessageRecipientGroupServiceClient {
return pb.NewMessageRecipientGroupServiceClient(this.pickConn())
}
func (this *RPCClient) MessageRecipientRPC() pb.MessageRecipientServiceClient {
return pb.NewMessageRecipientServiceClient(this.pickConn())
}
func (this *RPCClient) MessageMediaRPC() pb.MessageMediaServiceClient {
return pb.NewMessageMediaServiceClient(this.pickConn())
}
func (this *RPCClient) MessageMediaInstanceRPC() pb.MessageMediaInstanceServiceClient {
return pb.NewMessageMediaInstanceServiceClient(this.pickConn())
}
func (this *RPCClient) MessageTaskRPC() pb.MessageTaskServiceClient {
return pb.NewMessageTaskServiceClient(this.pickConn())
}
func (this *RPCClient) MessageTaskLogRPC() pb.MessageTaskLogServiceClient {
return pb.NewMessageTaskLogServiceClient(this.pickConn())
}
func (this *RPCClient) MessageReceiverRPC() pb.MessageReceiverServiceClient {
return pb.NewMessageReceiverServiceClient(this.pickConn())
}
func (this *RPCClient) IPLibraryRPC() pb.IPLibraryServiceClient {
return pb.NewIPLibraryServiceClient(this.pickConn())
}
@@ -416,14 +389,6 @@ func (this *RPCClient) NodeTaskRPC() pb.NodeTaskServiceClient {
return pb.NewNodeTaskServiceClient(this.pickConn())
}
func (this *RPCClient) AuthorityKeyRPC() pb.AuthorityKeyServiceClient {
return pb.NewAuthorityKeyServiceClient(this.pickConn())
}
func (this *RPCClient) AuthorityNodeRPC() pb.AuthorityNodeServiceClient {
return pb.NewAuthorityNodeServiceClient(this.pickConn())
}
func (this *RPCClient) LatestItemRPC() pb.LatestItemServiceClient {
return pb.NewLatestItemServiceClient(this.pickConn())
}
@@ -550,12 +515,15 @@ func (this *RPCClient) init() error {
grpc.MaxCallSendMsgSize(128<<20),
grpc.UseCompressor(gzip.Name),
)
var keepaliveParams = grpc.WithKeepaliveParams(keepalive.ClientParameters{
Time: 30 * time.Second,
})
if u.Scheme == "http" {
conn, err = grpc.Dial(apiHost, grpc.WithTransportCredentials(insecure.NewCredentials()), callOptions)
conn, err = grpc.Dial(apiHost, grpc.WithTransportCredentials(insecure.NewCredentials()), callOptions, keepaliveParams)
} else if u.Scheme == "https" {
conn, err = grpc.Dial(apiHost, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
InsecureSkipVerify: true,
})), callOptions)
})), callOptions, keepaliveParams)
} else {
return errors.New("parse endpoint failed: invalid scheme '" + u.Scheme + "'")
}

View File

@@ -34,14 +34,9 @@ func TestRPCClient_NodeRPC(t *testing.T) {
func TestRPC_Dial_HTTP(t *testing.T) {
client, err := NewRPCClient(&configs.APIConfig{
RPC: struct {
Endpoints []string `yaml:"endpoints"`
DisableUpdate bool `yaml:"disableUpdate"`
}{
Endpoints: []string{"http://127.0.0.1:8004"},
},
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
RPCEndpoints: []string{"https://127.0.0.1:8003"},
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
}, true)
if err != nil {
t.Fatal(err)
@@ -56,14 +51,9 @@ func TestRPC_Dial_HTTP(t *testing.T) {
func TestRPC_Dial_HTTP_2(t *testing.T) {
client, err := NewRPCClient(&configs.APIConfig{
RPC: struct {
Endpoints []string `yaml:"endpoints"`
DisableUpdate bool `yaml:"disableUpdate"`
}{
Endpoints: []string{"https://127.0.0.1:8003"},
},
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
RPCEndpoints: []string{"https://127.0.0.1:8003"},
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
}, true)
if err != nil {
t.Fatal(err)
@@ -78,14 +68,9 @@ func TestRPC_Dial_HTTP_2(t *testing.T) {
func TestRPC_Dial_HTTPS(t *testing.T) {
client, err := NewRPCClient(&configs.APIConfig{
RPC: struct {
Endpoints []string `yaml:"endpoints"`
DisableUpdate bool `yaml:"disableUpdate"`
}{
Endpoints: []string{"https://127.0.0.1:8004"},
},
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
RPCEndpoints: []string{"https://127.0.0.1:8004"},
NodeId: "a7e55782dab39bce0901058a1e14a0e6",
Secret: "lvyPobI3BszkJopz5nPTocOs0OLkEJ7y",
}, true)
if err != nil {
t.Fatal(err)

162
internal/utils/exec/cmd.go Normal file
View File

@@ -0,0 +1,162 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package executils
import (
"bytes"
"context"
"os"
"os/exec"
"strings"
"time"
)
type Cmd struct {
name string
args []string
env []string
dir string
ctx context.Context
timeout time.Duration
cancelFunc func()
captureStdout bool
captureStderr bool
stdout *bytes.Buffer
stderr *bytes.Buffer
rawCmd *exec.Cmd
}
func NewCmd(name string, args ...string) *Cmd {
return &Cmd{
name: name,
args: args,
}
}
func NewTimeoutCmd(timeout time.Duration, name string, args ...string) *Cmd {
return (&Cmd{
name: name,
args: args,
}).WithTimeout(timeout)
}
func (this *Cmd) WithTimeout(timeout time.Duration) *Cmd {
this.timeout = timeout
ctx, cancelFunc := context.WithTimeout(context.Background(), timeout)
this.ctx = ctx
this.cancelFunc = cancelFunc
return this
}
func (this *Cmd) WithStdout() *Cmd {
this.captureStdout = true
return this
}
func (this *Cmd) WithStderr() *Cmd {
this.captureStderr = true
return this
}
func (this *Cmd) WithEnv(env []string) *Cmd {
this.env = env
return this
}
func (this *Cmd) WithDir(dir string) *Cmd {
this.dir = dir
return this
}
func (this *Cmd) Start() error {
var cmd = this.compose()
return cmd.Start()
}
func (this *Cmd) Wait() error {
var cmd = this.compose()
return cmd.Wait()
}
func (this *Cmd) Run() error {
if this.cancelFunc != nil {
defer this.cancelFunc()
}
var cmd = this.compose()
return cmd.Run()
}
func (this *Cmd) RawStdout() string {
if this.stdout != nil {
return this.stdout.String()
}
return ""
}
func (this *Cmd) Stdout() string {
return strings.TrimSpace(this.RawStdout())
}
func (this *Cmd) RawStderr() string {
if this.stderr != nil {
return this.stderr.String()
}
return ""
}
func (this *Cmd) Stderr() string {
return strings.TrimSpace(this.RawStderr())
}
func (this *Cmd) String() string {
if this.rawCmd != nil {
return this.rawCmd.String()
}
var newCmd = exec.Command(this.name, this.args...)
return newCmd.String()
}
func (this *Cmd) Process() *os.Process {
if this.rawCmd != nil {
return this.rawCmd.Process
}
return nil
}
func (this *Cmd) compose() *exec.Cmd {
if this.rawCmd != nil {
return this.rawCmd
}
if this.ctx != nil {
this.rawCmd = exec.CommandContext(this.ctx, this.name, this.args...)
} else {
this.rawCmd = exec.Command(this.name, this.args...)
}
if this.env != nil {
this.rawCmd.Env = this.env
}
if len(this.dir) > 0 {
this.rawCmd.Dir = this.dir
}
if this.captureStdout {
this.stdout = &bytes.Buffer{}
this.rawCmd.Stdout = this.stdout
}
if this.captureStderr {
this.stderr = &bytes.Buffer{}
this.rawCmd.Stderr = this.stderr
}
return this.rawCmd
}

View File

@@ -0,0 +1,61 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package executils_test
import (
executils "github.com/TeaOSLab/EdgeAdmin/internal/utils/exec"
"testing"
"time"
)
func TestNewTimeoutCmd_Sleep(t *testing.T) {
var cmd = executils.NewTimeoutCmd(1*time.Second, "sleep", "3")
cmd.WithStdout()
cmd.WithStderr()
err := cmd.Run()
t.Log("error:", err)
t.Log("stdout:", cmd.Stdout())
t.Log("stderr:", cmd.Stderr())
}
func TestNewTimeoutCmd_Echo(t *testing.T) {
var cmd = executils.NewTimeoutCmd(10*time.Second, "echo", "-n", "hello")
cmd.WithStdout()
cmd.WithStderr()
err := cmd.Run()
t.Log("error:", err)
t.Log("stdout:", cmd.Stdout())
t.Log("stderr:", cmd.Stderr())
}
func TestNewTimeoutCmd_Echo2(t *testing.T) {
var cmd = executils.NewCmd("echo", "hello")
cmd.WithStdout()
cmd.WithStderr()
err := cmd.Run()
t.Log("error:", err)
t.Log("stdout:", cmd.Stdout())
t.Log("raw stdout:", cmd.RawStdout())
t.Log("stderr:", cmd.Stderr())
t.Log("raw stderr:", cmd.RawStderr())
}
func TestNewTimeoutCmd_Echo3(t *testing.T) {
var cmd = executils.NewCmd("echo", "-n", "hello")
err := cmd.Run()
t.Log("error:", err)
t.Log("stdout:", cmd.Stdout())
t.Log("stderr:", cmd.Stderr())
}
func TestCmd_Process(t *testing.T) {
var cmd = executils.NewCmd("echo", "-n", "hello")
err := cmd.Run()
t.Log("error:", err)
t.Log(cmd.Process())
}
func TestNewTimeoutCmd_String(t *testing.T) {
var cmd = executils.NewCmd("echo", "-n", "hello")
t.Log("stdout:", cmd.String())
}

View File

@@ -0,0 +1,58 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build linux
package executils
import (
"golang.org/x/sys/unix"
"io/fs"
"os"
"os/exec"
"syscall"
)
// LookPath customize our LookPath() function, to work in broken $PATH environment variable
func LookPath(file string) (string, error) {
result, err := exec.LookPath(file)
if err == nil && len(result) > 0 {
return result, nil
}
// add common dirs contains executable files these may be excluded in $PATH environment variable
var binPaths = []string{
"/usr/sbin",
"/usr/bin",
"/usr/local/sbin",
"/usr/local/bin",
}
for _, binPath := range binPaths {
var fullPath = binPath + string(os.PathSeparator) + file
stat, err := os.Stat(fullPath)
if err != nil {
continue
}
if stat.IsDir() {
return "", syscall.EISDIR
}
var mode = stat.Mode()
if mode.IsDir() {
return "", syscall.EISDIR
}
err = syscall.Faccessat(unix.AT_FDCWD, fullPath, unix.X_OK, unix.AT_EACCESS)
if err == nil || (err != syscall.ENOSYS && err != syscall.EPERM) {
return fullPath, err
}
if mode&0111 != 0 {
return fullPath, nil
}
return "", fs.ErrPermission
}
return "", &exec.Error{
Name: file,
Err: exec.ErrNotFound,
}
}

View File

@@ -0,0 +1,10 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !linux
package executils
import "os/exec"
func LookPath(file string) (string, error) {
return exec.LookPath(file)
}

View File

@@ -3,6 +3,7 @@
package utils
import (
executils "github.com/TeaOSLab/EdgeAdmin/internal/utils/exec"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/types"
"os/exec"
@@ -14,7 +15,7 @@ func AddPortsToFirewall(ports []int) {
// Linux
if runtime.GOOS == "linux" {
// firewalld
firewallCmd, _ := exec.LookPath("firewall-cmd")
firewallCmd, _ := executils.LookPath("firewall-cmd")
if len(firewallCmd) > 0 {
err := exec.Command(firewallCmd, "--add-port="+types.String(port)+"/tcp").Run()
if err == nil {

View File

@@ -3,8 +3,10 @@ package utils
import (
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/logs"
"github.com/miekg/dns"
"sync"
)
var sharedDNSClient *dns.Client
@@ -33,17 +35,47 @@ func LookupCNAME(host string) (string, error) {
m.RecursionDesired = true
var lastErr error
for _, serverAddr := range sharedDNSConfig.Servers {
r, _, err := sharedDNSClient.Exchange(m, configutils.QuoteIP(serverAddr)+":"+sharedDNSConfig.Port)
if err != nil {
lastErr = err
continue
}
if len(r.Answer) == 0 {
continue
}
var success = false
var result = ""
return r.Answer[0].(*dns.CNAME).Target, nil
var serverAddrs = sharedDNSConfig.Servers
{
var publicDNSHosts = []string{"8.8.8.8" /** Google **/, "8.8.4.4" /** Google **/}
for _, publicDNSHost := range publicDNSHosts {
if !lists.ContainsString(serverAddrs, publicDNSHost) {
serverAddrs = append(serverAddrs, publicDNSHost)
}
}
}
var wg = &sync.WaitGroup{}
for _, serverAddr := range serverAddrs {
wg.Add(1)
go func(serverAddr string) {
defer wg.Done()
r, _, err := sharedDNSClient.Exchange(m, configutils.QuoteIP(serverAddr)+":"+sharedDNSConfig.Port)
if err != nil {
lastErr = err
return
}
success = true
if len(r.Answer) == 0 {
return
}
result = r.Answer[0].(*dns.CNAME).Target
}(serverAddr)
}
wg.Wait()
if success {
return result, nil
}
return "", lastErr
}

View File

@@ -8,5 +8,8 @@ import (
)
func TestLookupCNAME(t *testing.T) {
t.Log(utils.LookupCNAME("www.yun4s.cn"))
for _, domain := range []string{"www.yun4s.cn", "example.com"} {
result, err := utils.LookupCNAME(domain)
t.Log(domain, "=>", result, err)
}
}

View File

@@ -30,17 +30,17 @@ func FormatBytes(bytes int64) string {
if bytes < Pow1024(1) {
return FormatInt64(bytes) + "B"
} else if bytes < Pow1024(2) {
return TrimZeroSuffix(fmt.Sprintf("%.2fKB", float64(bytes)/float64(Pow1024(1))))
return TrimZeroSuffix(fmt.Sprintf("%.2fKiB", float64(bytes)/float64(Pow1024(1))))
} else if bytes < Pow1024(3) {
return TrimZeroSuffix(fmt.Sprintf("%.2fMB", float64(bytes)/float64(Pow1024(2))))
return TrimZeroSuffix(fmt.Sprintf("%.2fMiB", float64(bytes)/float64(Pow1024(2))))
} else if bytes < Pow1024(4) {
return TrimZeroSuffix(fmt.Sprintf("%.2fGB", float64(bytes)/float64(Pow1024(3))))
return TrimZeroSuffix(fmt.Sprintf("%.2fGiB", float64(bytes)/float64(Pow1024(3))))
} else if bytes < Pow1024(5) {
return TrimZeroSuffix(fmt.Sprintf("%.2fTB", float64(bytes)/float64(Pow1024(4))))
return TrimZeroSuffix(fmt.Sprintf("%.2fTiB", float64(bytes)/float64(Pow1024(4))))
} else if bytes < Pow1024(6) {
return TrimZeroSuffix(fmt.Sprintf("%.2fPB", float64(bytes)/float64(Pow1024(5))))
return TrimZeroSuffix(fmt.Sprintf("%.2fPiB", float64(bytes)/float64(Pow1024(5))))
} else {
return TrimZeroSuffix(fmt.Sprintf("%.2fEB", float64(bytes)/float64(Pow1024(6))))
return TrimZeroSuffix(fmt.Sprintf("%.2fEiB", float64(bytes)/float64(Pow1024(6))))
}
}

View File

@@ -5,6 +5,7 @@ package utils
import (
"errors"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
executils "github.com/TeaOSLab/EdgeAdmin/internal/utils/exec"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/files"
"os"
@@ -21,7 +22,7 @@ func (this *ServiceManager) Install(exePath string, args []string) error {
return errors.New("only root users can install the service")
}
systemd, err := exec.LookPath("systemctl")
systemd, err := executils.LookPath("systemctl")
if err != nil {
return this.installInitService(exePath, args)
}
@@ -36,7 +37,7 @@ func (this *ServiceManager) Start() error {
}
if files.NewFile(systemdServiceFile).Exists() {
systemd, err := exec.LookPath("systemctl")
systemd, err := executils.LookPath("systemctl")
if err != nil {
return err
}
@@ -53,7 +54,7 @@ func (this *ServiceManager) Uninstall() error {
}
if files.NewFile(systemdServiceFile).Exists() {
systemd, err := exec.LookPath("systemctl")
systemd, err := executils.LookPath("systemctl")
if err != nil {
return err
}
@@ -93,7 +94,7 @@ func (this *ServiceManager) installInitService(exePath string, args []string) er
return err
}
chkCmd, err := exec.LookPath("chkconfig")
chkCmd, err := executils.LookPath("chkconfig")
if err != nil {
return err
}

95
internal/utils/unzip.go Normal file
View File

@@ -0,0 +1,95 @@
package utils
import (
"archive/zip"
"errors"
"io"
"os"
)
type Unzip struct {
zipFile string
targetDir string
}
func NewUnzip(zipFile string, targetDir string) *Unzip {
return &Unzip{
zipFile: zipFile,
targetDir: targetDir,
}
}
func (this *Unzip) Run() error {
if len(this.zipFile) == 0 {
return errors.New("zip file should not be empty")
}
if len(this.targetDir) == 0 {
return errors.New("target dir should not be empty")
}
reader, err := zip.OpenReader(this.zipFile)
if err != nil {
return err
}
defer func() {
_ = reader.Close()
}()
for _, file := range reader.File {
var info = file.FileInfo()
var target = this.targetDir + "/" + file.Name
// 目录
if info.IsDir() {
stat, err := os.Stat(target)
if err != nil {
if !os.IsNotExist(err) {
return err
} else {
err = os.MkdirAll(target, info.Mode())
if err != nil {
return err
}
}
} else if !stat.IsDir() {
err = os.MkdirAll(target, info.Mode())
if err != nil {
return err
}
}
continue
}
// 文件
err = func(file *zip.File, target string) error {
fileReader, err := file.Open()
if err != nil {
return err
}
defer func() {
_ = fileReader.Close()
}()
// remove old
_ = os.Remove(target)
// create new
fileWriter, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, file.FileInfo().Mode())
if err != nil {
return err
}
defer func() {
_ = fileWriter.Close()
}()
_, err = io.Copy(fileWriter, fileReader)
return err
}(file, target)
if err != nil {
return err
}
}
return nil
}

View File

@@ -9,6 +9,7 @@ import (
"errors"
"fmt"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
executils "github.com/TeaOSLab/EdgeAdmin/internal/utils/exec"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
@@ -87,14 +88,10 @@ func (this *UpgradeManager) Start() error {
}()
// 检查unzip
unzipExe, _ := exec.LookPath("unzip")
if len(unzipExe) == 0 {
// TODO install unzip automatically or pack with a static 'unzip' file
return errors.New("can not find 'unzip' command")
}
unzipExe, _ := executils.LookPath("unzip")
// 检查cp
cpExe, _ := exec.LookPath("cp")
cpExe, _ := executils.LookPath("cp")
if len(cpExe) == 0 {
return errors.New("can not find 'cp' command")
}
@@ -232,12 +229,24 @@ func (this *UpgradeManager) Start() error {
return fmt.Errorf("remove old dir '%s' failed: %w", unzipDir, err)
}
}
var unzipCmd = exec.Command(unzipExe, "-q", "-o", destFile, "-d", unzipDir)
var unzipStderr = &bytes.Buffer{}
unzipCmd.Stderr = unzipStderr
err = unzipCmd.Run()
if err != nil {
return fmt.Errorf("unzip installation file failed: %w: %s", err, unzipStderr.String())
if len(unzipExe) > 0 {
var unzipCmd = exec.Command(unzipExe, "-q", "-o", destFile, "-d", unzipDir)
var unzipStderr = &bytes.Buffer{}
unzipCmd.Stderr = unzipStderr
err = unzipCmd.Run()
if err != nil {
return fmt.Errorf("unzip installation file failed: %w: %s", err, unzipStderr.String())
}
} else {
var unzipCmd = &Unzip{
zipFile: destFile,
targetDir: unzipDir,
}
err = unzipCmd.Run()
if err != nil {
return fmt.Errorf("unzip installation file failed: %w", err)
}
}
installationFiles, err := filepath.Glob(unzipDir + "/edge-" + this.component + "/*")

View File

@@ -9,6 +9,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/index/loginutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
@@ -106,7 +107,7 @@ func (this *ParentAction) CreateLog(level string, messageCode langs.MessageCode,
}
}
}
err := dao.SharedLogDAO.CreateAdminLog(this.AdminContext(), level, this.Request.URL.Path, desc, this.RequestRemoteIP(), messageCode, args)
err := dao.SharedLogDAO.CreateAdminLog(this.AdminContext(), level, this.Request.URL.Path, desc, loginutils.RemoteIP(&this.ActionObject), messageCode, args)
if err != nil {
utils.PrintError(err)
}

View File

@@ -1,82 +0,0 @@
package recipients
import (
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"regexp"
)
type CreatePopupAction struct {
actionutils.ParentAction
}
func (this *CreatePopupAction) Init() {
this.Nav("", "", "")
}
func (this *CreatePopupAction) RunGet(params struct{}) {
this.Show()
}
func (this *CreatePopupAction) RunPost(params struct {
AdminId int64
InstanceId int64
User string
TelegramToken string
GroupIds string
Description string
TimeFromHour string
TimeFromMinute string
TimeFromSecond string
TimeToHour string
TimeToMinute string
TimeToSecond string
Must *actions.Must
CSRF *actionutils.CSRF
}) {
params.Must.
Field("adminId", params.AdminId).
Gt(0, "请选择系统用户").
Field("instanceId", params.InstanceId).
Gt(0, "请选择媒介")
groupIds := utils.SplitNumbers(params.GroupIds)
var digitReg = regexp.MustCompile(`^\d+$`)
var timeFrom = ""
if digitReg.MatchString(params.TimeFromHour) && digitReg.MatchString(params.TimeFromMinute) && digitReg.MatchString(params.TimeFromSecond) {
timeFrom = params.TimeFromHour + ":" + params.TimeFromMinute + ":" + params.TimeFromSecond
}
var timeTo = ""
if digitReg.MatchString(params.TimeToHour) && digitReg.MatchString(params.TimeToMinute) && digitReg.MatchString(params.TimeToSecond) {
timeTo = params.TimeToHour + ":" + params.TimeToMinute + ":" + params.TimeToSecond
}
resp, err := this.RPC().MessageRecipientRPC().CreateMessageRecipient(this.AdminContext(), &pb.CreateMessageRecipientRequest{
AdminId: params.AdminId,
MessageMediaInstanceId: params.InstanceId,
User: params.User,
MessageRecipientGroupIds: groupIds,
Description: params.Description,
TimeFrom: timeFrom,
TimeTo: timeTo,
})
if err != nil {
this.ErrorPage(err)
return
}
defer this.CreateLogInfo(codes.MessageRecipient_LogCreateMessageRecipient, resp.MessageRecipientId)
this.Success()
}

View File

@@ -1,25 +0,0 @@
package recipients
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type DeleteAction struct {
actionutils.ParentAction
}
func (this *DeleteAction) RunPost(params struct {
RecipientId int64
}) {
defer this.CreateLogInfo(codes.MessageRecipient_LogDeleteMessageRecipient, params.RecipientId)
_, err := this.RPC().MessageRecipientRPC().DeleteMessageRecipient(this.AdminContext(), &pb.DeleteMessageRecipientRequest{MessageRecipientId: params.RecipientId})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -1,38 +0,0 @@
package groups
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
)
type CreatePopupAction struct {
actionutils.ParentAction
}
func (this *CreatePopupAction) Init() {
this.Nav("", "", "")
}
func (this *CreatePopupAction) RunGet(params struct{}) {
this.Show()
}
func (this *CreatePopupAction) RunPost(params struct {
Name string
Must *actions.Must
CSRF *actionutils.CSRF
}) {
params.Must.
Field("name", params.Name).
Require("请输入分组名称")
_, err := this.RPC().MessageRecipientGroupRPC().CreateMessageRecipientGroup(this.AdminContext(), &pb.CreateMessageRecipientGroupRequest{Name: params.Name})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -1,22 +0,0 @@
package groups
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type DeleteAction struct {
actionutils.ParentAction
}
func (this *DeleteAction) RunPost(params struct {
GroupId int64
}) {
_, err := this.RPC().MessageRecipientGroupRPC().DeleteMessageRecipientGroup(this.AdminContext(), &pb.DeleteMessageRecipientGroupRequest{MessageRecipientGroupId: params.GroupId})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -1,34 +0,0 @@
package groups
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "group")
}
func (this *IndexAction) RunGet(params struct{}) {
groupsResp, err := this.RPC().MessageRecipientGroupRPC().FindAllEnabledMessageRecipientGroups(this.AdminContext(), &pb.FindAllEnabledMessageRecipientGroupsRequest{})
if err != nil {
this.ErrorPage(err)
return
}
groupMaps := []maps.Map{}
for _, group := range groupsResp.MessageRecipientGroups {
groupMaps = append(groupMaps, maps.Map{
"id": group.Id,
"name": group.Name,
"isOn": group.IsOn,
})
}
this.Data["groups"] = groupMaps
this.Show()
}

View File

@@ -1,23 +0,0 @@
package groups
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeAdmin)).
Data("teaMenu", "admins").
Data("teaSubMenu", "recipients").
Prefix("/admins/recipients/groups").
Get("", new(IndexAction)).
GetPost("/createPopup", new(CreatePopupAction)).
GetPost("/updatePopup", new(UpdatePopupAction)).
Post("/delete", new(DeleteAction)).
Get("/selectPopup", new(SelectPopupAction)).
EndAll()
})
}

View File

@@ -1,39 +0,0 @@
package groups
import (
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
)
type SelectPopupAction struct {
actionutils.ParentAction
}
func (this *SelectPopupAction) RunGet(params struct {
GroupIds string
}) {
selectedGroupIds := utils.SplitNumbers(params.GroupIds)
groupsResp, err := this.RPC().MessageRecipientGroupRPC().FindAllEnabledMessageRecipientGroups(this.AdminContext(), &pb.FindAllEnabledMessageRecipientGroupsRequest{})
if err != nil {
this.ErrorPage(err)
return
}
groupMaps := []maps.Map{}
for _, group := range groupsResp.MessageRecipientGroups {
if lists.ContainsInt64(selectedGroupIds, group.Id) {
continue
}
groupMaps = append(groupMaps, maps.Map{
"id": group.Id,
"name": group.Name,
"isOn": group.IsOn,
})
}
this.Data["groups"] = groupMaps
this.Show()
}

View File

@@ -1,64 +0,0 @@
package groups
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
)
type UpdatePopupAction struct {
actionutils.ParentAction
}
func (this *UpdatePopupAction) Init() {
this.Nav("", "", "")
}
func (this *UpdatePopupAction) RunGet(params struct {
GroupId int64
}) {
groupResp, err := this.RPC().MessageRecipientGroupRPC().FindEnabledMessageRecipientGroup(this.AdminContext(), &pb.FindEnabledMessageRecipientGroupRequest{MessageRecipientGroupId: params.GroupId})
if err != nil {
this.ErrorPage(err)
return
}
group := groupResp.MessageRecipientGroup
if group == nil {
this.NotFound("messageRecipientGroup", params.GroupId)
return
}
this.Data["group"] = maps.Map{
"id": group.Id,
"name": group.Name,
"isOn": group.IsOn,
}
this.Show()
}
func (this *UpdatePopupAction) RunPost(params struct {
GroupId int64
Name string
IsOn bool
Must *actions.Must
CSRF *actionutils.CSRF
}) {
params.Must.
Field("name", params.Name).
Require("请输入分组名称")
_, err := this.RPC().MessageRecipientGroupRPC().UpdateMessageRecipientGroup(this.AdminContext(), &pb.UpdateMessageRecipientGroupRequest{
MessageRecipientGroupId: params.GroupId,
Name: params.Name,
IsOn: params.IsOn,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -1,74 +0,0 @@
package recipients
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "recipient")
}
func (this *IndexAction) RunGet(params struct {
}) {
// TODO 增加系统用户、媒介类型等条件搜索
countResp, err := this.RPC().MessageRecipientRPC().CountAllEnabledMessageRecipients(this.AdminContext(), &pb.CountAllEnabledMessageRecipientsRequest{
AdminId: 0,
MediaType: "",
MessageRecipientGroupId: 0,
Keyword: "",
})
if err != nil {
this.ErrorPage(err)
return
}
count := countResp.Count
page := this.NewPage(count)
this.Data["page"] = page.AsHTML()
recipientsResp, err := this.RPC().MessageRecipientRPC().ListEnabledMessageRecipients(this.AdminContext(), &pb.ListEnabledMessageRecipientsRequest{
AdminId: 0,
MediaType: "",
MessageRecipientGroupId: 0,
Keyword: "",
Offset: page.Offset,
Size: page.Size,
})
if err != nil {
this.ErrorPage(err)
return
}
recipientMaps := []maps.Map{}
for _, recipient := range recipientsResp.MessageRecipients {
if recipient.Admin == nil {
continue
}
if recipient.MessageMediaInstance == nil {
continue
}
recipientMaps = append(recipientMaps, maps.Map{
"id": recipient.Id,
"admin": maps.Map{
"id": recipient.Admin.Id,
"fullname": recipient.Admin.Fullname,
"username": recipient.Admin.Username,
},
"groups": recipient.MessageRecipientGroups,
"isOn": recipient.IsOn,
"instance": maps.Map{
"name": recipient.MessageMediaInstance.Name,
},
"user": recipient.User,
"description": recipient.Description,
})
}
this.Data["recipients"] = recipientMaps
this.Show()
}

View File

@@ -1,25 +0,0 @@
package recipients
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeAdmin)).
Data("teaMenu", "admins").
Data("teaSubMenu", "recipients").
Prefix("/admins/recipients").
Get("", new(IndexAction)).
GetPost("/createPopup", new(CreatePopupAction)).
GetPost("/update", new(UpdateAction)).
Post("/delete", new(DeleteAction)).
Post("/mediaOptions", new(MediaOptionsAction)).
Get("/recipient", new(RecipientAction)).
GetPost("/test", new(TestAction)).
EndAll()
})
}

View File

@@ -1,267 +0,0 @@
package instances
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/monitorconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
)
type CreatePopupAction struct {
actionutils.ParentAction
}
func (this *CreatePopupAction) Init() {
this.Nav("", "", "")
}
func (this *CreatePopupAction) RunGet(params struct{}) {
this.Show()
}
func (this *CreatePopupAction) RunPost(params struct {
Name string
MediaType string
EmailSmtp string
EmailUsername string
EmailPassword string
EmailFrom string
WebHookURL string
WebHookMethod string
WebHookHeaderNames []string
WebHookHeaderValues []string
WebHookContentType string
WebHookParamNames []string
WebHookParamValues []string
WebHookBody string
ScriptType string
ScriptPath string
ScriptLang string
ScriptCode string
ScriptCwd string
ScriptEnvNames []string
ScriptEnvValues []string
DingTalkWebHookURL string
QyWeixinCorporateId string
QyWeixinAgentId string
QyWeixinAppSecret string
QyWeixinTextFormat string
QyWeixinRobotWebHookURL string
QyWeixinRobotTextFormat string
AliyunSmsSign string
AliyunSmsTemplateCode string
AliyunSmsTemplateVarNames []string
AliyunSmsTemplateVarValues []string
AliyunSmsAccessKeyId string
AliyunSmsAccessKeySecret string
TelegramToken string
RateMinutes int32
RateCount int32
HashLife int32
Description string
Must *actions.Must
CSRF *actionutils.CSRF
}) {
params.Must.
Field("name", params.Name).
Require("请输入媒介名称").
Field("mediaType", params.MediaType).
Require("请选择媒介类型")
options := maps.Map{}
switch params.MediaType {
case "email":
params.Must.
Field("emailSmtp", params.EmailSmtp).
Require("请输入SMTP地址").
Field("emailUsername", params.EmailUsername).
Require("请输入邮箱账号").
Field("emailPassword", params.EmailPassword).
Require("请输入密码或授权码")
options["smtp"] = params.EmailSmtp
options["username"] = params.EmailUsername
options["password"] = params.EmailPassword
options["from"] = params.EmailFrom
case "webHook":
params.Must.
Field("webHookURL", params.WebHookURL).
Require("请输入URL地址").
Match("(?i)^(http|https)://", "URL地址必须以http或https开头").
Field("webHookMethod", params.WebHookMethod).
Require("请选择请求方法")
options["url"] = params.WebHookURL
options["method"] = params.WebHookMethod
options["contentType"] = params.WebHookContentType
headers := []maps.Map{}
if len(params.WebHookHeaderNames) > 0 {
for index, name := range params.WebHookHeaderNames {
if index < len(params.WebHookHeaderValues) {
headers = append(headers, maps.Map{
"name": name,
"value": params.WebHookHeaderValues[index],
})
}
}
}
options["headers"] = headers
if params.WebHookContentType == "params" {
webHookParams := []maps.Map{}
for index, name := range params.WebHookParamNames {
if index < len(params.WebHookParamValues) {
webHookParams = append(webHookParams, maps.Map{
"name": name,
"value": params.WebHookParamValues[index],
})
}
}
options["params"] = webHookParams
} else if params.WebHookContentType == "body" {
options["body"] = params.WebHookBody
}
case "script":
if params.ScriptType == "path" {
params.Must.
Field("scriptPath", params.ScriptPath).
Require("请输入脚本路径")
} else if params.ScriptType == "code" {
params.Must.
Field("scriptCode", params.ScriptCode).
Require("请输入脚本代码")
} else {
params.Must.
Field("scriptPath", params.ScriptPath).
Require("请输入脚本路径")
}
options["scriptType"] = params.ScriptType
options["path"] = params.ScriptPath
options["scriptLang"] = params.ScriptLang
options["script"] = params.ScriptCode
options["cwd"] = params.ScriptCwd
env := []maps.Map{}
for index, envName := range params.ScriptEnvNames {
if index < len(params.ScriptEnvValues) {
env = append(env, maps.Map{
"name": envName,
"value": params.ScriptEnvValues[index],
})
}
}
options["env"] = env
case "dingTalk":
params.Must.
Field("dingTalkWebHookURL", params.DingTalkWebHookURL).
Require("请输入Hook地址").
Match("^https:", "Hook地址必须以https://开头")
options["webHookURL"] = params.DingTalkWebHookURL
case "qyWeixin":
params.Must.
Field("qyWeixinCorporateId", params.QyWeixinCorporateId).
Require("请输入企业ID").
Field("qyWeixinAgentId", params.QyWeixinAgentId).
Require("请输入应用AgentId").
Field("qyWeixinSecret", params.QyWeixinAppSecret).
Require("请输入应用Secret")
options["corporateId"] = params.QyWeixinCorporateId
options["agentId"] = params.QyWeixinAgentId
options["appSecret"] = params.QyWeixinAppSecret
options["textFormat"] = params.QyWeixinTextFormat
case "qyWeixinRobot":
params.Must.
Field("qyWeixinRobotWebHookURL", params.QyWeixinRobotWebHookURL).
Require("请输入WebHook地址").
Match("^https:", "WebHook地址必须以https://开头")
options["webHookURL"] = params.QyWeixinRobotWebHookURL
options["textFormat"] = params.QyWeixinRobotTextFormat
case "aliyunSms":
params.Must.
Field("aliyunSmsSign", params.AliyunSmsSign).
Require("请输入签名名称").
Field("aliyunSmsTemplateCode", params.AliyunSmsTemplateCode).
Require("请输入模板CODE").
Field("aliyunSmsAccessKeyId", params.AliyunSmsAccessKeyId).
Require("请输入AccessKey ID").
Field("aliyunSmsAccessKeySecret", params.AliyunSmsAccessKeySecret).
Require("请输入AccessKey Secret")
options["sign"] = params.AliyunSmsSign
options["templateCode"] = params.AliyunSmsTemplateCode
options["accessKeyId"] = params.AliyunSmsAccessKeyId
options["accessKeySecret"] = params.AliyunSmsAccessKeySecret
variables := []maps.Map{}
for index, name := range params.AliyunSmsTemplateVarNames {
if index < len(params.AliyunSmsTemplateVarValues) {
variables = append(variables, maps.Map{
"name": name,
"value": params.AliyunSmsTemplateVarValues[index],
})
}
}
options["variables"] = variables
case "telegram":
params.Must.
Field("telegramToken", params.TelegramToken).
Require("请输入机器人Token")
options["token"] = params.TelegramToken
default:
this.Fail("错误的媒介类型")
}
optionsJSON, err := json.Marshal(options)
if err != nil {
this.ErrorPage(err)
return
}
var rateConfig = &monitorconfigs.RateConfig{
Minutes: params.RateMinutes,
Count: params.RateCount,
}
rateJSON, err := json.Marshal(rateConfig)
if err != nil {
this.ErrorPage(err)
return
}
resp, err := this.RPC().MessageMediaInstanceRPC().CreateMessageMediaInstance(this.AdminContext(), &pb.CreateMessageMediaInstanceRequest{
Name: params.Name,
MediaType: params.MediaType,
ParamsJSON: optionsJSON,
Description: params.Description,
RateJSON: rateJSON,
HashLife: params.HashLife,
})
if err != nil {
this.ErrorPage(err)
return
}
defer this.CreateLogInfo(codes.MessageMediaInstance_LogCreateMessageMediaInstance, resp.MessageMediaInstanceId)
this.Success()
}

View File

@@ -1,25 +0,0 @@
package instances
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type DeleteAction struct {
actionutils.ParentAction
}
func (this *DeleteAction) RunPost(params struct {
InstanceId int64
}) {
defer this.CreateLogInfo(codes.MessageMediaInstance_LogDeleteMessageMediaInstance, params.InstanceId)
_, err := this.RPC().MessageMediaInstanceRPC().DeleteMessageMediaInstance(this.AdminContext(), &pb.DeleteMessageMediaInstanceRequest{MessageMediaInstanceId: params.InstanceId})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -1,61 +0,0 @@
package instances
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "instance")
}
func (this *IndexAction) RunGet(params struct {
}) {
// TODO 增加系统用户、媒介类型等条件搜索
countResp, err := this.RPC().MessageMediaInstanceRPC().CountAllEnabledMessageMediaInstances(this.AdminContext(), &pb.CountAllEnabledMessageMediaInstancesRequest{
MediaType: "",
Keyword: "",
})
if err != nil {
this.ErrorPage(err)
return
}
count := countResp.Count
page := this.NewPage(count)
this.Data["page"] = page.AsHTML()
instancesResp, err := this.RPC().MessageMediaInstanceRPC().ListEnabledMessageMediaInstances(this.AdminContext(), &pb.ListEnabledMessageMediaInstancesRequest{
MediaType: "",
Keyword: "",
Offset: page.Offset,
Size: page.Size,
})
if err != nil {
this.ErrorPage(err)
return
}
instanceMaps := []maps.Map{}
for _, instance := range instancesResp.MessageMediaInstances {
if instance.MessageMedia == nil {
continue
}
instanceMaps = append(instanceMaps, maps.Map{
"id": instance.Id,
"name": instance.Name,
"isOn": instance.IsOn,
"media": maps.Map{
"name": instance.MessageMedia.Name,
},
"description": instance.Description,
})
}
this.Data["instances"] = instanceMaps
this.Show()
}

View File

@@ -1,25 +0,0 @@
package instances
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeAdmin)).
Data("teaMenu", "admins").
Data("teaSubMenu", "instances").
Prefix("/admins/recipients/instances").
Get("", new(IndexAction)).
GetPost("/createPopup", new(CreatePopupAction)).
GetPost("/update", new(UpdateAction)).
Post("/delete", new(DeleteAction)).
Get("/instance", new(InstanceAction)).
GetPost("/test", new(TestAction)).
Post("/options", new(OptionsAction)).
EndAll()
})
}

View File

@@ -1,67 +0,0 @@
package instances
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/monitorconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type InstanceAction struct {
actionutils.ParentAction
}
func (this *InstanceAction) Init() {
this.Nav("", "", "instance")
}
func (this *InstanceAction) RunGet(params struct {
InstanceId int64
}) {
instanceResp, err := this.RPC().MessageMediaInstanceRPC().FindEnabledMessageMediaInstance(this.AdminContext(), &pb.FindEnabledMessageMediaInstanceRequest{MessageMediaInstanceId: params.InstanceId})
if err != nil {
this.ErrorPage(err)
return
}
instance := instanceResp.MessageMediaInstance
if instance == nil || instance.MessageMedia == nil {
this.NotFound("messageMediaInstance", params.InstanceId)
return
}
mediaParams := maps.Map{}
if len(instance.ParamsJSON) > 0 {
err = json.Unmarshal(instance.ParamsJSON, &mediaParams)
if err != nil {
this.ErrorPage(err)
return
}
}
// 频率
var rateConfig = &monitorconfigs.RateConfig{}
if len(instance.RateJSON) > 0 {
err = json.Unmarshal(instance.RateJSON, rateConfig)
if err != nil {
this.ErrorPage(err)
return
}
}
this.Data["instance"] = maps.Map{
"id": instance.Id,
"name": instance.Name,
"isOn": instance.IsOn,
"media": maps.Map{
"type": instance.MessageMedia.Type,
"name": instance.MessageMedia.Name,
},
"description": instance.Description,
"params": mediaParams,
"rate": rateConfig,
"hashLife": instance.HashLife,
}
this.Show()
}

View File

@@ -1,39 +0,0 @@
package instances
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
// 媒介类型选项
type OptionsAction struct {
actionutils.ParentAction
}
func (this *OptionsAction) RunPost(params struct{}) {
resp, err := this.RPC().MessageMediaInstanceRPC().ListEnabledMessageMediaInstances(this.AdminContext(), &pb.ListEnabledMessageMediaInstancesRequest{
Offset: 0,
Size: 1000,
})
if err != nil {
this.ErrorPage(err)
return
}
instanceMaps := []maps.Map{}
for _, instance := range resp.MessageMediaInstances {
instanceMaps = append(instanceMaps, maps.Map{
"id": instance.Id,
"name": instance.Name,
"description": instance.Description,
"media": maps.Map{
"type": instance.MessageMedia.Type,
"name": instance.MessageMedia.Name,
"userDescription": instance.MessageMedia.UserDescription,
},
})
}
this.Data["instances"] = instanceMaps
this.Success()
}

View File

@@ -1,88 +0,0 @@
package instances
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
)
type TestAction struct {
actionutils.ParentAction
}
func (this *TestAction) Init() {
this.Nav("", "", "test")
}
func (this *TestAction) RunGet(params struct {
InstanceId int64
}) {
instanceResp, err := this.RPC().MessageMediaInstanceRPC().FindEnabledMessageMediaInstance(this.AdminContext(), &pb.FindEnabledMessageMediaInstanceRequest{MessageMediaInstanceId: params.InstanceId})
if err != nil {
this.ErrorPage(err)
return
}
instance := instanceResp.MessageMediaInstance
if instance == nil || instance.MessageMedia == nil {
this.NotFound("messageMediaInstance", params.InstanceId)
return
}
mediaParams := maps.Map{}
if len(instance.ParamsJSON) > 0 {
err = json.Unmarshal(instance.ParamsJSON, &mediaParams)
if err != nil {
this.ErrorPage(err)
return
}
}
this.Data["instance"] = maps.Map{
"id": instance.Id,
"isOn": instance.IsOn,
"media": maps.Map{
"type": instance.MessageMedia.Type,
"name": instance.MessageMedia.Name,
"userDescription": instance.MessageMedia.UserDescription,
},
"description": instance.Description,
"params": mediaParams,
}
this.Show()
}
func (this *TestAction) RunPost(params struct {
InstanceId int64
Subject string
Body string
User string
Must *actions.Must
CSRF *actionutils.CSRF
}) {
params.Must.
Field("instanceId", params.InstanceId).
Gt(0, "请选择正确的媒介")
resp, err := this.RPC().MessageTaskRPC().CreateMessageTask(this.AdminContext(), &pb.CreateMessageTaskRequest{
RecipientId: 0,
InstanceId: params.InstanceId,
User: params.User,
Subject: params.Subject,
Body: params.Body,
IsPrimary: true,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["taskId"] = resp.MessageTaskId
defer this.CreateLogInfo(codes.MessageTask_LogCreateTestingMessageTask, resp.MessageTaskId)
this.Success()
}

View File

@@ -1,317 +0,0 @@
package instances
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/monitorconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
)
type UpdateAction struct {
actionutils.ParentAction
}
func (this *UpdateAction) Init() {
this.Nav("", "", "update")
}
func (this *UpdateAction) RunGet(params struct {
InstanceId int64
}) {
instanceResp, err := this.RPC().MessageMediaInstanceRPC().FindEnabledMessageMediaInstance(this.AdminContext(), &pb.FindEnabledMessageMediaInstanceRequest{MessageMediaInstanceId: params.InstanceId})
if err != nil {
this.ErrorPage(err)
return
}
instance := instanceResp.MessageMediaInstance
if instance == nil || instance.MessageMedia == nil {
this.NotFound("messageMediaInstance", params.InstanceId)
return
}
mediaParams := maps.Map{}
if len(instance.ParamsJSON) > 0 {
err = json.Unmarshal(instance.ParamsJSON, &mediaParams)
if err != nil {
this.ErrorPage(err)
return
}
}
var rateConfig = &monitorconfigs.RateConfig{}
if len(instance.RateJSON) > 0 {
err = json.Unmarshal(instance.RateJSON, rateConfig)
if err != nil {
this.ErrorPage(err)
return
}
}
this.Data["instance"] = maps.Map{
"id": instance.Id,
"name": instance.Name,
"isOn": instance.IsOn,
"media": maps.Map{
"type": instance.MessageMedia.Type,
"name": instance.MessageMedia.Name,
},
"description": instance.Description,
"params": mediaParams,
"rate": rateConfig,
"hashLife": instance.HashLife,
}
this.Show()
}
func (this *UpdateAction) RunPost(params struct {
InstanceId int64
Name string
MediaType string
EmailSmtp string
EmailUsername string
EmailPassword string
EmailFrom string
WebHookURL string
WebHookMethod string
WebHookHeaderNames []string
WebHookHeaderValues []string
WebHookContentType string
WebHookParamNames []string
WebHookParamValues []string
WebHookBody string
ScriptType string
ScriptPath string
ScriptLang string
ScriptCode string
ScriptCwd string
ScriptEnvNames []string
ScriptEnvValues []string
DingTalkWebHookURL string
QyWeixinCorporateId string
QyWeixinAgentId string
QyWeixinAppSecret string
QyWeixinTextFormat string
QyWeixinRobotWebHookURL string
QyWeixinRobotTextFormat string
AliyunSmsSign string
AliyunSmsTemplateCode string
AliyunSmsTemplateVarNames []string
AliyunSmsTemplateVarValues []string
AliyunSmsAccessKeyId string
AliyunSmsAccessKeySecret string
TelegramToken string
GroupIds string
Description string
IsOn bool
RateMinutes int32
RateCount int32
HashLife int32
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo(codes.MessageMediaInstance_LogUpdateMessageMediaInstance, params.InstanceId)
params.Must.
Field("name", params.Name).
Require("请输入媒介名称").
Field("mediaType", params.MediaType).
Require("请选择媒介类型")
options := maps.Map{}
switch params.MediaType {
case "email":
params.Must.
Field("emailSmtp", params.EmailSmtp).
Require("请输入SMTP地址").
Field("emailUsername", params.EmailUsername).
Require("请输入邮箱账号").
Field("emailPassword", params.EmailPassword).
Require("请输入密码或授权码")
options["smtp"] = params.EmailSmtp
options["username"] = params.EmailUsername
options["password"] = params.EmailPassword
options["from"] = params.EmailFrom
case "webHook":
params.Must.
Field("webHookURL", params.WebHookURL).
Require("请输入URL地址").
Match("(?i)^(http|https)://", "URL地址必须以http或https开头").
Field("webHookMethod", params.WebHookMethod).
Require("请选择请求方法")
options["url"] = params.WebHookURL
options["method"] = params.WebHookMethod
options["contentType"] = params.WebHookContentType
headers := []maps.Map{}
if len(params.WebHookHeaderNames) > 0 {
for index, name := range params.WebHookHeaderNames {
if index < len(params.WebHookHeaderValues) {
headers = append(headers, maps.Map{
"name": name,
"value": params.WebHookHeaderValues[index],
})
}
}
}
options["headers"] = headers
if params.WebHookContentType == "params" {
webHookParams := []maps.Map{}
for index, name := range params.WebHookParamNames {
if index < len(params.WebHookParamValues) {
webHookParams = append(webHookParams, maps.Map{
"name": name,
"value": params.WebHookParamValues[index],
})
}
}
options["params"] = webHookParams
} else if params.WebHookContentType == "body" {
options["body"] = params.WebHookBody
}
case "script":
if params.ScriptType == "path" {
params.Must.
Field("scriptPath", params.ScriptPath).
Require("请输入脚本路径")
} else if params.ScriptType == "code" {
params.Must.
Field("scriptCode", params.ScriptCode).
Require("请输入脚本代码")
} else {
params.Must.
Field("scriptPath", params.ScriptPath).
Require("请输入脚本路径")
}
options["scriptType"] = params.ScriptType
options["path"] = params.ScriptPath
options["scriptLang"] = params.ScriptLang
options["script"] = params.ScriptCode
options["cwd"] = params.ScriptCwd
env := []maps.Map{}
for index, envName := range params.ScriptEnvNames {
if index < len(params.ScriptEnvValues) {
env = append(env, maps.Map{
"name": envName,
"value": params.ScriptEnvValues[index],
})
}
}
options["env"] = env
case "dingTalk":
params.Must.
Field("dingTalkWebHookURL", params.DingTalkWebHookURL).
Require("请输入Hook地址").
Match("^https:", "Hook地址必须以https://开头")
options["webHookURL"] = params.DingTalkWebHookURL
case "qyWeixin":
params.Must.
Field("qyWeixinCorporateId", params.QyWeixinCorporateId).
Require("请输入企业ID").
Field("qyWeixinAgentId", params.QyWeixinAgentId).
Require("请输入应用AgentId").
Field("qyWeixinSecret", params.QyWeixinAppSecret).
Require("请输入应用Secret")
options["corporateId"] = params.QyWeixinCorporateId
options["agentId"] = params.QyWeixinAgentId
options["appSecret"] = params.QyWeixinAppSecret
options["textFormat"] = params.QyWeixinTextFormat
case "qyWeixinRobot":
params.Must.
Field("qyWeixinRobotWebHookURL", params.QyWeixinRobotWebHookURL).
Require("请输入WebHook地址").
Match("^https:", "WebHook地址必须以https://开头")
options["webHookURL"] = params.QyWeixinRobotWebHookURL
options["textFormat"] = params.QyWeixinRobotTextFormat
case "aliyunSms":
params.Must.
Field("aliyunSmsSign", params.AliyunSmsSign).
Require("请输入签名名称").
Field("aliyunSmsTemplateCode", params.AliyunSmsTemplateCode).
Require("请输入模板CODE").
Field("aliyunSmsAccessKeyId", params.AliyunSmsAccessKeyId).
Require("请输入AccessKey ID").
Field("aliyunSmsAccessKeySecret", params.AliyunSmsAccessKeySecret).
Require("请输入AccessKey Secret")
options["sign"] = params.AliyunSmsSign
options["templateCode"] = params.AliyunSmsTemplateCode
options["accessKeyId"] = params.AliyunSmsAccessKeyId
options["accessKeySecret"] = params.AliyunSmsAccessKeySecret
variables := []maps.Map{}
for index, name := range params.AliyunSmsTemplateVarNames {
if index < len(params.AliyunSmsTemplateVarValues) {
variables = append(variables, maps.Map{
"name": name,
"value": params.AliyunSmsTemplateVarValues[index],
})
}
}
options["variables"] = variables
case "telegram":
params.Must.
Field("telegramToken", params.TelegramToken).
Require("请输入机器人Token")
options["token"] = params.TelegramToken
default:
this.Fail("错误的媒介类型")
}
optionsJSON, err := json.Marshal(options)
if err != nil {
this.ErrorPage(err)
return
}
var rateConfig = &monitorconfigs.RateConfig{
Minutes: params.RateMinutes,
Count: params.RateCount,
}
rateJSON, err := json.Marshal(rateConfig)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().MessageMediaInstanceRPC().UpdateMessageMediaInstance(this.AdminContext(), &pb.UpdateMessageMediaInstanceRequest{
MessageMediaInstanceId: params.InstanceId,
Name: params.Name,
MediaType: params.MediaType,
ParamsJSON: optionsJSON,
Description: params.Description,
RateJSON: rateJSON,
HashLife: params.HashLife,
IsOn: params.IsOn,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -1,61 +0,0 @@
package logs
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "log")
}
func (this *IndexAction) RunGet(params struct{}) {
countResp, err := this.RPC().MessageTaskLogRPC().CountMessageTaskLogs(this.AdminContext(), &pb.CountMessageTaskLogsRequest{})
if err != nil {
this.ErrorPage(err)
return
}
page := this.NewPage(countResp.Count)
this.Data["page"] = page.AsHTML()
logsResp, err := this.RPC().MessageTaskLogRPC().ListMessageTaskLogs(this.AdminContext(), &pb.ListMessageTaskLogsRequest{
Offset: page.Offset,
Size: page.Size,
})
if err != nil {
this.ErrorPage(err)
return
}
logMaps := []maps.Map{}
for _, log := range logsResp.MessageTaskLogs {
if log.MessageTask.MessageRecipient != nil {
log.MessageTask.User = log.MessageTask.MessageRecipient.User
}
logMaps = append(logMaps, maps.Map{
"task": maps.Map{
"id": log.MessageTask.Id,
"user": log.MessageTask.User,
"subject": log.MessageTask.Subject,
"body": log.MessageTask.Body,
"instance": maps.Map{
"id": log.MessageTask.MessageMediaInstance.Id,
"name": log.MessageTask.MessageMediaInstance.Name,
},
},
"isOk": log.IsOk,
"error": log.Error,
"response": log.Response,
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", log.CreatedAt),
})
}
this.Data["logs"] = logMaps
this.Show()
}

View File

@@ -1,19 +0,0 @@
package logs
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeAdmin)).
Data("teaMenu", "admins").
Data("teaSubMenu", "recipients").
Prefix("/admins/recipients/logs").
Get("", new(IndexAction)).
EndAll()
})
}

View File

@@ -1,32 +0,0 @@
package recipients
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
// 媒介类型选项
type MediaOptionsAction struct {
actionutils.ParentAction
}
func (this *MediaOptionsAction) RunPost(params struct{}) {
resp, err := this.RPC().MessageMediaRPC().FindAllMessageMedias(this.AdminContext(), &pb.FindAllMessageMediasRequest{})
if err != nil {
this.ErrorPage(err)
return
}
mediaMaps := []maps.Map{}
for _, media := range resp.MessageMedias {
mediaMaps = append(mediaMaps, maps.Map{
"id": media.Id,
"type": media.Type,
"name": media.Name,
"description": media.Description,
})
}
this.Data["medias"] = mediaMaps
this.Success()
}

View File

@@ -1,52 +0,0 @@
package recipients
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type RecipientAction struct {
actionutils.ParentAction
}
func (this *RecipientAction) Init() {
this.Nav("", "", "recipient")
}
func (this *RecipientAction) RunGet(params struct {
RecipientId int64
}) {
recipientResp, err := this.RPC().MessageRecipientRPC().FindEnabledMessageRecipient(this.AdminContext(), &pb.FindEnabledMessageRecipientRequest{MessageRecipientId: params.RecipientId})
if err != nil {
this.ErrorPage(err)
return
}
recipient := recipientResp.MessageRecipient
if recipient == nil || recipient.Admin == nil || recipient.MessageMediaInstance == nil {
this.NotFound("messageRecipient", params.RecipientId)
return
}
this.Data["recipient"] = maps.Map{
"id": recipient.Id,
"admin": maps.Map{
"id": recipient.Admin.Id,
"fullname": recipient.Admin.Fullname,
"username": recipient.Admin.Username,
},
"groups": recipient.MessageRecipientGroups,
"isOn": recipient.IsOn,
"instance": maps.Map{
"id": recipient.MessageMediaInstance.Id,
"name": recipient.MessageMediaInstance.Name,
"description": recipient.MessageMediaInstance.Description,
},
"user": recipient.User,
"description": recipient.Description,
"timeFrom": recipient.TimeFrom,
"timeTo": recipient.TimeTo,
}
this.Show()
}

View File

@@ -1,27 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package tasks
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type DeleteAction struct {
actionutils.ParentAction
}
func (this *DeleteAction) RunPost(params struct {
TaskId int64
}) {
defer this.CreateLogInfo(codes.MessageTask_LogDeleteMessageTask, params.TaskId)
_, err := this.RPC().MessageTaskRPC().DeleteMessageTask(this.AdminContext(), &pb.DeleteMessageTaskRequest{MessageTaskId: params.TaskId})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -1,103 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package tasks
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "task")
}
func (this *IndexAction) RunGet(params struct {
Status int32
}) {
this.Data["status"] = params.Status
if params.Status > 3 {
params.Status = 0
}
countWaitingResp, err := this.RPC().MessageTaskRPC().CountMessageTasksWithStatus(this.AdminContext(), &pb.CountMessageTasksWithStatusRequest{Status: pb.CountMessageTasksWithStatusRequest_MessageTaskStatusNone})
if err != nil {
this.ErrorPage(err)
return
}
var countWaiting = countWaitingResp.Count
this.Data["countWaiting"] = countWaiting
countFailedResp, err := this.RPC().MessageTaskRPC().CountMessageTasksWithStatus(this.AdminContext(), &pb.CountMessageTasksWithStatusRequest{Status: pb.CountMessageTasksWithStatusRequest_MessageTaskStatusFailed})
if err != nil {
this.ErrorPage(err)
return
}
var countFailed = countFailedResp.Count
this.Data["countFailed"] = countFailed
// 列表
var total = int64(0)
switch params.Status {
case 0:
total = countWaiting
case 3:
total = countFailed
}
page := this.NewPage(total)
this.Data["page"] = page.AsHTML()
var taskMaps = []maps.Map{}
tasksResp, err := this.RPC().MessageTaskRPC().ListMessageTasksWithStatus(this.AdminContext(), &pb.ListMessageTasksWithStatusRequest{
Status: pb.ListMessageTasksWithStatusRequest_Status(params.Status),
Offset: page.Offset,
Size: page.Size,
})
if err != nil {
this.ErrorPage(err)
return
}
for _, task := range tasksResp.MessageTasks {
var resultMap = maps.Map{}
var result = task.Result
if result != nil {
resultMap = maps.Map{
"isOk": result.IsOk,
"error": result.Error,
"response": result.Response,
}
}
//var recipients = []string{}
var user = ""
var instanceMap maps.Map
if task.MessageRecipient != nil {
user = task.MessageRecipient.User
if task.MessageRecipient.MessageMediaInstance != nil {
instanceMap = maps.Map{
"id": task.MessageRecipient.MessageMediaInstance.Id,
"name": task.MessageRecipient.MessageMediaInstance.Name,
}
}
}
taskMaps = append(taskMaps, maps.Map{
"id": task.Id,
"subject": task.Subject,
"body": task.Body,
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", task.CreatedAt),
"result": resultMap,
"status": task.Status,
"user": user,
"instance": instanceMap,
})
}
this.Data["tasks"] = taskMaps
this.Show()
}

View File

@@ -1,21 +0,0 @@
package tasks
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeAdmin)).
Data("teaMenu", "admins").
Data("teaSubMenu", "recipients").
Prefix("/admins/recipients/tasks").
Get("", new(IndexAction)).
Post("/taskInfo", new(TaskInfoAction)).
Post("/delete", new(DeleteAction)).
EndAll()
})
}

View File

@@ -1,40 +0,0 @@
package tasks
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type TaskInfoAction struct {
actionutils.ParentAction
}
func (this *TaskInfoAction) Init() {
this.Nav("", "", "")
}
func (this *TaskInfoAction) RunPost(params struct {
TaskId int64
}) {
resp, err := this.RPC().MessageTaskRPC().FindEnabledMessageTask(this.AdminContext(), &pb.FindEnabledMessageTaskRequest{MessageTaskId: params.TaskId})
if err != nil {
this.ErrorPage(err)
return
}
if resp.MessageTask == nil {
this.NotFound("messageTask", params.TaskId)
return
}
result := resp.MessageTask.Result
this.Data["status"] = resp.MessageTask.Status
this.Data["result"] = maps.Map{
"isOk": result.IsOk,
"response": result.Response,
"error": result.Error,
}
this.Success()
}

View File

@@ -1,114 +0,0 @@
package recipients
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
)
type TestAction struct {
actionutils.ParentAction
}
func (this *TestAction) Init() {
this.Nav("", "", "test")
}
func (this *TestAction) RunGet(params struct {
RecipientId int64
}) {
recipientResp, err := this.RPC().MessageRecipientRPC().FindEnabledMessageRecipient(this.AdminContext(), &pb.FindEnabledMessageRecipientRequest{MessageRecipientId: params.RecipientId})
if err != nil {
this.ErrorPage(err)
return
}
recipient := recipientResp.MessageRecipient
if recipient == nil || recipient.Admin == nil || recipient.MessageMediaInstance == nil {
this.NotFound("messageRecipient", params.RecipientId)
return
}
this.Data["recipient"] = maps.Map{
"id": recipient.Id,
"admin": maps.Map{
"id": recipient.Admin.Id,
"fullname": recipient.Admin.Fullname,
"username": recipient.Admin.Username,
},
"instance": maps.Map{
"id": recipient.MessageMediaInstance.Id,
"name": recipient.MessageMediaInstance.Name,
"description": recipient.MessageMediaInstance.Description,
},
"user": recipient.User,
}
instanceResp, err := this.RPC().MessageMediaInstanceRPC().FindEnabledMessageMediaInstance(this.AdminContext(), &pb.FindEnabledMessageMediaInstanceRequest{MessageMediaInstanceId: recipient.MessageMediaInstance.Id})
if err != nil {
this.ErrorPage(err)
return
}
instance := instanceResp.MessageMediaInstance
if instance == nil || instance.MessageMedia == nil {
this.NotFound("messageMediaInstance", recipient.MessageMediaInstance.Id)
return
}
mediaParams := maps.Map{}
if len(instance.ParamsJSON) > 0 {
err = json.Unmarshal(instance.ParamsJSON, &mediaParams)
if err != nil {
this.ErrorPage(err)
return
}
}
this.Data["instance"] = maps.Map{
"id": instance.Id,
"isOn": instance.IsOn,
"media": maps.Map{
"type": instance.MessageMedia.Type,
"name": instance.MessageMedia.Name,
"userDescription": instance.MessageMedia.UserDescription,
},
"description": instance.Description,
"params": mediaParams,
}
this.Show()
}
func (this *TestAction) RunPost(params struct {
InstanceId int64
Subject string
Body string
User string
Must *actions.Must
CSRF *actionutils.CSRF
}) {
params.Must.
Field("instanceId", params.InstanceId).
Gt(0, "请选择正确的媒介")
resp, err := this.RPC().MessageTaskRPC().CreateMessageTask(this.AdminContext(), &pb.CreateMessageTaskRequest{
RecipientId: 0,
InstanceId: params.InstanceId,
User: params.User,
Subject: params.Subject,
Body: params.Body,
IsPrimary: true,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["taskId"] = resp.MessageTaskId
defer this.CreateLogInfo(codes.MessageTask_LogCreateTestingMessageTask, resp.MessageTaskId)
this.Success()
}

View File

@@ -1,144 +0,0 @@
package recipients
import (
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"regexp"
"strings"
)
type UpdateAction struct {
actionutils.ParentAction
}
func (this *UpdateAction) Init() {
this.Nav("", "", "update")
}
func (this *UpdateAction) RunGet(params struct {
RecipientId int64
}) {
recipientResp, err := this.RPC().MessageRecipientRPC().FindEnabledMessageRecipient(this.AdminContext(), &pb.FindEnabledMessageRecipientRequest{MessageRecipientId: params.RecipientId})
if err != nil {
this.ErrorPage(err)
return
}
recipient := recipientResp.MessageRecipient
if recipient == nil || recipient.Admin == nil || recipient.MessageMediaInstance == nil {
this.NotFound("messageRecipient", params.RecipientId)
return
}
var timeFromHour = ""
var timeFromMinute = ""
var timeFromSecond = ""
if len(recipient.TimeFrom) > 0 {
var pieces = strings.Split(recipient.TimeFrom, ":")
timeFromHour = pieces[0]
timeFromMinute = pieces[1]
timeFromSecond = pieces[2]
}
var timeToHour = ""
var timeToMinute = ""
var timeToSecond = ""
if len(recipient.TimeTo) > 0 {
var pieces = strings.Split(recipient.TimeTo, ":")
timeToHour = pieces[0]
timeToMinute = pieces[1]
timeToSecond = pieces[2]
}
this.Data["recipient"] = maps.Map{
"id": recipient.Id,
"admin": maps.Map{
"id": recipient.Admin.Id,
"fullname": recipient.Admin.Fullname,
"username": recipient.Admin.Username,
},
"groups": recipient.MessageRecipientGroups,
"isOn": recipient.IsOn,
"instance": maps.Map{
"id": recipient.MessageMediaInstance.Id,
"name": recipient.MessageMediaInstance.Name,
},
"user": recipient.User,
"description": recipient.Description,
"timeFromHour": timeFromHour,
"timeFromMinute": timeFromMinute,
"timeFromSecond": timeFromSecond,
"timeToHour": timeToHour,
"timeToMinute": timeToMinute,
"timeToSecond": timeToSecond,
}
this.Show()
}
func (this *UpdateAction) RunPost(params struct {
RecipientId int64
AdminId int64
User string
InstanceId int64
GroupIds string
Description string
IsOn bool
TimeFromHour string
TimeFromMinute string
TimeFromSecond string
TimeToHour string
TimeToMinute string
TimeToSecond string
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo(codes.MessageRecipient_LogUpdateMessageRecipient, params.RecipientId)
params.Must.
Field("adminId", params.AdminId).
Gt(0, "请选择系统用户").
Field("instanceId", params.InstanceId).
Gt(0, "请选择媒介")
groupIds := utils.SplitNumbers(params.GroupIds)
var digitReg = regexp.MustCompile(`^\d+$`)
var timeFrom = ""
if digitReg.MatchString(params.TimeFromHour) && digitReg.MatchString(params.TimeFromMinute) && digitReg.MatchString(params.TimeFromSecond) {
timeFrom = params.TimeFromHour + ":" + params.TimeFromMinute + ":" + params.TimeFromSecond
}
var timeTo = ""
if digitReg.MatchString(params.TimeToHour) && digitReg.MatchString(params.TimeToMinute) && digitReg.MatchString(params.TimeToSecond) {
timeTo = params.TimeToHour + ":" + params.TimeToMinute + ":" + params.TimeToSecond
}
_, err := this.RPC().MessageRecipientRPC().UpdateMessageRecipient(this.AdminContext(), &pb.UpdateMessageRecipientRequest{
MessageRecipientId: params.RecipientId,
AdminId: params.AdminId,
MessageMediaInstanceId: params.InstanceId,
User: params.User,
MessageRecipientGroupIds: groupIds,
Description: params.Description,
IsOn: params.IsOn,
TimeFrom: timeFrom,
TimeTo: timeTo,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -49,6 +49,7 @@ func init() {
Post("/start", new(node.StartAction)).
Post("/stop", new(node.StopAction)).
Post("/up", new(node.UpAction)).
Post("/updateIsOn", new(node.UpdateIsOnAction)).
Get("/detail", new(node.DetailAction)).
GetPost("/updateDNSPopup", new(node.UpdateDNSPopupAction)).
Post("/syncDomain", new(node.SyncDomainAction)).

View File

@@ -4,12 +4,23 @@ package nodeutils
import (
"errors"
"fmt"
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
executils "github.com/TeaOSLab/EdgeAdmin/internal/utils/exec"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"gopkg.in/yaml.v3"
"os"
"runtime"
"strconv"
"time"
)
// InitNodeInfo 初始化节点信息
@@ -104,3 +115,124 @@ func InitNodeInfo(parentAction *actionutils.ParentAction, nodeId int64) (*pb.Nod
return nodeResp.Node, nil
}
// InstallLocalNode 安装本地节点
func InstallLocalNode() error {
var targetDir = Tea.Root
var nodeDir = targetDir + "/edge-node"
var apiAddr = "http://127.0.0.1:8001" // 先固定
// 查找节点安装文件
var zipFile = Tea.Root + "/edge-api/deploy/edge-node-linux-" + runtime.GOARCH + "-v" + teaconst.Version /** 默认和管理系统一致 **/ + ".zip"
{
stat, err := os.Stat(zipFile)
if err != nil {
if os.IsNotExist(err) {
return errors.New("installer file not found in '" + zipFile + "'")
}
return fmt.Errorf("open installer file failed: %w", err)
}
if stat.IsDir() {
return errors.New("invalid installer file '" + zipFile + "'")
}
}
// 解压节点
var unzip = utils.NewUnzip(zipFile, targetDir)
err := unzip.Run()
if err != nil {
return fmt.Errorf("unzip installer file failed: %w", err)
}
// 创建节点
rpcClient, err := rpc.SharedRPC()
if err != nil {
return fmt.Errorf("create rpc client failed: %w", err)
}
var ctx = rpcClient.Context(0)
nodeClustersResp, err := rpcClient.NodeClusterRPC().ListEnabledNodeClusters(ctx, &pb.ListEnabledNodeClustersRequest{
IdDesc: true,
Offset: 0,
Size: 1,
})
if err != nil {
return err
}
if len(nodeClustersResp.NodeClusters) == 0 {
return errors.New("no clusters yet, please create a cluster at least")
}
var clusterId = nodeClustersResp.NodeClusters[0].Id
// 检查节点是否已生成
countNodesResp, err := rpcClient.NodeRPC().CountAllEnabledNodesMatch(ctx, &pb.CountAllEnabledNodesMatchRequest{
NodeClusterId: clusterId,
})
if err != nil {
return err
}
if countNodesResp.Count > 0 {
// 这里先不判断是否有本地节点,只要有节点,就不允许再次执行
return errors.New("there are already nodes in the cluster")
}
createNodeResp, err := rpcClient.NodeRPC().CreateNode(ctx, &pb.CreateNodeRequest{
Name: "本地节点",
NodeClusterId: clusterId,
NodeLogin: nil,
NodeGroupId: 0,
DnsRoutes: nil,
NodeRegionId: 0,
})
if err != nil {
return err
}
var nodeId = createNodeResp.NodeId
nodeResp, err := rpcClient.NodeRPC().FindEnabledNode(ctx, &pb.FindEnabledNodeRequest{NodeId: nodeId})
if err != nil {
return err
}
if nodeResp.Node == nil {
return errors.New("could not find local node with created id '" + types.String(nodeId) + "'")
}
var node = nodeResp.Node
// 生成节点配置
var apiConfig = &configs.APIConfig{
RPCEndpoints: []string{apiAddr},
RPCDisableUpdate: true,
NodeId: node.UniqueId,
Secret: node.Secret,
}
apiConfigYAML, err := yaml.Marshal(apiConfig)
if err != nil {
return fmt.Errorf("encode config failed: %w", err)
}
err = os.WriteFile(nodeDir+"/configs/api_node.yaml", apiConfigYAML, 0666)
if err != nil {
return fmt.Errorf("write config file failed: %w", err)
}
// 测试节点
{
var cmd = executils.NewTimeoutCmd(5*time.Second, nodeDir+"/bin/edge-node", "test")
cmd.WithStdout()
cmd.WithStderr()
err = cmd.Run()
if err != nil {
return fmt.Errorf("node test failed: %w", err)
}
}
// 启动节点
{
var cmd = executils.NewTimeoutCmd(5*time.Second, nodeDir+"/bin/edge-node", "start")
cmd.WithStdout()
cmd.WithStderr()
err = cmd.Run()
if err != nil {
return fmt.Errorf("node start failed: %w", err)
}
}
return nil
}

View File

@@ -0,0 +1,16 @@
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package nodeutils_test
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
_ "github.com/iwind/TeaGo/bootstrap"
"testing"
)
func TestInstallLocalNode(t *testing.T) {
err := nodeutils.InstallLocalNode()
if err != nil {
t.Fatal(err)
}
}

View File

@@ -1,62 +0,0 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package thresholds
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "node", "update")
this.SecondMenu("threshold")
}
func (this *IndexAction) RunGet(params struct {
ClusterId int64
NodeId int64
}) {
_, err := nodeutils.InitNodeInfo(this.Parent(), params.NodeId)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["nodeId"] = params.NodeId
// 列出所有阈值
thresholdsResp, err := this.RPC().NodeThresholdRPC().FindAllEnabledNodeThresholds(this.AdminContext(), &pb.FindAllEnabledNodeThresholdsRequest{
Role: "node",
NodeClusterId: params.ClusterId,
NodeId: params.NodeId,
})
if err != nil {
this.ErrorPage(err)
return
}
thresholdMaps := []maps.Map{}
for _, threshold := range thresholdsResp.NodeThresholds {
thresholdMaps = append(thresholdMaps, maps.Map{
"id": threshold.Id,
"itemName": nodeconfigs.FindNodeValueItemName(threshold.Item),
"paramName": nodeconfigs.FindNodeValueItemParamName(threshold.Item, threshold.Param),
"operatorName": nodeconfigs.FindNodeValueOperatorName(threshold.Operator),
"value": nodeconfigs.UnmarshalNodeValue(threshold.ValueJSON),
"sumMethodName": nodeconfigs.FindNodeValueSumMethodName(threshold.SumMethod),
"duration": threshold.Duration,
"durationUnitName": nodeconfigs.FindNodeValueDurationUnitName(threshold.DurationUnit),
"isOn": threshold.IsOn,
})
}
this.Data["thresholds"] = thresholdMaps
this.Show()
}

View File

@@ -0,0 +1,35 @@
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package node
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
type UpdateIsOnAction struct {
actionutils.ParentAction
}
func (this *UpdateIsOnAction) RunPost(params struct {
NodeId int64
IsOn bool
}) {
if params.IsOn {
defer this.CreateLogInfo(codes.Node_LogUpdateNodeOn, params.NodeId)
} else {
defer this.CreateLogInfo(codes.Node_LogUpdateNodeOff, params.NodeId)
}
_, err := this.RPC().NodeRPC().UpdateNodeIsOn(this.AdminContext(), &pb.UpdateNodeIsOnRequest{
NodeId: params.NodeId,
IsOn: params.IsOn,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -14,7 +14,7 @@ type IndexAction struct {
}
func (this *IndexAction) Init() {
this.Nav("", "setting", "")
this.Nav("", "setting", "index")
this.SecondMenu("dns")
}

View File

@@ -0,0 +1,303 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package dns
import (
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
timeutil "github.com/iwind/TeaGo/utils/time"
)
type RecordsAction struct {
actionutils.ParentAction
}
func (this *RecordsAction) Init() {
this.Nav("", "setting", "records")
this.SecondMenu("dns")
}
func (this *RecordsAction) RunGet(params struct {
ClusterId int64
}) {
// 集群信息
clusterResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeCluster(this.AdminContext(), &pb.FindEnabledNodeClusterRequest{NodeClusterId: params.ClusterId})
if err != nil {
this.ErrorPage(err)
return
}
var cluster = clusterResp.NodeCluster
if cluster == nil {
this.NotFound("nodeCluster", params.ClusterId)
return
}
this.Data["cluster"] = maps.Map{
"id": cluster.Id,
"name": cluster.Name,
}
// DNS信息
dnsResp, err := this.RPC().NodeClusterRPC().FindEnabledNodeClusterDNS(this.AdminContext(), &pb.FindEnabledNodeClusterDNSRequest{NodeClusterId: params.ClusterId})
if err != nil {
this.ErrorPage(err)
return
}
var defaultRoute = dnsResp.DefaultRoute
var domainName = ""
var dnsMap = maps.Map{
"dnsName": dnsResp.Name,
"domainId": 0,
"domainName": "",
"providerId": 0,
"providerName": "",
"providerTypeName": "",
}
if dnsResp.Domain != nil {
domainName = dnsResp.Domain.Name
dnsMap["domainId"] = dnsResp.Domain.Id
dnsMap["domainName"] = dnsResp.Domain.Name
}
if dnsResp.Provider != nil {
dnsMap["providerId"] = dnsResp.Provider.Id
dnsMap["providerName"] = dnsResp.Provider.Name
dnsMap["providerTypeName"] = dnsResp.Provider.TypeName
}
if len(dnsResp.CnameRecords) > 0 {
dnsMap["cnameRecords"] = dnsResp.CnameRecords
} else {
dnsMap["cnameRecords"] = []string{}
}
this.Data["dnsInfo"] = dnsMap
// 未安装的节点
notInstalledNodesResp, err := this.RPC().NodeRPC().FindAllEnabledNodesDNSWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodesDNSWithNodeClusterIdRequest{
NodeClusterId: params.ClusterId,
IsInstalled: false,
})
if err != nil {
this.ErrorPage(err)
return
}
var allNodes = notInstalledNodesResp.Nodes
// 节点DNS解析记录
nodesResp, err := this.RPC().NodeRPC().FindAllEnabledNodesDNSWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledNodesDNSWithNodeClusterIdRequest{
NodeClusterId: params.ClusterId,
IsInstalled: true,
})
if err != nil {
this.ErrorPage(err)
return
}
var installedNodeIdsMap = map[int64]bool{}
for _, node := range nodesResp.Nodes {
installedNodeIdsMap[node.Id] = true
}
allNodes = append(allNodes, nodesResp.Nodes...)
var nodeMaps = []maps.Map{}
for _, node := range allNodes {
var isInstalled = installedNodeIdsMap[node.Id]
if len(node.Routes) > 0 {
for _, route := range node.Routes {
// 检查是否已解析
var isResolved = false
if isInstalled && cluster.DnsDomainId > 0 && len(cluster.DnsName) > 0 && len(node.IpAddr) > 0 {
var recordType = "A"
if utils.IsIPv6(node.IpAddr) {
recordType = "AAAA"
}
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
DnsDomainId: cluster.DnsDomainId,
Name: cluster.DnsName,
Type: recordType,
Route: route.Code,
Value: node.IpAddr,
})
if err != nil {
this.ErrorPage(err)
return
}
isResolved = checkResp.IsOk
}
nodeMaps = append(nodeMaps, maps.Map{
"id": node.Id,
"name": node.Name,
"ipAddr": node.IpAddr,
"ipAddrId": node.NodeIPAddressId,
"route": maps.Map{
"name": route.Name,
"code": route.Code,
},
"clusterId": node.NodeClusterId,
"isResolved": isResolved,
"isInstalled": isInstalled,
"isBackup": node.IsBackupForCluster || node.IsBackupForGroup,
"isOffline": node.IsOffline,
})
}
} else {
// 默认线路
var isResolved = false
if isInstalled && len(defaultRoute) > 0 {
var recordType = "A"
if utils.IsIPv6(node.IpAddr) {
recordType = "AAAA"
}
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
DnsDomainId: cluster.DnsDomainId,
Name: cluster.DnsName,
Type: recordType,
Route: defaultRoute,
Value: node.IpAddr,
})
if err != nil {
this.ErrorPage(err)
return
}
isResolved = checkResp.IsOk
}
nodeMaps = append(nodeMaps, maps.Map{
"id": node.Id,
"name": node.Name,
"ipAddr": node.IpAddr,
"ipAddrId": node.NodeIPAddressId,
"route": maps.Map{
"name": "",
"code": "",
},
"clusterId": node.NodeClusterId,
"isResolved": isResolved,
"isInstalled": isInstalled,
"isBackup": node.IsBackupForCluster || node.IsBackupForGroup,
"isOffline": node.IsOffline,
})
}
}
this.Data["nodes"] = nodeMaps
// 代理服务解析记录
serversResp, err := this.RPC().ServerRPC().FindAllEnabledServersDNSWithNodeClusterId(this.AdminContext(), &pb.FindAllEnabledServersDNSWithNodeClusterIdRequest{NodeClusterId: params.ClusterId})
if err != nil {
this.ErrorPage(err)
return
}
var serverMaps = []maps.Map{}
for _, server := range serversResp.Servers {
// 检查是否已解析
isResolved := false
if cluster.DnsDomainId > 0 && len(cluster.DnsName) > 0 && len(server.DnsName) > 0 && len(domainName) > 0 {
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
DnsDomainId: cluster.DnsDomainId,
Name: server.DnsName,
Type: "CNAME",
Value: cluster.DnsName + "." + domainName,
})
if err != nil {
this.ErrorPage(err)
return
}
isResolved = checkResp.IsOk
}
serverMaps = append(serverMaps, maps.Map{
"id": server.Id,
"name": server.Name,
"dnsName": server.DnsName,
"isResolved": isResolved,
})
}
this.Data["servers"] = serverMaps
// 检查解析记录是否有变化
checkChangesResp, err := this.RPC().NodeClusterRPC().CheckNodeClusterDNSChanges(this.AdminContext(), &pb.CheckNodeClusterDNSChangesRequest{NodeClusterId: params.ClusterId})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["dnsHasChanges"] = checkChangesResp.IsChanged
// 需要解决的问题
issuesResp, err := this.RPC().DNSRPC().FindAllDNSIssues(this.AdminContext(), &pb.FindAllDNSIssuesRequest{
NodeClusterId: params.ClusterId,
})
if err != nil {
this.ErrorPage(err)
return
}
var issueMaps = []maps.Map{}
for _, issue := range issuesResp.Issues {
issueMaps = append(issueMaps, maps.Map{
"target": issue.Target,
"targetId": issue.TargetId,
"type": issue.Type,
"description": issue.Description,
"params": issue.Params,
})
}
this.Data["issues"] = issueMaps
// 当前正在执行的任务
resp, err := this.RPC().DNSTaskRPC().FindAllDoingDNSTasks(this.AdminContext(), &pb.FindAllDoingDNSTasksRequest{
NodeClusterId: params.ClusterId,
})
if err != nil {
this.ErrorPage(err)
return
}
var taskMaps = []maps.Map{}
for _, task := range resp.DnsTasks {
var clusterMap maps.Map = nil
var nodeMap maps.Map = nil
var serverMap maps.Map = nil
var domainMap maps.Map = nil
if task.NodeCluster != nil {
clusterMap = maps.Map{
"id": task.NodeCluster.Id,
"name": task.NodeCluster.Name,
}
}
if task.Node != nil {
nodeMap = maps.Map{
"id": task.Node.Id,
"name": task.Node.Name,
}
}
if task.Server != nil {
serverMap = maps.Map{
"id": task.Server.Id,
"name": task.Server.Name,
}
}
if task.DnsDomain != nil {
domainMap = maps.Map{
"id": task.DnsDomain.Id,
"name": task.DnsDomain.Name,
}
}
taskMaps = append(taskMaps, maps.Map{
"id": task.Id,
"type": task.Type,
"isDone": task.IsDone,
"isOk": task.IsOk,
"error": task.Error,
"updatedTime": timeutil.FormatTime("Y-m-d H:i:s", task.UpdatedAt),
"cluster": clusterMap,
"node": nodeMap,
"server": serverMap,
"domain": domainMap,
})
}
this.Data["tasks"] = taskMaps
this.Show()
}

View File

@@ -100,6 +100,9 @@ func (this *IndexAction) RunPost(params struct {
HttpAllNodeIPShowPage bool
HttpAllEnableServerAddrVariable bool
HttpAllDomainAuditingIsOn bool
HttpAllDomainAuditingPrompt string
HttpAllServerName string
HttpAllSupportsLowVersionHTTP bool
HttpAllMatchCertFromAllServers bool
@@ -119,6 +122,11 @@ func (this *IndexAction) RunPost(params struct {
PerformanceAutoWriteTimeout bool
PerformanceDebug bool
// TCP端口设置
TcpAllPortRangeMin int
TcpAllPortRangeMax int
TcpAllDenyPorts []int
Must *actions.Must
CSRF *actionutils.CSRF
}) {
@@ -172,6 +180,9 @@ func (this *IndexAction) RunPost(params struct {
config.HTTPAll.NodeIPShowPage = params.HttpAllNodeIPShowPage
config.HTTPAll.NodeIPPageHTML = params.HttpAllNodeIPPageHTML
config.HTTPAll.DomainAuditingIsOn = params.HttpAllDomainAuditingIsOn
config.HTTPAll.DomainAuditingPrompt = params.HttpAllDomainAuditingPrompt
// HTTP All
config.HTTPAll.ServerName = params.HttpAllServerName
config.HTTPAll.SupportsLowVersionHTTP = params.HttpAllSupportsLowVersionHTTP
@@ -191,6 +202,23 @@ func (this *IndexAction) RunPost(params struct {
// 日志
config.Log.RecordServerError = params.LogRecordServerError
// TCP
if params.TcpAllPortRangeMin < 1024 {
params.TcpAllPortRangeMin = 1024
}
if params.TcpAllPortRangeMax > 65534 {
params.TcpAllPortRangeMax = 65534
} else if params.TcpAllPortRangeMax < 1024 {
params.TcpAllPortRangeMax = 1024
}
if params.TcpAllPortRangeMin > params.TcpAllPortRangeMax {
params.TcpAllPortRangeMin, params.TcpAllPortRangeMax = params.TcpAllPortRangeMax, params.TcpAllPortRangeMin
}
config.TCPAll.DenyPorts = params.TcpAllDenyPorts
config.TCPAll.PortRangeMin = params.TcpAllPortRangeMin
config.TCPAll.PortRangeMax = params.TcpAllPortRangeMax
// 性能
config.Performance.AutoReadTimeout = params.PerformanceAutoReadTimeout
config.Performance.AutoWriteTimeout = params.PerformanceAutoWriteTimeout

View File

@@ -112,6 +112,7 @@ func (this *IndexAction) RunGet(params struct {
"clock": clockConfig,
"autoRemoteStart": cluster.AutoRemoteStart,
"autoInstallNftables": cluster.AutoInstallNftables,
"autoSystemTuning": cluster.AutoSystemTuning,
"sshParams": sshParams,
"domainName": fullDomainName,
}
@@ -139,6 +140,7 @@ func (this *IndexAction) RunPost(params struct {
ClockCheckChrony bool
AutoRemoteStart bool
AutoInstallNftables bool
AutoSystemTuning bool
Must *actions.Must
}) {
@@ -193,6 +195,7 @@ func (this *IndexAction) RunPost(params struct {
ClockJSON: clockConfigJSON,
AutoRemoteStart: params.AutoRemoteStart,
AutoInstallNftables: params.AutoInstallNftables,
AutoSystemTuning: params.AutoSystemTuning,
SshParamsJSON: sshParamsJSON,
})
if err != nil {

View File

@@ -40,6 +40,7 @@ func init() {
// DNS
Prefix("/clusters/cluster/settings/dns").
GetPost("", new(dns.IndexAction)).
Get("/records", new(dns.RecordsAction)).
Post("/randomName", new(dns.RandomNameAction)).
// 系统服务设置

View File

@@ -45,6 +45,7 @@ func (this *IndexAction) RunGet(params struct {
func (this *IndexAction) RunPost(params struct {
ClusterId int64
IsOn bool
Quality int
RequireCache bool
MinLengthJSON []byte
MaxLengthJSON []byte
@@ -59,6 +60,13 @@ func (this *IndexAction) RunPost(params struct {
RequireCache: params.RequireCache,
}
if params.Quality < 0 {
params.Quality = 0
} else if params.Quality > 100 {
params.Quality = 100
}
config.Quality = params.Quality
if len(params.MinLengthJSON) > 0 {
var minLength = &shared.SizeCapacity{}
err := json.Unmarshal(params.MinLengthJSON, minLength)
@@ -79,6 +87,11 @@ func (this *IndexAction) RunPost(params struct {
config.MaxLength = maxLength
}
err := config.Init()
if err != nil {
this.Fail("配置校验失败:" + err.Error())
}
configJSON, err := json.Marshal(config)
if err != nil {
this.ErrorPage(err)
@@ -87,7 +100,7 @@ func (this *IndexAction) RunPost(params struct {
_, err = this.RPC().NodeClusterRPC().UpdateNodeClusterWebPPolicy(this.AdminContext(), &pb.UpdateNodeClusterWebPPolicyRequest{
NodeClusterId: params.ClusterId,
WebpPolicyJSON: configJSON,
WebPPolicyJSON: configJSON,
})
if err != nil {

View File

@@ -180,7 +180,7 @@ func (this *ClusterHelper) createSettingMenu(cluster *pb.NodeCluster, info *pb.F
"name": this.Lang(actionPtr, codes.NodeClusterMenu_SettingWebP),
"url": "/clusters/cluster/settings/webp?clusterId=" + clusterId,
"isActive": selectedItem == "webp",
"isOn": info != nil && info.WebpIsOn,
"isOn": info != nil && info.WebPIsOn,
})
items = this.filterMenuItems1(items, info, clusterId, selectedItem, actionPtr)

View File

@@ -1,7 +1,9 @@
package clusters
import (
"crypto/rand"
"encoding/json"
"fmt"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
@@ -9,6 +11,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/rands"
)
type CreateAction struct {
@@ -44,6 +47,18 @@ func (this *CreateAction) RunGet(params struct{}) {
}
this.Data["totalNodes"] = totalNodesResp.Count
// 随机子域名
var defaultDNSName = "g" + rands.HexString(6) + ".cdn"
{
var b = make([]byte, 3)
_, err = rand.Read(b)
if err == nil {
defaultDNSName = fmt.Sprintf("g%x.cdn", b)
}
}
this.Data["defaultDNSName"] = defaultDNSName
this.Data["dnsName"] = defaultDNSName
this.Show()
}
@@ -64,6 +79,7 @@ func (this *CreateAction) RunPost(params struct {
InstallDir string
SystemdServiceIsOn bool
AutoInstallNftables bool
AutoSystemTuning bool
// DNS相关
DnsDomainId int64
@@ -132,6 +148,7 @@ func (this *CreateAction) RunPost(params struct {
SystemServicesJSON: systemServicesJSON,
GlobalServerConfigJSON: globalServerConfigJSON,
AutoInstallNftables: params.AutoInstallNftables,
AutoSystemTuning: params.AutoSystemTuning,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -8,7 +8,6 @@ import (
"encoding/json"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeAdmin/internal/utils/sizes"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/lists"
@@ -19,6 +18,7 @@ import (
"os/exec"
"regexp"
"runtime"
"strings"
)
// CheckDiskPartitions 检查服务器磁盘空间
@@ -47,9 +47,17 @@ func CheckDiskPartitions(thresholdPercent float64) (path string, usage uint64, u
if p.Fstype != rootFS {
continue
}
// skip some specified partitions on macOS
if runtime.GOOS == "darwin" {
if strings.Contains(p.Mountpoint, "/Developer/") {
continue
}
}
stat, _ := disk.Usage(p.Mountpoint)
if stat != nil {
if stat.Used < 2*uint64(sizes.G) {
if stat.Used < (5<<30) || stat.Free > (100<<30) {
continue
}
if stat.UsedPercent > thresholdPercent {

View File

@@ -154,17 +154,6 @@ func (this *IndexAction) RunPost(params struct{}) {
"version": "",
}
}
if resp.MonitorNodeUpgradeInfo != nil {
this.Data["monitorNodeUpgradeInfo"] = maps.Map{
"count": resp.MonitorNodeUpgradeInfo.CountNodes,
"version": resp.MonitorNodeUpgradeInfo.NewVersion,
}
} else {
this.Data["monitorNodeUpgradeInfo"] = maps.Map{
"count": 0,
"version": "",
}
}
if resp.ApiNodeUpgradeInfo != nil {
this.Data["apiNodeUpgradeInfo"] = maps.Map{
"count": resp.ApiNodeUpgradeInfo.CountNodes,
@@ -176,39 +165,6 @@ func (this *IndexAction) RunPost(params struct{}) {
"version": "",
}
}
if resp.UserNodeUpgradeInfo != nil {
this.Data["userNodeUpgradeInfo"] = maps.Map{
"count": resp.UserNodeUpgradeInfo.CountNodes,
"version": resp.UserNodeUpgradeInfo.NewVersion,
}
} else {
this.Data["userNodeUpgradeInfo"] = maps.Map{
"count": 0,
"version": 0,
}
}
if resp.AuthorityNodeUpgradeInfo != nil {
this.Data["authorityNodeUpgradeInfo"] = maps.Map{
"count": resp.AuthorityNodeUpgradeInfo.CountNodes,
"version": resp.AuthorityNodeUpgradeInfo.NewVersion,
}
} else {
this.Data["authorityNodeUpgradeInfo"] = maps.Map{
"count": 0,
"version": "",
}
}
if resp.NsNodeUpgradeInfo != nil {
this.Data["nsNodeUpgradeInfo"] = maps.Map{
"count": resp.NsNodeUpgradeInfo.CountNodes,
"version": resp.NsNodeUpgradeInfo.NewVersion,
}
} else {
this.Data["nsNodeUpgradeInfo"] = maps.Map{
"count": 0,
"version": "",
}
}
// 域名排行
{

View File

@@ -52,9 +52,13 @@ func (this *CreatePopupAction) RunPost(params struct {
Type string
// DNSPod
ParamId string
ParamToken string
ParamRegion string
ParamDNSPodId string
ParamDNSPodToken string
ParamDNSPodRegion string
ParamDNSPodAPIType string
ParamDNSPodAccessKeyId string
ParamDNSPodAccessKeySecret string
// AliDNS
ParamAliDNSAccessKeyId string
@@ -89,18 +93,31 @@ func (this *CreatePopupAction) RunPost(params struct {
Field("type", params.Type).
Require("请选择服务商厂家")
apiParams := maps.Map{}
var apiParams = maps.Map{}
switch params.Type {
case "dnspod":
params.Must.
Field("paramId", params.ParamId).
Require("请输入密钥ID").
Field("paramToken", params.ParamToken).
Require("请输入密钥Token")
apiParams["apiType"] = params.ParamDNSPodAPIType
switch params.ParamDNSPodAPIType {
case "tencentDNS":
params.Must.
Field("paramDNSPodAccessKeyId", params.ParamDNSPodAccessKeyId).
Require("请输入SecretId").
Field("paramDNSPodAccessKeySecret", params.ParamDNSPodAccessKeySecret).
Require("请输入SecretKey")
apiParams["accessKeyId"] = params.ParamDNSPodAccessKeyId
apiParams["accessKeySecret"] = params.ParamDNSPodAccessKeySecret
apiParams["region"] = params.ParamDNSPodRegion
default:
params.Must.
Field("paramId", params.ParamDNSPodId).
Require("请输入密钥ID").
Field("paramToken", params.ParamDNSPodToken).
Require("请输入密钥Token")
apiParams["id"] = params.ParamId
apiParams["token"] = params.ParamToken
apiParams["region"] = params.ParamRegion
apiParams["id"] = params.ParamDNSPodId
apiParams["token"] = params.ParamDNSPodToken
apiParams["region"] = params.ParamDNSPodRegion
}
case "alidns":
params.Must.
Field("paramAliDNSAccessKeyId", params.ParamAliDNSAccessKeyId).

View File

@@ -79,9 +79,13 @@ func (this *UpdatePopupAction) RunPost(params struct {
Type string
// DNSPod
ParamId string
ParamToken string
ParamRegion string
ParamDNSPodId string
ParamDNSPodToken string
ParamDNSPodRegion string
ParamDNSPodAPIType string
ParamDNSPodAccessKeyId string
ParamDNSPodAccessKeySecret string
// AliDNS
ParamAliDNSAccessKeyId string
@@ -118,18 +122,31 @@ func (this *UpdatePopupAction) RunPost(params struct {
Field("type", params.Type).
Require("请选择服务商厂家")
apiParams := maps.Map{}
var apiParams = maps.Map{}
switch params.Type {
case "dnspod":
params.Must.
Field("paramId", params.ParamId).
Require("请输入密钥ID").
Field("paramToken", params.ParamToken).
Require("请输入密钥Token")
apiParams["apiType"] = params.ParamDNSPodAPIType
switch params.ParamDNSPodAPIType {
case "tencentDNS":
params.Must.
Field("paramDNSPodAccessKeyId", params.ParamDNSPodAccessKeyId).
Require("请输入SecretId").
Field("paramDNSPodAccessKeySecret", params.ParamDNSPodAccessKeySecret).
Require("请输入SecretKey")
apiParams["accessKeyId"] = params.ParamDNSPodAccessKeyId
apiParams["accessKeySecret"] = params.ParamDNSPodAccessKeySecret
apiParams["region"] = params.ParamDNSPodRegion
default:
params.Must.
Field("paramId", params.ParamDNSPodId).
Require("请输入密钥ID").
Field("paramToken", params.ParamDNSPodToken).
Require("请输入密钥Token")
apiParams["id"] = params.ParamId
apiParams["token"] = params.ParamToken
apiParams["region"] = params.ParamRegion
apiParams["id"] = params.ParamDNSPodId
apiParams["token"] = params.ParamDNSPodToken
apiParams["region"] = params.ParamDNSPodRegion
}
case "alidns":
params.Must.
Field("paramAliDNSAccessKeyId", params.ParamAliDNSAccessKeyId).

View File

@@ -175,7 +175,7 @@ func (this *IndexAction) RunPost(params struct {
})
if err != nil {
err = dao.SharedLogDAO.CreateAdminLog(rpcClient.Context(0), oplogs.LevelError, this.Request.URL.Path, langs.DefaultMessage(codes.AdminLogin_LogSystemError, err.Error()), this.RequestRemoteIP(), codes.AdminLogin_LogSystemError, []any{err.Error()})
err = dao.SharedLogDAO.CreateAdminLog(rpcClient.Context(0), oplogs.LevelError, this.Request.URL.Path, langs.DefaultMessage(codes.AdminLogin_LogSystemError, err.Error()), loginutils.RemoteIP(&this.ActionObject), codes.AdminLogin_LogSystemError, []any{err.Error()})
if err != nil {
utils.PrintError(err)
}
@@ -185,7 +185,7 @@ func (this *IndexAction) RunPost(params struct {
}
if !resp.IsOk {
err = dao.SharedLogDAO.CreateAdminLog(rpcClient.Context(0), oplogs.LevelWarn, this.Request.URL.Path, langs.DefaultMessage(codes.AdminLogin_LogFailed, params.Username), this.RequestRemoteIP(), codes.AdminLogin_LogFailed, []any{params.Username})
err = dao.SharedLogDAO.CreateAdminLog(rpcClient.Context(0), oplogs.LevelWarn, this.Request.URL.Path, langs.DefaultMessage(codes.AdminLogin_LogFailed, params.Username), loginutils.RemoteIP(&this.ActionObject), codes.AdminLogin_LogFailed, []any{params.Username})
if err != nil {
utils.PrintError(err)
}
@@ -225,7 +225,7 @@ func (this *IndexAction) RunPost(params struct {
params.Auth.StoreAdmin(adminId, params.Remember)
// 记录日志
err = dao.SharedLogDAO.CreateAdminLog(rpcClient.Context(adminId), oplogs.LevelInfo, this.Request.URL.Path, langs.DefaultMessage(codes.AdminLogin_LogSuccess, params.Username), this.RequestRemoteIP(), codes.AdminLogin_LogSuccess, []any{params.Username})
err = dao.SharedLogDAO.CreateAdminLog(rpcClient.Context(adminId), oplogs.LevelInfo, this.Request.URL.Path, langs.DefaultMessage(codes.AdminLogin_LogSuccess, params.Username), loginutils.RemoteIP(&this.ActionObject), codes.AdminLogin_LogSuccess, []any{params.Username})
if err != nil {
utils.PrintError(err)
}
@@ -235,7 +235,7 @@ func (this *IndexAction) RunPost(params struct {
// 检查登录区域
func (this *IndexAction) checkRegion() bool {
var ip = this.RequestRemoteIP()
var ip = loginutils.RemoteIP(&this.ActionObject)
var result = iplibrary.LookupIP(ip)
if result != nil && result.IsOk() && result.CountryId() > 0 && lists.ContainsInt64([]int64{9, 10}, result.CountryId()) {
return false

View File

@@ -3,12 +3,15 @@
package loginutils
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"github.com/iwind/TeaGo/actions"
stringutil "github.com/iwind/TeaGo/utils/string"
"net"
"net/http"
"regexp"
"strings"
)
// CalculateClientFingerprint 计算客户端指纹
@@ -17,8 +20,26 @@ func CalculateClientFingerprint(action *actions.ActionObject) string {
}
// RemoteIP 获取客户端IP
// TODO 将来增加是否使用代理设置即从X-Real-IP中获取IP
func RemoteIP(action *actions.ActionObject) string {
securityConfig, _ := configloaders.LoadSecurityConfig()
if securityConfig != nil {
if len(securityConfig.ClientIPHeaderNames) > 0 {
var headerNames = regexp.MustCompile(`[,;\s]`).Split(securityConfig.ClientIPHeaderNames, -1)
for _, headerName := range headerNames {
headerName = http.CanonicalHeaderKey(strings.TrimSpace(headerName))
if len(headerName) == 0 {
continue
}
var ipValue = action.Request.Header.Get(headerName)
if net.ParseIP(ipValue) != nil {
return ipValue
}
}
}
}
ip, _, _ := net.SplitHostPort(action.Request.RemoteAddr)
return ip
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/setup"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/index/loginutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
@@ -146,7 +147,7 @@ func (this *OtpAction) RunPost(params struct {
this.ErrorPage(err)
return
}
err = dao.SharedLogDAO.CreateAdminLog(rpcClient.Context(adminId), oplogs.LevelInfo, this.Request.URL.Path, this.Lang(codes.AdminLogin_LogOtpVerifiedSuccess), this.RequestRemoteIP(), codes.AdminLogin_LogOtpVerifiedSuccess, nil)
err = dao.SharedLogDAO.CreateAdminLog(rpcClient.Context(adminId), oplogs.LevelInfo, this.Request.URL.Path, this.Lang(codes.AdminLogin_LogOtpVerifiedSuccess), loginutils.RemoteIP(&this.ActionObject), codes.AdminLogin_LogOtpVerifiedSuccess, nil)
if err != nil {
utils.PrintError(err)
}

View File

@@ -36,31 +36,43 @@ func (this *AddServerNamePopupAction) RunPost(params struct {
// 去除空格
serverName = regexp.MustCompile(`\s+`).ReplaceAllString(serverName, "")
// 处理URL
if regexp.MustCompile(`^(?i)(http|https|ftp)://`).MatchString(serverName) {
u, err := url.Parse(serverName)
if err == nil && len(u.Host) > 0 {
serverName = u.Host
// 是否包含了多个域名
var splitReg = regexp.MustCompile(`([,、|,;|])`)
if splitReg.MatchString(serverName) {
params.ServerNames = strings.Join(splitReg.Split(serverName, -1), "\n")
params.Mode = "multiple"
} else {
// 处理URL
if regexp.MustCompile(`^(?i)(http|https|ftp)://`).MatchString(serverName) {
u, err := url.Parse(serverName)
if err == nil && len(u.Host) > 0 {
serverName = u.Host
}
}
}
// 去除端口
if regexp.MustCompile(`:\d+$`).MatchString(serverName) {
host, _, err := net.SplitHostPort(serverName)
if err == nil && len(host) > 0 {
serverName = host
// 去除端口
if regexp.MustCompile(`:\d+$`).MatchString(serverName) {
host, _, err := net.SplitHostPort(serverName)
if err == nil && len(host) > 0 {
serverName = host
}
}
}
params.Must.
Field("serverName", serverName).
Require("请输入域名")
params.Must.
Field("serverName", serverName).
Require("请输入域名")
this.Data["serverName"] = maps.Map{
"name": serverName,
"type": "full",
this.Data["serverName"] = maps.Map{
"name": serverName,
"type": "full",
}
this.Success()
return
}
} else if params.Mode == "multiple" {
}
if params.Mode == "multiple" {
if len(params.ServerNames) == 0 {
this.FailField("serverNames", "请输入至少域名")
}
@@ -99,8 +111,6 @@ func (this *AddServerNamePopupAction) RunPost(params struct {
"type": "full",
"subNames": serverNames,
}
} else {
this.Fail("错误的mode参数")
}
this.Success()

View File

@@ -17,12 +17,16 @@ func (this *IndexAction) Init() {
}
func (this *IndexAction) RunGet(params struct {
UserId int64
Type string
Keyword string
UserId int64
Type string
Keyword string
UserType string
}) {
this.Data["type"] = params.Type
this.Data["keyword"] = params.Keyword
this.Data["userType"] = params.UserType
var userOnly = params.UserId > 0 || params.UserType == "user"
// 当前用户
this.Data["searchingUserId"] = params.UserId
@@ -58,8 +62,9 @@ func (this *IndexAction) RunGet(params struct {
{
// all
resp, err := this.RPC().ACMETaskRPC().CountAllEnabledACMETasks(this.AdminContext(), &pb.CountAllEnabledACMETasksRequest{
UserId: params.UserId,
Keyword: params.Keyword,
UserId: params.UserId,
Keyword: params.Keyword,
UserOnly: userOnly,
})
if err != nil {
this.ErrorPage(err)
@@ -72,6 +77,7 @@ func (this *IndexAction) RunGet(params struct {
UserId: params.UserId,
IsAvailable: true,
Keyword: params.Keyword,
UserOnly: userOnly,
})
if err != nil {
this.ErrorPage(err)
@@ -84,6 +90,7 @@ func (this *IndexAction) RunGet(params struct {
UserId: params.UserId,
IsExpired: true,
Keyword: params.Keyword,
UserOnly: userOnly,
})
if err != nil {
this.ErrorPage(err)
@@ -96,6 +103,7 @@ func (this *IndexAction) RunGet(params struct {
UserId: params.UserId,
ExpiringDays: 7,
Keyword: params.Keyword,
UserOnly: userOnly,
})
if err != nil {
this.ErrorPage(err)
@@ -108,6 +116,7 @@ func (this *IndexAction) RunGet(params struct {
UserId: params.UserId,
ExpiringDays: 30,
Keyword: params.Keyword,
UserOnly: userOnly,
})
if err != nil {
this.ErrorPage(err)
@@ -130,10 +139,11 @@ func (this *IndexAction) RunGet(params struct {
case "":
page = this.NewPage(countAll)
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{
UserId: params.UserId,
Offset: page.Offset,
Size: page.Size,
Keyword: params.Keyword,
UserId: params.UserId,
Offset: page.Offset,
Size: page.Size,
Keyword: params.Keyword,
UserOnly: userOnly,
})
case "available":
page = this.NewPage(countAvailable)
@@ -143,6 +153,7 @@ func (this *IndexAction) RunGet(params struct {
Offset: page.Offset,
Size: page.Size,
Keyword: params.Keyword,
UserOnly: userOnly,
})
case "expired":
page = this.NewPage(countExpired)
@@ -152,6 +163,7 @@ func (this *IndexAction) RunGet(params struct {
Offset: page.Offset,
Size: page.Size,
Keyword: params.Keyword,
UserOnly: userOnly,
})
case "7days":
page = this.NewPage(count7Days)
@@ -161,6 +173,7 @@ func (this *IndexAction) RunGet(params struct {
Offset: page.Offset,
Size: page.Size,
Keyword: params.Keyword,
UserOnly: userOnly,
})
case "30days":
page = this.NewPage(count30Days)
@@ -170,14 +183,16 @@ func (this *IndexAction) RunGet(params struct {
Offset: page.Offset,
Size: page.Size,
Keyword: params.Keyword,
UserOnly: userOnly,
})
default:
page = this.NewPage(countAll)
tasksResp, err = this.RPC().ACMETaskRPC().ListEnabledACMETasks(this.AdminContext(), &pb.ListEnabledACMETasksRequest{
UserId: params.UserId,
Keyword: params.Keyword,
Offset: page.Offset,
Size: page.Size,
UserId: params.UserId,
Keyword: params.Keyword,
UserOnly: userOnly,
Offset: page.Offset,
Size: page.Size,
})
}
if err != nil {
@@ -242,6 +257,23 @@ func (this *IndexAction) RunGet(params struct {
}
}
// user
userResp, err := this.RPC().ACMETaskRPC().FindACMETaskUser(this.AdminContext(), &pb.FindACMETaskUserRequest{AcmeTaskId: task.Id})
if err != nil {
this.ErrorPage(err)
return
}
var taskUserMap = maps.Map{
"id": 0,
}
if userResp.User != nil {
taskUserMap = maps.Map{
"id": userResp.User.Id,
"username": userResp.User.Username,
"fullname": userResp.User.Fullname,
}
}
taskMaps = append(taskMaps, maps.Map{
"id": task.Id,
"authType": task.AuthType,
@@ -257,6 +289,7 @@ func (this *IndexAction) RunGet(params struct {
"autoRenew": task.AutoRenew,
"cert": certMap,
"log": logMap,
"user": taskUserMap,
})
}
this.Data["tasks"] = taskMaps

View File

@@ -19,13 +19,19 @@ func (this *IndexAction) Init() {
}
func (this *IndexAction) RunGet(params struct {
UserId int64
Type string
Keyword string
UserId int64
Type string // [empty] | ca | 7days | ...
Keyword string
UserType string
}) {
this.Data["type"] = params.Type
this.Data["keyword"] = params.Keyword
if params.UserId > 0 {
params.UserType = "user"
}
this.Data["userType"] = params.UserType
// 当前用户
this.Data["searchingUserId"] = params.UserId
var userMap = maps.Map{
@@ -57,12 +63,15 @@ func (this *IndexAction) RunGet(params struct {
var count7Days int64
var count30Days int64
var userOnly = params.UserType == "user" || params.UserId > 0
// 计算数量
{
// all
resp, err := this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
UserId: params.UserId,
Keyword: params.Keyword,
UserId: params.UserId,
Keyword: params.Keyword,
UserOnly: userOnly,
})
if err != nil {
this.ErrorPage(err)
@@ -72,9 +81,10 @@ func (this *IndexAction) RunGet(params struct {
// CA
resp, err = this.RPC().SSLCertRPC().CountSSLCerts(this.AdminContext(), &pb.CountSSLCertRequest{
UserId: params.UserId,
IsCA: true,
Keyword: params.Keyword,
UserId: params.UserId,
IsCA: true,
Keyword: params.Keyword,
UserOnly: userOnly,
})
if err != nil {
this.ErrorPage(err)
@@ -87,6 +97,7 @@ func (this *IndexAction) RunGet(params struct {
UserId: params.UserId,
IsAvailable: true,
Keyword: params.Keyword,
UserOnly: userOnly,
})
if err != nil {
this.ErrorPage(err)
@@ -99,6 +110,7 @@ func (this *IndexAction) RunGet(params struct {
UserId: params.UserId,
IsExpired: true,
Keyword: params.Keyword,
UserOnly: userOnly,
})
if err != nil {
this.ErrorPage(err)
@@ -111,6 +123,7 @@ func (this *IndexAction) RunGet(params struct {
UserId: params.UserId,
ExpiringDays: 7,
Keyword: params.Keyword,
UserOnly: userOnly,
})
if err != nil {
this.ErrorPage(err)
@@ -123,6 +136,7 @@ func (this *IndexAction) RunGet(params struct {
UserId: params.UserId,
ExpiringDays: 30,
Keyword: params.Keyword,
UserOnly: userOnly,
})
if err != nil {
this.ErrorPage(err)
@@ -146,19 +160,21 @@ func (this *IndexAction) RunGet(params struct {
case "":
page = this.NewPage(countAll)
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
UserId: params.UserId,
Offset: page.Offset,
Size: page.Size,
Keyword: params.Keyword,
UserId: params.UserId,
Offset: page.Offset,
Size: page.Size,
Keyword: params.Keyword,
UserOnly: userOnly,
})
case "ca":
page = this.NewPage(countCA)
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
UserId: params.UserId,
IsCA: true,
Offset: page.Offset,
Size: page.Size,
Keyword: params.Keyword,
UserId: params.UserId,
IsCA: true,
Offset: page.Offset,
Size: page.Size,
Keyword: params.Keyword,
UserOnly: userOnly,
})
case "available":
page = this.NewPage(countAvailable)
@@ -168,6 +184,7 @@ func (this *IndexAction) RunGet(params struct {
Offset: page.Offset,
Size: page.Size,
Keyword: params.Keyword,
UserOnly: userOnly,
})
case "expired":
page = this.NewPage(countExpired)
@@ -177,6 +194,7 @@ func (this *IndexAction) RunGet(params struct {
Offset: page.Offset,
Size: page.Size,
Keyword: params.Keyword,
UserOnly: userOnly,
})
case "7days":
page = this.NewPage(count7Days)
@@ -195,14 +213,16 @@ func (this *IndexAction) RunGet(params struct {
Offset: page.Offset,
Size: page.Size,
Keyword: params.Keyword,
UserOnly: userOnly,
})
default:
page = this.NewPage(countAll)
listResp, err = this.RPC().SSLCertRPC().ListSSLCerts(this.AdminContext(), &pb.ListSSLCertsRequest{
UserId: params.UserId,
Keyword: params.Keyword,
Offset: page.Offset,
Size: page.Size,
UserId: params.UserId,
Keyword: params.Keyword,
UserOnly: userOnly,
Offset: page.Offset,
Size: page.Size,
})
}
if err != nil {
@@ -221,6 +241,7 @@ func (this *IndexAction) RunGet(params struct {
var certMaps = []maps.Map{}
var nowTime = time.Now().Unix()
for _, certConfig := range certConfigs {
// count servers
countServersResp, err := this.RPC().ServerRPC().CountAllEnabledServersWithSSLCertId(this.AdminContext(), &pb.CountAllEnabledServersWithSSLCertIdRequest{
SslCertId: certConfig.Id,
})
@@ -229,6 +250,23 @@ func (this *IndexAction) RunGet(params struct {
return
}
// user
userResp, err := this.RPC().SSLCertRPC().FindSSLCertUser(this.AdminContext(), &pb.FindSSLCertUserRequest{SslCertId: certConfig.Id})
if err != nil {
this.ErrorPage(err)
return
}
var certUserMap = maps.Map{
"id": 0,
}
if userResp.User != nil {
certUserMap = maps.Map{
"id": userResp.User.Id,
"username": userResp.User.Username,
"fullname": userResp.User.Fullname,
}
}
certMaps = append(certMaps, maps.Map{
"isOn": certConfig.IsOn,
"beginDay": timeutil.FormatTime("Y-m-d", certConfig.TimeBeginAt),
@@ -236,6 +274,7 @@ func (this *IndexAction) RunGet(params struct {
"isExpired": nowTime > certConfig.TimeEndAt,
"isAvailable": nowTime <= certConfig.TimeEndAt,
"countServers": countServersResp.Count,
"user": certUserMap,
})
}
this.Data["certInfos"] = certMaps

View File

@@ -1,16 +0,0 @@
package components
import (
"github.com/iwind/TeaGo/actions"
)
type Helper struct {
}
func NewHelper() *Helper {
return &Helper{}
}
func (this *Helper) BeforeAction(action *actions.ActionObject) {
action.Data["teaMenu"] = "servers"
}

View File

@@ -1,118 +0,0 @@
package components
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
)
const (
SettingCodeServerGlobalConfig = "serverGlobalConfig"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "component", "index")
this.SecondMenu("global")
}
func (this *IndexAction) RunGet(params struct{}) {
valueJSONResp, err := this.RPC().SysSettingRPC().ReadSysSetting(this.AdminContext(), &pb.ReadSysSettingRequest{Code: SettingCodeServerGlobalConfig})
if err != nil {
this.ErrorPage(err)
return
}
valueJSON := valueJSONResp.ValueJSON
globalConfig := &serverconfigs.GlobalConfig{}
// 默认值
globalConfig.HTTPAll.DomainAuditingIsOn = false
if len(valueJSON) > 0 {
err = json.Unmarshal(valueJSON, globalConfig)
if err != nil {
this.ErrorPage(err)
return
}
}
this.Data["globalConfig"] = globalConfig
this.Show()
}
func (this *IndexAction) RunPost(params struct {
GlobalConfigJSON []byte
Must *actions.Must
// 不匹配域名相关
AllowMismatchDomains []string
DomainMismatchAction string
DomainMismatchActionPageStatusCode int
DomainMismatchActionPageContentHTML string
// TCP端口设置
TcpAllPortRangeMin int
TcpAllPortRangeMax int
TcpAllDenyPorts []int
DefaultDomain string
}) {
// 创建日志
defer this.CreateLogInfo(codes.Server_LogUpdateGlobalSettings)
if len(params.GlobalConfigJSON) == 0 {
this.Fail("错误的配置信息,请刷新当前页面后重试")
}
globalConfig := &serverconfigs.GlobalConfig{}
err := json.Unmarshal(params.GlobalConfigJSON, globalConfig)
if err != nil {
this.Fail("配置校验失败:" + err.Error())
}
// TCP端口范围
if params.TcpAllPortRangeMin < 1024 {
params.TcpAllPortRangeMin = 1024
}
if params.TcpAllPortRangeMax > 65534 {
params.TcpAllPortRangeMax = 65534
} else if params.TcpAllPortRangeMax < 1024 {
params.TcpAllPortRangeMax = 1024
}
if params.TcpAllPortRangeMin > params.TcpAllPortRangeMax {
params.TcpAllPortRangeMin, params.TcpAllPortRangeMax = params.TcpAllPortRangeMax, params.TcpAllPortRangeMin
}
globalConfig.TCPAll.DenyPorts = params.TcpAllDenyPorts
globalConfig.TCPAll.PortRangeMin = params.TcpAllPortRangeMin
globalConfig.TCPAll.PortRangeMax = params.TcpAllPortRangeMax
// 修改配置
globalConfigJSON, err := json.Marshal(globalConfig)
if err != nil {
this.ErrorPage(err)
return
}
_, err = this.RPC().SysSettingRPC().UpdateSysSetting(this.AdminContext(), &pb.UpdateSysSettingRequest{
Code: SettingCodeServerGlobalConfig,
ValueJSON: globalConfigJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
// 通知更新
_, err = this.RPC().ServerRPC().NotifyServersChange(this.AdminContext(), &pb.NotifyServersChangeRequest{})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -71,7 +71,13 @@ func (this *CreateRulePopupAction) RunPost(params struct {
Field("prefix", params.Prefix).
Require("请选择参数")
rule := &firewallconfigs.HTTPFirewallRule{
if len(params.Value) > 4096 {
this.FailField("value", "对比值内容长度不能超过4096个字符")
return
}
var rule = &firewallconfigs.HTTPFirewallRule{
Id: params.RuleId,
IsOn: true,
}
@@ -81,7 +87,7 @@ func (this *CreateRulePopupAction) RunPost(params struct {
rule.Param = "${" + params.Prefix + "}"
}
paramFilters := []*firewallconfigs.ParamFilter{}
var paramFilters = []*firewallconfigs.ParamFilter{}
if len(params.ParamFiltersJSON) > 0 {
err := json.Unmarshal(params.ParamFiltersJSON, &paramFilters)
if err != nil {

View File

@@ -54,7 +54,7 @@ func (this *CreateSetPopupAction) RunGet(params struct {
}
// 所有可选的动作
actionMaps := []maps.Map{}
var actionMaps = []maps.Map{}
for _, action := range firewallconfigs.AllActions {
actionMaps = append(actionMaps, maps.Map{
"name": action.Name,
@@ -64,6 +64,9 @@ func (this *CreateSetPopupAction) RunGet(params struct {
}
this.Data["actions"] = actionMaps
// 是否为全局
this.Data["isGlobalPolicy"] = firewallPolicy.ServerId == 0
this.Show()
}

View File

@@ -31,8 +31,8 @@ func (this *IndexAction) RunGet(params struct {
this.ErrorPage(err)
return
}
count := countResp.Count
page := this.NewPage(count)
var count = countResp.Count
var page = this.NewPage(count)
listResp, err := this.RPC().HTTPFirewallPolicyRPC().ListEnabledHTTPFirewallPolicies(this.AdminContext(), &pb.ListEnabledHTTPFirewallPoliciesRequest{
NodeClusterId: params.ClusterId,
@@ -44,10 +44,10 @@ func (this *IndexAction) RunGet(params struct {
this.ErrorPage(err)
return
}
policyMaps := []maps.Map{}
var policyMaps = []maps.Map{}
for _, policy := range listResp.HttpFirewallPolicies {
countInbound := 0
countOutbound := 0
var countInbound = 0
var countOutbound = 0
if len(policy.InboundJSON) > 0 {
inboundConfig := &firewallconfigs.HTTPFirewallInboundConfig{}
err = json.Unmarshal(policy.InboundJSON, inboundConfig)
@@ -72,7 +72,7 @@ func (this *IndexAction) RunGet(params struct {
this.ErrorPage(err)
return
}
countClusters := countClustersResp.Count
var countClusters = countClustersResp.Count
// mode
if len(policy.Mode) == 0 {

View File

@@ -95,6 +95,7 @@ func (this *PolicyAction) RunGet(params struct {
"modeInfo": firewallconfigs.FindFirewallMode(firewallPolicy.Mode),
"groups": internalGroups,
"blockOptions": firewallPolicy.BlockOptions,
"pageOptions": firewallPolicy.PageOptions,
"captchaOptions": firewallPolicy.CaptchaOptions,
"useLocalFirewall": firewallPolicy.UseLocalFirewall,
"synFlood": firewallPolicy.SYNFlood,

View File

@@ -34,6 +34,7 @@ func (this *UpdateAction) RunGet(params struct {
return
}
// block options
if firewallPolicy.BlockOptions == nil {
firewallPolicy.BlockOptions = &firewallconfigs.HTTPFirewallBlockAction{
StatusCode: http.StatusForbidden,
@@ -43,6 +44,11 @@ func (this *UpdateAction) RunGet(params struct {
}
}
// page options
if firewallPolicy.PageOptions == nil {
firewallPolicy.PageOptions = firewallconfigs.DefaultHTTPFirewallPageAction()
}
// mode
if len(firewallPolicy.Mode) == 0 {
firewallPolicy.Mode = firewallconfigs.FirewallModeDefend
@@ -71,6 +77,7 @@ func (this *UpdateAction) RunGet(params struct {
"isOn": firewallPolicy.IsOn,
"mode": firewallPolicy.Mode,
"blockOptions": firewallPolicy.BlockOptions,
"pageOptions": firewallPolicy.PageOptions,
"captchaOptions": firewallPolicy.CaptchaOptions,
"useLocalFirewall": firewallPolicy.UseLocalFirewall,
"synFloodConfig": firewallPolicy.SYNFlood,
@@ -107,6 +114,7 @@ func (this *UpdateAction) RunPost(params struct {
Name string
GroupCodes []string
BlockOptionsJSON []byte
PageOptionsJSON []byte
CaptchaOptionsJSON []byte
Description string
IsOn bool
@@ -132,6 +140,19 @@ func (this *UpdateAction) RunPost(params struct {
err := json.Unmarshal(params.BlockOptionsJSON, blockOptions)
if err != nil {
this.Fail("拦截动作参数校验失败:" + err.Error())
return
}
// 校验显示页面选项JSON
var pageOptions = &firewallconfigs.HTTPFirewallPageAction{}
err = json.Unmarshal(params.PageOptionsJSON, pageOptions)
if err != nil {
this.Fail("校验显示页面动作配置失败:" + err.Error())
return
}
if pageOptions.Status < 100 && pageOptions.Status > 999 {
this.Fail("显示页面动作的状态码配置错误:" + types.String(pageOptions.Status))
return
}
// 校验验证码选项JSON
@@ -139,6 +160,24 @@ func (this *UpdateAction) RunPost(params struct {
err = json.Unmarshal(params.CaptchaOptionsJSON, captchaOptions)
if err != nil {
this.Fail("验证码动作参数校验失败:" + err.Error())
return
}
// 检查极验配置
if captchaOptions.CaptchaType == firewallconfigs.CaptchaTypeGeeTest || captchaOptions.GeeTestConfig.IsOn {
if captchaOptions.CaptchaType == firewallconfigs.CaptchaTypeGeeTest && !captchaOptions.GeeTestConfig.IsOn {
this.Fail("人机识别动作配置的默认验证方式为极验-行为验,所以需要选择允许用户使用极验")
return
}
if len(captchaOptions.GeeTestConfig.CaptchaId) == 0 {
this.FailField("geetestCaptchaId", "请输入极验-验证ID")
return
}
if len(captchaOptions.GeeTestConfig.CaptchaKey) == 0 {
this.FailField("geetestCaptchaKey", "请输入极验-验证Key")
return
}
}
// 最大内容尺寸
@@ -153,6 +192,7 @@ func (this *UpdateAction) RunPost(params struct {
Description: params.Description,
FirewallGroupCodes: params.GroupCodes,
BlockOptionsJSON: params.BlockOptionsJSON,
PageOptionsJSON: params.PageOptionsJSON,
CaptchaOptionsJSON: params.CaptchaOptionsJSON,
Mode: params.Mode,
UseLocalFirewall: params.UseLocalFirewall,

View File

@@ -0,0 +1,28 @@
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package servers
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
// DeleteServersAction 删除一组网站
type DeleteServersAction struct {
actionutils.ParentAction
}
func (this *DeleteServersAction) RunPost(params struct {
ServerIds []int64
}) {
defer this.CreateLogInfo(codes.Server_LogDeleteServers)
_, err := this.RPC().ServerRPC().DeleteServers(this.AdminContext(), &pb.DeleteServersRequest{ServerIds: params.ServerIds})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -53,12 +53,16 @@ func (this *IndexAction) RunPost(params struct {
defer this.CreateLogInfo(codes.ServerCache_LogUpdateCacheSettings, params.WebId)
// 校验配置
cacheConfig := &serverconfigs.HTTPCacheConfig{}
var cacheConfig = &serverconfigs.HTTPCacheConfig{}
err := json.Unmarshal(params.CacheJSON, cacheConfig)
if err != nil {
this.ErrorPage(err)
return
}
// 分组不支持主域名
cacheConfig.Key = nil
err = cacheConfig.Init()
if err != nil {
this.Fail("检查配置失败:" + err.Error())

View File

@@ -111,6 +111,7 @@ func (this *SettingAction) RunPost(params struct {
FollowRedirects: reverseProxyConfig.FollowRedirects,
ProxyProtocolJSON: proxyProtocolJSON,
Retry50X: reverseProxyConfig.Retry50X,
Retry40X: reverseProxyConfig.Retry40X,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -111,6 +111,7 @@ func (this *SettingAction) RunPost(params struct {
FollowRedirects: reverseProxyConfig.FollowRedirects,
ProxyProtocolJSON: proxyProtocolJSON,
Retry50X: reverseProxyConfig.Retry50X,
Retry40X: reverseProxyConfig.Retry40X,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -19,6 +19,7 @@ func init() {
GetPost("/create", new(CreateAction)).
GetPost("/update", new(UpdateAction)).
Post("/nearby", new(NearbyAction)).
Post("/deleteServers", new(DeleteServersAction)).
//
GetPost("/addPortPopup", new(AddPortPopupAction)).

View File

@@ -0,0 +1,82 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package iplists
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/types"
"strings"
)
type DeleteCountAction struct {
actionutils.ParentAction
}
func (this *DeleteCountAction) RunPost(params struct {
Ip string
Keyword string
GlobalOnly bool
Unread bool
EventLevel string
ListType string
Count int64
}) {
var count = params.Count
if count <= 0 || count >= 100_000 {
this.Fail("'count' 参数错误")
return
}
itemIdsResp, err := this.RPC().IPItemRPC().ListAllIPItemIds(this.AdminContext(), &pb.ListAllIPItemIdsRequest{
Keyword: params.Keyword,
GlobalOnly: params.GlobalOnly,
Unread: params.Unread,
EventLevel: params.EventLevel,
ListType: params.ListType,
Ip: params.Ip,
Offset: 0,
Size: count,
})
if err != nil {
this.ErrorPage(err)
return
}
var itemIds = itemIdsResp.IpItemIds
if len(itemIds) == 0 {
this.Success()
}
// 记录日志
defer func() {
var itemIdStrings = []string{}
for _, itemId := range itemIds {
itemIdStrings = append(itemIdStrings, types.String(itemId))
}
var itemIdsDescription = ""
if len(itemIdStrings) > 10 {
itemIdsDescription = strings.Join(itemIdStrings[:10], ", ") + " ..."
} else {
itemIdsDescription = strings.Join(itemIdStrings, ", ")
}
this.CreateLogInfo(codes.IPList_LogDeleteIPBatch, itemIdsDescription)
}()
_, err = this.RPC().IPItemRPC().DeleteIPItems(this.AdminContext(), &pb.DeleteIPItemsRequest{IpItemIds: itemIds})
if err != nil {
this.ErrorPage(err)
return
}
// 通知左侧菜单Badge更新
helpers.NotifyIPItemsCountChanges()
this.Success()
}

View File

@@ -63,6 +63,7 @@ func (this *IndexAction) RunGet(params struct {
}
var count = countResp.Count
var page = this.NewPage(count)
this.Data["totalItems"] = count
this.Data["page"] = page.AsHTML()
itemsResp, err := this.RPC().IPItemRPC().ListAllEnabledIPItems(this.AdminContext(), &pb.ListAllEnabledIPItemsRequest{

View File

@@ -22,6 +22,7 @@ func init() {
Get("/exportData", new(ExportDataAction)).
Post("/delete", new(DeleteAction)).
Post("/deleteItems", new(DeleteItemsAction)).
Post("/deleteCount", new(DeleteCountAction)).
GetPost("/test", new(TestAction)).
GetPost("/update", new(UpdateAction)).
Get("/items", new(ItemsAction)).

View File

@@ -2,6 +2,7 @@ package log
import (
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
@@ -61,6 +62,27 @@ func (this *HistoryAction) RunGet(params struct {
return
}
// 检查当前网站有无开启访问日志
this.Data["serverAccessLogIsOn"] = true
groupResp, err := this.RPC().ServerGroupRPC().FindEnabledServerGroupConfigInfo(this.AdminContext(), &pb.FindEnabledServerGroupConfigInfoRequest{
ServerId: params.ServerId,
})
if err != nil {
this.ErrorPage(err)
return
}
if !groupResp.HasAccessLogConfig {
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithServerId(this.AdminContext(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
if webConfig != nil && webConfig.AccessLogRef != nil && !webConfig.AccessLogRef.IsOn {
this.Data["serverAccessLogIsOn"] = false
}
}
var day = params.Day
var ipList = []string{}
var wafMaps = []maps.Map{}

View File

@@ -2,6 +2,7 @@ package log
import (
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/lists"
@@ -41,8 +42,29 @@ func (this *IndexAction) RunGet(params struct {
return
}
// 检查当前网站有无开启访问日志
this.Data["serverAccessLogIsOn"] = true
groupResp, err := this.RPC().ServerGroupRPC().FindEnabledServerGroupConfigInfo(this.AdminContext(), &pb.FindEnabledServerGroupConfigInfoRequest{
ServerId: params.ServerId,
})
if err != nil {
this.ErrorPage(err)
return
}
if !groupResp.HasAccessLogConfig {
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithServerId(this.AdminContext(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
if webConfig != nil && webConfig.AccessLogRef != nil && !webConfig.AccessLogRef.IsOn {
this.Data["serverAccessLogIsOn"] = false
}
}
// 记录最近使用
_, err := this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
_, err = this.RPC().LatestItemRPC().IncreaseLatestItem(this.AdminContext(), &pb.IncreaseLatestItemRequest{
ItemType: "server",
ItemId: params.ServerId,
})

View File

@@ -2,6 +2,7 @@ package log
import (
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
@@ -55,6 +56,27 @@ func (this *TodayAction) RunGet(params struct {
return
}
// 检查当前网站有无开启访问日志
this.Data["serverAccessLogIsOn"] = true
groupResp, err := this.RPC().ServerGroupRPC().FindEnabledServerGroupConfigInfo(this.AdminContext(), &pb.FindEnabledServerGroupConfigInfoRequest{
ServerId: params.ServerId,
})
if err != nil {
this.ErrorPage(err)
return
}
if !groupResp.HasAccessLogConfig {
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithServerId(this.AdminContext(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
if webConfig != nil && webConfig.AccessLogRef != nil && !webConfig.AccessLogRef.IsOn {
this.Data["serverAccessLogIsOn"] = false
}
}
resp, err := this.RPC().HTTPAccessLogRPC().ListHTTPAccessLogs(this.AdminContext(), &pb.ListHTTPAccessLogsRequest{
Partition: params.Partition,
RequestId: params.RequestId,

View File

@@ -21,7 +21,7 @@ func (this *IndexAction) Init() {
func (this *IndexAction) RunGet(params struct {
ServerId int64
}) {
// 服务分组设置
// 网站分组设置
groupResp, err := this.RPC().ServerGroupRPC().FindEnabledServerGroupConfigInfo(this.AdminContext(), &pb.FindEnabledServerGroupConfigInfoRequest{
ServerId: params.ServerId,
})

View File

@@ -4,6 +4,7 @@ import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -12,6 +13,7 @@ import (
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"strings"
)
type IndexAction struct {
@@ -92,6 +94,48 @@ func (this *IndexAction) RunPost(params struct {
return
}
// 检查Key
if cacheConfig.Key != nil && cacheConfig.Key.IsOn {
if cacheConfig.Key.Scheme != "http" && cacheConfig.Key.Scheme != "https" {
this.Fail("缓存主域名协议只能是http或者https")
return
}
if len(cacheConfig.Key.Host) == 0 {
this.Fail("请输入缓存主域名")
return
}
cacheConfig.Key.Host = strings.ToLower(strings.TrimSuffix(cacheConfig.Key.Host, "/"))
if !domainutils.ValidateDomainFormat(cacheConfig.Key.Host) {
this.Fail("请输入正确的缓存主域名")
return
}
// 检查域名所属
serverIdResp, err := this.RPC().HTTPWebRPC().FindServerIdWithHTTPWebId(this.AdminContext(), &pb.FindServerIdWithHTTPWebIdRequest{HttpWebId: params.WebId})
if err != nil {
this.ErrorPage(err)
return
}
var serverId = serverIdResp.ServerId
if serverId <= 0 {
this.Fail("找不到要操作的网站")
return
}
existServerNameResp, err := this.RPC().ServerRPC().CheckServerNameInServer(this.AdminContext(), &pb.CheckServerNameInServerRequest{
ServerId: serverId,
ServerName: cacheConfig.Key.Host,
})
if err != nil {
this.ErrorPage(err)
return
}
if !existServerNameResp.Exists {
this.Fail("域名 '" + cacheConfig.Key.Host + "' 在当前网站中并未绑定,不能作为缓存主域名")
return
}
}
err = cacheConfig.Init()
if err != nil {
this.Fail("检查配置失败:" + err.Error())

View File

@@ -1,6 +1,7 @@
package settings
import (
"encoding/json"
"errors"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
@@ -32,7 +33,7 @@ func (this *IndexAction) RunGet(params struct {
this.ErrorPage(err)
return
}
clusterMaps := []maps.Map{}
var clusterMaps = []maps.Map{}
for _, cluster := range resp.NodeClusters {
clusterMaps = append(clusterMaps, maps.Map{
"id": cluster.Id,
@@ -50,7 +51,7 @@ func (this *IndexAction) RunGet(params struct {
this.ErrorPage(err)
return
}
server := serverResp.Server
var server = serverResp.Server
if server == nil {
this.NotFound("server", params.ServerId)
return
@@ -71,7 +72,7 @@ func (this *IndexAction) RunGet(params struct {
this.initUserPlan(server)
// 集群
clusterId := int64(0)
var clusterId = int64(0)
this.Data["clusterName"] = ""
if server.NodeCluster != nil {
clusterId = server.NodeCluster.Id
@@ -79,7 +80,7 @@ func (this *IndexAction) RunGet(params struct {
}
// 分组
groupMaps := []maps.Map{}
var groupMaps = []maps.Map{}
if len(server.ServerGroups) > 0 {
for _, group := range server.ServerGroups {
groupMaps = append(groupMaps, maps.Map{
@@ -89,23 +90,36 @@ func (this *IndexAction) RunGet(params struct {
}
}
this.Data["server"] = maps.Map{
"id": server.Id,
"clusterId": clusterId,
"type": server.Type,
"name": server.Name,
"description": server.Description,
"isOn": server.IsOn,
"groups": groupMaps,
// 域名和限流状态
var trafficLimitStatus *serverconfigs.TrafficLimitStatus
if len(server.Config) > 0 {
var serverConfig = &serverconfigs.ServerConfig{}
err = json.Unmarshal(server.Config, serverConfig)
if err == nil {
if serverConfig.TrafficLimitStatus != nil && serverConfig.TrafficLimitStatus.IsValid() {
trafficLimitStatus = serverConfig.TrafficLimitStatus
}
}
}
serverType := serverconfigs.FindServerType(server.Type)
this.Data["server"] = maps.Map{
"id": server.Id,
"clusterId": clusterId,
"type": server.Type,
"name": server.Name,
"description": server.Description,
"isOn": server.IsOn,
"groups": groupMaps,
"trafficLimitStatus": trafficLimitStatus,
}
var serverType = serverconfigs.FindServerType(server.Type)
if serverType == nil {
this.ErrorPage(errors.New("invalid server type '" + server.Type + "'"))
return
}
typeName := serverType.GetString("name")
var typeName = serverType.GetString("name")
this.Data["typeName"] = typeName
// 记录最近使用

View File

@@ -4,6 +4,7 @@ import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -11,6 +12,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"strings"
)
type IndexAction struct {
@@ -71,12 +73,55 @@ func (this *IndexAction) RunPost(params struct {
defer this.CreateLogInfo(codes.ServerCache_LogUpdateCacheSettings, params.WebId)
// 校验配置
cacheConfig := &serverconfigs.HTTPCacheConfig{}
var cacheConfig = &serverconfigs.HTTPCacheConfig{}
err := json.Unmarshal(params.CacheJSON, cacheConfig)
if err != nil {
this.ErrorPage(err)
return
}
// 检查Key
if cacheConfig.Key != nil && cacheConfig.Key.IsOn {
if cacheConfig.Key.Scheme != "http" && cacheConfig.Key.Scheme != "https" {
this.Fail("缓存主域名协议只能是http或者https")
return
}
if len(cacheConfig.Key.Host) == 0 {
this.Fail("请输入缓存主域名")
return
}
cacheConfig.Key.Host = strings.ToLower(strings.TrimSuffix(cacheConfig.Key.Host, "/"))
if !domainutils.ValidateDomainFormat(cacheConfig.Key.Host) {
this.Fail("请输入正确的缓存主域名")
return
}
// 检查域名所属
serverIdResp, err := this.RPC().HTTPWebRPC().FindServerIdWithHTTPWebId(this.AdminContext(), &pb.FindServerIdWithHTTPWebIdRequest{HttpWebId: params.WebId})
if err != nil {
this.ErrorPage(err)
return
}
var serverId = serverIdResp.ServerId
if serverId <= 0 {
this.Fail("找不到要操作的网站")
return
}
existServerNameResp, err := this.RPC().ServerRPC().CheckServerNameInServer(this.AdminContext(), &pb.CheckServerNameInServerRequest{
ServerId: serverId,
ServerName: cacheConfig.Key.Host,
})
if err != nil {
this.ErrorPage(err)
return
}
if !existServerNameResp.Exists {
this.Fail("域名 '" + cacheConfig.Key.Host + "' 在当前网站中并未绑定,不能作为缓存主域名")
return
}
}
err = cacheConfig.Init()
if err != nil {
this.Fail("检查配置失败:" + err.Error())

View File

@@ -130,8 +130,6 @@ func (this *LocationHelper) createMenus(serverIdString string, locationIdString
"isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.Compression != nil && locationConfig.Web.Compression.IsPrior,
})
menuItems = this.filterMenuItems3(locationConfig, menuItems, serverIdString, locationIdString, secondMenuItem, actionPtr)
menuItems = append(menuItems, maps.Map{
"name": this.Lang(actionPtr, codes.Server_MenuSettingPages),
"url": "/servers/server/settings/locations/pages?serverId=" + serverIdString + "&locationId=" + locationIdString,
@@ -156,6 +154,9 @@ func (this *LocationHelper) createMenus(serverIdString string, locationIdString
"isActive": secondMenuItem == "webp",
"isOn": locationConfig != nil && locationConfig.Web != nil && locationConfig.Web.WebP != nil && locationConfig.Web.WebP.IsPrior,
})
menuItems = this.filterMenuItems3(locationConfig, menuItems, serverIdString, locationIdString, secondMenuItem, actionPtr)
menuItems = append(menuItems, maps.Map{
"name": this.Lang(actionPtr, codes.Server_MenuSettingStat),
"url": "/servers/server/settings/locations/stat?serverId=" + serverIdString + "&locationId=" + locationIdString,

View File

@@ -102,6 +102,7 @@ func (this *SettingAction) RunPost(params struct {
FollowRedirects: reverseProxyConfig.FollowRedirects,
ProxyProtocolJSON: proxyProtocolJSON,
Retry50X: reverseProxyConfig.Retry50X,
Retry40X: reverseProxyConfig.Retry40X,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -1,6 +1,7 @@
package waf
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
@@ -37,12 +38,23 @@ func (this *IndexAction) RunGet(params struct {
return
}
if firewallPolicy != nil {
// captcha action
var captchaOptions = firewallconfigs.DefaultHTTPFirewallCaptchaAction()
if len(firewallPolicy.CaptchaOptionsJSON) > 0 {
err = json.Unmarshal(firewallPolicy.CaptchaOptionsJSON, captchaOptions)
if err != nil {
this.ErrorPage(err)
return
}
}
this.Data["firewallPolicy"] = maps.Map{
"id": firewallPolicy.Id,
"name": firewallPolicy.Name,
"isOn": firewallPolicy.IsOn,
"mode": firewallPolicy.Mode,
"modeInfo": firewallconfigs.FindFirewallMode(firewallPolicy.Mode),
"id": firewallPolicy.Id,
"name": firewallPolicy.Name,
"isOn": firewallPolicy.IsOn,
"mode": firewallPolicy.Mode,
"modeInfo": firewallconfigs.FindFirewallMode(firewallPolicy.Mode),
"captchaOptions": captchaOptions,
}
} else {
this.Data["firewallPolicy"] = nil

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