1package session
2
3import (
4 "context"
5 "errors"
6 "fmt"
7 "strings"
8
9 "tug/internal/platform/sshkey"
10 "tug/internal/platform/sshkey/openssh"
11 "tug/internal/storage"
12)
13
14func (s *Service) SSHKeys(ctx context.Context, userID string) ([]storage.SSHKey, error) {
15 keys, err := s.store.SSHKeysOf(ctx, userID)
16 if err != nil {
17 return nil, failure("list ssh keys", err)
18 }
19 return keys, nil
20}
21
22func (s *Service) AddSSHKey(ctx context.Context, p Principal, line, label string) (storage.SSHKey, error) {
23 const operation = "add ssh key"
24 if p.SessionID == "" {
25 return storage.SSHKey{}, fmt.Errorf("session: %s: %w: no current session", operation, ErrNoSession)
26 }
27 key, err := openssh.Parse(line)
28 if err != nil {
29 return storage.SSHKey{}, fmt.Errorf("session: %s: %w", operation, err)
30 }
31 if err := storage.CheckSSHKeyLabel(strings.TrimSpace(label)); err != nil {
32 return storage.SSHKey{}, fmt.Errorf("session: %s: %w", operation, err)
33 }
34 added, err := s.store.AddSSHKeyAudited(ctx, storage.AddSSHKeyInput{UserID: p.UserID, Key: key, Label: label, SessionID: p.SessionID}, p.UserID)
35 switch {
36 case errors.Is(err, sshkey.ErrOwned), errors.Is(err, sshkey.ErrTaken), errors.Is(err, sshkey.ErrLimit):
37 return storage.SSHKey{}, fmt.Errorf("session: %s: %w", operation, err)
38 case errors.Is(err, storage.ErrInvalid), errors.Is(err, storage.ErrSSHKeyDisabled), errors.Is(err, storage.ErrSSHKeyPending):
39 return storage.SSHKey{}, fmt.Errorf("session: %s: %w: %w", operation, ErrNoSession, err)
40 case err != nil:
41 return storage.SSHKey{}, failure(operation, err)
42 }
43 return added, nil
44}
45
46func (s *Service) RemoveSSHKey(ctx context.Context, p Principal, keyID string) (storage.SSHKey, error) {
47 const operation = "remove ssh key"
48 if p.SessionID == "" {
49 return storage.SSHKey{}, fmt.Errorf("session: %s: %w: no current session", operation, ErrNoSession)
50 }
51 removed, err := s.store.RemoveSSHKeyAudited(ctx, p.UserID, keyID, p.SessionID, p.UserID)
52 switch {
53 case errors.Is(err, storage.ErrSSHKeyNotFound):
54 return storage.SSHKey{}, fmt.Errorf("session: %s: %w: %w", operation, ErrNoSuchSSHKey, err)
55 case errors.Is(err, storage.ErrInvalid):
56 return storage.SSHKey{}, fmt.Errorf("session: %s: %w: %w", operation, ErrNoSession, err)
57 case err != nil:
58 return storage.SSHKey{}, failure(operation, err)
59 }
60 return removed, nil
61}