From 46cac263ca9f350fbc414b795e42f79d4d241e28 Mon Sep 17 00:00:00 2001
From: zeripath <art27@cantab.net>
Date: Thu, 7 Oct 2021 21:10:14 +0100
Subject: [PATCH] Handle duplicate keys on GPG key ring (#17242)

It is possible that a keyring can contain duplicate keys on a keyring due to jpegs or
other layers. This currently leads to a confusing error for the user - where we report
a duplicate key insertion.

This PR simply coalesces keys into one key if there are duplicates.

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: 6543 <6543@obermui.de>
---
 models/gpg_key_add.go | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/models/gpg_key_add.go b/models/gpg_key_add.go
index 635872c920..711fc86dee 100644
--- a/models/gpg_key_add.go
+++ b/models/gpg_key_add.go
@@ -101,6 +101,46 @@ func AddGPGKey(ownerID int64, content, token, signature string) ([]*GPGKey, erro
 		verified = true
 	}
 
+	if len(ekeys) > 1 {
+		id2key := map[string]*openpgp.Entity{}
+		newEKeys := make([]*openpgp.Entity, 0, len(ekeys))
+		for _, ekey := range ekeys {
+			id := ekey.PrimaryKey.KeyIdString()
+			if original, has := id2key[id]; has {
+				// Coalesce this with the other one
+				for _, subkey := range ekey.Subkeys {
+					if subkey.PublicKey == nil {
+						continue
+					}
+					found := false
+
+					for _, originalSubkey := range original.Subkeys {
+						if originalSubkey.PublicKey == nil {
+							continue
+						}
+						if originalSubkey.PublicKey.KeyId == subkey.PublicKey.KeyId {
+							found = true
+							break
+						}
+					}
+					if !found {
+						original.Subkeys = append(original.Subkeys, subkey)
+					}
+				}
+				for name, identity := range ekey.Identities {
+					if _, has := original.Identities[name]; has {
+						continue
+					}
+					original.Identities[name] = identity
+				}
+				continue
+			}
+			id2key[id] = ekey
+			newEKeys = append(newEKeys, ekey)
+		}
+		ekeys = newEKeys
+	}
+
 	for _, ekey := range ekeys {
 		// Key ID cannot be duplicated.
 		has, err := db.GetEngine(ctx).Where("key_id=?", ekey.PrimaryKey.KeyIdString()).