cmd/oauth2.go
author rjp <zimpenfish@gmail.com>
Mon, 23 Jan 2023 16:39:02 +0000
changeset 267 5b91a65ba95a
parent 245 910f00ab2799
child 265 05c40b36d3b2
permissions -rw-r--r--
Update to handle non-int64 IDs Pleroma/Akkoma and GotoSocial use opaque IDs rather than `int64`s like Mastodon which means that `madon` can't talk to either of those. This commit updates everything that can be an ID to `madon.ActivityID` which is an alias for `string` - can't create a specific type for it since there's more than a few places where they're concatenated directly to strings for URLs, etc. Which means it could just as easily be a direct `string` type itself but I find that having distinct types can often make the code more readable and understandable. One extra bit is that `statusOpts` has grown a `_hasReplyTo` boolean to indicate whether the `--in-reply-to` flag was given or not because we can't distinguish because "empty because default" or "empty because given and empty". Another way around this would be to set the default to some theoretically impossible or unlikely string but you never know when someone might spin up an instance where, e.g., admin posts have negative integer IDs.

// Copyright © 2017-2018 Mikael Berthe <mikael@lilotux.net>
//
// Licensed under the MIT license.
// Please see the LICENSE file is this directory.

package cmd

import (
	"fmt"
	"os"

	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	//"github.com/McKael/madonctl/printer"
)

var oauth2Cmd = &cobra.Command{
	Use:   "oauth2",
	Short: "OAuth2 authentication/authorization",
	Example: `  madonctl oauth2                 # Interactive OAuth2 login
  madonctl oauth2 get-url         # Display OAuth2 auhtorization URL
  madonctl oauth2 code CODE       # Enter OAuth2 code

  madonctl oauth2 > config.yaml   # Redirect to configuration file`,
	RunE: func(cmd *cobra.Command, args []string) error {
		return oAuth2Interactive(args)
	},
	PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
		// Initialize application; do not log in yet
		return madonInit(false)
	},
}

func init() {
	RootCmd.AddCommand(oauth2Cmd)

	// Subcommands
	oauth2Cmd.AddCommand(oauth2Subcommands...)
}

var oauth2Subcommands = []*cobra.Command{
	&cobra.Command{
		Use:   "get-url",
		Short: "Get OAuth2 URL",
		RunE: func(cmd *cobra.Command, args []string) error {
			return oAuth2GetURL()
		},
	},
	&cobra.Command{
		Use:   "code CODE",
		Short: "Log in with OAuth2 code",
		RunE: func(cmd *cobra.Command, args []string) error {
			return oAuth2ExchangeCode(args)
		},
	},
}

func oAuth2GetURL() error {
	// (gClient != nil thanks to PreRun)

	url, err := gClient.LoginOAuth2("", scopes)
	if err != nil {
		return errors.Wrap(err, "OAuth2 authentication failed")
	}

	fmt.Printf("%s\n", url)
	return nil
}

func oAuth2ExchangeCode(args []string) error {
	// (gClient != nil thanks to PreRun)

	if len(args) != 1 {
		return errors.New("wrong usage: code needs 1 argument")
	}

	code := args[0]

	if code == "" {
		return errors.New("no code entered")
	}

	// The code has been set; proceed with token exchange
	_, err := gClient.LoginOAuth2(code, scopes)
	if err != nil {
		return err
	}

	if gClient.UserToken != nil {
		errPrint("Login successful.\n")
		errPrint("The new token is %s.\n", gClient.UserToken.AccessToken)
		configDump(true)
	}
	return nil
}

// oAuth2Interactive is the default behaviour
func oAuth2Interactive(args []string) error {
	// (gClient != nil thanks to PreRun)

	url, err := gClient.LoginOAuth2("", scopes)
	if err != nil {
		return errors.Wrap(err, "OAuth2 authentication failed")
	}

	fmt.Fprintf(os.Stderr, "Visit the URL for the auth dialog:\n%s\n", url)
	fmt.Fprintf(os.Stderr, "Enter code: ")
	var code string
	if _, err := fmt.Scan(&code); err != nil {
		return err
	}

	if code == "" {
		return errors.New("no code entered")
	}

	// The code has been set; proceed with token exchange
	return oAuth2ExchangeCode([]string{code})
}