mirror of
https://github.com/go-gitea/gitea
synced 2025-07-22 18:28:37 +00:00
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
This commit is contained in:
30
services/asymkey/deploy_key.go
Normal file
30
services/asymkey/deploy_key.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// 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 (
|
||||
"code.gitea.io/gitea/models"
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
)
|
||||
|
||||
// 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 := models.DeleteDeployKey(ctx, doer, id); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := committer.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return asymkey_model.RewriteAllPublicKeys()
|
||||
}
|
16
services/asymkey/main_test.go
Normal file
16
services/asymkey/main_test.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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 asymkey
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m, filepath.Join("..", ".."))
|
||||
}
|
388
services/asymkey/sign.go
Normal file
388
services/asymkey/sign.go
Normal file
@@ -0,0 +1,388 @@
|
||||
// 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"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
"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/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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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 := asymkey_model.ListGPGKeys(db.DefaultContext, 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(repoWikiPath string, u *user_model.User) (bool, string, *git.Signature, error) {
|
||||
rules := signingModeFromStrings(setting.Repository.Signing.Wiki)
|
||||
signingKey, sig := SigningKey(repoWikiPath)
|
||||
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 := asymkey_model.ListGPGKeys(db.DefaultContext, 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(repoWikiPath)
|
||||
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 := asymkey_model.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(repoPath string, u *user_model.User, tmpBasePath, parentCommit string) (bool, string, *git.Signature, error) {
|
||||
rules := signingModeFromStrings(setting.Repository.Signing.CRUDActions)
|
||||
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 := asymkey_model.ListGPGKeys(db.DefaultContext, 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 := asymkey_model.ParseCommitWithSignature(commit)
|
||||
if !verification.Verified {
|
||||
return false, "", nil, &ErrWontSign{parentSigned}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true, signingKey, sig, nil
|
||||
}
|
||||
|
||||
// SignMerge determines if we should sign a PR merge commit to the base repository
|
||||
func SignMerge(pr *models.PullRequest, 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 := asymkey_model.ListGPGKeys(db.DefaultContext, 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 := models.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 := asymkey_model.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 := asymkey_model.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 := asymkey_model.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 := asymkey_model.ParseCommitWithSignature(commit)
|
||||
if !verification.Verified {
|
||||
return false, "", nil, &ErrWontSign{commitsSigned}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true, signingKey, signer, nil
|
||||
}
|
49
services/asymkey/ssh_key.go
Normal file
49
services/asymkey/ssh_key.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// 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 (
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
)
|
||||
|
||||
// DeletePublicKey deletes SSH key information both in database and authorized_keys file.
|
||||
func DeletePublicKey(doer *user_model.User, id int64) (err error) {
|
||||
key, err := asymkey_model.GetPublicKeyByID(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if user has access to delete this key.
|
||||
if !doer.IsAdmin && doer.ID != key.OwnerID {
|
||||
return asymkey_model.ErrKeyAccessDenied{
|
||||
UserID: doer.ID,
|
||||
KeyID: key.ID,
|
||||
Note: "public",
|
||||
}
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer committer.Close()
|
||||
|
||||
if err = asymkey_model.DeletePublicKeys(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = committer.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
committer.Close()
|
||||
|
||||
if key.Type == asymkey_model.KeyTypePrincipal {
|
||||
return asymkey_model.RewriteAllPrincipalKeys()
|
||||
}
|
||||
|
||||
return asymkey_model.RewriteAllPublicKeys()
|
||||
}
|
83
services/asymkey/ssh_key_test.go
Normal file
83
services/asymkey/ssh_key_test.go
Normal file
@@ -0,0 +1,83 @@
|
||||
// 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 (
|
||||
"testing"
|
||||
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
"code.gitea.io/gitea/models/login"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
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
|
||||
asymkey_model.AddPublicKeysBySource(user, s, []string{kase.keyString})
|
||||
keys, err := asymkey_model.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)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user