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 }