revoke.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. package cert
  2. import (
  3. "log"
  4. "os"
  5. "runtime"
  6. "time"
  7. "github.com/0xJacky/Nginx-UI/internal/translation"
  8. "github.com/0xJacky/Nginx-UI/internal/transport"
  9. "github.com/go-acme/lego/v4/lego"
  10. legolog "github.com/go-acme/lego/v4/log"
  11. "github.com/pkg/errors"
  12. "github.com/uozi-tech/cosy/logger"
  13. cSettings "github.com/uozi-tech/cosy/settings"
  14. )
  15. // RevokeCert revokes a certificate and provides log messages through channels
  16. func RevokeCert(payload *ConfigPayload, certLogger *Logger, logChan chan string, errChan chan error) {
  17. lock()
  18. defer unlock()
  19. defer func() {
  20. if err := recover(); err != nil {
  21. buf := make([]byte, 1024)
  22. runtime.Stack(buf, false)
  23. logger.Error(err)
  24. }
  25. }()
  26. // Initialize a channel writer to receive logs
  27. cw := NewChannelWriter()
  28. defer close(errChan)
  29. defer close(cw.Ch)
  30. // Initialize a logger
  31. l := log.New(os.Stderr, "", log.LstdFlags)
  32. l.SetOutput(cw)
  33. // Hijack the logger of lego
  34. oldLogger := legolog.Logger
  35. legolog.Logger = l
  36. // Restore the original logger
  37. defer func() {
  38. legolog.Logger = oldLogger
  39. }()
  40. // Start a goroutine to fetch and process logs from channel
  41. go func() {
  42. for msg := range cw.Ch {
  43. logChan <- string(msg)
  44. }
  45. }()
  46. // Create client for communication with CA server
  47. certLogger.Info(translation.C("[Nginx UI] Preparing for certificate revocation"))
  48. user, err := payload.GetACMEUser()
  49. if err != nil {
  50. errChan <- errors.Wrap(err, "get ACME user error")
  51. return
  52. }
  53. config := lego.NewConfig(user)
  54. config.CADirURL = user.CADir
  55. // Skip TLS check if proxy is configured
  56. if config.HTTPClient != nil {
  57. t, err := transport.NewTransport(
  58. transport.WithProxy(user.Proxy))
  59. if err != nil {
  60. errChan <- errors.Wrap(err, "create transport error")
  61. return
  62. }
  63. config.HTTPClient.Transport = t
  64. }
  65. config.Certificate.KeyType = payload.GetKeyType()
  66. // Create the client
  67. client, err := lego.NewClient(config)
  68. if err != nil {
  69. errChan <- errors.Wrap(err, "create client error")
  70. return
  71. }
  72. revoke(payload, client, certLogger, errChan)
  73. // If the revoked certificate was used for the server itself, reload server TLS certificate
  74. if payload.GetCertificatePath() == cSettings.ServerSettings.SSLCert &&
  75. payload.GetCertificateKeyPath() == cSettings.ServerSettings.SSLKey {
  76. certLogger.Info(translation.C("[Nginx UI] Certificate was used for server, reloading server TLS certificate"))
  77. ReloadServerTLSCertificate()
  78. }
  79. certLogger.Info(translation.C("[Nginx UI] Revocation completed"))
  80. // Wait for logs to be written
  81. time.Sleep(2 * time.Second)
  82. }
  83. // revoke implements the internal certificate revocation logic
  84. func revoke(payload *ConfigPayload, client *lego.Client, l *Logger, errChan chan error) {
  85. l.Info(translation.C("[Nginx UI] Revoking certificate"))
  86. err := client.Certificate.Revoke(payload.Resource.Certificate)
  87. if err != nil {
  88. errChan <- errors.Wrap(err, "revoke certificate error")
  89. return
  90. }
  91. l.Info(translation.C("[Nginx UI] Certificate successfully revoked"))
  92. return
  93. }