Docker template generator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

monitor.go 2.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package certs
  2. import (
  3. "github.com/csmith/dotege/model"
  4. "go.uber.org/zap"
  5. "io/ioutil"
  6. "path"
  7. "strings"
  8. )
  9. // CertificateMonitor handles scanning for new/updated certificates
  10. type CertificateMonitor struct {
  11. logger *zap.SugaredLogger
  12. channel chan<- model.FoundCertificate
  13. directories []string
  14. certs map[string]*model.FoundCertificate
  15. }
  16. // NewCertificateManager creates a new CertificateMonitor.
  17. func NewCertificateManager(logger *zap.SugaredLogger, channel chan<- model.FoundCertificate) *CertificateMonitor {
  18. return &CertificateMonitor{
  19. logger: logger,
  20. channel: channel,
  21. }
  22. }
  23. // AddDirectory adds a new directory to monitor
  24. func (c *CertificateMonitor) AddDirectory(directory string) {
  25. c.directories = append(c.directories, directory)
  26. go c.scanForFolders(directory)
  27. }
  28. func (c *CertificateMonitor) scanForFolders(dir string) {
  29. dirs, err := ioutil.ReadDir(dir)
  30. if err != nil {
  31. c.logger.Errorf("Unable to read directory %s - %s", dir, err.Error())
  32. return
  33. }
  34. for _, d := range dirs {
  35. if d.IsDir() {
  36. c.scanForCerts(d.Name(), path.Join(dir, d.Name()))
  37. }
  38. }
  39. }
  40. func (c *CertificateMonitor) scanForCerts(vhost string, dir string) {
  41. files, err := ioutil.ReadDir(dir)
  42. if err != nil {
  43. c.logger.Errorf("Unable to read directory %s - %s", dir, err.Error())
  44. return
  45. }
  46. cert := model.FoundCertificate{}
  47. for _, f := range files {
  48. ext := path.Ext(f.Name())
  49. base := path.Base(f.Name())
  50. if ext == "pem" {
  51. prefix := strings.Split(base, "-")[0]
  52. added := maybeAddPart(&cert, prefix, path.Join(dir, f.Name()))
  53. if added && f.ModTime().After(cert.ModTime) {
  54. cert.ModTime = f.ModTime()
  55. }
  56. }
  57. }
  58. c.maybeAddCert(vhost, cert)
  59. }
  60. func maybeAddPart(cert *model.FoundCertificate, part string, path string) bool {
  61. switch part {
  62. case "cert":
  63. cert.Cert = path
  64. case "chain":
  65. cert.Chain = path
  66. case "fullchain":
  67. cert.FullChain = path
  68. case "privkey":
  69. cert.PrivateKey = path
  70. default:
  71. return false
  72. }
  73. return true
  74. }
  75. func (c *CertificateMonitor) maybeAddCert(vhost string, cert model.FoundCertificate) {
  76. if len(cert.Cert) > 0 && len(cert.Chain) > 0 && len(cert.FullChain) > 0 && len(cert.PrivateKey) > 0 {
  77. if existing, ok := c.certs[vhost]; ok {
  78. if cert.ModTime.After(existing.ModTime) {
  79. c.logger.Debugf("Found newer certificate files for %s in %s", vhost, path.Dir(cert.Cert))
  80. c.certs[vhost] = &cert
  81. c.channel <- cert
  82. }
  83. } else {
  84. c.logger.Debugf("Found new certificate files for %s in %s", vhost, path.Dir(cert.Cert))
  85. c.certs[vhost] = &cert
  86. c.channel <- cert
  87. }
  88. }
  89. }