mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 11:44:02 +03:00
Add telegram api
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
package conntypes
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
const ConnIDLength = 8
|
||||
|
||||
type ConnID [ConnIDLength]byte
|
||||
|
||||
func (c ConnID) String() string {
|
||||
return hex.EncodeToString(c[:])
|
||||
}
|
||||
|
||||
func NewConnID() ConnID {
|
||||
var id ConnID
|
||||
|
||||
if _, err := rand.Read(id[:]); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
@@ -9,6 +9,7 @@ require (
|
||||
github.com/allegro/bigcache v1.2.1
|
||||
github.com/beevik/ntp v0.2.0
|
||||
github.com/cespare/xxhash v1.1.0
|
||||
github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/pkg/errors v0.8.1 // indirect
|
||||
github.com/prometheus/client_golang v1.1.0
|
||||
|
||||
@@ -40,6 +40,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d h1:hJXjZMxj0SWlMoQkzeZDLi2cmeiWKa7y1B8Rg+qaoEc=
|
||||
github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
|
||||
+2
-1
@@ -5,13 +5,14 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/wrappers"
|
||||
)
|
||||
|
||||
type TelegramRequest struct {
|
||||
Logger *zap.SugaredLogger
|
||||
ClientConn wrappers.StreamReadWriteCloser
|
||||
ConnID wrappers.ConnID
|
||||
ConnID conntypes.ConnID
|
||||
Ctx context.Context
|
||||
Cancel context.CancelFunc
|
||||
ClientProtocol ClientProtocol
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@ import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/9seconds/mtg/config"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
"github.com/9seconds/mtg/stats"
|
||||
"github.com/9seconds/mtg/telegram"
|
||||
@@ -53,7 +54,7 @@ func (p *Proxy) accept(conn net.Conn) {
|
||||
}
|
||||
}()
|
||||
|
||||
connID := wrappers.NewConnID()
|
||||
connID := conntypes.NewConnID()
|
||||
logger := p.Logger.With("connection_id", connID)
|
||||
|
||||
if err := utils.InitTCP(conn); err != nil {
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
)
|
||||
|
||||
const (
|
||||
addressesURLV4 = "https://core.telegram.org/getProxyConfig" // nolint: gas
|
||||
addressesURLV6 = "https://core.telegram.org/getProxyConfigV6" // nolint: gas
|
||||
)
|
||||
|
||||
var addressesProxyForSplitter = regexp.MustCompile(`\s+`)
|
||||
|
||||
func AddressesV4() (map[conntypes.DC][]string, conntypes.DC, error) {
|
||||
return getAddresses(addressesURLV4)
|
||||
}
|
||||
|
||||
func AddressesV6() (map[conntypes.DC][]string, conntypes.DC, error) {
|
||||
return getAddresses(addressesURLV6)
|
||||
}
|
||||
|
||||
func getAddresses(url string) (map[conntypes.DC][]string, conntypes.DC, error) {
|
||||
resp, err := request(url)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("cannot get http response: %w", err)
|
||||
}
|
||||
defer resp.Close()
|
||||
|
||||
scanner := bufio.NewScanner(resp)
|
||||
data := map[conntypes.DC][]string{}
|
||||
|
||||
var defaultDC = conntypes.DCDefaultIdx
|
||||
for scanner.Scan() {
|
||||
text := strings.TrimSpace(scanner.Text())
|
||||
switch {
|
||||
case strings.HasPrefix(text, "#"):
|
||||
continue
|
||||
|
||||
case strings.HasPrefix(text, "proxy_for"):
|
||||
addr, idx, err := addressesParseProxyFor(text)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("cannot parse 'proxy_for' section: %w", err)
|
||||
}
|
||||
if addresses, ok := data[idx]; ok {
|
||||
data[idx] = append(addresses, addr)
|
||||
} else {
|
||||
data[idx] = []string{addr}
|
||||
}
|
||||
|
||||
case strings.HasPrefix(text, "default"):
|
||||
idx, err := addressesParseDefault(text)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("cannot parse 'default' section: %w", err)
|
||||
}
|
||||
defaultDC = idx
|
||||
}
|
||||
}
|
||||
|
||||
err = scanner.Err()
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("cannot parse http response: %w", err)
|
||||
}
|
||||
|
||||
return data, defaultDC, nil
|
||||
}
|
||||
|
||||
func addressesParseProxyFor(text string) (string, conntypes.DC, error) {
|
||||
chunks := addressesProxyForSplitter.Split(text, 3)
|
||||
if len(chunks) != 3 || chunks[0] != "proxy_for" {
|
||||
return "", 0, fmt.Errorf("incorrect config %s", text)
|
||||
}
|
||||
|
||||
dc, err := strconv.ParseInt(chunks[1], 10, 16)
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("incorrect config '%s': %w", text, err)
|
||||
}
|
||||
|
||||
addr := strings.TrimRight(chunks[2], ";")
|
||||
if _, _, err = net.SplitHostPort(addr); err != nil {
|
||||
return "", 0, fmt.Errorf("incorrect config '%s': %w", text, err)
|
||||
}
|
||||
|
||||
return addr, conntypes.DC(dc), nil
|
||||
}
|
||||
|
||||
func addressesParseDefault(text string) (conntypes.DC, error) {
|
||||
chunks := addressesProxyForSplitter.Split(text, 2)
|
||||
if len(chunks) != 2 || chunks[0] != "default" {
|
||||
return 0, fmt.Errorf("incorrect config '%s'", text)
|
||||
}
|
||||
|
||||
dcString := strings.TrimRight(chunks[1], ";")
|
||||
dc, err := strconv.ParseInt(dcString, 10, 16)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("incorrect config '%s': %w", text, err)
|
||||
}
|
||||
|
||||
return conntypes.DC(dc), nil
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
apiUserAgent = "mtg"
|
||||
apiHTTPTimeout = 30 * time.Second
|
||||
)
|
||||
|
||||
var httpClient = http.Client{
|
||||
Timeout: apiHTTPTimeout,
|
||||
}
|
||||
|
||||
func request(url string) (io.ReadCloser, error) {
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
req.Header.Set("Accept", "text/plan")
|
||||
req.Header.Set("User-Agent", apiUserAgent)
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
if resp != nil {
|
||||
io.Copy(ioutil.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
}
|
||||
return nil, fmt.Errorf("cannot perform a request: %w", err)
|
||||
}
|
||||
|
||||
return resp.Body, err
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
const secretURL = "https://core.telegram.org/getProxySecret" // nolint: gas
|
||||
|
||||
func Secret() ([]byte, error) {
|
||||
resp, err := request(secretURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot access telegram server: %w", err)
|
||||
}
|
||||
defer resp.Close()
|
||||
|
||||
secret, err := ioutil.ReadAll(resp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot read response: %w", err)
|
||||
}
|
||||
|
||||
return secret, nil
|
||||
}
|
||||
@@ -2,8 +2,6 @@ package wrappers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
@@ -11,16 +9,9 @@ import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/9seconds/mtg/config"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
)
|
||||
|
||||
const ConnIDLength = 8
|
||||
|
||||
type ConnID [ConnIDLength]byte
|
||||
|
||||
func (c ConnID) String() string {
|
||||
return hex.EncodeToString(c[:])
|
||||
}
|
||||
|
||||
type connPurpose uint8
|
||||
|
||||
const (
|
||||
@@ -37,7 +28,7 @@ type wrapperConn struct {
|
||||
parent net.Conn
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
connID ConnID
|
||||
connID conntypes.ConnID
|
||||
logger *zap.SugaredLogger
|
||||
localAddr *net.TCPAddr
|
||||
remoteAddr *net.TCPAddr
|
||||
@@ -121,7 +112,7 @@ func (w *wrapperConn) RemoteAddr() *net.TCPAddr {
|
||||
func newConn(ctx context.Context,
|
||||
cancel context.CancelFunc,
|
||||
parent net.Conn,
|
||||
connID ConnID,
|
||||
connID conntypes.ConnID,
|
||||
purpose connPurpose) StreamReadWriteCloser {
|
||||
localAddr := *parent.LocalAddr().(*net.TCPAddr)
|
||||
|
||||
@@ -156,22 +147,12 @@ func newConn(ctx context.Context,
|
||||
func NewClientConn(ctx context.Context,
|
||||
cancel context.CancelFunc,
|
||||
parent net.Conn,
|
||||
connID ConnID) StreamReadWriteCloser {
|
||||
connID conntypes.ConnID) StreamReadWriteCloser {
|
||||
return newConn(ctx, cancel, parent, connID, connPurposeClient)
|
||||
}
|
||||
|
||||
func NewTelegramConn(ctx context.Context,
|
||||
cancel context.CancelFunc,
|
||||
parent net.Conn) StreamReadWriteCloser {
|
||||
return newConn(ctx, cancel, parent, ConnID{}, connPurposeTelegram)
|
||||
}
|
||||
|
||||
func NewConnID() ConnID {
|
||||
var id ConnID
|
||||
|
||||
if _, err := rand.Read(id[:]); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return id
|
||||
return newConn(ctx, cancel, parent, conntypes.ConnID{}, connPurposeTelegram)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user