mirror of
https://github.com/wiz0u/WTelegramClient.git
synced 2026-01-03 07:09:56 +01:00
factorize IndirectStream
This commit is contained in:
parent
3730cdc7f0
commit
f711948da7
|
|
@ -1227,7 +1227,7 @@ namespace WTelegram
|
|||
=> UploadFileAsync(File.OpenRead(pathname), Path.GetFileName(pathname), progress);
|
||||
|
||||
/// <summary>Helper function to upload a file to Telegram</summary>
|
||||
/// <param name="stream">Content of the file to upload</param>
|
||||
/// <param name="stream">Content of the file to upload. This method close/dispose the stream</param>
|
||||
/// <param name="filename">Name of the file</param>
|
||||
/// <param name="progress">(optional) Callback for tracking the progression of the transfer</param>
|
||||
/// <returns>an <see cref="InputFile"/> or <see cref="InputFileBig"/> than can be used in various requests</returns>
|
||||
|
|
@ -1406,7 +1406,7 @@ namespace WTelegram
|
|||
using var stream = await response.Content.ReadAsStreamAsync();
|
||||
mimeType = response.Content.Headers.ContentType?.MediaType;
|
||||
if (response.Content.Headers.ContentLength is long length)
|
||||
return await UploadFileAsync(new Helpers.StreamWithLength { length = length, innerStream = stream }, filename);
|
||||
return await UploadFileAsync(new Helpers.IndirectStream(stream) { ContentLength = length }, filename);
|
||||
else
|
||||
{
|
||||
using var ms = new MemoryStream();
|
||||
|
|
|
|||
|
|
@ -253,20 +253,22 @@ namespace WTelegram
|
|||
0x3f, 0x00
|
||||
};
|
||||
|
||||
internal class StreamWithLength : Stream
|
||||
public class IndirectStream : Stream
|
||||
{
|
||||
public Stream innerStream;
|
||||
public long length;
|
||||
public override bool CanRead => true;
|
||||
public override bool CanSeek => false;
|
||||
public override bool CanWrite => false;
|
||||
public override long Length => length;
|
||||
public override long Position { get => innerStream.Position; set => throw new NotSupportedException(); }
|
||||
public override void Flush() { }
|
||||
public override int Read(byte[] buffer, int offset, int count) => innerStream.Read(buffer, offset, count);
|
||||
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
|
||||
public override void SetLength(long value) => throw new NotSupportedException();
|
||||
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
|
||||
public IndirectStream(Stream innerStream) => _innerStream = innerStream;
|
||||
public long? ContentLength;
|
||||
protected readonly Stream _innerStream;
|
||||
public override bool CanRead => _innerStream.CanRead;
|
||||
public override bool CanSeek => _innerStream.CanSeek;
|
||||
public override bool CanWrite => _innerStream.CanWrite;
|
||||
public override long Length => ContentLength ?? _innerStream.Length;
|
||||
public override long Position { get => _innerStream.Position; set => _innerStream.Position = value; }
|
||||
public override void Flush() => _innerStream.Flush();
|
||||
public override int Read(byte[] buffer, int offset, int count) => _innerStream.Read(buffer, offset, count);
|
||||
public override long Seek(long offset, SeekOrigin origin) => _innerStream.Seek(offset, origin);
|
||||
public override void SetLength(long value) => _innerStream.SetLength(value);
|
||||
public override void Write(byte[] buffer, int offset, int count) => _innerStream.Write(buffer, offset, count);
|
||||
protected override void Dispose(bool disposing) => _innerStream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,28 +11,15 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace WTelegram
|
||||
{
|
||||
class TlsStream : Stream
|
||||
class TlsStream : Helpers.IndirectStream
|
||||
{
|
||||
public TlsStream(Stream innerStream) => _innerStream = innerStream;
|
||||
private readonly Stream _innerStream;
|
||||
public TlsStream(Stream innerStream) : base(innerStream) { }
|
||||
private int _tlsFrameleft;
|
||||
private readonly byte[] _tlsSendHeader = new byte[] { 0x17, 0x03, 0x03, 0, 0 };
|
||||
private readonly byte[] _tlsReadHeader = new byte[5];
|
||||
static readonly byte[] TlsServerHelloPart3 = new byte[] { 0x14, 0x03, 0x03, 0x00, 0x01, 0x01, 0x17, 0x03, 0x03 };
|
||||
static readonly byte[] TlsServerHello3 = new byte[] { 0x14, 0x03, 0x03, 0x00, 0x01, 0x01, 0x17, 0x03, 0x03 };
|
||||
static readonly byte[] TlsClientPrefix = new byte[] { 0x14, 0x03, 0x03, 0x00, 0x01, 0x01 };
|
||||
|
||||
public override bool CanRead => true;
|
||||
public override bool CanSeek => false;
|
||||
public override bool CanWrite => true;
|
||||
public override long Length => throw new NotSupportedException();
|
||||
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
|
||||
public override void Flush() => _innerStream.Flush();
|
||||
public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException();
|
||||
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
|
||||
public override void SetLength(long value) => throw new NotSupportedException();
|
||||
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
|
||||
protected override void Dispose(bool disposing) => _innerStream.Dispose();
|
||||
|
||||
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken ct)
|
||||
{
|
||||
if (_tlsFrameleft == 0)
|
||||
|
|
@ -71,9 +58,9 @@ namespace WTelegram
|
|||
if (part1[0] == 0x16 && part1[1] == 0x03 && part1[2] == 0x03)
|
||||
{
|
||||
var part2size = BinaryPrimitives.ReadUInt16BigEndian(part1.AsSpan(3));
|
||||
var part23 = new byte[part2size + TlsServerHelloPart3.Length + 2];
|
||||
var part23 = new byte[part2size + TlsServerHello3.Length + 2];
|
||||
if (await stream.FullReadAsync(part23, part23.Length, ct) == part23.Length)
|
||||
if (TlsServerHelloPart3.SequenceEqual(part23.Skip(part2size).Take(TlsServerHelloPart3.Length)))
|
||||
if (TlsServerHello3.SequenceEqual(part23.Skip(part2size).Take(TlsServerHello3.Length)))
|
||||
{
|
||||
var part4size = BinaryPrimitives.ReadUInt16BigEndian(part23.AsSpan(part23.Length - 2));
|
||||
var part4 = new byte[part4size];
|
||||
|
|
@ -98,42 +85,50 @@ namespace WTelegram
|
|||
throw new ApplicationException("TLS Handshake failed");
|
||||
}
|
||||
|
||||
static readonly byte[] TlsClientHello1 = new byte[] {
|
||||
static readonly byte[] TlsClientHello1 = new byte[11] {
|
||||
0x16, 0x03, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0xfc, 0x03, 0x03 };
|
||||
static readonly byte[] TlsClientHello2 = new byte[] {
|
||||
// digest[32]
|
||||
// 0x20
|
||||
// random[32]
|
||||
// 0x00, 0x20, grease(0) GREASE are two identical bytes ending with nibble 'A'
|
||||
static readonly byte[] TlsClientHello2 = new byte[34] {
|
||||
0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30, 0xcc, 0xa9,
|
||||
0xcc, 0xa8, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x35, 0x01, 0x00, 0x01, 0x93 };
|
||||
static readonly byte[] TlsClientHello3 = new byte[] {
|
||||
// grease(2), 0x00, 0x00, 0x00, 0x00
|
||||
// len { len { 0x00 len { domain } } } len is 16-bit big-endian length of the following block of data
|
||||
static readonly byte[] TlsClientHello3 = new byte[101] {
|
||||
0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08,
|
||||
0, 0, // grease 4
|
||||
0x4A, 0x4A, // = grease(4)
|
||||
0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00,
|
||||
0x00, 0x10, 0x00, 0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31,
|
||||
0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x12, 0x00,
|
||||
0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x12, 0x00,
|
||||
0x10, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x08, 0x06, 0x06,
|
||||
0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x33, 0x00, 0x2b, 0x00, 0x29,
|
||||
0, 0, // grease 4
|
||||
0x4A, 0x4A, // = grease(4)
|
||||
0x00, 0x01, 0x00, 0x00, 0x1d, 0x00, 0x20 };
|
||||
static readonly byte[] TlsClientHello4 = new byte[] {
|
||||
// random[32] = public key
|
||||
static readonly byte[] TlsClientHello4 = new byte[35] {
|
||||
0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x2b, 0x00, 0x0b, 0x0a,
|
||||
0, 0, // grease 6
|
||||
0x6A, 0x6A, // = grease(6)
|
||||
0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x03, 0x01, 0x00, 0x1b, 0x00, 0x03, 0x02, 0x00, 0x02,
|
||||
0, 0, // grease 3
|
||||
0x3A, 0x3A, // = grease(3)
|
||||
0x00, 0x01, 0x00, 0x00, 0x15 };
|
||||
// len { padding } padding with NUL bytes to reach 517 bytes
|
||||
|
||||
static byte[] TlsClientHello(byte[] key, byte[] domain)
|
||||
{
|
||||
int dlen = domain.Length;
|
||||
var greases = new byte[7];
|
||||
Encryption.RNG.GetBytes(greases);
|
||||
for (int i = 0; i < 7; i++) greases[i] = (byte)((greases[i] & 0xF0) + 0x0A);
|
||||
if (greases[3] == greases[2]) greases[3] = (byte)(0x10 ^ greases[3]);
|
||||
for (int i = 0; i < 7; i++) greases[i] = (byte)((greases[i] & 0xF0) + 0x0A);
|
||||
if (greases[3] == greases[2]) greases[3] ^= 0x10;
|
||||
|
||||
var buffer = new byte[517];
|
||||
TlsClientHello1.CopyTo(buffer, 0);
|
||||
TlsClientHello2.CopyTo(buffer, 80);
|
||||
buffer[43] = buffer[77] = 0x20;
|
||||
Encryption.RNG.GetBytes(buffer, 44, 32);
|
||||
buffer[43] = buffer[77] = 0x20;
|
||||
buffer[78] = buffer[79] = greases[0];
|
||||
TlsClientHello2.CopyTo(buffer, 80);
|
||||
buffer[114] = buffer[115] = greases[2];
|
||||
buffer[121] = (byte)(dlen + 5);
|
||||
buffer[123] = (byte)(dlen + 3);
|
||||
|
|
@ -156,7 +151,6 @@ namespace WTelegram
|
|||
stamp ^= (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
BinaryPrimitives.WriteInt32LittleEndian(digest.AsSpan(28), stamp);
|
||||
digest.CopyTo(buffer, 11);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue