2021-12-19 08:37:18 +03:00
// Copyright 2021 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2021-12-19 08:37:18 +03:00
package asymkey
import (
"bytes"
2023-09-14 20:09:32 +03:00
"context"
2021-12-19 08:37:18 +03:00
"fmt"
"strings"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"github.com/42wim/sshsig"
)
// ParseCommitWithSSHSignature check if signature is good against keystore.
2023-09-14 20:09:32 +03:00
func ParseCommitWithSSHSignature ( ctx context . Context , c * git . Commit , committer * user_model . User ) * CommitVerification {
2021-12-19 08:37:18 +03:00
// Now try to associate the signature with the committer, if present
if committer . ID != 0 {
2023-11-24 06:49:41 +03:00
keys , err := db . Find [ PublicKey ] ( ctx , FindPublicKeyOptions {
OwnerID : committer . ID ,
NotKeytype : KeyTypePrincipal ,
} )
2021-12-19 08:37:18 +03:00
if err != nil { // Skipping failed to get ssh keys of user
log . Error ( "ListPublicKeys: %v" , err )
return & CommitVerification {
CommittingUser : committer ,
Verified : false ,
Reason : "gpg.error.failed_retrieval_gpg_keys" ,
}
}
2023-09-14 20:09:32 +03:00
committerEmailAddresses , err := user_model . GetEmailAddresses ( ctx , committer . ID )
2021-12-19 08:37:18 +03:00
if err != nil {
log . Error ( "GetEmailAddresses: %v" , err )
}
activated := false
for _ , e := range committerEmailAddresses {
if e . IsActivated && strings . EqualFold ( e . Email , c . Committer . Email ) {
activated = true
break
}
}
for _ , k := range keys {
if k . Verified && activated {
commitVerification := verifySSHCommitVerification ( c . Signature . Signature , c . Signature . Payload , k , committer , committer , c . Committer . Email )
if commitVerification != nil {
return commitVerification
}
}
}
}
return & CommitVerification {
CommittingUser : committer ,
Verified : false ,
Reason : NoKeyFound ,
}
}
func verifySSHCommitVerification ( sig , payload string , k * PublicKey , committer , signer * user_model . User , email string ) * CommitVerification {
if err := sshsig . Verify ( bytes . NewBuffer ( [ ] byte ( payload ) ) , [ ] byte ( sig ) , [ ] byte ( k . Content ) , "git" ) ; err != nil {
return nil
}
return & CommitVerification { // Everything is ok
CommittingUser : committer ,
Verified : true ,
Reason : fmt . Sprintf ( "%s / %s" , signer . Name , k . Fingerprint ) ,
SigningUser : signer ,
SigningSSHKey : k ,
SigningEmail : email ,
}
}