Update to version 2.42.1
Some changes Removed FutureAccesList code as it works only with UWP
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using ModernKeePassLib.Keys;
|
||||
using ModernKeePassLib.Utility;
|
||||
using Windows.Storage;
|
||||
@@ -24,7 +25,7 @@ namespace ModernKeePassLib.Test.Keys
|
||||
private const string ExpectedFileEnd = "</Data>\r\n\t</Key>\r\n</KeyFile>";
|
||||
|
||||
[Fact]
|
||||
public void TestConstruct()
|
||||
public async Task TestConstruct()
|
||||
{
|
||||
var expectedKeyData = new byte[]
|
||||
{
|
||||
@@ -34,16 +35,14 @@ namespace ModernKeePassLib.Test.Keys
|
||||
0x45, 0xfc, 0xc8, 0x92, 0xbd, 0xeb, 0xaf, 0xc3
|
||||
};
|
||||
|
||||
var folder = StorageFolder.GetFolderFromPathAsync(Path.GetTempPath()).GetAwaiter().GetResult();
|
||||
var file = folder.CreateFileAsync(TestCreateFile, CreationCollisionOption.ReplaceExisting).GetAwaiter().GetResult();
|
||||
using (var fs = file.OpenStreamForWriteAsync().GetAwaiter().GetResult())
|
||||
var folder = await StorageFolder.GetFolderFromPathAsync(Path.GetTempPath());
|
||||
var file = await folder.CreateFileAsync(TestCreateFile, CreationCollisionOption.ReplaceExisting);
|
||||
await using (var fs = await file.OpenStreamForWriteAsync())
|
||||
{
|
||||
using (var sw = new StreamWriter(fs))
|
||||
{
|
||||
sw.Write(ExpectedFileStart);
|
||||
sw.Write(TestKey);
|
||||
sw.Write(ExpectedFileEnd);
|
||||
}
|
||||
await using var sw = new StreamWriter(fs);
|
||||
sw.Write(ExpectedFileStart);
|
||||
sw.Write(TestKey);
|
||||
sw.Write(ExpectedFileEnd);
|
||||
}
|
||||
|
||||
try
|
||||
@@ -54,19 +53,19 @@ namespace ModernKeePassLib.Test.Keys
|
||||
}
|
||||
finally
|
||||
{
|
||||
file.DeleteAsync().GetAwaiter().GetResult();
|
||||
await file.DeleteAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestCreate()
|
||||
public async Task TestCreate()
|
||||
{
|
||||
var folder = StorageFolder.GetFolderFromPathAsync(Path.GetTempPath()).GetAwaiter().GetResult();
|
||||
var file = folder.CreateFileAsync(TestCreateFile, CreationCollisionOption.ReplaceExisting).GetAwaiter().GetResult();
|
||||
var folder = await StorageFolder.GetFolderFromPathAsync(Path.GetTempPath());
|
||||
var file = await folder.CreateFileAsync(TestCreateFile, CreationCollisionOption.ReplaceExisting);
|
||||
KcpKeyFile.Create(file, null);
|
||||
try
|
||||
{
|
||||
var fileContents = FileIO.ReadTextAsync(file).GetAwaiter().GetResult();
|
||||
var fileContents = await FileIO.ReadTextAsync(file);
|
||||
|
||||
Assert.Equal(185, fileContents.Length);
|
||||
Assert.StartsWith(ExpectedFileStart, fileContents);
|
||||
@@ -74,7 +73,7 @@ namespace ModernKeePassLib.Test.Keys
|
||||
}
|
||||
finally
|
||||
{
|
||||
file.DeleteAsync().GetAwaiter().GetResult();
|
||||
await file.DeleteAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
ModernKeePassLib.UwpTest/Assets/LockScreenLogo.scale-200.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
ModernKeePassLib.UwpTest/Assets/SplashScreen.scale-200.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
ModernKeePassLib.UwpTest/Assets/Square150x150Logo.scale-200.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
ModernKeePassLib.UwpTest/Assets/Square44x44Logo.scale-200.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.2 KiB |
BIN
ModernKeePassLib.UwpTest/Assets/StoreLogo.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
ModernKeePassLib.UwpTest/Assets/Wide310x150Logo.scale-200.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
86
ModernKeePassLib.UwpTest/KcpKeyFileTests.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.AccessCache;
|
||||
using ModernKeePassLib.Keys;
|
||||
using ModernKeePassLib.Utility;
|
||||
using Xunit;
|
||||
|
||||
namespace ModernKeePassLib.UwpTest
|
||||
{
|
||||
public class KcpKeyFileTests
|
||||
{
|
||||
private const string TestCreateFile = "TestCreate.xml";
|
||||
private const string TestKey = "0123456789";
|
||||
|
||||
private const string ExpectedFileStart =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
|
||||
"<KeyFile>\r\n" +
|
||||
"\t<Meta>\r\n" +
|
||||
"\t\t<Version>1.00</Version>\r\n" +
|
||||
"\t</Meta>\r\n" +
|
||||
"\t<Key>\r\n" +
|
||||
"\t\t<Data>";
|
||||
|
||||
private const string ExpectedFileEnd = "</Data>\r\n\t</Key>\r\n</KeyFile>";
|
||||
|
||||
[Fact]
|
||||
public async Task TestConstruct()
|
||||
{
|
||||
var expectedKeyData = new byte[]
|
||||
{
|
||||
0x95, 0x94, 0xdc, 0xb9, 0x91, 0xc6, 0x65, 0xa0,
|
||||
0x81, 0xf6, 0x6f, 0xca, 0x07, 0x1a, 0x30, 0xd1,
|
||||
0x1d, 0x65, 0xcf, 0x8d, 0x9c, 0x60, 0xfb, 0xe6,
|
||||
0x45, 0xfc, 0xc8, 0x92, 0xbd, 0xeb, 0xaf, 0xc3
|
||||
};
|
||||
|
||||
var folder = await StorageFolder.GetFolderFromPathAsync(Path.GetTempPath());
|
||||
var file = await folder.CreateFileAsync(TestCreateFile, CreationCollisionOption.ReplaceExisting);
|
||||
var token = StorageApplicationPermissions.FutureAccessList.Add(file);
|
||||
using (var fs = await file.OpenStreamForWriteAsync())
|
||||
{
|
||||
using (var sw = new StreamWriter(fs))
|
||||
{
|
||||
sw.Write(ExpectedFileStart);
|
||||
sw.Write(TestKey);
|
||||
sw.Write(ExpectedFileEnd);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var keyFile = new KcpKeyFile(token);
|
||||
var keyData = keyFile.KeyData.ReadData();
|
||||
Assert.True(MemUtil.ArraysEqual(keyData, expectedKeyData));
|
||||
}
|
||||
finally
|
||||
{
|
||||
await file.DeleteAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TestCreate()
|
||||
{
|
||||
var folder = await StorageFolder.GetFolderFromPathAsync(Path.GetTempPath());
|
||||
var file = await folder.CreateFileAsync(TestCreateFile, CreationCollisionOption.ReplaceExisting);
|
||||
var token = StorageApplicationPermissions.FutureAccessList.Add(file);
|
||||
KcpKeyFile.Create(token, null);
|
||||
try
|
||||
{
|
||||
var fileContents = await FileIO.ReadTextAsync(file);
|
||||
|
||||
Assert.Equal(185, fileContents.Length);
|
||||
Assert.StartsWith(ExpectedFileStart, fileContents);
|
||||
Assert.EndsWith(ExpectedFileEnd, fileContents);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await file.DeleteAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
179
ModernKeePassLib.UwpTest/ModernKeePassLib.UwpTest.csproj
Normal file
@@ -0,0 +1,179 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProjectGuid>{E43877FF-6725-43DA-A3AF-F1A7CB86EE03}</ProjectGuid>
|
||||
<OutputType>AppContainerExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ModernKeePassLib.UwpTest</RootNamespace>
|
||||
<AssemblyName>ModernKeePassLib.UwpTest</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.17763.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<UnitTestPlatformVersion Condition="'$(UnitTestPlatformVersion)' == ''">$(VisualStudioVersion)</UnitTestPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\ARM\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
|
||||
<OutputPath>bin\ARM\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\ARM64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>ARM64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM64'">
|
||||
<OutputPath>bin\ARM64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>ARM64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<SDKReference Include="TestPlatform.Universal, Version=$(UnitTestPlatformVersion)" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="KcpKeyFileTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="UnitTestApp.xaml.cs">
|
||||
<DependentUpon>UnitTestApp.xaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="UnitTestApp.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</AppxManifest>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Properties\Default.rd.xml" />
|
||||
<Content Include="Assets\LockScreenLogo.scale-200.png" />
|
||||
<Content Include="Assets\SplashScreen.scale-200.png" />
|
||||
<Content Include="Assets\Square150x150Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||
<Content Include="Assets\StoreLogo.png" />
|
||||
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
|
||||
<Version>6.2.8</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MSTest.TestAdapter">
|
||||
<Version>1.4.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MSTest.TestFramework">
|
||||
<Version>1.4.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="xunit">
|
||||
<Version>2.4.1</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ModernKeePassLib\ModernKeePassLib.csproj">
|
||||
<Project>{15a7e2e5-2b46-4975-afbd-2898e47e5ba1}</Project>
|
||||
<Name>ModernKeePassLib</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
||||
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.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>
|
46
ModernKeePassLib.UwpTest/Package.appxmanifest
Normal file
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
IgnorableNamespaces="uap mp">
|
||||
|
||||
<Identity Name="bdd8e2db-adc6-45a8-b9e9-133fd7361434"
|
||||
Publisher="CN=GeoffroyBONNEVILLE"
|
||||
Version="1.0.0.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="bdd8e2db-adc6-45a8-b9e9-133fd7361434" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
<Properties>
|
||||
<DisplayName>ModernKeePassLib.UwpTest</DisplayName>
|
||||
<PublisherDisplayName>GeoffroyBONNEVILLE</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate" />
|
||||
</Resources>
|
||||
<Applications>
|
||||
<Application Id="vstest.executionengine.universal.App"
|
||||
Executable="$targetnametoken$.exe"
|
||||
EntryPoint="ModernKeePassLib.UwpTest.App">
|
||||
<uap:VisualElements
|
||||
DisplayName="ModernKeePassLib.UwpTest"
|
||||
Square150x150Logo="Assets\Square150x150Logo.png"
|
||||
Square44x44Logo="Assets\Square44x44Logo.png"
|
||||
Description="ModernKeePassLib.UwpTest"
|
||||
BackgroundColor="transparent">
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png"/>
|
||||
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
</Application>
|
||||
</Applications>
|
||||
<Capabilities>
|
||||
<Capability Name="internetClientServer" />
|
||||
<Capability Name="privateNetworkClientServer" />
|
||||
</Capabilities>
|
||||
</Package>
|
18
ModernKeePassLib.UwpTest/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyTitle("ModernKeePassLib.UwpTest")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("ModernKeePassLib.UwpTest")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: AssemblyMetadata("TargetPlatform","UAP")]
|
||||
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: ComVisible(false)]
|
29
ModernKeePassLib.UwpTest/Properties/Default.rd.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<!--
|
||||
This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
|
||||
developers. However, you can modify these parameters to modify the behavior of the .NET Native
|
||||
optimizer.
|
||||
|
||||
Runtime Directives are documented at https://go.microsoft.com/fwlink/?LinkID=391919
|
||||
|
||||
To fully enable reflection for App1.MyClass and all of its public/private members
|
||||
<Type Name="App1.MyClass" Dynamic="Required All"/>
|
||||
|
||||
To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
|
||||
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
|
||||
|
||||
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
|
||||
<Namespace Name="DataClasses.ViewModels" Serialize="All" />
|
||||
-->
|
||||
|
||||
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
|
||||
<Application>
|
||||
<!--
|
||||
An Assembly element with Name="*Application*" applies to all assemblies in
|
||||
the application package. The asterisks are not wildcards.
|
||||
-->
|
||||
<Assembly Name="*Application*" Dynamic="Required All" />
|
||||
<!-- Add your application specific runtime directives here. -->
|
||||
|
||||
|
||||
</Application>
|
||||
</Directives>
|
7
ModernKeePassLib.UwpTest/UnitTestApp.xaml
Normal file
@@ -0,0 +1,7 @@
|
||||
<Application
|
||||
x:Class="ModernKeePassLib.UwpTest.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:ModernKeePassLib.UwpTest">
|
||||
|
||||
</Application>
|
102
ModernKeePassLib.UwpTest/UnitTestApp.xaml.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
namespace ModernKeePassLib.UwpTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
sealed partial class App : Application
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.Suspending += OnSuspending;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the application is launched normally by the end user. Other entry points
|
||||
/// will be used such as when the application is launched to open a specific file.
|
||||
/// </summary>
|
||||
/// <param name="e">Details about the launch request and process.</param>
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs e)
|
||||
{
|
||||
|
||||
#if DEBUG
|
||||
if (System.Diagnostics.Debugger.IsAttached)
|
||||
{
|
||||
this.DebugSettings.EnableFrameRateCounter = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
Frame rootFrame = Window.Current.Content as Frame;
|
||||
|
||||
// Do not repeat app initialization when the Window already has content,
|
||||
// just ensure that the window is active
|
||||
if (rootFrame == null)
|
||||
{
|
||||
// Create a Frame to act as the navigation context and navigate to the first page
|
||||
rootFrame = new Frame();
|
||||
|
||||
rootFrame.NavigationFailed += OnNavigationFailed;
|
||||
|
||||
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
|
||||
{
|
||||
//TODO: Load state from previously suspended application
|
||||
}
|
||||
|
||||
// Place the frame in the current Window
|
||||
Window.Current.Content = rootFrame;
|
||||
}
|
||||
|
||||
Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.CreateDefaultUI();
|
||||
|
||||
// Ensure the current window is active
|
||||
Window.Current.Activate();
|
||||
|
||||
Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.Run(e.Arguments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when Navigation to a certain page fails
|
||||
/// </summary>
|
||||
/// <param name="sender">The Frame which failed navigation</param>
|
||||
/// <param name="e">Details about the navigation failure</param>
|
||||
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
|
||||
{
|
||||
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when application execution is being suspended. Application state is saved
|
||||
/// without knowing whether the application will be terminated or resumed with the contents
|
||||
/// of memory still intact.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the suspend request.</param>
|
||||
/// <param name="e">Details about the suspend request.</param>
|
||||
private void OnSuspending(object sender, SuspendingEventArgs e)
|
||||
{
|
||||
var deferral = e.SuspendingOperation.GetDeferral();
|
||||
//TODO: Save application state and stop any background activity
|
||||
deferral.Complete();
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,17 +10,57 @@ EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|ARM = Release|ARM
|
||||
Release|ARM64 = Release|ARM64
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Release|x64.Build.0 = Release|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@@ -225,6 +225,25 @@ namespace ModernKeePassLib.Cryptography
|
||||
return MemUtil.BytesToUInt64(pb);
|
||||
}
|
||||
|
||||
internal ulong GetRandomUInt64(ulong uMaxExcl)
|
||||
{
|
||||
if(uMaxExcl == 0) { Debug.Assert(false); throw new ArgumentOutOfRangeException("uMaxExcl"); }
|
||||
|
||||
ulong uGen, uRem;
|
||||
do
|
||||
{
|
||||
uGen = GetRandomUInt64();
|
||||
uRem = uGen % uMaxExcl;
|
||||
}
|
||||
while((uGen - uRem) > (ulong.MaxValue - (uMaxExcl - 1UL)));
|
||||
// This ensures that the last number of the block (i.e.
|
||||
// (uGen - uRem) + (uMaxExcl - 1)) is generatable;
|
||||
// for signed longs, overflow to negative number:
|
||||
// while((uGen - uRem) + (uMaxExcl - 1) < 0);
|
||||
|
||||
return uRem;
|
||||
}
|
||||
|
||||
#if CRSBENCHMARK
|
||||
public static string Benchmark()
|
||||
{
|
||||
|
@@ -28,37 +28,39 @@ using System.Security.Cryptography;
|
||||
|
||||
namespace ModernKeePassLib.Cryptography
|
||||
{
|
||||
public sealed class CryptoStreamEx : CryptoStream
|
||||
{
|
||||
private ICryptoTransform m_t;
|
||||
private SymmetricAlgorithm m_a;
|
||||
public sealed class CryptoStreamEx : CryptoStream
|
||||
{
|
||||
private ICryptoTransform m_t;
|
||||
private SymmetricAlgorithm m_a;
|
||||
|
||||
public CryptoStreamEx(Stream s, ICryptoTransform t, CryptoStreamMode m,
|
||||
SymmetricAlgorithm a) : base(s, t, m)
|
||||
{
|
||||
m_t = t;
|
||||
m_a = a;
|
||||
}
|
||||
public CryptoStreamEx(Stream s, ICryptoTransform t, CryptoStreamMode m,
|
||||
SymmetricAlgorithm a) : base(s, t, m)
|
||||
{
|
||||
m_t = t;
|
||||
m_a = a;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try { base.Dispose(disposing); }
|
||||
// Unnecessary exception from CryptoStream with
|
||||
// RijndaelManagedTransform when a stream hasn't been
|
||||
// read completely (e.g. incorrect master key)
|
||||
catch (CryptographicException) { }
|
||||
catch (Exception) { Debug.Assert(false); }
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try { base.Dispose(disposing); }
|
||||
// Unnecessary exception from CryptoStream with
|
||||
// RijndaelManagedTransform when a stream hasn't been
|
||||
// read completely (e.g. incorrect master key)
|
||||
catch(CryptographicException) { }
|
||||
// Similar to above, at the beginning of the stream
|
||||
catch(IndexOutOfRangeException) { }
|
||||
catch(Exception) { Debug.Assert(false); }
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
try { if (m_t != null) { m_t.Dispose(); m_t = null; } }
|
||||
catch (Exception) { Debug.Assert(false); }
|
||||
if(disposing)
|
||||
{
|
||||
try { if(m_t != null) { m_t.Dispose(); m_t = null; } }
|
||||
catch(Exception) { Debug.Assert(false); }
|
||||
|
||||
// In .NET 2.0, SymmetricAlgorithm.Dispose() is not public
|
||||
try { if (m_a != null) { m_a.Clear(); m_a = null; } }
|
||||
catch (Exception) { Debug.Assert(false); }
|
||||
}
|
||||
}
|
||||
}
|
||||
// In .NET 2.0, SymmetricAlgorithm.Dispose() is not public
|
||||
try { if(m_a != null) { m_a.Clear(); m_a = null; } }
|
||||
catch(Exception) { Debug.Assert(false); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@@ -42,13 +42,13 @@ namespace ModernKeePassLib.Cryptography.KeyDerivation
|
||||
private const uint MaxVersion = 0x13;
|
||||
|
||||
private const int MinSalt = 8;
|
||||
private const int MaxSalt = int.MaxValue; // .NET limit; 2^32 - 1 in spec
|
||||
private const int MaxSalt = int.MaxValue; // .NET limit; 2^32 - 1 in spec.
|
||||
|
||||
internal const ulong MinIterations = 1;
|
||||
internal const ulong MaxIterations = uint.MaxValue;
|
||||
|
||||
internal const ulong MinMemory = 1024 * 8; // For parallelism = 1
|
||||
// internal const ulong MaxMemory = (ulong)uint.MaxValue * 1024UL; // Spec
|
||||
// internal const ulong MaxMemory = (ulong)uint.MaxValue * 1024UL; // Spec.
|
||||
internal const ulong MaxMemory = int.MaxValue; // .NET limit
|
||||
|
||||
internal const uint MinParallelism = 1;
|
||||
|
@@ -36,20 +36,20 @@ namespace ModernKeePassLib.Cryptography.PasswordGenerator
|
||||
if(pwProfile.Length == 0) return PwgError.Success;
|
||||
|
||||
PwCharSet pcs = new PwCharSet(pwProfile.CharSet.ToString());
|
||||
PwGenerator.PrepareCharSet(pcs, pwProfile);
|
||||
if(!PwGenerator.PrepareCharSet(pcs, pwProfile))
|
||||
return PwgError.InvalidCharSet;
|
||||
|
||||
char[] v = new char[pwProfile.Length];
|
||||
try
|
||||
{
|
||||
for(int i = 0; i < v.Length; ++i)
|
||||
{
|
||||
char ch = PwGenerator.GenerateCharacter(pwProfile,
|
||||
pcs, crsRandomSource);
|
||||
|
||||
char ch = PwGenerator.GenerateCharacter(pcs, crsRandomSource);
|
||||
if(ch == char.MinValue)
|
||||
return PwgError.TooFewCharacters;
|
||||
|
||||
v[i] = ch;
|
||||
if(pwProfile.NoRepeatingCharacters) pcs.Remove(ch);
|
||||
}
|
||||
|
||||
byte[] pbUtf8 = StrUtil.Utf8.GetBytes(v);
|
||||
|
@@ -34,92 +34,61 @@ namespace ModernKeePassLib.Cryptography.PasswordGenerator
|
||||
{
|
||||
psOut = ProtectedString.Empty;
|
||||
|
||||
string strPattern = pwProfile.Pattern;
|
||||
if(string.IsNullOrEmpty(strPattern)) return PwgError.Success;
|
||||
|
||||
CharStream cs = new CharStream(strPattern);
|
||||
LinkedList<char> llGenerated = new LinkedList<char>();
|
||||
PwCharSet pcsCurrent = new PwCharSet();
|
||||
PwCharSet pcsCustom = new PwCharSet();
|
||||
PwCharSet pcsUsed = new PwCharSet();
|
||||
bool bInCharSetDef = false;
|
||||
PwCharSet pcs = new PwCharSet();
|
||||
|
||||
string strPattern = ExpandPattern(pwProfile.Pattern);
|
||||
if(strPattern.Length == 0) return PwgError.Success;
|
||||
|
||||
CharStream csStream = new CharStream(strPattern);
|
||||
char ch = csStream.ReadChar();
|
||||
|
||||
while(ch != char.MinValue)
|
||||
while(true)
|
||||
{
|
||||
pcsCurrent.Clear();
|
||||
char ch = cs.ReadChar();
|
||||
if(ch == char.MinValue) break;
|
||||
|
||||
bool bGenerateChar = false;
|
||||
pcs.Clear();
|
||||
|
||||
if(ch == '\\')
|
||||
{
|
||||
ch = csStream.ReadChar();
|
||||
if(ch == char.MinValue) // Backslash at the end
|
||||
{
|
||||
llGenerated.AddLast('\\');
|
||||
break;
|
||||
}
|
||||
ch = cs.ReadChar();
|
||||
if(ch == char.MinValue) return PwgError.InvalidPattern;
|
||||
|
||||
if(bInCharSetDef) pcsCustom.Add(ch);
|
||||
else
|
||||
{
|
||||
llGenerated.AddLast(ch);
|
||||
pcsUsed.Add(ch);
|
||||
}
|
||||
}
|
||||
else if(ch == '^')
|
||||
{
|
||||
ch = csStream.ReadChar();
|
||||
if(ch == char.MinValue) // ^ at the end
|
||||
{
|
||||
llGenerated.AddLast('^');
|
||||
break;
|
||||
}
|
||||
|
||||
if(bInCharSetDef) pcsCustom.Remove(ch);
|
||||
pcs.Add(ch); // Allow "{...}" support and char check
|
||||
}
|
||||
else if(ch == '[')
|
||||
{
|
||||
pcsCustom.Clear();
|
||||
bInCharSetDef = true;
|
||||
if(!ReadCustomCharSet(cs, pcs))
|
||||
return PwgError.InvalidPattern;
|
||||
}
|
||||
else if(ch == ']')
|
||||
else
|
||||
{
|
||||
pcsCurrent.Add(pcsCustom.ToString());
|
||||
if(!pcs.AddCharSet(ch))
|
||||
return PwgError.InvalidPattern;
|
||||
}
|
||||
|
||||
bInCharSetDef = false;
|
||||
bGenerateChar = true;
|
||||
}
|
||||
else if(bInCharSetDef)
|
||||
int nCount = 1;
|
||||
if(cs.PeekChar() == '{')
|
||||
{
|
||||
if(pcsCustom.AddCharSet(ch) == false)
|
||||
pcsCustom.Add(ch);
|
||||
nCount = ReadCount(cs);
|
||||
if(nCount < 0) return PwgError.InvalidPattern;
|
||||
}
|
||||
else if(pcsCurrent.AddCharSet(ch) == false)
|
||||
{
|
||||
llGenerated.AddLast(ch);
|
||||
pcsUsed.Add(ch);
|
||||
}
|
||||
else bGenerateChar = true;
|
||||
|
||||
if(bGenerateChar)
|
||||
for(int i = 0; i < nCount; ++i)
|
||||
{
|
||||
PwGenerator.PrepareCharSet(pcsCurrent, pwProfile);
|
||||
|
||||
if(!PwGenerator.PrepareCharSet(pcs, pwProfile))
|
||||
return PwgError.InvalidCharSet;
|
||||
if(pwProfile.NoRepeatingCharacters)
|
||||
pcsCurrent.Remove(pcsUsed.ToString());
|
||||
|
||||
char chGen = PwGenerator.GenerateCharacter(pwProfile,
|
||||
pcsCurrent, crsRandomSource);
|
||||
{
|
||||
foreach(char chUsed in llGenerated)
|
||||
pcs.Remove(chUsed);
|
||||
}
|
||||
|
||||
char chGen = PwGenerator.GenerateCharacter(pcs,
|
||||
crsRandomSource);
|
||||
if(chGen == char.MinValue) return PwgError.TooFewCharacters;
|
||||
|
||||
llGenerated.AddLast(chGen);
|
||||
pcsUsed.Add(chGen);
|
||||
}
|
||||
|
||||
ch = csStream.ReadChar();
|
||||
}
|
||||
|
||||
if(llGenerated.Count == 0) return PwgError.Success;
|
||||
@@ -135,53 +104,70 @@ namespace ModernKeePassLib.Cryptography.PasswordGenerator
|
||||
MemUtil.ZeroByteArray(pbUtf8);
|
||||
|
||||
MemUtil.ZeroArray<char>(v);
|
||||
llGenerated.Clear();
|
||||
|
||||
return PwgError.Success;
|
||||
}
|
||||
|
||||
private static string ExpandPattern(string strPattern)
|
||||
private static bool ReadCustomCharSet(CharStream cs, PwCharSet pcsOut)
|
||||
{
|
||||
if(strPattern == null) { Debug.Assert(false); return string.Empty; }
|
||||
|
||||
string str = strPattern;
|
||||
Debug.Assert(cs.PeekChar() != '['); // Consumed already
|
||||
Debug.Assert(pcsOut.Size == 0);
|
||||
|
||||
bool bAdd = true;
|
||||
while(true)
|
||||
{
|
||||
int nOpen = FindFirstUnescapedChar(str, '{');
|
||||
int nClose = FindFirstUnescapedChar(str, '}');
|
||||
char ch = cs.ReadChar();
|
||||
if(ch == char.MinValue) return false;
|
||||
if(ch == ']') break;
|
||||
|
||||
if((nOpen >= 0) && (nOpen < nClose))
|
||||
if(ch == '\\')
|
||||
{
|
||||
string strCount = str.Substring(nOpen + 1, nClose - nOpen - 1);
|
||||
str = str.Remove(nOpen, nClose - nOpen + 1);
|
||||
ch = cs.ReadChar();
|
||||
if(ch == char.MinValue) return false;
|
||||
|
||||
uint uRepeat;
|
||||
if(StrUtil.TryParseUInt(strCount, out uRepeat) && (nOpen >= 1))
|
||||
{
|
||||
if(uRepeat == 0)
|
||||
str = str.Remove(nOpen - 1, 1);
|
||||
else
|
||||
str = str.Insert(nOpen, new string(str[nOpen - 1], (int)uRepeat - 1));
|
||||
}
|
||||
if(bAdd) pcsOut.Add(ch);
|
||||
else pcsOut.Remove(ch);
|
||||
}
|
||||
else if(ch == '^')
|
||||
{
|
||||
if(bAdd) bAdd = false;
|
||||
else return false; // '^' toggles the mode only once
|
||||
}
|
||||
else
|
||||
{
|
||||
PwCharSet pcs = new PwCharSet();
|
||||
if(!pcs.AddCharSet(ch)) return false;
|
||||
|
||||
if(bAdd) pcsOut.Add(pcs.ToString());
|
||||
else pcsOut.Remove(pcs.ToString());
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
return str;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int FindFirstUnescapedChar(string str, char ch)
|
||||
private static int ReadCount(CharStream cs)
|
||||
{
|
||||
for(int i = 0; i < str.Length; ++i)
|
||||
{
|
||||
char chCur = str[i];
|
||||
if(cs.ReadChar() != '{') { Debug.Assert(false); return -1; }
|
||||
|
||||
if(chCur == '\\') ++i; // Next is escaped, skip it
|
||||
else if(chCur == ch) return i;
|
||||
// Ensure not empty
|
||||
char chFirst = cs.PeekChar();
|
||||
if((chFirst < '0') || (chFirst > '9')) return -1;
|
||||
|
||||
long n = 0;
|
||||
while(true)
|
||||
{
|
||||
char ch = cs.ReadChar();
|
||||
if(ch == '}') break;
|
||||
|
||||
if((ch >= '0') && (ch <= '9'))
|
||||
{
|
||||
n = (n * 10L) + (long)(ch - '0');
|
||||
if(n > int.MaxValue) return -1;
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return (int)n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -43,7 +43,6 @@ namespace ModernKeePassLib.Cryptography.PasswordGenerator
|
||||
public static readonly string UpperHex = "0123456789ABCDEF";
|
||||
public static readonly string LowerHex = "0123456789abcdef";
|
||||
|
||||
public static readonly string Invalid = "\t\r\n";
|
||||
public static readonly string LookAlike = @"O0l1I|";
|
||||
|
||||
internal static readonly string MenuAccels = PwCharSet.LowerCase + PwCharSet.Digits;
|
||||
|
@@ -36,7 +36,9 @@ namespace ModernKeePassLib.Cryptography.PasswordGenerator
|
||||
Success = 0,
|
||||
Unknown = 1,
|
||||
TooFewCharacters = 2,
|
||||
UnknownAlgorithm = 3
|
||||
UnknownAlgorithm = 3,
|
||||
InvalidCharSet = 4,
|
||||
InvalidPattern = 5
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -94,30 +96,33 @@ namespace ModernKeePassLib.Cryptography.PasswordGenerator
|
||||
return new CryptoRandomStream(CrsAlgorithm.ChaCha20, pbKey);
|
||||
}
|
||||
|
||||
internal static char GenerateCharacter(PwProfile pwProfile,
|
||||
PwCharSet pwCharSet, CryptoRandomStream crsRandomSource)
|
||||
internal static char GenerateCharacter(PwCharSet pwCharSet,
|
||||
CryptoRandomStream crsRandomSource)
|
||||
{
|
||||
if(pwCharSet.Size == 0) return char.MinValue;
|
||||
uint cc = pwCharSet.Size;
|
||||
if(cc == 0) return char.MinValue;
|
||||
|
||||
ulong uIndex = crsRandomSource.GetRandomUInt64();
|
||||
uIndex %= (ulong)pwCharSet.Size;
|
||||
|
||||
char ch = pwCharSet[(uint)uIndex];
|
||||
|
||||
if(pwProfile.NoRepeatingCharacters)
|
||||
pwCharSet.Remove(ch);
|
||||
|
||||
return ch;
|
||||
uint i = (uint)crsRandomSource.GetRandomUInt64(cc);
|
||||
return pwCharSet[i];
|
||||
}
|
||||
|
||||
internal static void PrepareCharSet(PwCharSet pwCharSet, PwProfile pwProfile)
|
||||
internal static bool PrepareCharSet(PwCharSet pwCharSet, PwProfile pwProfile)
|
||||
{
|
||||
pwCharSet.Remove(PwCharSet.Invalid);
|
||||
uint cc = pwCharSet.Size;
|
||||
for(uint i = 0; i < cc; ++i)
|
||||
{
|
||||
char ch = pwCharSet[i];
|
||||
if((ch == char.MinValue) || (ch == '\t') || (ch == '\r') ||
|
||||
(ch == '\n') || char.IsSurrogate(ch))
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pwProfile.ExcludeLookAlike) pwCharSet.Remove(PwCharSet.LookAlike);
|
||||
|
||||
if(pwProfile.ExcludeCharacters.Length > 0)
|
||||
if(!string.IsNullOrEmpty(pwProfile.ExcludeCharacters))
|
||||
pwCharSet.Remove(pwProfile.ExcludeCharacters);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static void Shuffle(char[] v, CryptoRandomStream crsRandomSource)
|
||||
@@ -127,8 +132,7 @@ namespace ModernKeePassLib.Cryptography.PasswordGenerator
|
||||
|
||||
for(int i = v.Length - 1; i >= 1; --i)
|
||||
{
|
||||
ulong r = crsRandomSource.GetRandomUInt64();
|
||||
int j = (int)(r % (ulong)(i + 1));
|
||||
int j = (int)crsRandomSource.GetRandomUInt64((ulong)(i + 1));
|
||||
|
||||
char t = v[i];
|
||||
v[i] = v[j];
|
||||
|
@@ -87,7 +87,7 @@ namespace ModernKeePassLib.Interfaces
|
||||
bool SetText(string strNewText, LogStatusType lsType);
|
||||
|
||||
/// <summary>
|
||||
/// Check if the user cancelled the current work.
|
||||
/// Check whether the user cancelled the current work.
|
||||
/// </summary>
|
||||
/// <returns>Returns <c>true</c> if the caller should continue
|
||||
/// the current work.</returns>
|
||||
|
@@ -66,7 +66,7 @@ namespace ModernKeePassLib.Interfaces
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flag that determines if the object does expire.
|
||||
/// Flag that determines whether the object expires.
|
||||
/// </summary>
|
||||
bool Expires
|
||||
{
|
||||
|
@@ -21,9 +21,12 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
using ModernKeePassLib.Cryptography;
|
||||
using ModernKeePassLib.Cryptography.KeyDerivation;
|
||||
using ModernKeePassLib.Interfaces;
|
||||
using ModernKeePassLib.Native;
|
||||
using ModernKeePassLib.Resources;
|
||||
using ModernKeePassLib.Security;
|
||||
using ModernKeePassLib.Utility;
|
||||
@@ -166,7 +169,6 @@ namespace ModernKeePassLib.Keys
|
||||
{
|
||||
ValidateUserKeys();
|
||||
|
||||
// Concatenate user key data
|
||||
List<byte[]> lData = new List<byte[]>();
|
||||
int cbData = 0;
|
||||
foreach(IUserKey pKey in m_vUserKeys)
|
||||
@@ -199,13 +201,17 @@ namespace ModernKeePassLib.Keys
|
||||
{
|
||||
if(ckOther == null) throw new ArgumentNullException("ckOther");
|
||||
|
||||
bool bEqual;
|
||||
byte[] pbThis = CreateRawCompositeKey32();
|
||||
byte[] pbOther = ckOther.CreateRawCompositeKey32();
|
||||
bool bResult = MemUtil.ArraysEqual(pbThis, pbOther);
|
||||
MemUtil.ZeroByteArray(pbOther);
|
||||
MemUtil.ZeroByteArray(pbThis);
|
||||
try
|
||||
{
|
||||
byte[] pbOther = ckOther.CreateRawCompositeKey32();
|
||||
bEqual = MemUtil.ArraysEqual(pbThis, pbOther);
|
||||
MemUtil.ZeroByteArray(pbOther);
|
||||
}
|
||||
finally { MemUtil.ZeroByteArray(pbThis); }
|
||||
|
||||
return bResult;
|
||||
return bEqual;
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
@@ -231,31 +237,90 @@ namespace ModernKeePassLib.Keys
|
||||
{
|
||||
if(p == null) { Debug.Assert(false); throw new ArgumentNullException("p"); }
|
||||
|
||||
byte[] pbRaw32 = CreateRawCompositeKey32();
|
||||
if((pbRaw32 == null) || (pbRaw32.Length != 32))
|
||||
{ Debug.Assert(false); return null; }
|
||||
byte[] pbRaw32 = null, pbTrf32 = null;
|
||||
ProtectedBinary pbRet = null;
|
||||
|
||||
KdfEngine kdf = KdfPool.Get(p.KdfUuid);
|
||||
if(kdf == null) // CryptographicExceptions are translated to "file corrupted"
|
||||
throw new Exception(KLRes.UnknownKdf + MessageService.NewParagraph +
|
||||
KLRes.FileNewVerOrPlgReq + MessageService.NewParagraph +
|
||||
"UUID: " + p.KdfUuid.ToHexString() + ".");
|
||||
|
||||
byte[] pbTrf32 = kdf.Transform(pbRaw32, p);
|
||||
if(pbTrf32 == null) { Debug.Assert(false); return null; }
|
||||
|
||||
if(pbTrf32.Length != 32)
|
||||
try
|
||||
{
|
||||
Debug.Assert(false);
|
||||
pbTrf32 = CryptoUtil.HashSha256(pbTrf32);
|
||||
pbRaw32 = CreateRawCompositeKey32();
|
||||
if((pbRaw32 == null) || (pbRaw32.Length != 32))
|
||||
{ Debug.Assert(false); return null; }
|
||||
|
||||
KdfEngine kdf = KdfPool.Get(p.KdfUuid);
|
||||
if(kdf == null) // CryptographicExceptions are translated to "file corrupted"
|
||||
throw new Exception(KLRes.UnknownKdf + MessageService.NewParagraph +
|
||||
KLRes.FileNewVerOrPlgReq + MessageService.NewParagraph +
|
||||
"UUID: " + p.KdfUuid.ToHexString() + ".");
|
||||
|
||||
pbTrf32 = kdf.Transform(pbRaw32, p);
|
||||
if(pbTrf32 == null) { Debug.Assert(false); return null; }
|
||||
if(pbTrf32.Length != 32)
|
||||
{
|
||||
Debug.Assert(false);
|
||||
pbTrf32 = CryptoUtil.HashSha256(pbTrf32);
|
||||
}
|
||||
|
||||
pbRet = new ProtectedBinary(true, pbTrf32);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(pbRaw32 != null) MemUtil.ZeroByteArray(pbRaw32);
|
||||
if(pbTrf32 != null) MemUtil.ZeroByteArray(pbTrf32);
|
||||
}
|
||||
|
||||
ProtectedBinary pbRet = new ProtectedBinary(true, pbTrf32);
|
||||
MemUtil.ZeroByteArray(pbTrf32);
|
||||
MemUtil.ZeroByteArray(pbRaw32);
|
||||
return pbRet;
|
||||
}
|
||||
|
||||
private sealed class CkGkTaskInfo
|
||||
{
|
||||
public volatile ProtectedBinary Key = null;
|
||||
public volatile string Error = null;
|
||||
}
|
||||
|
||||
internal ProtectedBinary GenerateKey32Ex(KdfParameters p, IStatusLogger sl)
|
||||
{
|
||||
if(sl == null) return GenerateKey32(p);
|
||||
|
||||
CkGkTaskInfo ti = new CkGkTaskInfo();
|
||||
|
||||
ThreadStart f = delegate()
|
||||
{
|
||||
if(ti == null) { Debug.Assert(false); return; }
|
||||
|
||||
try { ti.Key = GenerateKey32(p); }
|
||||
catch(ThreadAbortException exAbort)
|
||||
{
|
||||
ti.Error = ((exAbort != null) ? exAbort.Message : null);
|
||||
Thread.ResetAbort();
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Debug.Assert(false);
|
||||
ti.Error = ((ex != null) ? ex.Message : null);
|
||||
}
|
||||
};
|
||||
|
||||
Thread th = new Thread(f);
|
||||
th.Start();
|
||||
|
||||
Debug.Assert(PwDefs.UIUpdateDelay >= 2);
|
||||
while(!th.Join(PwDefs.UIUpdateDelay / 2))
|
||||
{
|
||||
if(!sl.ContinueWork())
|
||||
{
|
||||
try { th.Abort(); }
|
||||
catch(Exception) { Debug.Assert(false); }
|
||||
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(ti.Error)) throw new Exception(ti.Error);
|
||||
|
||||
Debug.Assert(ti.Key != null);
|
||||
return ti.Key;
|
||||
}
|
||||
|
||||
private void ValidateUserKeys()
|
||||
{
|
||||
int nAccounts = 0;
|
||||
@@ -280,14 +345,11 @@ namespace ModernKeePassLib.Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
return KLRes.InvalidCompositeKey + MessageService.NewParagraph +
|
||||
KLRes.InvalidCompositeKeyHint;
|
||||
return (KLRes.InvalidCompositeKey + MessageService.NewParagraph +
|
||||
KLRes.InvalidCompositeKeyHint);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a new invalid composite key exception.
|
||||
/// </summary>
|
||||
public InvalidCompositeKeyException()
|
||||
{
|
||||
}
|
||||
|
@@ -67,14 +67,13 @@ namespace ModernKeePassLib.Keys
|
||||
{
|
||||
get { return m_pbKeyData; }
|
||||
}
|
||||
|
||||
#if ModernKeePassLib
|
||||
public KcpKeyFile(StorageFile strKeyFile)
|
||||
{
|
||||
Construct(IOConnectionInfo.FromFile(strKeyFile), false);
|
||||
}
|
||||
public KcpKeyFile(StorageFile keyFile)
|
||||
{
|
||||
Construct(IOConnectionInfo.FromStorageFile(keyFile), false);
|
||||
}
|
||||
#else
|
||||
public KcpKeyFile(string strKeyFile)
|
||||
public KcpKeyFile(string strKeyFile)
|
||||
{
|
||||
Construct(IOConnectionInfo.FromPath(strKeyFile), false);
|
||||
}
|
||||
@@ -183,19 +182,19 @@ namespace ModernKeePassLib.Keys
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new, random key-file.
|
||||
/// </summary>
|
||||
/// <param name="strFilePath">Path where the key-file should be saved to.
|
||||
/// If the file exists already, it will be overwritten.</param>
|
||||
/// <param name="pbAdditionalEntropy">Additional entropy used to generate
|
||||
/// the random key. May be <c>null</c> (in this case only the KeePass-internal
|
||||
/// random number generator is used).</param>
|
||||
/// <returns>Returns a <c>FileSaveResult</c> error code.</returns>
|
||||
/// <summary>
|
||||
/// Create a new, random key-file.
|
||||
/// </summary>
|
||||
/// <param name="strFilePath">Path where the key-file should be saved to.
|
||||
/// If the file exists already, it will be overwritten.</param>
|
||||
/// <param name="pbAdditionalEntropy">Additional entropy used to generate
|
||||
/// the random key. May be <c>null</c> (in this case only the KeePass-internal
|
||||
/// random number generator is used).</param>
|
||||
/// <returns>Returns a <c>FileSaveResult</c> error code.</returns>
|
||||
#if ModernKeePassLib
|
||||
public static void Create(StorageFile strFilePath, byte[] pbAdditionalEntropy)
|
||||
public static void Create(StorageFile file, byte[] pbAdditionalEntropy)
|
||||
#else
|
||||
public static void Create(string strFilePath, byte[] pbAdditionalEntropy)
|
||||
public static void Create(string strFilePath, byte[] pbAdditionalEntropy)
|
||||
#endif
|
||||
{
|
||||
byte[] pbKey32 = CryptoRandom.Instance.GetRandomBytes(32);
|
||||
@@ -215,7 +214,11 @@ namespace ModernKeePassLib.Keys
|
||||
}
|
||||
}
|
||||
|
||||
CreateXmlKeyFile(strFilePath, pbFinalKey32);
|
||||
#if ModernKeePassLib
|
||||
CreateXmlKeyFile(file, pbFinalKey32);
|
||||
#else
|
||||
CreateXmlKeyFile(strFilePath, pbFinalKey32);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
@@ -276,19 +279,23 @@ namespace ModernKeePassLib.Keys
|
||||
|
||||
return pbKeyData;
|
||||
}
|
||||
|
||||
#if ModernKeePassLib
|
||||
private static void CreateXmlKeyFile(StorageFile strFile, byte[] pbKeyData)
|
||||
private static void CreateXmlKeyFile(StorageFile file, byte[] pbKeyData)
|
||||
{
|
||||
Debug.Assert(file != null);
|
||||
if (file == null) throw new ArgumentNullException(nameof(file));
|
||||
#else
|
||||
private static void CreateXmlKeyFile(string strFile, byte[] pbKeyData)
|
||||
#endif
|
||||
private static void CreateXmlKeyFile(string strFile, byte[] pbKeyData)
|
||||
{
|
||||
Debug.Assert(strFile != null);
|
||||
if(strFile == null) throw new ArgumentNullException("strFile");
|
||||
#endif
|
||||
Debug.Assert(pbKeyData != null);
|
||||
if(pbKeyData == null) throw new ArgumentNullException("pbKeyData");
|
||||
|
||||
#if ModernKeePassLib
|
||||
IOConnectionInfo ioc = IOConnectionInfo.FromFile(strFile);
|
||||
var ioc = IOConnectionInfo.FromStorageFile(file);
|
||||
#else
|
||||
IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile);
|
||||
#endif
|
||||
|
@@ -21,9 +21,9 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
using ModernKeePassLib.Cryptography;
|
||||
using ModernKeePassLib.Security;
|
||||
using ModernKeePassLib.Utility;
|
||||
using ModernKeePassLib.Cryptography;
|
||||
|
||||
namespace ModernKeePassLib.Keys
|
||||
{
|
||||
|
@@ -145,7 +145,7 @@ namespace ModernKeePassLib.Keys
|
||||
|
||||
public override byte[] GetKey(KeyProviderQueryContext ctx)
|
||||
{
|
||||
return new byte[]{ 2, 3, 5, 7, 11, 13 };
|
||||
return new byte[] { 2, 3, 5, 7, 11, 13 };
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@@ -3,14 +3,14 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Version>2.41.1</Version>
|
||||
<Version>2.42.1</Version>
|
||||
<Authors>Geoffroy Bonneville</Authors>
|
||||
<PackageLicenseUrl>https://www.gnu.org/licenses/gpl-3.0.en.html</PackageLicenseUrl>
|
||||
<PackageProjectUrl>https://github.com/wismna/ModernKeePass</PackageProjectUrl>
|
||||
<Description>Portable KeePass Password Management Library that targets .Net Standard and WinRT. Allows reading, editing and writing to KeePass 2.x databases.</Description>
|
||||
<Company>wismna</Company>
|
||||
<Product>ModernKeePassLib</Product>
|
||||
<PackageReleaseNotes>Allow opening Storage File from FutureAccessList with a token</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>Update to version 2.42.1</PackageReleaseNotes>
|
||||
<PackageTags>KeePass KeePassLib Portable PCL NetStandard ModernKeePass</PackageTags>
|
||||
<Copyright>Copyright © 2019 Geoffroy Bonneville</Copyright>
|
||||
</PropertyGroup>
|
||||
|
@@ -22,6 +22,12 @@ namespace ModernKeePassLib.Native
|
||||
{
|
||||
return Environment.OSVersion.Platform;
|
||||
}
|
||||
|
||||
internal static string DecodeArgsToPath(string strApp)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(strApp)) return strApp;
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
internal static class NativeMethods
|
||||
|
@@ -234,16 +234,16 @@ namespace ModernKeePassLib.Native
|
||||
{
|
||||
ProcessStartInfo psi = new ProcessStartInfo();
|
||||
|
||||
psi.FileName = EncodePath(strAppPath);
|
||||
if(!string.IsNullOrEmpty(strParams)) psi.Arguments = strParams;
|
||||
|
||||
psi.CreateNoWindow = true;
|
||||
psi.FileName = strAppPath;
|
||||
psi.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
psi.UseShellExecute = false;
|
||||
|
||||
psi.RedirectStandardOutput = bStdOut;
|
||||
|
||||
if(strStdInput != null) psi.RedirectStandardInput = true;
|
||||
|
||||
if(!string.IsNullOrEmpty(strParams)) psi.Arguments = strParams;
|
||||
|
||||
Process p = Process.Start(psi);
|
||||
pToDispose = p;
|
||||
|
||||
@@ -291,7 +291,7 @@ namespace ModernKeePassLib.Native
|
||||
#if !ModernKeePassLib
|
||||
if((f & AppRunFlags.DoEvents) != AppRunFlags.None)
|
||||
{
|
||||
List<Form> lDisabledForms = new List<Form>();
|
||||
List<Form> lDisabledForms = new List<Form>();
|
||||
if((f & AppRunFlags.DisableForms) != AppRunFlags.None)
|
||||
{
|
||||
foreach(Form form in Application.OpenForms)
|
||||
@@ -456,5 +456,76 @@ namespace ModernKeePassLib.Native
|
||||
// https://referencesource.microsoft.com/#mscorlib/system/runtime/interopservices/windowsruntime/winrtclassactivator.cs
|
||||
return Type.GetType(strType + ", Windows, ContentType=WindowsRuntime", false);
|
||||
}
|
||||
|
||||
internal static string EncodeDataToArgs(string strData)
|
||||
{
|
||||
if(strData == null) { Debug.Assert(false); return string.Empty; }
|
||||
|
||||
// Cf. EncodePath and DecodeArgsToPath
|
||||
if(MonoWorkarounds.IsRequired(3471228285U) && IsUnix())
|
||||
{
|
||||
string str = strData;
|
||||
|
||||
str = str.Replace("\\", "\\\\");
|
||||
str = str.Replace("\"", "\\\"");
|
||||
|
||||
// Whether '\'' needs to be encoded depends on the context
|
||||
// (e.g. surrounding quotes); as we do not know what the
|
||||
// caller does with the returned string, we assume that
|
||||
// it will be used in a context where '\'' must not be
|
||||
// encoded; this behavior is documented
|
||||
// str = str.Replace("\'", "\\\'");
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// See SHELLEXECUTEINFO structure documentation
|
||||
return strData.Replace("\"", "\"\"\"");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encode a path for <c>Process.Start</c>.
|
||||
/// </summary>
|
||||
internal static string EncodePath(string strPath)
|
||||
{
|
||||
if(strPath == null) { Debug.Assert(false); return string.Empty; }
|
||||
|
||||
// Cf. EncodeDataToArgs and DecodeArgsToPath
|
||||
if(MonoWorkarounds.IsRequired(3471228285U) && IsUnix())
|
||||
{
|
||||
string str = strPath;
|
||||
|
||||
str = str.Replace("\\", "\\\\");
|
||||
str = str.Replace("\"", "\\\"");
|
||||
|
||||
// '\'' must not be encoded in paths (only in args)
|
||||
// str = str.Replace("\'", "\\\'");
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
return strPath; // '\"' is not allowed in paths on Windows
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode command line arguments to a path for <c>Process.Start</c>.
|
||||
/// </summary>
|
||||
internal static string DecodeArgsToPath(string strArgs)
|
||||
{
|
||||
if(strArgs == null) { Debug.Assert(false); return string.Empty; }
|
||||
|
||||
string str = strArgs;
|
||||
|
||||
// Cf. EncodeDataToArgs and EncodePath
|
||||
// if(MonoWorkarounds.IsRequired(3471228285U) && IsUnix())
|
||||
// {
|
||||
// string strPlh = Guid.NewGuid().ToString();
|
||||
// str = str.Replace("\\\\", strPlh);
|
||||
// str = str.Replace("\\\'", "\'");
|
||||
// str = str.Replace(strPlh, "\\\\"); // Restore
|
||||
// }
|
||||
|
||||
return str; // '\"' is not allowed in paths on Windows
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -39,6 +39,9 @@ namespace ModernKeePassLib.Native
|
||||
internal const uint FILE_SUPPORTS_TRANSACTIONS = 0x00200000;
|
||||
internal const int MAX_TRANSACTION_DESCRIPTION_LENGTH = 64;
|
||||
|
||||
internal static readonly Guid FOLDERID_SkyDrive = new Guid(
|
||||
"A52BBA46-E9E1-435F-B3D9-28DAA648C0F6");
|
||||
|
||||
// internal const uint TF_SFT_SHOWNORMAL = 0x00000001;
|
||||
// internal const uint TF_SFT_HIDDEN = 0x00000008;
|
||||
|
||||
@@ -179,6 +182,10 @@ namespace ModernKeePassLib.Native
|
||||
string lpNewFileName, IntPtr lpProgressRoutine, IntPtr lpData,
|
||||
UInt32 dwFlags, IntPtr hTransaction);
|
||||
|
||||
[DllImport("Shell32.dll")]
|
||||
private static extern int SHGetKnownFolderPath(ref Guid rfid, uint dwFlags,
|
||||
IntPtr hToken, out IntPtr ppszPath);
|
||||
|
||||
#if (!KeePassLibSD && !KeePassUAP)
|
||||
[DllImport("ShlWApi.dll", CharSet = CharSet.Auto)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
@@ -256,5 +263,29 @@ namespace ModernKeePassLib.Native
|
||||
return strRtDir;
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static string GetKnownFolderPath(Guid g)
|
||||
{
|
||||
if(Marshal.SystemDefaultCharSize != 2) { Debug.Assert(false); return string.Empty; }
|
||||
|
||||
IntPtr pszPath = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
if(SHGetKnownFolderPath(ref g, 0, IntPtr.Zero, out pszPath) == 0)
|
||||
{
|
||||
if(pszPath != IntPtr.Zero)
|
||||
return Marshal.PtrToStringUni(pszPath);
|
||||
else { Debug.Assert(false); }
|
||||
}
|
||||
}
|
||||
catch(Exception) { Debug.Assert(false); }
|
||||
finally
|
||||
{
|
||||
try { if(pszPath != IntPtr.Zero) Marshal.FreeCoTaskMem(pszPath); }
|
||||
catch(Exception) { Debug.Assert(false); }
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -21,10 +21,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
|
||||
#if ModernKeePassLib
|
||||
using Windows.UI.Xaml.Controls;
|
||||
#if !KeePassUAP
|
||||
using System.Drawing;
|
||||
#endif
|
||||
|
||||
using ModernKeePassLib.Collections;
|
||||
@@ -132,7 +131,7 @@ namespace ModernKeePassLib
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <c>IOConnection</c> of the currently opened database file.
|
||||
/// <c>IOConnection</c> of the currently open database file.
|
||||
/// Is never <c>null</c>.
|
||||
/// </summary>
|
||||
public IOConnectionInfo IOConnectionInfo
|
||||
@@ -660,8 +659,8 @@ namespace ModernKeePassLib
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the currently opened database. The file is written to the location
|
||||
/// it has been opened from.
|
||||
/// Save the currently open database. The file is written to the
|
||||
/// location it has been opened from.
|
||||
/// </summary>
|
||||
/// <param name="slLogger">Logger that recieves status information.</param>
|
||||
public void Save(IStatusLogger slLogger)
|
||||
@@ -695,16 +694,16 @@ namespace ModernKeePassLib
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the currently opened database to a different location. If
|
||||
/// Save the currently open database to a different location. If
|
||||
/// <paramref name="bIsPrimaryNow" /> is <c>true</c>, the specified
|
||||
/// location is made the default location for future saves
|
||||
/// using <c>SaveDatabase</c>.
|
||||
/// </summary>
|
||||
/// <param name="ioConnection">New location to serialize the database to.</param>
|
||||
/// <param name="bIsPrimaryNow">If <c>true</c>, the new location is made the
|
||||
/// standard location for the database. If <c>false</c>, a copy of the currently
|
||||
/// opened database is saved to the specified location, but it isn't
|
||||
/// made the default location (i.e. no lock files will be moved for
|
||||
/// <param name="bIsPrimaryNow">If <c>true</c>, the new location is made
|
||||
/// the standard location for the database. If <c>false</c>, a copy of the
|
||||
/// currently open database is saved to the specified location, but it
|
||||
/// isn't made the default location (i.e. no lock files will be moved for
|
||||
/// example).</param>
|
||||
/// <param name="slLogger">Logger that recieves status information.</param>
|
||||
public void SaveAs(IOConnectionInfo ioConnection, bool bIsPrimaryNow,
|
||||
@@ -736,8 +735,8 @@ namespace ModernKeePassLib
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the currently opened database. No confirmation message is shown
|
||||
/// before closing. Unsaved changes will be lost.
|
||||
/// Closes the currently open database. No confirmation message
|
||||
/// is shown before closing. Unsaved changes will be lost.
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
@@ -801,6 +800,12 @@ namespace ModernKeePassLib
|
||||
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;
|
||||
@@ -1087,8 +1092,8 @@ namespace ModernKeePassLib
|
||||
|
||||
if(pgLocal.IsContainedIn(pg)) continue;
|
||||
|
||||
if(!pgLocal.CanAddGroup(pg)) { Debug.Assert(false); continue; }
|
||||
pg.ParentGroup.Groups.Remove(pg);
|
||||
|
||||
// pgLocal.AddGroup(pg, true);
|
||||
InsertObjectAtBestPos<PwGroup>(pgLocal.Groups, pg, ppSrc);
|
||||
pg.ParentGroup = pgLocal;
|
||||
@@ -1643,7 +1648,7 @@ namespace ModernKeePassLib
|
||||
|
||||
return null;
|
||||
}
|
||||
#elif !KeePassLibSD
|
||||
#elif !KeePassLibSD && !ModernKeePassLib
|
||||
[Obsolete("Additionally specify the size.")]
|
||||
public Image GetCustomIcon(PwUuid pwIconId)
|
||||
{
|
||||
|
@@ -55,18 +55,18 @@ namespace ModernKeePassLib
|
||||
/// e.g. 2.19 = 0x02130000.
|
||||
/// It is highly recommended to use <c>FileVersion64</c> instead.
|
||||
/// </summary>
|
||||
public static readonly uint Version32 = 0x02290000;
|
||||
public static readonly uint Version32 = 0x022A0100;
|
||||
|
||||
/// <summary>
|
||||
/// Version, encoded as 64-bit unsigned integer
|
||||
/// (component-wise, 16 bits per component).
|
||||
/// </summary>
|
||||
public static readonly ulong FileVersion64 = 0x0002002900000000UL;
|
||||
public static readonly ulong FileVersion64 = 0x0002002A00010000UL;
|
||||
|
||||
/// <summary>
|
||||
/// Version, encoded as string.
|
||||
/// </summary>
|
||||
public static readonly string VersionString = "2.41";
|
||||
public static readonly string VersionString = "2.42.1";
|
||||
|
||||
public static readonly string Copyright = @"Copyright © 2003-2019 Dominik Reichl";
|
||||
|
||||
@@ -181,6 +181,12 @@ namespace ModernKeePassLib
|
||||
/// </summary>
|
||||
public static readonly string DefaultAutoTypeSequenceTan = @"{PASSWORD}";
|
||||
|
||||
/// <summary>
|
||||
/// Maximum time (in milliseconds) after which the user interface
|
||||
/// should be updated.
|
||||
/// </summary>
|
||||
internal const int UIUpdateDelay = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Check if a name is a standard field name.
|
||||
/// </summary>
|
||||
|
@@ -61,7 +61,7 @@ namespace ModernKeePassLib
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Methods for merging password databases/entries.
|
||||
/// Methods for merging databases/entries.
|
||||
/// </summary>
|
||||
public enum PwMergeMethod
|
||||
{
|
||||
|
@@ -25,19 +25,24 @@ using System.Text.RegularExpressions;
|
||||
using ModernKeePassLib.Collections;
|
||||
using ModernKeePassLib.Delegates;
|
||||
using ModernKeePassLib.Interfaces;
|
||||
using ModernKeePassLib.Resources;
|
||||
using ModernKeePassLib.Security;
|
||||
using ModernKeePassLib.Utility;
|
||||
|
||||
namespace ModernKeePassLib
|
||||
{
|
||||
/// <summary>
|
||||
/// A group containing several password entries.
|
||||
/// A group containing subgroups and entries.
|
||||
/// </summary>
|
||||
public sealed class PwGroup : ITimeLogger, IStructureItem, IDeepCloneable<PwGroup>
|
||||
{
|
||||
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 PwObjectList<PwGroup> m_listGroups = new PwObjectList<PwGroup>();
|
||||
private PwObjectList<PwEntry> m_listEntries = new PwObjectList<PwEntry>();
|
||||
private PwGroup m_pParentGroup = null;
|
||||
@@ -139,7 +144,8 @@ namespace ModernKeePassLib
|
||||
{
|
||||
get { return m_pParentGroup; }
|
||||
|
||||
// Plugins: use <c>PwGroup.AddGroup</c> instead.
|
||||
// Plugins: use the PwGroup.AddGroup method instead.
|
||||
// Internal: check depth using CanAddGroup/CheckCanAddGroup.
|
||||
internal set { Debug.Assert(value != this); m_pParentGroup = value; }
|
||||
}
|
||||
|
||||
@@ -1244,7 +1250,7 @@ namespace ModernKeePassLib
|
||||
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;
|
||||
@@ -1367,21 +1373,34 @@ namespace ModernKeePassLib
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Get the level of the group (i.e. the number of parent groups).
|
||||
/// Get the depth of this group (i.e. the number of ancestors).
|
||||
/// </summary>
|
||||
/// <returns>Number of parent groups.</returns>
|
||||
public uint GetLevel()
|
||||
/// <returns>Depth of this group.</returns>
|
||||
public uint GetDepth()
|
||||
{
|
||||
PwGroup pg = m_pParentGroup;
|
||||
uint uLevel = 0;
|
||||
uint d = 0;
|
||||
|
||||
while(pg != null)
|
||||
{
|
||||
pg = pg.ParentGroup;
|
||||
++uLevel;
|
||||
pg = pg.m_pParentGroup;
|
||||
++d;
|
||||
}
|
||||
|
||||
return 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);
|
||||
}
|
||||
|
||||
public string GetAutoTypeSequenceInherited()
|
||||
@@ -1520,13 +1539,31 @@ namespace ModernKeePassLib
|
||||
{
|
||||
if(subGroup == null) throw new ArgumentNullException("subGroup");
|
||||
|
||||
CheckCanAddGroup(subGroup);
|
||||
m_listGroups.Add(subGroup);
|
||||
|
||||
if(bTakeOwnership) subGroup.m_pParentGroup = this;
|
||||
if(bTakeOwnership) subGroup.ParentGroup = 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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an entry to this group.
|
||||
/// </summary>
|
||||
|
@@ -59,6 +59,7 @@ namespace ModernKeePassLib.Resources
|
||||
m_strOldFormat = TryGetEx(dictNew, "OldFormat", m_strOldFormat);
|
||||
m_strPassive = TryGetEx(dictNew, "Passive", m_strPassive);
|
||||
m_strPreAuth = TryGetEx(dictNew, "PreAuth", m_strPreAuth);
|
||||
m_strStructsTooDeep = TryGetEx(dictNew, "StructsTooDeep", m_strStructsTooDeep);
|
||||
m_strTimeout = TryGetEx(dictNew, "Timeout", m_strTimeout);
|
||||
m_strTryAgainSecs = TryGetEx(dictNew, "TryAgainSecs", m_strTryAgainSecs);
|
||||
m_strUnknownHeaderId = TryGetEx(dictNew, "UnknownHeaderId", m_strUnknownHeaderId);
|
||||
@@ -101,6 +102,7 @@ namespace ModernKeePassLib.Resources
|
||||
"OldFormat",
|
||||
"Passive",
|
||||
"PreAuth",
|
||||
"StructsTooDeep",
|
||||
"Timeout",
|
||||
"TryAgainSecs",
|
||||
"UnknownHeaderId",
|
||||
@@ -346,10 +348,10 @@ namespace ModernKeePassLib.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
|
||||
{
|
||||
@@ -477,6 +479,17 @@ namespace ModernKeePassLib.Resources
|
||||
get { return m_strPreAuth; }
|
||||
}
|
||||
|
||||
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>
|
||||
|
@@ -9,7 +9,7 @@ namespace ModernKeePassLib.Resources
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
public static class KSRes
|
||||
public static partial class KSRes
|
||||
{
|
||||
private static string TryGetEx(Dictionary<string, string> dictNew,
|
||||
string strName, string strDefault)
|
||||
|
@@ -23,18 +23,19 @@ using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using Windows.Storage.AccessCache;
|
||||
#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT)
|
||||
using System.Security.AccessControl;
|
||||
#endif
|
||||
|
||||
using ModernKeePassLib.Native;
|
||||
using ModernKeePassLib.Utility;
|
||||
using System.Threading.Tasks;
|
||||
#if ModernKeePassLib
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.Streams;
|
||||
#endif
|
||||
|
||||
using ModernKeePassLib.Cryptography;
|
||||
using ModernKeePassLib.Delegates;
|
||||
using ModernKeePassLib.Native;
|
||||
using ModernKeePassLib.Resources;
|
||||
using ModernKeePassLib.Utility;
|
||||
|
||||
namespace ModernKeePassLib.Serialization
|
||||
{
|
||||
@@ -210,10 +211,10 @@ namespace ModernKeePassLib.Serialization
|
||||
// trying to set 'Owner' or 'Group' can result in an
|
||||
// UnauthorizedAccessException; thus we restore 'Access' (DACL) only
|
||||
const AccessControlSections acs = AccessControlSections.Access;
|
||||
|
||||
#endif
|
||||
bool bEfsEncrypted = false;
|
||||
byte[] pbSec = null;
|
||||
|
||||
DateTime? otCreation = null;
|
||||
|
||||
bool bBaseExists = IOConnection.FileExists(m_iocBase);
|
||||
@@ -228,9 +229,7 @@ namespace ModernKeePassLib.Serialization
|
||||
try { if(bEfsEncrypted) File.Decrypt(m_iocBase.Path); } // For TxF
|
||||
catch(Exception) { Debug.Assert(false); }
|
||||
#endif
|
||||
#if ModernKeePassLib
|
||||
otCreation = m_iocBase.StorageFile.DateCreated.UtcDateTime;
|
||||
#else
|
||||
#if !ModernKeePassLib
|
||||
otCreation = File.GetCreationTimeUtc(m_iocBase.Path);
|
||||
#endif
|
||||
#if !ModernKeePassLib
|
||||
@@ -238,7 +237,7 @@ namespace ModernKeePassLib.Serialization
|
||||
FileSecurity sec = File.GetAccessControl(m_iocBase.Path, acs);
|
||||
if(sec != null) pbSec = sec.GetSecurityDescriptorBinaryForm();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch(Exception) { Debug.Assert(NativeLib.IsUnix()); }
|
||||
|
||||
// if((long)(faBase & FileAttributes.ReadOnly) != 0)
|
||||
@@ -337,6 +336,7 @@ namespace ModernKeePassLib.Serialization
|
||||
{
|
||||
if(NativeLib.IsUnix()) return;
|
||||
if(!m_iocBase.IsLocalFile()) return;
|
||||
if(IsOneDriveWorkaroundRequired()) return;
|
||||
|
||||
string strID = StrUtil.AlphaNumericOnly(Convert.ToBase64String(
|
||||
CryptoRandom.Instance.GetRandomBytes(16)));
|
||||
@@ -354,7 +354,7 @@ namespace ModernKeePassLib.Serialization
|
||||
#if ModernKeePassLib
|
||||
var tempFile = ApplicationData.Current.TemporaryFolder.CreateFileAsync(m_iocTemp.Path).GetAwaiter()
|
||||
.GetResult();
|
||||
m_iocTemp = IOConnectionInfo.FromFile(tempFile);
|
||||
m_iocTemp = IOConnectionInfo.FromStorageFile(tempFile);
|
||||
#else
|
||||
m_iocTemp = IOConnectionInfo.FromPath(strTemp);
|
||||
#endif
|
||||
@@ -370,13 +370,10 @@ namespace ModernKeePassLib.Serialization
|
||||
|
||||
if(TxfMoveWithTx()) return true;
|
||||
|
||||
// Move the temporary file onto the base file's drive first,
|
||||
// such that it cannot happen that both the base file and
|
||||
// the temporary file are deleted/corrupted
|
||||
#if ModernKeePassLib
|
||||
m_iocTemp.StorageFile = ApplicationData.Current.TemporaryFolder.CreateFileAsync(m_iocTemp.Path).GetAwaiter()
|
||||
.GetResult();
|
||||
#else
|
||||
// Move the temporary file onto the base file's drive first,
|
||||
// such that it cannot happen that both the base file and
|
||||
// the temporary file are deleted/corrupted
|
||||
#if !ModernKeePassLib
|
||||
const uint f = (NativeMethods.MOVEFILE_COPY_ALLOWED |
|
||||
NativeMethods.MOVEFILE_REPLACE_EXISTING);
|
||||
bool b = NativeMethods.MoveFileEx(m_iocTemp.Path, m_iocTxfMidFallback.Path, f);
|
||||
@@ -391,9 +388,7 @@ namespace ModernKeePassLib.Serialization
|
||||
|
||||
private bool TxfMoveWithTx()
|
||||
{
|
||||
#if ModernKeePassLib
|
||||
return true;
|
||||
#else
|
||||
#if !ModernKeePassLib
|
||||
IntPtr hTx = new IntPtr((int)NativeMethods.INVALID_HANDLE_VALUE);
|
||||
Debug.Assert(hTx.ToInt64() == NativeMethods.INVALID_HANDLE_VALUE);
|
||||
try
|
||||
@@ -438,9 +433,8 @@ namespace ModernKeePassLib.Serialization
|
||||
catch(Exception) { Debug.Assert(false); }
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static void ClearOld()
|
||||
@@ -470,5 +464,89 @@ namespace ModernKeePassLib.Serialization
|
||||
}
|
||||
catch(Exception) { Debug.Assert(false); }
|
||||
}
|
||||
|
||||
// https://sourceforge.net/p/keepass/discussion/329220/thread/672ffecc65/
|
||||
// https://sourceforge.net/p/keepass/discussion/329221/thread/514786c23a/
|
||||
private bool IsOneDriveWorkaroundRequired()
|
||||
{
|
||||
#if !ModernKeePassLib
|
||||
if(NativeLib.IsUnix()) return false;
|
||||
|
||||
try
|
||||
{
|
||||
string strReleaseId = (Registry.GetValue(
|
||||
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
|
||||
"ReleaseId", string.Empty) as string);
|
||||
if(strReleaseId != "1809") return false;
|
||||
|
||||
string strFile = m_iocBase.Path;
|
||||
|
||||
GFunc<string, string, bool> fMatch = delegate(string strRoot, string strSfx)
|
||||
{
|
||||
if(string.IsNullOrEmpty(strRoot)) return false;
|
||||
string strPfx = UrlUtil.EnsureTerminatingSeparator(
|
||||
strRoot, false) + strSfx;
|
||||
return strFile.StartsWith(strPfx, StrUtil.CaseIgnoreCmp);
|
||||
};
|
||||
GFunc<string, string, bool> fMatchEnv = delegate(string strEnv, string strSfx)
|
||||
{
|
||||
return fMatch(Environment.GetEnvironmentVariable(strEnv), strSfx);
|
||||
};
|
||||
|
||||
string strKnown = NativeMethods.GetKnownFolderPath(
|
||||
NativeMethods.FOLDERID_SkyDrive);
|
||||
if(fMatch(strKnown, string.Empty)) return true;
|
||||
|
||||
if(fMatchEnv("USERPROFILE", "OneDrive\\")) return true;
|
||||
if(fMatchEnv("OneDrive", string.Empty)) return true;
|
||||
if(fMatchEnv("OneDriveCommercial", string.Empty)) return true;
|
||||
if(fMatchEnv("OneDriveConsumer", string.Empty)) return true;
|
||||
|
||||
using(RegistryKey kAccs = Registry.CurrentUser.OpenSubKey(
|
||||
"Software\\Microsoft\\OneDrive\\Accounts", false))
|
||||
{
|
||||
string[] vAccs = (((kAccs != null) ? kAccs.GetSubKeyNames() :
|
||||
null) ?? new string[0]);
|
||||
|
||||
foreach(string strAcc in vAccs)
|
||||
{
|
||||
if(string.IsNullOrEmpty(strAcc)) { Debug.Assert(false); continue; }
|
||||
|
||||
using(RegistryKey kTenants = kAccs.OpenSubKey(
|
||||
strAcc + "\\Tenants", false))
|
||||
{
|
||||
string[] vTenants = (((kTenants != null) ?
|
||||
kTenants.GetSubKeyNames() : null) ?? new string[0]);
|
||||
|
||||
foreach(string strT in vTenants)
|
||||
{
|
||||
if(string.IsNullOrEmpty(strT)) { Debug.Assert(false); continue; }
|
||||
|
||||
using(RegistryKey kT = kTenants.OpenSubKey(strT, false))
|
||||
{
|
||||
string[] vPaths = (((kT != null) ?
|
||||
kT.GetValueNames() : null) ?? new string[0]);
|
||||
|
||||
foreach(string strPath in vPaths)
|
||||
{
|
||||
if((strPath == null) || (strPath.Length < 4) ||
|
||||
(strPath[1] != ':'))
|
||||
{
|
||||
Debug.Assert(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(fMatch(strPath, string.Empty)) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception) { Debug.Assert(false); }
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -24,7 +24,6 @@ using System.IO;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
#if (!ModernKeePassLib && !KeePassLibSD && !KeePassUAP)
|
||||
using System.Net.Cache;
|
||||
using System.Net.Security;
|
||||
@@ -600,7 +599,12 @@ namespace ModernKeePassLib.Serialization
|
||||
|
||||
private static Stream OpenReadLocal(IOConnectionInfo ioc)
|
||||
{
|
||||
#if ModernKeePassLib
|
||||
return ioc.StorageFile.OpenAsync(FileAccessMode.Read).GetAwaiter().GetResult().AsStream();
|
||||
#else
|
||||
return new FileStream(ioc.Path, FileMode.Open, FileAccess.Read,
|
||||
FileShare.Read);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT)
|
||||
@@ -654,7 +658,7 @@ namespace ModernKeePassLib.Serialization
|
||||
RaiseIOAccessPreEvent(ioc, IOAccessType.Exists);
|
||||
|
||||
#if ModernKeePassLib
|
||||
return ioc.StorageFile.IsAvailable;
|
||||
return ioc.StorageFile != null;
|
||||
#else
|
||||
if(ioc.IsLocalFile()) return File.Exists(ioc.Path);
|
||||
|
||||
@@ -696,7 +700,7 @@ namespace ModernKeePassLib.Serialization
|
||||
|
||||
#if ModernKeePassLib
|
||||
if (!ioc.IsLocalFile()) return;
|
||||
ioc.StorageFile?.DeleteAsync().GetAwaiter().GetResult();
|
||||
ioc.StorageFile?.DeleteAsync().GetAwaiter().GetResult();
|
||||
#else
|
||||
if(ioc.IsLocalFile()) { File.Delete(ioc.Path); return; }
|
||||
|
||||
@@ -718,7 +722,7 @@ namespace ModernKeePassLib.Serialization
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rename/move a file. For local file system and WebDAV, the
|
||||
@@ -735,7 +739,7 @@ namespace ModernKeePassLib.Serialization
|
||||
|
||||
#if ModernKeePassLib
|
||||
if (!iocFrom.IsLocalFile()) return;
|
||||
iocFrom.StorageFile?.RenameAsync(iocTo.Path).GetAwaiter().GetResult();
|
||||
iocFrom.StorageFile?.RenameAsync(iocTo.Path).GetAwaiter().GetResult();
|
||||
#else
|
||||
if(iocFrom.IsLocalFile()) { File.Move(iocFrom.Path, iocTo.Path); return; }
|
||||
|
||||
|
@@ -25,14 +25,12 @@ using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
#if ModernKeePassLib
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Storage;
|
||||
//using PCLStorage;
|
||||
#endif
|
||||
|
||||
using ModernKeePassLib.Interfaces;
|
||||
using ModernKeePassLib.Utility;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Storage.AccessCache;
|
||||
|
||||
namespace ModernKeePassLib.Serialization
|
||||
{
|
||||
@@ -70,6 +68,8 @@ namespace ModernKeePassLib.Serialization
|
||||
{
|
||||
// private IOFileFormatHint m_ioHint = IOFileFormatHint.None;
|
||||
|
||||
public StorageFile StorageFile { get; set; }
|
||||
|
||||
private string m_strUrl = string.Empty;
|
||||
public string Path
|
||||
{
|
||||
@@ -316,29 +316,17 @@ namespace ModernKeePassLib.Serialization
|
||||
}
|
||||
|
||||
#if ModernKeePassLib
|
||||
public static IOConnectionInfo FromFile(StorageFile file)
|
||||
public static IOConnectionInfo FromStorageFile(StorageFile file)
|
||||
{
|
||||
IOConnectionInfo ioc = new IOConnectionInfo();
|
||||
|
||||
ioc.StorageFile = file;
|
||||
ioc.Path = file.Path;
|
||||
ioc.CredSaveMode = IOCredSaveMode.NoSave;
|
||||
|
||||
return ioc;
|
||||
}
|
||||
|
||||
public static IOConnectionInfo FromPath(string strPath)
|
||||
{
|
||||
IOConnectionInfo ioc = new IOConnectionInfo();
|
||||
|
||||
ioc.Path = strPath;
|
||||
ioc.StorageFile = StorageApplicationPermissions.FutureAccessList.GetFileAsync(strPath).GetAwaiter().GetResult();
|
||||
ioc.StorageFile = file;
|
||||
ioc.CredSaveMode = IOCredSaveMode.NoSave;
|
||||
|
||||
return ioc;
|
||||
}
|
||||
#else
|
||||
public static IOConnectionInfo FromPath(string strPath)
|
||||
public static IOConnectionInfo FromPath(string strPath)
|
||||
{
|
||||
IOConnectionInfo ioc = new IOConnectionInfo();
|
||||
|
||||
@@ -348,10 +336,6 @@ namespace ModernKeePassLib.Serialization
|
||||
return ioc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
public StorageFile StorageFile { get; set; }
|
||||
|
||||
public bool CanProbablyAccess()
|
||||
{
|
||||
#if ModernKeePassLib
|
||||
|
@@ -30,13 +30,14 @@ using System.Drawing;
|
||||
|
||||
using ModernKeePassLib;
|
||||
using ModernKeePassLib.Collections;
|
||||
using ModernKeePassLib.Cryptography;
|
||||
using ModernKeePassLib.Cryptography.Cipher;
|
||||
using ModernKeePassLib.Interfaces;
|
||||
using ModernKeePassLib.Resources;
|
||||
using ModernKeePassLib.Security;
|
||||
using ModernKeePassLib.Utility;
|
||||
|
||||
using ModernKeePassLib.Cryptography;
|
||||
using ModernKeePassLib.Cryptography.Cipher;
|
||||
|
||||
namespace ModernKeePassLib.Serialization
|
||||
{
|
||||
/// <summary>
|
||||
@@ -97,36 +98,10 @@ namespace ModernKeePassLib.Serialization
|
||||
|
||||
private void ReadXmlStreamed(Stream sXml, Stream 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 ModernKeePassLib || KeePassUAP
|
||||
xrs.DtdProcessing = DtdProcessing.Prohibit;
|
||||
#else
|
||||
#if !KeePassLibSD
|
||||
// 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;
|
||||
#endif
|
||||
|
||||
return xrs;
|
||||
}
|
||||
|
||||
private static XmlReader CreateXmlReader(Stream readerStream)
|
||||
{
|
||||
XmlReaderSettings xrs = CreateStdXmlReaderSettings();
|
||||
return XmlReader.Create(readerStream, xrs);
|
||||
using(XmlReader xr = XmlUtilEx.CreateXmlReader(sXml))
|
||||
{
|
||||
ReadDocumentStreamed(xr, sParent);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadDocumentStreamed(XmlReader xr, Stream sParentStream)
|
||||
@@ -179,7 +154,7 @@ namespace ModernKeePassLib.Serialization
|
||||
}
|
||||
|
||||
++uTagCounter;
|
||||
if(((uTagCounter % 256) == 0) && bSupportsStatus)
|
||||
if(((uTagCounter & 0xFFU) == 0) && bSupportsStatus)
|
||||
{
|
||||
Debug.Assert(lStreamLength == sParentStream.Length);
|
||||
uint uPct = (uint)((sParentStream.Position * 100) /
|
||||
@@ -189,7 +164,8 @@ namespace ModernKeePassLib.Serialization
|
||||
// position/length values (M120413)
|
||||
if(uPct > 100) { Debug.Assert(false); uPct = 100; }
|
||||
|
||||
m_slLogger.SetProgress(uPct);
|
||||
if(!m_slLogger.SetProgress(uPct))
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1028,28 +1004,31 @@ namespace ModernKeePassLib.Serialization
|
||||
private void ReadUnknown(XmlReader xr)
|
||||
{
|
||||
Debug.Assert(false); // Unknown node!
|
||||
Debug.Assert(xr.NodeType == XmlNodeType.Element);
|
||||
|
||||
if(xr.IsEmptyElement) { m_bReadNextNode = true; return; }
|
||||
bool bRead = false;
|
||||
int cOpen = 0;
|
||||
|
||||
string strUnknownName = xr.Name;
|
||||
|
||||
XorredBuffer xb = ProcessNode(xr);
|
||||
if(xb != null) { xb.Dispose(); return; } // ProcessNode sets m_bReadNextNode
|
||||
|
||||
bool bRead = true;
|
||||
while(true)
|
||||
do
|
||||
{
|
||||
if(bRead) xr.Read();
|
||||
bRead = true;
|
||||
|
||||
if(xr.NodeType == XmlNodeType.EndElement) break;
|
||||
if(xr.NodeType != XmlNodeType.Element) { bRead = true; 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);
|
||||
bRead = m_bReadNextNode;
|
||||
++cOpen;
|
||||
}
|
||||
}
|
||||
}
|
||||
while(cOpen > 0);
|
||||
|
||||
Debug.Assert(xr.Name == strUnknownName); // On end tag
|
||||
m_bReadNextNode = true;
|
||||
m_bReadNextNode = bRead;
|
||||
}
|
||||
|
||||
private XorredBuffer ProcessNode(XmlReader xr)
|
||||
|
@@ -55,26 +55,23 @@ namespace ModernKeePassLib.Serialization
|
||||
/// </summary>
|
||||
public sealed partial class KdbxFile
|
||||
{
|
||||
/// <summary>
|
||||
/// Load a KDBX file.
|
||||
/// </summary>
|
||||
/// <param name="strFilePath">File to load.</param>
|
||||
/// <param name="fmt">Format.</param>
|
||||
/// <param name="slLogger">Status logger (optional).</param>
|
||||
#if ModernKeePassLib
|
||||
public void Load(StorageFile file, KdbxFormat fmt, IStatusLogger slLogger)
|
||||
{
|
||||
IOConnectionInfo ioc = IOConnectionInfo.FromFile(file);
|
||||
Load(IOConnection.OpenRead(ioc), fmt, slLogger);
|
||||
}
|
||||
|
||||
{
|
||||
IOConnectionInfo ioc = IOConnectionInfo.FromStorageFile(file);
|
||||
#else
|
||||
/// <summary>
|
||||
/// Load a KDBX file.
|
||||
/// </summary>
|
||||
/// <param name="strFilePath">File to load.</param>
|
||||
/// <param name="fmt">Format.</param>
|
||||
/// <param name="slLogger">Status logger (optional).</param>
|
||||
public void Load(string strFilePath, KdbxFormat fmt, IStatusLogger slLogger)
|
||||
public void Load(string strFilePath, KdbxFormat fmt, IStatusLogger slLogger)
|
||||
{
|
||||
IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFilePath);
|
||||
#endif
|
||||
Load(IOConnection.OpenRead(ioc), fmt, slLogger);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Load a KDBX file from a stream.
|
||||
@@ -202,19 +199,17 @@ namespace ModernKeePassLib.Serialization
|
||||
}
|
||||
|
||||
#if KeePassDebug_WriteXml
|
||||
// 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();
|
||||
#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);
|
||||
}
|
||||
} */
|
||||
#endif
|
||||
|
||||
ReadXmlStreamed(sXml, sHashing);
|
||||
@@ -413,7 +408,7 @@ namespace ModernKeePassLib.Serialization
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
if(m_slLogger != null)
|
||||
m_slLogger.SetText(KLRes.UnknownHeaderId + @": " +
|
||||
m_slLogger.SetText(KLRes.UnknownHeaderId + ": " +
|
||||
kdbID.ToString() + "!", LogStatusType.Warning);
|
||||
break;
|
||||
}
|
||||
|
@@ -429,7 +429,7 @@ namespace ModernKeePassLib.Serialization
|
||||
};
|
||||
|
||||
if(!pgRoot.TraverseTree(TraversalMethod.PreOrder, gh, eh))
|
||||
throw new InvalidOperationException();
|
||||
throw new OperationCanceledException();
|
||||
|
||||
while(groupStack.Count > 1)
|
||||
{
|
||||
|
@@ -378,8 +378,8 @@ namespace ModernKeePassLib.Serialization
|
||||
|
||||
Debug.Assert(m_pwDatabase != null);
|
||||
Debug.Assert(m_pwDatabase.MasterKey != null);
|
||||
ProtectedBinary pbinUser = m_pwDatabase.MasterKey.GenerateKey32(
|
||||
m_pwDatabase.KdfParameters);
|
||||
ProtectedBinary pbinUser = m_pwDatabase.MasterKey.GenerateKey32Ex(
|
||||
m_pwDatabase.KdfParameters, m_slLogger);
|
||||
Debug.Assert(pbinUser != null);
|
||||
if(pbinUser == null)
|
||||
throw new SecurityException(KLRes.InvalidCompositeKey);
|
||||
@@ -492,7 +492,7 @@ namespace ModernKeePassLib.Serialization
|
||||
{
|
||||
if(pb == null) { Debug.Assert(false); return; }
|
||||
|
||||
if(string.IsNullOrEmpty(strName)) strName = "File.bin";
|
||||
strName = UrlUtil.GetSafeFileName(strName);
|
||||
|
||||
string strPath;
|
||||
int iTry = 1;
|
||||
@@ -500,8 +500,8 @@ namespace ModernKeePassLib.Serialization
|
||||
{
|
||||
strPath = UrlUtil.EnsureTerminatingSeparator(strSaveDir, false);
|
||||
|
||||
string strExt = UrlUtil.GetExtension(strName);
|
||||
string strDesc = UrlUtil.StripExtension(strName);
|
||||
string strExt = UrlUtil.GetExtension(strName);
|
||||
|
||||
strPath += strDesc;
|
||||
if(iTry > 1)
|
||||
|
@@ -46,6 +46,7 @@ namespace ModernKeePassLib.Translation
|
||||
public sealed class KPTranslation
|
||||
{
|
||||
public static readonly string FileExtension = "lngx";
|
||||
internal const string FileExtension1x = "lng";
|
||||
|
||||
private KPTranslationProperties m_props = new KPTranslationProperties();
|
||||
public KPTranslationProperties Properties
|
||||
|
@@ -264,8 +264,7 @@ namespace ModernKeePassLib.Utility
|
||||
[MethodImpl(MioNoOptimize)]
|
||||
public static void ZeroByteArray(byte[] pbArray)
|
||||
{
|
||||
Debug.Assert(pbArray != null);
|
||||
if(pbArray == null) throw new ArgumentNullException("pbArray");
|
||||
if(pbArray == null) { Debug.Assert(false); return; }
|
||||
|
||||
Array.Clear(pbArray, 0, pbArray.Length);
|
||||
}
|
||||
@@ -277,7 +276,7 @@ namespace ModernKeePassLib.Utility
|
||||
[MethodImpl(MioNoOptimize)]
|
||||
public static void ZeroArray<T>(T[] v)
|
||||
{
|
||||
if(v == null) { Debug.Assert(false); throw new ArgumentNullException("v"); }
|
||||
if(v == null) { Debug.Assert(false); return; }
|
||||
|
||||
Array.Clear(v, 0, v.Length);
|
||||
}
|
||||
|
@@ -116,9 +116,6 @@ namespace ModernKeePassLib.Utility
|
||||
// 1760:
|
||||
// Input focus is not restored when activating a form.
|
||||
// https://sourceforge.net/p/keepass/bugs/1760/
|
||||
// 2139:
|
||||
// Shortcut keys are ignored.
|
||||
// https://sourceforge.net/p/keepass/feature-requests/2139/
|
||||
// 2140:
|
||||
// Explicit control focusing is ignored.
|
||||
// https://sourceforge.net/p/keepass/feature-requests/2140/
|
||||
|
@@ -24,7 +24,6 @@ using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
#if !KeePassUAP
|
||||
using System.Drawing;
|
||||
@@ -44,45 +43,41 @@ namespace ModernKeePassLib.Utility
|
||||
/// </summary>
|
||||
public sealed class CharStream
|
||||
{
|
||||
private string m_strString = string.Empty;
|
||||
private int m_nPos = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public CharStream(string str)
|
||||
{
|
||||
Debug.Assert(str != null);
|
||||
if(str == null) throw new ArgumentNullException("str");
|
||||
if(str == null) { Debug.Assert(false); throw new ArgumentNullException("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;
|
||||
m_str = str;
|
||||
}
|
||||
|
||||
public char ReadChar()
|
||||
{
|
||||
if(m_nPos < 0) return char.MinValue;
|
||||
if(m_nPos >= m_strString.Length) return char.MinValue;
|
||||
if(m_iPos >= m_str.Length) return char.MinValue;
|
||||
|
||||
char chRet = m_strString[m_nPos];
|
||||
++m_nPos;
|
||||
return chRet;
|
||||
return m_str[m_iPos++];
|
||||
}
|
||||
|
||||
public char ReadChar(bool bSkipWhiteSpace)
|
||||
{
|
||||
if(bSkipWhiteSpace == false) return ReadChar();
|
||||
if(!bSkipWhiteSpace) return ReadChar();
|
||||
|
||||
while(true)
|
||||
{
|
||||
char ch = ReadChar();
|
||||
|
||||
if((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n'))
|
||||
return ch;
|
||||
}
|
||||
@@ -90,29 +85,25 @@ namespace ModernKeePassLib.Utility
|
||||
|
||||
public char PeekChar()
|
||||
{
|
||||
if(m_nPos < 0) return char.MinValue;
|
||||
if(m_nPos >= m_strString.Length) return char.MinValue;
|
||||
if(m_iPos >= m_str.Length) return char.MinValue;
|
||||
|
||||
return m_strString[m_nPos];
|
||||
return m_str[m_iPos];
|
||||
}
|
||||
|
||||
public char PeekChar(bool bSkipWhiteSpace)
|
||||
{
|
||||
if(bSkipWhiteSpace == false) return PeekChar();
|
||||
if(!bSkipWhiteSpace) return PeekChar();
|
||||
|
||||
int iIndex = m_nPos;
|
||||
while(true)
|
||||
int i = m_iPos;
|
||||
while(i < m_str.Length)
|
||||
{
|
||||
if(iIndex < 0) return char.MinValue;
|
||||
if(iIndex >= m_strString.Length) return char.MinValue;
|
||||
|
||||
char ch = m_strString[iIndex];
|
||||
|
||||
char ch = m_str[i];
|
||||
if((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n'))
|
||||
return ch;
|
||||
|
||||
++iIndex;
|
||||
++i;
|
||||
}
|
||||
|
||||
return char.MinValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,44 +396,46 @@ namespace ModernKeePassLib.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)
|
||||
public static void SplitCommandLine(string strCmdLine, out string strApp,
|
||||
out string strArgs)
|
||||
{
|
||||
Debug.Assert(strCmdLine != null); if(strCmdLine == null) throw new ArgumentNullException("strCmdLine");
|
||||
SplitCommandLine(strCmdLine, out strApp, out strArgs, true);
|
||||
}
|
||||
|
||||
internal static void SplitCommandLine(string strCmdLine, out string strApp,
|
||||
out string strArgs, bool bDecodeAppToPath)
|
||||
{
|
||||
if(strCmdLine == null) { Debug.Assert(false); throw new ArgumentNullException("strCmdLine"); }
|
||||
|
||||
string str = strCmdLine.Trim();
|
||||
|
||||
strApp = null; strArgs = null;
|
||||
strApp = null;
|
||||
strArgs = null;
|
||||
|
||||
if(str.StartsWith("\""))
|
||||
{
|
||||
int nSecond = str.IndexOf('\"', 1);
|
||||
if(nSecond >= 1)
|
||||
int iSecond = UrlUtil.IndexOfSecondEnclQuote(str);
|
||||
if(iSecond >= 1)
|
||||
{
|
||||
strApp = str.Substring(1, nSecond - 1).Trim();
|
||||
strArgs = str.Remove(0, nSecond + 1).Trim();
|
||||
strApp = str.Substring(1, iSecond - 1).Trim();
|
||||
strArgs = str.Remove(0, iSecond + 1).Trim();
|
||||
}
|
||||
}
|
||||
|
||||
if(strApp == null)
|
||||
{
|
||||
int nSpace = str.IndexOf(' ');
|
||||
|
||||
if(nSpace >= 0)
|
||||
int iSpace = str.IndexOf(' ');
|
||||
if(iSpace >= 0)
|
||||
{
|
||||
strApp = str.Substring(0, nSpace);
|
||||
strArgs = str.Remove(0, nSpace).Trim();
|
||||
strApp = str.Substring(0, iSpace).Trim();
|
||||
strArgs = str.Remove(0, iSpace + 1).Trim();
|
||||
}
|
||||
else strApp = strCmdLine;
|
||||
else strApp = str;
|
||||
}
|
||||
|
||||
if(strApp == null) strApp = string.Empty;
|
||||
if(strApp == null) { Debug.Assert(false); strApp = string.Empty; }
|
||||
if(strArgs == null) strArgs = string.Empty;
|
||||
|
||||
if(bDecodeAppToPath) strApp = NativeLib.DecodeArgsToPath(strApp);
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
@@ -1289,7 +1282,7 @@ namespace ModernKeePassLib.Utility
|
||||
if(uBytes <= uGB) return (((uBytes - 1UL) / uMB) + 1UL).ToString() + " MB";
|
||||
if(uBytes <= uTB) return (((uBytes - 1UL) / uGB) + 1UL).ToString() + " GB";
|
||||
|
||||
return (((uBytes - 1UL)/ uTB) + 1UL).ToString() + " TB";
|
||||
return (((uBytes - 1UL) / uTB) + 1UL).ToString() + " TB";
|
||||
}
|
||||
|
||||
public static string FormatDataSizeKB(ulong uBytes)
|
||||
|
@@ -23,6 +23,7 @@ using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
#if ModernKeePassLib
|
||||
using Windows.Storage;
|
||||
@@ -38,12 +39,8 @@ namespace ModernKeePassLib.Utility
|
||||
/// </summary>
|
||||
public static class UrlUtil
|
||||
{
|
||||
private static readonly char[] m_vDirSeps = new char[] {
|
||||
'\\', '/', UrlUtil.LocalDirSepChar };
|
||||
#if !ModernKeePassLib
|
||||
private static readonly char[] m_vPathTrimCharsWs = new char[] {
|
||||
private static readonly char[] g_vPathTrimCharsWs = new char[] {
|
||||
'\"', ' ', '\t', '\r', '\n' };
|
||||
#endif
|
||||
|
||||
public static char LocalDirSepChar
|
||||
{
|
||||
@@ -57,6 +54,32 @@ namespace ModernKeePassLib.Utility
|
||||
#endif
|
||||
}
|
||||
|
||||
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:
|
||||
@@ -79,7 +102,7 @@ namespace ModernKeePassLib.Utility
|
||||
Debug.Assert(strFile != null);
|
||||
if(strFile == null) throw new ArgumentNullException("strFile");
|
||||
|
||||
int nLastSep = strFile.LastIndexOfAny(m_vDirSeps);
|
||||
int nLastSep = strFile.LastIndexOfAny(UrlUtil.DirSepChars);
|
||||
if(nLastSep < 0) return string.Empty; // No directory
|
||||
|
||||
if(bEnsureValidDirSpec && (nLastSep == 2) && (strFile[1] == ':') &&
|
||||
@@ -103,7 +126,7 @@ namespace ModernKeePassLib.Utility
|
||||
{
|
||||
Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath");
|
||||
|
||||
int nLastSep = strPath.LastIndexOfAny(m_vDirSeps);
|
||||
int nLastSep = strPath.LastIndexOfAny(UrlUtil.DirSepChars);
|
||||
|
||||
if(nLastSep < 0) return strPath;
|
||||
if(nLastSep >= (strPath.Length - 1)) return string.Empty;
|
||||
@@ -120,7 +143,7 @@ namespace ModernKeePassLib.Utility
|
||||
{
|
||||
Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath");
|
||||
|
||||
int nLastDirSep = strPath.LastIndexOfAny(m_vDirSeps);
|
||||
int nLastDirSep = strPath.LastIndexOfAny(UrlUtil.DirSepChars);
|
||||
int nLastExtDot = strPath.LastIndexOf('.');
|
||||
|
||||
if(nLastExtDot <= nLastDirSep) return strPath;
|
||||
@@ -137,7 +160,7 @@ namespace ModernKeePassLib.Utility
|
||||
{
|
||||
Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath");
|
||||
|
||||
int nLastDirSep = strPath.LastIndexOfAny(m_vDirSeps);
|
||||
int nLastDirSep = strPath.LastIndexOfAny(UrlUtil.DirSepChars);
|
||||
int nLastExtDot = strPath.LastIndexOf('.');
|
||||
|
||||
if(nLastExtDot <= nLastDirSep) return string.Empty;
|
||||
@@ -162,11 +185,8 @@ namespace ModernKeePassLib.Utility
|
||||
if(nLength <= 0) return string.Empty;
|
||||
|
||||
char chLast = strPath[nLength - 1];
|
||||
|
||||
for(int i = 0; i < m_vDirSeps.Length; ++i)
|
||||
{
|
||||
if(chLast == m_vDirSeps[i]) return strPath;
|
||||
}
|
||||
if(Array.IndexOf<char>(UrlUtil.DirSepChars, chLast) >= 0)
|
||||
return strPath;
|
||||
|
||||
if(bUrl) return (strPath + '/');
|
||||
return (strPath + UrlUtil.LocalDirSepChar);
|
||||
@@ -230,21 +250,35 @@ namespace ModernKeePassLib.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 = str.IndexOf('\"', 1);
|
||||
int iSecond = IndexOfSecondEnclQuote(str);
|
||||
if(iSecond <= 0) return str;
|
||||
|
||||
return str.Substring(1, iSecond - 1);
|
||||
@@ -256,7 +290,7 @@ namespace ModernKeePassLib.Utility
|
||||
if(strUrl == null) throw new ArgumentNullException("strUrl");
|
||||
|
||||
string str = strUrl;
|
||||
if(str.StartsWith(@"file:///", StrUtil.CaseIgnoreCmp))
|
||||
if(str.StartsWith("file:///", StrUtil.CaseIgnoreCmp))
|
||||
str = str.Substring(8, str.Length - 8);
|
||||
|
||||
str = str.Replace('/', UrlUtil.LocalDirSepChar);
|
||||
@@ -338,8 +372,8 @@ namespace ModernKeePassLib.Utility
|
||||
|
||||
string strBase = GetShortestAbsolutePath(strBaseFile);
|
||||
string strTarget = GetShortestAbsolutePath(strTargetFile);
|
||||
string[] vBase = strBase.Split(m_vDirSeps);
|
||||
string[] vTarget = strTarget.Split(m_vDirSeps);
|
||||
string[] vBase = strBase.Split(UrlUtil.DirSepChars);
|
||||
string[] vTarget = strTarget.Split(UrlUtil.DirSepChars);
|
||||
|
||||
int i = 0;
|
||||
while((i < (vBase.Length - 1)) && (i < (vTarget.Length - 1)) &&
|
||||
@@ -416,13 +450,14 @@ namespace ModernKeePassLib.Utility
|
||||
if(IsUncPath(strPath))
|
||||
{
|
||||
char chSep = strPath[0];
|
||||
Debug.Assert(Array.IndexOf<char>(m_vDirSeps, chSep) >= 0);
|
||||
char[] vSep = ((chSep == '/') ? (new char[] { '/' }) :
|
||||
(new char[] { '\\', '/' }));
|
||||
|
||||
List<string> l = new List<string>();
|
||||
#if !KeePassLibSD
|
||||
string[] v = strPath.Split(m_vDirSeps, StringSplitOptions.None);
|
||||
string[] v = strPath.Split(vSep, StringSplitOptions.None);
|
||||
#else
|
||||
string[] v = strPath.Split(m_vDirSeps);
|
||||
string[] v = strPath.Split(vSep);
|
||||
#endif
|
||||
Debug.Assert((v.Length >= 3) && (v[0].Length == 0) &&
|
||||
(v[1].Length == 0));
|
||||
@@ -463,8 +498,8 @@ namespace ModernKeePassLib.Utility
|
||||
}
|
||||
catch(Exception) { Debug.Assert(false); return strPath; }
|
||||
|
||||
Debug.Assert(str.IndexOf("\\..\\") < 0);
|
||||
foreach(char ch in m_vDirSeps)
|
||||
Debug.Assert((str.IndexOf("\\..\\") < 0) || NativeLib.IsUnix());
|
||||
foreach(char ch in UrlUtil.DirSepChars)
|
||||
{
|
||||
string strSep = new string(ch, 1);
|
||||
str = str.Replace(strSep + "." + strSep, strSep);
|
||||
@@ -494,24 +529,30 @@ namespace ModernKeePassLib.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 nNetScheme = strUrl.IndexOf(@"://", StrUtil.CaseIgnoreCmp);
|
||||
int nShScheme = strUrl.IndexOf(@":/", StrUtil.CaseIgnoreCmp);
|
||||
int nSmpScheme = strUrl.IndexOf(@":", StrUtil.CaseIgnoreCmp);
|
||||
int i = strUrl.IndexOf(':');
|
||||
if(i < 0) return strUrl; // No scheme to remove
|
||||
++i;
|
||||
|
||||
if((nNetScheme < 0) && (nShScheme < 0) && (nSmpScheme < 0))
|
||||
return strUrl; // No scheme
|
||||
// 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
|
||||
|
||||
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);
|
||||
return strUrl.Substring(i);
|
||||
}
|
||||
|
||||
public static string ConvertSeparators(string strPath)
|
||||
@@ -538,22 +579,50 @@ namespace ModernKeePassLib.Utility
|
||||
|
||||
public static string FilterFileName(string strName)
|
||||
{
|
||||
if(strName == null) { Debug.Assert(false); return string.Empty; }
|
||||
if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return string.Empty; }
|
||||
|
||||
string str = strName;
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
|
||||
|
||||
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('|', '-');
|
||||
StringBuilder sb = new StringBuilder(strName.Length);
|
||||
foreach(char ch in strName)
|
||||
{
|
||||
if(ch < '\u0020') continue;
|
||||
|
||||
return str;
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -672,7 +741,7 @@ namespace ModernKeePassLib.Utility
|
||||
foreach(string strPathRaw in v)
|
||||
{
|
||||
if(strPathRaw == null) { Debug.Assert(false); continue; }
|
||||
string strPath = strPathRaw.Trim(m_vPathTrimCharsWs);
|
||||
string strPath = strPathRaw.Trim(g_vPathTrimCharsWs);
|
||||
if(strPath.Length == 0) { Debug.Assert(false); continue; }
|
||||
Debug.Assert(strPath == strPathRaw);
|
||||
|
||||
@@ -709,7 +778,7 @@ namespace ModernKeePassLib.Utility
|
||||
if(fi == null) { Debug.Assert(false); continue; }
|
||||
string strPathRaw = fi.FullName;
|
||||
if(strPathRaw == null) { Debug.Assert(false); continue; }
|
||||
string strPath = strPathRaw.Trim(m_vPathTrimCharsWs);
|
||||
string strPath = strPathRaw.Trim(g_vPathTrimCharsWs);
|
||||
if(strPath.Length == 0) { Debug.Assert(false); continue; }
|
||||
Debug.Assert(strPath == strPathRaw);
|
||||
|
||||
@@ -783,5 +852,19 @@ namespace ModernKeePassLib.Utility
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -50,7 +50,7 @@ namespace ModernKeePassLib.Utility
|
||||
xrs.IgnoreProcessingInstructions = true;
|
||||
xrs.IgnoreWhitespace = true;
|
||||
|
||||
#if KeePassUAP
|
||||
#if KeePassUAP || ModernKeePassLib
|
||||
xrs.DtdProcessing = DtdProcessing.Prohibit;
|
||||
#else
|
||||
// Also see PrepMonoDev.sh script
|
||||
|