added UI for opening a database with OTPs. Some TODOs and things not yet working!

This commit is contained in:
Philipp Crocoll
2013-11-17 07:17:15 +01:00
parent 59eace5834
commit c686cbeeb3
23 changed files with 2745 additions and 4945 deletions

View File

@@ -3,6 +3,7 @@ using Android.App;
using System.IO;
using Android.Content;
using Android.OS;
using KeePassLib.Keys;
using KeePassLib.Serialization;
using keepass2android.Io;
@@ -22,7 +23,7 @@ namespace keepass2android
/// <summary>
/// Loads the specified data as the currently open database, as unlocked.
/// </summary>
void LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, string s, string keyFile, ProgressDialogStatusLogger statusLogger);
void LoadDatabase(IOConnectionInfo ioConnectionInfo, MemoryStream memoryStream, CompositeKey compKey, ProgressDialogStatusLogger statusLogger);
/// <summary>
/// Returns the current database

View File

@@ -107,16 +107,6 @@ namespace keepass2android.Io
}
}
public bool CompleteIoId()
{
throw new NotImplementedException();
}
public bool? FileExists()
{
throw new NotImplementedException();
}
public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc)
{
return UrlUtil.StripExtension(
@@ -207,5 +197,19 @@ namespace keepass2android.Io
parent += "/";
return parent + newFilename;
}
public IOConnectionInfo GetParentPath(IOConnectionInfo ioc)
{
return IoUtil.GetParentPath(ioc);
}
public IOConnectionInfo GetFilePath(IOConnectionInfo folderPath, string filename)
{
IOConnectionInfo res = folderPath.CloneDeep();
if (!res.Path.EndsWith("/"))
res.Path += "/";
res.Path += filename;
return res;
}
}
}

View File

@@ -400,16 +400,6 @@ namespace keepass2android.Io
return new CachedWriteTransaction(ioc, useFileTransaction, this);
}
public bool CompleteIoId()
{
throw new NotImplementedException();
}
public bool? FileExists()
{
throw new NotImplementedException();
}
public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc)
{
return UrlUtil.StripExtension(
@@ -487,6 +477,54 @@ namespace keepass2android.Io
return _cachedStorage.CreateFilePath(parent, newFilename);
}
public IOConnectionInfo GetParentPath(IOConnectionInfo ioc)
{
return _cachedStorage.GetParentPath(ioc);
}
public IOConnectionInfo GetFilePath(IOConnectionInfo folderPath, string filename)
{
try
{
IOConnectionInfo res = _cachedStorage.GetFilePath(folderPath, filename);
//some file storage implementations require accessing the network to determine the file path (e.g. because
//they might contain file ids). In this case, we need to cache the result to enable cached access to such files
StoreFilePath(folderPath, filename, res);
return res;
}
catch (Exception)
{
IOConnectionInfo res;
if (!TryGetCachedFilePath(folderPath, filename, out res)) throw;
return res;
}
}
private void StoreFilePath(IOConnectionInfo folderPath, string filename, IOConnectionInfo res)
{
File.WriteAllText(CachedFilePath(GetPseudoIoc(folderPath, filename)) + ".filepath", res.Path);
}
private IOConnectionInfo GetPseudoIoc(IOConnectionInfo folderPath, string filename)
{
IOConnectionInfo res = folderPath.CloneDeep();
if (!res.Path.EndsWith("/"))
res.Path += "/";
res.Path += filename;
return res;
}
private bool TryGetCachedFilePath(IOConnectionInfo folderPath, string filename, out IOConnectionInfo res)
{
res = folderPath.CloneDeep();
string filePathCache = CachedFilePath(GetPseudoIoc(folderPath, filename)) + ".filepath";
if (!File.Exists(filePathCache))
return false;
res.Path = File.ReadAllText(filePathCache);
return true;
}
public string GetBaseVersionHash(IOConnectionInfo ioc)
{

View File

@@ -82,19 +82,6 @@ namespace keepass2android.Io
/// <param name="useFileTransaction">if true, force to use file system level transaction. This might be ignored if the file storage has built in transaction support</param>
IWriteTransaction OpenWriteTransaction(IOConnectionInfo ioc, bool useFileTransaction);
/// <summary>
/// brings up a dialog to query credentials or something like this.
/// </summary>
/// <returns>true if success, false if error or cancelled by user</returns>
bool CompleteIoId( /*in/out ioId*/);
/// <summary>
/// Checks whether the given file exists.
/// </summary>
/// <returns>true if it exists, false if not. Null if the check couldn't be performed (e.g. because no credentials available or no connection established.)</returns>
bool? FileExists( /*ioId*/);
string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc);
/// <summary>
@@ -135,10 +122,10 @@ namespace keepass2android.Io
void StartSelectFile(IFileStorageSetupInitiatorActivity activity, bool isForSave, int requestCode, string protocolId);
/// <summary>
/// Initiates the process for choosing a file in the given file storage.
/// Initiates the process for using a file in the given file storage.
/// The file storage should either call OnImmediateResult or StartFileUsageProcess
/// If alwaysReturnSuccess is true, the activity should be finished with ResultCode Ok.
/// This can make sense if a higher-level file storage has the file cached by still wants to
/// This can make sense if a higher-level file storage has the file cached but still wants to
/// give the cached storage the chance to initialize file access.
/// </summary>
void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode, bool alwaysReturnSuccess);
@@ -157,6 +144,17 @@ namespace keepass2android.Io
//returns the path of a file "newFilename" in the folder "parent"
//this may create the file if this is required to get a path (if a UUID is part of the file path)
string CreateFilePath(string parent, string newFilename);
/// <summary>
/// returns the parent folder of ioc
/// </summary>
IOConnectionInfo GetParentPath(IOConnectionInfo ioc);
/// <summary>
/// returns the file path of the file "filename" in the folderPath.
/// </summary>
/// The method may throw FileNotFoundException or not in case the file doesn't exist.
IOConnectionInfo GetFilePath(IOConnectionInfo folderPath, string filename);
}
public interface IWriteTransaction: IDisposable

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Text;
using Java.IO;
using KeePassLib.Serialization;
namespace keepass2android.Io
{
@@ -30,5 +31,20 @@ namespace keepass2android.Io
}
public static IOConnectionInfo GetParentPath(IOConnectionInfo ioc)
{
var iocParent = ioc.CloneDeep();
if (iocParent.Path.EndsWith("/"))
iocParent.Path = iocParent.Path.Substring(0, iocParent.Path.Length - 1);
int slashPos = iocParent.Path.LastIndexOf("/", StringComparison.Ordinal);
if (slashPos == -1)
iocParent.Path = "";
else
{
iocParent.Path = iocParent.Path.Substring(0, slashPos);
}
return iocParent;
}
}
}

View File

@@ -151,16 +151,6 @@ namespace keepass2android.Io
}
}
public bool CompleteIoId()
{
throw new NotImplementedException();
}
public bool? FileExists()
{
throw new NotImplementedException();
}
public string GetFilenameWithoutPathAndExt(IOConnectionInfo ioc)
{
return UrlUtil.StripExtension(

View File

@@ -82,29 +82,14 @@ namespace keepass2android
}
/// <summary>
/// Do not call this method directly. Call App.Kp2a.LoadDatabase instead.
/// </summary>
public void LoadData(IKp2aApp app, IOConnectionInfo iocInfo, MemoryStream databaseData, String password, String keyfile, ProgressDialogStatusLogger status)
public void LoadData(IKp2aApp app, IOConnectionInfo iocInfo, MemoryStream databaseData, CompositeKey compositeKey, ProgressDialogStatusLogger status)
{
PwDatabase pwDatabase = new PwDatabase();
CompositeKey compositeKey = new CompositeKey();
compositeKey.AddUserKey(new KcpPassword(password));
if (!String.IsNullOrEmpty(keyfile))
{
try
{
compositeKey.AddUserKey(new KcpKeyFile(keyfile));
} catch (Exception e)
{
Kp2aLog.Log(e.ToString());
throw new KeyFileException();
}
}
IFileStorage fileStorage = _app.GetFileStorage(iocInfo);
var filename = fileStorage.GetFilenameWithoutPathAndExt(iocInfo);
try
@@ -115,7 +100,9 @@ namespace keepass2android
}
catch (InvalidCompositeKeyException)
{
if ((password == "") && (keyfile != null))
KcpPassword passwordKey = (KcpPassword)compositeKey.GetUserKey(typeof(KcpPassword));
if ((passwordKey != null) && (passwordKey.Password.ReadString() == "") && (compositeKey.UserKeyCount > 1))
{
//if we don't get a password, we don't know whether this means "empty password" or "no password"
//retry without password:

View File

@@ -19,6 +19,7 @@ using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using KeePassLib.Keys;
using KeePassLib.Serialization;
namespace keepass2android
@@ -26,20 +27,20 @@ namespace keepass2android
public class LoadDb : RunnableOnFinish {
private readonly IOConnectionInfo _ioc;
private readonly Task<MemoryStream> _databaseData;
private readonly String _pass;
private readonly String _key;
private readonly CompositeKey _compositeKey;
private readonly string _keyfileOrProvider;
private readonly IKp2aApp _app;
private readonly bool _rememberKeyfile;
public LoadDb(IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, String pass, String key, OnFinish finish): base(finish)
public LoadDb(IKp2aApp app, IOConnectionInfo ioc, Task<MemoryStream> databaseData, CompositeKey compositeKey, String keyfileOrProvider, OnFinish finish): base(finish)
{
_app = app;
_ioc = ioc;
_databaseData = databaseData;
_pass = pass;
_key = key;
_compositeKey = compositeKey;
_keyfileOrProvider = keyfileOrProvider;
_rememberKeyfile = app.GetBooleanPreference(PreferenceKey.remember_keyfile);
}
@@ -50,8 +51,8 @@ namespace keepass2android
{
StatusLogger.UpdateMessage(UiStringKey.loading_database);
MemoryStream memoryStream = _databaseData == null ? null : _databaseData.Result;
_app.LoadDatabase(_ioc, memoryStream, _pass, _key, StatusLogger);
SaveFileData(_ioc, _key);
_app.LoadDatabase(_ioc, memoryStream, _compositeKey, StatusLogger);
SaveFileData(_ioc, _keyfileOrProvider);
}
catch (KeyFileException)
@@ -88,13 +89,13 @@ namespace keepass2android
Finish(true);
}
private void SaveFileData(IOConnectionInfo ioc, String key) {
private void SaveFileData(IOConnectionInfo ioc, String keyfileOrProvider) {
if (!_rememberKeyfile)
{
key = "";
keyfileOrProvider = "";
}
_app.StoreOpenedFileAsRecent(ioc, key);
_app.StoreOpenedFileAsRecent(ioc, keyfileOrProvider);
}