From 1d72b87bca4042d36cea1f1e775803a5252cd224 Mon Sep 17 00:00:00 2001 From: Vidhu Kant Sharma Date: Wed, 15 Jun 2022 16:32:32 +0530 Subject: now macli handles logging in by itself --- auth/auth.go | 29 +++++++++++++++++++++-- auth/client.go | 8 ++++--- auth/server.go | 73 ++++++++++++++++++++++++++++++++++++++++++++++------------ auth/token.go | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 158 insertions(+), 22 deletions(-) (limited to 'auth') diff --git a/auth/auth.go b/auth/auth.go index e75d228..a8d28c7 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -21,6 +21,9 @@ package auth import ( "os" "os/user" + "os/exec" + "runtime" + "errors" "fmt" ) @@ -42,14 +45,36 @@ func Login() { clientId := askClientId() challenge := codeChallenge() link := generateLink(clientId, challenge) - fmt.Println("Please open this link in the browser:") - fmt.Println(link) + + openInBrowser(link) + listen(clientId, challenge) } func generateLink(clientId, challenge string) string { return "https://myanimelist.net/v1/oauth2/authorize?response_type=code&client_id=" + clientId + "&code_challenge=" + challenge } +func openInBrowser(url string) { + fmt.Println("Attempting to launch \x1b[36m" + url + "\x1b[0m in your default web browser. If it doesn't launch please manually copy-paste the link.") + + var err error + switch runtime.GOOS { + case "linux": + err = exec.Command("xdg-open", url).Start() + case "windows": + err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start() + case "darwin": + err = exec.Command("open", url).Start() + default: + err = errors.New("") + } + + if err != nil { + fmt.Println("There was an error while launching your browser.", err) + fmt.Println("Please manually copy and paste the above URL into your web browser.") + } +} + func Logout() { deleteClientId() deleteToken() diff --git a/auth/client.go b/auth/client.go index 7268b8f..f266a42 100644 --- a/auth/client.go +++ b/auth/client.go @@ -40,10 +40,12 @@ func setClientId(clientId string) { func deleteClientId() { err := keyring.Delete(serviceName + clientSuffix, userName) - // TODO: if secret doesnt exist dont show error + // if secret doesnt exist dont show error if err != nil { - fmt.Println(err) - os.Exit(1) + if err.Error() != "secret not found in keyring" { + fmt.Println("Error while deleting Client ID", err.Error()) + os.Exit(1) + } } } diff --git a/auth/server.go b/auth/server.go index eef95bb..5a18a36 100644 --- a/auth/server.go +++ b/auth/server.go @@ -18,18 +18,61 @@ along with this program. If not, see . package auth -// import ( -// "net/http" -// "os" -// "fmt" -// ) -// -// func listen() { -// http.HandleFunc("/", getRoot) -// -// err := http.ListenAndServe(":8000", nil) -// if err != nil { -// fmt.Println("There was an error initialising the server", err.Error()) -// os.Exit(1) -// } -// } +import ( + "net/http" + "net/url" + "encoding/json" + "os" + "fmt" + // "io/ioutil" +) + +func listen(clientId, verifier string) { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + query := r.URL.Query() + + code, codePresent := query["code"] + if !codePresent { + // TODO: check if error message present + fmt.Println("Error: response from MyAnimeList doesn't contain required code.") + os.Exit(1) + } + + accessToken, refreshToken, expiresIn := requestToken(clientId, verifier, code[0]) + + if accessToken != "" { + w.WriteHeader(200) + w.Write([]byte("

You have successfully logged into macli.

")) + } + + setToken(accessToken) + setRefreshToken(refreshToken) + setExpiresIn(expiresIn) + }) + + err := http.ListenAndServe(":8000", nil) + if err != nil { + fmt.Println("There was an error initialising the server", err.Error()) + os.Exit(1) + } +} + +func requestToken(clientId, verifier, code string) (string, string, string) { + data := url.Values{ + "client_id": {clientId}, + "code_verifier": {verifier}, + "grant_type": {"authorization_code"}, + "code": {code}, + } + + resp, err := http.PostForm("https://myanimelist.net/v1/oauth2/token", data) + if err != nil { + fmt.Println("Error while requesting an access token:", err) + os.Exit(1) + } + + var res map[string]interface{} + json.NewDecoder(resp.Body).Decode(&res) + + return fmt.Sprintf("%v", res["access_token"]), fmt.Sprintf("%v", res["refresh_token"]), fmt.Sprintf("%v", res["expires_in"]) +} diff --git a/auth/token.go b/auth/token.go index 5997025..fb1073f 100644 --- a/auth/token.go +++ b/auth/token.go @@ -24,6 +24,9 @@ import ( "github.com/zalando/go-keyring" ) +var refreshPrefix string = "-refresh-token" +var expiresPrefix string = "-expires-in" + func GetToken() string { secret, err := keyring.Get(serviceName, userName) if err != nil { @@ -45,9 +48,72 @@ func setToken(secret string) { func deleteToken() { err := keyring.Delete(serviceName, userName) - // TODO: if secret doesnt exist dont show error + // if secret doesnt exist dont show error + if err != nil { + if err.Error() != "secret not found in keyring" { + fmt.Println("Error while deleting authentication token", err.Error()) + os.Exit(1) + } + } +} + +// currently refreshtoken has no use +func setRefreshToken(secret string) { + err := keyring.Set(serviceName + refreshPrefix, userName, secret) + if err != nil { + fmt.Println("Error while writing access token to keychain", err) + os.Exit(1) + } +} + +func getRefreshToken() string { + secret, err := keyring.Get(serviceName + refreshPrefix, userName) + if err != nil { + fmt.Println("\x1b[31mError while reading refresh token from keychain:", err.Error(), "\x1b[0m") + fmt.Println("Your access token won't be automatically refreshed. If you have problems using macli please run `macli login` to log in again.") + os.Exit(1) + } + + return secret +} + +func deleteRefreshToken() { + err := keyring.Delete(serviceName + refreshPrefix, userName) + // if secret doesnt exist dont show error + if err != nil { + if err.Error() != "secret not found in keyring" { + fmt.Println("Error while deleting refresh token", err.Error()) + os.Exit(1) + } + } +} + +func setExpiresIn(secret string) { + err := keyring.Set(serviceName + expiresPrefix, userName, secret) if err != nil { - fmt.Println(err) + fmt.Println("Error while writing token expire time to keychain", err) os.Exit(1) } } + +func getExpiresIn() string { + secret, err := keyring.Get(serviceName + expiresPrefix, userName) + if err != nil { + fmt.Println("\x1b[31mError while reading token expire time from keychain:", err.Error(), "\x1b[0m") + fmt.Println("Please log in again using `macli login` if problems occour") + // os.Exit(1) + } + + return secret +} + +func deleteExpiresIn() { + err := keyring.Delete(serviceName + expiresPrefix, userName) + // if secret doesnt exist dont show error + if err != nil { + if err.Error() != "secret not found in keyring" { + fmt.Println("Error while deleting token expires in data", err.Error()) + os.Exit(1) + } + } +} -- cgit v1.2.3