From 26c51380a6fea7ffe6e0adc4467c756735679268 Mon Sep 17 00:00:00 2001 From: tdakkota Date: Sat, 29 Jan 2022 16:24:12 +0300 Subject: [PATCH] docs(auth): add some examples --- internal/crypto/srp/new_hash.go | 2 +- telegram/auth/password.go | 4 ++ telegram/auth/password_example_test.go | 62 ++++++++++++++++ .../{auth_test.go => auth_example_test.go} | 72 +++++++++++++++++-- 4 files changed, 133 insertions(+), 7 deletions(-) create mode 100644 telegram/auth/password_example_test.go rename telegram/{auth_test.go => auth_example_test.go} (60%) diff --git a/internal/crypto/srp/new_hash.go b/internal/crypto/srp/new_hash.go index 8fd720d2ae..b5bb44a9bc 100644 --- a/internal/crypto/srp/new_hash.go +++ b/internal/crypto/srp/new_hash.go @@ -29,7 +29,7 @@ func (s SRP) computeXV(password, clientSalt, serverSalt []byte, g, p *big.Int) ( // See https://github.com/tdlib/td/blob/fa8feefed70d64271945e9d5fd010b957d93c8cd/td/telegram/PasswordManager.cpp#L57. // // TDesktop implementation: -// See https://github.com/telegramdesktop/tdesktop/blob/624d83dc6008310d5fb88831f4d633992c864ba1/Telegram/SourceFiles/core/core_cloud_password.cpp#L68. +// See https://github.com/telegramdesktop/tdesktop/blob/v3.4.8/Telegram/SourceFiles/core/core_cloud_password.cpp#L68. func (s SRP) NewHash(password []byte, i Input) (hash, newSalt []byte, _ error) { // Generate a new new_password_hash using the KDF algorithm specified in the new_settings, // just append 32 sufficiently random bytes to the salt1, first. Proceed as for checking passwords with SRP, diff --git a/telegram/auth/password.go b/telegram/auth/password.go index fca7e1e479..91742ab7fc 100644 --- a/telegram/auth/password.go +++ b/telegram/auth/password.go @@ -69,6 +69,8 @@ type UpdatePasswordOptions struct { // Hint is new password hint. Hint string // Password is password callback. + // + // If password was requested and Password is nil, ErrPasswordNotProvided error will be returned. Password func(ctx context.Context) (string, error) } @@ -146,6 +148,8 @@ func (r *ResetFailedWaitError) Error() string { // ResetPassword resets cloud password and returns time to wait until reset be performed. // If time is zero, password was successfully reset. // +// May return ResetFailedWaitError. +// // See https://core.telegram.org/api/srp#password-reset. func (c *Client) ResetPassword(ctx context.Context) (time.Time, error) { r, err := c.api.AccountResetPassword(ctx) diff --git a/telegram/auth/password_example_test.go b/telegram/auth/password_example_test.go new file mode 100644 index 0000000000..a7b4fd70c8 --- /dev/null +++ b/telegram/auth/password_example_test.go @@ -0,0 +1,62 @@ +package auth_test + +import ( + "context" + "fmt" + + "github.com/go-faster/errors" + + "github.com/gotd/td/telegram" + "github.com/gotd/td/telegram/auth" +) + +func ExampleClient_UpdatePassword() { + ctx := context.Background() + client := telegram.NewClient(telegram.TestAppID, telegram.TestAppHash, telegram.Options{}) + if err := client.Run(ctx, func(ctx context.Context) error { + // Updating password. + if err := client.Auth().UpdatePassword(ctx, "new_password", auth.UpdatePasswordOptions{ + // Hint sets new password hint. + Hint: "new password hint", + // Password will be called if old password is requested by Telegram. + // + // If password was requested and Password is nil, auth.ErrPasswordNotProvided error will be returned. + Password: func(ctx context.Context) (string, error) { + return "old_password", nil + }, + }); err != nil { + return err + } + + return nil + }); err != nil { + panic(err) + } +} + +func ExampleClient_ResetPassword() { + ctx := context.Background() + client := telegram.NewClient(telegram.TestAppID, telegram.TestAppHash, telegram.Options{}) + if err := client.Run(ctx, func(ctx context.Context) error { + wait, err := client.Auth().ResetPassword(ctx) + var waitErr *auth.ResetFailedWaitError + switch { + case errors.As(err, &waitErr): + // Telegram requested wait until making new reset request. + fmt.Printf("Wait until %s to reset password.\n", wait.String()) + case err != nil: + return err + } + + // If returned time is zero, password was successfully reset. + if wait.IsZero() { + fmt.Println("Password was reset.") + return nil + } + + fmt.Printf("Password will be reset on %s.\n", wait.String()) + return nil + }); err != nil { + panic(err) + } +} diff --git a/telegram/auth_test.go b/telegram/auth_example_test.go similarity index 60% rename from telegram/auth_test.go rename to telegram/auth_example_test.go index ea19d93044..201cfc52f5 100644 --- a/telegram/auth_test.go +++ b/telegram/auth_example_test.go @@ -3,7 +3,6 @@ package telegram_test import ( "bufio" "context" - "crypto/rand" "fmt" "log" "os" @@ -17,7 +16,46 @@ import ( "github.com/gotd/td/tg" ) -func ExampleClient_Auth() { +func ExampleClient_Auth_codeOnly() { + check := func(err error) { + if err != nil { + panic(err) + } + } + + var ( + appIDString = os.Getenv("APP_ID") + appHash = os.Getenv("APP_HASH") + phone = os.Getenv("PHONE") + ) + if appIDString == "" || appHash == "" || phone == "" { + log.Fatal("PHONE, APP_ID or APP_HASH is not set") + } + + appID, err := strconv.Atoi(appIDString) + check(err) + + ctx := context.Background() + client := telegram.NewClient(appID, appHash, telegram.Options{}) + codeAsk := func(ctx context.Context, sentCode *tg.AuthSentCode) (string, error) { + fmt.Print("code:") + code, err := bufio.NewReader(os.Stdin).ReadString('\n') + if err != nil { + return "", err + } + code = strings.ReplaceAll(code, "\n", "") + return code, nil + } + + check(client.Run(ctx, func(ctx context.Context) error { + return auth.NewFlow( + auth.CodeOnly(phone, auth.CodeAuthenticatorFunc(codeAsk)), + auth.SendCodeOptions{}, + ).Run(ctx, client.Auth()) + })) +} + +func ExampleClient_Auth_password() { check := func(err error) { if err != nil { panic(err) @@ -67,10 +105,32 @@ func ExampleClient_Auth_test() { DCList: dcs.Test(), }) if err := client.Run(ctx, func(ctx context.Context) error { - return auth.NewFlow( - auth.Test(rand.Reader, dcID), - auth.SendCodeOptions{}, - ).Run(ctx, client.Auth()) + return client.Auth().Test(ctx, dcID) + }); err != nil { + panic(err) + } +} + +func ExampleClient_Auth_bot() { + ctx := context.Background() + client := telegram.NewClient(telegram.TestAppID, telegram.TestAppHash, telegram.Options{}) + if err := client.Run(ctx, func(ctx context.Context) error { + // Checking auth status. + status, err := client.Auth().Status(ctx) + if err != nil { + return err + } + // Can be already authenticated if we have valid session in + // session storage. + if !status.Authorized { + // Otherwise, perform bot authentication. + if _, err := client.Auth().Bot(ctx, os.Getenv("BOT_TOKEN")); err != nil { + return err + } + } + + // All good, manually authenticated. + return nil }); err != nil { panic(err) }