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:
@@ -0,0 +1,254 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/go-faster/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/bin"
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/tgerr"
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/tgmock"
|
||||
)
|
||||
|
||||
func getHex(t testing.TB, in string) []byte {
|
||||
res, err := hex.DecodeString(in)
|
||||
if err != nil {
|
||||
t.Fatal("failed to get hex", err)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func TestClient_AuthSignIn(t *testing.T) {
|
||||
const (
|
||||
phone = "123123"
|
||||
code = "1010"
|
||||
password = "secret"
|
||||
codeHash = "hash"
|
||||
)
|
||||
ctx := context.Background()
|
||||
testUser := &tg.User{ID: 1}
|
||||
invoker := tgmock.Invoker(func(body bin.Encoder) (bin.Encoder, error) {
|
||||
switch req := body.(type) {
|
||||
case *tg.UsersGetUsersRequest:
|
||||
return nil, &tgerr.Error{
|
||||
Code: 401,
|
||||
Message: "AUTH_KEY_UNREGISTERED",
|
||||
Type: "AUTH_KEY_UNREGISTERED",
|
||||
}
|
||||
case *tg.AuthSendCodeRequest:
|
||||
settings := tg.CodeSettings{}
|
||||
settings.SetCurrentNumber(true)
|
||||
assert.Equal(t, &tg.AuthSendCodeRequest{
|
||||
PhoneNumber: phone,
|
||||
APIHash: testAppHash,
|
||||
APIID: testAppID,
|
||||
Settings: settings,
|
||||
}, req)
|
||||
return &tg.AuthSentCode{
|
||||
Type: &tg.AuthSentCodeTypeApp{},
|
||||
PhoneCodeHash: codeHash,
|
||||
}, nil
|
||||
case *tg.AuthSignInRequest:
|
||||
assert.Equal(t, &tg.AuthSignInRequest{
|
||||
PhoneNumber: phone,
|
||||
PhoneCodeHash: codeHash,
|
||||
PhoneCode: code,
|
||||
}, req)
|
||||
return nil, tgerr.New(401, "SESSION_PASSWORD_NEEDED")
|
||||
case *tg.AccountGetPasswordRequest:
|
||||
algo := &tg.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow{
|
||||
Salt1: getHex(t, "4D11FB6BEC38F9D2546BB0F61E4F1C99A1BC0DB8F0D5F35B1291B37B213123D7ED48F3C6794D495B"),
|
||||
Salt2: getHex(t, "A1B181AAFE88188680AE32860D60BB01"),
|
||||
G: 3,
|
||||
P: getHex(t, "C71CAEB9C6B1C9048E6C522F70F13F73980D40238E3E21C14934D037563D930F"+
|
||||
"48198A0AA7C14058229493D22530F4DBFA336F6E0AC925139543AED44CCE7C37"+
|
||||
"20FD51F69458705AC68CD4FE6B6B13ABDC9746512969328454F18FAF8C595F64"+
|
||||
"2477FE96BB2A941D5BCD1D4AC8CC49880708FA9B378E3C4F3A9060BEE67CF9A4"+
|
||||
"A4A695811051907E162753B56B0F6B410DBA74D8A84B2A14B3144E0EF1284754"+
|
||||
"FD17ED950D5965B4B9DD46582DB1178D169C6BC465B0D6FF9CA3928FEF5B9AE4"+
|
||||
"E418FC15E83EBEA0F87FA9FF5EED70050DED2849F47BF959D956850CE929851F"+
|
||||
"0D8115F635B105EE2E4E15D04B2454BF6F4FADF034B10403119CD8E3B92FCC5B"),
|
||||
}
|
||||
pwd := &tg.AccountPassword{
|
||||
NewAlgo: algo,
|
||||
NewSecureAlgo: &tg.SecurePasswordKdfAlgoPBKDF2HMACSHA512iter100000{},
|
||||
}
|
||||
pwd.SetCurrentAlgo(algo)
|
||||
return pwd, nil
|
||||
case *tg.AuthCheckPasswordRequest:
|
||||
// TODO(ernado): Check actual secure remote password here.
|
||||
switch pwd := req.Password.(type) {
|
||||
case *tg.InputCheckPasswordSRP:
|
||||
assert.NotEmpty(t, pwd.A)
|
||||
assert.NotEmpty(t, pwd.M1)
|
||||
assert.NotEqual(t, pwd.SRPID, 0)
|
||||
default:
|
||||
t.Errorf("unexpectd pwd type %T", pwd)
|
||||
}
|
||||
return &tg.AuthAuthorization{
|
||||
User: testUser,
|
||||
}, nil
|
||||
}
|
||||
return nil, errors.New("unexpected")
|
||||
})
|
||||
|
||||
t.Run("Manual", func(t *testing.T) {
|
||||
// 1. Request code from server to device.
|
||||
client := testClient(invoker)
|
||||
sentCode, err := client.SendCode(ctx, phone, SendCodeOptions{CurrentNumber: true})
|
||||
require.NoError(t, err)
|
||||
h := sentCode.(*tg.AuthSentCode).PhoneCodeHash
|
||||
require.Equal(t, codeHash, h)
|
||||
|
||||
// 2. Send code from device to server.
|
||||
// Server is responding with 2FA password prompt.
|
||||
_, signInErr := client.SignIn(ctx, phone, code, h)
|
||||
require.ErrorIs(t, signInErr, ErrPasswordAuthNeeded)
|
||||
|
||||
// 3. Provide 2FA password.
|
||||
result, err := client.Password(ctx, password)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, testUser, result.User)
|
||||
})
|
||||
|
||||
flow := NewFlow(
|
||||
Constant(phone, password, CodeAuthenticatorFunc(
|
||||
func(ctx context.Context, _ *tg.AuthSentCode) (string, error) {
|
||||
return code, nil
|
||||
},
|
||||
)),
|
||||
SendCodeOptions{CurrentNumber: true},
|
||||
)
|
||||
t.Run("AuthFlow", func(t *testing.T) {
|
||||
require.NoError(t, flow.Run(ctx, testClient(invoker)))
|
||||
})
|
||||
t.Run("IfNecessary", func(t *testing.T) {
|
||||
require.NoError(t, testClient(invoker).IfNecessary(ctx, flow))
|
||||
})
|
||||
}
|
||||
|
||||
func TestClientTestAuth(t *testing.T) {
|
||||
const (
|
||||
codeHash = "hash"
|
||||
dcID = 2
|
||||
)
|
||||
ctx := context.Background()
|
||||
invoker := tgmock.Invoker(func(body bin.Encoder) (bin.Encoder, error) {
|
||||
switch req := body.(type) {
|
||||
case *tg.AuthSendCodeRequest:
|
||||
assert.Equal(t, &tg.AuthSendCodeRequest{
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
APIHash: testAppHash,
|
||||
APIID: testAppID,
|
||||
Settings: tg.CodeSettings{},
|
||||
}, req)
|
||||
return &tg.AuthSentCode{
|
||||
Type: &tg.AuthSentCodeTypeApp{
|
||||
Length: 6,
|
||||
},
|
||||
PhoneCodeHash: codeHash,
|
||||
}, nil
|
||||
case *tg.AuthSignInRequest:
|
||||
if !strings.HasPrefix(req.PhoneNumber, "99966") {
|
||||
t.Fatalf("unexpected phone number %s", req.PhoneNumber)
|
||||
}
|
||||
dcPart := req.PhoneNumber[5:6]
|
||||
assert.Equal(t, strconv.Itoa(dcID), dcPart, "dc part of phone number")
|
||||
assert.Equal(t, &tg.AuthSignInRequest{
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
PhoneCodeHash: codeHash,
|
||||
PhoneCode: strings.Repeat(dcPart, 6),
|
||||
}, req)
|
||||
return &tg.AuthAuthorization{
|
||||
User: &tg.User{ID: 1},
|
||||
}, nil
|
||||
}
|
||||
return nil, errors.New("unexpected")
|
||||
})
|
||||
require.NoError(t, NewFlow(
|
||||
Test(rand.New(rand.NewSource(1)), dcID),
|
||||
SendCodeOptions{},
|
||||
).Run(ctx, testClient(invoker)))
|
||||
}
|
||||
|
||||
func TestClientTestSignUp(t *testing.T) {
|
||||
const (
|
||||
dcID = 2
|
||||
codeHash = "hash"
|
||||
tosID = "foo"
|
||||
)
|
||||
ctx := context.Background()
|
||||
invoker := tgmock.Invoker(func(body bin.Encoder) (bin.Encoder, error) {
|
||||
switch req := body.(type) {
|
||||
case *tg.AuthSendCodeRequest:
|
||||
assert.Equal(t, &tg.AuthSendCodeRequest{
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
APIHash: testAppHash,
|
||||
APIID: testAppID,
|
||||
Settings: tg.CodeSettings{},
|
||||
}, req)
|
||||
return &tg.AuthSentCode{
|
||||
Type: &tg.AuthSentCodeTypeApp{
|
||||
Length: 6,
|
||||
},
|
||||
PhoneCodeHash: codeHash,
|
||||
}, nil
|
||||
case *tg.AuthSignUpRequest:
|
||||
assert.Equal(t, &tg.AuthSignUpRequest{
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
PhoneCodeHash: codeHash,
|
||||
FirstName: "Test",
|
||||
LastName: "User",
|
||||
}, req)
|
||||
return &tg.AuthAuthorization{
|
||||
User: &tg.User{ID: 1},
|
||||
}, nil
|
||||
case *tg.HelpAcceptTermsOfServiceRequest:
|
||||
return &tg.BoolTrue{}, nil
|
||||
case *tg.AuthSignInRequest:
|
||||
if !strings.HasPrefix(req.PhoneNumber, "99966") {
|
||||
t.Fatalf("unexpected phone number %s", req.PhoneNumber)
|
||||
}
|
||||
dcPart := req.PhoneNumber[5:6]
|
||||
assert.Equal(t, strconv.Itoa(dcID), dcPart, "dc part of phone number")
|
||||
assert.Equal(t, &tg.AuthSignInRequest{
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
PhoneCodeHash: codeHash,
|
||||
PhoneCode: strings.Repeat(dcPart, 6),
|
||||
}, req)
|
||||
|
||||
res := &tg.AuthAuthorizationSignUpRequired{}
|
||||
res.SetTermsOfService(tg.HelpTermsOfService{ID: tg.DataJSON{Data: tosID}})
|
||||
|
||||
return res, nil
|
||||
}
|
||||
return nil, errors.New("unexpected")
|
||||
})
|
||||
require.NoError(t, NewFlow(
|
||||
Test(rand.New(rand.NewSource(1)), dcID),
|
||||
SendCodeOptions{},
|
||||
).Run(ctx, testClient(invoker)))
|
||||
}
|
||||
|
||||
func TestClient_AcceptTOS(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
mockTest(func(a *require.Assertions, mock *tgmock.Mock, client *Client) {
|
||||
mock.Expect().ThenUnregistered()
|
||||
a.Error(client.AcceptTOS(ctx, tg.DataJSON{
|
||||
Data: `{"data":"data"}`,
|
||||
}))
|
||||
|
||||
mock.Expect().ThenTrue()
|
||||
a.NoError(client.AcceptTOS(ctx, tg.DataJSON{
|
||||
Data: `{"data":"data"}`,
|
||||
}))
|
||||
})(t)
|
||||
}
|
||||
Reference in New Issue
Block a user