From 7fd186d298dcc9a9d49cb6ef92babdeacf198593 Mon Sep 17 00:00:00 2001 From: coward Date: Wed, 6 Mar 2024 16:24:49 +0800 Subject: [PATCH] =?UTF-8?q?:new:=E5=88=9D=E5=A7=8B=E5=8C=96=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E4=BB=A5=E5=8F=8A=E4=B8=80=E4=BA=9B=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/client.go | 10 ++- config/config.go | 1 + config/file.go | 10 +++ constant/admin.go | 21 +++++ go.mod | 9 ++- go.sum | 53 ++++++++++++ initialize/init.go | 36 ++++++++- main.go | 5 ++ model/entity/base.go | 165 +++++++++++++++++++++++++++++++++++++- model/entity/user.go | 19 +++++ model/entity/wireguard.go | 1 + script/db_migrate.go | 76 ++++++++++++++++++ utils/avatar.go | 34 ++++++++ utils/file_system.go | 41 ++++++++++ utils/password.go | 30 +++++++ 15 files changed, 500 insertions(+), 11 deletions(-) create mode 100644 config/file.go create mode 100644 constant/admin.go create mode 100644 model/entity/user.go create mode 100644 script/db_migrate.go create mode 100644 utils/avatar.go create mode 100644 utils/file_system.go create mode 100644 utils/password.go diff --git a/client/client.go b/client/client.go index c9659a4..0120fb8 100644 --- a/client/client.go +++ b/client/client.go @@ -1,13 +1,17 @@ package client import ( + "github.com/cowardmrx/go_aliyun_oss" + "github.com/go-resty/resty/v2" "github.com/redis/go-redis/v9" "golang.zx2c4.com/wireguard/wgctrl" "gorm.io/gorm" ) var ( - WireguardClient *wgctrl.Client // wireguard客户端 - DB *gorm.DB // 数据库客户端 - Redis *redis.Client // redis客户端 + WireguardClient *wgctrl.Client // wireguard客户端 + DB *gorm.DB // 数据库客户端 + Redis *redis.Client // redis客户端 + HttpClient *resty.Client // http客户端 + OSS *go_aliyun_oss.AliOssClient // oss客户端 ) diff --git a/config/config.go b/config/config.go index 84546bd..7dd30b7 100644 --- a/config/config.go +++ b/config/config.go @@ -6,4 +6,5 @@ type config struct { Http *http `yaml:"http"` Database *database `yaml:"database"` Redis *redis `yaml:"redis"` + File *file `yaml:"file"` } diff --git a/config/file.go b/config/file.go new file mode 100644 index 0000000..4930633 --- /dev/null +++ b/config/file.go @@ -0,0 +1,10 @@ +package config + +type file struct { + Type string `yaml:"type"` + Path string `yaml:"path"` + Endpoint string `yaml:"endpoint"` + AccessId string `yaml:"accessId"` + AccessSecret string `yaml:"accessSecret"` + BucketName string `yaml:"bucketName"` +} diff --git a/constant/admin.go b/constant/admin.go new file mode 100644 index 0000000..0005236 --- /dev/null +++ b/constant/admin.go @@ -0,0 +1,21 @@ +package constant + +type UserType int + +const ( + NormalAdmin UserType = iota + SuperAdmin +) + +var UserTypeMap = map[UserType]string{ + NormalAdmin: "普通管理员", + SuperAdmin: "超级管理员", +} + +func (u UserType) String() string { + if v, ok := UserTypeMap[u]; ok { + return v + } + + return "未知类型" +} diff --git a/go.mod b/go.mod index 32c27d7..c899eee 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,11 @@ module wireguard-dashboard go 1.21 require ( + github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/cowardmrx/go_aliyun_oss v1.0.6 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect @@ -13,6 +15,7 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/go-resty/resty/v2 v2.11.0 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/google/go-cmp v0.5.9 // indirect @@ -35,14 +38,18 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/redis/go-redis/v9 v9.5.1 // indirect + github.com/satori/go.uuid v1.2.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect + go.uber.org/multierr v1.10.0 // indirect + go.uber.org/zap v1.27.0 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.14.0 // indirect - golang.org/x/net v0.10.0 // indirect + golang.org/x/net v0.17.0 // indirect golang.org/x/sync v0.1.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect + golang.org/x/time v0.3.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 // indirect google.golang.org/protobuf v1.30.0 // indirect diff --git a/go.sum b/go.sum index f38d80e..ad15764 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,6 @@ +github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible h1:QoRMR0TCctLDqBCMyOu1eXdZyMw3F7uGA9qPn2J4+R8= +github.com/aliyun/aliyun-oss-go-sdk v2.2.5+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -6,6 +9,8 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/cowardmrx/go_aliyun_oss v1.0.6 h1:KVCCUJe4n/hGzNH1RBuu4qDGa9PfTYJOLsAt3GDZx3s= +github.com/cowardmrx/go_aliyun_oss v1.0.6/go.mod h1:hisPCZT3TaXex2fCTXRl/rozLw/dpifyIJtihBlRnkk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= @@ -22,6 +27,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8= +github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= @@ -50,6 +57,9 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= @@ -72,6 +82,8 @@ github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNc github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8= github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -86,22 +98,45 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -109,10 +144,27 @@ golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b h1:J1CaxgLerRR5lgx3wnr6L04cJFbWoceSK9JWBdglINo= golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b/go.mod h1:tqur9LnfstdR9ep2LaJT4lFUl0EjlHtge+gAjmsHUG4= @@ -122,6 +174,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/initialize/init.go b/initialize/init.go index fb224ab..c41fa6d 100644 --- a/initialize/init.go +++ b/initialize/init.go @@ -2,6 +2,8 @@ package initialize import ( "fmt" + "github.com/cowardmrx/go_aliyun_oss" + "github.com/go-resty/resty/v2" "github.com/redis/go-redis/v9" "golang.zx2c4.com/wireguard/wgctrl" "gopkg.in/yaml.v3" @@ -20,10 +22,12 @@ import ( // Init // @description: 初始化 func Init() { - initConfig() // 读取配置文件 - initWireguard() // 初始化wireguard客户端 - initDatabase() // 初始化数据库 - initRedis() // 初始化redis + initConfig() // 读取配置文件 + initWireguard() // 初始化wireguard客户端 + initDatabase() // 初始化数据库 + initRedis() // 初始化redis + initHttpClient() // 初始化http客户端 + initOSS() // 初始化oss客户端链接 } // initConfig @@ -98,3 +102,27 @@ func initRedis() { client.Redis = c } + +// initHttpClient +// @description: 初始化http客户端 +func initHttpClient() { + client.HttpClient = resty.New() +} + +// initOSS +// @description: 初始化oss客户端 +func initOSS() { + if config.Config.File.Type != "oss" { + return + } + ossConfig := &go_aliyun_oss.AliOssConfig{ + EndPoint: config.Config.File.Endpoint, + AccessKeyId: config.Config.File.AccessId, + AccessKeySecret: config.Config.File.AccessSecret, + BucketName: config.Config.File.BucketName, + OriginalFileName: false, + } + + ossClient := ossConfig.CreateOssConnect() + client.OSS = ossClient +} diff --git a/main.go b/main.go index 2dd8b90..9bedc5d 100644 --- a/main.go +++ b/main.go @@ -2,15 +2,20 @@ package main import ( "fmt" + "go.uber.org/zap" "log" "net/http" "wireguard-dashboard/config" "wireguard-dashboard/initialize" "wireguard-dashboard/route" + "wireguard-dashboard/script" ) func init() { initialize.Init() // 初始化 + if err := script.NewScript().Do(); err != nil { + zap.S().Errorf("执行脚本错误: %v", err.Error()) + } } func main() { diff --git a/model/entity/base.go b/model/entity/base.go index 2fc49d7..a17e1a9 100644 --- a/model/entity/base.go +++ b/model/entity/base.go @@ -1,15 +1,18 @@ package entity import ( + "database/sql/driver" + "fmt" "github.com/google/uuid" - "gorm.io/datatypes" "gorm.io/gorm" + "strings" + "time" ) type Base struct { Id string `json:"id" gorm:"primaryKey;type:varchar(36);not null;comment:'主键'"` - CreatedAt datatypes.Time - UpdatedAt datatypes.Time + CreatedAt DateTime + UpdatedAt DateTime } func (b *Base) BeforeCreate(*gorm.DB) (err error) { @@ -19,3 +22,159 @@ func (b *Base) BeforeCreate(*gorm.DB) (err error) { return } + +// 默认时间格式 +const dateTimeFormat = "2006-01-02 15:04:05.000" + +// DateTime 自定义时间类型 +type DateTime time.Time + +// 可能包含的时间格式 +var formatMap = map[string]string{ + "yyyy-mm-dd hh:mm:ss": "2006-01-02 15:04:05", + "yyyy-mm-dd hh:mm": "2006-01-02 15:04", + "yyyy-mm-dd hh": "2006-01-02 15:04", + "yyyy-mm-dd": "2006-01-02", + "yyyy-mm": "2006-01", + "mm-dd": "01-02", + "dd-mm-yy hh:mm:ss": "02-01-06 15:04:05", + "yyyy/mm/dd hh:mm:ss": "2006/01/02 15:04:05", + "yyyy/mm/dd hh:mm": "2006/01/02 15:04", + "yyyy/mm/dd hh": "2006/01/02 15", + "yyyy/mm/dd": "2006/01/02", + "yyyy/mm": "2006/01", + "mm/dd": "01/02", + "dd/mm/yy hh:mm:ss": "02/01/06 15:04:05", + "yyyy": "2006", + "mm": "01", + "hh:mm:ss": "15:04:05", + "mm:ss": "04:05", +} + +// Scan implements the Scanner interface. +func (dt *DateTime) Scan(value interface{}) error { + // mysql 内部日期的格式可能是 2006-01-02 15:04:05 +0800 CST 格式,所以检出的时候还需要进行一次格式化 + tTime, _ := time.Parse("2006-01-02 15:04:05 +0800 CST", value.(time.Time).String()) + *dt = DateTime(tTime) + return nil +} + +// Value implements the driver Valuer interface. +func (dt DateTime) Value() (dv driver.Value, err error) { + // 0001-01-01 00:00:00 属于空值,遇到空值解析成 null 即可 + if dt.String() == "0001-01-01 00:00:00.000" { + return nil, nil + } + dv, err = []byte(dt.Format(dateTimeFormat)), nil + return +} + +// 用于 fmt.Println 和后续验证场景 +func (dt DateTime) String() string { + return dt.Format(dateTimeFormat) +} + +// Format 格式化 +func (dt *DateTime) Format(fm string) string { + return time.Time(*dt).Format(fm) +} + +// AutoParse 假装是个自动解析时间的函数 +func (dt DateTime) AutoParse(timeStr string) (t time.Time, err error) { + // 循环匹配预设的时间格式 + for _, v := range formatMap { + // 尝试解析,没报错就是解析成功了 + t, err = time.ParseInLocation(v, timeStr, time.Local) + if err == nil { + // 错误为空,表示匹配上了 + return + } + } + return +} + +// After 时间比较 +func (dt *DateTime) After(now time.Time) bool { + return time.Time(*dt).After(now) +} + +// Before 时间比较 +func (dt *DateTime) Before(now time.Time) bool { + return time.Time(*dt).Before(now) +} + +// IBefore 时间比较 +func (dt *DateTime) IBefore(now DateTime) bool { + return dt.Before(time.Time(now)) +} + +// SubTime 对比 +func (dt DateTime) SubTime(t time.Time) time.Duration { + return dt.ToTime().Sub(t) +} + +// Sub 对比 +func (dt DateTime) Sub(t DateTime) time.Duration { + return dt.ToTime().Sub(t.ToTime()) +} + +// ToTime 转换为golang的时间类型 +func (dt DateTime) ToTime() time.Time { + return time.Time(dt) +} + +// IsNil 是否为空值 +func (dt DateTime) IsNil() bool { + return dt.Format(dateTimeFormat) == "0001-01-01 00:00:00.000" +} + +// Unix 实现Unix函数 +func (dt DateTime) Unix() int64 { + return dt.ToTime().Unix() +} + +// EndOfCentury 获取本世纪最后时间 +func (dt DateTime) EndOfCentury() DateTime { + yearEnd := time.Now().Local().Year()/100*100 + 99 + return DateTime(time.Date(yearEnd, 12, 31, 23, 59, 59, 999999999, time.Local)) +} + +// Add +// @description: 添加时间 +// @receiver dt +// @param t +func (dt DateTime) Add(d time.Duration) DateTime { + return DateTime(dt.ToTime().Add(d)) +} + +// ======== 序列化 JSON ======== + +// MarshalJSON 时间到字符串 +func (dt DateTime) MarshalJSON() ([]byte, error) { + // 过滤掉空数据 + if dt.IsNil() { + return []byte("\"\""), nil + } + output := fmt.Sprintf(`"%s"`, dt.Format("2006-01-02 15:04:05")) + return []byte(output), nil +} + +// UnmarshalJSON 字符串到时间 +func (dt *DateTime) UnmarshalJSON(b []byte) (err error) { + if len(b) == 2 { + *dt = DateTime{} + return + } + // 解析指定的格式 + var now time.Time + if strings.HasPrefix(string(b), "\"") { + now, err = dt.AutoParse(string(b)[1 : len(b)-1]) + } else { + now, err = dt.AutoParse(string(b)) + } + if err != nil { + return + } + *dt = DateTime(now) + return +} diff --git a/model/entity/user.go b/model/entity/user.go new file mode 100644 index 0000000..7f38c77 --- /dev/null +++ b/model/entity/user.go @@ -0,0 +1,19 @@ +package entity + +import "wireguard-dashboard/constant" + +// User +// @description: 用户信息 +type User struct { + Base + Avatar string `json:"avatar" gorm:"type:varchar(255);not null;comment:'头像'"` + Name string `json:"name" gorm:"type:varchar(50);not null;comment:'用户名'"` + Account string `json:"account" gorm:"type:varchar(50);not null;comment:'账号'"` + Email string `json:"email" gorm:"type:varchar(255);default null;comment:'联系邮箱'"` + Password string `json:"password" gorm:"type:varchar(255);not null;comment:'密码'"` + IsAdmin constant.UserType `json:"isAdmin" gorm:"type:int(1);not null;comment:'是否为管理员'"` +} + +func (*User) TableName() string { + return "t_user" +} diff --git a/model/entity/wireguard.go b/model/entity/wireguard.go index 8c905b5..a80159b 100644 --- a/model/entity/wireguard.go +++ b/model/entity/wireguard.go @@ -33,6 +33,7 @@ type Client struct { UseServerDns int `json:"useServerDns" gorm:"type:int(1);default 1;comment:'是否使用服务端dns'"` EnableAfterCreation int `json:"enableAfterCreation" gorm:"type:int(1);default 1;comment:'是否创建后启用'"` Keys string `json:"keys" gorm:"type:text;default null;comment:'公钥和密钥的json串'"` + UserId string `json:"userId" gorm:"type:char(36);not null;comment:'创建人id'"` } func (*Client) TableName() string { diff --git a/script/db_migrate.go b/script/db_migrate.go new file mode 100644 index 0000000..646cd88 --- /dev/null +++ b/script/db_migrate.go @@ -0,0 +1,76 @@ +package script + +import ( + "go.uber.org/zap" + "wireguard-dashboard/client" + "wireguard-dashboard/constant" + "wireguard-dashboard/model/entity" + "wireguard-dashboard/utils" +) + +type Script struct{} + +func NewScript() Script { + return Script{} +} + +func (s Script) Do() error { + if err := s.DBMigrate(); err != nil { + return err + } + + if err := s.CreateSuperAdmin(); err != nil { + return err + } + + return nil +} + +// DBMigrate +// @description: 实体migrate +// @receiver s +// @return error +func (s Script) DBMigrate() error { + var ent = []any{ + new(entity.User), + new(entity.Server), + new(entity.Client), + } + + return client.DB.AutoMigrate(ent...) +} + +// CreateSuperAdmin +// @description: 创建首个超级管理员 +// @receiver s +// @return error +func (s Script) CreateSuperAdmin() error { + var count int64 + if err := client.DB.Model(&entity.User{}).Where("is_admin = ?", 1).Count(&count).Error; err != nil { + return err + } + + // 没有超管就创建一个 + if count <= 0 { + avatarPath, err := utils.Avatar().GenerateAvatar() + if err != nil { + zap.S().Errorf("生成头像失败: %v", err.Error()) + return err + } + + if err = client.DB.Create(&entity.User{ + Avatar: avatarPath, + Name: "超牛管理员", + Account: "Admin", + Email: "", + Password: utils.Password().GenerateHashPassword("admin123"), + IsAdmin: constant.SuperAdmin, + }).Error; err != nil { + zap.S().Errorf("创建管理员失败: %v", err.Error()) + } + + return nil + } + + return nil +} diff --git a/utils/avatar.go b/utils/avatar.go new file mode 100644 index 0000000..b7969fc --- /dev/null +++ b/utils/avatar.go @@ -0,0 +1,34 @@ +package utils + +import ( + "fmt" + "go.uber.org/zap" + "math/rand" + "time" + "wireguard-dashboard/client" +) + +type avatar struct{} + +func Avatar() avatar { + return avatar{} +} + +func (avatar) GenerateAvatar() (path string, err error) { + rand.New(rand.NewSource(time.Now().UnixNano())) + r := client.HttpClient.R() + result, err := r.Get(fmt.Sprintf("https://api.dicebear.com/7.x/croodles/png?seed=%d&scale=100&size=80&clip=true&randomizeIds=true&beard=variant01,variant02,variant03&"+ + "eyes=variant01,variant02,variant03,variant04,variant05,variant06,variant07,variant08,variant09,variant10,variant11,variant12&mustache=variant01,variant02,variant03&"+ + "topColor=000000,0fa958,699bf7", rand.Uint32())) + if err != nil { + zap.S().Errorf("生成头像失败") + return "", err + } + + filePath, err := FileSystem().UploadFile(result.Body(), ".png") + if err != nil { + return "", err + } + + return filePath, nil +} diff --git a/utils/file_system.go b/utils/file_system.go new file mode 100644 index 0000000..24beff8 --- /dev/null +++ b/utils/file_system.go @@ -0,0 +1,41 @@ +package utils + +import ( + "fmt" + "os" + "time" + "wireguard-dashboard/client" + "wireguard-dashboard/config" +) + +type fileSystem struct{} + +func FileSystem() fileSystem { + return fileSystem{} +} + +// UploadFile +// @description: 上传文件 +// @receiver fileSystem +// @param file +// @return filePath +// @return err +func (fileSystem) UploadFile(file []byte, suffix string) (filePath string, err error) { + switch config.Config.File.Type { + case "oss": + ossObj, err := client.OSS.Put(config.Config.File.Path, file, suffix) + if err != nil { + return "", err + } + + return ossObj.LongPath, nil + case "local": + filePath = fmt.Sprintf("%v/%d-avatar%s", config.Config.File.Path, time.Now().Unix(), suffix) + if err = os.WriteFile(filePath, file, os.FileMode(0777)); err != nil { + return "", err + } + + return filePath, nil + } + return "", nil +} diff --git a/utils/password.go b/utils/password.go new file mode 100644 index 0000000..547990a --- /dev/null +++ b/utils/password.go @@ -0,0 +1,30 @@ +package utils + +import "golang.org/x/crypto/bcrypt" + +type password struct{} + +func Password() password { + return password{} +} + +// GenerateHashPassword +// @description: 生成hash密码 +// @receiver password +// @param pass +// @return string +func (password) GenerateHashPassword(pass string) string { + bytePass := []byte(pass) + hPass, _ := bcrypt.GenerateFromPassword(bytePass, bcrypt.DefaultCost) + return string(hPass) +} + +// ComparePassword +// @description: 密码比对 +// @receiver password +// @param dbPass +// @param pass +// @return bool +func (password) ComparePassword(dbPass, pass string) bool { + return bcrypt.CompareHashAndPassword([]byte(dbPass), []byte(pass)) == nil +}