|
|
@@ -1,9 +1,14 @@
|
|
|
using Ryujinx.Common;
|
|
|
using Ryujinx.Common.Logging;
|
|
|
+using Ryujinx.Common.Memory;
|
|
|
+using Ryujinx.Common.Utilities;
|
|
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|
|
using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService;
|
|
|
+using System;
|
|
|
using System.IO;
|
|
|
+using System.Runtime.CompilerServices;
|
|
|
using System.Runtime.InteropServices;
|
|
|
+using System.Security.Cryptography;
|
|
|
|
|
|
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
|
|
{
|
|
|
@@ -186,5 +191,66 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
|
|
|
|
|
return ResultCode.Success;
|
|
|
}
|
|
|
+
|
|
|
+ [Command(10700)]
|
|
|
+ // nn::friends::GetPlayHistoryRegistrationKey(b8 unknown, nn::account::Uid) -> buffer<nn::friends::PlayHistoryRegistrationKey, 0x1a>
|
|
|
+ public ResultCode GetPlayHistoryRegistrationKey(ServiceCtx context)
|
|
|
+ {
|
|
|
+ bool unknownBool = context.RequestData.ReadBoolean();
|
|
|
+ UserId userId = context.RequestData.ReadStruct<UserId>();
|
|
|
+
|
|
|
+ long bufferPosition = context.Request.RecvListBuff[0].Position;
|
|
|
+
|
|
|
+ if (userId.IsNull)
|
|
|
+ {
|
|
|
+ return ResultCode.InvalidArgument;
|
|
|
+ }
|
|
|
+
|
|
|
+ // NOTE: Calls nn::friends::detail::service::core::PlayHistoryManager::GetInstance and stores the instance.
|
|
|
+
|
|
|
+ byte[] randomBytes = new byte[8];
|
|
|
+ Random random = new Random();
|
|
|
+
|
|
|
+ random.NextBytes(randomBytes);
|
|
|
+
|
|
|
+ // NOTE: Calls nn::friends::detail::service::core::UuidManager::GetInstance and stores the instance.
|
|
|
+ // Then call nn::friends::detail::service::core::AccountStorageManager::GetInstance and store the instance.
|
|
|
+ // Then it checks if an Uuid is already stored for the UserId, if not it generates a random Uuid.
|
|
|
+ // And store it in the savedata 8000000000000080 in the friends:/uid.bin file.
|
|
|
+
|
|
|
+ Array16<byte> randomGuid = new Array16<byte>();
|
|
|
+
|
|
|
+ Guid.NewGuid().ToByteArray().AsSpan().CopyTo(randomGuid.ToSpan());
|
|
|
+
|
|
|
+ PlayHistoryRegistrationKey playHistoryRegistrationKey = new PlayHistoryRegistrationKey
|
|
|
+ {
|
|
|
+ Type = 0x101,
|
|
|
+ KeyIndex = (byte)(randomBytes[0] & 7),
|
|
|
+ UserIdBool = 0, // TODO: Find it.
|
|
|
+ UnknownBool = (byte)(unknownBool ? 1 : 0), // TODO: Find it.
|
|
|
+ Reserved = new Array11<byte>(),
|
|
|
+ Uuid = randomGuid
|
|
|
+ };
|
|
|
+
|
|
|
+ ReadOnlySpan<byte> playHistoryRegistrationKeyBuffer = SpanHelpers.AsByteSpan(ref playHistoryRegistrationKey);
|
|
|
+
|
|
|
+ /*
|
|
|
+
|
|
|
+ NOTE: The service uses the KeyIndex to get a random key from a keys buffer (since the key index is stored in the returned buffer).
|
|
|
+ We currently don't support play history and online services so we can use a blank key for now.
|
|
|
+ Code for reference:
|
|
|
+
|
|
|
+ byte[] hmacKey = new byte[0x20];
|
|
|
+
|
|
|
+ HMACSHA256 hmacSha256 = new HMACSHA256(hmacKey);
|
|
|
+ byte[] hmacHash = hmacSha256.ComputeHash(playHistoryRegistrationKeyBuffer);
|
|
|
+
|
|
|
+ */
|
|
|
+
|
|
|
+ context.Memory.Write((ulong)bufferPosition, playHistoryRegistrationKeyBuffer);
|
|
|
+ context.Memory.Write((ulong)bufferPosition + 0x20, new byte[0x20]); // HmacHash
|
|
|
+
|
|
|
+ return ResultCode.Success;
|
|
|
+ }
|
|
|
}
|
|
|
}
|