aboutsummaryrefslogtreecommitdiff
path: root/object/signed/commit/parse.go
diff options
context:
space:
mode:
Diffstat (limited to 'object/signed/commit/parse.go')
-rw-r--r--object/signed/commit/parse.go104
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})
+}