diff --git a/models/auth/secret.go b/models/auth/secret.go
new file mode 100644
index 0000000000..32b1c48e9c
--- /dev/null
+++ b/models/auth/secret.go
@@ -0,0 +1,54 @@
+// Copyright 2022 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 auth
+
+import (
+ "fmt"
+ "regexp"
+
+ "code.gitea.io/gitea/modules/timeutil"
+)
+
+type ErrSecretNameInvalid struct {
+ Name string
+}
+
+func (err ErrSecretNameInvalid) Error() string {
+ return fmt.Sprintf("secret name %s is invalid", err.Name)
+}
+
+type ErrSecretDataInvalid struct {
+ Data string
+}
+
+func (err ErrSecretDataInvalid) Error() string {
+ return fmt.Sprintf("secret data %s is invalid", err.Data)
+}
+
+var nameRE = regexp.MustCompile("[^a-zA-Z0-9-_.]+")
+
+type Secret struct {
+ ID int64
+ UserID int64 `xorm:"index"`
+ RepoID int64 `xorm:"index"`
+ Name string
+ Data string
+ PullRequest bool
+ CreatedUnix timeutil.TimeStamp
+}
+
+ // Validate validates the required fields and formats.
+func (s *Secret) Validate() error {
+ switch {
+ case len(s.Name) == 0:
+ return ErrSecretNameInvalid{Name: s.Name}
+ case len(s.Data) == 0:
+ return ErrSecretDataInvalid{Data: s.Data}
+ case nameRE.MatchString(s.Name):
+ return ErrSecretNameInvalid{Name: s.Name}
+ default:
+ return nil
+ }
+}
diff --git a/models/db/search.go b/models/db/search.go
index 704a48ed1e..f4bbd9d3fa 100644
--- a/models/db/search.go
+++ b/models/db/search.go
@@ -4,6 +4,12 @@
package db
+import (
+ "context"
+
+ "xorm.io/builder"
+)
+
// SearchOrderBy is used to sort the result
type SearchOrderBy string
@@ -28,3 +34,14 @@ const (
SearchOrderByForks SearchOrderBy = "num_forks ASC"
SearchOrderByForksReverse SearchOrderBy = "num_forks DESC"
)
+
+func FindObjects[Object any](ctx context.Context, cond builder.Cond, opts *ListOptions, objects *[]*Object) error {
+ sess := GetEngine(ctx).Where(cond)
+ if opts != nil && opts.PageSize > 0 {
+ if opts.Page < 1 {
+ opts.Page = 1
+ }
+ sess.Limit(opts.PageSize, opts.PageSize * (opts.Page - 1))
+ }
+ return sess.Find(objects)
+}
diff --git a/routers/web/repo/setting.go b/routers/web/repo/setting.go
index 69088e1821..c479008736 100644
--- a/routers/web/repo/setting.go
+++ b/routers/web/repo/setting.go
@@ -46,6 +46,7 @@ import (
org_service "code.gitea.io/gitea/services/org"
repo_service "code.gitea.io/gitea/services/repository"
wiki_service "code.gitea.io/gitea/services/wiki"
+ secret_service "code.gitea.io/gitea/services/secrets"
)
const (
@@ -1113,6 +1114,13 @@ func DeployKeys(ctx *context.Context) {
}
ctx.Data["Deploykeys"] = keys
+ tokens, err := secret_service.FindRepoSecrets(ctx, ctx.Repo.Repository.ID)
+ if err != nil {
+ ctx.ServerError("FindRepoSecrets", err)
+ return
+ }
+ ctx.Data["Tokens"] = tokens
+
ctx.HTML(http.StatusOK, tplDeployKeys)
}
diff --git a/services/secrets/secrets.go b/services/secrets/secrets.go
index 0459855781..4f113958d4 100644
--- a/services/secrets/secrets.go
+++ b/services/secrets/secrets.go
@@ -5,9 +5,14 @@
package secrets
import (
+ "context"
"fmt"
+ auth_model "code.gitea.io/gitea/models/auth"
+ "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/setting"
+
+ "xorm.io/builder"
)
// MasterKeyProviderType is the type of master key provider
@@ -96,3 +101,45 @@ func DecryptString(enc string) (string, error) {
return encProvider.DecryptString(enc, key)
}
+
+func InsertRepoSecret(ctx context.Context, repoID int64, key, data string, pullRequest bool) error {
+ v, err := EncryptString( data)
+ if err != nil {
+ return err
+ }
+return db.Insert(ctx, &auth_model.Secret{
+ RepoID: repoID,
+ Name: key,
+ Data: v,
+ PullRequest: pullRequest,
+})
+}
+
+func InsertOrgSecret(ctx context.Context, userID int64, key, data string, pullRequest bool) error {
+ v, err := EncryptString(data)
+ if err != nil {
+ return err
+ }
+return db.Insert(ctx, &auth_model.Secret{
+ UserID: userID,
+ Name: key,
+ Data: v,
+ PullRequest: pullRequest,
+})
+}
+
+func DeleteSecretByID(ctx context.Context, id int64) error {
+_, err := db.DeleteByBean(ctx, &auth_model.Secret{ID: id})
+return err
+}
+
+
+func FindRepoSecrets(ctx context.Context,repoID int64) ([]*auth_model.Secret, error) {
+ var res []*auth_model.Secret
+ return res, db.FindObjects(ctx, builder.Eq{"repo_id": repoID}, nil,&res)
+}
+
+func FindUserSecrets(ctx context.Context, userID int64) ([]*auth_model.Secret, error) {
+ var res []*auth_model.Secret
+ return res, db.FindObjects(ctx, builder.Eq{"user_id": userID}, nil,&res)
+}
diff --git a/templates/repo/settings/deploy_keys.tmpl b/templates/repo/settings/deploy_keys.tmpl
index 44c916eefb..f656640cad 100644
--- a/templates/repo/settings/deploy_keys.tmpl
+++ b/templates/repo/settings/deploy_keys.tmpl
@@ -75,6 +75,8 @@
{{end}}
+
+ {{template "settings/tokens" .}}
diff --git a/templates/repo/settings/tokens.tmpl b/templates/repo/settings/tokens.tmpl
new file mode 100644
index 0000000000..ed85b71c1b
--- /dev/null
+++ b/templates/repo/settings/tokens.tmpl
@@ -0,0 +1,73 @@
+
+ {{template "base/alert" .}}
+
+
+
+ {{if .Deploykeys}}
+
+ {{range .Deploykeys}}
+
+
+
+
+
+ {{svg "octicon-key" 32}}
+
+
+
{{.Name}}
+
+ {{.Fingerprint}}
+
+
+ {{$.locale.Tr "settings.add_on"}} {{.CreatedUnix.FormatShort}} — {{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{.UpdatedUnix.FormatShort}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}} - {{$.locale.Tr "settings.can_read_info"}}{{if not .IsReadOnly}} / {{$.locale.Tr "settings.can_write_info"}} {{end}}
+
+
+
+ {{end}}
+
+ {{else}}
+ {{.locale.Tr "repo.settings.no_deploy_keys"}}
+ {{end}}
+
+