ManagerServer.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. using Microsoft.IdentityModel.Tokens;
  2. using Ryujinx.Common.Logging;
  3. using Ryujinx.HLE.HOS.Kernel.Threading;
  4. using Ryujinx.HLE.HOS.Services.Account.Acc.AsyncContext;
  5. using System;
  6. using System.IdentityModel.Tokens.Jwt;
  7. using System.Security.Cryptography;
  8. using System.Text;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
  12. {
  13. class ManagerServer
  14. {
  15. // TODO: Determine where and how NetworkServiceAccountId is set.
  16. private const long NetworkServiceAccountId = 0xcafe;
  17. private UserId _userId;
  18. public ManagerServer(UserId userId)
  19. {
  20. _userId = userId;
  21. }
  22. private static string GenerateIdToken()
  23. {
  24. using RSA provider = RSA.Create(2048);
  25. RSAParameters parameters = provider.ExportParameters(true);
  26. RsaSecurityKey secKey = new RsaSecurityKey(parameters);
  27. SigningCredentials credentials = new SigningCredentials(secKey, "RS256");
  28. credentials.Key.KeyId = parameters.ToString();
  29. var header = new JwtHeader(credentials)
  30. {
  31. { "jku", "https://e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com/1.0.0/certificates" }
  32. };
  33. byte[] rawUserId = new byte[0x10];
  34. RandomNumberGenerator.Fill(rawUserId);
  35. byte[] deviceId = new byte[0x10];
  36. RandomNumberGenerator.Fill(deviceId);
  37. byte[] deviceAccountId = new byte[0x10];
  38. RandomNumberGenerator.Fill(deviceId);
  39. var payload = new JwtPayload
  40. {
  41. { "sub", BitConverter.ToString(rawUserId).Replace("-", "").ToLower() },
  42. { "aud", "ed9e2f05d286f7b8" },
  43. { "di", BitConverter.ToString(deviceId).Replace("-", "").ToLower() },
  44. { "sn", "XAW10000000000" },
  45. { "bs:did", BitConverter.ToString(deviceAccountId).Replace("-", "").ToLower() },
  46. { "iss", "https://e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com" },
  47. { "typ", "id_token" },
  48. { "iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds() },
  49. { "jti", Guid.NewGuid().ToString() },
  50. { "exp", (DateTimeOffset.UtcNow + TimeSpan.FromHours(3)).ToUnixTimeSeconds() }
  51. };
  52. JwtSecurityToken securityToken = new JwtSecurityToken(header, payload);
  53. return new JwtSecurityTokenHandler().WriteToken(securityToken);
  54. }
  55. public ResultCode CheckAvailability(ServiceCtx context)
  56. {
  57. // NOTE: This opens the file at "su/baas/USERID_IN_UUID_STRING.dat" where USERID_IN_UUID_STRING is formatted as "%08x-%04x-%04x-%02x%02x-%08x%04x".
  58. // Then it searches the Availability of Online Services related to the UserId in this file and returns it.
  59. Logger.Stub?.PrintStub(LogClass.ServiceAcc);
  60. // NOTE: Even if we try to return different error codes here, the guest still needs other calls.
  61. return ResultCode.Success;
  62. }
  63. public ResultCode GetAccountId(ServiceCtx context)
  64. {
  65. // NOTE: This opens the file at "su/baas/USERID_IN_UUID_STRING.dat" (where USERID_IN_UUID_STRING is formatted
  66. // as "%08x-%04x-%04x-%02x%02x-%08x%04x") in the account:/ savedata.
  67. // Then it searches the NetworkServiceAccountId related to the UserId in this file and returns it.
  68. Logger.Stub?.PrintStub(LogClass.ServiceAcc, new { NetworkServiceAccountId });
  69. context.ResponseData.Write(NetworkServiceAccountId);
  70. return ResultCode.Success;
  71. }
  72. public ResultCode EnsureIdTokenCacheAsync(ServiceCtx context, out IAsyncContext asyncContext)
  73. {
  74. KEvent asyncEvent = new KEvent(context.Device.System.KernelContext);
  75. AsyncExecution asyncExecution = new AsyncExecution(asyncEvent);
  76. asyncExecution.Initialize(1000, EnsureIdTokenCacheAsyncImpl);
  77. asyncContext = new IAsyncContext(asyncExecution);
  78. // return ResultCode.NullObject if the IAsyncContext pointer is null. Doesn't occur in our case.
  79. return ResultCode.Success;
  80. }
  81. private async Task EnsureIdTokenCacheAsyncImpl(CancellationToken token)
  82. {
  83. // NOTE: This open the file at "su/baas/USERID_IN_UUID_STRING.dat" (where USERID_IN_UUID_STRING is formatted as "%08x-%04x-%04x-%02x%02x-%08x%04x")
  84. // in the "account:/" savedata.
  85. // Then its read data, use dauth API with this data to get the Token Id and probably store the dauth response
  86. // in "su/cache/USERID_IN_UUID_STRING.dat" (where USERID_IN_UUID_STRING is formatted as "%08x-%04x-%04x-%02x%02x-%08x%04x") in the "account:/" savedata.
  87. // Since we don't support online services, we can stub it.
  88. Logger.Stub?.PrintStub(LogClass.ServiceAcc);
  89. // TODO: Use a real function instead, with the CancellationToken.
  90. await Task.CompletedTask;
  91. }
  92. public ResultCode LoadIdTokenCache(ServiceCtx context)
  93. {
  94. ulong bufferPosition = context.Request.ReceiveBuff[0].Position;
  95. ulong bufferSize = context.Request.ReceiveBuff[0].Size;
  96. // NOTE: This opens the file at "su/cache/USERID_IN_UUID_STRING.dat" (where USERID_IN_UUID_STRING is formatted as "%08x-%04x-%04x-%02x%02x-%08x%04x")
  97. // in the "account:/" savedata and writes some data in the buffer.
  98. // Since we don't support online services, we can stub it.
  99. Logger.Stub?.PrintStub(LogClass.ServiceAcc);
  100. /*
  101. if (internal_object != null)
  102. {
  103. if (bufferSize > 0xC00)
  104. {
  105. return ResultCode.InvalidIdTokenCacheBufferSize;
  106. }
  107. }
  108. */
  109. byte[] tokenData = Encoding.ASCII.GetBytes(GenerateIdToken());
  110. context.Memory.Write(bufferPosition, tokenData);
  111. context.ResponseData.Write(tokenData.Length);
  112. return ResultCode.Success;
  113. }
  114. public ResultCode GetNintendoAccountUserResourceCacheForApplication(ServiceCtx context)
  115. {
  116. Logger.Stub?.PrintStub(LogClass.ServiceAcc, new { NetworkServiceAccountId });
  117. context.ResponseData.Write(NetworkServiceAccountId);
  118. // TODO: determine and fill the output IPC buffer.
  119. return ResultCode.Success;
  120. }
  121. public ResultCode StoreOpenContext(ServiceCtx context)
  122. {
  123. Logger.Stub?.PrintStub(LogClass.ServiceAcc);
  124. return ResultCode.Success;
  125. }
  126. }
  127. }