diff options
Diffstat (limited to 'object/signed/commit/parse.go')
| -rw-r--r-- | object/signed/commit/parse.go | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/object/signed/commit/parse.go b/object/signed/commit/parse.go new file mode 100644 index 00000000..1714327f --- /dev/null +++ b/object/signed/commit/parse.go @@ -0,0 +1,104 @@ +package signedcommit + +import ( + "bytes" + + objectid "codeberg.org/lindenii/furgit/object/id" +) + +// Parse parses one raw commit object body for signature extraction. +// +// The returned Commit remains valid only while body remains unchanged. +// +// Labels: Deps-Borrowed, Life-Parent. +func Parse(body []byte) (*Commit, error) { + commit := &Commit{ + body: body, + signatures: make(map[objectid.Algorithm][]byteRange), + } + + payloadStart := 0 + i := 0 + + for 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] + i = next + + if len(line) == 0 { + commit.appendPayloadRange(payloadStart, len(body)) + + return commit, nil + } + + if line[0] == ' ' { + continue + } + + if !bytes.HasPrefix(line, []byte("gpgsig")) { + continue + } + + commit.appendPayloadRange(payloadStart, lineStart) + + key, valueStart, found := bytes.Cut(line, []byte{' '}) + if found { + if algo, ok := objectid.ParseSignatureHeaderName(string(key)); ok { + commit.signatures[algo] = append(commit.signatures[algo], byteRange{ + start: lineEnd - len(valueStart), + end: next, + }) + } + } + + for i < len(body) { + rel := bytes.IndexByte(body[i:], '\n') + next = len(body) + lineEnd = len(body) + if rel >= 0 { + lineEnd = i + rel + next = lineEnd + 1 + } + + contStart := i + cont := body[contStart:lineEnd] + if len(cont) == 0 || cont[0] != ' ' { + break + } + + if found { + if algo, ok := objectid.ParseSignatureHeaderName(string(key)); ok { + commit.signatures[algo] = append(commit.signatures[algo], byteRange{ + start: contStart + 1, + end: next, + }) + } + } + + i = next + } + + payloadStart = i + } + + commit.appendPayloadRange(payloadStart, len(body)) + + return commit, nil +} + +func (commit *Commit) appendPayloadRange(start, end int) { + if start >= end { + return + } + + commit.payload = append(commit.payload, byteRange{start: start, end: end}) +} |
