forked from eden-emu/eden
140 lines
3.9 KiB
C++
140 lines
3.9 KiB
C++
|
// 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;
|
||
|
}
|