forked from
tangled.org/core
Monorepo for Tangled — https://tangled.org
1package commitverify
2
3import (
4 "log"
5
6 "github.com/go-git/go-git/v5/plumbing/object"
7 "tangled.org/core/appview/db"
8 "tangled.org/core/appview/models"
9 "tangled.org/core/crypto"
10 "tangled.org/core/types"
11)
12
13type verifiedCommit struct {
14 fingerprint string
15 hash string
16}
17
18type VerifiedCommits map[verifiedCommit]struct{}
19
20func (vcs VerifiedCommits) IsVerified(hash string) bool {
21 for vc := range vcs {
22 if vc.hash == hash {
23 return true
24 }
25 }
26 return false
27}
28
29func (vcs VerifiedCommits) Fingerprint(hash string) string {
30 for vc := range vcs {
31 if vc.hash == hash {
32 return vc.fingerprint
33 }
34 }
35 return ""
36}
37
38func GetVerifiedObjectCommits(e db.Execer, emailToDid map[string]string, commits []*object.Commit) (VerifiedCommits, error) {
39 ndCommits := []types.NiceDiff{}
40 for _, commit := range commits {
41 ndCommits = append(ndCommits, ObjectCommitToNiceDiff(commit))
42 }
43 return GetVerifiedCommits(e, emailToDid, ndCommits)
44}
45
46func GetVerifiedCommits(e db.Execer, emailToDid map[string]string, ndCommits []types.NiceDiff) (VerifiedCommits, error) {
47 vcs := VerifiedCommits{}
48
49 didPubkeyCache := make(map[string][]models.PublicKey)
50
51 for _, commit := range ndCommits {
52 c := commit.Commit
53
54 committerEmail := c.Committer.Email
55 if did, exists := emailToDid[committerEmail]; exists {
56 // check if we've already fetched public keys for this did
57 pubKeys, ok := didPubkeyCache[did]
58 if !ok {
59 // fetch and cache public keys
60 keys, err := db.GetPublicKeysForDid(e, did)
61 if err != nil {
62 log.Printf("failed to fetch pubkey for %s: %v", committerEmail, err)
63 continue
64 }
65 pubKeys = keys
66 didPubkeyCache[did] = pubKeys
67 }
68
69 // try to verify with any associated pubkeys
70 for _, pk := range pubKeys {
71 if _, ok := crypto.VerifyCommitSignature(pk.Key, commit); ok {
72
73 fp, err := crypto.SSHFingerprint(pk.Key)
74 if err != nil {
75 log.Println("error computing ssh fingerprint:", err)
76 }
77
78 vc := verifiedCommit{fingerprint: fp, hash: c.This}
79 vcs[vc] = struct{}{}
80 break
81 }
82 }
83
84 }
85 }
86
87 return vcs, nil
88}
89
90// ObjectCommitToNiceDiff is a compatibility function to convert a
91// commit object into a NiceDiff structure.
92func ObjectCommitToNiceDiff(c *object.Commit) types.NiceDiff {
93 var niceDiff types.NiceDiff
94
95 // set commit information
96 niceDiff.Commit.Message = c.Message
97 niceDiff.Commit.Author = c.Author
98 niceDiff.Commit.This = c.Hash.String()
99 niceDiff.Commit.Committer = c.Committer
100 niceDiff.Commit.Tree = c.TreeHash.String()
101 niceDiff.Commit.PGPSignature = c.PGPSignature
102
103 changeId, ok := c.ExtraHeaders["change-id"]
104 if ok {
105 niceDiff.Commit.ChangedId = string(changeId)
106 }
107
108 // set parent hash if available
109 if len(c.ParentHashes) > 0 {
110 niceDiff.Commit.Parent = c.ParentHashes[0].String()
111 }
112
113 // XXX: Stats and Diff fields are typically populated
114 // after fetching the actual diff information, which isn't
115 // directly available in the commit object itself.
116
117 return niceDiff
118}