Compare commits
3 commits
70fc1acc68
...
81f5b527a0
Author | SHA1 | Date | |
---|---|---|---|
81f5b527a0 | |||
db6017dccf | |||
4cbf1d4b4d |
6 changed files with 132 additions and 106 deletions
|
@ -76,7 +76,18 @@ func (c *loginCommand) Execute() error {
|
||||||
return fmt.Errorf("unable to register the application; %w", err)
|
return fmt.Errorf("unable to register the application; %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
consentPageURL := authCodeURL(gtsClient.Authentication)
|
oauth2Conf := oauth2.Config{
|
||||||
|
ClientID: gtsClient.Authentication.ClientID,
|
||||||
|
ClientSecret: gtsClient.Authentication.ClientSecret,
|
||||||
|
Scopes: []string{"read"},
|
||||||
|
RedirectURL: internal.RedirectUri,
|
||||||
|
Endpoint: oauth2.Endpoint{
|
||||||
|
AuthURL: gtsClient.Authentication.Instance + "/oauth/authorize",
|
||||||
|
TokenURL: gtsClient.Authentication.Instance + "/oauth/token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
consentPageURL := authCodeURL(oauth2Conf)
|
||||||
|
|
||||||
openLink(consentPageURL)
|
openLink(consentPageURL)
|
||||||
|
|
||||||
|
@ -89,7 +100,7 @@ func (c *loginCommand) Execute() error {
|
||||||
return fmt.Errorf("failed to read access code; %w", err)
|
return fmt.Errorf("failed to read access code; %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gtsClient.Authentication, err = addAccessToken(gtsClient.Authentication, code)
|
gtsClient.Authentication, err = addAccessToken(gtsClient.Authentication, oauth2Conf, code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to get the access token; %w", err)
|
return fmt.Errorf("unable to get the access token; %w", err)
|
||||||
}
|
}
|
||||||
|
@ -109,36 +120,17 @@ func (c *loginCommand) Execute() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func authCodeURL(account config.Authentication) string {
|
func authCodeURL(oauth2Conf oauth2.Config) string {
|
||||||
config := oauth2.Config{
|
url := oauth2Conf.AuthCodeURL(
|
||||||
ClientID: account.ClientID,
|
"state",
|
||||||
ClientSecret: account.ClientSecret,
|
oauth2.AccessTypeOffline,
|
||||||
Scopes: []string{"read"},
|
) + "&client_name=" + internal.ApplicationName
|
||||||
RedirectURL: internal.RedirectUri,
|
|
||||||
Endpoint: oauth2.Endpoint{
|
|
||||||
AuthURL: account.Instance + "/oauth/authorize",
|
|
||||||
TokenURL: account.Instance + "/oauth/token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
url := config.AuthCodeURL("state", oauth2.AccessTypeOffline) + fmt.Sprintf("&client_name=%s", internal.ApplicationName)
|
|
||||||
|
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
func addAccessToken(authentication config.Authentication, code string) (config.Authentication, error) {
|
func addAccessToken(authentication config.Authentication, oauth2Conf oauth2.Config, code string) (config.Authentication, error) {
|
||||||
ouauth2Conf := oauth2.Config{
|
token, err := oauth2Conf.Exchange(context.Background(), code)
|
||||||
ClientID: authentication.ClientID,
|
|
||||||
ClientSecret: authentication.ClientSecret,
|
|
||||||
Scopes: []string{"read", "write"},
|
|
||||||
RedirectURL: internal.RedirectUri,
|
|
||||||
Endpoint: oauth2.Endpoint{
|
|
||||||
AuthURL: authentication.Instance + "/oauth/authorize",
|
|
||||||
TokenURL: authentication.Instance + "/oauth/token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
token, err := ouauth2Conf.Exchange(context.Background(), code)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return config.Authentication{}, fmt.Errorf("unable to exchange the code for an access token; %w", err)
|
return config.Authentication{}, fmt.Errorf("unable to exchange the code for an access token; %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"slices"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Executor interface {
|
type Executor interface {
|
||||||
|
@ -75,71 +73,3 @@ func run() error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func commandUsageFunc(name, summary string, flagset *flag.FlagSet) func() {
|
|
||||||
return func() {
|
|
||||||
var builder strings.Builder
|
|
||||||
|
|
||||||
fmt.Fprintf(
|
|
||||||
&builder,
|
|
||||||
"SUMMARY:\n %s - %s\n\nUSAGE:\n enbas %s [flags]\n\nFLAGS:",
|
|
||||||
name,
|
|
||||||
summary,
|
|
||||||
name,
|
|
||||||
)
|
|
||||||
|
|
||||||
flagset.VisitAll(func(f *flag.Flag) {
|
|
||||||
fmt.Fprintf(
|
|
||||||
&builder,
|
|
||||||
"\n -%s, --%s\n %s",
|
|
||||||
f.Name,
|
|
||||||
f.Name,
|
|
||||||
f.Usage,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
builder.WriteString("\n")
|
|
||||||
|
|
||||||
w := flag.CommandLine.Output()
|
|
||||||
|
|
||||||
fmt.Fprint(w, builder.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func enbasUsageFunc(summaries map[string]string) func() {
|
|
||||||
cmds := make([]string, len(summaries))
|
|
||||||
ind := 0
|
|
||||||
|
|
||||||
for k := range summaries {
|
|
||||||
cmds[ind] = k
|
|
||||||
ind++
|
|
||||||
}
|
|
||||||
|
|
||||||
slices.Sort(cmds)
|
|
||||||
|
|
||||||
return func() {
|
|
||||||
var builder strings.Builder
|
|
||||||
|
|
||||||
builder.WriteString("SUMMARY:\n enbas - A GoToSocial client for the terminal.\n\n")
|
|
||||||
|
|
||||||
if binaryVersion != "" {
|
|
||||||
builder.WriteString("VERSION:\n " + binaryVersion + "\n\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.WriteString("USAGE:\n enbas [flags]\n enbas [command]\n\nCOMMANDS:")
|
|
||||||
|
|
||||||
for _, cmd := range cmds {
|
|
||||||
fmt.Fprintf(&builder, "\n %s\t%s", cmd, summaries[cmd])
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.WriteString("\n\nFLAGS:\n -help, --help\n print the help message\n")
|
|
||||||
flag.VisitAll(func(f *flag.Flag) {
|
|
||||||
fmt.Fprintf(&builder, "\n -%s, --%s\n %s\n", f.Name, f.Name, f.Usage)
|
|
||||||
})
|
|
||||||
|
|
||||||
builder.WriteString("\nUse \"enbas [command] --help\" for more information about a command.\n")
|
|
||||||
|
|
||||||
w := flag.CommandLine.Output()
|
|
||||||
fmt.Fprint(w, builder.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
|
||||||
|
@ -32,7 +33,7 @@ var accountDetailsFormat = `
|
||||||
ACCOUNT ID:
|
ACCOUNT ID:
|
||||||
%s
|
%s
|
||||||
|
|
||||||
CREATED AT:
|
JOINED ON:
|
||||||
%s
|
%s
|
||||||
|
|
||||||
STATS:
|
STATS:
|
||||||
|
@ -144,11 +145,11 @@ func (c *showCommand) showAccount(gts *client.Client) error {
|
||||||
account.DisplayName,
|
account.DisplayName,
|
||||||
account.Username,
|
account.Username,
|
||||||
account.ID,
|
account.ID,
|
||||||
account.CreatedAt,
|
account.CreatedAt.Format("02 Jan 2006"),
|
||||||
account.FollowersCount,
|
account.FollowersCount,
|
||||||
account.FollowingCount,
|
account.FollowingCount,
|
||||||
account.StatusCount,
|
account.StatusCount,
|
||||||
stripHTMLTags(account.Note),
|
wrapLine(stripHTMLTags(account.Note), "\n ", 80),
|
||||||
metadata,
|
metadata,
|
||||||
account.URL,
|
account.URL,
|
||||||
)
|
)
|
||||||
|
@ -171,3 +172,26 @@ func stripHTMLTags(text string) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func wrapLine(line, separator string, charLimit int) string {
|
||||||
|
if len(line) <= charLimit {
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
|
||||||
|
leftcursor, rightcursor := 0, 0
|
||||||
|
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
for rightcursor < (len(line) - charLimit) {
|
||||||
|
rightcursor += charLimit
|
||||||
|
for !unicode.IsSpace(rune(line[rightcursor-1])) {
|
||||||
|
rightcursor--
|
||||||
|
}
|
||||||
|
builder.WriteString(line[leftcursor:rightcursor] + separator)
|
||||||
|
leftcursor = rightcursor
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString(line[rightcursor:])
|
||||||
|
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
76
cmd/enbas/usage.go
Normal file
76
cmd/enbas/usage.go
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func commandUsageFunc(name, summary string, flagset *flag.FlagSet) func() {
|
||||||
|
return func() {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
fmt.Fprintf(
|
||||||
|
&builder,
|
||||||
|
"SUMMARY:\n %s - %s\n\nUSAGE:\n enbas %s [flags]\n\nFLAGS:",
|
||||||
|
name,
|
||||||
|
summary,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
|
||||||
|
flagset.VisitAll(func(f *flag.Flag) {
|
||||||
|
fmt.Fprintf(
|
||||||
|
&builder,
|
||||||
|
"\n -%s, --%s\n %s",
|
||||||
|
f.Name,
|
||||||
|
f.Name,
|
||||||
|
f.Usage,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
builder.WriteString("\n")
|
||||||
|
|
||||||
|
w := flag.CommandLine.Output()
|
||||||
|
|
||||||
|
fmt.Fprint(w, builder.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func enbasUsageFunc(summaries map[string]string) func() {
|
||||||
|
cmds := make([]string, len(summaries))
|
||||||
|
ind := 0
|
||||||
|
|
||||||
|
for k := range summaries {
|
||||||
|
cmds[ind] = k
|
||||||
|
ind++
|
||||||
|
}
|
||||||
|
|
||||||
|
slices.Sort(cmds)
|
||||||
|
|
||||||
|
return func() {
|
||||||
|
var builder strings.Builder
|
||||||
|
|
||||||
|
builder.WriteString("SUMMARY:\n enbas - A GoToSocial client for the terminal.\n\n")
|
||||||
|
|
||||||
|
if binaryVersion != "" {
|
||||||
|
builder.WriteString("VERSION:\n " + binaryVersion + "\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString("USAGE:\n enbas [flags]\n enbas [command]\n\nCOMMANDS:")
|
||||||
|
|
||||||
|
for _, cmd := range cmds {
|
||||||
|
fmt.Fprintf(&builder, "\n %s\t%s", cmd, summaries[cmd])
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString("\n\nFLAGS:\n -help, --help\n print the help message\n")
|
||||||
|
flag.VisitAll(func(f *flag.Flag) {
|
||||||
|
fmt.Fprintf(&builder, "\n -%s, --%s\n %s\n", f.Name, f.Name, f.Usage)
|
||||||
|
})
|
||||||
|
|
||||||
|
builder.WriteString("\nUse \"enbas [command] --help\" for more information about a command.\n")
|
||||||
|
|
||||||
|
w := flag.CommandLine.Output()
|
||||||
|
fmt.Fprint(w, builder.String())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,13 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
Acct string `json:"acct"`
|
Acct string `json:"acct"`
|
||||||
Avatar string `json:"avatar"`
|
Avatar string `json:"avatar"`
|
||||||
AvatarStatic string `json:"avatar_static"`
|
AvatarStatic string `json:"avatar_static"`
|
||||||
Bot bool `json:"bot"`
|
Bot bool `json:"bot"`
|
||||||
CreatedAt string `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
CustomCSS string `json:"custom_css"`
|
CustomCSS string `json:"custom_css"`
|
||||||
Discoverable bool `json:"discoverable"`
|
Discoverable bool `json:"discoverable"`
|
||||||
DisplayName string `json:"display_name"`
|
DisplayName string `json:"display_name"`
|
||||||
|
@ -19,7 +21,7 @@ type Account struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
LastStatusAt string `json:"last_status_at"`
|
LastStatusAt string `json:"last_status_at"`
|
||||||
Locked bool `json:"locked"`
|
Locked bool `json:"locked"`
|
||||||
MuteExpiresAt string `json:"mute_expires_at"`
|
MuteExpiresAt time.Time `json:"mute_expires_at"`
|
||||||
Note string `json:"note"`
|
Note string `json:"note"`
|
||||||
Role AccountRole `json:"role"`
|
Role AccountRole `json:"role"`
|
||||||
Source Source `json:"source"`
|
Source Source `json:"source"`
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
type Status struct {
|
type Status struct {
|
||||||
Account Account `json:"account"`
|
Account Account `json:"account"`
|
||||||
Application Application `json:"application"`
|
Application Application `json:"application"`
|
||||||
Bookmarked bool `json:"bookmarked"`
|
Bookmarked bool `json:"bookmarked"`
|
||||||
Card Card `json:"card"`
|
Card Card `json:"card"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
CreatedAt string `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
Emojis []Emoji `json:"emojis"`
|
Emojis []Emoji `json:"emojis"`
|
||||||
Favourited bool `json:"favourited"`
|
Favourited bool `json:"favourited"`
|
||||||
FavouritesCount int `json:"favourites_count"`
|
FavouritesCount int `json:"favourites_count"`
|
||||||
|
@ -61,7 +63,7 @@ type Poll struct {
|
||||||
Expired bool `json:"expired"`
|
Expired bool `json:"expired"`
|
||||||
Voted bool `json:"voted"`
|
Voted bool `json:"voted"`
|
||||||
Multiple bool `json:"multiple"`
|
Multiple bool `json:"multiple"`
|
||||||
ExpiredAt string `json:"expires_at"`
|
ExpiredAt time.Time `json:"expires_at"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
OwnVotes []int `json:"own_votes"`
|
OwnVotes []int `json:"own_votes"`
|
||||||
VotersCount int `json:"voters_count"`
|
VotersCount int `json:"voters_count"`
|
||||||
|
@ -80,7 +82,7 @@ type StatusReblogged struct {
|
||||||
Bookmarked bool `json:"bookmarked"`
|
Bookmarked bool `json:"bookmarked"`
|
||||||
Card Card `json:"card"`
|
Card Card `json:"card"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
CreatedAt string `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
Emojis []Emoji `json:"emojis"`
|
Emojis []Emoji `json:"emojis"`
|
||||||
Favourited bool `json:"favourited"`
|
Favourited bool `json:"favourited"`
|
||||||
FavouritesCount int `json:"favourites_count"`
|
FavouritesCount int `json:"favourites_count"`
|
||||||
|
|
Loading…
Reference in a new issue