Draw the actual rest of the fucking owl.

Change-Id: Ia04fb49ebbe3a5afccc57e62f6335e35b45192fe
diff --git a/bgpwtf/cccampix/verifier/processor_pgp.go b/bgpwtf/cccampix/verifier/processor_pgp.go
new file mode 100644
index 0000000..423cb7e
--- /dev/null
+++ b/bgpwtf/cccampix/verifier/processor_pgp.go
@@ -0,0 +1,153 @@
+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:
+				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
+
+}