package admin import ( "context" "errors" "fmt" "strings" "time" "tug/internal/platform/sshkey/openssh" "tug/internal/storage" ) type SSHKey struct { ID string Fingerprint string Type string Label string AddedAt time.Time } func (s *Service) sshKeys(ctx context.Context, id string) ([]SSHKey, error) { keys, err := s.store.SSHKeysOf(ctx, id) if err != nil { return nil, failed("read user's ssh keys", err) } out := make([]SSHKey, 0, len(keys)) for _, k := range keys { out = append(out, sshKeyOf(k)) } return out, nil } func (s *Service) AddSSHKey(ctx context.Context, actor, id, line, label string) (SSHKey, error) { const operation = "add ssh key" key, err := openssh.Parse(line) if err != nil { return SSHKey{}, failed(operation, err) } if err := storage.CheckSSHKeyLabel(strings.TrimSpace(label)); err != nil { return SSHKey{}, failed(operation, err) } added, err := s.store.AddSSHKeyAudited(ctx, storage.AddSSHKeyInput{UserID: id, Key: key, Label: label}, actor) switch { case errors.Is(err, storage.ErrSSHKeyDisabled): return SSHKey{}, ProblemSSHKeyDisabled case errors.Is(err, storage.ErrSSHKeyPending): return SSHKey{}, ProblemSSHKeyPending case err != nil: return SSHKey{}, target(operation, err) } return sshKeyOf(added), nil } func (s *Service) RemoveSSHKey(ctx context.Context, actor, id, keyID string) (SSHKey, error) { removed, err := s.store.RemoveSSHKeyAudited(ctx, id, keyID, "", actor) switch { case errors.Is(err, storage.ErrSSHKeyNotFound): return SSHKey{}, fmt.Errorf("admin: remove ssh key: %w: %w", ErrNotFound, err) case err != nil: return SSHKey{}, target("remove ssh key", err) } return sshKeyOf(removed), nil } func sshKeyOf(k storage.SSHKey) SSHKey { return SSHKey{ID: k.ID, Fingerprint: k.Fingerprint, Type: k.Type, Label: k.Label, AddedAt: k.AddedAt} }