|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"github.com/fsnotify/fsnotify"
|
|
|
|
|
"flag"
|
|
|
|
|
"log"
|
|
|
|
|
"os"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"time"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Cert struct {
|
|
|
|
|
PrivateKey string
|
|
|
|
|
PublicKey string
|
|
|
|
|
Owner string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Config struct {
|
|
|
|
|
Source Cert
|
|
|
|
|
Target Cert
|
|
|
|
|
Reload string
|
|
|
|
|
WatchDelay string
|
|
|
|
|
watcher *fsnotify.Watcher
|
|
|
|
|
delay_time time.Duration
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LoadConfig(path string) Config {
|
|
|
|
|
var config Config
|
|
|
|
|
|
|
|
|
|
config_data, err := os.ReadFile(path)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal("invalid config path %s: %v", path, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = json.Unmarshal(config_data, &config)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err, "json format error")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
config.delay_time, err = time.ParseDuration(config.WatchDelay)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("can't parse watch_delay setting %s: %v", config.WatchDelay, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return config
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func ParseOpts() Config {
|
|
|
|
|
var config_file string
|
|
|
|
|
|
|
|
|
|
flag.StringVar(&config_file, "config", "cert-bouncer.json", ".json config to use.")
|
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
|
|
return LoadConfig(config_file)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (cfg *Config) SyncCerts() {
|
|
|
|
|
log.Println("SYNC CERTS CALLED");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (cfg *Config) HandleEvents() {
|
|
|
|
|
doit := time.NewTimer(cfg.delay_time)
|
|
|
|
|
doit.Stop()
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
select {
|
|
|
|
|
case event, ok := <-cfg.watcher.Events:
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.Println("EVENT", event)
|
|
|
|
|
|
|
|
|
|
if event.Name == cfg.Source.PrivateKey {
|
|
|
|
|
doit.Reset(cfg.delay_time)
|
|
|
|
|
}
|
|
|
|
|
case <-doit.C:
|
|
|
|
|
cfg.SyncCerts()
|
|
|
|
|
case err, ok := <-cfg.watcher.Errors:
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.Println("failed to watch", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (cfg *Config) WatchFiles() {
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
cfg.watcher, err = fsnotify.NewWatcher()
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err, "Can't watch files.")
|
|
|
|
|
}
|
|
|
|
|
defer cfg.watcher.Close()
|
|
|
|
|
|
|
|
|
|
go cfg.HandleEvents()
|
|
|
|
|
|
|
|
|
|
cfg.Source.PrivateKey, err = filepath.Abs(cfg.Source.PrivateKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("can't convert %s to absolut path: %v",
|
|
|
|
|
cfg.Source.PrivateKey, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = cfg.watcher.Add(cfg.Source.PrivateKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("can't watch %s: %v", err, cfg.Source.PrivateKey)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
<-make(chan struct{})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
config := ParseOpts()
|
|
|
|
|
config.WatchFiles()
|
|
|
|
|
}
|