package engine import ( "context" "crypto/rand" "encoding/base64" "errors" "jarl/internal/model" "jarl/internal/nscheck" "jarl/internal/render" "jarl/internal/store" ) // viewKeySeedMeta is where the seed of the view keys is kept. const viewKeySeedMeta = "view_key_seed" // ViewKeySeed returns the seed the view keys' secrets are derived from // (render/viewkeys.go), creating it the first time. func ViewKeySeed(ctx context.Context, st *store.Store) ([]byte, error) { v, err := st.GetMeta(ctx, viewKeySeedMeta) if err == nil { return base64.StdEncoding.DecodeString(v) } if !errors.Is(err, store.ErrNotFound) { return nil, err } seed := make([]byte, 32) if _, err := rand.Read(seed); err != nil { return nil, err } if err := st.SetMeta(ctx, viewKeySeedMeta, base64.StdEncoding.EncodeToString(seed)); err != nil { return nil, err } return seed, nil } // extras returns what jarld's configuration adds to the rendered // configuration, with the view keys' seed. func (e *Engine) extras(ctx context.Context) render.Extras { x := e.cfg.Extras e.seedMu.Lock() defer e.seedMu.Unlock() if e.seed == nil { seed, err := ViewKeySeed(ctx, e.store) if err != nil { e.log.Warn("view keys: reading their seed failed", "err", err) return x } e.seed = seed } x.ViewKeySeed = e.seed return x } // ViewKey returns the TSIG key that selects a zone's view on this server // (nil without views). func (e *Engine) ViewKey(ctx context.Context, st *model.State, z *model.Zone) *nscheck.Key { v := st.Views[z.ViewID] if v == nil { return nil } x := e.extras(ctx) if len(x.ViewKeySeed) == 0 { return nil } return &nscheck.Key{Name: render.ViewKeyName(v.Name), Algorithm: render.ViewKeyAlgorithm, Secret: render.ViewKeySecret(x.ViewKeySeed, v.ID)} } // GeneratedStatements lists what Jarl adds to named.conf by itself // (render.GeneratedStatements). func (e *Engine) GeneratedStatements(ctx context.Context, st *model.State) []render.Generated { return render.GeneratedStatements(st, e.cfg.Paths, e.extras(ctx)) }