Compare commits

..

16 Commits

Author SHA1 Message Date
c3ef51e87f 🐛errors包导入掉了 2024-09-04 11:42:01 +08:00
72420f2ede 🐛修复可重复创建相同账号的bug 2024-09-04 10:06:29 +08:00
a12552a608 🎨去除首页的诗词 2024-08-27 09:48:48 +08:00
5f200ea989 🎨不想写啦 2024-08-23 11:25:27 +08:00
3f14df72be 📝修改文档 2024-08-23 10:36:21 +08:00
29902afe65 📝添加readme 2024-08-23 10:29:37 +08:00
coward
ddef41dfca 添加 web/.env 2024-08-22 16:02:01 +08:00
6c6b40593e 🎨优化 2024-08-22 16:01:00 +08:00
45d83da5c7 🎨优化一哈 2024-08-22 15:37:21 +08:00
4fa123baa8 🎨优化一下子 2024-08-22 14:16:33 +08:00
c7a56b1dde 🐛修复一个牛逼的bug 2024-08-22 11:43:23 +08:00
37446ea958 🎨 2024-08-22 11:14:28 +08:00
1b28b196a0 🎨打印日志看输出 2024-08-21 16:39:30 +08:00
1a5ab341ab 🐛 2024-08-21 14:33:50 +08:00
299ec93199 🐛修复客户端链接列表的bug 2024-08-21 14:12:43 +08:00
32f61a0eef 🎨优化 2024-08-21 11:43:57 +08:00
26 changed files with 5038 additions and 39 deletions

56
.gitignore vendored
View File

@@ -233,33 +233,33 @@ fabric.properties
# vendor/
# Go workspace file
go.work
./go.work
.idea
web/.idea
./.idea
./web/.idea
web/node_modules
web/.DS_Store
web/dist
web/dist-ssr
web/*.local
web/.eslintcache
web/report.html
web/vite.config.*.timestamp*
./web/node_modules
./web/.DS_Store
./web/dist
./web/dist-ssr
./web/*.local
./web/.eslintcache
./web/report.html
./web/vite.config.*.timestamp*
web/yarn.lock
web/npm-debug.log*
web/.pnpm-error.log*
web/.pnpm-debug.log
web/tests/**/coverage/
web/.vscode/
./web/yarn.lock
./web/npm-debug.log*
./web/.pnpm-error.log*
./web/.pnpm-debug.log
./web/tests/**/coverage/
./web/.vscode/
# Editor directories and files
web/*.suo
web/*.ntvs*
web/*.njsproj
web/*.sln
web/tsconfig.tsbuildinfo
./web/*.suo
./web/*.ntvs*
./web/*.njsproj
./web/*.sln
./web/tsconfig.tsbuildinfo
dist/assets
dist/resource
@@ -267,10 +267,10 @@ dist/favicon.png
dist/favicon.svg
dist/index.html
template/tmp/*
logs/*
app.yaml
*.db
.env
*.env
./template/tmp/*
./logs/*
./app.yaml
./*.db
./.env
./*.env

91
README.md Normal file
View File

@@ -0,0 +1,91 @@
# Wireguard-UI
> wireguard的管理面板UI
## 安装(仅提供docker方式)
OS X & Linux & Windows:
```sh
# 先要创建一个配置文件 app.yaml
http:
port: 6687
endpoint: localhost:3100,localhost:6687
database:
driver: sqlite # sqlite时只填写db即可目前仅支持sqlite | mysql | pgsql
host:
port:
user:
password:
db: wg
cache:
type: redis # 缓存类型 暂时仅支持redis
host: 192.168.1.1
port: 6379
password: pGhQKwj7DE7FbFL1
db: 15
file:
type: oss # 文件类型支持本地文件存储与阿里云oss存储
path: test/ # oss填写前缀目录
endpoint: # oss必填
accessId: # oss必填
accessSecret: # oss必填
bucketName: # oss必填
# 邮件设置
mail:
host:
port:
user:
password:
skipTls:
# 一些系统配置
wireguard:
restartMode: DELAY
delayTime: 20
# 其中依赖了redis等自行安装一个即可
```
```sh
# 创建docker-compose.yaml
version: "3"
services:
wg:
image: gitea.mrx.ltd/go-pkg/wireguard-srv:2.1.0
container_name: wg-srv
restart: always
cap_add:
- NET_ADMIN
network_mode: host
logging:
driver: json-file
options:
max-size: 50m
volumes:
- ./app.yaml:/app/app.yaml
- ./db:/app/db
- ./logs:/app/logs
- /etc/wireguard:/etc/wireguard
- /etc/localtime:/etc/localtime
```
```sh
默认账户密码
账户: admin
密码: admin123
```
## 示例
![img.png](img.png)
![img_1.png](img_1.png)
![img_7.png](img_7.png)
![img_8.png](img_8.png)
![img_2.png](img_2.png)
![img_3.png](img_3.png)
![img_4.png](img_4.png)
![img_5.png](img_5.png)
![img_6.png](img_6.png)

View File

@@ -3,6 +3,7 @@ package api
import (
"fmt"
"github.com/gin-gonic/gin"
"strings"
"time"
"wireguard-ui/component"
"wireguard-ui/http/param"
@@ -77,17 +78,25 @@ func (DashboardApi) ConnectionList(c *gin.Context) {
for _, iaip := range peer.AllowedIPs {
ipAllocation += iaip.String() + ","
}
// 去除一下最右边的逗号
if len(ipAllocation) > 0 {
ipAllocation = strings.TrimRight(ipAllocation, ",")
}
connections = append(connections, vo.DataTraffic{
Name: clientInfo.Name,
Email: clientInfo.Email,
IpAllocation: clientInfo.IpAllocation,
IpAllocation: ipAllocation,
Online: time.Since(peer.LastHandshakeTime).Minutes() < 3,
ReceiveBytes: utils.FlowCalculation().Parse(peer.TransmitBytes),
TransmitBytes: utils.FlowCalculation().Parse(peer.ReceiveBytes),
ConnectEndpoint: ipAllocation,
ConnectEndpoint: peer.Endpoint.String(),
LastHandAt: peer.LastHandshakeTime.Format("2006-01-02 15:04:05"),
})
}
if len(connections) <= 0 {
connections = []vo.DataTraffic{}
}
response.R(c).OkWithData(connections)
}

33
http/api/remote.go Normal file
View File

@@ -0,0 +1,33 @@
package api
import "github.com/gin-gonic/gin"
type remote struct{}
func Remote() remote {
return remote{}
}
// SaveAuthClient
// @description: 添加授权客户端
// @receiver remote
// @param c
func (remote) SaveAuthClient(c *gin.Context) {
return
}
// DeleteAuthClient
// @description: 删除授权客户端
// @receiver remote
// @param c
func (remote) DeleteAuthClient(c *gin.Context) {
return
}
// GetClientNodes
// @description: 获取客户端节点
// @receiver remote
// @param c
func (remote) GetClientNodes(c *gin.Context) {
return
}

View File

@@ -50,13 +50,13 @@ func Authorization() gin.HandlerFunc {
// 查询用户
user, err := service.User().GetUserById(userClaims.ID)
if err != nil {
response.R(c).FailedWithError("用户不存在")
response.R(c).AuthorizationFailed("用户不存在")
c.Abort()
return
}
if user.Status != constant.Enabled {
response.R(c).FailedWithError("用户状态异常,请联系管理员处理!")
response.R(c).AuthorizationFailed("用户状态异常,请联系管理员处理!")
c.Abort()
return
}

View File

@@ -52,8 +52,8 @@ func RequestLog() gin.HandlerFunc {
method := c.Request.Method // 请求方式
ip := c.ClientIP() // 取出IP
// 处理实际客户端IP
if c.Request.Header.Get("X-Real-IP") != "" {
ip = c.Request.Header.Get("X-Real-IP") // 这个是网关Nginx自定义的Header头
if c.Request.Header.Get("X-Real-Ip") != "" {
ip = c.Request.Header.Get("X-Real-Ip") // 这个是网关Nginx自定义的Header头
} else if c.Request.Header.Get("X-Forwarded-For") != "" {
ip = c.Request.Header.Get("X-Forwarded-For") // 这个是网关Nginx自定义的Header头
}

BIN
img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

BIN
img_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
img_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
img_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
img_4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
img_5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
img_6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
img_7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
img_8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

16
model/oauth_client.go Normal file
View File

@@ -0,0 +1,16 @@
package model
// AuthClient
// @description: 认证客户端
type AuthClient struct {
Base
Name string `json:"name" gorm:"type:varchar(255);not null;comment: '客户端名称'"`
ClientID string `json:"clientID" gorm:"type:varchar(255);not null;comment: '客户端ID'"`
ClientKey string `json:"clientKey" gorm:"type:varchar(255);not null;comment: '客户端key'"`
ExpireAt string `json:"expireAt" gorm:"type:varchar(255);not null;comment: '过期时间'"`
IsEnabled int `json:"isEnabled" gorm:"type:int(1);not null;comment: '是否启用'"`
}
func (AuthClient) TableName() string {
return "t_oauth_client"
}

View File

@@ -45,7 +45,7 @@ func (script) GenerateConfig() error {
Email: client.Email,
PublicKey: client.Keys.PublicKey,
PresharedKey: client.Keys.PresharedKey,
AllowedIPS: client.AllowedIpsStr,
AllowedIPS: client.IpAllocationStr,
Endpoint: client.Endpoint,
CreateUser: client.CreateUser,
Enabled: cast.ToBool(client.Enabled),

View File

@@ -1,6 +1,7 @@
package service
import (
"errors"
"gorm.io/gorm"
gdb "wireguard-ui/global/client"
"wireguard-ui/global/constant"
@@ -39,6 +40,11 @@ func (s user) CreateUser(user *model.User) (err error) {
return s.Model(&model.User{}).Where("id = ?", user.Id).Updates(&updates).Error
}
// 判断账号是否已经存在
if _, err = s.GetUserByAccount(user.Account); err == nil {
return errors.New("账号已经存在,请勿重复创建!")
}
defaultPassword := utils.Password().GenerateHashPassword("admin123")
if user.Password == "" { // 没有密码给一个默认密码
user.Password = defaultPassword

3
web/.env Normal file
View File

@@ -0,0 +1,3 @@
VITE_TITLE = 'Wireguard-UI'
VITE_PORT = 3100

View File

@@ -37,7 +37,6 @@ export async function addDynamicRoutes() {
// 有token的情况
const userStore = useUserStore()
try {
const permissionStore = usePermissionStore()
!userStore.id && (await userStore.getUserInfo())
@@ -49,8 +48,8 @@ export async function addDynamicRoutes() {
router.addRoute(NOT_FOUND_ROUTE)
} catch (error) {
console.error(error)
$message.error('初始化用户信息失败: ' + error)
userStore.logout()
$message.error('初始化用户信息失败: ' + error)
}
}

View File

@@ -6,6 +6,7 @@ export default {
component: Layout,
redirect: '/client',
meta: {
title: '客户端',
order: 2,
},
children: [

View File

@@ -6,6 +6,7 @@ export default {
component: Layout,
redirect: '/setting',
meta: {
title: '设置',
order: 3,
},
children: [

View File

@@ -6,6 +6,7 @@ export default {
component: Layout,
redirect: '/user',
meta: {
title: '管理员',
order: 1,
},
children: [

View File

@@ -10,7 +10,7 @@
</div>
</div>
<p class="mt-40 text-14 opacity-60" style="cursor: pointer" @click="dailyPoe">{{ dailyPoetry.content || '莫向外求但从心觅行有不得反求诸己' }}</p>
<p class="mt-40 text-14 opacity-60">{{ dailyPoetry.content || '莫向外求,但从心觅,行有不得,反求诸己。' }}</p>
<p class="mt-32 text-right text-12 opacity-40"> {{ dailyPoetry.author || '佚名' }}</p>
</n-card>
<n-card class="ml-12 w-70%">
@@ -233,7 +233,7 @@ async function getClientConnections() {
const initFunc = debounce(() => {
getClientConnections()
dailyPoe()
// dailyPoe()
// connectionList()
},500)

View File

@@ -6,6 +6,7 @@ export default {
component: Layout,
redirect: '/workbench',
meta: {
title: '工作台',
order: 0,
},
children: [

4838
web/stats.html Normal file

File diff suppressed because one or more lines are too long