mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-09 13:36:35 +00:00
87e5d0b6e4
Signed-off-by: lizzie <lizzie@eden-emu.dev> - [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions). - [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md) - [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability. ------------------- `OpenSystemApplicationProxy` `OpenSystemApplicationProxy` ALSO yes those cmds DO NOT take an attribute Implemented SVC infos to match Atmosphere's values Implement more stub I2C session cmds stub CMD2103 for rhythm groove better error handling on svc get info to match ams (see ams svc info) Virtual Boy classic fix adept from https://git.ryujinx.app/projects/Kenji-NX/commit/2288084b531b185f5840a696b23265014f07e2f2 by @Mythrax acc:u1 was missing the *Deprecated cmd Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4343 Reviewed-by: CamilleLaVey <camillelavey99@gmail.com> Reviewed-by: Maufeat <sahyno1996@gmail.com>
1658 lines
70 KiB
C++
1658 lines
70 KiB
C++
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
|
|
#include "common/common_types.h"
|
|
#include "common/fs/file.h"
|
|
#include "common/fs/path_util.h"
|
|
#include "common/logging.h"
|
|
#include <ranges>
|
|
#include "common/stb.h"
|
|
#include "common/string_util.h"
|
|
#include "common/swap.h"
|
|
#include "core/constants.h"
|
|
#include "core/core.h"
|
|
#include "core/core_timing.h"
|
|
#include "core/file_sys/control_metadata.h"
|
|
#include "core/file_sys/patch_manager.h"
|
|
#include "core/hle/service/acc/acc.h"
|
|
#include "core/hle/service/acc/async_context.h"
|
|
#include "core/hle/service/acc/errors.h"
|
|
#include "core/hle/service/acc/profile_manager.h"
|
|
#include "core/hle/service/cmif_serialization.h"
|
|
#include "core/hle/service/glue/glue_manager.h"
|
|
#include "core/hle/service/server_manager.h"
|
|
#include "core/loader/loader.h"
|
|
|
|
namespace Service::Account {
|
|
|
|
// Thumbnails are hard coded to be at least this size
|
|
constexpr std::size_t THUMBNAIL_SIZE = 0x24000;
|
|
|
|
static std::filesystem::path GetImagePath(const Common::UUID& uuid) {
|
|
return Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) /
|
|
fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormattedString());
|
|
}
|
|
|
|
static void JPGToMemory(void* context, void* data, int len) {
|
|
std::vector<u8>* jpg_image = static_cast<std::vector<u8>*>(context);
|
|
unsigned char* jpg = static_cast<unsigned char*>(data);
|
|
jpg_image->insert(jpg_image->end(), jpg, jpg + len);
|
|
}
|
|
|
|
static void SanitizeJPEGImageSize(std::vector<u8>& image) {
|
|
constexpr std::size_t max_jpeg_image_size = 0x20000;
|
|
constexpr int profile_dimensions = 256;
|
|
int original_width, original_height, color_channels;
|
|
|
|
const auto plain_image =
|
|
stbi_load_from_memory(image.data(), static_cast<int>(image.size()), &original_width,
|
|
&original_height, &color_channels, STBI_rgb);
|
|
|
|
// Resize image to match 256*256
|
|
if (original_width != profile_dimensions || original_height != profile_dimensions) {
|
|
// Use vector instead of array to avoid overflowing the stack
|
|
std::vector<u8> out_image(profile_dimensions * profile_dimensions * STBI_rgb);
|
|
stbir_resize_uint8_srgb(plain_image, original_width, original_height, 0, out_image.data(),
|
|
profile_dimensions, profile_dimensions, 0, STBI_rgb, 0,
|
|
STBIR_FILTER_BOX);
|
|
image.clear();
|
|
if (!stbi_write_jpg_to_func(JPGToMemory, &image, profile_dimensions, profile_dimensions,
|
|
STBI_rgb, out_image.data(), 0)) {
|
|
LOG_ERROR(Service_ACC, "Failed to resize the user provided image.");
|
|
}
|
|
}
|
|
|
|
image.resize((std::min)(image.size(), max_jpeg_image_size));
|
|
}
|
|
|
|
class IManagerForSystemService final : public ServiceFramework<IManagerForSystemService> {
|
|
public:
|
|
explicit IManagerForSystemService(Core::System& system_, Common::UUID uuid)
|
|
: ServiceFramework{system_, "IManagerForSystemService"}, account_id{uuid} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, D<&IManagerForSystemService::CheckAvailability>, "CheckAvailability"},
|
|
{1, D<&IManagerForSystemService::GetAccountId>, "GetAccountId"},
|
|
{2, nullptr, "EnsureIdTokenCacheAsync"},
|
|
{3, D<&IManagerForSystemService::LoadIdTokenCacheDeprecated>, "LoadIdTokenCacheDeprecated"}, // 19.0.0+
|
|
{4, D<&IManagerForSystemService::LoadIdTokenCache>, "LoadIdTokenCache"}, // 19.0.0+
|
|
{100, nullptr, "SetSystemProgramIdentification"},
|
|
{101, nullptr, "RefreshNotificationTokenAsync"}, // 7.0.0+
|
|
{110, nullptr, "GetServiceEntryRequirementCache"}, // 4.0.0+
|
|
{111, nullptr, "InvalidateServiceEntryRequirementCache"}, // 4.0.0+
|
|
{112, nullptr, "InvalidateTokenCache"}, // 4.0.0 - 6.2.0
|
|
{113, nullptr, "GetServiceEntryRequirementCacheForOnlinePlay"}, // 6.1.0+
|
|
{120, nullptr, "GetNintendoAccountId"},
|
|
{121, nullptr, "CalculateNintendoAccountAuthenticationFingerprint"}, // 9.0.0+
|
|
{130, nullptr, "GetNintendoAccountUserResourceCache"},
|
|
{131, nullptr, "RefreshNintendoAccountUserResourceCacheAsync"},
|
|
{132, nullptr, "RefreshNintendoAccountUserResourceCacheAsyncIfSecondsElapsed"},
|
|
{133, nullptr, "GetNintendoAccountVerificationUrlCache"}, // 9.0.0+
|
|
{134, nullptr, "RefreshNintendoAccountVerificationUrlCache"}, // 9.0.0+
|
|
{135, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsyncIfSecondsElapsed"}, // 9.0.0+
|
|
{136, nullptr, "GetNintendoAccountUserResourceCache"}, // 19.0.0+
|
|
{140, nullptr, "GetNetworkServiceLicenseCache"}, // 5.0.0+
|
|
{141, nullptr, "RefreshNetworkServiceLicenseCacheAsync"}, // 5.0.0+
|
|
{142, nullptr, "RefreshNetworkServiceLicenseCacheAsyncIfSecondsElapsed"}, // 5.0.0+
|
|
{143, D<&IManagerForSystemService::GetNetworkServiceLicenseCacheEx>, "GetNetworkServiceLicenseCacheEx"}, // 15.0.0+
|
|
{150, nullptr, "CreateAuthorizationRequest"},
|
|
{160, nullptr, "RequiresUpdateNetworkServiceAccountIdTokenCache"},
|
|
{161, nullptr, "RequireReauthenticationOfNetworkServiceAccount"},
|
|
{170, nullptr, "CreateDeviceHistoryRequest"}, // 17.0.0+
|
|
{180, nullptr, "GetRequestForNintendoAccountReauthentication"} // 18.0.0+
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
|
|
private:
|
|
Result CheckAvailability() {
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
|
R_SUCCEED();
|
|
}
|
|
|
|
Result GetAccountId(Out<u64> out_account_id) {
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
|
*out_account_id = account_id.Hash();
|
|
R_SUCCEED();
|
|
}
|
|
|
|
Result LoadIdTokenCacheDeprecated() {
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
|
R_SUCCEED();
|
|
}
|
|
|
|
Result LoadIdTokenCache() {
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
|
R_SUCCEED();
|
|
}
|
|
|
|
Result GetNetworkServiceLicenseCacheEx(Out<u32> out_license, Out<s64> out_expiration) {
|
|
LOG_DEBUG(Service_ACC, "(STUBBED) called.");
|
|
|
|
*out_license = 0;
|
|
*out_expiration = 0;
|
|
|
|
R_SUCCEED();
|
|
}
|
|
|
|
Common::UUID account_id;
|
|
};
|
|
|
|
// 3.0.0+
|
|
class IFloatingRegistrationRequest final : public ServiceFramework<IFloatingRegistrationRequest> {
|
|
public:
|
|
explicit IFloatingRegistrationRequest(Core::System& system_, Common::UUID)
|
|
: ServiceFramework{system_, "IFloatingRegistrationRequest"} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "GetSessionId"},
|
|
{12, nullptr, "GetAccountId"},
|
|
{13, nullptr, "GetLinkedNintendoAccountId"},
|
|
{14, nullptr, "GetNickname"},
|
|
{15, nullptr, "GetProfileImage"},
|
|
{16, nullptr, "GetProfileLargeImage"}, // 18.0.0+
|
|
{21, nullptr, "LoadIdTokenCache"},
|
|
{100, nullptr, "RegisterUser"}, // [1.0.0-3.0.2] RegisterAsync
|
|
{101, nullptr, "RegisterUserWithUid"}, // [1.0.0-3.0.2] RegisterWithUidAsync
|
|
{102, nullptr, "RegisterNetworkServiceAccountAsync"}, // 4.0.0+
|
|
{103, nullptr, "RegisterNetworkServiceAccountWithUidAsync"}, // 4.0.0+
|
|
{110, nullptr, "SetSystemProgramIdentification"},
|
|
{111, nullptr, "EnsureIdTokenCacheAsync"},
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
class IAdministrator final : public ServiceFramework<IAdministrator> {
|
|
public:
|
|
explicit IAdministrator(Core::System& system_, Common::UUID)
|
|
: ServiceFramework{system_, "IAdministrator"} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "CheckAvailability"},
|
|
{1, nullptr, "GetAccountId"},
|
|
{2, nullptr, "EnsureIdTokenCacheAsync"},
|
|
{3, nullptr, "LoadIdTokenCache"},
|
|
{100, nullptr, "SetSystemProgramIdentification"},
|
|
{101, nullptr, "RefreshNotificationTokenAsync"}, // 7.0.0+
|
|
{110, nullptr, "GetServiceEntryRequirementCache"}, // 4.0.0+
|
|
{111, nullptr, "InvalidateServiceEntryRequirementCache"}, // 4.0.0+
|
|
{112, nullptr, "InvalidateTokenCache"}, // 4.0.0 - 6.2.0
|
|
{113, nullptr, "GetServiceEntryRequirementCacheForOnlinePlay"}, // 6.1.0+
|
|
{120, nullptr, "GetNintendoAccountId"},
|
|
{121, nullptr, "CalculateNintendoAccountAuthenticationFingerprint"}, // 9.0.0+
|
|
{130, nullptr, "GetNintendoAccountUserResourceCache"},
|
|
{131, nullptr, "RefreshNintendoAccountUserResourceCacheAsync"},
|
|
{132, nullptr, "RefreshNintendoAccountUserResourceCacheAsyncIfSecondsElapsed"},
|
|
{133, nullptr, "GetNintendoAccountVerificationUrlCache"}, // 9.0.0+
|
|
{134, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsync"}, // 9.0.0+
|
|
{135, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsyncIfSecondsElapsed"}, // 9.0.0+
|
|
{140, nullptr, "GetNetworkServiceLicenseCache"}, // 5.0.0+
|
|
{141, nullptr, "RefreshNetworkServiceLicenseCacheAsync"}, // 5.0.0+
|
|
{142, nullptr, "RefreshNetworkServiceLicenseCacheAsyncIfSecondsElapsed"}, // 5.0.0+
|
|
{143, nullptr, "GetNetworkServiceLicenseCacheEx"},
|
|
{150, nullptr, "CreateAuthorizationRequest"},
|
|
{160, nullptr, "RequiresUpdateNetworkServiceAccountIdTokenCache"},
|
|
{161, nullptr, "RequireReauthenticationOfNetworkServiceAccount"},
|
|
{170, nullptr, "CreateDeviceHistoryRequest"}, // 17.0.0+
|
|
{180, nullptr, "GetRequestForNintendoAccountReauthentication"}, // 18.0.0+
|
|
{200, nullptr, "IsRegistered"},
|
|
{201, nullptr, "RegisterAsync"},
|
|
{202, nullptr, "UnregisterAsync"},
|
|
{203, nullptr, "DeleteRegistrationInfoLocally"},
|
|
{220, nullptr, "SynchronizeProfileAsync"},
|
|
{221, nullptr, "UploadProfileAsync"},
|
|
{222, nullptr, "SynchronizaProfileAsyncIfSecondsElapsed"},
|
|
{250, &IAdministrator::IsLinkedWithNintendoAccount, "IsLinkedWithNintendoAccount"},
|
|
{251, nullptr, "CreateProcedureToLinkWithNintendoAccount"},
|
|
{252, nullptr, "ResumeProcedureToLinkWithNintendoAccount"},
|
|
{255, nullptr, "CreateProcedureToUpdateLinkageStateOfNintendoAccount"},
|
|
{256, nullptr, "ResumeProcedureToUpdateLinkageStateOfNintendoAccount"},
|
|
{260, nullptr, "CreateProcedureToLinkNnidWithNintendoAccount"}, // 3.0.0+
|
|
{261, nullptr, "ResumeProcedureToLinkNnidWithNintendoAccount"}, // 3.0.0+
|
|
{280, nullptr, "ProxyProcedureToAcquireApplicationAuthorizationForNintendoAccount"},
|
|
{290, nullptr, "GetRequestForNintendoAccountUserResourceView"}, // 8.0.0+
|
|
{300, nullptr, "TryRecoverNintendoAccountUserStateAsync"}, // 6.0.0+
|
|
{400, nullptr, "IsServiceEntryRequirementCacheRefreshRequiredForOnlinePlay"}, // 6.1.0+
|
|
{401, nullptr, "RefreshServiceEntryRequirementCacheForOnlinePlayAsync"}, // 6.1.0+
|
|
{900, nullptr, "GetAuthenticationInfoForWin"}, // 9.0.0+
|
|
{901, nullptr, "ImportAsyncForWin"}, // 9.0.0+
|
|
{997, nullptr, "DebugUnlinkNintendoAccountAsync"},
|
|
{998, nullptr, "DebugSetAvailabilityErrorDetail"},
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
|
|
private:
|
|
void IsLinkedWithNintendoAccount(HLERequestContext& ctx) {
|
|
IPC::ResponseBuilder rb{ctx, 3};
|
|
rb.Push(ResultSuccess);
|
|
rb.Push(false);
|
|
}
|
|
};
|
|
|
|
class IAuthorizationRequest final : public ServiceFramework<IAuthorizationRequest> {
|
|
public:
|
|
explicit IAuthorizationRequest(Core::System& system_, Common::UUID)
|
|
: ServiceFramework{system_, "IAuthorizationRequest"} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "GetSessionId"},
|
|
{10, nullptr, "InvokeWithoutInteractionAsync"},
|
|
{19, nullptr, "IsAuthorized"},
|
|
{20, nullptr, "GetAuthorizationCode"},
|
|
{21, nullptr, "GetIdToken"},
|
|
{22, nullptr, "GetState"},
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
class IOAuthProcedure final : public ServiceFramework<IOAuthProcedure> {
|
|
public:
|
|
explicit IOAuthProcedure(Core::System& system_, Common::UUID)
|
|
: ServiceFramework{system_, "IOAuthProcedure"} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "PrepareAsync"},
|
|
{1, nullptr, "GetRequest"},
|
|
{2, nullptr, "ApplyResponse"},
|
|
{3, nullptr, "ApplyResponseAsync"},
|
|
{10, nullptr, "Suspend"},
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
// 3.0.0+
|
|
class IOAuthProcedureForExternalNsa final : public ServiceFramework<IOAuthProcedureForExternalNsa> {
|
|
public:
|
|
explicit IOAuthProcedureForExternalNsa(Core::System& system_, Common::UUID)
|
|
: ServiceFramework{system_, "IOAuthProcedureForExternalNsa"} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "PrepareAsync"},
|
|
{1, nullptr, "GetRequest"},
|
|
{2, nullptr, "ApplyResponse"},
|
|
{3, nullptr, "ApplyResponseAsync"},
|
|
{10, nullptr, "Suspend"},
|
|
{100, nullptr, "GetAccountId"},
|
|
{101, nullptr, "GetLinkedNintendoAccountId"},
|
|
{102, nullptr, "GetNickname"},
|
|
{103, nullptr, "GetProfileImage"},
|
|
{104, nullptr, "GetProfileLargeImage"} // 18.0.0+
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
class IOAuthProcedureForNintendoAccountLinkage final
|
|
: public ServiceFramework<IOAuthProcedureForNintendoAccountLinkage> {
|
|
public:
|
|
explicit IOAuthProcedureForNintendoAccountLinkage(Core::System& system_, Common::UUID)
|
|
: ServiceFramework{system_, "IOAuthProcedureForNintendoAccountLinkage"} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "PrepareAsync"},
|
|
{1, nullptr, "GetRequest"},
|
|
{2, nullptr, "ApplyResponse"},
|
|
{3, nullptr, "ApplyResponseAsync"},
|
|
{10, nullptr, "Suspend"},
|
|
{100, nullptr, "GetRequestWithTheme"},
|
|
{101, nullptr, "IsNetworkServiceAccountReplaced"},
|
|
{199, nullptr, "GetUrlForIntroductionOfExtraMembership"}, // 2.0.0 - 5.1.0
|
|
{200, nullptr, "ApplyAsyncWithAuthorizedToken"},
|
|
{210, nullptr, "IsProfileAvailable"}, // 17.0.0+
|
|
{220, nullptr, "RegisterUserAsyncWithoutProfile"}, // 17.0.0+
|
|
{221, nullptr, "RegisterUserWithProfileAsync"}, // 17.0.0+
|
|
{230, nullptr, "RegisterUserWithLargeImageProfileAsync"}, // 18.0.0+
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
class INotifier final : public ServiceFramework<INotifier> {
|
|
public:
|
|
explicit INotifier(Core::System& system_, Common::UUID)
|
|
: ServiceFramework{system_, "INotifier"} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "GetSystemEvent"},
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
class IProfileCommon : public ServiceFramework<IProfileCommon> {
|
|
public:
|
|
explicit IProfileCommon(Core::System& system_, const char* name, bool editor_commands,
|
|
Common::UUID user_id_, ProfileManager& profile_manager_)
|
|
: ServiceFramework{system_, name}, profile_manager{profile_manager_}, user_id{user_id_} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, &IProfileCommon::Get, "Get"},
|
|
{1, &IProfileCommon::GetBase, "GetBase"},
|
|
{10, &IProfileCommon::GetImageSize, "GetImageSize"},
|
|
{11, &IProfileCommon::LoadImage, "LoadImage"},
|
|
{20, &IProfileCommon::Unknown20, "Unknown20"},
|
|
{21, &IProfileCommon::Unknown21, "Unknown21"},
|
|
{30, &IProfileCommon::Unknown30, "Unknown30"}
|
|
};
|
|
// clang-format on
|
|
RegisterHandlers(functions);
|
|
|
|
if (editor_commands) {
|
|
// clang-format off
|
|
static const FunctionInfo editor_functions[] = {
|
|
{100, &IProfileCommon::Store, "Store"},
|
|
{101, &IProfileCommon::StoreWithImage, "StoreWithImage"},
|
|
{110, &IProfileCommon::Unknown110, "Unknown110"}
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(editor_functions);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
void Unknown20(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "(STUBBED) called.");
|
|
|
|
// TODO (jarrodnorwell)
|
|
// inbytes: 0x0, outbytes: 0x4
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void Unknown21(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "(STUBBED) called.");
|
|
|
|
// TODO (jarrodnorwell)
|
|
// buffers: [0x6], inbytes: 0x0, outbytes: 0x4
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void Unknown30(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "(STUBBED) called.");
|
|
|
|
// TODO (jarrodnorwell)
|
|
// inbytes: 0x0, outbytes: 0x10
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void Unknown110(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "(STUBBED) called.");
|
|
|
|
// TODO (jarrodnorwell)
|
|
// buffer_entry_sizes: [0x80, 0x0], buffers: [0x19, 0x5], inbytes: 0x38, outbytes: 0x0
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void Get(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
|
|
ProfileBase profile_base{};
|
|
UserData data{};
|
|
if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
|
|
ctx.WriteBuffer(data);
|
|
IPC::ResponseBuilder rb{ctx, 16};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushRaw(profile_base);
|
|
} else {
|
|
LOG_ERROR(Service_ACC, "Failed to get profile base and data for user=0x{}",
|
|
user_id.RawString());
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code
|
|
}
|
|
}
|
|
|
|
void GetBase(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
|
|
ProfileBase profile_base{};
|
|
if (profile_manager.GetProfileBase(user_id, profile_base)) {
|
|
IPC::ResponseBuilder rb{ctx, 16};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushRaw(profile_base);
|
|
} else {
|
|
LOG_ERROR(Service_ACC, "Failed to get profile base for user=0x{}", user_id.RawString());
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code
|
|
}
|
|
}
|
|
|
|
void LoadImage(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called");
|
|
|
|
IPC::ResponseBuilder rb{ctx, 3};
|
|
rb.Push(ResultSuccess);
|
|
|
|
const Common::FS::IOFile image(GetImagePath(user_id), Common::FS::FileAccessMode::Read,
|
|
Common::FS::FileType::BinaryFile);
|
|
if (!image.IsOpen()) {
|
|
LOG_WARNING(Service_ACC,
|
|
"Failed to load user provided image! Falling back to built-in backup...");
|
|
ctx.WriteBuffer(Core::Constants::ACCOUNT_BACKUP_JPEG);
|
|
rb.Push(static_cast<u32>(Core::Constants::ACCOUNT_BACKUP_JPEG.size()));
|
|
return;
|
|
}
|
|
|
|
std::vector<u8> buffer(image.GetSize());
|
|
|
|
if (image.Read(buffer) != buffer.size()) {
|
|
LOG_ERROR(Service_ACC, "Failed to read all the bytes in the user provided image.");
|
|
}
|
|
|
|
SanitizeJPEGImageSize(buffer);
|
|
|
|
ctx.WriteBuffer(buffer);
|
|
rb.Push(static_cast<u32>(buffer.size()));
|
|
}
|
|
|
|
void GetImageSize(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called");
|
|
IPC::ResponseBuilder rb{ctx, 3};
|
|
rb.Push(ResultSuccess);
|
|
|
|
const Common::FS::IOFile image(GetImagePath(user_id), Common::FS::FileAccessMode::Read,
|
|
Common::FS::FileType::BinaryFile);
|
|
|
|
if (!image.IsOpen()) {
|
|
LOG_WARNING(Service_ACC,
|
|
"Failed to load user provided image! Falling back to built-in backup...");
|
|
rb.Push(static_cast<u32>(Core::Constants::ACCOUNT_BACKUP_JPEG.size()));
|
|
return;
|
|
}
|
|
|
|
std::vector<u8> buffer(image.GetSize());
|
|
|
|
if (image.Read(buffer) != buffer.size()) {
|
|
LOG_ERROR(Service_ACC, "Failed to read all the bytes in the user provided image.");
|
|
}
|
|
|
|
SanitizeJPEGImageSize(buffer);
|
|
rb.Push(static_cast<u32>(buffer.size()));
|
|
}
|
|
|
|
void LoadIdTokenCache(HLERequestContext& ctx) {
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
|
|
|
std::vector<u8> token_data(0x100);
|
|
std::fill(token_data.begin(), token_data.end(), u8(0));
|
|
|
|
(void)ctx.WriteBuffer(token_data);
|
|
|
|
IPC::ResponseBuilder rb{ctx, 3};
|
|
rb.Push(ResultSuccess);
|
|
rb.Push(static_cast<u32>(token_data.size()));
|
|
}
|
|
|
|
void GetNintendoAccountUserResourceCacheForApplication(HLERequestContext& ctx) {
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
|
|
|
std::vector<u8> nas_user_base_for_application(0x68);
|
|
(void)ctx.WriteBuffer(nas_user_base_for_application);
|
|
|
|
if (ctx.CanWriteBuffer(1)) {
|
|
std::vector<u8> unknown_out_buffer(ctx.GetWriteBufferSize(1));
|
|
(void)ctx.WriteBuffer(unknown_out_buffer, 1);
|
|
}
|
|
|
|
IPC::ResponseBuilder rb{ctx, 4};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushRaw<u64>(profile_manager.GetLastOpenedUser().Hash());
|
|
}
|
|
|
|
void Store(HLERequestContext& ctx) {
|
|
IPC::RequestParser rp{ctx};
|
|
const auto base = rp.PopRaw<ProfileBase>();
|
|
|
|
const auto user_data = ctx.ReadBuffer();
|
|
|
|
LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}",
|
|
Common::StringFromFixedZeroTerminatedBuffer(
|
|
reinterpret_cast<const char*>(base.username.data()), base.username.size()),
|
|
base.timestamp, base.user_uuid.RawString());
|
|
|
|
if (user_data.size() < sizeof(UserData)) {
|
|
LOG_ERROR(Service_ACC, "UserData buffer too small!");
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(Account::ResultInvalidArrayLength);
|
|
return;
|
|
}
|
|
|
|
UserData data;
|
|
std::memcpy(&data, user_data.data(), sizeof(UserData));
|
|
|
|
if (!profile_manager.SetProfileBaseAndData(user_id, base, data)) {
|
|
LOG_ERROR(Service_ACC, "Failed to update user data and base!");
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(Account::ResultAccountUpdateFailed);
|
|
return;
|
|
}
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void StoreWithImage(HLERequestContext& ctx) {
|
|
IPC::RequestParser rp{ctx};
|
|
const auto base = rp.PopRaw<ProfileBase>();
|
|
|
|
const auto image_data = ctx.ReadBufferA(0);
|
|
const auto user_data = ctx.ReadBufferX(0);
|
|
|
|
LOG_INFO(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}",
|
|
Common::StringFromFixedZeroTerminatedBuffer(
|
|
reinterpret_cast<const char*>(base.username.data()), base.username.size()),
|
|
base.timestamp, base.user_uuid.RawString());
|
|
|
|
if (user_data.size() < sizeof(UserData)) {
|
|
LOG_ERROR(Service_ACC, "UserData buffer too small!");
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(Account::ResultInvalidArrayLength);
|
|
return;
|
|
}
|
|
|
|
UserData data;
|
|
std::memcpy(&data, user_data.data(), sizeof(UserData));
|
|
|
|
Common::FS::IOFile image(GetImagePath(user_id), Common::FS::FileAccessMode::Write,
|
|
Common::FS::FileType::BinaryFile);
|
|
|
|
if (!image.IsOpen() || !image.SetSize(image_data.size()) ||
|
|
image.Write(image_data) != image_data.size() ||
|
|
!profile_manager.SetProfileBaseAndData(user_id, base, data)) {
|
|
LOG_ERROR(Service_ACC, "Failed to update profile data, base, and image!");
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(Account::ResultAccountUpdateFailed);
|
|
return;
|
|
}
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
ProfileManager& profile_manager;
|
|
Common::UUID user_id{}; ///< The user id this profile refers to.
|
|
};
|
|
|
|
class IProfile final : public IProfileCommon {
|
|
public:
|
|
explicit IProfile(Core::System& system_, Common::UUID user_id_,
|
|
ProfileManager& profile_manager_)
|
|
: IProfileCommon{system_, "IProfile", false, user_id_, profile_manager_} {}
|
|
};
|
|
|
|
class IProfileEditor final : public IProfileCommon {
|
|
public:
|
|
explicit IProfileEditor(Core::System& system_, Common::UUID user_id_,
|
|
ProfileManager& profile_manager_)
|
|
: IProfileCommon{system_, "IProfileEditor", true, user_id_, profile_manager_} {}
|
|
};
|
|
|
|
class ISessionObject final : public ServiceFramework<ISessionObject> {
|
|
public:
|
|
explicit ISessionObject(Core::System& system_, Common::UUID)
|
|
: ServiceFramework{system_, "ISessionObject"} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{999, nullptr, "Dummy"},
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
class IGuestLoginRequest final : public ServiceFramework<IGuestLoginRequest> {
|
|
public:
|
|
explicit IGuestLoginRequest(Core::System& system_, Common::UUID)
|
|
: ServiceFramework{system_, "IGuestLoginRequest"} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "GetSessionId"},
|
|
{11, nullptr, "Unknown"}, // 1.0.0 - 2.3.0 (the name is blank on Switchbrew)
|
|
{12, nullptr, "GetAccountId"},
|
|
{13, nullptr, "GetLinkedNintendoAccountId"},
|
|
{14, nullptr, "GetNickname"},
|
|
{15, nullptr, "GetProfileImage"},
|
|
{16, nullptr, "GetProfileLargeImage"}, // 18.0.0+
|
|
{21, nullptr, "LoadIdTokenCache"}, // 3.0.0+
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
class EnsureTokenIdCacheAsyncInterface final : public IAsyncContext {
|
|
public:
|
|
explicit EnsureTokenIdCacheAsyncInterface(Core::System& system_) : IAsyncContext{system_} {
|
|
MarkComplete();
|
|
}
|
|
~EnsureTokenIdCacheAsyncInterface() = default;
|
|
|
|
void LoadIdTokenCache(HLERequestContext& ctx) {
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
|
|
|
IPC::ResponseBuilder rb{ctx, 3};
|
|
rb.Push(ResultSuccess);
|
|
rb.Push(0);
|
|
}
|
|
|
|
protected:
|
|
bool IsComplete() const override {
|
|
return true;
|
|
}
|
|
|
|
void Cancel() override {}
|
|
|
|
Result GetResult() const override {
|
|
return ResultSuccess;
|
|
}
|
|
};
|
|
|
|
class IManagerForApplication final : public ServiceFramework<IManagerForApplication> {
|
|
public:
|
|
explicit IManagerForApplication(Core::System& system_,
|
|
const std::shared_ptr<ProfileManager>& profile_manager_)
|
|
: ServiceFramework{system_, "IManagerForApplication"},
|
|
ensure_token_id{std::make_shared<EnsureTokenIdCacheAsyncInterface>(system)},
|
|
profile_manager{profile_manager_} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, &IManagerForApplication::CheckAvailability, "CheckAvailability"},
|
|
{1, &IManagerForApplication::GetAccountId, "GetAccountId"},
|
|
{2, &IManagerForApplication::EnsureIdTokenCacheAsync, "EnsureIdTokenCacheAsync"},
|
|
{3, &IManagerForApplication::LoadIdTokenCacheDeprecated, "LoadIdTokenCacheDeprecated"},
|
|
{4, &IManagerForApplication::LoadIdTokenCache, "LoadIdTokenCache"},
|
|
{130, &IManagerForApplication::GetNintendoAccountUserResourceCacheForApplication, "GetNintendoAccountUserResourceCacheForApplication"},
|
|
{136, &IManagerForApplication::GetNintendoAccountUserResourceCacheForApplication, "GetNintendoAccountUserResourceCache"}, // 19.0.0+
|
|
{150, nullptr, "CreateAuthorizationRequest"},
|
|
{160, &IManagerForApplication::StoreOpenContext, "StoreOpenContext"},
|
|
{170, nullptr, "LoadNetworkServiceLicenseKindAsync"},
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
|
|
private:
|
|
void CheckAvailability(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "(STUBBED) called");
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void GetAccountId(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called");
|
|
|
|
IPC::ResponseBuilder rb{ctx, 4};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushRaw<u64>(profile_manager->GetLastOpenedUser().Hash());
|
|
}
|
|
|
|
void EnsureIdTokenCacheAsync(HLERequestContext& ctx) {
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushIpcInterface(ctx, ensure_token_id);
|
|
}
|
|
|
|
void LoadIdTokenCacheDeprecated(HLERequestContext& ctx) {
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
|
|
|
ensure_token_id->LoadIdTokenCache(ctx);
|
|
}
|
|
|
|
void LoadIdTokenCache(HLERequestContext& ctx) {
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
|
|
|
std::vector<u8> token_data(0x100);
|
|
std::fill(token_data.begin(), token_data.end(), u8(0));
|
|
|
|
ctx.WriteBuffer(token_data);
|
|
|
|
IPC::ResponseBuilder rb{ctx, 3};
|
|
rb.Push(ResultSuccess);
|
|
rb.Push(static_cast<u32>(token_data.size()));
|
|
}
|
|
|
|
void GetNintendoAccountUserResourceCacheForApplication(HLERequestContext& ctx) {
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
|
|
|
std::vector<u8> nas_user_base_for_application(0x68);
|
|
ctx.WriteBuffer(nas_user_base_for_application);
|
|
|
|
if (ctx.CanWriteBuffer(1)) {
|
|
std::vector<u8> unknown_out_buffer(ctx.GetWriteBufferSize(1));
|
|
ctx.WriteBuffer(unknown_out_buffer, 1);
|
|
}
|
|
|
|
IPC::ResponseBuilder rb{ctx, 4};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushRaw<u64>(profile_manager->GetLastOpenedUser().Hash());
|
|
}
|
|
|
|
void StoreOpenContext(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called");
|
|
|
|
profile_manager->StoreOpenedUsers();
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
std::shared_ptr<EnsureTokenIdCacheAsyncInterface> ensure_token_id{};
|
|
std::shared_ptr<ProfileManager> profile_manager;
|
|
};
|
|
|
|
// 6.0.0+
|
|
class IAsyncNetworkServiceLicenseKindContext final
|
|
: public ServiceFramework<IAsyncNetworkServiceLicenseKindContext> {
|
|
public:
|
|
explicit IAsyncNetworkServiceLicenseKindContext(Core::System& system_, Common::UUID)
|
|
: ServiceFramework{system_, "IAsyncNetworkServiceLicenseKindContext"} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "GetSystemEvent"},
|
|
{1, nullptr, "Cancel"},
|
|
{2, nullptr, "HasDone"},
|
|
{3, nullptr, "GetResult"},
|
|
{4, nullptr, "GetNetworkServiceLicenseKind"},
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
// 8.0.0+
|
|
class IOAuthProcedureForUserRegistration final
|
|
: public ServiceFramework<IOAuthProcedureForUserRegistration> {
|
|
public:
|
|
explicit IOAuthProcedureForUserRegistration(Core::System& system_, Common::UUID)
|
|
: ServiceFramework{system_, "IOAuthProcedureForUserRegistration"} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "PrepareAsync"},
|
|
{1, nullptr, "GetRequest"},
|
|
{2, nullptr, "ApplyResponse"},
|
|
{3, nullptr, "ApplyResponseAsync"},
|
|
{10, nullptr, "Suspend"},
|
|
{100, nullptr, "GetAccountId"},
|
|
{101, nullptr, "GetLinkedNintendoAccountId"},
|
|
{102, nullptr, "GetNickname"},
|
|
{103, nullptr, "GetProfileImage"},
|
|
{104, nullptr, "GetProfileLargeImage"}, // 18.0.0+
|
|
{110, nullptr, "RegisterUserAsync"},
|
|
{111, nullptr, "GetUid"},
|
|
{200, nullptr, "ApplyResponseForUserCreationAsync"}, // 17.0.0+
|
|
{205, nullptr, "SuspendAfterApplyResponse"}, // 17.0.0+
|
|
{210, nullptr, "IsProfileAvailable"}, // 17.0.0+
|
|
{220, nullptr, "RegisterUserAsyncWithoutProfile"}, // 17.0.0+
|
|
{221, nullptr, "RegisterUserWithProfileAsync"}, // 17.0.0+
|
|
{230, nullptr, "RegisterUserWithLargeImageProfileAsync"} // 18.0.0+
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
class DAUTH_O final : public ServiceFramework<DAUTH_O> {
|
|
public:
|
|
explicit DAUTH_O(Core::System& system_, Common::UUID) : ServiceFramework{system_, "dauth:o"} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "EnsureAuthenticationTokenCacheAsync"},
|
|
{1, nullptr, "LoadAuthenticationTokenCache"},
|
|
{2, nullptr, "InvalidateAuthenticationTokenCache"},
|
|
{3, nullptr, "IsDeviceAuthenticationTokenCacheAvailable"},
|
|
{10, nullptr, "EnsureEdgeTokenCacheAsync"},
|
|
{11, nullptr, "LoadEdgeTokenCache"},
|
|
{12, nullptr, "InvalidateEdgeTokenCache"},
|
|
{13, nullptr, "IsEdgeTokenCacheAvailable"},
|
|
{20, nullptr, "EnsureApplicationAuthenticationCacheAsync"},
|
|
{21, nullptr, "LoadApplicationAuthenticationTokenCache"},
|
|
{22, nullptr, "LoadApplicationNetworkServiceClientConfigCache"},
|
|
{23, nullptr, "IsApplicationAuthenticationCacheAvailable"},
|
|
{24, nullptr, "InvalidateApplicationAuthenticationCache"},
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
// 6.0.0+
|
|
class IAsyncResult final : public ServiceFramework<IAsyncResult> {
|
|
public:
|
|
explicit IAsyncResult(Core::System& system_, Common::UUID)
|
|
: ServiceFramework{system_, "IAsyncResult"} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "GetResult"},
|
|
{1, nullptr, "Cancel"},
|
|
{2, nullptr, "IsAvailable"},
|
|
{3, nullptr, "GetSystemEvent"},
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
void Module::Interface::GetUserCount(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called");
|
|
IPC::ResponseBuilder rb{ctx, 3};
|
|
rb.Push(ResultSuccess);
|
|
rb.Push<u32>(static_cast<u32>(profile_manager->GetUserCount()));
|
|
}
|
|
|
|
void Module::Interface::GetUserExistence(HLERequestContext& ctx) {
|
|
IPC::RequestParser rp{ctx};
|
|
Common::UUID user_id = rp.PopRaw<Common::UUID>();
|
|
LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
|
|
|
|
IPC::ResponseBuilder rb{ctx, 3};
|
|
rb.Push(ResultSuccess);
|
|
rb.Push(profile_manager->UserExists(user_id));
|
|
}
|
|
|
|
void Module::Interface::ListAllUsers(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called");
|
|
ctx.WriteBuffer(profile_manager->GetAllUsers());
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void Module::Interface::ListOpenUsers(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called");
|
|
ctx.WriteBuffer(profile_manager->GetOpenUsers());
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void Module::Interface::GetLastOpenedUser(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called");
|
|
IPC::ResponseBuilder rb{ctx, 6};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushRaw<Common::UUID>(profile_manager->GetLastOpenedUser());
|
|
}
|
|
|
|
void Module::Interface::GetProfile(HLERequestContext& ctx) {
|
|
IPC::RequestParser rp{ctx};
|
|
Common::UUID user_id = rp.PopRaw<Common::UUID>();
|
|
LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushIpcInterface<IProfile>(ctx, system, user_id, *profile_manager);
|
|
}
|
|
|
|
void Module::Interface::IsUserRegistrationRequestPermitted(HLERequestContext& ctx) {
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
|
IPC::ResponseBuilder rb{ctx, 3};
|
|
rb.Push(ResultSuccess);
|
|
rb.Push(profile_manager->CanSystemRegisterUser());
|
|
}
|
|
|
|
void Module::Interface::InitializeApplicationInfo(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called");
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(InitializeApplicationInfoBase());
|
|
}
|
|
|
|
void Module::Interface::InitializeApplicationInfoRestricted(HLERequestContext& ctx) {
|
|
LOG_WARNING(Service_ACC, "(Partial implementation) called");
|
|
|
|
// TODO(ogniK): We require checking if the user actually owns the title and what not. As of
|
|
// currently, we assume the user owns the title. InitializeApplicationInfoBase SHOULD be called
|
|
// first then we do extra checks if the game is a digital copy.
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(InitializeApplicationInfoBase());
|
|
}
|
|
|
|
Result Module::Interface::InitializeApplicationInfoBase() {
|
|
if (application_info) {
|
|
LOG_ERROR(Service_ACC, "Application already initialized");
|
|
return Account::ResultApplicationInfoAlreadyInitialized;
|
|
}
|
|
|
|
// TODO(ogniK): This should be changed to reflect the target process for when we have multiple
|
|
// processes emulated. As we don't actually have pid support we should assume we're just using
|
|
// our own process
|
|
Glue::ApplicationLaunchProperty launch_property{};
|
|
const auto result = system.GetARPManager().GetLaunchProperty(
|
|
&launch_property, system.GetApplicationProcessProgramID());
|
|
|
|
if (result != ResultSuccess) {
|
|
LOG_ERROR(Service_ACC, "Failed to get launch property");
|
|
return Account::ResultInvalidApplication;
|
|
}
|
|
|
|
switch (launch_property.base_game_storage_id) {
|
|
case FileSys::StorageId::GameCard:
|
|
application_info.application_type = ApplicationType::GameCard;
|
|
break;
|
|
case FileSys::StorageId::Host:
|
|
case FileSys::StorageId::NandSystem:
|
|
case FileSys::StorageId::NandUser:
|
|
case FileSys::StorageId::SdCard:
|
|
case FileSys::StorageId::None: // Yuzu specific, differs from hardware
|
|
application_info.application_type = ApplicationType::Digital;
|
|
break;
|
|
default:
|
|
LOG_ERROR(Service_ACC, "Invalid game storage ID! storage_id={}",
|
|
launch_property.base_game_storage_id);
|
|
return Account::ResultInvalidApplication;
|
|
}
|
|
|
|
LOG_WARNING(Service_ACC, "ApplicationInfo init required");
|
|
// TODO(ogniK): Actual initialization here
|
|
|
|
return ResultSuccess;
|
|
}
|
|
|
|
void Module::Interface::GetBaasAccountManagerForApplication(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called");
|
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushIpcInterface<IManagerForApplication>(ctx, system, profile_manager);
|
|
}
|
|
|
|
void Module::Interface::IsUserAccountSwitchLocked(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called");
|
|
FileSys::NACP nacp;
|
|
const auto res = system.GetAppLoader().ReadControlData(nacp);
|
|
|
|
bool is_locked = false;
|
|
|
|
if (res != Loader::ResultStatus::Success) {
|
|
const FileSys::PatchManager pm{system.GetApplicationProcessProgramID(),
|
|
system.GetFileSystemController(),
|
|
system.GetContentProvider()};
|
|
const auto nacp_unique = pm.GetControlMetadata().first;
|
|
|
|
if (nacp_unique != nullptr) {
|
|
is_locked = nacp_unique->GetUserAccountSwitchLock();
|
|
} else {
|
|
LOG_ERROR(Service_ACC, "nacp_unique is null!");
|
|
}
|
|
} else {
|
|
is_locked = nacp.GetUserAccountSwitchLock();
|
|
}
|
|
|
|
IPC::ResponseBuilder rb{ctx, 3};
|
|
rb.Push(ResultSuccess);
|
|
rb.Push(is_locked);
|
|
}
|
|
|
|
void Module::Interface::InitializeApplicationInfoV2(HLERequestContext& ctx) {
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void Module::Interface::BeginUserRegistration(HLERequestContext& ctx) {
|
|
const auto user_id = Common::UUID::MakeRandom();
|
|
profile_manager->CreateNewUser(user_id, "Eden");
|
|
|
|
LOG_INFO(Service_ACC, "called, uuid={}", user_id.FormattedString());
|
|
|
|
IPC::ResponseBuilder rb{ctx, 6};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushRaw(user_id);
|
|
}
|
|
|
|
void Module::Interface::CompleteUserRegistration(HLERequestContext& ctx) {
|
|
IPC::RequestParser rp{ctx};
|
|
Common::UUID user_id = rp.PopRaw<Common::UUID>();
|
|
|
|
LOG_INFO(Service_ACC, "called, uuid={}", user_id.FormattedString());
|
|
|
|
profile_manager->WriteUserSaveFile();
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void Module::Interface::DeleteUser(HLERequestContext& ctx) {
|
|
IPC::RequestParser rp{ctx};
|
|
Common::UUID user_id = rp.PopRaw<Common::UUID>();
|
|
LOG_INFO(Service_ACC, "called, uuid={}", user_id.FormattedString());
|
|
if (!profile_manager->RemoveUser(user_id)) {
|
|
LOG_ERROR(Service_ACC, "Failed to delete user with uuid={}", user_id.RawString());
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(1U);
|
|
return;
|
|
}
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void Module::Interface::SetUserPosition(HLERequestContext& ctx) {
|
|
IPC::RequestParser rp{ctx};
|
|
|
|
u64 position = rp.Pop<u64>();
|
|
Common::UUID user_id = rp.PopRaw<Common::UUID>();
|
|
|
|
LOG_DEBUG(Service_ACC, "called, position={} user_id={}", position, user_id.FormattedString());
|
|
|
|
profile_manager->SetUserPosition(position, user_id);
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void Module::Interface::GetProfileEditor(HLERequestContext& ctx) {
|
|
IPC::RequestParser rp{ctx};
|
|
Common::UUID user_id = rp.PopRaw<Common::UUID>();
|
|
|
|
LOG_DEBUG(Service_ACC, "called, user_id=0x{}", user_id.RawString());
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushIpcInterface<IProfileEditor>(ctx, system, user_id, *profile_manager);
|
|
}
|
|
|
|
void Module::Interface::GetBaasAccountAdministrator(HLERequestContext &ctx) {
|
|
IPC::RequestParser rp{ctx};
|
|
const auto uuid = rp.PopRaw<Common::UUID>();
|
|
|
|
LOG_INFO(Service_ACC, "called, uuid=0x{}", uuid.RawString());
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushIpcInterface<IAdministrator>(ctx, system, uuid);
|
|
}
|
|
|
|
void Module::Interface::ListQualifiedUsers(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called");
|
|
|
|
// All users should be qualified. We don't actually have parental control or anything to do with
|
|
// nintendo online currently. We're just going to assume the user running the game has access to
|
|
// the game regardless of parental control settings.
|
|
ctx.WriteBuffer(profile_manager->GetAllUsers());
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void Module::Interface::ListOpenContextStoredUsers(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called");
|
|
|
|
ctx.WriteBuffer(profile_manager->GetStoredOpenedUsers());
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void Module::Interface::StoreSaveDataThumbnailApplication(HLERequestContext& ctx) {
|
|
IPC::RequestParser rp{ctx};
|
|
const auto uuid = rp.PopRaw<Common::UUID>();
|
|
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}", uuid.RawString());
|
|
|
|
// TODO(ogniK): Check if application ID is zero on acc initialize. As we don't have a reliable
|
|
// way of confirming things like the TID, we're going to assume a non zero value for the time
|
|
// being.
|
|
constexpr u64 tid{1};
|
|
StoreSaveDataThumbnail(ctx, uuid, tid);
|
|
}
|
|
|
|
void Module::Interface::GetBaasAccountManagerForSystemService(HLERequestContext& ctx) {
|
|
IPC::RequestParser rp{ctx};
|
|
const auto uuid = rp.PopRaw<Common::UUID>();
|
|
|
|
LOG_INFO(Service_ACC, "called, uuid=0x{}", uuid.RawString());
|
|
|
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
|
rb.Push(ResultSuccess);
|
|
rb.PushIpcInterface<IManagerForSystemService>(ctx, system, uuid);
|
|
}
|
|
|
|
void Module::Interface::StoreSaveDataThumbnailSystem(HLERequestContext& ctx) {
|
|
IPC::RequestParser rp{ctx};
|
|
const auto uuid = rp.PopRaw<Common::UUID>();
|
|
const auto tid = rp.Pop<u64_le>();
|
|
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}, tid={:016X}", uuid.RawString(), tid);
|
|
StoreSaveDataThumbnail(ctx, uuid, tid);
|
|
}
|
|
|
|
void Module::Interface::GetPinCodeLength(HLERequestContext& ctx) {
|
|
LOG_WARNING(Service_ACC, "(STUBBED) called");
|
|
|
|
IPC::ResponseBuilder rb{ctx, 3};
|
|
rb.Push(ResultSuccess);
|
|
rb.Push<u32>(0);
|
|
}
|
|
|
|
void Module::Interface::StoreSaveDataThumbnail(HLERequestContext& ctx, const Common::UUID& uuid,
|
|
const u64 tid) {
|
|
IPC::ResponseBuilder rb{ctx, 2};
|
|
|
|
if (tid == 0) {
|
|
LOG_ERROR(Service_ACC, "TitleID is not valid!");
|
|
rb.Push(Account::ResultInvalidApplication);
|
|
return;
|
|
}
|
|
|
|
if (uuid.IsInvalid()) {
|
|
LOG_ERROR(Service_ACC, "User ID is not valid!");
|
|
rb.Push(Account::ResultInvalidUserId);
|
|
return;
|
|
}
|
|
const auto thumbnail_size = ctx.GetReadBufferSize();
|
|
if (thumbnail_size != THUMBNAIL_SIZE) {
|
|
LOG_ERROR(Service_ACC, "Buffer size is empty! size={:X} expecting {:X}", thumbnail_size,
|
|
THUMBNAIL_SIZE);
|
|
rb.Push(Account::ResultInvalidArrayLength);
|
|
return;
|
|
}
|
|
|
|
// TODO(ogniK): Construct save data thumbnail
|
|
rb.Push(ResultSuccess);
|
|
}
|
|
|
|
void Module::Interface::TrySelectUserWithoutInteractionDeprecated(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called");
|
|
// A u8 is passed into this function which we can safely ignore. It's to determine if we have
|
|
// access to use the network or not by the looks of it
|
|
IPC::ResponseBuilder rb{ctx, 6};
|
|
if (profile_manager->GetUserCount() != 1) {
|
|
rb.Push(ResultSuccess);
|
|
rb.PushRaw(Common::InvalidUUID);
|
|
return;
|
|
}
|
|
|
|
const auto user_list = profile_manager->GetAllUsers();
|
|
if (std::ranges::all_of(user_list, [](const auto& user) { return user.IsInvalid(); })) {
|
|
rb.Push(ResultUnknown); // TODO(ogniK): Find the correct error code
|
|
rb.PushRaw(Common::InvalidUUID);
|
|
return;
|
|
}
|
|
|
|
// Select the first user we have
|
|
rb.Push(ResultSuccess);
|
|
rb.PushRaw(profile_manager->GetUser(0)->uuid);
|
|
}
|
|
|
|
void Module::Interface::TrySelectUserWithoutInteraction(HLERequestContext& ctx) {
|
|
LOG_DEBUG(Service_ACC, "called");
|
|
// A u8 is passed into this function which we can safely ignore. It's to determine if we have
|
|
// access to use the network or not by the looks of it
|
|
IPC::ResponseBuilder rb{ctx, 6};
|
|
if (profile_manager->GetUserCount() != 1) {
|
|
rb.Push(ResultSuccess);
|
|
rb.PushRaw(Common::InvalidUUID);
|
|
return;
|
|
}
|
|
|
|
const auto user_list = profile_manager->GetAllUsers();
|
|
if (std::ranges::all_of(user_list, [](const auto& user) { return user.IsInvalid(); })) {
|
|
rb.Push(ResultUnknown); // TODO(ogniK): Find the correct error code
|
|
rb.PushRaw(Common::InvalidUUID);
|
|
return;
|
|
}
|
|
|
|
// Select the first user we have
|
|
rb.Push(ResultSuccess);
|
|
rb.PushRaw(profile_manager->GetUser(0)->uuid);
|
|
}
|
|
|
|
Module::Interface::Interface(std::shared_ptr<Module> module_,
|
|
std::shared_ptr<ProfileManager> profile_manager_,
|
|
Core::System& system_, const char* name)
|
|
: ServiceFramework{system_, name}, module{std::move(module_)},
|
|
profile_manager{std::move(profile_manager_)} {}
|
|
|
|
Module::Interface::~Interface() = default;
|
|
|
|
class ACC_AA final : public Module::Interface {
|
|
public:
|
|
explicit ACC_AA(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_)
|
|
: Interface(std::move(module_), std::move(profile_manager_), system_, "acc:aa") {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "EnsureCacheAsync"},
|
|
{1, nullptr, "LoadCache"},
|
|
{2, nullptr, "GetDeviceAccountId"},
|
|
{50, nullptr, "RegisterNotificationTokenAsync"}, // 1.0.0 - 6.2.0
|
|
{51, nullptr, "UnregisterNotificationTokenAsync"}, // 1.0.0 - 6.2.0
|
|
};
|
|
// clang-format on
|
|
RegisterHandlers(functions);
|
|
}
|
|
~ACC_AA() override = default;
|
|
};
|
|
|
|
class ACC_SU final : public Module::Interface {
|
|
public:
|
|
explicit ACC_SU(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_)
|
|
: Interface(std::move(module_), std::move(profile_manager_), system_, "acc:su") {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, &ACC_SU::GetUserCount, "GetUserCount"},
|
|
{1, &ACC_SU::GetUserExistence, "GetUserExistence"},
|
|
{2, &ACC_SU::ListAllUsers, "ListAllUsers"},
|
|
{3, &ACC_SU::ListOpenUsers, "ListOpenUsers"},
|
|
{4, &ACC_SU::GetLastOpenedUser, "GetLastOpenedUser"},
|
|
{5, &ACC_SU::GetProfile, "GetProfile"},
|
|
{6, nullptr, "GetProfileDigest"},
|
|
{50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
|
|
{51, &ACC_SU::TrySelectUserWithoutInteractionDeprecated, "TrySelectUserWithoutInteractionDeprecated"},
|
|
{52, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, // 19.0.0+
|
|
{60, &ACC_SU::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"},
|
|
{99, nullptr, "DebugActivateOpenContextRetention"},
|
|
{100, nullptr, "GetUserRegistrationNotifier"},
|
|
{101, nullptr, "GetUserStateChangeNotifier"},
|
|
{102, &ACC_SU::GetBaasAccountManagerForSystemService, "GetBaasAccountManagerForSystemService"},
|
|
{103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
|
|
{104, nullptr, "GetProfileUpdateNotifier"},
|
|
{105, nullptr, "CheckNetworkServiceAvailabilityAsync"},
|
|
{106, nullptr, "GetProfileSyncNotifier"},
|
|
{110, &ACC_SU::StoreSaveDataThumbnailSystem, "StoreSaveDataThumbnail"},
|
|
{111, nullptr, "ClearSaveDataThumbnail"},
|
|
{112, nullptr, "LoadSaveDataThumbnail"},
|
|
{113, nullptr, "GetSaveDataThumbnailExistence"},
|
|
{120, nullptr, "ListOpenUsersInApplication"},
|
|
{130, nullptr, "ActivateOpenContextRetention"},
|
|
{140, &ACC_SU::ListQualifiedUsers, "ListQualifiedUsers"},
|
|
{150, nullptr, "AuthenticateApplicationAsync"},
|
|
{151, nullptr, "EnsureSignedDeviceIdentifierCacheForNintendoAccountAsync"},
|
|
{152, nullptr, "LoadSignedDeviceIdentifierCacheForNintendoAccount"},
|
|
{190, nullptr, "GetUserLastOpenedApplication"},
|
|
{191, nullptr, "ActivateOpenContextHolder"},
|
|
{200, &ACC_SU::BeginUserRegistration, "BeginUserRegistration"},
|
|
{201, &ACC_SU::CompleteUserRegistration, "CompleteUserRegistration"},
|
|
{202, nullptr, "CancelUserRegistration"},
|
|
{203, &ACC_SU::DeleteUser, "DeleteUser"},
|
|
{204, &ACC_SU::SetUserPosition, "SetUserPosition"},
|
|
{205, &ACC_SU::GetProfileEditor, "GetProfileEditor"},
|
|
{206, nullptr, "CompleteUserRegistrationForcibly"},
|
|
{210, nullptr, "CreateFloatingRegistrationRequest"},
|
|
{211, nullptr, "CreateProcedureToRegisterUserWithNintendoAccount"},
|
|
{212, nullptr, "ResumeProcedureToRegisterUserWithNintendoAccount"},
|
|
{230, nullptr, "AuthenticateServiceAsync"},
|
|
{250, &ACC_SU::GetBaasAccountAdministrator, "GetBaasAccountAdministrator"},
|
|
{290, nullptr, "ProxyProcedureForGuestLoginWithNintendoAccount"},
|
|
{291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"},
|
|
{299, nullptr, "SuspendBackgroundDaemon"},
|
|
{400, nullptr, "SetPinCode"}, // 18.0.0+
|
|
{401, &ACC_SU::GetPinCodeLength, "GetPinCodeLength"}, // 18.0.0+
|
|
{402, nullptr, "GetPinCode"}, // 18.0.0+
|
|
{403, nullptr, "GetPinCodeParity"},
|
|
{404, nullptr, "VerifyPinCode"},
|
|
{405, nullptr, "IsPinCodeVerificationForbidden"},
|
|
{410, nullptr, "GetPinCodeErrorCount"}, // 18.0.0+
|
|
{411, nullptr, "ResetPinCodeErrorCount"}, // 18.0.0+
|
|
{412, nullptr, "IncrementPinCodeErrorCount"}, // 18.0.0+
|
|
{900, nullptr, "SetUserUnqualifiedForDebug"},
|
|
{901, nullptr, "UnsetUserUnqualifiedForDebug"},
|
|
{902, nullptr, "ListUsersUnqualifiedForDebug"},
|
|
{910, nullptr, "RefreshFirmwareSettingsForDebug"},
|
|
{997, nullptr, "DebugInvalidateTokenCacheForUser"},
|
|
{998, nullptr, "DebugSetUserStateClose"},
|
|
{999, nullptr, "DebugSetUserStateOpen"},
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
~ACC_SU() override = default;
|
|
};
|
|
|
|
class ACC_U0 final : public Module::Interface {
|
|
public:
|
|
ACC_U0(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_)
|
|
: Interface(std::move(module_), std::move(profile_manager_), system_, "acc:u0") {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, &ACC_U0::GetUserCount, "GetUserCount"},
|
|
{1, &ACC_U0::GetUserExistence, "GetUserExistence"},
|
|
{2, &ACC_U0::ListAllUsers, "ListAllUsers"},
|
|
{3, &ACC_U0::ListOpenUsers, "ListOpenUsers"},
|
|
{4, &ACC_U0::GetLastOpenedUser, "GetLastOpenedUser"},
|
|
{5, &ACC_U0::GetProfile, "GetProfile"},
|
|
{6, nullptr, "GetProfileDigest"}, // 3.0.0+
|
|
{50, &ACC_U0::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
|
|
{51, &ACC_U0::TrySelectUserWithoutInteractionDeprecated, "TrySelectUserWithoutInteractionDeprecated"},
|
|
{52, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
|
|
{60, &ACC_U0::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0
|
|
{99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+
|
|
{100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"},
|
|
{101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"},
|
|
{102, nullptr, "AuthenticateApplicationAsync"},
|
|
{103, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+
|
|
{110, &ACC_U0::StoreSaveDataThumbnailApplication, "StoreSaveDataThumbnail"},
|
|
{111, nullptr, "ClearSaveDataThumbnail"},
|
|
{120, nullptr, "CreateGuestLoginRequest"},
|
|
{130, nullptr, "LoadOpenContext"}, // 5.0.0+
|
|
{131, &ACC_U0::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 6.0.0+
|
|
{140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"}, // 6.0.0+
|
|
{141, &ACC_U0::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+
|
|
{150, &ACC_U0::IsUserAccountSwitchLocked, "IsUserAccountSwitchLocked"}, // 6.0.0+
|
|
{160, &ACC_U0::InitializeApplicationInfoV2, "InitializeApplicationInfoV2"},
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
~ACC_U0() override = default;
|
|
};
|
|
|
|
class ACC_U1 final : public Module::Interface {
|
|
public:
|
|
ACC_U1(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_)
|
|
: Interface(std::move(module_), std::move(profile_manager_), system_, "acc:u1") {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, &ACC_U1::GetUserCount, "GetUserCount"},
|
|
{1, &ACC_U1::GetUserExistence, "GetUserExistence"},
|
|
{2, &ACC_U1::ListAllUsers, "ListAllUsers"},
|
|
{3, &ACC_U1::ListOpenUsers, "ListOpenUsers"},
|
|
{4, &ACC_U1::GetLastOpenedUser, "GetLastOpenedUser"},
|
|
{5, &ACC_U1::GetProfile, "GetProfile"},
|
|
{6, nullptr, "GetProfileDigest"},
|
|
{50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
|
|
{51, &ACC_U1::TrySelectUserWithoutInteractionDeprecated, "TrySelectUserWithoutInteractionDeprecated"},
|
|
{52, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
|
|
{60, &ACC_U1::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"},
|
|
{99, nullptr, "DebugActivateOpenContextRetention"},
|
|
{100, nullptr, "GetUserRegistrationNotifier"},
|
|
{101, nullptr, "GetUserStateChangeNotifier"},
|
|
{102, &ACC_U1::GetBaasAccountManagerForSystemService, "GetBaasAccountManagerForSystemService"},
|
|
{103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
|
|
{104, nullptr, "GetProfileUpdateNotifier"},
|
|
{105, nullptr, "CheckNetworkServiceAvailabilityAsync"},
|
|
{106, nullptr, "GetProfileSyncNotifier"},
|
|
{110, &ACC_U1::StoreSaveDataThumbnailApplication, "StoreSaveDataThumbnail"},
|
|
{111, nullptr, "ClearSaveDataThumbnail"},
|
|
{112, nullptr, "LoadSaveDataThumbnail"},
|
|
{113, nullptr, "GetSaveDataThumbnailExistence"},
|
|
{120, nullptr, "ListOpenUsersInApplication"},
|
|
{130, nullptr, "ActivateOpenContextRetention"},
|
|
{140, &ACC_U1::ListQualifiedUsers, "ListQualifiedUsers"},
|
|
{150, nullptr, "AuthenticateApplicationAsync"},
|
|
{151, nullptr, "EnsureSignedDeviceIdentifierCacheForNintendoAccountAsync"},
|
|
{152, nullptr, "LoadSignedDeviceIdentifierCacheForNintendoAccount"},
|
|
{190, nullptr, "GetUserLastOpenedApplication"},
|
|
{191, nullptr, "ActivateOpenContextHolder"},
|
|
{401, &ACC_U1::GetPinCodeLength, "GetPinCodeLength"}, // 18.0.0+
|
|
{402, nullptr, "GetPinCode"}, // 18.0.0+
|
|
{997, nullptr, "DebugInvalidateTokenCacheForUser"},
|
|
{998, nullptr, "DebugSetUserStateClose"},
|
|
{999, nullptr, "DebugSetUserStateOpen"},
|
|
};
|
|
// clang-format on
|
|
|
|
RegisterHandlers(functions);
|
|
}
|
|
~ACC_U1() override = default;
|
|
};
|
|
|
|
class DAUTH_0 final : public ServiceFramework<DAUTH_0> {
|
|
public:
|
|
explicit DAUTH_0(Core::System& system_) : ServiceFramework{system_, "dauth:0"} {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "EnsureAuthenticationTokenCacheAsync"},
|
|
{1, nullptr, "LoadAuthenticationTokenCache"},
|
|
{2, nullptr, "InvalidateAuthenticationTokenCache"},
|
|
{3, nullptr, "IsDeviceAuthenticationTokenCacheAvailable"},
|
|
{10, nullptr, "EnsureEdgeTokenCacheAsync"},
|
|
{11, nullptr, "LoadEdgeTokenCache"},
|
|
{12, nullptr, "InvalidateEdgeTokenCache"},
|
|
{13, nullptr, "IsEdgeTokenCacheAvailable"},
|
|
{20, nullptr, "EnsureApplicationAuthenticationCacheAsync"},
|
|
{21, nullptr, "LoadApplicationAuthenticationTokenCache"},
|
|
{22, nullptr, "LoadApplicationNetworkServiceClientConfigCache"},
|
|
{23, nullptr, "IsApplicationAuthenticationCacheAvailable"},
|
|
{24, nullptr, "InvalidateApplicationAuthenticationCache"},
|
|
{30, nullptr, "EnsureGameCardAuthenticationCacheAsync"},
|
|
{31, nullptr, "LoadGameCardAuthenticationTokenCache"},
|
|
{32, nullptr, "IsGameCardAuthenticationCacheAvailable"},
|
|
{33, nullptr, "InvalidateGameCardAuthenticationCache"},
|
|
{1000, nullptr, "GetInactiveElicenseUsedEvent"},
|
|
{9000, nullptr, "ImportVirtualClientCertificate"},
|
|
{9010, nullptr, "DeleteVirtualClientCertificate"},
|
|
};
|
|
// clang-format on
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
class ACC_E final : public Module::Interface {
|
|
public:
|
|
explicit ACC_E(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_)
|
|
: Interface(std::move(module_), std::move(profile_manager_), system_, "acc:e") {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{ 0, nullptr, "GetUserCount"},
|
|
{ 1, nullptr, "GetUserExistence"},
|
|
{ 2, nullptr, "ListAllUsers"},
|
|
{ 3, nullptr, "ListOpenUsers"},
|
|
{ 4, nullptr, "GetLastOpenedUser"},
|
|
{ 5, nullptr, "GetProfile"},
|
|
{ 6, nullptr, "GetProfileDigest"},
|
|
{ 50, nullptr, "IsUserRegistrationRequestPermitted"},
|
|
{ 51, nullptr, "TrySelectUserWithoutInteractionDeprecated"},
|
|
{ 52, nullptr, "TrySelectUserWithoutInteraction"},
|
|
{ 99, nullptr, "DebugActivateOpenContextRetention"},
|
|
{ 100, nullptr, "GetUserRegistrationNotifier"},
|
|
{ 101, nullptr, "GetUserStateChangeNotifier"},
|
|
{ 102, nullptr, "GetBaasAccountManagerForSystemService"},
|
|
{ 103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
|
|
{ 104, nullptr, "GetProfileUpdateNotifier"},
|
|
{ 105, nullptr, "CheckNetworkServiceAvailabilityAsync"},
|
|
{ 106, nullptr, "GetProfileSyncNotifier"},
|
|
{ 110, nullptr, "StoreSaveDataThumbnail"},
|
|
{ 111, nullptr, "ClearSaveDataThumbnail"},
|
|
{ 112, nullptr, "LoadSaveDataThumbnail"},
|
|
{ 113, nullptr, "GetSaveDataThumbnailExistence"},
|
|
{ 120, nullptr, "ListOpenUsersInApplication"},
|
|
{ 130, nullptr, "ActivateOpenContextRetention"},
|
|
{ 140, nullptr, "ListQualifiedUsers"},
|
|
{ 151, nullptr, "EnsureSignedDeviceIdentifierCacheForNintendoAccountAsync"},
|
|
{ 152, nullptr, "LoadSignedDeviceIdentifierCacheForNintendoAccount"},
|
|
{ 170, nullptr, "GetNasOp2MembershipStateChangeNotifier"},
|
|
{ 191, nullptr, "UpdateNotificationReceiverInfo"},
|
|
{ 200, nullptr, "BeginUserRegistration"},
|
|
{ 201, nullptr, "CompleteUserRegistration"},
|
|
{ 202, nullptr, "CancelUserRegistration"},
|
|
{ 203, nullptr, "DeleteUser"},
|
|
{ 204, nullptr, "SetUserPosition"},
|
|
{ 205, nullptr, "GetProfileEditor"},
|
|
{ 206, nullptr, "CompleteUserRegistrationForcibly"},
|
|
{ 210, nullptr, "CreateFloatingRegistrationRequest"},
|
|
{ 211, nullptr, "CreateProcedureToRegisterUserWithNintendoAccount"},
|
|
{ 212, nullptr, "ResumeProcedureToRegisterUserWithNintendoAccount"},
|
|
{ 213, nullptr, "CreateProcedureToCreateUserWithNintendoAccount"},
|
|
{ 214, nullptr, "ResumeProcedureToCreateUserWithNintendoAccount"},
|
|
{ 215, nullptr, "ResumeProcedureToCreateUserWithNintendoAccountAfterApplyResponse"},
|
|
{ 230, nullptr, "AuthenticateServiceAsync"},
|
|
{ 250, nullptr, "GetBaasAccountAdministrator"},
|
|
{ 251, nullptr, "SynchronizeNetworkServiceAccountsSnapshotAsync"},
|
|
{ 290, nullptr, "ProxyProcedureForGuestLoginWithNintendoAccount"},
|
|
{ 291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"},
|
|
{ 292, nullptr, "ProxyProcedureForDeviceMigrationAuthenticatingOperatingUser"},
|
|
{ 293, nullptr, "ProxyProcedureForDeviceMigrationDownload"},
|
|
{ 299, nullptr, "SuspendBackgroundDaemon"},
|
|
{ 350, nullptr, "CreateDeviceMigrationUserExportRequest"},
|
|
{ 351, nullptr, "UploadNasCredential"},
|
|
{ 352, nullptr, "CreateDeviceMigrationUserImportRequest"},
|
|
{ 353, nullptr, "DeleteUserMigrationSaveData"},
|
|
{ 400, nullptr, "SetPinCode"},
|
|
{ 401, nullptr, "GetPinCodeLength"},
|
|
{ 402, nullptr, "GetPinCode"},
|
|
{ 403, nullptr, "GetPinCodeParity"},
|
|
{ 404, nullptr, "VerifyPinCode"},
|
|
{ 405, nullptr, "IsPinCodeVerificationForbidden"},
|
|
{ 410, nullptr, "GetPinCodeErrorCount"},
|
|
{ 411, nullptr, "ResetPinCodeErrorCount"},
|
|
{ 412, nullptr, "IncrementPinCodeErrorCount"},
|
|
{ 413, nullptr, "SetPinCodeErrorCount"},
|
|
{ 420, nullptr, "SetStartPenaltyTime"},
|
|
{ 421, nullptr, "GetStartPenaltyTime"},
|
|
{ 900, nullptr, "SetUserUnqualifiedForDebug"},
|
|
{ 901, nullptr, "UnsetUserUnqualifiedForDebug"},
|
|
{ 902, nullptr, "ListUsersUnqualifiedForDebug"},
|
|
{ 910, nullptr, "RefreshFirmwareSettingsForDebug"},
|
|
{ 997, nullptr, "DebugInvalidateTokenCacheForUser"},
|
|
{ 998, nullptr, "DebugSetUserStateClose"},
|
|
{ 999, nullptr, "DebugSetUserStateOpen"},
|
|
{ 1000, nullptr, "CreateIAccountEntityServiceForApplication"},
|
|
{ 1100, nullptr, "CreateIUserStateManager"},
|
|
{ 10050, nullptr, "IsUserRegistrationRequestPermittedForAccountPolicy"},
|
|
{ 10105, nullptr, "CheckNetworkServiceAvailabilityAsyncForAccountPolicy"},
|
|
};
|
|
// clang-format on
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
class ACC_E_U1 final : public Module::Interface {
|
|
public:
|
|
explicit ACC_E_U1(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_)
|
|
: Interface(std::move(module_), std::move(profile_manager_), system_, "acc:e:u1") {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "GetUserCount"},
|
|
{1, nullptr, "GetUserExistence"},
|
|
{2, nullptr, "ListAllUsers"},
|
|
{3, nullptr, "ListOpenUsers"},
|
|
{4, nullptr, "GetLastOpenedUser"},
|
|
{5, nullptr, "GetProfile"},
|
|
{6, nullptr, "GetProfileDigest"},
|
|
{50, nullptr, "IsUserRegistrationRequestPermitted"},
|
|
{51, nullptr, "TrySelectUserWithoutInteractionDeprecated"},
|
|
{99, nullptr, "DebugActivateOpenContextRetention"},
|
|
{100, nullptr, "GetUserRegistrationNotifier"},
|
|
{101, nullptr, "GetUserStateChangeNotifier"},
|
|
{102, nullptr, "GetBaasAccountManagerForSystemService"},
|
|
{103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
|
|
{104, nullptr, "GetProfileUpdateNotifier"},
|
|
{105, nullptr, "CheckNetworkServiceAvailabilityAsync"},
|
|
{106, nullptr, "GetProfileSyncNotifier"},
|
|
{110, nullptr, "StoreSaveDataThumbnail"},
|
|
{111, nullptr, "ClearSaveDataThumbnail"},
|
|
{112, nullptr, "LoadSaveDataThumbnail"},
|
|
{113, nullptr, "GetSaveDataThumbnailExistence"},
|
|
{120, nullptr, "ListOpenUsersInApplication"},
|
|
{130, nullptr, "ActivateOpenContextRetention"},
|
|
{140, nullptr, "ListQualifiedUsers"},
|
|
{151, nullptr, "EnsureSignedDeviceIdentifierCacheForNintendoAccountAsync"},
|
|
{152, nullptr, "LoadSignedDeviceIdentifierCacheForNintendoAccount"},
|
|
{170, nullptr, "GetNasOp2MembershipStateChangeNotifier"},
|
|
{191, nullptr, "UpdateNotificationReceiverInfo"},
|
|
{997, nullptr, "DebugInvalidateTokenCacheForUser"},
|
|
{998, nullptr, "DebugSetUserStateClose"},
|
|
{999, nullptr, "DebugSetUserStateOpen"},
|
|
};
|
|
// clang-format on
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
class ACC_E_U2 final : public Module::Interface {
|
|
public:
|
|
explicit ACC_E_U2(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_)
|
|
: Interface(std::move(module_), std::move(profile_manager_), system_, "acc:e:u2") {
|
|
// clang-format off
|
|
static const FunctionInfo functions[] = {
|
|
{0, nullptr, "GetUserCount"},
|
|
{1, nullptr, "GetUserExistence"},
|
|
{2, nullptr, "ListAllUsers"},
|
|
{3, nullptr, "ListOpenUsers"},
|
|
{4, nullptr, "GetLastOpenedUser"},
|
|
{5, nullptr, "GetProfile"},
|
|
{6, nullptr, "GetProfileDigest"},
|
|
{50, nullptr, "#IsUserRegistrationRequestPermitted"},
|
|
{51, nullptr, "TrySelectUserWithoutInteractionDeprecated"},
|
|
{52, nullptr, "TrySelectUserWithoutInteraction"},
|
|
{99, nullptr, "DebugActivateOpenContextRetention"},
|
|
{100, nullptr, "GetUserRegistrationNotifier"},
|
|
{101, nullptr, "GetUserStateChangeNotifier"},
|
|
{102, nullptr, "GetBaasAccountManagerForSystemService"},
|
|
{103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
|
|
{104, nullptr, "GetProfileUpdateNotifier"},
|
|
{105, nullptr, "CheckNetworkServiceAvailabilityAsync"},
|
|
{106, nullptr, "GetProfileSyncNotifier"},
|
|
{110, nullptr, "StoreSaveDataThumbnail"},
|
|
{111, nullptr, "ClearSaveDataThumbnail"},
|
|
{112, nullptr, "LoadSaveDataThumbnail"},
|
|
{113, nullptr, "GetSaveDataThumbnailExistence"},
|
|
{120, nullptr, "ListOpenUsersInApplication"},
|
|
{130, nullptr, "ActivateOpenContextRetention"},
|
|
{140, nullptr, "ListQualifiedUsers"},
|
|
{151, nullptr, "EnsureSignedDeviceIdentifierCacheForNintendoAccountAsync"},
|
|
{152, nullptr, "LoadSignedDeviceIdentifierCacheForNintendoAccount"},
|
|
{170, nullptr, "GetNasOp2MembershipStateChangeNotifier"},
|
|
{191, nullptr, "UpdateNotificationReceiverInfo"},
|
|
{205, nullptr, "GetProfileEditor"},
|
|
{401, nullptr, "GetPinCodeLength"},
|
|
{402, nullptr, "GetPinCode"},
|
|
{403, nullptr, "GetPinCodeParity"},
|
|
{404, nullptr, "VerifyPinCode"},
|
|
{405, nullptr, "IsPinCodeVerificationForbidden"},
|
|
{997, nullptr, "DebugInvalidateTokenCacheForUser"},
|
|
{998, nullptr, "DebugSetUserStateClose"},
|
|
{999, nullptr, "DebugSetUserStateOpen"},
|
|
};
|
|
// clang-format on
|
|
RegisterHandlers(functions);
|
|
}
|
|
};
|
|
|
|
void LoopProcess(Core::System& system) {
|
|
auto module = std::make_shared<Module>();
|
|
auto profile_manager = std::make_shared<ProfileManager>();
|
|
auto server_manager = std::make_unique<ServerManager>(system);
|
|
|
|
server_manager->RegisterNamedService("acc:aa", std::make_shared<ACC_AA>(module, profile_manager, system));
|
|
server_manager->RegisterNamedService("acc:su", std::make_shared<ACC_SU>(module, profile_manager, system));
|
|
server_manager->RegisterNamedService("acc:u0", std::make_shared<ACC_U0>(module, profile_manager, system));
|
|
server_manager->RegisterNamedService("acc:u1", std::make_shared<ACC_U1>(module, profile_manager, system));
|
|
|
|
server_manager->RegisterNamedService("acc:e", std::make_shared<ACC_E>(module, profile_manager, system));
|
|
server_manager->RegisterNamedService("acc:e:u1", std::make_shared<ACC_E_U1>(module, profile_manager, system));
|
|
server_manager->RegisterNamedService("acc:e:u2", std::make_shared<ACC_E_U2>(module, profile_manager, system));
|
|
|
|
server_manager->RegisterNamedService("dauth:0", std::make_shared<DAUTH_0>(system));
|
|
ServerManager::RunServer(std::move(server_manager));
|
|
}
|
|
|
|
} // namespace Service::Account
|