mirror of
https://github.com/mautrix/telegram.git
synced 2026-05-17 07:25:46 +03:00
client: add initial proxy support (#1062)
This commit is contained in:
@@ -210,11 +210,15 @@ func NewTelegramClient(ctx context.Context, tc *TelegramConnector, login *bridge
|
||||
Storage: client.ScopedStore,
|
||||
AccessHasher: client.ScopedStore,
|
||||
})
|
||||
|
||||
resolver, err := GetProxyResolver(tc.Config.ProxyConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.client = telegram.NewClient(tc.Config.APIID, tc.Config.APIHash, telegram.Options{
|
||||
CustomSessionStorage: &login.Metadata.(*UserLoginMetadata).Session,
|
||||
Logger: zaplog,
|
||||
UpdateHandler: client.updatesManager,
|
||||
Resolver: resolver,
|
||||
OnDead: client.onDead,
|
||||
OnSession: client.onSession,
|
||||
OnConnected: client.onConnected,
|
||||
|
||||
@@ -55,6 +55,13 @@ type DeviceInfo struct {
|
||||
LangCode string `yaml:"lang_code"`
|
||||
}
|
||||
|
||||
type ProxyConfig struct {
|
||||
Type string `yaml:"type"`
|
||||
Address string `yaml:"address"`
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
}
|
||||
|
||||
type TelegramConfig struct {
|
||||
APIID int `yaml:"api_id"`
|
||||
APIHash string `yaml:"api_hash"`
|
||||
@@ -68,6 +75,8 @@ type TelegramConfig struct {
|
||||
TimeoutSeconds int `yaml:"timeout_seconds"`
|
||||
} `yaml:"ping"`
|
||||
|
||||
ProxyConfig ProxyConfig `yaml:"proxy"`
|
||||
|
||||
Sync struct {
|
||||
UpdateLimit int `yaml:"update_limit"`
|
||||
CreateLimit int `yaml:"create_limit"`
|
||||
@@ -161,6 +170,10 @@ func upgradeConfig(helper up.Helper) {
|
||||
helper.Copy(up.Bool, "member_list", "skip_deleted")
|
||||
helper.Copy(up.Int, "ping", "interval_seconds")
|
||||
helper.Copy(up.Int, "ping", "timeout_seconds")
|
||||
helper.Copy(up.Str, "proxy", "type")
|
||||
helper.Copy(up.Str|up.Null, "proxy", "address")
|
||||
helper.Copy(up.Str|up.Null, "proxy", "username")
|
||||
helper.Copy(up.Str|up.Null, "proxy", "password")
|
||||
helper.Copy(up.Int, "sync", "update_limit")
|
||||
helper.Copy(up.Int, "sync", "create_limit")
|
||||
helper.Copy(up.Int, "sync", "login_sync_limit")
|
||||
@@ -187,6 +200,7 @@ func (tc *TelegramConnector) GetConfig() (example string, data any, upgrader up.
|
||||
{"animated_sticker"},
|
||||
{"member_list"},
|
||||
{"ping"},
|
||||
{"proxy"},
|
||||
{"sync"},
|
||||
{"takeout"},
|
||||
{"max_member_count"},
|
||||
|
||||
@@ -54,6 +54,16 @@ ping:
|
||||
# The timeout (in seconds) for a single ping.
|
||||
timeout_seconds: 10
|
||||
|
||||
# Proxy settings
|
||||
proxy:
|
||||
# Allowed types: disabled, socks5, mtproxy
|
||||
type: disabled
|
||||
# Proxy IP address/domain name and port.
|
||||
address: "127.0.0.1:1080"
|
||||
# Proxy authentication (optional). Put MTProxy secret in password field.
|
||||
username:
|
||||
password:
|
||||
|
||||
sync:
|
||||
# Number of most recently active dialogs to check when syncing chats.
|
||||
# Set to -1 to remove limit.
|
||||
|
||||
@@ -125,7 +125,12 @@ func (bl *baseLogin) makeClient(ctx context.Context, dispatcher *tg.UpdateDispat
|
||||
if dispatcher == nil {
|
||||
dispatcher = ptr.Ptr(tg.NewUpdateDispatcher())
|
||||
}
|
||||
resolver, err := GetProxyResolver(bl.main.Config.ProxyConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bl.client = telegram.NewClient(bl.main.Config.APIID, bl.main.Config.APIHash, telegram.Options{
|
||||
Resolver: resolver,
|
||||
CustomSessionStorage: &bl.session,
|
||||
Logger: zaplog,
|
||||
Device: bl.main.deviceConfig(),
|
||||
|
||||
@@ -63,7 +63,16 @@ func (bl *BotLogin) SubmitUserInput(ctx context.Context, input map[string]string
|
||||
ctx = log.WithContext(ctx)
|
||||
|
||||
botToken := input[LoginStepIDBotToken]
|
||||
err := logoutBotAPI(ctx, botToken)
|
||||
dialFunc, err := GetProxyDialFunc(bl.main.Config.ProxyConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
httpClient := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
DialContext: dialFunc,
|
||||
},
|
||||
}
|
||||
err = logoutBotAPI(ctx, botToken, httpClient)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to logout from bot API: %w", err)
|
||||
}
|
||||
@@ -86,12 +95,12 @@ type botAPIResponse struct {
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func logoutBotAPI(ctx context.Context, token string) error {
|
||||
func logoutBotAPI(ctx context.Context, token string, client *http.Client) error {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://api.telegram.org/bot"+token+"/logOut", nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to prepare request: %w", err)
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
|
||||
61
pkg/connector/proxy.go
Normal file
61
pkg/connector/proxy.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// mautrix-telegram - A Matrix-Telegram puppeting bridge.
|
||||
// Copyright (C) 2026 Vladislav Agarkov
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package connector
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/net/proxy"
|
||||
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/telegram/dcs"
|
||||
)
|
||||
|
||||
func GetProxyDialFunc(cfg ProxyConfig) (dcs.DialFunc, error) {
|
||||
switch cfg.Type {
|
||||
// we can't proxy HTTP through mtproxy
|
||||
case "disabled", "mtproxy":
|
||||
return nil, nil
|
||||
case "socks5":
|
||||
var auth *proxy.Auth
|
||||
if cfg.Username != "" && cfg.Password != "" {
|
||||
auth = &proxy.Auth{User: cfg.Username, Password: cfg.Password}
|
||||
}
|
||||
sock5, err := proxy.SOCKS5("tcp", cfg.Address, auth, proxy.Direct)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sock5.(proxy.ContextDialer).DialContext, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported proxy type %s", cfg.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func GetProxyResolver(cfg ProxyConfig) (dcs.Resolver, error) {
|
||||
switch cfg.Type {
|
||||
case "disabled", "socks5":
|
||||
dialer, err := GetProxyDialFunc(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resolver := dcs.Plain(dcs.PlainOptions{Dial: dialer})
|
||||
return resolver, nil
|
||||
case "mtproxy":
|
||||
return dcs.MTProxy(cfg.Address, []byte(cfg.Password), dcs.MTProxyOptions{})
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported proxy type %s", cfg.Type)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user