Raw
 1package admin
 2
 3import (
 4	"context"
 5	"errors"
 6	"fmt"
 7	"strings"
 8	"time"
 9
10	"tug/internal/platform/sshkey/openssh"
11	"tug/internal/storage"
12)
13
14type SSHKey struct {
15	ID          string
16	Fingerprint string
17	Type        string
18	Label       string
19	AddedAt     time.Time
20}
21
22func (s *Service) sshKeys(ctx context.Context, id string) ([]SSHKey, error) {
23	keys, err := s.store.SSHKeysOf(ctx, id)
24	if err != nil {
25		return nil, failed("read user's ssh keys", err)
26	}
27	out := make([]SSHKey, 0, len(keys))
28	for _, k := range keys {
29		out = append(out, sshKeyOf(k))
30	}
31	return out, nil
32}
33
34func (s *Service) AddSSHKey(ctx context.Context, actor, id, line, label string) (SSHKey, error) {
35	const operation = "add ssh key"
36	key, err := openssh.Parse(line)
37	if err != nil {
38		return SSHKey{}, failed(operation, err)
39	}
40	if err := storage.CheckSSHKeyLabel(strings.TrimSpace(label)); err != nil {
41		return SSHKey{}, failed(operation, err)
42	}
43	added, err := s.store.AddSSHKeyAudited(ctx, storage.AddSSHKeyInput{UserID: id, Key: key, Label: label}, actor)
44	switch {
45	case errors.Is(err, storage.ErrSSHKeyDisabled):
46		return SSHKey{}, ProblemSSHKeyDisabled
47	case errors.Is(err, storage.ErrSSHKeyPending):
48		return SSHKey{}, ProblemSSHKeyPending
49	case err != nil:
50		return SSHKey{}, target(operation, err)
51	}
52	return sshKeyOf(added), nil
53}
54
55func (s *Service) RemoveSSHKey(ctx context.Context, actor, id, keyID string) (SSHKey, error) {
56	removed, err := s.store.RemoveSSHKeyAudited(ctx, id, keyID, "", actor)
57	switch {
58	case errors.Is(err, storage.ErrSSHKeyNotFound):
59		return SSHKey{}, fmt.Errorf("admin: remove ssh key: %w: %w", ErrNotFound, err)
60	case err != nil:
61		return SSHKey{}, target("remove ssh key", err)
62	}
63	return sshKeyOf(removed), nil
64}
65
66func sshKeyOf(k storage.SSHKey) SSHKey {
67	return SSHKey{ID: k.ID, Fingerprint: k.Fingerprint, Type: k.Type, Label: k.Label, AddedAt: k.AddedAt}
68}