-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
saltpack_ui.go
159 lines (146 loc) · 7.23 KB
/
saltpack_ui.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.
package client
import (
"fmt"
"golang.org/x/net/context"
"github.com/keybase/client/go/libkb"
keybase1 "github.com/keybase/client/go/protocol/keybase1"
)
type SaltpackUI struct {
libkb.Contextified
terminal libkb.TerminalUI
interactive bool
force bool
}
func (s *SaltpackUI) doNonInteractive(arg keybase1.SaltpackPromptForDecryptArg) error {
var err error
switch arg.Sender.SenderType {
case keybase1.SaltpackSenderType_TRACKING_BROKE:
if s.force {
s.G().Log.Warning("Your view of the sender is broken, but forcing through.")
return nil
}
err = libkb.IdentifyFailedError{Assertion: arg.Sender.Username, Reason: "sender identity failed"}
case keybase1.SaltpackSenderType_REVOKED:
if s.force {
s.G().Log.Warning("The key that authenticated this message is revoked, but forcing through.")
return nil
}
err = libkb.IdentifyFailedError{Assertion: arg.Sender.Username, Reason: "sender key revoked"}
case keybase1.SaltpackSenderType_EXPIRED:
if s.force {
s.G().Log.Warning("The key that authenticated this message is expired, but forcing through.")
return nil
}
err = libkb.IdentifyFailedError{Assertion: arg.Sender.Username, Reason: "sender key expired"}
case keybase1.SaltpackSenderType_NOT_TRACKED:
s.G().Log.Warning("The sender of this message is a Keybase user you don't follow. Consider doing so for even stronger security!")
case keybase1.SaltpackSenderType_TRACKING_OK, keybase1.SaltpackSenderType_SELF, keybase1.SaltpackSenderType_UNKNOWN, keybase1.SaltpackSenderType_ANONYMOUS:
// No need to issue warnings here
default:
panic("unexpected SenderType in SaltpackPromptForDecrypt")
}
if err != nil {
w := s.terminal.ErrorWriter()
fmt.Fprint(w, ColorString(s.G(), "red", "Use --force to decrypt anyway.\n"))
}
return err
}
func (s *SaltpackUI) doInteractive(arg keybase1.SaltpackPromptForDecryptArg) error {
def := libkb.PromptDefaultYes
switch arg.Sender.SenderType {
case keybase1.SaltpackSenderType_TRACKING_OK, keybase1.SaltpackSenderType_SELF:
// No need to ask for confirmation in this case.
return nil
case keybase1.SaltpackSenderType_TRACKING_BROKE, keybase1.SaltpackSenderType_REVOKED, keybase1.SaltpackSenderType_EXPIRED:
def = libkb.PromptDefaultNo
case keybase1.SaltpackSenderType_UNKNOWN, keybase1.SaltpackSenderType_ANONYMOUS, keybase1.SaltpackSenderType_NOT_TRACKED:
// In this case the default answer is yes.
default:
panic("unexpected SenderType in SaltpackPromptForDecrypt")
}
ok, err := s.terminal.PromptYesNo(PromptDescriptorDecryptInteractive, "Go ahead and decrypt?", def)
if err != nil {
return err
}
if !ok {
return libkb.CanceledError{M: "decryption canceled"}
}
return nil
}
func (s *SaltpackUI) SaltpackPromptForDecrypt(_ context.Context, arg keybase1.SaltpackPromptForDecryptArg) (err error) {
w := s.terminal.ErrorWriter()
switch arg.Sender.SenderType {
case keybase1.SaltpackSenderType_TRACKING_OK:
fmt.Fprint(w, ColorString(s.G(), "green", "Authored by %s.\n", ColorString(s.G(), "bold", arg.Sender.Username)))
case keybase1.SaltpackSenderType_NOT_TRACKED:
fmt.Fprint(w, ColorString(s.G(), "green", "Authored by %s (whom you do not follow).\n", ColorString(s.G(), "bold", arg.Sender.Username)))
case keybase1.SaltpackSenderType_UNKNOWN:
fmt.Fprint(w, ColorString(s.G(), "green", "The author of this message is unknown to Keybase (key ID: %s).\n", arg.SigningKID))
case keybase1.SaltpackSenderType_SELF:
fmt.Fprint(w, ColorString(s.G(), "green", "Authored by %s (you).\n", ColorString(s.G(), "bold", arg.Sender.Username)))
case keybase1.SaltpackSenderType_ANONYMOUS:
fmt.Fprint(w, ColorString(s.G(), "green", "The sender of this message has chosen to remain anonymous.\n"))
case keybase1.SaltpackSenderType_TRACKING_BROKE:
fmt.Fprint(w, ColorString(s.G(), "red", "Authored by %s.\nYou follow the sender of this message, but your view of them is broken.\n", ColorString(s.G(), "bold", arg.Sender.Username)))
case keybase1.SaltpackSenderType_REVOKED:
fmt.Fprint(w, ColorString(s.G(), "red", "Authored by %s, however the key that authenticated this message has been revoked (key ID: %s).\n", ColorString(s.G(), "bold", arg.Sender.Username), arg.SigningKID))
case keybase1.SaltpackSenderType_EXPIRED:
fmt.Fprint(w, ColorString(s.G(), "red", "Authored by %s, however the key that authenticated this message has expired (key ID: %s).\n", ColorString(s.G(), "bold", arg.Sender.Username), arg.SigningKID))
default:
return fmt.Errorf("Unexpected sender type: %s", arg.Sender.SenderType)
}
if !s.interactive {
return s.doNonInteractive(arg)
}
return s.doInteractive(arg)
}
func (s *SaltpackUI) SaltpackVerifySuccess(_ context.Context, arg keybase1.SaltpackVerifySuccessArg) error {
// write messages to stderr
w := s.terminal.ErrorWriter()
var un string
switch arg.Sender.SenderType {
case keybase1.SaltpackSenderType_UNKNOWN:
un = fmt.Sprintf("The signer of this message is unknown to Keybase.\nSigning key ID: %s", arg.SigningKID)
case keybase1.SaltpackSenderType_TRACKING_OK:
un = fmt.Sprintf("Signed by %s", ColorString(s.G(), "bold", arg.Sender.Username))
case keybase1.SaltpackSenderType_NOT_TRACKED:
un = fmt.Sprintf("Signed by %s (whom you do not follow)", ColorString(s.G(), "bold", arg.Sender.Username))
s.G().Log.Warning("The sender of this message is a Keybase user you don't follow. Consider doing so for even stronger security!")
case keybase1.SaltpackSenderType_SELF:
un = fmt.Sprintf("Signed by %s (you)", ColorString(s.G(), "bold", arg.Sender.Username))
default:
return fmt.Errorf("Unexpected sender type: %s", arg.Sender.SenderType)
}
fmt.Fprint(w, ColorString(s.G(), "green", "%s.\n", un))
return nil
}
// SaltpackVerifyBadSender is responsible for short-circuiting the output of the bad
// message. It returns an error if the --force argument isn't present, and the
// VerifyEngine bubbles that up. This is similar to doNonInteractive above.
func (s *SaltpackUI) SaltpackVerifyBadSender(_ context.Context, arg keybase1.SaltpackVerifyBadSenderArg) error {
// write messages to stderr
var message string
var errorReason string
switch arg.Sender.SenderType {
case keybase1.SaltpackSenderType_TRACKING_BROKE:
message = fmt.Sprintf("Signed by %s, but their tracking statement is broken.", ColorString(s.G(), "bold", arg.Sender.Username))
errorReason = "tracking statement broken"
case keybase1.SaltpackSenderType_REVOKED:
message = fmt.Sprintf("Signed by %s, but the key they used is revoked:\n %s", ColorString(s.G(), "bold", arg.Sender.Username), arg.SigningKID.String())
errorReason = "sender key revoked"
case keybase1.SaltpackSenderType_EXPIRED:
message = fmt.Sprintf("Signed by %s, but the key they used is expired:\n %s", ColorString(s.G(), "bold", arg.Sender.Username), arg.SigningKID.String())
errorReason = "sender key expired"
default:
return fmt.Errorf("Unexpected bad sender type: %s", arg.Sender.SenderType)
}
w := s.terminal.ErrorWriter()
fmt.Fprint(w, ColorString(s.G(), "red", "Problem verifying the sender: %s\n", message))
if s.force {
return nil
}
fmt.Fprint(w, ColorString(s.G(), "red", "Use --force to see the message anyway.\n"))
return libkb.IdentifyFailedError{Assertion: arg.Sender.Username, Reason: errorReason}
}