diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2021-12-10 16:14:24 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-10 16:14:24 +0800 |
commit | 3ca5dc7e32b372d14ff80d96f14b8f6a805862f1 (patch) | |
tree | 50d193ed0dacf2888d57b193a9b0d36065aff205 /models | |
parent | 0a9fcf63a49799ad3b0f146c54879161bac61e10 (diff) | |
download | gitea-3ca5dc7e32b372d14ff80d96f14b8f6a805862f1.tar.gz gitea-3ca5dc7e32b372d14ff80d96f14b8f6a805862f1.zip |
Move keys to models/asymkey (#17917)
* Move keys to models/keys
* Rename models/keys -> models/asymkey
* change the missed package name
* Fix package alias
* Fix test
* Fix docs
* Fix test
* Fix test
* merge
Diffstat (limited to 'models')
-rw-r--r-- | models/asymkey/error.go | 248 | ||||
-rw-r--r-- | models/asymkey/gpg_key.go (renamed from models/gpg_key.go) | 11 | ||||
-rw-r--r-- | models/asymkey/gpg_key_add.go (renamed from models/gpg_key_add.go) | 2 | ||||
-rw-r--r-- | models/asymkey/gpg_key_commit_verification.go (renamed from models/gpg_key_commit_verification.go) | 24 | ||||
-rw-r--r-- | models/asymkey/gpg_key_common.go (renamed from models/gpg_key_common.go) | 2 | ||||
-rw-r--r-- | models/asymkey/gpg_key_import.go (renamed from models/gpg_key_import.go) | 2 | ||||
-rw-r--r-- | models/asymkey/gpg_key_test.go (renamed from models/gpg_key_test.go) | 2 | ||||
-rw-r--r-- | models/asymkey/gpg_key_verify.go (renamed from models/gpg_key_verify.go) | 2 | ||||
-rw-r--r-- | models/asymkey/main_test.go | 29 | ||||
-rw-r--r-- | models/asymkey/ssh_key.go (renamed from models/ssh_key.go) | 45 | ||||
-rw-r--r-- | models/asymkey/ssh_key_authorized_keys.go (renamed from models/ssh_key_authorized_keys.go) | 8 | ||||
-rw-r--r-- | models/asymkey/ssh_key_authorized_principals.go (renamed from models/ssh_key_authorized_principals.go) | 2 | ||||
-rw-r--r-- | models/asymkey/ssh_key_deploy.go (renamed from models/ssh_key_deploy.go) | 82 | ||||
-rw-r--r-- | models/asymkey/ssh_key_fingerprint.go (renamed from models/ssh_key_fingerprint.go) | 2 | ||||
-rw-r--r-- | models/asymkey/ssh_key_parse.go (renamed from models/ssh_key_parse.go) | 5 | ||||
-rw-r--r-- | models/asymkey/ssh_key_principals.go (renamed from models/ssh_key_principals.go) | 4 | ||||
-rw-r--r-- | models/asymkey/ssh_key_test.go (renamed from models/ssh_key_test.go) | 7 | ||||
-rw-r--r-- | models/commit.go | 8 | ||||
-rw-r--r-- | models/commit_status.go | 5 | ||||
-rw-r--r-- | models/db/error.go | 13 | ||||
-rw-r--r-- | models/error.go | 277 | ||||
-rw-r--r-- | models/main_test.go | 6 | ||||
-rw-r--r-- | models/pull_sign.go | 133 | ||||
-rw-r--r-- | models/repo.go | 61 | ||||
-rw-r--r-- | models/repo_sign.go | 251 | ||||
-rw-r--r-- | models/statistic.go | 3 | ||||
-rw-r--r-- | models/user.go | 9 | ||||
-rw-r--r-- | models/user_test.go | 69 |
28 files changed, 412 insertions, 900 deletions
diff --git a/models/asymkey/error.go b/models/asymkey/error.go new file mode 100644 index 0000000000..7add553bd6 --- /dev/null +++ b/models/asymkey/error.go @@ -0,0 +1,248 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package asymkey + +import "fmt" + +// ErrKeyUnableVerify represents a "KeyUnableVerify" kind of error. +type ErrKeyUnableVerify struct { + Result string +} + +// IsErrKeyUnableVerify checks if an error is a ErrKeyUnableVerify. +func IsErrKeyUnableVerify(err error) bool { + _, ok := err.(ErrKeyUnableVerify) + return ok +} + +func (err ErrKeyUnableVerify) Error() string { + return fmt.Sprintf("Unable to verify key content [result: %s]", err.Result) +} + +// ErrKeyNotExist represents a "KeyNotExist" kind of error. +type ErrKeyNotExist struct { + ID int64 +} + +// IsErrKeyNotExist checks if an error is a ErrKeyNotExist. +func IsErrKeyNotExist(err error) bool { + _, ok := err.(ErrKeyNotExist) + return ok +} + +func (err ErrKeyNotExist) Error() string { + return fmt.Sprintf("public key does not exist [id: %d]", err.ID) +} + +// ErrKeyAlreadyExist represents a "KeyAlreadyExist" kind of error. +type ErrKeyAlreadyExist struct { + OwnerID int64 + Fingerprint string + Content string +} + +// IsErrKeyAlreadyExist checks if an error is a ErrKeyAlreadyExist. +func IsErrKeyAlreadyExist(err error) bool { + _, ok := err.(ErrKeyAlreadyExist) + return ok +} + +func (err ErrKeyAlreadyExist) Error() string { + return fmt.Sprintf("public key already exists [owner_id: %d, finger_print: %s, content: %s]", + err.OwnerID, err.Fingerprint, err.Content) +} + +// ErrKeyNameAlreadyUsed represents a "KeyNameAlreadyUsed" kind of error. +type ErrKeyNameAlreadyUsed struct { + OwnerID int64 + Name string +} + +// IsErrKeyNameAlreadyUsed checks if an error is a ErrKeyNameAlreadyUsed. +func IsErrKeyNameAlreadyUsed(err error) bool { + _, ok := err.(ErrKeyNameAlreadyUsed) + return ok +} + +func (err ErrKeyNameAlreadyUsed) Error() string { + return fmt.Sprintf("public key already exists [owner_id: %d, name: %s]", err.OwnerID, err.Name) +} + +// ErrGPGNoEmailFound represents a "ErrGPGNoEmailFound" kind of error. +type ErrGPGNoEmailFound struct { + FailedEmails []string + ID string +} + +// IsErrGPGNoEmailFound checks if an error is a ErrGPGNoEmailFound. +func IsErrGPGNoEmailFound(err error) bool { + _, ok := err.(ErrGPGNoEmailFound) + return ok +} + +func (err ErrGPGNoEmailFound) Error() string { + return fmt.Sprintf("none of the emails attached to the GPG key could be found: %v", err.FailedEmails) +} + +// ErrGPGInvalidTokenSignature represents a "ErrGPGInvalidTokenSignature" kind of error. +type ErrGPGInvalidTokenSignature struct { + Wrapped error + ID string +} + +// IsErrGPGInvalidTokenSignature checks if an error is a ErrGPGInvalidTokenSignature. +func IsErrGPGInvalidTokenSignature(err error) bool { + _, ok := err.(ErrGPGInvalidTokenSignature) + return ok +} + +func (err ErrGPGInvalidTokenSignature) Error() string { + return "the provided signature does not sign the token with the provided key" +} + +// ErrGPGKeyParsing represents a "ErrGPGKeyParsing" kind of error. +type ErrGPGKeyParsing struct { + ParseError error +} + +// IsErrGPGKeyParsing checks if an error is a ErrGPGKeyParsing. +func IsErrGPGKeyParsing(err error) bool { + _, ok := err.(ErrGPGKeyParsing) + return ok +} + +func (err ErrGPGKeyParsing) Error() string { + return fmt.Sprintf("failed to parse gpg key %s", err.ParseError.Error()) +} + +// ErrGPGKeyNotExist represents a "GPGKeyNotExist" kind of error. +type ErrGPGKeyNotExist struct { + ID int64 +} + +// IsErrGPGKeyNotExist checks if an error is a ErrGPGKeyNotExist. +func IsErrGPGKeyNotExist(err error) bool { + _, ok := err.(ErrGPGKeyNotExist) + return ok +} + +func (err ErrGPGKeyNotExist) Error() string { + return fmt.Sprintf("public gpg key does not exist [id: %d]", err.ID) +} + +// ErrGPGKeyImportNotExist represents a "GPGKeyImportNotExist" kind of error. +type ErrGPGKeyImportNotExist struct { + ID string +} + +// IsErrGPGKeyImportNotExist checks if an error is a ErrGPGKeyImportNotExist. +func IsErrGPGKeyImportNotExist(err error) bool { + _, ok := err.(ErrGPGKeyImportNotExist) + return ok +} + +func (err ErrGPGKeyImportNotExist) Error() string { + return fmt.Sprintf("public gpg key import does not exist [id: %s]", err.ID) +} + +// ErrGPGKeyIDAlreadyUsed represents a "GPGKeyIDAlreadyUsed" kind of error. +type ErrGPGKeyIDAlreadyUsed struct { + KeyID string +} + +// IsErrGPGKeyIDAlreadyUsed checks if an error is a ErrKeyNameAlreadyUsed. +func IsErrGPGKeyIDAlreadyUsed(err error) bool { + _, ok := err.(ErrGPGKeyIDAlreadyUsed) + return ok +} + +func (err ErrGPGKeyIDAlreadyUsed) Error() string { + return fmt.Sprintf("public key already exists [key_id: %s]", err.KeyID) +} + +// ErrGPGKeyAccessDenied represents a "GPGKeyAccessDenied" kind of Error. +type ErrGPGKeyAccessDenied struct { + UserID int64 + KeyID int64 +} + +// IsErrGPGKeyAccessDenied checks if an error is a ErrGPGKeyAccessDenied. +func IsErrGPGKeyAccessDenied(err error) bool { + _, ok := err.(ErrGPGKeyAccessDenied) + return ok +} + +// Error pretty-prints an error of type ErrGPGKeyAccessDenied. +func (err ErrGPGKeyAccessDenied) Error() string { + return fmt.Sprintf("user does not have access to the key [user_id: %d, key_id: %d]", + err.UserID, err.KeyID) +} + +// ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error. +type ErrKeyAccessDenied struct { + UserID int64 + KeyID int64 + Note string +} + +// IsErrKeyAccessDenied checks if an error is a ErrKeyAccessDenied. +func IsErrKeyAccessDenied(err error) bool { + _, ok := err.(ErrKeyAccessDenied) + return ok +} + +func (err ErrKeyAccessDenied) Error() string { + return fmt.Sprintf("user does not have access to the key [user_id: %d, key_id: %d, note: %s]", + err.UserID, err.KeyID, err.Note) +} + +// ErrDeployKeyNotExist represents a "DeployKeyNotExist" kind of error. +type ErrDeployKeyNotExist struct { + ID int64 + KeyID int64 + RepoID int64 +} + +// IsErrDeployKeyNotExist checks if an error is a ErrDeployKeyNotExist. +func IsErrDeployKeyNotExist(err error) bool { + _, ok := err.(ErrDeployKeyNotExist) + return ok +} + +func (err ErrDeployKeyNotExist) Error() string { + return fmt.Sprintf("Deploy key does not exist [id: %d, key_id: %d, repo_id: %d]", err.ID, err.KeyID, err.RepoID) +} + +// ErrDeployKeyAlreadyExist represents a "DeployKeyAlreadyExist" kind of error. +type ErrDeployKeyAlreadyExist struct { + KeyID int64 + RepoID int64 +} + +// IsErrDeployKeyAlreadyExist checks if an error is a ErrDeployKeyAlreadyExist. +func IsErrDeployKeyAlreadyExist(err error) bool { + _, ok := err.(ErrDeployKeyAlreadyExist) + return ok +} + +func (err ErrDeployKeyAlreadyExist) Error() string { + return fmt.Sprintf("public key already exists [key_id: %d, repo_id: %d]", err.KeyID, err.RepoID) +} + +// ErrDeployKeyNameAlreadyUsed represents a "DeployKeyNameAlreadyUsed" kind of error. +type ErrDeployKeyNameAlreadyUsed struct { + RepoID int64 + Name string +} + +// IsErrDeployKeyNameAlreadyUsed checks if an error is a ErrDeployKeyNameAlreadyUsed. +func IsErrDeployKeyNameAlreadyUsed(err error) bool { + _, ok := err.(ErrDeployKeyNameAlreadyUsed) + return ok +} + +func (err ErrDeployKeyNameAlreadyUsed) Error() string { + return fmt.Sprintf("public key with name already exists [repo_id: %d, name: %s]", err.RepoID, err.Name) +} diff --git a/models/gpg_key.go b/models/asymkey/gpg_key.go index ce27a9237e..ced6ca37a3 100644 --- a/models/gpg_key.go +++ b/models/asymkey/gpg_key.go @@ -2,9 +2,10 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package asymkey import ( + "context" "fmt" "strings" "time" @@ -63,12 +64,8 @@ func (key *GPGKey) AfterLoad(session *xorm.Session) { } // ListGPGKeys returns a list of public keys belongs to given user. -func ListGPGKeys(uid int64, listOptions db.ListOptions) ([]*GPGKey, error) { - return listGPGKeys(db.GetEngine(db.DefaultContext), uid, listOptions) -} - -func listGPGKeys(e db.Engine, uid int64, listOptions db.ListOptions) ([]*GPGKey, error) { - sess := e.Table(&GPGKey{}).Where("owner_id=? AND primary_key_id=''", uid) +func ListGPGKeys(ctx context.Context, uid int64, listOptions db.ListOptions) ([]*GPGKey, error) { + sess := db.GetEngine(ctx).Table(&GPGKey{}).Where("owner_id=? AND primary_key_id=''", uid) if listOptions.Page != 0 { sess = db.SetSessionPagination(sess, &listOptions) } diff --git a/models/gpg_key_add.go b/models/asymkey/gpg_key_add.go index 711fc86dee..8f84bba1df 100644 --- a/models/gpg_key_add.go +++ b/models/asymkey/gpg_key_add.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package asymkey import ( "strings" diff --git a/models/gpg_key_commit_verification.go b/models/asymkey/gpg_key_commit_verification.go index 48f58c07b6..5ec4e335d5 100644 --- a/models/gpg_key_commit_verification.go +++ b/models/asymkey/gpg_key_commit_verification.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package asymkey import ( "fmt" @@ -70,7 +70,7 @@ const ( ) // ParseCommitsWithSignature checks if signaute of commits are corresponding to users gpg keys. -func ParseCommitsWithSignature(oldCommits []*user_model.UserCommit, repository *repo_model.Repository) []*SignCommit { +func ParseCommitsWithSignature(oldCommits []*user_model.UserCommit, repoTrustModel repo_model.TrustModelType, isCodeReader func(*user_model.User) (bool, error)) []*SignCommit { newCommits := make([]*SignCommit, 0, len(oldCommits)) keyMap := map[string]bool{} @@ -80,7 +80,7 @@ func ParseCommitsWithSignature(oldCommits []*user_model.UserCommit, repository * Verification: ParseCommitWithSignature(c.Commit), } - _ = CalculateTrustStatus(signCommit.Verification, repository, &keyMap) + _ = CalculateTrustStatus(signCommit.Verification, repoTrustModel, isCodeReader, &keyMap) newCommits = append(newCommits, signCommit) } @@ -159,7 +159,7 @@ func ParseCommitWithSignature(c *git.Commit) *CommitVerification { // Now try to associate the signature with the committer, if present if committer.ID != 0 { - keys, err := ListGPGKeys(committer.ID, db.ListOptions{}) + keys, err := ListGPGKeys(db.DefaultContext, committer.ID, db.ListOptions{}) if err != nil { // Skipping failed to get gpg keys of user log.Error("ListGPGKeys: %v", err) return &CommitVerification{ @@ -448,18 +448,16 @@ func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *use } // CalculateTrustStatus will calculate the TrustStatus for a commit verification within a repository -func CalculateTrustStatus(verification *CommitVerification, repository *repo_model.Repository, keyMap *map[string]bool) (err error) { +// There are several trust models in Gitea +func CalculateTrustStatus(verification *CommitVerification, repoTrustModel repo_model.TrustModelType, isCodeReader func(*user_model.User) (bool, error), 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 == repo_model.CommitterTrustModel { + if repoTrustModel == repo_model.CommitterTrustModel { // default to "unmatched" verification.TrustStatus = "unmatched" @@ -482,7 +480,7 @@ func CalculateTrustStatus(verification *CommitVerification, repository *repo_mod // However in the repo_model.CollaboratorCommitterTrustModel we cannot mark this as trusted // unless the default key matches the email of a non-user. - if trustModel == repo_model.CollaboratorCommitterTrustModel && (verification.CommittingUser.ID != 0 || + if repoTrustModel == repo_model.CollaboratorCommitterTrustModel && (verification.CommittingUser.ID != 0 || verification.SigningUser.Email != verification.CommittingUser.Email) { verification.TrustStatus = "untrusted" } @@ -494,11 +492,11 @@ func CalculateTrustStatus(verification *CommitVerification, repository *repo_mod var has bool isMember, has = (*keyMap)[verification.SigningKey.KeyID] if !has { - isMember, err = IsOwnerMemberCollaborator(repository, verification.SigningUser.ID) + isMember, err = isCodeReader(verification.SigningUser) (*keyMap)[verification.SigningKey.KeyID] = isMember } } else { - isMember, err = IsOwnerMemberCollaborator(repository, verification.SigningUser.ID) + isMember, err = isCodeReader(verification.SigningUser) } if !isMember { @@ -508,7 +506,7 @@ func CalculateTrustStatus(verification *CommitVerification, repository *repo_mod // This should be marked as questionable unless the signing user is a collaborator/team member etc. verification.TrustStatus = "unmatched" } - } else if trustModel == repo_model.CollaboratorCommitterTrustModel && verification.CommittingUser.ID != verification.SigningUser.ID { + } else if repoTrustModel == repo_model.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" } diff --git a/models/gpg_key_common.go b/models/asymkey/gpg_key_common.go index 72803625ee..1ea510c45f 100644 --- a/models/gpg_key_common.go +++ b/models/asymkey/gpg_key_common.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package asymkey import ( "bytes" diff --git a/models/gpg_key_import.go b/models/asymkey/gpg_key_import.go index 1eed929627..210c4b835b 100644 --- a/models/gpg_key_import.go +++ b/models/asymkey/gpg_key_import.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package asymkey import "code.gitea.io/gitea/models/db" diff --git a/models/gpg_key_test.go b/models/asymkey/gpg_key_test.go index 8f51c146aa..07bb77bdf4 100644 --- a/models/gpg_key_test.go +++ b/models/asymkey/gpg_key_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package asymkey import ( "testing" diff --git a/models/gpg_key_verify.go b/models/asymkey/gpg_key_verify.go index 1824086021..152765cc3a 100644 --- a/models/gpg_key_verify.go +++ b/models/asymkey/gpg_key_verify.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package asymkey import ( "strconv" diff --git a/models/asymkey/main_test.go b/models/asymkey/main_test.go new file mode 100644 index 0000000000..1c4f7752e2 --- /dev/null +++ b/models/asymkey/main_test.go @@ -0,0 +1,29 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package asymkey + +import ( + "path/filepath" + "testing" + + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/setting" +) + +func init() { + setting.SetCustomPathAndConf("", "", "") + setting.LoadForTest() +} + +func TestMain(m *testing.M) { + unittest.MainTest(m, filepath.Join("..", ".."), + "gpg_key.yml", + "public_key.yml", + "deploy_key.yml", + "gpg_key_import.yml", + "user.yml", + "email_address.yml", + ) +} diff --git a/models/ssh_key.go b/models/asymkey/ssh_key.go index 0d97096149..cc63663221 100644 --- a/models/ssh_key.go +++ b/models/asymkey/ssh_key.go @@ -3,9 +3,10 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package asymkey import ( + "context" "fmt" "strings" "time" @@ -247,13 +248,13 @@ func UpdatePublicKeyUpdated(id int64) error { return nil } -// deletePublicKeys does the actual key deletion but does not update authorized_keys file. -func deletePublicKeys(e db.Engine, keyIDs ...int64) error { +// DeletePublicKeys does the actual key deletion but does not update authorized_keys file. +func DeletePublicKeys(ctx context.Context, keyIDs ...int64) error { if len(keyIDs) == 0 { return nil } - _, err := e.In("id", keyIDs).Delete(new(PublicKey)) + _, err := db.GetEngine(ctx).In("id", keyIDs).Delete(new(PublicKey)) return err } @@ -325,40 +326,6 @@ func PublicKeyIsExternallyManaged(id int64) (bool, error) { return false, nil } -// DeletePublicKey deletes SSH key information both in database and authorized_keys file. -func DeletePublicKey(doer *user_model.User, id int64) (err error) { - key, err := GetPublicKeyByID(id) - if err != nil { - return err - } - - // Check if user has access to delete this key. - if !doer.IsAdmin && doer.ID != key.OwnerID { - return ErrKeyAccessDenied{doer.ID, key.ID, "public"} - } - - ctx, committer, err := db.TxContext() - if err != nil { - return err - } - defer committer.Close() - - if err = deletePublicKeys(db.GetEngine(ctx), id); err != nil { - return err - } - - if err = committer.Commit(); err != nil { - return err - } - committer.Close() - - if key.Type == KeyTypePrincipal { - return RewriteAllPrincipalKeys() - } - - return RewriteAllPublicKeys() -} - // deleteKeysMarkedForDeletion returns true if ssh keys needs update func deleteKeysMarkedForDeletion(keys []string) (bool, error) { // Start session @@ -377,7 +344,7 @@ func deleteKeysMarkedForDeletion(keys []string) (bool, error) { log.Error("SearchPublicKeyByContent: %v", err) continue } - if err = deletePublicKeys(sess, key.ID); err != nil { + if err = DeletePublicKeys(ctx, key.ID); err != nil { log.Error("deletePublicKeys: %v", err) continue } diff --git a/models/ssh_key_authorized_keys.go b/models/asymkey/ssh_key_authorized_keys.go index 7843390ffc..dd058f5d11 100644 --- a/models/ssh_key_authorized_keys.go +++ b/models/asymkey/ssh_key_authorized_keys.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package asymkey import ( "bufio" @@ -118,10 +118,6 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error { // Note: db.GetEngine(db.DefaultContext).Iterate does not get latest data after insert/delete, so we have to call this function // outside any session scope independently. func RewriteAllPublicKeys() error { - return rewriteAllPublicKeys(db.GetEngine(db.DefaultContext)) -} - -func rewriteAllPublicKeys(e db.Engine) error { // Don't rewrite key if internal server if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile { return nil @@ -169,7 +165,7 @@ func rewriteAllPublicKeys(e db.Engine) error { } } - if err := regeneratePublicKeys(e, t); err != nil { + if err := RegeneratePublicKeys(t); err != nil { return err } diff --git a/models/ssh_key_authorized_principals.go b/models/asymkey/ssh_key_authorized_principals.go index c053b4b6d5..a8c48c50aa 100644 --- a/models/ssh_key_authorized_principals.go +++ b/models/asymkey/ssh_key_authorized_principals.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package asymkey import ( "bufio" diff --git a/models/ssh_key_deploy.go b/models/asymkey/ssh_key_deploy.go index 672974afb3..fc6324792a 100644 --- a/models/ssh_key_deploy.go +++ b/models/asymkey/ssh_key_deploy.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package asymkey import ( "context" @@ -11,8 +11,6 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/timeutil" "xorm.io/builder" @@ -169,13 +167,9 @@ func AddDeployKey(repoID int64, name, content string, readOnly bool) (*DeployKey } // GetDeployKeyByID returns deploy key by given ID. -func GetDeployKeyByID(id int64) (*DeployKey, error) { - return getDeployKeyByID(db.GetEngine(db.DefaultContext), id) -} - -func getDeployKeyByID(e db.Engine, id int64) (*DeployKey, error) { +func GetDeployKeyByID(ctx context.Context, id int64) (*DeployKey, error) { key := new(DeployKey) - has, err := e.ID(id).Get(key) + has, err := db.GetEngine(ctx).ID(id).Get(key) if err != nil { return nil, err } else if !has { @@ -215,68 +209,6 @@ func UpdateDeployKey(key *DeployKey) error { return err } -// DeleteDeployKey deletes deploy key from its repository authorized_keys file if needed. -func DeleteDeployKey(doer *user_model.User, id int64) error { - ctx, committer, err := db.TxContext() - if err != nil { - return err - } - defer committer.Close() - - if err := deleteDeployKey(ctx, doer, id); err != nil { - return err - } - return committer.Commit() -} - -func deleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error { - sess := db.GetEngine(ctx) - key, err := getDeployKeyByID(sess, id) - if err != nil { - if IsErrDeployKeyNotExist(err) { - return nil - } - return fmt.Errorf("GetDeployKeyByID: %v", err) - } - - // Check if user has access to delete this key. - if !doer.IsAdmin { - repo, err := repo_model.GetRepositoryByIDCtx(ctx, key.RepoID) - if err != nil { - return fmt.Errorf("repo_model.GetRepositoryByID: %v", err) - } - has, err := isUserRepoAdmin(sess, repo, doer) - if err != nil { - return fmt.Errorf("GetUserRepoPermission: %v", err) - } else if !has { - return ErrKeyAccessDenied{doer.ID, key.ID, "deploy"} - } - } - - if _, err = sess.ID(key.ID).Delete(new(DeployKey)); err != nil { - return fmt.Errorf("delete deploy key [%d]: %v", key.ID, err) - } - - // Check if this is the last reference to same key content. - has, err := sess. - Where("key_id = ?", key.KeyID). - Get(new(DeployKey)) - if err != nil { - return err - } else if !has { - if err = deletePublicKeys(sess, key.KeyID); err != nil { - return err - } - - // after deleted the public keys, should rewrite the public keys file - if err = rewriteAllPublicKeys(sess); err != nil { - return err - } - } - - return nil -} - // ListDeployKeysOptions are options for ListDeployKeys type ListDeployKeysOptions struct { db.ListOptions @@ -300,12 +232,8 @@ func (opt ListDeployKeysOptions) toCond() builder.Cond { } // ListDeployKeys returns a list of deploy keys matching the provided arguments. -func ListDeployKeys(opts *ListDeployKeysOptions) ([]*DeployKey, error) { - return listDeployKeys(db.GetEngine(db.DefaultContext), opts) -} - -func listDeployKeys(e db.Engine, opts *ListDeployKeysOptions) ([]*DeployKey, error) { - sess := e.Where(opts.toCond()) +func ListDeployKeys(ctx context.Context, opts *ListDeployKeysOptions) ([]*DeployKey, error) { + sess := db.GetEngine(ctx).Where(opts.toCond()) if opts.Page != 0 { sess = db.SetSessionPagination(sess, opts) diff --git a/models/ssh_key_fingerprint.go b/models/asymkey/ssh_key_fingerprint.go index 85296c961c..437f283bfa 100644 --- a/models/ssh_key_fingerprint.go +++ b/models/asymkey/ssh_key_fingerprint.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package asymkey import ( "errors" diff --git a/models/ssh_key_parse.go b/models/asymkey/ssh_key_parse.go index 748c66da7d..734bd4ccab 100644 --- a/models/ssh_key_parse.go +++ b/models/asymkey/ssh_key_parse.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package asymkey import ( "crypto/rsa" @@ -18,6 +18,7 @@ import ( "strconv" "strings" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" @@ -157,7 +158,7 @@ func parseKeyString(content string) (string, error) { // It returns the actual public key line on success. func CheckPublicKeyString(content string) (_ string, err error) { if setting.SSH.Disabled { - return "", ErrSSHDisabled{} + return "", db.ErrSSHDisabled{} } content, err = parseKeyString(content) diff --git a/models/ssh_key_principals.go b/models/asymkey/ssh_key_principals.go index 9a17a56f1a..19fc6644cb 100644 --- a/models/ssh_key_principals.go +++ b/models/asymkey/ssh_key_principals.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package asymkey import ( "errors" @@ -76,7 +76,7 @@ func addPrincipalKey(e db.Engine, key *PublicKey) (err error) { // CheckPrincipalKeyString strips spaces and returns an error if the given principal contains newlines func CheckPrincipalKeyString(user *user_model.User, content string) (_ string, err error) { if setting.SSH.Disabled { - return "", ErrSSHDisabled{} + return "", db.ErrSSHDisabled{} } content = strings.TrimSpace(content) diff --git a/models/ssh_key_test.go b/models/asymkey/ssh_key_test.go index b52a36bdbd..62c07c6035 100644 --- a/models/ssh_key_test.go +++ b/models/asymkey/ssh_key_test.go @@ -3,7 +3,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package asymkey import ( "strings" @@ -14,11 +14,6 @@ import ( "github.com/stretchr/testify/assert" ) -func init() { - setting.SetCustomPathAndConf("", "", "") - setting.LoadForTest() -} - func Test_SSHParsePublicKey(t *testing.T) { testCases := []struct { name string diff --git a/models/commit.go b/models/commit.go index 8de71da1b3..5df6964a1d 100644 --- a/models/commit.go +++ b/models/commit.go @@ -5,6 +5,7 @@ package models import ( + asymkey_model "code.gitea.io/gitea/models/asymkey" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" @@ -13,9 +14,12 @@ import ( // ConvertFromGitCommit converts git commits into SignCommitWithStatuses func ConvertFromGitCommit(commits []*git.Commit, repo *repo_model.Repository) []*SignCommitWithStatuses { return ParseCommitsWithStatus( - ParseCommitsWithSignature( + asymkey_model.ParseCommitsWithSignature( user_model.ValidateCommitsWithEmails(commits), - repo, + repo.GetTrustModel(), + func(user *user_model.User) (bool, error) { + return IsUserRepoAdmin(repo, user) + }, ), repo, ) diff --git a/models/commit_status.go b/models/commit_status.go index e0942d2028..93b6f93f96 100644 --- a/models/commit_status.go +++ b/models/commit_status.go @@ -12,6 +12,7 @@ import ( "strings" "time" + asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -328,11 +329,11 @@ func NewCommitStatus(opts NewCommitStatusOptions) error { type SignCommitWithStatuses struct { Status *CommitStatus Statuses []*CommitStatus - *SignCommit + *asymkey_model.SignCommit } // ParseCommitsWithStatus checks commits latest statuses and calculates its worst status state -func ParseCommitsWithStatus(oldCommits []*SignCommit, repo *repo_model.Repository) []*SignCommitWithStatuses { +func ParseCommitsWithStatus(oldCommits []*asymkey_model.SignCommit, repo *repo_model.Repository) []*SignCommitWithStatuses { newCommits := make([]*SignCommitWithStatuses, 0, len(oldCommits)) for _, c := range oldCommits { diff --git a/models/db/error.go b/models/db/error.go index adaeedcc09..f20cc9b4cb 100644 --- a/models/db/error.go +++ b/models/db/error.go @@ -29,3 +29,16 @@ func ErrCancelledf(format string, args ...interface{}) error { fmt.Sprintf(format, args...), } } + +// ErrSSHDisabled represents an "SSH disabled" error. +type ErrSSHDisabled struct{} + +// IsErrSSHDisabled checks if an error is a ErrSSHDisabled. +func IsErrSSHDisabled(err error) bool { + _, ok := err.(ErrSSHDisabled) + return ok +} + +func (err ErrSSHDisabled) Error() string { + return "SSH is disabled" +} diff --git a/models/error.go b/models/error.go index 20ed7f90e1..54556fd787 100644 --- a/models/error.go +++ b/models/error.go @@ -28,19 +28,6 @@ func (err ErrNotExist) Error() string { return fmt.Sprintf("record does not exist [id: %d]", err.ID) } -// ErrSSHDisabled represents an "SSH disabled" error. -type ErrSSHDisabled struct{} - -// IsErrSSHDisabled checks if an error is a ErrSSHDisabled. -func IsErrSSHDisabled(err error) bool { - _, ok := err.(ErrSSHDisabled) - return ok -} - -func (err ErrSSHDisabled) Error() string { - return "SSH is disabled" -} - // ErrUserOwnRepos represents a "UserOwnRepos" kind of error. type ErrUserOwnRepos struct { UID int64 @@ -151,254 +138,6 @@ func (err ErrWikiInvalidFileName) Error() string { return fmt.Sprintf("Invalid wiki filename: %s", err.FileName) } -// __________ ___. .__ .__ ____ __. -// \______ \__ _\_ |__ | | |__| ____ | |/ _|____ ___.__. -// | ___/ | \ __ \| | | |/ ___\ | <_/ __ < | | -// | | | | / \_\ \ |_| \ \___ | | \ ___/\___ | -// |____| |____/|___ /____/__|\___ > |____|__ \___ > ____| -// \/ \/ \/ \/\/ - -// ErrKeyUnableVerify represents a "KeyUnableVerify" kind of error. -type ErrKeyUnableVerify struct { - Result string -} - -// IsErrKeyUnableVerify checks if an error is a ErrKeyUnableVerify. -func IsErrKeyUnableVerify(err error) bool { - _, ok := err.(ErrKeyUnableVerify) - return ok -} - -func (err ErrKeyUnableVerify) Error() string { - return fmt.Sprintf("Unable to verify key content [result: %s]", err.Result) -} - -// ErrKeyNotExist represents a "KeyNotExist" kind of error. -type ErrKeyNotExist struct { - ID int64 -} - -// IsErrKeyNotExist checks if an error is a ErrKeyNotExist. -func IsErrKeyNotExist(err error) bool { - _, ok := err.(ErrKeyNotExist) - return ok -} - -func (err ErrKeyNotExist) Error() string { - return fmt.Sprintf("public key does not exist [id: %d]", err.ID) -} - -// ErrKeyAlreadyExist represents a "KeyAlreadyExist" kind of error. -type ErrKeyAlreadyExist struct { - OwnerID int64 - Fingerprint string - Content string -} - -// IsErrKeyAlreadyExist checks if an error is a ErrKeyAlreadyExist. -func IsErrKeyAlreadyExist(err error) bool { - _, ok := err.(ErrKeyAlreadyExist) - return ok -} - -func (err ErrKeyAlreadyExist) Error() string { - return fmt.Sprintf("public key already exists [owner_id: %d, finger_print: %s, content: %s]", - err.OwnerID, err.Fingerprint, err.Content) -} - -// ErrKeyNameAlreadyUsed represents a "KeyNameAlreadyUsed" kind of error. -type ErrKeyNameAlreadyUsed struct { - OwnerID int64 - Name string -} - -// IsErrKeyNameAlreadyUsed checks if an error is a ErrKeyNameAlreadyUsed. -func IsErrKeyNameAlreadyUsed(err error) bool { - _, ok := err.(ErrKeyNameAlreadyUsed) - return ok -} - -func (err ErrKeyNameAlreadyUsed) Error() string { - return fmt.Sprintf("public key already exists [owner_id: %d, name: %s]", err.OwnerID, err.Name) -} - -// ErrGPGNoEmailFound represents a "ErrGPGNoEmailFound" kind of error. -type ErrGPGNoEmailFound struct { - FailedEmails []string - ID string -} - -// IsErrGPGNoEmailFound checks if an error is a ErrGPGNoEmailFound. -func IsErrGPGNoEmailFound(err error) bool { - _, ok := err.(ErrGPGNoEmailFound) - return ok -} - -func (err ErrGPGNoEmailFound) Error() string { - return fmt.Sprintf("none of the emails attached to the GPG key could be found: %v", err.FailedEmails) -} - -// ErrGPGInvalidTokenSignature represents a "ErrGPGInvalidTokenSignature" kind of error. -type ErrGPGInvalidTokenSignature struct { - Wrapped error - ID string -} - -// IsErrGPGInvalidTokenSignature checks if an error is a ErrGPGInvalidTokenSignature. -func IsErrGPGInvalidTokenSignature(err error) bool { - _, ok := err.(ErrGPGInvalidTokenSignature) - return ok -} - -func (err ErrGPGInvalidTokenSignature) Error() string { - return "the provided signature does not sign the token with the provided key" -} - -// ErrGPGKeyParsing represents a "ErrGPGKeyParsing" kind of error. -type ErrGPGKeyParsing struct { - ParseError error -} - -// IsErrGPGKeyParsing checks if an error is a ErrGPGKeyParsing. -func IsErrGPGKeyParsing(err error) bool { - _, ok := err.(ErrGPGKeyParsing) - return ok -} - -func (err ErrGPGKeyParsing) Error() string { - return fmt.Sprintf("failed to parse gpg key %s", err.ParseError.Error()) -} - -// ErrGPGKeyNotExist represents a "GPGKeyNotExist" kind of error. -type ErrGPGKeyNotExist struct { - ID int64 -} - -// IsErrGPGKeyNotExist checks if an error is a ErrGPGKeyNotExist. -func IsErrGPGKeyNotExist(err error) bool { - _, ok := err.(ErrGPGKeyNotExist) - return ok -} - -func (err ErrGPGKeyNotExist) Error() string { - return fmt.Sprintf("public gpg key does not exist [id: %d]", err.ID) -} - -// ErrGPGKeyImportNotExist represents a "GPGKeyImportNotExist" kind of error. -type ErrGPGKeyImportNotExist struct { - ID string -} - -// IsErrGPGKeyImportNotExist checks if an error is a ErrGPGKeyImportNotExist. -func IsErrGPGKeyImportNotExist(err error) bool { - _, ok := err.(ErrGPGKeyImportNotExist) - return ok -} - -func (err ErrGPGKeyImportNotExist) Error() string { - return fmt.Sprintf("public gpg key import does not exist [id: %s]", err.ID) -} - -// ErrGPGKeyIDAlreadyUsed represents a "GPGKeyIDAlreadyUsed" kind of error. -type ErrGPGKeyIDAlreadyUsed struct { - KeyID string -} - -// IsErrGPGKeyIDAlreadyUsed checks if an error is a ErrKeyNameAlreadyUsed. -func IsErrGPGKeyIDAlreadyUsed(err error) bool { - _, ok := err.(ErrGPGKeyIDAlreadyUsed) - return ok -} - -func (err ErrGPGKeyIDAlreadyUsed) Error() string { - return fmt.Sprintf("public key already exists [key_id: %s]", err.KeyID) -} - -// ErrGPGKeyAccessDenied represents a "GPGKeyAccessDenied" kind of Error. -type ErrGPGKeyAccessDenied struct { - UserID int64 - KeyID int64 -} - -// IsErrGPGKeyAccessDenied checks if an error is a ErrGPGKeyAccessDenied. -func IsErrGPGKeyAccessDenied(err error) bool { - _, ok := err.(ErrGPGKeyAccessDenied) - return ok -} - -// Error pretty-prints an error of type ErrGPGKeyAccessDenied. -func (err ErrGPGKeyAccessDenied) Error() string { - return fmt.Sprintf("user does not have access to the key [user_id: %d, key_id: %d]", - err.UserID, err.KeyID) -} - -// ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error. -type ErrKeyAccessDenied struct { - UserID int64 - KeyID int64 - Note string -} - -// IsErrKeyAccessDenied checks if an error is a ErrKeyAccessDenied. -func IsErrKeyAccessDenied(err error) bool { - _, ok := err.(ErrKeyAccessDenied) - return ok -} - -func (err ErrKeyAccessDenied) Error() string { - return fmt.Sprintf("user does not have access to the key [user_id: %d, key_id: %d, note: %s]", - err.UserID, err.KeyID, err.Note) -} - -// ErrDeployKeyNotExist represents a "DeployKeyNotExist" kind of error. -type ErrDeployKeyNotExist struct { - ID int64 - KeyID int64 - RepoID int64 -} - -// IsErrDeployKeyNotExist checks if an error is a ErrDeployKeyNotExist. -func IsErrDeployKeyNotExist(err error) bool { - _, ok := err.(ErrDeployKeyNotExist) - return ok -} - -func (err ErrDeployKeyNotExist) Error() string { - return fmt.Sprintf("Deploy key does not exist [id: %d, key_id: %d, repo_id: %d]", err.ID, err.KeyID, err.RepoID) -} - -// ErrDeployKeyAlreadyExist represents a "DeployKeyAlreadyExist" kind of error. -type ErrDeployKeyAlreadyExist struct { - KeyID int64 - RepoID int64 -} - -// IsErrDeployKeyAlreadyExist checks if an error is a ErrDeployKeyAlreadyExist. -func IsErrDeployKeyAlreadyExist(err error) bool { - _, ok := err.(ErrDeployKeyAlreadyExist) - return ok -} - -func (err ErrDeployKeyAlreadyExist) Error() string { - return fmt.Sprintf("public key already exists [key_id: %d, repo_id: %d]", err.KeyID, err.RepoID) -} - -// ErrDeployKeyNameAlreadyUsed represents a "DeployKeyNameAlreadyUsed" kind of error. -type ErrDeployKeyNameAlreadyUsed struct { - RepoID int64 - Name string -} - -// IsErrDeployKeyNameAlreadyUsed checks if an error is a ErrDeployKeyNameAlreadyUsed. -func IsErrDeployKeyNameAlreadyUsed(err error) bool { - _, ok := err.(ErrDeployKeyNameAlreadyUsed) - return ok -} - -func (err ErrDeployKeyNameAlreadyUsed) Error() string { - return fmt.Sprintf("public key with name already exists [repo_id: %d, name: %s]", err.RepoID, err.Name) -} - // _____ ___________ __ // / _ \ ____ ____ ____ ______ _____\__ ___/___ | | __ ____ ____ // / /_\ \_/ ___\/ ___\/ __ \ / ___// ___/ | | / _ \| |/ // __ \ / \ @@ -878,22 +617,6 @@ func (err ErrUserDoesNotHaveAccessToRepo) Error() string { return fmt.Sprintf("user doesn't have access to repo [user_id: %d, repo_name: %s]", err.UserID, err.RepoName) } -// ErrWontSign explains the first reason why a commit would not be signed -// There may be other reasons - this is just the first reason found -type ErrWontSign struct { - Reason signingMode -} - -func (e *ErrWontSign) Error() string { - return fmt.Sprintf("wont sign: %s", e.Reason) -} - -// IsErrWontSign checks if an error is a ErrWontSign -func IsErrWontSign(err error) bool { - _, ok := err.(*ErrWontSign) - return ok -} - // __________ .__ // \______ \____________ ____ ____ | |__ // | | _/\_ __ \__ \ / \_/ ___\| | \ diff --git a/models/main_test.go b/models/main_test.go index 20107eab1e..8d5291a8aa 100644 --- a/models/main_test.go +++ b/models/main_test.go @@ -10,10 +10,16 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" ) +func init() { + setting.SetCustomPathAndConf("", "", "") + setting.LoadForTest() +} + // TestFixturesAreConsistent assert that test fixtures are consistent func TestFixturesAreConsistent(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) diff --git a/models/pull_sign.go b/models/pull_sign.go deleted file mode 100644 index 269e8e06d2..0000000000 --- a/models/pull_sign.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2019 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package models - -import ( - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/login" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" -) - -// SignMerge determines if we should sign a PR merge commit to the base repository -func (pr *PullRequest) SignMerge(u *user_model.User, tmpBasePath, baseCommit, headCommit string) (bool, string, *git.Signature, error) { - if err := pr.LoadBaseRepo(); err != nil { - log.Error("Unable to get Base Repo for pull request") - return false, "", nil, err - } - repo := pr.BaseRepo - - signingKey, signer := SigningKey(repo.RepoPath()) - if signingKey == "" { - return false, "", nil, &ErrWontSign{noKey} - } - rules := signingModeFromStrings(setting.Repository.Signing.Merges) - - var gitRepo *git.Repository - var err error - -Loop: - for _, rule := range rules { - switch rule { - case never: - return false, "", nil, &ErrWontSign{never} - case always: - break Loop - case pubkey: - keys, err := ListGPGKeys(u.ID, db.ListOptions{}) - if err != nil { - return false, "", nil, err - } - if len(keys) == 0 { - return false, "", nil, &ErrWontSign{pubkey} - } - case twofa: - twofaModel, err := login.GetTwoFactorByUID(u.ID) - if err != nil && !login.IsErrTwoFactorNotEnrolled(err) { - return false, "", nil, err - } - if twofaModel == nil { - return false, "", nil, &ErrWontSign{twofa} - } - case approved: - protectedBranch, err := GetProtectedBranchBy(repo.ID, pr.BaseBranch) - if err != nil { - return false, "", nil, err - } - if protectedBranch == nil { - return false, "", nil, &ErrWontSign{approved} - } - if protectedBranch.GetGrantedApprovalsCount(pr) < 1 { - return false, "", nil, &ErrWontSign{approved} - } - case baseSigned: - if gitRepo == nil { - gitRepo, err = git.OpenRepository(tmpBasePath) - if err != nil { - return false, "", nil, err - } - defer gitRepo.Close() - } - commit, err := gitRepo.GetCommit(baseCommit) - if err != nil { - return false, "", nil, err - } - verification := ParseCommitWithSignature(commit) - if !verification.Verified { - return false, "", nil, &ErrWontSign{baseSigned} - } - case headSigned: - if gitRepo == nil { - gitRepo, err = git.OpenRepository(tmpBasePath) - if err != nil { - return false, "", nil, err - } - defer gitRepo.Close() - } - commit, err := gitRepo.GetCommit(headCommit) - if err != nil { - return false, "", nil, err - } - verification := ParseCommitWithSignature(commit) - if !verification.Verified { - return false, "", nil, &ErrWontSign{headSigned} - } - case commitsSigned: - if gitRepo == nil { - gitRepo, err = git.OpenRepository(tmpBasePath) - if err != nil { - return false, "", nil, err - } - defer gitRepo.Close() - } - commit, err := gitRepo.GetCommit(headCommit) - if err != nil { - return false, "", nil, err - } - verification := ParseCommitWithSignature(commit) - if !verification.Verified { - return false, "", nil, &ErrWontSign{commitsSigned} - } - // need to work out merge-base - mergeBaseCommit, _, err := gitRepo.GetMergeBase("", baseCommit, headCommit) - if err != nil { - return false, "", nil, err - } - commitList, err := commit.CommitsBeforeUntil(mergeBaseCommit) - if err != nil { - return false, "", nil, err - } - for _, commit := range commitList { - verification := ParseCommitWithSignature(commit) - if !verification.Verified { - return false, "", nil, &ErrWontSign{commitsSigned} - } - } - } - } - return true, signingKey, signer, nil -} diff --git a/models/repo.go b/models/repo.go index 6bdc4c20d2..adc62c9528 100644 --- a/models/repo.go +++ b/models/repo.go @@ -20,6 +20,7 @@ import ( _ "image/jpeg" // Needed for jpeg support admin_model "code.gitea.io/gitea/models/admin" + asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" @@ -856,12 +857,13 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { } // Delete Deploy Keys - deployKeys, err := listDeployKeys(sess, &ListDeployKeysOptions{RepoID: repoID}) + deployKeys, err := asymkey_model.ListDeployKeys(ctx, &asymkey_model.ListDeployKeysOptions{RepoID: repoID}) if err != nil { return fmt.Errorf("listDeployKeys: %v", err) } + var needRewriteKeysFile = len(deployKeys) > 0 for _, dKey := range deployKeys { - if err := deleteDeployKey(ctx, doer, dKey.ID); err != nil { + if err := DeleteDeployKey(ctx, doer, dKey.ID); err != nil { return fmt.Errorf("deleteDeployKeys: %v", err) } } @@ -1049,6 +1051,12 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { committer.Close() + if needRewriteKeysFile { + if err := asymkey_model.RewriteAllPublicKeys(); err != nil { + log.Error("RewriteAllPublicKeys failed: %v", err) + } + } + // We should always delete the files after the database transaction succeed. If // we delete the file but the database rollback, the repository will be broken. @@ -1407,3 +1415,52 @@ func LinkedRepository(a *repo_model.Attachment) (*repo_model.Repository, unit.Ty } return nil, -1, nil } + +// DeleteDeployKey delete deploy keys +func DeleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error { + key, err := asymkey_model.GetDeployKeyByID(ctx, id) + if err != nil { + if asymkey_model.IsErrDeployKeyNotExist(err) { + return nil + } + return fmt.Errorf("GetDeployKeyByID: %v", err) + } + + sess := db.GetEngine(ctx) + + // Check if user has access to delete this key. + if !doer.IsAdmin { + repo, err := repo_model.GetRepositoryByIDCtx(ctx, key.RepoID) + if err != nil { + return fmt.Errorf("GetRepositoryByID: %v", err) + } + has, err := isUserRepoAdmin(sess, repo, doer) + if err != nil { + return fmt.Errorf("GetUserRepoPermission: %v", err) + } else if !has { + return asymkey_model.ErrKeyAccessDenied{ + UserID: doer.ID, + KeyID: key.ID, + Note: "deploy", + } + } + } + + if _, err = sess.ID(key.ID).Delete(new(asymkey_model.DeployKey)); err != nil { + return fmt.Errorf("delete deploy key [%d]: %v", key.ID, err) + } + + // Check if this is the last reference to same key content. + has, err := sess. + Where("key_id = ?", key.KeyID). + Get(new(asymkey_model.DeployKey)) + if err != nil { + return err + } else if !has { + if err = asymkey_model.DeletePublicKeys(ctx, key.KeyID); err != nil { + return err + } + } + + return nil +} diff --git a/models/repo_sign.go b/models/repo_sign.go deleted file mode 100644 index 1c736a62da..0000000000 --- a/models/repo_sign.go +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright 2019 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package models - -import ( - "strings" - - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/login" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/process" - "code.gitea.io/gitea/modules/setting" -) - -type signingMode string - -const ( - never signingMode = "never" - always signingMode = "always" - pubkey signingMode = "pubkey" - twofa signingMode = "twofa" - parentSigned signingMode = "parentsigned" - baseSigned signingMode = "basesigned" - headSigned signingMode = "headsigned" - commitsSigned signingMode = "commitssigned" - approved signingMode = "approved" - noKey signingMode = "nokey" -) - -func signingModeFromStrings(modeStrings []string) []signingMode { - returnable := make([]signingMode, 0, len(modeStrings)) - for _, mode := range modeStrings { - signMode := signingMode(strings.ToLower(strings.TrimSpace(mode))) - switch signMode { - case never: - return []signingMode{never} - case always: - return []signingMode{always} - case pubkey: - fallthrough - case twofa: - fallthrough - case parentSigned: - fallthrough - case baseSigned: - fallthrough - case headSigned: - fallthrough - case approved: - fallthrough - case commitsSigned: - returnable = append(returnable, signMode) - } - } - if len(returnable) == 0 { - return []signingMode{never} - } - return returnable -} - -// SigningKey returns the KeyID and git Signature for the repo -func SigningKey(repoPath string) (string, *git.Signature) { - if setting.Repository.Signing.SigningKey == "none" { - return "", nil - } - - if setting.Repository.Signing.SigningKey == "default" || setting.Repository.Signing.SigningKey == "" { - // Can ignore the error here as it means that commit.gpgsign is not set - value, _ := git.NewCommand("config", "--get", "commit.gpgsign").RunInDir(repoPath) - sign, valid := git.ParseBool(strings.TrimSpace(value)) - if !sign || !valid { - return "", nil - } - - signingKey, _ := git.NewCommand("config", "--get", "user.signingkey").RunInDir(repoPath) - signingName, _ := git.NewCommand("config", "--get", "user.name").RunInDir(repoPath) - signingEmail, _ := git.NewCommand("config", "--get", "user.email").RunInDir(repoPath) - return strings.TrimSpace(signingKey), &git.Signature{ - Name: strings.TrimSpace(signingName), - Email: strings.TrimSpace(signingEmail), - } - } - - return setting.Repository.Signing.SigningKey, &git.Signature{ - Name: setting.Repository.Signing.SigningName, - Email: setting.Repository.Signing.SigningEmail, - } -} - -// PublicSigningKey gets the public signing key within a provided repository directory -func PublicSigningKey(repoPath string) (string, error) { - signingKey, _ := SigningKey(repoPath) - if signingKey == "" { - return "", nil - } - - content, stderr, err := process.GetManager().ExecDir(-1, repoPath, - "gpg --export -a", "gpg", "--export", "-a", signingKey) - if err != nil { - log.Error("Unable to get default signing key in %s: %s, %s, %v", repoPath, signingKey, stderr, err) - return "", err - } - return content, nil -} - -// SignInitialCommit determines if we should sign the initial commit to this repository -func SignInitialCommit(repoPath string, u *user_model.User) (bool, string, *git.Signature, error) { - rules := signingModeFromStrings(setting.Repository.Signing.InitialCommit) - signingKey, sig := SigningKey(repoPath) - if signingKey == "" { - return false, "", nil, &ErrWontSign{noKey} - } - -Loop: - for _, rule := range rules { - switch rule { - case never: - return false, "", nil, &ErrWontSign{never} - case always: - break Loop - case pubkey: - keys, err := ListGPGKeys(u.ID, db.ListOptions{}) - if err != nil { - return false, "", nil, err - } - if len(keys) == 0 { - return false, "", nil, &ErrWontSign{pubkey} - } - case twofa: - twofaModel, err := login.GetTwoFactorByUID(u.ID) - if err != nil && !login.IsErrTwoFactorNotEnrolled(err) { - return false, "", nil, err - } - if twofaModel == nil { - return false, "", nil, &ErrWontSign{twofa} - } - } - } - return true, signingKey, sig, nil -} - -// SignWikiCommit determines if we should sign the commits to this repository wiki -func SignWikiCommit(repo *repo_model.Repository, u *user_model.User) (bool, string, *git.Signature, error) { - rules := signingModeFromStrings(setting.Repository.Signing.Wiki) - signingKey, sig := SigningKey(repo.WikiPath()) - if signingKey == "" { - return false, "", nil, &ErrWontSign{noKey} - } - -Loop: - for _, rule := range rules { - switch rule { - case never: - return false, "", nil, &ErrWontSign{never} - case always: - break Loop - case pubkey: - keys, err := ListGPGKeys(u.ID, db.ListOptions{}) - if err != nil { - return false, "", nil, err - } - if len(keys) == 0 { - return false, "", nil, &ErrWontSign{pubkey} - } - case twofa: - twofaModel, err := login.GetTwoFactorByUID(u.ID) - if err != nil && !login.IsErrTwoFactorNotEnrolled(err) { - return false, "", nil, err - } - if twofaModel == nil { - return false, "", nil, &ErrWontSign{twofa} - } - case parentSigned: - gitRepo, err := git.OpenRepository(repo.WikiPath()) - if err != nil { - return false, "", nil, err - } - defer gitRepo.Close() - commit, err := gitRepo.GetCommit("HEAD") - if err != nil { - return false, "", nil, err - } - if commit.Signature == nil { - return false, "", nil, &ErrWontSign{parentSigned} - } - verification := ParseCommitWithSignature(commit) - if !verification.Verified { - return false, "", nil, &ErrWontSign{parentSigned} - } - } - } - return true, signingKey, sig, nil -} - -// SignCRUDAction determines if we should sign a CRUD commit to this repository -func SignCRUDAction(repo *repo_model.Repository, u *user_model.User, tmpBasePath, parentCommit string) (bool, string, *git.Signature, error) { - rules := signingModeFromStrings(setting.Repository.Signing.CRUDActions) - signingKey, sig := SigningKey(repo.RepoPath()) - if signingKey == "" { - return false, "", nil, &ErrWontSign{noKey} - } - -Loop: - for _, rule := range rules { - switch rule { - case never: - return false, "", nil, &ErrWontSign{never} - case always: - break Loop - case pubkey: - keys, err := ListGPGKeys(u.ID, db.ListOptions{}) - if err != nil { - return false, "", nil, err - } - if len(keys) == 0 { - return false, "", nil, &ErrWontSign{pubkey} - } - case twofa: - twofaModel, err := login.GetTwoFactorByUID(u.ID) - if err != nil && !login.IsErrTwoFactorNotEnrolled(err) { - return false, "", nil, err - } - if twofaModel == nil { - return false, "", nil, &ErrWontSign{twofa} - } - case parentSigned: - gitRepo, err := git.OpenRepository(tmpBasePath) - if err != nil { - return false, "", nil, err - } - defer gitRepo.Close() - commit, err := gitRepo.GetCommit(parentCommit) - if err != nil { - return false, "", nil, err - } - if commit.Signature == nil { - return false, "", nil, &ErrWontSign{parentSigned} - } - verification := ParseCommitWithSignature(commit) - if !verification.Verified { - return false, "", nil, &ErrWontSign{parentSigned} - } - } - } - return true, signingKey, sig, nil -} diff --git a/models/statistic.go b/models/statistic.go index 055f312c11..175815081f 100644 --- a/models/statistic.go +++ b/models/statistic.go @@ -5,6 +5,7 @@ package models import ( + asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/login" repo_model "code.gitea.io/gitea/models/repo" @@ -47,7 +48,7 @@ func GetStatistic() (stats Statistic) { e := db.GetEngine(db.DefaultContext) stats.Counter.User = user_model.CountUsers() stats.Counter.Org = CountOrganizations() - stats.Counter.PublicKey, _ = e.Count(new(PublicKey)) + stats.Counter.PublicKey, _ = e.Count(new(asymkey_model.PublicKey)) stats.Counter.Repo = repo_model.CountRepositories(true) stats.Counter.Watch, _ = e.Count(new(Watch)) stats.Counter.Star, _ = e.Count(new(Star)) diff --git a/models/user.go b/models/user.go index 1427833e21..2a727dd124 100644 --- a/models/user.go +++ b/models/user.go @@ -12,6 +12,7 @@ import ( _ "image/jpeg" // Needed for jpeg support + asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" @@ -234,23 +235,23 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) { } // ***** START: PublicKey ***** - if _, err = e.Delete(&PublicKey{OwnerID: u.ID}); err != nil { + if _, err = e.Delete(&asymkey_model.PublicKey{OwnerID: u.ID}); err != nil { return fmt.Errorf("deletePublicKeys: %v", err) } // ***** END: PublicKey ***** // ***** START: GPGPublicKey ***** - keys, err := listGPGKeys(e, u.ID, db.ListOptions{}) + keys, err := asymkey_model.ListGPGKeys(ctx, u.ID, db.ListOptions{}) if err != nil { return fmt.Errorf("ListGPGKeys: %v", err) } // Delete GPGKeyImport(s). for _, key := range keys { - if _, err = e.Delete(&GPGKeyImport{KeyID: key.KeyID}); err != nil { + if _, err = e.Delete(&asymkey_model.GPGKeyImport{KeyID: key.KeyID}); err != nil { return fmt.Errorf("deleteGPGKeyImports: %v", err) } } - if _, err = e.Delete(&GPGKey{OwnerID: u.ID}); err != nil { + if _, err = e.Delete(&asymkey_model.GPGKey{OwnerID: u.ID}); err != nil { return fmt.Errorf("deleteGPGKeys: %v", err) } // ***** END: GPGPublicKey ***** diff --git a/models/user_test.go b/models/user_test.go index d3c7718d69..4749a3af73 100644 --- a/models/user_test.go +++ b/models/user_test.go @@ -8,7 +8,6 @@ import ( "fmt" "testing" - "code.gitea.io/gitea/models/login" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -121,71 +120,3 @@ func TestGetOrgRepositoryIDs(t *testing.T) { // User 5's team has no access to any repo assert.Len(t, accessibleRepos, 0) } - -func TestAddLdapSSHPublicKeys(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - s := &login.Source{ID: 1} - - testCases := []struct { - keyString string - number int - keyContents []string - }{ - { - keyString: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n", - number: 1, - keyContents: []string{ - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=", - }, - }, - { - keyString: `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment -ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment`, - number: 2, - keyContents: []string{ - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=", - "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag=", - }, - }, - { - keyString: `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment -# comment asmdna,ndp -ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment`, - number: 2, - keyContents: []string{ - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=", - "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag=", - }, - }, - { - keyString: `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment -382488320jasdj1lasmva/vasodifipi4193-fksma.cm -ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment`, - number: 2, - keyContents: []string{ - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=", - "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag=", - }, - }, - } - - for i, kase := range testCases { - s.ID = int64(i) + 20 - AddPublicKeysBySource(user, s, []string{kase.keyString}) - keys, err := ListPublicKeysBySource(user.ID, s.ID) - assert.NoError(t, err) - if err != nil { - continue - } - assert.Len(t, keys, kase.number) - - for _, key := range keys { - assert.Contains(t, kase.keyContents, key.Content) - } - for _, key := range keys { - DeletePublicKey(user, key.ID) - } - } -} |