mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-27 09:11:53 -05:00
9066d09c57
* Add ssh certificate support * Add ssh certificate support to builtin ssh * Write trusted-user-ca-keys.pem based on configuration * Update app.example.ini * Update templates/user/settings/keys_principal.tmpl Co-authored-by: silverwind <me@silverwind.io> * Remove unused locale string * Update options/locale/locale_en-US.ini Co-authored-by: silverwind <me@silverwind.io> * Update options/locale/locale_en-US.ini Co-authored-by: silverwind <me@silverwind.io> * Update models/ssh_key.go Co-authored-by: silverwind <me@silverwind.io> * Add missing creation of SSH.Rootpath * Update cheatsheet, example and locale strings * Update models/ssh_key.go Co-authored-by: zeripath <art27@cantab.net> * Update models/ssh_key.go Co-authored-by: zeripath <art27@cantab.net> * Update models/ssh_key.go Co-authored-by: zeripath <art27@cantab.net> * Update models/ssh_key.go Co-authored-by: zeripath <art27@cantab.net> * Update models/ssh_key.go * Optimizations based on feedback * Validate CA keys for external sshd * Add filename option and change default filename Add a SSH_TRUSTED_USER_CA_KEYS_FILENAME option which default is RUN_USER/.ssh/gitea-trusted-user-ca-keys.pem Do not write a file when SSH_TRUSTED_USER_CA_KEYS is empty. Add some more documentation. * Remove unneeded principalkey functions * Add blank line * Apply suggestions from code review Co-authored-by: zeripath <art27@cantab.net> * Add SSH_AUTHORIZED_PRINCIPALS_ALLOW option This adds a SSH_AUTHORIZED_PRINCIPALS_ALLOW which is default email,username this means that users only can add the principals that match their email or username. To allow anything the admin need to set the option anything. This allows for a safe default in gitea which protects against malicious users using other user's prinicipals. (before that user could set it). This commit also has some small other fixes from the last code review. * Rewrite principal keys file on user deletion * Use correct rewrite method * Set correct AuthorizedPrincipalsBackup default setting * Rewrite principalsfile when adding principals * Add update authorized_principals option to admin dashboard * Handle non-primary emails Signed-off-by: Andrew Thornton <art27@cantab.net> * Add the command actually to the dashboard template * Update models/ssh_key.go Co-authored-by: silverwind <me@silverwind.io> * By default do not show principal options unless there are CA keys set or they are explicitly set Signed-off-by: Andrew Thornton <art27@cantab.net> * allow settings when enabled * Fix typos in TrustedUserCAKeys path * Allow every CASignatureAlgorithms algorithm As this depends on the content of TrustedUserCAKeys we should allow all signature algorithms as admins can choose the specific algorithm on their signing CA * Update models/ssh_key.go Co-authored-by: Lauris BH <lauris@nix.lv> * Fix linting issue Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: techknowlogick <matti@mdranta.net> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
204 lines
6.2 KiB
Go
204 lines
6.2 KiB
Go
// Copyright 2014 The Gogs Authors. All rights reserved.
|
|
// Copyright 2018 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 setting
|
|
|
|
import (
|
|
"code.gitea.io/gitea/models"
|
|
"code.gitea.io/gitea/modules/auth"
|
|
"code.gitea.io/gitea/modules/base"
|
|
"code.gitea.io/gitea/modules/context"
|
|
"code.gitea.io/gitea/modules/setting"
|
|
)
|
|
|
|
const (
|
|
tplSettingsKeys base.TplName = "user/settings/keys"
|
|
)
|
|
|
|
// Keys render user's SSH/GPG public keys page
|
|
func Keys(ctx *context.Context) {
|
|
ctx.Data["Title"] = ctx.Tr("settings")
|
|
ctx.Data["PageIsSettingsKeys"] = true
|
|
ctx.Data["DisableSSH"] = setting.SSH.Disabled
|
|
ctx.Data["BuiltinSSH"] = setting.SSH.StartBuiltinServer
|
|
ctx.Data["AllowPrincipals"] = setting.SSH.AuthorizedPrincipalsEnabled
|
|
|
|
loadKeysData(ctx)
|
|
|
|
ctx.HTML(200, tplSettingsKeys)
|
|
}
|
|
|
|
// KeysPost response for change user's SSH/GPG keys
|
|
func KeysPost(ctx *context.Context, form auth.AddKeyForm) {
|
|
ctx.Data["Title"] = ctx.Tr("settings")
|
|
ctx.Data["PageIsSettingsKeys"] = true
|
|
ctx.Data["DisableSSH"] = setting.SSH.Disabled
|
|
ctx.Data["BuiltinSSH"] = setting.SSH.StartBuiltinServer
|
|
ctx.Data["AllowPrincipals"] = setting.SSH.AuthorizedPrincipalsEnabled
|
|
|
|
if ctx.HasError() {
|
|
loadKeysData(ctx)
|
|
|
|
ctx.HTML(200, tplSettingsKeys)
|
|
return
|
|
}
|
|
switch form.Type {
|
|
case "principal":
|
|
content, err := models.CheckPrincipalKeyString(ctx.User, form.Content)
|
|
if err != nil {
|
|
if models.IsErrSSHDisabled(err) {
|
|
ctx.Flash.Info(ctx.Tr("settings.ssh_disabled"))
|
|
} else {
|
|
ctx.Flash.Error(ctx.Tr("form.invalid_ssh_principal", err.Error()))
|
|
}
|
|
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
|
|
return
|
|
}
|
|
if _, err = models.AddPrincipalKey(ctx.User.ID, content, 0); err != nil {
|
|
ctx.Data["HasPrincipalError"] = true
|
|
switch {
|
|
case models.IsErrKeyAlreadyExist(err), models.IsErrKeyNameAlreadyUsed(err):
|
|
loadKeysData(ctx)
|
|
|
|
ctx.Data["Err_Content"] = true
|
|
ctx.RenderWithErr(ctx.Tr("settings.ssh_principal_been_used"), tplSettingsKeys, &form)
|
|
default:
|
|
ctx.ServerError("AddPrincipalKey", err)
|
|
}
|
|
return
|
|
}
|
|
ctx.Flash.Success(ctx.Tr("settings.add_principal_success", form.Content))
|
|
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
|
|
case "gpg":
|
|
keys, err := models.AddGPGKey(ctx.User.ID, form.Content)
|
|
if err != nil {
|
|
ctx.Data["HasGPGError"] = true
|
|
switch {
|
|
case models.IsErrGPGKeyParsing(err):
|
|
ctx.Flash.Error(ctx.Tr("form.invalid_gpg_key", err.Error()))
|
|
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
|
|
case models.IsErrGPGKeyIDAlreadyUsed(err):
|
|
loadKeysData(ctx)
|
|
|
|
ctx.Data["Err_Content"] = true
|
|
ctx.RenderWithErr(ctx.Tr("settings.gpg_key_id_used"), tplSettingsKeys, &form)
|
|
case models.IsErrGPGNoEmailFound(err):
|
|
loadKeysData(ctx)
|
|
|
|
ctx.Data["Err_Content"] = true
|
|
ctx.RenderWithErr(ctx.Tr("settings.gpg_no_key_email_found"), tplSettingsKeys, &form)
|
|
default:
|
|
ctx.ServerError("AddPublicKey", err)
|
|
}
|
|
return
|
|
}
|
|
keyIDs := ""
|
|
for _, key := range keys {
|
|
keyIDs += key.KeyID
|
|
keyIDs += ", "
|
|
}
|
|
if len(keyIDs) > 0 {
|
|
keyIDs = keyIDs[:len(keyIDs)-2]
|
|
}
|
|
ctx.Flash.Success(ctx.Tr("settings.add_gpg_key_success", keyIDs))
|
|
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
|
|
case "ssh":
|
|
content, err := models.CheckPublicKeyString(form.Content)
|
|
if err != nil {
|
|
if models.IsErrSSHDisabled(err) {
|
|
ctx.Flash.Info(ctx.Tr("settings.ssh_disabled"))
|
|
} else if models.IsErrKeyUnableVerify(err) {
|
|
ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
|
|
} else {
|
|
ctx.Flash.Error(ctx.Tr("form.invalid_ssh_key", err.Error()))
|
|
}
|
|
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
|
|
return
|
|
}
|
|
|
|
if _, err = models.AddPublicKey(ctx.User.ID, form.Title, content, 0); err != nil {
|
|
ctx.Data["HasSSHError"] = true
|
|
switch {
|
|
case models.IsErrKeyAlreadyExist(err):
|
|
loadKeysData(ctx)
|
|
|
|
ctx.Data["Err_Content"] = true
|
|
ctx.RenderWithErr(ctx.Tr("settings.ssh_key_been_used"), tplSettingsKeys, &form)
|
|
case models.IsErrKeyNameAlreadyUsed(err):
|
|
loadKeysData(ctx)
|
|
|
|
ctx.Data["Err_Title"] = true
|
|
ctx.RenderWithErr(ctx.Tr("settings.ssh_key_name_used"), tplSettingsKeys, &form)
|
|
case models.IsErrKeyUnableVerify(err):
|
|
ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
|
|
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
|
|
default:
|
|
ctx.ServerError("AddPublicKey", err)
|
|
}
|
|
return
|
|
}
|
|
ctx.Flash.Success(ctx.Tr("settings.add_key_success", form.Title))
|
|
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
|
|
|
|
default:
|
|
ctx.Flash.Warning("Function not implemented")
|
|
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
|
|
}
|
|
|
|
}
|
|
|
|
// DeleteKey response for delete user's SSH/GPG key
|
|
func DeleteKey(ctx *context.Context) {
|
|
|
|
switch ctx.Query("type") {
|
|
case "gpg":
|
|
if err := models.DeleteGPGKey(ctx.User, ctx.QueryInt64("id")); err != nil {
|
|
ctx.Flash.Error("DeleteGPGKey: " + err.Error())
|
|
} else {
|
|
ctx.Flash.Success(ctx.Tr("settings.gpg_key_deletion_success"))
|
|
}
|
|
case "ssh":
|
|
if err := models.DeletePublicKey(ctx.User, ctx.QueryInt64("id")); err != nil {
|
|
ctx.Flash.Error("DeletePublicKey: " + err.Error())
|
|
} else {
|
|
ctx.Flash.Success(ctx.Tr("settings.ssh_key_deletion_success"))
|
|
}
|
|
case "principal":
|
|
if err := models.DeletePublicKey(ctx.User, ctx.QueryInt64("id")); err != nil {
|
|
ctx.Flash.Error("DeletePublicKey: " + err.Error())
|
|
} else {
|
|
ctx.Flash.Success(ctx.Tr("settings.ssh_principal_deletion_success"))
|
|
}
|
|
default:
|
|
ctx.Flash.Warning("Function not implemented")
|
|
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
|
|
}
|
|
ctx.JSON(200, map[string]interface{}{
|
|
"redirect": setting.AppSubURL + "/user/settings/keys",
|
|
})
|
|
}
|
|
|
|
func loadKeysData(ctx *context.Context) {
|
|
keys, err := models.ListPublicKeys(ctx.User.ID, models.ListOptions{})
|
|
if err != nil {
|
|
ctx.ServerError("ListPublicKeys", err)
|
|
return
|
|
}
|
|
ctx.Data["Keys"] = keys
|
|
|
|
gpgkeys, err := models.ListGPGKeys(ctx.User.ID, models.ListOptions{})
|
|
if err != nil {
|
|
ctx.ServerError("ListGPGKeys", err)
|
|
return
|
|
}
|
|
ctx.Data["GPGKeys"] = gpgkeys
|
|
|
|
principals, err := models.ListPrincipalKeys(ctx.User.ID, models.ListOptions{})
|
|
if err != nil {
|
|
ctx.ServerError("ListPrincipalKeys", err)
|
|
return
|
|
}
|
|
ctx.Data["Principals"] = principals
|
|
}
|