1package libkb
2
3import (
4	"sync"
5	"time"
6
7	keybase1 "github.com/keybase/client/go/protocol/keybase1"
8)
9
10type KeychainMode int
11
12const (
13	KeychainModeNone   KeychainMode = 0
14	KeychainModeOS     KeychainMode = 1
15	KeychainModeMemory KeychainMode = 2
16)
17
18type DeviceWithKeys struct {
19	signingKey    GenericKey
20	encryptionKey GenericKey
21	deviceID      keybase1.DeviceID
22	deviceName    string
23	deviceCtime   keybase1.Time
24	keychainMode  KeychainMode
25}
26
27func NewDeviceWithKeys(signingKey, encryptionKey GenericKey, deviceID keybase1.DeviceID, deviceName string, keychainMode KeychainMode) *DeviceWithKeys {
28	return &DeviceWithKeys{
29		signingKey:    signingKey,
30		encryptionKey: encryptionKey,
31		deviceID:      deviceID,
32		deviceName:    deviceName,
33		keychainMode:  keychainMode,
34	}
35}
36func NewDeviceWithKeysOnly(signingKey, encryptionKey GenericKey, keychainMode KeychainMode) *DeviceWithKeys {
37	return &DeviceWithKeys{
38		signingKey:    signingKey,
39		encryptionKey: encryptionKey,
40		keychainMode:  keychainMode,
41	}
42}
43func (d DeviceWithKeys) EncryptionKey() GenericKey {
44	return d.encryptionKey
45}
46func (d DeviceWithKeys) SigningKey() GenericKey {
47	return d.signingKey
48}
49func (d DeviceWithKeys) DeviceID() keybase1.DeviceID {
50	return d.deviceID
51}
52func (d DeviceWithKeys) DeviceName() string {
53	return d.deviceName
54}
55func (d DeviceWithKeys) DeviceCtime() keybase1.Time {
56	return d.deviceCtime
57}
58func (d *DeviceWithKeys) SetDeviceInfo(i keybase1.DeviceID, n string) {
59	d.deviceID = i
60	d.deviceName = n
61}
62
63func (d DeviceWithKeys) HasBothKeys() bool {
64	return d.signingKey != nil && d.encryptionKey != nil
65}
66
67type SelfDestructingDeviceWithKeys struct {
68	sync.Mutex
69	deviceWithKeys    *DeviceWithKeys
70	testPostCleanHook func()
71}
72
73func NewSelfDestructingDeviceWithKeys(m MetaContext, k *DeviceWithKeys, d time.Duration) *SelfDestructingDeviceWithKeys {
74	ret := &SelfDestructingDeviceWithKeys{
75		deviceWithKeys: k,
76	}
77	go ret.setFuse(m, d)
78	return ret
79}
80
81func (s *SelfDestructingDeviceWithKeys) setFuse(m MetaContext, d time.Duration) {
82	<-m.G().Clock().After(d)
83	s.Lock()
84	defer s.Unlock()
85	s.deviceWithKeys = nil
86	if s.testPostCleanHook != nil {
87		s.testPostCleanHook()
88	}
89}
90
91func (s *SelfDestructingDeviceWithKeys) SetTestPostCleanHook(f func()) {
92	s.Lock()
93	defer s.Unlock()
94	s.testPostCleanHook = f
95}
96
97func (s *SelfDestructingDeviceWithKeys) DeviceWithKeys() *DeviceWithKeys {
98	s.Lock()
99	defer s.Unlock()
100	if s.deviceWithKeys == nil {
101		return nil
102	}
103	ret := *s.deviceWithKeys
104	return &ret
105}
106
107type ownerDeviceReply struct {
108	Status      AppStatus         `json:"status"`
109	UID         keybase1.UID      `json:"uid"`
110	DeviceID    keybase1.DeviceID `json:"device_id"`
111	DeviceName  string            `json:"device_name"`
112	DeviceCtime keybase1.Time     `json:"device_ctime"`
113}
114
115func (o *ownerDeviceReply) GetAppStatus() *AppStatus {
116	return &o.Status
117}
118
119func (d *DeviceWithKeys) Populate(m MetaContext) (uid keybase1.UID, err error) {
120	arg := APIArg{
121		Endpoint:    "key/owner/device",
122		SessionType: APISessionTypeNONE,
123		Args:        HTTPArgs{"kid": S{Val: d.signingKey.GetKID().String()}},
124	}
125	var res ownerDeviceReply
126	if err = m.G().API.GetDecode(m, arg, &res); err != nil {
127		return uid, err
128	}
129	d.deviceID = res.DeviceID
130	d.deviceName = res.DeviceName
131	d.deviceCtime = res.DeviceCtime
132	return res.UID, nil
133}
134
135func (d *DeviceWithKeys) ToProvisioningKeyActiveDevice(m MetaContext, uv keybase1.UserVersion) *ActiveDevice {
136	return NewProvisioningKeyActiveDevice(m, uv, d)
137}
138