Add mtproto handshake

This commit is contained in:
9seconds
2019-09-10 16:44:00 +03:00
parent 1617866c24
commit b280f47731
4 changed files with 102 additions and 1 deletions
+96
View File
@@ -0,0 +1,96 @@
package mtproto
import (
"fmt"
"github.com/9seconds/mtg/mtproto/rpc"
"github.com/9seconds/mtg/protocol"
"github.com/9seconds/mtg/telegram"
"github.com/9seconds/mtg/wrappers"
)
func TelegramProtocol(req *protocol.TelegramRequest) (wrappers.Wrap, error) {
conn, err := telegram.Middle.Dial(req.Ctx,
req.Cancel,
req.ClientProtocol.DC(),
req.ClientProtocol.ConnectionProtocol())
if err != nil {
return nil, fmt.Errorf("cannot connect to telegram: %w", err)
}
rpcNonceConn := wrappers.NewMtprotoFrame(conn, rpc.SeqNoNonce)
rpcNonceReq, err := doRPCNonceRequest(rpcNonceConn)
if err != nil {
return nil, fmt.Errorf("cannot do nonce request: %w", err)
}
rpcNonceResp, err := getRPCNonceResponse(rpcNonceConn, rpcNonceReq)
if err != nil {
return nil, fmt.Errorf("cannot get nonce response: %w", err)
}
secureConn := wrappers.NewMiddleProxyCipher(conn, rpcNonceReq, rpcNonceResp, telegram.Middle.Secret())
frameConn := wrappers.NewMtprotoFrame(secureConn, rpc.SeqNoHandshake)
if err := doRPCHandshakeRequest(frameConn); err != nil {
return nil, fmt.Errorf("cannot do handshake request: %w", err)
}
if err := getRPCHandshakeResponse(frameConn); err != nil {
return nil, fmt.Errorf("cannot get handshake response: %w", err)
}
return frameConn, nil
}
func doRPCNonceRequest(conn wrappers.PacketWriter) (*rpc.NonceRequest, error) {
rpcNonceReq, err := rpc.NewNonceRequest(telegram.Middle.Secret())
if err != nil {
panic(err)
}
if err := conn.Write(rpcNonceReq.Bytes()); err != nil {
return nil, err
}
return rpcNonceReq, nil
}
func getRPCNonceResponse(conn wrappers.PacketReader, req *rpc.NonceRequest) (*rpc.NonceResponse, error) {
packet, err := conn.Read()
if err != nil {
return nil, fmt.Errorf("cannot read from connection: %w", err)
}
resp, err := rpc.NewNonceResponse(packet)
if err != nil {
return nil, fmt.Errorf("cannot build rpc nonce responce: %w", err)
}
if err = resp.Valid(req); err != nil {
return nil, fmt.Errorf("invalid nonce response: %w", err)
}
return resp, nil
}
func doRPCHandshakeRequest(conn wrappers.PacketWriter) error {
if err := conn.Write(rpc.HandshakeRequest); err != nil {
return fmt.Errorf("cannot make a request: %w", err)
}
return nil
}
func getRPCHandshakeResponse(conn wrappers.PacketReader) error {
packet, err := conn.Read()
if err != nil {
return fmt.Errorf("cannot read a response: %w", err)
}
resp, err := rpc.NewHandshakeResponse(packet)
if err != nil {
return fmt.Errorf("cannot build a handshake response: %w", err)
}
if err := resp.Valid(); err != nil {
return fmt.Errorf("invalid handshake response: %w", err)
}
return nil
}
+5
View File
@@ -17,12 +17,17 @@ const telegramDialTimeout = 10 * time.Second
type baseTelegram struct {
dialer net.Dialer
secret []byte
v4DefaultDC conntypes.DC
V6DefaultDC conntypes.DC
v4Addresses map[conntypes.DC][]string
v6Addresses map[conntypes.DC][]string
}
func (b *baseTelegram) Secret() []byte {
return b.secret
}
func (b *baseTelegram) dialToAddress(ctx context.Context,
cancel context.CancelFunc,
addr string) (wrappers.StreamReadWriteCloser, error) {
+1
View File
@@ -12,4 +12,5 @@ type Telegram interface {
context.CancelFunc,
conntypes.DC,
conntypes.ConnectionProtocol) (wrappers.StreamReadWriteCloser, error)
Secret() []byte
}
-1
View File
@@ -21,7 +21,6 @@ var Middle = NewMiddleTelegram()
type middleTelegram struct {
baseTelegram
secret []byte
mutex sync.RWMutex
}