github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/pgp_purge.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 engine
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"os"
    10  	"path/filepath"
    11  
    12  	"github.com/keybase/client/go/libkb"
    13  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    14  )
    15  
    16  // PGPPurge is an engine.
    17  type PGPPurge struct {
    18  	libkb.Contextified
    19  	arg       keybase1.PGPPurgeArg
    20  	me        *libkb.User
    21  	filenames []string
    22  }
    23  
    24  // NewPGPPurge creates a PGPPurge engine.
    25  func NewPGPPurge(g *libkb.GlobalContext, arg keybase1.PGPPurgeArg) *PGPPurge {
    26  	return &PGPPurge{
    27  		Contextified: libkb.NewContextified(g),
    28  		arg:          arg,
    29  	}
    30  }
    31  
    32  // Name is the unique engine name.
    33  func (e *PGPPurge) Name() string {
    34  	return "PGPPurge"
    35  }
    36  
    37  // GetPrereqs returns the engine prereqs.
    38  func (e *PGPPurge) Prereqs() Prereqs {
    39  	return Prereqs{
    40  		Device: true,
    41  	}
    42  }
    43  
    44  // RequiredUIs returns the required UIs.
    45  func (e *PGPPurge) RequiredUIs() []libkb.UIKind {
    46  	return []libkb.UIKind{}
    47  }
    48  
    49  // SubConsumers returns the other UI consumers for this engine.
    50  func (e *PGPPurge) SubConsumers() []libkb.UIConsumer {
    51  	return []libkb.UIConsumer{
    52  		&SaltpackEncrypt{newKeyfinderHook: NewSaltpackUserKeyfinderAsInterface},
    53  	}
    54  }
    55  
    56  // Run starts the engine.
    57  func (e *PGPPurge) Run(m libkb.MetaContext) error {
    58  	me, err := libkb.LoadMe(libkb.NewLoadUserPubOptionalArg(e.G()))
    59  	if err != nil {
    60  		return err
    61  	}
    62  	e.me = me
    63  
    64  	// get all PGP blocks in keyring
    65  	ring, err := m.ActiveDevice().Keyring(m)
    66  	if err != nil {
    67  		return err
    68  	}
    69  	blocks, err := ring.AllPGPBlocks()
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	// export each one to a file
    75  	if err := e.exportBlocks(m, blocks); err != nil {
    76  		return err
    77  	}
    78  
    79  	if e.arg.DoPurge {
    80  		// if purge flag set, remove all PGP blocks from keyring and save it
    81  		err = ring.RemoveAllPGPBlocks()
    82  		if err != nil {
    83  			return err
    84  		}
    85  		err = ring.Save()
    86  		if err != nil {
    87  			return err
    88  		}
    89  	}
    90  
    91  	return nil
    92  }
    93  
    94  // KeyFiles returns the filenames of the exported keys.
    95  func (e *PGPPurge) KeyFiles() []string {
    96  	return e.filenames
    97  }
    98  
    99  func (e *PGPPurge) exportBlocks(m libkb.MetaContext, blocks []*libkb.SKB) error {
   100  	sstore := libkb.NewSecretStore(m, e.me.GetNormalizedName())
   101  	promptArg := libkb.SecretKeyPromptArg{
   102  		SecretUI: m.UIs().SecretUI,
   103  		Reason:   "export private PGP key",
   104  	}
   105  
   106  	for i, block := range blocks {
   107  		block.SetUID(e.me.GetUID())
   108  		key, err := block.PromptAndUnlock(m, promptArg, sstore, e.me)
   109  		if err != nil {
   110  			return err
   111  		}
   112  
   113  		pgpKey, ok := key.(*libkb.PGPKeyBundle)
   114  		if !ok {
   115  			return fmt.Errorf("unlocked key incorrect type")
   116  		}
   117  
   118  		name := fmt.Sprintf("kb-%04d-%s.saltpack", i, pgpKey.GetFingerprint())
   119  		path := filepath.Join(e.G().Env.GetConfigDir(), name)
   120  		if err := e.encryptToFile(m, pgpKey, path); err != nil {
   121  			return err
   122  		}
   123  
   124  		e.filenames = append(e.filenames, path)
   125  	}
   126  
   127  	return nil
   128  }
   129  
   130  func (e *PGPPurge) encryptToFile(m libkb.MetaContext, bundle *libkb.PGPKeyBundle, filename string) error {
   131  	out, err := os.Create(filename)
   132  	if err != nil {
   133  		return err
   134  	}
   135  	defer out.Close()
   136  
   137  	var buf bytes.Buffer
   138  	if err := bundle.EncodeToStream(libkb.NopWriteCloser{W: &buf}, true); err != nil {
   139  		return err
   140  	}
   141  
   142  	// encrypt
   143  	arg := &SaltpackEncryptArg{
   144  		Source: &buf,
   145  		Sink:   out,
   146  		Opts: keybase1.SaltpackEncryptOptions{
   147  			Recipients:       []string{m.CurrentUsername().String()},
   148  			AuthenticityType: keybase1.AuthenticityType_SIGNED,
   149  			UsePaperKeys:     true,
   150  			UseDeviceKeys:    true,
   151  			UseEntityKeys:    true,
   152  		},
   153  	}
   154  	eng := NewSaltpackEncrypt(arg, NewSaltpackUserKeyfinderAsInterface)
   155  	return RunEngine2(m, eng)
   156  }