enhance(wip): error handle

This commit is contained in:
Jacky 2025-01-24 16:37:45 +08:00
parent 3f95ae5d90
commit 650196d06a
No known key found for this signature in database
GPG key ID: 215C21B10DF38B4D
93 changed files with 5228 additions and 3738 deletions

View file

@ -35,7 +35,7 @@ func autoCert(certModel *model.Cert) {
defer log.Exit()
if len(certModel.Filename) == 0 {
log.Error(errors.New("filename is empty"))
log.Error(ErrCertModelFilenameEmpty)
return
}

View file

@ -5,7 +5,6 @@ import (
"encoding/pem"
"github.com/0xJacky/Nginx-UI/internal/helper"
"github.com/0xJacky/Nginx-UI/internal/nginx"
"github.com/pkg/errors"
"os"
"time"
)
@ -19,24 +18,24 @@ type Info struct {
func GetCertInfo(sslCertificatePath string) (info *Info, err error) {
if !helper.IsUnderDirectory(sslCertificatePath, nginx.GetConfPath()) {
err = errors.New("ssl certificate path is not under the nginx conf path")
err = ErrCertPathIsNotUnderTheNginxConfDir
return
}
certData, err := os.ReadFile(sslCertificatePath)
if err != nil {
err = errors.Wrap(err, "error read certificate")
return
}
block, _ := pem.Decode(certData)
if block == nil || block.Type != "CERTIFICATE" {
err = errors.New("certificate decoding error")
err = ErrCertDecode
return
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
err = errors.Wrap(err, "certificate parsing error")
err = ErrCertParse
return
}

13
internal/cert/errors.go Normal file
View file

@ -0,0 +1,13 @@
package cert
import "github.com/uozi-tech/cosy"
var (
e = cosy.NewErrorScope("cert")
ErrCertModelFilenameEmpty = e.New(50001, "filename is empty")
ErrCertPathIsNotUnderTheNginxConfDir = e.New(50002, "cert path is not under the nginx conf dir")
ErrCertDecode = e.New(50003, "certificate decode error")
ErrCertParse = e.New(50004, "certificate parse error")
ErrPayloadResourceIsNil = e.New(50005, "payload resource is nil")
ErrPathIsNotUnderTheNginxConfDir = e.New(50006, "path: {0} is not under the nginx conf dir: {1}")
)

View file

@ -10,7 +10,7 @@ import (
func renew(payload *ConfigPayload, client *lego.Client, l *log.Logger, errChan chan error) {
if payload.Resource == nil {
errChan <- errors.New("resource is nil")
errChan <- ErrPayloadResourceIsNil
return
}

View file

@ -3,7 +3,6 @@ package cert
import (
"bytes"
"encoding/json"
"fmt"
"github.com/0xJacky/Nginx-UI/internal/helper"
"github.com/0xJacky/Nginx-UI/internal/nginx"
"github.com/0xJacky/Nginx-UI/internal/notification"
@ -33,13 +32,11 @@ func SyncToRemoteServer(c *model.Cert) (err error) {
nginxConfPath := nginx.GetConfPath()
if !helper.IsUnderDirectory(c.SSLCertificatePath, nginxConfPath) {
return fmt.Errorf("ssl_certificate_path: %s is not under the nginx conf path: %s",
c.SSLCertificatePath, nginxConfPath)
return e.NewWithParams(50006, ErrPathIsNotUnderTheNginxConfDir.Error(), c.SSLCertificatePath, nginxConfPath)
}
if !helper.IsUnderDirectory(c.SSLCertificateKeyPath, nginxConfPath) {
return fmt.Errorf("ssl_certificate_key_path: %s is not under the nginx conf path: %s",
c.SSLCertificateKeyPath, nginxConfPath)
return e.NewWithParams(50006, ErrPathIsNotUnderTheNginxConfDir.Error(), c.SSLCertificateKeyPath, nginxConfPath)
}
certBytes, err := os.ReadFile(c.SSLCertificatePath)

View file

@ -1,7 +1,6 @@
package cert
import (
"fmt"
"github.com/0xJacky/Nginx-UI/internal/helper"
"github.com/0xJacky/Nginx-UI/internal/nginx"
"os"
@ -22,13 +21,11 @@ func (c *Content) WriteFile() (err error) {
nginxConfPath := nginx.GetConfPath()
if !helper.IsUnderDirectory(c.SSLCertificatePath, nginxConfPath) {
return fmt.Errorf("ssl_certificate_path: %s is not under the nginx conf path: %s",
c.SSLCertificatePath, nginxConfPath)
return e.NewWithParams(50006, ErrPathIsNotUnderTheNginxConfDir.Error(), c.SSLCertificatePath, nginxConfPath)
}
if !helper.IsUnderDirectory(c.SSLCertificateKeyPath, nginxConfPath) {
return fmt.Errorf("ssl_certificate_key_path: %s is not under the nginx conf path: %s",
c.SSLCertificateKeyPath, nginxConfPath)
return e.NewWithParams(50006, ErrPathIsNotUnderTheNginxConfDir.Error(), c.SSLCertificateKeyPath, nginxConfPath)
}
// MkdirAll creates a directory named path, along with any necessary parents,

View file

@ -0,0 +1,8 @@
package config
import "github.com/uozi-tech/cosy"
var (
e = cosy.NewErrorScope("config")
ErrPathIsNotUnderTheNginxConfDir = e.New(50006, "path: {0} is not under the nginx conf dir: {1}")
)

View file

@ -4,7 +4,6 @@ import (
"bytes"
"crypto/tls"
"encoding/json"
"fmt"
"github.com/0xJacky/Nginx-UI/internal/helper"
"github.com/0xJacky/Nginx-UI/internal/nginx"
"github.com/0xJacky/Nginx-UI/internal/notification"
@ -35,8 +34,7 @@ func SyncToRemoteServer(c *model.Config) (err error) {
nginxConfPath := nginx.GetConfPath()
if !helper.IsUnderDirectory(c.Filepath, nginxConfPath) {
return fmt.Errorf("config: %s is not under the nginx conf path: %s",
c.Filepath, nginxConfPath)
return e.NewWithParams(50006, ErrPathIsNotUnderTheNginxConfDir.Error(), c.Filepath, nginxConfPath)
}
configBytes, err := os.ReadFile(c.Filepath)
@ -76,13 +74,11 @@ func SyncRenameOnRemoteServer(origPath, newPath string, syncNodeIds []uint64) (e
nginxConfPath := nginx.GetConfPath()
if !helper.IsUnderDirectory(origPath, nginxConfPath) {
return fmt.Errorf("config: %s is not under the nginx conf path: %s",
origPath, nginxConfPath)
return e.NewWithParams(50006, ErrPathIsNotUnderTheNginxConfDir.Error(), origPath, nginxConfPath)
}
if !helper.IsUnderDirectory(newPath, nginxConfPath) {
return fmt.Errorf("config: %s is not under the nginx conf path: %s",
newPath, nginxConfPath)
return e.NewWithParams(50006, ErrPathIsNotUnderTheNginxConfDir.Error(), newPath, nginxConfPath)
}
payload := &RenameConfigPayload{

View file

@ -5,27 +5,25 @@ import (
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"fmt"
"github.com/0xJacky/Nginx-UI/settings"
"github.com/pkg/errors"
"io"
)
// AesEncrypt encrypts text and given key with AES.
func AesEncrypt(text []byte) ([]byte, error) {
if len(text) == 0 {
return nil, errors.New("AesEncrypt text is empty")
return nil, ErrPlainTextEmpty
}
block, err := aes.NewCipher(settings.CryptoSettings.GetSecretMd5())
if err != nil {
return nil, fmt.Errorf("AesEncrypt invalid key: %v", err)
return nil, err
}
b := base64.StdEncoding.EncodeToString(text)
ciphertext := make([]byte, aes.BlockSize+len(b))
iv := ciphertext[:aes.BlockSize]
if _, err = io.ReadFull(rand.Reader, iv); err != nil {
return nil, fmt.Errorf("AesEncrypt unable to read IV: %w", err)
return nil, err
}
cfb := cipher.NewCFBEncrypter(block, iv)
@ -42,7 +40,7 @@ func AesDecrypt(text []byte) ([]byte, error) {
}
if len(text) < aes.BlockSize {
return nil, errors.New("AesDecrypt ciphertext too short")
return nil, ErrCipherTextTooShort
}
iv := text[:aes.BlockSize]
@ -52,7 +50,7 @@ func AesDecrypt(text []byte) ([]byte, error) {
data, err := base64.StdEncoding.DecodeString(string(text))
if err != nil {
return nil, fmt.Errorf("AesDecrypt invalid decrypted base64 string: %w", err)
return nil, err
}
return data, nil

View file

@ -0,0 +1,9 @@
package crypto
import "github.com/uozi-tech/cosy"
var (
e = cosy.NewErrorScope("crypto")
ErrPlainTextEmpty = e.New(50001, "plain text is empty")
ErrCipherTextTooShort = e.New(50002, "cipher text is too short")
)

View file

@ -3,7 +3,7 @@ package helper
import (
"strings"
"github.com/gorilla/websocket"
"github.com/pkg/errors"
"errors"
"syscall"
)

View file

@ -6,7 +6,7 @@ import (
"github.com/0xJacky/Nginx-UI/settings"
"github.com/caarlos0/env/v11"
"github.com/google/uuid"
"github.com/pkg/errors"
"errors"
"github.com/uozi-tech/cosy/logger"
cSettings "github.com/uozi-tech/cosy/settings"
"golang.org/x/crypto/bcrypt"

8
internal/nginx/errors.go Normal file
View file

@ -0,0 +1,8 @@
package nginx
import "github.com/uozi-tech/cosy"
var (
e = cosy.NewErrorScope("nginx")
ErrBlockIsNil = e.New(50001, "block is nil")
)

View file

@ -155,7 +155,7 @@ func buildComment(c []string) string {
func parse(block config.IBlock, ngxConfig *NgxConfig) (err error) {
if block == nil {
err = errors.New("block is nil")
err = ErrBlockIsNil
return
}
for _, v := range block.GetDirectives() {

View file

@ -0,0 +1,14 @@
package nginx_log
import "github.com/uozi-tech/cosy"
var (
e = cosy.NewErrorScope("nginx_log")
ErrLogPathIsNotUnderTheLogDirWhiteList = e.New(50001, "the log path is not under the paths in settings.NginxSettings.LogDirWhiteList")
ErrServerIdxOutOfRange = e.New(50002, "serverIdx out of range")
ErrDirectiveIdxOutOfRange = e.New(50003, "directiveIdx out of range")
ErrLogDirective = e.New(50004, "directive.Params neither access_log nor error_log")
ErrDirectiveParamsIsEmpty = e.New(50005, "directive params is empty")
ErrErrorLogPathIsEmpty = e.New(50006, "settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui.com/guide/config-nginx.html for more information")
ErrAccessLogPathIsEmpty = e.New(50007, "settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui.com/guide/config-nginx.html for more information")
)

View file

@ -0,0 +1,41 @@
package nginx_log
import (
"fmt"
"github.com/0xJacky/Nginx-UI/internal/cache"
"github.com/0xJacky/Nginx-UI/internal/helper"
"github.com/0xJacky/Nginx-UI/internal/nginx"
"github.com/0xJacky/Nginx-UI/settings"
"path/filepath"
)
// IsLogPathUnderWhiteList checks if the log path is under one of the paths in LogDirWhiteList
func IsLogPathUnderWhiteList(path string) bool {
cacheKey := fmt.Sprintf("isLogPathUnderWhiteList:%s", path)
res, ok := cache.Get(cacheKey)
// deep copy
logDirWhiteList := append([]string{}, settings.NginxSettings.LogDirWhiteList...)
accessLogPath := nginx.GetAccessLogPath()
errorLogPath := nginx.GetErrorLogPath()
if accessLogPath != "" {
logDirWhiteList = append(logDirWhiteList, filepath.Dir(accessLogPath))
}
if errorLogPath != "" {
logDirWhiteList = append(logDirWhiteList, filepath.Dir(errorLogPath))
}
// no cache, check it
if !ok {
for _, whitePath := range logDirWhiteList {
if helper.IsUnderDirectory(path, whitePath) {
cache.Set(cacheKey, true, 0)
return true
}
}
return false
}
return res.(bool)
}

View file

@ -11,9 +11,9 @@ var (
ErrNginxConfNotIncludeSitesEnabled = e.New(4043, "Nginx conf not include sites-enabled")
ErrorNginxConfNoStreamBlock = e.New(4044, "Nginx conf no stream block")
ErrNginxConfNotIncludeStreamEnabled = e.New(4045, "Nginx conf not include stream-enabled")
ErrFailedToCreateBackup = e.New(5001, "Failed to create backup")
ErrFailedToCreateBackup = e.New(5002, "Failed to create backup")
ErrSitesAvailableNotExist = e.New(4046, "Sites-available directory not exist")
ErrSitesEnabledNotExist = e.New(4047, "Sites-enabled directory not exist")
ErrStreamAvailableNotExist = e.New(4048, "Stream-available directory not exist")
ErrStreamEnabledNotExist = e.New(4049, "Stream-enabled directory not exist")
ErrStreamAvailableNotExist = e.New(4048, "Streams-available directory not exist")
ErrStreamEnabledNotExist = e.New(4049, "Streams-enabled directory not exist")
)

View file

@ -6,7 +6,6 @@ import (
"time"
"github.com/0xJacky/Nginx-UI/internal/nginx"
"github.com/spf13/cast"
"github.com/tufanbarisyildirim/gonginx/config"
"github.com/tufanbarisyildirim/gonginx/dumper"
"github.com/tufanbarisyildirim/gonginx/parser"
@ -88,7 +87,7 @@ func FixNginxConfIncludeSites() error {
}
// create a backup file (+.bak.timestamp)
backupPath := path + ".bak." + cast.ToString(time.Now().Unix())
backupPath := fmt.Sprintf("%s.bak.%d", path, time.Now().Unix())
err = os.WriteFile(backupPath, content, 0644)
if err != nil {
return ErrFailedToCreateBackup
@ -133,7 +132,7 @@ func FixNginxConfIncludeStreams() error {
}
// create a backup file (+.bak.timestamp)
backupPath := path + ".bak." + cast.ToString(time.Now().Unix())
backupPath := fmt.Sprintf("%s.bak.%d", path, time.Now().Unix())
err = os.WriteFile(backupPath, content, 0644)
if err != nil {
return ErrFailedToCreateBackup

View file

@ -29,11 +29,11 @@ func Delete(name string) (err error) {
enabledPath := nginx.GetConfPath("sites-enabled", name)
if !helper.FileExists(availablePath) {
return fmt.Errorf("site not found")
return ErrSiteNotFound
}
if helper.FileExists(enabledPath) {
return fmt.Errorf("site is enabled")
return ErrSiteIsEnabled
}
certModel := model.Cert{Filename: name}

View file

@ -3,7 +3,6 @@ package site
import (
"github.com/0xJacky/Nginx-UI/internal/helper"
"github.com/0xJacky/Nginx-UI/internal/nginx"
"github.com/pkg/errors"
)
// Duplicate duplicates a site by copying the file
@ -12,7 +11,7 @@ func Duplicate(src, dst string) (err error) {
dst = nginx.GetConfPath("sites-available", dst)
if helper.FileExists(dst) {
return errors.New("file exists")
return ErrDstFileExists
}
_, err = helper.CopyFile(src, dst)

10
internal/site/errors.go Normal file
View file

@ -0,0 +1,10 @@
package site
import "github.com/uozi-tech/cosy"
var (
e = cosy.NewErrorScope("site")
ErrSiteNotFound = e.New(40401, "site not found")
ErrDstFileExists = e.New(50001, "destination file already exists")
ErrSiteIsEnabled = e.New(50002, "site is enabled")
)

View file

@ -24,7 +24,7 @@ func Rename(oldName string, newName string) (err error) {
// check if dst file exists, do not rename
if helper.FileExists(newPath) {
return fmt.Errorf("file exists")
return ErrDstFileExists
}
s := query.Site
@ -84,9 +84,9 @@ func syncRename(oldName, newName string) {
client.SetBaseURL(node.URL)
resp, err := client.R().
SetHeader("X-Node-Secret", node.Token).
SetBody(map[string]string{
"new_name": newName,
}).
SetBody(map[string]string{
"new_name": newName,
}).
Post(fmt.Sprintf("/api/sites/%s/rename", oldName))
if err != nil {
notification.Error("Rename Remote Site Error", err.Error())

View file

@ -19,7 +19,7 @@ import (
func Save(name string, content string, overwrite bool, siteCategoryId uint64, syncNodeIds []uint64) (err error) {
path := nginx.GetConfPath("sites-available", name)
if !overwrite && helper.FileExists(path) {
return fmt.Errorf("file exists")
return ErrDstFileExists
}
err = os.WriteFile(path, []byte(content), 0644)

15
internal/user/errors.go Normal file
View file

@ -0,0 +1,15 @@
package user
import "github.com/uozi-tech/cosy"
var (
e = cosy.NewErrorScope("user")
ErrPasswordIncorrect = e.New(40301, "password incorrect")
ErrUserBanned = e.New(40303, "user banned")
ErrOTPCode = e.New(40304, "invalid otp code")
ErrRecoveryCode = e.New(40305, "invalid recovery code")
ErrWebAuthnNotConfigured = e.New(50000, "WebAuthn settings are not configured")
ErrUserNotEnabledOTPAs2FA = e.New(50001, "user not enabled otp as 2fa")
ErrOTPOrRecoveryCodeEmpty = e.New(50002, "otp or recovery code empty")
ErrSessionNotFound = e.New(40401, "session not found")
)

View file

@ -1,7 +1,6 @@
package user
import (
"errors"
"github.com/0xJacky/Nginx-UI/model"
"github.com/0xJacky/Nginx-UI/query"
"github.com/0xJacky/Nginx-UI/settings"
@ -9,11 +8,6 @@ import (
"time"
)
var (
ErrPasswordIncorrect = errors.New("password incorrect")
ErrUserBanned = errors.New("user banned")
)
func Login(name string, password string) (user *model.User, err error) {
u := query.User

View file

@ -9,16 +9,10 @@ import (
"github.com/0xJacky/Nginx-UI/internal/crypto"
"github.com/0xJacky/Nginx-UI/model"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/pquerna/otp/totp"
"time"
)
var (
ErrOTPCode = errors.New("invalid otp code")
ErrRecoveryCode = errors.New("invalid recovery code")
)
func VerifyOTP(user *model.User, otp, recoveryCode string) (err error) {
if otp != "" {
decrypted, err := crypto.AesDecrypt(user.OTPSecret)