revoke.go 3.0 KB

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