You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
88 lines
2.2 KiB
88 lines
2.2 KiB
3 years ago
|
package session
|
||
|
|
||
|
import (
|
||
|
"encoding/base64"
|
||
|
"encoding/binary"
|
||
|
"net"
|
||
|
"strconv"
|
||
|
|
||
|
"github.com/go-faster/errors"
|
||
|
|
||
|
"github.com/gotd/td/internal/crypto"
|
||
|
)
|
||
|
|
||
|
// https://github.com/LonamiWebs/Telethon/blob/master/telethon/sessions/string.py#L11
|
||
|
const latestTelethonVersion byte = '1'
|
||
|
|
||
|
// TelethonSession decodes Telethon's StringSession string to the Data.
|
||
|
// Notice that Telethon does not save tg.Config and server salt.
|
||
|
//
|
||
|
// See https://docs.telethon.dev/en/latest/modules/sessions.html#telethon.sessions.string.StringSession.
|
||
|
//
|
||
|
// See https://github.com/LonamiWebs/Telethon/blob/master/telethon/sessions/string.py#L29-L46.
|
||
|
func TelethonSession(hx string) (*Data, error) {
|
||
|
if len(hx) < 1 {
|
||
|
return nil, errors.Errorf("given string too small: %d", len(hx))
|
||
|
}
|
||
|
version := hx[0]
|
||
|
if version != latestTelethonVersion {
|
||
|
return nil, errors.Errorf("unexpected version %q, latest supported is %q",
|
||
|
version,
|
||
|
latestTelethonVersion,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
data, err := base64.URLEncoding.DecodeString(hx[1:])
|
||
|
if err != nil {
|
||
|
return nil, errors.Wrap(err, "decode hex")
|
||
|
}
|
||
|
|
||
|
return decodeStringSession(data)
|
||
|
}
|
||
|
|
||
|
func decodeStringSession(data []byte) (*Data, error) {
|
||
|
// Given parameter should contain version + data
|
||
|
// where data encoded using pack as '>B4sH256s' or '>B16sH256s'
|
||
|
// depending on IP type.
|
||
|
//
|
||
|
// Table:
|
||
|
//
|
||
|
// | Size | Type | Description |
|
||
|
// |------|--------|-------------|
|
||
|
// | 1 | byte | DC ID |
|
||
|
// | 4/16 | bytes | IP address |
|
||
|
// | 2 | uint16 | Port |
|
||
|
// | 256 | bytes | Auth key |
|
||
|
var ipLength int
|
||
|
switch len(data) {
|
||
|
case 263:
|
||
|
ipLength = 4
|
||
|
case 275:
|
||
|
ipLength = 16
|
||
|
default:
|
||
|
return nil, errors.Errorf("decoded hex has invalid length: %d", len(data))
|
||
|
}
|
||
|
|
||
|
// | 1 | byte | DC ID |
|
||
|
dcID := data[0]
|
||
|
|
||
|
// | 4/16 | bytes | IP address |
|
||
|
addr := make(net.IP, 0, 16)
|
||
|
addr = append(addr, data[1:1+ipLength]...)
|
||
|
|
||
|
// | 2 | uint16 | Port |
|
||
|
port := binary.BigEndian.Uint16(data[1+ipLength : 3+ipLength])
|
||
|
|
||
|
// | 256 | bytes | Auth key |
|
||
|
var key crypto.Key
|
||
|
copy(key[:], data[3+ipLength:])
|
||
|
id := key.WithID().ID
|
||
|
|
||
|
return &Data{
|
||
|
DC: int(dcID),
|
||
|
Addr: net.JoinHostPort(addr.String(), strconv.Itoa(int(port))),
|
||
|
AuthKey: key[:],
|
||
|
AuthKeyID: id[:],
|
||
|
}, nil
|
||
|
}
|