github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/service/device.go (about)

     1  // Copyright 2015 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  	"errors"
     9  
    10  	"github.com/keybase/client/go/engine"
    11  	"github.com/keybase/client/go/gregor"
    12  	"github.com/keybase/client/go/libkb"
    13  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    14  	"github.com/keybase/go-framed-msgpack-rpc/rpc"
    15  	"golang.org/x/net/context"
    16  )
    17  
    18  // DeviceHandler is the RPC handler for the device interface.
    19  type DeviceHandler struct {
    20  	*BaseHandler
    21  	libkb.Contextified
    22  	gregor *gregorHandler
    23  }
    24  
    25  // NewDeviceHandler creates a DeviceHandler for the xp transport.
    26  func NewDeviceHandler(xp rpc.Transporter, g *libkb.GlobalContext, gregor *gregorHandler) *DeviceHandler {
    27  	return &DeviceHandler{
    28  		BaseHandler:  NewBaseHandler(g, xp),
    29  		Contextified: libkb.NewContextified(g),
    30  		gregor:       gregor,
    31  	}
    32  }
    33  
    34  // DeviceList returns a list of all the devices for a user.
    35  func (h *DeviceHandler) DeviceList(ctx context.Context, sessionID int) ([]keybase1.Device, error) {
    36  	uis := libkb.UIs{
    37  		LogUI:     h.getLogUI(sessionID),
    38  		SessionID: sessionID,
    39  	}
    40  	eng := engine.NewDevList(h.G())
    41  	m := libkb.NewMetaContext(ctx, h.G()).WithUIs(uis)
    42  	if err := engine.RunEngine2(m, eng); err != nil {
    43  		return nil, err
    44  	}
    45  	return eng.List(), nil
    46  }
    47  
    48  // DeviceHistoryList returns a list of all the devices for a user,
    49  // with detailed history and provisioner, revoker information.
    50  func (h *DeviceHandler) DeviceHistoryList(nctx context.Context, sessionID int) ([]keybase1.DeviceDetail, error) {
    51  	uis := libkb.UIs{
    52  		LogUI:     h.getLogUI(sessionID),
    53  		SessionID: sessionID,
    54  	}
    55  	eng := engine.NewDeviceHistorySelf(h.G())
    56  	m := libkb.NewMetaContext(nctx, h.G()).WithUIs(uis)
    57  	if err := engine.RunEngine2(m, eng); err != nil {
    58  		return nil, err
    59  	}
    60  	return eng.Devices(), nil
    61  }
    62  
    63  // DeviceAdd starts the kex2 device provisioning on the
    64  // provisioner (device X/C1)
    65  func (h *DeviceHandler) DeviceAdd(c context.Context, sessionID int) error {
    66  	uis := libkb.UIs{
    67  		ProvisionUI: h.getProvisionUI(sessionID),
    68  		SecretUI:    h.getSecretUI(sessionID, h.G()),
    69  		SessionID:   sessionID,
    70  	}
    71  	m := libkb.NewMetaContext(c, h.G()).WithUIs(uis)
    72  	eng := engine.NewDeviceAdd(h.G())
    73  	return engine.RunEngine2(m, eng)
    74  }
    75  
    76  // CheckDeviceNameFormat verifies that the device name has a valid
    77  // format.
    78  func (h *DeviceHandler) CheckDeviceNameFormat(_ context.Context, arg keybase1.CheckDeviceNameFormatArg) (bool, error) {
    79  	ok := libkb.CheckDeviceName.F(arg.Name)
    80  	if ok {
    81  		return ok, nil
    82  	}
    83  	return false, errors.New(libkb.CheckDeviceName.Hint)
    84  }
    85  
    86  type _deviceChange struct {
    87  	DeviceID string `json:"device_id"`
    88  }
    89  
    90  func LoopAndDismissForDeviceChangeNotifications(mctx libkb.MetaContext, dismisser libkb.GregorState,
    91  	gregorState gregor.State, exceptedDeviceID string) (err error) {
    92  
    93  	items, err := gregorState.Items()
    94  	if err != nil {
    95  		return err
    96  	}
    97  	var body _deviceChange
    98  	for _, item := range items {
    99  		category := item.Category().String()
   100  		if !(category == "device.revoked" || category == "device.new") {
   101  			continue
   102  		}
   103  		err := json.Unmarshal(item.Body().Bytes(), &body)
   104  		if err != nil {
   105  			return err
   106  		}
   107  		itemID := item.Metadata().MsgID()
   108  		if body.DeviceID != exceptedDeviceID {
   109  			mctx.Debug("dismissing device notification %s for %s", category, body.DeviceID)
   110  			err := dismisser.DismissItem(mctx.Ctx(), nil, itemID)
   111  			if err != nil {
   112  				return err
   113  			}
   114  		}
   115  	}
   116  	return nil
   117  }
   118  
   119  func (h *DeviceHandler) DismissDeviceChangeNotifications(c context.Context) (err error) {
   120  	mctx := libkb.NewMetaContext(c, h.G())
   121  	defer mctx.Trace("DismissDeviceChangeNotifications", &err)()
   122  
   123  	gcli, err := h.gregor.getGregorCli()
   124  	if err != nil {
   125  		return err
   126  	}
   127  	state, err := gcli.StateMachineState(c, nil, true)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	activeDeviceID := h.G().ActiveDevice.DeviceID().String()
   132  	dismisser := h.G().GregorState
   133  	err = LoopAndDismissForDeviceChangeNotifications(mctx, dismisser, state, activeDeviceID)
   134  	return err
   135  }
   136  
   137  func (h *DeviceHandler) CheckDeviceNameForUser(ctx context.Context, arg keybase1.CheckDeviceNameForUserArg) error {
   138  	mctx := libkb.NewMetaContext(ctx, h.G())
   139  	_, err := mctx.G().API.Get(mctx, libkb.APIArg{
   140  		Endpoint:    "device/check_name",
   141  		SessionType: libkb.APISessionTypeNONE,
   142  		Args: libkb.HTTPArgs{
   143  			"username":   libkb.S{Val: arg.Username},
   144  			"devicename": libkb.S{Val: arg.Devicename},
   145  		},
   146  	})
   147  
   148  	if err == nil {
   149  		return err
   150  	}
   151  
   152  	if apiErr, ok := err.(*libkb.APIError); ok {
   153  		switch apiErr.Code {
   154  		case libkb.SCDeviceNameInUse:
   155  			return libkb.DeviceNameInUseError{}
   156  		case libkb.SCInputError:
   157  			return libkb.DeviceBadNameError{}
   158  		}
   159  	}
   160  
   161  	return err
   162  }