Просмотр исходного кода

Merge pull request #12777 from t895/firmware-warning

android: Add key warning
liamwhite 2 лет назад
Родитель
Сommit
3e2d3548f2

+ 5 - 0
src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt

@@ -619,6 +619,11 @@ object NativeLibrary {
      */
     external fun clearFilesystemProvider()
 
+    /**
+     * Checks if all necessary keys are present for decryption
+     */
+    external fun areKeysPresent(): Boolean
+
     /**
      * Button type for use in onTouchEvent
      */

+ 24 - 8
src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/MessageDialogFragment.kt

@@ -26,9 +26,15 @@ class MessageDialogFragment : DialogFragment() {
         val descriptionId = requireArguments().getInt(DESCRIPTION_ID)
         val descriptionString = requireArguments().getString(DESCRIPTION_STRING)!!
         val helpLinkId = requireArguments().getInt(HELP_LINK)
+        val dismissible = requireArguments().getBoolean(DISMISSIBLE)
+        val clearPositiveAction = requireArguments().getBoolean(CLEAR_POSITIVE_ACTION)
 
         val builder = MaterialAlertDialogBuilder(requireContext())
 
+        if (clearPositiveAction) {
+            messageDialogViewModel.positiveAction = null
+        }
+
         if (messageDialogViewModel.positiveAction == null) {
             builder.setPositiveButton(R.string.close, null)
         } else {
@@ -51,6 +57,8 @@ class MessageDialogFragment : DialogFragment() {
             }
         }
 
+        isCancelable = dismissible
+
         return builder.show()
     }
 
@@ -67,6 +75,8 @@ class MessageDialogFragment : DialogFragment() {
         private const val DESCRIPTION_ID = "DescriptionId"
         private const val DESCRIPTION_STRING = "DescriptionString"
         private const val HELP_LINK = "Link"
+        private const val DISMISSIBLE = "Dismissible"
+        private const val CLEAR_POSITIVE_ACTION = "ClearPositiveAction"
 
         fun newInstance(
             activity: FragmentActivity? = null,
@@ -75,22 +85,28 @@ class MessageDialogFragment : DialogFragment() {
             descriptionId: Int = 0,
             descriptionString: String = "",
             helpLinkId: Int = 0,
+            dismissible: Boolean = true,
             positiveAction: (() -> Unit)? = null
         ): MessageDialogFragment {
+            var clearPositiveAction = false
+            if (activity != null) {
+                ViewModelProvider(activity)[MessageDialogViewModel::class.java].apply {
+                    clear()
+                    this.positiveAction = positiveAction
+                }
+            } else {
+                clearPositiveAction = true
+            }
+
             val dialog = MessageDialogFragment()
-            val bundle = Bundle()
-            bundle.apply {
+            val bundle = Bundle().apply {
                 putInt(TITLE_ID, titleId)
                 putString(TITLE_STRING, titleString)
                 putInt(DESCRIPTION_ID, descriptionId)
                 putString(DESCRIPTION_STRING, descriptionString)
                 putInt(HELP_LINK, helpLinkId)
-            }
-            if (activity != null) {
-                ViewModelProvider(activity)[MessageDialogViewModel::class.java].apply {
-                    clear()
-                    this.positiveAction = positiveAction
-                }
+                putBoolean(DISMISSIBLE, dismissible)
+                putBoolean(CLEAR_POSITIVE_ACTION, clearPositiveAction)
             }
             dialog.arguments = bundle
             return dialog

+ 4 - 2
src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt

@@ -31,6 +31,7 @@ import androidx.preference.PreferenceManager
 import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
 import com.google.android.material.transition.MaterialFadeThrough
 import kotlinx.coroutines.launch
+import org.yuzu.yuzu_emu.NativeLibrary
 import java.io.File
 import org.yuzu.yuzu_emu.R
 import org.yuzu.yuzu_emu.YuzuApplication
@@ -162,7 +163,7 @@ class SetupFragment : Fragment() {
                     R.string.install_prod_keys_warning_help,
                     {
                         val file = File(DirectoryInitialization.userDirectory + "/keys/prod.keys")
-                        if (file.exists()) {
+                        if (file.exists() && NativeLibrary.areKeysPresent()) {
                             StepState.COMPLETE
                         } else {
                             StepState.INCOMPLETE
@@ -347,7 +348,8 @@ class SetupFragment : Fragment() {
     val getProdKey =
         registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
             if (result != null) {
-                if (mainActivity.processKey(result)) {
+                mainActivity.processKey(result)
+                if (NativeLibrary.areKeysPresent()) {
                     keyCallback.onStepCompleted()
                 }
             }

+ 7 - 0
src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt

@@ -31,6 +31,9 @@ class HomeViewModel : ViewModel() {
     private val _reloadPropertiesList = MutableStateFlow(false)
     val reloadPropertiesList get() = _reloadPropertiesList.asStateFlow()
 
+    private val _checkKeys = MutableStateFlow(false)
+    val checkKeys = _checkKeys.asStateFlow()
+
     var navigatedToSetup = false
 
     fun setNavigationVisibility(visible: Boolean, animated: Boolean) {
@@ -66,4 +69,8 @@ class HomeViewModel : ViewModel() {
     fun reloadPropertiesList(reload: Boolean) {
         _reloadPropertiesList.value = reload
     }
+
+    fun setCheckKeys(value: Boolean) {
+        _checkKeys.value = value
+    }
 }

+ 42 - 0
src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt

@@ -64,6 +64,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
 
     override var themeId: Int = 0
 
+    private val CHECKED_DECRYPTION = "CheckedDecryption"
+    private var checkedDecryption = false
+
     override fun onCreate(savedInstanceState: Bundle?) {
         val splashScreen = installSplashScreen()
         splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
@@ -75,6 +78,18 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
         binding = ActivityMainBinding.inflate(layoutInflater)
         setContentView(binding.root)
 
+        if (savedInstanceState != null) {
+            checkedDecryption = savedInstanceState.getBoolean(CHECKED_DECRYPTION)
+        }
+        if (!checkedDecryption) {
+            val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext)
+                .getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true)
+            if (!firstTimeSetup) {
+                checkKeys()
+            }
+            checkedDecryption = true
+        }
+
         WindowCompat.setDecorFitsSystemWindows(window, false)
         window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
 
@@ -150,6 +165,16 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
                     }
                 }
             }
+            launch {
+                repeatOnLifecycle(Lifecycle.State.CREATED) {
+                    homeViewModel.checkKeys.collect {
+                        if (it) {
+                            checkKeys()
+                            homeViewModel.setCheckKeys(false)
+                        }
+                    }
+                }
+            }
         }
 
         // Dismiss previous notifications (should not happen unless a crash occurred)
@@ -158,6 +183,21 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
         setInsets()
     }
 
+    private fun checkKeys() {
+        if (!NativeLibrary.areKeysPresent()) {
+            MessageDialogFragment.newInstance(
+                titleId = R.string.keys_missing,
+                descriptionId = R.string.keys_missing_description,
+                helpLinkId = R.string.keys_missing_help
+            ).show(supportFragmentManager, MessageDialogFragment.TAG)
+        }
+    }
+
+    override fun onSaveInstanceState(outState: Bundle) {
+        super.onSaveInstanceState(outState)
+        outState.putBoolean(CHECKED_DECRYPTION, checkedDecryption)
+    }
+
     fun finishSetup(navController: NavController) {
         navController.navigate(R.id.action_firstTimeSetupFragment_to_gamesFragment)
         (binding.navigationView as NavigationBarView).setupWithNavController(navController)
@@ -349,6 +389,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
                     R.string.install_keys_success,
                     Toast.LENGTH_SHORT
                 ).show()
+                homeViewModel.setCheckKeys(true)
                 gamesViewModel.reloadGames(true)
                 return true
             } else {
@@ -399,6 +440,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
                         firmwarePath.deleteRecursively()
                         cacheFirmwareDir.copyRecursively(firmwarePath, true)
                         NativeLibrary.initializeSystem(true)
+                        homeViewModel.setCheckKeys(true)
                         getString(R.string.save_file_imported_success)
                     }
                 } catch (e: Exception) {

+ 14 - 7
src/android/app/src/main/jni/native.cpp

@@ -464,8 +464,8 @@ int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject
     };
 
     return static_cast<int>(
-        ContentManager::InstallNSP(&EmulationSession::GetInstance().System(),
-                                   EmulationSession::GetInstance().System().GetFilesystem().get(),
+        ContentManager::InstallNSP(EmulationSession::GetInstance().System(),
+                                   *EmulationSession::GetInstance().System().GetFilesystem(),
                                    GetJString(env, j_file), callback));
 }
 
@@ -825,7 +825,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeUpdate(JNIEnv* env, jobject job
 void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeDLC(JNIEnv* env, jobject jobj,
                                                      jstring jprogramId) {
     auto program_id = EmulationSession::GetProgramId(env, jprogramId);
-    ContentManager::RemoveAllDLC(&EmulationSession::GetInstance().System(), program_id);
+    ContentManager::RemoveAllDLC(EmulationSession::GetInstance().System(), program_id);
 }
 
 void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj, jstring jprogramId,
@@ -835,8 +835,9 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj,
                               program_id, GetJString(env, jname));
 }
 
-jobject Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* env, jobject jobj,
-                                                                      jobject jcallback) {
+jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* env,
+                                                                           jobject jobj,
+                                                                           jobject jcallback) {
     auto jlambdaClass = env->GetObjectClass(jcallback);
     auto jlambdaInvokeMethod = env->GetMethodID(
         jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
@@ -848,7 +849,7 @@ jobject Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* en
 
     auto& session = EmulationSession::GetInstance();
     std::vector<std::string> result = ContentManager::VerifyInstalledContents(
-        &session.System(), session.GetContentProvider(), callback);
+        session.System(), *session.GetContentProvider(), callback);
     jobjectArray jresult =
         env->NewObjectArray(result.size(), IDCache::GetStringClass(), ToJString(env, ""));
     for (size_t i = 0; i < result.size(); ++i) {
@@ -869,7 +870,7 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyGameContents(JNIEnv* env, jobje
     };
     auto& session = EmulationSession::GetInstance();
     return static_cast<jint>(
-        ContentManager::VerifyGameContents(&session.System(), GetJString(env, jpath), callback));
+        ContentManager::VerifyGameContents(session.System(), GetJString(env, jpath), callback));
 }
 
 jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj,
@@ -918,4 +919,10 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_clearFilesystemProvider(JNIEnv* env,
     EmulationSession::GetInstance().GetContentProvider()->ClearAllEntries();
 }
 
+jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_areKeysPresent(JNIEnv* env, jobject jobj) {
+    auto& system = EmulationSession::GetInstance().System();
+    system.GetFileSystemController().CreateFactories(*system.GetFilesystem());
+    return ContentManager::AreKeysPresent();
+}
+
 } // extern "C"

+ 3 - 0
src/android/app/src/main/res/values/strings.xml

@@ -144,6 +144,9 @@
     <string name="no_save_data_found">No save data found</string>
     <string name="verify_installed_content">Verify installed content</string>
     <string name="verify_installed_content_description">Checks all installed content for corruption</string>
+    <string name="keys_missing">Encryption keys are missing</string>
+    <string name="keys_missing_description">Firmware and retail games cannot be decrypted</string>
+    <string name="keys_missing_help">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
 
     <!-- Applet launcher strings -->
     <string name="applets">Applet launcher</string>

+ 35 - 28
src/frontend_common/content_manager.h

@@ -47,14 +47,14 @@ inline bool RemoveDLC(const Service::FileSystem::FileSystemController& fs_contro
 
 /**
  * \brief Removes all DLC for a game
- * \param system Raw pointer to the system instance
+ * \param system Reference to the system instance
  * \param program_id Program ID for the game that will have all of its DLC removed
  * \return Number of DLC removed
  */
-inline size_t RemoveAllDLC(Core::System* system, const u64 program_id) {
+inline size_t RemoveAllDLC(Core::System& system, const u64 program_id) {
     size_t count{};
-    const auto& fs_controller = system->GetFileSystemController();
-    const auto dlc_entries = system->GetContentProvider().ListEntriesFilter(
+    const auto& fs_controller = system.GetFileSystemController();
+    const auto dlc_entries = system.GetContentProvider().ListEntriesFilter(
         FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
     std::vector<u64> program_dlc_entries;
 
@@ -124,15 +124,15 @@ inline bool RemoveMod(const Service::FileSystem::FileSystemController& fs_contro
 
 /**
  * \brief Installs an NSP
- * \param system Raw pointer to the system instance
- * \param vfs Raw pointer to the VfsFilesystem instance in Core::System
+ * \param system Reference to the system instance
+ * \param vfs Reference to the VfsFilesystem instance in Core::System
  * \param filename Path to the NSP file
  * \param callback Callback to report the progress of the installation. The first size_t
  * parameter is the total size of the virtual file and the second is the current progress. If you
  * return true to the callback, it will cancel the installation as soon as possible.
  * \return [InstallResult] representing how the installation finished
  */
-inline InstallResult InstallNSP(Core::System* system, FileSys::VfsFilesystem* vfs,
+inline InstallResult InstallNSP(Core::System& system, FileSys::VfsFilesystem& vfs,
                                 const std::string& filename,
                                 const std::function<bool(size_t, size_t)>& callback) {
     const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
@@ -159,7 +159,7 @@ inline InstallResult InstallNSP(Core::System* system, FileSys::VfsFilesystem* vf
     };
 
     std::shared_ptr<FileSys::NSP> nsp;
-    FileSys::VirtualFile file = vfs->OpenFile(filename, FileSys::Mode::Read);
+    FileSys::VirtualFile file = vfs.OpenFile(filename, FileSys::Mode::Read);
     if (boost::to_lower_copy(file->GetName()).ends_with(std::string("nsp"))) {
         nsp = std::make_shared<FileSys::NSP>(file);
         if (nsp->IsExtractedType()) {
@@ -173,7 +173,7 @@ inline InstallResult InstallNSP(Core::System* system, FileSys::VfsFilesystem* vf
         return InstallResult::Failure;
     }
     const auto res =
-        system->GetFileSystemController().GetUserNANDContents()->InstallEntry(*nsp, true, copy);
+        system.GetFileSystemController().GetUserNANDContents()->InstallEntry(*nsp, true, copy);
     switch (res) {
     case FileSys::InstallResult::Success:
         return InstallResult::Success;
@@ -188,17 +188,17 @@ inline InstallResult InstallNSP(Core::System* system, FileSys::VfsFilesystem* vf
 
 /**
  * \brief Installs an NCA
- * \param vfs Raw pointer to the VfsFilesystem instance in Core::System
+ * \param vfs Reference to the VfsFilesystem instance in Core::System
  * \param filename Path to the NCA file
- * \param registered_cache Raw pointer to the registered cache that the NCA will be installed to
+ * \param registered_cache Reference to the registered cache that the NCA will be installed to
  * \param title_type Type of NCA package to install
  * \param callback Callback to report the progress of the installation. The first size_t
  * parameter is the total size of the virtual file and the second is the current progress. If you
  * return true to the callback, it will cancel the installation as soon as possible.
  * \return [InstallResult] representing how the installation finished
  */
-inline InstallResult InstallNCA(FileSys::VfsFilesystem* vfs, const std::string& filename,
-                                FileSys::RegisteredCache* registered_cache,
+inline InstallResult InstallNCA(FileSys::VfsFilesystem& vfs, const std::string& filename,
+                                FileSys::RegisteredCache& registered_cache,
                                 const FileSys::TitleType title_type,
                                 const std::function<bool(size_t, size_t)>& callback) {
     const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
@@ -224,7 +224,7 @@ inline InstallResult InstallNCA(FileSys::VfsFilesystem* vfs, const std::string&
         return true;
     };
 
-    const auto nca = std::make_shared<FileSys::NCA>(vfs->OpenFile(filename, FileSys::Mode::Read));
+    const auto nca = std::make_shared<FileSys::NCA>(vfs.OpenFile(filename, FileSys::Mode::Read));
     const auto id = nca->GetStatus();
 
     // Game updates necessary are missing base RomFS
@@ -233,7 +233,7 @@ inline InstallResult InstallNCA(FileSys::VfsFilesystem* vfs, const std::string&
         return InstallResult::Failure;
     }
 
-    const auto res = registered_cache->InstallEntry(*nca, title_type, true, copy);
+    const auto res = registered_cache.InstallEntry(*nca, title_type, true, copy);
     if (res == FileSys::InstallResult::Success) {
         return InstallResult::Success;
     } else if (res == FileSys::InstallResult::OverwriteExisting) {
@@ -245,19 +245,19 @@ inline InstallResult InstallNCA(FileSys::VfsFilesystem* vfs, const std::string&
 
 /**
  * \brief Verifies the installed contents for a given ManualContentProvider
- * \param system Raw pointer to the system instance
- * \param provider Raw pointer to the content provider that's tracking indexed games
+ * \param system Reference to the system instance
+ * \param provider Reference to the content provider that's tracking indexed games
  * \param callback Callback to report the progress of the installation. The first size_t
  * parameter is the total size of the installed contents and the second is the current progress. If
  * you return true to the callback, it will cancel the installation as soon as possible.
  * \return A list of entries that failed to install. Returns an empty vector if successful.
  */
 inline std::vector<std::string> VerifyInstalledContents(
-    Core::System* system, FileSys::ManualContentProvider* provider,
+    Core::System& system, FileSys::ManualContentProvider& provider,
     const std::function<bool(size_t, size_t)>& callback) {
     // Get content registries.
-    auto bis_contents = system->GetFileSystemController().GetSystemNANDContents();
-    auto user_contents = system->GetFileSystemController().GetUserNANDContents();
+    auto bis_contents = system.GetFileSystemController().GetSystemNANDContents();
+    auto user_contents = system.GetFileSystemController().GetUserNANDContents();
 
     std::vector<FileSys::RegisteredCache*> content_providers;
     if (bis_contents) {
@@ -309,11 +309,11 @@ inline std::vector<std::string> VerifyInstalledContents(
             const auto title_id = nca.GetTitleId();
             std::string title_name = "unknown";
 
-            const auto control = provider->GetEntry(FileSys::GetBaseTitleID(title_id),
-                                                    FileSys::ContentRecordType::Control);
+            const auto control = provider.GetEntry(FileSys::GetBaseTitleID(title_id),
+                                                   FileSys::ContentRecordType::Control);
             if (control && control->GetStatus() == Loader::ResultStatus::Success) {
-                const FileSys::PatchManager pm{title_id, system->GetFileSystemController(),
-                                               *provider};
+                const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
+                                               provider};
                 const auto [nacp, logo] = pm.ParseControlNCA(*control);
                 if (nacp) {
                     title_name = nacp->GetApplicationName();
@@ -335,7 +335,7 @@ inline std::vector<std::string> VerifyInstalledContents(
 
 /**
  * \brief Verifies the contents of a given game
- * \param system Raw pointer to the system instance
+ * \param system Reference to the system instance
  * \param game_path Patch to the game file
  * \param callback Callback to report the progress of the installation. The first size_t
  * parameter is the total size of the installed contents and the second is the current progress. If
@@ -343,10 +343,10 @@ inline std::vector<std::string> VerifyInstalledContents(
  * \return GameVerificationResult representing how the verification process finished
  */
 inline GameVerificationResult VerifyGameContents(
-    Core::System* system, const std::string& game_path,
+    Core::System& system, const std::string& game_path,
     const std::function<bool(size_t, size_t)>& callback) {
-    const auto loader = Loader::GetLoader(
-        *system, system->GetFilesystem()->OpenFile(game_path, FileSys::Mode::Read));
+    const auto loader =
+        Loader::GetLoader(system, system.GetFilesystem()->OpenFile(game_path, FileSys::Mode::Read));
     if (loader == nullptr) {
         return GameVerificationResult::NotImplemented;
     }
@@ -368,4 +368,11 @@ inline GameVerificationResult VerifyGameContents(
     return GameVerificationResult::Success;
 }
 
+/**
+ * Checks if the keys required for decrypting firmware and games are available
+ */
+inline bool AreKeysPresent() {
+    return !Core::Crypto::KeyManager::Instance().BaseDeriveNecessary();
+}
+
 } // namespace ContentManager

+ 10 - 115
src/yuzu/main.cpp

@@ -423,7 +423,7 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk
     RemoveCachedContents();
 
     // Gen keys if necessary
-    OnReinitializeKeys(ReinitializeKeyBehavior::NoWarning);
+    OnCheckFirmwareDecryption();
 
     game_list->LoadCompatibilityList();
     game_list->PopulateAsync(UISettings::values.game_dirs);
@@ -1574,8 +1574,6 @@ void GMainWindow::ConnectMenuEvents() {
     connect(multiplayer_state, &MultiplayerState::SaveConfig, this, &GMainWindow::OnSaveConfig);
 
     // Tools
-    connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this,
-                                                ReinitializeKeyBehavior::Warning));
     connect_menu(ui->action_Load_Album, &GMainWindow::OnAlbum);
     connect_menu(ui->action_Load_Cabinet_Nickname_Owner,
                  [this]() { OnCabinet(Service::NFP::CabinetMode::StartNicknameAndOwnerSettings); });
@@ -2501,7 +2499,7 @@ void GMainWindow::RemoveUpdateContent(u64 program_id, InstalledEntryType type) {
 }
 
 void GMainWindow::RemoveAddOnContent(u64 program_id, InstalledEntryType type) {
-    const size_t count = ContentManager::RemoveAllDLC(system.get(), program_id);
+    const size_t count = ContentManager::RemoveAllDLC(*system, program_id);
     if (count == 0) {
         QMessageBox::warning(this, GetGameListErrorRemoving(type),
                              tr("There are no DLC installed for this title."));
@@ -2798,8 +2796,7 @@ void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) {
         return progress.wasCanceled();
     };
 
-    const auto result =
-        ContentManager::VerifyGameContents(system.get(), game_path, QtProgressCallback);
+    const auto result = ContentManager::VerifyGameContents(*system, game_path, QtProgressCallback);
     progress.close();
     switch (result) {
     case ContentManager::GameVerificationResult::Success:
@@ -3268,7 +3265,7 @@ void GMainWindow::OnMenuInstallToNAND() {
                 return false;
             };
             future = QtConcurrent::run([this, &file, progress_callback] {
-                return ContentManager::InstallNSP(system.get(), vfs.get(), file.toStdString(),
+                return ContentManager::InstallNSP(*system, *vfs, file.toStdString(),
                                                   progress_callback);
             });
 
@@ -3371,7 +3368,7 @@ ContentManager::InstallResult GMainWindow::InstallNCA(const QString& filename) {
         }
         return false;
     };
-    return ContentManager::InstallNCA(vfs.get(), filename.toStdString(), registered_cache,
+    return ContentManager::InstallNCA(*vfs, filename.toStdString(), *registered_cache,
                                       static_cast<FileSys::TitleType>(index), progress_callback);
 }
 
@@ -4121,7 +4118,7 @@ void GMainWindow::OnVerifyInstalledContents() {
     };
 
     const std::vector<std::string> result =
-        ContentManager::VerifyInstalledContents(system.get(), provider.get(), QtProgressCallback);
+        ContentManager::VerifyInstalledContents(*system, *provider, QtProgressCallback);
     progress.close();
 
     if (result.empty()) {
@@ -4551,122 +4548,20 @@ void GMainWindow::OnMouseActivity() {
     }
 }
 
-void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
-    if (behavior == ReinitializeKeyBehavior::Warning) {
-        const auto res = QMessageBox::information(
-            this, tr("Confirm Key Rederivation"),
-            tr("You are about to force rederive all of your keys. \nIf you do not know what "
-               "this "
-               "means or what you are doing, \nthis is a potentially destructive action. "
-               "\nPlease "
-               "make sure this is what you want \nand optionally make backups.\n\nThis will "
-               "delete "
-               "your autogenerated key files and re-run the key derivation module."),
-            QMessageBox::StandardButtons{QMessageBox::Ok, QMessageBox::Cancel});
-
-        if (res == QMessageBox::Cancel)
-            return;
-
-        const auto keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
-
-        Common::FS::RemoveFile(keys_dir / "prod.keys_autogenerated");
-        Common::FS::RemoveFile(keys_dir / "console.keys_autogenerated");
-        Common::FS::RemoveFile(keys_dir / "title.keys_autogenerated");
-    }
-
-    Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
-    bool all_keys_present{true};
-
-    if (keys.BaseDeriveNecessary()) {
-        Core::Crypto::PartitionDataManager pdm{vfs->OpenDirectory("", FileSys::Mode::Read)};
-
-        const auto function = [this, &keys, &pdm] {
-            keys.PopulateFromPartitionData(pdm);
-
-            system->GetFileSystemController().CreateFactories(*vfs);
-            keys.DeriveETicket(pdm, system->GetContentProvider());
-        };
-
-        QString errors;
-        if (!pdm.HasFuses()) {
-            errors += tr("Missing fuses");
-        }
-        if (!pdm.HasBoot0()) {
-            errors += tr(" - Missing BOOT0");
-        }
-        if (!pdm.HasPackage2()) {
-            errors += tr(" - Missing BCPKG2-1-Normal-Main");
-        }
-        if (!pdm.HasProdInfo()) {
-            errors += tr(" - Missing PRODINFO");
-        }
-        if (!errors.isEmpty()) {
-            all_keys_present = false;
-            QMessageBox::warning(
-                this, tr("Derivation Components Missing"),
-                tr("Encryption keys are missing. "
-                   "<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu "
-                   "quickstart guide</a> to get all your keys, firmware and "
-                   "games.<br><br><small>(%1)</small>")
-                    .arg(errors));
-        }
-
-        QProgressDialog prog(this);
-        prog.setRange(0, 0);
-        prog.setLabelText(tr("Deriving keys...\nThis may take up to a minute depending \non your "
-                             "system's performance."));
-        prog.setWindowTitle(tr("Deriving Keys"));
-
-        prog.show();
-
-        auto future = QtConcurrent::run(function);
-        while (!future.isFinished()) {
-            QCoreApplication::processEvents();
-        }
-
-        prog.close();
-    }
-
+void GMainWindow::OnCheckFirmwareDecryption() {
     system->GetFileSystemController().CreateFactories(*vfs);
-
-    if (all_keys_present && !this->CheckSystemArchiveDecryption()) {
-        LOG_WARNING(Frontend, "Mii model decryption failed");
+    if (!ContentManager::AreKeysPresent()) {
         QMessageBox::warning(
-            this, tr("System Archive Decryption Failed"),
-            tr("Encryption keys failed to decrypt firmware. "
+            this, tr("Derivation Components Missing"),
+            tr("Encryption keys are missing. "
                "<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu "
                "quickstart guide</a> to get all your keys, firmware and "
                "games."));
     }
-
     SetFirmwareVersion();
-
-    if (behavior == ReinitializeKeyBehavior::Warning) {
-        game_list->PopulateAsync(UISettings::values.game_dirs);
-    }
-
     UpdateMenuState();
 }
 
-bool GMainWindow::CheckSystemArchiveDecryption() {
-    constexpr u64 MiiModelId = 0x0100000000000802;
-
-    auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
-    if (!bis_system) {
-        // Not having system BIS files is not an error.
-        return true;
-    }
-
-    auto mii_nca = bis_system->GetEntry(MiiModelId, FileSys::ContentRecordType::Data);
-    if (!mii_nca) {
-        // Not having the Mii model is not an error.
-        return true;
-    }
-
-    // Return whether we are able to decrypt the RomFS of the Mii model.
-    return mii_nca->GetRomFS().get() != nullptr;
-}
-
 bool GMainWindow::CheckFirmwarePresence() {
     constexpr u64 MiiEditId = static_cast<u64>(Service::AM::Applets::AppletProgramId::MiiEdit);
 

+ 1 - 7
src/yuzu/main.h

@@ -125,11 +125,6 @@ enum class EmulatedDirectoryTarget {
     SDMC,
 };
 
-enum class ReinitializeKeyBehavior {
-    NoWarning,
-    Warning,
-};
-
 namespace VkDeviceInfo {
 class Record;
 }
@@ -400,7 +395,7 @@ private slots:
     void OnMiiEdit();
     void OnOpenControllerMenu();
     void OnCaptureScreenshot();
-    void OnReinitializeKeys(ReinitializeKeyBehavior behavior);
+    void OnCheckFirmwareDecryption();
     void OnLanguageChanged(const QString& locale);
     void OnMouseActivity();
     bool OnShutdownBegin();
@@ -441,7 +436,6 @@ private:
     void LoadTranslation();
     void OpenPerGameConfiguration(u64 title_id, const std::string& file_name);
     bool CheckDarkMode();
-    bool CheckSystemArchiveDecryption();
     bool CheckFirmwarePresence();
     void SetFirmwareVersion();
     void ConfigureFilesystemProvider(const std::string& filepath);

+ 0 - 5
src/yuzu/main.ui

@@ -224,11 +224,6 @@
     <string>&amp;Stop</string>
    </property>
   </action>
-  <action name="action_Rederive">
-   <property name="text">
-    <string>&amp;Reinitialize keys...</string>
-   </property>
-  </action>
   <action name="action_Verify_installed_contents">
    <property name="text">
     <string>&amp;Verify Installed Contents</string>