install ui

This commit is contained in:
Jacky 2021-08-31 23:48:46 +08:00
parent 39a3b13595
commit 2287b1792c
56 changed files with 398 additions and 116 deletions

View file

@ -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
View 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",
})
}

View file

@ -1,5 +1,5 @@
[server]
HttpPort = 9000
HttpPort = 9100
RunMode = debug
JwtSecret = F7AFBC0E-227E-40AC-918D-60122D725398
Email = me@jackyu.cn

View file

@ -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

View file

@ -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=

View file

@ -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)

View file

@ -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{})

View file

@ -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

View file

@ -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
}