From 6f249d20b05589a433a662020711b1dc20063011 Mon Sep 17 00:00:00 2001 From: coward Date: Thu, 13 Jun 2024 14:34:03 +0800 Subject: [PATCH] =?UTF-8?q?:art:=E6=96=B0=E5=A2=9E=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E7=A6=BB=E7=BA=BF=E9=80=9A=E7=9F=A5=E9=80=89=E9=A1=B9?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E4=BB=A5=E5=8F=8A=E7=9B=91=E5=90=AC=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- http/param/client.go | 1 + model/entity/wireguard.go | 1 + model/vo/client.go | 1 + queues/consumer.go | 3 + queues/offline_monitoring.go | 65 +++++++++++++++++++ repository/client.go | 6 +- web-src/.vscode/extensions.json | 18 ----- web-src/.vscode/settings.json | 31 --------- web-src/.vscode/vue3.0.code-snippets | 22 ------- web-src/.vscode/vue3.2.code-snippets | 17 ----- web-src/.vscode/vue3.3.code-snippets | 20 ------ web-src/public/platform-config.json | 2 +- web-src/src/api/clients.ts | 5 ++ web-src/src/api/user.ts | 6 ++ .../components/lay-navbar/component/user.vue | 19 ++++++ web-src/src/utils/http/index.ts | 8 --- web-src/src/views/server/clients.vue | 39 +++++++++-- web-src/src/views/server/component/detail.vue | 23 +++++-- 18 files changed, 155 insertions(+), 132 deletions(-) create mode 100644 queues/offline_monitoring.go delete mode 100644 web-src/.vscode/extensions.json delete mode 100644 web-src/.vscode/settings.json delete mode 100644 web-src/.vscode/vue3.0.code-snippets delete mode 100644 web-src/.vscode/vue3.2.code-snippets delete mode 100644 web-src/.vscode/vue3.3.code-snippets diff --git a/http/param/client.go b/http/param/client.go index 8a58472..69034fd 100644 --- a/http/param/client.go +++ b/http/param/client.go @@ -35,6 +35,7 @@ type SaveClient struct { EnabledAfterCreation *int `json:"enableAfterCreation" form:"enableAfterCreation" binding:"required,oneof=1 0"` Keys *template_data.Keys `json:"keys" form:"keys" binding:"omitempty"` Enabled *int `json:"enabled" form:"enabled" binding:"required,oneof=1 0"` + OfflineMonitoring *int `json:"offlineMonitoring" form:"offlineMonitoring" binding:"required,oneof=1 0"` } // ControlServer diff --git a/model/entity/wireguard.go b/model/entity/wireguard.go index 206993b..4b7b5ad 100644 --- a/model/entity/wireguard.go +++ b/model/entity/wireguard.go @@ -35,6 +35,7 @@ type Client struct { Keys string `json:"keys" gorm:"type:text;default null;comment:'公钥和密钥的json串'"` UserId string `json:"userId" gorm:"type:char(36);not null;comment:'创建人id'"` Enabled *int `json:"enabled" gorm:"type:tinyint(1);default 1;comment:'状态(0 - 禁用 | 1 - 正常)'"` + OfflineMonitoring *int `json:"offlineMonitoring" gorm:"tinyint(1);default 0;comment:'是否启用离线监听(0 - 禁用 | 1 - 启用)"` User *User `json:"user" gorm:"foreignKey:UserId"` Server *Server `json:"server" gorm:"foreignKey:ServerId"` } diff --git a/model/vo/client.go b/model/vo/client.go index 5021e5d..7216bcf 100644 --- a/model/vo/client.go +++ b/model/vo/client.go @@ -23,6 +23,7 @@ type Client struct { Keys template_data.Keys `json:"keys" gorm:"-"` CreateUser string `json:"createUser"` Enabled bool `json:"enabled"` + OfflineMonitoring int `json:"offlineMonitoring"` CreatedAt entity.JsonTime `json:"createdAt"` UpdatedAt entity.JsonTime `json:"updatedAt"` } diff --git a/queues/consumer.go b/queues/consumer.go index 28e88eb..fda03e6 100644 --- a/queues/consumer.go +++ b/queues/consumer.go @@ -3,5 +3,8 @@ package queues // StartConsumer // @description: 启动消费者 func StartConsumer() { + // 同步配置文件 go asyncWireguardConfigFile() + // 离线监听 + go offlineMonitoring() } diff --git a/queues/offline_monitoring.go b/queues/offline_monitoring.go new file mode 100644 index 0000000..cc81d4f --- /dev/null +++ b/queues/offline_monitoring.go @@ -0,0 +1,65 @@ +package queues + +import ( + "fmt" + "gitee.ltd/lxh/logger/log" + "strings" + "time" + "wireguard-dashboard/client" + "wireguard-dashboard/repository" + "wireguard-dashboard/utils" +) + +// offlineMonitoring +// @description: 离线监听任务 +func offlineMonitoring() { + for { + devices, err := client.WireguardClient.Devices() + if err != nil { + time.Sleep(5 * time.Minute) // 休眠五分钟再执行 + offlineMonitoring() + continue + } + + // 遍历客户端数据,并渲染数据信息 + for _, d := range devices { + for _, p := range d.Peers { + clientInfo, err := repository.Client().GetByPublicKey(p.PublicKey.String()) + if err != nil { + continue + } + + // 没有启用离线监听时,即使客户端已经离线则也不执行 + if *clientInfo.OfflineMonitoring != 1 || clientInfo.Email == "" { + continue + } + + var ipAllocation string + for _, iaip := range p.AllowedIPs { + ipAllocation += iaip.String() + "," + } + ipAllocation = strings.TrimRight(ipAllocation, ",") + isOnline := time.Since(p.LastHandshakeTime).Minutes() < 3 + + // 未离线 + if !isOnline { + continue + } + + content := fmt.Sprintf("客户端:%s\r\n", clientInfo.Name) + content += fmt.Sprintf("客户端IP:%s\r\n", ipAllocation) + content += fmt.Sprintf("端点IP:%s", p.Endpoint.String()) + content += fmt.Sprintf("最后握手时间:%s\r\n", p.LastHandshakeTime.Format("2006-01-02 15:04:05")) + content += fmt.Sprintf("离线时间:%s\r\n", time.Now().Format("2006-01-02 15:04:05")) + + // 离线并且配置了邮箱,准备发送邮件 + err = utils.Mail().SendMail(clientInfo.Email, fmt.Sprintf("客户端离线通知"), content, "") + if err != nil { + log.Errorf("发送离线通知邮件失败: %v", err.Error()) + continue + } + + } + } + } +} diff --git a/repository/client.go b/repository/client.go index 664fb8b..b2cf758 100644 --- a/repository/client.go +++ b/repository/client.go @@ -38,7 +38,7 @@ func (r clientRepo) List(p param.ClientList) (data []vo.Client, total int64, err Scopes(utils.Page(p.Current, p.Size)). Joins("LEFT JOIN t_user as tu ON twc.user_id = tu.id"). Select("twc.id", "twc.created_at", "twc.updated_at", "twc.name", "twc.email", "twc.subnet_range", "twc.ip_allocation as ip_allocation_str", "twc.allowed_ips as allowed_ips_str", - "twc.extra_allowed_ips as extra_allowed_ips_str", "twc.endpoint", "twc.use_server_dns", "twc.enable_after_creation", "twc.enabled", "twc.keys as keys_str", "tu.name as create_user") + "twc.extra_allowed_ips as extra_allowed_ips_str", "twc.endpoint", "twc.use_server_dns", "twc.enable_after_creation", "twc.enabled", "twc.keys as keys_str", "tu.name as create_user", "twc.offline_monitoring") if p.Name != "" { sel.Where("twc.name LIKE ?", "%"+p.Name+"%") @@ -104,6 +104,7 @@ func (r clientRepo) Save(p param.SaveClient, adminId string) (client *entity.Cli EnableAfterCreation: p.EnabledAfterCreation, UserId: adminId, Enabled: p.Enabled, + OfflineMonitoring: p.OfflineMonitoring, } // id不为空,更新信息 @@ -113,7 +114,7 @@ func (r clientRepo) Save(p param.SaveClient, adminId string) (client *entity.Cli if err = r.Model(&entity.Client{}). Where("id = ?", p.Id).Select("name", "email", "subnet_range", "ip_allocation", "allowed_ips", "extra_allowed_ips", "endpoint", "use_server_dns", "enable_after_creation", - "user_id", "enabled"). + "user_id", "enabled", "offline_monitoring"). Updates(ent).Error; err != nil { return } @@ -186,6 +187,7 @@ func (r clientRepo) Save(p param.SaveClient, adminId string) (client *entity.Cli Keys: string(keysStr), UserId: adminId, Enabled: p.Enabled, + OfflineMonitoring: p.OfflineMonitoring, } err = r.Model(&entity.Client{}).Create(ent).Error diff --git a/web-src/.vscode/extensions.json b/web-src/.vscode/extensions.json deleted file mode 100644 index c1a5fbc..0000000 --- a/web-src/.vscode/extensions.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "recommendations": [ - "christian-kohler.path-intellisense", - "vscode-icons-team.vscode-icons", - "davidanson.vscode-markdownlint", - "ms-azuretools.vscode-docker", - "stylelint.vscode-stylelint", - "bradlc.vscode-tailwindcss", - "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode", - "redhat.vscode-yaml", - "csstools.postcss", - "mikestead.dotenv", - "eamodio.gitlens", - "antfu.iconify", - "Vue.volar" - ] -} diff --git a/web-src/.vscode/settings.json b/web-src/.vscode/settings.json deleted file mode 100644 index 9fc6a43..0000000 --- a/web-src/.vscode/settings.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "editor.formatOnType": true, - "editor.formatOnSave": true, - "[vue]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "editor.tabSize": 2, - "editor.formatOnPaste": true, - "editor.guides.bracketPairs": "active", - "files.autoSave": "afterDelay", - "git.confirmSync": false, - "workbench.startupEditor": "newUntitledFile", - "editor.suggestSelection": "first", - "editor.acceptSuggestionOnCommitCharacter": false, - "css.lint.propertyIgnoredDueToDisplay": "ignore", - "editor.quickSuggestions": { - "other": true, - "comments": true, - "strings": true - }, - "files.associations": { - "editor.snippetSuggestions": "top" - }, - "[css]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit" - }, - "iconify.excludes": ["el"] -} diff --git a/web-src/.vscode/vue3.0.code-snippets b/web-src/.vscode/vue3.0.code-snippets deleted file mode 100644 index bb43589..0000000 --- a/web-src/.vscode/vue3.0.code-snippets +++ /dev/null @@ -1,22 +0,0 @@ -{ - "Vue3.0快速生成模板": { - "scope": "vue", - "prefix": "Vue3.0", - "body": [ - "\n", - "\n", - "", - "$2" - ], - "description": "Vue3.0" - } -} diff --git a/web-src/.vscode/vue3.2.code-snippets b/web-src/.vscode/vue3.2.code-snippets deleted file mode 100644 index 2cebb46..0000000 --- a/web-src/.vscode/vue3.2.code-snippets +++ /dev/null @@ -1,17 +0,0 @@ -{ - "Vue3.2+快速生成模板": { - "scope": "vue", - "prefix": "Vue3.2+", - "body": [ - "\n", - "\n", - "", - "$2" - ], - "description": "Vue3.2+" - } -} diff --git a/web-src/.vscode/vue3.3.code-snippets b/web-src/.vscode/vue3.3.code-snippets deleted file mode 100644 index dc7a106..0000000 --- a/web-src/.vscode/vue3.3.code-snippets +++ /dev/null @@ -1,20 +0,0 @@ -{ - "Vue3.3+defineOptions快速生成模板": { - "scope": "vue", - "prefix": "Vue3.3+", - "body": [ - "\n", - "\n", - "", - "$2" - ], - "description": "Vue3.3+defineOptions快速生成模板" - } -} diff --git a/web-src/public/platform-config.json b/web-src/public/platform-config.json index 0f670d8..62da303 100644 --- a/web-src/public/platform-config.json +++ b/web-src/public/platform-config.json @@ -1,6 +1,6 @@ { "Version": "5.5.0", - "Title": "WG-Dashboard", + "Title": "wg-dashboard", "FixedHeader": true, "HiddenSideBar": false, "MultiTagsCache": false, diff --git a/web-src/src/api/clients.ts b/web-src/src/api/clients.ts index ebf771e..b0eaca8 100644 --- a/web-src/src/api/clients.ts +++ b/web-src/src/api/clients.ts @@ -47,3 +47,8 @@ export const getClientConnects = () => { export const offlineClient = (id: string) => { return http.request("post", baseUri("/client/offline/" + id)); }; + +// 发送邮件 +export const sendMail = (id: string) => { + return http.request("post", baseUri("/client/to-email/" + id)); +}; diff --git a/web-src/src/api/user.ts b/web-src/src/api/user.ts index 0f54116..285cfca 100644 --- a/web-src/src/api/user.ts +++ b/web-src/src/api/user.ts @@ -1,5 +1,6 @@ import { http } from "@/utils/http"; import { baseUri } from "@/api/utils"; +import { data } from "autoprefixer"; // 获取当前登陆用户信息 export const getUser = () => { @@ -30,3 +31,8 @@ export const deleteUser = (userId: string) => { export const changePassword = (data?: object) => { return http.request("post", baseUri("/user/change-password"), { data }); }; + +// 生成头像 +export const generateAvatar = () => { + return http.request("post", baseUri("/user/change-avatar")); +}; diff --git a/web-src/src/layout/components/lay-navbar/component/user.vue b/web-src/src/layout/components/lay-navbar/component/user.vue index 7920342..1dd3dea 100644 --- a/web-src/src/layout/components/lay-navbar/component/user.vue +++ b/web-src/src/layout/components/lay-navbar/component/user.vue @@ -1,6 +1,7 @@