This repository has been archived by the owner on Apr 2, 2024. It is now read-only.
/
authentication.go
123 lines (98 loc) 路 3.21 KB
/
authentication.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
package spotify
import (
"fmt"
"net/http"
"os"
"time"
"github.com/olivia-ai/olivia/util"
"github.com/olivia-ai/olivia/user"
"github.com/zmb3/spotify"
"golang.org/x/oauth2"
)
var (
redirectURL = os.Getenv("REDIRECT_URL")
callbackURL = os.Getenv("CALLBACK_URL")
tokenChannel = make(chan *oauth2.Token)
state = "abc123"
auth spotify.Authenticator
)
func init() {
// Set default value of the callback url
if callbackURL == "" {
callbackURL = "https://olivia-api.herokuapp.com/callback"
}
// Set default value of the redirect url
if redirectURL == "" {
redirectURL = "https://olivia-ai.org/chat"
}
// Initialize the authenticator
auth = spotify.NewAuthenticator(
callbackURL,
spotify.ScopeStreaming,
spotify.ScopeUserModifyPlaybackState,
spotify.ScopeUserReadPlaybackState,
)
}
// LoginSpotify logins the user with its token to Spotify
func LoginSpotify(locale, token string) string {
information := user.GetUserInformation(token)
// Generate the authentication url
auth.SetAuthInfo(information.SpotifyID, information.SpotifySecret)
url := auth.AuthURL(state)
// Waits for the authentication to be completed, and save the client in user's information
go func() {
authenticationToken := <-tokenChannel
// If the token is empty reset the credentials of the user
if *authenticationToken == (oauth2.Token{}) {
user.ChangeUserInformation(token, func(information user.Information) user.Information {
information.SpotifyID = ""
information.SpotifySecret = ""
return information
})
}
// Save the authentication token
user.ChangeUserInformation(token, func(information user.Information) user.Information {
information.SpotifyToken = authenticationToken
return information
})
}()
return fmt.Sprintf(util.GetMessage(locale, "spotify login"), url)
}
// RenewSpotifyToken renews the spotify token with the user's information token and returns
// the spotify client.
func RenewSpotifyToken(token string) spotify.Client {
authenticationToken := user.GetUserInformation(token).SpotifyToken
client := auth.NewClient(authenticationToken)
// Renew the authentication token
if m, _ := time.ParseDuration("5m30s"); time.Until(authenticationToken.Expiry) < m {
user.ChangeUserInformation(token, func(information user.Information) user.Information {
information.SpotifyToken, _ = client.Token()
return information
})
}
return client
}
// CheckTokensPresence checks if the spotify tokens are present
func CheckTokensPresence(token string) bool {
information := user.GetUserInformation(token)
return information.SpotifyID == "" || information.SpotifySecret == ""
}
// CompleteAuth completes the Spotify authentication.
func CompleteAuth(w http.ResponseWriter, r *http.Request) {
token, err := auth.Token(state, r)
if err != nil {
http.Error(w, "Couldn't get token", http.StatusForbidden)
tokenChannel <- &oauth2.Token{}
return
}
if st := r.FormValue("state"); st != state {
http.NotFound(w, r)
tokenChannel <- &oauth2.Token{}
return
}
// Use the token to get an authenticated client
w.Header().Set("Content-Type", "text/html")
// Redirect the user
fmt.Fprintf(w, `<meta http-equiv="refresh" content="0; url = %s" />`, redirectURL)
tokenChannel <- token
}