blob: a0cea61351b9ff09c01f62521e9e5b7233feabcd [file] [log] [blame]
package main
import (
"context"
"encoding/hex"
"fmt"
"sync"
"time"
pb "code.hackerspace.pl/hscloud/bgpwtf/cccampix/proto"
"code.hackerspace.pl/hscloud/bgpwtf/cccampix/verifier/model"
"github.com/golang/glog"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type pgp struct {
pgpc pb.PGPEncryptorClient
}
func newPGP(pgpc pb.PGPEncryptorClient) (*pgp, error) {
return &pgp{
pgpc: pgpc,
}, nil
}
func (p *pgp) Name() string {
return "PGP"
}
func (p *pgp) NextRun(now time.Time, lastRun bool) time.Time {
if lastRun {
return now.Add(1 * time.Minute)
}
return now.Add(15 * time.Minute)
}
func (p *pgp) RunAll(ctx context.Context, m model.Model) error {
keys, err := m.GetPGPKeysRequiringAttention(ctx)
if err != nil {
return fmt.Errorf("GetPGPKeysRequiringAttention: %v", err)
}
if len(keys) == 0 {
return nil
}
s := make(chan struct{}, 20)
errC := make(chan error, len(keys))
knownC := make(chan *model.PeerPGPKey, len(keys))
unknownC := make(chan *model.PeerPGPKey, len(keys))
var wg sync.WaitGroup
wg.Add(len(keys))
for _, key := range keys {
go func(k *model.PeerPGPKey) {
s <- struct{}{}
defer func() {
wg.Done()
<-s
}()
glog.Infof("PGP: Processing %v", *k)
// HACK(q3k)
if k.State == "known" {
knownC <- k
return
}
fp, err := hex.DecodeString(k.Fingerprint)
if err != nil {
errC <- fmt.Errorf("could not decode fingerprint %q: %v", k.Fingerprint, err)
return
}
req := &pb.KeyInfoRequest{
Fingerprint: fp,
Caching: pb.KeyInfoRequest_CACHING_FORCE_REMOTE,
}
_, err = p.pgpc.KeyInfo(ctx, req)
s, ok := status.FromError(err)
switch {
case err == nil:
knownC <- k
case ok && s.Code() == codes.NotFound:
unknownC <- k
default:
unknownC <- k
errC <- err
}
}(key)
}
wg.Wait()
close(errC)
close(knownC)
close(unknownC)
pcr := []*model.PeerCheckResult{}
positive := []string{}
for p := range knownC {
positive = append(positive, p.Fingerprint)
pcr = append(pcr, &model.PeerCheckResult{
PeerASN: p.PeerASN,
CheckName: "pgp",
Time: time.Now(),
Status: model.PeerCheckStatus_Okay,
})
}
negative := []string{}
for n := range unknownC {
negative = append(negative, n.Fingerprint)
pcr = append(pcr, &model.PeerCheckResult{
PeerASN: n.PeerASN,
CheckName: "pgp",
Time: time.Now(),
Status: model.PeerCheckStatus_Failed,
Message: fmt.Sprintf("key %q not found on keyservers", n.Fingerprint),
})
}
glog.Infof("%v, %v", positive, negative)
if len(positive) > 0 || len(negative) > 0 {
err := m.ValidatePGPKeys(ctx, positive, negative)
if err != nil {
return fmt.Errorf("ValidatePGPKeys(%v, %v): %v", positive, negative, err)
}
}
if len(pcr) > 0 {
err = m.SubmitPeerCheckResults(ctx, "pgp", pcr)
if err != nil {
return err
}
}
errs := []error{}
for err := range errC {
errs = append(errs, err)
}
if len(errs) > 0 {
glog.Errorf("Errors while processing keys: %v", errs)
return fmt.Errorf("Errors ocurred while processing keys")
}
return nil
}