cert.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. package api
  2. import (
  3. "github.com/0xJacky/Nginx-UI/logger"
  4. "github.com/0xJacky/Nginx-UI/server/internal/cert"
  5. "github.com/0xJacky/Nginx-UI/server/internal/cert/dns"
  6. "github.com/0xJacky/Nginx-UI/server/internal/nginx"
  7. "github.com/0xJacky/Nginx-UI/server/model"
  8. "github.com/gin-gonic/gin"
  9. "github.com/gorilla/websocket"
  10. "github.com/spf13/cast"
  11. "net/http"
  12. "os"
  13. "path/filepath"
  14. "strings"
  15. )
  16. const (
  17. Success = "success"
  18. Info = "info"
  19. Error = "error"
  20. )
  21. type IssueCertResponse struct {
  22. Status string `json:"status"`
  23. Message string `json:"message"`
  24. SSLCertificate string `json:"ssl_certificate,omitempty"`
  25. SSLCertificateKey string `json:"ssl_certificate_key,omitempty"`
  26. }
  27. func handleIssueCertLogChan(conn *websocket.Conn, logChan chan string) {
  28. defer func() {
  29. if err := recover(); err != nil {
  30. logger.Error(err)
  31. }
  32. }()
  33. for logString := range logChan {
  34. err := conn.WriteJSON(IssueCertResponse{
  35. Status: Info,
  36. Message: logString,
  37. })
  38. if err != nil {
  39. logger.Error(err)
  40. return
  41. }
  42. }
  43. }
  44. func IssueCert(c *gin.Context) {
  45. var upGrader = websocket.Upgrader{
  46. CheckOrigin: func(r *http.Request) bool {
  47. return true
  48. },
  49. }
  50. // upgrade http to websocket
  51. ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
  52. if err != nil {
  53. logger.Error(err)
  54. return
  55. }
  56. defer func(ws *websocket.Conn) {
  57. _ = ws.Close()
  58. }(ws)
  59. // read
  60. buffer := &cert.ConfigPayload{}
  61. err = ws.ReadJSON(buffer)
  62. if err != nil {
  63. logger.Error(err)
  64. return
  65. }
  66. certModel, err := model.FirstOrCreateCert(c.Param("name"))
  67. if err != nil {
  68. logger.Error(err)
  69. return
  70. }
  71. logChan := make(chan string, 1)
  72. errChan := make(chan error, 1)
  73. go cert.IssueCert(buffer, logChan, errChan)
  74. go handleIssueCertLogChan(ws, logChan)
  75. // block, until errChan closes
  76. for err = range errChan {
  77. errLog := &cert.AutoCertErrorLog{}
  78. errLog.SetCertModel(&certModel)
  79. errLog.Exit("issue cert", err)
  80. err = ws.WriteJSON(IssueCertResponse{
  81. Status: Error,
  82. Message: err.Error(),
  83. })
  84. if err != nil {
  85. logger.Error(err)
  86. return
  87. }
  88. return
  89. }
  90. certDirName := strings.Join(buffer.ServerName, "_")
  91. sslCertificatePath := nginx.GetConfPath("ssl", certDirName, "fullchain.cer")
  92. sslCertificateKeyPath := nginx.GetConfPath("ssl", certDirName, "private.key")
  93. err = certModel.Updates(&model.Cert{
  94. Domains: buffer.ServerName,
  95. SSLCertificatePath: sslCertificatePath,
  96. SSLCertificateKeyPath: sslCertificateKeyPath,
  97. })
  98. if err != nil {
  99. logger.Error(err)
  100. err = ws.WriteJSON(IssueCertResponse{
  101. Status: Error,
  102. Message: err.Error(),
  103. })
  104. return
  105. }
  106. certModel.ClearLog()
  107. err = ws.WriteJSON(IssueCertResponse{
  108. Status: Success,
  109. Message: "Issued certificate successfully",
  110. SSLCertificate: sslCertificatePath,
  111. SSLCertificateKey: sslCertificateKeyPath,
  112. })
  113. if err != nil {
  114. logger.Error(err)
  115. return
  116. }
  117. }
  118. func GetCertList(c *gin.Context) {
  119. certList := model.GetCertList(c.Query("name"), c.Query("domain"))
  120. c.JSON(http.StatusOK, gin.H{
  121. "data": certList,
  122. })
  123. }
  124. func getCert(c *gin.Context, certModel *model.Cert) {
  125. type resp struct {
  126. *model.Cert
  127. SSLCertification string `json:"ssl_certification"`
  128. SSLCertificationKey string `json:"ssl_certification_key"`
  129. CertificateInfo *CertificateInfo `json:"certificate_info,omitempty"`
  130. }
  131. var sslCertificationBytes, sslCertificationKeyBytes []byte
  132. var certificateInfo *CertificateInfo
  133. if certModel.SSLCertificatePath != "" {
  134. if _, err := os.Stat(certModel.SSLCertificatePath); err == nil {
  135. sslCertificationBytes, _ = os.ReadFile(certModel.SSLCertificatePath)
  136. }
  137. pubKey, err := cert.GetCertInfo(certModel.SSLCertificatePath)
  138. if err != nil {
  139. ErrHandler(c, err)
  140. return
  141. }
  142. certificateInfo = &CertificateInfo{
  143. SubjectName: pubKey.Subject.CommonName,
  144. IssuerName: pubKey.Issuer.CommonName,
  145. NotAfter: pubKey.NotAfter,
  146. NotBefore: pubKey.NotBefore,
  147. }
  148. }
  149. if certModel.SSLCertificateKeyPath != "" {
  150. if _, err := os.Stat(certModel.SSLCertificateKeyPath); err == nil {
  151. sslCertificationKeyBytes, _ = os.ReadFile(certModel.SSLCertificateKeyPath)
  152. }
  153. }
  154. c.JSON(http.StatusOK, resp{
  155. certModel,
  156. string(sslCertificationBytes),
  157. string(sslCertificationKeyBytes),
  158. certificateInfo,
  159. })
  160. }
  161. func GetCert(c *gin.Context) {
  162. certModel, err := model.FirstCertByID(cast.ToInt(c.Param("id")))
  163. if err != nil {
  164. ErrHandler(c, err)
  165. return
  166. }
  167. getCert(c, &certModel)
  168. }
  169. func AddCert(c *gin.Context) {
  170. var json struct {
  171. Name string `json:"name"`
  172. SSLCertificatePath string `json:"ssl_certificate_path" binding:"required"`
  173. SSLCertificateKeyPath string `json:"ssl_certificate_key_path" binding:"required"`
  174. SSLCertification string `json:"ssl_certification"`
  175. SSLCertificationKey string `json:"ssl_certification_key"`
  176. }
  177. if !BindAndValid(c, &json) {
  178. return
  179. }
  180. certModel := &model.Cert{
  181. Name: json.Name,
  182. SSLCertificatePath: json.SSLCertificatePath,
  183. SSLCertificateKeyPath: json.SSLCertificateKeyPath,
  184. }
  185. err := certModel.Insert()
  186. if err != nil {
  187. ErrHandler(c, err)
  188. return
  189. }
  190. err = os.MkdirAll(filepath.Dir(json.SSLCertificatePath), 0644)
  191. if err != nil {
  192. ErrHandler(c, err)
  193. return
  194. }
  195. err = os.MkdirAll(filepath.Dir(json.SSLCertificateKeyPath), 0644)
  196. if err != nil {
  197. ErrHandler(c, err)
  198. return
  199. }
  200. if json.SSLCertification != "" {
  201. err = os.WriteFile(json.SSLCertificatePath, []byte(json.SSLCertification), 0644)
  202. if err != nil {
  203. ErrHandler(c, err)
  204. return
  205. }
  206. }
  207. if json.SSLCertificationKey != "" {
  208. err = os.WriteFile(json.SSLCertificateKeyPath, []byte(json.SSLCertificationKey), 0644)
  209. if err != nil {
  210. ErrHandler(c, err)
  211. return
  212. }
  213. }
  214. getCert(c, certModel)
  215. }
  216. func ModifyCert(c *gin.Context) {
  217. id := cast.ToInt(c.Param("id"))
  218. var json struct {
  219. Name string `json:"name"`
  220. SSLCertificatePath string `json:"ssl_certificate_path" binding:"required"`
  221. SSLCertificateKeyPath string `json:"ssl_certificate_key_path" binding:"required"`
  222. SSLCertification string `json:"ssl_certification"`
  223. SSLCertificationKey string `json:"ssl_certification_key"`
  224. }
  225. if !BindAndValid(c, &json) {
  226. return
  227. }
  228. certModel, err := model.FirstCertByID(id)
  229. if err != nil {
  230. ErrHandler(c, err)
  231. return
  232. }
  233. err = certModel.Updates(&model.Cert{
  234. Name: json.Name,
  235. SSLCertificatePath: json.SSLCertificatePath,
  236. SSLCertificateKeyPath: json.SSLCertificateKeyPath,
  237. })
  238. if err != nil {
  239. ErrHandler(c, err)
  240. return
  241. }
  242. err = os.MkdirAll(filepath.Dir(json.SSLCertificatePath), 0644)
  243. if err != nil {
  244. ErrHandler(c, err)
  245. return
  246. }
  247. err = os.MkdirAll(filepath.Dir(json.SSLCertificateKeyPath), 0644)
  248. if err != nil {
  249. ErrHandler(c, err)
  250. return
  251. }
  252. if json.SSLCertification != "" {
  253. err = os.WriteFile(json.SSLCertificatePath, []byte(json.SSLCertification), 0644)
  254. if err != nil {
  255. ErrHandler(c, err)
  256. return
  257. }
  258. }
  259. if json.SSLCertificationKey != "" {
  260. err = os.WriteFile(json.SSLCertificateKeyPath, []byte(json.SSLCertificationKey), 0644)
  261. if err != nil {
  262. ErrHandler(c, err)
  263. return
  264. }
  265. }
  266. GetCert(c)
  267. }
  268. func RemoveCert(c *gin.Context) {
  269. id := cast.ToInt(c.Param("id"))
  270. certModel, err := model.FirstCertByID(id)
  271. if err != nil {
  272. ErrHandler(c, err)
  273. return
  274. }
  275. err = certModel.Remove()
  276. if err != nil {
  277. ErrHandler(c, err)
  278. return
  279. }
  280. c.JSON(http.StatusNoContent, nil)
  281. }
  282. func GetDNSProvidersList(c *gin.Context) {
  283. c.JSON(http.StatusOK, dns.GetProvidersList())
  284. }
  285. func GetDNSProvider(c *gin.Context) {
  286. code := c.Param("code")
  287. provider, ok := dns.GetProvider(code)
  288. if !ok {
  289. c.JSON(http.StatusNotFound, gin.H{
  290. "message": "provider not found",
  291. })
  292. return
  293. }
  294. c.JSON(http.StatusOK, provider)
  295. }