1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
/*
Hockeypuck - OpenPGP key server
Copyright (C) 2012 Casey Marshall
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package hockeypuck
// Merge the contents of srcKey into dstKey, modifying in-place.
// Packets in src not found in dst are appended to the matching parent.
// Conflicting packets and unmatched parents are ignored.
func MergeKey(dstKey *PubKey, srcKey *PubKey) {
dstObjects := mapKey(dstKey)
pktObjChan := make(chan PacketObject)
go func() {
srcKey.Traverse(pktObjChan)
close(pktObjChan)
}()
// Track src parent object in src traverse
var srcPubKey *PubKey
var srcUserId *UserId
var srcSignable PacketObject
var srcParent PacketObject
var hasParent bool
for srcObj := range pktObjChan {
switch srcObj.(type) {
case *PubKey:
srcPubKey = srcObj.(*PubKey)
srcSignable = srcObj
srcParent = nil
hasParent = false
case *UserId:
srcUserId = srcObj.(*UserId)
srcSignable = srcObj
srcParent = srcPubKey
hasParent = true
case *UserAttribute:
srcSignable = srcObj
srcParent = srcUserId
hasParent = true
case *SubKey:
srcSignable = srcObj
srcParent = srcPubKey
hasParent = true
case *Signature:
srcParent = srcSignable
hasParent = true
}
// match in dst tree
_, dstHas := dstObjects[srcObj.GetDigest()]
if dstHas {
continue // We already have it
}
if hasParent {
dstParentObj, dstHasParent := dstObjects[srcParent.GetDigest()]
if dstHasParent {
appendPacketObject(dstParentObj, srcObj)
}
}
}
}
// Map a tree of packet objects by strong hash.
func mapKey(root PacketObject) (objects map[string]PacketObject) {
objects = make(map[string]PacketObject)
pktObjChan := make(chan PacketObject)
go func() {
root.Traverse(pktObjChan)
close(pktObjChan)
}()
for pktObj := range pktObjChan {
objects[pktObj.GetDigest()] = pktObj
}
return
}
// Append a src packet under dst parent.
func appendPacketObject(dstParent PacketObject, srcObj PacketObject) {
if sig, isa := srcObj.(*Signature); isa {
if dst, isa := dstParent.(Signable); isa {
dst.AppendSig(sig)
}
} else if uattr, isa := srcObj.(*UserAttribute); isa {
if uid, isa := dstParent.(*UserId); isa {
uid.Attributes = append(uid.Attributes, uattr)
}
} else if uid, isa := srcObj.(*UserId); isa {
if pubKey, isa := dstParent.(*PubKey); isa {
pubKey.Identities = append(pubKey.Identities, uid)
}
} else if subKey, isa := srcObj.(*SubKey); isa {
if pubKey, isa := dstParent.(*PubKey); isa {
pubKey.SubKeys = append(pubKey.SubKeys, subKey)
}
}
}
|