2013-02-23 11:43:42 -05:00
|
|
|
/*
|
|
|
|
This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file is based on Keepassdroid, Copyright Brian Pellin.
|
|
|
|
|
|
|
|
Keepass2Android is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
2014-01-26 08:27:27 -05:00
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
2013-02-23 11:43:42 -05:00
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Keepass2Android is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Keepass2Android. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
using System;
|
2013-07-25 08:47:05 -04:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.IO;
|
2014-02-02 17:36:19 -05:00
|
|
|
using System.Net.Security;
|
2013-02-23 11:43:42 -05:00
|
|
|
using Android.App;
|
|
|
|
using Android.Content;
|
2013-09-15 14:08:14 -04:00
|
|
|
using Android.Graphics.Drawables;
|
2013-06-25 15:27:41 -04:00
|
|
|
using Android.OS;
|
2013-02-23 11:43:42 -05:00
|
|
|
using Android.Runtime;
|
2014-02-19 15:49:18 -05:00
|
|
|
using Android.Views;
|
2013-08-08 14:40:02 -04:00
|
|
|
using Android.Widget;
|
2014-01-25 22:38:12 -05:00
|
|
|
using KeePassLib;
|
2013-09-03 17:10:59 -04:00
|
|
|
using KeePassLib.Cryptography.Cipher;
|
2013-07-25 08:47:05 -04:00
|
|
|
using KeePassLib.Keys;
|
2013-06-14 00:14:50 -04:00
|
|
|
using KeePassLib.Serialization;
|
|
|
|
using Android.Preferences;
|
2013-09-28 15:14:21 -04:00
|
|
|
#if !EXCLUDE_TWOFISH
|
2013-09-03 17:10:59 -04:00
|
|
|
using TwofishCipher;
|
2013-09-28 15:14:21 -04:00
|
|
|
#endif
|
2013-07-09 03:59:17 -04:00
|
|
|
using keepass2android.Io;
|
2013-11-20 13:14:57 -05:00
|
|
|
using keepass2android.addons.OtpKeyProv;
|
2013-02-23 11:43:42 -05:00
|
|
|
|
|
|
|
namespace keepass2android
|
|
|
|
{
|
2013-02-27 16:11:44 -05:00
|
|
|
#if NoNet
|
2013-06-15 16:02:48 -04:00
|
|
|
/// <summary>
|
|
|
|
/// Static strings containing App names for the Offline ("nonet") release
|
|
|
|
/// </summary>
|
2013-02-27 16:11:44 -05:00
|
|
|
public static class AppNames
|
2013-02-27 00:23:22 -05:00
|
|
|
{
|
2013-02-27 16:11:44 -05:00
|
|
|
public const string AppName = "@string/app_name_nonet";
|
2013-10-12 16:20:02 -04:00
|
|
|
public const int AppNameResource = Resource.String.app_name_nonet;
|
2013-02-27 16:11:44 -05:00
|
|
|
public const string AppNameShort = "@string/short_app_name_nonet";
|
|
|
|
public const string AppLauncherTitle = "@string/short_app_name_nonet";
|
2013-05-05 23:28:13 -04:00
|
|
|
public const string PackagePart = "keepass2android_nonet";
|
2013-07-17 15:57:10 -04:00
|
|
|
public const int LauncherIcon = Resource.Drawable.ic_launcher_offline;
|
2013-07-17 17:11:28 -04:00
|
|
|
|
|
|
|
public const string Searchable = "@xml/searchable_offline";
|
2013-02-27 00:23:22 -05:00
|
|
|
}
|
2013-02-27 16:11:44 -05:00
|
|
|
#else
|
2013-06-15 16:02:48 -04:00
|
|
|
/// <summary>
|
|
|
|
/// Static strings containing App names for the Online release
|
|
|
|
/// </summary>
|
2013-02-27 16:11:44 -05:00
|
|
|
public static class AppNames
|
|
|
|
{
|
2014-04-01 01:26:50 -04:00
|
|
|
#if DEBUG
|
|
|
|
public const string AppName = "Keepass2Android Debug";
|
|
|
|
#else
|
2013-02-27 16:11:44 -05:00
|
|
|
public const string AppName = "@string/app_name";
|
2014-04-01 01:26:50 -04:00
|
|
|
#endif
|
|
|
|
|
2013-10-12 16:20:02 -04:00
|
|
|
public const int AppNameResource = Resource.String.app_name;
|
2014-05-14 01:23:31 -04:00
|
|
|
public const string AppNameShort = "@string/short_app_name" + "DBG";
|
|
|
|
public const string AppLauncherTitle = "@string/app_name" + " Debug";
|
2014-03-23 11:57:52 -04:00
|
|
|
#if DEBUG
|
|
|
|
public const string PackagePart = "keepass2android_debug";
|
2014-05-14 01:23:31 -04:00
|
|
|
public const string Searchable = "@xml/searchable_debug";
|
2014-03-23 11:57:52 -04:00
|
|
|
#else
|
2013-05-05 23:28:13 -04:00
|
|
|
public const string PackagePart = "keepass2android";
|
2014-05-14 01:23:31 -04:00
|
|
|
public const string Searchable = "@xml/searchable";
|
2014-03-23 11:57:52 -04:00
|
|
|
#endif
|
2013-07-17 15:57:10 -04:00
|
|
|
public const int LauncherIcon = Resource.Drawable.ic_launcher;
|
2014-05-14 01:23:31 -04:00
|
|
|
|
2013-02-27 16:11:44 -05:00
|
|
|
}
|
|
|
|
#endif
|
2013-06-18 15:12:34 -04:00
|
|
|
/// <summary>
|
|
|
|
/// Main implementation of the IKp2aApp interface for usage in the real app.
|
|
|
|
/// </summary>
|
2013-08-08 14:40:02 -04:00
|
|
|
public class Kp2aApp: IKp2aApp, ICacheSupervisor
|
|
|
|
{
|
2013-07-25 08:47:05 -04:00
|
|
|
public void LockDatabase(bool allowQuickUnlock = true)
|
|
|
|
{
|
2013-08-03 06:33:19 -04:00
|
|
|
if (GetDb().Loaded)
|
2013-07-25 08:47:05 -04:00
|
|
|
{
|
2013-07-26 15:10:03 -04:00
|
|
|
if (QuickUnlockEnabled && allowQuickUnlock &&
|
2013-07-25 08:47:05 -04:00
|
|
|
_db.KpDatabase.MasterKey.ContainsType(typeof(KcpPassword)) &&
|
|
|
|
!((KcpPassword)App.Kp2a.GetDb().KpDatabase.MasterKey.GetUserKey(typeof(KcpPassword))).Password.IsEmpty)
|
|
|
|
{
|
|
|
|
if (!QuickLocked)
|
|
|
|
{
|
|
|
|
Kp2aLog.Log("QuickLocking database");
|
|
|
|
|
|
|
|
QuickLocked = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Kp2aLog.Log("Database already QuickLocked");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Kp2aLog.Log("Locking database");
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-07-25 08:47:05 -04:00
|
|
|
// Couldn't quick-lock, so unload database instead
|
|
|
|
_db.Clear();
|
|
|
|
QuickLocked = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Kp2aLog.Log("Database not loaded, couldn't lock");
|
|
|
|
}
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-07-26 15:10:03 -04:00
|
|
|
UpdateOngoingNotification();
|
|
|
|
Application.Context.SendBroadcast(new Intent(Intents.DatabaseLocked));
|
2013-06-14 00:14:50 -04:00
|
|
|
}
|
|
|
|
|
2014-01-25 22:38:12 -05:00
|
|
|
public void LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compositeKey, ProgressDialogStatusLogger statusLogger, IDatabaseLoader databaseLoader)
|
2013-07-25 08:47:05 -04:00
|
|
|
{
|
2014-01-25 22:38:12 -05:00
|
|
|
_db.LoadData(this, ioConnectionInfo, memoryStream, compositeKey, statusLogger, databaseLoader);
|
2013-07-25 08:47:05 -04:00
|
|
|
|
2013-07-26 15:10:03 -04:00
|
|
|
UpdateOngoingNotification();
|
2013-07-25 08:47:05 -04:00
|
|
|
}
|
|
|
|
|
2013-07-26 15:10:03 -04:00
|
|
|
internal void UnlockDatabase()
|
2013-07-25 08:47:05 -04:00
|
|
|
{
|
2013-07-26 15:10:03 -04:00
|
|
|
QuickLocked = false;
|
2013-07-25 08:47:05 -04:00
|
|
|
|
2013-07-26 15:10:03 -04:00
|
|
|
UpdateOngoingNotification();
|
|
|
|
}
|
2013-07-25 08:47:05 -04:00
|
|
|
|
2013-09-06 14:12:12 -04:00
|
|
|
public void UpdateOngoingNotification()
|
2013-07-25 08:47:05 -04:00
|
|
|
{
|
2013-07-26 15:10:03 -04:00
|
|
|
// Start or update the notification icon service to reflect the current state
|
|
|
|
var ctx = Application.Context;
|
2014-04-15 00:03:22 -04:00
|
|
|
StartOnGoingService(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void StartOnGoingService(Context ctx)
|
|
|
|
{
|
|
|
|
ctx.StartService(new Intent(ctx, typeof (OngoingNotificationsService)));
|
2013-07-25 08:47:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
public bool DatabaseIsUnlocked
|
|
|
|
{
|
|
|
|
get { return _db.Loaded && !QuickLocked; }
|
|
|
|
}
|
|
|
|
|
|
|
|
#region QuickUnlock
|
|
|
|
public void SetQuickUnlockEnabled(bool enabled)
|
|
|
|
{
|
|
|
|
if (enabled)
|
|
|
|
{
|
|
|
|
//Set KeyLength of QuickUnlock at time of enabling.
|
|
|
|
//This is important to not allow an attacker to set the length to 1 when QuickUnlock is started already.
|
|
|
|
|
|
|
|
var ctx = Application.Context;
|
|
|
|
var prefs = PreferenceManager.GetDefaultSharedPreferences(ctx);
|
|
|
|
QuickUnlockKeyLength = Math.Max(1, int.Parse(prefs.GetString(ctx.GetString(Resource.String.QuickUnlockLength_key), ctx.GetString(Resource.String.QuickUnlockLength_default))));
|
|
|
|
}
|
|
|
|
QuickUnlockEnabled = enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool QuickUnlockEnabled { get; private set; }
|
|
|
|
|
|
|
|
public int QuickUnlockKeyLength { get; private set; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// If true, the database must be regarded as locked and not exposed to the user.
|
|
|
|
/// </summary>
|
|
|
|
public bool QuickLocked { get; private set; }
|
|
|
|
|
|
|
|
#endregion
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-07-25 08:47:05 -04:00
|
|
|
private Database _db;
|
|
|
|
|
2013-06-14 00:14:50 -04:00
|
|
|
/// <summary>
|
|
|
|
/// See comments to EntryEditActivityState.
|
|
|
|
/// </summary>
|
2013-06-15 06:40:01 -04:00
|
|
|
internal EntryEditActivityState EntryEditActivityState = null;
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-06-15 06:40:01 -04:00
|
|
|
public FileDbHelper FileDbHelper;
|
2013-09-15 14:08:14 -04:00
|
|
|
private List<IFileStorage> _fileStorages;
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-09-15 14:08:14 -04:00
|
|
|
public Database GetDb()
|
2013-06-14 00:14:50 -04:00
|
|
|
{
|
2013-06-15 06:40:01 -04:00
|
|
|
if (_db == null)
|
2013-06-14 00:14:50 -04:00
|
|
|
{
|
2013-06-15 06:40:01 -04:00
|
|
|
_db = CreateNewDatabase();
|
2013-06-14 00:14:50 -04:00
|
|
|
}
|
|
|
|
|
2013-06-15 06:40:01 -04:00
|
|
|
return _db;
|
2013-06-14 00:14:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public bool GetBooleanPreference(PreferenceKey key)
|
|
|
|
{
|
|
|
|
Context ctx = Application.Context;
|
|
|
|
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(ctx);
|
|
|
|
switch (key)
|
|
|
|
{
|
|
|
|
case PreferenceKey.remember_keyfile:
|
|
|
|
return prefs.GetBoolean(ctx.Resources.GetString(Resource.String.keyfile_key), ctx.Resources.GetBoolean(Resource.Boolean.keyfile_default));
|
|
|
|
case PreferenceKey.UseFileTransactions:
|
|
|
|
return prefs.GetBoolean(ctx.Resources.GetString(Resource.String.UseFileTransactions_key), true);
|
2013-07-11 11:27:10 -04:00
|
|
|
case PreferenceKey.CheckForFileChangesOnSave:
|
|
|
|
return prefs.GetBoolean(ctx.Resources.GetString(Resource.String.CheckForFileChangesOnSave_key), true);
|
2013-06-14 00:14:50 -04:00
|
|
|
default:
|
|
|
|
throw new Exception("unexpected key!");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void CheckForOpenFileChanged(Activity activity)
|
|
|
|
{
|
2013-06-15 06:40:01 -04:00
|
|
|
if (_db.DidOpenFileChange())
|
2013-06-14 00:14:50 -04:00
|
|
|
{
|
2013-06-15 06:40:01 -04:00
|
|
|
if (_db.ReloadRequested)
|
2013-06-14 00:14:50 -04:00
|
|
|
{
|
2013-08-06 14:46:09 -04:00
|
|
|
LockDatabase(false);
|
2013-06-15 06:40:01 -04:00
|
|
|
activity.SetResult(KeePass.ExitReloadDb);
|
2013-06-14 00:14:50 -04:00
|
|
|
activity.Finish();
|
2013-08-01 16:20:39 -04:00
|
|
|
//todo: return?
|
2013-06-14 00:14:50 -04:00
|
|
|
}
|
2013-08-01 16:20:39 -04:00
|
|
|
AskForReload(activity);
|
|
|
|
}
|
|
|
|
}
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-08-01 16:20:39 -04:00
|
|
|
private void AskForReload(Activity activity)
|
|
|
|
{
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
|
|
builder.SetTitle(activity.GetString(Resource.String.AskReloadFile_title));
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-08-01 16:20:39 -04:00
|
|
|
builder.SetMessage(activity.GetString(Resource.String.AskReloadFile));
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-08-01 16:20:39 -04:00
|
|
|
builder.SetPositiveButton(activity.GetString(Android.Resource.String.Yes),
|
|
|
|
(dlgSender, dlgEvt) =>
|
|
|
|
{
|
|
|
|
_db.ReloadRequested = true;
|
|
|
|
activity.SetResult(KeePass.ExitReloadDb);
|
|
|
|
activity.Finish();
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-08-01 16:20:39 -04:00
|
|
|
});
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-08-01 16:20:39 -04:00
|
|
|
builder.SetNegativeButton(activity.GetString(Android.Resource.String.No), (dlgSender, dlgEvt) =>
|
|
|
|
{
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-08-01 16:20:39 -04:00
|
|
|
});
|
2013-06-14 00:14:50 -04:00
|
|
|
|
|
|
|
|
2013-08-01 16:20:39 -04:00
|
|
|
Dialog dialog = builder.Create();
|
|
|
|
dialog.Show();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void StoreOpenedFileAsRecent(IOConnectionInfo ioc, string keyfile)
|
2013-06-14 00:14:50 -04:00
|
|
|
{
|
2013-06-15 06:40:01 -04:00
|
|
|
FileDbHelper.CreateFile(ioc, keyfile);
|
2013-06-14 00:14:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
public string GetResourceString(UiStringKey key)
|
|
|
|
{
|
2013-09-15 14:08:14 -04:00
|
|
|
return GetResourceString(key.ToString());
|
2013-06-14 00:14:50 -04:00
|
|
|
}
|
2013-09-15 14:08:14 -04:00
|
|
|
public string GetResourceString(string key)
|
|
|
|
{
|
|
|
|
var field = typeof(Resource.String).GetField(key);
|
|
|
|
if (field == null)
|
|
|
|
throw new Exception("Invalid key " + key);
|
|
|
|
return Application.Context.GetString((int)field.GetValue(null));
|
|
|
|
}
|
|
|
|
public Drawable GetResourceDrawable(string key)
|
|
|
|
{
|
|
|
|
var field = typeof(Resource.Drawable).GetField(key);
|
|
|
|
if (field == null)
|
|
|
|
throw new Exception("Invalid key " + key);
|
|
|
|
return Application.Context.Resources.GetDrawable((int)field.GetValue(null));
|
|
|
|
}
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-07-17 10:26:12 -04:00
|
|
|
public void AskYesNoCancel(UiStringKey titleKey, UiStringKey messageKey,
|
|
|
|
EventHandler<DialogClickEventArgs> yesHandler,
|
|
|
|
EventHandler<DialogClickEventArgs> noHandler,
|
|
|
|
EventHandler<DialogClickEventArgs> cancelHandler,
|
|
|
|
Context ctx)
|
|
|
|
{
|
|
|
|
AskYesNoCancel(titleKey, messageKey, UiStringKey.yes, UiStringKey.no,
|
|
|
|
yesHandler, noHandler, cancelHandler, ctx);
|
|
|
|
}
|
|
|
|
|
2013-06-14 00:14:50 -04:00
|
|
|
public void AskYesNoCancel(UiStringKey titleKey, UiStringKey messageKey,
|
2013-07-17 10:26:12 -04:00
|
|
|
UiStringKey yesString, UiStringKey noString,
|
|
|
|
EventHandler<DialogClickEventArgs> yesHandler,
|
2013-06-14 00:14:50 -04:00
|
|
|
EventHandler<DialogClickEventArgs> noHandler,
|
|
|
|
EventHandler<DialogClickEventArgs> cancelHandler,
|
|
|
|
Context ctx)
|
|
|
|
{
|
2013-07-11 11:27:10 -04:00
|
|
|
Handler handler = new Handler(Looper.MainLooper);
|
|
|
|
handler.Post(() =>
|
|
|
|
{
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
|
|
|
|
builder.SetTitle(GetResourceString(titleKey));
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-07-11 11:27:10 -04:00
|
|
|
builder.SetMessage(GetResourceString(messageKey));
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-07-17 10:26:12 -04:00
|
|
|
builder.SetPositiveButton(GetResourceString(yesString), yesHandler);
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-07-17 10:26:12 -04:00
|
|
|
builder.SetNegativeButton(GetResourceString(noString), noHandler);
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-11-20 13:14:57 -05:00
|
|
|
if (cancelHandler != null)
|
|
|
|
{
|
|
|
|
builder.SetNeutralButton(ctx.GetString(Android.Resource.String.Cancel),
|
|
|
|
cancelHandler);
|
|
|
|
}
|
2013-06-14 00:14:50 -04:00
|
|
|
|
2013-07-11 11:27:10 -04:00
|
|
|
Dialog dialog = builder.Create();
|
|
|
|
dialog.Show();
|
|
|
|
}
|
|
|
|
);
|
2013-06-14 00:14:50 -04:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:27:41 -04:00
|
|
|
public Handler UiThreadHandler
|
|
|
|
{
|
|
|
|
get { return new Handler(); }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Simple wrapper around ProgressDialog implementing IProgressDialog
|
|
|
|
/// </summary>
|
|
|
|
private class RealProgressDialog : IProgressDialog
|
|
|
|
{
|
|
|
|
private readonly ProgressDialog _pd;
|
|
|
|
|
|
|
|
public RealProgressDialog(Context ctx)
|
|
|
|
{
|
2013-07-25 08:47:05 -04:00
|
|
|
_pd = new ProgressDialog(ctx);
|
2013-06-25 15:27:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
public void SetTitle(string title)
|
|
|
|
{
|
|
|
|
_pd.SetTitle(title);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetMessage(string message)
|
|
|
|
{
|
|
|
|
_pd.SetMessage(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Dismiss()
|
|
|
|
{
|
|
|
|
_pd.Dismiss();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Show()
|
|
|
|
{
|
|
|
|
_pd.Show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public IProgressDialog CreateProgressDialog(Context ctx)
|
|
|
|
{
|
|
|
|
return new RealProgressDialog(ctx);
|
|
|
|
}
|
|
|
|
|
2013-07-09 03:59:17 -04:00
|
|
|
public IFileStorage GetFileStorage(IOConnectionInfo iocInfo)
|
|
|
|
{
|
2013-08-08 14:40:02 -04:00
|
|
|
if (iocInfo.IsLocalFile())
|
2013-12-12 04:24:24 -05:00
|
|
|
return new BuiltInFileStorage(this);
|
2013-08-08 14:40:02 -04:00
|
|
|
else
|
|
|
|
{
|
2013-09-15 14:08:14 -04:00
|
|
|
IFileStorage innerFileStorage = GetCloudFileStorage(iocInfo);
|
|
|
|
|
2013-11-17 01:17:15 -05:00
|
|
|
if (DatabaseCacheEnabled)
|
2013-08-14 00:05:25 -04:00
|
|
|
{
|
2013-11-17 01:17:15 -05:00
|
|
|
//TODO
|
2013-09-15 14:08:14 -04:00
|
|
|
return new CachingFileStorage(innerFileStorage, Application.Context.CacheDir.Path, this);
|
2013-08-14 00:05:25 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-09-15 14:08:14 -04:00
|
|
|
return innerFileStorage;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private IFileStorage GetCloudFileStorage(IOConnectionInfo iocInfo)
|
|
|
|
{
|
|
|
|
foreach (IFileStorage fs in FileStorages)
|
|
|
|
{
|
|
|
|
foreach (string protocolId in fs.SupportedProtocols)
|
|
|
|
{
|
|
|
|
if (iocInfo.Path.StartsWith(protocolId + "://"))
|
|
|
|
return fs;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
//TODO: catch!
|
2013-10-12 16:20:02 -04:00
|
|
|
throw new NoFileStorageFoundException("Unknown protocol " + iocInfo.Path);
|
2013-09-15 14:08:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
public IEnumerable<IFileStorage> FileStorages
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (_fileStorages == null)
|
|
|
|
{
|
|
|
|
_fileStorages = new List<IFileStorage>
|
|
|
|
{
|
2013-09-28 15:14:21 -04:00
|
|
|
#if !EXCLUDE_JAVAFILESTORAGE
|
2013-12-26 00:31:40 -05:00
|
|
|
#if !NoNet
|
2013-09-17 00:53:18 -04:00
|
|
|
new DropboxFileStorage(Application.Context, this),
|
2013-11-27 16:21:29 -05:00
|
|
|
new DropboxAppFolderFileStorage(Application.Context, this),
|
2013-10-24 22:05:37 -04:00
|
|
|
new GoogleDriveFileStorage(Application.Context, this),
|
2013-11-05 23:25:19 -05:00
|
|
|
new SkyDriveFileStorage(Application.Context, this),
|
2013-12-31 03:46:57 -05:00
|
|
|
new SftpFileStorage(this),
|
2013-12-26 00:31:40 -05:00
|
|
|
#endif
|
2013-09-28 15:14:21 -04:00
|
|
|
#endif
|
2013-12-12 04:24:24 -05:00
|
|
|
new BuiltInFileStorage(this)
|
2013-09-15 14:08:14 -04:00
|
|
|
};
|
2013-08-14 00:05:25 -04:00
|
|
|
}
|
2013-09-15 14:08:14 -04:00
|
|
|
return _fileStorages;
|
2013-08-08 14:40:02 -04:00
|
|
|
}
|
2013-07-09 03:59:17 -04:00
|
|
|
}
|
|
|
|
|
2013-08-01 16:20:39 -04:00
|
|
|
public void TriggerReload(Context ctx)
|
|
|
|
{
|
2013-08-14 00:05:25 -04:00
|
|
|
Handler handler = new Handler(Looper.MainLooper);
|
|
|
|
handler.Post(() =>
|
|
|
|
{
|
|
|
|
AskForReload((Activity) ctx);
|
|
|
|
});
|
2013-08-01 16:20:39 -04:00
|
|
|
}
|
|
|
|
|
2014-02-02 17:36:19 -05:00
|
|
|
public RemoteCertificateValidationCallback CertificateValidationCallback
|
2013-12-12 04:24:24 -05:00
|
|
|
{
|
2014-02-02 17:36:19 -05:00
|
|
|
get
|
|
|
|
{
|
|
|
|
var prefs = PreferenceManager.GetDefaultSharedPreferences(Application.Context);
|
2013-12-12 04:24:24 -05:00
|
|
|
|
2014-02-02 17:36:19 -05:00
|
|
|
ValidationMode validationMode = ValidationMode.Warn;
|
2013-12-12 04:24:24 -05:00
|
|
|
|
2014-02-02 17:36:19 -05:00
|
|
|
string strValMode = prefs.GetString(Application.Context.Resources.GetString(Resource.String.AcceptAllServerCertificates_key),
|
|
|
|
Application.Context.Resources.GetString(Resource.String.AcceptAllServerCertificates_default));
|
2013-12-12 04:24:24 -05:00
|
|
|
|
2014-02-02 17:36:19 -05:00
|
|
|
if (strValMode == "IGNORE")
|
|
|
|
validationMode = ValidationMode.Ignore;
|
|
|
|
else if (strValMode == "ERROR")
|
|
|
|
validationMode = ValidationMode.Error;
|
|
|
|
;
|
2013-12-12 04:24:24 -05:00
|
|
|
|
2014-02-02 17:36:19 -05:00
|
|
|
switch (validationMode)
|
|
|
|
{
|
|
|
|
case ValidationMode.Ignore:
|
|
|
|
return (sender, certificate, chain, errors) =>
|
|
|
|
{
|
|
|
|
ShowToast(Application.Context.GetString(Resource.String.CertificateWarning,
|
|
|
|
new Java.Lang.Object[]
|
2013-12-12 04:24:24 -05:00
|
|
|
{
|
2014-02-02 17:36:19 -05:00
|
|
|
errors.ToString()
|
2013-12-12 04:24:24 -05:00
|
|
|
}));
|
2014-02-02 17:36:19 -05:00
|
|
|
return true;
|
|
|
|
};
|
|
|
|
case ValidationMode.Warn:
|
|
|
|
return (sender, certificate, chain, errors) =>
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
case ValidationMode.Error:
|
|
|
|
return (sender, certificate, chain, errors) =>
|
|
|
|
{
|
|
|
|
if (errors == SslPolicyErrors.None)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
};;
|
|
|
|
default:
|
|
|
|
throw new ArgumentOutOfRangeException();
|
|
|
|
}
|
|
|
|
|
2013-12-12 04:24:24 -05:00
|
|
|
}
|
2014-02-02 17:36:19 -05:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
enum ValidationMode
|
|
|
|
{
|
|
|
|
Ignore, Warn, Error
|
2013-12-12 04:24:24 -05:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:27:41 -04:00
|
|
|
|
|
|
|
internal void OnTerminate()
|
2013-06-14 00:14:50 -04:00
|
|
|
{
|
2013-06-15 06:40:01 -04:00
|
|
|
if (_db != null)
|
2013-06-14 00:14:50 -04:00
|
|
|
{
|
2013-06-15 06:40:01 -04:00
|
|
|
_db.Clear();
|
2013-06-14 00:14:50 -04:00
|
|
|
}
|
|
|
|
|
2013-06-15 06:40:01 -04:00
|
|
|
if (FileDbHelper != null && FileDbHelper.IsOpen())
|
2013-06-14 00:14:50 -04:00
|
|
|
{
|
2013-06-15 06:40:01 -04:00
|
|
|
FileDbHelper.Close();
|
2013-06-14 00:14:50 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void OnCreate(Application app)
|
|
|
|
{
|
2013-06-15 06:40:01 -04:00
|
|
|
FileDbHelper = new FileDbHelper(app);
|
|
|
|
FileDbHelper.Open();
|
2013-06-14 00:14:50 -04:00
|
|
|
|
|
|
|
#if DEBUG
|
|
|
|
foreach (UiStringKey key in Enum.GetValues(typeof(UiStringKey)))
|
|
|
|
{
|
|
|
|
GetResourceString(key);
|
|
|
|
}
|
|
|
|
#endif
|
2013-09-28 15:14:21 -04:00
|
|
|
#if !EXCLUDE_TWOFISH
|
2013-09-03 17:10:59 -04:00
|
|
|
CipherPool.GlobalPool.AddCipher(new TwofishCipherEngine());
|
2013-09-28 15:14:21 -04:00
|
|
|
#endif
|
2013-06-14 00:14:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Database CreateNewDatabase()
|
|
|
|
{
|
2013-06-15 06:40:01 -04:00
|
|
|
_db = new Database(new DrawableFactory(), this);
|
|
|
|
return _db;
|
2013-06-14 00:14:50 -04:00
|
|
|
}
|
2013-08-08 14:40:02 -04:00
|
|
|
|
2013-11-20 13:14:57 -05:00
|
|
|
internal void ShowToast(string message)
|
2013-08-08 14:40:02 -04:00
|
|
|
{
|
|
|
|
var handler = new Handler(Looper.MainLooper);
|
2014-02-19 15:49:18 -05:00
|
|
|
handler.Post(() => { var toast = Toast.MakeText(Application.Context, message, ToastLength.Long);
|
|
|
|
toast.SetGravity(GravityFlags.Center, 0, 0);
|
|
|
|
toast.Show();
|
|
|
|
});
|
2013-08-08 14:40:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
public void CouldntSaveToRemote(IOConnectionInfo ioc, Exception e)
|
|
|
|
{
|
2013-08-14 00:05:25 -04:00
|
|
|
ShowToast(Application.Context.GetString(Resource.String.CouldNotSaveToRemote, e.Message));
|
2013-08-08 14:40:02 -04:00
|
|
|
}
|
|
|
|
|
2013-08-14 00:05:25 -04:00
|
|
|
|
2013-08-08 14:40:02 -04:00
|
|
|
public void CouldntOpenFromRemote(IOConnectionInfo ioc, Exception ex)
|
|
|
|
{
|
2013-08-14 00:05:25 -04:00
|
|
|
ShowToast(Application.Context.GetString(Resource.String.CouldNotLoadFromRemote, ex.Message));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void UpdatedCachedFileOnLoad(IOConnectionInfo ioc)
|
|
|
|
{
|
2013-11-20 13:14:57 -05:00
|
|
|
ShowToast(Application.Context.GetString(Resource.String.UpdatedCachedFileOnLoad,
|
|
|
|
new Java.Lang.Object[] { Application.Context.GetString(Resource.String.database_file) }));
|
2013-08-14 00:05:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
public void UpdatedRemoteFileOnLoad(IOConnectionInfo ioc)
|
|
|
|
{
|
|
|
|
ShowToast(Application.Context.GetString(Resource.String.UpdatedRemoteFileOnLoad));
|
2013-08-08 14:40:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
public void NotifyOpenFromLocalDueToConflict(IOConnectionInfo ioc)
|
|
|
|
{
|
2013-08-14 00:05:25 -04:00
|
|
|
ShowToast(Application.Context.GetString(Resource.String.NotifyOpenFromLocalDueToConflict));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void LoadedFromRemoteInSync(IOConnectionInfo ioc)
|
|
|
|
{
|
|
|
|
ShowToast(Application.Context.GetString(Resource.String.LoadedFromRemoteInSync));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void ClearOfflineCache()
|
|
|
|
{
|
2013-12-12 04:24:24 -05:00
|
|
|
new CachingFileStorage(new BuiltInFileStorage(this), Application.Context.CacheDir.Path, this).ClearCache();
|
2013-08-08 14:40:02 -04:00
|
|
|
}
|
2013-09-15 14:08:14 -04:00
|
|
|
|
|
|
|
public IFileStorage GetFileStorage(string protocolId)
|
|
|
|
{
|
|
|
|
return GetFileStorage(new IOConnectionInfo() {Path = protocolId + "://"});
|
|
|
|
}
|
2013-11-17 01:17:15 -05:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// returns a file storage object to be used when accessing the auxiliary OTP file
|
|
|
|
/// </summary>
|
|
|
|
/// The reason why this requires a different file storage is the different caching behavior.
|
|
|
|
public IFileStorage GetOtpAuxFileStorage(IOConnectionInfo iocInfo)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (iocInfo.IsLocalFile())
|
2013-12-12 04:24:24 -05:00
|
|
|
return new BuiltInFileStorage(this);
|
2013-11-17 01:17:15 -05:00
|
|
|
else
|
|
|
|
{
|
|
|
|
IFileStorage innerFileStorage = GetCloudFileStorage(iocInfo);
|
|
|
|
|
|
|
|
|
|
|
|
if (DatabaseCacheEnabled)
|
|
|
|
{
|
2013-11-20 13:14:57 -05:00
|
|
|
return new OtpAuxCachingFileStorage(innerFileStorage, Application.Context.CacheDir.Path, new OtpAuxCacheSupervisor(this));
|
2013-11-17 01:17:15 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return innerFileStorage;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static bool DatabaseCacheEnabled
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
var prefs = PreferenceManager.GetDefaultSharedPreferences(Application.Context);
|
|
|
|
bool cacheEnabled = prefs.GetBoolean(Application.Context.Resources.GetString(Resource.String.UseOfflineCache_key),
|
|
|
|
true);
|
|
|
|
return cacheEnabled;
|
|
|
|
}
|
|
|
|
}
|
2013-11-25 15:08:15 -05:00
|
|
|
|
|
|
|
public void OnScreenOff()
|
|
|
|
{
|
|
|
|
if (PreferenceManager.GetDefaultSharedPreferences(Application.Context)
|
|
|
|
.GetBoolean(
|
|
|
|
Application.Context.GetString(Resource.String.LockWhenScreenOff_key),
|
|
|
|
false))
|
|
|
|
{
|
|
|
|
App.Kp2a.LockDatabase();
|
|
|
|
}
|
|
|
|
}
|
2013-08-08 14:40:02 -04:00
|
|
|
}
|
2013-06-14 00:14:50 -04:00
|
|
|
|
|
|
|
|
2013-11-20 13:14:57 -05:00
|
|
|
///Application class for Keepass2Android: Contains static Database variable to be used by all components.
|
2013-02-27 00:23:22 -05:00
|
|
|
#if NoNet
|
2013-02-27 16:11:44 -05:00
|
|
|
[Application(Debuggable=false, Label=AppNames.AppName)]
|
2013-02-23 11:43:42 -05:00
|
|
|
#else
|
2013-06-14 00:14:50 -04:00
|
|
|
#if RELEASE
|
2013-02-27 16:11:44 -05:00
|
|
|
[Application(Debuggable=false, Label=AppNames.AppName)]
|
2013-06-14 00:14:50 -04:00
|
|
|
#else
|
|
|
|
[Application(Debuggable = true, Label = AppNames.AppName)]
|
|
|
|
#endif
|
2013-02-23 11:43:42 -05:00
|
|
|
#endif
|
|
|
|
public class App : Application {
|
|
|
|
|
|
|
|
public App (IntPtr javaReference, JniHandleOwnership transfer)
|
|
|
|
: base(javaReference, transfer)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-06-15 06:40:01 -04:00
|
|
|
public static readonly Kp2aApp Kp2a = new Kp2aApp();
|
|
|
|
|
2013-02-23 11:43:42 -05:00
|
|
|
public override void OnCreate() {
|
|
|
|
base.OnCreate();
|
|
|
|
|
2013-07-06 10:11:38 -04:00
|
|
|
Kp2aLog.Log("Creating application "+PackageName+". Version=" + PackageManager.GetPackageInfo(PackageName, 0).VersionCode);
|
2013-02-23 11:43:42 -05:00
|
|
|
|
2013-06-15 06:40:01 -04:00
|
|
|
Kp2a.OnCreate(this);
|
2013-07-21 15:46:58 -04:00
|
|
|
AndroidEnvironment.UnhandledExceptionRaiser += MyApp_UnhandledExceptionHandler;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MyApp_UnhandledExceptionHandler(object sender, RaiseThrowableEventArgs e)
|
|
|
|
{
|
|
|
|
Kp2aLog.Log(e.Exception.ToString());
|
|
|
|
// Do your error handling here.
|
|
|
|
throw e.Exception;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void Dispose(bool disposing)
|
|
|
|
{
|
|
|
|
AndroidEnvironment.UnhandledExceptionRaiser -= MyApp_UnhandledExceptionHandler;
|
|
|
|
base.Dispose(disposing);
|
2013-02-23 11:43:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
public override void OnTerminate() {
|
|
|
|
base.OnTerminate();
|
2013-07-06 10:11:38 -04:00
|
|
|
Kp2aLog.Log("Terminating application");
|
2013-06-15 06:40:01 -04:00
|
|
|
Kp2a.OnTerminate();
|
2013-02-23 11:43:42 -05:00
|
|
|
}
|
|
|
|
|
2013-06-14 00:14:50 -04:00
|
|
|
|
|
|
|
}
|
2013-02-23 11:43:42 -05:00
|
|
|
}
|
|
|
|
|