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.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  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.logger.Infof("Adding certificate directory %s", directory)
  26. c.directories = append(c.directories, directory)
  27. go c.scanForFolders(directory)
  28. }
  29. func (c *CertificateMonitor) scanForFolders(dir string) {
  30. c.logger.Debugf("Scanning folder %s for certificates", dir)
  31. dirs, err := ioutil.ReadDir(dir)
  32. if err != nil {
  33. c.logger.Errorf("Unable to read directory %s - %s", dir, err.Error())
  34. return
  35. }
  36. for _, d := range dirs {
  37. if d.IsDir() {
  38. c.scanForCerts(d.Name(), path.Join(dir, d.Name()))
  39. }
  40. }
  41. }
  42. func (c *CertificateMonitor) scanForCerts(vhost string, dir string) {
  43. c.logger.Debugf("Scanning folder %s for certificates for %s", dir, vhost)
  44. files, err := ioutil.ReadDir(dir)
  45. if err != nil {
  46. c.logger.Errorf("Unable to read directory %s - %s", dir, err.Error())
  47. return
  48. }
  49. cert := model.FoundCertificate{}
  50. for _, f := range files {
  51. ext := path.Ext(f.Name())
  52. base := path.Base(f.Name())
  53. base = base[:len(base)-len(ext)]
  54. c.logger.Debugf("File %s has extension %s, base name %s", f.Name(), ext, base)
  55. if ext == ".pem" {
  56. prefix := strings.Split(base, "-")[0]
  57. added := maybeAddPart(&cert, prefix, path.Join(dir, f.Name()))
  58. c.logger.Debugf("\tFile prefix is %s, added status %s", prefix, added)
  59. if added && f.ModTime().After(cert.ModTime) {
  60. cert.ModTime = f.ModTime()
  61. }
  62. }
  63. }
  64. c.maybeAddCert(vhost, cert)
  65. }
  66. func maybeAddPart(cert *model.FoundCertificate, part string, path string) bool {
  67. switch part {
  68. case "cert":
  69. cert.Cert = path
  70. case "chain":
  71. cert.Chain = path
  72. case "fullchain":
  73. cert.FullChain = path
  74. case "privkey":
  75. cert.PrivateKey = path
  76. default:
  77. return false
  78. }
  79. return true
  80. }
  81. func (c *CertificateMonitor) maybeAddCert(vhost string, cert model.FoundCertificate) {
  82. if len(cert.Cert) > 0 && len(cert.Chain) > 0 && len(cert.FullChain) > 0 && len(cert.PrivateKey) > 0 {
  83. if existing, ok := c.certs[vhost]; ok {
  84. if cert.ModTime.After(existing.ModTime) {
  85. c.logger.Debugf("Found newer certificate files for %s in %s", vhost, path.Dir(cert.Cert))
  86. c.certs[vhost] = &cert
  87. c.channel <- cert
  88. }
  89. } else {
  90. c.logger.Debugf("Found new certificate files for %s in %s", vhost, path.Dir(cert.Cert))
  91. c.certs[vhost] = &cert
  92. c.channel <- cert
  93. }
  94. }
  95. }