mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 15:14:03 +03:00
Add background update for middle proxy
This commit is contained in:
@@ -25,8 +25,4 @@ var (
|
|||||||
|
|
||||||
HandshakeSenderPID = []byte("IPIPPRPDTIME")
|
HandshakeSenderPID = []byte("IPIPPRPDTIME")
|
||||||
HandshakePeerPID = []byte("IPIPPRPDTIME")
|
HandshakePeerPID = []byte("IPIPPRPDTIME")
|
||||||
|
|
||||||
HandshakeRequest = append(TagHandshake,
|
|
||||||
append(HandshakeFlags,
|
|
||||||
append(HandshakeSenderPID, HandshakePeerPID...)...)...)
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import "github.com/9seconds/mtg/mtproto"
|
||||||
|
|
||||||
|
var HandshakeRequest = append(mtproto.TagHandshake,
|
||||||
|
append(mtproto.HandshakeFlags,
|
||||||
|
append(mtproto.HandshakeSenderPID, mtproto.HandshakePeerPID...)...)...)
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/9seconds/mtg/mtproto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HandshakeResponse struct {
|
||||||
|
Type []byte
|
||||||
|
Flags []byte
|
||||||
|
SenderPID []byte
|
||||||
|
PeerPID []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns a serialized handshake response.
|
||||||
|
func (r *HandshakeResponse) Bytes() []byte {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
buf.Write(r.Type) // nolint: gosec
|
||||||
|
buf.Write(r.Flags) // nolint: gosec
|
||||||
|
buf.Write(r.SenderPID) // nolint: gosec
|
||||||
|
buf.Write(r.PeerPID) // nolint: gosec
|
||||||
|
|
||||||
|
return buf.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid checks that handshake response compliments request.
|
||||||
|
func (r *HandshakeResponse) Valid() error {
|
||||||
|
if !bytes.Equal(r.Type, mtproto.TagHandshake) {
|
||||||
|
return errors.New("Unexpected handshake tag")
|
||||||
|
}
|
||||||
|
if !bytes.Equal(r.PeerPID, mtproto.HandshakeSenderPID) {
|
||||||
|
return errors.New("Incorrect sender PID")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHandshakeResponse constructs new handshake response from the given
|
||||||
|
// data.
|
||||||
|
func NewHandshakeResponse(data []byte) (*HandshakeResponse, error) {
|
||||||
|
if len(data) != 32 {
|
||||||
|
return nil, fmt.Errorf("Incorrect handshake response length %d", len(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &HandshakeResponse{
|
||||||
|
Type: data[:4],
|
||||||
|
Flags: data[4:8],
|
||||||
|
SenderPID: data[8:20],
|
||||||
|
PeerPID: data[20:],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/9seconds/mtg/mtproto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NonceRequest struct {
|
||||||
|
KeySelector []byte
|
||||||
|
CryptoTS []byte
|
||||||
|
Nonce []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns serialized nonce request.
|
||||||
|
func (r *NonceRequest) Bytes() []byte {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
buf.Write(mtproto.TagNonce) // nolint: gosec
|
||||||
|
buf.Write(r.KeySelector) // nolint: gosec
|
||||||
|
buf.Write(mtproto.NonceCryptoAES) // nolint: gosec
|
||||||
|
buf.Write(r.CryptoTS) // nolint: gosec
|
||||||
|
buf.Write(r.Nonce) // nolint: gosec
|
||||||
|
|
||||||
|
return buf.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNonceRequest builds new none request based on proxy secret.
|
||||||
|
func NewNonceRequest(proxySecret []byte) (*NonceRequest, error) {
|
||||||
|
nonce := make([]byte, 16)
|
||||||
|
keySelector := make([]byte, 4)
|
||||||
|
cryptoTS := make([]byte, 4)
|
||||||
|
|
||||||
|
if _, err := rand.Read(nonce); err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot generate nonce: %w", err)
|
||||||
|
}
|
||||||
|
copy(keySelector, proxySecret)
|
||||||
|
|
||||||
|
timestamp := time.Now().Truncate(time.Second).Unix() % 4294967296 // 256 ^ 4 - do not know how to name
|
||||||
|
binary.LittleEndian.PutUint32(cryptoTS, uint32(timestamp))
|
||||||
|
|
||||||
|
return &NonceRequest{
|
||||||
|
KeySelector: keySelector,
|
||||||
|
CryptoTS: cryptoTS,
|
||||||
|
Nonce: nonce,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/9seconds/mtg/mtproto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NonceResponse struct {
|
||||||
|
NonceRequest
|
||||||
|
|
||||||
|
Type []byte
|
||||||
|
Crypto []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns serialized form of the nonce response.
|
||||||
|
func (r *NonceResponse) Bytes() []byte {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
buf.Write(r.Type) // nolint: gosec
|
||||||
|
buf.Write(r.KeySelector) // nolint: gosec
|
||||||
|
buf.Write(r.Crypto) // nolint: gosec
|
||||||
|
buf.Write(r.CryptoTS) // nolint: gosec
|
||||||
|
buf.Write(r.Nonce) // nolint: gosec
|
||||||
|
|
||||||
|
return buf.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NonceResponse) Valid(req *NonceRequest) error {
|
||||||
|
if !bytes.Equal(r.Type, mtproto.TagNonce) {
|
||||||
|
return errors.New("Unexpected RPC type")
|
||||||
|
}
|
||||||
|
if !bytes.Equal(r.Crypto, mtproto.NonceCryptoAES) {
|
||||||
|
return errors.New("Unexpected crypto type")
|
||||||
|
}
|
||||||
|
if !bytes.Equal(r.KeySelector, req.KeySelector) {
|
||||||
|
return errors.New("Unexpected key selector")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNonceResponse build new nonce response based on the given data.
|
||||||
|
func NewNonceResponse(data []byte) (*NonceResponse, error) {
|
||||||
|
if len(data) != 32 {
|
||||||
|
return nil, fmt.Errorf("Unexpected message length %d", len(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &NonceResponse{
|
||||||
|
NonceRequest: NonceRequest{
|
||||||
|
KeySelector: data[4:8],
|
||||||
|
CryptoTS: data[12:16],
|
||||||
|
Nonce: data[16:],
|
||||||
|
},
|
||||||
|
Type: data[:4],
|
||||||
|
Crypto: data[8:12],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package mtproto
|
package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
@@ -3,13 +3,19 @@ package telegram
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/9seconds/mtg/conntypes"
|
"github.com/9seconds/mtg/conntypes"
|
||||||
"github.com/9seconds/mtg/telegram/api"
|
"github.com/9seconds/mtg/telegram/api"
|
||||||
"github.com/9seconds/mtg/wrappers"
|
"github.com/9seconds/mtg/wrappers"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const middleTelegramBackgroundUpdateEvery = time.Hour
|
||||||
|
|
||||||
type middleTelegram struct {
|
type middleTelegram struct {
|
||||||
baseTelegram
|
baseTelegram
|
||||||
|
|
||||||
@@ -44,6 +50,15 @@ func (m *middleTelegram) update() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *middleTelegram) backgroundUpdate() {
|
||||||
|
logger := zap.S().Named("telegram")
|
||||||
|
for range time.Tick(middleTelegramBackgroundUpdateEvery) {
|
||||||
|
if err := m.update(); err != nil {
|
||||||
|
logger.Warnw("Cannot update Telegram proxies", "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *middleTelegram) Dial(ctx context.Context,
|
func (m *middleTelegram) Dial(ctx context.Context,
|
||||||
cancel context.CancelFunc,
|
cancel context.CancelFunc,
|
||||||
dc conntypes.DC,
|
dc conntypes.DC,
|
||||||
@@ -52,5 +67,22 @@ func (m *middleTelegram) Dial(ctx context.Context,
|
|||||||
dc = conntypes.DCDefaultIdx
|
dc = conntypes.DCDefaultIdx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.mutex.RLock()
|
||||||
|
defer m.mutex.RUnlock()
|
||||||
|
|
||||||
return m.baseTelegram.dial(ctx, cancel, dc, protocol)
|
return m.baseTelegram.dial(ctx, cancel, dc, protocol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewMiddleTelegram() Telegram {
|
||||||
|
tg := &middleTelegram{
|
||||||
|
baseTelegram: baseTelegram{
|
||||||
|
dialer: net.Dialer{Timeout: telegramDialTimeout},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := tg.update(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
go tg.backgroundUpdate()
|
||||||
|
|
||||||
|
return tg
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user