Skip to content

Commit

Permalink
Merge pull request from GHSA-wxrm-jhpf-vp6v
Browse files Browse the repository at this point in the history
Fix preferences import vulnerability
  • Loading branch information
Stypox committed Apr 23, 2024
2 parents c915b6e + f0db2aa commit a69bbab
Show file tree
Hide file tree
Showing 27 changed files with 665 additions and 244 deletions.
1 change: 1 addition & 0 deletions app/src/main/java/org/schabi/newpipe/error/UserAction.java
Expand Up @@ -6,6 +6,7 @@
public enum UserAction {
USER_REPORT("user report"),
UI_ERROR("ui error"),
DATABASE_IMPORT_EXPORT("database import or export"),
SUBSCRIPTION_CHANGE("subscription change"),
SUBSCRIPTION_UPDATE("subscription update"),
SUBSCRIPTION_GET("get subscription"),
Expand Down
Expand Up @@ -21,9 +21,15 @@
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;

import com.grack.nanojson.JsonParserException;

import org.schabi.newpipe.NewPipeDatabase;
import org.schabi.newpipe.R;
import org.schabi.newpipe.error.ErrorInfo;
import org.schabi.newpipe.error.ErrorUtil;
import org.schabi.newpipe.error.UserAction;
import org.schabi.newpipe.settings.export.BackupFileLocator;
import org.schabi.newpipe.settings.export.ImportExportManager;
import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard;
import org.schabi.newpipe.streams.io.StoredFileHelper;
import org.schabi.newpipe.util.NavigationHelper;
Expand All @@ -42,7 +48,7 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {

private final SimpleDateFormat exportDateFormat =
new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US);
private ContentSettingsManager manager;
private ImportExportManager manager;
private String importExportDataPathKey;
private final ActivityResultLauncher<Intent> requestImportPathLauncher =
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
Expand All @@ -57,8 +63,7 @@ public void onCreatePreferences(@Nullable final Bundle savedInstanceState,
@Nullable final String rootKey) {
final File homeDir = ContextCompat.getDataDir(requireContext());
Objects.requireNonNull(homeDir);
manager = new ContentSettingsManager(new NewPipeFileLocator(homeDir));
manager.deleteSettingsFile();
manager = new ImportExportManager(new BackupFileLocator(homeDir));

importExportDataPathKey = getString(R.string.import_export_data_path);

Expand Down Expand Up @@ -165,7 +170,7 @@ private void exportDatabase(final StoredFileHelper file, final Uri exportDataUri
Toast.makeText(requireContext(), R.string.export_complete_toast, Toast.LENGTH_SHORT)
.show();
} catch (final Exception e) {
ErrorUtil.showUiErrorSnackbar(this, "Exporting database", e);
showErrorSnackbar(e, "Exporting database and settings");
}
}

Expand All @@ -182,16 +187,21 @@ private void importDatabase(final StoredFileHelper file, final Uri importDataUri
throw new IOException("Could not create databases dir");
}

// replace the current database
if (!manager.extractDb(file)) {
Toast.makeText(requireContext(), R.string.could_not_import_all_files,
Toast.LENGTH_LONG)
.show();
}

// if settings file exist, ask if it should be imported.
if (manager.extractSettings(file)) {
final boolean hasJsonPrefs = manager.exportHasJsonPrefs(file);
if (hasJsonPrefs || manager.exportHasSerializedPrefs(file)) {
new androidx.appcompat.app.AlertDialog.Builder(requireContext())
.setTitle(R.string.import_settings)
.setMessage(hasJsonPrefs ? null : requireContext()
.getString(R.string.import_settings_vulnerable_format))
.setOnDismissListener(dialog -> finishImport(importDataUri))
.setNegativeButton(R.string.cancel, (dialog, which) -> {
dialog.dismiss();
finishImport(importDataUri);
Expand All @@ -201,7 +211,16 @@ private void importDatabase(final StoredFileHelper file, final Uri importDataUri
final Context context = requireContext();
final SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context);
manager.loadSharedPreferences(prefs);
try {
if (hasJsonPrefs) {
manager.loadJsonPrefs(file, prefs);
} else {
manager.loadSerializedPrefs(file, prefs);
}
} catch (IOException | ClassNotFoundException | JsonParserException e) {
createErrorNotification(e, "Importing preferences");
return;
}
cleanImport(context, prefs);
finishImport(importDataUri);
})
Expand All @@ -210,7 +229,7 @@ private void importDatabase(final StoredFileHelper file, final Uri importDataUri
finishImport(importDataUri);
}
} catch (final Exception e) {
ErrorUtil.showUiErrorSnackbar(this, "Importing database", e);
showErrorSnackbar(e, "Importing database and settings");
}
}

Expand Down Expand Up @@ -247,7 +266,7 @@ private void cleanImport(@NonNull final Context context,
}

/**
* Save import path and restart system.
* Save import path and restart app.
*
* @param importDataUri The import path to save
*/
Expand All @@ -268,4 +287,15 @@ private void saveLastImportExportDataUri(final Uri importExportDataUri) {
.putString(importExportDataPathKey, importExportDataUri.toString());
editor.apply();
}

private void showErrorSnackbar(final Throwable e, final String request) {
ErrorUtil.showSnackbar(this, new ErrorInfo(e, UserAction.DATABASE_IMPORT_EXPORT, request));
}

private void createErrorNotification(final Throwable e, final String request) {
ErrorUtil.createNotification(
requireContext(),
new ErrorInfo(e, UserAction.DATABASE_IMPORT_EXPORT, request)
);
}
}

This file was deleted.

This file was deleted.

@@ -0,0 +1,28 @@
package org.schabi.newpipe.settings.export

import java.io.File

/**
* Locates specific files of NewPipe based on the home directory of the app.
*/
class BackupFileLocator(private val homeDir: File) {
companion object {
const val FILE_NAME_DB = "newpipe.db"
@Deprecated(
"Serializing preferences with Java's ObjectOutputStream is vulnerable to injections",
replaceWith = ReplaceWith("FILE_NAME_JSON_PREFS")
)
const val FILE_NAME_SERIALIZED_PREFS = "newpipe.settings"
const val FILE_NAME_JSON_PREFS = "preferences.json"
}

val dbDir by lazy { File(homeDir, "/databases") }

val db by lazy { File(dbDir, FILE_NAME_DB) }

val dbJournal by lazy { File(dbDir, "$FILE_NAME_DB-journal") }

val dbShm by lazy { File(dbDir, "$FILE_NAME_DB-shm") }

val dbWal by lazy { File(dbDir, "$FILE_NAME_DB-wal") }
}

0 comments on commit a69bbab

Please sign in to comment.