package main
import (
- "fmt"
-
"git.vexingworkshop.com/signal9/dead-tooter/pkg/mastodon"
)
func main() {
app := mastodon.Application{}
err := app.Load("dead-tooter")
- /*
- app, err := mastodon.App{
- ClientName: "dead-tooter",
- RedirectUris: "urn:ietf:wg:oauth:2.0:oob",
- Scopes: "read write follow push",
- Website: "https://dead-tooter.vexingworkshop.com",
- }.Create()
- */
-
if err != nil {
panic(err.Error())
}
- //app.Save()
-
- fmt.Printf("%v", app)
-
- bearer := app.Login()
- fmt.Printf("%v", bearer)
+ token := app.Login()
+ app.VerifyCredentials(token)
}
--- /dev/null
+package mastodon
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "os/exec"
+)
+
+type Account struct {
+}
+
+func (a *Account) Authorize(app Application) (code string) {
+ v := url.Values{}
+ v.Set("client_id", app.ClientID)
+ v.Set("response_type", "code")
+ v.Set("redirect_uri", RedirectUris)
+
+ u := url.URL{
+ Host: "hackers.town",
+ Path: "oauth/authorize",
+ RawQuery: v.Encode(),
+ }
+ u.Scheme = "https"
+
+ err := exec.Command("xdg-open", u.String()).Start()
+ if err != nil {
+ panic(err.Error())
+ }
+
+ fmt.Print("Enter returned code: ")
+ fmt.Scanln(&code)
+
+ return
+}
+
+func (a *Account) RequestToken(app Application, code string) (token Token) {
+ v := url.Values{}
+ v.Set("client_id", app.ClientID)
+ v.Set("code", code)
+ v.Set("redirect_uri", app.RedirectURI)
+ v.Set("grant_type", "authorization_code")
+
+ u := url.URL{
+ Host: "hackers.town",
+ Path: "oauth/token",
+ RawQuery: v.Encode(),
+ }
+ u.Scheme = "https"
+
+ resp, err := http.PostForm(u.String(), v)
+ if err != nil {
+ panic(err.Error())
+ }
+ defer resp.Body.Close()
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ err = json.Unmarshal(body, &token)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ return
+}
"net/url"
)
+// RedirectUris when passed to the redirect_uris parameter, will
+// show return the authorization code instead of redirecting the client.
+const RedirectUris = "urn:ietf:wg:oauth:2.0:oob"
+
// App represents the basic and methods necessary to register an application
// with a Mastodon server.
type App struct {
// Create calls the Mastodon API to register the App. It returns an Application
// instance.
-func (a App) Create() (application Application, err error) {
+//
+// app, err := mastodon.App{
+// ClientName: "dead-tooter",
+// RedirectUris: mastodon.RedirectUris,
+// Scopes: "read write follow push",
+// Website: "https://dead-tooter.vexingworkshop.com",
+// }.Create()
+func (a *App) Create() (application Application, err error) {
resp, err := http.PostForm("https://hackers.town/api/v1/apps",
url.Values{
"client_name": {a.ClientName},
import (
"encoding/json"
+ "fmt"
"io"
"net/http"
"net/url"
const configdir = "foodir/"
+// Token struct contains the data returned by the Application login request.
+type Token struct {
+ AccessToken string `json:"access_token"`
+ TokenType string `json:"token_type"`
+ Scope string `json:"scope"`
+ CreatedAt int `json:"created_at"`
+}
+
// Application represents the data and functions that establish a
// Mastodon API application.
type Application struct {
}
// Save will store a serialized version of the Application struct to a file.
-func (a Application) Save() {
+func (a *Application) Save() {
err := os.Mkdir(configdir, 0750)
if err != nil && !os.IsExist(err) {
panic(err.Error())
// Login authenticates the application to the Mastodon API, returning
// a bearer token to be used with future requests.
-func (a Application) Login() (bearer Bearer) {
+func (a *Application) Login() (token Token) {
resp, err := http.PostForm("https://hackers.town/oauth/token",
url.Values{
"client_id": {a.ClientID},
panic(err.Error())
}
- err = json.Unmarshal(body, &bearer)
+ err = json.Unmarshal(body, &token)
if err != nil {
panic(err.Error())
}
return
}
-// Bearer struct contains the data returned by the Application login request.
-type Bearer struct {
- AccessToken string `json:"access_token"`
- TokenType string `json:"token_type"`
- Scope string `json:"scope"`
- CreatedAt int `json:"created_at"`
+// VerifyCredentials accepts a Token object and validates the contained
+// token against the Mastodon API.
+func (a *Application) VerifyCredentials(token Token) {
+ client := &http.Client{}
+
+ req, err := http.NewRequest("GET",
+ "https://hackers.town/api/v1/apps/verify_credentials", nil)
+ if err != nil {
+ panic(err.Error())
+ }
+ req.Header.Add("Authorization", "Bearer "+token.AccessToken)
+
+ resp, err := client.Do(req)
+ if err != nil {
+ panic(err.Error())
+ }
+ defer resp.Body.Close()
+
+ fmt.Printf("%s", resp.Status)
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ var dummy Application
+ err = json.Unmarshal(body, &dummy)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ fmt.Printf("%+v", dummy)
}