service_identity.go (5980B)
1 // This file is part of gnunet-go, a GNUnet-implementation in Golang. 2 // Copyright (C) 2019-2022 Bernd Fix >Y< 3 // 4 // gnunet-go is free software: you can redistribute it and/or modify it 5 // under the terms of the GNU Affero General Public License as published 6 // by the Free Software Foundation, either version 3 of the License, 7 // or (at your option) any later version. 8 // 9 // gnunet-go is distributed in the hope that it will be useful, but 10 // WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 // Affero General Public License for more details. 13 // 14 // You should have received a copy of the GNU Affero General Public License 15 // along with this program. If not, see <http://www.gnu.org/licenses/>. 16 // 17 // SPDX-License-Identifier: AGPL3.0-or-later 18 19 package zonemaster 20 21 import ( 22 "context" 23 "fmt" 24 "gnunet/core" 25 "gnunet/crypto" 26 "gnunet/message" 27 "gnunet/service/store" 28 "gnunet/transport" 29 "gnunet/util" 30 31 "github.com/bfix/gospel/logger" 32 ) 33 34 //---------------------------------------------------------------------- 35 // "GNUnet Identity" service implementation: 36 //---------------------------------------------------------------------- 37 38 type IdentitySession struct { 39 id int 40 updates bool 41 back transport.Responder 42 } 43 44 type Identity struct{} 45 46 type IdentityService struct { 47 zm *ZoneMaster // reference to main service 48 clients *util.Map[int, *IdentitySession] // client sessions 49 } 50 51 func NewIdentityService(zm *ZoneMaster) *IdentityService { 52 srv := new(IdentityService) 53 srv.zm = zm 54 srv.clients = util.NewMap[int, *IdentitySession]() 55 return srv 56 } 57 58 func (ident *IdentityService) NewSession(id int, back transport.Responder) { 59 sess := &IdentitySession{ 60 id: id, 61 updates: false, 62 back: back, 63 } 64 ident.clients.Put(id, sess, 0) 65 } 66 67 func (ident *IdentityService) CloseSession(id int) { 68 ident.clients.Delete(id, 0) 69 } 70 71 func (ident *IdentityService) FollowUpdates(id int) *IdentitySession { 72 if sess, ok := ident.clients.Get(id, 0); ok { 73 sess.updates = true 74 return sess 75 } 76 return nil 77 } 78 79 func (ident *IdentityService) Start(ctx context.Context, id int) (err error) { 80 // flag client as update receiver 81 sess := ident.FollowUpdates(id) 82 if sess == nil { 83 err = fmt.Errorf("no session available for client %d", id) 84 return 85 } 86 // initial update is to send all existing identites 87 var list []*store.Zone 88 if list, err = ident.zm.zdb.GetZones(""); err != nil { 89 return 90 } 91 for _, ident := range list { 92 resp := message.NewIdentityUpdateMsg(ident.Name, ident.Key) 93 logger.Printf(logger.DBG, "[identity:%d] Sending %v", id, resp) 94 if err = sess.back.Send(ctx, resp); err != nil { 95 logger.Printf(logger.ERROR, "[identity:%d] Can't send response (%v): %v\n", id, resp, err) 96 return 97 } 98 } 99 // terminate with EOL 100 resp := message.NewIdentityUpdateMsg("", nil) 101 if err = sess.back.Send(ctx, resp); err != nil { 102 logger.Printf(logger.ERROR, "[identity:%d] Can't send response (%v): %v\n", id, resp, err) 103 return 104 } 105 return 106 } 107 108 func (ident *IdentityService) Create(ctx context.Context, cid int, zk *crypto.ZonePrivate, name string) (err error) { 109 // get client session 110 sess, ok := ident.clients.Get(cid, 0) 111 if !ok { 112 err = fmt.Errorf("no session available for client %d", cid) 113 return 114 } 115 // add identity 116 id := store.NewZone(name, zk) 117 err = ident.zm.zdb.SetZone(id) 118 rc := 0 119 if err != nil { 120 rc = 1 121 } 122 resp := message.NewIdentityResultCodeMsg(rc) 123 if err = sess.back.Send(ctx, resp); err != nil { 124 logger.Printf(logger.ERROR, "[identity:%d] Can't send response (%v): %v\n", cid, resp, err) 125 return 126 } 127 return 128 } 129 130 // HandleMessage processes a single incoming message 131 func (ident *IdentityService) HandleMessage(ctx context.Context, sender *util.PeerID, msg message.Message, back transport.Responder) bool { 132 // assemble log label 133 var id int 134 var label string 135 if v := ctx.Value(core.CtxKey("params")); v != nil { 136 if ps, ok := v.(util.ParameterSet); ok { 137 label, _ = util.GetParam[string](ps, "label") 138 id, _ = util.GetParam[int](ps, "id") 139 } 140 } 141 // perform lookup 142 switch m := msg.(type) { 143 144 // start identity update listener 145 case *message.IdentityStartMsg: 146 if err := ident.Start(ctx, id); err != nil { 147 logger.Printf(logger.ERROR, "[identity%s] Identity session for %d failed: %v\n", label, id, err) 148 return false 149 } 150 151 // create a new identity with given private key 152 case *message.IdentityCreateMsg: 153 if err := ident.Create(ctx, id, m.ZoneKey, m.Name()); err != nil { 154 logger.Printf(logger.ERROR, "[identity%s] Identity create failed: %v\n", label, err) 155 return false 156 } 157 158 // rename identity 159 case *message.IdentityRenameMsg: 160 id, err := ident.zm.zdb.GetZoneByName(m.OldName()) 161 if err != nil { 162 logger.Printf(logger.ERROR, "[identity%s] Identity lookup failed: %v\n", label, err) 163 return false 164 } 165 // change name 166 id.Name = m.NewName() 167 err = ident.zm.zdb.SetZone(id) 168 169 // send response 170 rc := 0 171 if err != nil { 172 rc = 1 173 } 174 resp := message.NewIdentityResultCodeMsg(rc) 175 if !sendResponse(ctx, "identity"+label, resp, back) { 176 return false 177 } 178 179 // delete identity 180 case *message.IdentityDeleteMsg: 181 id, err := ident.zm.zdb.GetZoneByName(m.Name()) 182 if err != nil { 183 logger.Printf(logger.ERROR, "[identity%s] Identity lookup failed: %v\n", label, err) 184 return false 185 } 186 // delete in database 187 id.Name = "" 188 err = ident.zm.zdb.SetZone(id) 189 190 // send response 191 rc := 0 192 if err != nil { 193 rc = 1 194 } 195 resp := message.NewIdentityResultCodeMsg(rc) 196 if !sendResponse(ctx, "identity"+label, resp, back) { 197 return false 198 } 199 200 // lookup identity 201 case *message.IdentityLookupMsg: 202 id, err := ident.zm.zdb.GetZoneByName(m.Name) 203 if err != nil { 204 logger.Printf(logger.ERROR, "[identity%s] Identity lookup failed: %v\n", label, err) 205 return false 206 } 207 resp := message.NewIdentityUpdateMsg(id.Name, id.Key) 208 if !sendResponse(ctx, "identity"+label, resp, back) { 209 return false 210 } 211 } 212 return true 213 }