github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/service/user_handler.go (about)

     1  // Copyright 2016 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package service
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"strings"
    10  
    11  	"golang.org/x/net/context"
    12  
    13  	"github.com/keybase/client/go/gregor"
    14  	"github.com/keybase/client/go/libkb"
    15  	gregor1 "github.com/keybase/client/go/protocol/gregor1"
    16  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    17  )
    18  
    19  const userHandlerName = "userHandler"
    20  
    21  type userHandler struct {
    22  	libkb.Contextified
    23  	userBlockedHandlers []UserBlockedHandler
    24  }
    25  
    26  type UserBlockedHandler interface {
    27  	UserBlocked(m libkb.MetaContext, badUIDs map[keybase1.UID]bool) error
    28  }
    29  
    30  func newUserHandler(g *libkb.GlobalContext) *userHandler {
    31  	return &userHandler{
    32  		Contextified: libkb.NewContextified(g),
    33  	}
    34  }
    35  
    36  func (r *userHandler) PushUserBlockedHandler(h UserBlockedHandler) {
    37  	r.userBlockedHandlers = append(r.userBlockedHandlers, h)
    38  }
    39  
    40  func (r *userHandler) Create(ctx context.Context, cli gregor1.IncomingInterface, category string, item gregor.Item) (bool, error) {
    41  	m := libkb.NewMetaContext(ctx, r.G())
    42  	switch category {
    43  	case "user.key_change":
    44  		return true, r.keyChange(m)
    45  	case "user.identity_change":
    46  		return true, r.identityChange(m)
    47  	case "user.password_change":
    48  		return true, r.passwordChange(m, cli, category, item)
    49  	case "user.passphrase_state":
    50  		return true, r.passphraseStateUpdate(m, cli, category, item)
    51  	case "user.blocked":
    52  		return true, r.userBlocked(m, cli, category, item)
    53  	default:
    54  		if strings.HasPrefix(category, "user.") {
    55  			return false, fmt.Errorf("unknown userHandler category: %q", category)
    56  		}
    57  		return false, nil
    58  	}
    59  }
    60  
    61  func (r *userHandler) keyChange(m libkb.MetaContext) error {
    62  	m.G().KeyfamilyChanged(m.Ctx(), m.G().Env.GetUID())
    63  
    64  	// check if this device was just revoked and if so, log out
    65  	return m.LogoutAndDeprovisionIfRevoked()
    66  }
    67  
    68  func (r *userHandler) identityChange(m libkb.MetaContext) error {
    69  	m.G().UserChanged(m.Ctx(), m.G().Env.GetUID())
    70  	return nil
    71  }
    72  
    73  func (r *userHandler) passwordChange(m libkb.MetaContext, cli gregor1.IncomingInterface, category string, item gregor.Item) error {
    74  	m.Debug("userHandler: %s received", category)
    75  	return r.G().GregorState.DismissItem(m.Ctx(), cli, item.Metadata().MsgID())
    76  }
    77  
    78  func (r *userHandler) passphraseStateUpdate(m libkb.MetaContext, cli gregor1.IncomingInterface, category string, item gregor.Item) error {
    79  	m.Debug("userHandler: %s received", category)
    80  	var msg keybase1.UserPassphraseStateMsg
    81  	if err := json.Unmarshal(item.Body().Bytes(), &msg); err != nil {
    82  		m.Warning("error unmarshaling user.passphrase_update item: %s", err)
    83  		return err
    84  	}
    85  	libkb.MaybeSavePassphraseState(m, msg.PassphraseState)
    86  	r.G().NotifyRouter.HandlePasswordChanged(m.Ctx(), msg.PassphraseState)
    87  	// Don't dismiss the item, so other devices know about it
    88  	return nil
    89  }
    90  
    91  func (r *userHandler) userBlocked(m libkb.MetaContext, cli gregor1.IncomingInterface, category string, item gregor.Item) error {
    92  	m.Debug("userHandler: %s received", category)
    93  	var msg keybase1.UserBlockedBody
    94  	if err := json.Unmarshal(item.Body().Bytes(), &msg); err != nil {
    95  		m.Warning("error unmarshaling user.blocked item: %s", err)
    96  		return err
    97  	}
    98  	m.Debug("Got user.blocked item: %+v", msg)
    99  	badUIDs := make(map[keybase1.UID]bool)
   100  
   101  	for _, r := range msg.Blocks {
   102  		if (r.Chat != nil && *r.Chat) || (r.Follow != nil && *r.Follow) {
   103  			badUIDs[r.Uid] = true
   104  		}
   105  
   106  		// regardless of status, clear user card cache for any uid
   107  		// that changed
   108  		if err := m.G().CardCache().Delete(r.Uid); err != nil {
   109  			m.Debug("CardCache.Delete(%s) error: %s", r.Uid, err)
   110  		}
   111  	}
   112  
   113  	// Ignore the error if we fail to block properly
   114  	_ = libkb.NewServertrustTrackerSyncer(m.G(), msg.Uid, libkb.FollowDirectionFollowing).Block(m, badUIDs)
   115  
   116  	m.Debug("Got user.blocked blocked UIDs %+v", badUIDs)
   117  	for _, h := range r.userBlockedHandlers {
   118  		tmp := h.UserBlocked(m, badUIDs)
   119  		if tmp != nil {
   120  			m.Warning("Error handling UserBlocked message: %s", tmp)
   121  		}
   122  	}
   123  
   124  	r.G().NotifyRouter.HandleUserBlocked(m.Ctx(), msg)
   125  
   126  	r.G().GetStellar().Refresh(m, "user.blocked message")
   127  
   128  	// dismiss this locally so it is only processed once per device
   129  	if err := r.G().GregorState.LocalDismissItem(m.Ctx(), item.Metadata().MsgID()); err != nil {
   130  		m.Warning("error in LocalDismissItem: %s", err)
   131  	}
   132  
   133  	return nil
   134  }
   135  
   136  func (r *userHandler) Dismiss(ctx context.Context, cli gregor1.IncomingInterface, category string, item gregor.Item) (bool, error) {
   137  	return false, nil
   138  }
   139  
   140  func (r *userHandler) IsAlive() bool {
   141  	return true
   142  }
   143  
   144  func (r *userHandler) Name() string {
   145  	return userHandlerName
   146  }