Verify database version before import

This commit is contained in:
ByteHamster 2020-02-05 00:29:07 +01:00
parent 7e2fd0b1d7
commit 75e0d2d7e1
4 changed files with 22 additions and 29 deletions

View File

@ -216,8 +216,8 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
private void showExportErrorDialog(final Throwable error) { private void showExportErrorDialog(final Throwable error) {
progressDialog.dismiss(); progressDialog.dismiss();
final AlertDialog.Builder alert = new AlertDialog.Builder(getContext()) final AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
.setNeutralButton(android.R.string.ok, (dialog, which) -> dialog.dismiss()); alert.setPositiveButton(android.R.string.ok, (dialog, which) -> dialog.dismiss());
alert.setTitle(R.string.export_error_label); alert.setTitle(R.string.export_error_label);
alert.setMessage(error.getMessage()); alert.setMessage(error.getMessage());
alert.show(); alert.show();

View File

@ -1,6 +1,8 @@
package de.danoeh.antennapod.core.storage; package de.danoeh.antennapod.core.storage;
import android.content.Context; import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.net.Uri; import android.net.Uri;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.util.Log; import android.util.Log;
@ -14,21 +16,10 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.util.Arrays;
public class DatabaseExporter { public class DatabaseExporter {
private static final String TAG = "DatabaseExporter"; private static final String TAG = "DatabaseExporter";
private static final byte[] SQLITE3_MAGIC = "SQLite format 3\0".getBytes(); private static final String TEMP_DB_NAME = PodDBAdapter.DATABASE_NAME + "_tmp";
public static boolean validateDB(Uri inputUri, Context context) throws IOException {
try (InputStream inputStream = context.getContentResolver().openInputStream(inputUri)) {
byte[] magicBuf = new byte[SQLITE3_MAGIC.length];
if (inputStream.read(magicBuf) == magicBuf.length) {
return Arrays.equals(SQLITE3_MAGIC, magicBuf);
}
}
return false;
}
public static void exportToDocument(Uri uri, Context context) throws IOException { public static void exportToDocument(Uri uri, Context context) throws IOException {
ParcelFileDescriptor pfd = null; ParcelFileDescriptor pfd = null;
@ -78,14 +69,21 @@ public class DatabaseExporter {
public static void importBackup(Uri inputUri, Context context) throws IOException { public static void importBackup(Uri inputUri, Context context) throws IOException {
InputStream inputStream = null; InputStream inputStream = null;
try { try {
if (!validateDB(inputUri, context)) { File tempDB = context.getDatabasePath(TEMP_DB_NAME);
throw new IOException(context.getString(R.string.import_bad_file)); inputStream = context.getContentResolver().openInputStream(inputUri);
FileUtils.copyInputStreamToFile(inputStream, tempDB);
SQLiteDatabase db = SQLiteDatabase.openDatabase(tempDB.getAbsolutePath(),
null, SQLiteDatabase.OPEN_READONLY);
if (db.getVersion() > PodDBAdapter.VERSION) {
throw new IOException(context.getString(R.string.import_no_downgrade));
} }
db.close();
File currentDB = context.getDatabasePath(PodDBAdapter.DATABASE_NAME); File currentDB = context.getDatabasePath(PodDBAdapter.DATABASE_NAME);
inputStream = context.getContentResolver().openInputStream(inputUri); currentDB.delete();
FileUtils.copyInputStreamToFile(inputStream, currentDB); FileUtils.moveFile(tempDB, currentDB);
} catch (IOException e) { } catch (IOException | SQLiteException e) {
Log.e(TAG, Log.getStackTraceString(e)); Log.e(TAG, Log.getStackTraceString(e));
throw e; throw e;
} finally { } finally {

View File

@ -48,6 +48,7 @@ public class PodDBAdapter {
private static final String TAG = "PodDBAdapter"; private static final String TAG = "PodDBAdapter";
public static final String DATABASE_NAME = "Antennapod.db"; public static final String DATABASE_NAME = "Antennapod.db";
public static final int VERSION = 1090000;
/** /**
* Maximum number of arguments for IN-operator. * Maximum number of arguments for IN-operator.
@ -1336,8 +1337,6 @@ public class PodDBAdapter {
* Helper class for opening the Antennapod database. * Helper class for opening the Antennapod database.
*/ */
private static class PodDBHelper extends SQLiteOpenHelper { private static class PodDBHelper extends SQLiteOpenHelper {
private static final int VERSION = 1090000;
/** /**
* Constructor. * Constructor.
* *
@ -1345,8 +1344,7 @@ public class PodDBAdapter {
* @param name Name of the database * @param name Name of the database
* @param factory to use for creating cursor objects * @param factory to use for creating cursor objects
*/ */
public PodDBHelper(final Context context, final String name, public PodDBHelper(final Context context, final String name, final CursorFactory factory) {
final CursorFactory factory) {
super(context, name, factory, VERSION, new PodDbErrorHandler()); super(context, name, factory, VERSION, new PodDbErrorHandler());
} }
@ -1369,10 +1367,8 @@ public class PodDBAdapter {
} }
@Override @Override
public void onUpgrade(final SQLiteDatabase db, final int oldVersion, public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
final int newVersion) { Log.w("DBAdapter", "Upgrading from version " + oldVersion + " to " + newVersion + ".");
Log.w("DBAdapter", "Upgrading from version " + oldVersion + " to "
+ newVersion + ".");
DBUpgrader.upgrade(db, oldVersion, newVersion); DBUpgrader.upgrade(db, oldVersion, newVersion);
} }
} }

View File

@ -572,6 +572,7 @@
<string name="opml_import_ask_read_permission">Access to external storage is required to read the OPML file</string> <string name="opml_import_ask_read_permission">Access to external storage is required to read the OPML file</string>
<string name="import_select_file">Select file to import</string> <string name="import_select_file">Select file to import</string>
<string name="import_ok">Import successful.\n\nPlease press OK to restart AntennaPod</string> <string name="import_ok">Import successful.\n\nPlease press OK to restart AntennaPod</string>
<string name="import_no_downgrade">This database was exported with a newer version of AntennaPod. Your current installation does not yet know how to handle this file.</string>
<!-- Sleep timer --> <!-- Sleep timer -->
<string name="set_sleeptimer_label">Set sleep timer</string> <string name="set_sleeptimer_label">Set sleep timer</string>
@ -768,7 +769,6 @@
<string name="cast_failed_to_play">Failed to start the playback of media</string> <string name="cast_failed_to_play">Failed to start the playback of media</string>
<string name="cast_failed_to_stop">Failed to stop the playback of media</string> <string name="cast_failed_to_stop">Failed to stop the playback of media</string>
<string name="cast_failed_to_pause">Failed to pause the playback of media</string> <string name="cast_failed_to_pause">Failed to pause the playback of media</string>
<!--<string name="cast_failed_to_connect">Could not connect to the device</string>-->
<string name="cast_failed_setting_volume">Failed to set the volume</string> <string name="cast_failed_setting_volume">Failed to set the volume</string>
<string name="cast_failed_no_connection">No connection to the cast device is present</string> <string name="cast_failed_no_connection">No connection to the cast device is present</string>
<string name="cast_failed_no_connection_trans">Connection to the cast device has been lost. Application is trying to re-establish the connection, if possible. Please wait for a few seconds and try again.</string> <string name="cast_failed_no_connection_trans">Connection to the cast device has been lost. Application is trying to re-establish the connection, if possible. Please wait for a few seconds and try again.</string>
@ -786,7 +786,6 @@
<string name="notification_channel_playing_description">Allows to control playback. This is the main notification you see while playing a podcast.</string> <string name="notification_channel_playing_description">Allows to control playback. This is the main notification you see while playing a podcast.</string>
<string name="notification_channel_error">Errors</string> <string name="notification_channel_error">Errors</string>
<string name="notification_channel_error_description">Shown if something went wrong, for example if download or gpodder sync fails.</string> <string name="notification_channel_error_description">Shown if something went wrong, for example if download or gpodder sync fails.</string>
<string name="import_bad_file">Invalid/corrupt file</string>
<!-- Widget settings --> <!-- Widget settings -->
<string name="widget_settings">Widget settings</string> <string name="widget_settings">Widget settings</string>