feat(login): select login mode with type flag

This commit is contained in:
iyear 2023-12-18 11:13:21 +08:00
parent ff0d44688f
commit 8127fb7a7b
6 changed files with 210 additions and 80 deletions

View File

@ -1,69 +0,0 @@
package login
import (
"context"
"errors"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/fatih/color"
"github.com/gotd/td/telegram/auth"
"github.com/gotd/td/tg"
)
// noSignUp can be embedded to prevent signing up.
type noSignUp struct{}
func (c noSignUp) SignUp(_ context.Context) (auth.UserInfo, error) {
return auth.UserInfo{}, errors.New("searchx don't support sign up Telegram account")
}
func (c noSignUp) AcceptTermsOfService(_ context.Context, tos tg.HelpTermsOfService) error {
return &auth.SignUpRequired{TermsOfService: tos}
}
// termAuth implements authentication via terminal.
type termAuth struct {
noSignUp
}
func (a termAuth) Phone(_ context.Context) (string, error) {
phone := ""
prompt := &survey.Input{
Message: "Enter your phone number:",
Default: "+86 12345678900",
}
if err := survey.AskOne(prompt, &phone, survey.WithValidator(survey.Required)); err != nil {
return "", err
}
color.Blue("Sending Code...")
return strings.TrimSpace(phone), nil
}
func (a termAuth) Password(_ context.Context) (string, error) {
pwd := ""
prompt := &survey.Input{
Message: "Enter 2FA Password:",
}
if err := survey.AskOne(prompt, &pwd, survey.WithValidator(survey.Required)); err != nil {
return "", err
}
return strings.TrimSpace(pwd), nil
}
func (a termAuth) Code(_ context.Context, _ *tg.AuthSentCode) (string, error) {
code := ""
prompt := &survey.Input{
Message: "Enter Code:",
}
if err := survey.AskOne(prompt, &code, survey.WithValidator(survey.Required)); err != nil {
return "", err
}
return strings.TrimSpace(code), nil
}

View File

@ -3,13 +3,16 @@ package login
import (
"context"
"crypto/rand"
"strings"
"time"
"github.com/AlecAivazis/survey/v2"
"github.com/cenkalti/backoff/v4"
"github.com/fatih/color"
"github.com/go-faster/errors"
"github.com/gotd/td/telegram"
"github.com/gotd/td/telegram/auth"
"github.com/gotd/td/tg"
"github.com/spf13/viper"
"github.com/iyear/tdl/pkg/consts"
@ -71,8 +74,65 @@ func Code(ctx context.Context) error {
return err
}
color.Blue("Login successfully! ID: %d, Username: %s", user.ID, user.Username)
color.Green("Login successfully! ID: %d, Username: %s", user.ID, user.Username)
return nil
})
}
// noSignUp can be embedded to prevent signing up.
type noSignUp struct{}
func (c noSignUp) SignUp(_ context.Context) (auth.UserInfo, error) {
return auth.UserInfo{}, errors.New("don't support sign up Telegram account")
}
func (c noSignUp) AcceptTermsOfService(_ context.Context, tos tg.HelpTermsOfService) error {
return &auth.SignUpRequired{TermsOfService: tos}
}
// termAuth implements authentication via terminal.
type termAuth struct {
noSignUp
}
func (a termAuth) Phone(_ context.Context) (string, error) {
phone := ""
prompt := &survey.Input{
Message: "Enter your phone number:",
Default: "+86 12345678900",
}
if err := survey.AskOne(prompt, &phone, survey.WithValidator(survey.Required)); err != nil {
return "", err
}
color.Blue("Sending Code...")
return strings.TrimSpace(phone), nil
}
func (a termAuth) Password(_ context.Context) (string, error) {
pwd := ""
prompt := &survey.Password{
Message: "Enter 2FA Password:",
}
if err := survey.AskOne(prompt, &pwd, survey.WithValidator(survey.Required)); err != nil {
return "", err
}
return strings.TrimSpace(pwd), nil
}
func (a termAuth) Code(_ context.Context, _ *tg.AuthSentCode) (string, error) {
code := ""
prompt := &survey.Input{
Message: "Enter Code:",
}
if err := survey.AskOne(prompt, &code, survey.WithValidator(survey.Required)); err != nil {
return "", err
}
return strings.TrimSpace(code), nil
}

View File

@ -26,12 +26,7 @@ import (
const tdata = "tdata"
type Options struct {
Desktop string
Passcode string
}
func Desktop(ctx context.Context, opts *Options) error {
func Desktop(ctx context.Context, opts Options) error {
ns := viper.GetString(consts.FlagNamespace)
kvd, err := kv.From(ctx).Open(ns)

32
app/login/login.go Normal file
View File

@ -0,0 +1,32 @@
package login
import (
"context"
"github.com/go-faster/errors"
)
//go:generate go-enum --values --names --flag --nocase
// Type
// ENUM(desktop, code, qr)
type Type int
type Options struct {
Type Type
Desktop string
Passcode string
}
func Run(ctx context.Context, opts Options) error {
switch opts.Type {
case TypeDesktop:
return Desktop(ctx, opts)
case TypeCode:
return Code(ctx)
case TypeQr:
return QR(ctx)
default:
return errors.Errorf("unsupported login type: %s", opts.Type)
}
}

106
app/login/login_enum.go Normal file
View File

@ -0,0 +1,106 @@
// Code generated by go-enum DO NOT EDIT.
// Version: 0.5.8
// Revision: 3d844c8ecc59661ed7aa17bfd65727bc06a60ad8
// Build Date: 2023-09-18T14:55:21Z
// Built By: goreleaser
package login
import (
"fmt"
"strings"
)
const (
// TypeDesktop is a Type of type Desktop.
TypeDesktop Type = iota
// TypeCode is a Type of type Code.
TypeCode
// TypeQr is a Type of type Qr.
TypeQr
)
var ErrInvalidType = fmt.Errorf("not a valid Type, try [%s]", strings.Join(_TypeNames, ", "))
const _TypeName = "desktopcodeqr"
var _TypeNames = []string{
_TypeName[0:7],
_TypeName[7:11],
_TypeName[11:13],
}
// TypeNames returns a list of possible string values of Type.
func TypeNames() []string {
tmp := make([]string, len(_TypeNames))
copy(tmp, _TypeNames)
return tmp
}
// TypeValues returns a list of the values for Type
func TypeValues() []Type {
return []Type{
TypeDesktop,
TypeCode,
TypeQr,
}
}
var _TypeMap = map[Type]string{
TypeDesktop: _TypeName[0:7],
TypeCode: _TypeName[7:11],
TypeQr: _TypeName[11:13],
}
// String implements the Stringer interface.
func (x Type) String() string {
if str, ok := _TypeMap[x]; ok {
return str
}
return fmt.Sprintf("Type(%d)", x)
}
// IsValid provides a quick way to determine if the typed value is
// part of the allowed enumerated values
func (x Type) IsValid() bool {
_, ok := _TypeMap[x]
return ok
}
var _TypeValue = map[string]Type{
_TypeName[0:7]: TypeDesktop,
strings.ToLower(_TypeName[0:7]): TypeDesktop,
_TypeName[7:11]: TypeCode,
strings.ToLower(_TypeName[7:11]): TypeCode,
_TypeName[11:13]: TypeQr,
strings.ToLower(_TypeName[11:13]): TypeQr,
}
// ParseType attempts to convert a string to a Type.
func ParseType(name string) (Type, error) {
if x, ok := _TypeValue[name]; ok {
return x, nil
}
// Case insensitive parse, do a separate lookup to prevent unnecessary cost of lowercasing a string if we don't need to.
if x, ok := _TypeValue[strings.ToLower(name)]; ok {
return x, nil
}
return Type(0), fmt.Errorf("%s is %w", name, ErrInvalidType)
}
// Set implements the Golang flag.Value interface func.
func (x *Type) Set(val string) error {
v, err := ParseType(val)
*x = v
return err
}
// Get implements the Golang flag.Getter interface func.
func (x *Type) Get() interface{} {
return *x
}
// Type implements the github.com/spf13/pFlag Value interface.
func (x *Type) Type() string {
return "Type"
}

View File

@ -1,6 +1,9 @@
package cmd
import (
"fmt"
"strings"
"github.com/fatih/color"
"github.com/spf13/cobra"
@ -20,24 +23,27 @@ func NewLogin() *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
color.Yellow("WARN: If data exists in the namespace, data will be overwritten")
// Legacy flag
if code {
return login.Code(logger.Named(cmd.Context(), "login"))
}
return login.Desktop(cmd.Context(), &opts)
return login.Run(logger.Named(cmd.Context(), "login"), opts)
},
}
const (
desktop = "desktop"
)
const desktop = "desktop"
cmd.Flags().VarP(&opts.Type, "type", "T", fmt.Sprintf("login mode: [%s]", strings.Join(login.TypeNames(), ", ")))
cmd.Flags().StringVarP(&opts.Desktop, desktop, "d", "", "official desktop client path, and automatically find possible paths if empty")
cmd.Flags().StringVarP(&opts.Passcode, "passcode", "p", "", "passcode for desktop client, keep empty if no passcode")
// Deprecated
cmd.Flags().BoolVar(&code, "code", false, "login with code, instead of importing session from desktop client")
// completion and validation
_ = cmd.MarkFlagDirname(desktop)
_ = cmd.Flags().MarkDeprecated("code", "use `-T code` instead")
return cmd
}