Skip to content

Commit

Permalink
[Core] Fixed Uploading for VideoEntity
Browse files Browse the repository at this point in the history
  • Loading branch information
Linwenxuan04 committed Aug 22, 2024
1 parent 3309d6d commit a58320e
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 27 deletions.
23 changes: 22 additions & 1 deletion Lagrange.Core/Internal/Context/Uploader/Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ namespace Lagrange.Core.Internal.Context.Uploader;

internal static class Common
{
private const int BlockSize = 1024 * 1024;

public static NTV2RichMediaHighwayExt? GenerateExt(NTV2RichMediaUploadEvent @event)
{
if (@event.UKey == null) return null;
Expand All @@ -20,7 +22,26 @@ internal static class Common
UKey = @event.UKey,
Network = Convert(@event.Network),
MsgInfoBody = @event.MsgInfo.MsgInfoBody,
BlockSize = 1024 * 1024,
BlockSize = BlockSize,
Hash = new NTHighwayHash
{
FileSha1 = new List<byte[]> { index.Info.FileSha1.UnHex() }
}
};
}

public static NTV2RichMediaHighwayExt? GenerateExt(NTV2RichMediaUploadEvent @event, SubFileInfo subFile)
{
if (subFile.UKey == null) return null;

var index = @event.MsgInfo.MsgInfoBody[1].Index;
return new NTV2RichMediaHighwayExt
{
FileUuid = index.FileUuid,
UKey = subFile.UKey,
Network = Convert(subFile.IPv4s),
MsgInfoBody = @event.MsgInfo.MsgInfoBody,
BlockSize = BlockSize,
Hash = new NTHighwayHash
{
FileSha1 = new List<byte[]> { index.Info.FileSha1.UnHex() }
Expand Down
56 changes: 31 additions & 25 deletions Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,71 +11,77 @@ internal class VideoUploader : IHighwayUploader
{
public async Task UploadPrivate(ContextCollection context, MessageChain chain, IMessageEntity entity)
{
if (entity is VideoEntity { VideoStream: { } stream } video)
if (entity is VideoEntity { VideoStream: { } stream, ThumbnailStream: { } thumbnail } video)

Check failure on line 14 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 14 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 14 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 14 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (win-x86)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 14 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (linux-x64)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 14 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (linux-arm)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 14 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (linux-arm64)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 14 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (osx-x64)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 14 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (osx-arm64)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 14 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (linux-musl-x64)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 14 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (linux-musl-arm)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 14 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (linux-musl-arm64)

'VideoEntity' does not contain a definition for 'ThumbnailStream'
{
var uploadEvent = VideoUploadEvent.Create(video, chain.FriendInfo?.Uid ?? "");
var uploadResult = await context.Business.SendEvent(uploadEvent);
var metaResult = (VideoUploadEvent)uploadResult[0];

if (metaResult.UKey != null)
if (Common.GenerateExt(metaResult) is { } ext)
{
var index = metaResult.MsgInfo.MsgInfoBody[0].Index;
var extend = new NTV2RichMediaHighwayExt
var hash = metaResult.MsgInfo.MsgInfoBody[0].Index.Info.FileHash.UnHex();
bool hwSuccess = await context.Highway.UploadSrcByStreamAsync(1001, stream.Value, await Common.GetTicket(context), hash, ext.Serialize().ToArray());
if (!hwSuccess)
{
FileUuid = index.FileUuid,
UKey = metaResult.UKey,
Network = Common.Convert(metaResult.Network),
MsgInfoBody = metaResult.MsgInfo.MsgInfoBody,
BlockSize = 1024 * 1024,
Hash = new NTHighwayHash { FileSha1 = new List<byte[]> { index.Info.FileSha1.UnHex() } }
};

bool hwSuccess = await context.Highway.UploadSrcByStreamAsync(1001, stream.Value, await Common.GetTicket(context), index.Info.FileHash.UnHex(), extend.Serialize().ToArray());
await stream.Value.DisposeAsync();
throw new Exception();
}
}

if (Common.GenerateExt(metaResult, metaResult.SubFiles[0]) is { } subExt)
{
var hash = metaResult.MsgInfo.MsgInfoBody[1].Index.Info.FileHash.UnHex();
bool hwSuccess = await context.Highway.UploadSrcByStreamAsync(1002, thumbnail.Value, await Common.GetTicket(context), hash, subExt.Serialize().ToArray());
if (!hwSuccess)
{
await stream.Value.DisposeAsync();
await thumbnail.Value.DisposeAsync();
throw new Exception();
}
}

video.MsgInfo = metaResult.MsgInfo; // directly constructed by Tencent's BDH Server
video.Compat = metaResult.Compat; // for legacy QQ
await stream.Value.DisposeAsync();
await thumbnail.Value.DisposeAsync();
}
}

public async Task UploadGroup(ContextCollection context, MessageChain chain, IMessageEntity entity)
{
if (entity is VideoEntity { VideoStream: { } stream } video)
if (entity is VideoEntity { VideoStream: { } stream, ThumbnailStream: { } thumbnail } video)

Check failure on line 52 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (win-x64)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 52 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 52 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 52 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (win-x86)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 52 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (linux-x64)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 52 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (linux-arm)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 52 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (linux-arm64)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 52 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (osx-x64)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 52 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (osx-arm64)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 52 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (linux-musl-x64)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 52 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (linux-musl-arm)

'VideoEntity' does not contain a definition for 'ThumbnailStream'

Check failure on line 52 in Lagrange.Core/Internal/Context/Uploader/VideoUploader.cs

View workflow job for this annotation

GitHub Actions / build (linux-musl-arm64)

'VideoEntity' does not contain a definition for 'ThumbnailStream'
{
var uploadEvent = VideoGroupUploadEvent.Create(video, chain.GroupUin ?? 0);
var uploadResult = await context.Business.SendEvent(uploadEvent);
var metaResult = (VideoGroupUploadEvent)uploadResult[0];

if (metaResult.UKey != null)
if (Common.GenerateExt(metaResult) is { } ext)
{
var index = metaResult.MsgInfo.MsgInfoBody[0].Index;
var extend = new NTV2RichMediaHighwayExt
var hash = metaResult.MsgInfo.MsgInfoBody[0].Index.Info.FileHash.UnHex();
bool hwSuccess = await context.Highway.UploadSrcByStreamAsync(1005, stream.Value, await Common.GetTicket(context), hash, ext.Serialize().ToArray());
if (!hwSuccess)
{
FileUuid = index.FileUuid,
UKey = metaResult.UKey,
Network = Common.Convert(metaResult.Network),
MsgInfoBody = metaResult.MsgInfo.MsgInfoBody,
BlockSize = 1024 * 1024,
Hash = new NTHighwayHash { FileSha1 = Common.CalculateStreamBytes(stream.Value) }
};
await stream.Value.DisposeAsync();
throw new Exception();
}
}

bool hwSuccess = await context.Highway.UploadSrcByStreamAsync(1005, stream.Value, await Common.GetTicket(context), index.Info.FileHash.UnHex(), extend.Serialize().ToArray());
if (Common.GenerateExt(metaResult, metaResult.SubFiles[0]) is { } subExt)
{
var hash = metaResult.MsgInfo.MsgInfoBody[1].Index.Info.FileHash.UnHex();
bool hwSuccess = await context.Highway.UploadSrcByStreamAsync(1006, thumbnail.Value, await Common.GetTicket(context), hash, subExt.Serialize().ToArray());
if (!hwSuccess)
{
await stream.Value.DisposeAsync();
await thumbnail.Value.DisposeAsync();
throw new Exception();
}
}

video.MsgInfo = metaResult.MsgInfo; // directly constructed by Tencent's BDH Server
video.Compat = metaResult.Compat; // for legacy QQ
await stream.Value.DisposeAsync();
await thumbnail.Value.DisposeAsync();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ internal class SubFileInfo
{
[ProtoMember(1)] public uint SubType { get; set; }

[ProtoMember(2)] public string UKey { get; set; }
[ProtoMember(2)] public string? UKey { get; set; }

[ProtoMember(3)] public uint UKeyTtlSecond { get; set; }

Expand Down
159 changes: 159 additions & 0 deletions Lagrange.Core/Utility/Crypto/Provider/Sha/Sha1Stream.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
using System.Buffers.Binary;

namespace Lagrange.Core.Utility.Crypto.Provider.Sha;

public class Sha1Stream
{
private readonly uint[] _state = new uint[5];
private readonly int[] _count = new int[2];
private readonly byte[] _buffer = new byte[Sha1BlockSize];

public const int Sha1BlockSize = 64;
public const int Sha1DigestSize = 20;

private static readonly byte[] Padding = // Constant array for padding
{
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

public Sha1Stream() // Initialize SHA1 context
{
Reset();
}

private void Reset()
{
_state[0] = 0x67452301;
_state[1] = 0xEFCDAB89;
_state[2] = 0x98BADCFE;
_state[3] = 0x10325476;
_state[4] = 0xC3D2E1F0;

_count[0] = 0;
_count[1] = 0;
}

private void Transform(byte[] data) // Transform function
{
if (data.Length != 64) throw new ArgumentException("Data must be exactly 64 bytes");

var w = new uint[80]; // 1. Break chunk into sixteen 32-bit words
for (int i = 0; i < 16; i++)
{
w[i] = BinaryPrimitives.ReadUInt32BigEndian(data.AsSpan(i * 4));
}

for (int i = 16; i < 80; i++) // 2. Extend the sixteen 32-bit words into eighty 32-bit words
{
w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) << 1 | (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) >> 31;
}
uint a = _state[0]; // 3. Initialize hash value for this chunk
uint b = _state[1];
uint c = _state[2];
uint d = _state[3];
uint e = _state[4];

for (int i = 0; i < 80; i++) // 4. Main loop
{
uint temp = i switch
{
< 20 => ((b & c) | (~b & d)) + 0x5A827999,
< 40 => (b ^ c ^ d) + 0x6ED9EBA1,
< 60 => ((b & c) | (b & d) | (c & d)) + 0x8F1BBCDC,
_ => (b ^ c ^ d) + 0xCA62C1D6
};

temp += ((a << 5) | (a >> 27)) + e + w[i];
e = d;
d = c;
c = (b << 30) | (b >> 2);
b = a;
a = temp;
}

_state[0] += a; // 5. Add this chunk's hash to result so far
_state[1] += b;
_state[2] += c;
_state[3] += d;
_state[4] += e;
}

public void Update(byte[] data, int len) // Update SHA1 context
{
int index = (_count[0] >> 3) & 0x3F;
_count[0] += len << 3;

if (_count[0] < (len << 3)) _count[1]++;

_count[1] += len >> 29;

int partLen = Sha1BlockSize - index;
int i = 0;

if (len >= partLen)
{
Array.Copy(data, 0, _buffer, index, partLen);
Transform(_buffer);

for (i = partLen; i + Sha1BlockSize <= len; i += Sha1BlockSize)
{
Transform(data[i..(i + Sha1BlockSize)]);
}

index = 0;
}

Array.Copy(data, i, _buffer, index, len - i);
}

public void Hash(byte[] digest, bool bigEnding)
{
if (bigEnding)
{
for (int i = 0; i < _state.Length; i++)
{
BinaryPrimitives.WriteUInt32BigEndian(digest.AsSpan(i * 4), _state[i]);
}
}
else
{
for (int i = 0; i < _state.Length; i++)
{
BinaryPrimitives.WriteUInt32LittleEndian(digest.AsSpan(i * 4), _state[i]);
}
}
}

public void Final(byte[] digest)
{
if (digest.Length != Sha1DigestSize) throw new ArgumentException($"Digest array must be of size {Sha1DigestSize}");

var bits = new byte[8];
for (int i = 0; i < 8; i++)
{
int byteIndex = i >= 4 ? 0 : 1;
int shift = (3 - (i & 3)) * 8;
bits[i] = (byte)(_count[byteIndex] >> shift);
}

int index = (_count[0] >> 3) & 0x3F;
int padLen = index < 56 ? 56 - index : 120 - index;

Update(Padding, padLen);
Update(bits, 8);

for (int i = 0; i < Sha1DigestSize; i++)
{
int byteIndex = i >> 2;
int shift = (3 - (i & 3)) * 8;
digest[i] = (byte)(_state[byteIndex] >> shift);
}
}
}

0 comments on commit a58320e

Please sign in to comment.