Compare commits

..

99 Commits

Author SHA1 Message Date
PhilippC
b90ad6e595 New translations strings.xml (Portuguese) 2020-05-07 19:13:57 +02:00
PhilippC
38ce10e6cc New translations strings.xml (Swedish) 2020-05-07 19:13:53 +02:00
PhilippC
a6cd4c5358 New translations strings.xml (Turkish) 2020-04-19 20:00:14 +02:00
PhilippC
e2668f85ca New translations strings.xml (Indonesian) 2020-04-19 06:30:15 +02:00
PhilippC
2f3aa0aca3 New translations strings.xml (German) 2020-04-15 23:50:18 +02:00
PhilippC
4cf4299b37 New translations strings.xml (Chinese Simplified) 2020-04-14 16:50:13 +02:00
PhilippC
32bd3d0d6b New translations strings.xml (Arabic) 2020-04-14 15:30:14 +02:00
PhilippC
ea2a38a6ee New translations strings.xml (Basque) 2020-04-13 23:00:12 +02:00
PhilippC
6ec537e385 New translations strings.xml (Basque) 2020-04-13 22:50:09 +02:00
PhilippC
556855ab6c New translations strings.xml (Italian) 2020-04-06 07:00:45 +02:00
PhilippC
c98e789128 New translations strings.xml (Bulgarian) 2020-03-30 17:20:38 +02:00
PhilippC
cd2c65d763 New translations strings.xml (Hebrew) 2020-03-29 21:30:29 +02:00
PhilippC
c1116fb836 New translations strings.xml (Hebrew) 2020-03-29 21:20:29 +02:00
PhilippC
7b09a7c9bf New translations strings.xml (Greek) 2020-03-26 14:50:35 +01:00
PhilippC
c8029a835e New translations strings.xml (Greek) 2020-03-26 14:30:35 +01:00
PhilippC
0b18490ce7 New translations strings.xml (Greek) 2020-03-26 14:20:22 +01:00
PhilippC
395d85385f New translations strings.xml (Greek) 2020-03-26 14:10:28 +01:00
PhilippC
3da8e8a6cc New translations strings.xml (Catalan) 2020-03-23 20:50:35 +01:00
PhilippC
220a64393f New translations strings.xml (Catalan) 2020-03-23 20:40:32 +01:00
PhilippC
da64e724ed New translations strings.xml (Catalan) 2020-03-23 20:30:22 +01:00
PhilippC
28d3db3211 New translations strings.xml (Catalan) 2020-03-23 20:20:33 +01:00
PhilippC
eeabd3e7d9 New translations strings.xml (Catalan) 2020-03-23 20:10:29 +01:00
PhilippC
f30f6efaa0 New translations strings.xml (Ukrainian) 2020-03-18 07:50:50 +01:00
PhilippC
ff812441fc New translations strings.xml (Dutch) 2020-03-17 18:00:44 +01:00
PhilippC
91492f2a73 New translations strings.xml (Portuguese, Brazilian) 2020-03-12 11:50:45 +01:00
PhilippC
64252b6a04 New translations strings.xml (Portuguese, Brazilian) 2020-03-12 11:10:47 +01:00
PhilippC
1b5c294d5a New translations strings.xml (Czech) 2020-03-10 15:00:48 +01:00
PhilippC
2d6e4c9f94 New translations strings.xml (Japanese) 2020-03-05 10:40:18 +01:00
PhilippC
3ec6e73b33 New translations strings.xml (Russian) 2020-03-05 02:20:08 +01:00
PhilippC
e8db9a1e17 New translations strings.xml (Russian) 2020-03-05 01:50:06 +01:00
PhilippC
7c8470175a New translations strings.xml (Romanian) 2020-03-04 08:30:07 +01:00
PhilippC
5505dd4266 New translations strings.xml (Romanian) 2020-03-04 08:20:08 +01:00
PhilippC
3bdd05be5b New translations strings.xml (Slovak) 2020-02-29 21:40:09 +01:00
PhilippC
cfeb3db3ab New translations strings.xml (Russian) 2020-02-28 18:10:09 +01:00
PhilippC
c4d892dff7 New translations strings.xml (Spanish) 2020-02-25 20:30:07 +01:00
PhilippC
cc9c95aeec New translations strings.xml (Spanish) 2020-02-25 20:20:11 +01:00
PhilippC
5289ee9dc5 New translations strings.xml (Spanish) 2020-02-25 20:10:07 +01:00
PhilippC
82bcfa0a86 New translations strings.xml (French) 2020-02-22 17:20:07 +01:00
PhilippC
fe529e4f03 New translations strings.xml (Chinese Traditional) 2020-02-18 14:20:10 +01:00
PhilippC
7a8b1b9666 New translations strings.xml (Slovenian) 2020-02-18 13:20:10 +01:00
PhilippC
6199b6f6a2 New translations strings.xml (Polish) 2020-02-18 11:10:10 +01:00
PhilippC
6392202ab6 New translations strings.xml (Polish) 2020-02-18 11:00:12 +01:00
PhilippC
9b2ef0e8f6 New translations strings.xml (Vietnamese) 2020-02-17 12:12:27 +01:00
PhilippC
0c84610224 New translations strings.xml (Greek) 2020-02-17 12:12:25 +01:00
PhilippC
29a4c9a67e New translations strings.xml (Galician) 2020-02-17 12:12:21 +01:00
PhilippC
e8cf6d16ed New translations strings.xml (French) 2020-02-17 12:12:18 +01:00
PhilippC
554d827852 New translations strings.xml (Dutch) 2020-02-17 12:12:14 +01:00
PhilippC
8548440a5f New translations strings.xml (Danish) 2020-02-17 12:12:10 +01:00
PhilippC
e8542e7e39 New translations strings.xml (Croatian) 2020-02-17 12:12:08 +01:00
PhilippC
b1a5e34de4 New translations strings.xml (Chinese Traditional) 2020-02-17 12:12:04 +01:00
PhilippC
56dee832f9 New translations strings.xml (Hungarian) 2020-02-17 12:12:00 +01:00
PhilippC
c1d2e89a49 New translations strings.xml (Chinese Simplified) 2020-02-17 12:11:56 +01:00
PhilippC
57f57715ad New translations strings.xml (Bulgarian) 2020-02-17 12:11:52 +01:00
PhilippC
182cce9e8f New translations strings.xml (Basque) 2020-02-17 12:11:50 +01:00
PhilippC
df23c7c566 New translations strings.xml (Azerbaijani) 2020-02-17 12:11:48 +01:00
PhilippC
4fa605bc4d New translations strings.xml (Arabic) 2020-02-17 12:11:44 +01:00
PhilippC
706bc792f6 New translations strings.xml (Indonesian) 2020-02-17 12:11:40 +01:00
PhilippC
b0405d474d New translations strings.xml (Finnish) 2020-02-17 12:11:38 +01:00
PhilippC
bf3b6d84fd New translations strings.xml (Czech) 2020-02-17 12:11:35 +01:00
PhilippC
9a277231d2 New translations strings.xml (Catalan) 2020-02-17 12:11:32 +01:00
PhilippC
bec528d845 New translations strings.xml (Hebrew) 2020-02-17 12:11:28 +01:00
PhilippC
f1bf0c6220 New translations strings.xml (Italian) 2020-02-17 12:11:23 +01:00
PhilippC
bb9df5b93a New translations strings.xml (Korean) 2020-02-17 12:11:19 +01:00
PhilippC
34d0b703ba New translations strings.xml (Ukrainian) 2020-02-17 12:11:16 +01:00
PhilippC
e0920c3f08 New translations strings.xml (Turkish) 2020-02-17 12:11:14 +01:00
PhilippC
8c56cc37e4 New translations strings.xml (Swedish) 2020-02-17 12:11:11 +01:00
PhilippC
4e5f6ab9de New translations strings.xml (Spanish) 2020-02-17 12:11:09 +01:00
PhilippC
b6a666e1cc New translations strings.xml (Slovenian) 2020-02-17 12:11:04 +01:00
PhilippC
ea123c9b9c New translations strings.xml (Slovak) 2020-02-17 12:11:01 +01:00
PhilippC
97ecf17e92 New translations strings.xml (Serbian (Cyrillic)) 2020-02-17 12:10:57 +01:00
PhilippC
16dc8a9c7e New translations strings.xml (Japanese) 2020-02-17 12:10:52 +01:00
PhilippC
fcae243cfa New translations strings.xml (Russian) 2020-02-17 12:10:48 +01:00
PhilippC
f6e05cac0f New translations strings.xml (Portuguese, Brazilian) 2020-02-17 12:10:44 +01:00
PhilippC
3f97e53f5a New translations strings.xml (Portuguese) 2020-02-17 12:10:40 +01:00
PhilippC
b500be06f2 New translations strings.xml (Polish) 2020-02-17 12:10:38 +01:00
PhilippC
1b9d8ecfe3 New translations strings.xml (Persian) 2020-02-17 12:10:36 +01:00
PhilippC
a7b6c97634 New translations strings.xml (Norwegian Nynorsk) 2020-02-17 12:10:33 +01:00
PhilippC
1c797e0d68 New translations strings.xml (Norwegian Bokmal) 2020-02-17 12:10:29 +01:00
PhilippC
75f9b8338a New translations strings.xml (Romanian) 2020-02-17 12:10:27 +01:00
PhilippC
ee1b38cdb3 New translations strings.xml (German) 2020-02-17 12:10:23 +01:00
PhilippC
2be344daf3 New translations strings.xml (Indonesian) 2020-02-15 12:20:10 +01:00
PhilippC
e44d20e02b New translations strings.xml (Indonesian) 2020-02-14 13:20:11 +01:00
PhilippC
e2cab68003 New translations strings.xml (Indonesian) 2020-02-14 13:10:08 +01:00
PhilippC
7eef326c15 New translations strings.xml (Indonesian) 2020-02-14 10:00:10 +01:00
PhilippC
d1a56b8406 New translations strings.xml (Indonesian) 2020-02-14 09:50:12 +01:00
PhilippC
efa65ea520 New translations strings.xml (Indonesian) 2020-02-14 09:30:11 +01:00
PhilippC
bbac3ba77b New translations strings.xml (Indonesian) 2020-02-14 09:20:11 +01:00
PhilippC
aa8222b870 New translations strings.xml (Indonesian) 2020-02-14 09:10:08 +01:00
PhilippC
ad1c100485 New translations strings.xml (Indonesian) 2020-02-14 08:50:10 +01:00
PhilippC
ed0085fabd New translations strings.xml (Indonesian) 2020-02-14 08:30:13 +01:00
PhilippC
19283d159e New translations strings.xml (Finnish) 2020-02-13 08:50:09 +01:00
PhilippC
c61db37a0b New translations strings.xml (Finnish) 2020-02-13 08:40:09 +01:00
PhilippC
ec1e56984f New translations strings.xml (Finnish) 2020-02-13 08:30:07 +01:00
PhilippC
a048c762b0 New translations strings.xml (Czech) 2020-02-09 15:00:11 +01:00
PhilippC
2c8aa264f9 New translations strings.xml (Hebrew) 2020-02-07 14:40:08 +01:00
PhilippC
70eef6f9c9 New translations strings.xml (Hebrew) 2020-02-07 14:30:11 +01:00
PhilippC
fb828670ad New translations strings.xml (Hebrew) 2020-02-07 13:50:10 +01:00
PhilippC
15020a80e2 New translations strings.xml (Hebrew) 2020-02-07 13:40:08 +01:00
PhilippC
99b0d78502 New translations strings.xml (German) 2020-02-04 02:20:13 +01:00
513 changed files with 15335 additions and 38822 deletions

3
.gitignore vendored
View File

@@ -169,6 +169,3 @@ src/java/Keepass2AndroidPluginSDK2/build/generated/mockable-Google-Inc.-Google-A
/src/java/KP2AKdbLibrary/app/build
/src/java/KP2ASoftkeyboard_AS/app/.cxx
/src/java/KP2ASoftkeyboard_AS/app/src/main/libs
/src/java/KP2AKdbLibrary/app/.cxx
/src/ActionViewFilterTest
/docs/gdrive-verification

View File

@@ -8,27 +8,3 @@ files:
two_letters_code:
zh-CN: zh
zh-TW: zh-rTW
pt-PT: pt
pt-BR: pt-rBR
- source: src/java/android-filechooser-AS/app/src/main/res/values/strings.xml
translation: >-
/src/java/android-filechooser-AS/app/src/main/res/values-%two_letters_code%/%original_file_name%
translate_attributes: '0'
content_segmentation: '0'
languages_mapping:
two_letters_code:
zh-CN: zh
zh-TW: zh-rTW
pt-PT: pt
pt-BR: pt-rBR
- source: src/java/KP2ASoftkeyboard_AS/app/src/main/res/values/strings.xml
translation: >-
/src/java/KP2ASoftkeyboard_AS/app/src/main/res/values-%two_letters_code%/%original_file_name%
translate_attributes: '0'
content_segmentation: '0'
languages_mapping:
two_letters_code:
zh-CN: zh
zh-TW: zh-rTW
pt-PT: pt
pt-BR: pt-rBR

View File

@@ -98,23 +98,6 @@ It's time for action! As soon as possible, select Settings - Database - Export a
## Why is Keepass2Android's apk so big?
Please see [Keepass2Android Apk](Keepass2Android-Apk.md) for more information.
## I get a message "File is trashed" when reading or writing a file on Google Drive
This happens because ocaml-fuse (I guess you are on Linux  and use that) moves files to trash and then creates a new one instead of correctly updating the file on Google Drive (each file has a unique ID which Keepass2Android uses). Fortunately, this was fixed: https://github.com/astrada/google-drive-ocamlfuse/issues/494. After activating this option, please select "Change database" in KP2A, tap ,"Open file" and browse to the file on Google Drive again. After that, the message should no longer pop up.
## I get a message "The name must not be empty: null" when opening from Google Drive
Please follow these steps:
* select "Change database" on the password screen, then "Open database" and browse to your file again
* go to Android app settings and disable all permissions for the KP2A app. Then try again to open the database file.
* reboot the device
(Before running the following steps, make sure you don't have local changes in your database which have not been synchronized with Google Drive (this can happen if you worked offline). If you have, please open the database from the local cache and go to settings - database settings - export database and make a backup copy of the data.)
* clear KP2A's app cache in the Android settings
* uninstall & reinstall
One of these has helped all users so far, but unfortunately it's not totally clear to me why different steps are required (or nothing for most users).
# For developers
If you are interested in adding new features, you have two options:
Either your features can be implemented as a plug-in. Please see [How to create a plug-in?](How-to-create-a-plug-in_.md) for more information. Or you add the features directly in the source code of the projects and create a pull request.

View File

@@ -8,7 +8,7 @@ The password database file can be synchronized across different devices. This wo
# Where to get it?
Regular stable releases of Keepass2Android are available on [Google Play](https://play.google.com/store/apps/details?id=keepass2android.keepass2android).
Beta-releases can be obtained by opting in to the [Beta testing channel](https://play.google.com/apps/testing/keepass2android.keepass2android) or [Beta testing channel for Keepass2Android Offline](https://play.google.com/apps/testing/keepass2android.keepass2android_nonet).
Beta-releases can be obtained by opting in to the [Beta testing channel](https://play.google.com/apps/testing/keepass2android.keepass2android) or [Beta testing channel for Keepass2Android Offline](https://play.google.com/apps/testing/keepass2android.keepass2android_nonet). Please join the [Beta tester group](https://plus.google.com/communities/107293657110547776032) for news and discussions about the latest beta releases.
# How can I contribute?
* Help to translate Keepass2Android into your language or improve translations at [our Crowdin page](http://crowdin.net/project/keepass2android)
@@ -19,6 +19,4 @@ Beta-releases can be obtained by opting in to the [Beta testing channel](https:/
# How do I learn more?
Please see the [documentation](Documentation.md).
The project homepage is https://philipp.crocoll.net/keepass2android/index.html
[![Build Status](https://www.bitrise.io/app/43a23ab54dee9f7e/status.svg?token=2vryTsMQzTX3XRPikhgRwA&branch=master)](https://www.bitrise.io/app/43a23ab54dee9f7e)

View File

@@ -0,0 +1,48 @@
Additions allow you to add arbitrary C# to the generated classes
before they are compiled. This can be helpful for providing convenience
methods or adding pure C# classes.
== Adding Methods to Generated Classes ==
Let's say the library being bound has a Rectangle class with a constructor
that takes an x and y position, and a width and length size. It will look like
this:
public partial class Rectangle
{
public Rectangle (int x, int y, int width, int height)
{
// JNI bindings
}
}
Imagine we want to add a constructor to this class that takes a Point and
Size structure instead of 4 ints. We can add a new file called Rectangle.cs
with a partial class containing our new method:
public partial class Rectangle
{
public Rectangle (Point location, Size size) :
this (location.X, location.Y, size.Width, size.Height)
{
}
}
At compile time, the additions class will be added to the generated class
and the final assembly will a Rectangle class with both constructors.
== Adding C# Classes ==
Another thing that can be done is adding fully C# managed classes to the
generated library. In the above example, let's assume that there isn't a
Point class available in Java or our library. The one we create doesn't need
to interact with Java, so we'll create it like a normal class in C#.
By adding a Point.cs file with this class, it will end up in the binding library:
public class Point
{
public int X { get; set; }
public int Y { get; set; }
}

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}</ProjectGuid>
<ProjectTypeGuids>{10368E6C-D01B-4462-8E8B-01FC667A7035};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TemplateGuid>{77efb91c-a7e9-4b0e-a7c5-31eeec3c6d46}</TemplateGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>BiometricBinding</RootNamespace>
<AssemblyName>BiometricBinding</AssemblyName>
<FileAlignment>512</FileAlignment>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
<AndroidClassParser>class-parse</AndroidClassParser>
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>portable</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>portable</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Jars\AboutJars.txt" />
<None Include="Additions\AboutAdditions.txt" />
<LibraryProjectZip Include="Jars\biometric-1.0.0-rc02.aar" />
</ItemGroup>
<ItemGroup>
<TransformFile Include="Transforms\Metadata.xml" />
<TransformFile Include="Transforms\EnumFields.xml" />
<TransformFile Include="Transforms\EnumMethods.xml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.AndroidX.Fragment">
<Version>1.0.0-preview02</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.Bindings.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,24 @@
This directory is for Android .jars.
There are 2 types of jars that are supported:
== Input Jar ==
This is the jar that bindings should be generated for.
For example, if you were binding the Google Maps library, this would
be Google's "maps.jar".
Set the build action for these jars in the properties page to "InputJar".
== Reference Jars ==
These are jars that are referenced by the input jar. C# bindings will
not be created for these jars. These jars will be used to resolve
types used by the input jar.
NOTE: Do not add "android.jar" as a reference jar. It will be added automatically
based on the Target Framework selected.
Set the build action for these jars in the properties page to "ReferenceJar".

Binary file not shown.

View File

@@ -0,0 +1,30 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Android.App;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("BiometricBinding")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BiometricBinding")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,14 @@
<enum-field-mappings>
<!--
This example converts the constants Fragment_id, Fragment_name,
and Fragment_tag from android.support.v4.app.FragmentActivity.FragmentTag
to an enum called Android.Support.V4.App.FragmentTagType with values
Id, Name, and Tag.
<mapping jni-class="android/support/v4/app/FragmentActivity$FragmentTag" clr-enum-type="Android.Support.V4.App.FragmentTagType">
<field jni-name="Fragment_name" clr-name="Name" value="0" />
<field jni-name="Fragment_id" clr-name="Id" value="1" />
<field jni-name="Fragment_tag" clr-name="Tag" value="2" />
</mapping>
-->
</enum-field-mappings>

View File

@@ -0,0 +1,13 @@
<enum-method-mappings>
<!--
This example changes the Java method:
android.support.v4.app.Fragment.SavedState.writeToParcel (int flags)
to be:
android.support.v4.app.Fragment.SavedState.writeToParcel (Android.OS.ParcelableWriteFlags flags)
when bound in C#.
<mapping jni-class="android/support/v4/app/Fragment.SavedState">
<method jni-name="writeToParcel" parameter="flags" clr-enum-type="Android.OS.ParcelableWriteFlags" />
</mapping>
-->
</enum-method-mappings>

View File

@@ -0,0 +1,9 @@
<metadata>
<!--
This sample removes the class: android.support.v4.content.AsyncTaskLoader.LoadTask:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='AsyncTaskLoader.LoadTask']" />
This sample removes the method: android.support.v4.content.CursorLoader.loadInBackground:
<remove-node path="/api/package[@name='android.support.v4.content']/class[@name='CursorLoader']/method[@name='loadInBackground']" />
-->
</metadata>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Xamarin.Build.Download.0.10.0\build\Xamarin.Build.Download.props" Condition="Exists('..\packages\Xamarin.Build.Download.0.10.0\build\Xamarin.Build.Download.props')" />
<Import Project="..\packages\Xamarin.AndroidX.Migration.1.0.8\build\monoandroid90\Xamarin.AndroidX.Migration.props" Condition="Exists('..\packages\Xamarin.AndroidX.Migration.1.0.8\build\monoandroid90\Xamarin.AndroidX.Migration.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -13,11 +11,9 @@
<AssemblyName>JavaFileStorageBindings</AssemblyName>
<FileAlignment>512</FileAlignment>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v9.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
<AndroidClassParser>class-parse</AndroidClassParser>
<AndroidCodegenTarget>XAJavaInterop1</AndroidCodegenTarget>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -50,22 +46,11 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Java.Interop" />
<Reference Include="Mono.Android" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors" />
<Reference Include="System.Xml" />
<Reference Include="Xamarin.Google.Guava, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Google.Guava.28.2.0.1\lib\monoandroid90\Xamarin.Google.Guava.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Google.Guava.FailureAccess, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Google.Guava.FailureAccess.1.0.1.3\lib\monoandroid90\Xamarin.Google.Guava.FailureAccess.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Google.Guava.ListenableFuture, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Xamarin.Google.Guava.ListenableFuture.1.0.0.3\lib\monoandroid90\Xamarin.Google.Guava.ListenableFuture.dll</HintPath>
<Reference Include="GooglePlayServicesLib">
<HintPath>..\Components\googleplayservices-19.0.0\lib\android\GooglePlayServicesLib.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@@ -77,7 +62,6 @@
</LibraryProjectZip>
<None Include="Jars\AboutJars.txt" />
<None Include="Additions\AboutAdditions.txt" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<TransformFile Include="Transforms\Metadata.xml" />
@@ -99,10 +83,7 @@
</XamarinComponentReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PCloudBindings\PCloudBindings.csproj">
<Project>{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}</Project>
<Name>PCloudBindings</Name>
</ProjectReference>
<ProjectReference Include="..\PCloudBindings\PCloudBindings.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\msa-auth-0.8.6\classes-msa-auth.jar" />
@@ -113,12 +94,30 @@
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\commons-logging-1.1.1.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\google-api-client-1.16.0-rc.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\google-api-client-android-1.16.0-rc.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\google-api-services-drive-v2-rev102-1.16.0-rc.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\google-http-client-1.16.0-rc.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\google-http-client-android-1.16.0-rc.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\google-http-client-jackson-1.16.0-rc.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\google-http-client-jackson2-1.16.0-rc.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\google-oauth-client-1.16.0-rc.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\httpclient-4.0.3.jar" />
</ItemGroup>
@@ -131,6 +130,9 @@
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\json_simple-1.1.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\jsr305-1.3.9.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\google-http-client-gson-1.16.0-rc.jar" />
</ItemGroup>
@@ -138,113 +140,18 @@
<EmbeddedReferenceJar Include="Jars\jackson-core-2.7.4.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\okhttp-digest-2.5.jar" />
<EmbeddedJar Include="Jars\dropbox-core-sdk-3.1.1.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\okio-2.9.0.jar" />
<EmbeddedReferenceJar Include="Jars\gson-2.8.1.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\okhttp-4.10.0-RC1.jar" />
<EmbeddedReferenceJar Include="Jars\okhttp-4.2.2.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedJar Include="Jars\dropbox-core-sdk-4.0.0.jar" />
<EmbeddedReferenceJar Include="Jars\okio-2.2.2.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gson-2.8.6.jar" />
<EmbeddedReferenceJar Include="Jars\okhttp-digest-2.0.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\google-http-client-android-1.32.1.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\jsr305-3.0.2.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\google-http-client-1.32.1.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\google-http-client-jackson2-1.32.1.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\google-api-client-1.30.5.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\google-api-client-android-1.30.5.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\google-oauth-client-1.30.4.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\opencensus-contrib-http-util-0.24.0.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\grpc-context-1.22.1.jar" />
</ItemGroup>
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\gdrive\opencensus-api-0.24.0.jar" />
</ItemGroup>
<Import Project="..\packages\Xamarin.AndroidX.Annotation.Experimental.1.0.0.9\build\monoandroid9.0\Xamarin.AndroidX.Annotation.Experimental.targets" Condition="Exists('..\packages\Xamarin.AndroidX.Annotation.Experimental.1.0.0.9\build\monoandroid9.0\Xamarin.AndroidX.Annotation.Experimental.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}".</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.Annotation.Experimental.1.0.0.9\build\monoandroid9.0\Xamarin.AndroidX.Annotation.Experimental.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.Annotation.Experimental.1.0.0.9\build\monoandroid9.0\Xamarin.AndroidX.Annotation.Experimental.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.MultiDex.2.0.1.5\build\monoandroid90\Xamarin.AndroidX.MultiDex.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.MultiDex.2.0.1.5\build\monoandroid90\Xamarin.AndroidX.MultiDex.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.Migration.1.0.8\build\monoandroid90\Xamarin.AndroidX.Migration.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.Migration.1.0.8\build\monoandroid90\Xamarin.AndroidX.Migration.props'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.Migration.1.0.8\build\monoandroid90\Xamarin.AndroidX.Migration.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.Migration.1.0.8\build\monoandroid90\Xamarin.AndroidX.Migration.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.Annotation.1.2.0\build\monoandroid9.0\Xamarin.AndroidX.Annotation.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.Annotation.1.2.0\build\monoandroid9.0\Xamarin.AndroidX.Annotation.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.Arch.Core.Common.2.1.0.8\build\monoandroid9.0\Xamarin.AndroidX.Arch.Core.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.Arch.Core.Common.2.1.0.8\build\monoandroid9.0\Xamarin.AndroidX.Arch.Core.Common.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.Collection.1.1.0.7\build\monoandroid9.0\Xamarin.AndroidX.Collection.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.Collection.1.1.0.7\build\monoandroid9.0\Xamarin.AndroidX.Collection.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.Lifecycle.Common.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.Lifecycle.Common.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.Common.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.Lifecycle.LiveData.Core.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.LiveData.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.Lifecycle.LiveData.Core.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.LiveData.Core.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.Lifecycle.Runtime.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.Runtime.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.Lifecycle.Runtime.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.Runtime.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.Lifecycle.ViewModel.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.ViewModel.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.Lifecycle.ViewModel.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.ViewModel.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.SavedState.1.1.0.1\build\monoandroid9.0\Xamarin.AndroidX.SavedState.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.SavedState.1.1.0.1\build\monoandroid9.0\Xamarin.AndroidX.SavedState.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.Lifecycle.ViewModelSavedState.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.ViewModelSavedState.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.Lifecycle.ViewModelSavedState.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.ViewModelSavedState.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.VersionedParcelable.1.1.1.7\build\monoandroid9.0\Xamarin.AndroidX.VersionedParcelable.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.VersionedParcelable.1.1.1.7\build\monoandroid9.0\Xamarin.AndroidX.VersionedParcelable.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.Core.1.3.2.3\build\monoandroid9.0\Xamarin.AndroidX.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.Core.1.3.2.3\build\monoandroid9.0\Xamarin.AndroidX.Core.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.Activity.1.2.2\build\monoandroid9.0\Xamarin.AndroidX.Activity.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.Activity.1.2.2\build\monoandroid9.0\Xamarin.AndroidX.Activity.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.CustomView.1.1.0.6\build\monoandroid9.0\Xamarin.AndroidX.CustomView.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.CustomView.1.1.0.6\build\monoandroid9.0\Xamarin.AndroidX.CustomView.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.Loader.1.1.0.7\build\monoandroid9.0\Xamarin.AndroidX.Loader.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.Loader.1.1.0.7\build\monoandroid9.0\Xamarin.AndroidX.Loader.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.ViewPager.1.0.0.7\build\monoandroid9.0\Xamarin.AndroidX.ViewPager.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.ViewPager.1.0.0.7\build\monoandroid9.0\Xamarin.AndroidX.ViewPager.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.AndroidX.Fragment.1.3.2\build\monoandroid9.0\Xamarin.AndroidX.Fragment.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.AndroidX.Fragment.1.3.2\build\monoandroid9.0\Xamarin.AndroidX.Fragment.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Build.Download.0.10.0\build\Xamarin.Build.Download.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Build.Download.0.10.0\build\Xamarin.Build.Download.props'))" />
<Error Condition="!Exists('..\packages\Xamarin.Build.Download.0.10.0\build\Xamarin.Build.Download.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Build.Download.0.10.0\build\Xamarin.Build.Download.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.GooglePlayServices.Basement.117.6.0.4\build\monoandroid90\Xamarin.GooglePlayServices.Basement.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.GooglePlayServices.Basement.117.6.0.4\build\monoandroid90\Xamarin.GooglePlayServices.Basement.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.GooglePlayServices.Tasks.117.2.1.3\build\monoandroid90\Xamarin.GooglePlayServices.Tasks.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.GooglePlayServices.Tasks.117.2.1.3\build\monoandroid90\Xamarin.GooglePlayServices.Tasks.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.GooglePlayServices.Base.117.6.0.3\build\monoandroid90\Xamarin.GooglePlayServices.Base.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.GooglePlayServices.Base.117.6.0.3\build\monoandroid90\Xamarin.GooglePlayServices.Base.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.GooglePlayServices.Auth.Api.Phone.117.5.1.3\build\monoandroid90\Xamarin.GooglePlayServices.Auth.Api.Phone.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.GooglePlayServices.Auth.Api.Phone.117.5.1.3\build\monoandroid90\Xamarin.GooglePlayServices.Auth.Api.Phone.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.GooglePlayServices.Auth.Base.117.1.4.3\build\monoandroid90\Xamarin.GooglePlayServices.Auth.Base.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.GooglePlayServices.Auth.Base.117.1.4.3\build\monoandroid90\Xamarin.GooglePlayServices.Auth.Base.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.GooglePlayServices.Auth.119.2.0.3\build\monoandroid90\Xamarin.GooglePlayServices.Auth.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.GooglePlayServices.Auth.119.2.0.3\build\monoandroid90\Xamarin.GooglePlayServices.Auth.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Google.Guava.FailureAccess.1.0.1.3\build\monoandroid90\Xamarin.Google.Guava.FailureAccess.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Google.Guava.FailureAccess.1.0.1.3\build\monoandroid90\Xamarin.Google.Guava.FailureAccess.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Google.Guava.ListenableFuture.1.0.0.3\build\monoandroid90\Xamarin.Google.Guava.ListenableFuture.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Google.Guava.ListenableFuture.1.0.0.3\build\monoandroid90\Xamarin.Google.Guava.ListenableFuture.targets'))" />
<Error Condition="!Exists('..\packages\Xamarin.Google.Guava.28.2.0.1\build\monoandroid90\Xamarin.Google.Guava.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Xamarin.Google.Guava.28.2.0.1\build\monoandroid90\Xamarin.Google.Guava.targets'))" />
</Target>
<Import Project="..\packages\Xamarin.AndroidX.MultiDex.2.0.1.5\build\monoandroid90\Xamarin.AndroidX.MultiDex.targets" Condition="Exists('..\packages\Xamarin.AndroidX.MultiDex.2.0.1.5\build\monoandroid90\Xamarin.AndroidX.MultiDex.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.Migration.1.0.8\build\monoandroid90\Xamarin.AndroidX.Migration.targets" Condition="Exists('..\packages\Xamarin.AndroidX.Migration.1.0.8\build\monoandroid90\Xamarin.AndroidX.Migration.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.Annotation.1.2.0\build\monoandroid9.0\Xamarin.AndroidX.Annotation.targets" Condition="Exists('..\packages\Xamarin.AndroidX.Annotation.1.2.0\build\monoandroid9.0\Xamarin.AndroidX.Annotation.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.Arch.Core.Common.2.1.0.8\build\monoandroid9.0\Xamarin.AndroidX.Arch.Core.Common.targets" Condition="Exists('..\packages\Xamarin.AndroidX.Arch.Core.Common.2.1.0.8\build\monoandroid9.0\Xamarin.AndroidX.Arch.Core.Common.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.Collection.1.1.0.7\build\monoandroid9.0\Xamarin.AndroidX.Collection.targets" Condition="Exists('..\packages\Xamarin.AndroidX.Collection.1.1.0.7\build\monoandroid9.0\Xamarin.AndroidX.Collection.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.Lifecycle.Common.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.Common.targets" Condition="Exists('..\packages\Xamarin.AndroidX.Lifecycle.Common.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.Common.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.Lifecycle.LiveData.Core.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.LiveData.Core.targets" Condition="Exists('..\packages\Xamarin.AndroidX.Lifecycle.LiveData.Core.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.LiveData.Core.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.Lifecycle.Runtime.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.Runtime.targets" Condition="Exists('..\packages\Xamarin.AndroidX.Lifecycle.Runtime.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.Runtime.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.Lifecycle.ViewModel.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.ViewModel.targets" Condition="Exists('..\packages\Xamarin.AndroidX.Lifecycle.ViewModel.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.ViewModel.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.SavedState.1.1.0.1\build\monoandroid9.0\Xamarin.AndroidX.SavedState.targets" Condition="Exists('..\packages\Xamarin.AndroidX.SavedState.1.1.0.1\build\monoandroid9.0\Xamarin.AndroidX.SavedState.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.Lifecycle.ViewModelSavedState.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.ViewModelSavedState.targets" Condition="Exists('..\packages\Xamarin.AndroidX.Lifecycle.ViewModelSavedState.2.3.1\build\monoandroid9.0\Xamarin.AndroidX.Lifecycle.ViewModelSavedState.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.VersionedParcelable.1.1.1.7\build\monoandroid9.0\Xamarin.AndroidX.VersionedParcelable.targets" Condition="Exists('..\packages\Xamarin.AndroidX.VersionedParcelable.1.1.1.7\build\monoandroid9.0\Xamarin.AndroidX.VersionedParcelable.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.Core.1.3.2.3\build\monoandroid9.0\Xamarin.AndroidX.Core.targets" Condition="Exists('..\packages\Xamarin.AndroidX.Core.1.3.2.3\build\monoandroid9.0\Xamarin.AndroidX.Core.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.Activity.1.2.2\build\monoandroid9.0\Xamarin.AndroidX.Activity.targets" Condition="Exists('..\packages\Xamarin.AndroidX.Activity.1.2.2\build\monoandroid9.0\Xamarin.AndroidX.Activity.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.CustomView.1.1.0.6\build\monoandroid9.0\Xamarin.AndroidX.CustomView.targets" Condition="Exists('..\packages\Xamarin.AndroidX.CustomView.1.1.0.6\build\monoandroid9.0\Xamarin.AndroidX.CustomView.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.Loader.1.1.0.7\build\monoandroid9.0\Xamarin.AndroidX.Loader.targets" Condition="Exists('..\packages\Xamarin.AndroidX.Loader.1.1.0.7\build\monoandroid9.0\Xamarin.AndroidX.Loader.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.ViewPager.1.0.0.7\build\monoandroid9.0\Xamarin.AndroidX.ViewPager.targets" Condition="Exists('..\packages\Xamarin.AndroidX.ViewPager.1.0.0.7\build\monoandroid9.0\Xamarin.AndroidX.ViewPager.targets')" />
<Import Project="..\packages\Xamarin.AndroidX.Fragment.1.3.2\build\monoandroid9.0\Xamarin.AndroidX.Fragment.targets" Condition="Exists('..\packages\Xamarin.AndroidX.Fragment.1.3.2\build\monoandroid9.0\Xamarin.AndroidX.Fragment.targets')" />
<Import Project="..\packages\Xamarin.Build.Download.0.10.0\build\Xamarin.Build.Download.targets" Condition="Exists('..\packages\Xamarin.Build.Download.0.10.0\build\Xamarin.Build.Download.targets')" />
<Import Project="..\packages\Xamarin.GooglePlayServices.Basement.117.6.0.4\build\monoandroid90\Xamarin.GooglePlayServices.Basement.targets" Condition="Exists('..\packages\Xamarin.GooglePlayServices.Basement.117.6.0.4\build\monoandroid90\Xamarin.GooglePlayServices.Basement.targets')" />
<Import Project="..\packages\Xamarin.GooglePlayServices.Tasks.117.2.1.3\build\monoandroid90\Xamarin.GooglePlayServices.Tasks.targets" Condition="Exists('..\packages\Xamarin.GooglePlayServices.Tasks.117.2.1.3\build\monoandroid90\Xamarin.GooglePlayServices.Tasks.targets')" />
<Import Project="..\packages\Xamarin.GooglePlayServices.Base.117.6.0.3\build\monoandroid90\Xamarin.GooglePlayServices.Base.targets" Condition="Exists('..\packages\Xamarin.GooglePlayServices.Base.117.6.0.3\build\monoandroid90\Xamarin.GooglePlayServices.Base.targets')" />
<Import Project="..\packages\Xamarin.GooglePlayServices.Auth.Api.Phone.117.5.1.3\build\monoandroid90\Xamarin.GooglePlayServices.Auth.Api.Phone.targets" Condition="Exists('..\packages\Xamarin.GooglePlayServices.Auth.Api.Phone.117.5.1.3\build\monoandroid90\Xamarin.GooglePlayServices.Auth.Api.Phone.targets')" />
<Import Project="..\packages\Xamarin.GooglePlayServices.Auth.Base.117.1.4.3\build\monoandroid90\Xamarin.GooglePlayServices.Auth.Base.targets" Condition="Exists('..\packages\Xamarin.GooglePlayServices.Auth.Base.117.1.4.3\build\monoandroid90\Xamarin.GooglePlayServices.Auth.Base.targets')" />
<Import Project="..\packages\Xamarin.GooglePlayServices.Auth.119.2.0.3\build\monoandroid90\Xamarin.GooglePlayServices.Auth.targets" Condition="Exists('..\packages\Xamarin.GooglePlayServices.Auth.119.2.0.3\build\monoandroid90\Xamarin.GooglePlayServices.Auth.targets')" />
<Import Project="..\packages\Xamarin.Google.Guava.FailureAccess.1.0.1.3\build\monoandroid90\Xamarin.Google.Guava.FailureAccess.targets" Condition="Exists('..\packages\Xamarin.Google.Guava.FailureAccess.1.0.1.3\build\monoandroid90\Xamarin.Google.Guava.FailureAccess.targets')" />
<Import Project="..\packages\Xamarin.Google.Guava.ListenableFuture.1.0.0.3\build\monoandroid90\Xamarin.Google.Guava.ListenableFuture.targets" Condition="Exists('..\packages\Xamarin.Google.Guava.ListenableFuture.1.0.0.3\build\monoandroid90\Xamarin.Google.Guava.ListenableFuture.targets')" />
<Import Project="..\packages\Xamarin.Google.Guava.28.2.0.1\build\monoandroid90\Xamarin.Google.Guava.targets" Condition="Exists('..\packages\Xamarin.Google.Guava.28.2.0.1\build\monoandroid90\Xamarin.Google.Guava.targets')" />
</Project>

View File

@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Xamarin.AndroidX.Activity" version="1.2.2" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.Annotation" version="1.2.0" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.Annotation.Experimental" version="1.0.0.9" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.Arch.Core.Common" version="2.1.0.8" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.Collection" version="1.1.0.7" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.Core" version="1.3.2.3" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.CustomView" version="1.1.0.6" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.Fragment" version="1.3.2" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.Lifecycle.Common" version="2.3.1" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.Lifecycle.LiveData.Core" version="2.3.1" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.Lifecycle.Runtime" version="2.3.1" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.Lifecycle.ViewModel" version="2.3.1" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.Lifecycle.ViewModelSavedState" version="2.3.1" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.Loader" version="1.1.0.7" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.Migration" version="1.0.8" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.MultiDex" version="2.0.1.5" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.SavedState" version="1.1.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.VersionedParcelable" version="1.1.1.7" targetFramework="monoandroid90" />
<package id="Xamarin.AndroidX.ViewPager" version="1.0.0.7" targetFramework="monoandroid90" />
<package id="Xamarin.Build.Download" version="0.10.0" targetFramework="monoandroid90" />
<package id="Xamarin.Google.Guava" version="28.2.0.1" targetFramework="monoandroid90" />
<package id="Xamarin.Google.Guava.FailureAccess" version="1.0.1.3" targetFramework="monoandroid90" />
<package id="Xamarin.Google.Guava.ListenableFuture" version="1.0.0.3" targetFramework="monoandroid90" />
<package id="Xamarin.GooglePlayServices.Auth" version="119.2.0.3" targetFramework="monoandroid90" />
<package id="Xamarin.GooglePlayServices.Auth.Api.Phone" version="117.5.1.3" targetFramework="monoandroid90" />
<package id="Xamarin.GooglePlayServices.Auth.Base" version="117.1.4.3" targetFramework="monoandroid90" />
<package id="Xamarin.GooglePlayServices.Base" version="117.6.0.3" targetFramework="monoandroid90" />
<package id="Xamarin.GooglePlayServices.Basement" version="117.6.0.4" targetFramework="monoandroid90" />
<package id="Xamarin.GooglePlayServices.Tasks" version="117.2.1.3" targetFramework="monoandroid90" />
</packages>

View File

@@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.29418.71
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassLib2Android", "KeePassLib2Android\KeePassLib2Android.csproj", "{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "keepass2android", "keepass2android\keepass2android.csproj", "{A6CF8A86-37C1-4197-80FE-519DE2C842F5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kp2aKeyboardBinding", "Kp2aKeyboardBinding\Kp2aKeyboardBinding.csproj", "{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kp2aBusinessLogic", "Kp2aBusinessLogic\Kp2aBusinessLogic.csproj", "{53A9CB7F-6553-4BC0-B56B-9410BB2E59AA}"
@@ -21,11 +23,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginSdkBinding", "PluginS
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZlibAndroid", "ZlibAndroid\ZlibAndroid.csproj", "{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamsungPass", "SamsungPass\Xamarin.SamsungPass\SamsungPass\SamsungPass.csproj", "{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PCloudBindings", "PCloudBindings\PCloudBindings.csproj", "{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "keepass2android-app", "keepass2android\keepass2android-app.csproj", "{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamsungPass", "SamsungPass\Xamarin.SamsungPass\SamsungPass\SamsungPass.csproj", "{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BiometricBinding", "BiometricBinding\BiometricBinding.csproj", "{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -65,6 +67,34 @@ Global
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU
{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Mixed Platforms.Deploy.0 = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Win32.ActiveCfg = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|Win32.Build.0 = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|x64.ActiveCfg = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Debug|x64.Build.0 = Debug|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Any CPU.Build.0 = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Any CPU.Deploy.0 = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Mixed Platforms.Deploy.0 = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Win32.ActiveCfg = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|Win32.Build.0 = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|x64.ActiveCfg = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.Release|x64.Build.0 = Release|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.ReleaseNoNet|Any CPU.Deploy.0 = ReleaseNoNet|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.ReleaseNoNet|Mixed Platforms.Deploy.0 = ReleaseNoNet|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU
{A6CF8A86-37C1-4197-80FE-519DE2C842F5}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8779D4D-7C49-4C2F-82BD-2CDC448391DA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@@ -225,6 +255,24 @@ Global
{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}.ReleaseNoNet|Win32.Build.0 = Release|Any CPU
{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
{6C29A7E7-E016-4FC1-B1A0-DEE26AC711BB}.ReleaseNoNet|x64.Build.0 = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Win32.ActiveCfg = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|x64.ActiveCfg = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Release|Any CPU.Build.0 = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Release|Win32.ActiveCfg = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Release|x64.ActiveCfg = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@@ -249,66 +297,30 @@ Global
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Win32.Build.0 = ReleaseNoNet|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|x64.Build.0 = ReleaseNoNet|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Debug|Mixed Platforms.Deploy.0 = Debug|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Debug|Win32.ActiveCfg = Debug|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Debug|Win32.Build.0 = Debug|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Debug|Win32.Deploy.0 = Debug|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Debug|x64.ActiveCfg = Debug|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Debug|x64.Build.0 = Debug|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Debug|x64.Deploy.0 = Debug|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Release|Any CPU.Build.0 = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Release|Any CPU.Deploy.0 = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Release|Mixed Platforms.Deploy.0 = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Release|Win32.ActiveCfg = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Release|Win32.Build.0 = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Release|Win32.Deploy.0 = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Release|x64.ActiveCfg = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Release|x64.Build.0 = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.Release|x64.Deploy.0 = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.ReleaseNoNet|Any CPU.Deploy.0 = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.ReleaseNoNet|Mixed Platforms.Deploy.0 = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.ReleaseNoNet|Win32.Build.0 = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.ReleaseNoNet|Win32.Deploy.0 = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.ReleaseNoNet|x64.Build.0 = Release|Any CPU
{D4C32E0A-0193-4496-9DB4-02CC126FD9F3}.ReleaseNoNet|x64.Deploy.0 = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Win32.ActiveCfg = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|Win32.Build.0 = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|x64.ActiveCfg = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Debug|x64.Build.0 = Debug|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Release|Any CPU.Build.0 = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Release|Win32.ActiveCfg = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Release|Win32.Build.0 = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Release|x64.ActiveCfg = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.Release|x64.Build.0 = Release|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Any CPU.ActiveCfg = ReleaseNoNet|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Any CPU.Build.0 = ReleaseNoNet|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Mixed Platforms.ActiveCfg = ReleaseNoNet|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Mixed Platforms.Build.0 = ReleaseNoNet|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Win32.ActiveCfg = ReleaseNoNet|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|Win32.Build.0 = ReleaseNoNet|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU
{3A4B8E88-FA9B-4663-BCDA-21C12E3AF98A}.ReleaseNoNet|x64.Build.0 = ReleaseNoNet|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Win32.ActiveCfg = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Win32.Build.0 = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|x64.ActiveCfg = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|x64.Build.0 = Debug|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Any CPU.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Win32.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Win32.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|x64.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|x64.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Win32.Build.0 = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,11 +33,8 @@ namespace KeePassLib.Collections
private Dictionary<int, ProtectedBinary> m_d =
new Dictionary<int, ProtectedBinary>();
private readonly bool m_bDedupAdd;
public ProtectedBinarySet(bool bDedupAdd)
public ProtectedBinarySet()
{
m_bDedupAdd = bDedupAdd;
}
IEnumerator IEnumerable.GetEnumerator()
@@ -50,6 +47,11 @@ namespace KeePassLib.Collections
return m_d.GetEnumerator();
}
public void Clear()
{
m_d.Clear();
}
private int GetFreeID()
{
int i = m_d.Count;
@@ -103,9 +105,11 @@ namespace KeePassLib.Collections
{
if(pb == null) { Debug.Assert(false); return; }
if (m_bDedupAdd && (Find(pb) >= 0)) return; // Exists already
int i = Find(pb);
if(i >= 0) return; // Exists already
m_d[GetFreeID()] = pb;
i = GetFreeID();
m_d[i] = pb;
}
public void AddFrom(ProtectedBinaryDictionary d)

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,8 +20,8 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Diagnostics;
using KeePassLib.Interfaces;
@@ -34,47 +34,35 @@ namespace KeePassLib.Collections
public sealed class StringDictionaryEx : IDeepCloneable<StringDictionaryEx>,
IEnumerable<KeyValuePair<string, string>>, IEquatable<StringDictionaryEx>
{
private SortedDictionary<string, string> m_d =
private SortedDictionary<string, string> m_dict =
new SortedDictionary<string, string>();
// Non-null if and only if last mod. times should be remembered
private Dictionary<string, DateTime> m_dLastMod = null;
public int Count
{
get { return m_d.Count; }
get { return m_dict.Count; }
}
public StringDictionaryEx()
{
}
internal StringDictionaryEx(bool bRememberLastMod)
{
if (bRememberLastMod) m_dLastMod = new Dictionary<string, DateTime>();
}
IEnumerator IEnumerable.GetEnumerator()
{
return m_d.GetEnumerator();
return m_dict.GetEnumerator();
}
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
return m_d.GetEnumerator();
return m_dict.GetEnumerator();
}
public StringDictionaryEx CloneDeep()
{
StringDictionaryEx sdNew = new StringDictionaryEx();
foreach (KeyValuePair<string, string> kvp in m_d)
sdNew.m_d[kvp.Key] = kvp.Value;
foreach(KeyValuePair<string, string> kvp in m_dict)
sdNew.m_dict[kvp.Key] = kvp.Value; // Strings are immutable
if (m_dLastMod != null)
sdNew.m_dLastMod = new Dictionary<string, DateTime>(m_dLastMod);
Debug.Assert(Equals(sdNew));
return sdNew;
}
@@ -82,28 +70,14 @@ namespace KeePassLib.Collections
{
if(sdOther == null) { Debug.Assert(false); return false; }
if (m_d.Count != sdOther.m_d.Count) return false;
if(m_dict.Count != sdOther.m_dict.Count) return false;
foreach (KeyValuePair<string, string> kvp in sdOther.m_d)
foreach(KeyValuePair<string, string> kvp in sdOther.m_dict)
{
string str = Get(kvp.Key);
if((str == null) || (str != kvp.Value)) return false;
}
int cLastModT = ((m_dLastMod != null) ? m_dLastMod.Count : -1);
int cLastModO = ((sdOther.m_dLastMod != null) ? sdOther.m_dLastMod.Count : -1);
if (cLastModT != cLastModO) return false;
if (m_dLastMod != null)
{
foreach (KeyValuePair<string, DateTime> kvp in sdOther.m_dLastMod)
{
DateTime? odt = GetLastModificationTime(kvp.Key);
if (!odt.HasValue) return false;
if (odt.Value != kvp.Value) return false;
}
}
return true;
}
@@ -111,19 +85,8 @@ namespace KeePassLib.Collections
{
if(strName == null) { Debug.Assert(false); throw new ArgumentNullException("strName"); }
string str;
m_d.TryGetValue(strName, out str);
return str;
}
internal DateTime? GetLastModificationTime(string strName)
{
if (strName == null) { Debug.Assert(false); throw new ArgumentNullException("strName"); }
if (m_dLastMod == null) return null;
DateTime dt;
if (m_dLastMod.TryGetValue(strName, out dt)) return dt;
string s;
if(m_dict.TryGetValue(strName, out s)) return s;
return null;
}
@@ -131,40 +94,37 @@ namespace KeePassLib.Collections
{
if(strName == null) { Debug.Assert(false); throw new ArgumentNullException("strName"); }
return m_d.ContainsKey(strName);
return m_dict.ContainsKey(strName);
}
public void Set(string strName, string strValue)
/// <summary>
/// Set a string.
/// </summary>
/// <param name="strField">Identifier of the string field to modify.</param>
/// <param name="strNewValue">New value. This parameter must not be <c>null</c>.</param>
/// <exception cref="System.ArgumentNullException">Thrown if one of the input
/// parameters is <c>null</c>.</exception>
public void Set(string strField, string strNewValue)
{
if (strName == null) { Debug.Assert(false); throw new ArgumentNullException("strName"); }
if (strValue == null) { Debug.Assert(false); throw new ArgumentNullException("strValue"); }
if(strField == null) { Debug.Assert(false); throw new ArgumentNullException("strField"); }
if(strNewValue == null) { Debug.Assert(false); throw new ArgumentNullException("strNewValue"); }
m_d[strName] = strValue;
if (m_dLastMod != null) m_dLastMod[strName] = DateTime.UtcNow;
m_dict[strField] = strNewValue;
}
internal void Set(string strName, string strValue, DateTime? odtLastMod)
/// <summary>
/// Delete a string.
/// </summary>
/// <param name="strField">Name of the string field to delete.</param>
/// <returns>Returns <c>true</c> if the field has been successfully
/// removed, otherwise the return value is <c>false</c>.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public bool Remove(string strField)
{
if (strName == null) { Debug.Assert(false); throw new ArgumentNullException("strName"); }
if (strValue == null) { Debug.Assert(false); throw new ArgumentNullException("strValue"); }
if(strField == null) { Debug.Assert(false); throw new ArgumentNullException("strField"); }
m_d[strName] = strValue;
if (m_dLastMod != null)
{
if (odtLastMod.HasValue) m_dLastMod[strName] = odtLastMod.Value;
else m_dLastMod.Remove(strName);
}
}
public bool Remove(string strName)
{
if (strName == null) { Debug.Assert(false); throw new ArgumentNullException("strName"); }
if (m_dLastMod != null) m_dLastMod.Remove(strName);
return m_d.Remove(strName);
return m_dict.Remove(strField);
}
}
}

View File

@@ -29,28 +29,14 @@ namespace KeePassLib.Cryptography.Cipher
{
public sealed class ChaCha20Engine : ICipherEngine2
{
private static PwUuid m_uuid = null;
internal static PwUuid ChaCha20Uuid
{
get
{
PwUuid pu = m_uuid;
if (pu == null)
{
pu = new PwUuid(new byte[] {
private PwUuid m_uuid = new PwUuid(new byte[] {
0xD6, 0x03, 0x8A, 0x2B, 0x8B, 0x6F, 0x4C, 0xB5,
0xA5, 0x24, 0x33, 0x9A, 0x31, 0xDB, 0xB5, 0x9A });
m_uuid = pu;
}
return pu;
}
}
0xA5, 0x24, 0x33, 0x9A, 0x31, 0xDB, 0xB5, 0x9A
});
public PwUuid CipherUuid
{
get { return ChaCha20Uuid; }
get { return m_uuid; }
}
public string DisplayName

View File

@@ -367,27 +367,5 @@ namespace KeePassLib.Cryptography
Debug.Assert(iPos == pbRes.Length);
return pbRes;
}
private static int g_iWeakSeed = 0;
public static Random NewWeakRandom()
{
long s64 = DateTime.UtcNow.ToBinary();
int s32 = (int)((s64 >> 32) ^ s64);
lock (g_oSyncRoot)
{
unchecked
{
g_iWeakSeed += 0x78A8C4B7; // Prime number
s32 ^= g_iWeakSeed;
}
}
// Prevent overflow in the Random constructor of .NET 2.0
if (s32 == int.MinValue) s32 = int.MaxValue;
return new Random(s32);
}
}
}

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2020 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,57 +20,18 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Native;
using KeePassLib.Utility;
namespace KeePassLib.Cryptography
{
public static class CryptoUtil
{
private static bool? g_obProtData = null;
public static bool IsProtectedDataSupported
{
get
{
if (g_obProtData.HasValue) return g_obProtData.Value;
bool b = false;
try
{
Random r = CryptoRandom.NewWeakRandom();
byte[] pbData = new byte[137];
r.NextBytes(pbData);
byte[] pbEnt = new byte[41];
r.NextBytes(pbEnt);
byte[] pbEnc = ProtectedData.Protect(pbData, pbEnt,
DataProtectionScope.CurrentUser);
if ((pbEnc != null) && !MemUtil.ArraysEqual(pbEnc, pbData))
{
byte[] pbDec = ProtectedData.Unprotect(pbEnc, pbEnt,
DataProtectionScope.CurrentUser);
if ((pbDec != null) && MemUtil.ArraysEqual(pbDec, pbData))
b = true;
}
}
catch (Exception) { Debug.Assert(false); }
Debug.Assert(b); // Should be supported on all systems
g_obProtData = b;
return b;
}
}
public static byte[] HashSha256(byte[] pbData)
{
if(pbData == null) throw new ArgumentNullException("pbData");
@@ -105,22 +66,6 @@ namespace KeePassLib.Cryptography
return pbHash;
}
internal static byte[] HashSha256(string strFilePath)
{
byte[] pbHash = null;
using (FileStream fs = new FileStream(strFilePath, FileMode.Open,
FileAccess.Read, FileShare.Read))
{
using (SHA256Managed h = new SHA256Managed())
{
pbHash = h.ComputeHash(fs);
}
}
return pbHash;
}
/// <summary>
/// Create a cryptographic key of length <paramref name="cbOut" />
/// (in bytes) from <paramref name="pbIn" />.
@@ -180,75 +125,5 @@ namespace KeePassLib.Cryptography
MemUtil.ZeroByteArray(pbHash);
return pbRet;
}
#if !KeePassUAP
private static bool? g_obAesCsp = null;
internal static SymmetricAlgorithm CreateAes()
{
if (g_obAesCsp.HasValue)
return (g_obAesCsp.Value ? CreateAesCsp() : new RijndaelManaged());
SymmetricAlgorithm a = CreateAesCsp();
g_obAesCsp = (a != null);
return (a ?? new RijndaelManaged());
}
private static SymmetricAlgorithm CreateAesCsp()
{
try
{
// On Windows, the CSP implementation is only minimally
// faster (and for key derivations it's not used anyway,
// as KeePass uses a native implementation based on
// CNG/BCrypt, which is much faster)
if (!NativeLib.IsUnix()) return null;
string strFqn = Assembly.CreateQualifiedName(
"System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"System.Security.Cryptography.AesCryptoServiceProvider");
Type t = Type.GetType(strFqn);
if (t == null) return null;
return (Activator.CreateInstance(t) as SymmetricAlgorithm);
}
catch (Exception) { Debug.Assert(false); }
return null;
}
#endif
public static byte[] ProtectData(byte[] pb, byte[] pbOptEntropy,
DataProtectionScope s)
{
return ProtectDataPriv(pb, true, pbOptEntropy, s);
}
public static byte[] UnprotectData(byte[] pb, byte[] pbOptEntropy,
DataProtectionScope s)
{
return ProtectDataPriv(pb, false, pbOptEntropy, s);
}
private static byte[] ProtectDataPriv(byte[] pb, bool bProtect,
byte[] pbOptEntropy, DataProtectionScope s)
{
if (pb == null) throw new ArgumentNullException("pb");
if ((pbOptEntropy != null) && (pbOptEntropy.Length == 0))
pbOptEntropy = null;
if (CryptoUtil.IsProtectedDataSupported)
{
if (bProtect)
return ProtectedData.Protect(pb, pbOptEntropy, s);
return ProtectedData.Unprotect(pb, pbOptEntropy, s);
}
Debug.Assert(false);
byte[] pbCopy = new byte[pb.Length];
Array.Copy(pb, pbCopy, pb.Length);
return pbCopy;
}
}
}

View File

@@ -46,8 +46,6 @@ namespace KeePassLib.Cryptography.KeyDerivation
private const ulong NbBlockSizeInQW = NbBlockSize / 8UL;
private const ulong NbSyncPoints = 4;
private const ulong NbAddressesInBlock = 128;
private const int NbPreHashDigestLength = 64;
private const int NbPreHashSeedLength = NbPreHashDigestLength + 8;
@@ -58,7 +56,6 @@ namespace KeePassLib.Cryptography.KeyDerivation
private sealed class Argon2Ctx
{
public Argon2Type Type = Argon2Type.D;
public uint Version = 0;
public ulong Lanes = 0;
@@ -92,7 +89,7 @@ namespace KeePassLib.Cryptography.KeyDerivation
}
}
private byte[] Argon2Transform(byte[] pbMsg, byte[] pbSalt, uint uParallel,
private static byte[] Argon2d(byte[] pbMsg, byte[] pbSalt, uint uParallel,
ulong uMem, ulong uIt, int cbOut, uint uVersion, byte[] pbSecretKey,
byte[] pbAssocData)
{
@@ -104,7 +101,6 @@ namespace KeePassLib.Cryptography.KeyDerivation
#endif
Argon2Ctx ctx = new Argon2Ctx();
ctx.Type = m_t;
ctx.Version = uVersion;
ctx.Lanes = uParallel;
@@ -141,7 +137,7 @@ namespace KeePassLib.Cryptography.KeyDerivation
h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0);
MemUtil.UInt32ToBytesEx(uVersion, pbBuf, 0);
h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0);
MemUtil.UInt32ToBytesEx((uint)m_t, pbBuf, 0);
MemUtil.UInt32ToBytesEx(0, pbBuf, 0); // Argon2d type = 0
h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0);
MemUtil.UInt32ToBytesEx((uint)pbMsg.Length, pbBuf, 0);
h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0);
@@ -501,33 +497,8 @@ namespace KeePassLib.Cryptography.KeyDerivation
Debug.Assert(ctx.Version >= MinVersion);
bool bCanXor = (ctx.Version >= 0x13U);
ulong[] pbR = new ulong[NbBlockSizeInQW];
ulong[] pbTmp = new ulong[NbBlockSizeInQW];
ulong[] pbAddrInputZero = null;
bool bDataIndependentAddr = ((ctx.Type == Argon2Type.ID) &&
(ti.Pass == 0) && (ti.Slice < (NbSyncPoints / 2)));
if (bDataIndependentAddr)
{
pbAddrInputZero = new ulong[NbBlockSizeInQW * 3];
const int iInput = (int)NbBlockSizeInQW;
pbAddrInputZero[iInput] = ti.Pass;
pbAddrInputZero[iInput + 1] = ti.Lane;
pbAddrInputZero[iInput + 2] = ti.Slice;
pbAddrInputZero[iInput + 3] = ctx.MemoryBlocks;
pbAddrInputZero[iInput + 4] = ctx.TCost;
pbAddrInputZero[iInput + 5] = (ulong)ctx.Type;
}
ulong uStart = 0;
if ((ti.Pass == 0) && (ti.Slice == 0))
{
uStart = 2;
if (bDataIndependentAddr)
NextAddresses(pbAddrInputZero, pbR, pbTmp);
}
if((ti.Pass == 0) && (ti.Slice == 0)) uStart = 2;
ulong uCur = (ti.Lane * ctx.LaneLength) + (ti.Slice *
ctx.SegmentLength) + uStart;
@@ -535,21 +506,15 @@ namespace KeePassLib.Cryptography.KeyDerivation
ulong uPrev = (((uCur % ctx.LaneLength) == 0) ?
(uCur + ctx.LaneLength - 1UL) : (uCur - 1UL));
ulong[] pbR = new ulong[NbBlockSizeInQW];
ulong[] pbTmp = new ulong[NbBlockSizeInQW];
for(ulong i = uStart; i < ctx.SegmentLength; ++i)
{
if((uCur % ctx.LaneLength) == 1)
uPrev = uCur - 1UL;
ulong uPseudoRand;
if (bDataIndependentAddr)
{
ulong iMod = i % NbAddressesInBlock;
if (iMod == 0)
NextAddresses(pbAddrInputZero, pbR, pbTmp);
uPseudoRand = pbAddrInputZero[iMod];
}
else uPseudoRand = ctx.Mem[uPrev * NbBlockSizeInQW];
ulong uPseudoRand = ctx.Mem[uPrev * NbBlockSizeInQW];
ulong uRefLane = (uPseudoRand >> 32) % ctx.Lanes;
if((ti.Pass == 0) && (ti.Slice == 0))
uRefLane = ti.Lane;
@@ -571,7 +536,6 @@ namespace KeePassLib.Cryptography.KeyDerivation
MemUtil.ZeroArray<ulong>(pbR);
MemUtil.ZeroArray<ulong>(pbTmp);
if (pbAddrInputZero != null) MemUtil.ZeroArray<ulong>(pbAddrInputZero);
}
catch(Exception) { Debug.Assert(false); }
@@ -646,19 +610,6 @@ namespace KeePassLib.Cryptography.KeyDerivation
XorBlock(pMem, uNext, pbR, 0);
}
private static void NextAddresses(ulong[] pbAddrInputZero, ulong[] pbR,
ulong[] pbTmp)
{
// pbAddrInputZero contains an address block, an input block and a zero block
const ulong uAddr = 0;
const ulong uInput = NbBlockSizeInQW;
const ulong uZero = NbBlockSizeInQW * 2;
++pbAddrInputZero[uInput + 6];
FillBlock(pbAddrInputZero, uZero, uInput, uAddr, false, pbR, pbTmp);
FillBlock(pbAddrInputZero, uZero, uAddr, uAddr, false, pbR, pbTmp);
}
private static byte[] FinalHash(Argon2Ctx ctx, int cbOut, Blake2b h)
{
ulong[] pqBlockHash = new ulong[NbBlockSizeInQW];

View File

@@ -25,22 +25,11 @@ using System.Text;
namespace KeePassLib.Cryptography.KeyDerivation
{
public enum Argon2Type
{
// The values must be the same as in the Argon2 specification
D = 0,
ID = 2
}
public sealed partial class Argon2Kdf : KdfEngine
{
private static readonly PwUuid g_uuidD = new PwUuid(new byte[] {
private static readonly PwUuid g_uuid = new PwUuid(new byte[] {
0xEF, 0x63, 0x6D, 0xDF, 0x8C, 0x29, 0x44, 0x4B,
0x91, 0xF7, 0xA9, 0xA4, 0x03, 0xE3, 0x0A, 0x0C });
private static readonly PwUuid g_uuidID = new PwUuid(new byte[] {
0x9E, 0x29, 0x8B, 0x19, 0x56, 0xDB, 0x47, 0x73,
0xB2, 0x3D, 0xFC, 0x3E, 0xC6, 0xF0, 0xA1, 0xE6 });
public const string ParamSalt = "S"; // Byte[]
public const string ParamParallelism = "P"; // UInt32
@@ -67,35 +56,26 @@ namespace KeePassLib.Cryptography.KeyDerivation
internal const uint MaxParallelism = (1 << 24) - 1;
internal const ulong DefaultIterations = 2;
internal const ulong DefaultMemory = 64 * 1024 * 1024; // 64 MB
internal const ulong DefaultMemory = 1024 * 1024; // 1 MB
internal const uint DefaultParallelism = 2;
private readonly Argon2Type m_t;
public override PwUuid Uuid
{
get { return ((m_t == Argon2Type.D) ? g_uuidD : g_uuidID); }
get { return g_uuid; }
}
public override string Name
{
get { return ((m_t == Argon2Type.D) ? "Argon2d" : "Argon2id"); }
get { return "Argon2"; }
}
public Argon2Kdf() : this(Argon2Type.D)
{
}
public Argon2Kdf(Argon2Type t)
{
if ((t != Argon2Type.D) && (t != Argon2Type.ID))
throw new NotSupportedException();
m_t = t;
}
public override byte[] GetSeed(KdfParameters p)
{ return p.GetByteArray(ParamSalt); }
public Argon2Kdf()
{
}
public override KdfParameters GetDefaultParameters()
{
KdfParameters p = base.GetDefaultParameters();
@@ -112,7 +92,7 @@ namespace KeePassLib.Cryptography.KeyDerivation
public override void Randomize(KdfParameters p)
{
if(p == null) { Debug.Assert(false); return; }
Debug.Assert(p.KdfUuid.Equals(this.Uuid));
Debug.Assert(g_uuid.Equals(p.KdfUuid));
byte[] pb = CryptoRandom.Instance.GetRandomBytes(32);
p.SetByteArray(ParamSalt, pb);
@@ -148,22 +128,11 @@ namespace KeePassLib.Cryptography.KeyDerivation
byte[] pbSecretKey = p.GetByteArray(ParamSecretKey);
byte[] pbAssocData = p.GetByteArray(ParamAssocData);
byte[] pbRet;
if (m_t == Argon2Type.ID)
{
pbRet = Argon2Transform(pbMsg, pbSalt, uPar, uMem,
uIt, 32, v, pbSecretKey, pbAssocData);
}
else
{
if (pbSecretKey != null)
{
if (pbSecretKey != null) {
throw new ArgumentOutOfRangeException("Unsupported configuration: non-null pbSecretKey");
}
if (pbAssocData != null)
{
if (pbAssocData != null) {
throw new ArgumentOutOfRangeException("Unsupported configuration: non-null pbAssocData");
}
@@ -187,18 +156,16 @@ namespace KeePassLib.Cryptography.KeyDerivation
retPtr, (IntPtr)32,
(IntPtr)0, (IntPtr)0, Argon2_d, v);
if (ret != 0)
{
if (ret != 0) {
throw new Exception("argon2_hash failed with " + ret);
}
pbRet = new byte[32];
byte[] pbRet = new byte[32];
Marshal.Copy(retPtr, pbRet, 0, 32);
Marshal.FreeHGlobal(msgPtr);
Marshal.FreeHGlobal(saltPtr);
Marshal.FreeHGlobal(retPtr);
}
if(uMem > (100UL * 1024UL * 1024UL)) GC.Collect();
return pbRet;

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2020 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2020 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -41,11 +41,10 @@ namespace KeePassLib.Cryptography.KeyDerivation
private static void EnsureInitialized()
{
if(g_l.Count != 0) return;
if(g_l.Count > 0) return;
g_l.Add(new AesKdf());
g_l.Add(new Argon2Kdf(Argon2Type.D));
g_l.Add(new Argon2Kdf(Argon2Type.ID));
g_l.Add(new Argon2Kdf());
}
internal static KdfParameters GetDefaultParameters()

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,10 +33,5 @@ namespace KeePassLib.Interfaces
{
get;
}
PwUuid PreviousParentGroup
{
get;
}
}
}

View File

@@ -50,7 +50,6 @@
<HintPath>..\ProtoBuf\protobuf-net.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Security" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Mono.Android" />
@@ -72,9 +71,7 @@
<Compile Include="Cryptography\KeyDerivation\KdfParameters.cs" />
<Compile Include="Cryptography\KeyDerivation\KdfPool.cs" />
<Compile Include="IDatabaseFormat.cs" />
<Compile Include="Keys\KcpKeyFile.Xml.cs" />
<Compile Include="Kp2aLog.cs" />
<Compile Include="PwGroup.Search.cs" />
<Compile Include="Resources\Resource.designer.cs" />
<Compile Include="Resources\KLRes.Generated.cs" />
<Compile Include="Resources\KSRes.Generated.cs" />
@@ -163,7 +160,6 @@
<Compile Include="Utility\UrlUtil.cs" />
<Compile Include="Utility\TimeUtil.cs" />
<Compile Include="Delegates\Handlers.cs" />
<Compile Include="Utility\XmlUtilEx.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@@ -1,281 +0,0 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using KeePassLib.Cryptography;
using KeePassLib.Resources;
using KeePassLib.Serialization;
using KeePassLib.Utility;
namespace KeePassLib.Keys
{
[XmlType("KeyFile")]
public sealed class KfxFile
{
private const ulong KfxVersionCriticalMask = 0xFFFF000000000000UL;
private const int KfxDataHashLength = 4;
private KfxMeta m_meta = new KfxMeta();
public KfxMeta Meta
{
get { return m_meta; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_meta = value;
}
}
private KfxKey m_key = new KfxKey();
public KfxKey Key
{
get { return m_key; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_key = value;
}
}
public static KfxFile Create(ulong uVersion, byte[] pbKey, byte[] pbHash)
{
if(pbKey == null) throw new ArgumentNullException("pbKey");
if(pbKey.Length == 0) throw new ArgumentOutOfRangeException("pbKey");
if(uVersion == 0) uVersion = 0x0002000000000000;
// Null hash: generate one, empty hash: store no hash
if(pbHash == null) pbHash = HashData(pbKey);
VerifyHash(pbKey, pbHash);
KfxFile kf = new KfxFile();
if(uVersion == 0x0001000000000000)
kf.Meta.Version = "1.00"; // KeePass <= 2.46 used two zeros
else kf.Meta.Version = StrUtil.VersionToString(uVersion, 2);
if(uVersion == 0x0001000000000000)
kf.Key.Data.Value = Convert.ToBase64String(pbKey);
else if(uVersion == 0x0002000000000000)
{
kf.Key.Data.Value = FormatKeyHex(pbKey, 3);
if(pbHash.Length != 0)
kf.Key.Data.Hash = MemUtil.ByteArrayToHexString(pbHash);
}
else throw new NotSupportedException(KLRes.FileVersionUnsupported);
return kf;
}
internal static KfxFile Create(ulong uVersion, string strKey, string strHash)
{
byte[] pbKey = ParseKey(uVersion, strKey);
byte[] pbHash = ((strHash != null) ? ParseHash(strHash) : null);
return Create(uVersion, pbKey, pbHash);
}
internal static bool CanLoad(string strFilePath)
{
if(string.IsNullOrEmpty(strFilePath)) { Debug.Assert(false); return false; }
try
{
IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFilePath);
using(Stream s = IOConnection.OpenRead(ioc))
{
return (Load(s) != null);
}
}
catch(Exception) { }
return false;
}
public static KfxFile Load(Stream s)
{
return XmlUtilEx.Deserialize<KfxFile>(s);
}
public void Save(Stream s)
{
XmlUtilEx.Serialize<KfxFile>(s, this, true);
}
private static string FormatKeyHex(byte[] pb, int cTabs)
{
StringBuilder sb = new StringBuilder();
string str = MemUtil.ByteArrayToHexString(pb);
for(int i = 0; i < str.Length; ++i)
{
if((i & 0x1F) == 0)
{
sb.AppendLine();
sb.Append('\t', cTabs);
}
else if((i & 0x07) == 0) sb.Append(' ');
sb.Append(str[i]);
}
sb.AppendLine();
if(cTabs > 0) sb.Append('\t', cTabs - 1);
return sb.ToString();
}
private ulong GetVersion()
{
string str = m_meta.Version;
if(string.IsNullOrEmpty(str)) return 0;
return StrUtil.ParseVersion(str);
}
public byte[] GetKey()
{
ulong uVersion = GetVersion();
byte[] pbKey = ParseKey(uVersion, m_key.Data.Value);
if((pbKey == null) || (pbKey.Length == 0))
throw new FormatException(KLRes.FileCorrupted);
byte[] pbHash = ParseHash(m_key.Data.Hash);
VerifyHash(pbKey, pbHash);
return pbKey;
}
private static byte[] HashData(byte[] pb)
{
return MemUtil.Mid(CryptoUtil.HashSha256(pb), 0, KfxDataHashLength);
}
private static void VerifyHash(byte[] pbKey, byte[] pbHash)
{
// The hash is optional; empty hash means success
if((pbHash == null) || (pbHash.Length == 0)) return;
byte[] pbHashCmp = HashData(pbKey);
if(!MemUtil.ArraysEqual(pbHash, pbHashCmp))
throw new Exception("Keyfile hash mismatch!");
}
private static byte[] ParseKey(ulong uVersion, string strKey)
{
if(strKey == null) throw new ArgumentNullException("strKey");
strKey = StrUtil.RemoveWhiteSpace(strKey);
if(string.IsNullOrEmpty(strKey)) return MemUtil.EmptyByteArray;
uVersion &= KfxVersionCriticalMask;
byte[] pbKey;
if(uVersion == 0x0001000000000000)
pbKey = Convert.FromBase64String(strKey);
else if(uVersion == 0x0002000000000000)
pbKey = ParseHex(strKey);
else throw new NotSupportedException(KLRes.FileVersionUnsupported);
return pbKey;
}
private static byte[] ParseHash(string strHash)
{
return ParseHex(strHash);
}
private static byte[] ParseHex(string str)
{
if(str == null) throw new ArgumentNullException("str");
if(str.Length == 0) return MemUtil.EmptyByteArray;
if(((str.Length & 1) != 0) || !StrUtil.IsHexString(str, true))
throw new FormatException();
return MemUtil.HexStringToByteArray(str);
}
}
public sealed class KfxMeta
{
private string m_strVersion = string.Empty;
[DefaultValue("")]
public string Version
{
get { return m_strVersion; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strVersion = value;
}
}
}
public sealed class KfxKey
{
private KfxData m_data = new KfxData();
public KfxData Data
{
get { return m_data; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_data = value;
}
}
}
public sealed class KfxData
{
private string m_strHash = string.Empty;
[DefaultValue("")]
[XmlAttribute("Hash")]
public string Hash
{
get { return m_strHash; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strHash = value;
}
}
private string m_strValue = string.Empty;
[DefaultValue("")]
[XmlText]
public string Value
{
get { return m_strValue; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strValue = value;
}
}
}
}

View File

@@ -127,7 +127,8 @@ namespace KeePassLib.Keys
#endif
}
byte[] pbKey = LoadKeyFile(pbFileData);
byte[] pbKey = LoadXmlKeyFile(pbFileData);
if(pbKey == null) pbKey = LoadKeyFile(pbFileData);
if(pbKey == null) throw new InvalidOperationException();
@@ -150,59 +151,53 @@ namespace KeePassLib.Keys
private static byte[] LoadKeyFile(byte[] pbFileData)
{
if (pbFileData == null) throw new ArgumentNullException("pbFileData");
byte[] pbKey = LoadKeyFileXml(pbFileData);
if (pbKey != null) return pbKey;
int cb = pbFileData.Length;
if (cb == 32) return pbFileData;
if (cb == 64)
{
pbKey = LoadKeyFileHex(pbFileData);
if (pbKey != null) return pbKey;
}
return CryptoUtil.HashSha256(pbFileData);
}
private static byte[] LoadKeyFileXml(byte[] pbFileData)
{
KfxFile kf;
try
{
using (MemoryStream ms = new MemoryStream(pbFileData, false))
{
kf = KfxFile.Load(ms);
}
}
catch (Exception) { return null; }
// We have a syntactically valid XML key file;
// failing to verify the key should throw an exception
return ((kf != null) ? kf.GetKey() : null);
}
private static byte[] LoadKeyFileHex(byte[] pbFileData)
{
if(pbFileData == null) { Debug.Assert(false); return null; }
int iLength = pbFileData.Length;
byte[] pbKey = null;
if(iLength == 32) pbKey = LoadBinaryKey32(pbFileData);
else if(iLength == 64) pbKey = LoadHexKey32(pbFileData);
if(pbKey == null)
pbKey = CryptoUtil.HashSha256(pbFileData);
return pbKey;
}
private static byte[] LoadBinaryKey32(byte[] pbFileData)
{
if(pbFileData == null) { Debug.Assert(false); return null; }
if(pbFileData.Length != 32) { Debug.Assert(false); return null; }
return pbFileData;
}
private static byte[] LoadHexKey32(byte[] pbFileData)
{
if(pbFileData == null) { Debug.Assert(false); return null; }
if(pbFileData.Length != 64) { Debug.Assert(false); return null; }
try
{
int cc = pbFileData.Length;
if ((cc & 1) != 0) { Debug.Assert(false); return null; }
if(!StrUtil.IsHexString(pbFileData, true)) return null;
string strHex = StrUtil.Utf8.GetString(pbFileData);
return MemUtil.HexStringToByteArray(strHex);
byte[] pbKey = MemUtil.HexStringToByteArray(strHex);
if((pbKey == null) || (pbKey.Length != 32))
{
Debug.Assert(false);
return null;
}
return pbKey;
}
catch(Exception) { Debug.Assert(false); }
return null;
}
/// <summary>
/// Create a new, random key-file.
/// </summary>

View File

@@ -118,10 +118,5 @@ namespace keepass2android
sendIntent.SetType("text/plain");
ctx.StartActivity(Intent.CreateChooser(sendIntent, "Send log to..."));
}
public static void LogTask(object task, string activityName)
{
Log($"Task in activity {activityName} changed to {task?.GetType()?.Name ?? "null"}");
}
}
}

View File

@@ -1,6 +1,8 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,106 +20,61 @@
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
#if !KeePassUAP
using System.Drawing;
#endif
using System.IO;
using KeePassLib.Utility;
namespace KeePassLib
{
/// <summary>
/// Custom icon. <c>PwCustomIcon</c> objects are immutable.
/// </summary>
public sealed class PwCustomIcon
{
// Recommended maximum sizes, not obligatory
internal const int MaxWidth = 128;
internal const int MaxHeight = 128;
private readonly PwUuid m_uuid;
private readonly byte[] m_pbImageDataPng;
private string m_strName = string.Empty;
private DateTime? m_odtLastMod = null;
private Dictionary<long, Android.Graphics.Bitmap> m_dImageCache = new Dictionary<long, Android.Graphics.Bitmap>();
private PwUuid m_pwUuid;
private byte[] m_pbImageDataPng;
private Android.Graphics.Bitmap m_pCachedImage;
public PwUuid Uuid
{
get { return m_uuid; }
get { return m_pwUuid; }
}
public byte[] ImageDataPng
{
get { return m_pbImageDataPng; }
// When allowing 'set', do not copy the cache in 'Clone'
}
public string Name
{
get { return m_strName; }
set
{
if (value == null) throw new ArgumentNullException("value");
m_strName = value;
}
}
public DateTime? LastModificationTime
{
get { return m_odtLastMod; }
set { m_odtLastMod = value; }
}
[Obsolete("Use GetImage instead.")]
public Android.Graphics.Bitmap Image
{
get { return GetImage(); } // Backward compatibility
get { return m_pCachedImage; }
}
public PwCustomIcon(PwUuid pu, byte[] pbImageDataPng)
public PwCustomIcon(PwUuid pwUuid, byte[] pbImageDataPng)
{
if (pu == null) { Debug.Assert(false); throw new ArgumentNullException("pu"); }
if (pu.Equals(PwUuid.Zero)) { Debug.Assert(false); throw new ArgumentOutOfRangeException("pu"); }
if (pbImageDataPng == null) { Debug.Assert(false); throw new ArgumentNullException("pbImageDataPng"); }
Debug.Assert(pwUuid != null);
if(pwUuid == null) throw new ArgumentNullException("pwUuid");
Debug.Assert(!pwUuid.Equals(PwUuid.Zero));
if(pwUuid.Equals(PwUuid.Zero)) throw new ArgumentException("pwUuid == 0");
m_uuid = pu;
Debug.Assert(pbImageDataPng != null);
if(pbImageDataPng == null) throw new ArgumentNullException("pbImageDataPng");
m_pwUuid = pwUuid;
m_pbImageDataPng = pbImageDataPng;
}
private static long GetKey(int w, int h)
{
return (((long)w << 32) ^ (long)h);
}
/// <summary>
/// Get the icon as an <c>Image</c> (original size).
/// </summary>
public Android.Graphics.Bitmap GetImage()
{
const long lKey = -1;
Android.Graphics.Bitmap img;
if (m_dImageCache.TryGetValue(lKey, out img)) return img;
try { img = GfxUtil.LoadImage(m_pbImageDataPng); }
catch (Exception) { Debug.Assert(false); }
m_dImageCache[lKey] = img;
return img;
}
internal PwCustomIcon Clone()
{
PwCustomIcon ico = new PwCustomIcon(m_uuid, m_pbImageDataPng);
ico.m_strName = m_strName;
ico.m_odtLastMod = m_odtLastMod;
ico.m_dImageCache = m_dImageCache; // Same image data
return ico;
#if !KeePassLibSD
// MemoryStream ms = new MemoryStream(m_pbImageDataPng, false);
// m_pCachedImage = Image.FromStream(ms);
// ms.Close();
m_pCachedImage = GfxUtil.LoadImage(m_pbImageDataPng);
#else
m_pCachedImage = null;
#endif
}
}
}

View File

@@ -97,7 +97,7 @@ namespace KeePassLib
private int m_nHistoryMaxItems = DefaultHistoryMaxItems;
private long m_lHistoryMaxSize = DefaultHistoryMaxSize; // In bytes
private StringDictionaryEx m_dCustomData = new StringDictionaryEx(true);
private StringDictionaryEx m_dCustomData = new StringDictionaryEx();
private VariantDictionary m_dPublicCustomData = new VariantDictionary();
private byte[] m_pbHashOfFileOnDisk = null;
@@ -739,12 +739,6 @@ namespace KeePassLib
pgNew.Uuid = pg.Uuid;
pgNew.AssignProperties(pg, false, true);
if (!pgLocalContainer.CanAddGroup(pgNew))
{
Debug.Assert(false);
pgLocalContainer = m_pgRootGroup;
pgLocalContainer.CheckCanAddGroup(pgNew);
}
// pgLocalContainer.AddGroup(pgNew, true);
InsertObjectAtBestPos<PwGroup>(pgLocalContainer.Groups, pgNew, ppSrc);
pgNew.ParentGroup = pgLocalContainer;
@@ -844,24 +838,24 @@ namespace KeePassLib
MergeInLocationChanged(m_pgRootGroup, ppOrg, ppSrc);
ppOrg = null; // Pools are now invalid, because the location
ppSrc = null; // changed times have been merged in
}
// Delete *after* relocating, because relocating might empty
// some groups that are marked for deletion (and objects
// that weren't relocated yet might prevent the deletion)
Dictionary<PwUuid, PwDeletedObject> dDel = CreateDeletedObjectsPool();
if (mm == PwMergeMethod.Synchronize)
MergeInDeletionInfo(pdSource.m_vDeletedObjects, dDel);
ApplyDeletions(m_pgRootGroup, dDel);
// Delete *after* relocating, because relocating might
// empty some groups that are marked for deletion (and
// objects that weren't relocated yet might prevent the
// deletion)
Dictionary<PwUuid, PwDeletedObject> dOrgDel = CreateDeletedObjectsPool();
MergeInDeletionInfo(pdSource.m_vDeletedObjects, dOrgDel);
ApplyDeletions(m_pgRootGroup, dOrgDel);
// The list and the dictionary should be kept in sync
Debug.Assert(m_vDeletedObjects.UCount == (uint)dDel.Count);
Debug.Assert(m_vDeletedObjects.UCount == (uint)dOrgDel.Count);
}
// Must be called *after* merging groups, because group UUIDs
// are required for recycle bin and entry template UUIDs
MergeInDbProperties(pdSource, mm);
MergeInCustomIcons(pdSource, dDel);
Debug.Assert(m_vDeletedObjects.UCount == (uint)dDel.Count);
MergeInCustomIcons(pdSource);
MaintainBackups();
@@ -869,79 +863,15 @@ namespace KeePassLib
m_slStatus = slPrevStatus;
}
private void MergeInCustomIcons(PwDatabase pdSource,
Dictionary<PwUuid, PwDeletedObject> dDel)
private void MergeInCustomIcons(PwDatabase pdSource)
{
bool bIconsMod = false;
Dictionary<PwUuid, int> d = new Dictionary<PwUuid, int>();
for (int i = m_vCustomIcons.Count - 1; i >= 0; --i)
d[m_vCustomIcons[i].Uuid] = i;
Debug.Assert(d.Count == m_vCustomIcons.Count); // UUIDs unique
foreach (PwCustomIcon ciS in pdSource.m_vCustomIcons)
foreach(PwCustomIcon pwci in pdSource.CustomIcons)
{
int iT;
if (d.TryGetValue(ciS.Uuid, out iT))
{
PwCustomIcon ciT = m_vCustomIcons[iT];
if(GetCustomIconIndex(pwci.Uuid) >= 0) continue;
DateTime? odtT = ciT.LastModificationTime;
DateTime? odtS = ciS.LastModificationTime;
if (odtT.HasValue && odtS.HasValue)
{
if (odtT.Value >= odtS.Value) continue;
m_vCustomIcons.Add(pwci); // PwCustomIcon is immutable
m_bUINeedsIconUpdate = true;
}
else if (odtT.HasValue) continue;
else if (!odtS.HasValue) continue; // Both no time
m_vCustomIcons[iT] = ciS.Clone();
}
else
{
d[ciS.Uuid] = m_vCustomIcons.Count;
m_vCustomIcons.Add(ciS.Clone());
}
bIconsMod = true;
}
List<PwDeletedObject> lObsoleteDel = new List<PwDeletedObject>();
foreach (KeyValuePair<PwUuid, PwDeletedObject> kvpDel in dDel)
{
int iT;
if (d.TryGetValue(kvpDel.Key, out iT))
{
PwCustomIcon ci = m_vCustomIcons[iT];
if (ci == null) { Debug.Assert(false); continue; } // Dup. del. obj.?
DateTime? odt = ci.LastModificationTime;
if (odt.HasValue && (odt.Value > kvpDel.Value.DeletionTime))
lObsoleteDel.Add(kvpDel.Value);
else
{
m_vCustomIcons[iT] = null; // Preserve indices, removed below
bIconsMod = true;
}
}
}
Predicate<PwCustomIcon> f = delegate (PwCustomIcon ci) { return (ci == null); };
m_vCustomIcons.RemoveAll(f);
foreach (PwDeletedObject pdo in lObsoleteDel)
{
// Prevent future deletion attempts
if (!m_vDeletedObjects.Remove(pdo)) { Debug.Assert(false); }
if (!dDel.Remove(pdo.Uuid)) { Debug.Assert(false); }
}
if (bIconsMod) m_bUINeedsIconUpdate = true;
FixCustomIconRefs();
}
private Dictionary<PwUuid, PwDeletedObject> CreateDeletedObjectsPool()
@@ -1282,9 +1212,7 @@ namespace KeePassLib
PwObjectBlock<T> b = new PwObjectBlock<T>();
DateTime dtLoc;
PwUuid puPrevParent;
PwObjectPoolEx pPool = GetBestPool(t, ppOrg, ppSrc, out dtLoc,
out puPrevParent);
PwObjectPoolEx pPool = GetBestPool(t, ppOrg, ppSrc, out dtLoc);
b.Add(t, dtLoc, pPool);
lBlocks.Add(b);
@@ -1319,7 +1247,7 @@ namespace KeePassLib
}
if(idSrcNext == 0) break;
pPool = GetBestPool(tNext, ppOrg, ppSrc, out dtLoc, out puPrevParent);
pPool = GetBestPool(tNext, ppOrg, ppSrc, out dtLoc);
b.Add(tNext, dtLoc, pPool);
++u;
@@ -1332,18 +1260,16 @@ namespace KeePassLib
}
private static PwObjectPoolEx GetBestPool<T>(T t, PwObjectPoolEx ppOrg,
PwObjectPoolEx ppSrc, out DateTime dtLoc, out PwUuid puPrevParent)
PwObjectPoolEx ppSrc, out DateTime dtLoc)
where T : class, ITimeLogger, IStructureItem, IDeepCloneable<T>
{
PwObjectPoolEx p = null;
dtLoc = TimeUtil.SafeMinValueUtc;
puPrevParent = PwUuid.Zero;
IStructureItem ptOrg = ppOrg.GetItemByUuid(t.Uuid);
if(ptOrg != null)
{
dtLoc = ptOrg.LocationChanged;
puPrevParent = ptOrg.PreviousParentGroup;
p = ppOrg;
}
@@ -1351,7 +1277,6 @@ namespace KeePassLib
if((ptSrc != null) && (ptSrc.LocationChanged > dtLoc))
{
dtLoc = ptSrc.LocationChanged;
puPrevParent = ptSrc.PreviousParentGroup;
p = ppSrc;
}
@@ -1388,13 +1313,8 @@ namespace KeePassLib
GroupHandler gh = delegate(PwGroup pgSub)
{
DateTime dt;
PwUuid puPrevParent;
if (GetBestPool<PwGroup>(pgSub, ppOrg, ppSrc, out dt,
out puPrevParent) != null)
{
if(GetBestPool<PwGroup>(pgSub, ppOrg, ppSrc, out dt) != null)
pgSub.LocationChanged = dt;
pgSub.PreviousParentGroup = puPrevParent;
}
else { Debug.Assert(false); }
return true;
};
@@ -1402,13 +1322,8 @@ namespace KeePassLib
EntryHandler eh = delegate(PwEntry pe)
{
DateTime dt;
PwUuid puPrevParent;
if (GetBestPool<PwEntry>(pe, ppOrg, ppSrc, out dt,
out puPrevParent) != null)
{
if(GetBestPool<PwEntry>(pe, ppOrg, ppSrc, out dt) != null)
pe.LocationChanged = dt;
pe.PreviousParentGroup = puPrevParent;
}
else { Debug.Assert(false); }
return true;
};
@@ -1530,18 +1445,12 @@ namespace KeePassLib
foreach(KeyValuePair<string, string> kvp in pdSource.m_dCustomData)
{
if(bSourceNewer || !m_dCustomData.Exists(kvp.Key))
m_dCustomData.Set(kvp.Key, kvp.Value, null);
m_dCustomData.Set(kvp.Key, kvp.Value);
}
// 'Clone' duplicates deep values (e.g. byte arrays)
VariantDictionary vdS = (VariantDictionary)pdSource.m_dPublicCustomData.Clone();
if (bForce || bSourceNewer)
vdS.CopyTo(m_dPublicCustomData);
else
{
m_dPublicCustomData.CopyTo(vdS);
m_dPublicCustomData = vdS;
}
VariantDictionary vdLocal = m_dPublicCustomData; // Backup
m_dPublicCustomData = (VariantDictionary)pdSource.m_dPublicCustomData.Clone();
if(!bSourceNewer) vdLocal.CopyTo(m_dPublicCustomData); // Merge
}
private void MergeEntryHistory(PwEntry pe, PwEntry peSource,
@@ -1676,64 +1585,68 @@ namespace KeePassLib
else { Debug.Assert(false); return null; }
}
public bool DeleteCustomIcons(List<PwUuid> lUuids)
public bool DeleteCustomIcons(List<PwUuid> vUuidsToDelete)
{
if (lUuids == null) { Debug.Assert(false); throw new ArgumentNullException("lUuids"); }
if (lUuids.Count == 0) return false;
Dictionary<PwUuid, bool> dToDel = new Dictionary<PwUuid, bool>();
foreach (PwUuid pu in lUuids) { dToDel[pu] = true; }
DateTime dt = DateTime.UtcNow;
for (int i = m_vCustomIcons.Count - 1; i >= 0; --i)
{
PwUuid pu = m_vCustomIcons[i].Uuid;
if (dToDel.ContainsKey(pu))
{
m_vCustomIcons[i] = null; // Removed below
m_vDeletedObjects.Add(new PwDeletedObject(pu, dt));
}
}
Predicate<PwCustomIcon> f = delegate (PwCustomIcon ci) { return (ci == null); };
m_vCustomIcons.RemoveAll(f);
FixCustomIconRefs();
return true;
}
private void FixCustomIconRefs()
{
Dictionary<PwUuid, bool> d = new Dictionary<PwUuid, bool>();
foreach (PwCustomIcon ci in m_vCustomIcons) { d[ci.Uuid] = true; }
Debug.Assert(vUuidsToDelete != null);
if(vUuidsToDelete == null) throw new ArgumentNullException("vUuidsToDelete");
if(vUuidsToDelete.Count <= 0) return true;
GroupHandler gh = delegate(PwGroup pg)
{
PwUuid pu = pg.CustomIconUuid;
if (pu.Equals(PwUuid.Zero)) return true;
if (!d.ContainsKey(pu)) pg.CustomIconUuid = PwUuid.Zero;
PwUuid uuidThis = pg.CustomIconUuid;
if(uuidThis.Equals(PwUuid.Zero)) return true;
foreach(PwUuid uuidDelete in vUuidsToDelete)
{
if(uuidThis.Equals(uuidDelete))
{
pg.CustomIconUuid = PwUuid.Zero;
break;
}
}
return true;
};
EntryHandler eh = delegate(PwEntry pe)
{
FixCustomIconRefs(pe, d);
RemoveCustomIconUuid(pe, vUuidsToDelete);
return true;
};
gh(m_pgRootGroup);
m_pgRootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh);
}
private void FixCustomIconRefs(PwEntry pe, Dictionary<PwUuid, bool> d)
if(!m_pgRootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh))
{
PwUuid pu = pe.CustomIconUuid;
if (pu.Equals(PwUuid.Zero)) return;
if (!d.ContainsKey(pu)) pe.CustomIconUuid = PwUuid.Zero;
foreach (PwEntry peH in pe.History) FixCustomIconRefs(peH, d);
Debug.Assert(false);
return false;
}
foreach(PwUuid pwUuid in vUuidsToDelete)
{
int nIndex = GetCustomIconIndex(pwUuid);
if(nIndex >= 0) m_vCustomIcons.RemoveAt(nIndex);
}
return true;
}
private static void RemoveCustomIconUuid(PwEntry pe, List<PwUuid> vToDelete)
{
PwUuid uuidThis = pe.CustomIconUuid;
if(uuidThis.Equals(PwUuid.Zero)) return;
foreach(PwUuid uuidDelete in vToDelete)
{
if(uuidThis.Equals(uuidDelete))
{
pe.CustomIconUuid = PwUuid.Zero;
break;
}
}
foreach(PwEntry peHistory in pe.History)
RemoveCustomIconUuid(peHistory, vToDelete);
}
private int GetTotalObjectUuidCount()
{
@@ -2022,119 +1935,61 @@ namespace KeePassLib
return uDeleted;
}
public uint DeleteUnusedCustomIcons()
{
Dictionary<PwUuid, bool> dToDel = new Dictionary<PwUuid, bool>();
foreach (PwCustomIcon ci in m_vCustomIcons) { dToDel[ci.Uuid] = true; }
List<PwUuid> lToDelete = new List<PwUuid>();
foreach(PwCustomIcon pwci in m_vCustomIcons)
lToDelete.Add(pwci.Uuid);
GroupHandler gh = delegate(PwGroup pg)
{
PwUuid pu = pg.CustomIconUuid;
if (!pu.Equals(PwUuid.Zero)) dToDel.Remove(pu);
PwUuid pwUuid = pg.CustomIconUuid;
if((pwUuid == null) || pwUuid.Equals(PwUuid.Zero)) return true;
for(int i = 0; i < lToDelete.Count; ++i)
{
if(lToDelete[i].Equals(pwUuid))
{
lToDelete.RemoveAt(i);
break;
}
}
return true;
};
EntryHandler eh = delegate(PwEntry pe)
{
RemoveCustomIconsFromDict(dToDel, pe);
PwUuid pwUuid = pe.CustomIconUuid;
if((pwUuid == null) || pwUuid.Equals(PwUuid.Zero)) return true;
for(int i = 0; i < lToDelete.Count; ++i)
{
if(lToDelete[i].Equals(pwUuid))
{
lToDelete.RemoveAt(i);
break;
}
}
return true;
};
gh(m_pgRootGroup);
m_pgRootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh);
uint cDel = (uint)dToDel.Count;
if (cDel != 0)
uint uDeleted = 0;
foreach(PwUuid pwDel in lToDelete)
{
DeleteCustomIcons(new List<PwUuid>(dToDel.Keys));
m_bUINeedsIconUpdate = true;
int nIndex = GetCustomIconIndex(pwDel);
if(nIndex < 0) { Debug.Assert(false); continue; }
m_vCustomIcons.RemoveAt(nIndex);
++uDeleted;
}
return cDel;
}
private static void RemoveCustomIconsFromDict(Dictionary<PwUuid, bool> d,
PwEntry pe)
{
PwUuid pu = pe.CustomIconUuid;
if (!pu.Equals(PwUuid.Zero)) d.Remove(pu);
foreach (PwEntry peH in pe.History) RemoveCustomIconsFromDict(d, peH);
}
internal static void CopyCustomIcons(PwDatabase pdFrom, PwDatabase pdTo,
PwGroup pgSelect, bool bResetIfUnknown)
{
if (pgSelect == null) { Debug.Assert(false); return; }
Dictionary<PwUuid, PwCustomIcon> dFrom = new Dictionary<PwUuid, PwCustomIcon>();
if (pdFrom != null)
{
foreach (PwCustomIcon ci in pdFrom.m_vCustomIcons)
dFrom[ci.Uuid] = ci;
}
Dictionary<PwUuid, int> dTo = new Dictionary<PwUuid, int>();
if (pdTo != null)
{
for (int i = pdTo.m_vCustomIcons.Count - 1; i >= 0; --i)
dTo[pdTo.m_vCustomIcons[i].Uuid] = i;
}
Func<PwUuid, bool> fEnsureIcon = delegate (PwUuid puIcon)
{
if (puIcon.Equals(PwUuid.Zero)) return true;
if (pdTo == null) { Debug.Assert(false); return false; }
PwCustomIcon ciFrom;
if (!dFrom.TryGetValue(puIcon, out ciFrom)) { Debug.Assert(false); return false; }
int iTo;
if (dTo.TryGetValue(puIcon, out iTo))
{
PwCustomIcon ciTo = pdTo.m_vCustomIcons[iTo];
DateTime? odtFrom = ciFrom.LastModificationTime;
DateTime? odtTo = ciTo.LastModificationTime;
if (odtFrom.HasValue && odtTo.HasValue)
{
if (odtFrom.Value <= odtTo.Value) return true;
}
else if (odtTo.HasValue) return true;
else if (!odtFrom.HasValue) return true; // Both no time
pdTo.m_vCustomIcons[iTo] = ciFrom.Clone();
}
else
{
dTo[puIcon] = pdTo.m_vCustomIcons.Count;
pdTo.m_vCustomIcons.Add(ciFrom.Clone());
}
pdTo.Modified = true;
pdTo.UINeedsIconUpdate = true;
return true;
};
GroupHandler gh = delegate (PwGroup pgCur)
{
bool bTo = fEnsureIcon(pgCur.CustomIconUuid);
if (!bTo && bResetIfUnknown) pgCur.CustomIconUuid = PwUuid.Zero;
return true;
};
EntryHandler eh = delegate (PwEntry peCur)
{
bool bTo = fEnsureIcon(peCur.CustomIconUuid);
if (!bTo && bResetIfUnknown) peCur.CustomIconUuid = PwUuid.Zero;
return true;
};
gh(pgSelect);
pgSelect.TraverseTree(TraversalMethod.PreOrder, gh, eh);
if(uDeleted > 0) m_bUINeedsIconUpdate = true;
return uDeleted;
}
}
}

View File

@@ -228,18 +228,6 @@ namespace KeePassLib
/// </summary>
public sealed class SearchParameters
{
private string m_strName = string.Empty;
[DefaultValue("")]
public string Name
{
get { return m_strName; }
set
{
if (value == null) throw new ArgumentNullException("value");
m_strName = value;
}
}
private string m_strText = string.Empty;
[DefaultValue("")]
public string SearchString
@@ -252,20 +240,12 @@ namespace KeePassLib
}
}
private PwSearchMode m_sm = PwSearchMode.Simple;
public PwSearchMode SearchMode
{
get { return m_sm; }
set { m_sm = value; }
}
private bool m_bRegex = false;
[DefaultValue(false)]
[Obsolete]
[XmlIgnore]
public bool RegularExpression
{
get { return (m_sm == PwSearchMode.Regular); }
set { m_sm = (value ? PwSearchMode.Regular : PwSearchMode.Simple); }
get { return m_bRegex; }
set { m_bRegex = value; }
}
private bool m_bSearchInTitles = true;
@@ -316,22 +296,6 @@ namespace KeePassLib
set { m_bSearchInOther = value; }
}
private bool m_bSearchInStringNames = false;
[DefaultValue(false)]
public bool SearchInStringNames
{
get { return m_bSearchInStringNames; }
set { m_bSearchInStringNames = value; }
}
private bool m_bSearchInTags = true;
[DefaultValue(true)]
public bool SearchInTags
{
get { return m_bSearchInTags; }
set { m_bSearchInTags = value; }
}
private bool m_bSearchInUuids = false;
[DefaultValue(false)]
public bool SearchInUuids
@@ -340,14 +304,6 @@ namespace KeePassLib
set { m_bSearchInUuids = value; }
}
private bool m_bSearchInGroupPaths = false;
[DefaultValue(false)]
public bool SearchInGroupPaths
{
get { return m_bSearchInGroupPaths; }
set { m_bSearchInGroupPaths = value; }
}
private bool m_bSearchInGroupNames = false;
[DefaultValue(false)]
public bool SearchInGroupNames
@@ -356,12 +312,12 @@ namespace KeePassLib
set { m_bSearchInGroupNames = value; }
}
private bool m_bSearchInHistory = false;
[DefaultValue(false)]
public bool SearchInHistory
private bool m_bSearchInTags = true;
[DefaultValue(true)]
public bool SearchInTags
{
get { return m_bSearchInHistory; }
set { m_bSearchInHistory = value; }
get { return m_bSearchInTags; }
set { m_bSearchInTags = value; }
}
#if KeePassUAP
@@ -425,24 +381,20 @@ namespace KeePassLib
{
SearchParameters sp = new SearchParameters();
Debug.Assert(sp.m_strName.Length == 0);
Debug.Assert(sp.m_strText.Length == 0);
Debug.Assert(sp.m_sm == PwSearchMode.Simple);
// sp.m_strText = string.Empty;
// sp.m_bRegex = false;
sp.m_bSearchInTitles = false;
sp.m_bSearchInUserNames = false;
Debug.Assert(!sp.m_bSearchInPasswords);
// sp.m_bSearchInPasswords = false;
sp.m_bSearchInUrls = false;
sp.m_bSearchInNotes = false;
sp.m_bSearchInOther = false;
Debug.Assert(!sp.m_bSearchInStringNames);
// sp.m_bSearchInUuids = false;
// sp.SearchInGroupNames = false;
sp.m_bSearchInTags = false;
Debug.Assert(!sp.m_bSearchInUuids);
Debug.Assert(!sp.m_bSearchInGroupPaths);
Debug.Assert(!sp.m_bSearchInGroupNames);
Debug.Assert(!sp.m_bSearchInHistory);
// Debug.Assert(sp.m_scType == StringComparison.InvariantCultureIgnoreCase);
Debug.Assert(!sp.m_bExcludeExpired);
Debug.Assert(sp.m_bRespectEntrySearchingDisabled);
// sp.m_scType = StringComparison.InvariantCultureIgnoreCase;
// sp.m_bExcludeExpired = false;
// m_bRespectEntrySearchingDisabled = true;
return sp;
}

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -42,15 +42,14 @@ namespace KeePassLib
private PwUuid m_uuid = PwUuid.Zero;
private PwGroup m_pParentGroup = null;
private DateTime m_tParentGroupLastMod = PwDefs.DtDefaultNow;
private PwUuid m_puPrevParentGroup = PwUuid.Zero;
private ProtectedStringDictionary m_dStrings = new ProtectedStringDictionary();
private ProtectedBinaryDictionary m_dBinaries = new ProtectedBinaryDictionary();
private AutoTypeConfig m_cfgAutoType = new AutoTypeConfig();
private PwObjectList<PwEntry> m_lHistory = new PwObjectList<PwEntry>();
private ProtectedStringDictionary m_listStrings = new ProtectedStringDictionary();
private ProtectedBinaryDictionary m_listBinaries = new ProtectedBinaryDictionary();
private AutoTypeConfig m_listAutoType = new AutoTypeConfig();
private PwObjectList<PwEntry> m_listHistory = new PwObjectList<PwEntry>();
private PwIcon m_pwIcon = PwIcon.Key;
private PwUuid m_puCustomIcon = PwUuid.Zero;
private PwUuid m_pwCustomIconID = PwUuid.Zero;
private Color m_clrForeground = Color.Empty;
private Color m_clrBackground = Color.Empty;
@@ -63,21 +62,20 @@ namespace KeePassLib
private ulong m_uUsageCount = 0;
private string m_strOverrideUrl = string.Empty;
private bool m_bQualityCheck = true;
private List<string> m_lTags = new List<string>();
private List<string> m_vTags = new List<string>();
private StringDictionaryEx m_dCustomData = new StringDictionaryEx();
/// <summary>
/// UUID of this entry.
/// </summary>
/// </summary>
public PwUuid Uuid
{
get { return m_uuid; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
m_uuid = value;
}
}
@@ -89,7 +87,7 @@ namespace KeePassLib
{
get { return m_pParentGroup; }
// Plugins: use <c>PwGroup.AddEntry</c> instead.
/// Plugins: use <c>PwGroup.AddEntry</c> instead.
internal set { m_pParentGroup = value; }
}
@@ -102,26 +100,17 @@ namespace KeePassLib
set { m_tParentGroupLastMod = value; }
}
public PwUuid PreviousParentGroup
{
get { return m_puPrevParentGroup; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
m_puPrevParentGroup = value;
}
}
/// <summary>
/// Get or set all entry strings.
/// </summary>
public ProtectedStringDictionary Strings
{
get { return m_dStrings; }
get { return m_listStrings; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
m_dStrings = value;
Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
m_listStrings = value;
}
}
@@ -130,11 +119,11 @@ namespace KeePassLib
/// </summary>
public ProtectedBinaryDictionary Binaries
{
get { return m_dBinaries; }
get { return m_listBinaries; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
m_dBinaries = value;
Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
m_listBinaries = value;
}
}
@@ -143,11 +132,11 @@ namespace KeePassLib
/// </summary>
public AutoTypeConfig AutoType
{
get { return m_cfgAutoType; }
get { return m_listAutoType; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
m_cfgAutoType = value;
Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
m_listAutoType = value;
}
}
@@ -156,11 +145,11 @@ namespace KeePassLib
/// </summary>
public PwObjectList<PwEntry> History
{
get { return m_lHistory; }
get { return m_listHistory; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
m_lHistory = value;
Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
m_listHistory = value;
}
}
@@ -180,11 +169,11 @@ namespace KeePassLib
/// </summary>
public PwUuid CustomIconUuid
{
get { return m_puCustomIcon; }
get { return m_pwCustomIconID; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
m_puCustomIcon = value;
Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
m_pwCustomIconID = value;
}
}
@@ -263,34 +252,28 @@ namespace KeePassLib
}
/// <summary>
/// Entry-specific override URL.
/// Entry-specific override URL. If this string is non-empty,
/// </summary>
public string OverrideUrl
{
get { return m_strOverrideUrl; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
if (value == null) throw new ArgumentNullException("value");
m_strOverrideUrl = value;
}
}
public bool QualityCheck
{
get { return m_bQualityCheck; }
set { m_bQualityCheck = value; }
}
/// <summary>
/// List of tags associated with this entry.
/// </summary>
public List<string> Tags
{
get { StrUtil.NormalizeTags(m_lTags); return m_lTags; }
get { return m_vTags; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
m_lTags = value;
if (value == null) throw new ArgumentNullException("value");
m_vTags = value;
}
}
@@ -366,19 +349,19 @@ namespace KeePassLib
}
#if DEBUG
// For display in debugger
/// <summary>
public override string ToString()
{
return ("PwEntry '" + m_dStrings.ReadSafe(PwDefs.TitleField) + "'");
return (@"PwEntry '" + m_listStrings.ReadSafe(PwDefs.TitleField) + @"'");
}
#endif
/// <summary>
/// Clone the current entry. The returned entry is an exact value copy
/// of the current entry (including UUID and parent group reference).
/// All mutable members are cloned.
/// </summary>
/// <returns>Exact value clone. All references to mutable values changed.</returns>
/// </summary>
/// <returns>Exact value clone. All references to mutable values changed.</returns>
public PwEntry CloneDeep()
{
PwEntry peNew = new PwEntry(false, false);
@@ -386,15 +369,14 @@ namespace KeePassLib
peNew.m_uuid = m_uuid; // PwUuid is immutable
peNew.m_pParentGroup = m_pParentGroup;
peNew.m_tParentGroupLastMod = m_tParentGroupLastMod;
peNew.m_puPrevParentGroup = m_puPrevParentGroup;
peNew.m_dStrings = m_dStrings.CloneDeep();
peNew.m_dBinaries = m_dBinaries.CloneDeep();
peNew.m_cfgAutoType = m_cfgAutoType.CloneDeep();
peNew.m_lHistory = m_lHistory.CloneDeep();
peNew.m_listStrings = m_listStrings.CloneDeep();
peNew.m_listBinaries = m_listBinaries.CloneDeep();
peNew.m_listAutoType = m_listAutoType.CloneDeep();
peNew.m_listHistory = m_listHistory.CloneDeep();
peNew.m_pwIcon = m_pwIcon;
peNew.m_puCustomIcon = m_puCustomIcon;
peNew.m_pwCustomIconID = m_pwCustomIconID;
peNew.m_clrForeground = m_clrForeground;
peNew.m_clrBackground = m_clrBackground;
@@ -407,9 +389,8 @@ namespace KeePassLib
peNew.m_uUsageCount = m_uUsageCount;
peNew.m_strOverrideUrl = m_strOverrideUrl;
peNew.m_bQualityCheck = m_bQualityCheck;
peNew.m_lTags.AddRange(m_lTags);
peNew.m_vTags = new List<string>(m_vTags);
peNew.m_dCustomData = m_dCustomData.CloneDeep();
@@ -476,29 +457,27 @@ namespace KeePassLib
if (m_pParentGroup != pe.m_pParentGroup) return false;
if (!bIgnoreLastMod && (m_tParentGroupLastMod != pe.m_tParentGroupLastMod))
return false;
if (!m_puPrevParentGroup.Equals(pe.m_puPrevParentGroup))
return false;
}
if (!m_dStrings.EqualsDictionary(pe.m_dStrings, pwOpt, mpCmpStr))
if (!m_listStrings.EqualsDictionary(pe.m_listStrings, pwOpt, mpCmpStr))
return false;
if (!m_dBinaries.EqualsDictionary(pe.m_dBinaries)) return false;
if (!m_listBinaries.EqualsDictionary(pe.m_listBinaries)) return false;
if (!m_cfgAutoType.Equals(pe.m_cfgAutoType)) return false;
if (!m_listAutoType.Equals(pe.m_listAutoType)) return false;
if ((pwOpt & PwCompareOptions.IgnoreHistory) == PwCompareOptions.None)
{
bool bIgnoreLastBackup = ((pwOpt & PwCompareOptions.IgnoreLastBackup) !=
PwCompareOptions.None);
if (!bIgnoreLastBackup && (m_lHistory.UCount != pe.m_lHistory.UCount))
if (!bIgnoreLastBackup && (m_listHistory.UCount != pe.m_listHistory.UCount))
return false;
if (bIgnoreLastBackup && (m_lHistory.UCount == 0))
if (bIgnoreLastBackup && (m_listHistory.UCount == 0))
{
Debug.Assert(false);
return false;
}
if (bIgnoreLastBackup && ((m_lHistory.UCount - 1) != pe.m_lHistory.UCount))
if (bIgnoreLastBackup && ((m_listHistory.UCount - 1) != pe.m_listHistory.UCount))
return false;
PwCompareOptions cmpSub = PwCompareOptions.IgnoreParentGroup;
@@ -506,16 +485,16 @@ namespace KeePassLib
if (bIgnoreLastMod) cmpSub |= PwCompareOptions.IgnoreLastMod;
if (bIgnoreLastAccess) cmpSub |= PwCompareOptions.IgnoreLastAccess;
for (uint uHist = 0; uHist < pe.m_lHistory.UCount; ++uHist)
for (uint uHist = 0; uHist < pe.m_listHistory.UCount; ++uHist)
{
if (!m_lHistory.GetAt(uHist).EqualsEntry(pe.m_lHistory.GetAt(
if (!m_listHistory.GetAt(uHist).EqualsEntry(pe.m_listHistory.GetAt(
uHist), cmpSub, MemProtCmpMode.None))
return false;
}
}
if (m_pwIcon != pe.m_pwIcon) return false;
if (!m_puCustomIcon.Equals(pe.m_puCustomIcon)) return false;
if (!m_pwCustomIconID.Equals(pe.m_pwCustomIconID)) return false;
if (m_clrForeground != pe.m_clrForeground) return false;
if (m_clrBackground != pe.m_clrBackground) return false;
@@ -528,10 +507,12 @@ namespace KeePassLib
if (!bIgnoreLastAccess && (m_uUsageCount != pe.m_uUsageCount)) return false;
if (m_strOverrideUrl != pe.m_strOverrideUrl) return false;
if (m_bQualityCheck != pe.m_bQualityCheck) return false;
// The Tags property normalizes
if (!MemUtil.ListsEqual<string>(this.Tags, pe.Tags)) return false;
if (m_vTags.Count != pe.m_vTags.Count) return false;
for (int iTag = 0; iTag < m_vTags.Count; ++iTag)
{
if (m_vTags[iTag] != pe.m_vTags[iTag]) return false;
}
if (!m_dCustomData.Equals(pe.m_dCustomData)) return false;
@@ -562,19 +543,16 @@ namespace KeePassLib
m_uuid = peTemplate.m_uuid;
if (bAssignLocationChanged)
{
m_tParentGroupLastMod = peTemplate.m_tParentGroupLastMod;
m_puPrevParentGroup = peTemplate.m_puPrevParentGroup;
}
m_dStrings = peTemplate.m_dStrings.CloneDeep();
m_dBinaries = peTemplate.m_dBinaries.CloneDeep();
m_cfgAutoType = peTemplate.m_cfgAutoType.CloneDeep();
m_listStrings = peTemplate.m_listStrings.CloneDeep();
m_listBinaries = peTemplate.m_listBinaries.CloneDeep();
m_listAutoType = peTemplate.m_listAutoType.CloneDeep();
if (bIncludeHistory)
m_lHistory = peTemplate.m_lHistory.CloneDeep();
m_listHistory = peTemplate.m_listHistory.CloneDeep();
m_pwIcon = peTemplate.m_pwIcon;
m_puCustomIcon = peTemplate.m_puCustomIcon; // Immutable
m_pwCustomIconID = peTemplate.m_pwCustomIconID; // Immutable
m_clrForeground = peTemplate.m_clrForeground;
m_clrBackground = peTemplate.m_clrBackground;
@@ -587,9 +565,8 @@ namespace KeePassLib
m_uUsageCount = peTemplate.m_uUsageCount;
m_strOverrideUrl = peTemplate.m_strOverrideUrl;
m_bQualityCheck = peTemplate.m_bQualityCheck;
m_lTags = new List<string>(peTemplate.m_lTags);
m_vTags = new List<string>(peTemplate.m_vTags);
m_dCustomData = peTemplate.m_dCustomData.CloneDeep();
}
@@ -652,9 +629,9 @@ namespace KeePassLib
public void CreateBackup(PwDatabase pwHistMntcSettings)
{
PwEntry peCopy = CloneDeep();
peCopy.m_lHistory.Clear();
peCopy.History = new PwObjectList<PwEntry>(); // Remove history
m_lHistory.Add(peCopy); // Must be added at end, see EqualsEntry
m_listHistory.Add(peCopy); // Must be added at end, see EqualsEntry
if (pwHistMntcSettings != null) MaintainBackups(pwHistMntcSettings);
}
@@ -681,14 +658,12 @@ namespace KeePassLib
/// This parameter may be <c>null</c> (no maintenance then).</param>
public void RestoreFromBackup(uint uBackupIndex, PwDatabase pwHistMntcSettings)
{
if (uBackupIndex >= m_lHistory.UCount)
{
Debug.Assert(false);
Debug.Assert(uBackupIndex < m_listHistory.UCount);
if (uBackupIndex >= m_listHistory.UCount)
throw new ArgumentOutOfRangeException("uBackupIndex");
}
PwEntry pe = m_lHistory.GetAt(uBackupIndex);
if (pe == null) { Debug.Assert(false); throw new InvalidOperationException(); }
PwEntry pe = m_listHistory.GetAt(uBackupIndex);
Debug.Assert(pe != null); if (pe == null) throw new InvalidOperationException();
CreateBackup(pwHistMntcSettings); // Backup current data before restoring
AssignProperties(pe, false, false, false);
@@ -704,7 +679,7 @@ namespace KeePassLib
if (bIgnoreLastMod) cmpOpt |= PwCompareOptions.IgnoreLastMod;
if (bIgnoreLastAccess) cmpOpt |= PwCompareOptions.IgnoreLastAccess;
foreach (PwEntry pe in m_lHistory)
foreach (PwEntry pe in m_listHistory)
{
if (pe.EqualsEntry(peData, cmpOpt, MemProtCmpMode.None)) return true;
}
@@ -713,28 +688,21 @@ namespace KeePassLib
}
/// <summary>
/// Delete old history entries if there are too many or the
/// history size is too large.
/// <returns>If one or more history entries have been deleted,
/// <c>true</c> is returned. Otherwise <c>false</c>.</returns>
/// Delete old history items if there are too many or the history
/// size is too large.
/// <returns>If one or more history items have been deleted, <c>true</c>
/// is returned. Otherwise <c>false</c>.</returns>
/// </summary>
public bool MaintainBackups(PwDatabase pwSettings)
{
if (pwSettings == null) { Debug.Assert(false); return false; }
// Fix UUIDs of history entries; should not be necessary
PwUuid pu = m_uuid;
foreach (PwEntry pe in m_lHistory)
{
if (!pe.Uuid.Equals(pu)) { Debug.Assert(false); pe.Uuid = pu; }
}
bool bDeleted = false;
int nMaxItems = pwSettings.HistoryMaxItems;
if (nMaxItems >= 0)
{
while (m_lHistory.UCount > (uint)nMaxItems)
while (m_listHistory.UCount > (uint)nMaxItems)
{
RemoveOldestBackup();
bDeleted = true;
@@ -747,7 +715,7 @@ namespace KeePassLib
while (true)
{
ulong uHistSize = 0;
foreach (PwEntry pe in m_lHistory) { uHistSize += pe.GetSize(); }
foreach (PwEntry pe in m_listHistory) { uHistSize += pe.GetSize(); }
if (uHistSize > (ulong)lMaxSize)
{
@@ -766,9 +734,9 @@ namespace KeePassLib
DateTime dtMin = TimeUtil.SafeMaxValueUtc;
uint idxRemove = uint.MaxValue;
for (uint u = 0; u < m_lHistory.UCount; ++u)
for (uint u = 0; u < m_listHistory.UCount; ++u)
{
PwEntry pe = m_lHistory.GetAt(u);
PwEntry pe = m_listHistory.GetAt(u);
if (TimeUtil.Compare(pe.LastModificationTime, dtMin, true) < 0)
{
idxRemove = u;
@@ -776,12 +744,12 @@ namespace KeePassLib
}
}
if (idxRemove != uint.MaxValue) m_lHistory.RemoveAt(idxRemove);
if (idxRemove != uint.MaxValue) m_listHistory.RemoveAt(idxRemove);
}
public bool GetAutoTypeEnabled()
{
if (!m_cfgAutoType.Enabled) return false;
if (!m_listAutoType.Enabled) return false;
if (m_pParentGroup != null)
return m_pParentGroup.GetAutoTypeEnabledInherited();
@@ -791,7 +759,7 @@ namespace KeePassLib
public string GetAutoTypeSequence()
{
string strSeq = m_cfgAutoType.DefaultSequence;
string strSeq = m_listAutoType.DefaultSequence;
PwGroup pg = m_pParentGroup;
while (pg != null)
@@ -817,67 +785,69 @@ namespace KeePassLib
}
/// <summary>
/// Approximate the total size (in process memory) of this entry
/// in bytes (including strings, binaries and history entries).
/// Approximate the total size of this entry in bytes (including
/// strings, binaries and history entries).
/// </summary>
/// <returns>Size in bytes.</returns>
public ulong GetSize()
{
// This method assumes 64-bit pointers/references and Unicode
// strings (i.e. 2 bytes per character)
ulong uSize = 128; // Approx fixed length data
ulong cb = 276; // Number of bytes; approx. fixed length data
ulong cc = 0; // Number of characters
cb += (ulong)m_dStrings.UCount * 40;
foreach (KeyValuePair<string, ProtectedString> kvpStr in m_dStrings)
cc += (ulong)kvpStr.Key.Length + (ulong)kvpStr.Value.Length;
cb += (ulong)m_dBinaries.UCount * 65;
foreach (KeyValuePair<string, ProtectedBinary> kvpBin in m_dBinaries)
foreach (KeyValuePair<string, ProtectedString> kvpStr in m_listStrings)
{
cc += (ulong)kvpBin.Key.Length;
cb += (ulong)kvpBin.Value.Length;
uSize += (ulong)kvpStr.Key.Length;
uSize += (ulong)kvpStr.Value.Length;
}
cc += (ulong)m_cfgAutoType.DefaultSequence.Length;
cb += (ulong)m_cfgAutoType.AssociationsCount * 24;
foreach (AutoTypeAssociation a in m_cfgAutoType.Associations)
cc += (ulong)a.WindowName.Length + (ulong)a.Sequence.Length;
foreach (KeyValuePair<string, ProtectedBinary> kvpBin in m_listBinaries)
{
uSize += (ulong)kvpBin.Key.Length;
uSize += kvpBin.Value.Length;
}
cb += (ulong)m_lHistory.UCount * 8;
foreach (PwEntry peHistory in m_lHistory)
cb += peHistory.GetSize();
uSize += (ulong)m_listAutoType.DefaultSequence.Length;
foreach (AutoTypeAssociation a in m_listAutoType.Associations)
{
uSize += (ulong)a.WindowName.Length;
uSize += (ulong)a.Sequence.Length;
}
cc += (ulong)m_strOverrideUrl.Length;
foreach (PwEntry peHistory in m_listHistory)
uSize += peHistory.GetSize();
cb += (ulong)m_lTags.Count * 8;
foreach (string strTag in m_lTags)
cc += (ulong)strTag.Length;
uSize += (ulong)m_strOverrideUrl.Length;
foreach (string strTag in m_vTags)
uSize += (ulong)strTag.Length;
cb += (ulong)m_dCustomData.Count * 16;
foreach (KeyValuePair<string, string> kvp in m_dCustomData)
cc += (ulong)kvp.Key.Length + (ulong)kvp.Value.Length;
uSize += (ulong)kvp.Key.Length + (ulong)kvp.Value.Length;
return (cb + (cc << 1));
return uSize;
}
public bool HasTag(string strTag)
{
if (string.IsNullOrEmpty(strTag)) { Debug.Assert(false); return false; }
// this.Tags normalizes
return this.Tags.Contains(StrUtil.NormalizeTag(strTag));
for (int i = 0; i < m_vTags.Count; ++i)
{
if (m_vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp)) return true;
}
return false;
}
public bool AddTag(string strTag)
{
if (string.IsNullOrEmpty(strTag)) { Debug.Assert(false); return false; }
strTag = StrUtil.NormalizeTag(strTag);
if (this.Tags.Contains(strTag)) return false; // this.Tags normalizes
for (int i = 0; i < m_vTags.Count; ++i)
{
if (m_vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp)) return false;
}
m_lTags.Add(strTag);
m_vTags.Add(strTag);
return true;
}
@@ -885,17 +855,16 @@ namespace KeePassLib
{
if (string.IsNullOrEmpty(strTag)) { Debug.Assert(false); return false; }
// this.Tags normalizes
return this.Tags.Remove(StrUtil.NormalizeTag(strTag));
for (int i = 0; i < m_vTags.Count; ++i)
{
if (m_vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp))
{
m_vTags.RemoveAt(i);
return true;
}
}
internal List<string> GetTagsInherited()
{
List<string> l = ((m_pParentGroup != null) ?
m_pParentGroup.GetTagsInherited(false) : new List<string>());
l.AddRange(this.Tags);
StrUtil.NormalizeTags(l);
return l;
return false;
}
public bool IsContainedIn(PwGroup pgContainer)
@@ -917,10 +886,12 @@ namespace KeePassLib
if (bAlsoChangeHistoryUuids)
{
foreach (PwEntry peHist in m_lHistory)
foreach (PwEntry peHist in m_listHistory)
{
peHist.Uuid = pwNewUuid;
}
}
}
public void SetCreatedNow()
{

View File

@@ -316,13 +316,4 @@ namespace KeePassLib
Cinnamon,
Pantheon
}
public enum PwSearchMode
{
None = 0,
Simple,
Regular,
XPath
}
}

View File

@@ -1,372 +0,0 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.XPath;
using KeePassLib.Collections;
using KeePassLib.Delegates;
using KeePassLib.Interfaces;
using KeePassLib.Security;
using KeePassLib.Serialization;
using KeePassLib.Utility;
namespace KeePassLib
{
public sealed partial class PwGroup
{
private const int SearchContextStringMaxLength = 50; // Note, doesn't include elipsis, if added
public const string SearchContextUuid = "Uuid";
public const string SearchContextParentGroup = "Parent Group";
public const string SearchContextTags = "Tags";
/// <summary>
/// Search this group and all subgroups for entries.
/// </summary>
/// <param name="sp">Specifies the search method.</param>
/// <param name="listStorage">Entry list in which the search results will
/// be stored.</param>
public void SearchEntries(SearchParameters sp, PwObjectList<PwEntry> listStorage)
{
SearchEntries(sp, listStorage, null);
}
/// <summary>
/// Search this group and all subgroups for entries.
/// </summary>
/// <param name="sp">Specifies the search method.</param>
/// <param name="listStorage">Entry list in which the search results will
/// be stored.</param>
/// <param name="slStatus">Optional status reporting object.</param>
public void SearchEntries(SearchParameters sp, PwObjectList<PwEntry> listStorage,
IStatusLogger slStatus)
{
SearchEntries(sp, listStorage, null, slStatus);
}
/// <summary>
/// Search this group and all subgroups for entries.
/// </summary>
/// <param name="sp">Specifies the search method.</param>
/// <param name="listStorage">Entry list in which the search results will
/// be stored.</param>
/// <param name="resultContexts">Dictionary that will be populated with text fragments indicating the context of why each entry (keyed by Uuid) was returned</param>
public void SearchEntries(SearchParameters sp, PwObjectList<PwEntry> listStorage,
IDictionary<PwUuid, KeyValuePair<string, string>> resultContexts,
IStatusLogger slStatus)
{
if (sp == null)
{
Debug.Assert(false);
return;
}
if (listStorage == null)
{
Debug.Assert(false);
return;
}
ulong uCurEntries = 0, uTotalEntries = 0;
List<string> lTerms = StrUtil.SplitSearchTerms(sp.SearchString);
if ((lTerms.Count <= 1) || sp.RegularExpression)
{
if (slStatus != null) uTotalEntries = GetEntriesCount(true);
SearchEntriesSingle(sp, listStorage, resultContexts, slStatus, ref uCurEntries,
uTotalEntries);
return;
}
// Search longer strings first (for improved performance)
lTerms.Sort(StrUtil.CompareLengthGt);
string strFullSearch = sp.SearchString; // Backup
PwGroup pg = this;
for (int iTerm = 0; iTerm < lTerms.Count; ++iTerm)
{
// Update counters for a better state guess
if (slStatus != null)
{
ulong uRemRounds = (ulong) (lTerms.Count - iTerm);
uTotalEntries = uCurEntries + (uRemRounds *
pg.GetEntriesCount(true));
}
PwGroup pgNew = new PwGroup();
sp.SearchString = lTerms[iTerm];
bool bNegate = false;
if (sp.SearchString.StartsWith("-"))
{
sp.SearchString = sp.SearchString.Substring(1);
bNegate = (sp.SearchString.Length > 0);
}
if (!pg.SearchEntriesSingle(sp, pgNew.Entries, resultContexts, slStatus,
ref uCurEntries, uTotalEntries))
{
pg = null;
break;
}
if (bNegate)
{
PwObjectList<PwEntry> lCand = pg.GetEntries(true);
pg = new PwGroup();
foreach (PwEntry peCand in lCand)
{
if (pgNew.Entries.IndexOf(peCand) < 0) pg.Entries.Add(peCand);
}
}
else pg = pgNew;
}
if (pg != null) listStorage.Add(pg.Entries);
sp.SearchString = strFullSearch; // Restore
}
private bool SearchEntriesSingle(SearchParameters spIn,
PwObjectList<PwEntry> listStorage, IDictionary<PwUuid, KeyValuePair<string, string>> resultContexts,
IStatusLogger slStatus,
ref ulong uCurEntries, ulong uTotalEntries)
{
SearchParameters sp = spIn.Clone();
if (sp.SearchString == null)
{
Debug.Assert(false);
return true;
}
sp.SearchString = sp.SearchString.Trim();
bool bTitle = sp.SearchInTitles;
bool bUserName = sp.SearchInUserNames;
bool bPassword = sp.SearchInPasswords;
bool bUrl = sp.SearchInUrls;
bool bNotes = sp.SearchInNotes;
bool bOther = sp.SearchInOther;
bool bUuids = sp.SearchInUuids;
bool bGroupName = sp.SearchInGroupNames;
bool bTags = sp.SearchInTags;
bool bExcludeExpired = sp.ExcludeExpired;
bool bRespectEntrySearchingDisabled = sp.RespectEntrySearchingDisabled;
DateTime dtNow = DateTime.Now;
Regex rx = null;
if (sp.RegularExpression)
{
RegexOptions ro = RegexOptions.None; // RegexOptions.Compiled
if ((sp.ComparisonMode == StringComparison.CurrentCultureIgnoreCase) ||
#if !KeePassUAP
(sp.ComparisonMode == StringComparison.InvariantCultureIgnoreCase) ||
#endif
(sp.ComparisonMode == StringComparison.OrdinalIgnoreCase))
{
ro |= RegexOptions.IgnoreCase;
}
rx = new Regex(sp.SearchString, ro);
}
ulong uLocalCurEntries = uCurEntries;
EntryHandler eh = null;
if (sp.SearchString.Length <= 0) // Report all
{
eh = delegate(PwEntry pe)
{
if (slStatus != null)
{
if (!slStatus.SetProgress((uint) ((uLocalCurEntries *
100UL) / uTotalEntries))) return false;
++uLocalCurEntries;
}
if (bRespectEntrySearchingDisabled && !pe.GetSearchingEnabled())
return true; // Skip
if (bExcludeExpired && pe.Expires && (dtNow > pe.ExpiryTime))
return true; // Skip
listStorage.Add(pe);
return true;
};
}
else
{
eh = delegate(PwEntry pe)
{
if (slStatus != null)
{
if (!slStatus.SetProgress((uint) ((uLocalCurEntries *
100UL) / uTotalEntries))) return false;
++uLocalCurEntries;
}
if (bRespectEntrySearchingDisabled && !pe.GetSearchingEnabled())
return true; // Skip
if (bExcludeExpired && pe.Expires && (dtNow > pe.ExpiryTime))
return true; // Skip
uint uInitialResults = listStorage.UCount;
foreach (KeyValuePair<string, ProtectedString> kvp in pe.Strings)
{
string strKey = kvp.Key;
if (strKey == PwDefs.TitleField)
{
if (bTitle)
SearchEvalAdd(sp, kvp.Value.ReadString(),
rx, pe, listStorage, resultContexts, strKey);
}
else if (strKey == PwDefs.UserNameField)
{
if (bUserName)
SearchEvalAdd(sp, kvp.Value.ReadString(),
rx, pe, listStorage, resultContexts, strKey);
}
else if (strKey == PwDefs.PasswordField)
{
if (bPassword)
SearchEvalAdd(sp, kvp.Value.ReadString(),
rx, pe, listStorage, resultContexts, strKey);
}
else if (strKey == PwDefs.UrlField)
{
if (bUrl)
SearchEvalAdd(sp, kvp.Value.ReadString(),
rx, pe, listStorage, resultContexts, strKey);
}
else if (strKey == PwDefs.NotesField)
{
if (bNotes)
SearchEvalAdd(sp, kvp.Value.ReadString(),
rx, pe, listStorage, resultContexts, strKey);
}
else if (bOther)
SearchEvalAdd(sp, kvp.Value.ReadString(),
rx, pe, listStorage, resultContexts, strKey);
// An entry can match only once => break if we have added it
if (listStorage.UCount > uInitialResults) break;
}
if (bUuids && (listStorage.UCount == uInitialResults))
SearchEvalAdd(sp, pe.Uuid.ToHexString(), rx, pe, listStorage, resultContexts,
SearchContextTags);
if (bGroupName && (listStorage.UCount == uInitialResults) &&
(pe.ParentGroup != null))
SearchEvalAdd(sp, pe.ParentGroup.Name, rx, pe, listStorage, resultContexts,
SearchContextParentGroup);
if (bTags)
{
foreach (string strTag in pe.Tags)
{
if (listStorage.UCount != uInitialResults) break; // Match
SearchEvalAdd(sp, strTag, rx, pe, listStorage, resultContexts, SearchContextTags);
}
}
return true;
};
}
if (!PreOrderTraverseTree(null, eh)) return false;
uCurEntries = uLocalCurEntries;
return true;
}
private static void SearchEvalAdd(SearchParameters sp, string strDataField,
Regex rx, PwEntry pe, PwObjectList<PwEntry> lResults,
IDictionary<PwUuid, KeyValuePair<string, string>> resultContexts, string contextFieldName)
{
bool bMatch = false;
int matchPos;
if (rx == null)
{
matchPos = strDataField.IndexOf(sp.SearchString, sp.ComparisonMode);
bMatch = matchPos >= 0;
}
else
{
var match = rx.Match(strDataField);
bMatch = match.Success;
matchPos = match.Index;
}
if (!bMatch && (sp.DataTransformationFn != null))
{
string strCmp = sp.DataTransformationFn(strDataField, pe);
if (!object.ReferenceEquals(strCmp, strDataField))
{
if (rx == null)
{
matchPos = strCmp.IndexOf(sp.SearchString, sp.ComparisonMode);
bMatch = matchPos >= 0;
}
else
{
var match = rx.Match(strCmp);
bMatch = match.Success;
matchPos = match.Index;
}
}
}
if (bMatch)
{
lResults.Add(pe);
if (resultContexts != null)
{
// Trim the value if necessary
var contextString = strDataField;
if (contextString.Length > SearchContextStringMaxLength)
{
// Start 10% before actual data, and don't run over
var startPos = Math.Max(0,
Math.Min(matchPos - (SearchContextStringMaxLength / 10),
contextString.Length - SearchContextStringMaxLength));
contextString = "… " + contextString.Substring(startPos, SearchContextStringMaxLength) +
((startPos + SearchContextStringMaxLength < contextString.Length)
? " …"
: null);
}
resultContexts[pe.Uuid] = new KeyValuePair<string, string>(contextFieldName, contextString);
}
}
}
}
}

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,36 +20,35 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
using KeePassLib.Collections;
using KeePassLib.Delegates;
using KeePassLib.Interfaces;
using KeePassLib.Resources;
using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib
{
/// <summary>
/// A group containing subgroups and entries.
/// A group containing several password entries.
/// </summary>
public sealed partial class PwGroup : ITimeLogger, IStructureItem, IDeepCloneable<PwGroup>
public sealed class PwGroup : ITimeLogger, IStructureItem, IDeepCloneable<PwGroup>
{
private const int SearchContextStringMaxLength = 50; // Note, doesn't include elipsis, if added
public const string SearchContextUuid = "Uuid";
public const string SearchContextParentGroup = "Parent Group";
public const string SearchContextTags = "Tags";
public const bool DefaultAutoTypeEnabled = true;
public const bool DefaultSearchingEnabled = true;
// In the tree view of Windows 10, the X coordinate is reset
// to 0 after 256 nested nodes
private const uint MaxDepth = 126; // Depth 126 = level 127 < 256/2
private PwUuid m_uuid = PwUuid.Zero;
private PwGroup m_pParentGroup = null;
private DateTime m_tParentGroupLastMod = PwDefs.DtDefaultNow;
private PwUuid m_puPrevParentGroup = PwUuid.Zero;
private PwObjectList<PwGroup> m_listGroups = new PwObjectList<PwGroup>();
private PwObjectList<PwEntry> m_listEntries = new PwObjectList<PwEntry>();
private PwGroup m_pParentGroup = null;
private DateTime m_tParentGroupLastMod = PwDefs.DtDefaultNow;
private PwUuid m_uuid = PwUuid.Zero;
private string m_strName = string.Empty;
private string m_strNotes = string.Empty;
@@ -73,8 +72,6 @@ namespace KeePassLib
private PwUuid m_pwLastTopVisibleEntry = PwUuid.Zero;
private List<string> m_lTags = new List<string>();
private StringDictionaryEx m_dCustomData = new StringDictionaryEx();
/// <summary>
@@ -85,42 +82,11 @@ namespace KeePassLib
get { return m_uuid; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
m_uuid = value;
}
}
/// <summary>
/// Reference to the group to which this group belongs. May be <c>null</c>.
/// </summary>
public PwGroup ParentGroup
{
get { return m_pParentGroup; }
// Plugins: use the PwGroup.AddGroup method instead.
// Internal: check depth using CanAddGroup/CheckCanAddGroup.
internal set { Debug.Assert(value != this); m_pParentGroup = value; }
}
/// <summary>
/// The date/time when the location of the object was last changed.
/// </summary>
public DateTime LocationChanged
{
get { return m_tParentGroupLastMod; }
set { m_tParentGroupLastMod = value; }
}
public PwUuid PreviousParentGroup
{
get { return m_puPrevParentGroup; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
m_puPrevParentGroup = value;
}
}
/// <summary>
/// The name of this group. Cannot be <c>null</c>.
/// </summary>
@@ -129,7 +95,7 @@ namespace KeePassLib
get { return m_strName; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
m_strName = value;
}
}
@@ -142,7 +108,7 @@ namespace KeePassLib
get { return m_strNotes; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
m_strNotes = value;
}
}
@@ -166,11 +132,31 @@ namespace KeePassLib
get { return m_pwCustomIconID; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
m_pwCustomIconID = value;
}
}
/// <summary>
/// Reference to the group to which this group belongs. May be <c>null</c>.
/// </summary>
public PwGroup ParentGroup
{
get { return m_pParentGroup; }
// Plugins: use <c>PwGroup.AddGroup</c> instead.
internal set { Debug.Assert(value != this); m_pParentGroup = value; }
}
/// <summary>
/// The date/time when the location of the object was last changed.
/// </summary>
public DateTime LocationChanged
{
get { return m_tParentGroupLastMod; }
set { m_tParentGroupLastMod = value; }
}
/// <summary>
/// A flag that specifies if the group is shown as expanded or
/// collapsed in the user interface.
@@ -275,7 +261,7 @@ namespace KeePassLib
get { return m_strDefaultAutoTypeSequence; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
m_strDefaultAutoTypeSequence = value;
}
}
@@ -297,21 +283,11 @@ namespace KeePassLib
get { return m_pwLastTopVisibleEntry; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
Debug.Assert(value != null); if (value == null) throw new ArgumentNullException("value");
m_pwLastTopVisibleEntry = value;
}
}
public List<string> Tags
{
get { StrUtil.NormalizeTags(m_lTags); return m_lTags; }
set
{
if (value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); }
m_lTags = value;
}
}
/// <summary>
/// Custom data container that can be used by plugins to store
/// own data in KeePass groups.
@@ -350,11 +326,8 @@ namespace KeePassLib
if (bSetTimes)
{
DateTime dtNow = DateTime.UtcNow;
m_tCreation = dtNow;
m_tLastMod = dtNow;
m_tLastAccess = dtNow;
m_tParentGroupLastMod = dtNow;
m_tCreation = m_tLastMod = m_tLastAccess =
m_tParentGroupLastMod = DateTime.Now;
}
}
@@ -371,11 +344,8 @@ namespace KeePassLib
if (bSetTimes)
{
DateTime dtNow = DateTime.UtcNow;
m_tCreation = dtNow;
m_tLastMod = dtNow;
m_tLastAccess = dtNow;
m_tParentGroupLastMod = dtNow;
m_tCreation = m_tLastMod = m_tLastAccess =
m_tParentGroupLastMod = DateTime.Now;
}
if (strName != null) m_strName = strName;
@@ -404,11 +374,8 @@ namespace KeePassLib
pg.m_listGroups = m_listGroups.CloneDeep();
pg.m_listEntries = m_listEntries.CloneDeep();
pg.TakeOwnership(true, true, false);
pg.m_pParentGroup = m_pParentGroup;
pg.m_tParentGroupLastMod = m_tParentGroupLastMod;
pg.m_puPrevParentGroup = m_puPrevParentGroup;
pg.m_strName = m_strName;
pg.m_strNotes = m_strNotes;
@@ -433,8 +400,6 @@ namespace KeePassLib
pg.m_pwLastTopVisibleEntry = m_pwLastTopVisibleEntry;
pg.m_lTags.AddRange(m_lTags);
pg.m_dCustomData = m_dCustomData.CloneDeep();
return pg;
@@ -473,8 +438,6 @@ namespace KeePassLib
if (m_pParentGroup != pg.m_pParentGroup) return false;
if (!bIgnoreLastMod && (m_tParentGroupLastMod != pg.m_tParentGroupLastMod))
return false;
if (!m_puPrevParentGroup.Equals(pg.m_puPrevParentGroup))
return false;
}
if (m_strName != pg.m_strName) return false;
@@ -507,9 +470,6 @@ namespace KeePassLib
if (!m_pwLastTopVisibleEntry.Equals(pg.m_pwLastTopVisibleEntry)) return false;
// The Tags property normalizes
if (!MemUtil.ListsEqual<string>(this.Tags, pg.Tags)) return false;
if (!m_dCustomData.Equals(pg.m_dCustomData)) return false;
if ((pwOpt & PwCompareOptions.PropertiesOnly) == PwCompareOptions.None)
@@ -556,10 +516,7 @@ namespace KeePassLib
m_uuid = pgTemplate.m_uuid;
if(bAssignLocationChanged)
{
m_tParentGroupLastMod = pgTemplate.m_tParentGroupLastMod;
m_puPrevParentGroup = pgTemplate.m_puPrevParentGroup;
}
m_strName = pgTemplate.m_strName;
m_strNotes = pgTemplate.m_strNotes;
@@ -581,8 +538,6 @@ namespace KeePassLib
m_pwLastTopVisibleEntry = pgTemplate.m_pwLastTopVisibleEntry;
m_lTags = new List<string>(pgTemplate.m_lTags);
m_dCustomData = pgTemplate.m_dCustomData.CloneDeep();
}
@@ -607,7 +562,7 @@ namespace KeePassLib
/// get touched, too.</param>
public void Touch(bool bModified, bool bTouchParents)
{
m_tLastAccess = DateTime.UtcNow;
m_tLastAccess = DateTime.Now;
++m_uUsageCount;
if(bModified) m_tLastMod = m_tLastAccess;
@@ -712,15 +667,21 @@ namespace KeePassLib
}
}
foreach (PwGroup pg in m_listGroups)
{
if(groupHandler != null)
{
foreach(PwGroup pg in m_listGroups)
{
if(!groupHandler(pg)) return false;
}
if (!pg.PreOrderTraverseTree(groupHandler, entryHandler))
return false;
pg.PreOrderTraverseTree(groupHandler, entryHandler);
}
}
else // groupHandler == null
{
foreach(PwGroup pg in m_listGroups)
{
pg.PreOrderTraverseTree(null, entryHandler);
}
}
return true;
@@ -807,95 +768,357 @@ namespace KeePassLib
return PreOrderTraverseTree(null, eh);
}
internal List<string> GetTagsInherited(bool bNormalize)
/// <summary>
/// Search this group and all subgroups for entries.
/// </summary>
/// <param name="sp">Specifies the search method.</param>
/// <param name="listStorage">Entry list in which the search results will
/// be stored.</param>
public void SearchEntries(SearchParameters sp, PwObjectList<PwEntry> listStorage)
{
List<string> l = new List<string>();
PwGroup pg = this;
while (pg != null)
{
l.AddRange(pg.Tags);
pg = pg.m_pParentGroup;
SearchEntries(sp, listStorage, null);
}
if (bNormalize) StrUtil.NormalizeTags(l);
return l;
/// <summary>
/// Search this group and all subgroups for entries.
/// </summary>
/// <param name="sp">Specifies the search method.</param>
/// <param name="listStorage">Entry list in which the search results will
/// be stored.</param>
/// <param name="slStatus">Optional status reporting object.</param>
public void SearchEntries(SearchParameters sp, PwObjectList<PwEntry> listStorage,
IStatusLogger slStatus)
{
SearchEntries(sp, listStorage, null, slStatus);
}
/// <summary>
/// Search this group and all subgroups for entries.
/// </summary>
/// <param name="sp">Specifies the search method.</param>
/// <param name="listStorage">Entry list in which the search results will
/// be stored.</param>
/// <param name="resultContexts">Dictionary that will be populated with text fragments indicating the context of why each entry (keyed by Uuid) was returned</param>
public void SearchEntries(SearchParameters sp, PwObjectList<PwEntry> listStorage, IDictionary<PwUuid, KeyValuePair<string, string>> resultContexts,
IStatusLogger slStatus)
{
if (sp == null) { Debug.Assert(false); return; }
if (listStorage == null) { Debug.Assert(false); return; }
ulong uCurEntries = 0, uTotalEntries = 0;
List<string> lTerms = StrUtil.SplitSearchTerms(sp.SearchString);
if ((lTerms.Count <= 1) || sp.RegularExpression)
{
if (slStatus != null) uTotalEntries = GetEntriesCount(true);
SearchEntriesSingle(sp, listStorage, resultContexts, slStatus, ref uCurEntries,
uTotalEntries);
return;
}
// Search longer strings first (for improved performance)
lTerms.Sort(StrUtil.CompareLengthGt);
string strFullSearch = sp.SearchString; // Backup
PwGroup pg = this;
for (int iTerm = 0; iTerm < lTerms.Count; ++iTerm)
{
// Update counters for a better state guess
if (slStatus != null)
{
ulong uRemRounds = (ulong)(lTerms.Count - iTerm);
uTotalEntries = uCurEntries + (uRemRounds *
pg.GetEntriesCount(true));
}
PwGroup pgNew = new PwGroup();
sp.SearchString = lTerms[iTerm];
bool bNegate = false;
if (sp.SearchString.StartsWith("-"))
{
sp.SearchString = sp.SearchString.Substring(1);
bNegate = (sp.SearchString.Length > 0);
}
if (!pg.SearchEntriesSingle(sp, pgNew.Entries, resultContexts, slStatus,
ref uCurEntries, uTotalEntries))
{
pg = null;
break;
}
if (bNegate)
{
PwObjectList<PwEntry> lCand = pg.GetEntries(true);
pg = new PwGroup();
foreach (PwEntry peCand in lCand)
{
if (pgNew.Entries.IndexOf(peCand) < 0) pg.Entries.Add(peCand);
}
}
else pg = pgNew;
}
if (pg != null) listStorage.Add(pg.Entries);
sp.SearchString = strFullSearch; // Restore
}
private bool SearchEntriesSingle(SearchParameters spIn,
PwObjectList<PwEntry> listStorage, IDictionary<PwUuid, KeyValuePair<string, string>> resultContexts, IStatusLogger slStatus,
ref ulong uCurEntries, ulong uTotalEntries)
{
SearchParameters sp = spIn.Clone();
if (sp.SearchString == null) { Debug.Assert(false); return true; }
sp.SearchString = sp.SearchString.Trim();
bool bTitle = sp.SearchInTitles;
bool bUserName = sp.SearchInUserNames;
bool bPassword = sp.SearchInPasswords;
bool bUrl = sp.SearchInUrls;
bool bNotes = sp.SearchInNotes;
bool bOther = sp.SearchInOther;
bool bUuids = sp.SearchInUuids;
bool bGroupName = sp.SearchInGroupNames;
bool bTags = sp.SearchInTags;
bool bExcludeExpired = sp.ExcludeExpired;
bool bRespectEntrySearchingDisabled = sp.RespectEntrySearchingDisabled;
DateTime dtNow = DateTime.Now;
Regex rx = null;
if (sp.RegularExpression)
{
RegexOptions ro = RegexOptions.None; // RegexOptions.Compiled
if ((sp.ComparisonMode == StringComparison.CurrentCultureIgnoreCase) ||
#if !KeePassUAP
(sp.ComparisonMode == StringComparison.InvariantCultureIgnoreCase) ||
#endif
(sp.ComparisonMode == StringComparison.OrdinalIgnoreCase))
{
ro |= RegexOptions.IgnoreCase;
}
rx = new Regex(sp.SearchString, ro);
}
ulong uLocalCurEntries = uCurEntries;
EntryHandler eh = null;
if (sp.SearchString.Length <= 0) // Report all
{
eh = delegate(PwEntry pe)
{
if (slStatus != null)
{
if (!slStatus.SetProgress((uint)((uLocalCurEntries *
100UL) / uTotalEntries))) return false;
++uLocalCurEntries;
}
if (bRespectEntrySearchingDisabled && !pe.GetSearchingEnabled())
return true; // Skip
if (bExcludeExpired && pe.Expires && (dtNow > pe.ExpiryTime))
return true; // Skip
listStorage.Add(pe);
return true;
};
}
else
{
eh = delegate(PwEntry pe)
{
if (slStatus != null)
{
if (!slStatus.SetProgress((uint)((uLocalCurEntries *
100UL) / uTotalEntries))) return false;
++uLocalCurEntries;
}
if (bRespectEntrySearchingDisabled && !pe.GetSearchingEnabled())
return true; // Skip
if (bExcludeExpired && pe.Expires && (dtNow > pe.ExpiryTime))
return true; // Skip
uint uInitialResults = listStorage.UCount;
foreach (KeyValuePair<string, ProtectedString> kvp in pe.Strings)
{
string strKey = kvp.Key;
if (strKey == PwDefs.TitleField)
{
if (bTitle) SearchEvalAdd(sp, kvp.Value.ReadString(),
rx, pe, listStorage, resultContexts, strKey);
}
else if (strKey == PwDefs.UserNameField)
{
if (bUserName) SearchEvalAdd(sp, kvp.Value.ReadString(),
rx, pe, listStorage, resultContexts, strKey);
}
else if (strKey == PwDefs.PasswordField)
{
if (bPassword) SearchEvalAdd(sp, kvp.Value.ReadString(),
rx, pe, listStorage, resultContexts, strKey);
}
else if (strKey == PwDefs.UrlField)
{
if (bUrl) SearchEvalAdd(sp, kvp.Value.ReadString(),
rx, pe, listStorage, resultContexts, strKey);
}
else if (strKey == PwDefs.NotesField)
{
if (bNotes) SearchEvalAdd(sp, kvp.Value.ReadString(),
rx, pe, listStorage, resultContexts, strKey);
}
else if (bOther)
SearchEvalAdd(sp, kvp.Value.ReadString(),
rx, pe, listStorage, resultContexts, strKey);
// An entry can match only once => break if we have added it
if (listStorage.UCount > uInitialResults) break;
}
if (bUuids && (listStorage.UCount == uInitialResults))
SearchEvalAdd(sp, pe.Uuid.ToHexString(), rx, pe, listStorage, resultContexts, SearchContextTags);
if (bGroupName && (listStorage.UCount == uInitialResults) &&
(pe.ParentGroup != null))
SearchEvalAdd(sp, pe.ParentGroup.Name, rx, pe, listStorage, resultContexts, SearchContextParentGroup);
if (bTags)
{
foreach (string strTag in pe.Tags)
{
if (listStorage.UCount != uInitialResults) break; // Match
SearchEvalAdd(sp, strTag, rx, pe, listStorage, resultContexts, SearchContextTags);
}
}
return true;
};
}
if (!PreOrderTraverseTree(null, eh)) return false;
uCurEntries = uLocalCurEntries;
return true;
}
private static void SearchEvalAdd(SearchParameters sp, string strDataField,
Regex rx, PwEntry pe, PwObjectList<PwEntry> lResults, IDictionary<PwUuid, KeyValuePair<string, string>> resultContexts, string contextFieldName)
{
bool bMatch = false;
int matchPos;
if (rx == null)
{
matchPos = strDataField.IndexOf(sp.SearchString, sp.ComparisonMode);
bMatch = matchPos >= 0;
}
else
{
var match = rx.Match(strDataField);
bMatch = match.Success;
matchPos = match.Index;
}
if (!bMatch && (sp.DataTransformationFn != null))
{
string strCmp = sp.DataTransformationFn(strDataField, pe);
if (!object.ReferenceEquals(strCmp, strDataField))
{
if (rx == null)
{
matchPos = strCmp.IndexOf(sp.SearchString, sp.ComparisonMode);
bMatch = matchPos >= 0;
}
else
{
var match = rx.Match(strCmp);
bMatch = match.Success;
matchPos = match.Index;
}
}
}
if (bMatch)
{
lResults.Add(pe);
if (resultContexts != null)
{
// Trim the value if necessary
var contextString = strDataField;
if (contextString.Length > SearchContextStringMaxLength)
{
// Start 10% before actual data, and don't run over
var startPos = Math.Max(0, Math.Min(matchPos - (SearchContextStringMaxLength / 10), contextString.Length - SearchContextStringMaxLength));
contextString = "<22> " + contextString.Substring(startPos, SearchContextStringMaxLength) + ((startPos + SearchContextStringMaxLength < contextString.Length) ? " <20>" : null);
}
resultContexts[pe.Uuid] = new KeyValuePair<string, string>(contextFieldName, contextString);
}
}
}
public List<string> BuildEntryTagsList()
{
return BuildEntryTagsList(false, false);
return BuildEntryTagsList(false);
}
public List<string> BuildEntryTagsList(bool bSort)
{
return BuildEntryTagsList(bSort, false);
}
internal List<string> BuildEntryTagsList(bool bSort, bool bGroupTags)
{
Dictionary<string, bool> d = new Dictionary<string, bool>();
GroupHandler gh = null;
if (bGroupTags)
{
gh = delegate (PwGroup pg)
{
foreach (string strTag in pg.Tags) d[strTag] = true;
return true;
};
}
List<string> vTags = new List<string>();
EntryHandler eh = delegate(PwEntry pe)
{
foreach (string strTag in pe.Tags) d[strTag] = true;
foreach (string strTag in pe.Tags)
{
bool bFound = false;
for (int i = 0; i < vTags.Count; ++i)
{
if (vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp))
{
bFound = true;
break;
}
}
if (!bFound) vTags.Add(strTag);
}
return true;
};
if (gh != null) gh(this);
TraverseTree(TraversalMethod.PreOrder, gh, eh);
List<string> l = new List<string>(d.Keys);
if (bSort) l.Sort(StrUtil.CompareNaturally);
return l;
TraverseTree(TraversalMethod.PreOrder, null, eh);
if (bSort) vTags.Sort(StrUtil.CaseIgnoreComparer);
return vTags;
}
#if !KeePassLibSD
public IDictionary<string, uint> BuildEntryTagsDict(bool bSort)
{
Debug.Assert(!bSort); // Obsolete
IDictionary<string, uint> d;
if (!bSort) d = new Dictionary<string, uint>();
else d = new SortedDictionary<string, uint>();
GroupHandler gh = delegate (PwGroup pg)
{
foreach (string strTag in pg.Tags)
{
// For groups without entries
if (!d.ContainsKey(strTag)) d[strTag] = 0;
}
return true;
};
if (!bSort) d = new Dictionary<string, uint>(StrUtil.CaseIgnoreComparer);
else d = new SortedDictionary<string, uint>(StrUtil.CaseIgnoreComparer);
EntryHandler eh = delegate(PwEntry pe)
{
foreach (string strTag in pe.GetTagsInherited())
foreach (string strTag in pe.Tags)
{
uint u;
d.TryGetValue(strTag, out u);
d[strTag] = u + 1;
if (d.TryGetValue(strTag, out u)) d[strTag] = u + 1;
else d[strTag] = 1;
}
return true;
};
gh(this);
TraverseTree(TraversalMethod.PreOrder, gh, eh);
TraverseTree(TraversalMethod.PreOrder, null, eh);
return d;
}
#endif
@@ -904,29 +1127,24 @@ namespace KeePassLib
bool bSearchRecursive)
{
if (strTag == null) throw new ArgumentNullException("strTag");
if (strTag.Length == 0) return;
strTag = StrUtil.NormalizeTag(strTag);
if (string.IsNullOrEmpty(strTag)) return;
EntryHandler eh = delegate (PwEntry pe)
foreach (PwEntry pe in m_listEntries)
{
foreach (string strEntryTag in pe.GetTagsInherited())
foreach (string strEntryTag in pe.Tags)
{
if (strEntryTag == strTag)
if (strEntryTag.Equals(strTag, StrUtil.CaseIgnoreCmp))
{
listStorage.Add(pe);
break;
}
}
return true;
};
}
if (bSearchRecursive)
TraverseTree(TraversalMethod.PreOrder, null, eh);
else
{
foreach (PwEntry pe in m_listEntries) eh(pe);
foreach (PwGroup pg in m_listGroups)
pg.FindEntriesByTag(strTag, listStorage, true);
}
}
@@ -1061,7 +1279,7 @@ namespace KeePassLib
PwGroup pg = m_pParentGroup;
while (pg != null)
{
if (!bIncludeTopMostGroup && (pg.m_pParentGroup == null))
if ((!bIncludeTopMostGroup) && (pg.m_pParentGroup == null))
break;
strPath = pg.Name + strSeparator + strPath;
@@ -1184,34 +1402,21 @@ namespace KeePassLib
#endif
/// <summary>
/// Get the depth of this group (i.e. the number of ancestors).
/// Get the level of the group (i.e. the number of parent groups).
/// </summary>
/// <returns>Depth of this group.</returns>
public uint GetDepth()
/// <returns>Number of parent groups.</returns>
public uint GetLevel()
{
PwGroup pg = m_pParentGroup;
uint d = 0;
uint uLevel = 0;
while (pg != null)
{
pg = pg.m_pParentGroup;
++d;
pg = pg.ParentGroup;
++uLevel;
}
return d;
}
private uint GetHeight()
{
if (m_listGroups.UCount == 0) return 0;
uint h = 0;
foreach (PwGroup pgSub in m_listGroups)
{
h = Math.Max(h, pgSub.GetHeight());
}
return (h + 1);
return uLevel;
}
public string GetAutoTypeSequenceInherited()
@@ -1255,7 +1460,7 @@ namespace KeePassLib
/// subgroups.</returns>
public PwObjectList<PwGroup> GetGroups(bool bRecursive)
{
if (!bRecursive) return m_listGroups;
if (bRecursive == false) return m_listGroups;
PwObjectList<PwGroup> list = m_listGroups.CloneShallow();
foreach (PwGroup pgSub in m_listGroups)
@@ -1268,20 +1473,15 @@ namespace KeePassLib
public PwObjectList<PwEntry> GetEntries(bool bIncludeSubGroupEntries)
{
PwObjectList<PwEntry> l = new PwObjectList<PwEntry>();
if (bIncludeSubGroupEntries == false) return m_listEntries;
GroupHandler gh = delegate (PwGroup pg)
PwObjectList<PwEntry> list = m_listEntries.CloneShallow();
foreach (PwGroup pgSub in m_listGroups)
{
l.Add(pg.Entries);
return true;
};
list.Add(pgSub.GetEntries(true));
}
gh(this);
if (bIncludeSubGroupEntries)
PreOrderTraverseTree(gh, null);
Debug.Assert(l.UCount == GetEntriesCount(bIncludeSubGroupEntries));
return l;
return list;
}
/// <summary>
@@ -1350,29 +1550,11 @@ namespace KeePassLib
{
if (subGroup == null) throw new ArgumentNullException("subGroup");
CheckCanAddGroup(subGroup);
m_listGroups.Add(subGroup);
if (bTakeOwnership) subGroup.ParentGroup = this;
if (bTakeOwnership) subGroup.m_pParentGroup = this;
if (bUpdateLocationChangedOfSub) subGroup.LocationChanged = DateTime.UtcNow;
}
internal bool CanAddGroup(PwGroup pgSub)
{
if (pgSub == null) { Debug.Assert(false); return false; }
uint dCur = GetDepth(), hSub = pgSub.GetHeight();
return ((dCur + hSub + 1) <= MaxDepth);
}
internal void CheckCanAddGroup(PwGroup pgSub)
{
if (!CanAddGroup(pgSub))
{
Debug.Assert(false);
throw new InvalidOperationException(KLRes.StructsTooDeep);
}
if (bUpdateLocationChangedOfSub) subGroup.LocationChanged = DateTime.Now;
}
/// <summary>
@@ -1407,7 +1589,7 @@ namespace KeePassLib
// only assign it to the new one
if (bTakeOwnership) pe.ParentGroup = this;
if (bUpdateLocationChangedOfEntry) pe.LocationChanged = DateTime.UtcNow;
if (bUpdateLocationChangedOfEntry) pe.LocationChanged = DateTime.Now;
}
public void SortSubGroups(bool bRecursive)
@@ -1423,7 +1605,7 @@ namespace KeePassLib
public void DeleteAllObjects(PwDatabase pdContext)
{
DateTime dtNow = DateTime.UtcNow;
DateTime dtNow = DateTime.Now;
foreach (PwEntry pe in m_listEntries)
{
@@ -1467,7 +1649,7 @@ namespace KeePassLib
public void SetCreatedNow(bool bRecursive)
{
DateTime dt = DateTime.UtcNow;
DateTime dt = DateTime.Now;
m_tCreation = dt;
m_tLastAccess = dt;
@@ -1500,63 +1682,10 @@ namespace KeePassLib
pg.SetCreatedNow(true);
pg.TakeOwnership(true, true, true);
return pg;
}
internal string[] GetAutoTypeSequences(bool bWithStd)
{
try
{
Dictionary<string, bool> d = new Dictionary<string, bool>();
Action<string> fAdd = delegate (string str)
{
if (!string.IsNullOrEmpty(str)) d[str] = true;
};
if (bWithStd)
{
fAdd(PwDefs.DefaultAutoTypeSequence);
fAdd(PwDefs.DefaultAutoTypeSequenceTan);
}
GroupHandler gh = delegate (PwGroup pg)
{
fAdd(pg.DefaultAutoTypeSequence);
return true;
};
EntryHandler eh = delegate (PwEntry pe)
{
AutoTypeConfig c = pe.AutoType;
fAdd(c.DefaultSequence);
foreach (AutoTypeAssociation a in c.Associations)
{
fAdd(a.Sequence);
}
return true;
};
gh(this);
TraverseTree(TraversalMethod.PreOrder, gh, eh);
string[] v = new string[d.Count];
if (d.Count != 0)
{
d.Keys.CopyTo(v, 0);
Array.Sort<string>(v, StrUtil.CaseIgnoreComparer);
}
return v;
}
catch (Exception) { Debug.Assert(false); }
return new string[0];
}
}
public sealed class PwGroupComparer : IComparer<PwGroup>

View File

@@ -26,9 +26,6 @@ namespace KeePassLib.Resources
{
if(dictNew == null) throw new ArgumentNullException("dictNew");
m_strAlgorithmUnknown = TryGetEx(dictNew, "AlgorithmUnknown", m_strAlgorithmUnknown);
m_strCharSetInvalid = TryGetEx(dictNew, "CharSetInvalid", m_strCharSetInvalid);
m_strCharSetTooFewChars = TryGetEx(dictNew, "CharSetTooFewChars", m_strCharSetTooFewChars);
m_strCryptoStreamFailed = TryGetEx(dictNew, "CryptoStreamFailed", m_strCryptoStreamFailed);
m_strEncDataTooLarge = TryGetEx(dictNew, "EncDataTooLarge", m_strEncDataTooLarge);
m_strErrorInClipboard = TryGetEx(dictNew, "ErrorInClipboard", m_strErrorInClipboard);
@@ -44,7 +41,7 @@ namespace KeePassLib.Resources
m_strFileNewVerOrPlgReq = TryGetEx(dictNew, "FileNewVerOrPlgReq", m_strFileNewVerOrPlgReq);
m_strFileNewVerReq = TryGetEx(dictNew, "FileNewVerReq", m_strFileNewVerReq);
m_strFileSaveCorruptionWarning = TryGetEx(dictNew, "FileSaveCorruptionWarning", m_strFileSaveCorruptionWarning);
m_strFileSaveFailed2 = TryGetEx(dictNew, "FileSaveFailed2", m_strFileSaveFailed2);
m_strFileSaveFailed = TryGetEx(dictNew, "FileSaveFailed", m_strFileSaveFailed);
m_strFileSigInvalid = TryGetEx(dictNew, "FileSigInvalid", m_strFileSigInvalid);
m_strFileUnknownCipher = TryGetEx(dictNew, "FileUnknownCipher", m_strFileUnknownCipher);
m_strFileUnknownCompression = TryGetEx(dictNew, "FileUnknownCompression", m_strFileUnknownCompression);
@@ -58,18 +55,12 @@ namespace KeePassLib.Resources
m_strKeePass1xHint = TryGetEx(dictNew, "KeePass1xHint", m_strKeePass1xHint);
m_strKeyBits = TryGetEx(dictNew, "KeyBits", m_strKeyBits);
m_strKeyFileDbSel = TryGetEx(dictNew, "KeyFileDbSel", m_strKeyFileDbSel);
m_strKeyHashMismatch = TryGetEx(dictNew, "KeyHashMismatch", m_strKeyHashMismatch);
m_strMasterSeedLengthInvalid = TryGetEx(dictNew, "MasterSeedLengthInvalid", m_strMasterSeedLengthInvalid);
m_strOldFormat = TryGetEx(dictNew, "OldFormat", m_strOldFormat);
m_strPassive = TryGetEx(dictNew, "Passive", m_strPassive);
m_strPathBackslash = TryGetEx(dictNew, "PathBackslash", m_strPathBackslash);
m_strPatternInvalid = TryGetEx(dictNew, "PatternInvalid", m_strPatternInvalid);
m_strPreAuth = TryGetEx(dictNew, "PreAuth", m_strPreAuth);
m_strPwGenFailed = TryGetEx(dictNew, "PwGenFailed", m_strPwGenFailed);
m_strStructsTooDeep = TryGetEx(dictNew, "StructsTooDeep", m_strStructsTooDeep);
m_strTimeout = TryGetEx(dictNew, "Timeout", m_strTimeout);
m_strTryAgainSecs = TryGetEx(dictNew, "TryAgainSecs", m_strTryAgainSecs);
m_strUnknownError = TryGetEx(dictNew, "UnknownError", m_strUnknownError);
m_strUnknownHeaderId = TryGetEx(dictNew, "UnknownHeaderId", m_strUnknownHeaderId);
m_strUnknownKdf = TryGetEx(dictNew, "UnknownKdf", m_strUnknownKdf);
m_strUserAccountKeyError = TryGetEx(dictNew, "UserAccountKeyError", m_strUserAccountKeyError);
@@ -77,9 +68,6 @@ namespace KeePassLib.Resources
}
private static readonly string[] m_vKeyNames = {
"AlgorithmUnknown",
"CharSetInvalid",
"CharSetTooFewChars",
"CryptoStreamFailed",
"EncDataTooLarge",
"ErrorInClipboard",
@@ -95,7 +83,7 @@ namespace KeePassLib.Resources
"FileNewVerOrPlgReq",
"FileNewVerReq",
"FileSaveCorruptionWarning",
"FileSaveFailed2",
"FileSaveFailed",
"FileSigInvalid",
"FileUnknownCipher",
"FileUnknownCompression",
@@ -109,18 +97,12 @@ namespace KeePassLib.Resources
"KeePass1xHint",
"KeyBits",
"KeyFileDbSel",
"KeyHashMismatch",
"MasterSeedLengthInvalid",
"OldFormat",
"Passive",
"PathBackslash",
"PatternInvalid",
"PreAuth",
"PwGenFailed",
"StructsTooDeep",
"Timeout",
"TryAgainSecs",
"UnknownError",
"UnknownHeaderId",
"UnknownKdf",
"UserAccountKeyError",
@@ -132,39 +114,6 @@ namespace KeePassLib.Resources
return m_vKeyNames;
}
private static string m_strAlgorithmUnknown =
@"The algorithm is unknown.";
/// <summary>
/// Look up a localized string similar to
/// 'The algorithm is unknown.'.
/// </summary>
public static string AlgorithmUnknown
{
get { return m_strAlgorithmUnknown; }
}
private static string m_strCharSetInvalid =
@"The character set is invalid.";
/// <summary>
/// Look up a localized string similar to
/// 'The character set is invalid.'.
/// </summary>
public static string CharSetInvalid
{
get { return m_strCharSetInvalid; }
}
private static string m_strCharSetTooFewChars =
@"There are too few characters in the character set.";
/// <summary>
/// Look up a localized string similar to
/// 'There are too few characters in the character set.'.
/// </summary>
public static string CharSetTooFewChars
{
get { return m_strCharSetTooFewChars; }
}
private static string m_strCryptoStreamFailed =
@"Failed to initialize encryption/decryption stream!";
/// <summary>
@@ -330,15 +279,15 @@ namespace KeePassLib.Resources
get { return m_strFileSaveCorruptionWarning; }
}
private static string m_strFileSaveFailed2 =
@"Failed to save to the specified file!";
private static string m_strFileSaveFailed =
@"Failed to save the current database to the specified location!";
/// <summary>
/// Look up a localized string similar to
/// 'Failed to save to the specified file!'.
/// 'Failed to save the current database to the specified location!'.
/// </summary>
public static string FileSaveFailed2
public static string FileSaveFailed
{
get { return m_strFileSaveFailed2; }
get { return m_strFileSaveFailed; }
}
private static string m_strFileSigInvalid =
@@ -397,10 +346,10 @@ namespace KeePassLib.Resources
}
private static string m_strFrameworkNotImplExcp =
@"The .NET Framework/runtime under which KeePass is currently running does not support this operation.";
@"The .NET framework/runtime under which KeePass is currently running does not support this operation.";
/// <summary>
/// Look up a localized string similar to
/// 'The .NET Framework/runtime under which KeePass is currently running does not support this operation.'.
/// 'The .NET framework/runtime under which KeePass is currently running does not support this operation.'.
/// </summary>
public static string FrameworkNotImplExcp
{
@@ -419,10 +368,10 @@ namespace KeePassLib.Resources
}
private static string m_strInvalidCompositeKey =
@"The master key is invalid!";
@"The composite key is invalid!";
/// <summary>
/// Look up a localized string similar to
/// 'The master key is invalid!'.
/// 'The composite key is invalid!'.
/// </summary>
public static string InvalidCompositeKey
{
@@ -430,10 +379,10 @@ namespace KeePassLib.Resources
}
private static string m_strInvalidCompositeKeyHint =
@"Make sure that the master key is correct and try it again.";
@"Make sure the composite key is correct and try again.";
/// <summary>
/// Look up a localized string similar to
/// 'Make sure that the master key is correct and try it again.'.
/// 'Make sure the composite key is correct and try again.'.
/// </summary>
public static string InvalidCompositeKeyHint
{
@@ -484,17 +433,6 @@ namespace KeePassLib.Resources
get { return m_strKeyFileDbSel; }
}
private static string m_strKeyHashMismatch =
@"The key and the hash do not match, i.e. the key or the hash is invalid.";
/// <summary>
/// Look up a localized string similar to
/// 'The key and the hash do not match, i.e. the key or the hash is invalid.'.
/// </summary>
public static string KeyHashMismatch
{
get { return m_strKeyHashMismatch; }
}
private static string m_strMasterSeedLengthInvalid =
@"The length of the master key seed is invalid!";
/// <summary>
@@ -528,28 +466,6 @@ namespace KeePassLib.Resources
get { return m_strPassive; }
}
private static string m_strPathBackslash =
@"The path contains a backslash. Such paths are not supported (for security reasons).";
/// <summary>
/// Look up a localized string similar to
/// 'The path contains a backslash. Such paths are not supported (for security reasons).'.
/// </summary>
public static string PathBackslash
{
get { return m_strPathBackslash; }
}
private static string m_strPatternInvalid =
@"The pattern is invalid.";
/// <summary>
/// Look up a localized string similar to
/// 'The pattern is invalid.'.
/// </summary>
public static string PatternInvalid
{
get { return m_strPatternInvalid; }
}
private static string m_strPreAuth =
@"Pre-authenticate";
/// <summary>
@@ -561,28 +477,6 @@ namespace KeePassLib.Resources
get { return m_strPreAuth; }
}
private static string m_strPwGenFailed =
@"Failed to generate a password.";
/// <summary>
/// Look up a localized string similar to
/// 'Failed to generate a password.'.
/// </summary>
public static string PwGenFailed
{
get { return m_strPwGenFailed; }
}
private static string m_strStructsTooDeep =
@"Structures are nested too deeply.";
/// <summary>
/// Look up a localized string similar to
/// 'Structures are nested too deeply.'.
/// </summary>
public static string StructsTooDeep
{
get { return m_strStructsTooDeep; }
}
private static string m_strTimeout =
@"Timeout";
/// <summary>
@@ -605,17 +499,6 @@ namespace KeePassLib.Resources
get { return m_strTryAgainSecs; }
}
private static string m_strUnknownError =
@"An unknown error occurred.";
/// <summary>
/// Look up a localized string similar to
/// 'An unknown error occurred.'.
/// </summary>
public static string UnknownError
{
get { return m_strUnknownError; }
}
private static string m_strUnknownHeaderId =
@"Unknown header ID!";
/// <summary>

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,11 +33,11 @@ using KeePassLibSD;
namespace KeePassLib.Security
{
/// <summary>
/// A string that is protected in process memory.
/// Represents an in-memory encrypted string.
/// <c>ProtectedString</c> objects are immutable and thread-safe.
/// </summary>
#if (DEBUG && !KeePassLibSD)
[DebuggerDisplay("{ReadString()}")]
[DebuggerDisplay(@"{ReadString()}")]
#endif
public sealed class ProtectedString
{
@@ -48,24 +48,11 @@ namespace KeePassLib.Security
private bool m_bIsProtected;
private static readonly ProtectedString m_psEmpty = new ProtectedString();
/// <summary>
/// Get an empty <c>ProtectedString</c> object, without protection.
/// </summary>
public static ProtectedString Empty
{
get { return m_psEmpty; }
}
private static readonly ProtectedString m_psEmptyEx = new ProtectedString(
true, new byte[0]);
/// <summary>
/// Get an empty <c>ProtectedString</c> object, with protection turned on.
/// </summary>
public static ProtectedString EmptyEx
{
get { return m_psEmptyEx; }
}
/// <summary>
/// A flag specifying whether the <c>ProtectedString</c> object
/// has turned on memory protection or not.
@@ -79,8 +66,8 @@ namespace KeePassLib.Security
{
get
{
ProtectedBinary p = m_pbUtf8; // Local ref for thread-safety
if (p != null) return (p.Length == 0);
ProtectedBinary pBin = m_pbUtf8; // Local ref for thread-safety
if(pBin != null) return (pBin.Length == 0);
Debug.Assert(m_strPlainText != null);
return (m_strPlainText.Length == 0);
@@ -88,21 +75,18 @@ namespace KeePassLib.Security
}
private int m_nCachedLength = -1;
/// <summary>
/// Length of the protected string, in characters.
/// </summary>
public int Length
{
get
{
if(m_nCachedLength >= 0) return m_nCachedLength;
ProtectedBinary p = m_pbUtf8; // Local ref for thread-safety
if (p != null)
ProtectedBinary pBin = m_pbUtf8; // Local ref for thread-safety
if(pBin != null)
{
byte[] pbPlain = p.ReadData();
try { m_nCachedLength = StrUtil.Utf8.GetCharCount(pbPlain); }
finally { MemUtil.ZeroByteArray(pbPlain); }
byte[] pbPlain = pBin.ReadData();
m_nCachedLength = StrUtil.Utf8.GetCharCount(pbPlain);
MemUtil.ZeroByteArray(pbPlain);
}
else
{
@@ -156,16 +140,18 @@ namespace KeePassLib.Security
/// to the value passed in the <c>XorredBuffer</c> object.
/// </summary>
/// <param name="bEnableProtection">Enable protection or not.</param>
/// <param name="xb"><c>XorredBuffer</c> object containing the
/// <param name="xbProtected"><c>XorredBuffer</c> object containing the
/// string in UTF-8 representation. The UTF-8 string must not
/// be <c>null</c>-terminated.</param>
public ProtectedString(bool bEnableProtection, XorredBuffer xb)
public ProtectedString(bool bEnableProtection, XorredBuffer xbProtected)
{
if (xb == null) { Debug.Assert(false); throw new ArgumentNullException("xb"); }
Debug.Assert(xbProtected != null);
if(xbProtected == null) throw new ArgumentNullException("xbProtected");
byte[] pb = xb.ReadPlainText();
try { Init(bEnableProtection, pb); }
finally { if (bEnableProtection) MemUtil.ZeroByteArray(pb); }
byte[] pb = xbProtected.ReadPlainText();
Init(bEnableProtection, pb);
if(bEnableProtection) MemUtil.ZeroByteArray(pb);
}
private void Init(bool bEnableProtection, string str)
@@ -174,7 +160,7 @@ namespace KeePassLib.Security
m_bIsProtected = bEnableProtection;
// As the string already is in memory and immutable,
// The string already is in memory and immutable,
// protection would be useless
m_strPlainText = str;
}
@@ -192,8 +178,8 @@ namespace KeePassLib.Security
}
/// <summary>
/// Convert the protected string to a standard string object.
/// Be careful with this function, as the returned string object
/// Convert the protected string to a normal string object.
/// Be careful with this function, the returned string object
/// isn't protected anymore and stored in plain-text in the
/// process memory.
/// </summary>
@@ -208,64 +194,46 @@ namespace KeePassLib.Security
// No need to clear pb
// As the text is now visible in process memory anyway,
// there's no need to protect it anymore (strings are
// immutable and thus cannot be overwritten)
// there's no need to protect it anymore
m_strPlainText = str;
m_pbUtf8 = null; // Thread-safe order
return str;
}
/// <summary>
/// Read out the string and return it as a char array.
/// The returned array is not protected and should be cleared by
/// the caller.
/// </summary>
/// <returns>Plain-text char array.</returns>
public char[] ReadChars()
{
if (m_strPlainText != null) return m_strPlainText.ToCharArray();
byte[] pb = ReadUtf8();
char[] v;
try { v = StrUtil.Utf8.GetChars(pb); }
finally { MemUtil.ZeroByteArray(pb); }
return v;
}
/// <summary>
/// Read out the string and return a byte array that contains the
/// string encoded using UTF-8.
/// The returned array is not protected and should be cleared by
/// the caller.
/// string encoded using UTF-8. The returned string is not protected
/// anymore!
/// </summary>
/// <returns>Plain-text UTF-8 byte array.</returns>
public byte[] ReadUtf8()
{
ProtectedBinary p = m_pbUtf8; // Local ref for thread-safety
if (p != null) return p.ReadData();
ProtectedBinary pBin = m_pbUtf8; // Local ref for thread-safety
if(pBin != null) return pBin.ReadData();
return StrUtil.Utf8.GetBytes(m_strPlainText);
}
/// <summary>
/// Get the string as an UTF-8 sequence xorred with bytes
/// from a <c>CryptoRandomStream</c>.
/// Read the protected string and return it protected with a sequence
/// of bytes generated by a random stream.
/// </summary>
/// <param name="crsRandomSource">Random number source.</param>
/// <returns>Protected string.</returns>
public byte[] ReadXorredString(CryptoRandomStream crsRandomSource)
{
if (crsRandomSource == null) { Debug.Assert(false); throw new ArgumentNullException("crsRandomSource"); }
Debug.Assert(crsRandomSource != null); if(crsRandomSource == null) throw new ArgumentNullException("crsRandomSource");
byte[] pbData = ReadUtf8();
int cb = pbData.Length;
uint uLen = (uint)pbData.Length;
byte[] pbPad = crsRandomSource.GetRandomBytes((uint)cb);
Debug.Assert(pbPad.Length == cb);
byte[] randomPad = crsRandomSource.GetRandomBytes(uLen);
Debug.Assert(randomPad.Length == pbData.Length);
for (int i = 0; i < cb; ++i)
pbData[i] ^= pbPad[i];
for(uint i = 0; i < uLen; ++i)
pbData[i] ^= randomPad[i];
MemUtil.ZeroByteArray(pbPad);
return pbData;
}
@@ -274,34 +242,10 @@ namespace KeePassLib.Security
if(bProtect == m_bIsProtected) return this;
byte[] pb = ReadUtf8();
ProtectedString ps = new ProtectedString(bProtect, pb);
// No need to clear pb; either the current or the new object is unprotected
return new ProtectedString(bProtect, pb);
}
public bool Equals(ProtectedString ps, bool bCheckProtEqual)
{
if (ps == null) throw new ArgumentNullException("ps");
if (object.ReferenceEquals(this, ps)) return true; // Perf. opt.
bool bPA = m_bIsProtected, bPB = ps.m_bIsProtected;
if (bCheckProtEqual && (bPA != bPB)) return false;
if (!bPA && !bPB) return (ReadString() == ps.ReadString());
byte[] pbA = ReadUtf8(), pbB = null;
bool bEq;
try
{
pbB = ps.ReadUtf8();
bEq = MemUtil.ArraysEqual(pbA, pbB);
}
finally
{
if (bPA) MemUtil.ZeroByteArray(pbA);
if (bPB && (pbB != null)) MemUtil.ZeroByteArray(pbB);
}
return bEq;
if(bProtect) MemUtil.ZeroByteArray(pb);
return ps;
}
public ProtectedString Insert(int iStart, string strInsert)
@@ -310,14 +254,18 @@ namespace KeePassLib.Security
if(strInsert == null) throw new ArgumentNullException("strInsert");
if(strInsert.Length == 0) return this;
// Only operate directly with strings when m_bIsProtected is
// false, not in the case of non-null m_strPlainText, because
// the operation creates a new sequence in memory
if(!m_bIsProtected)
return new ProtectedString(false, ReadString().Insert(
iStart, strInsert));
UTF8Encoding utf8 = StrUtil.Utf8;
char[] v = ReadChars(), vNew = null;
byte[] pbNew = null;
ProtectedString ps;
byte[] pb = ReadUtf8();
char[] v = utf8.GetChars(pb);
char[] vNew;
try
{
@@ -331,20 +279,21 @@ namespace KeePassLib.Security
Array.Copy(vIns, 0, vNew, iStart, vIns.Length);
Array.Copy(v, iStart, vNew, iStart + vIns.Length,
v.Length - iStart);
pbNew = utf8.GetBytes(vNew);
ps = new ProtectedString(true, pbNew);
Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) ==
ReadString().Insert(iStart, strInsert));
}
finally
{
MemUtil.ZeroArray<char>(v);
if (vNew != null) MemUtil.ZeroArray<char>(vNew);
if (pbNew != null) MemUtil.ZeroByteArray(pbNew);
MemUtil.ZeroByteArray(pb);
}
byte[] pbNew = utf8.GetBytes(vNew);
ProtectedString ps = new ProtectedString(m_bIsProtected, pbNew);
Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) ==
ReadString().Insert(iStart, strInsert));
MemUtil.ZeroArray<char>(vNew);
MemUtil.ZeroByteArray(pbNew);
return ps;
}
@@ -354,81 +303,44 @@ namespace KeePassLib.Security
if(nCount < 0) throw new ArgumentOutOfRangeException("nCount");
if(nCount == 0) return this;
// Only operate directly with strings when m_bIsProtected is
// false, not in the case of non-null m_strPlainText, because
// the operation creates a new sequence in memory
if(!m_bIsProtected)
return new ProtectedString(false, ReadString().Remove(
iStart, nCount));
UTF8Encoding utf8 = StrUtil.Utf8;
char[] v = ReadChars(), vNew = null;
byte[] pbNew = null;
ProtectedString ps;
byte[] pb = ReadUtf8();
char[] v = utf8.GetChars(pb);
char[] vNew;
try
{
if((iStart + nCount) > v.Length)
throw new ArgumentException("(iStart + nCount) > v.Length");
throw new ArgumentException("iStart + nCount");
vNew = new char[v.Length - nCount];
Array.Copy(v, 0, vNew, 0, iStart);
Array.Copy(v, iStart + nCount, vNew, iStart, v.Length -
(iStart + nCount));
pbNew = utf8.GetBytes(vNew);
ps = new ProtectedString(true, pbNew);
Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) ==
ReadString().Remove(iStart, nCount));
}
finally
{
MemUtil.ZeroArray<char>(v);
if (vNew != null) MemUtil.ZeroArray<char>(vNew);
if (pbNew != null) MemUtil.ZeroByteArray(pbNew);
MemUtil.ZeroByteArray(pb);
}
byte[] pbNew = utf8.GetBytes(vNew);
ProtectedString ps = new ProtectedString(m_bIsProtected, pbNew);
Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) ==
ReadString().Remove(iStart, nCount));
MemUtil.ZeroArray<char>(vNew);
MemUtil.ZeroByteArray(pbNew);
return ps;
}
public static ProtectedString operator +(ProtectedString a, ProtectedString b)
{
if (a == null) throw new ArgumentNullException("a");
if (b == null) throw new ArgumentNullException("b");
if (b.IsEmpty) return a.WithProtection(a.IsProtected || b.IsProtected);
if (a.IsEmpty) return b.WithProtection(a.IsProtected || b.IsProtected);
if (!a.IsProtected && !b.IsProtected)
return new ProtectedString(false, a.ReadString() + b.ReadString());
char[] vA = a.ReadChars(), vB = null, vNew = null;
byte[] pbNew = null;
ProtectedString ps;
try
{
vB = b.ReadChars();
vNew = new char[vA.Length + vB.Length];
Array.Copy(vA, vNew, vA.Length);
Array.Copy(vB, 0, vNew, vA.Length, vB.Length);
pbNew = StrUtil.Utf8.GetBytes(vNew);
ps = new ProtectedString(true, pbNew);
}
finally
{
MemUtil.ZeroArray<char>(vA);
if (vB != null) MemUtil.ZeroArray<char>(vB);
if (vNew != null) MemUtil.ZeroArray<char>(vNew);
if (pbNew != null) MemUtil.ZeroByteArray(pbNew);
}
return ps;
}
public static ProtectedString operator +(ProtectedString a, string b)
{
ProtectedString psB = new ProtectedString(false, b);
return (a + psB);
}
}
}

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,90 +20,97 @@
using System;
using System.Diagnostics;
using KeePassLib.Utility;
namespace KeePassLib.Security
{
/// <summary>
/// A <c>XorredBuffer</c> object stores data that is encrypted
/// using a XOR pad.
/// Represents an object that is encrypted using a XOR pad until
/// it is read. <c>XorredBuffer</c> objects are immutable and
/// thread-safe.
/// </summary>
public sealed class XorredBuffer : IDisposable
public sealed class XorredBuffer
{
private byte[] m_pbCT;
private byte[] m_pbXorPad;
private byte[] m_pbData; // Never null
private byte[] m_pbXorPad; // Always valid for m_pbData
/// <summary>
/// Length of the protected data in bytes.
/// </summary>
public uint Length
{
get
{
if (m_pbCT == null) { Debug.Assert(false); throw new ObjectDisposedException(null); }
return (uint)m_pbCT.Length;
}
get { return (uint)m_pbData.Length; }
}
/// <summary>
/// Construct a new <c>XorredBuffer</c> object.
/// The <paramref name="pbCT" /> byte array must have the same
/// length as the <paramref name="pbXorPad" /> byte array.
/// Construct a new XOR-protected object using a protected byte array
/// and a XOR pad that decrypts the protected data. The
/// <paramref name="pbProtectedData" /> byte array must have the same size
/// as the <paramref name="pbXorPad" /> byte array.
/// The <c>XorredBuffer</c> object takes ownership of the two byte
/// arrays, i.e. the caller must not use them afterwards.
/// arrays, i.e. the caller must not use or modify them afterwards.
/// </summary>
/// <param name="pbCT">Data with XOR pad applied.</param>
/// <param name="pbProtectedData">Protected data (XOR pad applied).</param>
/// <param name="pbXorPad">XOR pad that can be used to decrypt the
/// <paramref name="pbCT" /> byte array.</param>
public XorredBuffer(byte[] pbCT, byte[] pbXorPad)
/// <paramref name="pbProtectedData" /> parameter.</param>
/// <exception cref="System.ArgumentNullException">Thrown if one of the input
/// parameters is <c>null</c>.</exception>
/// <exception cref="System.ArgumentException">Thrown if the byte arrays are
/// of different size.</exception>
public XorredBuffer(byte[] pbProtectedData, byte[] pbXorPad)
{
if (pbCT == null) { Debug.Assert(false); throw new ArgumentNullException("pbCT"); }
if(pbProtectedData == null) { Debug.Assert(false); throw new ArgumentNullException("pbProtectedData"); }
if(pbXorPad == null) { Debug.Assert(false); throw new ArgumentNullException("pbXorPad"); }
if (pbCT.Length != pbXorPad.Length)
{
Debug.Assert(false);
throw new ArgumentOutOfRangeException("pbXorPad");
}
m_pbCT = pbCT;
Debug.Assert(pbProtectedData.Length == pbXorPad.Length);
if(pbProtectedData.Length != pbXorPad.Length) throw new ArgumentException();
m_pbData = pbProtectedData;
m_pbXorPad = pbXorPad;
}
#if DEBUG
~XorredBuffer()
{
Debug.Assert((m_pbCT == null) && (m_pbXorPad == null));
}
#endif
public void Dispose()
{
if (m_pbCT == null) return;
MemUtil.ZeroByteArray(m_pbCT);
m_pbCT = null;
MemUtil.ZeroByteArray(m_pbXorPad);
m_pbXorPad = null;
}
/// <summary>
/// Get a copy of the plain-text. The caller is responsible
/// for clearing the byte array safely after using it.
/// </summary>
/// <returns>Plain-text byte array.</returns>
/// <returns>Unprotected plain-text byte array.</returns>
public byte[] ReadPlainText()
{
byte[] pbCT = m_pbCT, pbX = m_pbXorPad;
if ((pbCT == null) || (pbX == null) || (pbCT.Length != pbX.Length))
byte[] pbPlain = new byte[m_pbData.Length];
for(int i = 0; i < pbPlain.Length; ++i)
pbPlain[i] = (byte)(m_pbData[i] ^ m_pbXorPad[i]);
return pbPlain;
}
/* public bool EqualsValue(XorredBuffer xb)
{
Debug.Assert(false);
throw new ObjectDisposedException(null);
if(xb == null) { Debug.Assert(false); throw new ArgumentNullException("xb"); }
if(xb.m_pbData.Length != m_pbData.Length) return false;
for(int i = 0; i < m_pbData.Length; ++i)
{
byte bt1 = (byte)(m_pbData[i] ^ m_pbXorPad[i]);
byte bt2 = (byte)(xb.m_pbData[i] ^ xb.m_pbXorPad[i]);
if(bt1 != bt2) return false;
}
byte[] pbPT = new byte[pbCT.Length];
return true;
}
for (int i = 0; i < pbPT.Length; ++i)
pbPT[i] = (byte)(pbCT[i] ^ pbX[i]);
public bool EqualsValue(byte[] pb)
{
if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); }
return pbPT;
}
if(pb.Length != m_pbData.Length) return false;
for(int i = 0; i < m_pbData.Length; ++i)
{
if((byte)(m_pbData[i] ^ m_pbXorPad[i]) != pb[i]) return false;
}
return true;
} */
}
}

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,7 +23,10 @@ using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using keepass2android;
#if !KeePassUAP
using System.Drawing;
#endif
using KeePassLib;
using KeePassLib.Collections;
@@ -83,11 +86,8 @@ namespace KeePassLib.Serialization
private PwDeletedObject m_ctxDeletedObject = null;
private PwUuid m_uuidCustomIconID = PwUuid.Zero;
private byte[] m_pbCustomIconData = null;
private string m_strCustomIconName = null;
private DateTime? m_odtCustomIconLastMod = null;
private string m_strCustomDataKey = null;
private string m_strCustomDataValue = null;
private DateTime? m_odtCustomDataLastMod = null;
private string m_strGroupCustomDataKey = null;
private string m_strGroupCustomDataValue = null;
private string m_strEntryCustomDataKey = null;
@@ -95,10 +95,35 @@ namespace KeePassLib.Serialization
private void ReadXmlStreamed(Stream sXml, Stream sParent)
{
using (XmlReader xr = XmlUtilEx.CreateXmlReader(sXml))
{
ReadDocumentStreamed(xr, sParent);
ReadDocumentStreamed(CreateXmlReader(sXml), sParent);
}
internal static XmlReaderSettings CreateStdXmlReaderSettings()
{
XmlReaderSettings xrs = new XmlReaderSettings();
xrs.CloseInput = true;
xrs.IgnoreComments = true;
xrs.IgnoreProcessingInstructions = true;
xrs.IgnoreWhitespace = true;
#if KeePassUAP
xrs.DtdProcessing = DtdProcessing.Prohibit;
#else
#if !KeePassLibSD
xrs.ProhibitDtd = true; // Obsolete in .NET 4, but still there
// xrs.DtdProcessing = DtdProcessing.Prohibit; // .NET 4 only
#endif
xrs.ValidationType = ValidationType.None;
#endif
return xrs;
}
private static XmlReader CreateXmlReader(Stream readerStream)
{
XmlReaderSettings xrs = CreateStdXmlReaderSettings();
return XmlReader.Create(readerStream, xrs);
}
private void ReadDocumentStreamed(XmlReader xr, Stream sParentStream)
@@ -151,7 +176,7 @@ namespace KeePassLib.Serialization
}
++uTagCounter;
if (((uTagCounter & 0xFFU) == 0) && bSupportsStatus)
if(((uTagCounter % 256) == 0) && bSupportsStatus)
{
Debug.Assert(lStreamLength == sParentStream.Length);
uint uPct = (uint)((sParentStream.Position * 100) /
@@ -161,8 +186,7 @@ namespace KeePassLib.Serialization
// position/length values (M120413)
if(uPct > 100) { Debug.Assert(false); uPct = 100; }
if (!m_slLogger.SetProgress(uPct))
throw new OperationCanceledException();
m_slLogger.SetProgress(uPct);
}
}
@@ -306,10 +330,6 @@ namespace KeePassLib.Serialization
m_pbCustomIconData = Convert.FromBase64String(strData);
else { Debug.Assert(false); }
}
else if (xr.Name == ElemName)
m_strCustomIconName = ReadString(xr);
else if (xr.Name == ElemLastModTime)
m_odtCustomIconLastMod = ReadTime(xr);
else ReadUnknown(xr);
break;
@@ -346,8 +366,6 @@ namespace KeePassLib.Serialization
m_strCustomDataKey = ReadString(xr);
else if(xr.Name == ElemValue)
m_strCustomDataValue = ReadString(xr);
else if (xr.Name == ElemLastModTime)
m_odtCustomDataLastMod = ReadTime(xr);
else ReadUnknown(xr);
break;
@@ -391,10 +409,6 @@ namespace KeePassLib.Serialization
m_ctxGroup.EnableSearching = StrUtil.StringToBoolEx(ReadString(xr));
else if(xr.Name == ElemLastTopVisibleEntry)
m_ctxGroup.LastTopVisibleEntry = ReadUuid(xr);
else if (xr.Name == ElemPreviousParentGroup)
m_ctxGroup.PreviousParentGroup = ReadUuid(xr);
else if (xr.Name == ElemTags)
m_ctxGroup.Tags = StrUtil.StringToTags(ReadString(xr));
else if(xr.Name == ElemCustomData)
return SwitchContext(ctx, KdbContext.GroupCustomData, xr);
else if(xr.Name == ElemGroup)
@@ -452,12 +466,8 @@ namespace KeePassLib.Serialization
}
else if(xr.Name == ElemOverrideUrl)
m_ctxEntry.OverrideUrl = ReadString(xr);
else if (xr.Name == ElemQualityCheck)
m_ctxEntry.QualityCheck = ReadBool(xr, true);
else if(xr.Name == ElemTags)
m_ctxEntry.Tags = StrUtil.StringToTags(ReadString(xr));
else if (xr.Name == ElemPreviousParentGroup)
m_ctxEntry.PreviousParentGroup = ReadUuid(xr);
else if(xr.Name == ElemTimes)
return SwitchContext(ctx, KdbContext.EntryTimes, xr);
else if(xr.Name == ElemString)
@@ -504,7 +514,6 @@ namespace KeePassLib.Serialization
tl.LocationChanged = ReadTime(xr);
else ReadUnknown(xr);
break;
case KdbContext.EntryString:
if(xr.Name == ElemKey)
m_ctxStringName = ReadString(xr);
@@ -613,19 +622,12 @@ namespace KeePassLib.Serialization
{
if(!m_uuidCustomIconID.Equals(PwUuid.Zero) &&
(m_pbCustomIconData != null))
{
PwCustomIcon ci = new PwCustomIcon(m_uuidCustomIconID,
m_pbCustomIconData);
if (m_strCustomIconName != null) ci.Name = m_strCustomIconName;
ci.LastModificationTime = m_odtCustomIconLastMod;
m_pwDatabase.CustomIcons.Add(ci);
}
m_pwDatabase.CustomIcons.Add(new PwCustomIcon(
m_uuidCustomIconID, m_pbCustomIconData));
else { Debug.Assert(false); }
m_uuidCustomIconID = PwUuid.Zero;
m_pbCustomIconData = null;
m_strCustomIconName = null;
m_odtCustomIconLastMod = null;
return KdbContext.CustomIcons;
}
@@ -636,13 +638,11 @@ namespace KeePassLib.Serialization
else if((ctx == KdbContext.CustomDataItem) && (xr.Name == ElemStringDictExItem))
{
if((m_strCustomDataKey != null) && (m_strCustomDataValue != null))
m_pwDatabase.CustomData.Set(m_strCustomDataKey,
m_strCustomDataValue, m_odtCustomDataLastMod);
m_pwDatabase.CustomData.Set(m_strCustomDataKey, m_strCustomDataValue);
else { Debug.Assert(false); }
m_strCustomDataKey = null;
m_strCustomDataValue = null;
m_odtCustomDataLastMod = null;
return KdbContext.CustomData;
}
@@ -765,16 +765,10 @@ namespace KeePassLib.Serialization
{
XorredBuffer xb = ProcessNode(xr);
if(xb != null)
{
Debug.Assert(false); // Protected data is unexpected here
try
{
byte[] pb = xb.ReadPlainText();
if(pb.Length == 0) return string.Empty;
try { return StrUtil.Utf8.GetString(pb, 0, pb.Length); }
finally { MemUtil.ZeroByteArray(pb); }
}
finally { xb.Dispose(); }
return StrUtil.Utf8.GetString(pb, 0, pb.Length);
}
m_bReadNextNode = false; // ReadElementString skips end tag
@@ -787,55 +781,6 @@ namespace KeePassLib.Serialization
return xr.ReadElementString();
}
private byte[] ReadBase64(XmlReader xr, bool bRaw)
{
// if(bRaw) return ReadBase64RawInChunks(xr);
string str = (bRaw ? ReadStringRaw(xr) : ReadString(xr));
if (string.IsNullOrEmpty(str)) return MemUtil.EmptyByteArray;
return Convert.FromBase64String(str);
}
/* private byte[] m_pbBase64ReadBuf = new byte[1024 * 1024 * 3];
private byte[] ReadBase64RawInChunks(XmlReader xr)
{
xr.MoveToContent();
List<byte[]> lParts = new List<byte[]>();
byte[] pbBuf = m_pbBase64ReadBuf;
while(true)
{
int cb = xr.ReadElementContentAsBase64(pbBuf, 0, pbBuf.Length);
if(cb == 0) break;
byte[] pb = new byte[cb];
Array.Copy(pbBuf, 0, pb, 0, cb);
lParts.Add(pb);
// No break when cb < pbBuf.Length, because ReadElementContentAsBase64
// moves to the next XML node only when returning 0
}
m_bReadNextNode = false;
if(lParts.Count == 0) return MemUtil.EmptyByteArray;
if(lParts.Count == 1) return lParts[0];
long cbRes = 0;
for(int i = 0; i < lParts.Count; ++i)
cbRes += lParts[i].Length;
byte[] pbRes = new byte[cbRes];
int cbCur = 0;
for(int i = 0; i < lParts.Count; ++i)
{
Array.Copy(lParts[i], 0, pbRes, cbCur, lParts[i].Length);
cbCur += lParts[i].Length;
}
return pbRes;
} */
private bool ReadBool(XmlReader xr, bool bDefault)
{
string str = ReadString(xr);
@@ -848,9 +793,9 @@ namespace KeePassLib.Serialization
private PwUuid ReadUuid(XmlReader xr)
{
byte[] pb = ReadBase64(xr, false);
if (pb.Length == 0) return PwUuid.Zero;
return new PwUuid(pb);
string str = ReadString(xr);
if(string.IsNullOrEmpty(str)) return PwUuid.Zero;
return new PwUuid(Convert.FromBase64String(str));
}
private int ReadInt(XmlReader xr, int nDefault)
@@ -917,7 +862,8 @@ namespace KeePassLib.Serialization
// long l = ReadLong(xr, -1);
// if(l != -1) return DateTime.FromBinary(l);
byte[] pb = ReadBase64(xr, false);
string str = ReadString(xr);
byte[] pb = Convert.FromBase64String(str);
if(pb.Length != 8)
{
Debug.Assert(false);
@@ -926,16 +872,7 @@ namespace KeePassLib.Serialization
pb = pb8;
}
long lSec = MemUtil.BytesToInt64(pb);
try
{
return new DateTime(lSec * TimeSpan.TicksPerSecond, DateTimeKind.Utc);
}
catch (System.ArgumentOutOfRangeException e)
{
//files might contain bad data, e.g. see #868. Fall back to MinValue
Kp2aLog.Log("Failed to read date from file.");
return DateTime.MinValue;
}
}
else
{
@@ -961,11 +898,7 @@ namespace KeePassLib.Serialization
private ProtectedString ReadProtectedString(XmlReader xr)
{
XorredBuffer xb = ProcessNode(xr);
if (xb != null)
{
try { return new ProtectedString(true, xb); }
finally { xb.Dispose(); }
}
if(xb != null) return new ProtectedString(true, xb);
bool bProtect = false;
if(m_format == KdbxFormat.PlainXml)
@@ -977,7 +910,8 @@ namespace KeePassLib.Serialization
}
}
return new ProtectedString(bProtect, ReadString(xr));
ProtectedString ps = new ProtectedString(bProtect, ReadString(xr));
return ps;
}
private ProtectedBinary ReadProtectedBinary(XmlReader xr)
@@ -1019,13 +953,13 @@ namespace KeePassLib.Serialization
if(xb != null)
{
Debug.Assert(!bCompressed); // See SubWriteValue(ProtectedBinary value)
try { return new ProtectedBinary(true, xb); }
finally { xb.Dispose(); }
return new ProtectedBinary(true, xb);
}
byte[] pbData = ReadBase64(xr, true);
if (pbData.Length == 0) return new ProtectedBinary();
string strValue = ReadString(xr);
if(strValue.Length == 0) return new ProtectedBinary();
byte[] pbData = Convert.FromBase64String(strValue);
if(bCompressed) pbData = MemUtil.Decompress(pbData);
return new ProtectedBinary(false, pbData);
}
@@ -1033,37 +967,28 @@ namespace KeePassLib.Serialization
private void ReadUnknown(XmlReader xr)
{
Debug.Assert(false); // Unknown node!
Debug.Assert(xr.NodeType == XmlNodeType.Element);
bool bRead = false;
int cOpen = 0;
if(xr.IsEmptyElement) return;
do
string strUnknownName = xr.Name;
ProcessNode(xr);
while(xr.Read())
{
if (bRead) xr.Read();
bRead = true;
if(xr.NodeType == XmlNodeType.EndElement) break;
if(xr.NodeType != XmlNodeType.Element) continue;
if (xr.NodeType == XmlNodeType.EndElement) --cOpen;
else if (xr.NodeType == XmlNodeType.Element)
{
if (!xr.IsEmptyElement)
{
XorredBuffer xb = ProcessNode(xr);
if (xb != null) { xb.Dispose(); bRead = m_bReadNextNode; continue; }
ReadUnknown(xr);
}
++cOpen;
}
}
}
while (cOpen > 0);
m_bReadNextNode = bRead;
Debug.Assert(xr.Name == strUnknownName);
}
private XorredBuffer ProcessNode(XmlReader xr)
{
// Debug.Assert(xr.NodeType == XmlNodeType.Element);
XorredBuffer xb = null;
if(xr.HasAttributes)
{
if(xr.MoveToAttribute(AttrProtected))
@@ -1071,16 +996,21 @@ namespace KeePassLib.Serialization
if(xr.Value == ValTrue)
{
xr.MoveToElement();
string strEncrypted = ReadStringRaw(xr);
byte[] pbCT = ReadBase64(xr, true);
byte[] pbPad = m_randomStream.GetRandomBytes((uint)pbCT.Length);
byte[] pbEncrypted;
if(strEncrypted.Length > 0)
pbEncrypted = Convert.FromBase64String(strEncrypted);
else pbEncrypted = MemUtil.EmptyByteArray;
return new XorredBuffer(pbCT, pbPad);
byte[] pbPad = m_randomStream.GetRandomBytes((uint)pbEncrypted.Length);
xb = new XorredBuffer(pbEncrypted, pbPad);
}
}
}
return null;
return xb;
}
private static KdbContext SwitchContext(KdbContext ctxCurrent,

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -91,8 +91,7 @@ namespace KeePassLib.Serialization
m_format = fmt;
m_slLogger = slLogger;
// Other applications might not perform a deduplication
m_pbsBinaries = new ProtectedBinarySet(false);
m_pbsBinaries.Clear();
UTF8Encoding encNoBom = StrUtil.Utf8;
byte[] pbCipherKey = null;
@@ -150,6 +149,7 @@ namespace KeePassLib.Serialization
if (m_slLogger != null)
m_slLogger.SetText("KP2AKEY_DecodingDatabase", LogStatusType.AdditionalInfo);
sPlain = new HashedBlockStream(sDecrypted, false, 0, !m_bRepairMode);
}
else // KDBX >= 4
@@ -176,7 +176,6 @@ namespace KeePassLib.Serialization
if((sPlain == null) || (sPlain == sBlocks))
throw new SecurityException(KLRes.CryptoStreamFailed);
}
lStreams.Add(sPlain);
if(m_pwDatabase.Compression == PwCompressionAlgorithm.GZip)
@@ -191,11 +190,7 @@ namespace KeePassLib.Serialization
}
else if(fmt == KdbxFormat.PlainXml)
sXml = sHashing;
else
{
Debug.Assert(false);
throw new ArgumentOutOfRangeException("fmt");
}
else { Debug.Assert(false); throw new ArgumentOutOfRangeException("fmt"); }
if(fmt == KdbxFormat.Default)
{
@@ -208,22 +203,23 @@ namespace KeePassLib.Serialization
m_randomStream = new CryptoRandomStream(m_craInnerRandomStream,
m_pbInnerRandomStreamKey);
}
if (m_slLogger != null)
m_slLogger.SetText("KP2AKEY_ParsingDatabase", LogStatusType.AdditionalInfo);
#if KeePassDebug_WriteXml
#warning XML output is enabled!
/* using(FileStream fsOut = new FileStream("Raw.xml", FileMode.Create,
FileAccess.Write, FileShare.None))
{
while(true)
{
int b = sXml.ReadByte();
if(b == -1) throw new EndOfStreamException();
fsOut.WriteByte((byte)b);
}
} */
// FileStream fsOut = new FileStream("Raw.xml", FileMode.Create,
// FileAccess.Write, FileShare.None);
// try
// {
// while(true)
// {
// int b = sXml.ReadByte();
// if(b == -1) break;
// fsOut.WriteByte((byte)b);
// }
// }
// catch(Exception) { }
// fsOut.Close();
#endif
var stopWatch = Stopwatch.StartNew();
@@ -241,8 +237,8 @@ namespace KeePassLib.Serialization
Kp2aLog.Log(String.Format("ReadXmlStreamed: {0}ms", stopWatch.ElapsedMilliseconds));
}
}
// ReadXmlDom(sXml);
}
catch(CryptographicException) // Thrown on invalid padding
{
throw new CryptographicException(KLRes.FileCorrupted);
@@ -271,9 +267,9 @@ namespace KeePassLib.Serialization
Debug.Assert(m_pbHashOfFileOnDisk != null);
CleanUpInnerRandomStream();
// Reset memory protection settings (to always use reasonable
// defaults)
// defaults)
m_pwDatabase.MemoryProtection = new MemoryProtectionConfig();
// Remove old backups (this call is required here in order to apply
@@ -434,7 +430,7 @@ namespace KeePassLib.Serialization
default:
Debug.Assert(false);
if(m_slLogger != null)
m_slLogger.SetText(KLRes.UnknownHeaderId + ": " +
m_slLogger.SetText(KLRes.UnknownHeaderId + @": " +
kdbID.ToString() + "!", LogStatusType.Warning);
break;
}
@@ -491,7 +487,6 @@ namespace KeePassLib.Serialization
ProtectedBinary pb = new ProtectedBinary(bProt, pbData,
1, pbData.Length - 1);
Debug.Assert(m_pbsBinaries.Find(pb) < 0); // No deduplication?
m_pbsBinaries.Add(pb);
if(bProt) MemUtil.ZeroByteArray(pbData);
@@ -531,29 +526,6 @@ namespace KeePassLib.Serialization
m_craInnerRandomStream = (CrsAlgorithm)uID;
}
internal static PwGroup ReadGroup(Stream msData, PwDatabase pdContext,
bool bCopyIcons, bool bNewUuids, bool bSetCreatedNow)
{
PwDatabase pd = new PwDatabase();
pd.New(new IOConnectionInfo(), new CompositeKey(), "");
KdbxFile f = new KdbxFile(pd);
f.Load(msData, KdbxFormat.PlainXml, null);
if (bCopyIcons)
PwDatabase.CopyCustomIcons(pd, pdContext, pd.RootGroup, true);
if (bNewUuids)
{
pd.RootGroup.Uuid = new PwUuid(true);
pd.RootGroup.CreateNewItemUuids(true, true, true);
}
if (bSetCreatedNow) pd.RootGroup.SetCreatedNow(true);
return pd.RootGroup;
}
[Obsolete]
public static List<PwEntry> ReadEntries(Stream msData)
{
@@ -565,14 +537,81 @@ namespace KeePassLib.Serialization
{
return ReadEntries(msData, pdContext, true);
}
/// <summary>
/// Read entries from a stream.
/// </summary>
/// <param name="msData">Input stream to read the entries from.</param>
/// <returns>Extracted entries.</returns>
/// <param name="pdContext">Context database (e.g. for storing icons).</param>
/// <param name="bCopyIcons">If <c>true</c>, custom icons required by
/// the loaded entries are copied to the context database.</param>
/// <returns>Loaded entries.</returns>
public static List<PwEntry> ReadEntries(Stream msData, PwDatabase pdContext,
bool bCopyIcons)
{
if (msData == null) { Debug.Assert(false); return new List<PwEntry>(); }
List<PwEntry> lEntries = new List<PwEntry>();
/* KdbxFile f = new KdbxFile(pwDatabase);
if(msData == null) { Debug.Assert(false); return lEntries; }
f.m_format = KdbxFormat.PlainXml;
PwGroup pg = ReadGroup(msData, pdContext, bCopyIcons, true, true);
return pg.GetEntries(true).CloneShallowToList();
XmlDocument doc = new XmlDocument();
doc.Load(msData);
XmlElement el = doc.DocumentElement;
if(el.Name != ElemRoot) throw new FormatException();
List<PwEntry> vEntries = new List<PwEntry>();
foreach(XmlNode xmlChild in el.ChildNodes)
{
if(xmlChild.Name == ElemEntry)
{
PwEntry pe = f.ReadEntry(xmlChild);
pe.Uuid = new PwUuid(true);
foreach(PwEntry peHistory in pe.History)
peHistory.Uuid = pe.Uuid;
vEntries.Add(pe);
}
else { Debug.Assert(false); }
}
return vEntries; */
PwDatabase pd = new PwDatabase();
pd.New(new IOConnectionInfo(), new CompositeKey(), "");
KdbxFile f = new KdbxFile(pd);
f.Load(msData, KdbxFormat.PlainXml, null);
foreach(PwEntry pe in pd.RootGroup.Entries)
{
pe.SetUuid(new PwUuid(true), true);
lEntries.Add(pe);
if(bCopyIcons && (pdContext != null))
{
PwUuid pu = pe.CustomIconUuid;
if(!pu.Equals(PwUuid.Zero))
{
int iSrc = pd.GetCustomIconIndex(pu);
int iDst = pdContext.GetCustomIconIndex(pu);
if(iSrc < 0) { Debug.Assert(false); }
else if(iDst < 0)
{
pdContext.CustomIcons.Add(pd.CustomIcons[iSrc]);
pdContext.Modified = true;
pdContext.UINeedsIconUpdate = true;
}
}
}
}
return lEntries;
}
}
}

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@ using System.IO;
using System.Security;
using System.Text;
using System.Xml;
using keepass2android;
#if !KeePassUAP
using System.Drawing;
using System.Security.Cryptography;
@@ -48,6 +48,8 @@ using KeePassLib.Resources;
using KeePassLib.Security;
using KeePassLib.Utility;
using keepass2android;
namespace KeePassLib.Serialization
{
/// <summary>
@@ -87,7 +89,6 @@ namespace KeePassLib.Serialization
m_format = fmt;
m_slLogger = slLogger;
m_xmlWriter = null;
PwGroup pgRoot = (pgDataSource ?? m_pwDatabase.RootGroup);
UTF8Encoding encNoBom = StrUtil.Utf8;
@@ -95,7 +96,7 @@ namespace KeePassLib.Serialization
byte[] pbCipherKey = null;
byte[] pbHmacKey64 = null;
m_pbsBinaries = new ProtectedBinarySet(true);
m_pbsBinaries.Clear();
m_pbsBinaries.AddFrom(pgRoot);
List<Stream> lStreams = new List<Stream>();
@@ -106,10 +107,6 @@ namespace KeePassLib.Serialization
try
{
// Fix history entries (should not be necessary; just for safety,
// as e.g. XPath searches depend on correct history entry UUIDs)
if (m_pwDatabase.MaintainBackups()) { Debug.Assert(false); }
m_uFileVersion = GetMinKdbxVersion();
int cbEncKey, cbEncIV;
@@ -254,8 +251,6 @@ namespace KeePassLib.Serialization
private void CommonCleanUpWrite(List<Stream> lStreams, HashingStreamEx sHashing)
{
if (m_xmlWriter != null) { m_xmlWriter.Close(); m_xmlWriter = null; }
CloseStreams(lStreams);
Debug.Assert(lStreams.Contains(sHashing)); // sHashing must be closed
@@ -264,6 +259,7 @@ namespace KeePassLib.Serialization
CleanUpInnerRandomStream();
m_xmlWriter = null;
m_pbHashOfHeader = null;
}
@@ -453,16 +449,14 @@ namespace KeePassLib.Serialization
++uCurEntry;
if(m_slLogger != null)
{
if(!m_slLogger.SetProgress((100 * uCurEntry) / uNumEntries))
return false;
}
return true;
};
if(!pgRoot.TraverseTree(TraversalMethod.PreOrder, gh, eh))
throw new OperationCanceledException();
throw new InvalidOperationException();
while(groupStack.Count > 1)
{
@@ -547,16 +541,6 @@ namespace KeePassLib.Serialization
WriteObject(ElemEnableSearching, StrUtil.BoolToStringEx(pg.EnableSearching), false);
WriteObject(ElemLastTopVisibleEntry, pg.LastTopVisibleEntry);
if (m_uFileVersion >= FileVersion32_4_1)
{
if (!pg.PreviousParentGroup.Equals(PwUuid.Zero))
WriteObject(ElemPreviousParentGroup, pg.PreviousParentGroup);
List<string> lTags = pg.Tags;
if (lTags.Count != 0)
WriteObject(ElemTags, StrUtil.TagsToString(lTags, false), true);
}
if(pg.CustomData.Count > 0)
WriteList(ElemCustomData, pg.CustomData);
}
@@ -581,16 +565,8 @@ namespace KeePassLib.Serialization
WriteObject(ElemFgColor, StrUtil.ColorToUnnamedHtml(pe.ForegroundColor, true), false);
WriteObject(ElemBgColor, StrUtil.ColorToUnnamedHtml(pe.BackgroundColor, true), false);
WriteObject(ElemOverrideUrl, pe.OverrideUrl, true);
if ((m_uFileVersion >= FileVersion32_4_1) && !pe.QualityCheck)
WriteObject(ElemQualityCheck, false);
WriteObject(ElemTags, StrUtil.TagsToString(pe.Tags, false), true);
if ((m_uFileVersion >= FileVersion32_4_1) &&
!pe.PreviousParentGroup.Equals(PwUuid.Zero))
WriteObject(ElemPreviousParentGroup, pe.PreviousParentGroup);
WriteList(ElemTimes, pe);
WriteList(pe.Strings, true);
@@ -640,7 +616,7 @@ namespace KeePassLib.Serialization
foreach(AutoTypeAssociation a in cfgAutoType.Associations)
WriteObject(ElemAutoTypeItem, ElemWindow, ElemKeystrokeSequence,
new KeyValuePair<string, string>(a.WindowName, a.Sequence), null);
new KeyValuePair<string, string>(a.WindowName, a.Sequence));
m_xmlWriter.WriteEndElement();
}
@@ -660,7 +636,7 @@ namespace KeePassLib.Serialization
WriteObject(ElemUsageCount, times.UsageCount);
WriteObject(ElemLocationChanged, times.LocationChanged);
m_xmlWriter.WriteEndElement();
m_xmlWriter.WriteEndElement(); // Name
}
private void WriteList(string name, PwObjectList<PwEntry> value, bool bIsHistory)
@@ -714,13 +690,7 @@ namespace KeePassLib.Serialization
m_xmlWriter.WriteStartElement(name);
foreach(KeyValuePair<string, string> kvp in value)
{
DateTime? odtLastMod = null;
if (m_uFileVersion >= FileVersion32_4_1)
odtLastMod = value.GetLastModificationTime(kvp.Key);
WriteObject(ElemStringDictExItem, ElemKey, ElemValue, kvp, odtLastMod);
}
WriteObject(ElemStringDictExItem, ElemKey, ElemValue, kvp);
m_xmlWriter.WriteEndElement();
}
@@ -731,23 +701,15 @@ namespace KeePassLib.Serialization
m_xmlWriter.WriteStartElement(ElemCustomIcons);
foreach (PwCustomIcon ci in m_pwDatabase.CustomIcons)
foreach(PwCustomIcon pwci in m_pwDatabase.CustomIcons)
{
m_xmlWriter.WriteStartElement(ElemCustomIconItem);
WriteObject(ElemCustomIconItemID, ci.Uuid);
WriteObject(ElemCustomIconItemID, pwci.Uuid);
string strData = Convert.ToBase64String(ci.ImageDataPng);
string strData = Convert.ToBase64String(pwci.ImageDataPng);
WriteObject(ElemCustomIconItemData, strData, false);
if (m_uFileVersion >= FileVersion32_4_1)
{
if (ci.Name.Length != 0)
WriteObject(ElemName, ci.Name, true);
if (ci.LastModificationTime.HasValue)
WriteObject(ElemLastModTime, ci.LastModificationTime.Value);
}
m_xmlWriter.WriteEndElement();
}
@@ -847,22 +809,18 @@ namespace KeePassLib.Serialization
else WriteObject(name, TimeUtil.SerializeUtc(value), false);
}
private void WriteObject(string name, string strKeyName, string strValueName,
KeyValuePair<string, string> kvp, DateTime? odtLastMod)
private void WriteObject(string name, string strKeyName,
string strValueName, KeyValuePair<string, string> kvp)
{
m_xmlWriter.WriteStartElement(name);
m_xmlWriter.WriteStartElement(strKeyName);
m_xmlWriter.WriteString(StrUtil.SafeXmlString(kvp.Key));
m_xmlWriter.WriteEndElement();
m_xmlWriter.WriteStartElement(strValueName);
m_xmlWriter.WriteString(StrUtil.SafeXmlString(kvp.Value));
m_xmlWriter.WriteEndElement();
if (odtLastMod.HasValue)
WriteObject(ElemLastModTime, odtLastMod.Value);
m_xmlWriter.WriteEndElement();
}
@@ -899,9 +857,9 @@ namespace KeePassLib.Serialization
{
m_xmlWriter.WriteAttributeString(AttrProtected, ValTrue);
byte[] pbEnc = value.ReadXorredString(m_randomStream);
if (pbEnc.Length > 0)
m_xmlWriter.WriteBase64(pbEnc, 0, pbEnc.Length);
byte[] pbEncoded = value.ReadXorredString(m_randomStream);
if(pbEncoded.Length > 0)
m_xmlWriter.WriteBase64(pbEncoded, 0, pbEncoded.Length);
}
else
{
@@ -911,7 +869,7 @@ namespace KeePassLib.Serialization
// string transformation here. By default, language-dependent conversions
// should be applied, otherwise characters could be rendered incorrectly
// (code page problems).
if (g_bLocalizedNames)
if(m_bLocalizedNames)
{
StringBuilder sb = new StringBuilder();
foreach(char ch in strValue)
@@ -922,7 +880,8 @@ namespace KeePassLib.Serialization
// page area
if(char.IsSymbol(ch) || char.IsSurrogate(ch))
{
UnicodeCategory cat = CharUnicodeInfo.GetUnicodeCategory(ch);
System.Globalization.UnicodeCategory cat =
CharUnicodeInfo.GetUnicodeCategory(ch);
// Map character to correct position in code page
chMapped = (char)((int)cat * 32 + ch);
}
@@ -990,9 +949,9 @@ namespace KeePassLib.Serialization
{
m_xmlWriter.WriteAttributeString(AttrProtected, ValTrue);
byte[] pbEnc = value.ReadXorredData(m_randomStream);
if (pbEnc.Length > 0)
m_xmlWriter.WriteBase64(pbEnc, 0, pbEnc.Length);
byte[] pbEncoded = value.ReadXorredData(m_randomStream);
if(pbEncoded.Length > 0)
m_xmlWriter.WriteBase64(pbEncoded, 0, pbEncoded.Length);
}
else
{
@@ -1048,25 +1007,6 @@ namespace KeePassLib.Serialization
m_xmlWriter.WriteEndElement();
}
internal static void WriteGroup(Stream msOutput, PwDatabase pdContext,
PwGroup pg)
{
if (msOutput == null) throw new ArgumentNullException("msOutput");
// pdContext may be null
if (pg == null) throw new ArgumentNullException("pg");
PwDatabase pd = new PwDatabase();
pd.New(new IOConnectionInfo(), new CompositeKey(), pg.Name);
pd.RootGroup = pg.CloneDeep();
pd.RootGroup.ParentGroup = null;
PwDatabase.CopyCustomIcons(pdContext, pd, pd.RootGroup, true);
KdbxFile f = new KdbxFile(pd);
f.Save(msOutput, null, KdbxFormat.PlainXml, null);
}
[Obsolete]
public static bool WriteEntries(Stream msOutput, PwEntry[] vEntries)
{
@@ -1080,15 +1020,60 @@ namespace KeePassLib.Serialization
// pdContext may be null
if (vEntries == null) { Debug.Assert(false); return false; }
PwGroup pg = new PwGroup(true, true);
/* KdbxFile f = new KdbxFile(pwDatabase);
f.m_format = KdbxFormat.PlainXml;
XmlTextWriter xtw = null;
try { xtw = new XmlTextWriter(msOutput, StrUtil.Utf8); }
catch(Exception) { Debug.Assert(false); return false; }
if(xtw == null) { Debug.Assert(false); return false; }
f.m_xmlWriter = xtw;
xtw.Formatting = Formatting.Indented;
xtw.IndentChar = '\t';
xtw.Indentation = 1;
xtw.WriteStartDocument(true);
xtw.WriteStartElement(ElemRoot);
foreach(PwEntry pe in vEntries)
f.WriteEntry(pe, false);
xtw.WriteEndElement();
xtw.WriteEndDocument();
xtw.Flush();
xtw.Close();
return true; */
PwDatabase pd = new PwDatabase();
pd.New(new IOConnectionInfo(), new CompositeKey(), "");
PwGroup pg = pd.RootGroup;
if (pg == null) { Debug.Assert(false); return false; }
foreach (PwEntry pe in vEntries)
{
PwUuid pu = pe.CustomIconUuid;
if (!pu.Equals(PwUuid.Zero) && (pd.GetCustomIconIndex(pu) < 0))
{
int i = -1;
if (pdContext != null) i = pdContext.GetCustomIconIndex(pu);
if (i >= 0)
{
PwCustomIcon ci = pdContext.CustomIcons[i];
pd.CustomIcons.Add(ci);
}
else { Debug.Assert(pdContext == null); }
}
PwEntry peCopy = pe.CloneDeep();
pg.AddEntry(peCopy, true);
}
WriteGroup(msOutput, pdContext, pg);
KdbxFile f = new KdbxFile(pd);
f.Save(msOutput, null, KdbxFormat.PlainXml, null);
return true;
}
}

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -67,9 +67,6 @@ namespace KeePassLib.Serialization
/// </summary>
public sealed partial class KdbxFile
{
/// <summary>
/// System.Drawing.ColorTranslator is not supported on Android. Provide a custom implementation here for loading colors from file.
/// </summary>
private class ColorTranslator
{
public static Color FromHtml(String colorString)
@@ -111,7 +108,6 @@ namespace KeePassLib.Serialization
}
}
/// <summary>
/// File identifier, first 32-bit value.
/// </summary>
@@ -123,17 +119,16 @@ namespace KeePassLib.Serialization
internal const uint FileSignature2 = 0xB54BFB67;
/// <summary>
/// Maximum supported version of database files.
/// File version of files saved by the current <c>KdbxFile</c> class.
/// KeePass 2.07 has version 1.01, 2.08 has 1.02, 2.09 has 2.00,
/// 2.10 has 2.02, 2.11 has 2.04, 2.15 has 3.00, 2.20 has 3.01.
/// The first 2 bytes are critical (i.e. loading will fail, if the
/// file version is too high), the last 2 bytes are informational.
/// </summary>
private const uint FileVersion32 = 0x00040001;
private const uint FileVersion32 = 0x00040000;
public const uint FileVersion32_4_1 = 0x00040001; // 4.1
public const uint FileVersion32_4 = 0x00040000; // 4.0
public const uint FileVersion32_3_1 = 0x00030001; // 3.1
public const uint FileVersion32_4 = 0x00040000; // First of 4.x series
public const uint FileVersion32_3 = 0x00030001; // Old format 3.1
private const uint FileVersionCriticalMask = 0xFFFF0000;
@@ -148,7 +143,7 @@ namespace KeePassLib.Serialization
private const string ElemMeta = "Meta";
private const string ElemRoot = "Root";
private const string ElemGroup = "Group";
internal const string ElemEntry = "Entry";
private const string ElemEntry = "Entry";
private const string ElemGenerator = "Generator";
private const string ElemHeaderHash = "HeaderHash";
@@ -193,13 +188,12 @@ namespace KeePassLib.Serialization
private const string ElemName = "Name";
private const string ElemNotes = "Notes";
internal const string ElemUuid = "UUID";
private const string ElemUuid = "UUID";
private const string ElemIcon = "IconID";
private const string ElemCustomIconID = "CustomIconUUID";
private const string ElemFgColor = "ForegroundColor";
private const string ElemBgColor = "BackgroundColor";
private const string ElemOverrideUrl = "OverrideURL";
private const string ElemQualityCheck = "QualityCheck";
private const string ElemTimes = "Times";
private const string ElemTags = "Tags";
@@ -211,8 +205,6 @@ namespace KeePassLib.Serialization
private const string ElemUsageCount = "UsageCount";
private const string ElemLocationChanged = "LocationChanged";
private const string ElemPreviousParentGroup = "PreviousParentGroup";
private const string ElemGroupDefaultAutoTypeSeq = "DefaultAutoTypeSequence";
private const string ElemEnableAutoType = "EnableAutoType";
private const string ElemEnableSearching = "EnableSearching";
@@ -269,7 +261,7 @@ namespace KeePassLib.Serialization
private CrsAlgorithm m_craInnerRandomStream = CrsAlgorithm.ArcFourVariant;
private byte[] m_pbInnerRandomStreamKey = null;
private ProtectedBinarySet m_pbsBinaries = null;
private ProtectedBinarySet m_pbsBinaries = new ProtectedBinarySet();
private byte[] m_pbHashOfHeader = null;
private byte[] m_pbHashOfFileOnDisk = null;
@@ -279,7 +271,7 @@ namespace KeePassLib.Serialization
private const uint NeutralLanguageOffset = 0x100000; // 2^20, see 32-bit Unicode specs
private const uint NeutralLanguageIDSec = 0x7DC5C; // See 32-bit Unicode specs
private const uint NeutralLanguageID = NeutralLanguageOffset + NeutralLanguageIDSec;
private static bool g_bLocalizedNames = false;
private static bool m_bLocalizedNames = false;
private enum KdbxHeaderFieldID : byte
{
@@ -364,8 +356,8 @@ namespace KeePassLib.Serialization
public static void DetermineLanguageId()
{
// Test if localized names should be used. If localized names are used,
// the g_bLocalizedNames value must be set to true. By default, localized
// names should be used (otherwise characters could be corrupted
// the m_bLocalizedNames value must be set to true. By default, localized
// names should be used! (Otherwise characters could be corrupted
// because of different code pages).
unchecked
{
@@ -373,7 +365,7 @@ namespace KeePassLib.Serialization
foreach(char ch in PwDatabase.LocalizedAppName)
uTest = uTest * 5 + ch;
g_bLocalizedNames = (uTest != NeutralLanguageID);
m_bLocalizedNames = (uTest != NeutralLanguageID);
}
}
@@ -381,75 +373,40 @@ namespace KeePassLib.Serialization
{
if(m_uForceVersion != 0) return m_uForceVersion;
// See also KeePassKdb2x3.Export (KDBX 3.1 export module)
uint minVersionForKeys = m_pwDatabase.MasterKey.UserKeys.Select(key => key.GetMinKdbxVersion()).Max();
uint minRequiredVersion = Math.Max(minVersionForKeys, m_uFileVersion); //don't save a version lower than what we read
return Math.Max(minRequiredVersion, GetMinKdbxVersionOrig());
}
private uint GetMinKdbxVersionOrig()
{
if (m_uForceVersion != 0) return m_uForceVersion;
AesKdf kdfAes = new AesKdf();
if(!kdfAes.Uuid.Equals(m_pwDatabase.KdfParameters.KdfUuid))
return Math.Max(FileVersion32, minRequiredVersion);
// See also KeePassKdb2x3.Export (KDBX 3.1 export module)
if(m_pwDatabase.PublicCustomData.Count > 0)
return Math.Max(FileVersion32, minRequiredVersion);
uint uMin = 0;
bool bCustomData = false;
GroupHandler gh = delegate(PwGroup pg)
{
if(pg == null) { Debug.Assert(false); return true; }
if (pg.Tags.Count != 0)
uMin = Math.Max(uMin, FileVersion32_4_1);
if (pg.CustomData.Count != 0)
uMin = Math.Max(uMin, FileVersion32_4);
if(pg.CustomData.Count > 0) { bCustomData = true; return false; }
return true;
};
EntryHandler eh = delegate(PwEntry pe)
{
if(pe == null) { Debug.Assert(false); return true; }
if (!pe.QualityCheck)
uMin = Math.Max(uMin, FileVersion32_4_1);
if (pe.CustomData.Count != 0)
uMin = Math.Max(uMin, FileVersion32_4);
if(pe.CustomData.Count > 0) { bCustomData = true; return false; }
return true;
};
gh(m_pwDatabase.RootGroup);
m_pwDatabase.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh);
if(bCustomData)
return Math.Max(FileVersion32, minRequiredVersion);
if (uMin >= FileVersion32_4_1) return uMin; // All below is <= 4.1
foreach (PwCustomIcon ci in m_pwDatabase.CustomIcons)
{
if ((ci.Name.Length != 0) || ci.LastModificationTime.HasValue)
return FileVersion32_4_1;
}
foreach (KeyValuePair<string, string> kvp in m_pwDatabase.CustomData)
{
DateTime? odt = m_pwDatabase.CustomData.GetLastModificationTime(kvp.Key);
if (odt.HasValue) return FileVersion32_4_1;
}
if (uMin >= FileVersion32_4) return uMin; // All below is <= 4
if (m_pwDatabase.DataCipherUuid.Equals(ChaCha20Engine.ChaCha20Uuid))
return FileVersion32_4;
AesKdf kdfAes = new AesKdf();
if (!m_pwDatabase.KdfParameters.KdfUuid.Equals(kdfAes.Uuid))
return FileVersion32_4;
if (m_pwDatabase.PublicCustomData.Count != 0)
return FileVersion32_4;
return FileVersion32_3_1; // KDBX 3.1 is sufficient
return Math.Max(FileVersion32_3, minRequiredVersion); ; // KDBX 3.1 is sufficient
}
private void ComputeKeys(out byte[] pbCipherKey, int cbCipherKey,
@@ -464,7 +421,7 @@ namespace KeePassLib.Serialization
Debug.Assert(m_pbMasterSeed.Length == 32);
if(m_pbMasterSeed.Length != 32)
throw new FormatException(KLRes.MasterSeedLengthInvalid);
Array.Copy(m_pbMasterSeed, 0, pbCmp, 0, 32);
Debug.Assert(m_pwDatabase != null);
Debug.Assert(m_pwDatabase.MasterKey != null);
@@ -585,7 +542,7 @@ namespace KeePassLib.Serialization
{
if(pb == null) { Debug.Assert(false); return; }
strName = UrlUtil.GetSafeFileName(strName);
if(string.IsNullOrEmpty(strName)) strName = "File.bin";
string strPath;
int iTry = 1;
@@ -593,8 +550,8 @@ namespace KeePassLib.Serialization
{
strPath = UrlUtil.EnsureTerminatingSeparator(strSaveDir, false);
string strDesc = UrlUtil.StripExtension(strName);
string strExt = UrlUtil.GetExtension(strName);
string strDesc = UrlUtil.StripExtension(strName);
strPath += strDesc;
if(iTry > 1)
@@ -607,9 +564,17 @@ namespace KeePassLib.Serialization
}
while(File.Exists(strPath));
#if !KeePassLibSD
byte[] pbData = pb.ReadData();
try { File.WriteAllBytes(strPath, pbData); }
finally { if (pb.IsProtected) MemUtil.ZeroByteArray(pbData); }
File.WriteAllBytes(strPath, pbData);
MemUtil.ZeroByteArray(pbData);
#else
FileStream fs = new FileStream(strPath, FileMode.Create,
FileAccess.Write, FileShare.None);
byte[] pbData = pb.ReadData();
fs.Write(pbData, 0, pbData.Length);
fs.Close();
#endif
}
}
}

View File

@@ -28,8 +28,8 @@ namespace KeePassLib.Serialization
/// </summary>
public static KdbxFormat GetFormatToUse(string fileExt)
{
return fileExt.Equals(KdbpFile.FileNameExtension, StringComparison.OrdinalIgnoreCase) ? KdbxFormat.ProtocolBuffers :
(fileExt.Equals("xml", StringComparison.OrdinalIgnoreCase) ? KdbxFormat.PlainXml : KdbxFormat.Default);
// If the filename ends in .kdbp, use ProtocolBuffers format.
return fileExt.Equals(KdbpFile.FileNameExtension, StringComparison.OrdinalIgnoreCase) ? KdbxFormat.ProtocolBuffers : KdbxFormat.Default;
}
public static void WriteDocument(PwDatabase database, Stream stream, byte[] protectedStreamKey, byte[] hashOfHeader)

View File

@@ -37,7 +37,7 @@ namespace KeePassLib.Utility
/// </summary>
public static class MemUtil
{
public static readonly byte[] EmptyByteArray = new byte[0];
internal static readonly byte[] EmptyByteArray = new byte[0];
private static readonly uint[] m_vSBox = new uint[256] {
0xCD2FACB3, 0xE78A7F5C, 0x6F0803FC, 0xBCF6E230,
@@ -786,28 +786,5 @@ namespace KeePassLib.Utility
yield break;
}
internal static bool ListsEqual<T>(List<T> a, List<T> b)
where T : class, IEquatable<T>
{
if (object.ReferenceEquals(a, b)) return true;
if ((a == null) || (b == null)) return false;
int n = a.Count;
if (n != b.Count) return false;
for (int i = 0; i < n; ++i)
{
T tA = a[i], tB = b[i];
if (tA == null)
{
if (tB != null) return false;
}
else if (tB == null) return false;
else if (!tA.Equals(tB)) return false;
}
return true;
}
}
}

View File

@@ -429,7 +429,7 @@ Clipboard.SetText(ObjectsToMessage(vLines, true));*/
if ((strFilePath != null) && (strFilePath.Length > 0))
str += strFilePath + MessageService.NewParagraph;
str += KLRes.FileSaveFailed2;
str += KLRes.FileSaveFailed;
if ((ex != null) && (ex.Message != null) && (ex.Message.Length > 0))
str += MessageService.NewParagraph + ex.Message;

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@ using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
#if !KeePassUAP
using System.Drawing;
@@ -31,7 +32,6 @@ using System.Security.Cryptography;
#endif
using KeePassLib.Collections;
using KeePassLib.Cryptography;
using KeePassLib.Cryptography.PasswordGenerator;
using KeePassLib.Native;
using KeePassLib.Security;
@@ -43,41 +43,45 @@ namespace KeePassLib.Utility
/// </summary>
public sealed class CharStream
{
private readonly string m_str;
private int m_iPos = 0;
public long Position
{
get { return m_iPos; }
set
{
if ((value < 0) || (value > int.MaxValue))
throw new ArgumentOutOfRangeException("value");
m_iPos = (int)value;
}
}
private string m_strString = string.Empty;
private int m_nPos = 0;
public CharStream(string str)
{
if (str == null) { Debug.Assert(false); throw new ArgumentNullException("str"); }
Debug.Assert(str != null);
if(str == null) throw new ArgumentNullException("str");
m_str = str;
m_strString = str;
}
public void Seek(SeekOrigin org, int nSeek)
{
if(org == SeekOrigin.Begin)
m_nPos = nSeek;
else if(org == SeekOrigin.Current)
m_nPos += nSeek;
else if(org == SeekOrigin.End)
m_nPos = m_strString.Length + nSeek;
}
public char ReadChar()
{
if (m_iPos >= m_str.Length) return char.MinValue;
if(m_nPos < 0) return char.MinValue;
if(m_nPos >= m_strString.Length) return char.MinValue;
return m_str[m_iPos++];
char chRet = m_strString[m_nPos];
++m_nPos;
return chRet;
}
public char ReadChar(bool bSkipWhiteSpace)
{
if (!bSkipWhiteSpace) return ReadChar();
if(bSkipWhiteSpace == false) return ReadChar();
while(true)
{
char ch = ReadChar();
if((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n'))
return ch;
}
@@ -85,25 +89,29 @@ namespace KeePassLib.Utility
public char PeekChar()
{
if (m_iPos >= m_str.Length) return char.MinValue;
if(m_nPos < 0) return char.MinValue;
if(m_nPos >= m_strString.Length) return char.MinValue;
return m_str[m_iPos];
return m_strString[m_nPos];
}
public char PeekChar(bool bSkipWhiteSpace)
{
if (!bSkipWhiteSpace) return PeekChar();
if(bSkipWhiteSpace == false) return PeekChar();
int i = m_iPos;
while (i < m_str.Length)
int iIndex = m_nPos;
while(true)
{
char ch = m_str[i];
if(iIndex < 0) return char.MinValue;
if(iIndex >= m_strString.Length) return char.MinValue;
char ch = m_strString[iIndex];
if((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n'))
return ch;
++i;
}
return char.MinValue;
++iIndex;
}
}
}
@@ -179,7 +187,7 @@ namespace KeePassLib.Utility
/// </summary>
public static class StrUtil
{
public static readonly StringComparison CaseIgnoreCmp = StringComparison.OrdinalIgnoreCase;
public const StringComparison CaseIgnoreCmp = StringComparison.OrdinalIgnoreCase;
public static StringComparer CaseIgnoreComparer
{
@@ -291,82 +299,23 @@ namespace KeePassLib.Utility
return ("\\u" + sh.ToString(NumberFormatInfo.InvariantInfo) + "?");
}
internal static bool RtfIsURtf(string str)
{
if (str == null) { Debug.Assert(false); return false; }
const string p = "{\\urtf"; // Typically "{\\urtf1\\ansi\\ansicpg65001"
return (str.StartsWith(p) && (str.Length > p.Length) &&
char.IsDigit(str[p.Length]));
}
public static string RtfFix(string strRtf)
{
if (strRtf == null) { Debug.Assert(false); return string.Empty; }
string str = strRtf;
// Workaround for .NET bug: the Rtf property of a RichTextBox
// can return an RTF text starting with "{\\urtf", but
// setting such an RTF text throws an exception (the setter
// checks for the RTF text to start with "{\\rtf");
// https://sourceforge.net/p/keepass/discussion/329221/thread/7788872f/
// https://www.microsoft.com/en-us/download/details.aspx?id=10725
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb774284.aspx
// https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/RichTextBox.cs
if (RtfIsURtf(str)) str = str.Remove(2, 1); // Remove the 'u'
return str;
}
internal static string RtfFilterText(string strText)
{
if (strText == null) { Debug.Assert(false); return string.Empty; }
// A U+FFFC character causes the rest of the text to be lost.
// With '?', the string length, substring indices and
// character visibility remain the same.
// More special characters (unproblematic) in rich text boxes:
// https://docs.microsoft.com/en-us/windows/win32/api/richedit/ns-richedit-gettextex
return strText.Replace('\uFFFC', '?');
}
internal static bool ContainsHighChar(string str)
{
if (str == null) { Debug.Assert(false); return false; }
for (int i = 0; i < str.Length; ++i)
{
if (str[i] > '\u00FF') return true;
}
return false;
}
/// <summary>
/// Convert a string to a HTML sequence representing that string.
/// Convert a string into a valid HTML sequence representing that string.
/// </summary>
/// <param name="str">String to convert.</param>
/// <returns>String, HTML-encoded.</returns>
public static string StringToHtml(string str)
{
return StringToHtml(str, false);
}
internal static string StringToHtml(string str, bool bNbsp)
{
Debug.Assert(str != null); if(str == null) throw new ArgumentNullException("str");
str = str.Replace(@"&", @"&amp;"); // Must be first
str = str.Replace(@"&", @"&amp;");
str = str.Replace(@"<", @"&lt;");
str = str.Replace(@">", @"&gt;");
str = str.Replace("\"", @"&quot;");
str = str.Replace("\'", @"&#39;");
if (bNbsp) str = str.Replace(" ", @"&nbsp;"); // Before <br />
str = NormalizeNewLines(str, false);
str = str.Replace("\n", @"<br />" + MessageService.NewLine);
str = str.Replace("\n", @"<br />\n" );
return str;
}
@@ -408,6 +357,46 @@ namespace KeePassLib.Utility
return str;
}
/// <summary>
/// Split up a command line into application and argument.
/// </summary>
/// <param name="strCmdLine">Command line to split.</param>
/// <param name="strApp">Application path.</param>
/// <param name="strArgs">Arguments.</param>
public static void SplitCommandLine(string strCmdLine, out string strApp, out string strArgs)
{
Debug.Assert(strCmdLine != null); if(strCmdLine == null) throw new ArgumentNullException("strCmdLine");
string str = strCmdLine.Trim();
strApp = null; strArgs = null;
if(str.StartsWith("\""))
{
int nSecond = str.IndexOf('\"', 1);
if(nSecond >= 1)
{
strApp = str.Substring(1, nSecond - 1).Trim();
strArgs = str.Remove(0, nSecond + 1).Trim();
}
}
if(strApp == null)
{
int nSpace = str.IndexOf(' ');
if(nSpace >= 0)
{
strApp = str.Substring(0, nSpace);
strArgs = str.Remove(0, nSpace).Trim();
}
else strApp = strCmdLine;
}
if(strApp == null) strApp = string.Empty;
if(strArgs == null) strArgs = string.Empty;
}
// /// <summary>
// /// Initialize an RTF document based on given font face and size.
// /// </summary>
@@ -498,41 +487,41 @@ namespace KeePassLib.Utility
public static string FormatException(Exception excp)
{
string strText = string.Empty;
if (!string.IsNullOrEmpty(excp.Message))
strText += excp.Message + MessageService.NewLine;
string NewLine = "\n";
if(excp.Message != null)
strText += excp.Message + NewLine;
#if !KeePassLibSD
if (!string.IsNullOrEmpty(excp.Source))
strText += excp.Source + MessageService.NewLine;
if(excp.Source != null)
strText += excp.Source + NewLine;
#endif
if (!string.IsNullOrEmpty(excp.StackTrace))
strText += excp.StackTrace + MessageService.NewLine;
if(excp.StackTrace != null)
strText += excp.StackTrace + NewLine;
#if !KeePassLibSD
#if !KeePassUAP
if(excp.TargetSite != null)
strText += excp.TargetSite.ToString() + MessageService.NewLine;
strText += excp.TargetSite.ToString() + NewLine;
#endif
if(excp.Data != null)
{
strText += MessageService.NewLine;
strText += NewLine;
foreach(DictionaryEntry de in excp.Data)
strText += @"'" + de.Key + @"' -> '" + de.Value + @"'" +
MessageService.NewLine;
NewLine;
}
#endif
if(excp.InnerException != null)
{
strText += MessageService.NewLine + "Inner:" + MessageService.NewLine;
if (!string.IsNullOrEmpty(excp.InnerException.Message))
strText += excp.InnerException.Message + MessageService.NewLine;
strText += NewLine + "Inner:" + NewLine;
if(excp.InnerException.Message != null)
strText += excp.InnerException.Message + NewLine;
#if !KeePassLibSD
if (!string.IsNullOrEmpty(excp.InnerException.Source))
strText += excp.InnerException.Source + MessageService.NewLine;
if(excp.InnerException.Source != null)
strText += excp.InnerException.Source + NewLine;
#endif
if (!string.IsNullOrEmpty(excp.InnerException.StackTrace))
strText += excp.InnerException.StackTrace + MessageService.NewLine;
if(excp.InnerException.StackTrace != null)
strText += excp.InnerException.StackTrace + NewLine;
#if !KeePassLibSD
#if !KeePassUAP
if(excp.InnerException.TargetSite != null)
@@ -541,10 +530,10 @@ namespace KeePassLib.Utility
if(excp.InnerException.Data != null)
{
strText += MessageService.NewLine;
strText += NewLine;
foreach(DictionaryEntry de in excp.InnerException.Data)
strText += @"'" + de.Key + @"' -> '" + de.Value + @"'" +
MessageService.NewLine;
NewLine;
}
#endif
}
@@ -685,29 +674,19 @@ namespace KeePassLib.Utility
#endif
}
public static string CompactString3Dots(string strText, int cchMax)
public static string CompactString3Dots(string strText, int nMaxChars)
{
Debug.Assert(strText != null);
if(strText == null) throw new ArgumentNullException("strText");
Debug.Assert(cchMax >= 0);
if (cchMax < 0) throw new ArgumentOutOfRangeException("cchMax");
Debug.Assert(nMaxChars >= 0);
if(nMaxChars < 0) throw new ArgumentOutOfRangeException("nMaxChars");
if (strText.Length <= cchMax) return strText;
if(nMaxChars == 0) return string.Empty;
if(strText.Length <= nMaxChars) return strText;
if (cchMax == 0) return string.Empty;
if (cchMax <= 3) return new string('.', cchMax);
if(nMaxChars <= 3) return strText.Substring(0, nMaxChars);
return (strText.Substring(0, cchMax - 3) + "...");
}
private static readonly char[] g_vDots = new char[] { '.', '\u2026' };
private static readonly char[] g_vDotsWS = new char[] { '.', '\u2026',
' ', '\t', '\r', '\n' };
internal static string TrimDots(string strText, bool bTrimWhiteSpace)
{
if (strText == null) { Debug.Assert(false); return string.Empty; }
return strText.Trim(bTrimWhiteSpace ? g_vDotsWS : g_vDots);
return strText.Substring(0, nMaxChars - 3) + "...";
}
public static string GetStringBetween(string strText, int nStartIndex,
@@ -740,7 +719,7 @@ namespace KeePassLib.Utility
/// <summary>
/// Removes all characters that are not valid XML characters,
/// according to https://www.w3.org/TR/xml/#charsets .
/// according to http://www.w3.org/TR/xml/#charsets .
/// </summary>
/// <param name="strText">Source text.</param>
/// <returns>Text containing only valid XML characters.</returns>
@@ -936,10 +915,10 @@ namespace KeePassLib.Utility
for(char ch = 'A'; ch <= 'Z'; ++ch)
{
string strEnhAcc = @"(&" + ch.ToString() + ")";
string strEnhAcc = @"(&" + ch.ToString() + @")";
if(str.IndexOf(strEnhAcc) >= 0)
{
str = str.Replace(" " + strEnhAcc, string.Empty);
str = str.Replace(@" " + strEnhAcc, string.Empty);
str = str.Replace(strEnhAcc, string.Empty);
}
}
@@ -952,24 +931,35 @@ namespace KeePassLib.Utility
public static string AddAccelerator(string strMenuText,
List<char> lAvailKeys)
{
if (strMenuText == null) { Debug.Assert(false); return string.Empty; }
if(strMenuText == null) { Debug.Assert(false); return null; }
if(lAvailKeys == null) { Debug.Assert(false); return strMenuText; }
int xa = -1, xs = 0;
for(int i = 0; i < strMenuText.Length; ++i)
{
char ch = char.ToLowerInvariant(strMenuText[i]);
char ch = strMenuText[i];
for (int j = 0; j < lAvailKeys.Count; ++j)
{
if (char.ToLowerInvariant(lAvailKeys[j]) == ch)
{
lAvailKeys.RemoveAt(j);
return strMenuText.Insert(i, @"&");
}
}
#if KeePassLibSD
char chUpper = char.ToUpper(ch);
#else
char chUpper = char.ToUpperInvariant(ch);
#endif
xa = lAvailKeys.IndexOf(chUpper);
if(xa >= 0) { xs = i; break; }
#if KeePassLibSD
char chLower = char.ToLower(ch);
#else
char chLower = char.ToLowerInvariant(ch);
#endif
xa = lAvailKeys.IndexOf(chLower);
if(xa >= 0) { xs = i; break; }
}
return strMenuText;
if(xa < 0) return strMenuText;
lAvailKeys.RemoveAt(xa);
return strMenuText.Insert(xs, @"&");
}
public static string EncodeMenuText(string strText)
@@ -1031,7 +1021,7 @@ namespace KeePassLib.Utility
}
#if !KeePassLibSD
private static readonly char[] g_vPatternPartsSep = new char[] { '*' };
private static readonly char[] m_vPatternPartsSep = new char[] { '*' };
public static bool SimplePatternMatch(string strPattern, string strText,
StringComparison sc)
{
@@ -1040,18 +1030,23 @@ namespace KeePassLib.Utility
if(strPattern.IndexOf('*') < 0) return strText.Equals(strPattern, sc);
string[] vPatternParts = strPattern.Split(g_vPatternPartsSep,
string[] vPatternParts = strPattern.Split(m_vPatternPartsSep,
StringSplitOptions.RemoveEmptyEntries);
if(vPatternParts == null) { Debug.Assert(false); return true; }
if(vPatternParts.Length == 0) return true;
if(strText.Length == 0) return false;
if ((strPattern[0] != '*') && !strText.StartsWith(vPatternParts[0], sc))
if(!strPattern.StartsWith(@"*") && !strText.StartsWith(vPatternParts[0], sc))
{
return false;
if ((strPattern[strPattern.Length - 1] != '*') && !strText.EndsWith(
vPatternParts[vPatternParts.Length - 1], sc))
}
if(!strPattern.EndsWith(@"*") && !strText.EndsWith(vPatternParts[
vPatternParts.Length - 1], sc))
{
return false;
}
int iOffset = 0;
for(int i = 0; i < vPatternParts.Length; ++i)
@@ -1128,58 +1123,32 @@ namespace KeePassLib.Utility
return str;
}
private static char[] m_vNewLineChars = null;
public static void NormalizeNewLines(ProtectedStringDictionary dict,
bool bWindows)
{
if(dict == null) { Debug.Assert(false); return; }
List<string> lKeys = dict.GetKeys();
foreach (string strKey in lKeys)
if(m_vNewLineChars == null)
m_vNewLineChars = new char[]{ '\r', '\n' };
List<string> vKeys = dict.GetKeys();
foreach(string strKey in vKeys)
{
ProtectedString ps = dict.Get(strKey);
if(ps == null) { Debug.Assert(false); continue; }
char[] v = ps.ReadChars();
if (!IsNewLineNormalized(v, bWindows))
string strValue = ps.ReadString();
if(strValue.IndexOfAny(m_vNewLineChars) < 0) continue;
dict.Set(strKey, new ProtectedString(ps.IsProtected,
NormalizeNewLines(ps.ReadString(), bWindows)));
MemUtil.ZeroArray<char>(v);
NormalizeNewLines(strValue, bWindows)));
}
}
internal static bool IsNewLineNormalized(char[] v, bool bWindows)
{
if (v == null) { Debug.Assert(false); return true; }
if (bWindows)
{
int iFreeCr = -2; // Must be < -1 (for test "!= (i - 1)")
for (int i = 0; i < v.Length; ++i)
{
char ch = v[i];
if (ch == '\r')
{
if (iFreeCr >= 0) return false;
iFreeCr = i;
}
else if (ch == '\n')
{
if (iFreeCr != (i - 1)) return false;
iFreeCr = -2; // Consume \r
}
}
return (iFreeCr < 0); // Ensure no \r at end
}
return (Array.IndexOf<char>(v, '\r') < 0);
}
public static string GetNewLineSeq(string str)
{
if (str == null) { Debug.Assert(false); return MessageService.NewLine; }
if(str == null) { Debug.Assert(false); return "\n"; }
int n = str.Length, nLf = 0, nCr = 0, nCrLf = 0;
char chLast = char.MinValue;
@@ -1201,7 +1170,7 @@ namespace KeePassLib.Utility
nLf -= nCrLf;
int nMax = Math.Max(nCrLf, Math.Max(nCr, nLf));
if (nMax == 0) return MessageService.NewLine;
if(nMax == 0) return "\n";
if(nCrLf == nMax) return "\r\n";
return ((nLf == nMax) ? "\n" : "\r");
@@ -1332,15 +1301,7 @@ namespace KeePassLib.Utility
try
{
byte[] pbPlain = StrUtil.Utf8.GetBytes(strPlainText);
byte[] pbEnc = CryptoUtil.ProtectData(pbPlain, m_pbOptEnt,
DataProtectionScope.CurrentUser);
#if (!KeePassLibSD && !KeePassUAP)
return Convert.ToBase64String(pbEnc, Base64FormattingOptions.None);
#else
return Convert.ToBase64String(pbEnc);
#endif
throw new NotSupportedException();
}
catch(Exception) { Debug.Assert(false); }
@@ -1354,10 +1315,8 @@ namespace KeePassLib.Utility
try
{
byte[] pbEnc = Convert.FromBase64String(strCipherText);
byte[] pbPlain = CryptoUtil.UnprotectData(pbEnc, m_pbOptEnt,
DataProtectionScope.CurrentUser);
throw new NotSupportedException();
return StrUtil.Utf8.GetString(pbPlain, 0, pbPlain.Length);
}
catch(Exception) { Debug.Assert(false); }
@@ -1396,98 +1355,27 @@ namespace KeePassLib.Utility
return v;
}
private static readonly char[] g_vTagSep = new char[] { ',', ';' };
internal static string NormalizeTag(string strTag)
private static readonly char[] m_vTagSep = new char[] { ',', ';', ':' };
public static string TagsToString(List<string> vTags, bool bForDisplay)
{
if (strTag == null) { Debug.Assert(false); return string.Empty; }
strTag = strTag.Trim();
for (int i = g_vTagSep.Length - 1; i >= 0; --i)
strTag = strTag.Replace(g_vTagSep[i], '.');
return strTag;
}
internal static void NormalizeTags(List<string> lTags)
{
if (lTags == null) { Debug.Assert(false); return; }
bool bRemoveNulls = false;
for (int i = lTags.Count - 1; i >= 0; --i)
{
string str = NormalizeTag(lTags[i]);
if (string.IsNullOrEmpty(str))
{
lTags[i] = null;
bRemoveNulls = true;
}
else lTags[i] = str;
}
if (bRemoveNulls)
{
Predicate<string> f = delegate (string str) { return (str == null); };
lTags.RemoveAll(f);
}
if (lTags.Count >= 2)
{
// Deduplicate
Dictionary<string, bool> d = new Dictionary<string, bool>();
for (int i = lTags.Count - 1; i >= 0; --i)
d[lTags[i]] = true;
if (d.Count != lTags.Count)
{
lTags.Clear();
lTags.AddRange(d.Keys);
}
lTags.Sort(StrUtil.CompareNaturally);
}
}
internal static void AddTags(List<string> lTags, IEnumerable<string> eNewTags)
{
if (lTags == null) { Debug.Assert(false); return; }
if (eNewTags == null) { Debug.Assert(false); return; }
lTags.AddRange(eNewTags);
NormalizeTags(lTags);
}
public static string TagsToString(List<string> lTags, bool bForDisplay)
{
if (lTags == null) throw new ArgumentNullException("lTags");
#if DEBUG
// The input should be normalized
foreach (string str in lTags) { Debug.Assert(NormalizeTag(str) == str); }
List<string> l = new List<string>(lTags);
NormalizeTags(l);
Debug.Assert(l.Count == lTags.Count);
#endif
int n = lTags.Count;
if (n == 0) return string.Empty;
if (n == 1) return (lTags[0] ?? string.Empty);
if(vTags == null) throw new ArgumentNullException("vTags");
StringBuilder sb = new StringBuilder();
bool bFirst = true;
foreach (string strTag in lTags)
foreach(string strTag in vTags)
{
if(string.IsNullOrEmpty(strTag)) { Debug.Assert(false); continue; }
Debug.Assert(strTag.IndexOfAny(m_vTagSep) < 0);
if (bFirst) bFirst = false;
else
if(!bFirst)
{
if(bForDisplay) sb.Append(", ");
else sb.Append(';');
}
sb.Append(strTag);
bFirst = false;
}
return sb.ToString();
@@ -1500,9 +1388,13 @@ namespace KeePassLib.Utility
List<string> lTags = new List<string>();
if(strTags.Length == 0) return lTags;
lTags.AddRange(strTags.Split(g_vTagSep));
string[] vTags = strTags.Split(m_vTagSep);
foreach(string strTag in vTags)
{
string strFlt = strTag.Trim();
if(strFlt.Length > 0) lTags.Add(strFlt);
}
NormalizeTags(lTags);
return lTags;
}
@@ -1593,8 +1485,8 @@ namespace KeePassLib.Utility
string str = strMulti;
str = str.Replace("\r\n", " ");
str = str.Replace('\r', ' ');
str = str.Replace('\n', ' ');
str = str.Replace("\r", " ");
str = str.Replace("\n", " ");
return str;
}
@@ -1614,16 +1506,14 @@ namespace KeePassLib.Utility
if(((ch == ' ') || (ch == '\t') || (ch == '\r') ||
(ch == '\n')) && !bQuoted)
{
if (sbTerm.Length != 0)
{
l.Add(sbTerm.ToString());
if(sbTerm.Length > 0) l.Add(sbTerm.ToString());
sbTerm.Remove(0, sbTerm.Length);
}
}
else if(ch == '\"') bQuoted = !bQuoted;
else sbTerm.Append(ch);
}
if (sbTerm.Length != 0) l.Add(sbTerm.ToString());
if(sbTerm.Length > 0) l.Add(sbTerm.ToString());
return l;
}
@@ -1639,10 +1529,10 @@ namespace KeePassLib.Utility
return IsDataUri(strUri, null);
}
public static bool IsDataUri(string strUri, string strReqMediaType)
public static bool IsDataUri(string strUri, string strReqMimeType)
{
if(strUri == null) { Debug.Assert(false); return false; }
// strReqMediaType may be null
// strReqMimeType may be null
const string strPrefix = "data:";
if(!strUri.StartsWith(strPrefix, StrUtil.CaseIgnoreCmp))
@@ -1651,14 +1541,14 @@ namespace KeePassLib.Utility
int iC = strUri.IndexOf(',');
if(iC < 0) return false;
if (!string.IsNullOrEmpty(strReqMediaType))
if(!string.IsNullOrEmpty(strReqMimeType))
{
int iS = strUri.IndexOf(';', 0, iC);
int iTerm = ((iS >= 0) ? iS : iC);
string strMedia = strUri.Substring(strPrefix.Length,
string strMime = strUri.Substring(strPrefix.Length,
iTerm - strPrefix.Length);
if (!strMedia.Equals(strReqMediaType, StrUtil.CaseIgnoreCmp))
if(!strMime.Equals(strReqMimeType, StrUtil.CaseIgnoreCmp))
return false;
}
@@ -1669,20 +1559,20 @@ namespace KeePassLib.Utility
/// Create a data URI (according to RFC 2397).
/// </summary>
/// <param name="pbData">Data to encode.</param>
/// <param name="strMediaType">Optional MIME type. If <c>null</c>,
/// <param name="strMimeType">Optional MIME type. If <c>null</c>,
/// an appropriate type is used.</param>
/// <returns>Data URI.</returns>
public static string DataToDataUri(byte[] pbData, string strMediaType)
public static string DataToDataUri(byte[] pbData, string strMimeType)
{
if(pbData == null) throw new ArgumentNullException("pbData");
if (strMediaType == null) strMediaType = "application/octet-stream";
if(strMimeType == null) strMimeType = "application/octet-stream";
#if (!KeePassLibSD && !KeePassUAP)
return ("data:" + strMediaType + ";base64," + Convert.ToBase64String(
return ("data:" + strMimeType + ";base64," + Convert.ToBase64String(
pbData, Base64FormattingOptions.None));
#else
return ("data:" + strMediaType + ";base64," + Convert.ToBase64String(
return ("data:" + strMimeType + ";base64," + Convert.ToBase64String(
pbData));
#endif
}
@@ -1725,54 +1615,6 @@ namespace KeePassLib.Utility
return pb;
}
// https://www.iana.org/assignments/media-types/media-types.xhtml
private static readonly string[] g_vMediaTypePfx = new string[] {
"application/", "audio/", "example/", "font/", "image/",
"message/", "model/", "multipart/", "text/", "video/"
};
internal static bool IsMediaType(string str)
{
if (str == null) { Debug.Assert(false); return false; }
if (str.Length == 0) return false;
foreach (string strPfx in g_vMediaTypePfx)
{
if (str.StartsWith(strPfx, StrUtil.CaseIgnoreCmp))
return true;
}
return false;
}
internal static string GetCustomMediaType(string strFormat)
{
if (strFormat == null)
{
Debug.Assert(false);
return "application/octet-stream";
}
if (IsMediaType(strFormat)) return strFormat;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < strFormat.Length; ++i)
{
char ch = strFormat[i];
if (((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')) ||
((ch >= '0') && (ch <= '9')))
sb.Append(ch);
else if ((sb.Length != 0) && ((ch == '-') || (ch == '_')))
sb.Append(ch);
else { Debug.Assert(false); }
}
if (sb.Length == 0) return "application/octet-stream";
return ("application/vnd." + PwDefs.ShortProductName +
"." + sb.ToString());
}
/// <summary>
/// Remove placeholders from a string (wrapped in '{' and '}').
/// This doesn't remove environment variables (wrapped in '%').
@@ -1892,68 +1734,5 @@ namespace KeePassLib.Utility
// behavior of Notepad (on Windows 10)
return str.Replace('\0', ' ');
}
// https://sourceforge.net/p/keepass/discussion/329220/thread/f98dece5/
internal static string EnsureLtrPath(string strPath)
{
if (strPath == null) { Debug.Assert(false); return string.Empty; }
string str = strPath;
// U+200E = left-to-right mark
str = str.Replace("\\", "\\\u200E");
str = str.Replace("/", "/\u200E");
str = str.Replace("\u200E\u200E", "\u200E"); // Remove duplicates
return str;
}
internal static bool IsValid(string str)
{
if (str == null) { Debug.Assert(false); return false; }
int cc = str.Length;
for (int i = 0; i < cc; ++i)
{
char ch = str[i];
if (ch == '\0') return false;
if (char.IsLowSurrogate(ch)) return false;
if (char.IsHighSurrogate(ch))
{
if (++i >= cc) return false; // High surrogate at end
if (!char.IsLowSurrogate(str[i])) return false;
UnicodeCategory uc2 = char.GetUnicodeCategory(str, i - 1);
if (uc2 == UnicodeCategory.OtherNotAssigned) return false;
continue;
}
UnicodeCategory uc = char.GetUnicodeCategory(ch);
if (uc == UnicodeCategory.OtherNotAssigned) return false;
}
return true;
}
internal static string RemoveWhiteSpace(string str)
{
if (str == null) { Debug.Assert(false); return string.Empty; }
int cc = str.Length;
if (cc == 0) return string.Empty;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < cc; ++i)
{
char ch = str[i];
if (char.IsWhiteSpace(ch)) continue;
sb.Append(ch);
}
return sb.ToString();
}
}
}

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,10 +20,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using KeePassLib.Native;
@@ -35,7 +33,9 @@ namespace KeePassLib.Utility
/// </summary>
public static class UrlUtil
{
private static readonly char[] g_vPathTrimCharsWs = new char[] {
private static readonly char[] m_vDirSeps = new char[] {
'\\', '/', UrlUtil.LocalDirSepChar };
private static readonly char[] m_vPathTrimCharsWs = new char[] {
'\"', ' ', '\t', '\r', '\n' };
public static char LocalDirSepChar
@@ -43,32 +43,6 @@ namespace KeePassLib.Utility
get { return Path.DirectorySeparatorChar; }
}
private static char[] g_vDirSepChars = null;
private static char[] DirSepChars
{
get
{
if (g_vDirSepChars == null)
{
List<char> l = new List<char>();
l.Add('/'); // For URLs, also on Windows
// On Unix-like systems, '\\' is not a separator
if (!NativeLib.IsUnix()) l.Add('\\');
if (!l.Contains(UrlUtil.LocalDirSepChar))
{
Debug.Assert(false);
l.Add(UrlUtil.LocalDirSepChar);
}
g_vDirSepChars = l.ToArray();
}
return g_vDirSepChars;
}
}
/// <summary>
/// Get the directory (path) of a file name. The returned string may be
/// terminated by a directory separator character. Example:
@@ -91,7 +65,7 @@ namespace KeePassLib.Utility
Debug.Assert(strFile != null);
if(strFile == null) throw new ArgumentNullException("strFile");
int nLastSep = strFile.LastIndexOfAny(UrlUtil.DirSepChars);
int nLastSep = strFile.LastIndexOfAny(m_vDirSeps);
if(nLastSep < 0) return string.Empty; // No directory
if(bEnsureValidDirSpec && (nLastSep == 2) && (strFile[1] == ':') &&
@@ -115,7 +89,7 @@ namespace KeePassLib.Utility
{
Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath");
int nLastSep = strPath.LastIndexOfAny(UrlUtil.DirSepChars);
int nLastSep = strPath.LastIndexOfAny(m_vDirSeps);
if(nLastSep < 0) return strPath;
if(nLastSep >= (strPath.Length - 1)) return string.Empty;
@@ -132,7 +106,7 @@ namespace KeePassLib.Utility
{
Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath");
int nLastDirSep = strPath.LastIndexOfAny(UrlUtil.DirSepChars);
int nLastDirSep = strPath.LastIndexOfAny(m_vDirSeps);
int nLastExtDot = strPath.LastIndexOf('.');
if(nLastExtDot <= nLastDirSep) return strPath;
@@ -149,7 +123,7 @@ namespace KeePassLib.Utility
{
Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath");
int nLastDirSep = strPath.LastIndexOfAny(UrlUtil.DirSepChars);
int nLastDirSep = strPath.LastIndexOfAny(m_vDirSeps);
int nLastExtDot = strPath.LastIndexOf('.');
if(nLastExtDot <= nLastDirSep) return string.Empty;
@@ -174,8 +148,11 @@ namespace KeePassLib.Utility
if(nLength <= 0) return string.Empty;
char chLast = strPath[nLength - 1];
if (Array.IndexOf<char>(UrlUtil.DirSepChars, chLast) >= 0)
return strPath;
for(int i = 0; i < m_vDirSeps.Length; ++i)
{
if(chLast == m_vDirSeps[i]) return strPath;
}
if(bUrl) return (strPath + '/');
return (strPath + UrlUtil.LocalDirSepChar);
@@ -239,35 +216,21 @@ namespace KeePassLib.Utility
return false;
} */
internal static int IndexOfSecondEnclQuote(string str)
{
if (str == null) { Debug.Assert(false); return -1; }
if (str.Length <= 1) return -1;
if (str[0] != '\"') { Debug.Assert(false); return -1; }
if (NativeLib.IsUnix())
{
// Find non-escaped quote
string strFlt = str.Replace("\\\\", new string(
StrUtil.GetUnusedChar(str + "\\\""), 2)); // Same length
Match m = Regex.Match(strFlt, "[^\\\\]\\u0022");
int i = (((m != null) && m.Success) ? m.Index : -1);
return ((i >= 0) ? (i + 1) : -1); // Index of quote
}
// Windows does not allow quotes in folder/file names
return str.IndexOf('\"', 1);
}
public static string GetQuotedAppPath(string strPath)
{
if(strPath == null) { Debug.Assert(false); return string.Empty; }
// int nFirst = strPath.IndexOf('\"');
// int nSecond = strPath.IndexOf('\"', nFirst + 1);
// if((nFirst >= 0) && (nSecond >= 0))
// return strPath.Substring(nFirst + 1, nSecond - nFirst - 1);
// return strPath;
string str = strPath.Trim();
if(str.Length <= 1) return str;
if(str[0] != '\"') return str;
int iSecond = IndexOfSecondEnclQuote(str);
int iSecond = str.IndexOf('\"', 1);
if(iSecond <= 0) return str;
return str.Substring(1, iSecond - 1);
@@ -275,30 +238,21 @@ namespace KeePassLib.Utility
public static string FileUrlToPath(string strUrl)
{
if (strUrl == null) { Debug.Assert(false); throw new ArgumentNullException("strUrl"); }
if (strUrl.Length == 0) { Debug.Assert(false); return string.Empty; }
Debug.Assert(strUrl != null);
if(strUrl == null) throw new ArgumentNullException("strUrl");
if (!strUrl.StartsWith(Uri.UriSchemeFile + ":", StrUtil.CaseIgnoreCmp))
{
Debug.Assert(false);
return strUrl;
}
string str = strUrl;
if(str.StartsWith(@"file:///", StrUtil.CaseIgnoreCmp))
str = str.Substring(8, str.Length - 8);
try
{
Uri uri = new Uri(strUrl);
string str = uri.LocalPath;
if (!string.IsNullOrEmpty(str)) return str;
}
catch (Exception) { Debug.Assert(false); }
str = str.Replace('/', UrlUtil.LocalDirSepChar);
Debug.Assert(false);
return strUrl;
return str;
}
public static bool UnhideFile(string strFile)
{
#if KeePassLibSD
#if (KeePassLibSD || KeePassRT)
return false;
#else
if(strFile == null) throw new ArgumentNullException("strFile");
@@ -318,7 +272,7 @@ namespace KeePassLib.Utility
public static bool HideFile(string strFile, bool bHide)
{
#if KeePassLibSD
#if (KeePassLibSD || KeePassRT)
return false;
#else
if(strFile == null) throw new ArgumentNullException("strFile");
@@ -361,8 +315,9 @@ namespace KeePassLib.Utility
#if (!KeePassLibSD && !KeePassUAP)
if(NativeLib.IsUnix())
{
#endif
{
bool bBaseUnc = IsUncPath(strBaseFile);
bool bTargetUnc = IsUncPath(strTargetFile);
if((!bBaseUnc && bTargetUnc) || (bBaseUnc && !bTargetUnc))
@@ -370,8 +325,8 @@ namespace KeePassLib.Utility
string strBase = GetShortestAbsolutePath(strBaseFile);
string strTarget = GetShortestAbsolutePath(strTargetFile);
string[] vBase = strBase.Split(UrlUtil.DirSepChars);
string[] vTarget = strTarget.Split(UrlUtil.DirSepChars);
string[] vBase = strBase.Split(m_vDirSeps);
string[] vTarget = strTarget.Split(m_vDirSeps);
int i = 0;
while((i < (vBase.Length - 1)) && (i < (vTarget.Length - 1)) &&
@@ -397,8 +352,8 @@ namespace KeePassLib.Utility
{
const int nMaxPath = NativeMethods.MAX_PATH * 2;
StringBuilder sb = new StringBuilder(nMaxPath + 2);
if (!NativeMethods.PathRelativePathTo(sb, strBaseFile, 0,
strTargetFile, 0))
if(NativeMethods.PathRelativePathTo(sb, strBaseFile, 0,
strTargetFile, 0) == false)
return strTargetFile;
string str = sb.ToString();
@@ -448,14 +403,13 @@ namespace KeePassLib.Utility
if(IsUncPath(strPath))
{
char chSep = strPath[0];
char[] vSep = ((chSep == '/') ? (new char[] { '/' }) :
(new char[] { '\\', '/' }));
Debug.Assert(Array.IndexOf<char>(m_vDirSeps, chSep) >= 0);
List<string> l = new List<string>();
#if !KeePassLibSD
string[] v = strPath.Split(vSep, StringSplitOptions.None);
string[] v = strPath.Split(m_vDirSeps, StringSplitOptions.None);
#else
string[] v = strPath.Split(vSep);
string[] v = strPath.Split(m_vDirSeps);
#endif
Debug.Assert((v.Length >= 3) && (v[0].Length == 0) &&
(v[1].Length == 0));
@@ -484,11 +438,20 @@ namespace KeePassLib.Utility
}
string str;
try { str = Path.GetFullPath(strPath); }
try
{
#if KeePassRT
var dirT = Windows.Storage.StorageFolder.GetFolderFromPathAsync(
strPath).AwaitEx();
str = dirT.Path;
#else
str = Path.GetFullPath(strPath);
#endif
}
catch(Exception) { Debug.Assert(false); return strPath; }
Debug.Assert((str.IndexOf("\\..\\") < 0) || NativeLib.IsUnix());
foreach (char ch in UrlUtil.DirSepChars)
Debug.Assert(str.IndexOf("\\..\\") < 0);
foreach(char ch in m_vDirSeps)
{
string strSep = new string(ch, 1);
str = str.Replace(strSep + "." + strSep, strSep);
@@ -518,30 +481,24 @@ namespace KeePassLib.Utility
return nLength;
}
internal static string GetScheme(string strUrl)
{
if (string.IsNullOrEmpty(strUrl)) return string.Empty;
int i = strUrl.IndexOf(':');
if (i > 0) return strUrl.Substring(0, i);
return string.Empty;
}
public static string RemoveScheme(string strUrl)
{
if(string.IsNullOrEmpty(strUrl)) return string.Empty;
int i = strUrl.IndexOf(':');
if (i < 0) return strUrl; // No scheme to remove
++i;
int nNetScheme = strUrl.IndexOf(@"://", StrUtil.CaseIgnoreCmp);
int nShScheme = strUrl.IndexOf(@":/", StrUtil.CaseIgnoreCmp);
int nSmpScheme = strUrl.IndexOf(@":", StrUtil.CaseIgnoreCmp);
// A single '/' indicates a path (absolute) and should not be removed
if (((i + 1) < strUrl.Length) && (strUrl[i] == '/') &&
(strUrl[i + 1] == '/'))
i += 2; // Skip authority prefix
if((nNetScheme < 0) && (nShScheme < 0) && (nSmpScheme < 0))
return strUrl; // No scheme
return strUrl.Substring(i);
int nMin = Math.Min(Math.Min((nNetScheme >= 0) ? nNetScheme : int.MaxValue,
(nShScheme >= 0) ? nShScheme : int.MaxValue),
(nSmpScheme >= 0) ? nSmpScheme : int.MaxValue);
if(nMin == nNetScheme) return strUrl.Substring(nMin + 3);
if(nMin == nShScheme) return strUrl.Substring(nMin + 2);
return strUrl.Substring(nMin + 1);
}
public static string ConvertSeparators(string strPath)
@@ -568,54 +525,26 @@ namespace KeePassLib.Utility
public static string FilterFileName(string strName)
{
if (string.IsNullOrEmpty(strName)) { Debug.Assert(false); return string.Empty; }
if(strName == null) { Debug.Assert(false); return string.Empty; }
// https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
string str = strName;
StringBuilder sb = new StringBuilder(strName.Length);
foreach (char ch in strName)
{
if (ch < '\u0020') continue;
str = str.Replace('/', '-');
str = str.Replace('\\', '-');
str = str.Replace(":", string.Empty);
str = str.Replace("*", string.Empty);
str = str.Replace("?", string.Empty);
str = str.Replace("\"", string.Empty);
str = str.Replace(@"'", string.Empty);
str = str.Replace('<', '(');
str = str.Replace('>', ')');
str = str.Replace('|', '-');
switch (ch)
{
case '\"':
case '*':
case ':':
case '?':
break;
case '/':
case '\\':
case '|':
sb.Append('-');
break;
case '<':
sb.Append('(');
break;
case '>':
sb.Append(')');
break;
default: sb.Append(ch); break;
}
}
// Trim trailing spaces and periods
for (int i = sb.Length - 1; i >= 0; --i)
{
char ch = sb[i];
if ((ch == ' ') || (ch == '.')) sb.Remove(i, 1);
else break;
}
return sb.ToString();
return str;
}
/// <summary>
/// Get the host component of a URL.
/// Get the host component of an URL.
/// This method is faster and more fault-tolerant than creating
/// an <code>Uri</code> object and querying its <code>Host</code>
/// property.
@@ -730,11 +659,13 @@ namespace KeePassLib.Utility
foreach(string strPathRaw in v)
{
if(strPathRaw == null) { Debug.Assert(false); continue; }
string strPath = strPathRaw.Trim(g_vPathTrimCharsWs);
string strPath = strPathRaw.Trim(m_vPathTrimCharsWs);
if(strPath.Length == 0) { Debug.Assert(false); continue; }
Debug.Assert(strPath == strPathRaw);
if (strPath.EndsWith(strExt, StrUtil.CaseIgnoreCmp))
if(!strPath.EndsWith(strExt, StrUtil.CaseIgnoreCmp))
continue;
l.Add(strPathRaw);
}
}
@@ -767,11 +698,13 @@ namespace KeePassLib.Utility
if(fi == null) { Debug.Assert(false); continue; }
string strPathRaw = fi.FullName;
if(strPathRaw == null) { Debug.Assert(false); continue; }
string strPath = strPathRaw.Trim(g_vPathTrimCharsWs);
string strPath = strPathRaw.Trim(m_vPathTrimCharsWs);
if(strPath.Length == 0) { Debug.Assert(false); continue; }
Debug.Assert(strPath == strPathRaw);
if (strPath.EndsWith(strExt, StrUtil.CaseIgnoreCmp))
if(!strPath.EndsWith(strExt, StrUtil.CaseIgnoreCmp))
continue;
l.Add(fi);
}
}
@@ -780,82 +713,5 @@ namespace KeePassLib.Utility
return l;
}
#endif
public static char GetDriveLetter(string strPath)
{
if (strPath == null) throw new ArgumentNullException("strPath");
Debug.Assert(default(char) == '\0');
if (strPath.Length < 3) return '\0';
if ((strPath[1] != ':') || (strPath[2] != '\\')) return '\0';
char ch = char.ToUpperInvariant(strPath[0]);
return (((ch >= 'A') && (ch <= 'Z')) ? ch : '\0');
}
internal static string GetSafeFileName(string strName)
{
Debug.Assert(!string.IsNullOrEmpty(strName));
string str = FilterFileName(GetFileName(strName ?? string.Empty));
if (string.IsNullOrEmpty(str))
{
Debug.Assert(false);
return "File.dat";
}
return str;
}
internal static string GetCanonicalUri(string strUri)
{
if (string.IsNullOrEmpty(strUri)) { Debug.Assert(false); return strUri; }
try
{
Uri uri = new Uri(strUri);
if (uri.IsAbsoluteUri) return uri.AbsoluteUri;
else { Debug.Assert(false); }
}
catch (Exception) { Debug.Assert(false); }
return strUri;
}
/* internal static Dictionary<string, string> ParseQuery(string strQuery)
{
Dictionary<string, string> d = new Dictionary<string, string>();
if(string.IsNullOrEmpty(strQuery)) return d;
string[] vKvp = strQuery.Split(new char[] { '?', '&' });
if(vKvp == null) { Debug.Assert(false); return d; }
foreach(string strKvp in vKvp)
{
if(string.IsNullOrEmpty(strKvp)) continue;
string strKey, strValue;
int iSep = strKvp.IndexOf('=');
if(iSep < 0)
{
strKey = strKvp;
strValue = string.Empty;
}
else
{
strKey = strKvp.Substring(0, iSep);
strValue = strKvp.Substring(iSep + 1);
}
strKey = Uri.UnescapeDataString(strKey);
strValue = Uri.UnescapeDataString(strValue);
d[strKey] = strValue;
}
return d;
} */
}
}

View File

@@ -1,290 +0,0 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;
using KeePassLib.Delegates;
using KeePassLib.Interfaces;
using KeePassLib.Serialization;
namespace KeePassLib.Utility
{
public static class XmlUtilEx
{
public static XmlDocument CreateXmlDocument()
{
XmlDocument d = new XmlDocument();
// .NET 4.5.2 and newer do not resolve external XML resources
// by default; for older .NET versions, we explicitly
// prevent resolving
d.XmlResolver = null; // Default in old .NET: XmlUrlResolver object
return d;
}
public static XmlReaderSettings CreateXmlReaderSettings()
{
XmlReaderSettings xrs = new XmlReaderSettings();
xrs.CloseInput = false;
xrs.IgnoreComments = true;
xrs.IgnoreProcessingInstructions = true;
xrs.IgnoreWhitespace = true;
#if KeePassUAP
xrs.DtdProcessing = DtdProcessing.Prohibit;
#else
// Also see PrepMonoDev.sh script
xrs.ProhibitDtd = true; // Obsolete in .NET 4, but still there
// xrs.DtdProcessing = DtdProcessing.Prohibit; // .NET 4 only
#endif
xrs.ValidationType = ValidationType.None;
xrs.XmlResolver = null;
return xrs;
}
public static XmlReader CreateXmlReader(Stream s)
{
if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); }
return XmlReader.Create(s, CreateXmlReaderSettings());
}
public static XmlWriterSettings CreateXmlWriterSettings()
{
XmlWriterSettings xws = new XmlWriterSettings();
xws.CloseOutput = false;
xws.Encoding = StrUtil.Utf8;
xws.Indent = true;
xws.IndentChars = "\t";
xws.NewLineOnAttributes = false;
return xws;
}
public static XmlWriter CreateXmlWriter(Stream s)
{
if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); }
return XmlWriter.Create(s, CreateXmlWriterSettings());
}
public static T Deserialize<T>(Stream s)
{
if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); }
XmlSerializer xs = new XmlSerializer(typeof(T));
T t = default(T);
using(XmlReader xr = CreateXmlReader(s))
{
t = (T)xs.Deserialize(xr);
}
return t;
}
public static void Serialize<T>(Stream s, T t)
{
if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); }
XmlSerializer xs = new XmlSerializer(typeof(T));
using(XmlWriter xw = CreateXmlWriter(s))
{
xs.Serialize(xw, t);
}
}
internal static void Serialize<T>(Stream s, T t, bool bRemoveXsdXsi)
{
// One way to remove the "xsd" and "xsi" namespace declarations
// is to use an XmlSerializerNamespaces object containing only
// a ""/"" pair; this seems to work, but Microsoft's
// documentation explicitly states that it isn't supported:
// https://docs.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializernamespaces
// There are other, more complex ways, but these either rely on
// undocumented details or require the type T to be modified.
string str;
using(MemoryStream ms = new MemoryStream())
{
Serialize<T>(ms, t);
str = StrUtil.Utf8.GetString(ms.ToArray());
}
Func<string, string, bool> fFindPfx = delegate(string strText, string strSub)
{
int i = strText.IndexOf(strSub, StringComparison.Ordinal);
if(i < 0) return false;
if(i == 0) return true;
return char.IsWhiteSpace(strText[i - 1]);
};
if(bRemoveXsdXsi)
{
if(!fFindPfx(str, "xsd:") && !fFindPfx(str, "xsi:"))
{
Debug.Assert(str.IndexOf("xmlns:xsd") > 0);
str = str.Replace(" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"", string.Empty);
Debug.Assert(str.IndexOf("xmlns:xsd") < 0);
Debug.Assert(str.IndexOf("xmlns:xsi") > 0);
str = str.Replace(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", string.Empty);
Debug.Assert(str.IndexOf("xmlns:xsi") < 0);
}
else { Debug.Assert(false); } // "xsd"/"xsi" decl. may be required
}
MemUtil.Write(s, StrUtil.Utf8.GetBytes(str));
}
#if DEBUG
internal static void ValidateXml(string strXml, bool bReplaceStdEntities)
{
if(strXml == null) throw new ArgumentNullException("strXml");
if(strXml.Length == 0) { Debug.Assert(false); return; }
string str = strXml;
if(bReplaceStdEntities)
str = str.Replace("&nbsp;", "&#160;");
XmlDocument d = new XmlDocument();
d.LoadXml(str);
}
#endif
internal static XPathNodeIterator FindNodes(PwDatabase pd, string strXPath,
IStatusLogger sl, out XmlDocument xd)
{
if(pd == null) throw new ArgumentNullException("pd");
if(strXPath == null) { Debug.Assert(false); strXPath = string.Empty; }
KdbxFile kdbx = new KdbxFile(pd);
byte[] pbXml;
using(MemoryStream ms = new MemoryStream())
{
kdbx.Save(ms, null, KdbxFormat.PlainXml, sl);
pbXml = ms.ToArray();
}
string strXml = StrUtil.Utf8.GetString(pbXml);
xd = CreateXmlDocument();
xd.LoadXml(strXml);
XPathNavigator xpNav = xd.CreateNavigator();
return xpNav.Select(strXPath);
// XPathExpression xpExpr = xpNav.Compile(strXPath);
// xpExpr.SetContext(new XuXsltContext());
// return xpNav.Select(xpExpr);
}
/* private sealed class XuFnMatches : IXsltContextFunction
{
private readonly XPathResultType[] m_vArgTypes = new XPathResultType[] {
XPathResultType.String, XPathResultType.String, XPathResultType.String
};
public XPathResultType[] ArgTypes { get { return m_vArgTypes; } }
public int Maxargs { get { return 3; } }
public int Minargs { get { return 2; } }
public XPathResultType ReturnType { get { return XPathResultType.Boolean; } }
private static string GetArgString(object[] args, int i, string strDefault)
{
if(args == null) { Debug.Assert(false); return strDefault; }
if(i >= args.Length) return strDefault;
object o = args[i];
if(o == null) return strDefault;
XPathNodeIterator it = (o as XPathNodeIterator);
if(it != null) o = it.Current.Value;
return (o.ToString() ?? strDefault);
}
public object Invoke(XsltContext xsltContext, object[] args,
XPathNavigator docContext)
{
string strInput = GetArgString(args, 0, string.Empty);
string strPattern = GetArgString(args, 1, string.Empty);
string strFlags = GetArgString(args, 2, null);
RegexOptions ro = RegexOptions.None;
if(!string.IsNullOrEmpty(strFlags))
{
if(strFlags.IndexOf('s') >= 0) ro |= RegexOptions.Singleline;
if(strFlags.IndexOf('m') >= 0) ro |= RegexOptions.Multiline;
if(strFlags.IndexOf('i') >= 0) ro |= RegexOptions.IgnoreCase;
if(strFlags.IndexOf('x') >= 0) ro |= RegexOptions.IgnorePatternWhitespace;
}
return Regex.IsMatch(strInput, strPattern, ro);
}
}
private sealed class XuXsltContext : XsltContext
{
public override bool Whitespace { get { return false; } }
public override int CompareDocument(string baseUri, string nextbaseUri)
{
return string.CompareOrdinal(baseUri, nextbaseUri);
}
public override bool PreserveWhitespace(XPathNavigator node)
{
return false;
}
public override IXsltContextFunction ResolveFunction(string prefix,
string name, XPathResultType[] ArgTypes)
{
if(prefix != "kp") { Debug.Assert(false); return null; }
if(name == "matches") return new XuFnMatches();
Debug.Assert(false);
return null;
}
public override IXsltContextVariable ResolveVariable(string prefix,
string name)
{
Debug.Assert(false);
return null;
}
} */
}
}

View File

@@ -11,7 +11,7 @@ using KeePassLib.Keys;
using KeePassLib.Serialization;
using keepass2android.Io;
using KeePassLib.Interfaces;
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
#if !NoNet
using Keepass2android.Javafilestorage;
#endif
@@ -38,7 +38,7 @@ namespace keepass2android
/// <summary>
/// Locks all currently open databases, quicklocking if available (unless false is passed for allowQuickUnlock)
/// </summary>
void Lock(bool allowQuickUnlock, bool lockWasTriggeredByTimeout);
void Lock(bool allowQuickUnlock);
/// <summary>
@@ -119,11 +119,11 @@ namespace keepass2android
/// </summary>
IFileStorage GetFileStorage(IOConnectionInfo iocInfo, bool allowCache);
void TriggerReload(Context context, Action<bool> actionOnResult /*if not null, called when the user selected yes (true) or no (false)*/);
void TriggerReload(Context context);
bool CheckForDuplicateUuids { get; }
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
#if !NoNet
ICertificateErrorHandler CertificateErrorHandler { get; }

View File

@@ -250,10 +250,27 @@ namespace keepass2android.Io
return true;
}
//in previous implementations, we were checking for FLAG_SUPPORTS_WRITE in the document flags,
//but it seems like this is very poorly supported, e.g. Dropbox and OneDrive return !FLAG_SUPPORTS_WRITE
//even though writing work.
return false;
//KitKat or later...
var uri = Android.Net.Uri.Parse(ioc.Path);
cursor = _ctx.ContentResolver.Query(uri, null, null, null, null, null);
if (cursor != null && cursor.MoveToFirst())
{
int column = cursor.GetColumnIndex(DocumentsContract.Document.ColumnFlags);
if (column < 0)
return false; //seems like this is not supported. See below for reasoning to return false.
int flags = cursor.GetInt(column);
Kp2aLog.Log("File flags: " + flags);
if ((flags & (long) DocumentContractFlags.SupportsWrite) == 0)
{
if (reason != null)
reason.Result = UiStringKey.ReadOnlyReason_ReadOnlyFlag;
return true;
}
else return false;
}
else throw new Exception("couldn't move to first result element: " + (cursor == null) + uri.ToString());
}
catch (Exception e)
{

View File

@@ -120,13 +120,9 @@ namespace keepass2android.Io
public bool IsCached(IOConnectionInfo ioc)
{
bool result = File.Exists(CachedFilePath(ioc))
return File.Exists(CachedFilePath(ioc))
&& File.Exists(VersionFilePath(ioc))
&& File.Exists(BaseVersionFilePath(ioc));
Kp2aLog.Log(ioc.GetDisplayName() + " isCached = " + result);
return result;
}
public void Delete(IOConnectionInfo ioc)
@@ -597,15 +593,11 @@ namespace keepass2android.Io
public string GetBaseVersionHash(IOConnectionInfo ioc)
{
string hash = File.ReadAllText(BaseVersionFilePath(ioc));
Kp2aLog.Log(ioc.GetDisplayName() + " baseVersionHash = " + hash);
return hash;
return File.ReadAllText(BaseVersionFilePath(ioc));
}
public string GetLocalVersionHash(IOConnectionInfo ioc)
{
string hash = File.ReadAllText(VersionFilePath(ioc));
Kp2aLog.Log(ioc.GetDisplayName() + " localVersionHash = " + hash);
return hash;
return File.ReadAllText(VersionFilePath(ioc));
}
public bool HasLocalChanges(IOConnectionInfo ioc)
{

View File

@@ -217,10 +217,7 @@ namespace keepass2android.Io
{
using (var cl = GetClient(ioc))
{
var memStream = new MemoryStream();
cl.OpenRead(IocToLocalPath(ioc), FtpDataType.Binary, 0).CopyTo(memStream);
memStream.Seek(0, SeekOrigin.Begin);
return memStream;
return cl.OpenRead(IocToLocalPath(ioc), FtpDataType.Binary, 0);
}
}
catch (FtpCommandException ex)

View File

@@ -322,37 +322,20 @@ 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)))
{
logDebug("TryGetMsGraphClient returning client");
if (!(clientWithState.RequiresUserInteraction || (clientWithState.TokenExpiryDate < DateTime.Now) || (clientWithState.Client == null)))
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;
}
@@ -384,7 +367,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;
}
@@ -392,9 +375,7 @@ namespace keepass2android.Io
private void logDebug(string str)
{
#if DEBUG
Log.Debug("KP2A", "OneDrive2: " + str);
#endif
Log.Debug("KP2A", str);
}
@@ -550,49 +531,12 @@ namespace keepass2android.Io
Task.Run(async () =>
{
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();
@@ -877,17 +821,14 @@ 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
{
@@ -915,14 +856,13 @@ 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;
@@ -951,9 +891,7 @@ namespace keepass2android.Io
/*User me = await graphClient.Me.Request().WithForceRefresh(true).GetAsync();
logDebug("received name " + me.DisplayName);*/
var rootFolder = BuildRootPathForUser(authResult);
logDebug("Found RootPath for user");
return rootFolder;
return BuildRootPathForUser(authResult);
}
catch (MsalUiRequiredException ex)

View File

@@ -9,14 +9,14 @@ using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
#if !NoNet
using Keepass2android.Javafilestorage;
#endif
using KeePassLib.Serialization;
namespace keepass2android.Io
{
#if !NoNet && !EXCLUDE_JAVAFILESTORAGE
#if !NoNet
public class WebDavFileStorage: JavaFileStorage
{
public WebDavFileStorage(IKp2aApp app) : base(new Keepass2android.Javafilestorage.WebDavStorage(app.CertificateErrorHandler), app)

View File

@@ -12,7 +12,7 @@
<FileAlignment>512</FileAlignment>
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<TargetFrameworkVersion>v11.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
@@ -22,7 +22,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;_EXCLUDE_TWOFISH;_EXCLUDE_KEYBOARD;_EXCLUDE_FILECHOOSER;_EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
<DefineConstants>DEBUG;EXCLUDE_TWOFISH;_EXCLUDE_KEYBOARD;_EXCLUDE_FILECHOOSER;_EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidLinkMode>None</AndroidLinkMode>
@@ -34,7 +34,6 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<JavaMaximumHeapSize>4G</JavaMaximumHeapSize>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseNoNet|AnyCPU'">
@@ -130,10 +129,6 @@
<Compile Include="Utils\Spr\SprEngine.PickChars.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AndroidFileChooserBinding\AndroidFileChooserBinding.csproj">
<Project>{3c0f7fe5-639f-4422-a087-8b26cf862d1b}</Project>
<Name>AndroidFileChooserBinding</Name>
</ProjectReference>
<ProjectReference Include="..\JavaFileStorageBindings\JavaFileStorageBindings.csproj">
<Project>{48574278-4779-4b3a-a9e4-9cf1bc285d0b}</Project>
<Name>JavaFileStorageBindings</Name>
@@ -146,10 +141,6 @@
<Project>{70D3844A-D9FA-4A64-B205-A84C6A822196}</Project>
<Name>KP2AKdbLibraryBinding</Name>
</ProjectReference>
<ProjectReference Include="..\PCloudBindings\PCloudBindings.csproj">
<Project>{2db80c77-d46f-4970-b967-e9ffa9b2ac2e}</Project>
<Name>PCloudBindings</Name>
</ProjectReference>
<ProjectReference Include="..\TwofishCipher\TwofishCipher.csproj">
<Project>{5CF675A5-9BEE-4720-BED9-D5BF14A2EBF9}</Project>
<Name>TwofishCipher</Name>
@@ -163,118 +154,118 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentFTP">
<Version>31.3.1</Version>
<Version>27.1.3</Version>
</PackageReference>
<PackageReference Include="Microsoft.Graph">
<Version>1.21.0</Version>
<Version>1.17.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.Graph.Auth">
<Version>1.0.0-preview.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.Identity.Client">
<Version>4.8.2</Version>
<Version>4.4.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Core.Common">
<Version>1.1.1.3</Version>
<Version>1.1.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Core.Runtime">
<Version>1.1.1.3</Version>
<Version>1.1.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.Common">
<Version>1.1.1.3</Version>
<Version>1.1.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.LiveData">
<Version>1.1.1.3</Version>
<Version>1.1.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.LiveData.Core">
<Version>1.1.1.3</Version>
<Version>1.1.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.Runtime">
<Version>1.1.1.3</Version>
<Version>1.1.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Arch.Lifecycle.ViewModel">
<Version>1.1.1.3</Version>
<Version>1.1.1.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Animated.Vector.Drawable">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Annotations">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.AsyncLayoutInflater">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Collections">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Compat">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CoordinaterLayout">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Core.UI">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Core.Utils">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CursorAdapter">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CustomTabs">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.CustomView">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.DocumentFile">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.DrawerLayout">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Fragment">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Interpolator">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Loader">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.LocalBroadcastManager">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Media.Compat">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Print">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.SlidingPaneLayout">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.SwipeRefreshLayout">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v13">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v4">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.VersionedParcelable">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.ViewPager">
<Version>28.0.0.3</Version>
<Version>28.0.0.1</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />

View File

@@ -49,11 +49,6 @@ namespace keepass2android
get { return _activeActivity; }
private set
{
if (_activeActivity != null && _activeActivity != _previouslyActiveActivity)
{
_previouslyActiveActivity = _activeActivity;
}
_activeActivity = value;
if (_task != null)
_task.ActiveActivity = _activeActivity;
@@ -63,12 +58,6 @@ namespace keepass2android
_progressDialog.Show();
}
}
}
public Activity PreviouslyActiveActivity
{
get { return _previouslyActiveActivity; }
}
private readonly Handler _handler;
@@ -76,7 +65,7 @@ namespace keepass2android
private IProgressDialog _progressDialog;
private readonly IKp2aApp _app;
private Thread _thread;
private Activity _activeActivity, _previouslyActiveActivity;
private Activity _activeActivity;
private ProgressDialogStatusLogger _progressDialogStatusLogger;
public ProgressTask(IKp2aApp app, Activity activity, RunnableOnFinish task)

File diff suppressed because it is too large Load Diff

View File

@@ -88,7 +88,6 @@ namespace keepass2android
ReadOnlyReason_ReadOnlyKitKat,
ReadOnlyReason_LocalBackup,
Ok,
cancel,
FileNotFound
cancel
}
}

View File

@@ -51,7 +51,7 @@ namespace keepass2android
if (!MemUtil.ArraysEqual(_app.CurrentDb.KpDatabase.HashOfFileOnDisk, hashingRemoteStream.Hash))
{
_app.TriggerReload(_context, null);
_app.TriggerReload(_context);
Finish(true);
}
else

View File

@@ -27,7 +27,7 @@ namespace keepass2android
}
public byte[] HashOfLastStream { get; private set; }
public bool CanWrite { get { return _format != KdbxFormat.PlainXml; } }
public bool CanWrite { get { return true; } }
public string SuccessMessage { get { return null; } }
public void Save(PwDatabase kpDatabase, Stream stream)
{

View File

@@ -43,21 +43,17 @@ namespace keepass2android
try
{
remoteData = cachingFileStorage.GetRemoteDataAndHash(ioc, out hash);
Kp2aLog.Log("Checking for file change. Current hash = " + hash);
}
catch (FileNotFoundException)
{
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.RestoringRemoteFile));
cachingFileStorage.UpdateRemoteFile(ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions));
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
Kp2aLog.Log("Checking for file change: file not found");
return;
}
//check if remote file was modified:
var baseVersionHash = cachingFileStorage.GetBaseVersionHash(ioc);
Kp2aLog.Log("Checking for file change. baseVersionHash = " + baseVersionHash);
if (baseVersionHash != hash)
if (cachingFileStorage.GetBaseVersionHash(ioc) != hash)
{
//remote file is modified
if (cachingFileStorage.HasLocalChanges(ioc))
@@ -85,7 +81,8 @@ namespace keepass2android
{
//only the remote file was modified -> reload database.
//note: it's best to lock the database and do a complete reload here (also better for UI consistency in case something goes wrong etc.)
_app.TriggerReload(_context, (bool result) => Finish(result));
_app.TriggerReload(_context);
Finish(true);
}
}
else

View File

@@ -37,9 +37,6 @@ namespace keepass2android
_actionToPerform = actionToPerform;
}
//if set to true, the previously active active will be passed to ActionToPerformOnFinish instead null if no activity is on foreground
public bool AllowInactiveActivity { get; set; }
public override void Run()
{
if (Message == null)
@@ -49,7 +46,7 @@ namespace keepass2android
Handler.Post(() => {_actionToPerform(Success, Message, ActiveActivity);});
}
else
_actionToPerform(Success, Message, AllowInactiveActivity ? (ActiveActivity ?? PreviouslyActiveActivity) : ActiveActivity);
_actionToPerform(Success, Message, ActiveActivity);
base.Run();
}
}

View File

@@ -234,7 +234,7 @@ namespace keepass2android
else
{
// Let's not bother recovering from a failure to save. It is too much work.
App.Lock(false, false);
App.Lock(false);
}
}, OnFinishToRun);

View File

@@ -82,7 +82,7 @@ namespace keepass2android
_editGroup.App.DirtyGroups.Add(_editGroup.Group.ParentGroup);
} else
{
_editGroup._app.Lock(false, false);
_editGroup._app.Lock(false);
}
base.Run();

View File

@@ -123,7 +123,7 @@ namespace keepass2android
{
if (!(e is InvalidCompositeKeyException))
Kp2aLog.LogUnexpectedError(e);
Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + (e.Message ?? (e is FileNotFoundException ? _app.GetResourceString(UiStringKey.FileNotFound) : "")), false, Exception);
Finish(false, _app.GetResourceString(UiStringKey.ErrorOcurred) + " " + e.Message, false, Exception);
return;
}

View File

@@ -39,7 +39,7 @@ namespace keepass2android
protected OnFinish BaseOnFinish;
protected Handler Handler;
private ProgressDialogStatusLogger _statusLogger = new ProgressDialogStatusLogger(); //default: no logging but not null -> can be used whenever desired
private Activity _activeActivity, _previouslyActiveActivity;
private Activity _activeActivity;
public ProgressDialogStatusLogger StatusLogger
@@ -53,11 +53,6 @@ namespace keepass2android
get { return _activeActivity; }
set
{
if (_activeActivity != null && _activeActivity != _previouslyActiveActivity)
{
_previouslyActiveActivity = _activeActivity;
}
_activeActivity = value;
if (BaseOnFinish != null)
{
@@ -66,13 +61,6 @@ namespace keepass2android
}
}
public Activity PreviouslyActiveActivity
{
get { return _previouslyActiveActivity; }
}
protected OnFinish(Activity activeActivity, Handler handler)
{

View File

@@ -118,16 +118,12 @@ namespace keepass2android
}
bool hasStreamForOrigFile = (_streamForOrigFile != null);
bool hasChangeFast = hasStreamForOrigFile ||
fileStorage.CheckForFileChangeFast(ioc, _db.LastFileVersion); //first try to use the fast change detection;
bool hasHashChanged = hasChangeFast ||
(FileHashChanged(ioc, _db.KpDatabase.HashOfFileOnDisk) ==
FileHashChange.Changed); //if that fails, hash the file and compare:
if (hasHashChanged)
if (
(_streamForOrigFile != null)
|| fileStorage.CheckForFileChangeFast(ioc, _db.LastFileVersion) //first try to use the fast change detection
|| (FileHashChanged(ioc, _db.KpDatabase.HashOfFileOnDisk) == FileHashChange.Changed) //if that fails, hash the file and compare:
)
{
Kp2aLog.Log("Conflict. " + hasStreamForOrigFile + " " + hasChangeFast + " " + hasHashChanged);
//ask user...
_app.AskYesNoCancel(UiStringKey.TitleSyncQuestion, UiStringKey.MessageSyncQuestion,

Binary file not shown.

Binary file not shown.

View File

@@ -55,7 +55,7 @@
<ItemGroup>
<None Include="Jars\AboutJars.txt" />
<None Include="Additions\AboutAdditions.txt" />
<LibraryProjectZip Include="Jars\pcloud-sdk-android-1.2.0.aar" />
<LibraryProjectZip Include="Jars\pcloud-sdk-android-1.1.0.aar" />
</ItemGroup>
<ItemGroup>
<TransformFile Include="Transforms\Metadata.xml" />
@@ -71,6 +71,6 @@
</Target>
-->
<ItemGroup>
<EmbeddedReferenceJar Include="Jars\pcloud-sdk-java-core-1.2.0.jar" />
<EmbeddedReferenceJar Include="Jars\pcloud-sdk-java-core-1.1.0.jar" />
</ItemGroup>
</Project>

View File

@@ -54,7 +54,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<LibraryProjectZip Include="..\java\Keepass2AndroidPluginSDK2\app\build\outputs\aar\app-release.aar">
<LibraryProjectZip Include="..\java\Keepass2AndroidPluginSDK2\app\build\outputs\aar\Keepass2AndroidPluginSDK2-release.aar">
<Link>Jars\Keepass2AndroidPluginSDK2-release.aar</Link>
</LibraryProjectZip>
<None Include="Jars\AboutJars.txt" />

Some files were not shown because too many files have changed in this diff Show More