improved error handling for dropbox filestorage

This commit is contained in:
Philipp Crocoll 2013-09-17 06:53:18 +02:00
parent 15fde6ff92
commit 176ad6244d
8 changed files with 186 additions and 106 deletions

View File

@ -30,6 +30,7 @@ namespace keepass2android
public static void Log(string message) public static void Log(string message)
{ {
if (message != null)
Android.Util.Log.Debug("KP2A", message); Android.Util.Log.Debug("KP2A", message);
if (LogToFile) if (LogToFile)
{ {

View File

@ -17,8 +17,8 @@ namespace keepass2android.Io
{ {
public class DropboxFileStorage: JavaFileStorage public class DropboxFileStorage: JavaFileStorage
{ {
public DropboxFileStorage(Context ctx) : public DropboxFileStorage(Context ctx, IKp2aApp app) :
base(new Keepass2android.Javafilestorage.DropboxFileStorage(ctx)) base(new Keepass2android.Javafilestorage.DropboxFileStorage(ctx), app)
{ {
} }

View File

@ -1,16 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text;
using Android.App; using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Java.Lang;
using KeePassLib.Serialization; using KeePassLib.Serialization;
using KeePassLib.Utility; using KeePassLib.Utility;
using Keepass2android.Javafilestorage; using Keepass2android.Javafilestorage;
@ -23,11 +14,13 @@ namespace keepass2android.Io
{ {
public abstract IEnumerable<string> SupportedProtocols { get; } public abstract IEnumerable<string> SupportedProtocols { get; }
private IJavaFileStorage _jfs; private readonly IJavaFileStorage _jfs;
private readonly IKp2aApp _app;
public JavaFileStorage(IJavaFileStorage jfs) public JavaFileStorage(IJavaFileStorage jfs, IKp2aApp app)
{ {
this._jfs = jfs; _jfs = jfs;
_app = app;
} }
public void DeleteFile(IOConnectionInfo ioc) public void DeleteFile(IOConnectionInfo ioc)
@ -37,14 +30,17 @@ namespace keepass2android.Io
public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion) public bool CheckForFileChangeFast(IOConnectionInfo ioc, string previousFileVersion)
{ {
try return false;
//commented because this currently might use the network which is not permitted here
/*try
{ {
return _jfs.CheckForFileChangeFast(ioc.Path, previousFileVersion); return Jfs.CheckForFileChangeFast(ioc.Path, previousFileVersion);
} }
catch (Java.Lang.Exception e) catch (Java.Lang.Exception e)
{ {
throw LogAndConvertJavaException(e); throw LogAndConvertJavaException(e);
} }*/
} }
@ -52,7 +48,7 @@ namespace keepass2android.Io
{ {
try try
{ {
return _jfs.GetCurrentFileVersionFast(ioc.Path); return Jfs.GetCurrentFileVersionFast(ioc.Path);
} }
catch (Java.Lang.Exception e) catch (Java.Lang.Exception e)
{ {
@ -64,7 +60,7 @@ namespace keepass2android.Io
{ {
try try
{ {
return _jfs.OpenFileForRead(IocToPath(ioc)); return Jfs.OpenFileForRead(IocToPath(ioc));
} }
catch (FileNotFoundException e) catch (FileNotFoundException e)
{ {
@ -77,28 +73,35 @@ namespace keepass2android.Io
} }
private static Exception LogAndConvertJavaException(Java.Lang.Exception e) private Exception LogAndConvertJavaException(Java.Lang.Exception e)
{ {
Kp2aLog.Log(e.Message); Kp2aLog.Log(e.Message);
var ex = new Exception(e.LocalizedMessage ?? e.Message, e); var ex = new Exception(e.LocalizedMessage ??
e.Message ??
_app.GetResourceString(UiStringKey.ErrorOcurred)+e, e);
return ex; return ex;
} }
public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction) public IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction)
{ {
return new JavaFileStorageWriteTransaction(IocToPath(ioc), useFileTransaction, _jfs); return new JavaFileStorageWriteTransaction(IocToPath(ioc), useFileTransaction, this);
} }
public IFileStorageSetup RequiredSetup public IFileStorageSetup RequiredSetup
{ {
get get
{ {
if (_jfs.IsConnected) if (Jfs.IsConnected)
return null; return null;
return new JavaFileStorageSetup(this); return new JavaFileStorageSetup(this);
} }
} }
internal IJavaFileStorage Jfs
{
get { return _jfs; }
}
public class JavaFileStorageSetup : IFileStorageSetup, IFileStorageSetupOnResume public class JavaFileStorageSetup : IFileStorageSetup, IFileStorageSetupOnResume
{ {
private readonly JavaFileStorage _javaFileStorage; private readonly JavaFileStorage _javaFileStorage;
@ -112,11 +115,11 @@ namespace keepass2android.Io
{ {
try try
{ {
return _javaFileStorage._jfs.TryConnect(activity); return _javaFileStorage.Jfs.TryConnect(activity);
} }
catch (Java.Lang.Exception e) catch (Java.Lang.Exception e)
{ {
throw LogAndConvertJavaException(e); throw _javaFileStorage.LogAndConvertJavaException(e);
} }
} }
@ -124,12 +127,12 @@ namespace keepass2android.Io
{ {
try try
{ {
_javaFileStorage._jfs.OnResume(); _javaFileStorage.Jfs.OnResume();
return _javaFileStorage._jfs.IsConnected; return _javaFileStorage.Jfs.IsConnected;
} }
catch (Java.Lang.Exception e) catch (Java.Lang.Exception e)
{ {
throw LogAndConvertJavaException(e); throw _javaFileStorage.LogAndConvertJavaException(e);
} }
} }
} }
@ -138,10 +141,10 @@ namespace keepass2android.Io
{ {
private readonly string _path; private readonly string _path;
private readonly bool _useFileTransaction; private readonly bool _useFileTransaction;
private readonly IJavaFileStorage _javaFileStorage; private readonly JavaFileStorage _javaFileStorage;
private MemoryStream _memoryStream; private MemoryStream _memoryStream;
public JavaFileStorageWriteTransaction(string path, bool useFileTransaction, IJavaFileStorage javaFileStorage) public JavaFileStorageWriteTransaction(string path, bool useFileTransaction, JavaFileStorage javaFileStorage)
{ {
_path = path; _path = path;
_useFileTransaction = useFileTransaction; _useFileTransaction = useFileTransaction;
@ -163,11 +166,11 @@ namespace keepass2android.Io
{ {
try try
{ {
_javaFileStorage.UploadFile(_path, _memoryStream.ToArray(), _useFileTransaction); _javaFileStorage.Jfs.UploadFile(_path, _memoryStream.ToArray(), _useFileTransaction);
} }
catch (Java.Lang.Exception e) catch (Java.Lang.Exception e)
{ {
LogAndConvertJavaException(e); throw _javaFileStorage.LogAndConvertJavaException(e);
} }
} }
} }

View File

@ -22,6 +22,7 @@ import com.dropbox.client2.android.AndroidAuthSession;
import com.dropbox.client2.android.AuthActivity; import com.dropbox.client2.android.AuthActivity;
import com.dropbox.client2.exception.DropboxException; import com.dropbox.client2.exception.DropboxException;
import com.dropbox.client2.exception.DropboxServerException; import com.dropbox.client2.exception.DropboxServerException;
import com.dropbox.client2.exception.DropboxUnlinkedException;
import com.dropbox.client2.session.AccessTokenPair; import com.dropbox.client2.session.AccessTokenPair;
import com.dropbox.client2.session.AppKeyPair; import com.dropbox.client2.session.AppKeyPair;
import com.dropbox.client2.session.TokenPair; import com.dropbox.client2.session.TokenPair;
@ -182,6 +183,14 @@ public class DropboxFileStorage implements JavaFileStorage {
Log.d(TAG, "Exception of type " +e.getClass().getName()+":" + e.getMessage()); Log.d(TAG, "Exception of type " +e.getClass().getName()+":" + e.getMessage());
if (DropboxUnlinkedException.class.isAssignableFrom(e.getClass()) )
{
Log.d(TAG, "LoggedIn=false (due to unlink exception)");
setLoggedIn(false);
return new Exception("Unlinked from Dropbox!", e);
}
//test for special error FileNotFound which must be reported with FileNotFoundException //test for special error FileNotFound which must be reported with FileNotFoundException
if (DropboxServerException.class.isAssignableFrom(e.getClass()) ) if (DropboxServerException.class.isAssignableFrom(e.getClass()) )
{ {

View File

@ -47,9 +47,9 @@ namespace keepass2android
public const String KeyFilename = "fileName"; public const String KeyFilename = "fileName";
private const String KeyKeyfile = "keyFile"; private const String KeyKeyfile = "keyFile";
private const String KeyServerusername = "serverCredUser"; public const String KeyServerusername = "serverCredUser";
private const String KeyServerpassword = "serverCredPwd"; public const String KeyServerpassword = "serverCredPwd";
private const String KeyServercredmode = "serverCredRememberMode"; public const String KeyServercredmode = "serverCredRememberMode";
private const String ViewIntent = "android.intent.action.VIEW"; private const String ViewIntent = "android.intent.action.VIEW";
private const string ShowpasswordKey = "ShowPassword"; private const string ShowpasswordKey = "ShowPassword";
@ -74,7 +74,7 @@ namespace keepass2android
} }
static void PutIoConnectionToIntent(IOConnectionInfo ioc, Intent i) public static void PutIoConnectionToIntent(IOConnectionInfo ioc, Intent i)
{ {
i.PutExtra(KeyFilename, ioc.Path); i.PutExtra(KeyFilename, ioc.Path);
i.PutExtra(KeyServerusername, ioc.UserName); i.PutExtra(KeyServerusername, ioc.UserName);
@ -463,6 +463,18 @@ namespace keepass2android
Kp2aLog.Log("Starting QuickUnlock"); Kp2aLog.Log("Starting QuickUnlock");
StartActivityForResult(i, 0); StartActivityForResult(i, 0);
} }
else
{
//database not yet loaded.
//check if FileStorage setup is all done. Usually this should not occur here because the setup is
//performed in FileSelectActivity, but e.g. if the user unlinks from Dropbox saving might fail and
//the user is returned here.
if (App.Kp2a.GetFileStorage(_ioConnection).RequiredSetup != null)
{
GoToFileSelectActivity();
}
//check if pre-loading is enabled but wasn't started yet:
else if (_loadDbTask == null && _prefs.GetBoolean(GetString(Resource.String.PreloadDatabaseEnabled_key), true)) else if (_loadDbTask == null && _prefs.GetBoolean(GetString(Resource.String.PreloadDatabaseEnabled_key), true))
{ {
// Create task to kick off file loading while the user enters the password // Create task to kick off file loading while the user enters the password
@ -470,6 +482,7 @@ namespace keepass2android
} }
} }
} }
}
private void RetrieveSettings() { private void RetrieveSettings() {
CheckBox cbQuickUnlock = (CheckBox)FindViewById(Resource.Id.enable_quickunlock); CheckBox cbQuickUnlock = (CheckBox)FindViewById(Resource.Id.enable_quickunlock);
@ -539,18 +552,19 @@ namespace keepass2android
return true; return true;
case Resource.Id.menu_change_db: case Resource.Id.menu_change_db:
GoToFileSelectActivity();
return true;
}
return base.OnOptionsItemSelected(item);
}
private void GoToFileSelectActivity()
{
Intent intent = new Intent(this, typeof (FileSelectActivity)); Intent intent = new Intent(this, typeof (FileSelectActivity));
AppTask.ToIntent(intent); AppTask.ToIntent(intent);
StartActivityForResult(intent, 0); StartActivityForResult(intent, 0);
Finish(); Finish();
return true;
}
return base.OnOptionsItemSelected(item);
} }
private class AfterLoad : OnFinish { private class AfterLoad : OnFinish {

View File

@ -1403,41 +1403,41 @@ namespace keepass2android
// aapt resource value: 0x7f060113 // aapt resource value: 0x7f060113
public const int BinaryDirectory_title = 2131099923; public const int BinaryDirectory_title = 2131099923;
// aapt resource value: 0x7f060166 // aapt resource value: 0x7f060167
public const int CannotMoveGroupHere = 2131100006; public const int CannotMoveGroupHere = 2131100007;
// aapt resource value: 0x7f06017b
public const int ChangeLog = 2131100027;
// aapt resource value: 0x7f06017a // aapt resource value: 0x7f06017a
public const int ChangeLog = 2131100026; public const int ChangeLog_0_7 = 2131100026;
// aapt resource value: 0x7f060179
public const int ChangeLog_0_7 = 2131100025;
// aapt resource value: 0x7f060177
public const int ChangeLog_0_8 = 2131100023;
// aapt resource value: 0x7f060176
public const int ChangeLog_0_8_1 = 2131100022;
// aapt resource value: 0x7f060175
public const int ChangeLog_0_8_2 = 2131100021;
// aapt resource value: 0x7f060174
public const int ChangeLog_0_8_3 = 2131100020;
// aapt resource value: 0x7f060173
public const int ChangeLog_0_8_4 = 2131100019;
// aapt resource value: 0x7f060172
public const int ChangeLog_0_8_5 = 2131100018;
// aapt resource value: 0x7f060171
public const int ChangeLog_0_8_6 = 2131100017;
// aapt resource value: 0x7f060178 // aapt resource value: 0x7f060178
public const int ChangeLog_keptDonate = 2131100024; public const int ChangeLog_0_8 = 2131100024;
// aapt resource value: 0x7f060170 // aapt resource value: 0x7f060177
public const int ChangeLog_title = 2131100016; public const int ChangeLog_0_8_1 = 2131100023;
// aapt resource value: 0x7f060176
public const int ChangeLog_0_8_2 = 2131100022;
// aapt resource value: 0x7f060175
public const int ChangeLog_0_8_3 = 2131100021;
// aapt resource value: 0x7f060174
public const int ChangeLog_0_8_4 = 2131100020;
// aapt resource value: 0x7f060173
public const int ChangeLog_0_8_5 = 2131100019;
// aapt resource value: 0x7f060172
public const int ChangeLog_0_8_6 = 2131100018;
// aapt resource value: 0x7f060179
public const int ChangeLog_keptDonate = 2131100025;
// aapt resource value: 0x7f060171
public const int ChangeLog_title = 2131100017;
// aapt resource value: 0x7f060032 // aapt resource value: 0x7f060032
public const int CheckForFileChangesOnSave_key = 2131099698; public const int CheckForFileChangesOnSave_key = 2131099698;
@ -1487,6 +1487,9 @@ namespace keepass2android
// aapt resource value: 0x7f060158 // aapt resource value: 0x7f060158
public const int DownloadingRemoteFile = 2131099992; public const int DownloadingRemoteFile = 2131099992;
// aapt resource value: 0x7f060165
public const int ErrorOcurred = 2131100005;
// aapt resource value: 0x7f060055 // aapt resource value: 0x7f060055
public const int FileHandling_prefs = 2131099733; public const int FileHandling_prefs = 2131099733;
@ -1898,8 +1901,8 @@ namespace keepass2android
// aapt resource value: 0x7f060027 // aapt resource value: 0x7f060027
public const int display_prefs_key = 2131099687; public const int display_prefs_key = 2131099687;
// aapt resource value: 0x7f060167 // aapt resource value: 0x7f060168
public const int donate_question = 2131100007; public const int donate_question = 2131100008;
// aapt resource value: 0x7f06000c // aapt resource value: 0x7f06000c
public const int donate_url = 2131099660; public const int donate_url = 2131099660;
@ -2054,23 +2057,23 @@ namespace keepass2android
// aapt resource value: 0x7f060094 // aapt resource value: 0x7f060094
public const int file_browser = 2131099796; public const int file_browser = 2131099796;
// aapt resource value: 0x7f06016e // aapt resource value: 0x7f06016f
public const int filestoragename_dropbox = 2131100014; public const int filestoragename_dropbox = 2131100015;
// aapt resource value: 0x7f06016a
public const int filestoragename_file = 2131100010;
// aapt resource value: 0x7f06016b // aapt resource value: 0x7f06016b
public const int filestoragename_ftp = 2131100011; public const int filestoragename_file = 2131100011;
// aapt resource value: 0x7f06016f
public const int filestoragename_gdrive = 2131100015;
// aapt resource value: 0x7f06016c // aapt resource value: 0x7f06016c
public const int filestoragename_http = 2131100012; public const int filestoragename_ftp = 2131100012;
// aapt resource value: 0x7f060170
public const int filestoragename_gdrive = 2131100016;
// aapt resource value: 0x7f06016d // aapt resource value: 0x7f06016d
public const int filestoragename_https = 2131100013; public const int filestoragename_http = 2131100013;
// aapt resource value: 0x7f06016e
public const int filestoragename_https = 2131100014;
// aapt resource value: 0x7f06000f // aapt resource value: 0x7f06000f
public const int further_author_names = 2131099663; public const int further_author_names = 2131099663;
@ -2282,8 +2285,8 @@ namespace keepass2android
// aapt resource value: 0x7f0600cc // aapt resource value: 0x7f0600cc
public const int no_results = 2131099852; public const int no_results = 2131099852;
// aapt resource value: 0x7f060169 // aapt resource value: 0x7f06016a
public const int no_thanks = 2131100009; public const int no_thanks = 2131100010;
// aapt resource value: 0x7f0600cd // aapt resource value: 0x7f0600cd
public const int no_url_handler = 2131099853; public const int no_url_handler = 2131099853;
@ -2297,8 +2300,8 @@ namespace keepass2android
// aapt resource value: 0x7f060012 // aapt resource value: 0x7f060012
public const int oi_filemanager_web = 2131099666; public const int oi_filemanager_web = 2131099666;
// aapt resource value: 0x7f060168 // aapt resource value: 0x7f060169
public const int ok_donate = 2131100008; public const int ok_donate = 2131100009;
// aapt resource value: 0x7f06001b // aapt resource value: 0x7f06001b
public const int omitbackup_key = 2131099675; public const int omitbackup_key = 2131099675;
@ -2444,8 +2447,8 @@ namespace keepass2android
// aapt resource value: 0x7f060145 // aapt resource value: 0x7f060145
public const int suggest_improvements = 2131099973; public const int suggest_improvements = 2131099973;
// aapt resource value: 0x7f060165 // aapt resource value: 0x7f060166
public const int synchronize_database_menu = 2131100005; public const int synchronize_database_menu = 2131100006;
// aapt resource value: 0x7f060147 // aapt resource value: 0x7f060147
public const int translate_app = 2131099975; public const int translate_app = 2131099975;

View File

@ -386,7 +386,7 @@ namespace keepass2android
{ {
_fileStorages = new List<IFileStorage> _fileStorages = new List<IFileStorage>
{ {
new DropboxFileStorage(Application.Context), new DropboxFileStorage(Application.Context, this),
new BuiltInFileStorage() new BuiltInFileStorage()
}; };
} }

View File

@ -25,6 +25,7 @@ using Android.Views;
using Android.Widget; using Android.Widget;
using Android.Content.PM; using Android.Content.PM;
using KeePassLib.Serialization; using KeePassLib.Serialization;
using keepass2android.Io;
namespace keepass2android namespace keepass2android
{ {
@ -59,9 +60,9 @@ namespace keepass2android
private bool _recentMode; private bool _recentMode;
view.FileSelectButtons _fileSelectButtons; view.FileSelectButtons _fileSelectButtons;
bool _createdWithActivityResult;
internal AppTask AppTask; internal AppTask AppTask;
private IOConnectionInfo _iocToLaunch;
void ShowFilenameDialog(bool showOpenButton, bool showCreateButton, bool showBrowseButton, string defaultFilename, string detailsText, int requestCodeBrowse) void ShowFilenameDialog(bool showOpenButton, bool showCreateButton, bool showBrowseButton, string defaultFilename, string detailsText, int requestCodeBrowse)
{ {
@ -279,6 +280,18 @@ namespace keepass2android
AppTask = AppTask.CreateFromBundle(savedInstanceState); AppTask = AppTask.CreateFromBundle(savedInstanceState);
_recentMode = savedInstanceState.GetBoolean(BundleKeyRecentMode, _recentMode); _recentMode = savedInstanceState.GetBoolean(BundleKeyRecentMode, _recentMode);
string filenameToLaunch = savedInstanceState.GetString(PasswordActivity.KeyFilename);
if (filenameToLaunch != null)
{
_iocToLaunch = new IOConnectionInfo()
{
Path = filenameToLaunch,
UserName = savedInstanceState.GetString(PasswordActivity.KeyServerusername),
Password = savedInstanceState.GetString(PasswordActivity.KeyServerpassword),
CredSaveMode = (IOCredSaveMode) savedInstanceState.GetInt(PasswordActivity.KeyServercredmode)
};
}
} }
@ -305,6 +318,14 @@ namespace keepass2android
base.OnSaveInstanceState(outState); base.OnSaveInstanceState(outState);
AppTask.ToBundle(outState); AppTask.ToBundle(outState);
outState.PutBoolean(BundleKeyRecentMode, _recentMode); outState.PutBoolean(BundleKeyRecentMode, _recentMode);
if (_iocToLaunch != null)
{
outState.PutString(PasswordActivity.KeyFilename, _iocToLaunch.Path);
outState.PutString(PasswordActivity.KeyServerusername, _iocToLaunch.UserName);
outState.PutString(PasswordActivity.KeyServerpassword, _iocToLaunch.Password);
outState.PutInt(PasswordActivity.KeyServercredmode, (int)_iocToLaunch.CredSaveMode);
}
} }
private class LaunchGroupActivity : FileOnFinish { private class LaunchGroupActivity : FileOnFinish {
@ -382,7 +403,18 @@ namespace keepass2android
void LaunchPasswordActivityForIoc(IOConnectionInfo ioc) void LaunchPasswordActivityForIoc(IOConnectionInfo ioc)
{ {
if (App.Kp2a.GetFileStorage(ioc).RequiresCredentials(ioc)) IFileStorage fileStorage = App.Kp2a.GetFileStorage(ioc);
if (fileStorage.RequiredSetup != null)
{
if (!fileStorage.RequiredSetup.TrySetup(this))
{
//store ioc to launch. TrySetup hopefully launched another activity so we can check again in OnResume
_iocToLaunch = ioc;
return;
}
}
if (fileStorage.RequiresCredentials(ioc))
{ {
//Build dialog to query credentials: //Build dialog to query credentials:
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
@ -439,8 +471,6 @@ namespace keepass2android
{ {
base.OnActivityResult(requestCode, resultCode, data); base.OnActivityResult(requestCode, resultCode, data);
_createdWithActivityResult = true;
if (resultCode == KeePass.ExitCloseAfterTaskComplete) if (resultCode == KeePass.ExitCloseAfterTaskComplete)
{ {
Finish(); Finish();
@ -501,8 +531,29 @@ namespace keepass2android
Intent intent = Intent; Intent intent = Intent;
StartActivity(intent); StartActivity(intent);
Finish(); Finish();
return;
} }
//check if we are resuming after setting up the file storage:
if (_iocToLaunch != null)
{
try
{
IOConnectionInfo iocToLaunch = _iocToLaunch;
_iocToLaunch = null;
IFileStorageSetupOnResume fsSetup = App.Kp2a.GetFileStorage(iocToLaunch).RequiredSetup as IFileStorageSetupOnResume;
if ((fsSetup == null) || (fsSetup.TrySetupOnResume(this)))
{
LaunchPasswordActivityForIoc(iocToLaunch);
}
}
catch (Exception e)
{
Toast.MakeText(this, e.Message, ToastLength.Long).Show();
}
}
_fileSelectButtons.UpdateExternalStorageWarning(); _fileSelectButtons.UpdateExternalStorageWarning();
@ -517,8 +568,7 @@ namespace keepass2android
var db = App.Kp2a.GetDb(); var db = App.Kp2a.GetDb();
if (db.Loaded) if (db.Loaded)
{ {
PasswordActivity.Launch(this, db.Ioc, AppTask); LaunchPasswordActivityForIoc(db.Ioc);
Finish();
} }