github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/paperkey.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  // PaperKey creates paper backup keys for a user and pushes them to the server.
     5  // It checks for existing paper devices and offers to revoke the
     6  // keys.
     7  //
     8  
     9  package engine
    10  
    11  import (
    12  	"fmt"
    13  
    14  	"golang.org/x/net/context"
    15  
    16  	"github.com/keybase/client/go/libkb"
    17  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    18  )
    19  
    20  // PaperKey is an engine.
    21  type PaperKey struct {
    22  	passphrase libkb.PaperKeyPhrase
    23  	gen        *PaperKeyGen
    24  	libkb.Contextified
    25  }
    26  
    27  // NewPaperKey creates a PaperKey engine.
    28  func NewPaperKey(g *libkb.GlobalContext) *PaperKey {
    29  	return &PaperKey{
    30  		Contextified: libkb.NewContextified(g),
    31  	}
    32  }
    33  
    34  // Name is the unique engine name.
    35  func (e *PaperKey) Name() string {
    36  	return "PaperKey"
    37  }
    38  
    39  // GetPrereqs returns the engine prereqs.
    40  func (e *PaperKey) Prereqs() Prereqs {
    41  	return Prereqs{
    42  		Device: true,
    43  	}
    44  }
    45  
    46  // RequiredUIs returns the required UIs.
    47  func (e *PaperKey) RequiredUIs() []libkb.UIKind {
    48  	return []libkb.UIKind{
    49  		libkb.LoginUIKind,
    50  	}
    51  }
    52  
    53  // SubConsumers returns the other UI consumers for this engine.
    54  func (e *PaperKey) SubConsumers() []libkb.UIConsumer {
    55  	return []libkb.UIConsumer{
    56  		&RevokeEngine{},
    57  		&PaperKeyGen{},
    58  	}
    59  }
    60  
    61  // Run starts the engine.
    62  func (e *PaperKey) Run(m libkb.MetaContext) error {
    63  	m.G().LocalSigchainGuard().Set(m.Ctx(), "PaperKey")
    64  	defer m.G().LocalSigchainGuard().Clear(m.Ctx(), "PaperKey")
    65  
    66  	me, err := libkb.LoadMe(libkb.NewLoadUserArgWithMetaContext(m))
    67  	if err != nil {
    68  		return err
    69  	}
    70  
    71  	// check for existing paper keys
    72  	cki := me.GetComputedKeyInfos()
    73  	if cki == nil {
    74  		return fmt.Errorf("no computed key infos")
    75  	}
    76  
    77  	var needReload bool
    78  	var devicesToRevoke []*libkb.Device
    79  	for i, bdev := range cki.PaperDevices() {
    80  		revoke, err := m.UIs().LoginUI.PromptRevokePaperKeys(context.TODO(),
    81  			keybase1.PromptRevokePaperKeysArg{
    82  				Device: *bdev.ProtExport(),
    83  				Index:  i,
    84  			})
    85  		if err != nil {
    86  			m.Warning("prompt error: %s", err)
    87  			return err
    88  		}
    89  		if revoke {
    90  			devicesToRevoke = append(devicesToRevoke, bdev)
    91  		}
    92  	}
    93  
    94  	// Revoke all keys at once, not one-by-one. This way, a cancelation of the
    95  	// experience above will stop all operations
    96  	for _, bdev := range devicesToRevoke {
    97  		reng := NewRevokeDeviceEngine(m.G(), RevokeDeviceEngineArgs{ID: bdev.ID})
    98  		if err := RunEngine2(m, reng); err != nil {
    99  			// probably not a good idea to continue...
   100  			return err
   101  		}
   102  		needReload = true
   103  	}
   104  
   105  	if needReload {
   106  		me, err = libkb.LoadMe(libkb.NewLoadUserArgWithMetaContext(m))
   107  		if err != nil {
   108  			return err
   109  		}
   110  	}
   111  
   112  	ska1 := libkb.SecretKeyArg{
   113  		Me:      me,
   114  		KeyType: libkb.DeviceSigningKeyType,
   115  	}
   116  	signingKey, err := m.G().Keyrings.GetSecretKeyWithPrompt(m, m.SecretKeyPromptArg(ska1, "You must sign your new paper key"))
   117  	if err != nil {
   118  		return err
   119  	}
   120  
   121  	ska2 := libkb.SecretKeyArg{
   122  		Me:      me,
   123  		KeyType: libkb.DeviceEncryptionKeyType,
   124  	}
   125  	encryptionKeyGeneric, err := m.G().Keyrings.GetSecretKeyWithPrompt(m, m.SecretKeyPromptArg(ska2, "You must encrypt for your new paper key"))
   126  	if err != nil {
   127  		return err
   128  	}
   129  	encryptionKey, ok := encryptionKeyGeneric.(libkb.NaclDHKeyPair)
   130  	if !ok {
   131  		return fmt.Errorf("Unexpected encryption key type")
   132  	}
   133  
   134  	e.passphrase, err = libkb.MakePaperKeyPhrase(libkb.PaperKeyVersion)
   135  	if err != nil {
   136  		return err
   137  	}
   138  
   139  	kgarg := &PaperKeyGenArg{
   140  		Passphrase:     e.passphrase,
   141  		Me:             me,
   142  		SigningKey:     signingKey,
   143  		EncryptionKey:  encryptionKey,
   144  		PerUserKeyring: nil,
   145  	}
   146  	e.gen = NewPaperKeyGen(m.G(), kgarg)
   147  	if err := RunEngine2(m, e.gen); err != nil {
   148  		return err
   149  	}
   150  
   151  	return m.UIs().LoginUI.DisplayPaperKeyPhrase(m.Ctx(), keybase1.DisplayPaperKeyPhraseArg{Phrase: e.passphrase.String()})
   152  
   153  }
   154  
   155  func (e *PaperKey) Passphrase() string {
   156  	return e.passphrase.String()
   157  }
   158  
   159  func (e *PaperKey) SigKey() libkb.GenericKey {
   160  	return e.gen.SigKey()
   161  }
   162  
   163  func (e *PaperKey) EncKey() libkb.GenericKey {
   164  	return e.gen.EncKey()
   165  }
   166  
   167  func (e *PaperKey) DeviceID() keybase1.DeviceID {
   168  	return e.gen.DeviceID()
   169  }