certificate.go 6.4 KB

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