forked from keybase/managed-bots
/
oauth.go
124 lines (105 loc) · 2.98 KB
/
oauth.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
package gcalbot
import (
"context"
"fmt"
"net/http"
"net/url"
"github.com/malware-unicorn/managed-bots/base"
"github.com/malware-unicorn/go-keybase-chat-bot/kbchat/types/chat1"
"golang.org/x/oauth2"
)
func (h *HTTPSrv) oauthHandler(w http.ResponseWriter, r *http.Request) {
var err error
defer func() {
if err != nil {
h.Errorf("oauthHandler: %v", err)
h.showOAuthError(w)
}
}()
if r.URL == nil {
err = fmt.Errorf("r.URL == nil")
return
}
query := r.URL.Query()
state := query.Get("state")
req, err := h.db.GetState(state)
if err != nil {
err = fmt.Errorf("could not get state %q: %v", state, err)
return
} else if req == nil {
// no state is found
h.showOAuthError(w)
return
}
if req.IsComplete {
_, err = w.Write(base.MakeOAuthHTML("gcalbot", "success",
`<div class="success"> Success! </div>
<div>You can now close this page and return to the Keybase app.</div>`,
"/gcalbot/image/logo"))
if err != nil {
h.Errorf("oauthHandler: unable to write: %v", err)
}
return
}
code := query.Get("code")
if code == "" {
// no code is provided
h.showOAuthError(w)
return
}
token, err := h.oauth.Exchange(context.TODO(), code)
if err != nil {
return
}
err = h.db.InsertAccount(Account{
KeybaseUsername: req.KeybaseUsername,
AccountNickname: req.AccountNickname,
Token: *token,
})
if err != nil {
return
}
if err = h.db.CompleteState(state); err != nil {
return
}
loginToken := h.handler.LoginToken(req.KeybaseUsername)
redirectQuery := url.Values{}
redirectQuery.Add("token", loginToken)
redirectQuery.Add("username", req.KeybaseUsername)
redirectQuery.Add("account", req.AccountNickname)
redirectQuery.Add("conv_id", string(req.KeybaseConvID))
path := fmt.Sprintf("/gcalbot?%s", redirectQuery.Encode())
http.Redirect(w, r, path, http.StatusSeeOther)
}
func (h *HTTPSrv) showOAuthError(w http.ResponseWriter) {
if _, err := w.Write(base.MakeOAuthHTML("gcalbot", "error",
"Unable to complete request, please try running the bot command again!",
"/gcalbot/image/logo")); err != nil {
h.Errorf("oauthHandler: unable to write: %v", err)
}
}
func (h *Handler) requestOAuth(msg chat1.MsgSummary, accountNickname string) error {
state, err := base.MakeRequestID()
if err != nil {
return err
}
err = h.db.PutState(state, OAuthRequest{
KeybaseUsername: msg.Sender.Username,
AccountNickname: accountNickname,
KeybaseConvID: msg.ConvID,
})
if err != nil {
return err
}
authURL := h.oauth.AuthCodeURL(state, oauth2.ApprovalForce, oauth2.AccessTypeOffline)
_, err = h.kbc.SendMessageByTlfName(msg.Sender.Username,
"Visit %s to connect a Google account as '%s'.", authURL, accountNickname)
if err != nil {
return err
}
// If we are in a 1-1 conv directly or as a bot user with the sender, skip this message.
if !base.IsDirectPrivateMessage(h.kbc.GetUsername(), msg.Sender.Username, msg.Channel) {
h.ChatEcho(msg.ConvID, "OK! I've sent a message to @%s to authorize me.", msg.Sender.Username)
}
return nil
}