forked from markbates/goth
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mailru.go
138 lines (113 loc) · 3.54 KB
/
mailru.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
// Package mailru implements the OAuth2 protocol for authenticating users through mailru.com.
// This package can be used as a reference implementation of an OAuth2 provider for Goth.
package mailru
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"github.com/markbates/goth"
"golang.org/x/oauth2"
)
const (
authURL = "https://oauth.mail.ru/login"
tokenURL = "https://oauth.mail.ru/token"
endpointUser = "https://oauth.mail.ru/userinfo"
)
// New creates a new MAILRU provider and sets up important connection details.
// You should always call `mailru.New` to get a new provider. Never try to
// create one manually.
func New(clientID, clientSecret, redirectURL string, scopes ...string) *Provider {
var c = &oauth2.Config{
ClientID: clientID,
ClientSecret: clientSecret,
RedirectURL: redirectURL,
Endpoint: oauth2.Endpoint{
AuthURL: authURL,
TokenURL: tokenURL,
},
Scopes: []string{},
}
c.Scopes = append(c.Scopes, scopes...)
return &Provider{
name: "mailru",
oauthConfig: c,
}
}
// Provider is the implementation of `goth.Provider` for accessing MAILRU.
type Provider struct {
name string
httpClient *http.Client
oauthConfig *oauth2.Config
}
// Name is the name used to retrieve this provider later.
func (p *Provider) Name() string {
return p.name
}
// SetName is to update the name of the provider (needed in case of multiple providers of 1 type)
func (p *Provider) SetName(name string) {
p.name = name
}
func (p *Provider) Client() *http.Client {
return goth.HTTPClientWithFallBack(p.httpClient)
}
// BeginAuth asks MAILRU for an authentication end-point.
func (p *Provider) BeginAuth(state string) (goth.Session, error) {
return &Session{
AuthURL: p.oauthConfig.AuthCodeURL(state),
}, nil
}
// FetchUser will go to MAILRU and access basic information about the user.
func (p *Provider) FetchUser(session goth.Session) (_ goth.User, err error) {
var (
sess = session.(*Session)
user = goth.User{
AccessToken: sess.AccessToken,
RefreshToken: sess.RefreshToken,
Provider: p.Name(),
ExpiresAt: sess.ExpiresAt,
}
)
if user.AccessToken == "" {
return user, fmt.Errorf("%s cannot get user information without access token", p.name)
}
var reqURL = fmt.Sprintf(
"%s?access_token=%s",
endpointUser, sess.AccessToken,
)
res, err := p.Client().Get(reqURL)
if err != nil {
return user, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return user, fmt.Errorf("%s responded with a %d trying to fetch user information", p.name, res.StatusCode)
}
buf, err := ioutil.ReadAll(res.Body)
if err != nil {
return user, err
}
if err = json.Unmarshal(buf, &user.RawData); err != nil {
return user, err
}
// extract and ignore all errors
user.UserID, _ = user.RawData["id"].(string)
user.FirstName, _ = user.RawData["first_name"].(string)
user.LastName, _ = user.RawData["last_name"].(string)
user.NickName, _ = user.RawData["nickname"].(string)
user.Email, _ = user.RawData["email"].(string)
user.AvatarURL, _ = user.RawData["image"].(string)
return user, err
}
// Debug is a no-op for the mailru package.
func (p *Provider) Debug(debug bool) {}
// RefreshToken refresh token is not provided by mailru.
func (p *Provider) RefreshToken(refreshToken string) (*oauth2.Token, error) {
t := &oauth2.Token{RefreshToken: refreshToken}
ts := p.oauthConfig.TokenSource(goth.ContextForClient(p.Client()), t)
return ts.Token()
}
// RefreshTokenAvailable refresh token is not provided by mailru
func (p *Provider) RefreshTokenAvailable() bool {
return true
}