mirror of
https://codeberg.org/davrot/forgejo.git
synced 2025-05-16 20:00:03 +02:00
Add configurable Trust Models (#11712)
* Add configurable Trust Models Gitea's default signature verification model differs from GitHub. GitHub uses signatures to verify that the committer is who they say they are - meaning that when GitHub makes a signed commit it must be the committer. The GitHub model prevents re-publishing of commits after revocation of a key and prevents re-signing of other people's commits to create a completely trusted repository signed by one key or a set of trusted keys. The default behaviour of Gitea in contrast is to always display the avatar and information related to a signature. This allows signatures to be decoupled from the committer. That being said, allowing arbitary users to present other peoples commits as theirs is not necessarily desired therefore we have a trust model whereby signatures from collaborators are marked trusted, signatures matching the commit line are marked untrusted and signatures that match a user in the db but not the committer line are marked unmatched. The problem with this model is that this conflicts with Github therefore we need to provide an option to allow users to choose the Github model should they wish to. Signed-off-by: Andrew Thornton <art27@cantab.net> * Adjust locale strings Signed-off-by: Andrew Thornton <art27@cantab.net> * as per @6543 Co-authored-by: 6543 <6543@obermui.de> * Update models/gpg_key.go * Add migration for repository Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
parent
89c94e2f8e
commit
4979f15c3f
29 changed files with 441 additions and 139 deletions
|
@ -831,7 +831,7 @@ func ParseCommitsWithSignature(oldCommits *list.List, repository *Repository) *l
|
|||
newCommits = list.New()
|
||||
e = oldCommits.Front()
|
||||
)
|
||||
memberMap := map[int64]bool{}
|
||||
keyMap := map[string]bool{}
|
||||
|
||||
for e != nil {
|
||||
c := e.Value.(UserCommit)
|
||||
|
@ -840,7 +840,7 @@ func ParseCommitsWithSignature(oldCommits *list.List, repository *Repository) *l
|
|||
Verification: ParseCommitWithSignature(c.Commit),
|
||||
}
|
||||
|
||||
_ = CalculateTrustStatus(signCommit.Verification, repository, &memberMap)
|
||||
_ = CalculateTrustStatus(signCommit.Verification, repository, &keyMap)
|
||||
|
||||
newCommits.PushBack(signCommit)
|
||||
e = e.Next()
|
||||
|
@ -849,31 +849,70 @@ func ParseCommitsWithSignature(oldCommits *list.List, repository *Repository) *l
|
|||
}
|
||||
|
||||
// CalculateTrustStatus will calculate the TrustStatus for a commit verification within a repository
|
||||
func CalculateTrustStatus(verification *CommitVerification, repository *Repository, memberMap *map[int64]bool) (err error) {
|
||||
if verification.Verified {
|
||||
verification.TrustStatus = "trusted"
|
||||
if verification.SigningUser.ID != 0 {
|
||||
var isMember bool
|
||||
if memberMap != nil {
|
||||
var has bool
|
||||
isMember, has = (*memberMap)[verification.SigningUser.ID]
|
||||
if !has {
|
||||
isMember, err = repository.IsOwnerMemberCollaborator(verification.SigningUser.ID)
|
||||
(*memberMap)[verification.SigningUser.ID] = isMember
|
||||
}
|
||||
} else {
|
||||
isMember, err = repository.IsOwnerMemberCollaborator(verification.SigningUser.ID)
|
||||
}
|
||||
|
||||
if !isMember {
|
||||
verification.TrustStatus = "untrusted"
|
||||
if verification.CommittingUser.ID != verification.SigningUser.ID {
|
||||
// The committing user and the signing user are not the same and are not the default key
|
||||
// This should be marked as questionable unless the signing user is a collaborator/team member etc.
|
||||
verification.TrustStatus = "unmatched"
|
||||
}
|
||||
}
|
||||
}
|
||||
func CalculateTrustStatus(verification *CommitVerification, repository *Repository, keyMap *map[string]bool) (err error) {
|
||||
if !verification.Verified {
|
||||
return
|
||||
}
|
||||
|
||||
// There are several trust models in Gitea
|
||||
trustModel := repository.GetTrustModel()
|
||||
|
||||
// In the Committer trust model a signature is trusted if it matches the committer
|
||||
// - it doesn't matter if they're a collaborator, the owner, Gitea or Github
|
||||
// NB: This model is commit verification only
|
||||
if trustModel == CommitterTrustModel {
|
||||
// default to "unmatched"
|
||||
verification.TrustStatus = "unmatched"
|
||||
|
||||
// We can only verify against users in our database but the default key will match
|
||||
// against by email if it is not in the db.
|
||||
if (verification.SigningUser.ID != 0 &&
|
||||
verification.CommittingUser.ID == verification.SigningUser.ID) ||
|
||||
(verification.SigningUser.ID == 0 && verification.CommittingUser.ID == 0 &&
|
||||
verification.SigningUser.Email == verification.CommittingUser.Email) {
|
||||
verification.TrustStatus = "trusted"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Now we drop to the more nuanced trust models...
|
||||
verification.TrustStatus = "trusted"
|
||||
|
||||
if verification.SigningUser.ID == 0 {
|
||||
// This commit is signed by the default key - but this key is not assigned to a user in the DB.
|
||||
|
||||
// However in the CollaboratorCommitterTrustModel we cannot mark this as trusted
|
||||
// unless the default key matches the email of a non-user.
|
||||
if trustModel == CollaboratorCommitterTrustModel && (verification.CommittingUser.ID != 0 ||
|
||||
verification.SigningUser.Email != verification.CommittingUser.Email) {
|
||||
verification.TrustStatus = "untrusted"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var isMember bool
|
||||
if keyMap != nil {
|
||||
var has bool
|
||||
isMember, has = (*keyMap)[verification.SigningKey.KeyID]
|
||||
if !has {
|
||||
isMember, err = repository.IsOwnerMemberCollaborator(verification.SigningUser.ID)
|
||||
(*keyMap)[verification.SigningKey.KeyID] = isMember
|
||||
}
|
||||
} else {
|
||||
isMember, err = repository.IsOwnerMemberCollaborator(verification.SigningUser.ID)
|
||||
}
|
||||
|
||||
if !isMember {
|
||||
verification.TrustStatus = "untrusted"
|
||||
if verification.CommittingUser.ID != verification.SigningUser.ID {
|
||||
// The committing user and the signing user are not the same
|
||||
// This should be marked as questionable unless the signing user is a collaborator/team member etc.
|
||||
verification.TrustStatus = "unmatched"
|
||||
}
|
||||
} else if trustModel == CollaboratorCommitterTrustModel && verification.CommittingUser.ID != verification.SigningUser.ID {
|
||||
// The committing user and the signing user are not the same and our trustmodel states that they must match
|
||||
verification.TrustStatus = "unmatched"
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue