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
tokarchuk/v1.17
Lunny Xiao 3 years ago committed by GitHub
parent 0a9fcf63a4
commit 3ca5dc7e32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      cmd/admin.go
  2. 5
      cmd/serv.go
  3. 2
      docs/content/doc/advanced/config-cheat-sheet.en-us.md
  4. 6
      integrations/api_admin_test.go
  5. 8
      integrations/api_keys_test.go
  6. 8
      integrations/api_private_serv_test.go
  7. 248
      models/asymkey/error.go
  8. 11
      models/asymkey/gpg_key.go
  9. 2
      models/asymkey/gpg_key_add.go
  10. 24
      models/asymkey/gpg_key_commit_verification.go
  11. 2
      models/asymkey/gpg_key_common.go
  12. 2
      models/asymkey/gpg_key_import.go
  13. 2
      models/asymkey/gpg_key_test.go
  14. 2
      models/asymkey/gpg_key_verify.go
  15. 29
      models/asymkey/main_test.go
  16. 45
      models/asymkey/ssh_key.go
  17. 8
      models/asymkey/ssh_key_authorized_keys.go
  18. 2
      models/asymkey/ssh_key_authorized_principals.go
  19. 82
      models/asymkey/ssh_key_deploy.go
  20. 2
      models/asymkey/ssh_key_fingerprint.go
  21. 5
      models/asymkey/ssh_key_parse.go
  22. 4
      models/asymkey/ssh_key_principals.go
  23. 7
      models/asymkey/ssh_key_test.go
  24. 8
      models/commit.go
  25. 5
      models/commit_status.go
  26. 13
      models/db/error.go
  27. 277
      models/error.go
  28. 6
      models/main_test.go
  29. 133
      models/pull_sign.go
  30. 61
      models/repo.go
  31. 3
      models/statistic.go
  32. 9
      models/user.go
  33. 69
      models/user_test.go
  34. 7
      modules/context/repo.go
  35. 13
      modules/convert/convert.go
  36. 8
      modules/doctor/authorizedkeys.go
  37. 9
      modules/gitgraph/graph_models.go
  38. 6
      modules/private/serv.go
  39. 3
      modules/repository/init.go
  40. 10
      modules/ssh/ssh.go
  41. 8
      routers/api/v1/admin/user.go
  42. 4
      routers/api/v1/misc/signing.go
  43. 36
      routers/api/v1/repo/key.go
  44. 3
      routers/api/v1/repo/pull.go
  45. 2
      routers/api/v1/repo/repo.go
  46. 52
      routers/api/v1/user/gpg_key.go
  47. 35
      routers/api/v1/user/key.go
  48. 3
      routers/init.go
  49. 4
      routers/private/hook_verification.go
  50. 12
      routers/private/key.go
  51. 23
      routers/private/serv.go
  52. 2
      routers/web/admin/repos.go
  53. 7
      routers/web/repo/commit.go
  54. 7
      routers/web/repo/issue.go
  55. 29
      routers/web/repo/setting.go
  56. 5
      routers/web/repo/settings_test.go
  57. 7
      routers/web/repo/view.go
  58. 9
      routers/web/user/home.go
  59. 79
      routers/web/user/setting/keys.go
  60. 30
      services/asymkey/deploy_key.go
  61. 16
      services/asymkey/main_test.go
  62. 163
      services/asymkey/sign.go
  63. 49
      services/asymkey/ssh_key.go
  64. 83
      services/asymkey/ssh_key_test.go
  65. 10
      services/auth/source/ldap/source_authenticate.go
  66. 10
      services/auth/source/ldap/source_sync.go
  67. 5
      services/cron/tasks_extended.go
  68. 5
      services/pull/merge.go
  69. 3
      services/repository/archiver/archiver.go
  70. 3
      services/repository/files/commit.go
  71. 3
      services/repository/files/temp_repo.go
  72. 5
      services/repository/files/update.go
  73. 4
      services/repository/repository.go
  74. 12
      services/user/user.go
  75. 5
      services/wiki/wiki.go

@ -14,6 +14,7 @@ import (
"text/tabwriter" "text/tabwriter"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/login" "code.gitea.io/gitea/models/login"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -625,7 +626,7 @@ func runRegenerateKeys(_ *cli.Context) error {
if err := initDB(ctx); err != nil { if err := initDB(ctx); err != nil {
return err return err
} }
return models.RewriteAllPublicKeys() return asymkey_model.RewriteAllPublicKeys()
} }
func parseOAuth2Config(c *cli.Context) *oauth2.Source { func parseOAuth2Config(c *cli.Context) *oauth2.Source {

@ -17,6 +17,7 @@ import (
"time" "time"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/json"
@ -129,9 +130,9 @@ func runServ(c *cli.Context) error {
return fail("Internal error", "Failed to check provided key: %v", err) return fail("Internal error", "Failed to check provided key: %v", err)
} }
switch key.Type { switch key.Type {
case models.KeyTypeDeploy: case asymkey_model.KeyTypeDeploy:
println("Hi there! You've successfully authenticated with the deploy key named " + key.Name + ", but Gitea does not provide shell access.") println("Hi there! You've successfully authenticated with the deploy key named " + key.Name + ", but Gitea does not provide shell access.")
case models.KeyTypePrincipal: case asymkey_model.KeyTypePrincipal:
println("Hi there! You've successfully authenticated with the principal " + key.Content + ", but Gitea does not provide shell access.") println("Hi there! You've successfully authenticated with the principal " + key.Content + ", but Gitea does not provide shell access.")
default: default:
println("Hi there, " + user.Name + "! You've successfully authenticated with the key named " + key.Name + ", but Gitea does not provide shell access.") println("Hi there, " + user.Name + "! You've successfully authenticated with the key named " + key.Name + ", but Gitea does not provide shell access.")

@ -277,7 +277,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
- `SSH_AUTHORIZED_PRINCIPALS_ALLOW`: **off** or **username, email**: \[off, username, email, anything\]: Specify the principals values that users are allowed to use as principal. When set to `anything` no checks are done on the principal string. When set to `off` authorized principal are not allowed to be set. - `SSH_AUTHORIZED_PRINCIPALS_ALLOW`: **off** or **username, email**: \[off, username, email, anything\]: Specify the principals values that users are allowed to use as principal. When set to `anything` no checks are done on the principal string. When set to `off` authorized principal are not allowed to be set.
- `SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE`: **false/true**: Gitea will create a authorized_principals file by default when it is not using the internal ssh server and `SSH_AUTHORIZED_PRINCIPALS_ALLOW` is not `off`. - `SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE`: **false/true**: Gitea will create a authorized_principals file by default when it is not using the internal ssh server and `SSH_AUTHORIZED_PRINCIPALS_ALLOW` is not `off`.
- `SSH_AUTHORIZED_PRINCIPALS_BACKUP`: **false/true**: Enable SSH Authorized Principals Backup when rewriting all keys, default is true if `SSH_AUTHORIZED_PRINCIPALS_ALLOW` is not `off`. - `SSH_AUTHORIZED_PRINCIPALS_BACKUP`: **false/true**: Enable SSH Authorized Principals Backup when rewriting all keys, default is true if `SSH_AUTHORIZED_PRINCIPALS_ALLOW` is not `off`.
- `SSH_AUTHORIZED_KEYS_COMMAND_TEMPLATE`: **{{.AppPath}} --config={{.CustomConf}} serv key-{{.Key.ID}}**: Set the template for the command to passed on authorized keys. Possible keys are: AppPath, AppWorkPath, CustomConf, CustomPath, Key - where Key is a `models.PublicKey` and the others are strings which are shellquoted. - `SSH_AUTHORIZED_KEYS_COMMAND_TEMPLATE`: **{{.AppPath}} --config={{.CustomConf}} serv key-{{.Key.ID}}**: Set the template for the command to passed on authorized keys. Possible keys are: AppPath, AppWorkPath, CustomConf, CustomPath, Key - where Key is a `models/asymkey.PublicKey` and the others are strings which are shellquoted.
- `SSH_SERVER_CIPHERS`: **aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, arcfour256, arcfour128**: For the built-in SSH server, choose the ciphers to support for SSH connections, for system SSH this setting has no effect. - `SSH_SERVER_CIPHERS`: **aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, arcfour256, arcfour128**: For the built-in SSH server, choose the ciphers to support for SSH connections, for system SSH this setting has no effect.
- `SSH_SERVER_KEY_EXCHANGES`: **diffie-hellman-group1-sha1, diffie-hellman-group14-sha1, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, curve25519-sha256@libssh.org**: For the built-in SSH server, choose the key exchange algorithms to support for SSH connections, for system SSH this setting has no effect. - `SSH_SERVER_KEY_EXCHANGES`: **diffie-hellman-group1-sha1, diffie-hellman-group14-sha1, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, curve25519-sha256@libssh.org**: For the built-in SSH server, choose the key exchange algorithms to support for SSH connections, for system SSH this setting has no effect.
- `SSH_SERVER_MACS`: **hmac-sha2-256-etm@openssh.com, hmac-sha2-256, hmac-sha1, hmac-sha1-96**: For the built-in SSH server, choose the MACs to support for SSH connections, for system SSH this setting has no effect - `SSH_SERVER_MACS`: **hmac-sha2-256-etm@openssh.com, hmac-sha2-256, hmac-sha1, hmac-sha1-96**: For the built-in SSH server, choose the MACs to support for SSH connections, for system SSH this setting has no effect

@ -9,7 +9,7 @@ import (
"net/http" "net/http"
"testing" "testing"
"code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/json"
@ -34,7 +34,7 @@ func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) {
var newPublicKey api.PublicKey var newPublicKey api.PublicKey
DecodeJSON(t, resp, &newPublicKey) DecodeJSON(t, resp, &newPublicKey)
unittest.AssertExistsAndLoadBean(t, &models.PublicKey{ unittest.AssertExistsAndLoadBean(t, &asymkey_model.PublicKey{
ID: newPublicKey.ID, ID: newPublicKey.ID,
Name: newPublicKey.Title, Name: newPublicKey.Title,
Content: newPublicKey.Key, Content: newPublicKey.Key,
@ -45,7 +45,7 @@ func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) {
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token=%s", req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token=%s",
keyOwner.Name, newPublicKey.ID, token) keyOwner.Name, newPublicKey.ID, token)
session.MakeRequest(t, req, http.StatusNoContent) session.MakeRequest(t, req, http.StatusNoContent)
unittest.AssertNotExistsBean(t, &models.PublicKey{ID: newPublicKey.ID}) unittest.AssertNotExistsBean(t, &asymkey_model.PublicKey{ID: newPublicKey.ID})
} }
func TestAPIAdminDeleteMissingSSHKey(t *testing.T) { func TestAPIAdminDeleteMissingSSHKey(t *testing.T) {

@ -10,7 +10,7 @@ import (
"net/url" "net/url"
"testing" "testing"
"code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
@ -65,7 +65,7 @@ func TestCreateReadOnlyDeployKey(t *testing.T) {
var newDeployKey api.DeployKey var newDeployKey api.DeployKey
DecodeJSON(t, resp, &newDeployKey) DecodeJSON(t, resp, &newDeployKey)
unittest.AssertExistsAndLoadBean(t, &models.DeployKey{ unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{
ID: newDeployKey.ID, ID: newDeployKey.ID,
Name: rawKeyBody.Title, Name: rawKeyBody.Title,
Content: rawKeyBody.Key, Content: rawKeyBody.Key,
@ -90,7 +90,7 @@ func TestCreateReadWriteDeployKey(t *testing.T) {
var newDeployKey api.DeployKey var newDeployKey api.DeployKey
DecodeJSON(t, resp, &newDeployKey) DecodeJSON(t, resp, &newDeployKey)
unittest.AssertExistsAndLoadBean(t, &models.DeployKey{ unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{
ID: newDeployKey.ID, ID: newDeployKey.ID,
Name: rawKeyBody.Title, Name: rawKeyBody.Title,
Content: rawKeyBody.Key, Content: rawKeyBody.Key,
@ -116,7 +116,7 @@ func TestCreateUserKey(t *testing.T) {
var newPublicKey api.PublicKey var newPublicKey api.PublicKey
DecodeJSON(t, resp, &newPublicKey) DecodeJSON(t, resp, &newPublicKey)
unittest.AssertExistsAndLoadBean(t, &models.PublicKey{ unittest.AssertExistsAndLoadBean(t, &asymkey_model.PublicKey{
ID: newPublicKey.ID, ID: newPublicKey.ID,
OwnerID: user.ID, OwnerID: user.ID,
Name: rawKeyBody.Title, Name: rawKeyBody.Title,

@ -9,7 +9,7 @@ import (
"net/url" "net/url"
"testing" "testing"
"code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/private"
@ -27,7 +27,7 @@ func TestAPIPrivateNoServ(t *testing.T) {
assert.Equal(t, int64(1), key.ID) assert.Equal(t, int64(1), key.ID)
assert.Equal(t, "user2@localhost", key.Name) assert.Equal(t, "user2@localhost", key.Name)
deployKey, err := models.AddDeployKey(1, "test-deploy", "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGXEEzWmm1dxb+57RoK5KVCL0w2eNv9cqJX2AGGVlkFsVDhOXHzsadS3LTK4VlEbbrDMJdoti9yM8vclA8IeRacAAAAEc3NoOg== nocomment", false) deployKey, err := asymkey_model.AddDeployKey(1, "test-deploy", "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGXEEzWmm1dxb+57RoK5KVCL0w2eNv9cqJX2AGGVlkFsVDhOXHzsadS3LTK4VlEbbrDMJdoti9yM8vclA8IeRacAAAAEc3NoOg== nocomment", false)
assert.NoError(t, err) assert.NoError(t, err)
key, user, err = private.ServNoCommand(ctx, deployKey.KeyID) key, user, err = private.ServNoCommand(ctx, deployKey.KeyID)
@ -85,7 +85,7 @@ func TestAPIPrivateServ(t *testing.T) {
assert.Empty(t, results) assert.Empty(t, results)
// Add reading deploy key // Add reading deploy key
deployKey, err := models.AddDeployKey(19, "test-deploy", "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGXEEzWmm1dxb+57RoK5KVCL0w2eNv9cqJX2AGGVlkFsVDhOXHzsadS3LTK4VlEbbrDMJdoti9yM8vclA8IeRacAAAAEc3NoOg== nocomment", true) deployKey, err := asymkey_model.AddDeployKey(19, "test-deploy", "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGXEEzWmm1dxb+57RoK5KVCL0w2eNv9cqJX2AGGVlkFsVDhOXHzsadS3LTK4VlEbbrDMJdoti9yM8vclA8IeRacAAAAEc3NoOg== nocomment", true)
assert.NoError(t, err) assert.NoError(t, err)
// Can pull from repo we're a deploy key for // Can pull from repo we're a deploy key for
@ -117,7 +117,7 @@ func TestAPIPrivateServ(t *testing.T) {
assert.Empty(t, results) assert.Empty(t, results)
// Add writing deploy key // Add writing deploy key
deployKey, err = models.AddDeployKey(20, "test-deploy", "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGXEEzWmm1dxb+57RoK5KVCL0w2eNv9cqJX2AGGVlkFsVDhOXHzsadS3LTK4VlEbbrDMJdoti9yM8vclA8IeRacAAAAEc3NoOg== nocomment", false) deployKey, err = asymkey_model.AddDeployKey(20, "test-deploy", "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGXEEzWmm1dxb+57RoK5KVCL0w2eNv9cqJX2AGGVlkFsVDhOXHzsadS3LTK4VlEbbrDMJdoti9yM8vclA8IeRacAAAAEc3NoOg== nocomment", false)
assert.NoError(t, err) assert.NoError(t, err)
// Cannot push to a private repo with reading key // Cannot push to a private repo with reading key

@ -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)
}

@ -2,9 +2,10 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import ( import (
"context"
"fmt" "fmt"
"strings" "strings"
"time" "time"
@ -63,12 +64,8 @@ func (key *GPGKey) AfterLoad(session *xorm.Session) {
} }
// ListGPGKeys returns a list of public keys belongs to given user. // ListGPGKeys returns a list of public keys belongs to given user.
func ListGPGKeys(uid int64, listOptions db.ListOptions) ([]*GPGKey, error) { func ListGPGKeys(ctx context.Context, uid int64, listOptions db.ListOptions) ([]*GPGKey, error) {
return listGPGKeys(db.GetEngine(db.DefaultContext), uid, listOptions) sess := db.GetEngine(ctx).Table(&GPGKey{}).Where("owner_id=? AND primary_key_id=''", uid)
}
func listGPGKeys(e db.Engine, uid int64, listOptions db.ListOptions) ([]*GPGKey, error) {
sess := e.Table(&GPGKey{}).Where("owner_id=? AND primary_key_id=''", uid)
if listOptions.Page != 0 { if listOptions.Page != 0 {
sess = db.SetSessionPagination(sess, &listOptions) sess = db.SetSessionPagination(sess, &listOptions)
} }

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import ( import (
"strings" "strings"

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import ( import (
"fmt" "fmt"
@ -70,7 +70,7 @@ const (
) )
// ParseCommitsWithSignature checks if signaute of commits are corresponding to users gpg keys. // 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)) newCommits := make([]*SignCommit, 0, len(oldCommits))
keyMap := map[string]bool{} keyMap := map[string]bool{}
@ -80,7 +80,7 @@ func ParseCommitsWithSignature(oldCommits []*user_model.UserCommit, repository *
Verification: ParseCommitWithSignature(c.Commit), Verification: ParseCommitWithSignature(c.Commit),
} }
_ = CalculateTrustStatus(signCommit.Verification, repository, &keyMap) _ = CalculateTrustStatus(signCommit.Verification, repoTrustModel, isCodeReader, &keyMap)
newCommits = append(newCommits, signCommit) 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 // Now try to associate the signature with the committer, if present
if committer.ID != 0 { 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 if err != nil { // Skipping failed to get gpg keys of user
log.Error("ListGPGKeys: %v", err) log.Error("ListGPGKeys: %v", err)
return &CommitVerification{ 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 // 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 { if !verification.Verified {
return 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 // 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 // - it doesn't matter if they're a collaborator, the owner, Gitea or Github
// NB: This model is commit verification only // NB: This model is commit verification only
if trustModel == repo_model.CommitterTrustModel { if repoTrustModel == repo_model.CommitterTrustModel {
// default to "unmatched" // default to "unmatched"
verification.TrustStatus = "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 // However in the repo_model.CollaboratorCommitterTrustModel we cannot mark this as trusted
// unless the default key matches the email of a non-user. // 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.SigningUser.Email != verification.CommittingUser.Email) {
verification.TrustStatus = "untrusted" verification.TrustStatus = "untrusted"
} }
@ -494,11 +492,11 @@ func CalculateTrustStatus(verification *CommitVerification, repository *repo_mod
var has bool var has bool
isMember, has = (*keyMap)[verification.SigningKey.KeyID] isMember, has = (*keyMap)[verification.SigningKey.KeyID]
if !has { if !has {
isMember, err = IsOwnerMemberCollaborator(repository, verification.SigningUser.ID) isMember, err = isCodeReader(verification.SigningUser)
(*keyMap)[verification.SigningKey.KeyID] = isMember (*keyMap)[verification.SigningKey.KeyID] = isMember
} }
} else { } else {
isMember, err = IsOwnerMemberCollaborator(repository, verification.SigningUser.ID) isMember, err = isCodeReader(verification.SigningUser)
} }
if !isMember { 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. // This should be marked as questionable unless the signing user is a collaborator/team member etc.
verification.TrustStatus = "unmatched" 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 // The committing user and the signing user are not the same and our trustmodel states that they must match
verification.TrustStatus = "unmatched" verification.TrustStatus = "unmatched"
} }

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import ( import (
"bytes" "bytes"

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import "code.gitea.io/gitea/models/db" import "code.gitea.io/gitea/models/db"

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import ( import (
"testing" "testing"

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import ( import (
"strconv" "strconv"

@ -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",
)
}

@ -3,9 +3,10 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import ( import (
"context"
"fmt" "fmt"
"strings" "strings"
"time" "time"
@ -247,13 +248,13 @@ func UpdatePublicKeyUpdated(id int64) error {
return nil return nil
} }
// deletePublicKeys does the actual key deletion but does not update authorized_keys file. // DeletePublicKeys does the actual key deletion but does not update authorized_keys file.
func deletePublicKeys(e db.Engine, keyIDs ...int64) error { func DeletePublicKeys(ctx context.Context, keyIDs ...int64) error {
if len(keyIDs) == 0 { if len(keyIDs) == 0 {
return nil return nil
} }
_, err := e.In("id", keyIDs).Delete(new(PublicKey)) _, err := db.GetEngine(ctx).In("id", keyIDs).Delete(new(PublicKey))
return err return err
} }
@ -325,40 +326,6 @@ func PublicKeyIsExternallyManaged(id int64) (bool, error) {
return false, nil 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 // deleteKeysMarkedForDeletion returns true if ssh keys needs update
func deleteKeysMarkedForDeletion(keys []string) (bool, error) { func deleteKeysMarkedForDeletion(keys []string) (bool, error) {
// Start session // Start session
@ -377,7 +344,7 @@ func deleteKeysMarkedForDeletion(keys []string) (bool, error) {
log.Error("SearchPublicKeyByContent: %v", err) log.Error("SearchPublicKeyByContent: %v", err)
continue continue
} }
if err = deletePublicKeys(sess, key.ID); err != nil { if err = DeletePublicKeys(ctx, key.ID); err != nil {
log.Error("deletePublicKeys: %v", err) log.Error("deletePublicKeys: %v", err)
continue continue
} }

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import ( import (
"bufio" "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 // 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. // outside any session scope independently.
func RewriteAllPublicKeys() error { func RewriteAllPublicKeys() error {
return rewriteAllPublicKeys(db.GetEngine(db.DefaultContext))
}
func rewriteAllPublicKeys(e db.Engine) error {
// Don't rewrite key if internal server // Don't rewrite key if internal server
if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile { if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile {
return nil 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 return err
} }

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import ( import (
"bufio" "bufio"

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import ( import (
"context" "context"
@ -11,8 +11,6 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm" "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" "code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder" "xorm.io/builder"
@ -169,13 +167,9 @@ func AddDeployKey(repoID int64, name, content string, readOnly bool) (*DeployKey
} }
// GetDeployKeyByID returns deploy key by given ID. // GetDeployKeyByID returns deploy key by given ID.
func GetDeployKeyByID(id int64) (*DeployKey, error) { func GetDeployKeyByID(ctx context.Context, id int64) (*DeployKey, error) {
return getDeployKeyByID(db.GetEngine(db.DefaultContext), id)
}
func getDeployKeyByID(e db.Engine, id int64) (*DeployKey, error) {
key := new(DeployKey) key := new(DeployKey)
has, err := e.ID(id).Get(key) has, err := db.GetEngine(ctx).ID(id).Get(key)
if err != nil { if err != nil {
return nil, err return nil, err
} else if !has { } else if !has {
@ -215,68 +209,6 @@ func UpdateDeployKey(key *DeployKey) error {
return err 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 // ListDeployKeysOptions are options for ListDeployKeys
type ListDeployKeysOptions struct { type ListDeployKeysOptions struct {
db.ListOptions db.ListOptions
@ -300,12 +232,8 @@ func (opt ListDeployKeysOptions) toCond() builder.Cond {
} }
// ListDeployKeys returns a list of deploy keys matching the provided arguments. // ListDeployKeys returns a list of deploy keys matching the provided arguments.
func ListDeployKeys(opts *ListDeployKeysOptions) ([]*DeployKey, error) { func ListDeployKeys(ctx context.Context, opts *ListDeployKeysOptions) ([]*DeployKey, error) {
return listDeployKeys(db.GetEngine(db.DefaultContext), opts) sess := db.GetEngine(ctx).Where(opts.toCond())
}
func listDeployKeys(e db.Engine, opts *ListDeployKeysOptions) ([]*DeployKey, error) {
sess := e.Where(opts.toCond())
if opts.Page != 0 { if opts.Page != 0 {
sess = db.SetSessionPagination(sess, opts) sess = db.SetSessionPagination(sess, opts)

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import ( import (
"errors" "errors"

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import ( import (
"crypto/rsa" "crypto/rsa"
@ -18,6 +18,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting" "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. // It returns the actual public key line on success.
func CheckPublicKeyString(content string) (_ string, err error) { func CheckPublicKeyString(content string) (_ string, err error) {
if setting.SSH.Disabled { if setting.SSH.Disabled {
return "", ErrSSHDisabled{} return "", db.ErrSSHDisabled{}
} }
content, err = parseKeyString(content) content, err = parseKeyString(content)

@ -2,7 +2,7 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import ( import (
"errors" "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 // CheckPrincipalKeyString strips spaces and returns an error if the given principal contains newlines
func CheckPrincipalKeyString(user *user_model.User, content string) (_ string, err error) { func CheckPrincipalKeyString(user *user_model.User, content string) (_ string, err error) {
if setting.SSH.Disabled { if setting.SSH.Disabled {
return "", ErrSSHDisabled{} return "", db.ErrSSHDisabled{}
} }
content = strings.TrimSpace(content) content = strings.TrimSpace(content)

@ -3,7 +3,7 @@
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import ( import (
"strings" "strings"
@ -14,11 +14,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func init() {
setting.SetCustomPathAndConf("", "", "")
setting.LoadForTest()
}
func Test_SSHParsePublicKey(t *testing.T) { func Test_SSHParsePublicKey(t *testing.T) {
testCases := []struct { testCases := []struct {
name string name string

@ -5,6 +5,7 @@
package models package models
import ( import (
asymkey_model "code.gitea.io/gitea/models/asymkey"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
@ -13,9 +14,12 @@ import (
// ConvertFromGitCommit converts git commits into SignCommitWithStatuses // ConvertFromGitCommit converts git commits into SignCommitWithStatuses
func ConvertFromGitCommit(commits []*git.Commit, repo *repo_model.Repository) []*SignCommitWithStatuses { func ConvertFromGitCommit(commits []*git.Commit, repo *repo_model.Repository) []*SignCommitWithStatuses {
return ParseCommitsWithStatus( return ParseCommitsWithStatus(
ParseCommitsWithSignature( asymkey_model.ParseCommitsWithSignature(
user_model.ValidateCommitsWithEmails(commits), user_model.ValidateCommitsWithEmails(commits),
repo, repo.GetTrustModel(),
func(user *user_model.User) (bool, error) {
return IsUserRepoAdmin(repo, user)
},
), ),
repo, repo,
) )

@ -12,6 +12,7 @@ import (
"strings" "strings"
"time" "time"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -328,11 +329,11 @@ func NewCommitStatus(opts NewCommitStatusOptions) error {
type SignCommitWithStatuses struct { type SignCommitWithStatuses struct {
Status *CommitStatus Status *CommitStatus
Statuses []*CommitStatus Statuses []*CommitStatus
*SignCommit *asymkey_model.SignCommit
} }
// ParseCommitsWithStatus checks commits latest statuses and calculates its worst status state // 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)) newCommits := make([]*SignCommitWithStatuses, 0, len(oldCommits))
for _, c := range oldCommits { for _, c := range oldCommits {

@ -29,3 +29,16 @@ func ErrCancelledf(format string, args ...interface{}) error {
fmt.Sprintf(format, args...), 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"
}

@ -28,19 +28,6 @@ func (err ErrNotExist) Error() string {
return fmt.Sprintf("record does not exist [id: %d]", err.ID) 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. // ErrUserOwnRepos represents a "UserOwnRepos" kind of error.
type ErrUserOwnRepos struct { type ErrUserOwnRepos struct {
UID int64 UID int64
@ -151,254 +138,6 @@ func (err ErrWikiInvalidFileName) Error() string {
return fmt.Sprintf("Invalid wiki filename: %s", err.FileName) 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) 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
}
// __________ .__ // __________ .__
// \______ \____________ ____ ____ | |__ // \______ \____________ ____ ____ | |__
// | | _/\_ __ \__ \ / \_/ ___\| | \ // | | _/\_ __ \__ \ / \_/ ___\| | \

@ -10,10 +10,16 @@ import (
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func init() {
setting.SetCustomPathAndConf("", "", "")
setting.LoadForTest()
}
// TestFixturesAreConsistent assert that test fixtures are consistent // TestFixturesAreConsistent assert that test fixtures are consistent
func TestFixturesAreConsistent(t *testing.T) { func TestFixturesAreConsistent(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, unittest.PrepareTestDatabase())

@ -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
}

@ -20,6 +20,7 @@ import (
_ "image/jpeg" // Needed for jpeg support _ "image/jpeg" // Needed for jpeg support
admin_model "code.gitea.io/gitea/models/admin" 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/db"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" 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 // Delete Deploy Keys
deployKeys, err := listDeployKeys(sess, &ListDeployKeysOptions{RepoID: repoID}) deployKeys, err := asymkey_model.ListDeployKeys(ctx, &asymkey_model.ListDeployKeysOptions{RepoID: repoID})
if err != nil { if err != nil {
return fmt.Errorf("listDeployKeys: %v", err) return fmt.Errorf("listDeployKeys: %v", err)
} }
var needRewriteKeysFile = len(deployKeys) > 0
for _, dKey := range deployKeys { 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) return fmt.Errorf("deleteDeployKeys: %v", err)
} }
} }
@ -1049,6 +1051,12 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
committer.Close() 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 should always delete the files after the database transaction succeed. If
// we delete the file but the database rollback, the repository will be broken. // 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 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
}

@ -5,6 +5,7 @@
package models package models
import ( import (
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/login" "code.gitea.io/gitea/models/login"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
@ -47,7 +48,7 @@ func GetStatistic() (stats Statistic) {
e := db.GetEngine(db.DefaultContext) e := db.GetEngine(db.DefaultContext)
stats.Counter.User = user_model.CountUsers() stats.Counter.User = user_model.CountUsers()
stats.Counter.Org = CountOrganizations() 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.Repo = repo_model.CountRepositories(true)
stats.Counter.Watch, _ = e.Count(new(Watch)) stats.Counter.Watch, _ = e.Count(new(Watch))
stats.Counter.Star, _ = e.Count(new(Star)) stats.Counter.Star, _ = e.Count(new(Star))

@ -12,6 +12,7 @@ import (
_ "image/jpeg" // Needed for jpeg support _ "image/jpeg" // Needed for jpeg support
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
@ -234,23 +235,23 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
} }
// ***** START: PublicKey ***** // ***** 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) return fmt.Errorf("deletePublicKeys: %v", err)
} }
// ***** END: PublicKey ***** // ***** END: PublicKey *****
// ***** START: GPGPublicKey ***** // ***** START: GPGPublicKey *****
keys, err := listGPGKeys(e, u.ID, db.ListOptions{}) keys, err := asymkey_model.ListGPGKeys(ctx, u.ID, db.ListOptions{})
if err != nil { if err != nil {
return fmt.Errorf("ListGPGKeys: %v", err) return fmt.Errorf("ListGPGKeys: %v", err)
} }
// Delete GPGKeyImport(s). // Delete GPGKeyImport(s).
for _, key := range keys { 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) 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) return fmt.Errorf("deleteGPGKeys: %v", err)
} }
// ***** END: GPGPublicKey ***** // ***** END: GPGPublicKey *****

@ -8,7 +8,6 @@ import (
"fmt" "fmt"
"testing" "testing"
"code.gitea.io/gitea/models/login"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" 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 // User 5's team has no access to any repo
assert.Len(t, accessibleRepos, 0) 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)
}
}
}

@ -25,6 +25,7 @@ import (
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
asymkey_service "code.gitea.io/gitea/services/asymkey"
"github.com/editorconfig/editorconfig-core-go/v2" "github.com/editorconfig/editorconfig-core-go/v2"
"github.com/unknwon/com" "github.com/unknwon/com"
@ -120,7 +121,7 @@ func (r *Repository) CanCommitToBranch(doer *user_model.User) (CanCommitToBranch
requireSigned = protectedBranch.RequireSignedCommits requireSigned = protectedBranch.RequireSignedCommits
} }
sign, keyID, _, err := models.SignCRUDAction(r.Repository, doer, r.Repository.RepoPath(), git.BranchPrefix+r.BranchName) sign, keyID, _, err := asymkey_service.SignCRUDAction(r.Repository.RepoPath(), doer, r.Repository.RepoPath(), git.BranchPrefix+r.BranchName)
canCommit := r.CanEnableEditor() && userCanPush canCommit := r.CanEnableEditor() && userCanPush
if requireSigned { if requireSigned {
@ -128,8 +129,8 @@ func (r *Repository) CanCommitToBranch(doer *user_model.User) (CanCommitToBranch
} }
wontSignReason := "" wontSignReason := ""
if err != nil { if err != nil {
if models.IsErrWontSign(err) { if asymkey_service.IsErrWontSign(err) {
wontSignReason = string(err.(*models.ErrWontSign).Reason) wontSignReason = string(err.(*asymkey_service.ErrWontSign).Reason)
err = nil err = nil
} else { } else {
wontSignReason = "error" wontSignReason = "error"

@ -12,6 +12,7 @@ import (
"time" "time"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/login" "code.gitea.io/gitea/models/login"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
@ -152,7 +153,7 @@ func ToTag(repo *repo_model.Repository, t *git.Tag) *api.Tag {
// ToVerification convert a git.Commit.Signature to an api.PayloadCommitVerification // ToVerification convert a git.Commit.Signature to an api.PayloadCommitVerification
func ToVerification(c *git.Commit) *api.PayloadCommitVerification { func ToVerification(c *git.Commit) *api.PayloadCommitVerification {
verif := models.ParseCommitWithSignature(c) verif := asymkey_model.ParseCommitWithSignature(c)
commitVerification := &api.PayloadCommitVerification{ commitVerification := &api.PayloadCommitVerification{
Verified: verif.Verified, Verified: verif.Verified,
Reason: verif.Reason, Reason: verif.Reason,
@ -170,8 +171,8 @@ func ToVerification(c *git.Commit) *api.PayloadCommitVerification {
return commitVerification return commitVerification
} }
// ToPublicKey convert models.PublicKey to api.PublicKey // ToPublicKey convert asymkey_model.PublicKey to api.PublicKey
func ToPublicKey(apiLink string, key *models.PublicKey) *api.PublicKey { func ToPublicKey(apiLink string, key *asymkey_model.PublicKey) *api.PublicKey {
return &api.PublicKey{ return &api.PublicKey{
ID: key.ID, ID: key.ID,
Key: key.Content, Key: key.Content,
@ -183,7 +184,7 @@ func ToPublicKey(apiLink string, key *models.PublicKey) *api.PublicKey {
} }
// ToGPGKey converts models.GPGKey to api.GPGKey // ToGPGKey converts models.GPGKey to api.GPGKey
func ToGPGKey(key *models.GPGKey) *api.GPGKey { func ToGPGKey(key *asymkey_model.GPGKey) *api.GPGKey {
subkeys := make([]*api.GPGKey, len(key.SubsKey)) subkeys := make([]*api.GPGKey, len(key.SubsKey))
for id, k := range key.SubsKey { for id, k := range key.SubsKey {
subkeys[id] = &api.GPGKey{ subkeys[id] = &api.GPGKey{
@ -264,8 +265,8 @@ func ToGitHook(h *git.Hook) *api.GitHook {
} }
} }
// ToDeployKey convert models.DeployKey to api.DeployKey // ToDeployKey convert asymkey_model.DeployKey to api.DeployKey
func ToDeployKey(apiLink string, key *models.DeployKey) *api.DeployKey { func ToDeployKey(apiLink string, key *asymkey_model.DeployKey) *api.DeployKey {
return &api.DeployKey{ return &api.DeployKey{
ID: key.ID, ID: key.ID,
KeyID: key.KeyID, KeyID: key.KeyID,

@ -12,7 +12,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
) )
@ -32,7 +32,7 @@ func checkAuthorizedKeys(logger log.Logger, autofix bool) error {
return fmt.Errorf("Unable to open authorized_keys file. ERROR: %v", err) return fmt.Errorf("Unable to open authorized_keys file. ERROR: %v", err)
} }
logger.Warn("Unable to open authorized_keys. (ERROR: %v). Attempting to rewrite...", err) logger.Warn("Unable to open authorized_keys. (ERROR: %v). Attempting to rewrite...", err)
if err = models.RewriteAllPublicKeys(); err != nil { if err = asymkey_model.RewriteAllPublicKeys(); err != nil {
logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err) logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err)
return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %v", err) return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %v", err)
} }
@ -53,7 +53,7 @@ func checkAuthorizedKeys(logger log.Logger, autofix bool) error {
// now we regenerate and check if there are any lines missing // now we regenerate and check if there are any lines missing
regenerated := &bytes.Buffer{} regenerated := &bytes.Buffer{}
if err := models.RegeneratePublicKeys(regenerated); err != nil { if err := asymkey_model.RegeneratePublicKeys(regenerated); err != nil {
logger.Critical("Unable to regenerate authorized_keys file. ERROR: %v", err) logger.Critical("Unable to regenerate authorized_keys file. ERROR: %v", err)
return fmt.Errorf("Unable to regenerate authorized_keys file. ERROR: %v", err) return fmt.Errorf("Unable to regenerate authorized_keys file. ERROR: %v", err)
} }
@ -75,7 +75,7 @@ func checkAuthorizedKeys(logger log.Logger, autofix bool) error {
return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized_keys --fix"`) return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized_keys --fix"`)
} }
logger.Warn("authorized_keys is out of date. Attempting rewrite...") logger.Warn("authorized_keys is out of date. Attempting rewrite...")
err = models.RewriteAllPublicKeys() err = asymkey_model.RewriteAllPublicKeys()
if err != nil { if err != nil {
logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err) logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err)
return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %v", err) return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %v", err)

@ -10,6 +10,7 @@ import (
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -113,9 +114,11 @@ func (graph *Graph) LoadAndProcessCommits(repository *repo_model.Repository, git
} }
} }
c.Verification = models.ParseCommitWithSignature(c.Commit) c.Verification = asymkey_model.ParseCommitWithSignature(c.Commit)
_ = models.CalculateTrustStatus(c.Verification, repository, &keyMap) _ = asymkey_model.CalculateTrustStatus(c.Verification, repository.GetTrustModel(), func(user *user_model.User) (bool, error) {
return models.IsUserRepoAdmin(repository, user)
}, &keyMap)
statuses, err := models.GetLatestCommitStatus(repository.ID, c.Commit.ID.String(), db.ListOptions{}) statuses, err := models.GetLatestCommitStatus(repository.ID, c.Commit.ID.String(), db.ListOptions{})
if err != nil { if err != nil {
@ -236,7 +239,7 @@ func newRefsFromRefNames(refNames []byte) []git.Reference {
type Commit struct { type Commit struct {
Commit *git.Commit Commit *git.Commit
User *user_model.User User *user_model.User
Verification *models.CommitVerification Verification *asymkey_model.CommitVerification
Status *models.CommitStatus Status *models.CommitStatus
Flow int64 Flow int64
Row int Row int

@ -10,7 +10,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/json"
@ -19,12 +19,12 @@ import (
// KeyAndOwner is the response from ServNoCommand // KeyAndOwner is the response from ServNoCommand
type KeyAndOwner struct { type KeyAndOwner struct {
Key *models.PublicKey `json:"key"` Key *asymkey_model.PublicKey `json:"key"`
Owner *user_model.User `json:"user"` Owner *user_model.User `json:"user"`
} }
// ServNoCommand returns information about the provided key // ServNoCommand returns information about the provided key
func ServNoCommand(ctx context.Context, keyID int64) (*models.PublicKey, *user_model.User, error) { func ServNoCommand(ctx context.Context, keyID int64) (*asymkey_model.PublicKey, *user_model.User, error) {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/serv/none/%d", reqURL := setting.LocalURL + fmt.Sprintf("api/internal/serv/none/%d",
keyID) keyID)
resp, err := newInternalRequest(ctx, reqURL, "GET").Response() resp, err := newInternalRequest(ctx, reqURL, "GET").Response()

@ -20,6 +20,7 @@ import (
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
asymkey_service "code.gitea.io/gitea/services/asymkey"
"github.com/unknwon/com" "github.com/unknwon/com"
) )
@ -134,7 +135,7 @@ func initRepoCommit(tmpPath string, repo *repo_model.Repository, u *user_model.U
} }
if git.CheckGitVersionAtLeast("1.7.9") == nil { if git.CheckGitVersionAtLeast("1.7.9") == nil {
sign, keyID, signer, _ := models.SignInitialCommit(tmpPath, u) sign, keyID, signer, _ := asymkey_service.SignInitialCommit(tmpPath, u)
if sign { if sign {
args = append(args, "-S"+keyID) args = append(args, "-S"+keyID)

@ -22,7 +22,7 @@ import (
"sync" "sync"
"syscall" "syscall"
"code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
@ -172,9 +172,9 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool {
// look for the exact principal // look for the exact principal
principalLoop: principalLoop:
for _, principal := range cert.ValidPrincipals { for _, principal := range cert.ValidPrincipals {
pkey, err := models.SearchPublicKeyByContentExact(principal) pkey, err := asymkey_model.SearchPublicKeyByContentExact(principal)
if err != nil { if err != nil {
if models.IsErrKeyNotExist(err) { if asymkey_model.IsErrKeyNotExist(err) {
log.Debug("Principal Rejected: %s Unknown Principal: %s", ctx.RemoteAddr(), principal) log.Debug("Principal Rejected: %s Unknown Principal: %s", ctx.RemoteAddr(), principal)
continue principalLoop continue principalLoop
} }
@ -232,9 +232,9 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool {
log.Debug("Handle Public Key: %s Fingerprint: %s is not a certificate", ctx.RemoteAddr(), gossh.FingerprintSHA256(key)) log.Debug("Handle Public Key: %s Fingerprint: %s is not a certificate", ctx.RemoteAddr(), gossh.FingerprintSHA256(key))
} }
pkey, err := models.SearchPublicKeyByContent(strings.TrimSpace(string(gossh.MarshalAuthorizedKey(key)))) pkey, err := asymkey_model.SearchPublicKeyByContent(strings.TrimSpace(string(gossh.MarshalAuthorizedKey(key))))
if err != nil { if err != nil {
if models.IsErrKeyNotExist(err) { if asymkey_model.IsErrKeyNotExist(err) {
if log.IsWarn() { if log.IsWarn() {
log.Warn("Unknown public key: %s from %s", gossh.FingerprintSHA256(key), ctx.RemoteAddr()) log.Warn("Unknown public key: %s from %s", gossh.FingerprintSHA256(key), ctx.RemoteAddr())
log.Warn("Failed authentication attempt from %s", ctx.RemoteAddr()) log.Warn("Failed authentication attempt from %s", ctx.RemoteAddr())

@ -12,6 +12,7 @@ import (
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/login" "code.gitea.io/gitea/models/login"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -23,6 +24,7 @@ import (
"code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/api/v1/user"
"code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/routers/api/v1/utils"
asymkey_service "code.gitea.io/gitea/services/asymkey"
"code.gitea.io/gitea/services/mailer" "code.gitea.io/gitea/services/mailer"
user_service "code.gitea.io/gitea/services/user" user_service "code.gitea.io/gitea/services/user"
) )
@ -381,10 +383,10 @@ func DeleteUserPublicKey(ctx *context.APIContext) {
return return
} }
if err := models.DeletePublicKey(u, ctx.ParamsInt64(":id")); err != nil { if err := asymkey_service.DeletePublicKey(u, ctx.ParamsInt64(":id")); err != nil {
if models.IsErrKeyNotExist(err) { if asymkey_model.IsErrKeyNotExist(err) {
ctx.NotFound() ctx.NotFound()
} else if models.IsErrKeyAccessDenied(err) { } else if asymkey_model.IsErrKeyAccessDenied(err) {
ctx.Error(http.StatusForbidden, "", "You do not have access to this key") ctx.Error(http.StatusForbidden, "", "You do not have access to this key")
} else { } else {
ctx.Error(http.StatusInternalServerError, "DeleteUserPublicKey", err) ctx.Error(http.StatusInternalServerError, "DeleteUserPublicKey", err)

@ -8,8 +8,8 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
asymkey_service "code.gitea.io/gitea/services/asymkey"
) )
// SigningKey returns the public key of the default signing key if it exists // SigningKey returns the public key of the default signing key if it exists
@ -52,7 +52,7 @@ func SigningKey(ctx *context.APIContext) {
path = ctx.Repo.Repository.RepoPath() path = ctx.Repo.Repository.RepoPath()
} }
content, err := models.PublicSigningKey(path) content, err := asymkey_service.PublicSigningKey(path)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "gpg export", err) ctx.Error(http.StatusInternalServerError, "gpg export", err)
return return

@ -10,7 +10,8 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
@ -19,10 +20,11 @@ import (
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/routers/api/v1/utils"
asymkey_service "code.gitea.io/gitea/services/asymkey"
) )
// appendPrivateInformation appends the owner and key type information to api.PublicKey // appendPrivateInformation appends the owner and key type information to api.PublicKey
func appendPrivateInformation(apiKey *api.DeployKey, key *models.DeployKey, repository *repo_model.Repository) (*api.DeployKey, error) { func appendPrivateInformation(apiKey *api.DeployKey, key *asymkey_model.DeployKey, repository *repo_model.Repository) (*api.DeployKey, error) {
apiKey.ReadOnly = key.Mode == perm.AccessModeRead apiKey.ReadOnly = key.Mode == perm.AccessModeRead
if repository.ID == key.RepoID { if repository.ID == key.RepoID {
apiKey.Repository = convert.ToRepo(repository, key.Mode) apiKey.Repository = convert.ToRepo(repository, key.Mode)
@ -78,20 +80,20 @@ func ListDeployKeys(ctx *context.APIContext) {
// "200": // "200":
// "$ref": "#/responses/DeployKeyList" // "$ref": "#/responses/DeployKeyList"
opts := &models.ListDeployKeysOptions{ opts := &asymkey_model.ListDeployKeysOptions{
ListOptions: utils.GetListOptions(ctx), ListOptions: utils.GetListOptions(ctx),
RepoID: ctx.Repo.Repository.ID, RepoID: ctx.Repo.Repository.ID,
KeyID: ctx.FormInt64("key_id"), KeyID: ctx.FormInt64("key_id"),
Fingerprint: ctx.FormString("fingerprint"), Fingerprint: ctx.FormString("fingerprint"),
} }
keys, err := models.ListDeployKeys(opts) keys, err := asymkey_model.ListDeployKeys(db.DefaultContext, opts)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return
} }
count, err := models.CountDeployKeys(opts) count, err := asymkey_model.CountDeployKeys(opts)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return
@ -142,9 +144,9 @@ func GetDeployKey(ctx *context.APIContext) {
// "200": // "200":
// "$ref": "#/responses/DeployKey" // "$ref": "#/responses/DeployKey"
key, err := models.GetDeployKeyByID(ctx.ParamsInt64(":id")) key, err := asymkey_model.GetDeployKeyByID(db.DefaultContext, ctx.ParamsInt64(":id"))
if err != nil { if err != nil {
if models.IsErrDeployKeyNotExist(err) { if asymkey_model.IsErrDeployKeyNotExist(err) {
ctx.NotFound() ctx.NotFound()
} else { } else {
ctx.Error(http.StatusInternalServerError, "GetDeployKeyByID", err) ctx.Error(http.StatusInternalServerError, "GetDeployKeyByID", err)
@ -167,9 +169,9 @@ func GetDeployKey(ctx *context.APIContext) {
// HandleCheckKeyStringError handle check key error // HandleCheckKeyStringError handle check key error
func HandleCheckKeyStringError(ctx *context.APIContext, err error) { func HandleCheckKeyStringError(ctx *context.APIContext, err error) {
if models.IsErrSSHDisabled(err) { if db.IsErrSSHDisabled(err) {
ctx.Error(http.StatusUnprocessableEntity, "", "SSH is disabled") ctx.Error(http.StatusUnprocessableEntity, "", "SSH is disabled")
} else if models.IsErrKeyUnableVerify(err) { } else if asymkey_model.IsErrKeyUnableVerify(err) {
ctx.Error(http.StatusUnprocessableEntity, "", "Unable to verify key content") ctx.Error(http.StatusUnprocessableEntity, "", "Unable to verify key content")
} else { } else {
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("Invalid key content: %v", err)) ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("Invalid key content: %v", err))
@ -179,13 +181,13 @@ func HandleCheckKeyStringError(ctx *context.APIContext, err error) {
// HandleAddKeyError handle add key error // HandleAddKeyError handle add key error
func HandleAddKeyError(ctx *context.APIContext, err error) { func HandleAddKeyError(ctx *context.APIContext, err error) {
switch { switch {
case models.IsErrDeployKeyAlreadyExist(err): case asymkey_model.IsErrDeployKeyAlreadyExist(err):
ctx.Error(http.StatusUnprocessableEntity, "", "This key has already been added to this repository") ctx.Error(http.StatusUnprocessableEntity, "", "This key has already been added to this repository")
case models.IsErrKeyAlreadyExist(err): case asymkey_model.IsErrKeyAlreadyExist(err):
ctx.Error(http.StatusUnprocessableEntity, "", "Key content has been used as non-deploy key") ctx.Error(http.StatusUnprocessableEntity, "", "Key content has been used as non-deploy key")
case models.IsErrKeyNameAlreadyUsed(err): case asymkey_model.IsErrKeyNameAlreadyUsed(err):
ctx.Error(http.StatusUnprocessableEntity, "", "Key title has been used") ctx.Error(http.StatusUnprocessableEntity, "", "Key title has been used")
case models.IsErrDeployKeyNameAlreadyUsed(err): case asymkey_model.IsErrDeployKeyNameAlreadyUsed(err):
ctx.Error(http.StatusUnprocessableEntity, "", "A key with the same name already exists") ctx.Error(http.StatusUnprocessableEntity, "", "A key with the same name already exists")
default: default:
ctx.Error(http.StatusInternalServerError, "AddKey", err) ctx.Error(http.StatusInternalServerError, "AddKey", err)
@ -223,13 +225,13 @@ func CreateDeployKey(ctx *context.APIContext) {
// "$ref": "#/responses/validationError" // "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.CreateKeyOption) form := web.GetForm(ctx).(*api.CreateKeyOption)
content, err := models.CheckPublicKeyString(form.Key) content, err := asymkey_model.CheckPublicKeyString(form.Key)
if err != nil { if err != nil {
HandleCheckKeyStringError(ctx, err) HandleCheckKeyStringError(ctx, err)
return return
} }
key, err := models.AddDeployKey(ctx.Repo.Repository.ID, form.Title, content, form.ReadOnly) key, err := asymkey_model.AddDeployKey(ctx.Repo.Repository.ID, form.Title, content, form.ReadOnly)
if err != nil { if err != nil {
HandleAddKeyError(ctx, err) HandleAddKeyError(ctx, err)
return return
@ -268,8 +270,8 @@ func DeleteDeploykey(ctx *context.APIContext) {
// "403": // "403":
// "$ref": "#/responses/forbidden" // "$ref": "#/responses/forbidden"
if err := models.DeleteDeployKey(ctx.User, ctx.ParamsInt64(":id")); err != nil { if err := asymkey_service.DeleteDeployKey(ctx.User, ctx.ParamsInt64(":id")); err != nil {
if models.IsErrKeyAccessDenied(err) { if asymkey_model.IsErrKeyAccessDenied(err) {
ctx.Error(http.StatusForbidden, "", "You do not have access to this key") ctx.Error(http.StatusForbidden, "", "You do not have access to this key")
} else { } else {
ctx.Error(http.StatusInternalServerError, "DeleteDeployKey", err) ctx.Error(http.StatusInternalServerError, "DeleteDeployKey", err)

@ -26,6 +26,7 @@ import (
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/routers/api/v1/utils"
asymkey_service "code.gitea.io/gitea/services/asymkey"
"code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/forms"
issue_service "code.gitea.io/gitea/services/issue" issue_service "code.gitea.io/gitea/services/issue"
pull_service "code.gitea.io/gitea/services/pull" pull_service "code.gitea.io/gitea/services/pull"
@ -810,7 +811,7 @@ func MergePullRequest(ctx *context.APIContext) {
} }
if _, err := pull_service.IsSignedIfRequired(pr, ctx.User); err != nil { if _, err := pull_service.IsSignedIfRequired(pr, ctx.User); err != nil {
if !models.IsErrWontSign(err) { if !asymkey_service.IsErrWontSign(err) {
ctx.Error(http.StatusInternalServerError, "IsSignedIfRequired", err) ctx.Error(http.StatusInternalServerError, "IsSignedIfRequired", err)
return return
} }

@ -1023,7 +1023,7 @@ func Delete(ctx *context.APIContext) {
ctx.Repo.GitRepo.Close() ctx.Repo.GitRepo.Close()
} }
if err := repo_service.DeleteRepository(ctx.User, repo); err != nil { if err := repo_service.DeleteRepository(ctx.User, repo, true); err != nil {
ctx.Error(http.StatusInternalServerError, "DeleteRepository", err) ctx.Error(http.StatusInternalServerError, "DeleteRepository", err)
return return
} }

@ -8,7 +8,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/convert"
@ -18,7 +18,7 @@ import (
) )
func listGPGKeys(ctx *context.APIContext, uid int64, listOptions db.ListOptions) { func listGPGKeys(ctx *context.APIContext, uid int64, listOptions db.ListOptions) {
keys, err := models.ListGPGKeys(uid, listOptions) keys, err := asymkey_model.ListGPGKeys(db.DefaultContext, uid, listOptions)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "ListGPGKeys", err) ctx.Error(http.StatusInternalServerError, "ListGPGKeys", err)
return return
@ -29,7 +29,7 @@ func listGPGKeys(ctx *context.APIContext, uid int64, listOptions db.ListOptions)
apiKeys[i] = convert.ToGPGKey(keys[i]) apiKeys[i] = convert.ToGPGKey(keys[i])
} }
total, err := models.CountUserGPGKeys(uid) total, err := asymkey_model.CountUserGPGKeys(uid)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return
@ -114,9 +114,9 @@ func GetGPGKey(ctx *context.APIContext) {
// "404": // "404":
// "$ref": "#/responses/notFound" // "$ref": "#/responses/notFound"
key, err := models.GetGPGKeyByID(ctx.ParamsInt64(":id")) key, err := asymkey_model.GetGPGKeyByID(ctx.ParamsInt64(":id"))
if err != nil { if err != nil {
if models.IsErrGPGKeyNotExist(err) { if asymkey_model.IsErrGPGKeyNotExist(err) {
ctx.NotFound() ctx.NotFound()
} else { } else {
ctx.Error(http.StatusInternalServerError, "GetGPGKeyByID", err) ctx.Error(http.StatusInternalServerError, "GetGPGKeyByID", err)
@ -128,12 +128,12 @@ func GetGPGKey(ctx *context.APIContext) {
// CreateUserGPGKey creates new GPG key to given user by ID. // CreateUserGPGKey creates new GPG key to given user by ID.
func CreateUserGPGKey(ctx *context.APIContext, form api.CreateGPGKeyOption, uid int64) { func CreateUserGPGKey(ctx *context.APIContext, form api.CreateGPGKeyOption, uid int64) {
token := models.VerificationToken(ctx.User, 1) token := asymkey_model.VerificationToken(ctx.User, 1)
lastToken := models.VerificationToken(ctx.User, 0) lastToken := asymkey_model.VerificationToken(ctx.User, 0)
keys, err := models.AddGPGKey(uid, form.ArmoredKey, token, form.Signature) keys, err := asymkey_model.AddGPGKey(uid, form.ArmoredKey, token, form.Signature)
if err != nil && models.IsErrGPGInvalidTokenSignature(err) { if err != nil && asymkey_model.IsErrGPGInvalidTokenSignature(err) {
keys, err = models.AddGPGKey(uid, form.ArmoredKey, lastToken, form.Signature) keys, err = asymkey_model.AddGPGKey(uid, form.ArmoredKey, lastToken, form.Signature)
} }
if err != nil { if err != nil {
HandleAddGPGKeyError(ctx, err, token) HandleAddGPGKeyError(ctx, err, token)
@ -156,7 +156,7 @@ func GetVerificationToken(ctx *context.APIContext) {
// "404": // "404":
// "$ref": "#/responses/notFound" // "$ref": "#/responses/notFound"
token := models.VerificationToken(ctx.User, 1) token := asymkey_model.VerificationToken(ctx.User, 1)
ctx.PlainText(http.StatusOK, []byte(token)) ctx.PlainText(http.StatusOK, []byte(token))
} }
@ -178,25 +178,25 @@ func VerifyUserGPGKey(ctx *context.APIContext) {
// "$ref": "#/responses/validationError" // "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.VerifyGPGKeyOption) form := web.GetForm(ctx).(*api.VerifyGPGKeyOption)
token := models.VerificationToken(ctx.User, 1) token := asymkey_model.VerificationToken(ctx.User, 1)
lastToken := models.VerificationToken(ctx.User, 0) lastToken := asymkey_model.VerificationToken(ctx.User, 0)
_, err := models.VerifyGPGKey(ctx.User.ID, form.KeyID, token, form.Signature) _, err := asymkey_model.VerifyGPGKey(ctx.User.ID, form.KeyID, token, form.Signature)
if err != nil && models.IsErrGPGInvalidTokenSignature(err) { if err != nil && asymkey_model.IsErrGPGInvalidTokenSignature(err) {
_, err = models.VerifyGPGKey(ctx.User.ID, form.KeyID, lastToken, form.Signature) _, err = asymkey_model.VerifyGPGKey(ctx.User.ID, form.KeyID, lastToken, form.Signature)
} }
if err != nil { if err != nil {
if models.IsErrGPGInvalidTokenSignature(err) { if asymkey_model.IsErrGPGInvalidTokenSignature(err) {
ctx.Error(http.StatusUnprocessableEntity, "GPGInvalidSignature", fmt.Sprintf("The provided GPG key, signature and token do not match or token is out of date. Provide a valid signature for the token: %s", token)) ctx.Error(http.StatusUnprocessableEntity, "GPGInvalidSignature", fmt.Sprintf("The provided GPG key, signature and token do not match or token is out of date. Provide a valid signature for the token: %s", token))
return return
} }
ctx.Error(http.StatusInternalServerError, "VerifyUserGPGKey", err) ctx.Error(http.StatusInternalServerError, "VerifyUserGPGKey", err)
} }
key, err := models.GetGPGKeysByKeyID(form.KeyID) key, err := asymkey_model.GetGPGKeysByKeyID(form.KeyID)
if err != nil { if err != nil {
if models.IsErrGPGKeyNotExist(err) { if asymkey_model.IsErrGPGKeyNotExist(err) {
ctx.NotFound() ctx.NotFound()
} else { } else {
ctx.Error(http.StatusInternalServerError, "GetGPGKeysByKeyID", err) ctx.Error(http.StatusInternalServerError, "GetGPGKeysByKeyID", err)
@ -255,8 +255,8 @@ func DeleteGPGKey(ctx *context.APIContext) {
// "404": // "404":
// "$ref": "#/responses/notFound" // "$ref": "#/responses/notFound"
if err := models.DeleteGPGKey(ctx.User, ctx.ParamsInt64(":id")); err != nil { if err := asymkey_model.DeleteGPGKey(ctx.User, ctx.ParamsInt64(":id")); err != nil {
if models.IsErrGPGKeyAccessDenied(err) { if asymkey_model.IsErrGPGKeyAccessDenied(err) {
ctx.Error(http.StatusForbidden, "", "You do not have access to this key") ctx.Error(http.StatusForbidden, "", "You do not have access to this key")
} else { } else {
ctx.Error(http.StatusInternalServerError, "DeleteGPGKey", err) ctx.Error(http.StatusInternalServerError, "DeleteGPGKey", err)
@ -270,15 +270,15 @@ func DeleteGPGKey(ctx *context.APIContext) {
// HandleAddGPGKeyError handle add GPGKey error // HandleAddGPGKeyError handle add GPGKey error
func HandleAddGPGKeyError(ctx *context.APIContext, err error, token string) { func HandleAddGPGKeyError(ctx *context.APIContext, err error, token string) {
switch { switch {
case models.IsErrGPGKeyAccessDenied(err): case asymkey_model.IsErrGPGKeyAccessDenied(err):
ctx.Error(http.StatusUnprocessableEntity, "GPGKeyAccessDenied", "You do not have access to this GPG key") ctx.Error(http.StatusUnprocessableEntity, "GPGKeyAccessDenied", "You do not have access to this GPG key")
case models.IsErrGPGKeyIDAlreadyUsed(err): case asymkey_model.IsErrGPGKeyIDAlreadyUsed(err):
ctx.Error(http.StatusUnprocessableEntity, "GPGKeyIDAlreadyUsed", "A key with the same id already exists") ctx.Error(http.StatusUnprocessableEntity, "GPGKeyIDAlreadyUsed", "A key with the same id already exists")
case models.IsErrGPGKeyParsing(err): case asymkey_model.IsErrGPGKeyParsing(err):
ctx.Error(http.StatusUnprocessableEntity, "GPGKeyParsing", err) ctx.Error(http.StatusUnprocessableEntity, "GPGKeyParsing", err)
case models.IsErrGPGNoEmailFound(err): case asymkey_model.IsErrGPGNoEmailFound(err):
ctx.Error(http.StatusNotFound, "GPGNoEmailFound", fmt.Sprintf("None of the emails attached to the GPG key could be found. It may still be added if you provide a valid signature for the token: %s", token)) ctx.Error(http.StatusNotFound, "GPGNoEmailFound", fmt.Sprintf("None of the emails attached to the GPG key could be found. It may still be added if you provide a valid signature for the token: %s", token))
case models.IsErrGPGInvalidTokenSignature(err): case asymkey_model.IsErrGPGInvalidTokenSignature(err):
ctx.Error(http.StatusUnprocessableEntity, "GPGInvalidSignature", fmt.Sprintf("The provided GPG key, signature and token do not match or token is out of date. Provide a valid signature for the token: %s", token)) ctx.Error(http.StatusUnprocessableEntity, "GPGInvalidSignature", fmt.Sprintf("The provided GPG key, signature and token do not match or token is out of date. Provide a valid signature for the token: %s", token))
default: default:
ctx.Error(http.StatusInternalServerError, "AddGPGKey", err) ctx.Error(http.StatusInternalServerError, "AddGPGKey", err)

@ -7,7 +7,7 @@ package user
import ( import (
"net/http" "net/http"
"code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
@ -17,13 +17,14 @@ import (
"code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/repo" "code.gitea.io/gitea/routers/api/v1/repo"
"code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/routers/api/v1/utils"
asymkey_service "code.gitea.io/gitea/services/asymkey"
) )
// appendPrivateInformation appends the owner and key type information to api.PublicKey // appendPrivateInformation appends the owner and key type information to api.PublicKey
func appendPrivateInformation(apiKey *api.PublicKey, key *models.PublicKey, defaultUser *user_model.User) (*api.PublicKey, error) { func appendPrivateInformation(apiKey *api.PublicKey, key *asymkey_model.PublicKey, defaultUser *user_model.User) (*api.PublicKey, error) {
if key.Type == models.KeyTypeDeploy { if key.Type == asymkey_model.KeyTypeDeploy {
apiKey.KeyType = "deploy" apiKey.KeyType = "deploy"
} else if key.Type == models.KeyTypeUser { } else if key.Type == asymkey_model.KeyTypeUser {
apiKey.KeyType = "user" apiKey.KeyType = "user"
if defaultUser.ID == key.OwnerID { if defaultUser.ID == key.OwnerID {
@ -47,7 +48,7 @@ func composePublicKeysAPILink() string {
} }
func listPublicKeys(ctx *context.APIContext, user *user_model.User) { func listPublicKeys(ctx *context.APIContext, user *user_model.User) {
var keys []*models.PublicKey var keys []*asymkey_model.PublicKey
var err error var err error
var count int var count int
@ -58,14 +59,14 @@ func listPublicKeys(ctx *context.APIContext, user *user_model.User) {
// Querying not just listing // Querying not just listing
if username != "" { if username != "" {
// Restrict to provided uid // Restrict to provided uid
keys, err = models.SearchPublicKey(user.ID, fingerprint) keys, err = asymkey_model.SearchPublicKey(user.ID, fingerprint)
} else { } else {
// Unrestricted // Unrestricted
keys, err = models.SearchPublicKey(0, fingerprint) keys, err = asymkey_model.SearchPublicKey(0, fingerprint)
} }
count = len(keys) count = len(keys)
} else { } else {
total, err2 := models.CountPublicKeys(user.ID) total, err2 := asymkey_model.CountPublicKeys(user.ID)
if err2 != nil { if err2 != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
return return
@ -73,7 +74,7 @@ func listPublicKeys(ctx *context.APIContext, user *user_model.User) {
count = int(total) count = int(total)
// Use ListPublicKeys // Use ListPublicKeys
keys, err = models.ListPublicKeys(user.ID, utils.GetListOptions(ctx)) keys, err = asymkey_model.ListPublicKeys(user.ID, utils.GetListOptions(ctx))
} }
if err != nil { if err != nil {
@ -177,9 +178,9 @@ func GetPublicKey(ctx *context.APIContext) {
// "404": // "404":
// "$ref": "#/responses/notFound" // "$ref": "#/responses/notFound"
key, err := models.GetPublicKeyByID(ctx.ParamsInt64(":id")) key, err := asymkey_model.GetPublicKeyByID(ctx.ParamsInt64(":id"))
if err != nil { if err != nil {
if models.IsErrKeyNotExist(err) { if asymkey_model.IsErrKeyNotExist(err) {
ctx.NotFound() ctx.NotFound()
} else { } else {
ctx.Error(http.StatusInternalServerError, "GetPublicKeyByID", err) ctx.Error(http.StatusInternalServerError, "GetPublicKeyByID", err)
@ -197,13 +198,13 @@ func GetPublicKey(ctx *context.APIContext) {
// CreateUserPublicKey creates new public key to given user by ID. // CreateUserPublicKey creates new public key to given user by ID.
func CreateUserPublicKey(ctx *context.APIContext, form api.CreateKeyOption, uid int64) { func CreateUserPublicKey(ctx *context.APIContext, form api.CreateKeyOption, uid int64) {
content, err := models.CheckPublicKeyString(form.Key) content, err := asymkey_model.CheckPublicKeyString(form.Key)
if err != nil { if err != nil {
repo.HandleCheckKeyStringError(ctx, err) repo.HandleCheckKeyStringError(ctx, err)
return return
} }
key, err := models.AddPublicKey(uid, form.Title, content, 0) key, err := asymkey_model.AddPublicKey(uid, form.Title, content, 0)
if err != nil { if err != nil {
repo.HandleAddKeyError(ctx, err) repo.HandleAddKeyError(ctx, err)
return return
@ -263,7 +264,7 @@ func DeletePublicKey(ctx *context.APIContext) {
// "$ref": "#/responses/notFound" // "$ref": "#/responses/notFound"
id := ctx.ParamsInt64(":id") id := ctx.ParamsInt64(":id")
externallyManaged, err := models.PublicKeyIsExternallyManaged(id) externallyManaged, err := asymkey_model.PublicKeyIsExternallyManaged(id)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "PublicKeyIsExternallyManaged", err) ctx.Error(http.StatusInternalServerError, "PublicKeyIsExternallyManaged", err)
} }
@ -271,10 +272,10 @@ func DeletePublicKey(ctx *context.APIContext) {
ctx.Error(http.StatusForbidden, "", "SSH Key is externally managed for this user") ctx.Error(http.StatusForbidden, "", "SSH Key is externally managed for this user")
} }
if err := models.DeletePublicKey(ctx.User, id); err != nil { if err := asymkey_service.DeletePublicKey(ctx.User, id); err != nil {
if models.IsErrKeyNotExist(err) { if asymkey_model.IsErrKeyNotExist(err) {
ctx.NotFound() ctx.NotFound()
} else if models.IsErrKeyAccessDenied(err) { } else if asymkey_model.IsErrKeyAccessDenied(err) {
ctx.Error(http.StatusForbidden, "", "You do not have access to this key") ctx.Error(http.StatusForbidden, "", "You do not have access to this key")
} else { } else {
ctx.Error(http.StatusInternalServerError, "DeletePublicKey", err) ctx.Error(http.StatusInternalServerError, "DeletePublicKey", err)

@ -13,6 +13,7 @@ import (
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/modules/appstate" "code.gitea.io/gitea/modules/appstate"
"code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/eventsource" "code.gitea.io/gitea/modules/eventsource"
@ -87,7 +88,7 @@ func syncAppPathForGit(ctx context.Context) error {
mustInitCtx(ctx, repo_service.SyncRepositoryHooks) mustInitCtx(ctx, repo_service.SyncRepositoryHooks)
log.Info("re-write ssh public keys ...") log.Info("re-write ssh public keys ...")
mustInit(models.RewriteAllPublicKeys) mustInit(asymkey_model.RewriteAllPublicKeys)
runtimeState.LastAppPath = setting.AppPath runtimeState.LastAppPath = setting.AppPath
return appstate.AppState.Set(runtimeState) return appstate.AppState.Set(runtimeState)

@ -12,7 +12,7 @@ import (
"io" "io"
"os" "os"
"code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
) )
@ -97,7 +97,7 @@ func readAndVerifyCommit(sha string, repo *git.Repository, env []string) error {
if err != nil { if err != nil {
return err return err
} }
verification := models.ParseCommitWithSignature(commit) verification := asymkey_model.ParseCommitWithSignature(commit)
if !verification.Verified { if !verification.Verified {
cancel() cancel()
return &errUnverifiedCommit{ return &errUnverifiedCommit{

@ -8,7 +8,7 @@ package private
import ( import (
"net/http" "net/http"
"code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
@ -18,16 +18,16 @@ import (
func UpdatePublicKeyInRepo(ctx *context.PrivateContext) { func UpdatePublicKeyInRepo(ctx *context.PrivateContext) {
keyID := ctx.ParamsInt64(":id") keyID := ctx.ParamsInt64(":id")
repoID := ctx.ParamsInt64(":repoid") repoID := ctx.ParamsInt64(":repoid")
if err := models.UpdatePublicKeyUpdated(keyID); err != nil { if err := asymkey_model.UpdatePublicKeyUpdated(keyID); err != nil {
ctx.JSON(http.StatusInternalServerError, private.Response{ ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err.Error(), Err: err.Error(),
}) })
return return
} }
deployKey, err := models.GetDeployKeyByRepo(keyID, repoID) deployKey, err := asymkey_model.GetDeployKeyByRepo(keyID, repoID)
if err != nil { if err != nil {
if models.IsErrDeployKeyNotExist(err) { if asymkey_model.IsErrDeployKeyNotExist(err) {
ctx.PlainText(http.StatusOK, []byte("success")) ctx.PlainText(http.StatusOK, []byte("success"))
return return
} }
@ -37,7 +37,7 @@ func UpdatePublicKeyInRepo(ctx *context.PrivateContext) {
return return
} }
deployKey.UpdatedUnix = timeutil.TimeStampNow() deployKey.UpdatedUnix = timeutil.TimeStampNow()
if err = models.UpdateDeployKeyCols(deployKey, "updated_unix"); err != nil { if err = asymkey_model.UpdateDeployKeyCols(deployKey, "updated_unix"); err != nil {
ctx.JSON(http.StatusInternalServerError, private.Response{ ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err.Error(), Err: err.Error(),
}) })
@ -52,7 +52,7 @@ func UpdatePublicKeyInRepo(ctx *context.PrivateContext) {
func AuthorizedPublicKeyByContent(ctx *context.PrivateContext) { func AuthorizedPublicKeyByContent(ctx *context.PrivateContext) {
content := ctx.FormString("content") content := ctx.FormString("content")
publicKey, err := models.SearchPublicKeyByContent(content) publicKey, err := asymkey_model.SearchPublicKeyByContent(content)
if err != nil { if err != nil {
ctx.JSON(http.StatusInternalServerError, private.Response{ ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err.Error(), Err: err.Error(),

@ -11,6 +11,7 @@ import (
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
@ -34,9 +35,9 @@ func ServNoCommand(ctx *context.PrivateContext) {
} }
results := private.KeyAndOwner{} results := private.KeyAndOwner{}
key, err := models.GetPublicKeyByID(keyID) key, err := asymkey_model.GetPublicKeyByID(keyID)
if err != nil { if err != nil {
if models.IsErrKeyNotExist(err) { if asymkey_model.IsErrKeyNotExist(err) {
ctx.JSON(http.StatusUnauthorized, private.Response{ ctx.JSON(http.StatusUnauthorized, private.Response{
Err: fmt.Sprintf("Cannot find key: %d", keyID), Err: fmt.Sprintf("Cannot find key: %d", keyID),
}) })
@ -50,7 +51,7 @@ func ServNoCommand(ctx *context.PrivateContext) {
} }
results.Key = key results.Key = key
if key.Type == models.KeyTypeUser || key.Type == models.KeyTypePrincipal { if key.Type == asymkey_model.KeyTypeUser || key.Type == asymkey_model.KeyTypePrincipal {
user, err := user_model.GetUserByID(key.OwnerID) user, err := user_model.GetUserByID(key.OwnerID)
if err != nil { if err != nil {
if user_model.IsErrUserNotExist(err) { if user_model.IsErrUserNotExist(err) {
@ -184,9 +185,9 @@ func ServCommand(ctx *context.PrivateContext) {
} }
// Get the Public Key represented by the keyID // Get the Public Key represented by the keyID
key, err := models.GetPublicKeyByID(keyID) key, err := asymkey_model.GetPublicKeyByID(keyID)
if err != nil { if err != nil {
if models.IsErrKeyNotExist(err) { if asymkey_model.IsErrKeyNotExist(err) {
ctx.JSON(http.StatusNotFound, private.ErrServCommand{ ctx.JSON(http.StatusNotFound, private.ErrServCommand{
Results: results, Results: results,
Err: fmt.Sprintf("Cannot find key: %d", keyID), Err: fmt.Sprintf("Cannot find key: %d", keyID),
@ -205,7 +206,7 @@ func ServCommand(ctx *context.PrivateContext) {
results.UserID = key.OwnerID results.UserID = key.OwnerID
// If repo doesn't exist, deploy key doesn't make sense // If repo doesn't exist, deploy key doesn't make sense
if !repoExist && key.Type == models.KeyTypeDeploy { if !repoExist && key.Type == asymkey_model.KeyTypeDeploy {
ctx.JSON(http.StatusNotFound, private.ErrServCommand{ ctx.JSON(http.StatusNotFound, private.ErrServCommand{
Results: results, Results: results,
Err: fmt.Sprintf("Cannot find repository %s/%s", results.OwnerName, results.RepoName), Err: fmt.Sprintf("Cannot find repository %s/%s", results.OwnerName, results.RepoName),
@ -216,15 +217,15 @@ func ServCommand(ctx *context.PrivateContext) {
// Deploy Keys have ownerID set to 0 therefore we can't use the owner // Deploy Keys have ownerID set to 0 therefore we can't use the owner
// So now we need to check if the key is a deploy key // So now we need to check if the key is a deploy key
// We'll keep hold of the deploy key here for permissions checking // We'll keep hold of the deploy key here for permissions checking
var deployKey *models.DeployKey var deployKey *asymkey_model.DeployKey
var user *user_model.User var user *user_model.User
if key.Type == models.KeyTypeDeploy { if key.Type == asymkey_model.KeyTypeDeploy {
results.IsDeployKey = true results.IsDeployKey = true
var err error var err error
deployKey, err = models.GetDeployKeyByRepo(key.ID, repo.ID) deployKey, err = asymkey_model.GetDeployKeyByRepo(key.ID, repo.ID)
if err != nil { if err != nil {
if models.IsErrDeployKeyNotExist(err) { if asymkey_model.IsErrDeployKeyNotExist(err) {
ctx.JSON(http.StatusNotFound, private.ErrServCommand{ ctx.JSON(http.StatusNotFound, private.ErrServCommand{
Results: results, Results: results,
Err: fmt.Sprintf("Public (Deploy) Key: %d:%s is not authorized to %s %s/%s.", key.ID, key.Name, modeString, results.OwnerName, results.RepoName), Err: fmt.Sprintf("Public (Deploy) Key: %d:%s is not authorized to %s %s/%s.", key.ID, key.Name, modeString, results.OwnerName, results.RepoName),
@ -297,7 +298,7 @@ func ServCommand(ctx *context.PrivateContext) {
owner.Visibility.IsPrivate() || owner.Visibility.IsPrivate() ||
(user != nil && user.IsRestricted) || // user will be nil if the key is a deploykey (user != nil && user.IsRestricted) || // user will be nil if the key is a deploykey
setting.Service.RequireSignInView) { setting.Service.RequireSignInView) {
if key.Type == models.KeyTypeDeploy { if key.Type == asymkey_model.KeyTypeDeploy {
if deployKey.Mode < mode { if deployKey.Mode < mode {
ctx.JSON(http.StatusUnauthorized, private.ErrServCommand{ ctx.JSON(http.StatusUnauthorized, private.ErrServCommand{
Results: results, Results: results,

@ -52,7 +52,7 @@ func DeleteRepo(ctx *context.Context) {
ctx.Repo.GitRepo.Close() ctx.Repo.GitRepo.Close()
} }
if err := repo_service.DeleteRepository(ctx.User, repo); err != nil { if err := repo_service.DeleteRepository(ctx.User, repo, true); err != nil {
ctx.ServerError("DeleteRepository", err) ctx.ServerError("DeleteRepository", err)
return return
} }

@ -11,6 +11,7 @@ import (
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -344,13 +345,15 @@ func Diff(ctx *context.Context) {
ctx.Data["CommitStatus"] = models.CalcCommitStatus(statuses) ctx.Data["CommitStatus"] = models.CalcCommitStatus(statuses)
ctx.Data["CommitStatuses"] = statuses ctx.Data["CommitStatuses"] = statuses
verification := models.ParseCommitWithSignature(commit) verification := asymkey_model.ParseCommitWithSignature(commit)
ctx.Data["Verification"] = verification ctx.Data["Verification"] = verification
ctx.Data["Author"] = user_model.ValidateCommitWithEmail(commit) ctx.Data["Author"] = user_model.ValidateCommitWithEmail(commit)
ctx.Data["Parents"] = parents ctx.Data["Parents"] = parents
ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0 ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0
if err := models.CalculateTrustStatus(verification, ctx.Repo.Repository, nil); err != nil { if err := asymkey_model.CalculateTrustStatus(verification, ctx.Repo.Repository.GetTrustModel(), func(user *user_model.User) (bool, error) {
return models.IsUserRepoAdmin(ctx.Repo.Repository, user)
}, nil); err != nil {
ctx.ServerError("CalculateTrustStatus", err) ctx.ServerError("CalculateTrustStatus", err)
return return
} }

@ -34,6 +34,7 @@ import (
"code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/upload"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web"
asymkey_service "code.gitea.io/gitea/services/asymkey"
comment_service "code.gitea.io/gitea/services/comments" comment_service "code.gitea.io/gitea/services/comments"
"code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/forms"
issue_service "code.gitea.io/gitea/services/issue" issue_service "code.gitea.io/gitea/services/issue"
@ -1583,12 +1584,12 @@ func ViewIssue(ctx *context.Context) {
} }
ctx.Data["WillSign"] = false ctx.Data["WillSign"] = false
if ctx.User != nil { if ctx.User != nil {
sign, key, _, err := pull.SignMerge(ctx.User, pull.BaseRepo.RepoPath(), pull.BaseBranch, pull.GetGitRefName()) sign, key, _, err := asymkey_service.SignMerge(pull, ctx.User, pull.BaseRepo.RepoPath(), pull.BaseBranch, pull.GetGitRefName())
ctx.Data["WillSign"] = sign ctx.Data["WillSign"] = sign
ctx.Data["SigningKey"] = key ctx.Data["SigningKey"] = key
if err != nil { if err != nil {
if models.IsErrWontSign(err) { if asymkey_service.IsErrWontSign(err) {
ctx.Data["WontSignReason"] = err.(*models.ErrWontSign).Reason ctx.Data["WontSignReason"] = err.(*asymkey_service.ErrWontSign).Reason
} else { } else {
ctx.Data["WontSignReason"] = "error" ctx.Data["WontSignReason"] = "error"
log.Error("Error whilst checking if could sign pr %d in repo %s. Error: %v", pull.ID, pull.BaseRepo.FullName(), err) log.Error("Error whilst checking if could sign pr %d in repo %s. Error: %v", pull.ID, pull.BaseRepo.FullName(), err)

@ -15,6 +15,7 @@ import (
"time" "time"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
@ -34,6 +35,7 @@ import (
"code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/validation"
"code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/utils" "code.gitea.io/gitea/routers/utils"
asymkey_service "code.gitea.io/gitea/services/asymkey"
"code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/forms"
"code.gitea.io/gitea/services/mailer" "code.gitea.io/gitea/services/mailer"
"code.gitea.io/gitea/services/migrations" "code.gitea.io/gitea/services/migrations"
@ -62,7 +64,7 @@ func Settings(ctx *context.Context) {
ctx.Data["DisableNewPushMirrors"] = setting.Mirror.DisableNewPush ctx.Data["DisableNewPushMirrors"] = setting.Mirror.DisableNewPush
ctx.Data["DefaultMirrorInterval"] = setting.Mirror.DefaultInterval ctx.Data["DefaultMirrorInterval"] = setting.Mirror.DefaultInterval
signing, _ := models.SigningKey(ctx.Repo.Repository.RepoPath()) signing, _ := asymkey_service.SigningKey(ctx.Repo.Repository.RepoPath())
ctx.Data["SigningKeyAvailable"] = len(signing) > 0 ctx.Data["SigningKeyAvailable"] = len(signing) > 0
ctx.Data["SigningSettings"] = setting.Repository.Signing ctx.Data["SigningSettings"] = setting.Repository.Signing
pushMirrors, err := repo_model.GetPushMirrorsByRepoID(ctx.Repo.Repository.ID) pushMirrors, err := repo_model.GetPushMirrorsByRepoID(ctx.Repo.Repository.ID)
@ -476,7 +478,6 @@ func SettingsPost(ctx *context.Context) {
case "signing": case "signing":
changed := false changed := false
trustModel := repo_model.ToTrustModel(form.TrustModel) trustModel := repo_model.ToTrustModel(form.TrustModel)
if trustModel != repo.TrustModel { if trustModel != repo.TrustModel {
repo.TrustModel = trustModel repo.TrustModel = trustModel
@ -673,7 +674,7 @@ func SettingsPost(ctx *context.Context) {
ctx.Repo.GitRepo.Close() ctx.Repo.GitRepo.Close()
} }
if err := repo_service.DeleteRepository(ctx.User, ctx.Repo.Repository); err != nil { if err := repo_service.DeleteRepository(ctx.User, ctx.Repo.Repository, true); err != nil {
ctx.ServerError("DeleteRepository", err) ctx.ServerError("DeleteRepository", err)
return return
} }
@ -1029,7 +1030,7 @@ func DeployKeys(ctx *context.Context) {
ctx.Data["PageIsSettingsKeys"] = true ctx.Data["PageIsSettingsKeys"] = true
ctx.Data["DisableSSH"] = setting.SSH.Disabled ctx.Data["DisableSSH"] = setting.SSH.Disabled
keys, err := models.ListDeployKeys(&models.ListDeployKeysOptions{RepoID: ctx.Repo.Repository.ID}) keys, err := asymkey_model.ListDeployKeys(db.DefaultContext, &asymkey_model.ListDeployKeysOptions{RepoID: ctx.Repo.Repository.ID})
if err != nil { if err != nil {
ctx.ServerError("ListDeployKeys", err) ctx.ServerError("ListDeployKeys", err)
return return
@ -1045,7 +1046,7 @@ func DeployKeysPost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.settings.deploy_keys") ctx.Data["Title"] = ctx.Tr("repo.settings.deploy_keys")
ctx.Data["PageIsSettingsKeys"] = true ctx.Data["PageIsSettingsKeys"] = true
keys, err := models.ListDeployKeys(&models.ListDeployKeysOptions{RepoID: ctx.Repo.Repository.ID}) keys, err := asymkey_model.ListDeployKeys(db.DefaultContext, &asymkey_model.ListDeployKeysOptions{RepoID: ctx.Repo.Repository.ID})
if err != nil { if err != nil {
ctx.ServerError("ListDeployKeys", err) ctx.ServerError("ListDeployKeys", err)
return return
@ -1057,11 +1058,11 @@ func DeployKeysPost(ctx *context.Context) {
return return
} }
content, err := models.CheckPublicKeyString(form.Content) content, err := asymkey_model.CheckPublicKeyString(form.Content)
if err != nil { if err != nil {
if models.IsErrSSHDisabled(err) { if db.IsErrSSHDisabled(err) {
ctx.Flash.Info(ctx.Tr("settings.ssh_disabled")) ctx.Flash.Info(ctx.Tr("settings.ssh_disabled"))
} else if models.IsErrKeyUnableVerify(err) { } else if asymkey_model.IsErrKeyUnableVerify(err) {
ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key")) ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
} else { } else {
ctx.Data["HasError"] = true ctx.Data["HasError"] = true
@ -1072,20 +1073,20 @@ func DeployKeysPost(ctx *context.Context) {
return return
} }
key, err := models.AddDeployKey(ctx.Repo.Repository.ID, form.Title, content, !form.IsWritable) key, err := asymkey_model.AddDeployKey(ctx.Repo.Repository.ID, form.Title, content, !form.IsWritable)
if err != nil { if err != nil {
ctx.Data["HasError"] = true ctx.Data["HasError"] = true
switch { switch {
case models.IsErrDeployKeyAlreadyExist(err): case asymkey_model.IsErrDeployKeyAlreadyExist(err):
ctx.Data["Err_Content"] = true ctx.Data["Err_Content"] = true
ctx.RenderWithErr(ctx.Tr("repo.settings.key_been_used"), tplDeployKeys, &form) ctx.RenderWithErr(ctx.Tr("repo.settings.key_been_used"), tplDeployKeys, &form)
case models.IsErrKeyAlreadyExist(err): case asymkey_model.IsErrKeyAlreadyExist(err):
ctx.Data["Err_Content"] = true ctx.Data["Err_Content"] = true
ctx.RenderWithErr(ctx.Tr("settings.ssh_key_been_used"), tplDeployKeys, &form) ctx.RenderWithErr(ctx.Tr("settings.ssh_key_been_used"), tplDeployKeys, &form)
case models.IsErrKeyNameAlreadyUsed(err): case asymkey_model.IsErrKeyNameAlreadyUsed(err):
ctx.Data["Err_Title"] = true ctx.Data["Err_Title"] = true
ctx.RenderWithErr(ctx.Tr("repo.settings.key_name_used"), tplDeployKeys, &form) ctx.RenderWithErr(ctx.Tr("repo.settings.key_name_used"), tplDeployKeys, &form)
case models.IsErrDeployKeyNameAlreadyUsed(err): case asymkey_model.IsErrDeployKeyNameAlreadyUsed(err):
ctx.Data["Err_Title"] = true ctx.Data["Err_Title"] = true
ctx.RenderWithErr(ctx.Tr("repo.settings.key_name_used"), tplDeployKeys, &form) ctx.RenderWithErr(ctx.Tr("repo.settings.key_name_used"), tplDeployKeys, &form)
default: default:
@ -1101,7 +1102,7 @@ func DeployKeysPost(ctx *context.Context) {
// DeleteDeployKey response for deleting a deploy key // DeleteDeployKey response for deleting a deploy key
func DeleteDeployKey(ctx *context.Context) { func DeleteDeployKey(ctx *context.Context) {
if err := models.DeleteDeployKey(ctx.User, ctx.FormInt64("id")); err != nil { if err := asymkey_service.DeleteDeployKey(ctx.User, ctx.FormInt64("id")); err != nil {
ctx.Flash.Error("DeleteDeployKey: " + err.Error()) ctx.Flash.Error("DeleteDeployKey: " + err.Error())
} else { } else {
ctx.Flash.Success(ctx.Tr("repo.settings.deploy_key_deletion_success")) ctx.Flash.Success(ctx.Tr("repo.settings.deploy_key_deletion_success"))

@ -10,6 +10,7 @@ import (
"testing" "testing"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
@ -61,7 +62,7 @@ func TestAddReadOnlyDeployKey(t *testing.T) {
DeployKeysPost(ctx) DeployKeysPost(ctx)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status()) assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
unittest.AssertExistsAndLoadBean(t, &models.DeployKey{ unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{
Name: addKeyForm.Title, Name: addKeyForm.Title,
Content: addKeyForm.Content, Content: addKeyForm.Content,
Mode: perm.AccessModeRead, Mode: perm.AccessModeRead,
@ -91,7 +92,7 @@ func TestAddReadWriteOnlyDeployKey(t *testing.T) {
DeployKeysPost(ctx) DeployKeysPost(ctx)
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status()) assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
unittest.AssertExistsAndLoadBean(t, &models.DeployKey{ unittest.AssertExistsAndLoadBean(t, &asymkey_model.DeployKey{
Name: addKeyForm.Title, Name: addKeyForm.Title,
Content: addKeyForm.Content, Content: addKeyForm.Content,
Mode: perm.AccessModeWrite, Mode: perm.AccessModeWrite,

@ -20,6 +20,7 @@ import (
"time" "time"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit" unit_model "code.gitea.io/gitea/models/unit"
@ -777,9 +778,11 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri
ctx.Data["LatestCommit"] = latestCommit ctx.Data["LatestCommit"] = latestCommit
if latestCommit != nil { if latestCommit != nil {
verification := models.ParseCommitWithSignature(latestCommit) verification := asymkey_model.ParseCommitWithSignature(latestCommit)
if err := models.CalculateTrustStatus(verification, ctx.Repo.Repository, nil); err != nil { if err := asymkey_model.CalculateTrustStatus(verification, ctx.Repo.Repository.GetTrustModel(), func(user *user_model.User) (bool, error) {
return models.IsUserRepoAdmin(ctx.Repo.Repository, user)
}, nil); err != nil {
ctx.ServerError("CalculateTrustStatus", err) ctx.ServerError("CalculateTrustStatus", err)
return nil return nil
} }

@ -15,6 +15,7 @@ import (
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
@ -827,7 +828,7 @@ func repoIDMap(ctxUser *user_model.User, issueCountByRepo map[int64]int64, unitT
// ShowSSHKeys output all the ssh keys of user by uid // ShowSSHKeys output all the ssh keys of user by uid
func ShowSSHKeys(ctx *context.Context, uid int64) { func ShowSSHKeys(ctx *context.Context, uid int64) {
keys, err := models.ListPublicKeys(uid, db.ListOptions{}) keys, err := asymkey_model.ListPublicKeys(uid, db.ListOptions{})
if err != nil { if err != nil {
ctx.ServerError("ListPublicKeys", err) ctx.ServerError("ListPublicKeys", err)
return return
@ -843,7 +844,7 @@ func ShowSSHKeys(ctx *context.Context, uid int64) {
// ShowGPGKeys output all the public GPG keys of user by uid // ShowGPGKeys output all the public GPG keys of user by uid
func ShowGPGKeys(ctx *context.Context, uid int64) { func ShowGPGKeys(ctx *context.Context, uid int64) {
keys, err := models.ListGPGKeys(uid, db.ListOptions{}) keys, err := asymkey_model.ListGPGKeys(db.DefaultContext, uid, db.ListOptions{})
if err != nil { if err != nil {
ctx.ServerError("ListGPGKeys", err) ctx.ServerError("ListGPGKeys", err)
return return
@ -851,9 +852,9 @@ func ShowGPGKeys(ctx *context.Context, uid int64) {
entities := make([]*openpgp.Entity, 0) entities := make([]*openpgp.Entity, 0)
failedEntitiesID := make([]string, 0) failedEntitiesID := make([]string, 0)
for _, k := range keys { for _, k := range keys {
e, err := models.GPGKeyToEntity(k) e, err := asymkey_model.GPGKeyToEntity(k)
if err != nil { if err != nil {
if models.IsErrGPGKeyImportNotExist(err) { if asymkey_model.IsErrGPGKeyImportNotExist(err) {
failedEntitiesID = append(failedEntitiesID, k.KeyID) failedEntitiesID = append(failedEntitiesID, k.KeyID)
continue //Skip previous import without backup of imported armored key continue //Skip previous import without backup of imported armored key
} }

@ -8,12 +8,13 @@ package setting
import ( import (
"net/http" "net/http"
"code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web"
asymkey_service "code.gitea.io/gitea/services/asymkey"
"code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/forms"
) )
@ -51,9 +52,9 @@ func KeysPost(ctx *context.Context) {
} }
switch form.Type { switch form.Type {
case "principal": case "principal":
content, err := models.CheckPrincipalKeyString(ctx.User, form.Content) content, err := asymkey_model.CheckPrincipalKeyString(ctx.User, form.Content)
if err != nil { if err != nil {
if models.IsErrSSHDisabled(err) { if db.IsErrSSHDisabled(err) {
ctx.Flash.Info(ctx.Tr("settings.ssh_disabled")) ctx.Flash.Info(ctx.Tr("settings.ssh_disabled"))
} else { } else {
ctx.Flash.Error(ctx.Tr("form.invalid_ssh_principal", err.Error())) ctx.Flash.Error(ctx.Tr("form.invalid_ssh_principal", err.Error()))
@ -61,10 +62,10 @@ func KeysPost(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/keys") ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
return return
} }
if _, err = models.AddPrincipalKey(ctx.User.ID, content, 0); err != nil { if _, err = asymkey_model.AddPrincipalKey(ctx.User.ID, content, 0); err != nil {
ctx.Data["HasPrincipalError"] = true ctx.Data["HasPrincipalError"] = true
switch { switch {
case models.IsErrKeyAlreadyExist(err), models.IsErrKeyNameAlreadyUsed(err): case asymkey_model.IsErrKeyAlreadyExist(err), asymkey_model.IsErrKeyNameAlreadyUsed(err):
loadKeysData(ctx) loadKeysData(ctx)
ctx.Data["Err_Content"] = true ctx.Data["Err_Content"] = true
@ -77,36 +78,36 @@ func KeysPost(ctx *context.Context) {
ctx.Flash.Success(ctx.Tr("settings.add_principal_success", form.Content)) ctx.Flash.Success(ctx.Tr("settings.add_principal_success", form.Content))
ctx.Redirect(setting.AppSubURL + "/user/settings/keys") ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
case "gpg": case "gpg":
token := models.VerificationToken(ctx.User, 1) token := asymkey_model.VerificationToken(ctx.User, 1)
lastToken := models.VerificationToken(ctx.User, 0) lastToken := asymkey_model.VerificationToken(ctx.User, 0)
keys, err := models.AddGPGKey(ctx.User.ID, form.Content, token, form.Signature) keys, err := asymkey_model.AddGPGKey(ctx.User.ID, form.Content, token, form.Signature)
if err != nil && models.IsErrGPGInvalidTokenSignature(err) { if err != nil && asymkey_model.IsErrGPGInvalidTokenSignature(err) {
keys, err = models.AddGPGKey(ctx.User.ID, form.Content, lastToken, form.Signature) keys, err = asymkey_model.AddGPGKey(ctx.User.ID, form.Content, lastToken, form.Signature)
} }
if err != nil { if err != nil {
ctx.Data["HasGPGError"] = true ctx.Data["HasGPGError"] = true
switch { switch {
case models.IsErrGPGKeyParsing(err): case asymkey_model.IsErrGPGKeyParsing(err):
ctx.Flash.Error(ctx.Tr("form.invalid_gpg_key", err.Error())) ctx.Flash.Error(ctx.Tr("form.invalid_gpg_key", err.Error()))
ctx.Redirect(setting.AppSubURL + "/user/settings/keys") ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
case models.IsErrGPGKeyIDAlreadyUsed(err): case asymkey_model.IsErrGPGKeyIDAlreadyUsed(err):
loadKeysData(ctx) loadKeysData(ctx)
ctx.Data["Err_Content"] = true ctx.Data["Err_Content"] = true
ctx.RenderWithErr(ctx.Tr("settings.gpg_key_id_used"), tplSettingsKeys, &form) ctx.RenderWithErr(ctx.Tr("settings.gpg_key_id_used"), tplSettingsKeys, &form)
case models.IsErrGPGInvalidTokenSignature(err): case asymkey_model.IsErrGPGInvalidTokenSignature(err):
loadKeysData(ctx) loadKeysData(ctx)
ctx.Data["Err_Content"] = true ctx.Data["Err_Content"] = true
ctx.Data["Err_Signature"] = true ctx.Data["Err_Signature"] = true
ctx.Data["KeyID"] = err.(models.ErrGPGInvalidTokenSignature).ID ctx.Data["KeyID"] = err.(asymkey_model.ErrGPGInvalidTokenSignature).ID
ctx.RenderWithErr(ctx.Tr("settings.gpg_invalid_token_signature"), tplSettingsKeys, &form) ctx.RenderWithErr(ctx.Tr("settings.gpg_invalid_token_signature"), tplSettingsKeys, &form)
case models.IsErrGPGNoEmailFound(err): case asymkey_model.IsErrGPGNoEmailFound(err):
loadKeysData(ctx) loadKeysData(ctx)
ctx.Data["Err_Content"] = true ctx.Data["Err_Content"] = true
ctx.Data["Err_Signature"] = true ctx.Data["Err_Signature"] = true
ctx.Data["KeyID"] = err.(models.ErrGPGNoEmailFound).ID ctx.Data["KeyID"] = err.(asymkey_model.ErrGPGNoEmailFound).ID
ctx.RenderWithErr(ctx.Tr("settings.gpg_no_key_email_found"), tplSettingsKeys, &form) ctx.RenderWithErr(ctx.Tr("settings.gpg_no_key_email_found"), tplSettingsKeys, &form)
default: default:
ctx.ServerError("AddPublicKey", err) ctx.ServerError("AddPublicKey", err)
@ -124,21 +125,21 @@ func KeysPost(ctx *context.Context) {
ctx.Flash.Success(ctx.Tr("settings.add_gpg_key_success", keyIDs)) ctx.Flash.Success(ctx.Tr("settings.add_gpg_key_success", keyIDs))
ctx.Redirect(setting.AppSubURL + "/user/settings/keys") ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
case "verify_gpg": case "verify_gpg":
token := models.VerificationToken(ctx.User, 1) token := asymkey_model.VerificationToken(ctx.User, 1)
lastToken := models.VerificationToken(ctx.User, 0) lastToken := asymkey_model.VerificationToken(ctx.User, 0)
keyID, err := models.VerifyGPGKey(ctx.User.ID, form.KeyID, token, form.Signature) keyID, err := asymkey_model.VerifyGPGKey(ctx.User.ID, form.KeyID, token, form.Signature)
if err != nil && models.IsErrGPGInvalidTokenSignature(err) { if err != nil && asymkey_model.IsErrGPGInvalidTokenSignature(err) {
keyID, err = models.VerifyGPGKey(ctx.User.ID, form.KeyID, lastToken, form.Signature) keyID, err = asymkey_model.VerifyGPGKey(ctx.User.ID, form.KeyID, lastToken, form.Signature)
} }
if err != nil { if err != nil {
ctx.Data["HasGPGVerifyError"] = true ctx.Data["HasGPGVerifyError"] = true
switch { switch {
case models.IsErrGPGInvalidTokenSignature(err): case asymkey_model.IsErrGPGInvalidTokenSignature(err):
loadKeysData(ctx) loadKeysData(ctx)
ctx.Data["VerifyingID"] = form.KeyID ctx.Data["VerifyingID"] = form.KeyID
ctx.Data["Err_Signature"] = true ctx.Data["Err_Signature"] = true
ctx.Data["KeyID"] = err.(models.ErrGPGInvalidTokenSignature).ID ctx.Data["KeyID"] = err.(asymkey_model.ErrGPGInvalidTokenSignature).ID
ctx.RenderWithErr(ctx.Tr("settings.gpg_invalid_token_signature"), tplSettingsKeys, &form) ctx.RenderWithErr(ctx.Tr("settings.gpg_invalid_token_signature"), tplSettingsKeys, &form)
default: default:
ctx.ServerError("VerifyGPG", err) ctx.ServerError("VerifyGPG", err)
@ -147,11 +148,11 @@ func KeysPost(ctx *context.Context) {
ctx.Flash.Success(ctx.Tr("settings.verify_gpg_key_success", keyID)) ctx.Flash.Success(ctx.Tr("settings.verify_gpg_key_success", keyID))
ctx.Redirect(setting.AppSubURL + "/user/settings/keys") ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
case "ssh": case "ssh":
content, err := models.CheckPublicKeyString(form.Content) content, err := asymkey_model.CheckPublicKeyString(form.Content)
if err != nil { if err != nil {
if models.IsErrSSHDisabled(err) { if db.IsErrSSHDisabled(err) {
ctx.Flash.Info(ctx.Tr("settings.ssh_disabled")) ctx.Flash.Info(ctx.Tr("settings.ssh_disabled"))
} else if models.IsErrKeyUnableVerify(err) { } else if asymkey_model.IsErrKeyUnableVerify(err) {
ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key")) ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
} else { } else {
ctx.Flash.Error(ctx.Tr("form.invalid_ssh_key", err.Error())) ctx.Flash.Error(ctx.Tr("form.invalid_ssh_key", err.Error()))
@ -160,20 +161,20 @@ func KeysPost(ctx *context.Context) {
return return
} }
if _, err = models.AddPublicKey(ctx.User.ID, form.Title, content, 0); err != nil { if _, err = asymkey_model.AddPublicKey(ctx.User.ID, form.Title, content, 0); err != nil {
ctx.Data["HasSSHError"] = true ctx.Data["HasSSHError"] = true
switch { switch {
case models.IsErrKeyAlreadyExist(err): case asymkey_model.IsErrKeyAlreadyExist(err):
loadKeysData(ctx) loadKeysData(ctx)
ctx.Data["Err_Content"] = true ctx.Data["Err_Content"] = true
ctx.RenderWithErr(ctx.Tr("settings.ssh_key_been_used"), tplSettingsKeys, &form) ctx.RenderWithErr(ctx.Tr("settings.ssh_key_been_used"), tplSettingsKeys, &form)
case models.IsErrKeyNameAlreadyUsed(err): case asymkey_model.IsErrKeyNameAlreadyUsed(err):
loadKeysData(ctx) loadKeysData(ctx)
ctx.Data["Err_Title"] = true ctx.Data["Err_Title"] = true
ctx.RenderWithErr(ctx.Tr("settings.ssh_key_name_used"), tplSettingsKeys, &form) ctx.RenderWithErr(ctx.Tr("settings.ssh_key_name_used"), tplSettingsKeys, &form)
case models.IsErrKeyUnableVerify(err): case asymkey_model.IsErrKeyUnableVerify(err):
ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key")) ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
ctx.Redirect(setting.AppSubURL + "/user/settings/keys") ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
default: default:
@ -196,14 +197,14 @@ func DeleteKey(ctx *context.Context) {
switch ctx.FormString("type") { switch ctx.FormString("type") {
case "gpg": case "gpg":
if err := models.DeleteGPGKey(ctx.User, ctx.FormInt64("id")); err != nil { if err := asymkey_model.DeleteGPGKey(ctx.User, ctx.FormInt64("id")); err != nil {
ctx.Flash.Error("DeleteGPGKey: " + err.Error()) ctx.Flash.Error("DeleteGPGKey: " + err.Error())
} else { } else {
ctx.Flash.Success(ctx.Tr("settings.gpg_key_deletion_success")) ctx.Flash.Success(ctx.Tr("settings.gpg_key_deletion_success"))
} }
case "ssh": case "ssh":
keyID := ctx.FormInt64("id") keyID := ctx.FormInt64("id")
external, err := models.PublicKeyIsExternallyManaged(keyID) external, err := asymkey_model.PublicKeyIsExternallyManaged(keyID)
if err != nil { if err != nil {
ctx.ServerError("sshKeysExternalManaged", err) ctx.ServerError("sshKeysExternalManaged", err)
return return
@ -213,13 +214,13 @@ func DeleteKey(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/keys") ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
return return
} }
if err := models.DeletePublicKey(ctx.User, keyID); err != nil { if err := asymkey_service.DeletePublicKey(ctx.User, keyID); err != nil {
ctx.Flash.Error("DeletePublicKey: " + err.Error()) ctx.Flash.Error("DeletePublicKey: " + err.Error())
} else { } else {
ctx.Flash.Success(ctx.Tr("settings.ssh_key_deletion_success")) ctx.Flash.Success(ctx.Tr("settings.ssh_key_deletion_success"))
} }
case "principal": case "principal":
if err := models.DeletePublicKey(ctx.User, ctx.FormInt64("id")); err != nil { if err := asymkey_service.DeletePublicKey(ctx.User, ctx.FormInt64("id")); err != nil {
ctx.Flash.Error("DeletePublicKey: " + err.Error()) ctx.Flash.Error("DeletePublicKey: " + err.Error())
} else { } else {
ctx.Flash.Success(ctx.Tr("settings.ssh_principal_deletion_success")) ctx.Flash.Success(ctx.Tr("settings.ssh_principal_deletion_success"))
@ -234,32 +235,32 @@ func DeleteKey(ctx *context.Context) {
} }
func loadKeysData(ctx *context.Context) { func loadKeysData(ctx *context.Context) {
keys, err := models.ListPublicKeys(ctx.User.ID, db.ListOptions{}) keys, err := asymkey_model.ListPublicKeys(ctx.User.ID, db.ListOptions{})
if err != nil { if err != nil {
ctx.ServerError("ListPublicKeys", err) ctx.ServerError("ListPublicKeys", err)
return return
} }
ctx.Data["Keys"] = keys ctx.Data["Keys"] = keys
externalKeys, err := models.PublicKeysAreExternallyManaged(keys) externalKeys, err := asymkey_model.PublicKeysAreExternallyManaged(keys)
if err != nil { if err != nil {
ctx.ServerError("ListPublicKeys", err) ctx.ServerError("ListPublicKeys", err)
return return
} }
ctx.Data["ExternalKeys"] = externalKeys ctx.Data["ExternalKeys"] = externalKeys
gpgkeys, err := models.ListGPGKeys(ctx.User.ID, db.ListOptions{}) gpgkeys, err := asymkey_model.ListGPGKeys(db.DefaultContext, ctx.User.ID, db.ListOptions{})
if err != nil { if err != nil {
ctx.ServerError("ListGPGKeys", err) ctx.ServerError("ListGPGKeys", err)
return return
} }
ctx.Data["GPGKeys"] = gpgkeys ctx.Data["GPGKeys"] = gpgkeys
tokenToSign := models.VerificationToken(ctx.User, 1) tokenToSign := asymkey_model.VerificationToken(ctx.User, 1)
// generate a new aes cipher using the csrfToken // generate a new aes cipher using the csrfToken
ctx.Data["TokenToSign"] = tokenToSign ctx.Data["TokenToSign"] = tokenToSign
principals, err := models.ListPrincipalKeys(ctx.User.ID, db.ListOptions{}) principals, err := asymkey_model.ListPrincipalKeys(ctx.User.ID, db.ListOptions{})
if err != nil { if err != nil {
ctx.ServerError("ListPrincipalKeys", err) ctx.ServerError("ListPrincipalKeys", err)
return return

@ -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()
}

@ -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("..", ".."))
}

@ -1,15 +1,17 @@
// Copyright 2019 The Gitea Authors. All rights reserved. // Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package models package asymkey
import ( import (
"fmt"
"strings" "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/db"
"code.gitea.io/gitea/models/login" "code.gitea.io/gitea/models/login"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@ -63,6 +65,22 @@ func signingModeFromStrings(modeStrings []string) []signingMode {
return returnable 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 // SigningKey returns the KeyID and git Signature for the repo
func SigningKey(repoPath string) (string, *git.Signature) { func SigningKey(repoPath string) (string, *git.Signature) {
if setting.Repository.Signing.SigningKey == "none" { if setting.Repository.Signing.SigningKey == "none" {
@ -124,7 +142,7 @@ Loop:
case always: case always:
break Loop break Loop
case pubkey: case pubkey:
keys, err := ListGPGKeys(u.ID, db.ListOptions{}) keys, err := asymkey_model.ListGPGKeys(db.DefaultContext, u.ID, db.ListOptions{})
if err != nil { if err != nil {
return false, "", nil, err return false, "", nil, err
} }
@ -145,9 +163,9 @@ Loop:
} }
// SignWikiCommit determines if we should sign the commits to this repository wiki // 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) { func SignWikiCommit(repoWikiPath string, u *user_model.User) (bool, string, *git.Signature, error) {
rules := signingModeFromStrings(setting.Repository.Signing.Wiki) rules := signingModeFromStrings(setting.Repository.Signing.Wiki)
signingKey, sig := SigningKey(repo.WikiPath()) signingKey, sig := SigningKey(repoWikiPath)
if signingKey == "" { if signingKey == "" {
return false, "", nil, &ErrWontSign{noKey} return false, "", nil, &ErrWontSign{noKey}
} }
@ -160,7 +178,7 @@ Loop:
case always: case always:
break Loop break Loop
case pubkey: case pubkey:
keys, err := ListGPGKeys(u.ID, db.ListOptions{}) keys, err := asymkey_model.ListGPGKeys(db.DefaultContext, u.ID, db.ListOptions{})
if err != nil { if err != nil {
return false, "", nil, err return false, "", nil, err
} }
@ -176,7 +194,7 @@ Loop:
return false, "", nil, &ErrWontSign{twofa} return false, "", nil, &ErrWontSign{twofa}
} }
case parentSigned: case parentSigned:
gitRepo, err := git.OpenRepository(repo.WikiPath()) gitRepo, err := git.OpenRepository(repoWikiPath)
if err != nil { if err != nil {
return false, "", nil, err return false, "", nil, err
} }
@ -188,7 +206,7 @@ Loop:
if commit.Signature == nil { if commit.Signature == nil {
return false, "", nil, &ErrWontSign{parentSigned} return false, "", nil, &ErrWontSign{parentSigned}
} }
verification := ParseCommitWithSignature(commit) verification := asymkey_model.ParseCommitWithSignature(commit)
if !verification.Verified { if !verification.Verified {
return false, "", nil, &ErrWontSign{parentSigned} return false, "", nil, &ErrWontSign{parentSigned}
} }
@ -198,9 +216,9 @@ Loop:
} }
// SignCRUDAction determines if we should sign a CRUD commit to this repository // 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) { func SignCRUDAction(repoPath string, u *user_model.User, tmpBasePath, parentCommit string) (bool, string, *git.Signature, error) {
rules := signingModeFromStrings(setting.Repository.Signing.CRUDActions) rules := signingModeFromStrings(setting.Repository.Signing.CRUDActions)
signingKey, sig := SigningKey(repo.RepoPath()) signingKey, sig := SigningKey(repoPath)
if signingKey == "" { if signingKey == "" {
return false, "", nil, &ErrWontSign{noKey} return false, "", nil, &ErrWontSign{noKey}
} }
@ -213,7 +231,7 @@ Loop:
case always: case always:
break Loop break Loop
case pubkey: case pubkey:
keys, err := ListGPGKeys(u.ID, db.ListOptions{}) keys, err := asymkey_model.ListGPGKeys(db.DefaultContext, u.ID, db.ListOptions{})
if err != nil { if err != nil {
return false, "", nil, err return false, "", nil, err
} }
@ -241,7 +259,7 @@ Loop:
if commit.Signature == nil { if commit.Signature == nil {
return false, "", nil, &ErrWontSign{parentSigned} return false, "", nil, &ErrWontSign{parentSigned}
} }
verification := ParseCommitWithSignature(commit) verification := asymkey_model.ParseCommitWithSignature(commit)
if !verification.Verified { if !verification.Verified {
return false, "", nil, &ErrWontSign{parentSigned} return false, "", nil, &ErrWontSign{parentSigned}
} }
@ -249,3 +267,122 @@ Loop:
} }
return true, signingKey, sig, nil 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
}

@ -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()
}

@ -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)
}
}
}

@ -8,7 +8,7 @@ import (
"fmt" "fmt"
"strings" "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/db"
"code.gitea.io/gitea/models/login" "code.gitea.io/gitea/models/login"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -59,8 +59,8 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str
} }
if user != nil { if user != nil {
if isAttributeSSHPublicKeySet && models.SynchronizePublicKeys(user, source.loginSource, sr.SSHPublicKey) { if isAttributeSSHPublicKeySet && asymkey_model.SynchronizePublicKeys(user, source.loginSource, sr.SSHPublicKey) {
return user, models.RewriteAllPublicKeys() return user, asymkey_model.RewriteAllPublicKeys()
} }
return user, nil return user, nil
@ -95,8 +95,8 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str
mailer.SendRegisterNotifyMail(user) mailer.SendRegisterNotifyMail(user)
if isAttributeSSHPublicKeySet && models.AddPublicKeysBySource(user, source.loginSource, sr.SSHPublicKey) { if isAttributeSSHPublicKeySet && asymkey_model.AddPublicKeysBySource(user, source.loginSource, sr.SSHPublicKey) {
err = models.RewriteAllPublicKeys() err = asymkey_model.RewriteAllPublicKeys()
} }
if err == nil && len(source.AttributeAvatar) > 0 { if err == nil && len(source.AttributeAvatar) > 0 {

@ -10,7 +10,7 @@ import (
"sort" "sort"
"strings" "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/db"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@ -68,7 +68,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
log.Warn("SyncExternalUsers: Cancelled at update of %s before completed update of users", source.loginSource.Name) log.Warn("SyncExternalUsers: Cancelled at update of %s before completed update of users", source.loginSource.Name)
// Rewrite authorized_keys file if LDAP Public SSH Key attribute is set and any key was added or removed // Rewrite authorized_keys file if LDAP Public SSH Key attribute is set and any key was added or removed
if sshKeysNeedUpdate { if sshKeysNeedUpdate {
err = models.RewriteAllPublicKeys() err = asymkey_model.RewriteAllPublicKeys()
if err != nil { if err != nil {
log.Error("RewriteAllPublicKeys: %v", err) log.Error("RewriteAllPublicKeys: %v", err)
} }
@ -119,7 +119,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
if err == nil && isAttributeSSHPublicKeySet { if err == nil && isAttributeSSHPublicKeySet {
log.Trace("SyncExternalUsers[%s]: Adding LDAP Public SSH Keys for user %s", source.loginSource.Name, usr.Name) log.Trace("SyncExternalUsers[%s]: Adding LDAP Public SSH Keys for user %s", source.loginSource.Name, usr.Name)
if models.AddPublicKeysBySource(usr, source.loginSource, su.SSHPublicKey) { if asymkey_model.AddPublicKeysBySource(usr, source.loginSource, su.SSHPublicKey) {
sshKeysNeedUpdate = true sshKeysNeedUpdate = true
} }
} }
@ -129,7 +129,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
} }
} else if updateExisting { } else if updateExisting {
// Synchronize SSH Public Key if that attribute is set // Synchronize SSH Public Key if that attribute is set
if isAttributeSSHPublicKeySet && models.SynchronizePublicKeys(usr, source.loginSource, su.SSHPublicKey) { if isAttributeSSHPublicKeySet && asymkey_model.SynchronizePublicKeys(usr, source.loginSource, su.SSHPublicKey) {
sshKeysNeedUpdate = true sshKeysNeedUpdate = true
} }
@ -171,7 +171,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
// Rewrite authorized_keys file if LDAP Public SSH Key attribute is set and any key was added or removed // Rewrite authorized_keys file if LDAP Public SSH Key attribute is set and any key was added or removed
if sshKeysNeedUpdate { if sshKeysNeedUpdate {
err = models.RewriteAllPublicKeys() err = asymkey_model.RewriteAllPublicKeys()
if err != nil { if err != nil {
log.Error("RewriteAllPublicKeys: %v", err) log.Error("RewriteAllPublicKeys: %v", err)
} }

@ -9,6 +9,7 @@ import (
"time" "time"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/updatechecker" "code.gitea.io/gitea/modules/updatechecker"
@ -67,7 +68,7 @@ func registerRewriteAllPublicKeys() {
RunAtStart: false, RunAtStart: false,
Schedule: "@every 72h", Schedule: "@every 72h",
}, func(_ context.Context, _ *user_model.User, _ Config) error { }, func(_ context.Context, _ *user_model.User, _ Config) error {
return models.RewriteAllPublicKeys() return asymkey_model.RewriteAllPublicKeys()
}) })
} }
@ -77,7 +78,7 @@ func registerRewriteAllPrincipalKeys() {
RunAtStart: false, RunAtStart: false,
Schedule: "@every 72h", Schedule: "@every 72h",
}, func(_ context.Context, _ *user_model.User, _ Config) error { }, func(_ context.Context, _ *user_model.User, _ Config) error {
return models.RewriteAllPrincipalKeys() return asymkey_model.RewriteAllPrincipalKeys()
}) })
} }

@ -27,6 +27,7 @@ import (
"code.gitea.io/gitea/modules/references" "code.gitea.io/gitea/modules/references"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
asymkey_service "code.gitea.io/gitea/services/asymkey"
issue_service "code.gitea.io/gitea/services/issue" issue_service "code.gitea.io/gitea/services/issue"
) )
@ -218,7 +219,7 @@ func rawMerge(pr *models.PullRequest, doer *user_model.User, mergeStyle repo_mod
// Determine if we should sign // Determine if we should sign
signArg := "" signArg := ""
if git.CheckGitVersionAtLeast("1.7.9") == nil { if git.CheckGitVersionAtLeast("1.7.9") == nil {
sign, keyID, signer, _ := pr.SignMerge(doer, tmpBasePath, "HEAD", trackingBranch) sign, keyID, signer, _ := asymkey_service.SignMerge(pr, doer, tmpBasePath, "HEAD", trackingBranch)
if sign { if sign {
signArg = "-S" + keyID signArg = "-S" + keyID
if pr.BaseRepo.GetTrustModel() == repo_model.CommitterTrustModel || pr.BaseRepo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel { if pr.BaseRepo.GetTrustModel() == repo_model.CommitterTrustModel || pr.BaseRepo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel {
@ -553,7 +554,7 @@ func IsSignedIfRequired(pr *models.PullRequest, doer *user_model.User) (bool, er
return true, nil return true, nil
} }
sign, _, _, err := pr.SignMerge(doer, pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName()) sign, _, _, err := asymkey_service.SignMerge(pr, doer, pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName())
return sign, err return sign, err
} }

@ -14,7 +14,6 @@ import (
"strings" "strings"
"time" "time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
@ -171,7 +170,7 @@ func doArchive(r *ArchiveRequest) (*repo_model.RepoArchiver, error) {
rd.Close() rd.Close()
}() }()
var done = make(chan error) var done = make(chan error)
repo, err := models.LoadArchiverRepo(archiver) repo, err := repo_model.GetRepositoryByID(archiver.RepoID)
if err != nil { if err != nil {
return nil, fmt.Errorf("archiver.LoadRepo failed: %v", err) return nil, fmt.Errorf("archiver.LoadRepo failed: %v", err)
} }

@ -8,6 +8,7 @@ import (
"fmt" "fmt"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
@ -55,7 +56,7 @@ func CountDivergingCommits(repo *repo_model.Repository, branch string) (*git.Div
// GetPayloadCommitVerification returns the verification information of a commit // GetPayloadCommitVerification returns the verification information of a commit
func GetPayloadCommitVerification(commit *git.Commit) *structs.PayloadCommitVerification { func GetPayloadCommitVerification(commit *git.Commit) *structs.PayloadCommitVerification {
verification := &structs.PayloadCommitVerification{} verification := &structs.PayloadCommitVerification{}
commitVerification := models.ParseCommitWithSignature(commit) commitVerification := asymkey_model.ParseCommitWithSignature(commit)
if commit.Signature != nil { if commit.Signature != nil {
verification.Signature = commit.Signature.Signature verification.Signature = commit.Signature.Signature
verification.Payload = commit.Signature.Payload verification.Payload = commit.Signature.Payload

@ -20,6 +20,7 @@ import (
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
asymkey_service "code.gitea.io/gitea/services/asymkey"
"code.gitea.io/gitea/services/gitdiff" "code.gitea.io/gitea/services/gitdiff"
) )
@ -217,7 +218,7 @@ func (t *TemporaryUploadRepository) CommitTreeWithDate(author, committer *user_m
// Determine if we should sign // Determine if we should sign
if git.CheckGitVersionAtLeast("1.7.9") == nil { if git.CheckGitVersionAtLeast("1.7.9") == nil {
sign, keyID, signer, _ := models.SignCRUDAction(t.repo, author, t.basePath, "HEAD") sign, keyID, signer, _ := asymkey_service.SignCRUDAction(t.repo.RepoPath(), author, t.basePath, "HEAD")
if sign { if sign {
args = append(args, "-S"+keyID) args = append(args, "-S"+keyID)
if t.repo.GetTrustModel() == repo_model.CommitterTrustModel || t.repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel { if t.repo.GetTrustModel() == repo_model.CommitterTrustModel || t.repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel {

@ -21,6 +21,7 @@ import (
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
asymkey_service "code.gitea.io/gitea/services/asymkey"
repo_service "code.gitea.io/gitea/services/repository" repo_service "code.gitea.io/gitea/services/repository"
stdcharset "golang.org/x/net/html/charset" stdcharset "golang.org/x/net/html/charset"
@ -458,9 +459,9 @@ func VerifyBranchProtection(repo *repo_model.Repository, doer *user_model.User,
} }
} }
if protectedBranch.RequireSignedCommits { if protectedBranch.RequireSignedCommits {
_, _, _, err := models.SignCRUDAction(repo, doer, repo.RepoPath(), branchName) _, _, _, err := asymkey_service.SignCRUDAction(repo.RepoPath(), doer, repo.RepoPath(), branchName)
if err != nil { if err != nil {
if !models.IsErrWontSign(err) { if !asymkey_service.IsErrWontSign(err) {
return err return err
} }
return models.ErrUserCannotCommit{ return models.ErrUserCannotCommit{

@ -31,13 +31,15 @@ func CreateRepository(doer, owner *user_model.User, opts models.CreateRepoOption
} }
// DeleteRepository deletes a repository for a user or organization. // DeleteRepository deletes a repository for a user or organization.
func DeleteRepository(doer *user_model.User, repo *repo_model.Repository) error { func DeleteRepository(doer *user_model.User, repo *repo_model.Repository, notify bool) error {
if err := pull_service.CloseRepoBranchesPulls(doer, repo); err != nil { if err := pull_service.CloseRepoBranchesPulls(doer, repo); err != nil {
log.Error("CloseRepoBranchesPulls failed: %v", err) log.Error("CloseRepoBranchesPulls failed: %v", err)
} }
if notify {
// If the repo itself has webhooks, we need to trigger them before deleting it... // If the repo itself has webhooks, we need to trigger them before deleting it...
notification.NotifyDeleteRepository(doer, repo) notification.NotifyDeleteRepository(doer, repo)
}
err := models.DeleteRepository(doer, repo.OwnerID, repo.ID) err := models.DeleteRepository(doer, repo.OwnerID, repo.ID)
return err return err

@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
admin_model "code.gitea.io/gitea/models/admin" 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/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -31,11 +32,11 @@ func DeleteUser(u *user_model.User) error {
return fmt.Errorf("%s is an organization not a user", u.Name) return fmt.Errorf("%s is an organization not a user", u.Name)
} }
ctx, commiter, err := db.TxContext() ctx, committer, err := db.TxContext()
if err != nil { if err != nil {
return err return err
} }
defer commiter.Close() defer committer.Close()
// Note: A user owns any repository or belongs to any organization // Note: A user owns any repository or belongs to any organization
// cannot perform delete operation. // cannot perform delete operation.
@ -60,14 +61,15 @@ func DeleteUser(u *user_model.User) error {
return fmt.Errorf("DeleteUser: %v", err) return fmt.Errorf("DeleteUser: %v", err)
} }
if err := commiter.Commit(); err != nil { if err := committer.Commit(); err != nil {
return err return err
} }
committer.Close()
if err = models.RewriteAllPublicKeys(); err != nil { if err = asymkey_model.RewriteAllPublicKeys(); err != nil {
return err return err
} }
if err = models.RewriteAllPrincipalKeys(); err != nil { if err = asymkey_model.RewriteAllPrincipalKeys(); err != nil {
return err return err
} }

@ -22,6 +22,7 @@ import (
repo_module "code.gitea.io/gitea/modules/repository" repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/sync" "code.gitea.io/gitea/modules/sync"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
asymkey_service "code.gitea.io/gitea/services/asymkey"
) )
var ( var (
@ -225,7 +226,7 @@ func updateWikiPage(doer *user_model.User, repo *repo_model.Repository, oldWikiN
committer := doer.NewGitSig() committer := doer.NewGitSig()
sign, signingKey, signer, _ := models.SignWikiCommit(repo, doer) sign, signingKey, signer, _ := asymkey_service.SignWikiCommit(repo.WikiPath(), doer)
if sign { if sign {
commitTreeOpts.KeyID = signingKey commitTreeOpts.KeyID = signingKey
if repo.GetTrustModel() == repo_model.CommitterTrustModel || repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel { if repo.GetTrustModel() == repo_model.CommitterTrustModel || repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel {
@ -343,7 +344,7 @@ func DeleteWikiPage(doer *user_model.User, repo *repo_model.Repository, wikiName
committer := doer.NewGitSig() committer := doer.NewGitSig()
sign, signingKey, signer, _ := models.SignWikiCommit(repo, doer) sign, signingKey, signer, _ := asymkey_service.SignWikiCommit(repo.WikiPath(), doer)
if sign { if sign {
commitTreeOpts.KeyID = signingKey commitTreeOpts.KeyID = signingKey
if repo.GetTrustModel() == repo_model.CommitterTrustModel || repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel { if repo.GetTrustModel() == repo_model.CommitterTrustModel || repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel {

Loading…
Cancel
Save