Merge branch 'master' of c:/ph/keepass2android

This commit is contained in:
Philipp Crocoll
2021-02-18 17:57:37 +01:00
10 changed files with 154 additions and 42 deletions

View File

@@ -322,20 +322,37 @@ namespace keepass2android.Io
private async Task<IGraphServiceClient> TryGetMsGraphClient(String path, bool tryConnect)
{
String userId = OneDrive2ItemLocation<OneDrive2PrefixContainerType>.FromString(path).User.Id;
logDebug("TryGetMsGraphClient for " + userId);
if (mClientByUser.ContainsKey(userId))
{
logDebug("TryGetMsGraphClient found user " + userId);
GraphServiceClientWithState clientWithState = mClientByUser[userId];
if (!(clientWithState.RequiresUserInteraction || (clientWithState.TokenExpiryDate < DateTime.Now) || (clientWithState.Client == null)))
if (!(clientWithState.RequiresUserInteraction || (clientWithState.TokenExpiryDate < DateTime.Now) ||
(clientWithState.Client == null)))
{
logDebug("TryGetMsGraphClient returning client");
return clientWithState.Client;
}
else
{
logDebug("not returning client because " + clientWithState.RequiresUserInteraction + " " +
(clientWithState.TokenExpiryDate < DateTime.Now) + " " + (clientWithState.Client == null));
}
}
if (tryConnect)
{
logDebug("trying to connect...");
if (await TryLoginSilent(path) != null)
{
logDebug("trying to connect ok");
return mClientByUser[userId].Client;
}
logDebug("trying to connect failed");
}
logDebug("TryGetMsGraphClient for " + userId + " returns null");
return null;
}
@@ -367,7 +384,7 @@ namespace keepass2android.Io
if (authenticationResult.Account == null)
throw new Exception("authenticationResult.Account == null!");
mClientByUser[authenticationResult.Account.HomeAccountId.Identifier] = clientWithState;
logDebug("buildClient ok.");
return clientWithState.Client;
}
@@ -375,7 +392,9 @@ namespace keepass2android.Io
private void logDebug(string str)
{
Log.Debug("KP2A", str);
#if DEBUG
Log.Debug("KP2A", "OneDrive2: " + str);
#endif
}
@@ -530,13 +549,50 @@ namespace keepass2android.Io
{
Task.Run(async () =>
{
PathItemBuilder pathItemBuilder = await GetPathItemBuilder(path);
PathItemBuilder pathItemBuilder = await GetPathItemBuilder(path);
//for small files <2MB use the direct upload:
if (stream.Length < 2* 1024 * 1024)
{
return await
pathItemBuilder
.getPathItem()
.Content
.Request()
.PutAsync<DriveItem>(stream);
}
//for larger files use an upload session. This is required for 4MB and beyond, but as the docs are not very clear about this
//limit, let's use it a bit more often to be safe.
var uploadProps = new DriveItemUploadableProperties
{
ODataType = null,
AdditionalData = new Dictionary<string, object>
{
{ "@microsoft.graph.conflictBehavior", "replace" }
}
};
var uploadSession = await pathItemBuilder
.getPathItem()
.CreateUploadSession(uploadProps)
.Request()
.PostAsync();
// Max slice size must be a multiple of 320 KiB
int maxSliceSize = 320 * 1024;
var fileUploadTask = new LargeFileUploadTask<DriveItem>(uploadSession, stream, maxSliceSize);
var uploadResult = await fileUploadTask.UploadAsync();
if (!uploadResult.UploadSucceeded)
{
throw new Exception("Failed to upload data!");
}
return uploadResult.ItemResponse;
}).Wait();
@@ -821,14 +877,17 @@ namespace keepass2android.Io
public async void OnStart(IFileStorageSetupActivity activity)
{
logDebug("OneDrive2.OnStart");
if (activity.ProcessName.Equals(FileStorageSetupDefs.ProcessNameFileUsageSetup))
activity.State.PutString(FileStorageSetupDefs.ExtraPath, activity.Ioc.Path);
string rootPathForUser = await TryLoginSilent(activity.Ioc.Path);
if (rootPathForUser != null)
{
logDebug("rootPathForUser not null");
FinishActivityWithSuccess(activity, rootPathForUser);
return;
}
logDebug("rootPathForUser null");
try
{
@@ -856,13 +915,14 @@ namespace keepass2android.Io
private async Task<string> TryLoginSilent(string iocPath)
{
logDebug("Login Silent for " + iocPath);
IAccount account = null;
try
{
if (IsConnected(iocPath))
{
logDebug("Login Silent ok, connected");
return iocPath;
}
String userId = OneDrive2ItemLocation<OneDrive2PrefixContainerType>.FromString(iocPath).User?.Id;
@@ -891,7 +951,9 @@ namespace keepass2android.Io
/*User me = await graphClient.Me.Request().WithForceRefresh(true).GetAsync();
logDebug("received name " + me.DisplayName);*/
return BuildRootPathForUser(authResult);
var rootFolder = BuildRootPathForUser(authResult);
logDebug("Found RootPath for user");
return rootFolder;
}
catch (MsalUiRequiredException ex)

View File

@@ -1,11 +1,10 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
// Laufzeitversion:4.0.30319.42000
// This code was generated by a tool.
//
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
// der Code erneut generiert wird.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
@@ -15,7 +14,7 @@ namespace keepass2android
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
public partial class Resource
{

View File

@@ -176,6 +176,7 @@ namespace keepass2android
public void StopListening()
{
Kp2aLog.Log("Fingerprint: StopListening " + (_biometricPrompt != null ? " having prompt " : " without prompt"));
_biometricAuthCallbackAdapter?.IgnoreNextError();
_biometricPrompt?.CancelAuthentication();
}
@@ -272,7 +273,24 @@ namespace keepass2android
try
{
_keystore.Load(null);
var aliases = _keystore.Aliases();
if (aliases == null)
{
Kp2aLog.Log("KS: no aliases");
}
else
{
while (aliases.HasMoreElements)
{
var o = aliases.NextElement();
Kp2aLog.Log("alias: " + o?.ToString());
}
Kp2aLog.Log("KS: end aliases");
}
var key = _keystore.GetKey(GetAlias(_keyId), null);
if (key == null)
throw new Exception("Failed to init cipher for fingerprint Init: key is null");
var ivParams = new IvParameterSpec(_iv);
_cipher.Init(CipherMode.DecryptMode, key, ivParams);
@@ -286,27 +304,27 @@ namespace keepass2android
}
catch (KeyStoreException e)
{
throw new RuntimeException(FailedToInitCipher, e);
throw new RuntimeException(FailedToInitCipher + " (keystore)", e);
}
catch (CertificateException e)
{
throw new RuntimeException(FailedToInitCipher, e);
throw new RuntimeException(FailedToInitCipher + " (CertificateException)", e);
}
catch (UnrecoverableKeyException e)
{
throw new RuntimeException(FailedToInitCipher, e);
throw new RuntimeException(FailedToInitCipher + " (UnrecoverableKeyException)", e);
}
catch (IOException e)
{
throw new RuntimeException(FailedToInitCipher, e);
throw new RuntimeException(FailedToInitCipher + " (IOException)", e);
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException(FailedToInitCipher, e);
throw new RuntimeException(FailedToInitCipher + " (NoSuchAlgorithmException)", e);
}
catch (InvalidKeyException e)
{
throw new RuntimeException(FailedToInitCipher, e);
throw new RuntimeException(FailedToInitCipher + " (InvalidKeyException)" + e.ToString(), e);
}
}
@@ -349,14 +367,19 @@ namespace keepass2android
try
{
_keystore.Load(null);
_keyGen.Init(new KeyGenParameterSpec.Builder(GetAlias(_keyId),
KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(GetAlias(_keyId),
KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
.SetBlockModes(KeyProperties.BlockModeCbc)
// Require the user to authenticate with biometry to authorize every use
// of the key
.SetEncryptionPaddings(KeyProperties.EncryptionPaddingPkcs7)
.SetUserAuthenticationRequired(true)
.SetUserAuthenticationRequired(true);
if ((int)Build.VERSION.SdkInt >= 24)
builder.SetInvalidatedByBiometricEnrollment(false);
_keyGen.Init(
builder
.Build());
_keyGen.GenerateKey();
}

View File

@@ -429,7 +429,9 @@ namespace keepass2android
// Update last access time.
Entry.Touch(false);
if (PwDefs.IsTanEntry(Entry) && prefs.GetBoolean(GetString(Resource.String.TanExpiresOnUse_key), Resources.GetBoolean(Resource.Boolean.TanExpiresOnUse_default)) && ((Entry.Expires == false) || Entry.ExpiryTime > DateTime.Now))
if (PwDefs.IsTanEntry(Entry)
&& prefs.GetBoolean(GetString(Resource.String.TanExpiresOnUse_key), Resources.GetBoolean(Resource.Boolean.TanExpiresOnUse_default))
&& ((Entry.Expires == false) || Entry.ExpiryTime > DateTime.Now))
{
PwEntry backupEntry = Entry.CloneDeep();
Entry.ExpiryTime = DateTime.Now;

View File

@@ -35,7 +35,7 @@ namespace keepass2android
protected override bool FitSystemWindows(Rect insets)
{
if (Build.VERSION.SdkInt >= Build.VERSION_CODES.Kitkat)
if (Util.IsKitKatOrLater)
{
// Intentionally do not modify the bottom inset. For some reason,
// if the bottom inset is modified, window resizing stops working.

View File

@@ -236,6 +236,7 @@ namespace keepass2android
{
IOConnectionInfo ioc = new IOConnectionInfo();
Util.SetIoConnectionFromIntent(ioc, data);
Kp2aLog.Log("Set keyfile after returning from RequestCodeSelectKeyfile");
_keyFile = IOConnectionInfo.SerializeToString(ioc);
UpdateKeyfileIocView();
}
@@ -692,7 +693,8 @@ namespace keepass2android
String action = i.Action;
if ((action != null) && (action.Equals(Intents.StartWithOtp)))
{
{
Kp2aLog.Log("Launching with OTP");
if (!GetIocFromOtpIntent(savedInstanceState, i)) return;
_keepPasswordInOnResume = true;
}
@@ -772,7 +774,8 @@ namespace keepass2android
private void GetIocFromLaunchIntent(Intent i)
{
_makeCurrent = i.GetBooleanExtra("MakeCurrent", true);
Kp2aLog.Log("GetIocFromLaunchIntent()");
_makeCurrent = i.GetBooleanExtra("MakeCurrent", true);
Util.SetIoConnectionFromIntent(_ioConnection, i);
var keyFileFromIntent = i.GetStringExtra(KeyKeyfile);
if (keyFileFromIntent != null)
@@ -785,7 +788,9 @@ namespace keepass2android
}
else
{
_keyFile = null;
Kp2aLog.Log("no keyprovider specified");
_keyFile = null;
KeyProviderTypes.Clear();
}
@@ -843,7 +848,8 @@ namespace keepass2android
KeyProviderTypes.Clear();
if (string.IsNullOrEmpty(keyProviderString))
{
_keyFile = null;
Kp2aLog.Log("Reset keyfile");
_keyFile = null;
return;
}
@@ -852,12 +858,15 @@ namespace keepass2android
keyProviderString = keyProviderString.Substring(Kp2aKeyProviderStringPrefix.Length);
foreach (string type in keyProviderString.Split(';'))
{
Kp2aLog.Log("PasswordActivity: key file type " + type);
if (!type.Trim().Any())
continue;
if (type.StartsWith(KeyProviders.KeyFile.ToString()))
{
_keyFile = WebUtility.UrlDecode(type.Substring(KeyProviders.KeyFile.ToString().Length));
KeyProviderTypes.Add(KeyProviders.KeyFile);
Kp2aLog.Log("Added key file of length " + _keyFile.Length);
KeyProviderTypes.Add(KeyProviders.KeyFile);
continue;
}
foreach (KeyProviders providerType in Enum.GetValues(typeof(KeyProviders)))
@@ -872,9 +881,9 @@ namespace keepass2android
}
else
{
//legacy mode
_keyFile = null;
Kp2aLog.Log("PasswordActivity: legacy key file mode");
//legacy mode
_keyFile = null;
if (keyProviderString == KeyProviderIdOtp)
KeyProviderTypes.Add(KeyProviders.Otp);
@@ -1195,13 +1204,16 @@ namespace keepass2android
{
KeyProviderTypes.Clear();
_keyFile = null;
Kp2aLog.Log("PasswordModeSpinner item selected: " + args.Position);
switch (args.Position)
{
case 0:
break;
case 1:
//don't set to "" to prevent losing the filename. (ItemSelected is also called during recreation!)
_keyFile = (FindViewById(Resource.Id.label_keyfilename).Tag ?? "").ToString();
//don't set to "" to prevent losing the filename. (ItemSelected is also called during recreation!)
Kp2aLog.Log("key file length before: " + _keyFile?.Length);
_keyFile = (FindViewById(Resource.Id.label_keyfilename).Tag ?? "").ToString();
Kp2aLog.Log("key file length after: " + _keyFile?.Length);
KeyProviderTypes.Add(KeyProviders.KeyFile);
break;
case 2:
@@ -1242,11 +1254,16 @@ namespace keepass2android
private void RestoreState(Bundle savedInstanceState)
{
if (savedInstanceState != null)
{
{
Kp2aLog.Log("PasswordActivity: Restoring state from savedInstanceState");
_showPassword = savedInstanceState.GetBoolean(ShowpasswordKey, false);
MakePasswordMaskedOrVisible();
SetKeyProviderFromString(savedInstanceState.GetString(KeyFileOrProviderKey));
if (!string.IsNullOrEmpty(savedInstanceState.GetString(KeyFileOrProviderKey)))
Kp2aLog.Log("No key provider found");
else
Kp2aLog.Log("Key provider found");
SetKeyProviderFromString(savedInstanceState.GetString(KeyFileOrProviderKey));
_password = FindViewById<EditText>(Resource.Id.password_edit).Text = savedInstanceState.GetString(PasswordKey);
_pendingOtps = new List<string>(savedInstanceState.GetStringArrayList(PendingOtpsKey));

View File

@@ -40,7 +40,7 @@
<string name="homepage">https://github.com/PhilippC/keepass2android</string>
<string name="further_author_names">Alex Vallat, Ben Rush, Matthieu, Wiktor Ławski, gilbsgilbs, Chih-Hsuan Yen, DDoSolitary, marcoDallas</string>
<string name="designer_names">Niki Hüttner (http://www.close-cut.de), Stefano Pignataro (http://www.spstudio.at)</string>
<string name="supporter_names">Arno Welzel, Sebastián Ramírez</string>
<string name="supporter_names">Arno Welzel, Sebastián Ramírez, A. Finkhäuser</string>
<string name="issues">https://github.com/PhilippC/keepass2android/issues</string>
<string name="oi_filemanager_market">market://details?id=org.openintents.filemanager</string>
<string name="oi_filemanager_web">https://openintents.googlecode.com/files/FileManager-2.0.2.apk</string>

View File

@@ -45,12 +45,13 @@
<BundleAssemblies>false</BundleAssemblies>
<AndroidCreatePackagePerAbi>false</AndroidCreatePackagePerAbi>
<AndroidEnableMultiDex>true</AndroidEnableMultiDex>
<EnableProguard>true</EnableProguard>
<AotAssemblies>false</AotAssemblies>
<EnableLLVM>false</EnableLLVM>
<JavaMaximumHeapSize>2G</JavaMaximumHeapSize>
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
<MandroidI18n />
<AndroidLinkTool>r8</AndroidLinkTool>
<AndroidUseAapt2>false</AndroidUseAapt2>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>full</DebugType>

View File

@@ -136,13 +136,14 @@ namespace keepass2android.services.AutofillBase
if (query.IncompatiblePackageAndDomain == false)
{
Kp2aLog.Log("AF: (query.IncompatiblePackageAndDomain == false)");
//domain and package are compatible. Use Domain if available and package otherwise. Can fill without warning.
foreach (var entryDataset in BuildEntryDatasets(query.DomainOrPackage, query.WebDomain,
query.PackageName,
autofillIds, parser, DisplayWarning.None).Where(ds => ds != null)
)
{
Kp2aLog.Log("AF: Got EntryDataset " + (entryDataset == null));
responseBuilder.AddDataset(entryDataset);
hasEntryDataset = true;
}
@@ -196,7 +197,9 @@ namespace keepass2android.services.AutofillBase
DisplayWarning warning)
{
List<Dataset> result = new List<Dataset>();
Kp2aLog.Log("AF: BuildEntryDatasets");
var suggestedEntries = GetSuggestedEntries(query).ToDictionary(e => e.DatasetName, e => e);
Kp2aLog.Log("AF: BuildEntryDatasets found " + suggestedEntries.Count + " entries");
foreach (var filledAutofillFieldCollection in suggestedEntries.Values)
{
@@ -209,6 +212,8 @@ namespace keepass2android.services.AutofillBase
FilledAutofillFieldCollection partitionData =
AutofillHintsHelper.FilterForPartition(filledAutofillFieldCollection, parser.AutofillFields.FocusedAutofillCanonicalHints);
Kp2aLog.Log("AF: Add dataset");
result.Add(AutofillHelper.NewDataset(this, parser.AutofillFields, partitionData, IntentBuilder));
}
else
@@ -218,7 +223,10 @@ namespace keepass2android.services.AutofillBase
IntentBuilder.GetAuthIntentSenderForWarning(this, query, queryDomain, queryPackage, warning);
var datasetName = filledAutofillFieldCollection.DatasetName;
if (datasetName == null)
return null;
{
Kp2aLog.Log("AF: dataset name is null");
continue;
}
RemoteViews presentation =
AutofillHelper.NewRemoteViews(PackageName, datasetName, AppNames.LauncherIcon);
@@ -230,7 +238,7 @@ namespace keepass2android.services.AutofillBase
{
datasetBuilder.SetValue(autofillId, AutofillValue.ForText("PLACEHOLDER"));
}
Kp2aLog.Log("AF: Add auth dataset");
result.Add(datasetBuilder.Build());
}
}

View File

@@ -267,8 +267,8 @@ namespace keepass2android.services.AutofillBase
DomainName outDomain;
if (DomainName.TryParse(webDomain, domainSuffixParserCache, out outDomain))
{
webDomain = outDomain.RegisterableDomainName;
}
webDomain = outDomain.RawDomainName;
}
if (webDomain != null)
{