connector: hex-decode mtproxy secret
dcs.MTProxy expects raw secret bytes. Carrying them verbatim through a YAML string field is impossible: real secrets contain bytes >= 0x80 (faketls starts with 0xee, secured with 0xdd) which cannot survive a unicode string round-trip, so the value reached the bridge corrupted or empty (gotd then logged "invalid secret"). Accept the standard hex form printed by mtg/MTProxy tooling (e.g. "ee" + 16-byte secret + cloak domain hex) and decode it before handing the bytes to gotd. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -61,6 +61,8 @@ proxy:
|
||||
# Proxy IP address/domain name and port.
|
||||
address: "127.0.0.1:1080"
|
||||
# Proxy authentication (optional). Put MTProxy secret in password field.
|
||||
# For mtproxy, the secret must be hex-encoded (the same form mtg/MTProxy
|
||||
# tools print, e.g. "ee" + 16-byte secret + cloak domain hex for faketls).
|
||||
username:
|
||||
password:
|
||||
|
||||
|
||||
+23
-1
@@ -17,13 +17,31 @@
|
||||
package connector
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/proxy"
|
||||
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/telegram/dcs"
|
||||
)
|
||||
|
||||
// decodeMTProxySecret parses an MTProxy secret string into raw bytes.
|
||||
// MTProxy secrets are binary (faketls secrets begin with 0xEE, secured with 0xDD)
|
||||
// and cannot be carried verbatim in a YAML string field, so we accept the standard
|
||||
// hex encoding (optionally prefixed with "ee"/"dd") used by mtg/MTProxy tooling.
|
||||
func decodeMTProxySecret(s string) ([]byte, error) {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return nil, fmt.Errorf("mtproxy secret is empty")
|
||||
}
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("mtproxy secret must be hex-encoded: %w", err)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func GetProxyDialFunc(cfg ProxyConfig) (dcs.DialFunc, error) {
|
||||
switch cfg.Type {
|
||||
// we can't proxy HTTP through mtproxy
|
||||
@@ -54,7 +72,11 @@ func GetProxyResolver(cfg ProxyConfig) (dcs.Resolver, error) {
|
||||
resolver := dcs.Plain(dcs.PlainOptions{Dial: dialer})
|
||||
return resolver, nil
|
||||
case "mtproxy":
|
||||
return dcs.MTProxy(cfg.Address, []byte(cfg.Password), dcs.MTProxyOptions{})
|
||||
secret, err := decodeMTProxySecret(cfg.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dcs.MTProxy(cfg.Address, secret, dcs.MTProxyOptions{})
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported proxy type %s", cfg.Type)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package connector
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDecodeMTProxySecret(t *testing.T) {
|
||||
// faketls secret: 0xee + 16 bytes + cloak domain ("working-name.ru" = 15 bytes)
|
||||
hexSecret := "ee971746d927f4c0138b18447bfe1269bc70312e776f726b696e672d6e616d652e7275"
|
||||
want := []byte{
|
||||
0xee,
|
||||
0x97, 0x17, 0x46, 0xd9, 0x27, 0xf4, 0xc0, 0x13,
|
||||
0x8b, 0x18, 0x44, 0x7b, 0xfe, 0x12, 0x69, 0xbc,
|
||||
0x70, 0x31, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x69,
|
||||
0x6e, 0x67, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x2e,
|
||||
0x72, 0x75,
|
||||
}
|
||||
got, err := decodeMTProxySecret(hexSecret)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !bytes.Equal(got, want) {
|
||||
t.Fatalf("decoded bytes mismatch:\n got=%x\nwant=%x", got, want)
|
||||
}
|
||||
|
||||
if _, err := decodeMTProxySecret(" " + hexSecret + "\n"); err != nil {
|
||||
t.Fatalf("whitespace should be tolerated: %v", err)
|
||||
}
|
||||
|
||||
if _, err := decodeMTProxySecret(""); err == nil {
|
||||
t.Fatal("expected error for empty secret")
|
||||
}
|
||||
if _, err := decodeMTProxySecret("not-hex!!"); err == nil {
|
||||
t.Fatal("expected error for non-hex secret")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user