mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 18:35:51 +02:00
enhance(wip): error handle
This commit is contained in:
parent
3f95ae5d90
commit
650196d06a
93 changed files with 5228 additions and 3738 deletions
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
13
internal/cert/errors.go
Normal 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}")
|
||||
)
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
8
internal/config/errors.go
Normal file
8
internal/config/errors.go
Normal 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}")
|
||||
)
|
|
@ -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{
|
||||
|
|
|
@ -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
|
||||
|
|
9
internal/crypto/errors.go
Normal file
9
internal/crypto/errors.go
Normal 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")
|
||||
)
|
|
@ -3,7 +3,7 @@ package helper
|
|||
import (
|
||||
"strings"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/pkg/errors"
|
||||
"errors"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
|
|
|
@ -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
8
internal/nginx/errors.go
Normal 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")
|
||||
)
|
|
@ -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() {
|
||||
|
|
14
internal/nginx_log/errors.go
Normal file
14
internal/nginx_log/errors.go
Normal 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")
|
||||
)
|
41
internal/nginx_log/nginx_log.go
Normal file
41
internal/nginx_log/nginx_log.go
Normal 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)
|
||||
}
|
|
@ -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")
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
10
internal/site/errors.go
Normal 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")
|
||||
)
|
|
@ -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())
|
||||
|
|
|
@ -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
15
internal/user/errors.go
Normal 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")
|
||||
)
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue