Skip to content

Commit 8581bdd

Browse files
committed
enhance: validate certificate content before save
1 parent d67b842 commit 8581bdd

File tree

7 files changed

+305
-168
lines changed

7 files changed

+305
-168
lines changed

api/api.go

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,12 @@ import (
44
"errors"
55
"github.com/0xJacky/Nginx-UI/internal/logger"
66
"github.com/gin-gonic/gin"
7-
"github.com/gin-gonic/gin/binding"
87
val "github.com/go-playground/validator/v10"
98
"net/http"
109
"reflect"
11-
"regexp"
1210
"strings"
1311
)
1412

15-
func init() {
16-
if v, ok := binding.Validator.Engine().(*val.Validate); ok {
17-
err := v.RegisterValidation("alphanumdash", func(fl val.FieldLevel) bool {
18-
return regexp.MustCompile(`^[a-zA-Z0-9-]+$`).MatchString(fl.Field().String())
19-
})
20-
21-
if err != nil {
22-
logger.Fatal(err)
23-
}
24-
return
25-
}
26-
logger.Fatal("binding validator engine is not initialized")
27-
}
28-
2913
func ErrHandler(c *gin.Context, err error) {
3014
logger.GetLogger().Errorln(err)
3115
c.JSON(http.StatusInternalServerError, gin.H{
@@ -54,11 +38,18 @@ func BindAndValid(c *gin.Context, target interface{}) bool {
5438
return false
5539
}
5640

57-
t := reflect.TypeOf(target).Elem()
41+
t := reflect.TypeOf(target)
5842
errorsMap := make(map[string]interface{})
5943
for _, value := range verrs {
6044
var path []string
61-
getJsonPath(t, value.StructNamespace(), &path)
45+
46+
namespace := strings.Split(value.StructNamespace(), ".")
47+
48+
if t.Name() == "" && len(namespace) > 1 {
49+
namespace = namespace[1:]
50+
}
51+
52+
getJsonPath(t.Elem(), namespace, &path)
6253
insertError(errorsMap, path, value.Tag())
6354
}
6455

@@ -75,11 +66,7 @@ func BindAndValid(c *gin.Context, target interface{}) bool {
7566
}
7667

7768
// findField recursively finds the field in a nested struct
78-
func getJsonPath(t reflect.Type, namespace string, path *[]string) {
79-
fields := strings.Split(namespace, ".")
80-
if len(fields) == 0 {
81-
return
82-
}
69+
func getJsonPath(t reflect.Type, fields []string, path *[]string) {
8370
f, ok := t.FieldByName(fields[0])
8471
if !ok {
8572
return
@@ -88,7 +75,7 @@ func getJsonPath(t reflect.Type, namespace string, path *[]string) {
8875
*path = append(*path, f.Tag.Get("json"))
8976

9077
if len(fields) > 1 {
91-
subFields := strings.Join(fields[1:], ".")
78+
subFields := fields[1:]
9279
getJsonPath(f.Type, subFields, path)
9380
}
9481
}

api/certificate/certificate.go

Lines changed: 144 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,174 +1,174 @@
11
package certificate
22

33
import (
4-
"github.com/0xJacky/Nginx-UI/api"
5-
"github.com/0xJacky/Nginx-UI/api/cosy"
6-
"github.com/0xJacky/Nginx-UI/internal/cert"
7-
"github.com/0xJacky/Nginx-UI/model"
8-
"github.com/0xJacky/Nginx-UI/query"
9-
"github.com/gin-gonic/gin"
10-
"github.com/spf13/cast"
11-
"net/http"
12-
"os"
4+
"github.com/0xJacky/Nginx-UI/api"
5+
"github.com/0xJacky/Nginx-UI/api/cosy"
6+
"github.com/0xJacky/Nginx-UI/internal/cert"
7+
"github.com/0xJacky/Nginx-UI/model"
8+
"github.com/0xJacky/Nginx-UI/query"
9+
"github.com/gin-gonic/gin"
10+
"github.com/spf13/cast"
11+
"net/http"
12+
"os"
1313
)
1414

1515
type APICertificate struct {
16-
*model.Cert
17-
SSLCertificate string `json:"ssl_certificate,omitempty"`
18-
SSLCertificateKey string `json:"ssl_certificate_key,omitempty"`
19-
CertificateInfo *cert.Info `json:"certificate_info,omitempty"`
16+
*model.Cert
17+
SSLCertificate string `json:"ssl_certificate,omitempty"`
18+
SSLCertificateKey string `json:"ssl_certificate_key,omitempty"`
19+
CertificateInfo *cert.Info `json:"certificate_info,omitempty"`
2020
}
2121

2222
func Transformer(certModel *model.Cert) (certificate *APICertificate) {
23-
var sslCertificationBytes, sslCertificationKeyBytes []byte
24-
var certificateInfo *cert.Info
25-
if certModel.SSLCertificatePath != "" {
26-
if _, err := os.Stat(certModel.SSLCertificatePath); err == nil {
27-
sslCertificationBytes, _ = os.ReadFile(certModel.SSLCertificatePath)
28-
}
29-
30-
certificateInfo, _ = cert.GetCertInfo(certModel.SSLCertificatePath)
31-
}
32-
33-
if certModel.SSLCertificateKeyPath != "" {
34-
if _, err := os.Stat(certModel.SSLCertificateKeyPath); err == nil {
35-
sslCertificationKeyBytes, _ = os.ReadFile(certModel.SSLCertificateKeyPath)
36-
}
37-
}
38-
39-
return &APICertificate{
40-
Cert: certModel,
41-
SSLCertificate: string(sslCertificationBytes),
42-
SSLCertificateKey: string(sslCertificationKeyBytes),
43-
CertificateInfo: certificateInfo,
44-
}
23+
var sslCertificationBytes, sslCertificationKeyBytes []byte
24+
var certificateInfo *cert.Info
25+
if certModel.SSLCertificatePath != "" {
26+
if _, err := os.Stat(certModel.SSLCertificatePath); err == nil {
27+
sslCertificationBytes, _ = os.ReadFile(certModel.SSLCertificatePath)
28+
if !cert.IsPublicKey(string(sslCertificationBytes)) {
29+
sslCertificationBytes = []byte{}
30+
}
31+
}
32+
33+
certificateInfo, _ = cert.GetCertInfo(certModel.SSLCertificatePath)
34+
}
35+
36+
if certModel.SSLCertificateKeyPath != "" {
37+
if _, err := os.Stat(certModel.SSLCertificateKeyPath); err == nil {
38+
sslCertificationKeyBytes, _ = os.ReadFile(certModel.SSLCertificateKeyPath)
39+
if !cert.IsPrivateKey(string(sslCertificationKeyBytes)) {
40+
sslCertificationKeyBytes = []byte{}
41+
}
42+
}
43+
}
44+
45+
return &APICertificate{
46+
Cert: certModel,
47+
SSLCertificate: string(sslCertificationBytes),
48+
SSLCertificateKey: string(sslCertificationKeyBytes),
49+
CertificateInfo: certificateInfo,
50+
}
4551
}
4652

4753
func GetCertList(c *gin.Context) {
48-
cosy.Core[model.Cert](c).SetFussy("name", "domain").SetTransformer(func(m *model.Cert) any {
54+
cosy.Core[model.Cert](c).SetFussy("name", "domain").SetTransformer(func(m *model.Cert) any {
4955

50-
info, _ := cert.GetCertInfo(m.SSLCertificatePath)
56+
info, _ := cert.GetCertInfo(m.SSLCertificatePath)
5157

52-
return APICertificate{
53-
Cert: m,
54-
CertificateInfo: info,
55-
}
56-
}).PagingList()
58+
return APICertificate{
59+
Cert: m,
60+
CertificateInfo: info,
61+
}
62+
}).PagingList()
5763
}
5864

5965
func GetCert(c *gin.Context) {
60-
q := query.Cert
66+
q := query.Cert
6167

62-
certModel, err := q.FirstByID(cast.ToInt(c.Param("id")))
68+
certModel, err := q.FirstByID(cast.ToInt(c.Param("id")))
6369

64-
if err != nil {
65-
api.ErrHandler(c, err)
66-
return
67-
}
70+
if err != nil {
71+
api.ErrHandler(c, err)
72+
return
73+
}
6874

69-
c.JSON(http.StatusOK, Transformer(certModel))
75+
c.JSON(http.StatusOK, Transformer(certModel))
76+
}
77+
78+
type certJson struct {
79+
Name string `json:"name"`
80+
SSLCertificatePath string `json:"ssl_certificate_path" binding:"publickey_path"`
81+
SSLCertificateKeyPath string `json:"ssl_certificate_key_path" binding:"privatekey_path"`
82+
SSLCertificate string `json:"ssl_certificate" binding:"omitempty,publickey"`
83+
SSLCertificateKey string `json:"ssl_certificate_key" binding:"omitempty,privatekey"`
84+
ChallengeMethod string `json:"challenge_method"`
85+
DnsCredentialID int `json:"dns_credential_id"`
7086
}
7187

7288
func AddCert(c *gin.Context) {
73-
var json struct {
74-
Name string `json:"name"`
75-
SSLCertificatePath string `json:"ssl_certificate_path" binding:"required"`
76-
SSLCertificateKeyPath string `json:"ssl_certificate_key_path" binding:"required"`
77-
SSLCertificate string `json:"ssl_certificate"`
78-
SSLCertificateKey string `json:"ssl_certificate_key"`
79-
ChallengeMethod string `json:"challenge_method"`
80-
DnsCredentialID int `json:"dns_credential_id"`
81-
}
82-
if !api.BindAndValid(c, &json) {
83-
return
84-
}
85-
certModel := &model.Cert{
86-
Name: json.Name,
87-
SSLCertificatePath: json.SSLCertificatePath,
88-
SSLCertificateKeyPath: json.SSLCertificateKeyPath,
89-
ChallengeMethod: json.ChallengeMethod,
90-
DnsCredentialID: json.DnsCredentialID,
91-
}
92-
93-
err := certModel.Insert()
94-
95-
if err != nil {
96-
api.ErrHandler(c, err)
97-
return
98-
}
99-
100-
content := &cert.Content{
101-
SSLCertificatePath: json.SSLCertificatePath,
102-
SSLCertificateKeyPath: json.SSLCertificateKeyPath,
103-
SSLCertificate: json.SSLCertificate,
104-
SSLCertificateKey: json.SSLCertificateKey,
105-
}
106-
107-
err = content.WriteFile()
108-
109-
if err != nil {
110-
api.ErrHandler(c, err)
111-
return
112-
}
113-
114-
c.JSON(http.StatusOK, Transformer(certModel))
89+
var json certJson
90+
if !api.BindAndValid(c, &json) {
91+
return
92+
}
93+
certModel := &model.Cert{
94+
Name: json.Name,
95+
SSLCertificatePath: json.SSLCertificatePath,
96+
SSLCertificateKeyPath: json.SSLCertificateKeyPath,
97+
ChallengeMethod: json.ChallengeMethod,
98+
DnsCredentialID: json.DnsCredentialID,
99+
}
100+
101+
err := certModel.Insert()
102+
103+
if err != nil {
104+
api.ErrHandler(c, err)
105+
return
106+
}
107+
108+
content := &cert.Content{
109+
SSLCertificatePath: json.SSLCertificatePath,
110+
SSLCertificateKeyPath: json.SSLCertificateKeyPath,
111+
SSLCertificate: json.SSLCertificate,
112+
SSLCertificateKey: json.SSLCertificateKey,
113+
}
114+
115+
err = content.WriteFile()
116+
117+
if err != nil {
118+
api.ErrHandler(c, err)
119+
return
120+
}
121+
122+
c.JSON(http.StatusOK, Transformer(certModel))
115123
}
116124

117125
func ModifyCert(c *gin.Context) {
118-
id := cast.ToInt(c.Param("id"))
119-
120-
var json struct {
121-
Name string `json:"name"`
122-
SSLCertificatePath string `json:"ssl_certificate_path" binding:"required"`
123-
SSLCertificateKeyPath string `json:"ssl_certificate_key_path" binding:"required"`
124-
SSLCertificate string `json:"ssl_certificate"`
125-
SSLCertificateKey string `json:"ssl_certificate_key"`
126-
ChallengeMethod string `json:"challenge_method"`
127-
DnsCredentialID int `json:"dns_credential_id"`
128-
}
129-
130-
if !api.BindAndValid(c, &json) {
131-
return
132-
}
133-
134-
q := query.Cert
135-
136-
certModel, err := q.FirstByID(id)
137-
if err != nil {
138-
api.ErrHandler(c, err)
139-
return
140-
}
141-
142-
err = certModel.Updates(&model.Cert{
143-
Name: json.Name,
144-
SSLCertificatePath: json.SSLCertificatePath,
145-
SSLCertificateKeyPath: json.SSLCertificateKeyPath,
146-
ChallengeMethod: json.ChallengeMethod,
147-
DnsCredentialID: json.DnsCredentialID,
148-
})
149-
150-
if err != nil {
151-
api.ErrHandler(c, err)
152-
return
153-
}
154-
155-
content := &cert.Content{
156-
SSLCertificatePath: json.SSLCertificatePath,
157-
SSLCertificateKeyPath: json.SSLCertificateKeyPath,
158-
SSLCertificate: json.SSLCertificate,
159-
SSLCertificateKey: json.SSLCertificateKey,
160-
}
161-
162-
err = content.WriteFile()
163-
164-
if err != nil {
165-
api.ErrHandler(c, err)
166-
return
167-
}
168-
169-
GetCert(c)
126+
id := cast.ToInt(c.Param("id"))
127+
128+
var json certJson
129+
130+
if !api.BindAndValid(c, &json) {
131+
return
132+
}
133+
134+
q := query.Cert
135+
136+
certModel, err := q.FirstByID(id)
137+
if err != nil {
138+
api.ErrHandler(c, err)
139+
return
140+
}
141+
142+
err = certModel.Updates(&model.Cert{
143+
Name: json.Name,
144+
SSLCertificatePath: json.SSLCertificatePath,
145+
SSLCertificateKeyPath: json.SSLCertificateKeyPath,
146+
ChallengeMethod: json.ChallengeMethod,
147+
DnsCredentialID: json.DnsCredentialID,
148+
})
149+
150+
if err != nil {
151+
api.ErrHandler(c, err)
152+
return
153+
}
154+
155+
content := &cert.Content{
156+
SSLCertificatePath: json.SSLCertificatePath,
157+
SSLCertificateKeyPath: json.SSLCertificateKeyPath,
158+
SSLCertificate: json.SSLCertificate,
159+
SSLCertificateKey: json.SSLCertificateKey,
160+
}
161+
162+
err = content.WriteFile()
163+
164+
if err != nil {
165+
api.ErrHandler(c, err)
166+
return
167+
}
168+
169+
GetCert(c)
170170
}
171171

172172
func RemoveCert(c *gin.Context) {
173-
cosy.Core[model.Cert](c).Destroy()
173+
cosy.Core[model.Cert](c).Destroy()
174174
}

0 commit comments

Comments
 (0)