Merge branch 'filecorruptionhandling'
This commit is contained in:
@@ -52,7 +52,7 @@ namespace keepass2android
|
||||
/// <summary>
|
||||
/// Tell the app that the file from ioc was opened with keyfile.
|
||||
/// </summary>
|
||||
void StoreOpenedFileAsRecent(IOConnectionInfo ioc, string keyfile);
|
||||
void StoreOpenedFileAsRecent(IOConnectionInfo ioc, string keyfile, string displayName = "");
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new database and returns it
|
||||
|
||||
@@ -11,9 +11,11 @@ using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Content.PM;
|
||||
using Android.OS;
|
||||
using Android.Preferences;
|
||||
using Android.Support.V13.App;
|
||||
using Android.Support.V4.App;
|
||||
using Java.IO;
|
||||
using Java.Util;
|
||||
using KeePassLib.Serialization;
|
||||
using KeePassLib.Utility;
|
||||
using ActivityCompat = Android.Support.V13.App.ActivityCompat;
|
||||
@@ -379,7 +381,14 @@ namespace keepass2android.Io
|
||||
{
|
||||
if (ioc.IsLocalFile())
|
||||
{
|
||||
if (IsLocalFileFlaggedReadOnly(ioc))
|
||||
if (IsLocalBackup(ioc))
|
||||
{
|
||||
if (reason != null)
|
||||
reason.Result = UiStringKey.ReadOnlyReason_LocalBackup;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsLocalFileFlaggedReadOnly(ioc))
|
||||
{
|
||||
if (reason != null)
|
||||
reason.Result = UiStringKey.ReadOnlyReason_ReadOnlyFlag;
|
||||
@@ -400,7 +409,20 @@ namespace keepass2android.Io
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsLocalFileFlaggedReadOnly(IOConnectionInfo ioc)
|
||||
private readonly Dictionary<string, bool> _isLocalBackupCache = new Dictionary<string, bool>();
|
||||
private bool IsLocalBackup(IOConnectionInfo ioc)
|
||||
{
|
||||
bool result;
|
||||
if (_isLocalBackupCache.TryGetValue(ioc.Path, out result))
|
||||
return result;
|
||||
|
||||
result = (PreferenceManager.GetDefaultSharedPreferences(Application.Context)
|
||||
.GetBoolean(IoUtil.GetIocPrefKey(ioc, "is_local_backup"), false));
|
||||
_isLocalBackupCache[ioc.Path] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool IsLocalFileFlaggedReadOnly(IOConnectionInfo ioc)
|
||||
{
|
||||
//see http://stackoverflow.com/a/33292700/292233
|
||||
try
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Java.IO;
|
||||
using KeePassLib.Serialization;
|
||||
using KeePassLib.Utility;
|
||||
|
||||
namespace keepass2android.Io
|
||||
{
|
||||
@@ -125,5 +127,53 @@ namespace keepass2android.Io
|
||||
return ctx.FilesDir;
|
||||
}
|
||||
|
||||
}
|
||||
//creates a local ioc where the sourceIoc can be stored to
|
||||
public static IOConnectionInfo GetInternalIoc(IOConnectionInfo sourceIoc, Context ctx)
|
||||
{
|
||||
Java.IO.File internalDirectory = IoUtil.GetInternalDirectory(ctx);
|
||||
string targetPath = UrlUtil.GetFileName(sourceIoc.Path);
|
||||
targetPath = targetPath.Trim("|\\?*<\":>+[]/'".ToCharArray());
|
||||
if (targetPath == "")
|
||||
targetPath = "internal";
|
||||
if (new File(internalDirectory, targetPath).Exists())
|
||||
{
|
||||
int c = 1;
|
||||
var ext = UrlUtil.GetExtension(targetPath);
|
||||
var filenameWithoutExt = UrlUtil.StripExtension(targetPath);
|
||||
do
|
||||
{
|
||||
c++;
|
||||
targetPath = filenameWithoutExt + c;
|
||||
if (!String.IsNullOrEmpty(ext))
|
||||
targetPath += "." + ext;
|
||||
} while (new File(internalDirectory, targetPath).Exists());
|
||||
}
|
||||
return IOConnectionInfo.FromPath(new File(internalDirectory, targetPath).CanonicalPath);
|
||||
}
|
||||
|
||||
public static IOConnectionInfo ImportFileToInternalDirectory(IOConnectionInfo sourceIoc, Context ctx, IKp2aApp app)
|
||||
{
|
||||
var targetIoc = GetInternalIoc(sourceIoc, ctx);
|
||||
|
||||
|
||||
IoUtil.Copy(targetIoc, sourceIoc, app);
|
||||
return targetIoc;
|
||||
}
|
||||
|
||||
public static string GetIocPrefKey(IOConnectionInfo ioc, string suffix)
|
||||
{
|
||||
var iocAsHexString = IocAsHexString(ioc);
|
||||
|
||||
return "kp2a_ioc_key_" + iocAsHexString + suffix;
|
||||
}
|
||||
|
||||
|
||||
public static string IocAsHexString(IOConnectionInfo ioc)
|
||||
{
|
||||
SHA256Managed sha256 = new SHA256Managed();
|
||||
string iocAsHexString =
|
||||
MemUtil.ByteArrayToHexString(sha256.ComputeHash(Encoding.Unicode.GetBytes(ioc.Path.ToCharArray())));
|
||||
return iocAsHexString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ namespace keepass2android
|
||||
AskAddTemplatesMessage,
|
||||
ReadOnlyReason_PreKitKat,
|
||||
ReadOnlyReason_ReadOnlyFlag,
|
||||
ReadOnlyReason_ReadOnlyKitKat
|
||||
ReadOnlyReason_ReadOnlyKitKat,
|
||||
ReadOnlyReason_LocalBackup
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,27 +152,20 @@ namespace keepass2android
|
||||
set { _databaseFormat = value; }
|
||||
}
|
||||
|
||||
public static string GetFingerprintPrefKey(IOConnectionInfo ioc)
|
||||
{
|
||||
var iocAsHexString = IocAsHexString(ioc);
|
||||
public string IocAsHexString()
|
||||
{
|
||||
return IoUtil.IocAsHexString(Ioc);
|
||||
}
|
||||
|
||||
return "kp2a_ioc_" + iocAsHexString;
|
||||
}
|
||||
public static string GetFingerprintPrefKey(IOConnectionInfo ioc)
|
||||
{
|
||||
var iocAsHexString = IoUtil.IocAsHexString(ioc);
|
||||
|
||||
public string IocAsHexString()
|
||||
{
|
||||
return IocAsHexString(Ioc);
|
||||
}
|
||||
return "kp2a_ioc_" + iocAsHexString;
|
||||
}
|
||||
|
||||
private static string IocAsHexString(IOConnectionInfo ioc)
|
||||
{
|
||||
SHA256Managed sha256 = new SHA256Managed();
|
||||
string iocAsHexString =
|
||||
MemUtil.ByteArrayToHexString(sha256.ComputeHash(Encoding.Unicode.GetBytes(ioc.Path.ToCharArray())));
|
||||
return iocAsHexString;
|
||||
}
|
||||
|
||||
public static string GetFingerprintModePrefKey(IOConnectionInfo ioc)
|
||||
public static string GetFingerprintModePrefKey(IOConnectionInfo ioc)
|
||||
{
|
||||
return GetFingerprintPrefKey(ioc) + "_mode";
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ namespace keepass2android
|
||||
// to retry with typing the full password, but that's intended to avoid showing the password to a
|
||||
// a potentially unauthorized user (feature request https://keepass2android.codeplex.com/workitem/274)
|
||||
Handler handler = new Handler();
|
||||
OnFinish onFinish = new AfterLoad(handler, this);
|
||||
OnFinish onFinish = new AfterLoad(handler, this, _ioConnection);
|
||||
_performingLoad = true;
|
||||
LoadDb task = new LoadDb(App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, _keyFileOrProvider, onFinish);
|
||||
_loadDbFileTask = null; // prevent accidental re-use
|
||||
@@ -1446,7 +1446,7 @@ namespace keepass2android
|
||||
MakePasswordMaskedOrVisible();
|
||||
|
||||
Handler handler = new Handler();
|
||||
OnFinish onFinish = new AfterLoad(handler, this);
|
||||
OnFinish onFinish = new AfterLoad(handler, this, _ioConnection);
|
||||
LoadDb task = (KeyProviderType == KeyProviders.Otp)
|
||||
? new SaveOtpAuxFileAndLoadDb(App.Kp2a, _ioConnection, _loadDbFileTask, compositeKey, _keyFileOrProvider,
|
||||
onFinish, this)
|
||||
@@ -2023,11 +2023,13 @@ namespace keepass2android
|
||||
|
||||
private class AfterLoad : OnFinish {
|
||||
readonly PasswordActivity _act;
|
||||
private readonly IOConnectionInfo _ioConnection;
|
||||
|
||||
public AfterLoad(Handler handler, PasswordActivity act):base(handler)
|
||||
{
|
||||
_act = act;
|
||||
}
|
||||
public AfterLoad(Handler handler, PasswordActivity act, IOConnectionInfo ioConnection):base(handler)
|
||||
{
|
||||
_act = act;
|
||||
_ioConnection = ioConnection;
|
||||
}
|
||||
|
||||
|
||||
public override void Run()
|
||||
@@ -2038,41 +2040,63 @@ namespace keepass2android
|
||||
_act.ClearEnteredPassword();
|
||||
_act.BroadcastOpenDatabase();
|
||||
_act.InvalidCompositeKeyCount = 0;
|
||||
_act.LoadingErrorCount = 0;
|
||||
|
||||
|
||||
GC.Collect(); // Ensure temporary memory used while loading is collected
|
||||
GC.Collect(); // Ensure temporary memory used while loading is collected
|
||||
}
|
||||
|
||||
if (Exception != null)
|
||||
{
|
||||
_act.LoadingErrorCount++;
|
||||
}
|
||||
|
||||
if (Exception is InvalidCompositeKeyException)
|
||||
{
|
||||
_act.InvalidCompositeKeyCount++;
|
||||
if (_act.UsedFingerprintUnlock)
|
||||
{
|
||||
//disable fingerprint unlock if master password changed
|
||||
_act.ClearFingerprintUnlockData();
|
||||
_act.InitFingerprintUnlock();
|
||||
if ((Exception != null) && (Exception.Message == KeePassLib.Resources.KLRes.FileCorrupted))
|
||||
{
|
||||
Message = _act.GetString(Resource.String.CorruptDatabaseHelp);
|
||||
}
|
||||
|
||||
Message = _act.GetString(Resource.String.fingerprint_disabled_wrong_masterkey) + " " + _act.GetString(Resource.String.fingerprint_reenable2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_act.InvalidCompositeKeyCount > 1)
|
||||
{
|
||||
Message = _act.GetString(Resource.String.RepeatedInvalidCompositeKeyHelp);
|
||||
}
|
||||
else
|
||||
{
|
||||
Message = _act.GetString(Resource.String.FirstInvalidCompositeKeyError);
|
||||
}
|
||||
}
|
||||
|
||||
if (Exception is InvalidCompositeKeyException)
|
||||
{
|
||||
_act.InvalidCompositeKeyCount++;
|
||||
if (_act.UsedFingerprintUnlock)
|
||||
{
|
||||
//disable fingerprint unlock if master password changed
|
||||
_act.ClearFingerprintUnlockData();
|
||||
_act.InitFingerprintUnlock();
|
||||
|
||||
}
|
||||
if ((Exception != null) && (Exception.Message == KeePassLib.Resources.KLRes.FileCorrupted))
|
||||
{
|
||||
Message = _act.GetString(Resource.String.CorruptDatabaseHelp);
|
||||
}
|
||||
Message = _act.GetString(Resource.String.fingerprint_disabled_wrong_masterkey) + " " +
|
||||
_act.GetString(Resource.String.fingerprint_reenable2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_act.InvalidCompositeKeyCount > 1)
|
||||
{
|
||||
Message = _act.GetString(Resource.String.RepeatedInvalidCompositeKeyHelp);
|
||||
if (_act._prefs.GetBoolean(IoUtil.GetIocPrefKey(_ioConnection, "has_local_backup"), false))
|
||||
{
|
||||
Java.Lang.Object changeDb = _act.GetString(Resource.String.menu_change_db);
|
||||
Message += _act.GetString(Resource.String.HintLocalBackupInvalidCompositeKey, new Java.Lang.Object[] {changeDb});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Message = _act.GetString(Resource.String.FirstInvalidCompositeKeyError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if (_act.LoadingErrorCount > 1)
|
||||
{
|
||||
if (_act._prefs.GetBoolean(IoUtil.GetIocPrefKey(_ioConnection, "has_local_backup"), false))
|
||||
{
|
||||
Java.Lang.Object changeDb = _act.GetString(Resource.String.menu_change_db);
|
||||
Message += _act.GetString(Resource.String.HintLocalBackupOtherError, new Java.Lang.Object[] { changeDb });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ((Message != null) && (Message.Length > 150)) //show long messages as dialog
|
||||
@@ -2113,8 +2137,12 @@ namespace keepass2android
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public int LoadingErrorCount
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
private void BroadcastOpenDatabase()
|
||||
private void BroadcastOpenDatabase()
|
||||
{
|
||||
App.Kp2a.BroadcastDatabaseAction(this, Strings.ActionOpenDatabase);
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
<string name="NoDonationReminder_key">NoDonationReminder</string>
|
||||
|
||||
<string name="UseOfflineCache_key">UseOfflineCache</string>
|
||||
<string name="CreateBackups_key">CreateBackups_key</string>
|
||||
<string name="AcceptAllServerCertificates_key">AcceptAllServerCertificates</string>
|
||||
<string name="CheckForFileChangesOnSave_key">CheckForFileChangesOnSave</string>
|
||||
<string name="CheckForDuplicateUuids_key">CheckForDuplicateUuids_key</string>
|
||||
|
||||
@@ -360,7 +360,14 @@
|
||||
<string name="UseOfflineCache_title">Database caching</string>
|
||||
<string name="UseOfflineCache_summary">Keep a copy of remote database files in the application cache directory. This allows to use remote databases even when offline.</string>
|
||||
|
||||
<string name="AcceptAllServerCertificates_title">SSL certificates</string>
|
||||
<string name="CreateBackups_title">Local backups</string>
|
||||
<string name="CreateBackups_summary">Create a local backup copy after successfully loading a database.</string>
|
||||
<string name="UpdatingBackup">Updating local backup...</string>
|
||||
<string name="LocalBackupOf">Local backup of %1$s</string>
|
||||
|
||||
|
||||
|
||||
<string name="AcceptAllServerCertificates_title">SSL certificates</string>
|
||||
<string name="AcceptAllServerCertificates_summary">Define the behavior when certificate validation fails. Note: you can install certificates on your device if validation fails!</string>
|
||||
|
||||
|
||||
@@ -636,6 +643,7 @@
|
||||
<string name="ReadOnlyReason_PreKitKat">It seems like you opened the file from an external app. This way does not support writing. If you want to make changes to the database, please close the database and select Change database. Then open the file from one of the available options if possible.</string>
|
||||
<string name="ReadOnlyReason_ReadOnlyFlag">The read-only flag is set. Remove this flag if you want to make changes to the database.</string>
|
||||
<string name="ReadOnlyReason_ReadOnlyKitKat">Writing is not possible because of restrictions introduced in Android KitKat. If you want to make changes to the database, close the database and select Change database. Then open the file using System file picker.</string>
|
||||
<string name="ReadOnlyReason_LocalBackup">Local backups cannot be modified. You can use Database settings - Export database to export this backup to another location from which you can re-open it. It will then be writable again.</string>
|
||||
|
||||
<string name="AddCustomIcon">Add icon from file...</string>
|
||||
|
||||
@@ -685,6 +693,15 @@
|
||||
• Make sure you have selected the correct database file.
|
||||
|
||||
</string>
|
||||
|
||||
<string name="HintLocalBackupInvalidCompositeKey">
|
||||
\n
|
||||
• Hint: If you think your database file might be corrupt or you do not remember the master key after modifying it, you can try with the last successfully opened file version by clicking "%1$s" and selecting the local backup.</string>
|
||||
|
||||
<string name="HintLocalBackupOtherError">
|
||||
\n
|
||||
• Hint: Keepass2Android has stored the last successfully opened file version in internal memory. You can open it by clicking "%1$s" and selecting the local backup.
|
||||
</string>
|
||||
|
||||
<string name="CorruptDatabaseHelp">
|
||||
File is corrupted. \n
|
||||
|
||||
@@ -462,6 +462,15 @@
|
||||
android:defaultValue="true"
|
||||
android:title="@string/UseOfflineCache_title"
|
||||
android:key="@string/UseOfflineCache_key" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:enabled="true"
|
||||
android:persistent="true"
|
||||
android:summary="@string/CreateBackups_summary"
|
||||
android:defaultValue="true"
|
||||
android:title="@string/CreateBackups_title"
|
||||
android:key="@string/CreateBackups_key" />
|
||||
|
||||
<ListPreference
|
||||
android:key="@string/AcceptAllServerCertificates_key"
|
||||
android:title="@string/AcceptAllServerCertificates_title"
|
||||
|
||||
@@ -39,6 +39,8 @@ using TwofishCipher;
|
||||
using Keepass2android.Pluginsdk;
|
||||
using keepass2android.Io;
|
||||
using keepass2android.addons.OtpKeyProv;
|
||||
using KeePassLib.Interfaces;
|
||||
using KeePassLib.Utility;
|
||||
#if !NoNet
|
||||
using Keepass2android.Javafilestorage;
|
||||
using GoogleDriveFileStorage = keepass2android.Io.GoogleDriveFileStorage;
|
||||
@@ -160,11 +162,68 @@ namespace keepass2android
|
||||
|
||||
|
||||
|
||||
public void LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compositeKey, ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat)
|
||||
{
|
||||
_db.LoadData(this, ioConnectionInfo, memoryStream, compositeKey, statusLogger, databaseFormat);
|
||||
public void LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compositeKey,
|
||||
ProgressDialogStatusLogger statusLogger, IDatabaseFormat databaseFormat)
|
||||
{
|
||||
var prefs = PreferenceManager.GetDefaultSharedPreferences(Application.Context);
|
||||
var createBackup = prefs.GetBoolean(Application.Context.GetString(Resource.String.CreateBackups_key), true);
|
||||
|
||||
UpdateOngoingNotification();
|
||||
MemoryStream backupCopy = new MemoryStream();
|
||||
if (createBackup)
|
||||
{
|
||||
|
||||
memoryStream.CopyTo(backupCopy);
|
||||
backupCopy.Seek(0, SeekOrigin.Begin);
|
||||
//reset stream if we need to reuse it later:
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
|
||||
_db.LoadData(this, ioConnectionInfo, memoryStream, compositeKey, statusLogger, databaseFormat);
|
||||
|
||||
if (createBackup)
|
||||
{
|
||||
statusLogger.UpdateMessage(Application.Context.GetString(Resource.String.UpdatingBackup));
|
||||
Java.IO.File internalDirectory = IoUtil.GetInternalDirectory(Application.Context);
|
||||
string baseDisplayName = App.Kp2a.GetFileStorage(ioConnectionInfo).GetDisplayName(ioConnectionInfo);
|
||||
string targetPath = baseDisplayName;
|
||||
var charsToRemove = "|\\?*<\":>+[]/'";
|
||||
foreach (char c in charsToRemove)
|
||||
{
|
||||
targetPath = targetPath.Replace(c.ToString(), string.Empty);
|
||||
}
|
||||
if (targetPath == "")
|
||||
targetPath = "local_backup";
|
||||
|
||||
var targetIoc = IOConnectionInfo.FromPath(new Java.IO.File(internalDirectory, targetPath).CanonicalPath);
|
||||
|
||||
using (var transaction = new LocalFileStorage(App.Kp2a).OpenWriteTransaction(targetIoc, false))
|
||||
{
|
||||
var file = transaction.OpenFile();
|
||||
backupCopy.CopyTo(file);
|
||||
transaction.CommitWrite();
|
||||
}
|
||||
Java.Lang.Object baseIocDisplayName = baseDisplayName;
|
||||
|
||||
string keyfile = App.Kp2a.FileDbHelper.GetKeyFileForFile(ioConnectionInfo.Path);
|
||||
App.Kp2a.StoreOpenedFileAsRecent(targetIoc, keyfile, Application.Context.
|
||||
GetString(Resource.String.LocalBackupOf, new Java.Lang.Object[]{baseIocDisplayName}));
|
||||
|
||||
prefs.Edit()
|
||||
.PutBoolean(IoUtil.GetIocPrefKey(ioConnectionInfo, "has_local_backup"), true)
|
||||
.PutBoolean(IoUtil.GetIocPrefKey(targetIoc, "is_local_backup"), true)
|
||||
.Commit();
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
prefs.Edit()
|
||||
.PutBoolean(IoUtil.GetIocPrefKey(ioConnectionInfo, "has_local_backup"), false) //there might be an older local backup, but we won't "advertise" this anymore
|
||||
.Commit();
|
||||
}
|
||||
|
||||
UpdateOngoingNotification();
|
||||
}
|
||||
|
||||
internal void UnlockDatabase()
|
||||
@@ -301,9 +360,9 @@ namespace keepass2android
|
||||
dialog.Show();
|
||||
}
|
||||
|
||||
public void StoreOpenedFileAsRecent(IOConnectionInfo ioc, string keyfile)
|
||||
public void StoreOpenedFileAsRecent(IOConnectionInfo ioc, string keyfile, string displayName = "")
|
||||
{
|
||||
FileDbHelper.CreateFile(ioc, keyfile);
|
||||
FileDbHelper.CreateFile(ioc, keyfile, displayName);
|
||||
}
|
||||
|
||||
public string GetResourceString(UiStringKey key)
|
||||
|
||||
@@ -34,13 +34,14 @@ namespace keepass2android
|
||||
|
||||
private const String DatabaseName = "keepass2android";
|
||||
private const String FileTable = "files";
|
||||
private const int DatabaseVersion = 1;
|
||||
private const int DatabaseVersion = 2;
|
||||
|
||||
private const int MaxFiles = 15;
|
||||
|
||||
public const String KeyFileId = "_id";
|
||||
public const String KeyFileFilename = "fileName";
|
||||
public const String KeyFileUsername = "username";
|
||||
public const String KeyFileDisplayname = "displayname";
|
||||
public const String KeyFileUsername = "username";
|
||||
public const String KeyFilePassword = "password";
|
||||
public const String KeyFileCredsavemode = "credSaveMode";
|
||||
public const String KeyFileKeyfile = "keyFile";
|
||||
@@ -48,12 +49,14 @@ namespace keepass2android
|
||||
|
||||
private const String DatabaseCreate =
|
||||
"create table " + FileTable + " ( " + KeyFileId + " integer primary key autoincrement, "
|
||||
+ KeyFileFilename + " text not null, "
|
||||
+ KeyFileKeyfile + " text, "
|
||||
+ KeyFileFilename + " text not null, "
|
||||
+ KeyFileKeyfile + " text, "
|
||||
+ KeyFileUsername + " text, "
|
||||
+ KeyFilePassword + " text, "
|
||||
+ KeyFileCredsavemode + " integer not null,"
|
||||
+ KeyFileUpdated + " integer not null);";
|
||||
+ KeyFileUpdated + " integer not null,"
|
||||
+ KeyFileDisplayname + " text "
|
||||
+");";
|
||||
|
||||
private readonly Context mCtx;
|
||||
private DatabaseHelper mDbHelper;
|
||||
@@ -71,7 +74,11 @@ namespace keepass2android
|
||||
|
||||
|
||||
public override void OnUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
// Only one database version so far
|
||||
if (oldVersion == 1)
|
||||
{
|
||||
db.ExecSQL("alter table " + FileTable + " add column " + KeyFileDisplayname + " text ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -94,7 +101,7 @@ namespace keepass2android
|
||||
mDb.Close();
|
||||
}
|
||||
|
||||
public long CreateFile(IOConnectionInfo ioc, String keyFile) {
|
||||
public long CreateFile(IOConnectionInfo ioc, string keyFile, string displayName = "") {
|
||||
|
||||
// Check to see if this filename is already used
|
||||
ICursor cursor;
|
||||
@@ -126,6 +133,7 @@ namespace keepass2android
|
||||
vals.Put(KeyFileUsername, iocToStore.UserName);
|
||||
vals.Put(KeyFilePassword, iocToStore.Password);
|
||||
vals.Put(KeyFileCredsavemode, (int)iocToStore.CredSaveMode);
|
||||
vals.Put(KeyFileDisplayname, displayName);
|
||||
|
||||
result = mDb.Update(FileTable, vals, KeyFileId + " = " + id, null);
|
||||
|
||||
@@ -138,8 +146,9 @@ namespace keepass2android
|
||||
vals.Put(KeyFilePassword, iocToStore.Password);
|
||||
vals.Put(KeyFileCredsavemode, (int)iocToStore.CredSaveMode);
|
||||
vals.Put(KeyFileUpdated, Java.Lang.JavaSystem.CurrentTimeMillis());
|
||||
|
||||
result = mDb.Insert(FileTable, null, vals);
|
||||
vals.Put(KeyFileDisplayname, displayName);
|
||||
|
||||
result = mDb.Insert(FileTable, null, vals);
|
||||
|
||||
}
|
||||
// Delete all but the last X records
|
||||
@@ -193,7 +202,8 @@ namespace keepass2android
|
||||
KeyFileKeyfile,
|
||||
KeyFileUsername,
|
||||
KeyFilePassword,
|
||||
KeyFileCredsavemode
|
||||
KeyFileCredsavemode,
|
||||
KeyFileDisplayname
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -229,12 +229,21 @@ namespace keepass2android
|
||||
|
||||
public override void BindView(View view, Context context, ICursor cursor)
|
||||
{
|
||||
|
||||
String path = cursor.GetString(1);
|
||||
|
||||
TextView textView = view.FindViewById<TextView>(Resource.Id.file_filename);
|
||||
IOConnectionInfo ioc = new IOConnectionInfo { Path = path };
|
||||
var fileStorage = _app.GetFileStorage(ioc);
|
||||
textView.Text = fileStorage.GetDisplayName(ioc);
|
||||
|
||||
String displayName = cursor.GetString(6);
|
||||
if (string.IsNullOrEmpty(displayName))
|
||||
{
|
||||
displayName = fileStorage.GetDisplayName(ioc);
|
||||
|
||||
}
|
||||
|
||||
textView.Text = displayName;
|
||||
textView.Tag = ioc.Path;
|
||||
|
||||
}
|
||||
|
||||
@@ -865,7 +865,7 @@ namespace keepass2android
|
||||
{
|
||||
CompositeKey masterKey = App.Kp2a.GetDb().KpDatabase.MasterKey;
|
||||
var sourceIoc = ((KcpKeyFile)masterKey.GetUserKey(typeof(KcpKeyFile))).Ioc;
|
||||
var newIoc = ImportFileToInternalDirectory(sourceIoc);
|
||||
var newIoc = IoUtil.ImportFileToInternalDirectory(sourceIoc, Activity, App.Kp2a);
|
||||
((KcpKeyFile)masterKey.GetUserKey(typeof(KcpKeyFile))).ResetIoc(newIoc);
|
||||
var keyfileString = IOConnectionInfo.SerializeToString(newIoc);
|
||||
App.Kp2a.StoreOpenedFileAsRecent(App.Kp2a.GetDb().Ioc, keyfileString);
|
||||
@@ -934,7 +934,7 @@ namespace keepass2android
|
||||
try
|
||||
{
|
||||
var sourceIoc = App.Kp2a.GetDb().Ioc;
|
||||
var newIoc = ImportFileToInternalDirectory(sourceIoc);
|
||||
var newIoc = IoUtil.ImportFileToInternalDirectory(sourceIoc, Activity, App.Kp2a);
|
||||
return () =>
|
||||
{
|
||||
var builder = new AlertDialog.Builder(Activity);
|
||||
@@ -968,32 +968,6 @@ namespace keepass2android
|
||||
|
||||
}
|
||||
|
||||
private IOConnectionInfo ImportFileToInternalDirectory(IOConnectionInfo sourceIoc)
|
||||
{
|
||||
Java.IO.File internalDirectory = IoUtil.GetInternalDirectory(Activity);
|
||||
string targetPath = UrlUtil.GetFileName(sourceIoc.Path);
|
||||
targetPath = targetPath.Trim("|\\?*<\":>+[]/'".ToCharArray());
|
||||
if (targetPath == "")
|
||||
targetPath = "imported";
|
||||
if (new File(internalDirectory, targetPath).Exists())
|
||||
{
|
||||
int c = 1;
|
||||
var ext = UrlUtil.GetExtension(targetPath);
|
||||
var filenameWithoutExt = UrlUtil.StripExtension(targetPath);
|
||||
do
|
||||
{
|
||||
c++;
|
||||
targetPath = filenameWithoutExt + c;
|
||||
if (!String.IsNullOrEmpty(ext))
|
||||
targetPath += "." + ext;
|
||||
} while (new File(internalDirectory, targetPath).Exists());
|
||||
}
|
||||
var targetIoc = IOConnectionInfo.FromPath(new File(internalDirectory, targetPath).CanonicalPath);
|
||||
|
||||
IoUtil.Copy(targetIoc, sourceIoc, App.Kp2a);
|
||||
return targetIoc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void SetAlgorithm(Database db, Preference algorithm)
|
||||
|
||||
Reference in New Issue
Block a user