acc.cpp 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052
  1. // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project & 2024 suyu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <algorithm>
  4. #include <array>
  5. #include "common/common_types.h"
  6. #include "common/fs/file.h"
  7. #include "common/fs/path_util.h"
  8. #include "common/logging/log.h"
  9. #include "common/polyfill_ranges.h"
  10. #include "common/stb.h"
  11. #include "common/string_util.h"
  12. #include "common/swap.h"
  13. #include "core/constants.h"
  14. #include "core/core.h"
  15. #include "core/core_timing.h"
  16. #include "core/file_sys/control_metadata.h"
  17. #include "core/file_sys/patch_manager.h"
  18. #include "core/hle/service/acc/acc.h"
  19. #include "core/hle/service/acc/acc_aa.h"
  20. #include "core/hle/service/acc/acc_su.h"
  21. #include "core/hle/service/acc/acc_u0.h"
  22. #include "core/hle/service/acc/acc_u1.h"
  23. #include "core/hle/service/acc/async_context.h"
  24. #include "core/hle/service/acc/errors.h"
  25. #include "core/hle/service/acc/profile_manager.h"
  26. #include "core/hle/service/cmif_serialization.h"
  27. #include "core/hle/service/glue/glue_manager.h"
  28. #include "core/hle/service/server_manager.h"
  29. #include "core/loader/loader.h"
  30. namespace Service::Account {
  31. // Thumbnails are hard coded to be at least this size
  32. constexpr std::size_t THUMBNAIL_SIZE = 0x24000;
  33. static std::filesystem::path GetImagePath(const Common::UUID& uuid) {
  34. return Common::FS::GetSuyuPath(Common::FS::SuyuPath::NANDDir) /
  35. fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormattedString());
  36. }
  37. static void JPGToMemory(void* context, void* data, int len) {
  38. std::vector<u8>* jpg_image = static_cast<std::vector<u8>*>(context);
  39. unsigned char* jpg = static_cast<unsigned char*>(data);
  40. jpg_image->insert(jpg_image->end(), jpg, jpg + len);
  41. }
  42. static void SanitizeJPEGImageSize(std::vector<u8>& image) {
  43. constexpr std::size_t max_jpeg_image_size = 0x20000;
  44. constexpr int profile_dimensions = 256;
  45. int original_width, original_height, color_channels;
  46. const auto plain_image =
  47. stbi_load_from_memory(image.data(), static_cast<int>(image.size()), &original_width,
  48. &original_height, &color_channels, STBI_rgb);
  49. // Resize image to match 256*256
  50. if (original_width != profile_dimensions || original_height != profile_dimensions) {
  51. // Use vector instead of array to avoid overflowing the stack
  52. std::vector<u8> out_image(profile_dimensions * profile_dimensions * STBI_rgb);
  53. stbir_resize_uint8_srgb(plain_image, original_width, original_height, 0, out_image.data(),
  54. profile_dimensions, profile_dimensions, 0, STBI_rgb, 0,
  55. STBIR_FILTER_BOX);
  56. image.clear();
  57. if (!stbi_write_jpg_to_func(JPGToMemory, &image, profile_dimensions, profile_dimensions,
  58. STBI_rgb, out_image.data(), 0)) {
  59. LOG_ERROR(Service_ACC, "Failed to resize the user provided image.");
  60. }
  61. }
  62. image.resize(std::min(image.size(), max_jpeg_image_size));
  63. }
  64. class IManagerForSystemService final : public ServiceFramework<IManagerForSystemService> {
  65. public:
  66. explicit IManagerForSystemService(Core::System& system_, Common::UUID uuid)
  67. : ServiceFramework{system_, "IManagerForSystemService"}, account_id{uuid} {
  68. // clang-format off
  69. static const FunctionInfo functions[] = {
  70. {0, D<&IManagerForSystemService::CheckAvailability>, "CheckAvailability"},
  71. {1, D<&IManagerForSystemService::GetAccountId>, "GetAccountId"},
  72. {2, nullptr, "EnsureIdTokenCacheAsync"},
  73. {3, nullptr, "LoadIdTokenCache"},
  74. {100, nullptr, "SetSystemProgramIdentification"},
  75. {101, nullptr, "RefreshNotificationTokenAsync"}, // 7.0.0+
  76. {110, nullptr, "GetServiceEntryRequirementCache"}, // 4.0.0+
  77. {111, nullptr, "InvalidateServiceEntryRequirementCache"}, // 4.0.0+
  78. {112, nullptr, "InvalidateTokenCache"}, // 4.0.0 - 6.2.0
  79. {113, nullptr, "GetServiceEntryRequirementCacheForOnlinePlay"}, // 6.1.0+
  80. {120, nullptr, "GetNintendoAccountId"},
  81. {121, nullptr, "CalculateNintendoAccountAuthenticationFingerprint"}, // 9.0.0+
  82. {130, nullptr, "GetNintendoAccountUserResourceCache"},
  83. {131, nullptr, "RefreshNintendoAccountUserResourceCacheAsync"},
  84. {132, nullptr, "RefreshNintendoAccountUserResourceCacheAsyncIfSecondsElapsed"},
  85. {133, nullptr, "GetNintendoAccountVerificationUrlCache"}, // 9.0.0+
  86. {134, nullptr, "RefreshNintendoAccountVerificationUrlCache"}, // 9.0.0+
  87. {135, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsyncIfSecondsElapsed"}, // 9.0.0+
  88. {140, nullptr, "GetNetworkServiceLicenseCache"}, // 5.0.0+
  89. {141, nullptr, "RefreshNetworkServiceLicenseCacheAsync"}, // 5.0.0+
  90. {142, nullptr, "RefreshNetworkServiceLicenseCacheAsyncIfSecondsElapsed"}, // 5.0.0+
  91. {150, nullptr, "CreateAuthorizationRequest"},
  92. {160, nullptr, "RequiresUpdateNetworkServiceAccountIdTokenCache"},
  93. {161, nullptr, "RequireReauthenticationOfNetworkServiceAccount"},
  94. };
  95. // clang-format on
  96. RegisterHandlers(functions);
  97. }
  98. private:
  99. Result CheckAvailability() {
  100. LOG_WARNING(Service_ACC, "(STUBBED) called");
  101. R_SUCCEED();
  102. }
  103. Result GetAccountId(Out<u64> out_account_id) {
  104. LOG_WARNING(Service_ACC, "(STUBBED) called");
  105. *out_account_id = account_id.Hash();
  106. R_SUCCEED();
  107. }
  108. Common::UUID account_id;
  109. };
  110. // 3.0.0+
  111. class IFloatingRegistrationRequest final : public ServiceFramework<IFloatingRegistrationRequest> {
  112. public:
  113. explicit IFloatingRegistrationRequest(Core::System& system_, Common::UUID)
  114. : ServiceFramework{system_, "IFloatingRegistrationRequest"} {
  115. // clang-format off
  116. static const FunctionInfo functions[] = {
  117. {0, nullptr, "GetSessionId"},
  118. {12, nullptr, "GetAccountId"},
  119. {13, nullptr, "GetLinkedNintendoAccountId"},
  120. {14, nullptr, "GetNickname"},
  121. {15, nullptr, "GetProfileImage"},
  122. {21, nullptr, "LoadIdTokenCache"},
  123. {100, nullptr, "RegisterUser"}, // [1.0.0-3.0.2] RegisterAsync
  124. {101, nullptr, "RegisterUserWithUid"}, // [1.0.0-3.0.2] RegisterWithUidAsync
  125. {102, nullptr, "RegisterNetworkServiceAccountAsync"}, // 4.0.0+
  126. {103, nullptr, "RegisterNetworkServiceAccountWithUidAsync"}, // 4.0.0+
  127. {110, nullptr, "SetSystemProgramIdentification"},
  128. {111, nullptr, "EnsureIdTokenCacheAsync"},
  129. };
  130. // clang-format on
  131. RegisterHandlers(functions);
  132. }
  133. };
  134. class IAdministrator final : public ServiceFramework<IAdministrator> {
  135. public:
  136. explicit IAdministrator(Core::System& system_, Common::UUID)
  137. : ServiceFramework{system_, "IAdministrator"} {
  138. // clang-format off
  139. static const FunctionInfo functions[] = {
  140. {0, nullptr, "CheckAvailability"},
  141. {1, nullptr, "GetAccountId"},
  142. {2, nullptr, "EnsureIdTokenCacheAsync"},
  143. {3, nullptr, "LoadIdTokenCache"},
  144. {100, nullptr, "SetSystemProgramIdentification"},
  145. {101, nullptr, "RefreshNotificationTokenAsync"}, // 7.0.0+
  146. {110, nullptr, "GetServiceEntryRequirementCache"}, // 4.0.0+
  147. {111, nullptr, "InvalidateServiceEntryRequirementCache"}, // 4.0.0+
  148. {112, nullptr, "InvalidateTokenCache"}, // 4.0.0 - 6.2.0
  149. {113, nullptr, "GetServiceEntryRequirementCacheForOnlinePlay"}, // 6.1.0+
  150. {120, nullptr, "GetNintendoAccountId"},
  151. {121, nullptr, "CalculateNintendoAccountAuthenticationFingerprint"}, // 9.0.0+
  152. {130, nullptr, "GetNintendoAccountUserResourceCache"},
  153. {131, nullptr, "RefreshNintendoAccountUserResourceCacheAsync"},
  154. {132, nullptr, "RefreshNintendoAccountUserResourceCacheAsyncIfSecondsElapsed"},
  155. {133, nullptr, "GetNintendoAccountVerificationUrlCache"}, // 9.0.0+
  156. {134, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsync"}, // 9.0.0+
  157. {135, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsyncIfSecondsElapsed"}, // 9.0.0+
  158. {140, nullptr, "GetNetworkServiceLicenseCache"}, // 5.0.0+
  159. {141, nullptr, "RefreshNetworkServiceLicenseCacheAsync"}, // 5.0.0+
  160. {142, nullptr, "RefreshNetworkServiceLicenseCacheAsyncIfSecondsElapsed"}, // 5.0.0+
  161. {143, nullptr, "GetNetworkServiceLicenseCacheEx"},
  162. {150, nullptr, "CreateAuthorizationRequest"},
  163. {160, nullptr, "RequiresUpdateNetworkServiceAccountIdTokenCache"},
  164. {161, nullptr, "RequireReauthenticationOfNetworkServiceAccount"},
  165. {200, nullptr, "IsRegistered"},
  166. {201, nullptr, "RegisterAsync"},
  167. {202, nullptr, "UnregisterAsync"},
  168. {203, nullptr, "DeleteRegistrationInfoLocally"},
  169. {220, nullptr, "SynchronizeProfileAsync"},
  170. {221, nullptr, "UploadProfileAsync"},
  171. {222, nullptr, "SynchronizaProfileAsyncIfSecondsElapsed"},
  172. {250, nullptr, "IsLinkedWithNintendoAccount"},
  173. {251, nullptr, "CreateProcedureToLinkWithNintendoAccount"},
  174. {252, nullptr, "ResumeProcedureToLinkWithNintendoAccount"},
  175. {255, nullptr, "CreateProcedureToUpdateLinkageStateOfNintendoAccount"},
  176. {256, nullptr, "ResumeProcedureToUpdateLinkageStateOfNintendoAccount"},
  177. {260, nullptr, "CreateProcedureToLinkNnidWithNintendoAccount"}, // 3.0.0+
  178. {261, nullptr, "ResumeProcedureToLinkNnidWithNintendoAccount"}, // 3.0.0+
  179. {280, nullptr, "ProxyProcedureToAcquireApplicationAuthorizationForNintendoAccount"},
  180. {290, nullptr, "GetRequestForNintendoAccountUserResourceView"}, // 8.0.0+
  181. {300, nullptr, "TryRecoverNintendoAccountUserStateAsync"}, // 6.0.0+
  182. {400, nullptr, "IsServiceEntryRequirementCacheRefreshRequiredForOnlinePlay"}, // 6.1.0+
  183. {401, nullptr, "RefreshServiceEntryRequirementCacheForOnlinePlayAsync"}, // 6.1.0+
  184. {900, nullptr, "GetAuthenticationInfoForWin"}, // 9.0.0+
  185. {901, nullptr, "ImportAsyncForWin"}, // 9.0.0+
  186. {997, nullptr, "DebugUnlinkNintendoAccountAsync"},
  187. {998, nullptr, "DebugSetAvailabilityErrorDetail"},
  188. };
  189. // clang-format on
  190. RegisterHandlers(functions);
  191. }
  192. };
  193. class IAuthorizationRequest final : public ServiceFramework<IAuthorizationRequest> {
  194. public:
  195. explicit IAuthorizationRequest(Core::System& system_, Common::UUID)
  196. : ServiceFramework{system_, "IAuthorizationRequest"} {
  197. // clang-format off
  198. static const FunctionInfo functions[] = {
  199. {0, nullptr, "GetSessionId"},
  200. {10, nullptr, "InvokeWithoutInteractionAsync"},
  201. {19, nullptr, "IsAuthorized"},
  202. {20, nullptr, "GetAuthorizationCode"},
  203. {21, nullptr, "GetIdToken"},
  204. {22, nullptr, "GetState"},
  205. };
  206. // clang-format on
  207. RegisterHandlers(functions);
  208. }
  209. };
  210. class IOAuthProcedure final : public ServiceFramework<IOAuthProcedure> {
  211. public:
  212. explicit IOAuthProcedure(Core::System& system_, Common::UUID)
  213. : ServiceFramework{system_, "IOAuthProcedure"} {
  214. // clang-format off
  215. static const FunctionInfo functions[] = {
  216. {0, nullptr, "PrepareAsync"},
  217. {1, nullptr, "GetRequest"},
  218. {2, nullptr, "ApplyResponse"},
  219. {3, nullptr, "ApplyResponseAsync"},
  220. {10, nullptr, "Suspend"},
  221. };
  222. // clang-format on
  223. RegisterHandlers(functions);
  224. }
  225. };
  226. // 3.0.0+
  227. class IOAuthProcedureForExternalNsa final : public ServiceFramework<IOAuthProcedureForExternalNsa> {
  228. public:
  229. explicit IOAuthProcedureForExternalNsa(Core::System& system_, Common::UUID)
  230. : ServiceFramework{system_, "IOAuthProcedureForExternalNsa"} {
  231. // clang-format off
  232. static const FunctionInfo functions[] = {
  233. {0, nullptr, "PrepareAsync"},
  234. {1, nullptr, "GetRequest"},
  235. {2, nullptr, "ApplyResponse"},
  236. {3, nullptr, "ApplyResponseAsync"},
  237. {10, nullptr, "Suspend"},
  238. {100, nullptr, "GetAccountId"},
  239. {101, nullptr, "GetLinkedNintendoAccountId"},
  240. {102, nullptr, "GetNickname"},
  241. {103, nullptr, "GetProfileImage"},
  242. };
  243. // clang-format on
  244. RegisterHandlers(functions);
  245. }
  246. };
  247. class IOAuthProcedureForNintendoAccountLinkage final
  248. : public ServiceFramework<IOAuthProcedureForNintendoAccountLinkage> {
  249. public:
  250. explicit IOAuthProcedureForNintendoAccountLinkage(Core::System& system_, Common::UUID)
  251. : ServiceFramework{system_, "IOAuthProcedureForNintendoAccountLinkage"} {
  252. // clang-format off
  253. static const FunctionInfo functions[] = {
  254. {0, nullptr, "PrepareAsync"},
  255. {1, nullptr, "GetRequest"},
  256. {2, nullptr, "ApplyResponse"},
  257. {3, nullptr, "ApplyResponseAsync"},
  258. {10, nullptr, "Suspend"},
  259. {100, nullptr, "GetRequestWithTheme"},
  260. {101, nullptr, "IsNetworkServiceAccountReplaced"},
  261. {199, nullptr, "GetUrlForIntroductionOfExtraMembership"}, // 2.0.0 - 5.1.0
  262. {200, nullptr, "ApplyAsyncWithAuthorizedToken"},
  263. };
  264. // clang-format on
  265. RegisterHandlers(functions);
  266. }
  267. };
  268. class INotifier final : public ServiceFramework<INotifier> {
  269. public:
  270. explicit INotifier(Core::System& system_, Common::UUID)
  271. : ServiceFramework{system_, "INotifier"} {
  272. // clang-format off
  273. static const FunctionInfo functions[] = {
  274. {0, nullptr, "GetSystemEvent"},
  275. };
  276. // clang-format on
  277. RegisterHandlers(functions);
  278. }
  279. };
  280. class IProfileCommon : public ServiceFramework<IProfileCommon> {
  281. public:
  282. explicit IProfileCommon(Core::System& system_, const char* name, bool editor_commands,
  283. Common::UUID user_id_, ProfileManager& profile_manager_)
  284. : ServiceFramework{system_, name}, profile_manager{profile_manager_}, user_id{user_id_} {
  285. static const FunctionInfo functions[] = {
  286. {0, &IProfileCommon::Get, "Get"},
  287. {1, &IProfileCommon::GetBase, "GetBase"},
  288. {10, &IProfileCommon::GetImageSize, "GetImageSize"},
  289. {11, &IProfileCommon::LoadImage, "LoadImage"},
  290. };
  291. RegisterHandlers(functions);
  292. if (editor_commands) {
  293. static const FunctionInfo editor_functions[] = {
  294. {100, &IProfileCommon::Store, "Store"},
  295. {101, &IProfileCommon::StoreWithImage, "StoreWithImage"},
  296. };
  297. RegisterHandlers(editor_functions);
  298. }
  299. }
  300. protected:
  301. void Get(HLERequestContext& ctx) {
  302. LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
  303. ProfileBase profile_base{};
  304. UserData data{};
  305. if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
  306. ctx.WriteBuffer(data);
  307. IPC::ResponseBuilder rb{ctx, 16};
  308. rb.Push(ResultSuccess);
  309. rb.PushRaw(profile_base);
  310. } else {
  311. LOG_ERROR(Service_ACC, "Failed to get profile base and data for user=0x{}",
  312. user_id.RawString());
  313. IPC::ResponseBuilder rb{ctx, 2};
  314. rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code
  315. }
  316. }
  317. void GetBase(HLERequestContext& ctx) {
  318. LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
  319. ProfileBase profile_base{};
  320. if (profile_manager.GetProfileBase(user_id, profile_base)) {
  321. IPC::ResponseBuilder rb{ctx, 16};
  322. rb.Push(ResultSuccess);
  323. rb.PushRaw(profile_base);
  324. } else {
  325. LOG_ERROR(Service_ACC, "Failed to get profile base for user=0x{}", user_id.RawString());
  326. IPC::ResponseBuilder rb{ctx, 2};
  327. rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code
  328. }
  329. }
  330. void LoadImage(HLERequestContext& ctx) {
  331. LOG_DEBUG(Service_ACC, "called");
  332. IPC::ResponseBuilder rb{ctx, 3};
  333. rb.Push(ResultSuccess);
  334. const Common::FS::IOFile image(GetImagePath(user_id), Common::FS::FileAccessMode::Read,
  335. Common::FS::FileType::BinaryFile);
  336. if (!image.IsOpen()) {
  337. LOG_WARNING(Service_ACC,
  338. "Failed to load user provided image! Falling back to built-in backup...");
  339. ctx.WriteBuffer(Core::Constants::ACCOUNT_BACKUP_JPEG);
  340. rb.Push(static_cast<u32>(Core::Constants::ACCOUNT_BACKUP_JPEG.size()));
  341. return;
  342. }
  343. std::vector<u8> buffer(image.GetSize());
  344. if (image.Read(buffer) != buffer.size()) {
  345. LOG_ERROR(Service_ACC, "Failed to read all the bytes in the user provided image.");
  346. }
  347. SanitizeJPEGImageSize(buffer);
  348. ctx.WriteBuffer(buffer);
  349. rb.Push(static_cast<u32>(buffer.size()));
  350. }
  351. void GetImageSize(HLERequestContext& ctx) {
  352. LOG_DEBUG(Service_ACC, "called");
  353. IPC::ResponseBuilder rb{ctx, 3};
  354. rb.Push(ResultSuccess);
  355. const Common::FS::IOFile image(GetImagePath(user_id), Common::FS::FileAccessMode::Read,
  356. Common::FS::FileType::BinaryFile);
  357. if (!image.IsOpen()) {
  358. LOG_WARNING(Service_ACC,
  359. "Failed to load user provided image! Falling back to built-in backup...");
  360. rb.Push(static_cast<u32>(Core::Constants::ACCOUNT_BACKUP_JPEG.size()));
  361. return;
  362. }
  363. std::vector<u8> buffer(image.GetSize());
  364. if (image.Read(buffer) != buffer.size()) {
  365. LOG_ERROR(Service_ACC, "Failed to read all the bytes in the user provided image.");
  366. }
  367. SanitizeJPEGImageSize(buffer);
  368. rb.Push(static_cast<u32>(buffer.size()));
  369. }
  370. void Store(HLERequestContext& ctx) {
  371. IPC::RequestParser rp{ctx};
  372. const auto base = rp.PopRaw<ProfileBase>();
  373. const auto user_data = ctx.ReadBuffer();
  374. LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}",
  375. Common::StringFromFixedZeroTerminatedBuffer(
  376. reinterpret_cast<const char*>(base.username.data()), base.username.size()),
  377. base.timestamp, base.user_uuid.RawString());
  378. if (user_data.size() < sizeof(UserData)) {
  379. LOG_ERROR(Service_ACC, "UserData buffer too small!");
  380. IPC::ResponseBuilder rb{ctx, 2};
  381. rb.Push(Account::ResultInvalidArrayLength);
  382. return;
  383. }
  384. UserData data;
  385. std::memcpy(&data, user_data.data(), sizeof(UserData));
  386. if (!profile_manager.SetProfileBaseAndData(user_id, base, data)) {
  387. LOG_ERROR(Service_ACC, "Failed to update user data and base!");
  388. IPC::ResponseBuilder rb{ctx, 2};
  389. rb.Push(Account::ResultAccountUpdateFailed);
  390. return;
  391. }
  392. IPC::ResponseBuilder rb{ctx, 2};
  393. rb.Push(ResultSuccess);
  394. }
  395. void StoreWithImage(HLERequestContext& ctx) {
  396. IPC::RequestParser rp{ctx};
  397. const auto base = rp.PopRaw<ProfileBase>();
  398. const auto image_data = ctx.ReadBufferA(0);
  399. const auto user_data = ctx.ReadBufferX(0);
  400. LOG_INFO(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}",
  401. Common::StringFromFixedZeroTerminatedBuffer(
  402. reinterpret_cast<const char*>(base.username.data()), base.username.size()),
  403. base.timestamp, base.user_uuid.RawString());
  404. if (user_data.size() < sizeof(UserData)) {
  405. LOG_ERROR(Service_ACC, "UserData buffer too small!");
  406. IPC::ResponseBuilder rb{ctx, 2};
  407. rb.Push(Account::ResultInvalidArrayLength);
  408. return;
  409. }
  410. UserData data;
  411. std::memcpy(&data, user_data.data(), sizeof(UserData));
  412. Common::FS::IOFile image(GetImagePath(user_id), Common::FS::FileAccessMode::Write,
  413. Common::FS::FileType::BinaryFile);
  414. if (!image.IsOpen() || !image.SetSize(image_data.size()) ||
  415. image.Write(image_data) != image_data.size() ||
  416. !profile_manager.SetProfileBaseAndData(user_id, base, data)) {
  417. LOG_ERROR(Service_ACC, "Failed to update profile data, base, and image!");
  418. IPC::ResponseBuilder rb{ctx, 2};
  419. rb.Push(Account::ResultAccountUpdateFailed);
  420. return;
  421. }
  422. IPC::ResponseBuilder rb{ctx, 2};
  423. rb.Push(ResultSuccess);
  424. }
  425. ProfileManager& profile_manager;
  426. Common::UUID user_id{}; ///< The user id this profile refers to.
  427. };
  428. class IProfile final : public IProfileCommon {
  429. public:
  430. explicit IProfile(Core::System& system_, Common::UUID user_id_,
  431. ProfileManager& profile_manager_)
  432. : IProfileCommon{system_, "IProfile", false, user_id_, profile_manager_} {}
  433. };
  434. class IProfileEditor final : public IProfileCommon {
  435. public:
  436. explicit IProfileEditor(Core::System& system_, Common::UUID user_id_,
  437. ProfileManager& profile_manager_)
  438. : IProfileCommon{system_, "IProfileEditor", true, user_id_, profile_manager_} {}
  439. };
  440. class ISessionObject final : public ServiceFramework<ISessionObject> {
  441. public:
  442. explicit ISessionObject(Core::System& system_, Common::UUID)
  443. : ServiceFramework{system_, "ISessionObject"} {
  444. // clang-format off
  445. static const FunctionInfo functions[] = {
  446. {999, nullptr, "Dummy"},
  447. };
  448. // clang-format on
  449. RegisterHandlers(functions);
  450. }
  451. };
  452. class IGuestLoginRequest final : public ServiceFramework<IGuestLoginRequest> {
  453. public:
  454. explicit IGuestLoginRequest(Core::System& system_, Common::UUID)
  455. : ServiceFramework{system_, "IGuestLoginRequest"} {
  456. // clang-format off
  457. static const FunctionInfo functions[] = {
  458. {0, nullptr, "GetSessionId"},
  459. {11, nullptr, "Unknown"}, // 1.0.0 - 2.3.0 (the name is blank on Switchbrew)
  460. {12, nullptr, "GetAccountId"},
  461. {13, nullptr, "GetLinkedNintendoAccountId"},
  462. {14, nullptr, "GetNickname"},
  463. {15, nullptr, "GetProfileImage"},
  464. {21, nullptr, "LoadIdTokenCache"}, // 3.0.0+
  465. };
  466. // clang-format on
  467. RegisterHandlers(functions);
  468. }
  469. };
  470. class EnsureTokenIdCacheAsyncInterface final : public IAsyncContext {
  471. public:
  472. explicit EnsureTokenIdCacheAsyncInterface(Core::System& system_) : IAsyncContext{system_} {
  473. MarkComplete();
  474. }
  475. ~EnsureTokenIdCacheAsyncInterface() = default;
  476. void LoadIdTokenCache(HLERequestContext& ctx) {
  477. LOG_WARNING(Service_ACC, "(STUBBED) called");
  478. IPC::ResponseBuilder rb{ctx, 3};
  479. rb.Push(ResultSuccess);
  480. rb.Push(0);
  481. }
  482. protected:
  483. bool IsComplete() const override {
  484. return true;
  485. }
  486. void Cancel() override {}
  487. Result GetResult() const override {
  488. return ResultSuccess;
  489. }
  490. };
  491. class IManagerForApplication final : public ServiceFramework<IManagerForApplication> {
  492. public:
  493. explicit IManagerForApplication(Core::System& system_,
  494. const std::shared_ptr<ProfileManager>& profile_manager_)
  495. : ServiceFramework{system_, "IManagerForApplication"},
  496. ensure_token_id{std::make_shared<EnsureTokenIdCacheAsyncInterface>(system)},
  497. profile_manager{profile_manager_} {
  498. // clang-format off
  499. static const FunctionInfo functions[] = {
  500. {0, &IManagerForApplication::CheckAvailability, "CheckAvailability"},
  501. {1, &IManagerForApplication::GetAccountId, "GetAccountId"},
  502. {2, &IManagerForApplication::EnsureIdTokenCacheAsync, "EnsureIdTokenCacheAsync"},
  503. {3, &IManagerForApplication::LoadIdTokenCache, "LoadIdTokenCache"},
  504. {130, &IManagerForApplication::GetNintendoAccountUserResourceCacheForApplication, "GetNintendoAccountUserResourceCacheForApplication"},
  505. {150, nullptr, "CreateAuthorizationRequest"},
  506. {160, &IManagerForApplication::StoreOpenContext, "StoreOpenContext"},
  507. {170, nullptr, "LoadNetworkServiceLicenseKindAsync"},
  508. };
  509. // clang-format on
  510. RegisterHandlers(functions);
  511. }
  512. private:
  513. void CheckAvailability(HLERequestContext& ctx) {
  514. LOG_DEBUG(Service_ACC, "(STUBBED) called");
  515. IPC::ResponseBuilder rb{ctx, 3};
  516. rb.Push(ResultSuccess);
  517. rb.Push(false); // TODO: Check when this is supposed to return true and when not
  518. }
  519. void GetAccountId(HLERequestContext& ctx) {
  520. LOG_DEBUG(Service_ACC, "called");
  521. IPC::ResponseBuilder rb{ctx, 4};
  522. rb.Push(ResultSuccess);
  523. rb.PushRaw<u64>(profile_manager->GetLastOpenedUser().Hash());
  524. }
  525. void EnsureIdTokenCacheAsync(HLERequestContext& ctx) {
  526. LOG_WARNING(Service_ACC, "(STUBBED) called");
  527. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  528. rb.Push(ResultSuccess);
  529. rb.PushIpcInterface(ensure_token_id);
  530. }
  531. void LoadIdTokenCache(HLERequestContext& ctx) {
  532. LOG_WARNING(Service_ACC, "(STUBBED) called");
  533. ensure_token_id->LoadIdTokenCache(ctx);
  534. }
  535. void GetNintendoAccountUserResourceCacheForApplication(HLERequestContext& ctx) {
  536. LOG_WARNING(Service_ACC, "(STUBBED) called");
  537. std::vector<u8> nas_user_base_for_application(0x68);
  538. ctx.WriteBuffer(nas_user_base_for_application, 0);
  539. if (ctx.CanWriteBuffer(1)) {
  540. std::vector<u8> unknown_out_buffer(ctx.GetWriteBufferSize(1));
  541. ctx.WriteBuffer(unknown_out_buffer, 1);
  542. }
  543. IPC::ResponseBuilder rb{ctx, 4};
  544. rb.Push(ResultSuccess);
  545. rb.PushRaw<u64>(profile_manager->GetLastOpenedUser().Hash());
  546. }
  547. void StoreOpenContext(HLERequestContext& ctx) {
  548. LOG_DEBUG(Service_ACC, "called");
  549. profile_manager->StoreOpenedUsers();
  550. IPC::ResponseBuilder rb{ctx, 2};
  551. rb.Push(ResultSuccess);
  552. }
  553. std::shared_ptr<EnsureTokenIdCacheAsyncInterface> ensure_token_id{};
  554. std::shared_ptr<ProfileManager> profile_manager;
  555. };
  556. // 6.0.0+
  557. class IAsyncNetworkServiceLicenseKindContext final
  558. : public ServiceFramework<IAsyncNetworkServiceLicenseKindContext> {
  559. public:
  560. explicit IAsyncNetworkServiceLicenseKindContext(Core::System& system_, Common::UUID)
  561. : ServiceFramework{system_, "IAsyncNetworkServiceLicenseKindContext"} {
  562. // clang-format off
  563. static const FunctionInfo functions[] = {
  564. {0, nullptr, "GetSystemEvent"},
  565. {1, nullptr, "Cancel"},
  566. {2, nullptr, "HasDone"},
  567. {3, nullptr, "GetResult"},
  568. {4, nullptr, "GetNetworkServiceLicenseKind"},
  569. };
  570. // clang-format on
  571. RegisterHandlers(functions);
  572. }
  573. };
  574. // 8.0.0+
  575. class IOAuthProcedureForUserRegistration final
  576. : public ServiceFramework<IOAuthProcedureForUserRegistration> {
  577. public:
  578. explicit IOAuthProcedureForUserRegistration(Core::System& system_, Common::UUID)
  579. : ServiceFramework{system_, "IOAuthProcedureForUserRegistration"} {
  580. // clang-format off
  581. static const FunctionInfo functions[] = {
  582. {0, nullptr, "PrepareAsync"},
  583. {1, nullptr, "GetRequest"},
  584. {2, nullptr, "ApplyResponse"},
  585. {3, nullptr, "ApplyResponseAsync"},
  586. {10, nullptr, "Suspend"},
  587. {100, nullptr, "GetAccountId"},
  588. {101, nullptr, "GetLinkedNintendoAccountId"},
  589. {102, nullptr, "GetNickname"},
  590. {103, nullptr, "GetProfileImage"},
  591. {110, nullptr, "RegisterUserAsync"},
  592. {111, nullptr, "GetUid"},
  593. };
  594. // clang-format on
  595. RegisterHandlers(functions);
  596. }
  597. };
  598. class DAUTH_O final : public ServiceFramework<DAUTH_O> {
  599. public:
  600. explicit DAUTH_O(Core::System& system_, Common::UUID) : ServiceFramework{system_, "dauth:o"} {
  601. // clang-format off
  602. static const FunctionInfo functions[] = {
  603. {0, nullptr, "EnsureAuthenticationTokenCacheAsync"},
  604. {1, nullptr, "LoadAuthenticationTokenCache"},
  605. {2, nullptr, "InvalidateAuthenticationTokenCache"},
  606. {3, nullptr, "IsDeviceAuthenticationTokenCacheAvailable"},
  607. {10, nullptr, "EnsureEdgeTokenCacheAsync"},
  608. {11, nullptr, "LoadEdgeTokenCache"},
  609. {12, nullptr, "InvalidateEdgeTokenCache"},
  610. {13, nullptr, "IsEdgeTokenCacheAvailable"},
  611. {20, nullptr, "EnsureApplicationAuthenticationCacheAsync"},
  612. {21, nullptr, "LoadApplicationAuthenticationTokenCache"},
  613. {22, nullptr, "LoadApplicationNetworkServiceClientConfigCache"},
  614. {23, nullptr, "IsApplicationAuthenticationCacheAvailable"},
  615. {24, nullptr, "InvalidateApplicationAuthenticationCache"},
  616. };
  617. // clang-format on
  618. RegisterHandlers(functions);
  619. }
  620. };
  621. // 6.0.0+
  622. class IAsyncResult final : public ServiceFramework<IAsyncResult> {
  623. public:
  624. explicit IAsyncResult(Core::System& system_, Common::UUID)
  625. : ServiceFramework{system_, "IAsyncResult"} {
  626. // clang-format off
  627. static const FunctionInfo functions[] = {
  628. {0, nullptr, "GetResult"},
  629. {1, nullptr, "Cancel"},
  630. {2, nullptr, "IsAvailable"},
  631. {3, nullptr, "GetSystemEvent"},
  632. };
  633. // clang-format on
  634. RegisterHandlers(functions);
  635. }
  636. };
  637. void Module::Interface::GetUserCount(HLERequestContext& ctx) {
  638. LOG_DEBUG(Service_ACC, "called");
  639. IPC::ResponseBuilder rb{ctx, 3};
  640. rb.Push(ResultSuccess);
  641. rb.Push<u32>(static_cast<u32>(profile_manager->GetUserCount()));
  642. }
  643. void Module::Interface::GetUserExistence(HLERequestContext& ctx) {
  644. IPC::RequestParser rp{ctx};
  645. Common::UUID user_id = rp.PopRaw<Common::UUID>();
  646. LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
  647. IPC::ResponseBuilder rb{ctx, 3};
  648. rb.Push(ResultSuccess);
  649. rb.Push(profile_manager->UserExists(user_id));
  650. }
  651. void Module::Interface::ListAllUsers(HLERequestContext& ctx) {
  652. LOG_DEBUG(Service_ACC, "called");
  653. ctx.WriteBuffer(profile_manager->GetAllUsers());
  654. IPC::ResponseBuilder rb{ctx, 2};
  655. rb.Push(ResultSuccess);
  656. }
  657. void Module::Interface::ListOpenUsers(HLERequestContext& ctx) {
  658. LOG_DEBUG(Service_ACC, "called");
  659. ctx.WriteBuffer(profile_manager->GetOpenUsers());
  660. IPC::ResponseBuilder rb{ctx, 2};
  661. rb.Push(ResultSuccess);
  662. }
  663. void Module::Interface::GetLastOpenedUser(HLERequestContext& ctx) {
  664. LOG_DEBUG(Service_ACC, "called");
  665. IPC::ResponseBuilder rb{ctx, 6};
  666. rb.Push(ResultSuccess);
  667. rb.PushRaw<Common::UUID>(profile_manager->GetLastOpenedUser());
  668. }
  669. void Module::Interface::GetProfile(HLERequestContext& ctx) {
  670. IPC::RequestParser rp{ctx};
  671. Common::UUID user_id = rp.PopRaw<Common::UUID>();
  672. LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
  673. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  674. rb.Push(ResultSuccess);
  675. rb.PushIpcInterface<IProfile>(system, user_id, *profile_manager);
  676. }
  677. void Module::Interface::IsUserRegistrationRequestPermitted(HLERequestContext& ctx) {
  678. LOG_WARNING(Service_ACC, "(STUBBED) called");
  679. IPC::ResponseBuilder rb{ctx, 3};
  680. rb.Push(ResultSuccess);
  681. rb.Push(profile_manager->CanSystemRegisterUser());
  682. }
  683. void Module::Interface::InitializeApplicationInfo(HLERequestContext& ctx) {
  684. LOG_DEBUG(Service_ACC, "called");
  685. IPC::ResponseBuilder rb{ctx, 2};
  686. rb.Push(InitializeApplicationInfoBase());
  687. }
  688. void Module::Interface::InitializeApplicationInfoRestricted(HLERequestContext& ctx) {
  689. LOG_WARNING(Service_ACC, "(Partial implementation) called");
  690. // TODO(ogniK): We require checking if the user actually owns the title and what not. As of
  691. // currently, we assume the user owns the title. InitializeApplicationInfoBase SHOULD be called
  692. // first then we do extra checks if the game is a digital copy.
  693. IPC::ResponseBuilder rb{ctx, 2};
  694. rb.Push(InitializeApplicationInfoBase());
  695. }
  696. Result Module::Interface::InitializeApplicationInfoBase() {
  697. if (application_info) {
  698. LOG_ERROR(Service_ACC, "Application already initialized");
  699. return Account::ResultApplicationInfoAlreadyInitialized;
  700. }
  701. // TODO(ogniK): This should be changed to reflect the target process for when we have multiple
  702. // processes emulated. As we don't actually have pid support we should assume we're just using
  703. // our own process
  704. Glue::ApplicationLaunchProperty launch_property{};
  705. const auto result = system.GetARPManager().GetLaunchProperty(
  706. &launch_property, system.GetApplicationProcessProgramID());
  707. if (result != ResultSuccess) {
  708. LOG_ERROR(Service_ACC, "Failed to get launch property");
  709. return Account::ResultInvalidApplication;
  710. }
  711. switch (launch_property.base_game_storage_id) {
  712. case FileSys::StorageId::GameCard:
  713. application_info.application_type = ApplicationType::GameCard;
  714. break;
  715. case FileSys::StorageId::Host:
  716. case FileSys::StorageId::NandUser:
  717. case FileSys::StorageId::SdCard:
  718. case FileSys::StorageId::None: // Suyu specific, differs from hardware
  719. application_info.application_type = ApplicationType::Digital;
  720. break;
  721. default:
  722. LOG_ERROR(Service_ACC, "Invalid game storage ID! storage_id={}",
  723. launch_property.base_game_storage_id);
  724. return Account::ResultInvalidApplication;
  725. }
  726. LOG_WARNING(Service_ACC, "ApplicationInfo init required");
  727. // TODO(ogniK): Actual initialization here
  728. return ResultSuccess;
  729. }
  730. void Module::Interface::GetBaasAccountManagerForApplication(HLERequestContext& ctx) {
  731. LOG_DEBUG(Service_ACC, "called");
  732. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  733. rb.Push(ResultSuccess);
  734. rb.PushIpcInterface<IManagerForApplication>(system, profile_manager);
  735. }
  736. void Module::Interface::IsUserAccountSwitchLocked(HLERequestContext& ctx) {
  737. LOG_DEBUG(Service_ACC, "called");
  738. FileSys::NACP nacp;
  739. const auto res = system.GetAppLoader().ReadControlData(nacp);
  740. bool is_locked = false;
  741. if (res != Loader::ResultStatus::Success) {
  742. const FileSys::PatchManager pm{system.GetApplicationProcessProgramID(),
  743. system.GetFileSystemController(),
  744. system.GetContentProvider()};
  745. const auto nacp_unique = pm.GetControlMetadata().first;
  746. if (nacp_unique != nullptr) {
  747. is_locked = nacp_unique->GetUserAccountSwitchLock();
  748. } else {
  749. LOG_ERROR(Service_ACC, "nacp_unique is null!");
  750. }
  751. } else {
  752. is_locked = nacp.GetUserAccountSwitchLock();
  753. }
  754. IPC::ResponseBuilder rb{ctx, 3};
  755. rb.Push(ResultSuccess);
  756. rb.Push(is_locked);
  757. }
  758. void Module::Interface::InitializeApplicationInfoV2(HLERequestContext& ctx) {
  759. LOG_WARNING(Service_ACC, "(STUBBED) called");
  760. IPC::ResponseBuilder rb{ctx, 2};
  761. rb.Push(ResultSuccess);
  762. }
  763. void Module::Interface::BeginUserRegistration(HLERequestContext& ctx) {
  764. const auto user_id = Common::UUID::MakeRandom();
  765. profile_manager->CreateNewUser(user_id, "suyu");
  766. LOG_INFO(Service_ACC, "called, uuid={}", user_id.FormattedString());
  767. IPC::ResponseBuilder rb{ctx, 6};
  768. rb.Push(ResultSuccess);
  769. rb.PushRaw(user_id);
  770. }
  771. void Module::Interface::CompleteUserRegistration(HLERequestContext& ctx) {
  772. IPC::RequestParser rp{ctx};
  773. Common::UUID user_id = rp.PopRaw<Common::UUID>();
  774. LOG_INFO(Service_ACC, "called, uuid={}", user_id.FormattedString());
  775. profile_manager->WriteUserSaveFile();
  776. IPC::ResponseBuilder rb{ctx, 2};
  777. rb.Push(ResultSuccess);
  778. }
  779. void Module::Interface::GetProfileEditor(HLERequestContext& ctx) {
  780. IPC::RequestParser rp{ctx};
  781. Common::UUID user_id = rp.PopRaw<Common::UUID>();
  782. LOG_DEBUG(Service_ACC, "called, user_id=0x{}", user_id.RawString());
  783. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  784. rb.Push(ResultSuccess);
  785. rb.PushIpcInterface<IProfileEditor>(system, user_id, *profile_manager);
  786. }
  787. void Module::Interface::ListQualifiedUsers(HLERequestContext& ctx) {
  788. LOG_DEBUG(Service_ACC, "called");
  789. // All users should be qualified. We don't actually have parental control or anything to do with
  790. // nintendo online currently. We're just going to assume the user running the game has access to
  791. // the game regardless of parental control settings.
  792. ctx.WriteBuffer(profile_manager->GetAllUsers());
  793. IPC::ResponseBuilder rb{ctx, 2};
  794. rb.Push(ResultSuccess);
  795. }
  796. void Module::Interface::ListOpenContextStoredUsers(HLERequestContext& ctx) {
  797. LOG_DEBUG(Service_ACC, "called");
  798. ctx.WriteBuffer(profile_manager->GetStoredOpenedUsers());
  799. IPC::ResponseBuilder rb{ctx, 2};
  800. rb.Push(ResultSuccess);
  801. }
  802. void Module::Interface::StoreSaveDataThumbnailApplication(HLERequestContext& ctx) {
  803. IPC::RequestParser rp{ctx};
  804. const auto uuid = rp.PopRaw<Common::UUID>();
  805. LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}", uuid.RawString());
  806. // TODO(ogniK): Check if application ID is zero on acc initialize. As we don't have a reliable
  807. // way of confirming things like the TID, we're going to assume a non zero value for the time
  808. // being.
  809. constexpr u64 tid{1};
  810. StoreSaveDataThumbnail(ctx, uuid, tid);
  811. }
  812. void Module::Interface::GetBaasAccountManagerForSystemService(HLERequestContext& ctx) {
  813. IPC::RequestParser rp{ctx};
  814. const auto uuid = rp.PopRaw<Common::UUID>();
  815. LOG_INFO(Service_ACC, "called, uuid=0x{}", uuid.RawString());
  816. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  817. rb.Push(ResultSuccess);
  818. rb.PushIpcInterface<IManagerForSystemService>(system, uuid);
  819. }
  820. void Module::Interface::StoreSaveDataThumbnailSystem(HLERequestContext& ctx) {
  821. IPC::RequestParser rp{ctx};
  822. const auto uuid = rp.PopRaw<Common::UUID>();
  823. const auto tid = rp.Pop<u64_le>();
  824. LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}, tid={:016X}", uuid.RawString(), tid);
  825. StoreSaveDataThumbnail(ctx, uuid, tid);
  826. }
  827. void Module::Interface::StoreSaveDataThumbnail(HLERequestContext& ctx, const Common::UUID& uuid,
  828. const u64 tid) {
  829. IPC::ResponseBuilder rb{ctx, 2};
  830. if (tid == 0) {
  831. LOG_ERROR(Service_ACC, "TitleID is not valid!");
  832. rb.Push(Account::ResultInvalidApplication);
  833. return;
  834. }
  835. if (uuid.IsInvalid()) {
  836. LOG_ERROR(Service_ACC, "User ID is not valid!");
  837. rb.Push(Account::ResultInvalidUserId);
  838. return;
  839. }
  840. const auto thumbnail_size = ctx.GetReadBufferSize();
  841. if (thumbnail_size != THUMBNAIL_SIZE) {
  842. LOG_ERROR(Service_ACC, "Buffer size is empty! size={:X} expecting {:X}", thumbnail_size,
  843. THUMBNAIL_SIZE);
  844. rb.Push(Account::ResultInvalidArrayLength);
  845. return;
  846. }
  847. // TODO(ogniK): Construct save data thumbnail
  848. rb.Push(ResultSuccess);
  849. }
  850. void Module::Interface::TrySelectUserWithoutInteraction(HLERequestContext& ctx) {
  851. LOG_DEBUG(Service_ACC, "called");
  852. // A u8 is passed into this function which we can safely ignore. It's to determine if we have
  853. // access to use the network or not by the looks of it
  854. IPC::ResponseBuilder rb{ctx, 6};
  855. if (profile_manager->GetUserCount() != 1) {
  856. rb.Push(ResultSuccess);
  857. rb.PushRaw(Common::InvalidUUID);
  858. return;
  859. }
  860. const auto user_list = profile_manager->GetAllUsers();
  861. if (std::ranges::all_of(user_list, [](const auto& user) { return user.IsInvalid(); })) {
  862. rb.Push(ResultUnknown); // TODO(ogniK): Find the correct error code
  863. rb.PushRaw(Common::InvalidUUID);
  864. return;
  865. }
  866. // Select the first user we have
  867. rb.Push(ResultSuccess);
  868. rb.PushRaw(profile_manager->GetUser(0)->uuid);
  869. }
  870. Module::Interface::Interface(std::shared_ptr<Module> module_,
  871. std::shared_ptr<ProfileManager> profile_manager_,
  872. Core::System& system_, const char* name)
  873. : ServiceFramework{system_, name}, module{std::move(module_)},
  874. profile_manager{std::move(profile_manager_)} {}
  875. Module::Interface::~Interface() = default;
  876. void LoopProcess(Core::System& system) {
  877. auto module = std::make_shared<Module>();
  878. auto profile_manager = std::make_shared<ProfileManager>();
  879. auto server_manager = std::make_unique<ServerManager>(system);
  880. server_manager->RegisterNamedService("acc:aa",
  881. std::make_shared<ACC_AA>(module, profile_manager, system));
  882. server_manager->RegisterNamedService("acc:su",
  883. std::make_shared<ACC_SU>(module, profile_manager, system));
  884. server_manager->RegisterNamedService("acc:u0",
  885. std::make_shared<ACC_U0>(module, profile_manager, system));
  886. server_manager->RegisterNamedService("acc:u1",
  887. std::make_shared<ACC_U1>(module, profile_manager, system));
  888. ServerManager::RunServer(std::move(server_manager));
  889. }
  890. } // namespace Service::Account