aboutsummaryrefslogtreecommitdiffstats
path: root/identity/key.go
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2022-08-18 23:34:05 +0200
committerMichael Muré <batolettre@gmail.com>2022-08-18 23:44:06 +0200
commit5511c230b678a181cc596238bf6669428d1b1902 (patch)
tree8701efc87732439f993eb4f1d00585fc419b87ab /identity/key.go
parent5ca686b59751e3c87740b84108c54fc675a074cf (diff)
downloadgit-bug-5511c230b678a181cc596238bf6669428d1b1902.tar.gz
move {bug,identity} to /entities, move input to /commands
Diffstat (limited to 'identity/key.go')
-rw-r--r--identity/key.go234
1 files changed, 0 insertions, 234 deletions
diff --git a/identity/key.go b/identity/key.go
deleted file mode 100644
index 82b9b95c..00000000
--- a/identity/key.go
+++ /dev/null
@@ -1,234 +0,0 @@
-package identity
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "strings"
- "time"
-
- "github.com/ProtonMail/go-crypto/openpgp"
- "github.com/ProtonMail/go-crypto/openpgp/armor"
- "github.com/ProtonMail/go-crypto/openpgp/packet"
- "github.com/pkg/errors"
-
- "github.com/MichaelMure/git-bug/repository"
-)
-
-var errNoPrivateKey = fmt.Errorf("no private key")
-
-type Key struct {
- public *packet.PublicKey
- private *packet.PrivateKey
-}
-
-// GenerateKey generate a keypair (public+private)
-// The type and configuration of the key is determined by the default value in go's OpenPGP.
-func GenerateKey() *Key {
- entity, err := openpgp.NewEntity("", "", "", &packet.Config{
- // The armored format doesn't include the creation time, which makes the round-trip data not being fully equal.
- // We don't care about the creation time so we can set it to the zero value.
- Time: func() time.Time {
- return time.Time{}
- },
- })
- if err != nil {
- panic(err)
- }
- return &Key{
- public: entity.PrimaryKey,
- private: entity.PrivateKey,
- }
-}
-
-// generatePublicKey generate only a public key (only useful for testing)
-// See GenerateKey for the details.
-func generatePublicKey() *Key {
- k := GenerateKey()
- k.private = nil
- return k
-}
-
-func (k *Key) Public() *packet.PublicKey {
- return k.public
-}
-
-func (k *Key) Private() *packet.PrivateKey {
- return k.private
-}
-
-func (k *Key) Validate() error {
- if k.public == nil {
- return fmt.Errorf("nil public key")
- }
- if !k.public.CanSign() {
- return fmt.Errorf("public key can't sign")
- }
-
- if k.private != nil {
- if !k.private.CanSign() {
- return fmt.Errorf("private key can't sign")
- }
- }
-
- return nil
-}
-
-func (k *Key) Clone() *Key {
- clone := &Key{}
-
- pub := *k.public
- clone.public = &pub
-
- if k.private != nil {
- priv := *k.private
- clone.private = &priv
- }
-
- return clone
-}
-
-func (k *Key) MarshalJSON() ([]byte, error) {
- // Serialize only the public key, in the armored format.
- var buf bytes.Buffer
- w, err := armor.Encode(&buf, openpgp.PublicKeyType, nil)
- if err != nil {
- return nil, err
- }
-
- err = k.public.Serialize(w)
- if err != nil {
- return nil, err
- }
- err = w.Close()
- if err != nil {
- return nil, err
- }
- return json.Marshal(buf.String())
-}
-
-func (k *Key) UnmarshalJSON(data []byte) error {
- // De-serialize only the public key, in the armored format.
- var armored string
- err := json.Unmarshal(data, &armored)
- if err != nil {
- return err
- }
-
- block, err := armor.Decode(strings.NewReader(armored))
- if err == io.EOF {
- return fmt.Errorf("no armored data found")
- }
- if err != nil {
- return err
- }
-
- if block.Type != openpgp.PublicKeyType {
- return fmt.Errorf("invalid key type")
- }
-
- p, err := packet.Read(block.Body)
- if err != nil {
- return errors.Wrap(err, "failed to read public key packet")
- }
-
- public, ok := p.(*packet.PublicKey)
- if !ok {
- return errors.New("got no packet.publicKey")
- }
-
- // The armored format doesn't include the creation time, which makes the round-trip data not being fully equal.
- // We don't care about the creation time so we can set it to the zero value.
- public.CreationTime = time.Time{}
-
- k.public = public
- return nil
-}
-
-func (k *Key) loadPrivate(repo repository.RepoKeyring) error {
- item, err := repo.Keyring().Get(k.public.KeyIdString())
- if err == repository.ErrKeyringKeyNotFound {
- return errNoPrivateKey
- }
- if err != nil {
- return err
- }
-
- block, err := armor.Decode(bytes.NewReader(item.Data))
- if err == io.EOF {
- return fmt.Errorf("no armored data found")
- }
- if err != nil {
- return err
- }
-
- if block.Type != openpgp.PrivateKeyType {
- return fmt.Errorf("invalid key type")
- }
-
- p, err := packet.Read(block.Body)
- if err != nil {
- return errors.Wrap(err, "failed to read private key packet")
- }
-
- private, ok := p.(*packet.PrivateKey)
- if !ok {
- return errors.New("got no packet.privateKey")
- }
-
- // The armored format doesn't include the creation time, which makes the round-trip data not being fully equal.
- // We don't care about the creation time so we can set it to the zero value.
- private.CreationTime = time.Time{}
-
- k.private = private
- return nil
-}
-
-// ensurePrivateKey attempt to load the corresponding private key if it is not loaded already.
-// If no private key is found, returns errNoPrivateKey
-func (k *Key) ensurePrivateKey(repo repository.RepoKeyring) error {
- if k.private != nil {
- return nil
- }
-
- return k.loadPrivate(repo)
-}
-
-func (k *Key) storePrivate(repo repository.RepoKeyring) error {
- var buf bytes.Buffer
- w, err := armor.Encode(&buf, openpgp.PrivateKeyType, nil)
- if err != nil {
- return err
- }
- err = k.private.Serialize(w)
- if err != nil {
- return err
- }
- err = w.Close()
- if err != nil {
- return err
- }
-
- return repo.Keyring().Set(repository.Item{
- Key: k.public.KeyIdString(),
- Data: buf.Bytes(),
- })
-}
-
-func (k *Key) PGPEntity() *openpgp.Entity {
- uid := packet.NewUserId("", "", "")
- return &openpgp.Entity{
- PrimaryKey: k.public,
- PrivateKey: k.private,
- Identities: map[string]*openpgp.Identity{
- uid.Id: {
- Name: uid.Id,
- UserId: uid,
- SelfSignature: &packet.Signature{
- IsPrimaryId: func() *bool { b := true; return &b }(),
- },
- },
- },
- }
-}