certificate.go 6.1 KB

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