You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
4.3 KiB
154 lines
4.3 KiB
package auth |
|
|
|
import ( |
|
"context" |
|
|
|
"github.com/go-faster/errors" |
|
|
|
"github.com/gotd/td/tg" |
|
"github.com/gotd/td/tgerr" |
|
) |
|
|
|
// ErrPasswordInvalid means that password provided to Password is invalid. |
|
// |
|
// Note that telegram does not trim whitespace characters by default, check |
|
// that provided password is expected and clean whitespaces if needed. |
|
// You can use strings.TrimSpace(password) for this. |
|
var ErrPasswordInvalid = errors.New("invalid password") |
|
|
|
// Password performs login via secure remote password (aka 2FA). |
|
// |
|
// Method can be called after SignIn to provide password if requested. |
|
func (c *Client) Password(ctx context.Context, password string) (*tg.AuthAuthorization, error) { |
|
p, err := c.api.AccountGetPassword(ctx) |
|
if err != nil { |
|
return nil, errors.Wrap(err, "get SRP parameters") |
|
} |
|
|
|
a, err := PasswordHash([]byte(password), p.SRPID, p.SRPB, p.SecureRandom, p.CurrentAlgo) |
|
if err != nil { |
|
return nil, errors.Wrap(err, "compute password hash") |
|
} |
|
|
|
auth, err := c.api.AuthCheckPassword(ctx, &tg.InputCheckPasswordSRP{ |
|
SRPID: p.SRPID, |
|
A: a.A, |
|
M1: a.M1, |
|
}) |
|
if tg.IsPasswordHashInvalid(err) { |
|
return nil, ErrPasswordInvalid |
|
} |
|
if err != nil { |
|
return nil, errors.Wrap(err, "check password") |
|
} |
|
result, err := checkResult(auth) |
|
if err != nil { |
|
return nil, errors.Wrap(err, "check") |
|
} |
|
return result, nil |
|
} |
|
|
|
// SendCodeOptions defines how to send auth code to user. |
|
type SendCodeOptions struct { |
|
// AllowFlashCall allows phone verification via phone calls. |
|
AllowFlashCall bool |
|
// Pass true if the phone number is used on the current device. |
|
// Ignored if AllowFlashCall is not set. |
|
CurrentNumber bool |
|
// If a token that will be included in eventually sent SMSs is required: |
|
// required in newer versions of android, to use the android SMS receiver APIs. |
|
AllowAppHash bool |
|
} |
|
|
|
// SendCode requests code for provided phone number, returning code hash |
|
// and error if any. Use AuthFlow to reduce boilerplate. |
|
// |
|
// This method should be called first in user authentication flow. |
|
func (c *Client) SendCode(ctx context.Context, phone string, options SendCodeOptions) (*tg.AuthSentCode, error) { |
|
var settings tg.CodeSettings |
|
if options.AllowAppHash { |
|
settings.SetAllowAppHash(true) |
|
} |
|
if options.AllowFlashCall { |
|
settings.SetAllowFlashcall(true) |
|
} |
|
if options.CurrentNumber { |
|
settings.SetCurrentNumber(true) |
|
} |
|
|
|
sentCode, err := c.api.AuthSendCode(ctx, &tg.AuthSendCodeRequest{ |
|
PhoneNumber: phone, |
|
APIID: c.appID, |
|
APIHash: c.appHash, |
|
Settings: settings, |
|
}) |
|
if err != nil { |
|
return nil, errors.Wrap(err, "send code") |
|
} |
|
return sentCode, nil |
|
} |
|
|
|
// ErrPasswordAuthNeeded means that 2FA auth is required. |
|
// |
|
// Call Client.Password to provide 2FA password. |
|
var ErrPasswordAuthNeeded = errors.New("2FA required") |
|
|
|
// SignIn performs sign in with provided user phone, code and code hash. |
|
// |
|
// If ErrPasswordAuthNeeded is returned, call Password to provide 2FA |
|
// password. |
|
// |
|
// To obtain codeHash, use SendCode. |
|
func (c *Client) SignIn(ctx context.Context, phone, code, codeHash string) (*tg.AuthAuthorization, error) { |
|
auth, err := c.api.AuthSignIn(ctx, &tg.AuthSignInRequest{ |
|
PhoneNumber: phone, |
|
PhoneCodeHash: codeHash, |
|
PhoneCode: code, |
|
}) |
|
if tgerr.Is(err, "SESSION_PASSWORD_NEEDED") { |
|
return nil, ErrPasswordAuthNeeded |
|
} |
|
if err != nil { |
|
return nil, errors.Wrap(err, "sign in") |
|
} |
|
result, err := checkResult(auth) |
|
if err != nil { |
|
return nil, errors.Wrap(err, "check") |
|
} |
|
return result, nil |
|
} |
|
|
|
// AcceptTOS accepts version of Terms Of Service. |
|
func (c *Client) AcceptTOS(ctx context.Context, id tg.DataJSON) error { |
|
_, err := c.api.HelpAcceptTermsOfService(ctx, id) |
|
return err |
|
} |
|
|
|
// SignUp wraps parameters for SignUp. |
|
type SignUp struct { |
|
PhoneNumber string |
|
PhoneCodeHash string |
|
FirstName string |
|
LastName string |
|
} |
|
|
|
// SignUp registers a validated phone number in the system. |
|
// |
|
// To obtain codeHash, use SendCode. |
|
// Use AuthFlow helper to handle authentication flow. |
|
func (c *Client) SignUp(ctx context.Context, s SignUp) (*tg.AuthAuthorization, error) { |
|
auth, err := c.api.AuthSignUp(ctx, &tg.AuthSignUpRequest{ |
|
LastName: s.LastName, |
|
PhoneCodeHash: s.PhoneCodeHash, |
|
PhoneNumber: s.PhoneNumber, |
|
FirstName: s.FirstName, |
|
}) |
|
if err != nil { |
|
return nil, errors.Wrap(err, "request") |
|
} |
|
result, err := checkResult(auth) |
|
if err != nil { |
|
return nil, errors.Wrap(err, "check") |
|
} |
|
return result, nil |
|
}
|
|
|