code.gitea.io/gitea@v1.22.3/models/asymkey/gpg_key_add.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  	"strings"
     9  
    10  	"code.gitea.io/gitea/models/db"
    11  	"code.gitea.io/gitea/modules/log"
    12  
    13  	"github.com/keybase/go-crypto/openpgp"
    14  )
    15  
    16  //   __________________  ________   ____  __.
    17  //  /  _____/\______   \/  _____/  |    |/ _|____ ___.__.
    18  // /   \  ___ |     ___/   \  ___  |      <_/ __ <   |  |
    19  // \    \_\  \|    |   \    \_\  \ |    |  \  ___/\___  |
    20  //  \______  /|____|    \______  / |____|__ \___  > ____|
    21  //         \/                  \/          \/   \/\/
    22  //    _____       .___  .___
    23  //   /  _  \    __| _/__| _/
    24  //	/  /_\  \  / __ |/ __ |
    25  // /    |    \/ /_/ / /_/ |
    26  // \____|__  /\____ \____ |
    27  //         \/      \/    \/
    28  
    29  // This file contains functions relating to adding GPG Keys
    30  
    31  // addGPGKey add key, import and subkeys to database
    32  func addGPGKey(ctx context.Context, key *GPGKey, content string) (err error) {
    33  	// Add GPGKeyImport
    34  	if err = db.Insert(ctx, &GPGKeyImport{
    35  		KeyID:   key.KeyID,
    36  		Content: content,
    37  	}); err != nil {
    38  		return err
    39  	}
    40  	// Save GPG primary key.
    41  	if err = db.Insert(ctx, key); err != nil {
    42  		return err
    43  	}
    44  	// Save GPG subs key.
    45  	for _, subkey := range key.SubsKey {
    46  		if err := addGPGSubKey(ctx, subkey); err != nil {
    47  			return err
    48  		}
    49  	}
    50  	return nil
    51  }
    52  
    53  // addGPGSubKey add subkeys to database
    54  func addGPGSubKey(ctx context.Context, key *GPGKey) (err error) {
    55  	// Save GPG primary key.
    56  	if err = db.Insert(ctx, key); err != nil {
    57  		return err
    58  	}
    59  	// Save GPG subs key.
    60  	for _, subkey := range key.SubsKey {
    61  		if err := addGPGSubKey(ctx, subkey); err != nil {
    62  			return err
    63  		}
    64  	}
    65  	return nil
    66  }
    67  
    68  // AddGPGKey adds new public key to database.
    69  func AddGPGKey(ctx context.Context, ownerID int64, content, token, signature string) ([]*GPGKey, error) {
    70  	ekeys, err := checkArmoredGPGKeyString(content)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	ctx, committer, err := db.TxContext(ctx)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	defer committer.Close()
    80  
    81  	keys := make([]*GPGKey, 0, len(ekeys))
    82  
    83  	verified := false
    84  	// Handle provided signature
    85  	if signature != "" {
    86  		signer, err := openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token), strings.NewReader(signature))
    87  		if err != nil {
    88  			signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\n"), strings.NewReader(signature))
    89  		}
    90  		if err != nil {
    91  			signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\r\n"), strings.NewReader(signature))
    92  		}
    93  		if err != nil {
    94  			log.Error("Unable to validate token signature. Error: %v", err)
    95  			return nil, ErrGPGInvalidTokenSignature{
    96  				ID:      ekeys[0].PrimaryKey.KeyIdString(),
    97  				Wrapped: err,
    98  			}
    99  		}
   100  		ekeys = []*openpgp.Entity{signer}
   101  		verified = true
   102  	}
   103  
   104  	if len(ekeys) > 1 {
   105  		id2key := map[string]*openpgp.Entity{}
   106  		newEKeys := make([]*openpgp.Entity, 0, len(ekeys))
   107  		for _, ekey := range ekeys {
   108  			id := ekey.PrimaryKey.KeyIdString()
   109  			if original, has := id2key[id]; has {
   110  				// Coalesce this with the other one
   111  				for _, subkey := range ekey.Subkeys {
   112  					if subkey.PublicKey == nil {
   113  						continue
   114  					}
   115  					found := false
   116  
   117  					for _, originalSubkey := range original.Subkeys {
   118  						if originalSubkey.PublicKey == nil {
   119  							continue
   120  						}
   121  						if originalSubkey.PublicKey.KeyId == subkey.PublicKey.KeyId {
   122  							found = true
   123  							break
   124  						}
   125  					}
   126  					if !found {
   127  						original.Subkeys = append(original.Subkeys, subkey)
   128  					}
   129  				}
   130  				for name, identity := range ekey.Identities {
   131  					if _, has := original.Identities[name]; has {
   132  						continue
   133  					}
   134  					original.Identities[name] = identity
   135  				}
   136  				continue
   137  			}
   138  			id2key[id] = ekey
   139  			newEKeys = append(newEKeys, ekey)
   140  		}
   141  		ekeys = newEKeys
   142  	}
   143  
   144  	for _, ekey := range ekeys {
   145  		// Key ID cannot be duplicated.
   146  		has, err := db.GetEngine(ctx).Where("key_id=?", ekey.PrimaryKey.KeyIdString()).
   147  			Get(new(GPGKey))
   148  		if err != nil {
   149  			return nil, err
   150  		} else if has {
   151  			return nil, ErrGPGKeyIDAlreadyUsed{ekey.PrimaryKey.KeyIdString()}
   152  		}
   153  
   154  		// Get DB session
   155  
   156  		key, err := parseGPGKey(ctx, ownerID, ekey, verified)
   157  		if err != nil {
   158  			return nil, err
   159  		}
   160  
   161  		if err = addGPGKey(ctx, key, content); err != nil {
   162  			return nil, err
   163  		}
   164  		keys = append(keys, key)
   165  	}
   166  	return keys, committer.Commit()
   167  }