forked from gitea/gitea
		
	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>
This commit is contained in:
		
							parent
							
								
									9f9a1ce922
								
							
						
					
					
						commit
						5882e179a9
					
				| @ -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. | ||||
| 
 | ||||
|  | ||||
| @ -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. | ||||
| 
 | ||||
|  | ||||
| @ -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", | ||||
| 	}) | ||||
| } | ||||
|  | ||||
							
								
								
									
										48
									
								
								routers/web/org/setting_secrets.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								routers/web/org/setting_secrets.go
									
									
									
									
									
										Normal file
									
								
							| @ -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", | ||||
| 	) | ||||
| } | ||||
| @ -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 { | ||||
|  | ||||
							
								
								
									
										46
									
								
								routers/web/repo/setting_secrets.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								routers/web/repo/setting_secrets.go
									
									
									
									
									
										Normal file
									
								
							| @ -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", | ||||
| 	) | ||||
| } | ||||
							
								
								
									
										54
									
								
								routers/web/shared/secrets/secrets.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								routers/web/shared/secrets/secrets.go
									
									
									
									
									
										Normal file
									
								
							| @ -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, | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										45
									
								
								routers/web/user/setting/secrets.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								routers/web/user/setting/secrets.go
									
									
									
									
									
										Normal file
									
								
							| @ -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", | ||||
| 	) | ||||
| } | ||||
| @ -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() { | ||||
|  | ||||
| @ -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" .}} | ||||
|  | ||||
| @ -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"}} | ||||
|  | ||||
| @ -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> | ||||
|  | ||||
| @ -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}} | ||||
|  | ||||
| @ -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" .}} | ||||
|  | ||||
							
								
								
									
										68
									
								
								templates/shared/secrets/add_list.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								templates/shared/secrets/add_list.tmpl
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
| @ -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"}} | ||||
|  | ||||
							
								
								
									
										10
									
								
								templates/user/settings/secrets.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								templates/user/settings/secrets.tmpl
									
									
									
									
									
										Normal file
									
								
							| @ -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" .}} | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 KN4CK3R
						KN4CK3R