move gotd fork into repo. (#111)

- update to latest telegram layer
- remove some references to fields in tg.Entities that don't exist in
the schema
- originally added here:
https://github.com/beeper/td/commit/820929062a2ba0104397bc01235ab58a9cff780e
  - referenced here
-
https://github.com/mautrix/telegramgo/commit/124f0967ed195b5a380c9bd02e170ada9710dde3
-
https://github.com/mautrix/telegramgo/commit/4205047aab2e0639217148b5d125bfaab668bd8e
This commit is contained in:
Adam Van Ymeren
2025-06-27 20:03:37 -07:00
committed by GitHub
parent 0952df0244
commit 7a04f298d2
19264 changed files with 1539697 additions and 84 deletions
+179
View File
@@ -0,0 +1,179 @@
package auth
import (
"context"
"fmt"
"time"
"github.com/go-faster/errors"
"go.mau.fi/mautrix-telegram/pkg/gotd/crypto"
"go.mau.fi/mautrix-telegram/pkg/gotd/crypto/srp"
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
)
// PasswordHash computes password hash to log in.
//
// See https://core.telegram.org/api/srp#checking-the-password-with-srp.
func PasswordHash(
password []byte,
srpID int64,
srpB, secureRandom []byte,
alg tg.PasswordKdfAlgoClass,
) (*tg.InputCheckPasswordSRP, error) {
s := srp.NewSRP(crypto.DefaultRand())
algo, ok := alg.(*tg.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow)
if !ok {
return nil, errors.Errorf("unsupported algo: %T", alg)
}
a, err := s.Hash(password, srpB, secureRandom, srp.Input(*algo))
if err != nil {
return nil, errors.Wrap(err, "create SRP answer")
}
return &tg.InputCheckPasswordSRP{
SRPID: srpID,
A: a.A,
M1: a.M1,
}, nil
}
// NewPasswordHash computes new password hash to update password.
//
// Notice that NewPasswordHash mutates given alg.
//
// See https://core.telegram.org/api/srp#setting-a-new-2fa-password.
func NewPasswordHash(
password []byte,
algo *tg.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow,
) (hash []byte, _ error) {
s := srp.NewSRP(crypto.DefaultRand())
hash, newSalt, err := s.NewHash(password, srp.Input(*algo))
if err != nil {
return nil, errors.Wrap(err, "create SRP answer")
}
algo.Salt1 = newSalt
return hash, nil
}
var (
emptyPassword tg.InputCheckPasswordSRPClass = &tg.InputCheckPasswordEmpty{}
)
// UpdatePasswordOptions is options structure for UpdatePassword.
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)
}
// UpdatePassword sets new cloud password for this account.
//
// See https://core.telegram.org/api/srp#setting-a-new-2fa-password.
func (c *Client) UpdatePassword(
ctx context.Context,
newPassword string,
opts UpdatePasswordOptions,
) error {
p, err := c.api.AccountGetPassword(ctx)
if err != nil {
return errors.Wrap(err, "get SRP parameters")
}
algo, ok := p.NewAlgo.(*tg.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow)
if !ok {
return errors.Errorf("unsupported algo: %T", p.NewAlgo)
}
newHash, err := NewPasswordHash([]byte(newPassword), algo)
if err != nil {
return errors.Wrap(err, "compute new password hash")
}
var old = emptyPassword
if p.HasPassword {
if opts.Password == nil {
return ErrPasswordNotProvided
}
oldPassword, err := opts.Password(ctx)
if err != nil {
return errors.Wrap(err, "get password")
}
hash, err := PasswordHash([]byte(oldPassword), p.SRPID, p.SRPB, p.SecureRandom, p.CurrentAlgo)
if err != nil {
return errors.Wrap(err, "compute old password hash")
}
old = hash
}
if _, err := c.api.AccountUpdatePasswordSettings(ctx, &tg.AccountUpdatePasswordSettingsRequest{
Password: old,
NewSettings: tg.AccountPasswordInputSettings{
NewAlgo: algo,
NewPasswordHash: newHash,
Hint: opts.Hint,
},
}); err != nil {
return errors.Wrap(err, "update password")
}
return nil
}
// ResetFailedWaitError reports that you recently requested a password reset that was cancel and need to wait until the
// specified date before requesting another reset.
type ResetFailedWaitError struct {
Result tg.AccountResetPasswordFailedWait
}
// Until returns time required to wait.
func (r ResetFailedWaitError) Until() time.Duration {
retryDate := time.Unix(int64(r.Result.RetryDate), 0)
return time.Until(retryDate)
}
// Error implements error.
func (r *ResetFailedWaitError) Error() string {
return fmt.Sprintf("wait to reset password (%s)", r.Until())
}
// 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)
if err != nil {
return time.Time{}, errors.Wrap(err, "reset password")
}
switch v := r.(type) {
case *tg.AccountResetPasswordFailedWait:
return time.Time{}, &ResetFailedWaitError{Result: *v}
case *tg.AccountResetPasswordRequestedWait:
return time.Unix(int64(v.UntilDate), 0), nil
case *tg.AccountResetPasswordOk:
return time.Time{}, nil
default:
return time.Time{}, errors.Errorf("unexpected type %T", v)
}
}
// CancelPasswordReset cancels password reset.
//
// See https://core.telegram.org/api/srp#password-reset.
func (c *Client) CancelPasswordReset(ctx context.Context) error {
if _, err := c.api.AccountDeclinePasswordReset(ctx); err != nil {
return errors.Wrap(err, "cancel password reset")
}
return nil
}