Merge branch 'Branch_1.07'

# Resolved Conflicts:
#	src/keepass2android/Resources/values/strings.xml
This commit is contained in:
Philipp Crocoll
2019-10-10 03:25:02 +02:00
4 changed files with 242 additions and 165 deletions

View File

@@ -294,19 +294,37 @@ namespace keepass2android.Io
get { yield return ProtocolId; }
}
Dictionary<String /*userid*/, IGraphServiceClient> mClientByUser =
new Dictionary<String /*userid*/, IGraphServiceClient>();
class GraphServiceClientWithState
{
public IGraphServiceClient Client { get; set; }
public DateTime TokenExpiryDate { get; set; }
public bool RequiresUserInteraction { get; set; }
}
private IGraphServiceClient tryGetMsGraphClient(String path)
readonly Dictionary<String /*userid*/, GraphServiceClientWithState> mClientByUser =
new Dictionary<String /*userid*/, GraphServiceClientWithState>();
private async Task<IGraphServiceClient> TryGetMsGraphClient(String path, bool tryConnect)
{
String userId = OneDrive2ItemLocation<OneDrive2PrefixContainerType>.FromString(path).User.Id;
if (mClientByUser.ContainsKey(userId))
return mClientByUser[userId];
{
GraphServiceClientWithState clientWithState = mClientByUser[userId];
if (!(clientWithState.RequiresUserInteraction || (clientWithState.TokenExpiryDate < DateTime.Now) || (clientWithState.Client == null)))
return clientWithState.Client;
}
if (tryConnect)
{
if (await TryLoginSilent(path) != null)
{
return mClientByUser[userId].Client;
}
}
return null;
}
private IGraphServiceClient buildClient(AuthenticationResult authenticationResult)
private IGraphServiceClient BuildClient(AuthenticationResult authenticationResult)
{
logDebug("buildClient...");
@@ -321,14 +339,20 @@ namespace keepass2android.Io
return Task.FromResult(0);
});
GraphServiceClient graphClient = new GraphServiceClient(authenticationProvider);
GraphServiceClientWithState clientWithState = new GraphServiceClientWithState()
{
Client = new GraphServiceClient(authenticationProvider),
RequiresUserInteraction = false,
TokenExpiryDate = authenticationResult.ExpiresOn.LocalDateTime
};
if (authenticationResult.Account == null)
throw new Exception("authenticationResult.Account == null!");
mClientByUser[authenticationResult.Account.HomeAccountId.Identifier] = graphClient;
mClientByUser[authenticationResult.Account.HomeAccountId.Identifier] = clientWithState;
return graphClient;
return clientWithState.Client;
}
@@ -341,7 +365,7 @@ namespace keepass2android.Io
protected abstract string SpecialFolder { get; }
private PathItemBuilder GetPathItemBuilder(String path)
private async Task<PathItemBuilder> GetPathItemBuilder(String path)
{
PathItemBuilder result = new PathItemBuilder(SpecialFolder);
@@ -351,12 +375,13 @@ namespace keepass2android.Io
{
throw new Exception("path does not contain user");
}
result.client = null;
if (!mClientByUser.TryGetValue(result.itemLocation.User.Id, out result.client))
{
throw new Exception("failed to get client for " + result.itemLocation.User.Id);
}
result.client = await TryGetMsGraphClient(path, true);
if (result.client == null)
throw new Exception("Failed to connect or authenticate to OneDrive!");
return result;
}
@@ -400,10 +425,14 @@ namespace keepass2android.Io
{
try
{
PathItemBuilder pathItemBuilder = GetPathItemBuilder(ioc.Path);
Task.Run(async () => await pathItemBuilder.getPathItem()
.Request()
.DeleteAsync()).Wait();
Task.Run(async () =>
{
PathItemBuilder pathItemBuilder = await GetPathItemBuilder(ioc.Path);
await pathItemBuilder.getPathItem()
.Request()
.DeleteAsync();
}).Wait();
}
catch (Exception e)
{
@@ -426,13 +455,17 @@ namespace keepass2android.Io
try
{
string path = ioc.Path;
PathItemBuilder clientAndpath = GetPathItemBuilder(path);
logDebug("openFileForRead. Path=" + path);
Stream result = Task.Run(async () => await clientAndpath
.getPathItem()
.Content
.Request()
.GetAsync()).Result;
Stream result = Task.Run(async () =>
{
PathItemBuilder clientAndpath = await GetPathItemBuilder(path);
return await clientAndpath
.getPathItem()
.Content
.Request()
.GetAsync();
}).Result;
logDebug("ok");
return result;
@@ -479,14 +512,16 @@ namespace keepass2android.Io
{
try
{
PathItemBuilder pathItemBuilder = GetPathItemBuilder(path);
Task.Run(async () => await
pathItemBuilder
.getPathItem()
.Content
.Request()
.PutAsync<DriveItem>(stream)).Wait();
Task.Run(async () =>
{
PathItemBuilder pathItemBuilder = await GetPathItemBuilder(path);
return await
pathItemBuilder
.getPathItem()
.Content
.Request()
.PutAsync<DriveItem>(stream);
}).Wait();
}
catch (Exception e)
@@ -530,15 +565,16 @@ namespace keepass2android.Io
driveItem.Name = newDirName;
driveItem.Folder = new Folder();
PathItemBuilder pathItemBuilder = GetPathItemBuilder(parentIoc.Path);
DriveItem res = Task.Run(async () =>
{
logDebug("building request for " + pathItemBuilder.itemLocation);
DriveItem res = Task.Run(async () => await pathItemBuilder.getPathItem()
.Children
.Request()
.AddAsync(driveItem)).Result;
PathItemBuilder pathItemBuilder = await GetPathItemBuilder(parentIoc.Path);
return await pathItemBuilder.getPathItem()
.Children
.Request()
.AddAsync(driveItem);
}).Result;
}
@@ -552,43 +588,8 @@ namespace keepass2android.Io
{
try
{
PathItemBuilder pathItemBuilder = GetPathItemBuilder(ioc.Path);
logDebug("listing files for " + ioc.Path);
if (!pathItemBuilder.hasShare() && !pathItemBuilder.hasOneDrivePath())
{
logDebug("listing shares.");
return ListShares(pathItemBuilder.itemLocation, pathItemBuilder.client);
}
logDebug("listing regular children.");
List<FileDescription> result = new List<FileDescription>();
/*logDebug("parent before:" + parentPath);
parentPath = parentPath.substring(getProtocolPrefix().length());
logDebug("parent after: " + parentPath);*/
IDriveItemChildrenCollectionPage itemsPage = Task.Run(async () => await pathItemBuilder.getPathItem()
.Children
.Request()
.GetAsync()).Result;
while (true)
{
IList<DriveItem> items = itemsPage.CurrentPage;
if (!items.Any())
return result;
foreach (DriveItem i in items)
{
var e = GetFileDescription(pathItemBuilder.itemLocation.BuildLocalChildLocation(i.Name, i.Id, i.ParentReference?.DriveId), i);
result.Add(e);
}
var nextPageReqBuilder = itemsPage.NextPageRequest;
if (nextPageReqBuilder == null)
return result;
itemsPage = Task.Run(async () => await nextPageReqBuilder.GetAsync()).Result;
}
return Task.Run(async () => await ListContentsAsync(ioc)).Result;
}
catch (Exception e)
{
@@ -596,6 +597,46 @@ namespace keepass2android.Io
}
}
private async Task<IEnumerable<FileDescription>> ListContentsAsync(IOConnectionInfo ioc)
{
PathItemBuilder pathItemBuilder = await GetPathItemBuilder(ioc.Path);
logDebug("listing files for " + ioc.Path);
if (!pathItemBuilder.hasShare() && !pathItemBuilder.hasOneDrivePath())
{
logDebug("listing shares.");
return await ListShares(pathItemBuilder.itemLocation, pathItemBuilder.client);
}
logDebug("listing regular children.");
List<FileDescription> result = new List<FileDescription>();
/*logDebug("parent before:" + parentPath);
parentPath = parentPath.substring(getProtocolPrefix().length());
logDebug("parent after: " + parentPath);*/
IDriveItemChildrenCollectionPage itemsPage = await pathItemBuilder.getPathItem()
.Children
.Request()
.GetAsync();
while (true)
{
IList<DriveItem> items = itemsPage.CurrentPage;
if (!items.Any())
return result;
foreach (DriveItem i in items)
{
var e = GetFileDescription(pathItemBuilder.itemLocation.BuildLocalChildLocation(i.Name, i.Id, i.ParentReference?.DriveId), i);
result.Add(e);
}
var nextPageReqBuilder = itemsPage.NextPageRequest;
if (nextPageReqBuilder == null)
return result;
itemsPage = Task.Run(async () => await nextPageReqBuilder.GetAsync()).Result;
}
}
private FileDescription GetFileDescription(OneDrive2ItemLocation<OneDrive2PrefixContainerType> path, DriveItem i)
{
@@ -620,24 +661,7 @@ namespace keepass2android.Io
{
try
{
string filename = ioc.Path;
PathItemBuilder pathItemBuilder = GetPathItemBuilder(filename);
if (!pathItemBuilder.itemLocation.LocalPath.Any()
&& !pathItemBuilder.hasShare())
{
FileDescription rootEntry = new FileDescription();
rootEntry.CanRead = rootEntry.CanWrite = true;
rootEntry.Path = filename;
rootEntry.DisplayName = pathItemBuilder.itemLocation.User.Name;
rootEntry.IsDirectory = true;
return rootEntry;
}
IDriveItemRequestBuilder pathItem = pathItemBuilder.getPathItem();
DriveItem item = Task.Run(async () => await pathItem.Request().GetAsync()).Result;
return GetFileDescription(pathItemBuilder.itemLocation, item);
return Task.Run(async() => await GetFileDescriptionAsync(ioc)).Result;
}
catch (Exception e)
{
@@ -645,6 +669,28 @@ namespace keepass2android.Io
}
}
private async Task<FileDescription> GetFileDescriptionAsync(IOConnectionInfo ioc)
{
string filename = ioc.Path;
PathItemBuilder pathItemBuilder = await GetPathItemBuilder(filename);
if (!pathItemBuilder.itemLocation.LocalPath.Any()
&& !pathItemBuilder.hasShare())
{
FileDescription rootEntry = new FileDescription();
rootEntry.CanRead = rootEntry.CanWrite = true;
rootEntry.Path = filename;
rootEntry.DisplayName = pathItemBuilder.itemLocation.User.Name;
rootEntry.IsDirectory = true;
return rootEntry;
}
IDriveItemRequestBuilder pathItem = pathItemBuilder.getPathItem();
DriveItem item = await pathItem.Request().GetAsync();
return GetFileDescription(pathItemBuilder.itemLocation, item);
}
public bool RequiresSetup(IOConnectionInfo ioConnection)
{
return false;
@@ -663,13 +709,13 @@ namespace keepass2android.Io
}
private bool isConnected(String path)
private async Task<bool> IsConnectedAsync(string path, bool tryConnect)
{
try
{
logDebug("isConnected? " + path);
return tryGetMsGraphClient(path) != null;
return (await TryGetMsGraphClient(path, tryConnect)) != null;
}
catch (Exception e)
{
@@ -679,11 +725,15 @@ namespace keepass2android.Io
}
public bool IsConnected(string path)
{
return Task.Run(async () => await IsConnectedAsync(path, false)).Result;
}
public void PrepareFileUsage(IFileStorageSetupInitiatorActivity activity, IOConnectionInfo ioc, int requestCode,
bool alwaysReturnSuccess)
{
if (isConnected(ioc.Path))
if (IsConnected(ioc.Path))
{
Intent intent = new Intent();
intent.PutExtra(FileStorageSetupDefs.ExtraPath, ioc.Path);
@@ -698,7 +748,7 @@ namespace keepass2android.Io
public void PrepareFileUsage(Context ctx, IOConnectionInfo ioc)
{
if (!isConnected(ioc.Path))
if (!Task.Run(async() => await IsConnectedAsync(ioc.Path, true)).Result)
{
throw new Exception("MsGraph login required");
}
@@ -714,7 +764,7 @@ namespace keepass2android.Io
}
protected void finishActivityWithSuccess(
protected void FinishActivityWithSuccess(
IFileStorageSetupActivity setupActivity)
{
//Log.d("KP2AJ", "Success with authenticating!");
@@ -751,19 +801,50 @@ namespace keepass2android.Io
if (activity.ProcessName.Equals(FileStorageSetupDefs.ProcessNameFileUsageSetup))
activity.State.PutString(FileStorageSetupDefs.ExtraPath, activity.Ioc.Path);
string rootPathForUser = await TryLoginSilent(activity.Ioc.Path);
if (rootPathForUser != null)
{
FinishActivityWithSuccess(activity, rootPathForUser);
}
try
{
logDebug("try interactive");
AuthenticationResult res = await _publicClientApp.AcquireTokenInteractive(Scopes)
.WithParentActivityOrWindow((Activity)activity)
.ExecuteAsync();
logDebug("ok interactive");
BuildClient(res);
FinishActivityWithSuccess(activity, BuildRootPathForUser(res));
}
catch (Exception e)
{
logDebug("authenticating not successful: " + e);
Intent data = new Intent();
data.PutExtra(FileStorageSetupDefs.ExtraErrorMessage, "authenticating not successful");
((Activity)activity).SetResult(Result.Canceled, data);
((Activity)activity).Finish();
}
}
private async Task<string> TryLoginSilent(string iocPath)
{
IAccount account = null;
try
{
String userId = OneDrive2ItemLocation<OneDrive2PrefixContainerType>.FromString(activity.Ioc.Path).User?.Id;
if (mClientByUser.ContainsKey(userId))
if (IsConnected(iocPath))
{
finishActivityWithSuccess(activity);
return;
return iocPath;
}
String userId = OneDrive2ItemLocation<OneDrive2PrefixContainerType>.FromString(iocPath).User?.Id;
logDebug("needs acquire token");
logDebug("trying silent login " + activity.Ioc.Path);
logDebug("trying silent login " + iocPath);
account = Task.Run(async () => await _publicClientApp.GetAccountAsync(userId)).Result;
logDebug("getting user ok.");
@@ -783,54 +864,46 @@ namespace keepass2android.Io
.ExecuteAsync();
logDebug("AcquireTokenSilent ok.");
var graphClient = buildClient(authResult);
BuildClient(authResult);
/*User me = await graphClient.Me.Request().WithForceRefresh(true).GetAsync();
logDebug("received name " + me.DisplayName);*/
finishActivityWithSuccess(activity, authResult);
return;
return BuildRootPathForUser(authResult);
}
catch (MsalUiRequiredException ex)
{
logDebug("ui required");
GraphServiceClientWithState clientWithState = new GraphServiceClientWithState()
{
Client = null,
RequiresUserInteraction = true
};
mClientByUser[account.HomeAccountId.Identifier] = clientWithState;
logDebug("ui required");
return null;
}
catch (Exception ex)
{
logDebug("silent login failed: " + ex.ToString());
return null;
}
}
try
{
logDebug("try interactive");
AuthenticationResult res = await _publicClientApp.AcquireTokenInteractive(Scopes)
.WithParentActivityOrWindow((Activity)activity)
.ExecuteAsync();
logDebug("ok interactive");
buildClient(res);
finishActivityWithSuccess(activity, res);
}
catch (Exception e)
{
logDebug("authenticating not successful: " + e);
Intent data = new Intent();
data.PutExtra(FileStorageSetupDefs.ExtraErrorMessage, "authenticating not successful");
((Activity)activity).SetResult(Result.Canceled, data);
((Activity)activity).Finish();
}
return null;
}
string buildRootPathForUser(AuthenticationResult res)
string BuildRootPathForUser(AuthenticationResult res)
{
return OneDrive2ItemLocation<OneDrive2PrefixContainerType>.RootForUser(res.Account.Username, res.Account.HomeAccountId.Identifier).ToString();
}
private void finishActivityWithSuccess(IFileStorageSetupActivity activity, AuthenticationResult authResult)
private void FinishActivityWithSuccess(IFileStorageSetupActivity activity, string rootPathForUser)
{
activity.State.PutString(FileStorageSetupDefs.ExtraPath, buildRootPathForUser(authResult));
finishActivityWithSuccess(activity);
activity.State.PutString(FileStorageSetupDefs.ExtraPath, rootPathForUser);
FinishActivityWithSuccess(activity);
}
public void OnActivityResult(IFileStorageSetupActivity activity, int requestCode, int resultCode, Intent data)
@@ -871,13 +944,13 @@ namespace keepass2android.Io
}
private List<FileDescription> ListShares(OneDrive2ItemLocation<OneDrive2PrefixContainerType> parentPath, IGraphServiceClient client)
private async Task<List<FileDescription>> ListShares(OneDrive2ItemLocation<OneDrive2PrefixContainerType> parentPath, IGraphServiceClient client)
{
List<FileDescription> result = new List<FileDescription>();
DriveItem root = Task.Run(async () => await client.Me.Drive.Root.Request().GetAsync()).Result;
DriveItem root = await client.Me.Drive.Root.Request().GetAsync();
FileDescription myEntry = GetFileDescription(parentPath.BuildShare("me","me","me", root.ParentReference?.DriveId), root);
myEntry.DisplayName = MyOneDriveDisplayName;
@@ -888,8 +961,7 @@ namespace keepass2android.Io
IDriveSharedWithMeCollectionPage sharedWithMeCollectionPage =
Task.Run(async () => await client.Me.Drive.SharedWithMe().Request().GetAsync()).Result;
IDriveSharedWithMeCollectionPage sharedWithMeCollectionPage = await client.Me.Drive.SharedWithMe().Request().GetAsync();
while (true)
{
@@ -905,7 +977,7 @@ namespace keepass2android.Io
}
var b = sharedWithMeCollectionPage.NextPageRequest;
if (b == null) break;
sharedWithMeCollectionPage = Task.Run(async () => await b.GetAsync()).Result;
sharedWithMeCollectionPage = await b.GetAsync();
}
return result;
}
@@ -945,29 +1017,7 @@ namespace keepass2android.Io
{
try
{
DriveItem driveItem = new DriveItem();
driveItem.Name = newFilename;
driveItem.File = new File();
PathItemBuilder pathItemBuilder = GetPathItemBuilder(parent);
//see if such a file exists already:
var item = TryFindFile(pathItemBuilder, newFilename);
if (item != null)
{
return pathItemBuilder.itemLocation.BuildLocalChildLocation(item.Name, item.Id, item.ParentReference?.DriveId).ToString();
}
//doesn't exist. Create:
logDebug("building request for " + pathItemBuilder.itemLocation);
DriveItem res = Task.Run(async () => await pathItemBuilder.getPathItem()
.Children
.Request()
.AddAsync(driveItem)).Result;
return pathItemBuilder.itemLocation.BuildLocalChildLocation(res.Name, res.Id, res.ParentReference?.DriveId).ToString();
return Task.Run(async() => await CreateFilePathAsync(parent, newFilename)).Result;
}
catch (Exception e)
{
@@ -976,6 +1026,32 @@ namespace keepass2android.Io
}
private async Task<string> CreateFilePathAsync(string parent, string newFilename)
{
DriveItem driveItem = new DriveItem();
driveItem.Name = newFilename;
driveItem.File = new File();
PathItemBuilder pathItemBuilder = await GetPathItemBuilder(parent);
//see if such a file exists already:
var item = TryFindFile(pathItemBuilder, newFilename);
if (item != null)
{
return pathItemBuilder.itemLocation.BuildLocalChildLocation(item.Name, item.Id, item.ParentReference?.DriveId)
.ToString();
}
//doesn't exist. Create:
logDebug("building request for " + pathItemBuilder.itemLocation);
DriveItem res = await pathItemBuilder.getPathItem()
.Children
.Request()
.AddAsync(driveItem);
return pathItemBuilder.itemLocation.BuildLocalChildLocation(res.Name, res.Id, res.ParentReference?.DriveId)
.ToString();
}
public IOConnectionInfo GetParentPath(IOConnectionInfo ioc)
{
return IOConnectionInfo.FromPath(OneDrive2ItemLocation<OneDrive2PrefixContainerType>.FromString(ioc.Path).Parent.ToString());

View File

@@ -635,7 +635,7 @@
<string name="EntryChannel_desc">Értesítés a jelenleg kiválasztott bejegyzés egyszerűsített eléréséhez.</string>
<string name="ShowKeyboardDuringFingerprintAuth">A billentyűzet megjelenítése a jelszóbeíráshoz ujjlenyomat-leolvasás közben.</string>
<string name="ChangeLog_keptDonate">Lehetőségek kiterjesztése, hogy egy sörrel vagy valami mással támogasson</string>
<string name="ChangeLog"><b>Version 0.6.2</b>
<string name="ChangeLog">&lt;b&gt;Version 0.6.2&lt;/&gt;
* Google Drive/Dropbox/... integráció: Ha a hivatalos Google Drive vagy Dropbox applikációból nyit meg egy .kdbx fájlt, akkor az autómatikusan a KP2A-val kerül megnyitásra.
* Továbbfejlesztett kereső dialógus
* Továbbfejlesztett keresési eredmények ha a megosztott URL aldomaint tartalmaz

View File

@@ -543,7 +543,7 @@
<string name="SCOPE_QUERY_CREDENTIALS_title">Запрос учетных данных</string>
<string name="SCOPE_QUERY_CREDENTIALS_explanation">Плагину будет разрешено запрашивать учетные данные для веб-сайтов или приложений которые он использует.</string>
<string name="get_regular_version">Больше типов хранилищ</string>
<string name="CertificateWarning">Предупреждение: Ошибка проверки сертификата сервера: %1$ s. Установите соответствующий корневой сертификат на вашем устройстве или проверьте настройки!</string>
<string name="CertificateWarning">Предупреждение: Ошибка проверки сертификата сервера: %1$s. Установите соответствующий корневой сертификат на вашем устройстве или проверьте настройки!</string>
<string name="CertificateFailure">Ошибка: Проверка сертификата сервера не удалась! Установите соответствующий корневой сертификат или проверьте настройки!</string>
<string name="export_fileformats_title">Выберите формат файла</string>
<string name="killed_by_os">Извините! Keepass2Android был убит ОС Android! По соображениям безопасности Keepass2Android не сохраняет выбранные учетные данные на диске, так что вам нужно повторно открыть базу данных. Примечание: Это должно происходить очень редко. Если это так, пожалуйста, напишите мне сообщение на crocoapps@gmail.com.</string>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Generated by crowdin.net-->
<resources>
<string name="about_feedback">Feedback</string>
<string name="AboutText">Keepass2Android is a password manager providing read/write access to KeePass 2.x databases on Android.</string>
<string name="CreditsText">The User Interface is based on a port of KeepassDroid developed by Brian Pellin. Code for database operations is based on KeePass by Dominik Reichl. The Android robot is reproduced or modified from work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License.</string>