code.gitea.io/gitea@v1.21.7/routers/web/user/setting/keys.go (about)

     1  // Copyright 2014 The Gogs Authors. All rights reserved.
     2  // Copyright 2018 The Gitea Authors. All rights reserved.
     3  // SPDX-License-Identifier: MIT
     4  
     5  package setting
     6  
     7  import (
     8  	"net/http"
     9  
    10  	asymkey_model "code.gitea.io/gitea/models/asymkey"
    11  	"code.gitea.io/gitea/models/db"
    12  	"code.gitea.io/gitea/modules/base"
    13  	"code.gitea.io/gitea/modules/context"
    14  	"code.gitea.io/gitea/modules/setting"
    15  	"code.gitea.io/gitea/modules/web"
    16  	asymkey_service "code.gitea.io/gitea/services/asymkey"
    17  	"code.gitea.io/gitea/services/forms"
    18  )
    19  
    20  const (
    21  	tplSettingsKeys base.TplName = "user/settings/keys"
    22  )
    23  
    24  // Keys render user's SSH/GPG public keys page
    25  func Keys(ctx *context.Context) {
    26  	ctx.Data["Title"] = ctx.Tr("settings.ssh_gpg_keys")
    27  	ctx.Data["PageIsSettingsKeys"] = true
    28  	ctx.Data["DisableSSH"] = setting.SSH.Disabled
    29  	ctx.Data["BuiltinSSH"] = setting.SSH.StartBuiltinServer
    30  	ctx.Data["AllowPrincipals"] = setting.SSH.AuthorizedPrincipalsEnabled
    31  
    32  	loadKeysData(ctx)
    33  
    34  	ctx.HTML(http.StatusOK, tplSettingsKeys)
    35  }
    36  
    37  // KeysPost response for change user's SSH/GPG keys
    38  func KeysPost(ctx *context.Context) {
    39  	form := web.GetForm(ctx).(*forms.AddKeyForm)
    40  	ctx.Data["Title"] = ctx.Tr("settings")
    41  	ctx.Data["PageIsSettingsKeys"] = true
    42  	ctx.Data["DisableSSH"] = setting.SSH.Disabled
    43  	ctx.Data["BuiltinSSH"] = setting.SSH.StartBuiltinServer
    44  	ctx.Data["AllowPrincipals"] = setting.SSH.AuthorizedPrincipalsEnabled
    45  
    46  	if ctx.HasError() {
    47  		loadKeysData(ctx)
    48  
    49  		ctx.HTML(http.StatusOK, tplSettingsKeys)
    50  		return
    51  	}
    52  	switch form.Type {
    53  	case "principal":
    54  		content, err := asymkey_model.CheckPrincipalKeyString(ctx, ctx.Doer, form.Content)
    55  		if err != nil {
    56  			if db.IsErrSSHDisabled(err) {
    57  				ctx.Flash.Info(ctx.Tr("settings.ssh_disabled"))
    58  			} else {
    59  				ctx.Flash.Error(ctx.Tr("form.invalid_ssh_principal", err.Error()))
    60  			}
    61  			ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
    62  			return
    63  		}
    64  		if _, err = asymkey_model.AddPrincipalKey(ctx.Doer.ID, content, 0); err != nil {
    65  			ctx.Data["HasPrincipalError"] = true
    66  			switch {
    67  			case asymkey_model.IsErrKeyAlreadyExist(err), asymkey_model.IsErrKeyNameAlreadyUsed(err):
    68  				loadKeysData(ctx)
    69  
    70  				ctx.Data["Err_Content"] = true
    71  				ctx.RenderWithErr(ctx.Tr("settings.ssh_principal_been_used"), tplSettingsKeys, &form)
    72  			default:
    73  				ctx.ServerError("AddPrincipalKey", err)
    74  			}
    75  			return
    76  		}
    77  		ctx.Flash.Success(ctx.Tr("settings.add_principal_success", form.Content))
    78  		ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
    79  	case "gpg":
    80  		token := asymkey_model.VerificationToken(ctx.Doer, 1)
    81  		lastToken := asymkey_model.VerificationToken(ctx.Doer, 0)
    82  
    83  		keys, err := asymkey_model.AddGPGKey(ctx, ctx.Doer.ID, form.Content, token, form.Signature)
    84  		if err != nil && asymkey_model.IsErrGPGInvalidTokenSignature(err) {
    85  			keys, err = asymkey_model.AddGPGKey(ctx, ctx.Doer.ID, form.Content, lastToken, form.Signature)
    86  		}
    87  		if err != nil {
    88  			ctx.Data["HasGPGError"] = true
    89  			switch {
    90  			case asymkey_model.IsErrGPGKeyParsing(err):
    91  				ctx.Flash.Error(ctx.Tr("form.invalid_gpg_key", err.Error()))
    92  				ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
    93  			case asymkey_model.IsErrGPGKeyIDAlreadyUsed(err):
    94  				loadKeysData(ctx)
    95  
    96  				ctx.Data["Err_Content"] = true
    97  				ctx.RenderWithErr(ctx.Tr("settings.gpg_key_id_used"), tplSettingsKeys, &form)
    98  			case asymkey_model.IsErrGPGInvalidTokenSignature(err):
    99  				loadKeysData(ctx)
   100  				ctx.Data["Err_Content"] = true
   101  				ctx.Data["Err_Signature"] = true
   102  				keyID := err.(asymkey_model.ErrGPGInvalidTokenSignature).ID
   103  				ctx.Data["KeyID"] = keyID
   104  				ctx.Data["PaddedKeyID"] = asymkey_model.PaddedKeyID(keyID)
   105  				ctx.RenderWithErr(ctx.Tr("settings.gpg_invalid_token_signature"), tplSettingsKeys, &form)
   106  			case asymkey_model.IsErrGPGNoEmailFound(err):
   107  				loadKeysData(ctx)
   108  
   109  				ctx.Data["Err_Content"] = true
   110  				ctx.Data["Err_Signature"] = true
   111  				keyID := err.(asymkey_model.ErrGPGNoEmailFound).ID
   112  				ctx.Data["KeyID"] = keyID
   113  				ctx.Data["PaddedKeyID"] = asymkey_model.PaddedKeyID(keyID)
   114  				ctx.RenderWithErr(ctx.Tr("settings.gpg_no_key_email_found"), tplSettingsKeys, &form)
   115  			default:
   116  				ctx.ServerError("AddPublicKey", err)
   117  			}
   118  			return
   119  		}
   120  		keyIDs := ""
   121  		for _, key := range keys {
   122  			keyIDs += key.KeyID
   123  			keyIDs += ", "
   124  		}
   125  		if len(keyIDs) > 0 {
   126  			keyIDs = keyIDs[:len(keyIDs)-2]
   127  		}
   128  		ctx.Flash.Success(ctx.Tr("settings.add_gpg_key_success", keyIDs))
   129  		ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
   130  	case "verify_gpg":
   131  		token := asymkey_model.VerificationToken(ctx.Doer, 1)
   132  		lastToken := asymkey_model.VerificationToken(ctx.Doer, 0)
   133  
   134  		keyID, err := asymkey_model.VerifyGPGKey(ctx.Doer.ID, form.KeyID, token, form.Signature)
   135  		if err != nil && asymkey_model.IsErrGPGInvalidTokenSignature(err) {
   136  			keyID, err = asymkey_model.VerifyGPGKey(ctx.Doer.ID, form.KeyID, lastToken, form.Signature)
   137  		}
   138  		if err != nil {
   139  			ctx.Data["HasGPGVerifyError"] = true
   140  			switch {
   141  			case asymkey_model.IsErrGPGInvalidTokenSignature(err):
   142  				loadKeysData(ctx)
   143  				ctx.Data["VerifyingID"] = form.KeyID
   144  				ctx.Data["Err_Signature"] = true
   145  				keyID := err.(asymkey_model.ErrGPGInvalidTokenSignature).ID
   146  				ctx.Data["KeyID"] = keyID
   147  				ctx.Data["PaddedKeyID"] = asymkey_model.PaddedKeyID(keyID)
   148  				ctx.RenderWithErr(ctx.Tr("settings.gpg_invalid_token_signature"), tplSettingsKeys, &form)
   149  			default:
   150  				ctx.ServerError("VerifyGPG", err)
   151  			}
   152  		}
   153  		ctx.Flash.Success(ctx.Tr("settings.verify_gpg_key_success", keyID))
   154  		ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
   155  	case "ssh":
   156  		content, err := asymkey_model.CheckPublicKeyString(form.Content)
   157  		if err != nil {
   158  			if db.IsErrSSHDisabled(err) {
   159  				ctx.Flash.Info(ctx.Tr("settings.ssh_disabled"))
   160  			} else if asymkey_model.IsErrKeyUnableVerify(err) {
   161  				ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
   162  			} else if err == asymkey_model.ErrKeyIsPrivate {
   163  				ctx.Flash.Error(ctx.Tr("form.must_use_public_key"))
   164  			} else {
   165  				ctx.Flash.Error(ctx.Tr("form.invalid_ssh_key", err.Error()))
   166  			}
   167  			ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
   168  			return
   169  		}
   170  
   171  		if _, err = asymkey_model.AddPublicKey(ctx.Doer.ID, form.Title, content, 0); err != nil {
   172  			ctx.Data["HasSSHError"] = true
   173  			switch {
   174  			case asymkey_model.IsErrKeyAlreadyExist(err):
   175  				loadKeysData(ctx)
   176  
   177  				ctx.Data["Err_Content"] = true
   178  				ctx.RenderWithErr(ctx.Tr("settings.ssh_key_been_used"), tplSettingsKeys, &form)
   179  			case asymkey_model.IsErrKeyNameAlreadyUsed(err):
   180  				loadKeysData(ctx)
   181  
   182  				ctx.Data["Err_Title"] = true
   183  				ctx.RenderWithErr(ctx.Tr("settings.ssh_key_name_used"), tplSettingsKeys, &form)
   184  			case asymkey_model.IsErrKeyUnableVerify(err):
   185  				ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
   186  				ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
   187  			default:
   188  				ctx.ServerError("AddPublicKey", err)
   189  			}
   190  			return
   191  		}
   192  		ctx.Flash.Success(ctx.Tr("settings.add_key_success", form.Title))
   193  		ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
   194  	case "verify_ssh":
   195  		token := asymkey_model.VerificationToken(ctx.Doer, 1)
   196  		lastToken := asymkey_model.VerificationToken(ctx.Doer, 0)
   197  
   198  		fingerprint, err := asymkey_model.VerifySSHKey(ctx.Doer.ID, form.Fingerprint, token, form.Signature)
   199  		if err != nil && asymkey_model.IsErrSSHInvalidTokenSignature(err) {
   200  			fingerprint, err = asymkey_model.VerifySSHKey(ctx.Doer.ID, form.Fingerprint, lastToken, form.Signature)
   201  		}
   202  		if err != nil {
   203  			ctx.Data["HasSSHVerifyError"] = true
   204  			switch {
   205  			case asymkey_model.IsErrSSHInvalidTokenSignature(err):
   206  				loadKeysData(ctx)
   207  				ctx.Data["Err_Signature"] = true
   208  				ctx.Data["Fingerprint"] = err.(asymkey_model.ErrSSHInvalidTokenSignature).Fingerprint
   209  				ctx.RenderWithErr(ctx.Tr("settings.ssh_invalid_token_signature"), tplSettingsKeys, &form)
   210  			default:
   211  				ctx.ServerError("VerifySSH", err)
   212  			}
   213  		}
   214  		ctx.Flash.Success(ctx.Tr("settings.verify_ssh_key_success", fingerprint))
   215  		ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
   216  
   217  	default:
   218  		ctx.Flash.Warning("Function not implemented")
   219  		ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
   220  	}
   221  }
   222  
   223  // DeleteKey response for delete user's SSH/GPG key
   224  func DeleteKey(ctx *context.Context) {
   225  	switch ctx.FormString("type") {
   226  	case "gpg":
   227  		if err := asymkey_model.DeleteGPGKey(ctx, ctx.Doer, ctx.FormInt64("id")); err != nil {
   228  			ctx.Flash.Error("DeleteGPGKey: " + err.Error())
   229  		} else {
   230  			ctx.Flash.Success(ctx.Tr("settings.gpg_key_deletion_success"))
   231  		}
   232  	case "ssh":
   233  		keyID := ctx.FormInt64("id")
   234  		external, err := asymkey_model.PublicKeyIsExternallyManaged(keyID)
   235  		if err != nil {
   236  			ctx.ServerError("sshKeysExternalManaged", err)
   237  			return
   238  		}
   239  		if external {
   240  			ctx.Flash.Error(ctx.Tr("settings.ssh_externally_managed"))
   241  			ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
   242  			return
   243  		}
   244  		if err := asymkey_service.DeletePublicKey(ctx, ctx.Doer, keyID); err != nil {
   245  			ctx.Flash.Error("DeletePublicKey: " + err.Error())
   246  		} else {
   247  			ctx.Flash.Success(ctx.Tr("settings.ssh_key_deletion_success"))
   248  		}
   249  	case "principal":
   250  		if err := asymkey_service.DeletePublicKey(ctx, ctx.Doer, ctx.FormInt64("id")); err != nil {
   251  			ctx.Flash.Error("DeletePublicKey: " + err.Error())
   252  		} else {
   253  			ctx.Flash.Success(ctx.Tr("settings.ssh_principal_deletion_success"))
   254  		}
   255  	default:
   256  		ctx.Flash.Warning("Function not implemented")
   257  		ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
   258  	}
   259  	ctx.JSONRedirect(setting.AppSubURL + "/user/settings/keys")
   260  }
   261  
   262  func loadKeysData(ctx *context.Context) {
   263  	keys, err := asymkey_model.ListPublicKeys(ctx.Doer.ID, db.ListOptions{})
   264  	if err != nil {
   265  		ctx.ServerError("ListPublicKeys", err)
   266  		return
   267  	}
   268  	ctx.Data["Keys"] = keys
   269  
   270  	externalKeys, err := asymkey_model.PublicKeysAreExternallyManaged(keys)
   271  	if err != nil {
   272  		ctx.ServerError("ListPublicKeys", err)
   273  		return
   274  	}
   275  	ctx.Data["ExternalKeys"] = externalKeys
   276  
   277  	gpgkeys, err := asymkey_model.ListGPGKeys(ctx, ctx.Doer.ID, db.ListOptions{})
   278  	if err != nil {
   279  		ctx.ServerError("ListGPGKeys", err)
   280  		return
   281  	}
   282  	ctx.Data["GPGKeys"] = gpgkeys
   283  	tokenToSign := asymkey_model.VerificationToken(ctx.Doer, 1)
   284  
   285  	// generate a new aes cipher using the csrfToken
   286  	ctx.Data["TokenToSign"] = tokenToSign
   287  
   288  	principals, err := asymkey_model.ListPrincipalKeys(ctx.Doer.ID, db.ListOptions{})
   289  	if err != nil {
   290  		ctx.ServerError("ListPrincipalKeys", err)
   291  		return
   292  	}
   293  	ctx.Data["Principals"] = principals
   294  
   295  	ctx.Data["VerifyingID"] = ctx.FormString("verify_gpg")
   296  	ctx.Data["VerifyingFingerprint"] = ctx.FormString("verify_ssh")
   297  }