aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKN4CK3R <admin@oldschoolhack.me>2023-02-01 13:53:04 +0100
committerGitHub <noreply@github.com>2023-02-01 20:53:04 +0800
commit5882e179a93a00a0635c6c578ec6d43ce68d687b (patch)
treee1bba3b2d88f74e95f05214bedebc616e2452805
parent9f9a1ce92292739c3d0b5ee4bb654d883eb3b869 (diff)
downloadgitea-5882e179a93a00a0635c6c578ec6d43ce68d687b.tar.gz
gitea-5882e179a93a00a0635c6c578ec6d43ce68d687b.zip
Add user secrets (#22191)
Fixes #22183 Replaces #22187 This PR adds secrets for users. I refactored the files for organizations and repos to use the same logic and templates. I splitted the secrets from deploy keys again and reverted the fix from #22187. --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
-rw-r--r--docs/content/doc/secrets/overview.en-us.md16
-rw-r--r--options/locale/locale_en-US.ini2
-rw-r--r--routers/web/org/setting.go51
-rw-r--r--routers/web/org/setting_secrets.go48
-rw-r--r--routers/web/repo/setting.go39
-rw-r--r--routers/web/repo/setting_secrets.go46
-rw-r--r--routers/web/shared/secrets/secrets.go54
-rw-r--r--routers/web/user/setting/secrets.go45
-rw-r--r--routers/web/web.go15
-rw-r--r--templates/org/settings/secrets.tmpl70
-rw-r--r--templates/repo/settings/deploy_keys.tmpl6
-rw-r--r--templates/repo/settings/nav.tmpl3
-rw-r--r--templates/repo/settings/navbar.tmpl3
-rw-r--r--templates/repo/settings/secrets.tmpl86
-rw-r--r--templates/shared/secrets/add_list.tmpl68
-rw-r--r--templates/user/settings/navbar.tmpl3
-rw-r--r--templates/user/settings/secrets.tmpl10
17 files changed, 310 insertions, 255 deletions
diff --git a/docs/content/doc/secrets/overview.en-us.md b/docs/content/doc/secrets/overview.en-us.md
index 1a88d6cfbc..21fb65f98d 100644
--- a/docs/content/doc/secrets/overview.en-us.md
+++ b/docs/content/doc/secrets/overview.en-us.md
@@ -1,6 +1,6 @@
---
date: "2022-12-19T21:26:00+08:00"
-title: "Encrypted secrets"
+title: "Secrets"
slug: "secrets/overview"
draft: false
toc: false
@@ -12,24 +12,24 @@ menu:
identifier: "overview"
---
-# Encrypted secrets
+# Secrets
-Encrypted secrets allow you to store sensitive information in your organization or repository.
+Secrets allow you to store sensitive information in your user, organization or repository.
Secrets are available on Gitea 1.19+.
# Naming your secrets
The following rules apply to secret names:
-Secret names can only contain alphanumeric characters (`[a-z]`, `[A-Z]`, `[0-9]`) or underscores (`_`). Spaces are not allowed.
+- Secret names can only contain alphanumeric characters (`[a-z]`, `[A-Z]`, `[0-9]`) or underscores (`_`). Spaces are not allowed.
-Secret names must not start with the `GITHUB_` and `GITEA_` prefix.
+- Secret names must not start with the `GITHUB_` and `GITEA_` prefix.
-Secret names must not start with a number.
+- Secret names must not start with a number.
-Secret names are not case-sensitive.
+- Secret names are not case-sensitive.
-Secret names must be unique at the level they are created at.
+- Secret names must be unique at the level they are created at.
For example, a secret created at the repository level must have a unique name in that repository, and a secret created at the organization level must have a unique name at that level.
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 24809c5549..8a48a68b17 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -3254,7 +3254,7 @@ creation.value_placeholder = Input any content. Whitespace at the start and end
creation.success = The secret '%s' has been added.
creation.failed = Failed to add secret.
deletion = Remove secret
-deletion.description = Removing a secret will revoke its access to repositories. Continue?
+deletion.description = Removing a secret is permanent and cannot be undone. Continue?
deletion.success = The secret has been removed.
deletion.failed = Failed to remove secret.
diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go
index 80f5707245..5c9b7967c3 100644
--- a/routers/web/org/setting.go
+++ b/routers/web/org/setting.go
@@ -12,7 +12,6 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
- secret_model "code.gitea.io/gitea/models/secret"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/base"
@@ -38,8 +37,6 @@ const (
tplSettingsHooks base.TplName = "org/settings/hooks"
// tplSettingsLabels template path for render labels settings
tplSettingsLabels base.TplName = "org/settings/labels"
- // tplSettingsSecrets template path for render secrets settings
- tplSettingsSecrets base.TplName = "org/settings/secrets"
// tplSettingsRunners template path for render runners settings
tplSettingsRunners base.TplName = "org/settings/runners"
// tplSettingsRunnersEdit template path for render runners edit settings
@@ -253,51 +250,3 @@ func Labels(ctx *context.Context) {
ctx.Data["LabelTemplates"] = repo_module.LabelTemplates
ctx.HTML(http.StatusOK, tplSettingsLabels)
}
-
-// Secrets render organization secrets page
-func Secrets(ctx *context.Context) {
- ctx.Data["Title"] = ctx.Tr("repo.secrets")
- ctx.Data["PageIsOrgSettings"] = true
- ctx.Data["PageIsOrgSettingsSecrets"] = true
-
- secrets, err := secret_model.FindSecrets(ctx, secret_model.FindSecretsOptions{OwnerID: ctx.Org.Organization.ID})
- if err != nil {
- ctx.ServerError("FindSecrets", err)
- return
- }
- ctx.Data["Secrets"] = secrets
-
- ctx.HTML(http.StatusOK, tplSettingsSecrets)
-}
-
-// SecretsPost add secrets
-func SecretsPost(ctx *context.Context) {
- form := web.GetForm(ctx).(*forms.AddSecretForm)
-
- _, err := secret_model.InsertEncryptedSecret(ctx, ctx.Org.Organization.ID, 0, form.Title, form.Content)
- if err != nil {
- ctx.Flash.Error(ctx.Tr("secrets.creation.failed"))
- log.Error("validate secret: %v", err)
- ctx.Redirect(ctx.Org.OrgLink + "/settings/secrets")
- return
- }
-
- log.Trace("Org %d: secret added", ctx.Org.Organization.ID)
- ctx.Flash.Success(ctx.Tr("secrets.creation.success", form.Title))
- ctx.Redirect(ctx.Org.OrgLink + "/settings/secrets")
-}
-
-// SecretsDelete delete secrets
-func SecretsDelete(ctx *context.Context) {
- id := ctx.FormInt64("id")
- if _, err := db.DeleteByBean(ctx, &secret_model.Secret{ID: id}); err != nil {
- ctx.Flash.Error(ctx.Tr("secrets.deletion.failed"))
- log.Error("delete secret %d: %v", id, err)
- } else {
- ctx.Flash.Success(ctx.Tr("secrets.deletion.success"))
- }
-
- ctx.JSON(http.StatusOK, map[string]interface{}{
- "redirect": ctx.Org.OrgLink + "/settings/secrets",
- })
-}
diff --git a/routers/web/org/setting_secrets.go b/routers/web/org/setting_secrets.go
new file mode 100644
index 0000000000..1cdbe35f32
--- /dev/null
+++ b/routers/web/org/setting_secrets.go
@@ -0,0 +1,48 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package org
+
+import (
+ "net/http"
+
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/context"
+ shared "code.gitea.io/gitea/routers/web/shared/secrets"
+)
+
+const (
+ tplSettingsSecrets base.TplName = "org/settings/secrets"
+)
+
+// Secrets render organization secrets page
+func Secrets(ctx *context.Context) {
+ ctx.Data["Title"] = ctx.Tr("secrets.secrets")
+ ctx.Data["PageIsOrgSettings"] = true
+ ctx.Data["PageIsOrgSettingsSecrets"] = true
+
+ shared.SetSecretsContext(ctx, ctx.ContextUser.ID, 0)
+ if ctx.Written() {
+ return
+ }
+
+ ctx.HTML(http.StatusOK, tplSettingsSecrets)
+}
+
+// SecretsPost add secrets
+func SecretsPost(ctx *context.Context) {
+ shared.PerformSecretsPost(
+ ctx,
+ ctx.ContextUser.ID,
+ 0,
+ ctx.Org.OrgLink+"/settings/secrets",
+ )
+}
+
+// SecretsDelete delete secrets
+func SecretsDelete(ctx *context.Context) {
+ shared.PerformSecretsDelete(
+ ctx,
+ ctx.Org.OrgLink+"/settings/secrets",
+ )
+}
diff --git a/routers/web/repo/setting.go b/routers/web/repo/setting.go
index 73887195e6..e970dab3eb 100644
--- a/routers/web/repo/setting.go
+++ b/routers/web/repo/setting.go
@@ -19,7 +19,6 @@ import (
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
- secret_model "code.gitea.io/gitea/models/secret"
unit_model "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
@@ -1131,33 +1130,9 @@ func DeployKeys(ctx *context.Context) {
}
ctx.Data["Deploykeys"] = keys
- secrets, err := secret_model.FindSecrets(ctx, secret_model.FindSecretsOptions{RepoID: ctx.Repo.Repository.ID})
- if err != nil {
- ctx.ServerError("FindSecrets", err)
- return
- }
- ctx.Data["Secrets"] = secrets
-
ctx.HTML(http.StatusOK, tplDeployKeys)
}
-// SecretsPost response for creating a new secret
-func SecretsPost(ctx *context.Context) {
- form := web.GetForm(ctx).(*forms.AddSecretForm)
-
- _, err := secret_model.InsertEncryptedSecret(ctx, 0, ctx.Repo.Repository.ID, form.Title, form.Content)
- if err != nil {
- ctx.Flash.Error(ctx.Tr("secrets.creation.failed"))
- log.Error("validate secret: %v", err)
- ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys")
- return
- }
-
- log.Trace("Secret added: %d", ctx.Repo.Repository.ID)
- ctx.Flash.Success(ctx.Tr("secrets.creation.success", form.Title))
- ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys")
-}
-
// DeployKeysPost response for adding a deploy key of a repository
func DeployKeysPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.AddKeyForm)
@@ -1219,20 +1194,6 @@ func DeployKeysPost(ctx *context.Context) {
ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys")
}
-func DeleteSecret(ctx *context.Context) {
- id := ctx.FormInt64("id")
- if _, err := db.DeleteByBean(ctx, &secret_model.Secret{ID: id}); err != nil {
- ctx.Flash.Error(ctx.Tr("secrets.deletion.failed"))
- log.Error("delete secret %d: %v", id, err)
- } else {
- ctx.Flash.Success(ctx.Tr("secrets.deletion.success"))
- }
-
- ctx.JSON(http.StatusOK, map[string]interface{}{
- "redirect": ctx.Repo.RepoLink + "/settings/keys",
- })
-}
-
// DeleteDeployKey response for deleting a deploy key
func DeleteDeployKey(ctx *context.Context) {
if err := asymkey_service.DeleteDeployKey(ctx.Doer, ctx.FormInt64("id")); err != nil {
diff --git a/routers/web/repo/setting_secrets.go b/routers/web/repo/setting_secrets.go
new file mode 100644
index 0000000000..c42dee583b
--- /dev/null
+++ b/routers/web/repo/setting_secrets.go
@@ -0,0 +1,46 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repo
+
+import (
+ "net/http"
+
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/setting"
+ shared "code.gitea.io/gitea/routers/web/shared/secrets"
+)
+
+const (
+ tplSecrets base.TplName = "repo/settings/secrets"
+)
+
+func Secrets(ctx *context.Context) {
+ ctx.Data["Title"] = ctx.Tr("secrets.secrets")
+ ctx.Data["PageIsSettingsSecrets"] = true
+ ctx.Data["DisableSSH"] = setting.SSH.Disabled
+
+ shared.SetSecretsContext(ctx, 0, ctx.Repo.Repository.ID)
+ if ctx.Written() {
+ return
+ }
+
+ ctx.HTML(http.StatusOK, tplSecrets)
+}
+
+func SecretsPost(ctx *context.Context) {
+ shared.PerformSecretsPost(
+ ctx,
+ 0,
+ ctx.Repo.Repository.ID,
+ ctx.Repo.RepoLink+"/settings/secrets",
+ )
+}
+
+func DeleteSecret(ctx *context.Context) {
+ shared.PerformSecretsDelete(
+ ctx,
+ ctx.Repo.RepoLink+"/settings/secrets",
+ )
+}
diff --git a/routers/web/shared/secrets/secrets.go b/routers/web/shared/secrets/secrets.go
new file mode 100644
index 0000000000..e242c5e816
--- /dev/null
+++ b/routers/web/shared/secrets/secrets.go
@@ -0,0 +1,54 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package secrets
+
+import (
+ "net/http"
+
+ "code.gitea.io/gitea/models/db"
+ secret_model "code.gitea.io/gitea/models/secret"
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/web"
+ "code.gitea.io/gitea/services/forms"
+)
+
+func SetSecretsContext(ctx *context.Context, ownerID, repoID int64) {
+ secrets, err := secret_model.FindSecrets(ctx, secret_model.FindSecretsOptions{OwnerID: ownerID, RepoID: repoID})
+ if err != nil {
+ ctx.ServerError("FindSecrets", err)
+ return
+ }
+
+ ctx.Data["Secrets"] = secrets
+}
+
+func PerformSecretsPost(ctx *context.Context, ownerID, repoID int64, redirectURL string) {
+ form := web.GetForm(ctx).(*forms.AddSecretForm)
+
+ s, err := secret_model.InsertEncryptedSecret(ctx, ownerID, repoID, form.Title, form.Content)
+ if err != nil {
+ log.Error("InsertEncryptedSecret: %v", err)
+ ctx.Flash.Error(ctx.Tr("secrets.creation.failed"))
+ } else {
+ ctx.Flash.Success(ctx.Tr("secrets.creation.success", s.Name))
+ }
+
+ ctx.Redirect(redirectURL)
+}
+
+func PerformSecretsDelete(ctx *context.Context, redirectURL string) {
+ id := ctx.FormInt64("id")
+
+ if _, err := db.DeleteByBean(ctx, &secret_model.Secret{ID: id}); err != nil {
+ log.Error("Delete secret %d failed: %v", id, err)
+ ctx.Flash.Error(ctx.Tr("secrets.deletion.failed"))
+ } else {
+ ctx.Flash.Success(ctx.Tr("secrets.deletion.success"))
+ }
+
+ ctx.JSON(http.StatusOK, map[string]interface{}{
+ "redirect": redirectURL,
+ })
+}
diff --git a/routers/web/user/setting/secrets.go b/routers/web/user/setting/secrets.go
new file mode 100644
index 0000000000..3a57897d8f
--- /dev/null
+++ b/routers/web/user/setting/secrets.go
@@ -0,0 +1,45 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package setting
+
+import (
+ "net/http"
+
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/setting"
+ shared "code.gitea.io/gitea/routers/web/shared/secrets"
+)
+
+const (
+ tplSettingsSecrets base.TplName = "user/settings/secrets"
+)
+
+func Secrets(ctx *context.Context) {
+ ctx.Data["Title"] = ctx.Tr("secrets.secrets")
+ ctx.Data["PageIsSettingsSecrets"] = true
+
+ shared.SetSecretsContext(ctx, ctx.Doer.ID, 0)
+ if ctx.Written() {
+ return
+ }
+
+ ctx.HTML(http.StatusOK, tplSettingsSecrets)
+}
+
+func SecretsPost(ctx *context.Context) {
+ shared.PerformSecretsPost(
+ ctx,
+ ctx.Doer.ID,
+ 0,
+ setting.AppSubURL+"/user/settings/secrets",
+ )
+}
+
+func SecretsDelete(ctx *context.Context) {
+ shared.PerformSecretsDelete(
+ ctx,
+ setting.AppSubURL+"/user/settings/secrets",
+ )
+}
diff --git a/routers/web/web.go b/routers/web/web.go
index 88a12df19d..b7128fc3a9 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -469,6 +469,11 @@ func RegisterRoutes(m *web.Route) {
})
})
}, packagesEnabled)
+ m.Group("/secrets", func() {
+ m.Get("", user_setting.Secrets)
+ m.Post("", web.Bind(forms.AddSecretForm{}), user_setting.SecretsPost)
+ m.Post("/delete", user_setting.SecretsDelete)
+ })
m.Get("/organization", user_setting.Organization)
m.Get("/repos", user_setting.Repos)
m.Post("/repos/unadopted", user_setting.AdoptOrDeleteRepository)
@@ -982,10 +987,12 @@ func RegisterRoutes(m *web.Route) {
m.Combo("").Get(repo.DeployKeys).
Post(web.Bind(forms.AddKeyForm{}), repo.DeployKeysPost)
m.Post("/delete", repo.DeleteDeployKey)
- m.Group("/secrets", func() {
- m.Post("", web.Bind(forms.AddSecretForm{}), repo.SecretsPost)
- m.Post("/delete", repo.DeleteSecret)
- })
+ })
+
+ m.Group("/secrets", func() {
+ m.Get("", repo.Secrets)
+ m.Post("", web.Bind(forms.AddSecretForm{}), repo.SecretsPost)
+ m.Post("/delete", repo.DeleteSecret)
})
m.Group("/lfs", func() {
diff --git a/templates/org/settings/secrets.tmpl b/templates/org/settings/secrets.tmpl
index dd2a437b75..70add15f50 100644
--- a/templates/org/settings/secrets.tmpl
+++ b/templates/org/settings/secrets.tmpl
@@ -6,78 +6,10 @@
{{template "org/settings/navbar" .}}
<div class="ui twelve wide column content">
{{template "base/alert" .}}
- <h4 class="ui top attached header">
- {{.locale.Tr "secrets.secrets"}}
- <div class="ui right">
- <div class="ui primary tiny show-panel button" data-panel="#add-secret-panel">{{.locale.Tr "secrets.creation"}}</div>
- </div>
- </h4>
- <div class="ui attached segment">
- <div class="{{if not .HasError}}hide {{end}}mb-4" id="add-secret-panel">
- <form class="ui form" action="{{.Link}}" method="post">
- {{.CsrfTokenHtml}}
- <div class="field">
- {{.locale.Tr "secrets.description"}}
- </div>
- <div class="field{{if .Err_Title}} error{{end}}">
- <label for="secret-title">{{.locale.Tr "secrets.name"}}</label>
- <input id="secret-title" name="title" value="{{.title}}" autofocus required pattern="^[a-zA-Z_][a-zA-Z0-9_]*$" placeholder="{{.locale.Tr "secrets.creation.name_placeholder"}}">
- </div>
- <div class="field{{if .Err_Content}} error{{end}}">
- <label for="secret-content">{{.locale.Tr "secrets.value"}}</label>
- <textarea id="secret-content" name="content" required placeholder="{{.locale.Tr "secrets.creation.value_placeholder"}}">{{.content}}</textarea>
- </div>
- <button class="ui green button">
- {{.locale.Tr "secrets.creation"}}
- </button>
- <button class="ui hide-panel button" data-panel="#add-secret-panel">
- {{.locale.Tr "cancel"}}
- </button>
- </form>
- </div>
- {{if .Secrets}}
- <div class="ui key list">
- {{range .Secrets}}
- <div class="item">
- <div class="right floated content">
- <button class="ui red tiny button delete-button" data-url="{{$.Link}}/delete" data-id="{{.ID}}">
- {{$.locale.Tr "settings.delete_key"}}
- </button>
- </div>
- <div class="left floated content">
- <i>{{svg "octicon-key" 32}}</i>
- </div>
- <div class="content">
- <strong>{{.Name}}</strong>
- <div class="print meta">******</div>
- <div class="activity meta">
- <i>
- {{$.locale.Tr "settings.add_on"}}
- <span>{{.CreatedUnix.FormatShort}}</span>
- </i>
- </div>
- </div>
- </div>
- {{end}}
- </div>
- {{else}}
- {{.locale.Tr "secrets.none"}}
- {{end}}
- </div>
+ {{template "shared/secrets/add_list" .}}
</div>
</div>
</div>
</div>
-<div class="ui small basic delete modal">
- <div class="ui header">
- {{svg "octicon-trash" 16 "mr-2"}}
- {{.locale.Tr "secrets.deletion"}}
- </div>
- <div class="content">
- <p>{{.locale.Tr "secrets.deletion.description"}}</p>
- </div>
- {{template "base/delete_modal_actions" .}}
-</div>
-
{{template "base/footer" .}}
diff --git a/templates/repo/settings/deploy_keys.tmpl b/templates/repo/settings/deploy_keys.tmpl
index 32a1258b3a..44c916eefb 100644
--- a/templates/repo/settings/deploy_keys.tmpl
+++ b/templates/repo/settings/deploy_keys.tmpl
@@ -51,7 +51,7 @@
{{range .Deploykeys}}
<div class="item">
<div class="right floated content">
- <button class="ui red tiny button delete-button" data-modal-id="delete-deploy_keys-modal" data-url="{{$.Link}}/delete" data-id="{{.ID}}">
+ <button class="ui red tiny button delete-button" data-url="{{$.Link}}/delete" data-id="{{.ID}}">
{{$.locale.Tr "settings.delete_key"}}
</button>
</div>
@@ -75,11 +75,9 @@
{{end}}
</div>
</div>
- <br/>
- {{template "repo/settings/secrets" .}}
</div>
-<div class="ui small basic delete modal" id="delete-deploy_keys-modal">
+<div class="ui small basic delete modal">
<div class="ui icon header">
{{svg "octicon-trash"}}
{{.locale.Tr "repo.settings.deploy_key_deletion"}}
diff --git a/templates/repo/settings/nav.tmpl b/templates/repo/settings/nav.tmpl
index 3c00c5e188..3156d9b159 100644
--- a/templates/repo/settings/nav.tmpl
+++ b/templates/repo/settings/nav.tmpl
@@ -12,7 +12,8 @@
{{if or .SignedUser.AllowGitHook .SignedUser.IsAdmin}}
<li {{if .PageIsSettingsGitHooks}}class="current"{{end}}><a href="{{.RepoLink}}/settings/hooks/git">{{.locale.Tr "repo.settings.githooks"}}</a></li>
{{end}}
- <li {{if .PageIsSettingsKeys}}class="current"{{end}}><a href="{{.RepoLink}}/settings/keys">{{.locale.Tr "secrets.secrets"}}</a></li>
+ <li {{if .PageIsSettingsKeys}}class="current"{{end}}><a href="{{.RepoLink}}/settings/keys">{{.locale.Tr "repo.settings.deploy_keys"}}</a></li>
+ <li {{if .PageIsSettingsSecrets}}class="current"{{end}}><a href="{{.RepoLink}}/settings/secrets">{{.locale.Tr "secrets.secrets"}}</a></li>
</ul>
</div>
</div>
diff --git a/templates/repo/settings/navbar.tmpl b/templates/repo/settings/navbar.tmpl
index 2119f6b5a4..bdfbb6bf10 100644
--- a/templates/repo/settings/navbar.tmpl
+++ b/templates/repo/settings/navbar.tmpl
@@ -25,6 +25,9 @@
</a>
{{end}}
<a class="{{if .PageIsSettingsKeys}}active {{end}}item" href="{{.RepoLink}}/settings/keys">
+ {{.locale.Tr "repo.settings.deploy_keys"}}
+ </a>
+ <a class="{{if .PageIsSettingsSecrets}}active {{end}}item" href="{{.RepoLink}}/settings/secrets">
{{.locale.Tr "secrets.secrets"}}
</a>
{{if .LFSStartServer}}
diff --git a/templates/repo/settings/secrets.tmpl b/templates/repo/settings/secrets.tmpl
index 5eb917a83b..71c5c51157 100644
--- a/templates/repo/settings/secrets.tmpl
+++ b/templates/repo/settings/secrets.tmpl
@@ -1,80 +1,10 @@
-<div class="ui container">
- <h4 class="ui top attached header">
- {{.locale.Tr "secrets.secrets"}}
- <div class="ui right">
- <div class="ui primary tiny show-panel button" data-panel="#add-secret-panel">{{.locale.Tr "secrets.creation"}}</div>
- </div>
- </h4>
- <div class="ui attached segment">
- <div class="{{if not .HasError}}hide {{end}}mb-4" id="add-secret-panel">
- <form class="ui form" action="{{.Link}}/secrets" method="post">
- {{.CsrfTokenHtml}}
- <div class="field">
- {{.locale.Tr "secrets.description"}}
- </div>
- <div class="field{{if .Err_Title}} error{{end}}">
- <label for="secret-title">{{.locale.Tr "secrets.name"}}</label>
- <input id="secret-title" name="title" value="{{.title}}" autofocus required pattern="^[a-zA-Z_][a-zA-Z0-9_]*$" placeholder="{{.locale.Tr "secrets.creation.name_placeholder"}}">
- </div>
- <div class="field{{if .Err_Content}} error{{end}}">
- <label for="secret-content">{{.locale.Tr "secrets.value"}}</label>
- <textarea id="secret-content" name="content" required placeholder="{{.locale.Tr "secrets.creation.value_placeholder"}}">{{.content}}</textarea>
- </div>
- <button class="ui green button">
- {{.locale.Tr "secrets.creation"}}
- </button>
- <button class="ui hide-panel button" data-panel="#add-secret-panel">
- {{.locale.Tr "cancel"}}
- </button>
- </form>
- </div>
- {{if .Secrets}}
- <div class="ui key list">
- {{range .Secrets}}
- <div class="item">
- <div class="right floated content">
- <button class="ui red tiny button delete-button" data-modal-id="delete-secret-modal" data-url="{{$.Link}}/secrets/delete" data-id="{{.ID}}">
- {{$.locale.Tr "settings.delete_key"}}
- </button>
- </div>
- <div class="left floated content">
- <i>{{svg "octicon-key" 32}}</i>
- </div>
- <div class="content">
- <strong>{{.Name}}</strong>
- <div class="print meta">******</div>
- <div class="activity meta">
- <i>
- {{$.locale.Tr "settings.add_on"}}
- <span>{{.CreatedUnix.FormatShort}}</span>
- </i>
- </div>
- </div>
- </div>
- {{end}}
- </div>
- {{else}}
- {{.locale.Tr "secrets.none"}}
- {{end}}
- </div>
-</div>
-
-<div class="ui small basic delete modal" id="delete-secret-modal">
- <div class="ui icon header">
- {{svg "octicon-trash"}}
- {{.locale.Tr "secrets.deletion"}}
- </div>
- <div class="content">
- <p>{{.locale.Tr "secrets.deletion.description"}}</p>
- </div>
- <div class="actions">
- <div class="ui red basic inverted cancel button">
- <i class="remove icon"></i>
- {{.locale.Tr "modal.no"}}
- </div>
- <div class="ui green basic inverted ok button">
- <i class="checkmark icon"></i>
- {{.locale.Tr "modal.yes"}}
- </div>
+{{template "base/head" .}}
+<div class="page-content repository settings">
+ {{template "repo/header" .}}
+ {{template "repo/settings/navbar" .}}
+ <div class="ui container">
+ {{template "base/alert" .}}
+ {{template "shared/secrets/add_list" .}}
</div>
</div>
+{{template "base/footer" .}}
diff --git a/templates/shared/secrets/add_list.tmpl b/templates/shared/secrets/add_list.tmpl
new file mode 100644
index 0000000000..94bc8a1695
--- /dev/null
+++ b/templates/shared/secrets/add_list.tmpl
@@ -0,0 +1,68 @@
+<h4 class="ui top attached header">
+ {{.locale.Tr "secrets.secrets"}}
+ <div class="ui right">
+ <div class="ui primary tiny show-panel button" data-panel="#add-secret-panel">{{.locale.Tr "secrets.creation"}}</div>
+ </div>
+</h4>
+<div class="ui attached segment">
+ <div class="{{if not .HasError}}hide {{end}}mb-4" id="add-secret-panel">
+ <form class="ui form" action="{{.Link}}" method="post">
+ {{.CsrfTokenHtml}}
+ <div class="field">
+ {{.locale.Tr "secrets.description"}}
+ </div>
+ <div class="field{{if .Err_Title}} error{{end}}">
+ <label for="secret-title">{{.locale.Tr "secrets.name"}}</label>
+ <input id="secret-title" name="title" value="{{.title}}" autofocus required pattern="^[a-zA-Z_][a-zA-Z0-9_]*$" placeholder="{{.locale.Tr "secrets.creation.name_placeholder"}}">
+ </div>
+ <div class="field{{if .Err_Content}} error{{end}}">
+ <label for="secret-content">{{.locale.Tr "secrets.value"}}</label>
+ <textarea id="secret-content" name="content" required placeholder="{{.locale.Tr "secrets.creation.value_placeholder"}}">{{.content}}</textarea>
+ </div>
+ <button class="ui green button">
+ {{.locale.Tr "secrets.creation"}}
+ </button>
+ <button class="ui hide-panel button" data-panel="#add-secret-panel">
+ {{.locale.Tr "cancel"}}
+ </button>
+ </form>
+ </div>
+ {{if .Secrets}}
+ <div class="ui key list">
+ {{range .Secrets}}
+ <div class="item">
+ <div class="right floated content">
+ <button class="ui red tiny button delete-button" data-url="{{$.Link}}/delete" data-id="{{.ID}}">
+ {{$.locale.Tr "settings.delete_key"}}
+ </button>
+ </div>
+ <div class="left floated content">
+ <i>{{svg "octicon-key" 32}}</i>
+ </div>
+ <div class="content">
+ <strong>{{.Name}}</strong>
+ <div class="print meta">******</div>
+ <div class="activity meta">
+ <i>
+ {{$.locale.Tr "settings.add_on"}}
+ <span>{{.CreatedUnix.FormatShort}}</span>
+ </i>
+ </div>
+ </div>
+ </div>
+ {{end}}
+ </div>
+ {{else}}
+ {{.locale.Tr "secrets.none"}}
+ {{end}}
+</div>
+<div class="ui small basic delete modal">
+ <div class="ui header">
+ {{svg "octicon-trash" 16 "mr-2"}}
+ {{.locale.Tr "secrets.deletion"}}
+ </div>
+ <div class="content">
+ <p>{{.locale.Tr "secrets.deletion.description"}}</p>
+ </div>
+ {{template "base/delete_modal_actions" .}}
+</div>
diff --git a/templates/user/settings/navbar.tmpl b/templates/user/settings/navbar.tmpl
index 8fd869dc40..8deffde0b2 100644
--- a/templates/user/settings/navbar.tmpl
+++ b/templates/user/settings/navbar.tmpl
@@ -18,6 +18,9 @@
<a class="{{if .PageIsSettingsKeys}}active {{end}}item" href="{{AppSubUrl}}/user/settings/keys">
{{.locale.Tr "settings.ssh_gpg_keys"}}
</a>
+ <a class="{{if .PageIsSettingsSecrets}}active {{end}}item" href="{{AppSubUrl}}/user/settings/secrets">
+ {{.locale.Tr "secrets.secrets"}}
+ </a>
{{if .EnablePackages}}
<a class="{{if .PageIsSettingsPackages}}active {{end}}item" href="{{AppSubUrl}}/user/settings/packages">
{{.locale.Tr "packages.title"}}
diff --git a/templates/user/settings/secrets.tmpl b/templates/user/settings/secrets.tmpl
new file mode 100644
index 0000000000..1a6875acef
--- /dev/null
+++ b/templates/user/settings/secrets.tmpl
@@ -0,0 +1,10 @@
+{{template "base/head" .}}
+<div class="page-content user settings secrets">
+ {{template "user/settings/navbar" .}}
+ <div class="ui container">
+ {{template "base/alert" .}}
+ {{template "shared/secrets/add_list" .}}
+ </div>
+</div>
+
+{{template "base/footer" .}}