code.gitea.io/gitea@v1.21.7/models/asymkey/ssh_key_principals.go (about)

     1  // Copyright 2021 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package asymkey
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"strings"
    10  
    11  	"code.gitea.io/gitea/models/db"
    12  	"code.gitea.io/gitea/models/perm"
    13  	user_model "code.gitea.io/gitea/models/user"
    14  	"code.gitea.io/gitea/modules/setting"
    15  	"code.gitea.io/gitea/modules/util"
    16  )
    17  
    18  // __________       .__              .__             .__
    19  // \______   _______|__| ____   ____ |_____________  |  |   ______
    20  //  |     ___\_  __ |  |/    \_/ ___\|  \____ \__  \ |  |  /  ___/
    21  //  |    |    |  | \|  |   |  \  \___|  |  |_> / __ \|  |__\___ \
    22  //  |____|    |__|  |__|___|  /\___  |__|   __(____  |____/____  >
    23  //                          \/     \/   |__|       \/          \/
    24  //
    25  // This file contains functions related to principals
    26  
    27  // AddPrincipalKey adds new principal to database and authorized_principals file.
    28  func AddPrincipalKey(ownerID int64, content string, authSourceID int64) (*PublicKey, error) {
    29  	ctx, committer, err := db.TxContext(db.DefaultContext)
    30  	if err != nil {
    31  		return nil, err
    32  	}
    33  	defer committer.Close()
    34  
    35  	// Principals cannot be duplicated.
    36  	has, err := db.GetEngine(ctx).
    37  		Where("content = ? AND type = ?", content, KeyTypePrincipal).
    38  		Get(new(PublicKey))
    39  	if err != nil {
    40  		return nil, err
    41  	} else if has {
    42  		return nil, ErrKeyAlreadyExist{0, "", content}
    43  	}
    44  
    45  	key := &PublicKey{
    46  		OwnerID:       ownerID,
    47  		Name:          content,
    48  		Content:       content,
    49  		Mode:          perm.AccessModeWrite,
    50  		Type:          KeyTypePrincipal,
    51  		LoginSourceID: authSourceID,
    52  	}
    53  	if err = db.Insert(ctx, key); err != nil {
    54  		return nil, fmt.Errorf("addKey: %w", err)
    55  	}
    56  
    57  	if err = committer.Commit(); err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	committer.Close()
    62  
    63  	return key, RewriteAllPrincipalKeys(db.DefaultContext)
    64  }
    65  
    66  // CheckPrincipalKeyString strips spaces and returns an error if the given principal contains newlines
    67  func CheckPrincipalKeyString(ctx context.Context, user *user_model.User, content string) (_ string, err error) {
    68  	if setting.SSH.Disabled {
    69  		return "", db.ErrSSHDisabled{}
    70  	}
    71  
    72  	content = strings.TrimSpace(content)
    73  	if strings.ContainsAny(content, "\r\n") {
    74  		return "", util.NewInvalidArgumentErrorf("only a single line with a single principal please")
    75  	}
    76  
    77  	// check all the allowed principals, email, username or anything
    78  	// if any matches, return ok
    79  	for _, v := range setting.SSH.AuthorizedPrincipalsAllow {
    80  		switch v {
    81  		case "anything":
    82  			return content, nil
    83  		case "email":
    84  			emails, err := user_model.GetEmailAddresses(ctx, user.ID)
    85  			if err != nil {
    86  				return "", err
    87  			}
    88  			for _, email := range emails {
    89  				if !email.IsActivated {
    90  					continue
    91  				}
    92  				if content == email.Email {
    93  					return content, nil
    94  				}
    95  			}
    96  
    97  		case "username":
    98  			if content == user.Name {
    99  				return content, nil
   100  			}
   101  		}
   102  	}
   103  
   104  	return "", fmt.Errorf("didn't match allowed principals: %s", setting.SSH.AuthorizedPrincipalsAllow)
   105  }
   106  
   107  // ListPrincipalKeys returns a list of principals belongs to given user.
   108  func ListPrincipalKeys(uid int64, listOptions db.ListOptions) ([]*PublicKey, error) {
   109  	sess := db.GetEngine(db.DefaultContext).Where("owner_id = ? AND type = ?", uid, KeyTypePrincipal)
   110  	if listOptions.Page != 0 {
   111  		sess = db.SetSessionPagination(sess, &listOptions)
   112  
   113  		keys := make([]*PublicKey, 0, listOptions.PageSize)
   114  		return keys, sess.Find(&keys)
   115  	}
   116  
   117  	keys := make([]*PublicKey, 0, 5)
   118  	return keys, sess.Find(&keys)
   119  }