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

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
}