mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 02:15:48 +02:00
install ui
This commit is contained in:
parent
39a3b13595
commit
2287b1792c
56 changed files with 398 additions and 116 deletions
|
@ -1,46 +1,50 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"log"
|
||||
"net/http"
|
||||
"github.com/gin-gonic/gin"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
val "github.com/go-playground/validator/v10"
|
||||
val "github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
func ErrorHandler(c *gin.Context, err error) {
|
||||
log.Println(err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"message": err.Error(),
|
||||
})
|
||||
log.Println(err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"message": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
type ValidError struct {
|
||||
Key string
|
||||
Message string
|
||||
Key string
|
||||
Message string
|
||||
}
|
||||
|
||||
type ValidErrors gin.H
|
||||
|
||||
func BindAndValid(c *gin.Context, v interface{}) (bool, ValidErrors) {
|
||||
errs := make(ValidErrors)
|
||||
err := c.ShouldBind(v)
|
||||
if err != nil {
|
||||
errs := make(ValidErrors)
|
||||
err := c.ShouldBind(v)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
v := c.Value("trans")
|
||||
trans, _ := v.(ut.Translator)
|
||||
|
||||
v := c.Value("trans")
|
||||
trans, _ := v.(ut.Translator)
|
||||
verrs, ok := err.(val.ValidationErrors)
|
||||
if !ok {
|
||||
return false, errs
|
||||
}
|
||||
verrs, ok := err.(val.ValidationErrors)
|
||||
if !ok {
|
||||
return false, errs
|
||||
}
|
||||
|
||||
for key, value := range verrs.Translate(trans) {
|
||||
errs[key] = value
|
||||
}
|
||||
for key, value := range verrs.Translate(trans) {
|
||||
k := strings.Split(key, ".")
|
||||
sub := strings.ToLower(k[1])
|
||||
errs[sub] = value
|
||||
}
|
||||
|
||||
return false, errs
|
||||
}
|
||||
return false, errs
|
||||
}
|
||||
|
||||
return true, nil
|
||||
return true, nil
|
||||
}
|
||||
|
|
74
server/api/install.go
Normal file
74
server/api/install.go
Normal file
|
@ -0,0 +1,74 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"github.com/0xJacky/Nginx-UI/server/model"
|
||||
"github.com/0xJacky/Nginx-UI/server/settings"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
func installLockStatus() bool {
|
||||
lockPath := path.Join(settings.DataDir, "app.ini")
|
||||
_, err := os.Stat(lockPath)
|
||||
|
||||
return !os.IsNotExist(err)
|
||||
|
||||
}
|
||||
|
||||
func InstallLockCheck(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"lock": installLockStatus(),
|
||||
})
|
||||
}
|
||||
|
||||
type InstallJson struct {
|
||||
Email string `json:"email" binding:"required,email"`
|
||||
Username string `json:"username" binding:"required,max=255"`
|
||||
Password string `json:"password" binding:"required,max=255"`
|
||||
}
|
||||
|
||||
func InstallNginxUI(c *gin.Context) {
|
||||
// 安装过就别访问了
|
||||
if installLockStatus() {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"message": "installed",
|
||||
})
|
||||
return
|
||||
}
|
||||
var json InstallJson
|
||||
ok, verrs := BindAndValid(c, &json)
|
||||
if !ok {
|
||||
c.JSON(http.StatusNotAcceptable, gin.H{
|
||||
"errors": verrs,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
serverSettings := settings.Conf.Section("server")
|
||||
serverSettings.Key("JwtSecret").SetValue(uuid.New().String())
|
||||
serverSettings.Key("Email").SetValue(json.Email)
|
||||
err := settings.Save()
|
||||
if err != nil {
|
||||
ErrorHandler(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
curd := model.NewCurd(&model.Auth{})
|
||||
pwd, _ := bcrypt.GenerateFromPassword([]byte(json.Password), bcrypt.DefaultCost)
|
||||
err = curd.Add(&model.Auth{
|
||||
Name: json.Username,
|
||||
Password: string(pwd),
|
||||
})
|
||||
if err != nil {
|
||||
ErrorHandler(c, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "ok",
|
||||
})
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
[server]
|
||||
HttpPort = 9000
|
||||
HttpPort = 9100
|
||||
RunMode = debug
|
||||
JwtSecret = F7AFBC0E-227E-40AC-918D-60122D725398
|
||||
Email = me@jackyu.cn
|
||||
|
|
|
@ -9,6 +9,7 @@ require (
|
|||
github.com/go-acme/lego/v4 v4.4.0
|
||||
github.com/go-playground/universal-translator v0.17.0
|
||||
github.com/go-playground/validator/v10 v10.4.1
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/shirou/gopsutil/v3 v3.21.7
|
||||
github.com/spf13/cast v1.3.1
|
||||
|
|
|
@ -173,6 +173,7 @@ github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hf
|
|||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
|
|
|
@ -3,25 +3,22 @@ package main
|
|||
import (
|
||||
"flag"
|
||||
"github.com/0xJacky/Nginx-UI/server/model"
|
||||
"github.com/0xJacky/Nginx-UI/server/router"
|
||||
"github.com/0xJacky/Nginx-UI/server/settings"
|
||||
"github.com/0xJacky/Nginx-UI/server/tool"
|
||||
"log"
|
||||
"github.com/0xJacky/Nginx-UI/server/router"
|
||||
"github.com/0xJacky/Nginx-UI/server/settings"
|
||||
"github.com/0xJacky/Nginx-UI/server/tool"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var dbPath string
|
||||
var confPath string
|
||||
flag.StringVar(&confPath, "c", "app.ini", "Specify the conf path to load")
|
||||
flag.StringVar(&dbPath, "d", "database.db", "Specify the database path to load")
|
||||
var dataDir string
|
||||
flag.StringVar(&dataDir, "d", ".", "Specify the data dir")
|
||||
flag.Parse()
|
||||
|
||||
settings.Init(confPath)
|
||||
settings.Init(dataDir)
|
||||
model.Init()
|
||||
|
||||
r := router.InitRouter()
|
||||
|
||||
model.Init(dbPath)
|
||||
|
||||
log.Printf("nginx config dir path: %s", tool.GetNginxConfPath(""))
|
||||
|
||||
err := r.Run(":" + settings.ServerSettings.HttpPort)
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"github.com/0xJacky/Nginx-UI/server/settings"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
"log"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -17,19 +19,16 @@ type Model struct {
|
|||
DeletedAt *time.Time `gorm:"index" json:"deleted_at"`
|
||||
}
|
||||
|
||||
func Init(dbPath string) {
|
||||
func Init() {
|
||||
dbPath := path.Join(settings.DataDir, "database.db")
|
||||
var err error
|
||||
|
||||
db, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Info),
|
||||
PrepareStmt: true,
|
||||
})
|
||||
log.Println("database.db")
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
// Migrate the schema
|
||||
AutoMigrate(&ConfigBackup{})
|
||||
AutoMigrate(&Auth{})
|
||||
|
|
|
@ -5,35 +5,67 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/server/api"
|
||||
"github.com/0xJacky/Nginx-UI/server/model"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"github.com/go-playground/locales/en"
|
||||
"github.com/go-playground/locales/zh"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"github.com/go-playground/validator/v10"
|
||||
en_translations "github.com/go-playground/validator/v10/translations/en"
|
||||
zh_translations "github.com/go-playground/validator/v10/translations/zh"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func authRequired() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
token := c.GetHeader("Authorization")
|
||||
if token == "" {
|
||||
tmp, _ := base64.StdEncoding.DecodeString(c.Query("token"))
|
||||
token = string(tmp)
|
||||
if token == "" {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"message": "auth fail",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
return func(c *gin.Context) {
|
||||
token := c.GetHeader("Authorization")
|
||||
if token == "" {
|
||||
tmp, _ := base64.StdEncoding.DecodeString(c.Query("token"))
|
||||
token = string(tmp)
|
||||
if token == "" {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"message": "auth fail",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
n := model.CheckToken(token)
|
||||
n := model.CheckToken(token)
|
||||
|
||||
if n < 1 {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"message": "auth fail",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
if n < 1 {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"message": "auth fail",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func Translations() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
uni := ut.New(en.New(), zh.New())
|
||||
locale := c.GetHeader("locale")
|
||||
trans, _ := uni.GetTranslator(locale)
|
||||
v, ok := binding.Validator.Engine().(*validator.Validate)
|
||||
if ok {
|
||||
switch locale {
|
||||
case "zh":
|
||||
_ = zh_translations.RegisterDefaultTranslations(v, trans)
|
||||
break
|
||||
case "en":
|
||||
_ = en_translations.RegisterDefaultTranslations(v, trans)
|
||||
break
|
||||
default:
|
||||
_ = zh_translations.RegisterDefaultTranslations(v, trans)
|
||||
break
|
||||
}
|
||||
c.Set("trans", trans)
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func InitRouter() *gin.Engine {
|
||||
|
@ -41,23 +73,29 @@ func InitRouter() *gin.Engine {
|
|||
r.Use(gin.Logger())
|
||||
|
||||
r.Use(gin.Recovery())
|
||||
r.Use(Translations())
|
||||
|
||||
r.GET("/", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "Hello World",
|
||||
})
|
||||
})
|
||||
r.GET("/analytic", api.Analytic)
|
||||
|
||||
r.GET("install", api.InstallLockCheck)
|
||||
r.POST("install", api.InstallNginxUI)
|
||||
|
||||
r.POST("/login", api.Login)
|
||||
r.DELETE("/logout", api.Logout)
|
||||
r.DELETE("/logout", api.Logout)
|
||||
|
||||
g := r.Group("/", authRequired())
|
||||
{
|
||||
g.GET("/users", api.GetUsers)
|
||||
g.GET("/user/:id", api.GetUser)
|
||||
g.POST("/user", api.AddUser)
|
||||
g.POST("/user/:id", api.EditUser)
|
||||
g.DELETE("/user/:id", api.DeleteUser)
|
||||
r.GET("/analytic", api.Analytic)
|
||||
|
||||
g.GET("/users", api.GetUsers)
|
||||
g.GET("/user/:id", api.GetUser)
|
||||
g.POST("/user", api.AddUser)
|
||||
g.POST("/user/:id", api.EditUser)
|
||||
g.DELETE("/user/:id", api.DeleteUser)
|
||||
|
||||
g.GET("domains", api.GetDomains)
|
||||
g.GET("domain/:name", api.GetDomain)
|
||||
|
@ -74,10 +112,10 @@ func InitRouter() *gin.Engine {
|
|||
g.GET("backups", api.GetFileBackupList)
|
||||
g.GET("backup/:id", api.GetFileBackup)
|
||||
|
||||
g.GET("template/:name", api.GetTemplate)
|
||||
g.GET("template/:name", api.GetTemplate)
|
||||
|
||||
g.GET("cert/issue/:domain", api.IssueCert)
|
||||
g.GET("cert/:domain/info", api.CertInfo)
|
||||
g.GET("cert/:domain/info", api.CertInfo)
|
||||
}
|
||||
|
||||
return r
|
||||
|
|
|
@ -3,6 +3,8 @@ package settings
|
|||
import (
|
||||
"gopkg.in/ini.v1"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
var Conf *ini.File
|
||||
|
@ -18,16 +20,26 @@ type Server struct {
|
|||
|
||||
var ServerSettings = &Server{}
|
||||
|
||||
func Init(confPath string) {
|
||||
var err error
|
||||
var DataDir string
|
||||
var confPath string
|
||||
|
||||
Conf, err = ini.Load(confPath)
|
||||
if err != nil {
|
||||
log.Fatalf("setting.Setup, fail to parse '%s': %v", confPath, err)
|
||||
}
|
||||
func Init(dataDir string) {
|
||||
DataDir = dataDir
|
||||
confPath = path.Join(dataDir, "app.ini")
|
||||
if _, err := os.Stat(confPath); os.IsNotExist(err) {
|
||||
confPath = path.Join(dataDir, "app.example.ini")
|
||||
}
|
||||
Setup()
|
||||
}
|
||||
|
||||
mapTo("server", ServerSettings)
|
||||
func Setup() {
|
||||
var err error
|
||||
Conf, err = ini.Load(confPath)
|
||||
if err != nil {
|
||||
log.Fatalf("setting.Setup, fail to parse '%s': %v", confPath, err)
|
||||
}
|
||||
|
||||
mapTo("server", ServerSettings)
|
||||
}
|
||||
|
||||
func mapTo(section string, v interface{}) {
|
||||
|
@ -36,3 +48,13 @@ func mapTo(section string, v interface{}) {
|
|||
log.Fatalf("Cfg.MapTo %s err: %v", section, err)
|
||||
}
|
||||
}
|
||||
|
||||
func Save() (err error) {
|
||||
confPath = path.Join(DataDir, "app.ini")
|
||||
err = Conf.SaveTo(confPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
Setup()
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue