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;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using ModernKeePassLib.Keys;
|
using ModernKeePassLib.Keys;
|
||||||
using ModernKeePassLib.Utility;
|
using ModernKeePassLib.Utility;
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
@@ -24,7 +25,7 @@ namespace ModernKeePassLib.Test.Keys
|
|||||||
private const string ExpectedFileEnd = "</Data>\r\n\t</Key>\r\n</KeyFile>";
|
private const string ExpectedFileEnd = "</Data>\r\n\t</Key>\r\n</KeyFile>";
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestConstruct()
|
public async Task TestConstruct()
|
||||||
{
|
{
|
||||||
var expectedKeyData = new byte[]
|
var expectedKeyData = new byte[]
|
||||||
{
|
{
|
||||||
@@ -34,17 +35,15 @@ namespace ModernKeePassLib.Test.Keys
|
|||||||
0x45, 0xfc, 0xc8, 0x92, 0xbd, 0xeb, 0xaf, 0xc3
|
0x45, 0xfc, 0xc8, 0x92, 0xbd, 0xeb, 0xaf, 0xc3
|
||||||
};
|
};
|
||||||
|
|
||||||
var folder = StorageFolder.GetFolderFromPathAsync(Path.GetTempPath()).GetAwaiter().GetResult();
|
var folder = await StorageFolder.GetFolderFromPathAsync(Path.GetTempPath());
|
||||||
var file = folder.CreateFileAsync(TestCreateFile, CreationCollisionOption.ReplaceExisting).GetAwaiter().GetResult();
|
var file = await folder.CreateFileAsync(TestCreateFile, CreationCollisionOption.ReplaceExisting);
|
||||||
using (var fs = file.OpenStreamForWriteAsync().GetAwaiter().GetResult())
|
await using (var fs = await file.OpenStreamForWriteAsync())
|
||||||
{
|
|
||||||
using (var sw = new StreamWriter(fs))
|
|
||||||
{
|
{
|
||||||
|
await using var sw = new StreamWriter(fs);
|
||||||
sw.Write(ExpectedFileStart);
|
sw.Write(ExpectedFileStart);
|
||||||
sw.Write(TestKey);
|
sw.Write(TestKey);
|
||||||
sw.Write(ExpectedFileEnd);
|
sw.Write(ExpectedFileEnd);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -54,19 +53,19 @@ namespace ModernKeePassLib.Test.Keys
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
file.DeleteAsync().GetAwaiter().GetResult();
|
await file.DeleteAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestCreate()
|
public async Task TestCreate()
|
||||||
{
|
{
|
||||||
var folder = StorageFolder.GetFolderFromPathAsync(Path.GetTempPath()).GetAwaiter().GetResult();
|
var folder = await StorageFolder.GetFolderFromPathAsync(Path.GetTempPath());
|
||||||
var file = folder.CreateFileAsync(TestCreateFile, CreationCollisionOption.ReplaceExisting).GetAwaiter().GetResult();
|
var file = await folder.CreateFileAsync(TestCreateFile, CreationCollisionOption.ReplaceExisting);
|
||||||
KcpKeyFile.Create(file, null);
|
KcpKeyFile.Create(file, null);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var fileContents = FileIO.ReadTextAsync(file).GetAwaiter().GetResult();
|
var fileContents = await FileIO.ReadTextAsync(file);
|
||||||
|
|
||||||
Assert.Equal(185, fileContents.Length);
|
Assert.Equal(185, fileContents.Length);
|
||||||
Assert.StartsWith(ExpectedFileStart, fileContents);
|
Assert.StartsWith(ExpectedFileStart, fileContents);
|
||||||
@@ -74,7 +73,7 @@ namespace ModernKeePassLib.Test.Keys
|
|||||||
}
|
}
|
||||||
finally
|
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
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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|Any CPU = Release|Any CPU
|
||||||
|
Release|ARM = Release|ARM
|
||||||
|
Release|ARM64 = Release|ARM64
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{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|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.ActiveCfg = Release|Any CPU
|
||||||
{15A7E2E5-2B46-4975-AFBD-2898E47E5BA1}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
|
||||||
{4797E768-279A-493A-B21B-CD96AB1F8C20}.Release|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@@ -225,6 +225,25 @@ namespace ModernKeePassLib.Cryptography
|
|||||||
return MemUtil.BytesToUInt64(pb);
|
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
|
#if CRSBENCHMARK
|
||||||
public static string Benchmark()
|
public static string Benchmark()
|
||||||
{
|
{
|
||||||
|
@@ -47,6 +47,8 @@ namespace ModernKeePassLib.Cryptography
|
|||||||
// RijndaelManagedTransform when a stream hasn't been
|
// RijndaelManagedTransform when a stream hasn't been
|
||||||
// read completely (e.g. incorrect master key)
|
// read completely (e.g. incorrect master key)
|
||||||
catch(CryptographicException) { }
|
catch(CryptographicException) { }
|
||||||
|
// Similar to above, at the beginning of the stream
|
||||||
|
catch(IndexOutOfRangeException) { }
|
||||||
catch(Exception) { Debug.Assert(false); }
|
catch(Exception) { Debug.Assert(false); }
|
||||||
|
|
||||||
if(disposing)
|
if(disposing)
|
||||||
|
@@ -42,13 +42,13 @@ namespace ModernKeePassLib.Cryptography.KeyDerivation
|
|||||||
private const uint MaxVersion = 0x13;
|
private const uint MaxVersion = 0x13;
|
||||||
|
|
||||||
private const int MinSalt = 8;
|
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 MinIterations = 1;
|
||||||
internal const ulong MaxIterations = uint.MaxValue;
|
internal const ulong MaxIterations = uint.MaxValue;
|
||||||
|
|
||||||
internal const ulong MinMemory = 1024 * 8; // For parallelism = 1
|
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 ulong MaxMemory = int.MaxValue; // .NET limit
|
||||||
|
|
||||||
internal const uint MinParallelism = 1;
|
internal const uint MinParallelism = 1;
|
||||||
|
@@ -36,20 +36,20 @@ namespace ModernKeePassLib.Cryptography.PasswordGenerator
|
|||||||
if(pwProfile.Length == 0) return PwgError.Success;
|
if(pwProfile.Length == 0) return PwgError.Success;
|
||||||
|
|
||||||
PwCharSet pcs = new PwCharSet(pwProfile.CharSet.ToString());
|
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];
|
char[] v = new char[pwProfile.Length];
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
for(int i = 0; i < v.Length; ++i)
|
for(int i = 0; i < v.Length; ++i)
|
||||||
{
|
{
|
||||||
char ch = PwGenerator.GenerateCharacter(pwProfile,
|
char ch = PwGenerator.GenerateCharacter(pcs, crsRandomSource);
|
||||||
pcs, crsRandomSource);
|
|
||||||
|
|
||||||
if(ch == char.MinValue)
|
if(ch == char.MinValue)
|
||||||
return PwgError.TooFewCharacters;
|
return PwgError.TooFewCharacters;
|
||||||
|
|
||||||
v[i] = ch;
|
v[i] = ch;
|
||||||
|
if(pwProfile.NoRepeatingCharacters) pcs.Remove(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] pbUtf8 = StrUtil.Utf8.GetBytes(v);
|
byte[] pbUtf8 = StrUtil.Utf8.GetBytes(v);
|
||||||
|
@@ -34,92 +34,61 @@ namespace ModernKeePassLib.Cryptography.PasswordGenerator
|
|||||||
{
|
{
|
||||||
psOut = ProtectedString.Empty;
|
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>();
|
LinkedList<char> llGenerated = new LinkedList<char>();
|
||||||
PwCharSet pcsCurrent = new PwCharSet();
|
PwCharSet pcs = new PwCharSet();
|
||||||
PwCharSet pcsCustom = new PwCharSet();
|
|
||||||
PwCharSet pcsUsed = new PwCharSet();
|
|
||||||
bool bInCharSetDef = false;
|
|
||||||
|
|
||||||
string strPattern = ExpandPattern(pwProfile.Pattern);
|
while(true)
|
||||||
if(strPattern.Length == 0) return PwgError.Success;
|
|
||||||
|
|
||||||
CharStream csStream = new CharStream(strPattern);
|
|
||||||
char ch = csStream.ReadChar();
|
|
||||||
|
|
||||||
while(ch != char.MinValue)
|
|
||||||
{
|
{
|
||||||
pcsCurrent.Clear();
|
char ch = cs.ReadChar();
|
||||||
|
if(ch == char.MinValue) break;
|
||||||
|
|
||||||
bool bGenerateChar = false;
|
pcs.Clear();
|
||||||
|
|
||||||
if(ch == '\\')
|
if(ch == '\\')
|
||||||
{
|
{
|
||||||
ch = csStream.ReadChar();
|
ch = cs.ReadChar();
|
||||||
if(ch == char.MinValue) // Backslash at the end
|
if(ch == char.MinValue) return PwgError.InvalidPattern;
|
||||||
{
|
|
||||||
llGenerated.AddLast('\\');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(bInCharSetDef) pcsCustom.Add(ch);
|
pcs.Add(ch); // Allow "{...}" support and char check
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
else if(ch == '[')
|
else if(ch == '[')
|
||||||
{
|
{
|
||||||
pcsCustom.Clear();
|
if(!ReadCustomCharSet(cs, pcs))
|
||||||
bInCharSetDef = true;
|
return PwgError.InvalidPattern;
|
||||||
}
|
}
|
||||||
else if(ch == ']')
|
else
|
||||||
{
|
{
|
||||||
pcsCurrent.Add(pcsCustom.ToString());
|
if(!pcs.AddCharSet(ch))
|
||||||
|
return PwgError.InvalidPattern;
|
||||||
|
}
|
||||||
|
|
||||||
bInCharSetDef = false;
|
int nCount = 1;
|
||||||
bGenerateChar = true;
|
if(cs.PeekChar() == '{')
|
||||||
}
|
|
||||||
else if(bInCharSetDef)
|
|
||||||
{
|
{
|
||||||
if(pcsCustom.AddCharSet(ch) == false)
|
nCount = ReadCount(cs);
|
||||||
pcsCustom.Add(ch);
|
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)
|
if(pwProfile.NoRepeatingCharacters)
|
||||||
pcsCurrent.Remove(pcsUsed.ToString());
|
{
|
||||||
|
foreach(char chUsed in llGenerated)
|
||||||
char chGen = PwGenerator.GenerateCharacter(pwProfile,
|
pcs.Remove(chUsed);
|
||||||
pcsCurrent, crsRandomSource);
|
}
|
||||||
|
|
||||||
|
char chGen = PwGenerator.GenerateCharacter(pcs,
|
||||||
|
crsRandomSource);
|
||||||
if(chGen == char.MinValue) return PwgError.TooFewCharacters;
|
if(chGen == char.MinValue) return PwgError.TooFewCharacters;
|
||||||
|
|
||||||
llGenerated.AddLast(chGen);
|
llGenerated.AddLast(chGen);
|
||||||
pcsUsed.Add(chGen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ch = csStream.ReadChar();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(llGenerated.Count == 0) return PwgError.Success;
|
if(llGenerated.Count == 0) return PwgError.Success;
|
||||||
@@ -135,53 +104,70 @@ namespace ModernKeePassLib.Cryptography.PasswordGenerator
|
|||||||
MemUtil.ZeroByteArray(pbUtf8);
|
MemUtil.ZeroByteArray(pbUtf8);
|
||||||
|
|
||||||
MemUtil.ZeroArray<char>(v);
|
MemUtil.ZeroArray<char>(v);
|
||||||
llGenerated.Clear();
|
|
||||||
|
|
||||||
return PwgError.Success;
|
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; }
|
Debug.Assert(cs.PeekChar() != '['); // Consumed already
|
||||||
|
Debug.Assert(pcsOut.Size == 0);
|
||||||
string str = strPattern;
|
|
||||||
|
|
||||||
|
bool bAdd = true;
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
int nOpen = FindFirstUnescapedChar(str, '{');
|
char ch = cs.ReadChar();
|
||||||
int nClose = FindFirstUnescapedChar(str, '}');
|
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);
|
ch = cs.ReadChar();
|
||||||
str = str.Remove(nOpen, nClose - nOpen + 1);
|
if(ch == char.MinValue) return false;
|
||||||
|
|
||||||
uint uRepeat;
|
if(bAdd) pcsOut.Add(ch);
|
||||||
if(StrUtil.TryParseUInt(strCount, out uRepeat) && (nOpen >= 1))
|
else pcsOut.Remove(ch);
|
||||||
|
}
|
||||||
|
else if(ch == '^')
|
||||||
{
|
{
|
||||||
if(uRepeat == 0)
|
if(bAdd) bAdd = false;
|
||||||
str = str.Remove(nOpen - 1, 1);
|
else return false; // '^' toggles the mode only once
|
||||||
|
}
|
||||||
else
|
else
|
||||||
str = str.Insert(nOpen, new string(str[nOpen - 1], (int)uRepeat - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int FindFirstUnescapedChar(string str, char ch)
|
|
||||||
{
|
{
|
||||||
for(int i = 0; i < str.Length; ++i)
|
PwCharSet pcs = new PwCharSet();
|
||||||
|
if(!pcs.AddCharSet(ch)) return false;
|
||||||
|
|
||||||
|
if(bAdd) pcsOut.Add(pcs.ToString());
|
||||||
|
else pcsOut.Remove(pcs.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int ReadCount(CharStream cs)
|
||||||
{
|
{
|
||||||
char chCur = str[i];
|
if(cs.ReadChar() != '{') { Debug.Assert(false); return -1; }
|
||||||
|
|
||||||
if(chCur == '\\') ++i; // Next is escaped, skip it
|
// Ensure not empty
|
||||||
else if(chCur == ch) return i;
|
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 UpperHex = "0123456789ABCDEF";
|
||||||
public static readonly string LowerHex = "0123456789abcdef";
|
public static readonly string LowerHex = "0123456789abcdef";
|
||||||
|
|
||||||
public static readonly string Invalid = "\t\r\n";
|
|
||||||
public static readonly string LookAlike = @"O0l1I|";
|
public static readonly string LookAlike = @"O0l1I|";
|
||||||
|
|
||||||
internal static readonly string MenuAccels = PwCharSet.LowerCase + PwCharSet.Digits;
|
internal static readonly string MenuAccels = PwCharSet.LowerCase + PwCharSet.Digits;
|
||||||
|
@@ -36,7 +36,9 @@ namespace ModernKeePassLib.Cryptography.PasswordGenerator
|
|||||||
Success = 0,
|
Success = 0,
|
||||||
Unknown = 1,
|
Unknown = 1,
|
||||||
TooFewCharacters = 2,
|
TooFewCharacters = 2,
|
||||||
UnknownAlgorithm = 3
|
UnknownAlgorithm = 3,
|
||||||
|
InvalidCharSet = 4,
|
||||||
|
InvalidPattern = 5
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -94,30 +96,33 @@ namespace ModernKeePassLib.Cryptography.PasswordGenerator
|
|||||||
return new CryptoRandomStream(CrsAlgorithm.ChaCha20, pbKey);
|
return new CryptoRandomStream(CrsAlgorithm.ChaCha20, pbKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static char GenerateCharacter(PwProfile pwProfile,
|
internal static char GenerateCharacter(PwCharSet pwCharSet,
|
||||||
PwCharSet pwCharSet, CryptoRandomStream crsRandomSource)
|
CryptoRandomStream crsRandomSource)
|
||||||
{
|
{
|
||||||
if(pwCharSet.Size == 0) return char.MinValue;
|
uint cc = pwCharSet.Size;
|
||||||
|
if(cc == 0) return char.MinValue;
|
||||||
|
|
||||||
ulong uIndex = crsRandomSource.GetRandomUInt64();
|
uint i = (uint)crsRandomSource.GetRandomUInt64(cc);
|
||||||
uIndex %= (ulong)pwCharSet.Size;
|
return pwCharSet[i];
|
||||||
|
|
||||||
char ch = pwCharSet[(uint)uIndex];
|
|
||||||
|
|
||||||
if(pwProfile.NoRepeatingCharacters)
|
|
||||||
pwCharSet.Remove(ch);
|
|
||||||
|
|
||||||
return ch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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.ExcludeLookAlike) pwCharSet.Remove(PwCharSet.LookAlike);
|
||||||
|
|
||||||
if(pwProfile.ExcludeCharacters.Length > 0)
|
if(!string.IsNullOrEmpty(pwProfile.ExcludeCharacters))
|
||||||
pwCharSet.Remove(pwProfile.ExcludeCharacters);
|
pwCharSet.Remove(pwProfile.ExcludeCharacters);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void Shuffle(char[] v, CryptoRandomStream crsRandomSource)
|
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)
|
for(int i = v.Length - 1; i >= 1; --i)
|
||||||
{
|
{
|
||||||
ulong r = crsRandomSource.GetRandomUInt64();
|
int j = (int)crsRandomSource.GetRandomUInt64((ulong)(i + 1));
|
||||||
int j = (int)(r % (ulong)(i + 1));
|
|
||||||
|
|
||||||
char t = v[i];
|
char t = v[i];
|
||||||
v[i] = v[j];
|
v[i] = v[j];
|
||||||
|
@@ -87,7 +87,7 @@ namespace ModernKeePassLib.Interfaces
|
|||||||
bool SetText(string strNewText, LogStatusType lsType);
|
bool SetText(string strNewText, LogStatusType lsType);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if the user cancelled the current work.
|
/// Check whether the user cancelled the current work.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Returns <c>true</c> if the caller should continue
|
/// <returns>Returns <c>true</c> if the caller should continue
|
||||||
/// the current work.</returns>
|
/// the current work.</returns>
|
||||||
|
@@ -66,7 +66,7 @@ namespace ModernKeePassLib.Interfaces
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Flag that determines if the object does expire.
|
/// Flag that determines whether the object expires.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool Expires
|
bool Expires
|
||||||
{
|
{
|
||||||
|
@@ -21,9 +21,12 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
using ModernKeePassLib.Cryptography;
|
using ModernKeePassLib.Cryptography;
|
||||||
using ModernKeePassLib.Cryptography.KeyDerivation;
|
using ModernKeePassLib.Cryptography.KeyDerivation;
|
||||||
|
using ModernKeePassLib.Interfaces;
|
||||||
|
using ModernKeePassLib.Native;
|
||||||
using ModernKeePassLib.Resources;
|
using ModernKeePassLib.Resources;
|
||||||
using ModernKeePassLib.Security;
|
using ModernKeePassLib.Security;
|
||||||
using ModernKeePassLib.Utility;
|
using ModernKeePassLib.Utility;
|
||||||
@@ -166,7 +169,6 @@ namespace ModernKeePassLib.Keys
|
|||||||
{
|
{
|
||||||
ValidateUserKeys();
|
ValidateUserKeys();
|
||||||
|
|
||||||
// Concatenate user key data
|
|
||||||
List<byte[]> lData = new List<byte[]>();
|
List<byte[]> lData = new List<byte[]>();
|
||||||
int cbData = 0;
|
int cbData = 0;
|
||||||
foreach(IUserKey pKey in m_vUserKeys)
|
foreach(IUserKey pKey in m_vUserKeys)
|
||||||
@@ -199,13 +201,17 @@ namespace ModernKeePassLib.Keys
|
|||||||
{
|
{
|
||||||
if(ckOther == null) throw new ArgumentNullException("ckOther");
|
if(ckOther == null) throw new ArgumentNullException("ckOther");
|
||||||
|
|
||||||
|
bool bEqual;
|
||||||
byte[] pbThis = CreateRawCompositeKey32();
|
byte[] pbThis = CreateRawCompositeKey32();
|
||||||
|
try
|
||||||
|
{
|
||||||
byte[] pbOther = ckOther.CreateRawCompositeKey32();
|
byte[] pbOther = ckOther.CreateRawCompositeKey32();
|
||||||
bool bResult = MemUtil.ArraysEqual(pbThis, pbOther);
|
bEqual = MemUtil.ArraysEqual(pbThis, pbOther);
|
||||||
MemUtil.ZeroByteArray(pbOther);
|
MemUtil.ZeroByteArray(pbOther);
|
||||||
MemUtil.ZeroByteArray(pbThis);
|
}
|
||||||
|
finally { MemUtil.ZeroByteArray(pbThis); }
|
||||||
|
|
||||||
return bResult;
|
return bEqual;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
@@ -231,7 +237,12 @@ namespace ModernKeePassLib.Keys
|
|||||||
{
|
{
|
||||||
if(p == null) { Debug.Assert(false); throw new ArgumentNullException("p"); }
|
if(p == null) { Debug.Assert(false); throw new ArgumentNullException("p"); }
|
||||||
|
|
||||||
byte[] pbRaw32 = CreateRawCompositeKey32();
|
byte[] pbRaw32 = null, pbTrf32 = null;
|
||||||
|
ProtectedBinary pbRet = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pbRaw32 = CreateRawCompositeKey32();
|
||||||
if((pbRaw32 == null) || (pbRaw32.Length != 32))
|
if((pbRaw32 == null) || (pbRaw32.Length != 32))
|
||||||
{ Debug.Assert(false); return null; }
|
{ Debug.Assert(false); return null; }
|
||||||
|
|
||||||
@@ -241,21 +252,75 @@ namespace ModernKeePassLib.Keys
|
|||||||
KLRes.FileNewVerOrPlgReq + MessageService.NewParagraph +
|
KLRes.FileNewVerOrPlgReq + MessageService.NewParagraph +
|
||||||
"UUID: " + p.KdfUuid.ToHexString() + ".");
|
"UUID: " + p.KdfUuid.ToHexString() + ".");
|
||||||
|
|
||||||
byte[] pbTrf32 = kdf.Transform(pbRaw32, p);
|
pbTrf32 = kdf.Transform(pbRaw32, p);
|
||||||
if(pbTrf32 == null) { Debug.Assert(false); return null; }
|
if(pbTrf32 == null) { Debug.Assert(false); return null; }
|
||||||
|
|
||||||
if(pbTrf32.Length != 32)
|
if(pbTrf32.Length != 32)
|
||||||
{
|
{
|
||||||
Debug.Assert(false);
|
Debug.Assert(false);
|
||||||
pbTrf32 = CryptoUtil.HashSha256(pbTrf32);
|
pbTrf32 = CryptoUtil.HashSha256(pbTrf32);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtectedBinary pbRet = new ProtectedBinary(true, pbTrf32);
|
pbRet = new ProtectedBinary(true, pbTrf32);
|
||||||
MemUtil.ZeroByteArray(pbTrf32);
|
}
|
||||||
MemUtil.ZeroByteArray(pbRaw32);
|
finally
|
||||||
|
{
|
||||||
|
if(pbRaw32 != null) MemUtil.ZeroByteArray(pbRaw32);
|
||||||
|
if(pbTrf32 != null) MemUtil.ZeroByteArray(pbTrf32);
|
||||||
|
}
|
||||||
|
|
||||||
return pbRet;
|
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()
|
private void ValidateUserKeys()
|
||||||
{
|
{
|
||||||
int nAccounts = 0;
|
int nAccounts = 0;
|
||||||
@@ -280,14 +345,11 @@ namespace ModernKeePassLib.Keys
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return KLRes.InvalidCompositeKey + MessageService.NewParagraph +
|
return (KLRes.InvalidCompositeKey + MessageService.NewParagraph +
|
||||||
KLRes.InvalidCompositeKeyHint;
|
KLRes.InvalidCompositeKeyHint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Construct a new invalid composite key exception.
|
|
||||||
/// </summary>
|
|
||||||
public InvalidCompositeKeyException()
|
public InvalidCompositeKeyException()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@@ -67,11 +67,10 @@ namespace ModernKeePassLib.Keys
|
|||||||
{
|
{
|
||||||
get { return m_pbKeyData; }
|
get { return m_pbKeyData; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ModernKeePassLib
|
#if ModernKeePassLib
|
||||||
public KcpKeyFile(StorageFile strKeyFile)
|
public KcpKeyFile(StorageFile keyFile)
|
||||||
{
|
{
|
||||||
Construct(IOConnectionInfo.FromFile(strKeyFile), false);
|
Construct(IOConnectionInfo.FromStorageFile(keyFile), false);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
public KcpKeyFile(string strKeyFile)
|
public KcpKeyFile(string strKeyFile)
|
||||||
@@ -193,7 +192,7 @@ namespace ModernKeePassLib.Keys
|
|||||||
/// random number generator is used).</param>
|
/// random number generator is used).</param>
|
||||||
/// <returns>Returns a <c>FileSaveResult</c> error code.</returns>
|
/// <returns>Returns a <c>FileSaveResult</c> error code.</returns>
|
||||||
#if ModernKeePassLib
|
#if ModernKeePassLib
|
||||||
public static void Create(StorageFile strFilePath, byte[] pbAdditionalEntropy)
|
public static void Create(StorageFile file, byte[] pbAdditionalEntropy)
|
||||||
#else
|
#else
|
||||||
public static void Create(string strFilePath, byte[] pbAdditionalEntropy)
|
public static void Create(string strFilePath, byte[] pbAdditionalEntropy)
|
||||||
#endif
|
#endif
|
||||||
@@ -215,7 +214,11 @@ namespace ModernKeePassLib.Keys
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ModernKeePassLib
|
||||||
|
CreateXmlKeyFile(file, pbFinalKey32);
|
||||||
|
#else
|
||||||
CreateXmlKeyFile(strFilePath, pbFinalKey32);
|
CreateXmlKeyFile(strFilePath, pbFinalKey32);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================================================
|
// ================================================================
|
||||||
@@ -276,19 +279,23 @@ namespace ModernKeePassLib.Keys
|
|||||||
|
|
||||||
return pbKeyData;
|
return pbKeyData;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ModernKeePassLib
|
#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
|
#else
|
||||||
private static void CreateXmlKeyFile(string strFile, byte[] pbKeyData)
|
private static void CreateXmlKeyFile(string strFile, byte[] pbKeyData)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
Debug.Assert(strFile != null);
|
Debug.Assert(strFile != null);
|
||||||
if(strFile == null) throw new ArgumentNullException("strFile");
|
if(strFile == null) throw new ArgumentNullException("strFile");
|
||||||
|
#endif
|
||||||
Debug.Assert(pbKeyData != null);
|
Debug.Assert(pbKeyData != null);
|
||||||
if(pbKeyData == null) throw new ArgumentNullException("pbKeyData");
|
if(pbKeyData == null) throw new ArgumentNullException("pbKeyData");
|
||||||
|
|
||||||
#if ModernKeePassLib
|
#if ModernKeePassLib
|
||||||
IOConnectionInfo ioc = IOConnectionInfo.FromFile(strFile);
|
var ioc = IOConnectionInfo.FromStorageFile(file);
|
||||||
#else
|
#else
|
||||||
IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile);
|
IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile);
|
||||||
#endif
|
#endif
|
||||||
|
@@ -21,9 +21,9 @@ using System;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
using ModernKeePassLib.Cryptography;
|
||||||
using ModernKeePassLib.Security;
|
using ModernKeePassLib.Security;
|
||||||
using ModernKeePassLib.Utility;
|
using ModernKeePassLib.Utility;
|
||||||
using ModernKeePassLib.Cryptography;
|
|
||||||
|
|
||||||
namespace ModernKeePassLib.Keys
|
namespace ModernKeePassLib.Keys
|
||||||
{
|
{
|
||||||
|
@@ -3,14 +3,14 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<Version>2.41.1</Version>
|
<Version>2.42.1</Version>
|
||||||
<Authors>Geoffroy Bonneville</Authors>
|
<Authors>Geoffroy Bonneville</Authors>
|
||||||
<PackageLicenseUrl>https://www.gnu.org/licenses/gpl-3.0.en.html</PackageLicenseUrl>
|
<PackageLicenseUrl>https://www.gnu.org/licenses/gpl-3.0.en.html</PackageLicenseUrl>
|
||||||
<PackageProjectUrl>https://github.com/wismna/ModernKeePass</PackageProjectUrl>
|
<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>
|
<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>
|
<Company>wismna</Company>
|
||||||
<Product>ModernKeePassLib</Product>
|
<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>
|
<PackageTags>KeePass KeePassLib Portable PCL NetStandard ModernKeePass</PackageTags>
|
||||||
<Copyright>Copyright © 2019 Geoffroy Bonneville</Copyright>
|
<Copyright>Copyright © 2019 Geoffroy Bonneville</Copyright>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@@ -22,6 +22,12 @@ namespace ModernKeePassLib.Native
|
|||||||
{
|
{
|
||||||
return Environment.OSVersion.Platform;
|
return Environment.OSVersion.Platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static string DecodeArgsToPath(string strApp)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(strApp)) return strApp;
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class NativeMethods
|
internal static class NativeMethods
|
||||||
|
@@ -234,16 +234,16 @@ namespace ModernKeePassLib.Native
|
|||||||
{
|
{
|
||||||
ProcessStartInfo psi = new ProcessStartInfo();
|
ProcessStartInfo psi = new ProcessStartInfo();
|
||||||
|
|
||||||
|
psi.FileName = EncodePath(strAppPath);
|
||||||
|
if(!string.IsNullOrEmpty(strParams)) psi.Arguments = strParams;
|
||||||
|
|
||||||
psi.CreateNoWindow = true;
|
psi.CreateNoWindow = true;
|
||||||
psi.FileName = strAppPath;
|
|
||||||
psi.WindowStyle = ProcessWindowStyle.Hidden;
|
psi.WindowStyle = ProcessWindowStyle.Hidden;
|
||||||
psi.UseShellExecute = false;
|
psi.UseShellExecute = false;
|
||||||
|
|
||||||
psi.RedirectStandardOutput = bStdOut;
|
psi.RedirectStandardOutput = bStdOut;
|
||||||
|
|
||||||
if(strStdInput != null) psi.RedirectStandardInput = true;
|
if(strStdInput != null) psi.RedirectStandardInput = true;
|
||||||
|
|
||||||
if(!string.IsNullOrEmpty(strParams)) psi.Arguments = strParams;
|
|
||||||
|
|
||||||
Process p = Process.Start(psi);
|
Process p = Process.Start(psi);
|
||||||
pToDispose = p;
|
pToDispose = p;
|
||||||
|
|
||||||
@@ -456,5 +456,76 @@ namespace ModernKeePassLib.Native
|
|||||||
// https://referencesource.microsoft.com/#mscorlib/system/runtime/interopservices/windowsruntime/winrtclassactivator.cs
|
// https://referencesource.microsoft.com/#mscorlib/system/runtime/interopservices/windowsruntime/winrtclassactivator.cs
|
||||||
return Type.GetType(strType + ", Windows, ContentType=WindowsRuntime", false);
|
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 uint FILE_SUPPORTS_TRANSACTIONS = 0x00200000;
|
||||||
internal const int MAX_TRANSACTION_DESCRIPTION_LENGTH = 64;
|
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_SHOWNORMAL = 0x00000001;
|
||||||
// internal const uint TF_SFT_HIDDEN = 0x00000008;
|
// internal const uint TF_SFT_HIDDEN = 0x00000008;
|
||||||
|
|
||||||
@@ -179,6 +182,10 @@ namespace ModernKeePassLib.Native
|
|||||||
string lpNewFileName, IntPtr lpProgressRoutine, IntPtr lpData,
|
string lpNewFileName, IntPtr lpProgressRoutine, IntPtr lpData,
|
||||||
UInt32 dwFlags, IntPtr hTransaction);
|
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)
|
#if (!KeePassLibSD && !KeePassUAP)
|
||||||
[DllImport("ShlWApi.dll", CharSet = CharSet.Auto)]
|
[DllImport("ShlWApi.dll", CharSet = CharSet.Auto)]
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
@@ -256,5 +263,29 @@ namespace ModernKeePassLib.Native
|
|||||||
return strRtDir;
|
return strRtDir;
|
||||||
#endif
|
#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.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Drawing;
|
|
||||||
|
|
||||||
#if ModernKeePassLib
|
#if !KeePassUAP
|
||||||
using Windows.UI.Xaml.Controls;
|
using System.Drawing;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using ModernKeePassLib.Collections;
|
using ModernKeePassLib.Collections;
|
||||||
@@ -132,7 +131,7 @@ namespace ModernKeePassLib
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <c>IOConnection</c> of the currently opened database file.
|
/// <c>IOConnection</c> of the currently open database file.
|
||||||
/// Is never <c>null</c>.
|
/// Is never <c>null</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IOConnectionInfo IOConnectionInfo
|
public IOConnectionInfo IOConnectionInfo
|
||||||
@@ -660,8 +659,8 @@ namespace ModernKeePassLib
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Save the currently opened database. The file is written to the location
|
/// Save the currently open database. The file is written to the
|
||||||
/// it has been opened from.
|
/// location it has been opened from.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="slLogger">Logger that recieves status information.</param>
|
/// <param name="slLogger">Logger that recieves status information.</param>
|
||||||
public void Save(IStatusLogger slLogger)
|
public void Save(IStatusLogger slLogger)
|
||||||
@@ -695,16 +694,16 @@ namespace ModernKeePassLib
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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
|
/// <paramref name="bIsPrimaryNow" /> is <c>true</c>, the specified
|
||||||
/// location is made the default location for future saves
|
/// location is made the default location for future saves
|
||||||
/// using <c>SaveDatabase</c>.
|
/// using <c>SaveDatabase</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ioConnection">New location to serialize the database to.</param>
|
/// <param name="ioConnection">New location to serialize the database to.</param>
|
||||||
/// <param name="bIsPrimaryNow">If <c>true</c>, the new location is made the
|
/// <param name="bIsPrimaryNow">If <c>true</c>, the new location is made
|
||||||
/// standard location for the database. If <c>false</c>, a copy of the currently
|
/// the standard location for the database. If <c>false</c>, a copy of the
|
||||||
/// opened database is saved to the specified location, but it isn't
|
/// currently open database is saved to the specified location, but it
|
||||||
/// made the default location (i.e. no lock files will be moved for
|
/// isn't made the default location (i.e. no lock files will be moved for
|
||||||
/// example).</param>
|
/// example).</param>
|
||||||
/// <param name="slLogger">Logger that recieves status information.</param>
|
/// <param name="slLogger">Logger that recieves status information.</param>
|
||||||
public void SaveAs(IOConnectionInfo ioConnection, bool bIsPrimaryNow,
|
public void SaveAs(IOConnectionInfo ioConnection, bool bIsPrimaryNow,
|
||||||
@@ -736,8 +735,8 @@ namespace ModernKeePassLib
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Closes the currently opened database. No confirmation message is shown
|
/// Closes the currently open database. No confirmation message
|
||||||
/// before closing. Unsaved changes will be lost.
|
/// is shown before closing. Unsaved changes will be lost.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Close()
|
public void Close()
|
||||||
{
|
{
|
||||||
@@ -801,6 +800,12 @@ namespace ModernKeePassLib
|
|||||||
pgNew.Uuid = pg.Uuid;
|
pgNew.Uuid = pg.Uuid;
|
||||||
pgNew.AssignProperties(pg, false, true);
|
pgNew.AssignProperties(pg, false, true);
|
||||||
|
|
||||||
|
if(!pgLocalContainer.CanAddGroup(pgNew))
|
||||||
|
{
|
||||||
|
Debug.Assert(false);
|
||||||
|
pgLocalContainer = m_pgRootGroup;
|
||||||
|
pgLocalContainer.CheckCanAddGroup(pgNew);
|
||||||
|
}
|
||||||
// pgLocalContainer.AddGroup(pgNew, true);
|
// pgLocalContainer.AddGroup(pgNew, true);
|
||||||
InsertObjectAtBestPos<PwGroup>(pgLocalContainer.Groups, pgNew, ppSrc);
|
InsertObjectAtBestPos<PwGroup>(pgLocalContainer.Groups, pgNew, ppSrc);
|
||||||
pgNew.ParentGroup = pgLocalContainer;
|
pgNew.ParentGroup = pgLocalContainer;
|
||||||
@@ -1087,8 +1092,8 @@ namespace ModernKeePassLib
|
|||||||
|
|
||||||
if(pgLocal.IsContainedIn(pg)) continue;
|
if(pgLocal.IsContainedIn(pg)) continue;
|
||||||
|
|
||||||
|
if(!pgLocal.CanAddGroup(pg)) { Debug.Assert(false); continue; }
|
||||||
pg.ParentGroup.Groups.Remove(pg);
|
pg.ParentGroup.Groups.Remove(pg);
|
||||||
|
|
||||||
// pgLocal.AddGroup(pg, true);
|
// pgLocal.AddGroup(pg, true);
|
||||||
InsertObjectAtBestPos<PwGroup>(pgLocal.Groups, pg, ppSrc);
|
InsertObjectAtBestPos<PwGroup>(pgLocal.Groups, pg, ppSrc);
|
||||||
pg.ParentGroup = pgLocal;
|
pg.ParentGroup = pgLocal;
|
||||||
@@ -1643,7 +1648,7 @@ namespace ModernKeePassLib
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
#elif !KeePassLibSD
|
#elif !KeePassLibSD && !ModernKeePassLib
|
||||||
[Obsolete("Additionally specify the size.")]
|
[Obsolete("Additionally specify the size.")]
|
||||||
public Image GetCustomIcon(PwUuid pwIconId)
|
public Image GetCustomIcon(PwUuid pwIconId)
|
||||||
{
|
{
|
||||||
|
@@ -55,18 +55,18 @@ namespace ModernKeePassLib
|
|||||||
/// e.g. 2.19 = 0x02130000.
|
/// e.g. 2.19 = 0x02130000.
|
||||||
/// It is highly recommended to use <c>FileVersion64</c> instead.
|
/// It is highly recommended to use <c>FileVersion64</c> instead.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly uint Version32 = 0x02290000;
|
public static readonly uint Version32 = 0x022A0100;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version, encoded as 64-bit unsigned integer
|
/// Version, encoded as 64-bit unsigned integer
|
||||||
/// (component-wise, 16 bits per component).
|
/// (component-wise, 16 bits per component).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly ulong FileVersion64 = 0x0002002900000000UL;
|
public static readonly ulong FileVersion64 = 0x0002002A00010000UL;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version, encoded as string.
|
/// Version, encoded as string.
|
||||||
/// </summary>
|
/// </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";
|
public static readonly string Copyright = @"Copyright © 2003-2019 Dominik Reichl";
|
||||||
|
|
||||||
@@ -181,6 +181,12 @@ namespace ModernKeePassLib
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly string DefaultAutoTypeSequenceTan = @"{PASSWORD}";
|
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>
|
/// <summary>
|
||||||
/// Check if a name is a standard field name.
|
/// Check if a name is a standard field name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -61,7 +61,7 @@ namespace ModernKeePassLib
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Methods for merging password databases/entries.
|
/// Methods for merging databases/entries.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum PwMergeMethod
|
public enum PwMergeMethod
|
||||||
{
|
{
|
||||||
|
@@ -25,19 +25,24 @@ using System.Text.RegularExpressions;
|
|||||||
using ModernKeePassLib.Collections;
|
using ModernKeePassLib.Collections;
|
||||||
using ModernKeePassLib.Delegates;
|
using ModernKeePassLib.Delegates;
|
||||||
using ModernKeePassLib.Interfaces;
|
using ModernKeePassLib.Interfaces;
|
||||||
|
using ModernKeePassLib.Resources;
|
||||||
using ModernKeePassLib.Security;
|
using ModernKeePassLib.Security;
|
||||||
using ModernKeePassLib.Utility;
|
using ModernKeePassLib.Utility;
|
||||||
|
|
||||||
namespace ModernKeePassLib
|
namespace ModernKeePassLib
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A group containing several password entries.
|
/// A group containing subgroups and entries.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class PwGroup : ITimeLogger, IStructureItem, IDeepCloneable<PwGroup>
|
public sealed class PwGroup : ITimeLogger, IStructureItem, IDeepCloneable<PwGroup>
|
||||||
{
|
{
|
||||||
public const bool DefaultAutoTypeEnabled = true;
|
public const bool DefaultAutoTypeEnabled = true;
|
||||||
public const bool DefaultSearchingEnabled = 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<PwGroup> m_listGroups = new PwObjectList<PwGroup>();
|
||||||
private PwObjectList<PwEntry> m_listEntries = new PwObjectList<PwEntry>();
|
private PwObjectList<PwEntry> m_listEntries = new PwObjectList<PwEntry>();
|
||||||
private PwGroup m_pParentGroup = null;
|
private PwGroup m_pParentGroup = null;
|
||||||
@@ -139,7 +144,8 @@ namespace ModernKeePassLib
|
|||||||
{
|
{
|
||||||
get { return m_pParentGroup; }
|
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; }
|
internal set { Debug.Assert(value != this); m_pParentGroup = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1244,7 +1250,7 @@ namespace ModernKeePassLib
|
|||||||
PwGroup pg = m_pParentGroup;
|
PwGroup pg = m_pParentGroup;
|
||||||
while(pg != null)
|
while(pg != null)
|
||||||
{
|
{
|
||||||
if((!bIncludeTopMostGroup) && (pg.m_pParentGroup == null))
|
if(!bIncludeTopMostGroup && (pg.m_pParentGroup == null))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
strPath = pg.Name + strSeparator + strPath;
|
strPath = pg.Name + strSeparator + strPath;
|
||||||
@@ -1367,21 +1373,34 @@ namespace ModernKeePassLib
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
/// <returns>Number of parent groups.</returns>
|
/// <returns>Depth of this group.</returns>
|
||||||
public uint GetLevel()
|
public uint GetDepth()
|
||||||
{
|
{
|
||||||
PwGroup pg = m_pParentGroup;
|
PwGroup pg = m_pParentGroup;
|
||||||
uint uLevel = 0;
|
uint d = 0;
|
||||||
|
|
||||||
while(pg != null)
|
while(pg != null)
|
||||||
{
|
{
|
||||||
pg = pg.ParentGroup;
|
pg = pg.m_pParentGroup;
|
||||||
++uLevel;
|
++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()
|
public string GetAutoTypeSequenceInherited()
|
||||||
@@ -1520,13 +1539,31 @@ namespace ModernKeePassLib
|
|||||||
{
|
{
|
||||||
if(subGroup == null) throw new ArgumentNullException("subGroup");
|
if(subGroup == null) throw new ArgumentNullException("subGroup");
|
||||||
|
|
||||||
|
CheckCanAddGroup(subGroup);
|
||||||
m_listGroups.Add(subGroup);
|
m_listGroups.Add(subGroup);
|
||||||
|
|
||||||
if(bTakeOwnership) subGroup.m_pParentGroup = this;
|
if(bTakeOwnership) subGroup.ParentGroup = this;
|
||||||
|
|
||||||
if(bUpdateLocationChangedOfSub) subGroup.LocationChanged = DateTime.UtcNow;
|
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>
|
/// <summary>
|
||||||
/// Add an entry to this group.
|
/// Add an entry to this group.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -59,6 +59,7 @@ namespace ModernKeePassLib.Resources
|
|||||||
m_strOldFormat = TryGetEx(dictNew, "OldFormat", m_strOldFormat);
|
m_strOldFormat = TryGetEx(dictNew, "OldFormat", m_strOldFormat);
|
||||||
m_strPassive = TryGetEx(dictNew, "Passive", m_strPassive);
|
m_strPassive = TryGetEx(dictNew, "Passive", m_strPassive);
|
||||||
m_strPreAuth = TryGetEx(dictNew, "PreAuth", m_strPreAuth);
|
m_strPreAuth = TryGetEx(dictNew, "PreAuth", m_strPreAuth);
|
||||||
|
m_strStructsTooDeep = TryGetEx(dictNew, "StructsTooDeep", m_strStructsTooDeep);
|
||||||
m_strTimeout = TryGetEx(dictNew, "Timeout", m_strTimeout);
|
m_strTimeout = TryGetEx(dictNew, "Timeout", m_strTimeout);
|
||||||
m_strTryAgainSecs = TryGetEx(dictNew, "TryAgainSecs", m_strTryAgainSecs);
|
m_strTryAgainSecs = TryGetEx(dictNew, "TryAgainSecs", m_strTryAgainSecs);
|
||||||
m_strUnknownHeaderId = TryGetEx(dictNew, "UnknownHeaderId", m_strUnknownHeaderId);
|
m_strUnknownHeaderId = TryGetEx(dictNew, "UnknownHeaderId", m_strUnknownHeaderId);
|
||||||
@@ -101,6 +102,7 @@ namespace ModernKeePassLib.Resources
|
|||||||
"OldFormat",
|
"OldFormat",
|
||||||
"Passive",
|
"Passive",
|
||||||
"PreAuth",
|
"PreAuth",
|
||||||
|
"StructsTooDeep",
|
||||||
"Timeout",
|
"Timeout",
|
||||||
"TryAgainSecs",
|
"TryAgainSecs",
|
||||||
"UnknownHeaderId",
|
"UnknownHeaderId",
|
||||||
@@ -346,10 +348,10 @@ namespace ModernKeePassLib.Resources
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static string m_strFrameworkNotImplExcp =
|
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>
|
/// <summary>
|
||||||
/// Look up a localized string similar to
|
/// 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>
|
/// </summary>
|
||||||
public static string FrameworkNotImplExcp
|
public static string FrameworkNotImplExcp
|
||||||
{
|
{
|
||||||
@@ -477,6 +479,17 @@ namespace ModernKeePassLib.Resources
|
|||||||
get { return m_strPreAuth; }
|
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 =
|
private static string m_strTimeout =
|
||||||
@"Timeout";
|
@"Timeout";
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -9,7 +9,7 @@ namespace ModernKeePassLib.Resources
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class KSRes
|
public static partial class KSRes
|
||||||
{
|
{
|
||||||
private static string TryGetEx(Dictionary<string, string> dictNew,
|
private static string TryGetEx(Dictionary<string, string> dictNew,
|
||||||
string strName, string strDefault)
|
string strName, string strDefault)
|
||||||
|
@@ -23,18 +23,19 @@ using System.ComponentModel;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Windows.Storage.AccessCache;
|
||||||
#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT)
|
#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT)
|
||||||
using System.Security.AccessControl;
|
using System.Security.AccessControl;
|
||||||
#endif
|
#endif
|
||||||
|
#if ModernKeePassLib
|
||||||
using ModernKeePassLib.Native;
|
|
||||||
using ModernKeePassLib.Utility;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
using Windows.Storage.Streams;
|
#endif
|
||||||
|
|
||||||
using ModernKeePassLib.Cryptography;
|
using ModernKeePassLib.Cryptography;
|
||||||
|
using ModernKeePassLib.Delegates;
|
||||||
|
using ModernKeePassLib.Native;
|
||||||
using ModernKeePassLib.Resources;
|
using ModernKeePassLib.Resources;
|
||||||
|
using ModernKeePassLib.Utility;
|
||||||
|
|
||||||
namespace ModernKeePassLib.Serialization
|
namespace ModernKeePassLib.Serialization
|
||||||
{
|
{
|
||||||
@@ -210,10 +211,10 @@ namespace ModernKeePassLib.Serialization
|
|||||||
// trying to set 'Owner' or 'Group' can result in an
|
// trying to set 'Owner' or 'Group' can result in an
|
||||||
// UnauthorizedAccessException; thus we restore 'Access' (DACL) only
|
// UnauthorizedAccessException; thus we restore 'Access' (DACL) only
|
||||||
const AccessControlSections acs = AccessControlSections.Access;
|
const AccessControlSections acs = AccessControlSections.Access;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
bool bEfsEncrypted = false;
|
bool bEfsEncrypted = false;
|
||||||
byte[] pbSec = null;
|
byte[] pbSec = null;
|
||||||
|
|
||||||
DateTime? otCreation = null;
|
DateTime? otCreation = null;
|
||||||
|
|
||||||
bool bBaseExists = IOConnection.FileExists(m_iocBase);
|
bool bBaseExists = IOConnection.FileExists(m_iocBase);
|
||||||
@@ -228,9 +229,7 @@ namespace ModernKeePassLib.Serialization
|
|||||||
try { if(bEfsEncrypted) File.Decrypt(m_iocBase.Path); } // For TxF
|
try { if(bEfsEncrypted) File.Decrypt(m_iocBase.Path); } // For TxF
|
||||||
catch(Exception) { Debug.Assert(false); }
|
catch(Exception) { Debug.Assert(false); }
|
||||||
#endif
|
#endif
|
||||||
#if ModernKeePassLib
|
#if !ModernKeePassLib
|
||||||
otCreation = m_iocBase.StorageFile.DateCreated.UtcDateTime;
|
|
||||||
#else
|
|
||||||
otCreation = File.GetCreationTimeUtc(m_iocBase.Path);
|
otCreation = File.GetCreationTimeUtc(m_iocBase.Path);
|
||||||
#endif
|
#endif
|
||||||
#if !ModernKeePassLib
|
#if !ModernKeePassLib
|
||||||
@@ -337,6 +336,7 @@ namespace ModernKeePassLib.Serialization
|
|||||||
{
|
{
|
||||||
if(NativeLib.IsUnix()) return;
|
if(NativeLib.IsUnix()) return;
|
||||||
if(!m_iocBase.IsLocalFile()) return;
|
if(!m_iocBase.IsLocalFile()) return;
|
||||||
|
if(IsOneDriveWorkaroundRequired()) return;
|
||||||
|
|
||||||
string strID = StrUtil.AlphaNumericOnly(Convert.ToBase64String(
|
string strID = StrUtil.AlphaNumericOnly(Convert.ToBase64String(
|
||||||
CryptoRandom.Instance.GetRandomBytes(16)));
|
CryptoRandom.Instance.GetRandomBytes(16)));
|
||||||
@@ -354,7 +354,7 @@ namespace ModernKeePassLib.Serialization
|
|||||||
#if ModernKeePassLib
|
#if ModernKeePassLib
|
||||||
var tempFile = ApplicationData.Current.TemporaryFolder.CreateFileAsync(m_iocTemp.Path).GetAwaiter()
|
var tempFile = ApplicationData.Current.TemporaryFolder.CreateFileAsync(m_iocTemp.Path).GetAwaiter()
|
||||||
.GetResult();
|
.GetResult();
|
||||||
m_iocTemp = IOConnectionInfo.FromFile(tempFile);
|
m_iocTemp = IOConnectionInfo.FromStorageFile(tempFile);
|
||||||
#else
|
#else
|
||||||
m_iocTemp = IOConnectionInfo.FromPath(strTemp);
|
m_iocTemp = IOConnectionInfo.FromPath(strTemp);
|
||||||
#endif
|
#endif
|
||||||
@@ -373,10 +373,7 @@ namespace ModernKeePassLib.Serialization
|
|||||||
// Move the temporary file onto the base file's drive first,
|
// Move the temporary file onto the base file's drive first,
|
||||||
// such that it cannot happen that both the base file and
|
// such that it cannot happen that both the base file and
|
||||||
// the temporary file are deleted/corrupted
|
// the temporary file are deleted/corrupted
|
||||||
#if ModernKeePassLib
|
#if !ModernKeePassLib
|
||||||
m_iocTemp.StorageFile = ApplicationData.Current.TemporaryFolder.CreateFileAsync(m_iocTemp.Path).GetAwaiter()
|
|
||||||
.GetResult();
|
|
||||||
#else
|
|
||||||
const uint f = (NativeMethods.MOVEFILE_COPY_ALLOWED |
|
const uint f = (NativeMethods.MOVEFILE_COPY_ALLOWED |
|
||||||
NativeMethods.MOVEFILE_REPLACE_EXISTING);
|
NativeMethods.MOVEFILE_REPLACE_EXISTING);
|
||||||
bool b = NativeMethods.MoveFileEx(m_iocTemp.Path, m_iocTxfMidFallback.Path, f);
|
bool b = NativeMethods.MoveFileEx(m_iocTemp.Path, m_iocTxfMidFallback.Path, f);
|
||||||
@@ -391,9 +388,7 @@ namespace ModernKeePassLib.Serialization
|
|||||||
|
|
||||||
private bool TxfMoveWithTx()
|
private bool TxfMoveWithTx()
|
||||||
{
|
{
|
||||||
#if ModernKeePassLib
|
#if !ModernKeePassLib
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
IntPtr hTx = new IntPtr((int)NativeMethods.INVALID_HANDLE_VALUE);
|
IntPtr hTx = new IntPtr((int)NativeMethods.INVALID_HANDLE_VALUE);
|
||||||
Debug.Assert(hTx.ToInt64() == NativeMethods.INVALID_HANDLE_VALUE);
|
Debug.Assert(hTx.ToInt64() == NativeMethods.INVALID_HANDLE_VALUE);
|
||||||
try
|
try
|
||||||
@@ -438,9 +433,8 @@ namespace ModernKeePassLib.Serialization
|
|||||||
catch(Exception) { Debug.Assert(false); }
|
catch(Exception) { Debug.Assert(false); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
#endif
|
#endif
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void ClearOld()
|
internal static void ClearOld()
|
||||||
@@ -470,5 +464,89 @@ namespace ModernKeePassLib.Serialization
|
|||||||
}
|
}
|
||||||
catch(Exception) { Debug.Assert(false); }
|
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.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
#if (!ModernKeePassLib && !KeePassLibSD && !KeePassUAP)
|
#if (!ModernKeePassLib && !KeePassLibSD && !KeePassUAP)
|
||||||
using System.Net.Cache;
|
using System.Net.Cache;
|
||||||
using System.Net.Security;
|
using System.Net.Security;
|
||||||
@@ -600,7 +599,12 @@ namespace ModernKeePassLib.Serialization
|
|||||||
|
|
||||||
private static Stream OpenReadLocal(IOConnectionInfo ioc)
|
private static Stream OpenReadLocal(IOConnectionInfo ioc)
|
||||||
{
|
{
|
||||||
|
#if ModernKeePassLib
|
||||||
return ioc.StorageFile.OpenAsync(FileAccessMode.Read).GetAwaiter().GetResult().AsStream();
|
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)
|
#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT)
|
||||||
@@ -654,7 +658,7 @@ namespace ModernKeePassLib.Serialization
|
|||||||
RaiseIOAccessPreEvent(ioc, IOAccessType.Exists);
|
RaiseIOAccessPreEvent(ioc, IOAccessType.Exists);
|
||||||
|
|
||||||
#if ModernKeePassLib
|
#if ModernKeePassLib
|
||||||
return ioc.StorageFile.IsAvailable;
|
return ioc.StorageFile != null;
|
||||||
#else
|
#else
|
||||||
if(ioc.IsLocalFile()) return File.Exists(ioc.Path);
|
if(ioc.IsLocalFile()) return File.Exists(ioc.Path);
|
||||||
|
|
||||||
|
@@ -25,14 +25,12 @@ using System.IO;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
#if ModernKeePassLib
|
#if ModernKeePassLib
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
//using PCLStorage;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using ModernKeePassLib.Interfaces;
|
using ModernKeePassLib.Interfaces;
|
||||||
using ModernKeePassLib.Utility;
|
using ModernKeePassLib.Utility;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Windows.Storage.AccessCache;
|
|
||||||
|
|
||||||
namespace ModernKeePassLib.Serialization
|
namespace ModernKeePassLib.Serialization
|
||||||
{
|
{
|
||||||
@@ -70,6 +68,8 @@ namespace ModernKeePassLib.Serialization
|
|||||||
{
|
{
|
||||||
// private IOFileFormatHint m_ioHint = IOFileFormatHint.None;
|
// private IOFileFormatHint m_ioHint = IOFileFormatHint.None;
|
||||||
|
|
||||||
|
public StorageFile StorageFile { get; set; }
|
||||||
|
|
||||||
private string m_strUrl = string.Empty;
|
private string m_strUrl = string.Empty;
|
||||||
public string Path
|
public string Path
|
||||||
{
|
{
|
||||||
@@ -316,23 +316,11 @@ namespace ModernKeePassLib.Serialization
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if ModernKeePassLib
|
#if ModernKeePassLib
|
||||||
public static IOConnectionInfo FromFile(StorageFile file)
|
public static IOConnectionInfo FromStorageFile(StorageFile file)
|
||||||
{
|
{
|
||||||
IOConnectionInfo ioc = new IOConnectionInfo();
|
IOConnectionInfo ioc = new IOConnectionInfo();
|
||||||
|
|
||||||
ioc.StorageFile = file;
|
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.CredSaveMode = IOCredSaveMode.NoSave;
|
ioc.CredSaveMode = IOCredSaveMode.NoSave;
|
||||||
|
|
||||||
return ioc;
|
return ioc;
|
||||||
@@ -348,10 +336,6 @@ namespace ModernKeePassLib.Serialization
|
|||||||
return ioc;
|
return ioc;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
public StorageFile StorageFile { get; set; }
|
|
||||||
|
|
||||||
public bool CanProbablyAccess()
|
public bool CanProbablyAccess()
|
||||||
{
|
{
|
||||||
#if ModernKeePassLib
|
#if ModernKeePassLib
|
||||||
|
@@ -30,13 +30,14 @@ using System.Drawing;
|
|||||||
|
|
||||||
using ModernKeePassLib;
|
using ModernKeePassLib;
|
||||||
using ModernKeePassLib.Collections;
|
using ModernKeePassLib.Collections;
|
||||||
using ModernKeePassLib.Cryptography;
|
|
||||||
using ModernKeePassLib.Cryptography.Cipher;
|
|
||||||
using ModernKeePassLib.Interfaces;
|
using ModernKeePassLib.Interfaces;
|
||||||
using ModernKeePassLib.Resources;
|
using ModernKeePassLib.Resources;
|
||||||
using ModernKeePassLib.Security;
|
using ModernKeePassLib.Security;
|
||||||
using ModernKeePassLib.Utility;
|
using ModernKeePassLib.Utility;
|
||||||
|
|
||||||
|
using ModernKeePassLib.Cryptography;
|
||||||
|
using ModernKeePassLib.Cryptography.Cipher;
|
||||||
|
|
||||||
namespace ModernKeePassLib.Serialization
|
namespace ModernKeePassLib.Serialization
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -97,36 +98,10 @@ namespace ModernKeePassLib.Serialization
|
|||||||
|
|
||||||
private void ReadXmlStreamed(Stream sXml, Stream sParent)
|
private void ReadXmlStreamed(Stream sXml, Stream sParent)
|
||||||
{
|
{
|
||||||
ReadDocumentStreamed(CreateXmlReader(sXml), sParent);
|
using(XmlReader xr = XmlUtilEx.CreateXmlReader(sXml))
|
||||||
}
|
|
||||||
|
|
||||||
internal static XmlReaderSettings CreateStdXmlReaderSettings()
|
|
||||||
{
|
{
|
||||||
XmlReaderSettings xrs = new XmlReaderSettings();
|
ReadDocumentStreamed(xr, sParent);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadDocumentStreamed(XmlReader xr, Stream sParentStream)
|
private void ReadDocumentStreamed(XmlReader xr, Stream sParentStream)
|
||||||
@@ -179,7 +154,7 @@ namespace ModernKeePassLib.Serialization
|
|||||||
}
|
}
|
||||||
|
|
||||||
++uTagCounter;
|
++uTagCounter;
|
||||||
if(((uTagCounter % 256) == 0) && bSupportsStatus)
|
if(((uTagCounter & 0xFFU) == 0) && bSupportsStatus)
|
||||||
{
|
{
|
||||||
Debug.Assert(lStreamLength == sParentStream.Length);
|
Debug.Assert(lStreamLength == sParentStream.Length);
|
||||||
uint uPct = (uint)((sParentStream.Position * 100) /
|
uint uPct = (uint)((sParentStream.Position * 100) /
|
||||||
@@ -189,7 +164,8 @@ namespace ModernKeePassLib.Serialization
|
|||||||
// position/length values (M120413)
|
// position/length values (M120413)
|
||||||
if(uPct > 100) { Debug.Assert(false); uPct = 100; }
|
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)
|
private void ReadUnknown(XmlReader xr)
|
||||||
{
|
{
|
||||||
Debug.Assert(false); // Unknown node!
|
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;
|
do
|
||||||
|
|
||||||
XorredBuffer xb = ProcessNode(xr);
|
|
||||||
if(xb != null) { xb.Dispose(); return; } // ProcessNode sets m_bReadNextNode
|
|
||||||
|
|
||||||
bool bRead = true;
|
|
||||||
while(true)
|
|
||||||
{
|
{
|
||||||
if(bRead) xr.Read();
|
if(bRead) xr.Read();
|
||||||
|
bRead = true;
|
||||||
|
|
||||||
if(xr.NodeType == XmlNodeType.EndElement) break;
|
if(xr.NodeType == XmlNodeType.EndElement) --cOpen;
|
||||||
if(xr.NodeType != XmlNodeType.Element) { bRead = true; continue; }
|
else if(xr.NodeType == XmlNodeType.Element)
|
||||||
|
{
|
||||||
|
if(!xr.IsEmptyElement)
|
||||||
|
{
|
||||||
|
XorredBuffer xb = ProcessNode(xr);
|
||||||
|
if(xb != null) { xb.Dispose(); bRead = m_bReadNextNode; continue; }
|
||||||
|
|
||||||
ReadUnknown(xr);
|
++cOpen;
|
||||||
bRead = m_bReadNextNode;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(cOpen > 0);
|
||||||
|
|
||||||
Debug.Assert(xr.Name == strUnknownName); // On end tag
|
m_bReadNextNode = bRead;
|
||||||
m_bReadNextNode = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private XorredBuffer ProcessNode(XmlReader xr)
|
private XorredBuffer ProcessNode(XmlReader xr)
|
||||||
|
@@ -55,26 +55,23 @@ namespace ModernKeePassLib.Serialization
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class KdbxFile
|
public sealed partial class KdbxFile
|
||||||
{
|
{
|
||||||
#if ModernKeePassLib
|
|
||||||
public void Load(StorageFile file, KdbxFormat fmt, IStatusLogger slLogger)
|
|
||||||
{
|
|
||||||
IOConnectionInfo ioc = IOConnectionInfo.FromFile(file);
|
|
||||||
Load(IOConnection.OpenRead(ioc), fmt, slLogger);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Load a KDBX file.
|
/// Load a KDBX file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="strFilePath">File to load.</param>
|
/// <param name="strFilePath">File to load.</param>
|
||||||
/// <param name="fmt">Format.</param>
|
/// <param name="fmt">Format.</param>
|
||||||
/// <param name="slLogger">Status logger (optional).</param>
|
/// <param name="slLogger">Status logger (optional).</param>
|
||||||
|
#if ModernKeePassLib
|
||||||
|
public void Load(StorageFile file, KdbxFormat fmt, IStatusLogger slLogger)
|
||||||
|
{
|
||||||
|
IOConnectionInfo ioc = IOConnectionInfo.FromStorageFile(file);
|
||||||
|
#else
|
||||||
public void Load(string strFilePath, KdbxFormat fmt, IStatusLogger slLogger)
|
public void Load(string strFilePath, KdbxFormat fmt, IStatusLogger slLogger)
|
||||||
{
|
{
|
||||||
IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFilePath);
|
IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFilePath);
|
||||||
|
#endif
|
||||||
Load(IOConnection.OpenRead(ioc), fmt, slLogger);
|
Load(IOConnection.OpenRead(ioc), fmt, slLogger);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Load a KDBX file from a stream.
|
/// Load a KDBX file from a stream.
|
||||||
@@ -202,19 +199,17 @@ namespace ModernKeePassLib.Serialization
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if KeePassDebug_WriteXml
|
#if KeePassDebug_WriteXml
|
||||||
// FileStream fsOut = new FileStream("Raw.xml", FileMode.Create,
|
#warning XML output is enabled!
|
||||||
// FileAccess.Write, FileShare.None);
|
/* using(FileStream fsOut = new FileStream("Raw.xml", FileMode.Create,
|
||||||
// try
|
FileAccess.Write, FileShare.None))
|
||||||
// {
|
{
|
||||||
// while(true)
|
while(true)
|
||||||
// {
|
{
|
||||||
// int b = sXml.ReadByte();
|
int b = sXml.ReadByte();
|
||||||
// if(b == -1) break;
|
if(b == -1) throw new EndOfStreamException();
|
||||||
// fsOut.WriteByte((byte)b);
|
fsOut.WriteByte((byte)b);
|
||||||
// }
|
}
|
||||||
// }
|
} */
|
||||||
// catch(Exception) { }
|
|
||||||
// fsOut.Close();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ReadXmlStreamed(sXml, sHashing);
|
ReadXmlStreamed(sXml, sHashing);
|
||||||
@@ -413,7 +408,7 @@ namespace ModernKeePassLib.Serialization
|
|||||||
default:
|
default:
|
||||||
Debug.Assert(false);
|
Debug.Assert(false);
|
||||||
if(m_slLogger != null)
|
if(m_slLogger != null)
|
||||||
m_slLogger.SetText(KLRes.UnknownHeaderId + @": " +
|
m_slLogger.SetText(KLRes.UnknownHeaderId + ": " +
|
||||||
kdbID.ToString() + "!", LogStatusType.Warning);
|
kdbID.ToString() + "!", LogStatusType.Warning);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -429,7 +429,7 @@ namespace ModernKeePassLib.Serialization
|
|||||||
};
|
};
|
||||||
|
|
||||||
if(!pgRoot.TraverseTree(TraversalMethod.PreOrder, gh, eh))
|
if(!pgRoot.TraverseTree(TraversalMethod.PreOrder, gh, eh))
|
||||||
throw new InvalidOperationException();
|
throw new OperationCanceledException();
|
||||||
|
|
||||||
while(groupStack.Count > 1)
|
while(groupStack.Count > 1)
|
||||||
{
|
{
|
||||||
|
@@ -378,8 +378,8 @@ namespace ModernKeePassLib.Serialization
|
|||||||
|
|
||||||
Debug.Assert(m_pwDatabase != null);
|
Debug.Assert(m_pwDatabase != null);
|
||||||
Debug.Assert(m_pwDatabase.MasterKey != null);
|
Debug.Assert(m_pwDatabase.MasterKey != null);
|
||||||
ProtectedBinary pbinUser = m_pwDatabase.MasterKey.GenerateKey32(
|
ProtectedBinary pbinUser = m_pwDatabase.MasterKey.GenerateKey32Ex(
|
||||||
m_pwDatabase.KdfParameters);
|
m_pwDatabase.KdfParameters, m_slLogger);
|
||||||
Debug.Assert(pbinUser != null);
|
Debug.Assert(pbinUser != null);
|
||||||
if(pbinUser == null)
|
if(pbinUser == null)
|
||||||
throw new SecurityException(KLRes.InvalidCompositeKey);
|
throw new SecurityException(KLRes.InvalidCompositeKey);
|
||||||
@@ -492,7 +492,7 @@ namespace ModernKeePassLib.Serialization
|
|||||||
{
|
{
|
||||||
if(pb == null) { Debug.Assert(false); return; }
|
if(pb == null) { Debug.Assert(false); return; }
|
||||||
|
|
||||||
if(string.IsNullOrEmpty(strName)) strName = "File.bin";
|
strName = UrlUtil.GetSafeFileName(strName);
|
||||||
|
|
||||||
string strPath;
|
string strPath;
|
||||||
int iTry = 1;
|
int iTry = 1;
|
||||||
@@ -500,8 +500,8 @@ namespace ModernKeePassLib.Serialization
|
|||||||
{
|
{
|
||||||
strPath = UrlUtil.EnsureTerminatingSeparator(strSaveDir, false);
|
strPath = UrlUtil.EnsureTerminatingSeparator(strSaveDir, false);
|
||||||
|
|
||||||
string strExt = UrlUtil.GetExtension(strName);
|
|
||||||
string strDesc = UrlUtil.StripExtension(strName);
|
string strDesc = UrlUtil.StripExtension(strName);
|
||||||
|
string strExt = UrlUtil.GetExtension(strName);
|
||||||
|
|
||||||
strPath += strDesc;
|
strPath += strDesc;
|
||||||
if(iTry > 1)
|
if(iTry > 1)
|
||||||
|
@@ -46,6 +46,7 @@ namespace ModernKeePassLib.Translation
|
|||||||
public sealed class KPTranslation
|
public sealed class KPTranslation
|
||||||
{
|
{
|
||||||
public static readonly string FileExtension = "lngx";
|
public static readonly string FileExtension = "lngx";
|
||||||
|
internal const string FileExtension1x = "lng";
|
||||||
|
|
||||||
private KPTranslationProperties m_props = new KPTranslationProperties();
|
private KPTranslationProperties m_props = new KPTranslationProperties();
|
||||||
public KPTranslationProperties Properties
|
public KPTranslationProperties Properties
|
||||||
|
@@ -264,8 +264,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
[MethodImpl(MioNoOptimize)]
|
[MethodImpl(MioNoOptimize)]
|
||||||
public static void ZeroByteArray(byte[] pbArray)
|
public static void ZeroByteArray(byte[] pbArray)
|
||||||
{
|
{
|
||||||
Debug.Assert(pbArray != null);
|
if(pbArray == null) { Debug.Assert(false); return; }
|
||||||
if(pbArray == null) throw new ArgumentNullException("pbArray");
|
|
||||||
|
|
||||||
Array.Clear(pbArray, 0, pbArray.Length);
|
Array.Clear(pbArray, 0, pbArray.Length);
|
||||||
}
|
}
|
||||||
@@ -277,7 +276,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
[MethodImpl(MioNoOptimize)]
|
[MethodImpl(MioNoOptimize)]
|
||||||
public static void ZeroArray<T>(T[] v)
|
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);
|
Array.Clear(v, 0, v.Length);
|
||||||
}
|
}
|
||||||
|
@@ -116,9 +116,6 @@ namespace ModernKeePassLib.Utility
|
|||||||
// 1760:
|
// 1760:
|
||||||
// Input focus is not restored when activating a form.
|
// Input focus is not restored when activating a form.
|
||||||
// https://sourceforge.net/p/keepass/bugs/1760/
|
// https://sourceforge.net/p/keepass/bugs/1760/
|
||||||
// 2139:
|
|
||||||
// Shortcut keys are ignored.
|
|
||||||
// https://sourceforge.net/p/keepass/feature-requests/2139/
|
|
||||||
// 2140:
|
// 2140:
|
||||||
// Explicit control focusing is ignored.
|
// Explicit control focusing is ignored.
|
||||||
// https://sourceforge.net/p/keepass/feature-requests/2140/
|
// https://sourceforge.net/p/keepass/feature-requests/2140/
|
||||||
|
@@ -24,7 +24,6 @@ using System.Diagnostics;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
#if !KeePassUAP
|
#if !KeePassUAP
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
@@ -44,45 +43,41 @@ namespace ModernKeePassLib.Utility
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class CharStream
|
public sealed class CharStream
|
||||||
{
|
{
|
||||||
private string m_strString = string.Empty;
|
private readonly string m_str;
|
||||||
private int m_nPos = 0;
|
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)
|
public CharStream(string str)
|
||||||
{
|
{
|
||||||
Debug.Assert(str != null);
|
if(str == null) { Debug.Assert(false); throw new ArgumentNullException("str"); }
|
||||||
if(str == null) throw new ArgumentNullException("str");
|
|
||||||
|
|
||||||
m_strString = str;
|
m_str = str;
|
||||||
}
|
|
||||||
|
|
||||||
public void Seek(SeekOrigin org, int nSeek)
|
|
||||||
{
|
|
||||||
if(org == SeekOrigin.Begin)
|
|
||||||
m_nPos = nSeek;
|
|
||||||
else if(org == SeekOrigin.Current)
|
|
||||||
m_nPos += nSeek;
|
|
||||||
else if(org == SeekOrigin.End)
|
|
||||||
m_nPos = m_strString.Length + nSeek;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public char ReadChar()
|
public char ReadChar()
|
||||||
{
|
{
|
||||||
if(m_nPos < 0) return char.MinValue;
|
if(m_iPos >= m_str.Length) return char.MinValue;
|
||||||
if(m_nPos >= m_strString.Length) return char.MinValue;
|
|
||||||
|
|
||||||
char chRet = m_strString[m_nPos];
|
return m_str[m_iPos++];
|
||||||
++m_nPos;
|
|
||||||
return chRet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public char ReadChar(bool bSkipWhiteSpace)
|
public char ReadChar(bool bSkipWhiteSpace)
|
||||||
{
|
{
|
||||||
if(bSkipWhiteSpace == false) return ReadChar();
|
if(!bSkipWhiteSpace) return ReadChar();
|
||||||
|
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
char ch = ReadChar();
|
char ch = ReadChar();
|
||||||
|
|
||||||
if((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n'))
|
if((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n'))
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
@@ -90,29 +85,25 @@ namespace ModernKeePassLib.Utility
|
|||||||
|
|
||||||
public char PeekChar()
|
public char PeekChar()
|
||||||
{
|
{
|
||||||
if(m_nPos < 0) return char.MinValue;
|
if(m_iPos >= m_str.Length) return char.MinValue;
|
||||||
if(m_nPos >= m_strString.Length) return char.MinValue;
|
|
||||||
|
|
||||||
return m_strString[m_nPos];
|
return m_str[m_iPos];
|
||||||
}
|
}
|
||||||
|
|
||||||
public char PeekChar(bool bSkipWhiteSpace)
|
public char PeekChar(bool bSkipWhiteSpace)
|
||||||
{
|
{
|
||||||
if(bSkipWhiteSpace == false) return PeekChar();
|
if(!bSkipWhiteSpace) return PeekChar();
|
||||||
|
|
||||||
int iIndex = m_nPos;
|
int i = m_iPos;
|
||||||
while(true)
|
while(i < m_str.Length)
|
||||||
{
|
{
|
||||||
if(iIndex < 0) return char.MinValue;
|
char ch = m_str[i];
|
||||||
if(iIndex >= m_strString.Length) return char.MinValue;
|
|
||||||
|
|
||||||
char ch = m_strString[iIndex];
|
|
||||||
|
|
||||||
if((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n'))
|
if((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n'))
|
||||||
return ch;
|
return ch;
|
||||||
|
++i;
|
||||||
++iIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return char.MinValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,44 +396,46 @@ namespace ModernKeePassLib.Utility
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public static void SplitCommandLine(string strCmdLine, out string strApp,
|
||||||
/// Split up a command line into application and argument.
|
out string strArgs)
|
||||||
/// </summary>
|
|
||||||
/// <param name="strCmdLine">Command line to split.</param>
|
|
||||||
/// <param name="strApp">Application path.</param>
|
|
||||||
/// <param name="strArgs">Arguments.</param>
|
|
||||||
public static void SplitCommandLine(string strCmdLine, out string strApp, out string strArgs)
|
|
||||||
{
|
{
|
||||||
Debug.Assert(strCmdLine != null); if(strCmdLine == null) throw new ArgumentNullException("strCmdLine");
|
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();
|
string str = strCmdLine.Trim();
|
||||||
|
strApp = null;
|
||||||
strApp = null; strArgs = null;
|
strArgs = null;
|
||||||
|
|
||||||
if(str.StartsWith("\""))
|
if(str.StartsWith("\""))
|
||||||
{
|
{
|
||||||
int nSecond = str.IndexOf('\"', 1);
|
int iSecond = UrlUtil.IndexOfSecondEnclQuote(str);
|
||||||
if(nSecond >= 1)
|
if(iSecond >= 1)
|
||||||
{
|
{
|
||||||
strApp = str.Substring(1, nSecond - 1).Trim();
|
strApp = str.Substring(1, iSecond - 1).Trim();
|
||||||
strArgs = str.Remove(0, nSecond + 1).Trim();
|
strArgs = str.Remove(0, iSecond + 1).Trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strApp == null)
|
if(strApp == null)
|
||||||
{
|
{
|
||||||
int nSpace = str.IndexOf(' ');
|
int iSpace = str.IndexOf(' ');
|
||||||
|
if(iSpace >= 0)
|
||||||
if(nSpace >= 0)
|
|
||||||
{
|
{
|
||||||
strApp = str.Substring(0, nSpace);
|
strApp = str.Substring(0, iSpace).Trim();
|
||||||
strArgs = str.Remove(0, nSpace).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(strArgs == null) strArgs = string.Empty;
|
||||||
|
|
||||||
|
if(bDecodeAppToPath) strApp = NativeLib.DecodeArgsToPath(strApp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// /// <summary>
|
// /// <summary>
|
||||||
|
@@ -23,6 +23,7 @@ using System.Diagnostics;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
#if ModernKeePassLib
|
#if ModernKeePassLib
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
@@ -38,12 +39,8 @@ namespace ModernKeePassLib.Utility
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class UrlUtil
|
public static class UrlUtil
|
||||||
{
|
{
|
||||||
private static readonly char[] m_vDirSeps = new char[] {
|
private static readonly char[] g_vPathTrimCharsWs = new char[] {
|
||||||
'\\', '/', UrlUtil.LocalDirSepChar };
|
|
||||||
#if !ModernKeePassLib
|
|
||||||
private static readonly char[] m_vPathTrimCharsWs = new char[] {
|
|
||||||
'\"', ' ', '\t', '\r', '\n' };
|
'\"', ' ', '\t', '\r', '\n' };
|
||||||
#endif
|
|
||||||
|
|
||||||
public static char LocalDirSepChar
|
public static char LocalDirSepChar
|
||||||
{
|
{
|
||||||
@@ -57,6 +54,32 @@ namespace ModernKeePassLib.Utility
|
|||||||
#endif
|
#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>
|
/// <summary>
|
||||||
/// Get the directory (path) of a file name. The returned string may be
|
/// Get the directory (path) of a file name. The returned string may be
|
||||||
/// terminated by a directory separator character. Example:
|
/// terminated by a directory separator character. Example:
|
||||||
@@ -79,7 +102,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
Debug.Assert(strFile != null);
|
Debug.Assert(strFile != null);
|
||||||
if(strFile == null) throw new ArgumentNullException("strFile");
|
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(nLastSep < 0) return string.Empty; // No directory
|
||||||
|
|
||||||
if(bEnsureValidDirSpec && (nLastSep == 2) && (strFile[1] == ':') &&
|
if(bEnsureValidDirSpec && (nLastSep == 2) && (strFile[1] == ':') &&
|
||||||
@@ -103,7 +126,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
{
|
{
|
||||||
Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath");
|
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 < 0) return strPath;
|
||||||
if(nLastSep >= (strPath.Length - 1)) return string.Empty;
|
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");
|
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('.');
|
int nLastExtDot = strPath.LastIndexOf('.');
|
||||||
|
|
||||||
if(nLastExtDot <= nLastDirSep) return strPath;
|
if(nLastExtDot <= nLastDirSep) return strPath;
|
||||||
@@ -137,7 +160,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
{
|
{
|
||||||
Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath");
|
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('.');
|
int nLastExtDot = strPath.LastIndexOf('.');
|
||||||
|
|
||||||
if(nLastExtDot <= nLastDirSep) return string.Empty;
|
if(nLastExtDot <= nLastDirSep) return string.Empty;
|
||||||
@@ -162,11 +185,8 @@ namespace ModernKeePassLib.Utility
|
|||||||
if(nLength <= 0) return string.Empty;
|
if(nLength <= 0) return string.Empty;
|
||||||
|
|
||||||
char chLast = strPath[nLength - 1];
|
char chLast = strPath[nLength - 1];
|
||||||
|
if(Array.IndexOf<char>(UrlUtil.DirSepChars, chLast) >= 0)
|
||||||
for(int i = 0; i < m_vDirSeps.Length; ++i)
|
return strPath;
|
||||||
{
|
|
||||||
if(chLast == m_vDirSeps[i]) return strPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(bUrl) return (strPath + '/');
|
if(bUrl) return (strPath + '/');
|
||||||
return (strPath + UrlUtil.LocalDirSepChar);
|
return (strPath + UrlUtil.LocalDirSepChar);
|
||||||
@@ -230,21 +250,35 @@ namespace ModernKeePassLib.Utility
|
|||||||
return false;
|
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)
|
public static string GetQuotedAppPath(string strPath)
|
||||||
{
|
{
|
||||||
if(strPath == null) { Debug.Assert(false); return string.Empty; }
|
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();
|
string str = strPath.Trim();
|
||||||
if(str.Length <= 1) return str;
|
if(str.Length <= 1) return str;
|
||||||
if(str[0] != '\"') return str;
|
if(str[0] != '\"') return str;
|
||||||
|
|
||||||
int iSecond = str.IndexOf('\"', 1);
|
int iSecond = IndexOfSecondEnclQuote(str);
|
||||||
if(iSecond <= 0) return str;
|
if(iSecond <= 0) return str;
|
||||||
|
|
||||||
return str.Substring(1, iSecond - 1);
|
return str.Substring(1, iSecond - 1);
|
||||||
@@ -256,7 +290,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
if(strUrl == null) throw new ArgumentNullException("strUrl");
|
if(strUrl == null) throw new ArgumentNullException("strUrl");
|
||||||
|
|
||||||
string str = 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.Substring(8, str.Length - 8);
|
||||||
|
|
||||||
str = str.Replace('/', UrlUtil.LocalDirSepChar);
|
str = str.Replace('/', UrlUtil.LocalDirSepChar);
|
||||||
@@ -338,8 +372,8 @@ namespace ModernKeePassLib.Utility
|
|||||||
|
|
||||||
string strBase = GetShortestAbsolutePath(strBaseFile);
|
string strBase = GetShortestAbsolutePath(strBaseFile);
|
||||||
string strTarget = GetShortestAbsolutePath(strTargetFile);
|
string strTarget = GetShortestAbsolutePath(strTargetFile);
|
||||||
string[] vBase = strBase.Split(m_vDirSeps);
|
string[] vBase = strBase.Split(UrlUtil.DirSepChars);
|
||||||
string[] vTarget = strTarget.Split(m_vDirSeps);
|
string[] vTarget = strTarget.Split(UrlUtil.DirSepChars);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while((i < (vBase.Length - 1)) && (i < (vTarget.Length - 1)) &&
|
while((i < (vBase.Length - 1)) && (i < (vTarget.Length - 1)) &&
|
||||||
@@ -416,13 +450,14 @@ namespace ModernKeePassLib.Utility
|
|||||||
if(IsUncPath(strPath))
|
if(IsUncPath(strPath))
|
||||||
{
|
{
|
||||||
char chSep = strPath[0];
|
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>();
|
List<string> l = new List<string>();
|
||||||
#if !KeePassLibSD
|
#if !KeePassLibSD
|
||||||
string[] v = strPath.Split(m_vDirSeps, StringSplitOptions.None);
|
string[] v = strPath.Split(vSep, StringSplitOptions.None);
|
||||||
#else
|
#else
|
||||||
string[] v = strPath.Split(m_vDirSeps);
|
string[] v = strPath.Split(vSep);
|
||||||
#endif
|
#endif
|
||||||
Debug.Assert((v.Length >= 3) && (v[0].Length == 0) &&
|
Debug.Assert((v.Length >= 3) && (v[0].Length == 0) &&
|
||||||
(v[1].Length == 0));
|
(v[1].Length == 0));
|
||||||
@@ -463,8 +498,8 @@ namespace ModernKeePassLib.Utility
|
|||||||
}
|
}
|
||||||
catch(Exception) { Debug.Assert(false); return strPath; }
|
catch(Exception) { Debug.Assert(false); return strPath; }
|
||||||
|
|
||||||
Debug.Assert(str.IndexOf("\\..\\") < 0);
|
Debug.Assert((str.IndexOf("\\..\\") < 0) || NativeLib.IsUnix());
|
||||||
foreach(char ch in m_vDirSeps)
|
foreach(char ch in UrlUtil.DirSepChars)
|
||||||
{
|
{
|
||||||
string strSep = new string(ch, 1);
|
string strSep = new string(ch, 1);
|
||||||
str = str.Replace(strSep + "." + strSep, strSep);
|
str = str.Replace(strSep + "." + strSep, strSep);
|
||||||
@@ -494,24 +529,30 @@ namespace ModernKeePassLib.Utility
|
|||||||
return nLength;
|
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)
|
public static string RemoveScheme(string strUrl)
|
||||||
{
|
{
|
||||||
if(string.IsNullOrEmpty(strUrl)) return string.Empty;
|
if(string.IsNullOrEmpty(strUrl)) return string.Empty;
|
||||||
|
|
||||||
int nNetScheme = strUrl.IndexOf(@"://", StrUtil.CaseIgnoreCmp);
|
int i = strUrl.IndexOf(':');
|
||||||
int nShScheme = strUrl.IndexOf(@":/", StrUtil.CaseIgnoreCmp);
|
if(i < 0) return strUrl; // No scheme to remove
|
||||||
int nSmpScheme = strUrl.IndexOf(@":", StrUtil.CaseIgnoreCmp);
|
++i;
|
||||||
|
|
||||||
if((nNetScheme < 0) && (nShScheme < 0) && (nSmpScheme < 0))
|
// A single '/' indicates a path (absolute) and should not be removed
|
||||||
return strUrl; // No scheme
|
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,
|
return strUrl.Substring(i);
|
||||||
(nShScheme >= 0) ? nShScheme : int.MaxValue),
|
|
||||||
(nSmpScheme >= 0) ? nSmpScheme : int.MaxValue);
|
|
||||||
|
|
||||||
if(nMin == nNetScheme) return strUrl.Substring(nMin + 3);
|
|
||||||
if(nMin == nShScheme) return strUrl.Substring(nMin + 2);
|
|
||||||
return strUrl.Substring(nMin + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ConvertSeparators(string strPath)
|
public static string ConvertSeparators(string strPath)
|
||||||
@@ -538,22 +579,50 @@ namespace ModernKeePassLib.Utility
|
|||||||
|
|
||||||
public static string FilterFileName(string strName)
|
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('/', '-');
|
StringBuilder sb = new StringBuilder(strName.Length);
|
||||||
str = str.Replace('\\', '-');
|
foreach(char ch in strName)
|
||||||
str = str.Replace(":", string.Empty);
|
{
|
||||||
str = str.Replace("*", string.Empty);
|
if(ch < '\u0020') continue;
|
||||||
str = str.Replace("?", string.Empty);
|
|
||||||
str = str.Replace("\"", string.Empty);
|
|
||||||
str = str.Replace(@"'", string.Empty);
|
|
||||||
str = str.Replace('<', '(');
|
|
||||||
str = str.Replace('>', ')');
|
|
||||||
str = str.Replace('|', '-');
|
|
||||||
|
|
||||||
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>
|
/// <summary>
|
||||||
@@ -672,7 +741,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
foreach(string strPathRaw in v)
|
foreach(string strPathRaw in v)
|
||||||
{
|
{
|
||||||
if(strPathRaw == null) { Debug.Assert(false); continue; }
|
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; }
|
if(strPath.Length == 0) { Debug.Assert(false); continue; }
|
||||||
Debug.Assert(strPath == strPathRaw);
|
Debug.Assert(strPath == strPathRaw);
|
||||||
|
|
||||||
@@ -709,7 +778,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
if(fi == null) { Debug.Assert(false); continue; }
|
if(fi == null) { Debug.Assert(false); continue; }
|
||||||
string strPathRaw = fi.FullName;
|
string strPathRaw = fi.FullName;
|
||||||
if(strPathRaw == null) { Debug.Assert(false); continue; }
|
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; }
|
if(strPath.Length == 0) { Debug.Assert(false); continue; }
|
||||||
Debug.Assert(strPath == strPathRaw);
|
Debug.Assert(strPath == strPathRaw);
|
||||||
|
|
||||||
@@ -783,5 +852,19 @@ namespace ModernKeePassLib.Utility
|
|||||||
char ch = char.ToUpperInvariant(strPath[0]);
|
char ch = char.ToUpperInvariant(strPath[0]);
|
||||||
return (((ch >= 'A') && (ch <= 'Z')) ? ch : '\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.IgnoreProcessingInstructions = true;
|
||||||
xrs.IgnoreWhitespace = true;
|
xrs.IgnoreWhitespace = true;
|
||||||
|
|
||||||
#if KeePassUAP
|
#if KeePassUAP || ModernKeePassLib
|
||||||
xrs.DtdProcessing = DtdProcessing.Prohibit;
|
xrs.DtdProcessing = DtdProcessing.Prohibit;
|
||||||
#else
|
#else
|
||||||
// Also see PrepMonoDev.sh script
|
// Also see PrepMonoDev.sh script
|
||||||
|