|
@@ -1604,6 +1604,7 @@ void GMainWindow::ConnectMenuEvents() {
|
|
|
connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder);
|
|
connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder);
|
|
|
connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents);
|
|
connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents);
|
|
|
connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware);
|
|
connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware);
|
|
|
|
|
+ connect_menu(ui->action_Install_Keys, &GMainWindow::OnInstallDecryptionKeys);
|
|
|
connect_menu(ui->action_About, &GMainWindow::OnAbout);
|
|
connect_menu(ui->action_About, &GMainWindow::OnAbout);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1633,6 +1634,7 @@ void GMainWindow::UpdateMenuState() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ui->action_Install_Firmware->setEnabled(!emulation_running);
|
|
ui->action_Install_Firmware->setEnabled(!emulation_running);
|
|
|
|
|
+ ui->action_Install_Keys->setEnabled(!emulation_running);
|
|
|
|
|
|
|
|
for (QAction* action : applet_actions) {
|
|
for (QAction* action : applet_actions) {
|
|
|
action->setEnabled(is_firmware_available && !emulation_running);
|
|
action->setEnabled(is_firmware_available && !emulation_running);
|
|
@@ -4169,9 +4171,8 @@ void GMainWindow::OnInstallFirmware() {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- QString firmware_source_location =
|
|
|
|
|
- QFileDialog::getExistingDirectory(this, tr("Select Dumped Firmware Source Location"),
|
|
|
|
|
- QString::fromStdString(""), QFileDialog::ShowDirsOnly);
|
|
|
|
|
|
|
+ const QString firmware_source_location = QFileDialog::getExistingDirectory(
|
|
|
|
|
+ this, tr("Select Dumped Firmware Source Location"), {}, QFileDialog::ShowDirsOnly);
|
|
|
if (firmware_source_location.isEmpty()) {
|
|
if (firmware_source_location.isEmpty()) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
@@ -4202,8 +4203,9 @@ void GMainWindow::OnInstallFirmware() {
|
|
|
std::vector<std::filesystem::path> out;
|
|
std::vector<std::filesystem::path> out;
|
|
|
const Common::FS::DirEntryCallable callback =
|
|
const Common::FS::DirEntryCallable callback =
|
|
|
[&out](const std::filesystem::directory_entry& entry) {
|
|
[&out](const std::filesystem::directory_entry& entry) {
|
|
|
- if (entry.path().has_extension() && entry.path().extension() == ".nca")
|
|
|
|
|
|
|
+ if (entry.path().has_extension() && entry.path().extension() == ".nca") {
|
|
|
out.emplace_back(entry.path());
|
|
out.emplace_back(entry.path());
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
return true;
|
|
return true;
|
|
|
};
|
|
};
|
|
@@ -4235,7 +4237,6 @@ void GMainWindow::OnInstallFirmware() {
|
|
|
auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered");
|
|
auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered");
|
|
|
|
|
|
|
|
bool success = true;
|
|
bool success = true;
|
|
|
- bool cancelled = false;
|
|
|
|
|
int i = 0;
|
|
int i = 0;
|
|
|
for (const auto& firmware_src_path : out) {
|
|
for (const auto& firmware_src_path : out) {
|
|
|
i++;
|
|
i++;
|
|
@@ -4250,24 +4251,22 @@ void GMainWindow::OnInstallFirmware() {
|
|
|
success = false;
|
|
success = false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (QtProgressCallback(100, 20 + (int)(((float)(i) / (float)out.size()) * 70.0))) {
|
|
|
|
|
- success = false;
|
|
|
|
|
- cancelled = true;
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ if (QtProgressCallback(
|
|
|
|
|
+ 100, 20 + static_cast<int>(((i) / static_cast<float>(out.size())) * 70.0))) {
|
|
|
|
|
+ progress.close();
|
|
|
|
|
+ QMessageBox::warning(
|
|
|
|
|
+ this, tr("Firmware install failed"),
|
|
|
|
|
+ tr("Firmware installation cancelled, firmware may be in bad state, "
|
|
|
|
|
+ "restart yuzu or re-install firmware."));
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (!success && !cancelled) {
|
|
|
|
|
|
|
+ if (!success) {
|
|
|
progress.close();
|
|
progress.close();
|
|
|
QMessageBox::critical(this, tr("Firmware install failed"),
|
|
QMessageBox::critical(this, tr("Firmware install failed"),
|
|
|
tr("One or more firmware files failed to copy into NAND."));
|
|
tr("One or more firmware files failed to copy into NAND."));
|
|
|
return;
|
|
return;
|
|
|
- } else if (cancelled) {
|
|
|
|
|
- progress.close();
|
|
|
|
|
- QMessageBox::warning(this, tr("Firmware install failed"),
|
|
|
|
|
- tr("Firmware installation cancelled, firmware may be in bad state, "
|
|
|
|
|
- "restart yuzu or re-install firmware."));
|
|
|
|
|
- return;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Re-scan VFS for the newly placed firmware files.
|
|
// Re-scan VFS for the newly placed firmware files.
|
|
@@ -4295,6 +4294,84 @@ void GMainWindow::OnInstallFirmware() {
|
|
|
OnCheckFirmwareDecryption();
|
|
OnCheckFirmwareDecryption();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+void GMainWindow::OnInstallDecryptionKeys() {
|
|
|
|
|
+ // Don't do this while emulation is running.
|
|
|
|
|
+ if (emu_thread != nullptr && emu_thread->IsRunning()) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const QString key_source_location = QFileDialog::getOpenFileName(
|
|
|
|
|
+ this, tr("Select Dumped Keys Location"), {}, QStringLiteral("prod.keys (prod.keys)"), {},
|
|
|
|
|
+ QFileDialog::ReadOnly);
|
|
|
|
|
+ if (key_source_location.isEmpty()) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Verify that it contains prod.keys, title.keys and optionally, key_retail.bin
|
|
|
|
|
+ LOG_INFO(Frontend, "Installing key files from {}", key_source_location.toStdString());
|
|
|
|
|
+
|
|
|
|
|
+ const std::filesystem::path prod_key_path = key_source_location.toStdString();
|
|
|
|
|
+ const std::filesystem::path key_source_path = prod_key_path.parent_path();
|
|
|
|
|
+ if (!Common::FS::IsDir(key_source_path)) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ bool prod_keys_found = false;
|
|
|
|
|
+ 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");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // There should be at least prod.keys.
|
|
|
|
|
+ if (source_key_files.empty() || !prod_keys_found) {
|
|
|
|
|
+ QMessageBox::warning(this, tr("Decryption Keys install failed"),
|
|
|
|
|
+ tr("prod.keys is a required decryption key file."));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
|
|
|
|
|
+ for (auto key_file : source_key_files) {
|
|
|
|
|
+ std::filesystem::path destination_key_file = yuzu_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());
|
|
|
|
|
+ QMessageBox::critical(this, tr("Decryption Keys install failed"),
|
|
|
|
|
+ tr("One or more keys failed to copy."));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Reinitialize the key manager, re-read the vfs (for update/dlc files),
|
|
|
|
|
+ // and re-populate the game list in the UI if the user has already added
|
|
|
|
|
+ // game folders.
|
|
|
|
|
+ Core::Crypto::KeyManager::Instance().ReloadKeys();
|
|
|
|
|
+ system->GetFileSystemController().CreateFactories(*vfs);
|
|
|
|
|
+ game_list->PopulateAsync(UISettings::values.game_dirs);
|
|
|
|
|
+
|
|
|
|
|
+ if (ContentManager::AreKeysPresent()) {
|
|
|
|
|
+ QMessageBox::information(this, tr("Decryption Keys install succeeded"),
|
|
|
|
|
+ tr("Decryption Keys were successfully installed"));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ QMessageBox::critical(
|
|
|
|
|
+ this, tr("Decryption Keys install failed"),
|
|
|
|
|
+ tr("Decryption Keys failed to initialize. Check that your dumping tools are "
|
|
|
|
|
+ "up to date and re-dump keys."));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ OnCheckFirmwareDecryption();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void GMainWindow::OnAbout() {
|
|
void GMainWindow::OnAbout() {
|
|
|
AboutDialog aboutDialog(this);
|
|
AboutDialog aboutDialog(this);
|
|
|
aboutDialog.exec();
|
|
aboutDialog.exec();
|