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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
package signedtag
import (
"bytes"
"slices"
objectid "codeberg.org/lindenii/furgit/object/id"
)
var signatureBeginLines = [][]byte{ //nolint:gochecknoglobals
[]byte("-----BEGIN PGP SIGNATURE-----"),
[]byte("-----BEGIN PGP MESSAGE-----"),
[]byte("-----BEGIN SSH SIGNATURE-----"),
[]byte("-----BEGIN SIGNED MESSAGE-----"),
}
// Parse parses one raw tag object body for signature extraction.
//
// Git stores the signature for storageAlgo as an in-body ASCII-armored
// trailer, and may store additional signatures for other algorithms in
// gpgsig* headers.
//
// The returned Tag remains valid only while body remains unchanged.
//
// Labels: Deps-Borrowed, Life-Parent.
func Parse(body []byte, storageAlgo objectid.Algorithm) (*Tag, error) {
tag := &Tag{
body: body,
signatures: make(map[objectid.Algorithm][]byteRange),
}
signatureStart := len(body)
for i := 0; i < len(body); {
lineStart := i
rel := bytes.IndexByte(body[i:], '\n')
next := len(body)
lineEnd := len(body)
if rel >= 0 {
lineEnd = i + rel
next = lineEnd + 1
}
line := body[lineStart:lineEnd]
if slices.ContainsFunc(signatureBeginLines, func(begin []byte) bool {
return bytes.HasPrefix(line, begin)
}) {
signatureStart = lineStart
}
i = next
}
payloadStart := 0
payloadEnd := signatureStart
if signatureStart == len(body) {
payloadEnd = len(body)
}
for i := 0; i < payloadEnd; {
lineStart := i
rel := bytes.IndexByte(body[i:payloadEnd], '\n')
next := payloadEnd
lineEnd := payloadEnd
if rel >= 0 {
lineEnd = i + rel
next = lineEnd + 1
}
line := body[lineStart:lineEnd]
i = next
if len(line) == 0 {
break
}
if line[0] == ' ' {
continue
}
key, valueStart, found := bytes.Cut(line, []byte{' '})
if !found {
continue
}
algo, ok := objectid.ParseSignatureHeaderName(string(key))
if !ok {
continue
}
tag.appendPayloadRange(payloadStart, lineStart)
tag.signatures[algo] = append(tag.signatures[algo], byteRange{
start: lineEnd - len(valueStart),
end: next,
})
for i < payloadEnd {
rel := bytes.IndexByte(body[i:payloadEnd], '\n')
next = payloadEnd
lineEnd = payloadEnd
if rel >= 0 {
lineEnd = i + rel
next = lineEnd + 1
}
cont := body[i:lineEnd]
if len(cont) == 0 || cont[0] != ' ' {
break
}
tag.signatures[algo] = append(tag.signatures[algo], byteRange{
start: i + 1,
end: next,
})
i = next
}
payloadStart = i
}
tag.appendPayloadRange(payloadStart, payloadEnd)
if signatureStart != len(body) {
tag.signatures[storageAlgo] = append(tag.signatures[storageAlgo], byteRange{
start: signatureStart,
end: len(body),
})
}
return tag, nil
}
func (tag *Tag) appendPayloadRange(start, end int) {
if start >= end {
return
}
tag.payload = append(tag.payload, byteRange{start: start, end: end})
}
|