gnunet-go

GNUnet Bindings for Go
Log | Files | Refs | README | LICENSE

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 }