login.go
author Mikael Berthe <mikael@lilotux.net>
Wed, 10 May 2017 20:12:26 +0200
changeset 179 fbe21b4aabda
parent 178 b63095e0f301
child 199 9d9d27e7bad2
permissions -rw-r--r--
Version 1.5.0
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
130
c450bb73f59a Update credits
Mikael Berthe <mikael@lilotux.net>
parents: 129
diff changeset
     1
/*
c450bb73f59a Update credits
Mikael Berthe <mikael@lilotux.net>
parents: 129
diff changeset
     2
Copyright 2017 Mikael Berthe
c450bb73f59a Update credits
Mikael Berthe <mikael@lilotux.net>
parents: 129
diff changeset
     3
c450bb73f59a Update credits
Mikael Berthe <mikael@lilotux.net>
parents: 129
diff changeset
     4
Licensed under the MIT license.  Please see the LICENSE file is this directory.
c450bb73f59a Update credits
Mikael Berthe <mikael@lilotux.net>
parents: 129
diff changeset
     5
*/
c450bb73f59a Update credits
Mikael Berthe <mikael@lilotux.net>
parents: 129
diff changeset
     6
138
23d3a518d0ad Update package name in source files
Mikael Berthe <mikael@lilotux.net>
parents: 135
diff changeset
     7
package madon
85
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     8
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     9
import (
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    10
	"encoding/json"
107
f0db7634e540 Add scopes to the basic login, fix some login bugs
Mikael Berthe <mikael@lilotux.net>
parents: 89
diff changeset
    11
	"strings"
85
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    12
178
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
    13
	"golang.org/x/oauth2"
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
    14
162
68df3a01e1a7 Use github.com/pkg/errors
Mikael Berthe <mikael@lilotux.net>
parents: 159
diff changeset
    15
	"github.com/pkg/errors"
85
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    16
	"github.com/sendgrid/rest"
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    17
)
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    18
178
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
    19
const oAuthRelPath = "/oauth/"
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
    20
107
f0db7634e540 Add scopes to the basic login, fix some login bugs
Mikael Berthe <mikael@lilotux.net>
parents: 89
diff changeset
    21
// UserToken represents a user token as returned by the Mastodon API
85
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    22
type UserToken struct {
107
f0db7634e540 Add scopes to the basic login, fix some login bugs
Mikael Berthe <mikael@lilotux.net>
parents: 89
diff changeset
    23
	AccessToken string `json:"access_token"`
159
408aa794d9bb s/int/int64/ for IDs and time integers
Mikael Berthe <mikael@lilotux.net>
parents: 138
diff changeset
    24
	CreatedAt   int64  `json:"created_at"`
107
f0db7634e540 Add scopes to the basic login, fix some login bugs
Mikael Berthe <mikael@lilotux.net>
parents: 89
diff changeset
    25
	Scope       string `json:"scope"`
f0db7634e540 Add scopes to the basic login, fix some login bugs
Mikael Berthe <mikael@lilotux.net>
parents: 89
diff changeset
    26
	TokenType   string `json:"token_type"`
85
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    27
}
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    28
107
f0db7634e540 Add scopes to the basic login, fix some login bugs
Mikael Berthe <mikael@lilotux.net>
parents: 89
diff changeset
    29
// LoginBasic does basic user authentication
138
23d3a518d0ad Update package name in source files
Mikael Berthe <mikael@lilotux.net>
parents: 135
diff changeset
    30
func (mc *Client) LoginBasic(username, password string, scopes []string) error {
23d3a518d0ad Update package name in source files
Mikael Berthe <mikael@lilotux.net>
parents: 135
diff changeset
    31
	if mc == nil {
23d3a518d0ad Update package name in source files
Mikael Berthe <mikael@lilotux.net>
parents: 135
diff changeset
    32
		return ErrUninitializedClient
128
a5a00fad7a32 Add checks for client initialization
Mikael Berthe <mikael@lilotux.net>
parents: 125
diff changeset
    33
	}
a5a00fad7a32 Add checks for client initialization
Mikael Berthe <mikael@lilotux.net>
parents: 125
diff changeset
    34
85
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    35
	if username == "" {
162
68df3a01e1a7 Use github.com/pkg/errors
Mikael Berthe <mikael@lilotux.net>
parents: 159
diff changeset
    36
		return errors.New("missing username")
85
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    37
	}
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    38
	if password == "" {
162
68df3a01e1a7 Use github.com/pkg/errors
Mikael Berthe <mikael@lilotux.net>
parents: 159
diff changeset
    39
		return errors.New("missing password")
85
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    40
	}
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    41
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    42
	hdrs := make(map[string]string)
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    43
	opts := make(map[string]string)
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    44
138
23d3a518d0ad Update package name in source files
Mikael Berthe <mikael@lilotux.net>
parents: 135
diff changeset
    45
	hdrs["User-Agent"] = "madon/" + MadonVersion
85
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    46
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    47
	opts["grant_type"] = "password"
138
23d3a518d0ad Update package name in source files
Mikael Berthe <mikael@lilotux.net>
parents: 135
diff changeset
    48
	opts["client_id"] = mc.ID
23d3a518d0ad Update package name in source files
Mikael Berthe <mikael@lilotux.net>
parents: 135
diff changeset
    49
	opts["client_secret"] = mc.Secret
85
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    50
	opts["username"] = username
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    51
	opts["password"] = password
107
f0db7634e540 Add scopes to the basic login, fix some login bugs
Mikael Berthe <mikael@lilotux.net>
parents: 89
diff changeset
    52
	if len(scopes) > 0 {
f0db7634e540 Add scopes to the basic login, fix some login bugs
Mikael Berthe <mikael@lilotux.net>
parents: 89
diff changeset
    53
		opts["scope"] = strings.Join(scopes, " ")
f0db7634e540 Add scopes to the basic login, fix some login bugs
Mikael Berthe <mikael@lilotux.net>
parents: 89
diff changeset
    54
	}
85
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    55
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    56
	req := rest.Request{
178
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
    57
		BaseURL:     mc.InstanceURL + oAuthRelPath + "token",
85
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    58
		Headers:     hdrs,
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    59
		QueryParams: opts,
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    60
		Method:      rest.Post,
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    61
	}
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    62
125
2bbb72b9ebf6 Rework the API wrappers to handle arrays of parameters
Mikael Berthe <mikael@lilotux.net>
parents: 123
diff changeset
    63
	r, err := restAPI(req)
85
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    64
	if err != nil {
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    65
		return err
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    66
	}
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    67
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    68
	var resp UserToken
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    69
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    70
	err = json.Unmarshal([]byte(r.Body), &resp)
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    71
	if err != nil {
162
68df3a01e1a7 Use github.com/pkg/errors
Mikael Berthe <mikael@lilotux.net>
parents: 159
diff changeset
    72
		return errors.Wrap(err, "cannot unmarshal server response")
85
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    73
	}
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    74
138
23d3a518d0ad Update package name in source files
Mikael Berthe <mikael@lilotux.net>
parents: 135
diff changeset
    75
	mc.UserToken = &resp
85
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    76
	return nil
abf0f5e40281 Initial login support
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    77
}
135
c578c80ed882 Add SetUserToken() to restore a user token
Mikael Berthe <mikael@lilotux.net>
parents: 130
diff changeset
    78
c578c80ed882 Add SetUserToken() to restore a user token
Mikael Berthe <mikael@lilotux.net>
parents: 130
diff changeset
    79
// SetUserToken sets an existing user credentials
c578c80ed882 Add SetUserToken() to restore a user token
Mikael Berthe <mikael@lilotux.net>
parents: 130
diff changeset
    80
// No verification of the arguments is made.
138
23d3a518d0ad Update package name in source files
Mikael Berthe <mikael@lilotux.net>
parents: 135
diff changeset
    81
func (mc *Client) SetUserToken(token, username, password string, scopes []string) error {
23d3a518d0ad Update package name in source files
Mikael Berthe <mikael@lilotux.net>
parents: 135
diff changeset
    82
	if mc == nil {
23d3a518d0ad Update package name in source files
Mikael Berthe <mikael@lilotux.net>
parents: 135
diff changeset
    83
		return ErrUninitializedClient
135
c578c80ed882 Add SetUserToken() to restore a user token
Mikael Berthe <mikael@lilotux.net>
parents: 130
diff changeset
    84
	}
c578c80ed882 Add SetUserToken() to restore a user token
Mikael Berthe <mikael@lilotux.net>
parents: 130
diff changeset
    85
138
23d3a518d0ad Update package name in source files
Mikael Berthe <mikael@lilotux.net>
parents: 135
diff changeset
    86
	mc.UserToken = &UserToken{
135
c578c80ed882 Add SetUserToken() to restore a user token
Mikael Berthe <mikael@lilotux.net>
parents: 130
diff changeset
    87
		AccessToken: token,
c578c80ed882 Add SetUserToken() to restore a user token
Mikael Berthe <mikael@lilotux.net>
parents: 130
diff changeset
    88
		Scope:       strings.Join(scopes, " "),
c578c80ed882 Add SetUserToken() to restore a user token
Mikael Berthe <mikael@lilotux.net>
parents: 130
diff changeset
    89
		TokenType:   "bearer",
c578c80ed882 Add SetUserToken() to restore a user token
Mikael Berthe <mikael@lilotux.net>
parents: 130
diff changeset
    90
	}
c578c80ed882 Add SetUserToken() to restore a user token
Mikael Berthe <mikael@lilotux.net>
parents: 130
diff changeset
    91
	return nil
c578c80ed882 Add SetUserToken() to restore a user token
Mikael Berthe <mikael@lilotux.net>
parents: 130
diff changeset
    92
}
178
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
    93
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
    94
// LoginOAuth2 handles OAuth2 authentication
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
    95
// If code is empty, the URL to the server consent page will be returned;
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
    96
// if not, the user token is set.
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
    97
func (mc *Client) LoginOAuth2(code string, scopes []string) (string, error) {
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
    98
	if mc == nil {
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
    99
		return "", ErrUninitializedClient
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   100
	}
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   101
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   102
	conf := &oauth2.Config{
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   103
		ClientID:     mc.ID,
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   104
		ClientSecret: mc.Secret,
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   105
		Scopes:       scopes,
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   106
		Endpoint: oauth2.Endpoint{
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   107
			AuthURL:  mc.InstanceURL + oAuthRelPath + "authorize",
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   108
			TokenURL: mc.InstanceURL + oAuthRelPath + "token",
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   109
		},
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   110
		RedirectURL: NoRedirect,
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   111
	}
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   112
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   113
	if code == "" {
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   114
		// URL to consent page to ask for permission
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   115
		// for the scopes specified above.
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   116
		return conf.AuthCodeURL("state", oauth2.AccessTypeOffline), nil
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   117
	}
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   118
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   119
	// Return token
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   120
	t, err := conf.Exchange(nil, code)
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   121
	if err != nil {
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   122
		return "", errors.Wrap(err, "cannot convert code into a token")
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   123
	}
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   124
	if t == nil || t.AccessToken == "" {
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   125
		return "", errors.New("empty token")
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   126
	}
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   127
	return "", mc.SetUserToken(t.AccessToken, "", "", scopes)
b63095e0f301 Add OAuth 2.0 authentication support
Mikael Berthe <mikael@lilotux.net>
parents: 162
diff changeset
   128
}