aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVidhu Kant Sharma <vidhukant@vidhukant.xyz>2022-06-15 16:32:32 +0530
committerVidhu Kant Sharma <vidhukant@vidhukant.xyz>2022-06-15 16:32:32 +0530
commit1d72b87bca4042d36cea1f1e775803a5252cd224 (patch)
tree04a0185a473c7f9acd5c92bc4091d7c66f102e6b
parent83e1ce2508ea035fb299a88fe89e82f34e609499 (diff)
now macli handles logging in by itself
-rw-r--r--auth/auth.go29
-rw-r--r--auth/client.go8
-rw-r--r--auth/server.go73
-rw-r--r--auth/token.go70
4 files changed, 158 insertions, 22 deletions
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("<failed to detect platform>")
+ }
+
+ 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 <http://www.gnu.org/licenses/>.
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("<h1>You have successfully logged into macli.</h1>"))
+ }
+
+ 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)
+ }
+ }
+}