From 5311dee4b19fd60eab0ea5efd5a09f96a5219627 Mon Sep 17 00:00:00 2001 From: Vidhu Kant Sharma Date: Sat, 25 Nov 2023 20:04:12 +0530 Subject: first commit --- maltoken.go | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 maltoken.go (limited to 'maltoken.go') diff --git a/maltoken.go b/maltoken.go new file mode 100644 index 0000000..d73ea79 --- /dev/null +++ b/maltoken.go @@ -0,0 +1,110 @@ +/* +maltoken - A go package for the MyAnimeList OAuth mechanism +Copyright © 2023 Vidhu Kant Sharma + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +package maltoken + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "html" + "math/rand" + "net/http" + "net/url" + "strings" + "time" +) + +var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") +var SuccessHTML = "

Success! You may close this tab now.

" +var BadRequestHTML = "

Invalid request.

" +var ErrHTML = "

MyAnimeList responded with an error: %s

" + +func codeChallenge() string { + rand.Seed(time.Now().UnixNano()) + b := make([]rune, 128) + for i := range b { + b[i] = letterRunes[rand.Intn(len(letterRunes))] + } + return string(b) +} + +func GetChallengeLink(clientId string) (string, string) { + challenge := codeChallenge() + return challenge, "https://myanimelist.net/v1/oauth2/authorize?response_type=code&client_id=" + clientId + "&code_challenge=" + challenge +} + +func Listen(clientId, verifier string, port int) (map[string]interface{}, error) { + var res map[string]interface{} + var e error + + mux := http.NewServeMux() + server := &http.Server{ + Addr: fmt.Sprintf(":%d", port), + Handler: mux, + } + + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + code, codeExists := r.URL.Query()["code"] + if !codeExists { + fmt.Fprintf(w, BadRequestHTML) + return + } + + resp, err := http.PostForm("https://myanimelist.net/v1/oauth2/token", url.Values { + "client_id": {clientId}, + "code_verifier": {verifier}, + "grant_type": {"authorization_code"}, + "code": {code[0]}, + }) + if err != nil { + // error while making post request + e = err + go server.Shutdown(context.Background()) + return + } + + json.NewDecoder(resp.Body).Decode(&res) + + if res["error"] != nil { + // MyAnimeList returned error + errMsg := fmt.Sprintf("%v (%v)", res["message"], res["error"]) + e = errors.New(errMsg) + + if strings.Contains(ErrHTML, "%s") { + fmt.Fprintf(w, ErrHTML, html.EscapeString(errMsg)) + } else { + fmt.Fprintf(w, ErrHTML) + } + + go server.Shutdown(context.Background()) + return + } + + fmt.Fprintf(w, SuccessHTML) + go server.Shutdown(context.Background()) + }) + + err := server.ListenAndServe() + if err != nil && err != http.ErrServerClosed { + e = err + } + + return res, e +} -- cgit v1.2.3