forked from keybase/client
-
Notifications
You must be signed in to change notification settings - Fork 0
/
provisionee.go
137 lines (116 loc) · 3.2 KB
/
provisionee.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.
package kex2
import (
"time"
keybase1 "github.com/keybase/client/go/protocol"
rpc "github.com/keybase/go-framed-msgpack-rpc"
"golang.org/x/net/context"
)
type provisionee struct {
baseDevice
arg ProvisioneeArg
done chan error
}
// Provisionee is an interface that abstracts out the crypto and session
// management that a provisionee needs to do as part of the protocol.
type Provisionee interface {
GetLogFactory() rpc.LogFactory
HandleHello(keybase1.HelloArg) (keybase1.HelloRes, error)
HandleDidCounterSign([]byte) error
}
// ProvisioneeArg provides the details that a provisionee needs in order
// to run its course
type ProvisioneeArg struct {
KexBaseArg
Provisionee Provisionee
}
func newProvisionee(arg ProvisioneeArg) *provisionee {
ret := &provisionee{
baseDevice: baseDevice{
start: make(chan struct{}),
},
arg: arg,
done: make(chan error),
}
return ret
}
// RunProvisionee runs a provisionee given the necessary arguments.
func RunProvisionee(arg ProvisioneeArg) error {
p := newProvisionee(arg)
return p.run()
}
// Hello is called via the RPC server interface by the remote client.
// It in turn delegates the work to the passed in Provisionee interface,
// calling HandleHello()
func (p *provisionee) Hello(_ context.Context, arg keybase1.HelloArg) (res keybase1.HelloRes, err error) {
close(p.start)
res, err = p.arg.Provisionee.HandleHello(arg)
if err != nil {
p.done <- err
}
return res, err
}
// DidCounterSign is called via the RPC server interface by the remote client.
// It in turn delegates the work to the passed in Provisionee interface,
// calling HandleDidCounterSign()
func (p *provisionee) DidCounterSign(_ context.Context, sig []byte) (err error) {
err = p.arg.Provisionee.HandleDidCounterSign(sig)
p.done <- err
return err
}
func (p *provisionee) run() (err error) {
if err = p.setDeviceID(); err != nil {
return err
}
if err = p.startServer(p.arg.Secret); err != nil {
return err
}
if err = p.pickFirstConnection(); err != nil {
return err
}
err = <-p.done
return err
}
func (p *provisionee) startServer(s Secret) (err error) {
if p.conn, err = NewConn(p.arg.Ctx, p.arg.Mr, s, p.deviceID, p.arg.Timeout); err != nil {
return err
}
prot := keybase1.Kex2ProvisioneeProtocol(p)
p.xp = rpc.NewTransport(p.conn, p.arg.Provisionee.GetLogFactory(), nil)
srv := rpc.NewServer(p.xp, nil)
if err = srv.Register(prot); err != nil {
return err
}
if err = srv.AddCloseListener(p.done); err != nil {
return err
}
return srv.Run(true)
}
func (p *provisionee) pickFirstConnection() (err error) {
select {
case <-p.start:
case sec := <-p.arg.SecretChannel:
if len(sec) != SecretLen {
return ErrBadSecret
}
p.conn.Close()
err = p.startServer(sec)
if err != nil {
return err
}
cli := keybase1.Kex2ProvisionerClient{Cli: rpc.NewClient(p.xp, nil)}
if err = cli.KexStart(p.arg.Ctx); err != nil {
return err
}
case <-p.arg.Ctx.Done():
err = ErrCanceled
case <-time.After(p.arg.Timeout):
err = ErrTimedOut
}
return
}
func (p *provisionee) setDeviceID() (err error) {
p.deviceID, err = p.arg.getDeviceID()
return err
}