1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package engine
5
6import (
7	"errors"
8	"fmt"
9
10	"github.com/keybase/client/go/libkb"
11	keybase1 "github.com/keybase/client/go/protocol/keybase1"
12)
13
14type PGPPullPrivate struct {
15	arg keybase1.PGPPullPrivateArg
16}
17
18func (e *PGPPullPrivate) Name() string {
19	return "PGPPullPrivate"
20}
21
22func (e *PGPPullPrivate) Prereqs() Prereqs {
23	return Prereqs{}
24}
25
26func (e *PGPPullPrivate) RequiredUIs() []libkb.UIKind {
27	return []libkb.UIKind{}
28}
29
30func (e *PGPPullPrivate) SubConsumers() []libkb.UIConsumer {
31	return []libkb.UIConsumer{}
32}
33
34func NewPGPPullPrivate(arg keybase1.PGPPullPrivateArg) *PGPPullPrivate {
35	return &PGPPullPrivate{arg}
36}
37
38func (e *PGPPullPrivate) read(m libkb.MetaContext, fs *keybase1.SimpleFSClient, filepath string) (armored string, err error) {
39	opid, err := fs.SimpleFSMakeOpid(m.Ctx())
40	if err != nil {
41		return "", err
42	}
43	err = fs.SimpleFSOpen(m.Ctx(), keybase1.SimpleFSOpenArg{
44		OpID:  opid,
45		Dest:  keybase1.NewPathWithKbfsPath(filepath),
46		Flags: keybase1.OpenFlags_READ | keybase1.OpenFlags_EXISTING,
47	})
48	if err != nil {
49		return "", fmt.Errorf("pgp key not found; you may need to run `keybase pgp push-private` first (error: %s)", err)
50	}
51	defer fs.SimpleFSClose(m.Ctx(), opid)
52	var offset int64
53	bufsize := 64 * 1024
54	var data []byte
55	for {
56		m.Debug("SimpleFS: Reading at %d", offset)
57
58		content, err := fs.SimpleFSRead(m.Ctx(), keybase1.SimpleFSReadArg{
59			OpID:   opid,
60			Offset: offset,
61			Size:   bufsize,
62		})
63		if err != nil {
64			return "", err
65		}
66		m.Debug("SimpleFS: Read %d", len(content.Data))
67
68		if len(content.Data) > 0 {
69			offset += int64(len(content.Data))
70			data = append(data, content.Data...)
71		} else {
72			break
73		}
74	}
75	return string(data), nil
76}
77
78func (e *PGPPullPrivate) pull(m libkb.MetaContext, fp libkb.PGPFingerprint, tty string, fs *keybase1.SimpleFSClient) error {
79
80	username := m.CurrentUsername()
81	if username.IsNil() {
82		return libkb.NewLoginRequiredError("no username found")
83	}
84
85	filepath := "/private/" + username.String() + "/.keys/pgp/" + fp.String() + ".asc"
86
87	armored, err := e.read(m, fs, filepath)
88	if err != nil {
89		return err
90	}
91
92	err = m.G().GetGpgClient().ExportKeyArmored(m, armored)
93	if err != nil {
94		return err
95	}
96	return nil
97}
98
99func (e *PGPPullPrivate) Run(m libkb.MetaContext) (err error) {
100
101	defer m.Trace("PGPPullPrivate#Run", &err)()
102
103	tty, err := m.UIs().GPGUI.GetTTY(m.Ctx())
104	if err != nil {
105		return err
106	}
107
108	fingerprints, err := getPrivateFingerprints(m, e.arg.Fingerprints)
109	if err != nil {
110		return err
111	}
112	if len(fingerprints) == 0 {
113		return errors.New("no PGP keys provided")
114	}
115
116	fs, err := simpleFSClient(m)
117	if err != nil {
118		return err
119	}
120
121	for _, fp := range fingerprints {
122		err = e.pull(m, fp, tty, fs)
123		if err != nil {
124			return err
125		}
126	}
127
128	return nil
129}
130