Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
29c1c791d4 | |||
40019568f0 | |||
db065073e2 | |||
befaa17426 | |||
fae96eccf5 | |||
4a0ec7bdc9 | |||
331849522f |
39
README.md
@@ -34,14 +34,6 @@ file:
|
|||||||
accessSecret: # oss必填
|
accessSecret: # oss必填
|
||||||
bucketName: # oss必填
|
bucketName: # oss必填
|
||||||
|
|
||||||
# 邮件设置
|
|
||||||
mail:
|
|
||||||
host:
|
|
||||||
port:
|
|
||||||
user:
|
|
||||||
password:
|
|
||||||
skipTls:
|
|
||||||
|
|
||||||
# 一些系统配置
|
# 一些系统配置
|
||||||
wireguard:
|
wireguard:
|
||||||
restartMode: DELAY
|
restartMode: DELAY
|
||||||
@@ -78,14 +70,25 @@ services:
|
|||||||
账户: admin
|
账户: admin
|
||||||
密码: admin123
|
密码: admin123
|
||||||
```
|
```
|
||||||
|
## 配置示例
|
||||||
|
```text
|
||||||
|
1. 邮箱配置如下:
|
||||||
|
code: EMAIL_SMTP
|
||||||
|
配置项:
|
||||||
|
1. host: "xxxx.xxx"
|
||||||
|
2. port: "123"
|
||||||
|
3. user: "haha"
|
||||||
|
4. password: "haha123"
|
||||||
|
5. skipTls: "false"
|
||||||
|
```
|
||||||
|
|
||||||
## 示例
|
## 页面展示
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
@@ -7,6 +7,5 @@ type config struct {
|
|||||||
Database *database `yaml:"database"`
|
Database *database `yaml:"database"`
|
||||||
Cache *cache `yaml:"redis"`
|
Cache *cache `yaml:"redis"`
|
||||||
File *file `yaml:"file"`
|
File *file `yaml:"file"`
|
||||||
Mail *mail `yaml:"email"`
|
|
||||||
Wireguard *wireguard `yaml:"wireguard"`
|
Wireguard *wireguard `yaml:"wireguard"`
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
type mail struct {
|
|
||||||
Host string `json:"host" yaml:"host"`
|
|
||||||
Port int `json:"port" yaml:"port"`
|
|
||||||
User string `json:"user" yaml:"user"`
|
|
||||||
Password string `json:"password" yaml:"password"`
|
|
||||||
SkipTls bool `json:"skipTls" yaml:"skipTls"`
|
|
||||||
}
|
|
Before Width: | Height: | Size: 209 KiB After Width: | Height: | Size: 209 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
@@ -243,7 +243,14 @@ func (ClientApi) Download(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = utils.Mail().SendMail(data.Email, fmt.Sprintf("客户端: %s", data.Name), "请查收附件", outPath)
|
// 获取邮箱配置
|
||||||
|
emailConf, err := service.Setting().GetByCode("EMAIL_SMTP")
|
||||||
|
if err != nil {
|
||||||
|
response.R(c).FailedWithError("获取邮箱配置失败,请先到设置页面的【其他】里面添加code为【EMAIL_SMTP】的具体配置")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = utils.Mail(emailConf).SendMail(data.Email, fmt.Sprintf("客户端: %s", data.Name), "请查收附件", outPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.R(c).FailedWithError("发送邮件失败")
|
response.R(c).FailedWithError("发送邮件失败")
|
||||||
return
|
return
|
||||||
|
@@ -14,8 +14,11 @@ type Export struct {
|
|||||||
Global *Global `json:"global" label:"全局配置" binding:"required"`
|
Global *Global `json:"global" label:"全局配置" binding:"required"`
|
||||||
Server *Server `json:"server" label:"服务端配置" binding:"required"`
|
Server *Server `json:"server" label:"服务端配置" binding:"required"`
|
||||||
Clients []Client `json:"clients" label:"客户端" binding:"omitempty"`
|
Clients []Client `json:"clients" label:"客户端" binding:"omitempty"`
|
||||||
|
Other []Other `json:"other" label:"其他" binding:"omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Global
|
||||||
|
// @description: 全局配置
|
||||||
type Global struct {
|
type Global struct {
|
||||||
MTU int `json:"MTU" label:"MTU" binding:"required"`
|
MTU int `json:"MTU" label:"MTU" binding:"required"`
|
||||||
ConfigFilePath string `json:"configFilePath" label:"配置文件路径" binding:"required"`
|
ConfigFilePath string `json:"configFilePath" label:"配置文件路径" binding:"required"`
|
||||||
@@ -26,6 +29,8 @@ type Global struct {
|
|||||||
Table string `json:"table" label:"table" binding:"omitempty"`
|
Table string `json:"table" label:"table" binding:"omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Server
|
||||||
|
// @description: 服务端信息
|
||||||
type Server struct {
|
type Server struct {
|
||||||
IpScope []string `json:"ipScope" label:"ipScope" binding:"min=1,dive,required"`
|
IpScope []string `json:"ipScope" label:"ipScope" binding:"min=1,dive,required"`
|
||||||
ListenPort int `json:"listenPort" label:"listenPort" binding:"required"`
|
ListenPort int `json:"listenPort" label:"listenPort" binding:"required"`
|
||||||
@@ -35,6 +40,8 @@ type Server struct {
|
|||||||
PostDownScript string `json:"postDownScript" label:"postDownScript" binding:"omitempty"`
|
PostDownScript string `json:"postDownScript" label:"postDownScript" binding:"omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Client
|
||||||
|
// @description: 客户端信息
|
||||||
type Client struct {
|
type Client struct {
|
||||||
Name string `json:"name" label:"name" binding:"required"`
|
Name string `json:"name" label:"name" binding:"required"`
|
||||||
Email string `json:"email" label:"email" binding:"omitempty"`
|
Email string `json:"email" label:"email" binding:"omitempty"`
|
||||||
@@ -52,3 +59,11 @@ type Client struct {
|
|||||||
Enabled *constant.Status `json:"enabled" label:"enabled" binding:"required"`
|
Enabled *constant.Status `json:"enabled" label:"enabled" binding:"required"`
|
||||||
OfflineMonitoring *constant.Status `json:"offlineMonitoring" label:"offlineMonitoring" binding:"required"`
|
OfflineMonitoring *constant.Status `json:"offlineMonitoring" label:"offlineMonitoring" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Other
|
||||||
|
// @description: 其他配置
|
||||||
|
type Other struct {
|
||||||
|
Code string `json:"code" label:"code" binding:"required"`
|
||||||
|
Data string `json:"data" label:"data" binding:"required"`
|
||||||
|
Describe string `json:"describe" label:"describe" binding:"omitempty"`
|
||||||
|
}
|
||||||
|
@@ -90,6 +90,17 @@ func (s setting) GetAllSetting(blackList []string) (data []vo.SettingItem, err e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetByCode
|
||||||
|
// @description: 获取指定code的配置
|
||||||
|
// @receiver s
|
||||||
|
// @param code
|
||||||
|
// @return data
|
||||||
|
// @return err
|
||||||
|
func (s setting) GetByCode(code string) (data *model.Setting, err error) {
|
||||||
|
err = s.Model(&model.Setting{}).Where("code = ?", code).Take(&data).Error
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Export
|
// Export
|
||||||
// @description: 导出
|
// @description: 导出
|
||||||
// @receiver s
|
// @receiver s
|
||||||
@@ -141,6 +152,13 @@ func (s setting) Export() (data vo.Export, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查询其他配置
|
||||||
|
var others []vo.Other
|
||||||
|
if err = s.Model(&model.Setting{}).Where("code not in ?", []string{"WG_SETTING", "WG_SERVER"}).Find(&others).Error; err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Other = others
|
||||||
cj, _ := json.Marshal(clients)
|
cj, _ := json.Marshal(clients)
|
||||||
_ = json.Unmarshal(cj, &data.Clients)
|
_ = json.Unmarshal(cj, &data.Clients)
|
||||||
|
|
||||||
@@ -208,5 +226,17 @@ func (s setting) Import(data *vo.Export, loginUser *vo.User) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 其他配置写入
|
||||||
|
for _, v := range data.Other {
|
||||||
|
if err = s.SetData(&model.Setting{
|
||||||
|
Code: v.Code,
|
||||||
|
Data: v.Data,
|
||||||
|
Describe: v.Describe,
|
||||||
|
}); err != nil {
|
||||||
|
slog.Errorf("其他配置[%s]导入失败: %v", v.Code, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -2,28 +2,35 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/jordan-wright/email"
|
"github.com/jordan-wright/email"
|
||||||
|
"github.com/spf13/cast"
|
||||||
"mime"
|
"mime"
|
||||||
"net/smtp"
|
"net/smtp"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"wireguard-ui/config"
|
"wireguard-ui/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mail struct {
|
type mail struct {
|
||||||
*email.Email
|
*email.Email
|
||||||
addr string
|
addr string
|
||||||
auth smtp.Auth
|
auth smtp.Auth
|
||||||
|
conf map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func Mail() *mail {
|
func Mail(conf *model.Setting) *mail {
|
||||||
|
// 解析配置文件
|
||||||
|
var mailConf = make(map[string]string)
|
||||||
|
_ = json.Unmarshal([]byte(conf.Data), &mailConf)
|
||||||
var m mail
|
var m mail
|
||||||
em := email.NewEmail()
|
em := email.NewEmail()
|
||||||
m.Email = em
|
m.Email = em
|
||||||
m.auth = smtp.PlainAuth("", config.Config.Mail.User, config.Config.Mail.Password, config.Config.Mail.Host)
|
m.auth = smtp.PlainAuth("", mailConf["user"], mailConf["password"], mailConf["host"])
|
||||||
m.addr = fmt.Sprintf("%s:%d", config.Config.Mail.Host, config.Config.Mail.Port)
|
m.addr = fmt.Sprintf("%s:%s", mailConf["host"], mailConf["port"])
|
||||||
|
m.conf = mailConf
|
||||||
return &m
|
return &m
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +54,7 @@ func (m *mail) VerifyConfig() (err error) {
|
|||||||
// @param attacheFilePath
|
// @param attacheFilePath
|
||||||
// @return err
|
// @return err
|
||||||
func (m *mail) SendMail(to, subject, content, attacheFilePath string) (err error) {
|
func (m *mail) SendMail(to, subject, content, attacheFilePath string) (err error) {
|
||||||
m.From = fmt.Sprintf("wg-dashboard <%s>", config.Config.Mail.User)
|
m.From = fmt.Sprintf("wg-dashboard <%s>", m.conf["user"])
|
||||||
m.To = []string{to}
|
m.To = []string{to}
|
||||||
m.Subject = subject
|
m.Subject = subject
|
||||||
m.Text = []byte(content)
|
m.Text = []byte(content)
|
||||||
@@ -61,13 +68,13 @@ func (m *mail) SendMail(to, subject, content, attacheFilePath string) (err error
|
|||||||
atch.Header = emHeader
|
atch.Header = emHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Config.Mail.SkipTls {
|
if cast.ToBool(m.conf["skipTls"]) {
|
||||||
return m.Send(m.addr, m.auth)
|
return m.Send(m.addr, m.auth)
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsConfig := &tls.Config{}
|
tlsConfig := &tls.Config{}
|
||||||
tlsConfig.InsecureSkipVerify = config.Config.Mail.SkipTls
|
tlsConfig.InsecureSkipVerify = cast.ToBool(m.conf["skipTls"])
|
||||||
tlsConfig.ServerName = config.Config.Mail.Host
|
tlsConfig.ServerName = m.conf["host"]
|
||||||
|
|
||||||
return m.SendWithTLS(m.addr, m.auth, tlsConfig)
|
return m.SendWithTLS(m.addr, m.auth, tlsConfig)
|
||||||
}
|
}
|
||||||
|
@@ -85,14 +85,14 @@
|
|||||||
{{ cip }}
|
{{ cip }}
|
||||||
</n-button>
|
</n-button>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item label="可访问IP:">
|
<!-- <n-form-item label="可访问IP:">-->
|
||||||
<n-button v-if="row.allowedIps.length <= 0" dashed size="small">
|
<!-- <n-button v-if="row.allowedIps.length <= 0" dashed size="small">-->
|
||||||
-
|
<!-- - -->
|
||||||
</n-button>
|
<!-- </n-button>-->
|
||||||
<n-button v-else dashed mr-2 type="warning" v-for="aip in row.allowedIps" size="small">
|
<!-- <n-button v-else dashed mr-2 type="warning" v-for="aip in row.allowedIps" size="small">-->
|
||||||
{{ aip }}
|
<!-- {{ aip }}-->
|
||||||
</n-button>
|
<!-- </n-button>-->
|
||||||
</n-form-item>
|
<!-- </n-form-item>-->
|
||||||
<n-form-item label="创建人:">
|
<n-form-item label="创建人:">
|
||||||
<n-button color="#54150F" dashed size="small">
|
<n-button color="#54150F" dashed size="small">
|
||||||
{{ row.createUser }}
|
{{ row.createUser }}
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
禁用
|
禁用
|
||||||
</n-button>
|
</n-button>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item label="离线监听:">
|
<n-form-item label="离线通知:">
|
||||||
<n-button v-if="row.offlineMonitoring === 1" color="#067748" round :bordered="false" size="small">
|
<n-button v-if="row.offlineMonitoring === 1" color="#067748" round :bordered="false" size="small">
|
||||||
启用
|
启用
|
||||||
</n-button>
|
</n-button>
|
||||||
@@ -114,12 +114,12 @@
|
|||||||
禁用
|
禁用
|
||||||
</n-button>
|
</n-button>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item class="timeItem" label="时间:">
|
<!-- <n-form-item class="timeItem" label="时间:">-->
|
||||||
<n-space vertical>
|
<!-- <n-space vertical>-->
|
||||||
<span> 创建时间: {{ row.createdAt }}</span>
|
<!-- <span> 创建时间: {{ row.createdAt }}</span>-->
|
||||||
<span> 更新时间: {{ row.updatedAt }}</span>
|
<!-- <span> 更新时间: {{ row.updatedAt }}</span>-->
|
||||||
</n-space>
|
<!-- </n-space>-->
|
||||||
</n-form-item>
|
<!-- </n-form-item>-->
|
||||||
</n-form>
|
</n-form>
|
||||||
</div>
|
</div>
|
||||||
</n-card>
|
</n-card>
|
||||||
@@ -228,12 +228,18 @@
|
|||||||
<n-radio :value="0" :checked="editModalForm.enabled === 0" @change="editModalForm.enabled = 0">禁用</n-radio>
|
<n-radio :value="0" :checked="editModalForm.enabled === 0" @change="editModalForm.enabled = 0">禁用</n-radio>
|
||||||
</n-radio-group>
|
</n-radio-group>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item label="离线监听" path="offlineMonitoring">
|
<n-form-item label="离线通知" path="offlineMonitoring">
|
||||||
<n-radio-group :value="editModalForm.offlineMonitoring">
|
<n-radio-group :value="editModalForm.offlineMonitoring">
|
||||||
<n-radio :value="1" :checked="editModalForm.offlineMonitoring === 1" @change="editModalForm.offlineMonitoring = 1">启用</n-radio>
|
<n-radio :value="1" :checked="editModalForm.offlineMonitoring === 1" @change="editModalForm.offlineMonitoring = 1">启用</n-radio>
|
||||||
<n-radio :value="0" :checked="editModalForm.offlineMonitoring === 0" @change="editModalForm.offlineMonitoring = 0">禁用</n-radio>
|
<n-radio :value="0" :checked="editModalForm.offlineMonitoring === 0" @change="editModalForm.offlineMonitoring = 0">禁用</n-radio>
|
||||||
</n-radio-group>
|
</n-radio-group>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
|
<n-form-item class="timeItem" label="时间:">
|
||||||
|
<n-space vertical>
|
||||||
|
<span> 创建时间: {{ editModalForm.createdAt }}</span>
|
||||||
|
<span> 更新时间: {{ editModalForm.updatedAt }}</span>
|
||||||
|
</n-space>
|
||||||
|
</n-form-item>
|
||||||
<n-button type="info" style="margin-left: 40%" @click="updateClient()">确认</n-button>
|
<n-button type="info" style="margin-left: 40%" @click="updateClient()">确认</n-button>
|
||||||
</n-form>
|
</n-form>
|
||||||
</n-modal>
|
</n-modal>
|
||||||
@@ -319,7 +325,7 @@
|
|||||||
<n-radio :value="0" :checked="addModalForm.enabled === 0" @change="addModalForm.enabled = 0">禁用</n-radio>
|
<n-radio :value="0" :checked="addModalForm.enabled === 0" @change="addModalForm.enabled = 0">禁用</n-radio>
|
||||||
</n-radio-group>
|
</n-radio-group>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item label="离线监听" path="offlineMonitoring">
|
<n-form-item label="离线通知" path="offlineMonitoring">
|
||||||
<n-radio-group :value="addModalForm.offlineMonitoring">
|
<n-radio-group :value="addModalForm.offlineMonitoring">
|
||||||
<n-radio :value="1" :checked="addModalForm.offlineMonitoring === 1" @change="addModalForm.offlineMonitoring = 1">启用</n-radio>
|
<n-radio :value="1" :checked="addModalForm.offlineMonitoring === 1" @change="addModalForm.offlineMonitoring = 1">启用</n-radio>
|
||||||
<n-radio :value="0" :checked="addModalForm.offlineMonitoring === 0" @change="addModalForm.offlineMonitoring = 0">禁用</n-radio>
|
<n-radio :value="0" :checked="addModalForm.offlineMonitoring === 0" @change="addModalForm.offlineMonitoring = 0">禁用</n-radio>
|
||||||
@@ -440,7 +446,9 @@ const editModalForm = ref({
|
|||||||
presharedKey: ''
|
presharedKey: ''
|
||||||
},
|
},
|
||||||
enabled: 1,
|
enabled: 1,
|
||||||
offlineMonitoring: 1
|
offlineMonitoring: 1,
|
||||||
|
createdAt: '',
|
||||||
|
updatedAt: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
// 添加模态框的数据集
|
// 添加模态框的数据集
|
||||||
@@ -576,6 +584,8 @@ function openEditModal(row) {
|
|||||||
editModalForm.value.keys.presharedKey = row.keys.presharedKey
|
editModalForm.value.keys.presharedKey = row.keys.presharedKey
|
||||||
editModalForm.value.enabled = row.enabled
|
editModalForm.value.enabled = row.enabled
|
||||||
editModalForm.value.offlineMonitoring = row.offlineMonitoring
|
editModalForm.value.offlineMonitoring = row.offlineMonitoring
|
||||||
|
editModalForm.value.createdAt = row.createdAt
|
||||||
|
editModalForm.value.updatedAt = row.updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更改客户端信息
|
// 更改客户端信息
|
||||||
|
@@ -174,6 +174,9 @@
|
|||||||
<n-radio :value="false" :checked="editFormModel.data[index] === false" @change="editFormModel.data[index] = false">否</n-radio>
|
<n-radio :value="false" :checked="editFormModel.data[index] === false" @change="editFormModel.data[index] = false">否</n-radio>
|
||||||
</n-radio-group>
|
</n-radio-group>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
|
<n-form-item label="配置描述">
|
||||||
|
<n-input v-model:value="editFormModel.describe" />
|
||||||
|
</n-form-item>
|
||||||
<n-form-item>
|
<n-form-item>
|
||||||
<n-button type="info" @click="updateSetting">确认</n-button>
|
<n-button type="info" @click="updateSetting">确认</n-button>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
|