package server import ( "jarl/internal/api" "jarl/internal/auth" "jarl/internal/catalog" "jarl/internal/dnsname" "jarl/internal/engine" "jarl/internal/model" "jarl/internal/render" "jarl/internal/rr" "jarl/internal/version" ) func (s *Server) presentZone(st *model.State, z *model.Zone, counts map[int64]int) api.Zone { out := api.Zone{Zone: *z, Display: dnsname.Display(z.Name), View: st.ViewName(z), Records: counts[z.ID]} out.ZoneFile = render.ZoneFilePath(st, z, s.eng.Config().Paths) if z.Type == model.ZonePrimary { out.RName = dnsname.EmailFromMailbox(z.SOA.RName) } return out } func presentRecord(st *model.State, r *model.Record) api.Record { z := st.Zones[r.ZoneID] out := api.Record{Record: *r} if z != nil { out.Zone, out.View, out.RelativeName, out.EffectiveTTL = z.Name, st.ViewName(z), dnsname.Relative(r.Name, z.Name), r.EffectiveTTL(z) if rr.IsTextType(r.Type) { if p, err := rr.Parse(z.Name, r.Name, r.Type, r.Data); err == nil { if t, ok := rr.TextValue(p.RR); ok { out.Text = &t } } } } return out } func canReadRecord(p *auth.Principal, st *model.State, r *model.Record) bool { z := st.Zones[r.ZoneID] return z != nil && p.Can(auth.Action{Resource: auth.ResRecords, Zone: z.Name, View: st.ViewName(z), Name: r.Name, Type: r.Type}) } func presentView(st *model.State, v *model.View, colors map[int64]string) api.View { return api.View{View: *v, Zones: len(st.ZonesInView(v.ID)), Color: colors[v.ID]} } func presentACL(st *model.State, a *model.ACL) api.ACL { used := engine.FindACLRefs(st, a.Name) if used == nil { used = []string{} } return api.ACL{ACL: *a, UsedBy: used} } func presentKey(st *model.State, k *model.TSIGKey, withSecret bool) api.TSIGKey { out := api.TSIGKey{TSIGKey: *k, UsedBy: engine.FindKeyRefs(st, k.Name)} if out.UsedBy == nil { out.UsedBy = []string{} } if !withSecret { out.Secret = "" } return out } func optionWhere(st *model.State, o *model.Option) string { switch o.Scope { case model.ScopeView: if v := st.Views[o.ScopeID]; v != nil { return "view " + v.Name } case model.ScopeZone: if z := st.Zones[o.ScopeID]; z != nil { return "zone " + engine.ZoneLabel(st, z) } case model.ScopeTopLevel: return "top level" } return "server options" } func presentOption(st *model.State, o *model.Option) api.Option { out := api.Option{Option: *o, Where: optionWhere(st, o)} scope := catalog.ScopeOptions switch o.Scope { case model.ScopeView: scope = catalog.ScopeView case model.ScopeTopLevel: scope = catalog.ScopeTop case model.ScopeZone: if z := st.Zones[o.ScopeID]; z != nil { scope = catalog.ZoneScope(z.Type) } } if c, ok := catalog.Default().Lookup(scope, o.Name); ok { out.Description, out.Status = c.Description, c.Status } return out } // canReadOption reports whether p may see an option. func canReadOption(p *auth.Principal, st *model.State, o *model.Option) bool { switch o.Scope { case model.ScopeView: v := st.Views[o.ScopeID] return v != nil && p.Can(auth.Action{Resource: auth.ResViews, View: v.Name}) case model.ScopeZone: z := st.Zones[o.ScopeID] return z != nil && p.Can(auth.Action{Resource: auth.ResZones, Zone: z.Name, View: st.ViewName(z)}) } return p.Can(auth.Action{Resource: auth.ResOptions}) } func presentUser(u *model.User) api.User { out := api.User{User: *u} for _, g := range u.Grants { out.GrantStrings = append(out.GrantStrings, auth.FormatGrant(g)) } if out.GrantStrings == nil { out.GrantStrings = []string{} } return out } func presentToken(t *model.Token) api.Token { out := api.Token{Token: *t} for _, g := range t.Grants { out.GrantStrings = append(out.GrantStrings, auth.FormatGrant(g)) } return out } func (s *Server) whoamiOf(p *auth.Principal, se *model.Session) api.Whoami { out := api.Whoami{User: presentUser(p.User), Method: p.Method, Permissions: p.Summary(), Admin: p.IsAdmin(), Version: s.cfg.Version, Build: version.Info()} if p.Token != nil { t := presentToken(p.Token) out.Token = &t } if se != nil { out.CSRFToken = se.CSRFToken } return out }