From b8fc0e98f5033d957f51da8641996e034c6d90ad Mon Sep 17 00:00:00 2001 From: Adam Shamblin Date: Thu, 15 Dec 2022 22:13:09 -0700 Subject: [PATCH] Begin setting up commands thru login --- README.md | 6 ++++ cmd/application.go | 19 +++++++++++ cmd/login.go | 47 ++++++++++++++++++++++++++ cmd/root.go | 26 +++++++++++++++ cmd/version.go | 20 +++++++++++ go.mod | 7 ++++ go.sum | 10 ++++++ main.go | 39 ++-------------------- pkg/mastodon/app.go | 50 ---------------------------- pkg/mastodon/application.go | 66 +++++++++++++++++++++++++++++-------- 10 files changed, 190 insertions(+), 100 deletions(-) create mode 100644 cmd/application.go create mode 100644 cmd/login.go create mode 100644 cmd/root.go create mode 100644 cmd/version.go create mode 100644 go.sum delete mode 100644 pkg/mastodon/app.go diff --git a/README.md b/README.md index 04e835f..e83c454 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,9 @@ able to do with my Fedi data. * Delete follows/followers in bulk * by account age * by age of last post + +## Usage + +``` +dead-tooter login --host hackers.town +``` diff --git a/cmd/application.go b/cmd/application.go new file mode 100644 index 0000000..50e29d5 --- /dev/null +++ b/cmd/application.go @@ -0,0 +1,19 @@ +package tooter + +import "github.com/spf13/cobra" + +func init() { + rootCmd.AddCommand(cmdApp) +} + +/* +dead-tooter app create --client-name "" +*/ + +var cmdApp = &cobra.Command{ + Use: "application", + Short: "Register and perform application-level actions", + Long: "application, man", + Run: func(cmd *cobra.Command, args []string) { + }, +} diff --git a/cmd/login.go b/cmd/login.go new file mode 100644 index 0000000..e6b19ab --- /dev/null +++ b/cmd/login.go @@ -0,0 +1,47 @@ +package tooter + +import ( + "git.vexingworkshop.com/signal9/dead-tooter/pkg/mastodon" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(loginCmd) +} + +var loginCmd = &cobra.Command{ + Use: "login", + Short: "Login to Mastodon", + Long: "Initiate login to your Mastodon server of choice", + Run: func(cmd *cobra.Command, args []string) { + }, +} + +func login() { + app, err := mastodon.Load("dead-tooter") + if err != nil { + client := mastodon.Client{ + ClientName: "dead-tooter", + RedirectUris: mastodon.RedirectUris, + Scopes: "read write follow push", + Website: "https://dead-tooter.vexingworkshop.com", + } + app, err = mastodon.Create(client) + if err != nil { + panic(err.Error()) + } + app.Save() + } + + var account mastodon.Account + code := account.Authorize(app) + token, err := account.RequestToken(app, code) + if err != nil { + panic(err.Error()) + } + + err = account.VerifyCredentials(token) + if err != nil { + panic(err.Error()) + } +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..96aeedf --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,26 @@ +package tooter + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "dead-tooter", + Short: "A CLI for Mastodon hate scripts", + Long: `Provides a collection of capabilities that may or may not + be present in the Mastodon web UI`, + + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("d34d-t00t3r") + }, +} + +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} diff --git a/cmd/version.go b/cmd/version.go new file mode 100644 index 0000000..7e0a76e --- /dev/null +++ b/cmd/version.go @@ -0,0 +1,20 @@ +package tooter + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(versionCmd) +} + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Print the version number of d34d-t00ter", + Long: "Version, man, version!", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("d34d-t00ter, Mastodon hate CLI v0.1") + }, +} diff --git a/go.mod b/go.mod index 85301b8..e889d70 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,10 @@ module git.vexingworkshop.com/signal9/dead-tooter go 1.18 + +require github.com/spf13/cobra v1.6.1 + +require ( + github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..442875a --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index d030fd8..8975bc7 100644 --- a/main.go +++ b/main.go @@ -1,44 +1,9 @@ package main import ( - "fmt" - - "git.vexingworkshop.com/signal9/dead-tooter/pkg/mastodon" + cmd "git.vexingworkshop.com/signal9/dead-tooter/cmd" ) func main() { - app := mastodon.Application{} - err := app.Load("dead-tooter") - if err != nil { - panic(err.Error()) - } - - token, err := app.Login() - if err != nil { - panic(err.Error()) - } - - err = app.VerifyCredentials(token) - if err != nil { - panic(err.Error()) - } - - var account mastodon.Account - code := account.Authorize(app) - token, err = account.RequestToken(app, code) - if err != nil { - panic(err.Error()) - } - - err = account.VerifyCredentials(token) - if err != nil { - panic(err.Error()) - } - - followers, err := account.GetFollowers(token) - if err != nil { - panic(err.Error()) - } - - fmt.Printf("%+v\n", followers) + cmd.Execute() } diff --git a/pkg/mastodon/app.go b/pkg/mastodon/app.go deleted file mode 100644 index 69d8898..0000000 --- a/pkg/mastodon/app.go +++ /dev/null @@ -1,50 +0,0 @@ -package mastodon - -import ( - "encoding/json" - "io" - "net/http" - "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 { - ClientName string `json:"client_name"` - RedirectUris string `json:"redirect_uris"` - Scopes string `json:"scopes"` - Website string `json:"website"` -} - -// Create calls the Mastodon API to register the App. It returns an Application -// instance. -// -// 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}, - "redirect_uris": {a.RedirectUris}, - "scopes": {a.Scopes}, - "website": {a.Website}, - }, - ) - if err != nil { - panic(err.Error()) - } - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - err = json.Unmarshal(body, &application) - - return -} diff --git a/pkg/mastodon/application.go b/pkg/mastodon/application.go index b425047..4c48ce1 100644 --- a/pkg/mastodon/application.go +++ b/pkg/mastodon/application.go @@ -12,6 +12,10 @@ import ( const configdir = "foodir/" const mastohost = "hackers.town" +// 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" + // Token struct contains the data returned by the Application login request. type Token struct { AccessToken string `json:"access_token"` @@ -32,38 +36,74 @@ type Application struct { VapidKey string `json:"vapid_key,omitempty"` } -// Save will store a serialized version of the Application struct to a file. -func (a *Application) Save() { - err := os.Mkdir(configdir, 0750) - if err != nil && !os.IsExist(err) { - panic(err.Error()) - } +// Client represents the basic stanza required to register an application +// with the Mastodon API +type Client struct { + ClientName string `json:"client_name"` + RedirectUris string `json:"redirect_uris"` + Scopes string `json:"scopes"` + Website string `json:"website"` +} - data, err := json.Marshal(a) - if err != nil { - panic(err.Error()) +// Create calls the Mastodon API to regsiter the application. +func Create(client Client) (app Application, err error) { + v := url.Values{} + v.Set("client_name", client.ClientName) + v.Set("redirect_uris", client.RedirectUris) + v.Set("scopes", client.Scopes) + v.Set("website", client.Website) + + u := url.URL{ + Host: mastohost, + Path: "oauth/token", + RawQuery: v.Encode(), } + u.Scheme = "https" - err = os.WriteFile(configdir+a.Name, data, 0666) + resp, err := http.PostForm(u.String(), v) if err != nil { panic(err.Error()) } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + err = json.Unmarshal(body, &app) + + return } // Load will hydrate an Application instance based upon data stored in // a file. -func (a *Application) Load(name string) error { +func Load(name string) (app Application, err error) { data, err := os.ReadFile(configdir + name) if err != nil && os.IsNotExist(err) { + return + } + + err = json.Unmarshal(data, &app) + if err != nil { + return + } + + return app, nil +} + +// Save will store a serialized version of the Application struct to a file. +func (a *Application) Save() { + err := os.Mkdir(configdir, 0750) + if err != nil && !os.IsExist(err) { panic(err.Error()) } - err = json.Unmarshal(data, a) + data, err := json.Marshal(a) if err != nil { panic(err.Error()) } - return nil + err = os.WriteFile(configdir+a.Name, data, 0666) + if err != nil { + panic(err.Error()) + } } // Login authenticates the application to the Mastodon API, returning -- 2.39.5