cert get: combined file for HAProxy, --local, saved NAME; cert list shows get and last download
- jarl cert get --combined PATH writes the key and full chain in one file
(mode 600, atomic), kept outside --dir so it can live in HAProxy's crt
directory; JARL_CERT_COMBINED for the hook. Turning it on, moving it or
removing it ('') applies from the files on disk and runs the hook.
- jarl cert get --local writes the combined file and runs the hook from
this host's files, without asking jarld.
- jarl cert saved NAME shows all of one certificate's settings.
- jarl cert list: USES "get" for certificates for other hosts, and a
PULLED column (last download, "(old)" while a host is behind). Owners
now see their own downloads (pulled_by), not only administrators.
- jarl cert get without a name refuses per-certificate flags.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3fb159cf4d
commit
42e79af678
9 files changed
+578
-76
No files matched your search
+26
-12
@@ -33,7 +33,8 @@ type certView struct {
|
||||
// IssuingSince is set while Jarl is obtaining it.
|
||||
IssuingSince *time.Time `json:"issuing_since,omitempty"`
|
||||
// Owner is the user a certificate for another host belongs to; PulledBy
|
||||
// who downloaded it (list and get, administrators only).
|
||||
// who downloaded it (list and get; an owner who isn't an administrator
|
||||
// sees only their own downloads).
|
||||
Owner string `json:"owner,omitempty"`
|
||||
PulledBy []model.CertificatePull `json:"pulled_by,omitempty"`
|
||||
}
|
||||
@@ -116,12 +117,27 @@ func (s *Server) certFor(r *http.Request, p *auth.Principal, write bool) (*model
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// withOwners adds owners and downloads to views (for administrators).
|
||||
func (s *Server) withOwners(ctx context.Context, views []certView) error {
|
||||
// withOwners adds owners and downloads to views: all of them for an
|
||||
// administrator, the principal's own downloads for anyone else (who sees
|
||||
// only their own certificates).
|
||||
func (s *Server) withOwners(ctx context.Context, p *auth.Principal, views []certView) error {
|
||||
pulls, err := s.store.CertificatePulls(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !p.IsAdmin() {
|
||||
for i := range views {
|
||||
for _, pl := range pulls[views[i].ID] {
|
||||
if p.User != nil && pl.UserID == p.User.ID {
|
||||
views[i].PulledBy = append(views[i].PulledBy, pl)
|
||||
}
|
||||
}
|
||||
if p.User != nil && views[i].OwnerID != 0 {
|
||||
views[i].Owner = p.User.Username
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
users, err := s.store.ListUsers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -179,13 +195,13 @@ func (s *Server) certList(w http.ResponseWriter, r *http.Request, p *auth.Princi
|
||||
v.NamedUse = encdns.CertUses(st, s.cfg.Certs.FilesDir(c.Name))
|
||||
out = append(out, v)
|
||||
}
|
||||
if err := s.withOwners(r.Context(), p, out); err != nil {
|
||||
return err
|
||||
}
|
||||
if !p.IsAdmin() {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"certificates": out})
|
||||
return nil
|
||||
}
|
||||
if err := s.withOwners(r.Context(), out); err != nil {
|
||||
return err
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]any{"certificates": out, "account": s.cfg.Certs.AccountInfo(r.Context())})
|
||||
return nil
|
||||
}
|
||||
@@ -205,13 +221,11 @@ func (s *Server) certGet(w http.ResponseWriter, r *http.Request, p *auth.Princip
|
||||
}
|
||||
v := s.presentCert(c)
|
||||
v.NamedUse = encdns.CertUses(st, s.cfg.Certs.FilesDir(c.Name))
|
||||
if p.IsAdmin() {
|
||||
vs := []certView{v}
|
||||
if err := s.withOwners(r.Context(), vs); err != nil {
|
||||
return err
|
||||
}
|
||||
v = vs[0]
|
||||
vs := []certView{v}
|
||||
if err := s.withOwners(r.Context(), p, vs); err != nil {
|
||||
return err
|
||||
}
|
||||
v = vs[0]
|
||||
writeJSON(w, http.StatusOK, v)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user