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 }