package mill
import (
"context"
"errors"
"fmt"
"github.com/bluesky-social/indigo/atproto/syntax"
gossh "golang.org/x/crypto/ssh"
millproto "tangled.org/core/spindle/mill/proto"
millv1 "tangled.org/core/spindle/mill/proto/gen"
)
// the spindle's own check, the mill only picks the repo
type DebugKeyChecker interface {
DebugKeyAllowed(ctx context.Context, repoDid syntax.DID, key gossh.PublicKey) bool
}
func (m *Mill) SetDebugKeyChecker(c DebugKeyChecker) {
m.mu.Lock()
defer m.mu.Unlock()
m.debugKeys = c
}
func (m *Mill) handleDebugKeyRequest(s *millSession, req *millv1.DebugKeyRequest) {
resp := &millv1.DebugKeyResponse{RequestId: req.GetRequestId()}
allowed, err := m.debugKeyAllowed(s, req)
if err != nil {
resp.Error = err.Error()
}
resp.Allowed = allowed && err == nil
_ = s.send(&millproto.Message{DebugKeyResp: resp})
}
// the repo comes from the lease this node was given, never from the executor
func (m *Mill) debugKeyAllowed(s *millSession, req *millv1.DebugKeyRequest) (bool, error) {
m.mu.Lock()
checker := m.debugKeys
lease := m.leases[req.GetLeaseId()]
m.mu.Unlock()
if checker == nil {
return false, errors.New("no debug key checker attached")
}
if lease == nil || lease.nodeID != s.nodeID || lease.epoch != s.epoch {
return false, fmt.Errorf("no live lease %q on this node with matching epoch", req.GetLeaseId())
}
lease.mu.Lock()
repo := lease.repoDID
lease.mu.Unlock()
repoDid, err := syntax.ParseDID(repo)
if err != nil {
return false, fmt.Errorf("lease has no usable repo: %w", err)
}
key, err := gossh.ParsePublicKey(req.GetPublicKey())
if err != nil {
return false, fmt.Errorf("bad public key: %w", err)
}
return checker.DebugKeyAllowed(s.ctx, repoDid, key), nil
}