certificate.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. package certificate
  2. import (
  3. "net/http"
  4. "os"
  5. "github.com/0xJacky/Nginx-UI/internal/cert"
  6. "github.com/0xJacky/Nginx-UI/internal/helper"
  7. "github.com/0xJacky/Nginx-UI/internal/nginx"
  8. "github.com/0xJacky/Nginx-UI/internal/notification"
  9. "github.com/0xJacky/Nginx-UI/model"
  10. "github.com/0xJacky/Nginx-UI/query"
  11. "github.com/gin-gonic/gin"
  12. "github.com/go-acme/lego/v4/certcrypto"
  13. "github.com/spf13/cast"
  14. "github.com/uozi-tech/cosy"
  15. )
  16. type APICertificate struct {
  17. *model.Cert
  18. SSLCertificate string `json:"ssl_certificate,omitempty"`
  19. SSLCertificateKey string `json:"ssl_certificate_key,omitempty"`
  20. CertificateInfo *cert.Info `json:"certificate_info,omitempty"`
  21. }
  22. func Transformer(certModel *model.Cert) (certificate *APICertificate) {
  23. var sslCertificationBytes, sslCertificationKeyBytes []byte
  24. var certificateInfo *cert.Info
  25. if certModel.SSLCertificatePath != "" &&
  26. helper.IsUnderDirectory(certModel.SSLCertificatePath, nginx.GetConfPath()) {
  27. if _, err := os.Stat(certModel.SSLCertificatePath); err == nil {
  28. sslCertificationBytes, _ = os.ReadFile(certModel.SSLCertificatePath)
  29. if !cert.IsCertificate(string(sslCertificationBytes)) {
  30. sslCertificationBytes = []byte{}
  31. }
  32. }
  33. certificateInfo, _ = cert.GetCertInfo(certModel.SSLCertificatePath)
  34. }
  35. if certModel.SSLCertificateKeyPath != "" &&
  36. helper.IsUnderDirectory(certModel.SSLCertificateKeyPath, nginx.GetConfPath()) {
  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. return &APICertificate{
  45. Cert: certModel,
  46. SSLCertificate: string(sslCertificationBytes),
  47. SSLCertificateKey: string(sslCertificationKeyBytes),
  48. CertificateInfo: certificateInfo,
  49. }
  50. }
  51. func GetCertList(c *gin.Context) {
  52. cosy.Core[model.Cert](c).SetFussy("name", "domain").SetTransformer(func(m *model.Cert) any {
  53. info, _ := cert.GetCertInfo(m.SSLCertificatePath)
  54. return APICertificate{
  55. Cert: m,
  56. CertificateInfo: info,
  57. }
  58. }).PagingList()
  59. }
  60. func GetCert(c *gin.Context) {
  61. q := query.Cert
  62. certModel, err := q.FirstByID(cast.ToUint64(c.Param("id")))
  63. if err != nil {
  64. cosy.ErrHandler(c, err)
  65. return
  66. }
  67. c.JSON(http.StatusOK, Transformer(certModel))
  68. }
  69. type certJson struct {
  70. Name string `json:"name" binding:"required"`
  71. SSLCertificatePath string `json:"ssl_certificate_path" binding:"required,certificate_path"`
  72. SSLCertificateKeyPath string `json:"ssl_certificate_key_path" binding:"required,privatekey_path"`
  73. SSLCertificate string `json:"ssl_certificate" binding:"omitempty,certificate"`
  74. SSLCertificateKey string `json:"ssl_certificate_key" binding:"omitempty,privatekey"`
  75. KeyType certcrypto.KeyType `json:"key_type" binding:"omitempty,auto_cert_key_type"`
  76. ChallengeMethod string `json:"challenge_method"`
  77. DnsCredentialID uint64 `json:"dns_credential_id"`
  78. ACMEUserID uint64 `json:"acme_user_id"`
  79. SyncNodeIds []uint64 `json:"sync_node_ids"`
  80. }
  81. func AddCert(c *gin.Context) {
  82. var json certJson
  83. if !cosy.BindAndValid(c, &json) {
  84. return
  85. }
  86. certModel := &model.Cert{
  87. Name: json.Name,
  88. SSLCertificatePath: json.SSLCertificatePath,
  89. SSLCertificateKeyPath: json.SSLCertificateKeyPath,
  90. KeyType: json.KeyType,
  91. ChallengeMethod: json.ChallengeMethod,
  92. DnsCredentialID: json.DnsCredentialID,
  93. ACMEUserID: json.ACMEUserID,
  94. SyncNodeIds: json.SyncNodeIds,
  95. }
  96. err := certModel.Insert()
  97. if err != nil {
  98. cosy.ErrHandler(c, err)
  99. return
  100. }
  101. content := &cert.Content{
  102. SSLCertificatePath: json.SSLCertificatePath,
  103. SSLCertificateKeyPath: json.SSLCertificateKeyPath,
  104. SSLCertificate: json.SSLCertificate,
  105. SSLCertificateKey: json.SSLCertificateKey,
  106. }
  107. err = content.WriteFile()
  108. if err != nil {
  109. cosy.ErrHandler(c, err)
  110. return
  111. }
  112. err = cert.SyncToRemoteServer(certModel)
  113. if err != nil {
  114. notification.Error("Sync Certificate Error", err.Error(), nil)
  115. return
  116. }
  117. c.JSON(http.StatusOK, Transformer(certModel))
  118. }
  119. func ModifyCert(c *gin.Context) {
  120. id := cast.ToUint64(c.Param("id"))
  121. var json certJson
  122. if !cosy.BindAndValid(c, &json) {
  123. return
  124. }
  125. q := query.Cert
  126. certModel, err := q.FirstByID(id)
  127. if err != nil {
  128. cosy.ErrHandler(c, err)
  129. return
  130. }
  131. err = certModel.Updates(&model.Cert{
  132. Name: json.Name,
  133. SSLCertificatePath: json.SSLCertificatePath,
  134. SSLCertificateKeyPath: json.SSLCertificateKeyPath,
  135. ChallengeMethod: json.ChallengeMethod,
  136. KeyType: json.KeyType,
  137. DnsCredentialID: json.DnsCredentialID,
  138. ACMEUserID: json.ACMEUserID,
  139. SyncNodeIds: json.SyncNodeIds,
  140. })
  141. if err != nil {
  142. cosy.ErrHandler(c, err)
  143. return
  144. }
  145. content := &cert.Content{
  146. SSLCertificatePath: json.SSLCertificatePath,
  147. SSLCertificateKeyPath: json.SSLCertificateKeyPath,
  148. SSLCertificate: json.SSLCertificate,
  149. SSLCertificateKey: json.SSLCertificateKey,
  150. }
  151. err = content.WriteFile()
  152. if err != nil {
  153. cosy.ErrHandler(c, err)
  154. return
  155. }
  156. err = cert.SyncToRemoteServer(certModel)
  157. if err != nil {
  158. notification.Error("Sync Certificate Error", err.Error(), nil)
  159. return
  160. }
  161. GetCert(c)
  162. }
  163. func RemoveCert(c *gin.Context) {
  164. cosy.Core[model.Cert](c).Destroy()
  165. }
  166. func SyncCertificate(c *gin.Context) {
  167. var json cert.SyncCertificatePayload
  168. if !cosy.BindAndValid(c, &json) {
  169. return
  170. }
  171. certModel := &model.Cert{
  172. Name: json.Name,
  173. SSLCertificatePath: json.SSLCertificatePath,
  174. SSLCertificateKeyPath: json.SSLCertificateKeyPath,
  175. KeyType: json.KeyType,
  176. AutoCert: model.AutoCertSync,
  177. }
  178. db := model.UseDB()
  179. err := db.Where(certModel).FirstOrCreate(certModel).Error
  180. if err != nil {
  181. cosy.ErrHandler(c, err)
  182. return
  183. }
  184. content := &cert.Content{
  185. SSLCertificatePath: json.SSLCertificatePath,
  186. SSLCertificateKeyPath: json.SSLCertificateKeyPath,
  187. SSLCertificate: json.SSLCertificate,
  188. SSLCertificateKey: json.SSLCertificateKey,
  189. }
  190. err = content.WriteFile()
  191. if err != nil {
  192. cosy.ErrHandler(c, err)
  193. return
  194. }
  195. nginx.Reload()
  196. c.JSON(http.StatusOK, gin.H{
  197. "message": "ok",
  198. })
  199. }