diff options
Diffstat (limited to 'src/frontend_common/firmware_manager.cpp')
| -rw-r--r-- | src/frontend_common/firmware_manager.cpp | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/src/frontend_common/firmware_manager.cpp b/src/frontend_common/firmware_manager.cpp new file mode 100644 index 0000000000..f1022579be --- /dev/null +++ b/src/frontend_common/firmware_manager.cpp @@ -0,0 +1,139 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "firmware_manager.h" +#include <filesystem> +#include <common/fs/fs_paths.h> + +#include "common/fs/fs.h" +#include "common/fs/path_util.h" + +#include "common/logging/backend.h" + +#include "core/crypto/key_manager.h" +#include "frontend_common/content_manager.h" + +#ifdef ANDROID +#include <jni.h> +#include <common/android/id_cache.h> +#include <common/android/android_common.h> +#endif + +FirmwareManager::KeyInstallResult +FirmwareManager::InstallKeys(std::string location, std::string extension) { + LOG_INFO(Frontend, "Installing key files from {}", location); + + const auto keys_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::KeysDir); + +#ifdef ANDROID + JNIEnv *env = Common::Android::GetEnvForThread(); + + jstring jsrc = Common::Android::ToJString(env, location); + + jclass native = Common::Android::GetNativeLibraryClass(); + jmethodID getExtension = Common::Android::GetFileExtension(); + + jstring jext = static_cast<jstring>(env->CallStaticObjectMethod( + native, + getExtension, + jsrc + )); + + std::string ext = Common::Android::GetJString(env, jext); + + if (ext != extension) { + return ErrorWrongFilename; + } + + jmethodID copyToStorage = Common::Android::GetCopyToStorage(); + jstring jdest = Common::Android::ToJString(env, keys_dir.string()); + + jboolean copyResult = env->CallStaticBooleanMethod( + native, + copyToStorage, + jsrc, + jdest + ); + + if (!copyResult) { + return ErrorFailedCopy; + } +#else + if (!location.ends_with(extension)) { + return ErrorWrongFilename; + } + + bool prod_keys_found = false; + + const std::filesystem::path prod_key_path = location; + const std::filesystem::path key_source_path = prod_key_path.parent_path(); + + if (!Common::FS::IsDir(key_source_path)) { + return InvalidDir; + } + + std::vector<std::filesystem::path> source_key_files; + + if (Common::FS::Exists(prod_key_path)) { + prod_keys_found = true; + source_key_files.emplace_back(prod_key_path); + } + + if (Common::FS::Exists(key_source_path / "title.keys")) { + source_key_files.emplace_back(key_source_path / "title.keys"); + } + + if (Common::FS::Exists(key_source_path / "key_retail.bin")) { + source_key_files.emplace_back(key_source_path / "key_retail.bin"); + } + + if (source_key_files.empty() || !prod_keys_found) { + return ErrorWrongFilename; + } + + for (const auto &key_file : source_key_files) { + std::filesystem::path destination_key_file = keys_dir / key_file.filename(); + if (!std::filesystem::copy_file(key_file, + destination_key_file, + std::filesystem::copy_options::overwrite_existing)) { + LOG_ERROR(Frontend, + "Failed to copy file {} to {}", + key_file.string(), + destination_key_file.string()); + return ErrorFailedCopy; + } + } +#endif + + // Reinitialize the key manager + Core::Crypto::KeyManager::Instance().ReloadKeys(); + + if (ContentManager::AreKeysPresent()) { + return Success; + } + + // Let the frontend handle everything else + return ErrorFailedInit; +} + +FirmwareManager::FirmwareCheckResult FirmwareManager::VerifyFirmware(Core::System &system) { + if (!CheckFirmwarePresence(system)) { + return ErrorFirmwareMissing; + } else { + const auto pair = GetFirmwareVersion(system); + const auto firmware_data = pair.first; + const auto result = pair.second; + + if (result.IsError()) { + LOG_INFO(Frontend, "Unable to read firmware"); + return ErrorFirmwareCorrupted; + } + + // TODO: update this whenever newer firmware is properly supported + if (firmware_data.major > 19) { + return ErrorFirmwareTooNew; + } + } + + return FirmwareGood; +} |
