bgpwtf/cccampix/pgpencryptor: implement service

TODO:
  * tests

Change-Id: I5d0506542070236a8ee879fcb54bc9518e23b5e3
diff --git a/bgpwtf/cccampix/pgpencryptor/model/model.go b/bgpwtf/cccampix/pgpencryptor/model/model.go
new file mode 100644
index 0000000..4de3d4e
--- /dev/null
+++ b/bgpwtf/cccampix/pgpencryptor/model/model.go
@@ -0,0 +1,58 @@
+package model
+
+import (
+	"code.hackerspace.pl/hscloud/bgpwtf/cccampix/pgpencryptor/model/migrations"
+	"context"
+	"fmt"
+	migrate "github.com/golang-migrate/migrate/v4"
+	_ "github.com/golang-migrate/migrate/v4/database/cockroachdb"
+	"github.com/jmoiron/sqlx"
+	_ "github.com/lib/pq"
+	"strings"
+)
+
+type Model interface {
+	MigrateUp() error
+	PutKey(ctx context.Context, key *PgpKey) error
+	GetKey(ctx context.Context, keyID []byte) (*PgpKey, error)
+}
+
+type sqlModel struct {
+	db  *sqlx.DB
+	dsn string
+}
+
+type PgpKey struct {
+	Fingerprint []byte
+	KeyData     []byte
+	Okay        bool
+}
+
+func Connect(ctx context.Context, driver, dsn string) (Model, error) {
+	if dsn == "" {
+		return nil, fmt.Errorf("dsn cannot be empty")
+	}
+	db, err := sqlx.ConnectContext(ctx, driver, dsn)
+	if err != nil {
+		return nil, fmt.Errorf("could not connect to database: %v", err)
+	}
+	return &sqlModel{
+		db:  db,
+		dsn: dsn,
+	}, nil
+}
+
+func (m *sqlModel) MigrateUp() error {
+	dsn := "cockroach://" + strings.TrimPrefix(m.dsn, "postgres://")
+	mig, err := migrations.New(dsn)
+	if err != nil {
+		return err
+	}
+	err = mig.Up()
+	switch err {
+	case migrate.ErrNoChange:
+		return nil
+	default:
+		return err
+	}
+}