Skip to content

Commit

Permalink
docs(auth): add some examples
Browse files Browse the repository at this point in the history
  • Loading branch information
tdakkota committed Jan 29, 2022
1 parent bb3f7ee commit 26c5138
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 7 deletions.
2 changes: 1 addition & 1 deletion internal/crypto/srp/new_hash.go
Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions telegram/auth/password.go
Expand Up @@ -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)
}

Expand Down Expand Up @@ -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)
Expand Down
62 changes: 62 additions & 0 deletions 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)
}
}
72 changes: 66 additions & 6 deletions telegram/auth_test.go → telegram/auth_example_test.go
Expand Up @@ -3,7 +3,6 @@ package telegram_test
import (
"bufio"
"context"
"crypto/rand"
"fmt"
"log"
"os"
Expand All @@ -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)
Expand Down Expand Up @@ -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)
}
Expand Down

0 comments on commit 26c5138

Please sign in to comment.