mirror of
https://github.com/wismna/ModernKeePass.git
synced 2025-10-03 23:50:18 -04:00
WIP Lib version 2.39.1
This commit is contained in:
52
ModernKeePass.Shared/ModernKeePass.Shared.csproj
Normal file
52
ModernKeePass.Shared/ModernKeePass.Shared.csproj
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.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>
|
||||||
|
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{A3354969-5AAC-4075-8CBF-EA4805B59EFA}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>ModernKeePass.Shared</RootNamespace>
|
||||||
|
<AssemblyName>ModernKeePass.Shared</AssemblyName>
|
||||||
|
<DefaultLanguage>en-US</DefaultLanguage>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<TargetFrameworkProfile>
|
||||||
|
</TargetFrameworkProfile>
|
||||||
|
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<!-- A reference to the entire .NET Framework is automatically included -->
|
||||||
|
<None Include="project.json" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.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>
|
30
ModernKeePass.Shared/Properties/AssemblyInfo.cs
Normal file
30
ModernKeePass.Shared/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using System.Resources;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("ModernKeePass.Shared")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("ModernKeePass.Shared")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
[assembly: NeutralResourcesLanguage("en")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
10
ModernKeePass.Shared/project.json
Normal file
10
ModernKeePass.Shared/project.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"supports": {},
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.NETCore.Portable.Compatibility": "1.0.1",
|
||||||
|
"NETStandard.Library": "1.6.0"
|
||||||
|
},
|
||||||
|
"frameworks": {
|
||||||
|
"netstandard1.2": {}
|
||||||
|
}
|
||||||
|
}
|
@@ -9,8 +9,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePass.Lib", "Modern
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePass.LibTest", "ModernKeePassLib.Test\ModernKeePass.LibTest.csproj", "{0A4279CF-2A67-4868-9906-052E50C25F3B}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePass.LibTest", "ModernKeePassLib.Test\ModernKeePass.LibTest.csproj", "{0A4279CF-2A67-4868-9906-052E50C25F3B}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{F5034706-568F-408A-B7B3-4D38C6DB8A32}") = "Scripts", "Scripts\Scripts.pssproj", "{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePass.AppTest", "ModernKeePassApp.Test\ModernKeePass.AppTest.csproj", "{7E80F5E7-724A-4668-9333-B10F5D75C6D0}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernKeePass.AppTest", "ModernKeePassApp.Test\ModernKeePass.AppTest.csproj", "{7E80F5E7-724A-4668-9333-B10F5D75C6D0}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
@@ -89,22 +87,6 @@ Global
|
|||||||
{0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x86.ActiveCfg = Release|x86
|
{0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x86.ActiveCfg = Release|x86
|
||||||
{0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x86.Build.0 = Release|x86
|
{0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x86.Build.0 = Release|x86
|
||||||
{0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x86.Deploy.0 = Release|x86
|
{0A4279CF-2A67-4868-9906-052E50C25F3B}.Release|x86.Deploy.0 = Release|x86
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|ARM.Build.0 = Debug|Any CPU
|
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|ARM.ActiveCfg = Release|Any CPU
|
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|ARM.Build.0 = Release|Any CPU
|
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
{7E80F5E7-724A-4668-9333-B10F5D75C6D0}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||||
|
@@ -1,14 +0,0 @@
|
|||||||
using System;
|
|
||||||
using ModernKeePass.Services;
|
|
||||||
|
|
||||||
namespace ModernKeePass.Attributes
|
|
||||||
{
|
|
||||||
[AttributeUsage(AttributeTargets.All)]
|
|
||||||
public class DatabaseChangedAttribute: Attribute
|
|
||||||
{
|
|
||||||
public DatabaseChangedAttribute()
|
|
||||||
{
|
|
||||||
DatabaseService.Instance.HasChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,26 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using ModernKeePass.Interfaces;
|
|
||||||
|
|
||||||
namespace ModernKeePass.Aop
|
|
||||||
{
|
|
||||||
public class DatabaseChangedProxy<T>: IProxyInvocationHandler
|
|
||||||
{
|
|
||||||
private readonly T _decorated;
|
|
||||||
private readonly IDatabaseService _databaseService;
|
|
||||||
|
|
||||||
public DatabaseChangedProxy(T decorated, IDatabaseService databaseService)
|
|
||||||
{
|
|
||||||
_decorated = decorated;
|
|
||||||
_databaseService = databaseService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object Invoke(object proxy, MethodInfo method, object[] parameters)
|
|
||||||
{
|
|
||||||
object retVal = null;
|
|
||||||
retVal = method.Invoke(proxy, parameters);
|
|
||||||
_databaseService.HasChanged = true;
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -111,11 +111,9 @@
|
|||||||
<Compile Include="Actions\ClipboardAction.cs" />
|
<Compile Include="Actions\ClipboardAction.cs" />
|
||||||
<Compile Include="Actions\NavigateToUrlAction.cs" />
|
<Compile Include="Actions\NavigateToUrlAction.cs" />
|
||||||
<Compile Include="Actions\SetupFocusAction.cs" />
|
<Compile Include="Actions\SetupFocusAction.cs" />
|
||||||
<Compile Include="Aop\DatabaseChangedProxy.cs" />
|
|
||||||
<Compile Include="App.xaml.cs">
|
<Compile Include="App.xaml.cs">
|
||||||
<DependentUpon>App.xaml</DependentUpon>
|
<DependentUpon>App.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Aop\DatabaseChanged.cs" />
|
|
||||||
<Compile Include="Exceptions\DatabaseOpenedException.cs" />
|
<Compile Include="Exceptions\DatabaseOpenedException.cs" />
|
||||||
<Compile Include="Interfaces\ILicenseService.cs" />
|
<Compile Include="Interfaces\ILicenseService.cs" />
|
||||||
<Compile Include="Interfaces\IProxyInvocationHandler.cs" />
|
<Compile Include="Interfaces\IProxyInvocationHandler.cs" />
|
||||||
|
@@ -136,7 +136,7 @@ namespace ModernKeePassLib.Collections
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ps.ReadString() != kvp.Value.ReadString()) return false;
|
if(!ps.Equals(kvp.Value, false)) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bNeEqStd)
|
if(bNeEqStd)
|
||||||
@@ -292,12 +292,7 @@ namespace ModernKeePassLib.Collections
|
|||||||
if(ps == null) return; // Nothing to do, no assert
|
if(ps == null) return; // Nothing to do, no assert
|
||||||
|
|
||||||
if(ps.IsProtected != bProtect)
|
if(ps.IsProtected != bProtect)
|
||||||
{
|
Set(strField, ps.WithProtection(bProtect));
|
||||||
byte[] pbData = ps.ReadUtf8();
|
|
||||||
Set(strField, new ProtectedString(bProtect, pbData));
|
|
||||||
|
|
||||||
if(bProtect) MemUtil.ZeroByteArray(pbData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -352,6 +352,13 @@ namespace ModernKeePassLib.Collections
|
|||||||
m_vObjects.Sort(tComparer);
|
m_vObjects.Sort(tComparer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Sort(Comparison<T> tComparison)
|
||||||
|
{
|
||||||
|
if(tComparison == null) throw new ArgumentNullException("tComparison");
|
||||||
|
|
||||||
|
m_vObjects.Sort(tComparison);
|
||||||
|
}
|
||||||
|
|
||||||
public static PwObjectList<T> FromArray(T[] tArray)
|
public static PwObjectList<T> FromArray(T[] tArray)
|
||||||
{
|
{
|
||||||
if(tArray == null) throw new ArgumentNullException("tArray");
|
if(tArray == null) throw new ArgumentNullException("tArray");
|
||||||
|
@@ -223,11 +223,10 @@ namespace ModernKeePassLib.Cryptography
|
|||||||
pb = DiagnosticsExt.GetProcessEntropy();
|
pb = DiagnosticsExt.GetProcessEntropy();
|
||||||
MemUtil.Write(ms, pb);
|
MemUtil.Write(ms, pb);
|
||||||
#elif !KeePassLibSD
|
#elif !KeePassLibSD
|
||||||
Process p = null;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
p = Process.GetCurrentProcess();
|
using(Process p = Process.GetCurrentProcess())
|
||||||
|
{
|
||||||
pb = MemUtil.Int64ToBytes(p.Handle.ToInt64());
|
pb = MemUtil.Int64ToBytes(p.Handle.ToInt64());
|
||||||
MemUtil.Write(ms, pb);
|
MemUtil.Write(ms, pb);
|
||||||
pb = MemUtil.Int32ToBytes(p.HandleCount);
|
pb = MemUtil.Int32ToBytes(p.HandleCount);
|
||||||
@@ -259,12 +258,8 @@ namespace ModernKeePassLib.Cryptography
|
|||||||
// pb = MemUtil.UInt32ToBytes((uint)p.SessionId);
|
// pb = MemUtil.UInt32ToBytes((uint)p.SessionId);
|
||||||
// MemUtil.Write(ms, pb);
|
// MemUtil.Write(ms, pb);
|
||||||
}
|
}
|
||||||
catch(Exception) { Debug.Assert(NativeLib.IsUnix()); }
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
try { if(p != null) p.Dispose(); }
|
|
||||||
catch(Exception) { Debug.Assert(false); }
|
|
||||||
}
|
}
|
||||||
|
catch(Exception) { Debug.Assert(NativeLib.IsUnix()); }
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -35,6 +35,42 @@ namespace ModernKeePassLib.Cryptography
|
|||||||
{
|
{
|
||||||
public static class CryptoUtil
|
public static class CryptoUtil
|
||||||
{
|
{
|
||||||
|
private static bool? g_obProtData = null;
|
||||||
|
public static bool IsProtectedDataSupported
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(g_obProtData.HasValue) return g_obProtData.Value;
|
||||||
|
|
||||||
|
bool b = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Random r = CryptoRandom.NewWeakRandom();
|
||||||
|
|
||||||
|
byte[] pbData = new byte[137];
|
||||||
|
r.NextBytes(pbData);
|
||||||
|
|
||||||
|
byte[] pbEnt = new byte[41];
|
||||||
|
r.NextBytes(pbEnt);
|
||||||
|
|
||||||
|
byte[] pbEnc = ProtectedData.Protect(pbData, pbEnt,
|
||||||
|
DataProtectionScope.CurrentUser);
|
||||||
|
if((pbEnc != null) && !MemUtil.ArraysEqual(pbEnc, pbData))
|
||||||
|
{
|
||||||
|
byte[] pbDec = ProtectedData.Unprotect(pbEnc, pbEnt,
|
||||||
|
DataProtectionScope.CurrentUser);
|
||||||
|
if((pbDec != null) && MemUtil.ArraysEqual(pbDec, pbData))
|
||||||
|
b = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception) { Debug.Assert(false); }
|
||||||
|
|
||||||
|
Debug.Assert(b); // Should be supported on all systems
|
||||||
|
g_obProtData = b;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static byte[] HashSha256(byte[] pbData)
|
public static byte[] HashSha256(byte[] pbData)
|
||||||
{
|
{
|
||||||
if(pbData == null) throw new ArgumentNullException("pbData");
|
if(pbData == null) throw new ArgumentNullException("pbData");
|
||||||
@@ -165,5 +201,37 @@ namespace ModernKeePassLib.Cryptography
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
public static byte[] ProtectData(byte[] pb, byte[] pbOptEntropy,
|
||||||
|
DataProtectionScope s)
|
||||||
|
{
|
||||||
|
return ProtectDataPriv(pb, true, pbOptEntropy, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] UnprotectData(byte[] pb, byte[] pbOptEntropy,
|
||||||
|
DataProtectionScope s)
|
||||||
|
{
|
||||||
|
return ProtectDataPriv(pb, false, pbOptEntropy, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] ProtectDataPriv(byte[] pb, bool bProtect,
|
||||||
|
byte[] pbOptEntropy, DataProtectionScope s)
|
||||||
|
{
|
||||||
|
if(pb == null) throw new ArgumentNullException("pb");
|
||||||
|
|
||||||
|
if((pbOptEntropy != null) && (pbOptEntropy.Length == 0))
|
||||||
|
pbOptEntropy = null;
|
||||||
|
|
||||||
|
if(CryptoUtil.IsProtectedDataSupported)
|
||||||
|
{
|
||||||
|
if(bProtect)
|
||||||
|
return ProtectedData.Protect(pb, pbOptEntropy, s);
|
||||||
|
return ProtectedData.Unprotect(pb, pbOptEntropy, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Assert(false);
|
||||||
|
byte[] pbCopy = new byte[pb.Length];
|
||||||
|
Array.Copy(pb, pbCopy, pb.Length);
|
||||||
|
return pbCopy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -71,9 +71,6 @@ namespace ModernKeePassLib.Cryptography.KeyDerivation
|
|||||||
|
|
||||||
private static bool GCryptInitLib()
|
private static bool GCryptInitLib()
|
||||||
{
|
{
|
||||||
Debug.Assert(Marshal.SizeOf(typeof(int)) == 4); // Also on 64-bit systems
|
|
||||||
Debug.Assert(Marshal.SizeOf(typeof(uint)) == 4);
|
|
||||||
|
|
||||||
if(!NativeLib.IsUnix()) return false; // Independent of workaround state
|
if(!NativeLib.IsUnix()) return false; // Independent of workaround state
|
||||||
if(!MonoWorkarounds.IsRequired(1468)) return false; // Can be turned off
|
if(!MonoWorkarounds.IsRequired(1468)) return false; // Can be turned off
|
||||||
|
|
||||||
|
@@ -239,8 +239,7 @@ namespace ModernKeePassLib.Cryptography.PasswordGenerator
|
|||||||
PwProfile pp = new PwProfile();
|
PwProfile pp = new PwProfile();
|
||||||
Debug.Assert(psPassword != null); if(psPassword == null) return pp;
|
Debug.Assert(psPassword != null); if(psPassword == null) return pp;
|
||||||
|
|
||||||
byte[] pbUtf8 = psPassword.ReadUtf8();
|
char[] vChars = psPassword.ReadChars();
|
||||||
char[] vChars = StrUtil.Utf8.GetChars(pbUtf8);
|
|
||||||
|
|
||||||
pp.GeneratorType = PasswordGeneratorType.CharSet;
|
pp.GeneratorType = PasswordGeneratorType.CharSet;
|
||||||
pp.Length = (uint)vChars.Length;
|
pp.Length = (uint)vChars.Length;
|
||||||
@@ -266,7 +265,6 @@ namespace ModernKeePassLib.Cryptography.PasswordGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
MemUtil.ZeroArray<char>(vChars);
|
MemUtil.ZeroArray<char>(vChars);
|
||||||
MemUtil.ZeroByteArray(pbUtf8);
|
|
||||||
return pp;
|
return pp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -420,11 +420,12 @@ namespace ModernKeePassLib.Cryptography
|
|||||||
{
|
{
|
||||||
if(pbUnprotectedUtf8 == null) { Debug.Assert(false); return 0; }
|
if(pbUnprotectedUtf8 == null) { Debug.Assert(false); return 0; }
|
||||||
|
|
||||||
char[] vChars = StrUtil.Utf8.GetChars(pbUnprotectedUtf8);
|
char[] v = StrUtil.Utf8.GetChars(pbUnprotectedUtf8);
|
||||||
uint uResult = EstimatePasswordBits(vChars);
|
uint r;
|
||||||
MemUtil.ZeroArray<char>(vChars);
|
try { r = EstimatePasswordBits(v); }
|
||||||
|
finally { MemUtil.ZeroArray<char>(v); }
|
||||||
|
|
||||||
return uResult;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static QeCharType GetCharType(char ch)
|
private static QeCharType GetCharType(char ch)
|
||||||
|
@@ -22,6 +22,7 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Security;
|
using System.Security;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
@@ -55,6 +56,25 @@ namespace ModernKeePassLib.Cryptography
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static void Perform()
|
public static void Perform()
|
||||||
{
|
{
|
||||||
|
#if KeePassUAP
|
||||||
|
Debug.Assert(Marshal.SizeOf<int>() == 4);
|
||||||
|
Debug.Assert(Marshal.SizeOf<uint>() == 4);
|
||||||
|
Debug.Assert(Marshal.SizeOf<long>() == 8);
|
||||||
|
Debug.Assert(Marshal.SizeOf<ulong>() == 8);
|
||||||
|
Debug.Assert(Marshal.SizeOf<IntPtr>() == IntPtr.Size);
|
||||||
|
#else
|
||||||
|
Debug.Assert(Marshal.SizeOf(typeof(int)) == 4);
|
||||||
|
Debug.Assert(Marshal.SizeOf(typeof(uint)) == 4);
|
||||||
|
Debug.Assert(Marshal.SizeOf(typeof(long)) == 8);
|
||||||
|
Debug.Assert(Marshal.SizeOf(typeof(ulong)) == 8);
|
||||||
|
Debug.Assert(Marshal.SizeOf(typeof(IntPtr)) == IntPtr.Size);
|
||||||
|
#endif
|
||||||
|
Debug.Assert((IntPtr.Size == 4) || (IntPtr.Size == 8));
|
||||||
|
|
||||||
|
Debug.Assert((int)PwIcon.World == 1);
|
||||||
|
Debug.Assert((int)PwIcon.Warning == 2);
|
||||||
|
Debug.Assert((int)PwIcon.BlackBerry == 68);
|
||||||
|
|
||||||
Random r = CryptoRandom.NewWeakRandom();
|
Random r = CryptoRandom.NewWeakRandom();
|
||||||
|
|
||||||
TestFipsComplianceProblems(); // Must be the first test
|
TestFipsComplianceProblems(); // Must be the first test
|
||||||
@@ -76,10 +96,6 @@ namespace ModernKeePassLib.Cryptography
|
|||||||
TestStrUtil();
|
TestStrUtil();
|
||||||
TestUrlUtil();
|
TestUrlUtil();
|
||||||
|
|
||||||
Debug.Assert((int)PwIcon.World == 1);
|
|
||||||
Debug.Assert((int)PwIcon.Warning == 2);
|
|
||||||
Debug.Assert((int)PwIcon.BlackBerry == 68);
|
|
||||||
|
|
||||||
#if KeePassUAP
|
#if KeePassUAP
|
||||||
SelfTestEx.Perform();
|
SelfTestEx.Perform();
|
||||||
#endif
|
#endif
|
||||||
@@ -944,6 +960,14 @@ namespace ModernKeePassLib.Cryptography
|
|||||||
if(ps.ReadString() != str)
|
if(ps.ReadString() != str)
|
||||||
throw new SecurityException("ProtectedString-14");
|
throw new SecurityException("ProtectedString-14");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ps = new ProtectedString(false, "ABCD");
|
||||||
|
ps2 = new ProtectedString(true, "EFG");
|
||||||
|
ps += (ps2 + "HI");
|
||||||
|
if(!ps.Equals(new ProtectedString(true, "ABCDEFGHI"), true))
|
||||||
|
throw new SecurityException("ProtectedString-15");
|
||||||
|
if(!ps.Equals(new ProtectedString(false, "ABCDEFGHI"), false))
|
||||||
|
throw new SecurityException("ProtectedString-16");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1041,6 +1065,30 @@ namespace ModernKeePassLib.Cryptography
|
|||||||
throw new InvalidOperationException("StrUtil-Case1");
|
throw new InvalidOperationException("StrUtil-Case1");
|
||||||
if(string.Equals(@"a<b", @"a>b", StrUtil.CaseIgnoreCmp))
|
if(string.Equals(@"a<b", @"a>b", StrUtil.CaseIgnoreCmp))
|
||||||
throw new InvalidOperationException("StrUtil-Case2");
|
throw new InvalidOperationException("StrUtil-Case2");
|
||||||
|
|
||||||
|
const string strNL = "\n01\r23\n45\r\n67\r";
|
||||||
|
string strW = StrUtil.NormalizeNewLines(strNL, true);
|
||||||
|
string strL = StrUtil.NormalizeNewLines(strNL, false);
|
||||||
|
if(strW != "\r\n01\r\n23\r\n45\r\n67\r\n")
|
||||||
|
throw new InvalidOperationException("StrUtil-NewLine1");
|
||||||
|
if(strL != "\n01\n23\n45\n67\n")
|
||||||
|
throw new InvalidOperationException("StrUtil-NewLine2");
|
||||||
|
if(StrUtil.IsNewLineNormalized(strNL.ToCharArray(), true))
|
||||||
|
throw new InvalidOperationException("StrUtil-NewLine3");
|
||||||
|
if(StrUtil.IsNewLineNormalized(strNL.ToCharArray(), false))
|
||||||
|
throw new InvalidOperationException("StrUtil-NewLine4");
|
||||||
|
if(!StrUtil.IsNewLineNormalized(strW.ToCharArray(), true))
|
||||||
|
throw new InvalidOperationException("StrUtil-NewLine5");
|
||||||
|
if(StrUtil.IsNewLineNormalized(strW.ToCharArray(), false))
|
||||||
|
throw new InvalidOperationException("StrUtil-NewLine6");
|
||||||
|
if(StrUtil.IsNewLineNormalized(strL.ToCharArray(), true))
|
||||||
|
throw new InvalidOperationException("StrUtil-NewLine7");
|
||||||
|
if(!StrUtil.IsNewLineNormalized(strL.ToCharArray(), false))
|
||||||
|
throw new InvalidOperationException("StrUtil-NewLine8");
|
||||||
|
if(!StrUtil.IsNewLineNormalized(string.Empty.ToCharArray(), true))
|
||||||
|
throw new InvalidOperationException("StrUtil-NewLine9");
|
||||||
|
if(!StrUtil.IsNewLineNormalized(string.Empty.ToCharArray(), false))
|
||||||
|
throw new InvalidOperationException("StrUtil-NewLine10");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -275,7 +275,7 @@ namespace ModernKeePassLib.Keys
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
XmlDocument doc = new XmlDocument();
|
XmlDocument doc = XmlUtilEx.CreateXmlDocument();
|
||||||
doc.Load(ms);
|
doc.Load(ms);
|
||||||
|
|
||||||
XmlElement el = doc.DocumentElement;
|
XmlElement el = doc.DocumentElement;
|
||||||
@@ -320,49 +320,31 @@ namespace ModernKeePassLib.Keys
|
|||||||
#else
|
#else
|
||||||
IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile);
|
IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile);
|
||||||
#endif
|
#endif
|
||||||
Stream sOut = IOConnection.OpenWrite(ioc);
|
using(Stream s = IOConnection.OpenWrite(ioc))
|
||||||
|
{
|
||||||
|
using(XmlWriter xw = XmlUtilEx.CreateXmlWriter(s))
|
||||||
|
{
|
||||||
|
xw.WriteStartDocument();
|
||||||
|
xw.WriteStartElement(RootElementName); // <KeyFile>
|
||||||
|
|
||||||
#if ModernKeePassLib || KeePassUAP
|
xw.WriteStartElement(MetaElementName); // <Meta>
|
||||||
XmlWriterSettings xws = new XmlWriterSettings();
|
xw.WriteStartElement(VersionElementName); // <Version>
|
||||||
xws.Encoding = StrUtil.Utf8;
|
xw.WriteString("1.00");
|
||||||
xws.Indent = false;
|
xw.WriteEndElement(); // </Version>
|
||||||
|
xw.WriteEndElement(); // </Meta>
|
||||||
|
|
||||||
XmlWriter xtw = XmlWriter.Create(sOut, xws);
|
xw.WriteStartElement(KeyElementName); // <Key>
|
||||||
#else
|
|
||||||
XmlTextWriter xtw = new XmlTextWriter(sOut, StrUtil.Utf8);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
xtw.WriteStartDocument();
|
xw.WriteStartElement(KeyDataElementName); // <Data>
|
||||||
xtw.WriteWhitespace("\r\n");
|
xw.WriteString(Convert.ToBase64String(pbKeyData));
|
||||||
xtw.WriteStartElement(RootElementName); // KeyFile
|
xw.WriteEndElement(); // </Data>
|
||||||
xtw.WriteWhitespace("\r\n\t");
|
|
||||||
|
|
||||||
xtw.WriteStartElement(MetaElementName); // Meta
|
xw.WriteEndElement(); // </Key>
|
||||||
xtw.WriteWhitespace("\r\n\t\t");
|
|
||||||
xtw.WriteStartElement(VersionElementName); // Version
|
|
||||||
xtw.WriteString("1.00");
|
|
||||||
xtw.WriteEndElement(); // End Version
|
|
||||||
xtw.WriteWhitespace("\r\n\t");
|
|
||||||
xtw.WriteEndElement(); // End Meta
|
|
||||||
xtw.WriteWhitespace("\r\n\t");
|
|
||||||
|
|
||||||
xtw.WriteStartElement(KeyElementName); // Key
|
xw.WriteEndElement(); // </KeyFile>
|
||||||
xtw.WriteWhitespace("\r\n\t\t");
|
xw.WriteEndDocument();
|
||||||
|
}
|
||||||
xtw.WriteStartElement(KeyDataElementName); // Data
|
}
|
||||||
xtw.WriteString(Convert.ToBase64String(pbKeyData));
|
|
||||||
xtw.WriteEndElement(); // End Data
|
|
||||||
xtw.WriteWhitespace("\r\n\t");
|
|
||||||
|
|
||||||
xtw.WriteEndElement(); // End Key
|
|
||||||
xtw.WriteWhitespace("\r\n");
|
|
||||||
|
|
||||||
xtw.WriteEndElement(); // RootElementName
|
|
||||||
xtw.WriteWhitespace("\r\n");
|
|
||||||
xtw.WriteEndDocument(); // End KeyFile
|
|
||||||
xtw.Dispose();
|
|
||||||
|
|
||||||
sOut.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -65,11 +65,8 @@ namespace ModernKeePassLib.Keys
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public KcpUserAccount()
|
public KcpUserAccount()
|
||||||
{
|
{
|
||||||
// Test if ProtectedData is supported -- throws an exception
|
if(!CryptoUtil.IsProtectedDataSupported)
|
||||||
// when running on an old system (Windows 98 / ME).
|
throw new PlatformNotSupportedException(); // Windows 98/ME
|
||||||
byte[] pbDummyData = new byte[128];
|
|
||||||
ProtectedData.Protect(pbDummyData, m_pbEntropy,
|
|
||||||
DataProtectionScope.CurrentUser);
|
|
||||||
|
|
||||||
byte[] pbKey = LoadUserKey(false);
|
byte[] pbKey = LoadUserKey(false);
|
||||||
if(pbKey == null) pbKey = CreateUserKey();
|
if(pbKey == null) pbKey = CreateUserKey();
|
||||||
@@ -128,7 +125,7 @@ namespace ModernKeePassLib.Keys
|
|||||||
byte[] pbProtectedKey = File.ReadAllBytes(strFilePath);
|
byte[] pbProtectedKey = File.ReadAllBytes(strFilePath);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pbKey = ProtectedData.Unprotect(pbProtectedKey, m_pbEntropy,
|
pbKey = CryptoUtil.UnprotectData(pbProtectedKey, m_pbEntropy,
|
||||||
DataProtectionScope.CurrentUser);
|
DataProtectionScope.CurrentUser);
|
||||||
}
|
}
|
||||||
catch(Exception)
|
catch(Exception)
|
||||||
@@ -149,7 +146,7 @@ namespace ModernKeePassLib.Keys
|
|||||||
string strFilePath = GetUserKeyFilePath(true);
|
string strFilePath = GetUserKeyFilePath(true);
|
||||||
|
|
||||||
byte[] pbRandomKey = CryptoRandom.Instance.GetRandomBytes(64);
|
byte[] pbRandomKey = CryptoRandom.Instance.GetRandomBytes(64);
|
||||||
byte[] pbProtectedKey = ProtectedData.Protect(pbRandomKey,
|
byte[] pbProtectedKey = CryptoUtil.ProtectData(pbRandomKey,
|
||||||
m_pbEntropy, DataProtectionScope.CurrentUser);
|
m_pbEntropy, DataProtectionScope.CurrentUser);
|
||||||
#if ModernKeePassLib
|
#if ModernKeePassLib
|
||||||
var fileStream = StorageFile.GetFileFromPathAsync(strFilePath).GetAwaiter().GetResult().OpenStreamForWriteAsync().GetAwaiter().GetResult();
|
var fileStream = StorageFile.GetFileFromPathAsync(strFilePath).GetAwaiter().GetResult().OpenStreamForWriteAsync().GetAwaiter().GetResult();
|
||||||
|
@@ -130,6 +130,8 @@
|
|||||||
<Compile Include="Serialization\IOConnectionInfo.cs" />
|
<Compile Include="Serialization\IOConnectionInfo.cs" />
|
||||||
<Compile Include="Serialization\OldFormatException.cs" />
|
<Compile Include="Serialization\OldFormatException.cs" />
|
||||||
<Compile Include="Utility\AppLogEx.cs" />
|
<Compile Include="Utility\AppLogEx.cs" />
|
||||||
|
<Compile Include="Utility\TypeOverridePool.cs" />
|
||||||
|
<Compile Include="Utility\XmlUtilEx.cs" />
|
||||||
<None Include="Utility\GfxUtil.cs" />
|
<None Include="Utility\GfxUtil.cs" />
|
||||||
<Compile Include="Utility\GfxUtil.PCL.cs" />
|
<Compile Include="Utility\GfxUtil.PCL.cs" />
|
||||||
<Compile Include="Utility\MemUtil.cs" />
|
<Compile Include="Utility\MemUtil.cs" />
|
||||||
@@ -149,7 +151,7 @@
|
|||||||
<None Include="Libs\Windows.winmd" />
|
<None Include="Libs\Windows.winmd" />
|
||||||
<None Include="ModernKeePassLib.nuspec" />
|
<None Include="ModernKeePassLib.nuspec" />
|
||||||
<None Include="project.json" />
|
<None Include="project.json" />
|
||||||
<None Include="Utility\MessageService.cs" />
|
<Compile Include="Utility\MessageService.cs" />
|
||||||
<None Include="Native\NativeLib.cs" />
|
<None Include="Native\NativeLib.cs" />
|
||||||
<None Include="Native\NativeMethods.cs" />
|
<None Include="Native\NativeMethods.cs" />
|
||||||
<None Include="Native\NativeMethods.Unix.cs" />
|
<None Include="Native\NativeMethods.Unix.cs" />
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
<package >
|
<package >
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>ModernKeePassLib</id>
|
<id>ModernKeePassLib</id>
|
||||||
<version>2.38.2</version>
|
<version>2.39.1</version>
|
||||||
<title>ModernKeePassLib</title>
|
<title>ModernKeePassLib</title>
|
||||||
<authors>Geoffroy Bonneville</authors>
|
<authors>Geoffroy Bonneville</authors>
|
||||||
<owners>Geoffroy Bonneville</owners>
|
<owners>Geoffroy Bonneville</owners>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<projectUrl>https://github.com/wismna/ModernKeePass</projectUrl>
|
<projectUrl>https://github.com/wismna/ModernKeePass</projectUrl>
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<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>
|
||||||
<releaseNotes>Deactivation of buggy custom icon implementation</releaseNotes>
|
<releaseNotes>Implementation of KeePass library version 2.39.1</releaseNotes>
|
||||||
<copyright>Copyright © 2018 Geoffroy Bonneville</copyright>
|
<copyright>Copyright © 2018 Geoffroy Bonneville</copyright>
|
||||||
<tags>KeePass KeePassLib Portable PCL NetStandard</tags>
|
<tags>KeePass KeePassLib Portable PCL NetStandard</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
190
ModernKeePassLib/Native/ClipboardU.cs
Normal file
190
ModernKeePassLib/Native/ClipboardU.cs
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
KeePass Password Safe - The Open-Source Password Manager
|
||||||
|
Copyright (C) 2003-2018 Dominik Reichl <dominik.reichl@t-online.de>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ModernKeePassLib.Native
|
||||||
|
{
|
||||||
|
internal static class ClipboardU
|
||||||
|
{
|
||||||
|
private const string XSel = "xsel";
|
||||||
|
private const string XSelV = "--version";
|
||||||
|
private const string XSelR = "--output --clipboard";
|
||||||
|
private const string XSelC = "--clear --clipboard";
|
||||||
|
private const string XSelW = "--input --clipboard";
|
||||||
|
private const string XSelND = " --nodetach";
|
||||||
|
private const AppRunFlags XSelWF = AppRunFlags.WaitForExit;
|
||||||
|
|
||||||
|
private static bool? g_obXSel = null;
|
||||||
|
|
||||||
|
public static string GetText()
|
||||||
|
{
|
||||||
|
// System.Windows.Forms.Clipboard doesn't work properly,
|
||||||
|
// see Mono workaround 1530
|
||||||
|
|
||||||
|
// string str = GtkGetText();
|
||||||
|
// if(str != null) return str;
|
||||||
|
|
||||||
|
return XSelGetText();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool SetText(string strText, bool bMayBlock)
|
||||||
|
{
|
||||||
|
string str = (strText ?? string.Empty);
|
||||||
|
|
||||||
|
// System.Windows.Forms.Clipboard doesn't work properly,
|
||||||
|
// see Mono workaround 1530
|
||||||
|
|
||||||
|
// if(GtkSetText(str)) return true;
|
||||||
|
|
||||||
|
return XSelSetText(str, bMayBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================
|
||||||
|
// LibGTK
|
||||||
|
|
||||||
|
// Even though GTK+ 3 appears to be loaded already, performing a
|
||||||
|
// P/Invoke of LibGTK's gtk_init_check function terminates the
|
||||||
|
// process (!) with the following error message:
|
||||||
|
// "Gtk-ERROR **: GTK+ 2.x symbols detected. Using GTK+ 2.x and
|
||||||
|
// GTK+ 3 in the same process is not supported".
|
||||||
|
|
||||||
|
/* private static bool GtkInit()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// GTK requires GLib;
|
||||||
|
// the following throws if and only if GLib is unavailable
|
||||||
|
NativeMethods.g_free(IntPtr.Zero);
|
||||||
|
|
||||||
|
if(NativeMethods.gtk_init_check(IntPtr.Zero, IntPtr.Zero) !=
|
||||||
|
NativeMethods.G_FALSE)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Debug.Assert(false);
|
||||||
|
}
|
||||||
|
catch(Exception) { Debug.Assert(false); }
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GtkGetText()
|
||||||
|
{
|
||||||
|
IntPtr lpText = IntPtr.Zero;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(GtkInit())
|
||||||
|
{
|
||||||
|
IntPtr h = NativeMethods.gtk_clipboard_get(
|
||||||
|
NativeMethods.GDK_SELECTION_CLIPBOARD);
|
||||||
|
if(h != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
lpText = NativeMethods.gtk_clipboard_wait_for_text(h);
|
||||||
|
if(lpText != IntPtr.Zero)
|
||||||
|
return NativeMethods.Utf8ZToString(lpText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception) { Debug.Assert(false); }
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try { NativeMethods.g_free(lpText); }
|
||||||
|
catch(Exception) { Debug.Assert(false); }
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool GtkSetText(string str)
|
||||||
|
{
|
||||||
|
IntPtr lpText = IntPtr.Zero;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(GtkInit())
|
||||||
|
{
|
||||||
|
lpText = NativeMethods.Utf8ZFromString(str ?? string.Empty);
|
||||||
|
if(lpText == IntPtr.Zero) { Debug.Assert(false); return false; }
|
||||||
|
|
||||||
|
bool b = false;
|
||||||
|
for(int i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
IntPtr h = NativeMethods.gtk_clipboard_get((i == 0) ?
|
||||||
|
NativeMethods.GDK_SELECTION_PRIMARY :
|
||||||
|
NativeMethods.GDK_SELECTION_CLIPBOARD);
|
||||||
|
if(h != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
NativeMethods.gtk_clipboard_clear(h);
|
||||||
|
NativeMethods.gtk_clipboard_set_text(h, lpText, -1);
|
||||||
|
NativeMethods.gtk_clipboard_store(h);
|
||||||
|
b = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception) { Debug.Assert(false); }
|
||||||
|
finally { NativeMethods.Utf8ZFree(lpText); }
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} */
|
||||||
|
|
||||||
|
// =============================================================
|
||||||
|
// XSel
|
||||||
|
|
||||||
|
private static bool XSelInit()
|
||||||
|
{
|
||||||
|
if(g_obXSel.HasValue) return g_obXSel.Value;
|
||||||
|
|
||||||
|
string strTest = NativeLib.RunConsoleApp(XSel, XSelV);
|
||||||
|
|
||||||
|
bool b = (strTest != null);
|
||||||
|
g_obXSel = b;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string XSelGetText()
|
||||||
|
{
|
||||||
|
if(!XSelInit()) return null;
|
||||||
|
|
||||||
|
return NativeLib.RunConsoleApp(XSel, XSelR);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool XSelSetText(string str, bool bMayBlock)
|
||||||
|
{
|
||||||
|
if(!XSelInit()) return false;
|
||||||
|
|
||||||
|
string strOpt = (bMayBlock ? XSelND : string.Empty);
|
||||||
|
|
||||||
|
// xsel with an empty input can hang, thus use --clear
|
||||||
|
if(str.Length == 0)
|
||||||
|
return (NativeLib.RunConsoleApp(XSel, XSelC + strOpt,
|
||||||
|
null, XSelWF) != null);
|
||||||
|
|
||||||
|
// Use --nodetach to prevent clipboard corruption;
|
||||||
|
// https://sourceforge.net/p/keepass/bugs/1603/
|
||||||
|
return (NativeLib.RunConsoleApp(XSel, XSelW + strOpt,
|
||||||
|
str, XSelWF) != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -53,24 +53,6 @@ namespace ModernKeePassLib.Native
|
|||||||
set { m_bAllowNative = value; }
|
set { m_bAllowNative = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int? g_oiPointerSize = null;
|
|
||||||
/// <summary>
|
|
||||||
/// Size of a native pointer (in bytes).
|
|
||||||
/// </summary>
|
|
||||||
public static int PointerSize
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if(!g_oiPointerSize.HasValue)
|
|
||||||
#if KeePassUAP
|
|
||||||
g_oiPointerSize = Marshal.SizeOf<IntPtr>();
|
|
||||||
#else
|
|
||||||
g_oiPointerSize = Marshal.SizeOf(typeof(IntPtr));
|
|
||||||
#endif
|
|
||||||
return g_oiPointerSize.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ulong? m_ouMonoVersion = null;
|
private static ulong? m_ouMonoVersion = null;
|
||||||
public static ulong MonoVersion
|
public static ulong MonoVersion
|
||||||
{
|
{
|
||||||
@@ -195,19 +177,21 @@ namespace ModernKeePassLib.Native
|
|||||||
t = DesktopType.Xfce;
|
t = DesktopType.Xfce;
|
||||||
else if(strXdg.Equals("MATE", sc))
|
else if(strXdg.Equals("MATE", sc))
|
||||||
t = DesktopType.Mate;
|
t = DesktopType.Mate;
|
||||||
else if(strXdg.Equals("X-Cinnamon", sc))
|
else if(strXdg.Equals("X-Cinnamon", sc)) // Mint 18.3
|
||||||
t = DesktopType.Cinnamon;
|
t = DesktopType.Cinnamon;
|
||||||
else if(strXdg.Equals("Pantheon", sc)) // Elementary OS
|
else if(strXdg.Equals("Pantheon", sc)) // Elementary OS
|
||||||
t = DesktopType.Pantheon;
|
t = DesktopType.Pantheon;
|
||||||
else if(strXdg.Equals("KDE", sc) || // Mint 16
|
else if(strXdg.Equals("KDE", sc) || // Mint 16, Kubuntu 17.10
|
||||||
strGdm.Equals("kde-plasma", sc)) // Ubuntu 12.04
|
strGdm.Equals("kde-plasma", sc)) // Ubuntu 12.04
|
||||||
t = DesktopType.Kde;
|
t = DesktopType.Kde;
|
||||||
else if(strXdg.Equals("GNOME", sc))
|
else if(strXdg.Equals("GNOME", sc))
|
||||||
{
|
{
|
||||||
if(strGdm.Equals("cinnamon", sc)) // Mint 13
|
if(strGdm.Equals("cinnamon", sc)) // Mint 13
|
||||||
t = DesktopType.Cinnamon;
|
t = DesktopType.Cinnamon;
|
||||||
else t = DesktopType.Gnome;
|
else t = DesktopType.Gnome; // Fedora 27
|
||||||
}
|
}
|
||||||
|
else if(strXdg.Equals("ubuntu:GNOME", sc))
|
||||||
|
t = DesktopType.Gnome;
|
||||||
}
|
}
|
||||||
catch(Exception) { Debug.Assert(false); }
|
catch(Exception) { Debug.Assert(false); }
|
||||||
}
|
}
|
||||||
@@ -243,6 +227,7 @@ namespace ModernKeePassLib.Native
|
|||||||
|
|
||||||
RunProcessDelegate fnRun = delegate()
|
RunProcessDelegate fnRun = delegate()
|
||||||
{
|
{
|
||||||
|
Process pToDispose = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ProcessStartInfo psi = new ProcessStartInfo();
|
ProcessStartInfo psi = new ProcessStartInfo();
|
||||||
@@ -258,6 +243,7 @@ namespace ModernKeePassLib.Native
|
|||||||
if(!string.IsNullOrEmpty(strParams)) psi.Arguments = strParams;
|
if(!string.IsNullOrEmpty(strParams)) psi.Arguments = strParams;
|
||||||
|
|
||||||
Process p = Process.Start(psi);
|
Process p = Process.Start(psi);
|
||||||
|
pToDispose = p;
|
||||||
|
|
||||||
if(strStdInput != null)
|
if(strStdInput != null)
|
||||||
{
|
{
|
||||||
@@ -274,9 +260,11 @@ namespace ModernKeePassLib.Native
|
|||||||
p.WaitForExit();
|
p.WaitForExit();
|
||||||
else if((f & AppRunFlags.GCKeepAlive) != AppRunFlags.None)
|
else if((f & AppRunFlags.GCKeepAlive) != AppRunFlags.None)
|
||||||
{
|
{
|
||||||
|
pToDispose = null; // Thread disposes it
|
||||||
|
|
||||||
Thread th = new Thread(delegate()
|
Thread th = new Thread(delegate()
|
||||||
{
|
{
|
||||||
try { p.WaitForExit(); }
|
try { p.WaitForExit(); p.Dispose(); }
|
||||||
catch(Exception) { Debug.Assert(false); }
|
catch(Exception) { Debug.Assert(false); }
|
||||||
});
|
});
|
||||||
th.Start();
|
th.Start();
|
||||||
@@ -289,6 +277,11 @@ namespace ModernKeePassLib.Native
|
|||||||
#else
|
#else
|
||||||
catch(Exception) { }
|
catch(Exception) { }
|
||||||
#endif
|
#endif
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try { if(pToDispose != null) pToDispose.Dispose(); }
|
||||||
|
catch(Exception) { Debug.Assert(false); }
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
@@ -31,6 +31,14 @@ namespace ModernKeePassLib.Native
|
|||||||
{
|
{
|
||||||
internal const int MAX_PATH = 260;
|
internal const int MAX_PATH = 260;
|
||||||
|
|
||||||
|
internal const long INVALID_HANDLE_VALUE = -1;
|
||||||
|
|
||||||
|
internal const uint MOVEFILE_REPLACE_EXISTING = 0x00000001;
|
||||||
|
internal const uint MOVEFILE_COPY_ALLOWED = 0x00000002;
|
||||||
|
|
||||||
|
internal const uint FILE_SUPPORTS_TRANSACTIONS = 0x00200000;
|
||||||
|
internal const int MAX_TRANSACTION_DESCRIPTION_LENGTH = 64;
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
||||||
@@ -47,10 +55,9 @@ namespace ModernKeePassLib.Native
|
|||||||
internal static bool TransformKey(IntPtr pBuf256, IntPtr pKey256,
|
internal static bool TransformKey(IntPtr pBuf256, IntPtr pKey256,
|
||||||
UInt64 uRounds)
|
UInt64 uRounds)
|
||||||
{
|
{
|
||||||
if(Marshal.SizeOf(typeof(IntPtr)) == 8)
|
if(IntPtr.Size == 4)
|
||||||
return TransformKey64(pBuf256, pKey256, uRounds);
|
|
||||||
else
|
|
||||||
return TransformKey32(pBuf256, pKey256, uRounds);
|
return TransformKey32(pBuf256, pKey256, uRounds);
|
||||||
|
return TransformKey64(pBuf256, pKey256, uRounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport("KeePassNtv32.dll", EntryPoint = "TransformKeyTimed")]
|
[DllImport("KeePassNtv32.dll", EntryPoint = "TransformKeyTimed")]
|
||||||
@@ -66,10 +73,9 @@ namespace ModernKeePassLib.Native
|
|||||||
internal static bool TransformKeyTimed(IntPtr pBuf256, IntPtr pKey256,
|
internal static bool TransformKeyTimed(IntPtr pBuf256, IntPtr pKey256,
|
||||||
ref UInt64 puRounds, UInt32 uSeconds)
|
ref UInt64 puRounds, UInt32 uSeconds)
|
||||||
{
|
{
|
||||||
if(Marshal.SizeOf(typeof(IntPtr)) == 8)
|
if(IntPtr.Size == 4)
|
||||||
return TransformKeyTimed64(pBuf256, pKey256, ref puRounds, uSeconds);
|
|
||||||
else
|
|
||||||
return TransformKeyTimed32(pBuf256, pKey256, ref puRounds, uSeconds);
|
return TransformKeyTimed32(pBuf256, pKey256, ref puRounds, uSeconds);
|
||||||
|
return TransformKeyTimed64(pBuf256, pKey256, ref puRounds, uSeconds);
|
||||||
} */
|
} */
|
||||||
|
|
||||||
#if !KeePassUAP
|
#if !KeePassUAP
|
||||||
@@ -86,10 +92,9 @@ namespace ModernKeePassLib.Native
|
|||||||
internal static bool TransformKey(IntPtr pBuf256, IntPtr pKey256,
|
internal static bool TransformKey(IntPtr pBuf256, IntPtr pKey256,
|
||||||
UInt64 uRounds)
|
UInt64 uRounds)
|
||||||
{
|
{
|
||||||
if(NativeLib.PointerSize == 8)
|
if(IntPtr.Size == 4)
|
||||||
return TransformKey64(pBuf256, pKey256, uRounds);
|
|
||||||
else
|
|
||||||
return TransformKey32(pBuf256, pKey256, uRounds);
|
return TransformKey32(pBuf256, pKey256, uRounds);
|
||||||
|
return TransformKey64(pBuf256, pKey256, uRounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport("KeePassLibC32.dll", EntryPoint = "TransformKeyBenchmark256")]
|
[DllImport("KeePassLibC32.dll", EntryPoint = "TransformKeyBenchmark256")]
|
||||||
@@ -100,9 +105,9 @@ namespace ModernKeePassLib.Native
|
|||||||
|
|
||||||
internal static UInt64 TransformKeyBenchmark(UInt32 uTimeMs)
|
internal static UInt64 TransformKeyBenchmark(UInt32 uTimeMs)
|
||||||
{
|
{
|
||||||
if(NativeLib.PointerSize == 8)
|
if(IntPtr.Size == 4)
|
||||||
return TransformKeyBenchmark64(uTimeMs);
|
|
||||||
return TransformKeyBenchmark32(uTimeMs);
|
return TransformKeyBenchmark32(uTimeMs);
|
||||||
|
return TransformKeyBenchmark64(uTimeMs);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -116,11 +121,64 @@ namespace ModernKeePassLib.Native
|
|||||||
|
|
||||||
internal static bool TfShowLangBar(uint dwFlags)
|
internal static bool TfShowLangBar(uint dwFlags)
|
||||||
{
|
{
|
||||||
if(Marshal.SizeOf(typeof(IntPtr)) == 8)
|
if(IntPtr.Size == 4) return TF_ShowLangBar32(dwFlags);
|
||||||
return TF_ShowLangBar64(dwFlags);
|
return TF_ShowLangBar64(dwFlags);
|
||||||
return TF_ShowLangBar32(dwFlags);
|
|
||||||
} */
|
} */
|
||||||
|
|
||||||
|
[DllImport("KeePassLibC32.dll", EntryPoint = "ProtectProcessWithDacl")]
|
||||||
|
private static extern void ProtectProcessWithDacl32();
|
||||||
|
|
||||||
|
[DllImport("KeePassLibC64.dll", EntryPoint = "ProtectProcessWithDacl")]
|
||||||
|
private static extern void ProtectProcessWithDacl64();
|
||||||
|
|
||||||
|
internal static void ProtectProcessWithDacl()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(NativeLib.IsUnix()) return;
|
||||||
|
|
||||||
|
if(IntPtr.Size == 4) ProtectProcessWithDacl32();
|
||||||
|
else ProtectProcessWithDacl64();
|
||||||
|
}
|
||||||
|
catch(Exception) { Debug.Assert(false); }
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("Kernel32.dll", SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
internal static extern bool CloseHandle(IntPtr hObject);
|
||||||
|
|
||||||
|
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false,
|
||||||
|
SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
internal static extern bool GetVolumeInformation(string lpRootPathName,
|
||||||
|
StringBuilder lpVolumeNameBuffer, UInt32 nVolumeNameSize,
|
||||||
|
ref UInt32 lpVolumeSerialNumber, ref UInt32 lpMaximumComponentLength,
|
||||||
|
ref UInt32 lpFileSystemFlags, StringBuilder lpFileSystemNameBuffer,
|
||||||
|
UInt32 nFileSystemNameSize);
|
||||||
|
|
||||||
|
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false,
|
||||||
|
SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
internal static extern bool MoveFileEx(string lpExistingFileName,
|
||||||
|
string lpNewFileName, UInt32 dwFlags);
|
||||||
|
|
||||||
|
[DllImport("KtmW32.dll", CharSet = CharSet.Unicode, ExactSpelling = true,
|
||||||
|
SetLastError = true)]
|
||||||
|
internal static extern IntPtr CreateTransaction(IntPtr lpTransactionAttributes,
|
||||||
|
IntPtr lpUOW, UInt32 dwCreateOptions, UInt32 dwIsolationLevel,
|
||||||
|
UInt32 dwIsolationFlags, UInt32 dwTimeout, string lpDescription);
|
||||||
|
|
||||||
|
[DllImport("KtmW32.dll", SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
internal static extern bool CommitTransaction(IntPtr hTransaction);
|
||||||
|
|
||||||
|
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false,
|
||||||
|
SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
internal static extern bool MoveFileTransacted(string lpExistingFileName,
|
||||||
|
string lpNewFileName, IntPtr lpProgressRoutine, IntPtr lpData,
|
||||||
|
UInt32 dwFlags, IntPtr hTransaction);
|
||||||
|
|
||||||
#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)]
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
KeePass Password Safe - The Open-Source Password Manager
|
KeePass Password Safe - The Open-Source Password Manager
|
||||||
Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
|
Copyright (C) 2003-2018 Dominik Reichl <dominik.reichl@t-online.de>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -27,7 +27,7 @@ using System.Runtime.InteropServices;
|
|||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("wismna")]
|
[assembly: AssemblyCompany("wismna")]
|
||||||
[assembly: AssemblyProduct("ModernKeePassLib")]
|
[assembly: AssemblyProduct("ModernKeePassLib")]
|
||||||
[assembly: AssemblyCopyright("Copyright © 2017 Geoffroy Bonneville")]
|
[assembly: AssemblyCopyright("Copyright © 2018 Geoffroy Bonneville")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
@@ -40,5 +40,5 @@ using System.Runtime.InteropServices;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Assembly version information
|
// Assembly version information
|
||||||
[assembly: AssemblyVersion("2.37.0.2000")]
|
[assembly: AssemblyVersion("2.39.1.*")]
|
||||||
[assembly: AssemblyFileVersion("2.37.0.2000")]
|
[assembly: AssemblyFileVersion("2.39.1.0")]
|
||||||
|
@@ -607,9 +607,8 @@ namespace ModernKeePassLib
|
|||||||
m_bDatabaseOpened = true;
|
m_bDatabaseOpened = true;
|
||||||
m_bModified = true;
|
m_bModified = true;
|
||||||
|
|
||||||
m_pgRootGroup = new PwGroup(true, true,
|
m_pgRootGroup = new PwGroup(true, true, UrlUtil.StripExtension(
|
||||||
UrlUtil.StripExtension(UrlUtil.GetFileName(ioConnection.Path)),
|
UrlUtil.GetFileName(ioConnection.Path)), PwIcon.FolderOpen);
|
||||||
PwIcon.FolderOpen);
|
|
||||||
m_pgRootGroup.IsExpanded = true;
|
m_pgRootGroup.IsExpanded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,15 +635,15 @@ namespace ModernKeePassLib
|
|||||||
m_pgRootGroup.IsExpanded = true;
|
m_pgRootGroup.IsExpanded = true;
|
||||||
|
|
||||||
m_pwUserKey = pwKey;
|
m_pwUserKey = pwKey;
|
||||||
|
|
||||||
m_bModified = false;
|
m_bModified = false;
|
||||||
|
|
||||||
KdbxFile kdbx = new KdbxFile(this);
|
KdbxFile kdbx = new KdbxFile(this);
|
||||||
kdbx.DetachBinaries = m_strDetachBins;
|
kdbx.DetachBinaries = m_strDetachBins;
|
||||||
|
|
||||||
Stream s = IOConnection.OpenRead(ioSource);
|
using(Stream s = IOConnection.OpenRead(ioSource))
|
||||||
|
{
|
||||||
kdbx.Load(s, KdbxFormat.Default, slLogger);
|
kdbx.Load(s, KdbxFormat.Default, slLogger);
|
||||||
s.Dispose();
|
}
|
||||||
|
|
||||||
m_pbHashOfLastIO = kdbx.HashOfFileOnDisk;
|
m_pbHashOfLastIO = kdbx.HashOfFileOnDisk;
|
||||||
m_pbHashOfFileOnDisk = kdbx.HashOfFileOnDisk;
|
m_pbHashOfFileOnDisk = kdbx.HashOfFileOnDisk;
|
||||||
@@ -673,17 +672,21 @@ namespace ModernKeePassLib
|
|||||||
if(m_bUseFileLocks) fl = new FileLock(m_ioSource);
|
if(m_bUseFileLocks) fl = new FileLock(m_ioSource);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
FileTransactionEx ft = new FileTransactionEx(m_ioSource,
|
KdbxFile kdbx = new KdbxFile(this);
|
||||||
m_bUseFileTransactions);
|
|
||||||
Stream s = ft.OpenWrite();
|
|
||||||
|
|
||||||
KdbxFile kdb = new KdbxFile(this);
|
using(FileTransactionEx ft = new FileTransactionEx(m_ioSource,
|
||||||
kdb.Save(s, null, KdbxFormat.Default, slLogger);
|
m_bUseFileTransactions))
|
||||||
|
{
|
||||||
|
using(Stream s = ft.OpenWrite())
|
||||||
|
{
|
||||||
|
kdbx.Save(s, null, KdbxFormat.Default, slLogger);
|
||||||
|
}
|
||||||
|
|
||||||
ft.CommitWrite();
|
ft.CommitWrite();
|
||||||
|
}
|
||||||
|
|
||||||
m_pbHashOfLastIO = kdb.HashOfFileOnDisk;
|
m_pbHashOfLastIO = kdbx.HashOfFileOnDisk;
|
||||||
m_pbHashOfFileOnDisk = kdb.HashOfFileOnDisk;
|
m_pbHashOfFileOnDisk = kdbx.HashOfFileOnDisk;
|
||||||
Debug.Assert(m_pbHashOfFileOnDisk != null);
|
Debug.Assert(m_pbHashOfFileOnDisk != null);
|
||||||
}
|
}
|
||||||
finally { if(fl != null) fl.Dispose(); }
|
finally { if(fl != null) fl.Dispose(); }
|
||||||
@@ -1856,10 +1859,7 @@ namespace ModernKeePassLib
|
|||||||
using(Stream sOut = IOConnection.OpenWrite(iocBk))
|
using(Stream sOut = IOConnection.OpenWrite(iocBk))
|
||||||
{
|
{
|
||||||
MemUtil.CopyStream(sIn, sOut);
|
MemUtil.CopyStream(sIn, sOut);
|
||||||
sOut.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sIn.Close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1969,7 +1969,7 @@ namespace ModernKeePassLib
|
|||||||
if(psB == null) return false;
|
if(psB == null) return false;
|
||||||
|
|
||||||
// Ignore protection setting, compare values only
|
// Ignore protection setting, compare values only
|
||||||
if(!kvpA.Value.ReadString().Equals(psB.ReadString())) return false;
|
if(!psB.Equals(kvpA.Value, false)) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach(KeyValuePair<string, ProtectedString> kvpB in b.Strings)
|
foreach(KeyValuePair<string, ProtectedString> kvpB in b.Strings)
|
||||||
@@ -1980,22 +1980,18 @@ namespace ModernKeePassLib
|
|||||||
if(psA == null) return false;
|
if(psA == null) return false;
|
||||||
|
|
||||||
// Must be equal by logic
|
// Must be equal by logic
|
||||||
Debug.Assert(kvpB.Value.ReadString().Equals(psA.ReadString()));
|
Debug.Assert(psA.Equals(kvpB.Value, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(a.Binaries.UCount != b.Binaries.UCount) return false;
|
if(a.Binaries.UCount != b.Binaries.UCount) return false;
|
||||||
foreach(KeyValuePair<string, ProtectedBinary> kvpBin in a.Binaries)
|
foreach(KeyValuePair<string, ProtectedBinary> kvpBin in a.Binaries)
|
||||||
{
|
{
|
||||||
|
ProtectedBinary pbA = kvpBin.Value;
|
||||||
ProtectedBinary pbB = b.Binaries.Get(kvpBin.Key);
|
ProtectedBinary pbB = b.Binaries.Get(kvpBin.Key);
|
||||||
if(pbB == null) return false;
|
if(pbB == null) return false;
|
||||||
|
|
||||||
// Ignore protection setting, compare values only
|
// Ignore protection setting, compare values only
|
||||||
byte[] pbDataA = kvpBin.Value.ReadData();
|
if(!pbB.Equals(pbA, false)) return false;
|
||||||
byte[] pbDataB = pbB.ReadData();
|
|
||||||
bool bBinEq = MemUtil.ArraysEqual(pbDataA, pbDataB);
|
|
||||||
MemUtil.ZeroByteArray(pbDataA);
|
|
||||||
MemUtil.ZeroByteArray(pbDataB);
|
|
||||||
if(!bBinEq) return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@@ -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 const uint Version32 = 0x02260000;
|
public const uint Version32 = 0x02270100;
|
||||||
|
|
||||||
/// <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 const ulong FileVersion64 = 0x0002002600000000UL;
|
public const ulong FileVersion64 = 0x0002002700010000UL;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version, encoded as string.
|
/// Version, encoded as string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string VersionString = "2.38";
|
public const string VersionString = "2.39.1";
|
||||||
|
|
||||||
public const string Copyright = @"Copyright © 2003-2018 Dominik Reichl";
|
public const string Copyright = @"Copyright © 2003-2018 Dominik Reichl";
|
||||||
|
|
||||||
@@ -219,6 +219,15 @@ namespace ModernKeePassLib
|
|||||||
|
|
||||||
return (pe.Strings.ReadSafe(PwDefs.TitleField) == TanTitle);
|
return (pe.Strings.ReadSafe(PwDefs.TitleField) == TanTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static string GetTranslationDisplayVersion(string strFileVersion)
|
||||||
|
{
|
||||||
|
if(strFileVersion == null) { Debug.Assert(false); return string.Empty; }
|
||||||
|
|
||||||
|
if(strFileVersion == "2.39") return "2.39 / 2.39.1";
|
||||||
|
|
||||||
|
return strFileVersion;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// #pragma warning disable 1591 // Missing XML comments warning
|
// #pragma warning disable 1591 // Missing XML comments warning
|
||||||
|
@@ -782,45 +782,49 @@ namespace ModernKeePassLib
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Approximate the total size of this entry in bytes (including
|
/// Approximate the total size (in process memory) of this entry
|
||||||
/// strings, binaries and history entries).
|
/// in bytes (including strings, binaries and history entries).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Size in bytes.</returns>
|
/// <returns>Size in bytes.</returns>
|
||||||
public ulong GetSize()
|
public ulong GetSize()
|
||||||
{
|
{
|
||||||
ulong uSize = 128; // Approx fixed length data
|
// This method assumes 64-bit pointers/references and Unicode
|
||||||
|
// strings (i.e. 2 bytes per character)
|
||||||
|
|
||||||
|
ulong cb = 248; // Number of bytes; approx. fixed length data
|
||||||
|
ulong cc = 0; // Number of characters
|
||||||
|
|
||||||
|
cb += (ulong)m_listStrings.UCount * 40;
|
||||||
foreach(KeyValuePair<string, ProtectedString> kvpStr in m_listStrings)
|
foreach(KeyValuePair<string, ProtectedString> kvpStr in m_listStrings)
|
||||||
{
|
cc += (ulong)kvpStr.Key.Length + (ulong)kvpStr.Value.Length;
|
||||||
uSize += (ulong)kvpStr.Key.Length;
|
|
||||||
uSize += (ulong)kvpStr.Value.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
cb += (ulong)m_listBinaries.UCount * 65;
|
||||||
foreach(KeyValuePair<string, ProtectedBinary> kvpBin in m_listBinaries)
|
foreach(KeyValuePair<string, ProtectedBinary> kvpBin in m_listBinaries)
|
||||||
{
|
{
|
||||||
uSize += (ulong)kvpBin.Key.Length;
|
cc += (ulong)kvpBin.Key.Length;
|
||||||
uSize += kvpBin.Value.Length;
|
cb += (ulong)kvpBin.Value.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
uSize += (ulong)m_listAutoType.DefaultSequence.Length;
|
cc += (ulong)m_listAutoType.DefaultSequence.Length;
|
||||||
|
cb += (ulong)m_listAutoType.AssociationsCount * 24;
|
||||||
foreach(AutoTypeAssociation a in m_listAutoType.Associations)
|
foreach(AutoTypeAssociation a in m_listAutoType.Associations)
|
||||||
{
|
cc += (ulong)a.WindowName.Length + (ulong)a.Sequence.Length;
|
||||||
uSize += (ulong)a.WindowName.Length;
|
|
||||||
uSize += (ulong)a.Sequence.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
cb += (ulong)m_listHistory.UCount * 8;
|
||||||
foreach(PwEntry peHistory in m_listHistory)
|
foreach(PwEntry peHistory in m_listHistory)
|
||||||
uSize += peHistory.GetSize();
|
cb += peHistory.GetSize();
|
||||||
|
|
||||||
uSize += (ulong)m_strOverrideUrl.Length;
|
cc += (ulong)m_strOverrideUrl.Length;
|
||||||
|
|
||||||
|
cb += (ulong)m_vTags.Count * 8;
|
||||||
foreach(string strTag in m_vTags)
|
foreach(string strTag in m_vTags)
|
||||||
uSize += (ulong)strTag.Length;
|
cc += (ulong)strTag.Length;
|
||||||
|
|
||||||
|
cb += (ulong)m_dCustomData.Count * 16;
|
||||||
foreach(KeyValuePair<string, string> kvp in m_dCustomData)
|
foreach(KeyValuePair<string, string> kvp in m_dCustomData)
|
||||||
uSize += (ulong)kvp.Key.Length + (ulong)kvp.Value.Length;
|
cc += (ulong)kvp.Key.Length + (ulong)kvp.Value.Length;
|
||||||
|
|
||||||
return uSize;
|
return (cb + (cc << 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasTag(string strTag)
|
public bool HasTag(string strTag)
|
||||||
|
@@ -44,9 +44,8 @@ namespace ModernKeePassLib.Security
|
|||||||
long lID);
|
long lID);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a protected binary, i.e. a byte array that is encrypted
|
/// A protected binary, i.e. a byte array that is encrypted in memory.
|
||||||
/// in memory. A <c>ProtectedBinary</c> object is immutable and
|
/// A <c>ProtectedBinary</c> object is immutable and thread-safe.
|
||||||
/// thread-safe.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class ProtectedBinary : IEquatable<ProtectedBinary>
|
public sealed class ProtectedBinary : IEquatable<ProtectedBinary>
|
||||||
{
|
{
|
||||||
@@ -71,7 +70,7 @@ namespace ModernKeePassLib.Security
|
|||||||
private enum PbMemProt
|
private enum PbMemProt
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
ProtectedMemory,
|
ProtectedMemory, // DPAPI on Windows
|
||||||
ChaCha20,
|
ChaCha20,
|
||||||
ExtCrypt
|
ExtCrypt
|
||||||
}
|
}
|
||||||
@@ -90,7 +89,8 @@ namespace ModernKeePassLib.Security
|
|||||||
bool? ob = g_obProtectedMemorySupported;
|
bool? ob = g_obProtectedMemorySupported;
|
||||||
if(ob.HasValue) return ob.Value;
|
if(ob.HasValue) return ob.Value;
|
||||||
|
|
||||||
// Mono does not implement any encryption for ProtectedMemory;
|
// Mono does not implement any encryption for ProtectedMemory
|
||||||
|
// on Linux (Mono uses DPAPI on Windows);
|
||||||
// https://sourceforge.net/p/keepass/feature-requests/1907/
|
// https://sourceforge.net/p/keepass/feature-requests/1907/
|
||||||
if(NativeLib.IsUnix())
|
if(NativeLib.IsUnix())
|
||||||
{
|
{
|
||||||
@@ -177,7 +177,7 @@ namespace ModernKeePassLib.Security
|
|||||||
/// i.e. the caller is responsible for clearing it.</param>
|
/// i.e. the caller is responsible for clearing it.</param>
|
||||||
public ProtectedBinary(bool bEnableProtection, byte[] pbData)
|
public ProtectedBinary(bool bEnableProtection, byte[] pbData)
|
||||||
{
|
{
|
||||||
if(pbData == null) throw new ArgumentNullException("pbData");
|
if(pbData == null) throw new ArgumentNullException("pbData"); // For .Length
|
||||||
|
|
||||||
Init(bEnableProtection, pbData, 0, pbData.Length);
|
Init(bEnableProtection, pbData, 0, pbData.Length);
|
||||||
}
|
}
|
||||||
@@ -213,9 +213,8 @@ namespace ModernKeePassLib.Security
|
|||||||
if(xbProtected == null) throw new ArgumentNullException("xbProtected");
|
if(xbProtected == null) throw new ArgumentNullException("xbProtected");
|
||||||
|
|
||||||
byte[] pb = xbProtected.ReadPlainText();
|
byte[] pb = xbProtected.ReadPlainText();
|
||||||
Init(bEnableProtection, pb, 0, pb.Length);
|
try { Init(bEnableProtection, pb, 0, pb.Length); }
|
||||||
|
finally { if(bEnableProtection) MemUtil.ZeroByteArray(pb); }
|
||||||
if(bEnableProtection) MemUtil.ZeroByteArray(pb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Init(bool bEnableProtection, byte[] pbData, int iOffset,
|
private void Init(bool bEnableProtection, byte[] pbData, int iOffset,
|
||||||
@@ -374,7 +373,7 @@ namespace ModernKeePassLib.Security
|
|||||||
for(int i = 0; i < pb.Length; ++i)
|
for(int i = 0; i < pb.Length; ++i)
|
||||||
h = (h << 3) + h + (int)pb[i];
|
h = (h << 3) + h + (int)pb[i];
|
||||||
}
|
}
|
||||||
MemUtil.ZeroByteArray(pb);
|
if(m_bProtected) MemUtil.ZeroByteArray(pb);
|
||||||
|
|
||||||
m_hash = h;
|
m_hash = h;
|
||||||
return h;
|
return h;
|
||||||
@@ -382,25 +381,36 @@ namespace ModernKeePassLib.Security
|
|||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
return Equals(obj as ProtectedBinary);
|
return this.Equals(obj as ProtectedBinary, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Equals(ProtectedBinary other)
|
public bool Equals(ProtectedBinary other)
|
||||||
{
|
{
|
||||||
if(other == null) return false; // No assert
|
return this.Equals(other, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(ProtectedBinary other, bool bCheckProtEqual)
|
||||||
|
{
|
||||||
|
if(other == null) return false; // No assert
|
||||||
|
if(object.ReferenceEquals(this, other)) return true; // Perf. opt.
|
||||||
|
|
||||||
|
if(bCheckProtEqual && (m_bProtected != other.m_bProtected))
|
||||||
|
return false;
|
||||||
|
|
||||||
if(m_bProtected != other.m_bProtected) return false;
|
|
||||||
if(m_uDataLen != other.m_uDataLen) return false;
|
if(m_uDataLen != other.m_uDataLen) return false;
|
||||||
|
|
||||||
byte[] pbL = ReadData();
|
byte[] pbL = ReadData(), pbR = null;
|
||||||
byte[] pbR = other.ReadData();
|
bool bEq;
|
||||||
bool bEq = MemUtil.ArraysEqual(pbL, pbR);
|
try
|
||||||
MemUtil.ZeroByteArray(pbL);
|
{
|
||||||
MemUtil.ZeroByteArray(pbR);
|
pbR = other.ReadData();
|
||||||
|
bEq = MemUtil.ArraysEqual(pbL, pbR);
|
||||||
#if DEBUG
|
}
|
||||||
if(bEq) { Debug.Assert(GetHashCode() == other.GetHashCode()); }
|
finally
|
||||||
#endif
|
{
|
||||||
|
if(m_bProtected) MemUtil.ZeroByteArray(pbL);
|
||||||
|
if(other.m_bProtected && (pbR != null)) MemUtil.ZeroByteArray(pbR);
|
||||||
|
}
|
||||||
|
|
||||||
return bEq;
|
return bEq;
|
||||||
}
|
}
|
||||||
|
@@ -33,11 +33,11 @@ using KeePassLibSD;
|
|||||||
namespace ModernKeePassLib.Security
|
namespace ModernKeePassLib.Security
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an in-memory encrypted string.
|
/// A string that is protected in process memory.
|
||||||
/// <c>ProtectedString</c> objects are immutable and thread-safe.
|
/// <c>ProtectedString</c> objects are immutable and thread-safe.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#if (DEBUG && !KeePassLibSD)
|
#if (DEBUG && !KeePassLibSD)
|
||||||
[DebuggerDisplay(@"{ReadString()}")]
|
[DebuggerDisplay("{ReadString()}")]
|
||||||
#endif
|
#endif
|
||||||
public sealed class ProtectedString
|
public sealed class ProtectedString
|
||||||
{
|
{
|
||||||
@@ -48,11 +48,24 @@ namespace ModernKeePassLib.Security
|
|||||||
private bool m_bIsProtected;
|
private bool m_bIsProtected;
|
||||||
|
|
||||||
private static readonly ProtectedString m_psEmpty = new ProtectedString();
|
private static readonly ProtectedString m_psEmpty = new ProtectedString();
|
||||||
|
/// <summary>
|
||||||
|
/// Get an empty <c>ProtectedString</c> object, without protection.
|
||||||
|
/// </summary>
|
||||||
public static ProtectedString Empty
|
public static ProtectedString Empty
|
||||||
{
|
{
|
||||||
get { return m_psEmpty; }
|
get { return m_psEmpty; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly ProtectedString m_psEmptyEx = new ProtectedString(
|
||||||
|
true, new byte[0]);
|
||||||
|
/// <summary>
|
||||||
|
/// Get an empty <c>ProtectedString</c> object, with protection turned on.
|
||||||
|
/// </summary>
|
||||||
|
public static ProtectedString EmptyEx
|
||||||
|
{
|
||||||
|
get { return m_psEmptyEx; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A flag specifying whether the <c>ProtectedString</c> object
|
/// A flag specifying whether the <c>ProtectedString</c> object
|
||||||
/// has turned on memory protection or not.
|
/// has turned on memory protection or not.
|
||||||
@@ -66,8 +79,8 @@ namespace ModernKeePassLib.Security
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
ProtectedBinary pBin = m_pbUtf8; // Local ref for thread-safety
|
ProtectedBinary p = m_pbUtf8; // Local ref for thread-safety
|
||||||
if(pBin != null) return (pBin.Length == 0);
|
if(p != null) return (p.Length == 0);
|
||||||
|
|
||||||
Debug.Assert(m_strPlainText != null);
|
Debug.Assert(m_strPlainText != null);
|
||||||
return (m_strPlainText.Length == 0);
|
return (m_strPlainText.Length == 0);
|
||||||
@@ -75,18 +88,21 @@ namespace ModernKeePassLib.Security
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int m_nCachedLength = -1;
|
private int m_nCachedLength = -1;
|
||||||
|
/// <summary>
|
||||||
|
/// Length of the protected string, in characters.
|
||||||
|
/// </summary>
|
||||||
public int Length
|
public int Length
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if(m_nCachedLength >= 0) return m_nCachedLength;
|
if(m_nCachedLength >= 0) return m_nCachedLength;
|
||||||
|
|
||||||
ProtectedBinary pBin = m_pbUtf8; // Local ref for thread-safety
|
ProtectedBinary p = m_pbUtf8; // Local ref for thread-safety
|
||||||
if(pBin != null)
|
if(p != null)
|
||||||
{
|
{
|
||||||
byte[] pbPlain = pBin.ReadData();
|
byte[] pbPlain = p.ReadData();
|
||||||
m_nCachedLength = StrUtil.Utf8.GetCharCount(pbPlain);
|
try { m_nCachedLength = StrUtil.Utf8.GetCharCount(pbPlain); }
|
||||||
MemUtil.ZeroByteArray(pbPlain);
|
finally { MemUtil.ZeroByteArray(pbPlain); }
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -149,9 +165,8 @@ namespace ModernKeePassLib.Security
|
|||||||
if(xbProtected == null) throw new ArgumentNullException("xbProtected");
|
if(xbProtected == null) throw new ArgumentNullException("xbProtected");
|
||||||
|
|
||||||
byte[] pb = xbProtected.ReadPlainText();
|
byte[] pb = xbProtected.ReadPlainText();
|
||||||
Init(bEnableProtection, pb);
|
try { Init(bEnableProtection, pb); }
|
||||||
|
finally { if(bEnableProtection) MemUtil.ZeroByteArray(pb); }
|
||||||
if(bEnableProtection) MemUtil.ZeroByteArray(pb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Init(bool bEnableProtection, string str)
|
private void Init(bool bEnableProtection, string str)
|
||||||
@@ -160,7 +175,7 @@ namespace ModernKeePassLib.Security
|
|||||||
|
|
||||||
m_bIsProtected = bEnableProtection;
|
m_bIsProtected = bEnableProtection;
|
||||||
|
|
||||||
// The string already is in memory and immutable,
|
// As the string already is in memory and immutable,
|
||||||
// protection would be useless
|
// protection would be useless
|
||||||
m_strPlainText = str;
|
m_strPlainText = str;
|
||||||
}
|
}
|
||||||
@@ -178,8 +193,8 @@ namespace ModernKeePassLib.Security
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert the protected string to a normal string object.
|
/// Convert the protected string to a standard string object.
|
||||||
/// Be careful with this function, the returned string object
|
/// Be careful with this function, as the returned string object
|
||||||
/// isn't protected anymore and stored in plain-text in the
|
/// isn't protected anymore and stored in plain-text in the
|
||||||
/// process memory.
|
/// process memory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -194,23 +209,42 @@ namespace ModernKeePassLib.Security
|
|||||||
// No need to clear pb
|
// No need to clear pb
|
||||||
|
|
||||||
// As the text is now visible in process memory anyway,
|
// As the text is now visible in process memory anyway,
|
||||||
// there's no need to protect it anymore
|
// there's no need to protect it anymore (strings are
|
||||||
|
// immutable and thus cannot be overwritten)
|
||||||
m_strPlainText = str;
|
m_strPlainText = str;
|
||||||
m_pbUtf8 = null; // Thread-safe order
|
m_pbUtf8 = null; // Thread-safe order
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read out the string and return it as a char array.
|
||||||
|
/// The returned array is not protected and should be cleared by
|
||||||
|
/// the caller.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Plain-text char array.</returns>
|
||||||
|
public char[] ReadChars()
|
||||||
|
{
|
||||||
|
if(m_strPlainText != null) return m_strPlainText.ToCharArray();
|
||||||
|
|
||||||
|
byte[] pb = ReadUtf8();
|
||||||
|
char[] v;
|
||||||
|
try { v = StrUtil.Utf8.GetChars(pb); }
|
||||||
|
finally { MemUtil.ZeroByteArray(pb); }
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Read out the string and return a byte array that contains the
|
/// Read out the string and return a byte array that contains the
|
||||||
/// string encoded using UTF-8. The returned string is not protected
|
/// string encoded using UTF-8.
|
||||||
/// anymore!
|
/// The returned array is not protected and should be cleared by
|
||||||
|
/// the caller.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Plain-text UTF-8 byte array.</returns>
|
/// <returns>Plain-text UTF-8 byte array.</returns>
|
||||||
public byte[] ReadUtf8()
|
public byte[] ReadUtf8()
|
||||||
{
|
{
|
||||||
ProtectedBinary pBin = m_pbUtf8; // Local ref for thread-safety
|
ProtectedBinary p = m_pbUtf8; // Local ref for thread-safety
|
||||||
if(pBin != null) return pBin.ReadData();
|
if(p != null) return p.ReadData();
|
||||||
|
|
||||||
return StrUtil.Utf8.GetBytes(m_strPlainText);
|
return StrUtil.Utf8.GetBytes(m_strPlainText);
|
||||||
}
|
}
|
||||||
@@ -223,7 +257,7 @@ namespace ModernKeePassLib.Security
|
|||||||
/// <returns>Protected string.</returns>
|
/// <returns>Protected string.</returns>
|
||||||
public byte[] ReadXorredString(CryptoRandomStream crsRandomSource)
|
public byte[] ReadXorredString(CryptoRandomStream crsRandomSource)
|
||||||
{
|
{
|
||||||
Debug.Assert(crsRandomSource != null); if(crsRandomSource == null) throw new ArgumentNullException("crsRandomSource");
|
if(crsRandomSource == null) { Debug.Assert(false); throw new ArgumentNullException("crsRandomSource"); }
|
||||||
|
|
||||||
byte[] pbData = ReadUtf8();
|
byte[] pbData = ReadUtf8();
|
||||||
uint uLen = (uint)pbData.Length;
|
uint uLen = (uint)pbData.Length;
|
||||||
@@ -242,10 +276,34 @@ namespace ModernKeePassLib.Security
|
|||||||
if(bProtect == m_bIsProtected) return this;
|
if(bProtect == m_bIsProtected) return this;
|
||||||
|
|
||||||
byte[] pb = ReadUtf8();
|
byte[] pb = ReadUtf8();
|
||||||
ProtectedString ps = new ProtectedString(bProtect, pb);
|
|
||||||
|
|
||||||
if(bProtect) MemUtil.ZeroByteArray(pb);
|
// No need to clear pb; either the current or the new object is unprotected
|
||||||
return ps;
|
return new ProtectedString(bProtect, pb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(ProtectedString ps, bool bCheckProtEqual)
|
||||||
|
{
|
||||||
|
if(ps == null) throw new ArgumentNullException("ps");
|
||||||
|
if(object.ReferenceEquals(this, ps)) return true; // Perf. opt.
|
||||||
|
|
||||||
|
bool bPA = m_bIsProtected, bPB = ps.m_bIsProtected;
|
||||||
|
if(bCheckProtEqual && (bPA != bPB)) return false;
|
||||||
|
if(!bPA && !bPB) return (ReadString() == ps.ReadString());
|
||||||
|
|
||||||
|
byte[] pbA = ReadUtf8(), pbB = null;
|
||||||
|
bool bEq;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pbB = ps.ReadUtf8();
|
||||||
|
bEq = MemUtil.ArraysEqual(pbA, pbB);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if(bPA) MemUtil.ZeroByteArray(pbA);
|
||||||
|
if(bPB && (pbB != null)) MemUtil.ZeroByteArray(pbB);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bEq;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProtectedString Insert(int iStart, string strInsert)
|
public ProtectedString Insert(int iStart, string strInsert)
|
||||||
@@ -254,18 +312,14 @@ namespace ModernKeePassLib.Security
|
|||||||
if(strInsert == null) throw new ArgumentNullException("strInsert");
|
if(strInsert == null) throw new ArgumentNullException("strInsert");
|
||||||
if(strInsert.Length == 0) return this;
|
if(strInsert.Length == 0) return this;
|
||||||
|
|
||||||
// Only operate directly with strings when m_bIsProtected is
|
|
||||||
// false, not in the case of non-null m_strPlainText, because
|
|
||||||
// the operation creates a new sequence in memory
|
|
||||||
if(!m_bIsProtected)
|
if(!m_bIsProtected)
|
||||||
return new ProtectedString(false, ReadString().Insert(
|
return new ProtectedString(false, ReadString().Insert(
|
||||||
iStart, strInsert));
|
iStart, strInsert));
|
||||||
|
|
||||||
UTF8Encoding utf8 = StrUtil.Utf8;
|
UTF8Encoding utf8 = StrUtil.Utf8;
|
||||||
|
char[] v = ReadChars(), vNew = null;
|
||||||
byte[] pb = ReadUtf8();
|
byte[] pbNew = null;
|
||||||
char[] v = utf8.GetChars(pb);
|
ProtectedString ps;
|
||||||
char[] vNew;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -279,21 +333,20 @@ namespace ModernKeePassLib.Security
|
|||||||
Array.Copy(vIns, 0, vNew, iStart, vIns.Length);
|
Array.Copy(vIns, 0, vNew, iStart, vIns.Length);
|
||||||
Array.Copy(v, iStart, vNew, iStart + vIns.Length,
|
Array.Copy(v, iStart, vNew, iStart + vIns.Length,
|
||||||
v.Length - iStart);
|
v.Length - iStart);
|
||||||
|
|
||||||
|
pbNew = utf8.GetBytes(vNew);
|
||||||
|
ps = new ProtectedString(true, pbNew);
|
||||||
|
|
||||||
|
Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) ==
|
||||||
|
ReadString().Insert(iStart, strInsert));
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
MemUtil.ZeroArray<char>(v);
|
MemUtil.ZeroArray<char>(v);
|
||||||
MemUtil.ZeroByteArray(pb);
|
if(vNew != null) MemUtil.ZeroArray<char>(vNew);
|
||||||
|
if(pbNew != null) MemUtil.ZeroByteArray(pbNew);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] pbNew = utf8.GetBytes(vNew);
|
|
||||||
ProtectedString ps = new ProtectedString(m_bIsProtected, pbNew);
|
|
||||||
|
|
||||||
Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) ==
|
|
||||||
ReadString().Insert(iStart, strInsert));
|
|
||||||
|
|
||||||
MemUtil.ZeroArray<char>(vNew);
|
|
||||||
MemUtil.ZeroByteArray(pbNew);
|
|
||||||
return ps;
|
return ps;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,44 +356,81 @@ namespace ModernKeePassLib.Security
|
|||||||
if(nCount < 0) throw new ArgumentOutOfRangeException("nCount");
|
if(nCount < 0) throw new ArgumentOutOfRangeException("nCount");
|
||||||
if(nCount == 0) return this;
|
if(nCount == 0) return this;
|
||||||
|
|
||||||
// Only operate directly with strings when m_bIsProtected is
|
|
||||||
// false, not in the case of non-null m_strPlainText, because
|
|
||||||
// the operation creates a new sequence in memory
|
|
||||||
if(!m_bIsProtected)
|
if(!m_bIsProtected)
|
||||||
return new ProtectedString(false, ReadString().Remove(
|
return new ProtectedString(false, ReadString().Remove(
|
||||||
iStart, nCount));
|
iStart, nCount));
|
||||||
|
|
||||||
UTF8Encoding utf8 = StrUtil.Utf8;
|
UTF8Encoding utf8 = StrUtil.Utf8;
|
||||||
|
char[] v = ReadChars(), vNew = null;
|
||||||
byte[] pb = ReadUtf8();
|
byte[] pbNew = null;
|
||||||
char[] v = utf8.GetChars(pb);
|
ProtectedString ps;
|
||||||
char[] vNew;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if((iStart + nCount) > v.Length)
|
if((iStart + nCount) > v.Length)
|
||||||
throw new ArgumentException("iStart + nCount");
|
throw new ArgumentException("(iStart + nCount) > v.Length");
|
||||||
|
|
||||||
vNew = new char[v.Length - nCount];
|
vNew = new char[v.Length - nCount];
|
||||||
Array.Copy(v, 0, vNew, 0, iStart);
|
Array.Copy(v, 0, vNew, 0, iStart);
|
||||||
Array.Copy(v, iStart + nCount, vNew, iStart, v.Length -
|
Array.Copy(v, iStart + nCount, vNew, iStart, v.Length -
|
||||||
(iStart + nCount));
|
(iStart + nCount));
|
||||||
|
|
||||||
|
pbNew = utf8.GetBytes(vNew);
|
||||||
|
ps = new ProtectedString(true, pbNew);
|
||||||
|
|
||||||
|
Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) ==
|
||||||
|
ReadString().Remove(iStart, nCount));
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
MemUtil.ZeroArray<char>(v);
|
MemUtil.ZeroArray<char>(v);
|
||||||
MemUtil.ZeroByteArray(pb);
|
if(vNew != null) MemUtil.ZeroArray<char>(vNew);
|
||||||
|
if(pbNew != null) MemUtil.ZeroByteArray(pbNew);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] pbNew = utf8.GetBytes(vNew);
|
|
||||||
ProtectedString ps = new ProtectedString(m_bIsProtected, pbNew);
|
|
||||||
|
|
||||||
Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) ==
|
|
||||||
ReadString().Remove(iStart, nCount));
|
|
||||||
|
|
||||||
MemUtil.ZeroArray<char>(vNew);
|
|
||||||
MemUtil.ZeroByteArray(pbNew);
|
|
||||||
return ps;
|
return ps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ProtectedString operator +(ProtectedString a, ProtectedString b)
|
||||||
|
{
|
||||||
|
if(a == null) throw new ArgumentNullException("a");
|
||||||
|
if(b == null) throw new ArgumentNullException("b");
|
||||||
|
|
||||||
|
if(b.IsEmpty) return a;
|
||||||
|
if(a.IsEmpty) return b;
|
||||||
|
if(!a.IsProtected && !b.IsProtected)
|
||||||
|
return new ProtectedString(false, a.ReadString() + b.ReadString());
|
||||||
|
|
||||||
|
char[] vA = a.ReadChars(), vB = null, vNew = null;
|
||||||
|
byte[] pbNew = null;
|
||||||
|
ProtectedString ps;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
vB = b.ReadChars();
|
||||||
|
|
||||||
|
vNew = new char[vA.Length + vB.Length];
|
||||||
|
Array.Copy(vA, vNew, vA.Length);
|
||||||
|
Array.Copy(vB, 0, vNew, vA.Length, vB.Length);
|
||||||
|
|
||||||
|
pbNew = StrUtil.Utf8.GetBytes(vNew);
|
||||||
|
ps = new ProtectedString(true, pbNew);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
MemUtil.ZeroArray<char>(vA);
|
||||||
|
if(vB != null) MemUtil.ZeroArray<char>(vB);
|
||||||
|
if(vNew != null) MemUtil.ZeroArray<char>(vNew);
|
||||||
|
if(pbNew != null) MemUtil.ZeroByteArray(pbNew);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProtectedString operator +(ProtectedString a, string b)
|
||||||
|
{
|
||||||
|
ProtectedString psB = new ProtectedString(false, b);
|
||||||
|
return (a + psB);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -129,9 +129,12 @@ namespace ModernKeePassLib.Serialization
|
|||||||
{
|
{
|
||||||
s = IOConnection.OpenRead(iocLockFile);
|
s = IOConnection.OpenRead(iocLockFile);
|
||||||
if(s == null) return null;
|
if(s == null) return null;
|
||||||
StreamReader sr = new StreamReader(s, StrUtil.Utf8);
|
|
||||||
string str = sr.ReadToEnd();
|
string str = null;
|
||||||
sr.Dispose();
|
using(StreamReader sr = new StreamReader(s, StrUtil.Utf8))
|
||||||
|
{
|
||||||
|
str = sr.ReadToEnd();
|
||||||
|
}
|
||||||
if(str == null) { Debug.Assert(false); return null; }
|
if(str == null) { Debug.Assert(false); return null; }
|
||||||
|
|
||||||
str = StrUtil.NormalizeNewLines(str, false);
|
str = StrUtil.NormalizeNewLines(str, false);
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -32,19 +33,25 @@ using ModernKeePassLib.Utility;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
using Windows.Storage.Streams;
|
using Windows.Storage.Streams;
|
||||||
|
using ModernKeePassLib.Cryptography;
|
||||||
using ModernKeePassLib.Resources;
|
using ModernKeePassLib.Resources;
|
||||||
|
|
||||||
namespace ModernKeePassLib.Serialization
|
namespace ModernKeePassLib.Serialization
|
||||||
{
|
{
|
||||||
public sealed class FileTransactionEx
|
public sealed class FileTransactionEx : IDisposable
|
||||||
{
|
{
|
||||||
private bool m_bTransacted;
|
private bool m_bTransacted;
|
||||||
private IOConnectionInfo m_iocBase;
|
private IOConnectionInfo m_iocBase; // Null means disposed
|
||||||
private IOConnectionInfo m_iocTemp;
|
private IOConnectionInfo m_iocTemp;
|
||||||
|
private IOConnectionInfo m_iocTxfMidFallback = null; // Null <=> TxF not used
|
||||||
|
|
||||||
private bool m_bMadeUnhidden = false;
|
private bool m_bMadeUnhidden = false;
|
||||||
|
|
||||||
|
private List<IOConnectionInfo> m_lToDelete = new List<IOConnectionInfo>();
|
||||||
|
|
||||||
private const string StrTempSuffix = ".tmp";
|
private const string StrTempSuffix = ".tmp";
|
||||||
|
private const string StrTxfTempPrefix = PwDefs.ShortProductName + "_TxF_";
|
||||||
|
private const string StrTxfTempSuffix = ".tmp";
|
||||||
|
|
||||||
private static Dictionary<string, bool> g_dEnabled =
|
private static Dictionary<string, bool> g_dEnabled =
|
||||||
new Dictionary<string, bool>(StrUtil.CaseIgnoreComparer);
|
new Dictionary<string, bool>(StrUtil.CaseIgnoreComparer);
|
||||||
@@ -56,26 +63,23 @@ namespace ModernKeePassLib.Serialization
|
|||||||
set { g_bExtraSafe = value; }
|
set { g_bExtraSafe = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileTransactionEx(IOConnectionInfo iocBaseFile)
|
public FileTransactionEx(IOConnectionInfo iocBaseFile) :
|
||||||
|
this(iocBaseFile, true)
|
||||||
{
|
{
|
||||||
Initialize(iocBaseFile, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileTransactionEx(IOConnectionInfo iocBaseFile, bool bTransacted)
|
public FileTransactionEx(IOConnectionInfo iocBaseFile, bool bTransacted)
|
||||||
{
|
|
||||||
Initialize(iocBaseFile, bTransacted);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Initialize(IOConnectionInfo iocBaseFile, bool bTransacted)
|
|
||||||
{
|
{
|
||||||
if(iocBaseFile == null) throw new ArgumentNullException("iocBaseFile");
|
if(iocBaseFile == null) throw new ArgumentNullException("iocBaseFile");
|
||||||
|
|
||||||
m_bTransacted = bTransacted;
|
m_bTransacted = bTransacted;
|
||||||
|
|
||||||
m_iocBase = iocBaseFile.CloneDeep();
|
m_iocBase = iocBaseFile.CloneDeep();
|
||||||
|
if(m_iocBase.IsLocalFile())
|
||||||
|
m_iocBase.Path = UrlUtil.GetShortestAbsolutePath(m_iocBase.Path);
|
||||||
|
|
||||||
string strPath = m_iocBase.Path;
|
string strPath = m_iocBase.Path;
|
||||||
|
|
||||||
#if !ModernKeePassLib
|
|
||||||
if(m_iocBase.IsLocalFile())
|
if(m_iocBase.IsLocalFile())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -93,10 +97,23 @@ namespace ModernKeePassLib.Serialization
|
|||||||
if((long)(fa & FileAttributes.ReparsePoint) != 0)
|
if((long)(fa & FileAttributes.ReparsePoint) != 0)
|
||||||
m_bTransacted = false;
|
m_bTransacted = false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If the base and the temporary file are in different
|
||||||
|
// folders and the base file doesn't exist (i.e. we can't
|
||||||
|
// backup the ACL), a transaction would cause the new file
|
||||||
|
// to have the default ACL of the temporary folder instead
|
||||||
|
// of the one of the base folder; therefore, we don't use
|
||||||
|
// a transaction when the base file doesn't exist (this
|
||||||
|
// also results in other applications monitoring the folder
|
||||||
|
// to see one file creation only)
|
||||||
|
m_bTransacted = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(Exception) { Debug.Assert(false); }
|
catch(Exception) { Debug.Assert(false); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !ModernKeePassLib
|
||||||
// Prevent transactions for FTP URLs under .NET 4.0 in order to
|
// Prevent transactions for FTP URLs under .NET 4.0 in order to
|
||||||
// avoid/workaround .NET bug 621450:
|
// avoid/workaround .NET bug 621450:
|
||||||
// https://connect.microsoft.com/VisualStudio/feedback/details/621450/problem-renaming-file-on-ftp-server-using-ftpwebrequest-in-net-framework-4-0-vs2010-only
|
// https://connect.microsoft.com/VisualStudio/feedback/details/621450/problem-renaming-file-on-ftp-server-using-ftpwebrequest-in-net-framework-4-0-vs2010-only
|
||||||
@@ -118,90 +135,152 @@ namespace ModernKeePassLib.Serialization
|
|||||||
{
|
{
|
||||||
m_iocTemp = m_iocBase.CloneDeep();
|
m_iocTemp = m_iocBase.CloneDeep();
|
||||||
m_iocTemp.Path += StrTempSuffix;
|
m_iocTemp.Path += StrTempSuffix;
|
||||||
|
|
||||||
|
TxfPrepare(); // Adjusts m_iocTemp
|
||||||
}
|
}
|
||||||
else m_iocTemp = m_iocBase;
|
else m_iocTemp = m_iocBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~FileTransactionEx()
|
||||||
|
{
|
||||||
|
Dispose(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Dispose(bool bDisposing)
|
||||||
|
{
|
||||||
|
m_iocBase = null;
|
||||||
|
if(!bDisposing) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach(IOConnectionInfo ioc in m_lToDelete)
|
||||||
|
{
|
||||||
|
if(IOConnection.FileExists(ioc, false))
|
||||||
|
IOConnection.DeleteFile(ioc);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lToDelete.Clear();
|
||||||
|
}
|
||||||
|
catch(Exception) { Debug.Assert(false); }
|
||||||
|
}
|
||||||
|
|
||||||
public Stream OpenWrite()
|
public Stream OpenWrite()
|
||||||
{
|
{
|
||||||
if(!m_bTransacted) m_bMadeUnhidden = UrlUtil.UnhideFile(m_iocTemp.Path);
|
if(m_iocBase == null) { Debug.Assert(false); throw new ObjectDisposedException(null); }
|
||||||
else // m_bTransacted
|
|
||||||
{
|
if(!m_bTransacted) m_bMadeUnhidden |= UrlUtil.UnhideFile(m_iocTemp.Path);
|
||||||
try { IOConnection.DeleteFile(m_iocTemp); }
|
|
||||||
catch(Exception) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
return IOConnection.OpenWrite(m_iocTemp);
|
return IOConnection.OpenWrite(m_iocTemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CommitWrite()
|
public void CommitWrite()
|
||||||
{
|
{
|
||||||
if(m_bTransacted) CommitWriteTransaction();
|
if(m_iocBase == null) { Debug.Assert(false); throw new ObjectDisposedException(null); }
|
||||||
else // !m_bTransacted
|
|
||||||
|
if(!m_bTransacted)
|
||||||
{
|
{
|
||||||
if(m_bMadeUnhidden) UrlUtil.HideFile(m_iocTemp.Path, true); // Hide again
|
if(m_bMadeUnhidden) UrlUtil.HideFile(m_iocTemp.Path, true);
|
||||||
}
|
}
|
||||||
|
else CommitWriteTransaction();
|
||||||
|
|
||||||
|
m_iocBase = null; // Dispose
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CommitWriteTransaction()
|
private void CommitWriteTransaction()
|
||||||
{
|
{
|
||||||
bool bMadeUnhidden = UrlUtil.UnhideFile(m_iocBase.Path);
|
|
||||||
|
|
||||||
#if (!ModernKeePassLib && !KeePassLibSD)
|
|
||||||
FileSecurity bkSecurity = null;
|
|
||||||
bool bEfsEncrypted = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(g_bExtraSafe)
|
if(g_bExtraSafe)
|
||||||
{
|
{
|
||||||
if(!IOConnection.FileExists(m_iocTemp))
|
if(!IOConnection.FileExists(m_iocTemp))
|
||||||
throw new FileNotFoundException(m_iocTemp.Path +
|
throw new FileNotFoundException(m_iocTemp.Path +
|
||||||
Environment.NewLine + KLRes.FileSaveFailed);
|
MessageService.NewLine + KLRes.FileSaveFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IOConnection.FileExists(m_iocBase))
|
bool bMadeUnhidden = UrlUtil.UnhideFile(m_iocBase.Path);
|
||||||
{
|
|
||||||
#if (!ModernKeePassLib && !KeePassLibSD)
|
#if !ModernKeePassLib
|
||||||
if(m_iocBase.IsLocalFile())
|
// 'All' includes 'Audit' (SACL), which requires SeSecurityPrivilege,
|
||||||
|
// which we usually don't have and therefore get an exception;
|
||||||
|
// trying to set 'Owner' or 'Group' can result in an
|
||||||
|
// UnauthorizedAccessException; thus we restore 'Access' (DACL) only
|
||||||
|
const AccessControlSections acs = AccessControlSections.Access;
|
||||||
|
|
||||||
|
bool bEfsEncrypted = false;
|
||||||
|
byte[] pbSec = null;
|
||||||
|
#endif
|
||||||
|
DateTime? otCreation = null;
|
||||||
|
|
||||||
|
bool bBaseExists = IOConnection.FileExists(m_iocBase);
|
||||||
|
if(bBaseExists && m_iocBase.IsLocalFile())
|
||||||
{
|
{
|
||||||
|
// FileAttributes faBase = FileAttributes.Normal;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
#if !ModernKeePassLib
|
||||||
FileAttributes faBase = File.GetAttributes(m_iocBase.Path);
|
FileAttributes faBase = File.GetAttributes(m_iocBase.Path);
|
||||||
bEfsEncrypted = ((long)(faBase & FileAttributes.Encrypted) != 0);
|
bEfsEncrypted = ((long)(faBase & FileAttributes.Encrypted) != 0);
|
||||||
|
try { if(bEfsEncrypted) File.Decrypt(m_iocBase.Path); } // For TxF
|
||||||
DateTime tCreation = File.GetCreationTimeUtc(m_iocBase.Path);
|
|
||||||
bkSecurity = File.GetAccessControl(m_iocBase.Path);
|
|
||||||
|
|
||||||
File.SetCreationTimeUtc(m_iocTemp.Path, tCreation);
|
|
||||||
}
|
|
||||||
catch(Exception) { Debug.Assert(false); }
|
catch(Exception) { Debug.Assert(false); }
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
otCreation = File.GetCreationTimeUtc(m_iocBase.Path);
|
||||||
|
#if !ModernKeePassLib
|
||||||
|
// May throw with Mono
|
||||||
|
FileSecurity sec = File.GetAccessControl(m_iocBase.Path, acs);
|
||||||
|
if(sec != null) pbSec = sec.GetSecurityDescriptorBinaryForm();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
catch(Exception) { Debug.Assert(NativeLib.IsUnix()); }
|
||||||
|
|
||||||
IOConnection.DeleteFile(m_iocBase);
|
// if((long)(faBase & FileAttributes.ReadOnly) != 0)
|
||||||
|
// throw new UnauthorizedAccessException();
|
||||||
}
|
}
|
||||||
|
|
||||||
IOConnection.RenameFile(m_iocTemp, m_iocBase);
|
if(!TxfMove())
|
||||||
|
|
||||||
#if (!ModernKeePassLib && !KeePassLibSD)
|
|
||||||
if(m_iocBase.IsLocalFile())
|
|
||||||
{
|
{
|
||||||
|
if(bBaseExists) IOConnection.DeleteFile(m_iocBase);
|
||||||
|
IOConnection.RenameFile(m_iocTemp, m_iocBase);
|
||||||
|
}
|
||||||
|
else { Debug.Assert(pbSec != null); } // TxF success => NTFS => has ACL
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// If File.GetCreationTimeUtc fails, it may return a
|
||||||
|
// date with year 1601, and Unix times start in 1970,
|
||||||
|
// so testing for 1971 should ensure validity;
|
||||||
|
// https://msdn.microsoft.com/en-us/library/system.io.file.getcreationtimeutc.aspx
|
||||||
|
if(otCreation.HasValue && (otCreation.Value.Year >= 1971))
|
||||||
|
File.SetCreationTimeUtc(m_iocBase.Path, otCreation.Value);
|
||||||
|
|
||||||
|
#if !ModernKeePassLib
|
||||||
if(bEfsEncrypted)
|
if(bEfsEncrypted)
|
||||||
{
|
{
|
||||||
try { File.Encrypt(m_iocBase.Path); }
|
try { File.Encrypt(m_iocBase.Path); }
|
||||||
catch(Exception) { Debug.Assert(false); }
|
catch(Exception) { Debug.Assert(false); }
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bkSecurity != null)
|
// File.SetAccessControl(m_iocBase.Path, secPrev);
|
||||||
File.SetAccessControl(m_iocBase.Path, bkSecurity);
|
// Directly calling File.SetAccessControl with the previous
|
||||||
}
|
// FileSecurity object does not work; the binary form
|
||||||
catch(Exception) { Debug.Assert(false); }
|
// indirection is required;
|
||||||
|
// https://sourceforge.net/p/keepass/bugs/1738/
|
||||||
|
// https://msdn.microsoft.com/en-us/library/system.io.file.setaccesscontrol.aspx
|
||||||
|
if((pbSec != null) && (pbSec.Length != 0))
|
||||||
|
{
|
||||||
|
FileSecurity sec = new FileSecurity();
|
||||||
|
sec.SetSecurityDescriptorBinaryForm(pbSec, acs);
|
||||||
|
|
||||||
|
File.SetAccessControl(m_iocBase.Path, sec);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
catch(Exception) { Debug.Assert(false); }
|
||||||
|
|
||||||
if(bMadeUnhidden) UrlUtil.HideFile(m_iocBase.Path, true); // Hide again
|
if(bMadeUnhidden) UrlUtil.HideFile(m_iocBase.Path, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For plugins
|
// For plugins
|
||||||
@@ -213,5 +292,155 @@ namespace ModernKeePassLib.Serialization
|
|||||||
g_dEnabled[strPrefix] = obTransacted.Value;
|
g_dEnabled[strPrefix] = obTransacted.Value;
|
||||||
else g_dEnabled.Remove(strPrefix);
|
else g_dEnabled.Remove(strPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool TxfIsSupported(char chDriveLetter)
|
||||||
|
{
|
||||||
|
if(chDriveLetter == '\0') return false;
|
||||||
|
|
||||||
|
#if !ModernKeePassLib
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string strRoot = (new string(chDriveLetter, 1)) + ":\\";
|
||||||
|
|
||||||
|
const int cch = NativeMethods.MAX_PATH + 1;
|
||||||
|
StringBuilder sbName = new StringBuilder(cch + 1);
|
||||||
|
uint uSerial = 0, cchMaxComp = 0, uFlags = 0;
|
||||||
|
StringBuilder sbFileSystem = new StringBuilder(cch + 1);
|
||||||
|
|
||||||
|
if(!NativeMethods.GetVolumeInformation(strRoot, sbName, (uint)cch,
|
||||||
|
ref uSerial, ref cchMaxComp, ref uFlags, sbFileSystem, (uint)cch))
|
||||||
|
{
|
||||||
|
Debug.Assert(false, (new Win32Exception()).Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((uFlags & NativeMethods.FILE_SUPPORTS_TRANSACTIONS) != 0);
|
||||||
|
}
|
||||||
|
catch(Exception) { Debug.Assert(false); }
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TxfPrepare()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(NativeLib.IsUnix()) return;
|
||||||
|
if(!m_iocBase.IsLocalFile()) return;
|
||||||
|
|
||||||
|
string strID = StrUtil.AlphaNumericOnly(Convert.ToBase64String(
|
||||||
|
CryptoRandom.Instance.GetRandomBytes(16)));
|
||||||
|
string strTempDir = UrlUtil.GetTempPath();
|
||||||
|
// See also ClearOld method
|
||||||
|
string strTemp = UrlUtil.EnsureTerminatingSeparator(strTempDir,
|
||||||
|
false) + StrTxfTempPrefix + strID + StrTxfTempSuffix;
|
||||||
|
|
||||||
|
char chB = UrlUtil.GetDriveLetter(m_iocBase.Path);
|
||||||
|
char chT = UrlUtil.GetDriveLetter(strTemp);
|
||||||
|
if(!TxfIsSupported(chB)) return;
|
||||||
|
if((chT != chB) && !TxfIsSupported(chT)) return;
|
||||||
|
|
||||||
|
m_iocTxfMidFallback = m_iocTemp;
|
||||||
|
m_iocTemp = IOConnectionInfo.FromPath(strTemp);
|
||||||
|
|
||||||
|
m_lToDelete.Add(m_iocTemp);
|
||||||
|
}
|
||||||
|
catch(Exception) { Debug.Assert(false); m_iocTxfMidFallback = null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !ModernKeePassLib
|
||||||
|
private bool TxfMove()
|
||||||
|
{
|
||||||
|
if(m_iocTxfMidFallback == null) return false;
|
||||||
|
|
||||||
|
if(TxfMoveWithTx()) return true;
|
||||||
|
|
||||||
|
// Move the temporary file onto the base file's drive first,
|
||||||
|
// such that it cannot happen that both the base file and
|
||||||
|
// the temporary file are deleted/corrupted
|
||||||
|
const uint f = (NativeMethods.MOVEFILE_COPY_ALLOWED |
|
||||||
|
NativeMethods.MOVEFILE_REPLACE_EXISTING);
|
||||||
|
bool b = NativeMethods.MoveFileEx(m_iocTemp.Path, m_iocTxfMidFallback.Path, f);
|
||||||
|
if(b) b = NativeMethods.MoveFileEx(m_iocTxfMidFallback.Path, m_iocBase.Path, f);
|
||||||
|
if(!b) throw new Win32Exception();
|
||||||
|
|
||||||
|
Debug.Assert(!File.Exists(m_iocTemp.Path));
|
||||||
|
Debug.Assert(!File.Exists(m_iocTxfMidFallback.Path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TxfMoveWithTx()
|
||||||
|
{
|
||||||
|
IntPtr hTx = new IntPtr((int)NativeMethods.INVALID_HANDLE_VALUE);
|
||||||
|
Debug.Assert(hTx.ToInt64() == NativeMethods.INVALID_HANDLE_VALUE);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string strTx = PwDefs.ShortProductName + " TxF - " +
|
||||||
|
StrUtil.AlphaNumericOnly(Convert.ToBase64String(
|
||||||
|
CryptoRandom.Instance.GetRandomBytes(16)));
|
||||||
|
const int mchTx = NativeMethods.MAX_TRANSACTION_DESCRIPTION_LENGTH;
|
||||||
|
if(strTx.Length >= mchTx) strTx = strTx.Substring(0, mchTx - 1);
|
||||||
|
|
||||||
|
hTx = NativeMethods.CreateTransaction(IntPtr.Zero,
|
||||||
|
IntPtr.Zero, 0, 0, 0, 0, strTx);
|
||||||
|
if(hTx.ToInt64() == NativeMethods.INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
Debug.Assert(false, (new Win32Exception()).Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!NativeMethods.MoveFileTransacted(m_iocTemp.Path, m_iocBase.Path,
|
||||||
|
IntPtr.Zero, IntPtr.Zero, (NativeMethods.MOVEFILE_COPY_ALLOWED |
|
||||||
|
NativeMethods.MOVEFILE_REPLACE_EXISTING), hTx))
|
||||||
|
{
|
||||||
|
Debug.Assert(false, (new Win32Exception()).Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!NativeMethods.CommitTransaction(hTx))
|
||||||
|
{
|
||||||
|
Debug.Assert(false, (new Win32Exception()).Message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Assert(!File.Exists(m_iocTemp.Path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(Exception) { Debug.Assert(false); }
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if(hTx.ToInt64() != NativeMethods.INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
try { if(!NativeMethods.CloseHandle(hTx)) { Debug.Assert(false); } }
|
||||||
|
catch(Exception) { Debug.Assert(false); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void ClearOld()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// See also TxfPrepare method
|
||||||
|
DirectoryInfo di = new DirectoryInfo(UrlUtil.GetTempPath());
|
||||||
|
List<FileInfo> l = UrlUtil.GetFileInfos(di, StrTxfTempPrefix +
|
||||||
|
"*" + StrTxfTempSuffix, SearchOption.TopDirectoryOnly);
|
||||||
|
|
||||||
|
foreach(FileInfo fi in l)
|
||||||
|
{
|
||||||
|
if(fi == null) { Debug.Assert(false); continue; }
|
||||||
|
if(!fi.Name.StartsWith(StrTxfTempPrefix, StrUtil.CaseIgnoreCmp) ||
|
||||||
|
!fi.Name.EndsWith(StrTxfTempSuffix, StrUtil.CaseIgnoreCmp))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if((DateTime.UtcNow - fi.LastWriteTimeUtc).TotalDays > 1.0)
|
||||||
|
fi.Delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception) { Debug.Assert(false); }
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -431,7 +431,7 @@ namespace ModernKeePassLib.Serialization
|
|||||||
string strInfo = m_strProxyAddr;
|
string strInfo = m_strProxyAddr;
|
||||||
if(m_strProxyPort.Length > 0)
|
if(m_strProxyPort.Length > 0)
|
||||||
strInfo += ":" + m_strProxyPort;
|
strInfo += ":" + m_strProxyPort;
|
||||||
MessageService.ShowWarning(strInfo, ex.Message);
|
MessageService.ShowWarning(strInfo, ex);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -530,7 +530,7 @@ namespace ModernKeePassLib.Serialization
|
|||||||
/* KdbxFile f = new KdbxFile(pwDatabase);
|
/* KdbxFile f = new KdbxFile(pwDatabase);
|
||||||
f.m_format = KdbxFormat.PlainXml;
|
f.m_format = KdbxFormat.PlainXml;
|
||||||
|
|
||||||
XmlDocument doc = new XmlDocument();
|
XmlDocument doc = XmlUtilEx.CreateXmlDocument();
|
||||||
doc.Load(msData);
|
doc.Load(msData);
|
||||||
|
|
||||||
XmlElement el = doc.DocumentElement;
|
XmlElement el = doc.DocumentElement;
|
||||||
|
@@ -87,6 +87,7 @@ namespace ModernKeePassLib.Serialization
|
|||||||
|
|
||||||
m_format = fmt;
|
m_format = fmt;
|
||||||
m_slLogger = slLogger;
|
m_slLogger = slLogger;
|
||||||
|
m_xmlWriter = null;
|
||||||
|
|
||||||
PwGroup pgRoot = (pgDataSource ?? m_pwDatabase.RootGroup);
|
PwGroup pgRoot = (pgDataSource ?? m_pwDatabase.RootGroup);
|
||||||
UTF8Encoding encNoBom = StrUtil.Utf8;
|
UTF8Encoding encNoBom = StrUtil.Utf8;
|
||||||
@@ -203,44 +204,25 @@ namespace ModernKeePassLib.Serialization
|
|||||||
throw new ArgumentOutOfRangeException("fmt");
|
throw new ArgumentOutOfRangeException("fmt");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ModernKeePassLib || KeePassUAP
|
m_xmlWriter = XmlUtilEx.CreateXmlWriter(sXml, m_uFileVersion >= FileVersion32_4);
|
||||||
XmlWriterSettings xws = new XmlWriterSettings();
|
|
||||||
xws.Encoding = encNoBom;
|
|
||||||
xws.Indent = true;
|
|
||||||
xws.IndentChars = "\t";
|
|
||||||
xws.NewLineOnAttributes = false;
|
|
||||||
#if ModernKeePassLib
|
|
||||||
// This is needed for Argon2Kdf write
|
|
||||||
xws.Async = true;
|
|
||||||
if (m_uFileVersion >= FileVersion32_4) xws.CloseOutput = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
XmlWriter xw = XmlWriter.Create(sXml, xws);
|
|
||||||
#else
|
|
||||||
XmlTextWriter xw = new XmlTextWriter(sXml, encNoBom);
|
|
||||||
|
|
||||||
xw.Formatting = Formatting.Indented;
|
|
||||||
xw.IndentChar = '\t';
|
|
||||||
xw.Indentation = 1;
|
|
||||||
#endif
|
|
||||||
m_xmlWriter = xw;
|
|
||||||
|
|
||||||
WriteDocument(pgRoot);
|
WriteDocument(pgRoot);
|
||||||
|
|
||||||
m_xmlWriter.Flush();
|
m_xmlWriter.Flush();
|
||||||
m_xmlWriter.Dispose();
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
CommonCleanUpWrite(lStreams, sHashing);
|
||||||
|
|
||||||
if(pbCipherKey != null) MemUtil.ZeroByteArray(pbCipherKey);
|
if(pbCipherKey != null) MemUtil.ZeroByteArray(pbCipherKey);
|
||||||
if(pbHmacKey64 != null) MemUtil.ZeroByteArray(pbHmacKey64);
|
if(pbHmacKey64 != null) MemUtil.ZeroByteArray(pbHmacKey64);
|
||||||
|
|
||||||
CommonCleanUpWrite(lStreams, sHashing);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CommonCleanUpWrite(List<Stream> lStreams, HashingStreamEx sHashing)
|
private void CommonCleanUpWrite(List<Stream> lStreams, HashingStreamEx sHashing)
|
||||||
{
|
{
|
||||||
|
if(m_xmlWriter != null) { m_xmlWriter.Dispose(); m_xmlWriter = null; }
|
||||||
|
|
||||||
CloseStreams(lStreams);
|
CloseStreams(lStreams);
|
||||||
|
|
||||||
Debug.Assert(lStreams.Contains(sHashing)); // sHashing must be closed
|
Debug.Assert(lStreams.Contains(sHashing)); // sHashing must be closed
|
||||||
@@ -249,7 +231,6 @@ namespace ModernKeePassLib.Serialization
|
|||||||
|
|
||||||
CleanUpInnerRandomStream();
|
CleanUpInnerRandomStream();
|
||||||
|
|
||||||
m_xmlWriter = null;
|
|
||||||
m_pbHashOfHeader = null;
|
m_pbHashOfHeader = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -403,8 +403,8 @@ namespace ModernKeePassLib.Serialization
|
|||||||
ICipherEngine iCipher = CipherPool.GlobalPool.GetCipher(pu);
|
ICipherEngine iCipher = CipherPool.GlobalPool.GetCipher(pu);
|
||||||
if(iCipher == null) // CryptographicExceptions are translated to "file corrupted"
|
if(iCipher == null) // CryptographicExceptions are translated to "file corrupted"
|
||||||
throw new Exception(KLRes.FileUnknownCipher +
|
throw new Exception(KLRes.FileUnknownCipher +
|
||||||
Environment.NewLine + KLRes.FileNewVerOrPlgReq +
|
MessageService.NewParagraph + KLRes.FileNewVerOrPlgReq +
|
||||||
Environment.NewLine + "UUID: " + pu.ToHexString() + ".");
|
MessageService.NewParagraph + "UUID: " + pu.ToHexString() + ".");
|
||||||
|
|
||||||
ICipherEngine2 iCipher2 = (iCipher as ICipherEngine2);
|
ICipherEngine2 iCipher2 = (iCipher as ICipherEngine2);
|
||||||
if(iCipher2 != null)
|
if(iCipher2 != null)
|
||||||
@@ -476,7 +476,7 @@ namespace ModernKeePassLib.Serialization
|
|||||||
#if !ModernKeePassLib
|
#if !ModernKeePassLib
|
||||||
catch(CryptographicException) { }
|
catch(CryptographicException) { }
|
||||||
#endif
|
#endif
|
||||||
catch (Exception) { Debug.Assert(false); }
|
catch(Exception) { Debug.Assert(false); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not clear the list
|
// Do not clear the list
|
||||||
@@ -539,8 +539,8 @@ namespace ModernKeePassLib.Serialization
|
|||||||
FileStream fs = new FileStream(strPath, FileMode.Create,
|
FileStream fs = new FileStream(strPath, FileMode.Create,
|
||||||
FileAccess.Write, FileShare.None);
|
FileAccess.Write, FileShare.None);
|
||||||
byte[] pbData = pb.ReadData();
|
byte[] pbData = pb.ReadData();
|
||||||
fs.Write(pbData, 0, pbData.Length);
|
try { File.WriteAllBytes(strPath, pbData); }
|
||||||
fs.Close();
|
finally { if(pb.IsProtected) MemUtil.ZeroByteArray(pbData); }
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -111,23 +111,17 @@ namespace ModernKeePassLib.Translation
|
|||||||
if(xs == null) throw new ArgumentNullException("xs");
|
if(xs == null) throw new ArgumentNullException("xs");
|
||||||
|
|
||||||
#if !KeePassLibSD
|
#if !KeePassLibSD
|
||||||
GZipStream gz = new GZipStream(sOut, CompressionMode.Compress);
|
using(GZipStream gz = new GZipStream(sOut, CompressionMode.Compress))
|
||||||
#else
|
#else
|
||||||
GZipOutputStream gz = new GZipOutputStream(sOut);
|
using(GZipOutputStream gz = new GZipOutputStream(sOut))
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
XmlWriterSettings xws = new XmlWriterSettings();
|
using(XmlWriter xw = XmlUtilEx.CreateXmlWriter(gz))
|
||||||
xws.CheckCharacters = true;
|
{
|
||||||
xws.Encoding = StrUtil.Utf8;
|
|
||||||
xws.Indent = true;
|
|
||||||
xws.IndentChars = "\t";
|
|
||||||
|
|
||||||
XmlWriter xw = XmlWriter.Create(gz, xws);
|
|
||||||
|
|
||||||
xs.Serialize(xw, kpTrl);
|
xs.Serialize(xw, kpTrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
xw.Close();
|
|
||||||
gz.Close();
|
|
||||||
sOut.Close();
|
sOut.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,15 +142,17 @@ namespace ModernKeePassLib.Translation
|
|||||||
{
|
{
|
||||||
if(xs == null) throw new ArgumentNullException("xs");
|
if(xs == null) throw new ArgumentNullException("xs");
|
||||||
|
|
||||||
|
KPTranslation kpTrl = null;
|
||||||
|
|
||||||
#if !KeePassLibSD
|
#if !KeePassLibSD
|
||||||
GZipStream gz = new GZipStream(s, CompressionMode.Decompress);
|
using(GZipStream gz = new GZipStream(s, CompressionMode.Decompress))
|
||||||
#else
|
#else
|
||||||
GZipInputStream gz = new GZipInputStream(s);
|
using(GZipInputStream gz = new GZipInputStream(s))
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
kpTrl = (xs.Deserialize(gz) as KPTranslation);
|
||||||
|
}
|
||||||
|
|
||||||
KPTranslation kpTrl = (xs.Deserialize(gz) as KPTranslation);
|
|
||||||
|
|
||||||
gz.Close();
|
|
||||||
s.Close();
|
s.Close();
|
||||||
return kpTrl;
|
return kpTrl;
|
||||||
}
|
}
|
||||||
|
@@ -496,11 +496,21 @@ namespace ModernKeePassLib.Utility
|
|||||||
return UInt32ToBytes((uint)iValue);
|
return UInt32ToBytes((uint)iValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Int32ToBytesEx(int iValue, byte[] pb, int iOffset)
|
||||||
|
{
|
||||||
|
UInt32ToBytesEx((uint)iValue, pb, iOffset);
|
||||||
|
}
|
||||||
|
|
||||||
public static byte[] Int64ToBytes(long lValue)
|
public static byte[] Int64ToBytes(long lValue)
|
||||||
{
|
{
|
||||||
return UInt64ToBytes((ulong)lValue);
|
return UInt64ToBytes((ulong)lValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Int64ToBytesEx(long lValue, byte[] pb, int iOffset)
|
||||||
|
{
|
||||||
|
UInt64ToBytesEx((ulong)lValue, pb, iOffset);
|
||||||
|
}
|
||||||
|
|
||||||
public static uint RotateLeft32(uint u, int nBits)
|
public static uint RotateLeft32(uint u, int nBits)
|
||||||
{
|
{
|
||||||
return ((u << nBits) | (u >> (32 - nBits)));
|
return ((u << nBits) | (u >> (32 - nBits)));
|
||||||
|
@@ -23,7 +23,7 @@ using System.Collections.Specialized;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
#if !KeePassUAP
|
#if !ModernKeePassLib
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -34,6 +34,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
{
|
{
|
||||||
public sealed class MessageServiceEventArgs : EventArgs
|
public sealed class MessageServiceEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
|
#if !ModernKeePassLib
|
||||||
private string m_strTitle = string.Empty;
|
private string m_strTitle = string.Empty;
|
||||||
private string m_strText = string.Empty;
|
private string m_strText = string.Empty;
|
||||||
private MessageBoxButtons m_msgButtons = MessageBoxButtons.OK;
|
private MessageBoxButtons m_msgButtons = MessageBoxButtons.OK;
|
||||||
@@ -54,12 +55,14 @@ namespace ModernKeePassLib.Utility
|
|||||||
m_msgButtons = msgButtons;
|
m_msgButtons = msgButtons;
|
||||||
m_msgIcon = msgIcon;
|
m_msgIcon = msgIcon;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MessageService
|
public static class MessageService
|
||||||
{
|
{
|
||||||
private static volatile uint m_uCurrentMessageCount = 0;
|
private static volatile uint m_uCurrentMessageCount = 0;
|
||||||
|
|
||||||
|
#if !ModernKeePassLib
|
||||||
#if !KeePassLibSD
|
#if !KeePassLibSD
|
||||||
private const MessageBoxIcon m_mbiInfo = MessageBoxIcon.Information;
|
private const MessageBoxIcon m_mbiInfo = MessageBoxIcon.Information;
|
||||||
private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Warning;
|
private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Warning;
|
||||||
@@ -73,7 +76,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Hand;
|
private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Hand;
|
||||||
#endif
|
#endif
|
||||||
private const MessageBoxIcon m_mbiQuestion = MessageBoxIcon.Question;
|
private const MessageBoxIcon m_mbiQuestion = MessageBoxIcon.Question;
|
||||||
|
#endif
|
||||||
public static string NewLine
|
public static string NewLine
|
||||||
{
|
{
|
||||||
#if !KeePassLibSD
|
#if !KeePassLibSD
|
||||||
@@ -123,7 +126,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
|
|
||||||
Exception exObj = (obj as Exception);
|
Exception exObj = (obj as Exception);
|
||||||
string strObj = (obj as string);
|
string strObj = (obj as string);
|
||||||
#if (!KeePassLibSD && !KeePassRT)
|
#if (!KeePassLibSD && !ModernKeePassLib)
|
||||||
StringCollection scObj = (obj as StringCollection);
|
StringCollection scObj = (obj as StringCollection);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -131,10 +134,10 @@ namespace ModernKeePassLib.Utility
|
|||||||
{
|
{
|
||||||
if(bFullExceptions)
|
if(bFullExceptions)
|
||||||
strAppend = StrUtil.FormatException(exObj);
|
strAppend = StrUtil.FormatException(exObj);
|
||||||
else if((exObj.Message != null) && (exObj.Message.Length > 0))
|
else if(!string.IsNullOrEmpty(exObj.Message))
|
||||||
strAppend = exObj.Message;
|
strAppend = exObj.Message;
|
||||||
}
|
}
|
||||||
#if (!KeePassLibSD && !KeePassRT)
|
#if (!KeePassLibSD && !ModernKeePassLib)
|
||||||
else if(scObj != null)
|
else if(scObj != null)
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
@@ -146,7 +149,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
strAppend = sb.ToString();
|
strAppend = sb.ToString();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if(strObj != null)
|
else if (strObj != null)
|
||||||
strAppend = strObj;
|
strAppend = strObj;
|
||||||
else
|
else
|
||||||
strAppend = obj.ToString();
|
strAppend = obj.ToString();
|
||||||
@@ -163,7 +166,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
return sbText.ToString();
|
return sbText.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (!KeePassLibSD && !KeePassRT)
|
#if (!KeePassLibSD && !ModernKeePassLib)
|
||||||
internal static Form GetTopForm()
|
internal static Form GetTopForm()
|
||||||
{
|
{
|
||||||
FormCollection fc = Application.OpenForms;
|
FormCollection fc = Application.OpenForms;
|
||||||
@@ -173,7 +176,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !KeePassUAP
|
#if !ModernKeePassLib
|
||||||
internal static DialogResult SafeShowMessageBox(string strText, string strTitle,
|
internal static DialogResult SafeShowMessageBox(string strText, string strTitle,
|
||||||
MessageBoxButtons mb, MessageBoxIcon mi, MessageBoxDefaultButton mdb)
|
MessageBoxButtons mb, MessageBoxIcon mi, MessageBoxDefaultButton mdb)
|
||||||
{
|
{
|
||||||
|
@@ -104,6 +104,9 @@ namespace ModernKeePassLib.Utility
|
|||||||
// 1690:
|
// 1690:
|
||||||
// Removing items from a list view doesn't work properly.
|
// Removing items from a list view doesn't work properly.
|
||||||
// https://sourceforge.net/p/keepass/bugs/1690/
|
// https://sourceforge.net/p/keepass/bugs/1690/
|
||||||
|
// 1716:
|
||||||
|
// 'Always on Top' doesn't work properly on the Cinnamon desktop.
|
||||||
|
// https://sourceforge.net/p/keepass/bugs/1716/
|
||||||
// 2139:
|
// 2139:
|
||||||
// Shortcut keys are ignored.
|
// Shortcut keys are ignored.
|
||||||
// https://sourceforge.net/p/keepass/feature-requests/2139/
|
// https://sourceforge.net/p/keepass/feature-requests/2139/
|
||||||
@@ -560,7 +563,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
{
|
{
|
||||||
// Mono's WriteRecentlyUsedFiles method also loads the
|
// Mono's WriteRecentlyUsedFiles method also loads the
|
||||||
// XML file using XmlDocument
|
// XML file using XmlDocument
|
||||||
XmlDocument xd = new XmlDocument();
|
XmlDocument xd = XmlUtilEx.CreateXmlDocument();
|
||||||
xd.Load(strFile);
|
xd.Load(strFile);
|
||||||
}
|
}
|
||||||
catch(Exception) // The XML file is invalid
|
catch(Exception) // The XML file is invalid
|
||||||
|
@@ -301,6 +301,28 @@ namespace ModernKeePassLib.Utility
|
|||||||
return ("\\u" + sh.ToString(NumberFormatInfo.InvariantInfo) + "?");
|
return ("\\u" + sh.ToString(NumberFormatInfo.InvariantInfo) + "?");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string RtfFix(string strRtf)
|
||||||
|
{
|
||||||
|
if(strRtf == null) { Debug.Assert(false); return string.Empty; }
|
||||||
|
|
||||||
|
string str = strRtf;
|
||||||
|
|
||||||
|
// Workaround for .NET bug: the Rtf property of a RichTextBox
|
||||||
|
// can return an RTF text starting with "{\\urtf", but
|
||||||
|
// setting such an RTF text throws an exception (the setter
|
||||||
|
// checks for the RTF text to start with "{\\rtf");
|
||||||
|
// https://sourceforge.net/p/keepass/discussion/329221/thread/7788872f/
|
||||||
|
// https://www.microsoft.com/en-us/download/details.aspx?id=10725
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb774284.aspx
|
||||||
|
// https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/RichTextBox.cs
|
||||||
|
const string p = "{\\urtf"; // Typically "{\\urtf1\\ansi\\ansicpg65001"
|
||||||
|
if(str.StartsWith(p) && (str.Length > p.Length) &&
|
||||||
|
char.IsDigit(str[p.Length]))
|
||||||
|
str = str.Remove(2, 1); // Remove the 'u'
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert a string to a HTML sequence representing that string.
|
/// Convert a string to a HTML sequence representing that string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -324,7 +346,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
if(bNbsp) str = str.Replace(" ", @" "); // Before <br />
|
if(bNbsp) str = str.Replace(" ", @" "); // Before <br />
|
||||||
|
|
||||||
str = NormalizeNewLines(str, false);
|
str = NormalizeNewLines(str, false);
|
||||||
str = str.Replace("\n", @"<br />" + Environment.NewLine);
|
str = str.Replace("\n", @"<br />" + MessageService.NewLine);
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
@@ -497,40 +519,40 @@ namespace ModernKeePassLib.Utility
|
|||||||
{
|
{
|
||||||
string strText = string.Empty;
|
string strText = string.Empty;
|
||||||
|
|
||||||
if(excp.Message != null)
|
if(!string.IsNullOrEmpty(excp.Message))
|
||||||
strText += excp.Message + Environment.NewLine;
|
strText += excp.Message + MessageService.NewLine;
|
||||||
#if !KeePassLibSD
|
#if !KeePassLibSD
|
||||||
if(excp.Source != null)
|
if(!string.IsNullOrEmpty(excp.Source))
|
||||||
strText += excp.Source + Environment.NewLine;
|
strText += excp.Source + MessageService.NewLine;
|
||||||
#endif
|
#endif
|
||||||
if(excp.StackTrace != null)
|
if(!string.IsNullOrEmpty(excp.StackTrace))
|
||||||
strText += excp.StackTrace + Environment.NewLine;
|
strText += excp.StackTrace + MessageService.NewLine;
|
||||||
#if !KeePassLibSD
|
#if !KeePassLibSD
|
||||||
#if !ModernKeePassLib && !KeePassRT
|
#if !ModernKeePassLib && !KeePassRT
|
||||||
if(excp.TargetSite != null)
|
if(excp.TargetSite != null)
|
||||||
strText += excp.TargetSite.ToString() + Environment.NewLine;
|
strText += excp.TargetSite.ToString() + MessageService.NewLine;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(excp.Data != null)
|
if(excp.Data != null)
|
||||||
{
|
{
|
||||||
strText += Environment.NewLine;
|
strText += MessageService.NewLine;
|
||||||
foreach(DictionaryEntry de in excp.Data)
|
foreach(DictionaryEntry de in excp.Data)
|
||||||
strText += @"'" + de.Key + @"' -> '" + de.Value + @"'" +
|
strText += @"'" + de.Key + @"' -> '" + de.Value + @"'" +
|
||||||
Environment.NewLine;
|
MessageService.NewLine;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(excp.InnerException != null)
|
if(excp.InnerException != null)
|
||||||
{
|
{
|
||||||
strText += Environment.NewLine + "Inner:" + Environment.NewLine;
|
strText += MessageService.NewLine + "Inner:" + MessageService.NewLine;
|
||||||
if(excp.InnerException.Message != null)
|
if(!string.IsNullOrEmpty(excp.InnerException.Message))
|
||||||
strText += excp.InnerException.Message + Environment.NewLine;
|
strText += excp.InnerException.Message + MessageService.NewLine;
|
||||||
#if !KeePassLibSD
|
#if !KeePassLibSD
|
||||||
if(excp.InnerException.Source != null)
|
if(!string.IsNullOrEmpty(excp.InnerException.Source))
|
||||||
strText += excp.InnerException.Source + Environment.NewLine;
|
strText += excp.InnerException.Source + MessageService.NewLine;
|
||||||
#endif
|
#endif
|
||||||
if(excp.InnerException.StackTrace != null)
|
if(!string.IsNullOrEmpty(excp.InnerException.StackTrace))
|
||||||
strText += excp.InnerException.StackTrace + Environment.NewLine;
|
strText += excp.InnerException.StackTrace + MessageService.NewLine;
|
||||||
#if !KeePassLibSD
|
#if !KeePassLibSD
|
||||||
#if !ModernKeePassLib && !KeePassRT
|
#if !ModernKeePassLib && !KeePassRT
|
||||||
if(excp.InnerException.TargetSite != null)
|
if(excp.InnerException.TargetSite != null)
|
||||||
@@ -539,10 +561,10 @@ namespace ModernKeePassLib.Utility
|
|||||||
|
|
||||||
if(excp.InnerException.Data != null)
|
if(excp.InnerException.Data != null)
|
||||||
{
|
{
|
||||||
strText += Environment.NewLine;
|
strText += MessageService.NewLine;
|
||||||
foreach(DictionaryEntry de in excp.InnerException.Data)
|
foreach(DictionaryEntry de in excp.InnerException.Data)
|
||||||
strText += @"'" + de.Key + @"' -> '" + de.Value + @"'" +
|
strText += @"'" + de.Key + @"' -> '" + de.Value + @"'" +
|
||||||
Environment.NewLine;
|
MessageService.NewLine;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -1140,32 +1162,58 @@ namespace ModernKeePassLib.Utility
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static char[] m_vNewLineChars = null;
|
|
||||||
public static void NormalizeNewLines(ProtectedStringDictionary dict,
|
public static void NormalizeNewLines(ProtectedStringDictionary dict,
|
||||||
bool bWindows)
|
bool bWindows)
|
||||||
{
|
{
|
||||||
if(dict == null) { Debug.Assert(false); return; }
|
if(dict == null) { Debug.Assert(false); return; }
|
||||||
|
|
||||||
if(m_vNewLineChars == null)
|
List<string> lKeys = dict.GetKeys();
|
||||||
m_vNewLineChars = new char[]{ '\r', '\n' };
|
foreach(string strKey in lKeys)
|
||||||
|
|
||||||
List<string> vKeys = dict.GetKeys();
|
|
||||||
foreach(string strKey in vKeys)
|
|
||||||
{
|
{
|
||||||
ProtectedString ps = dict.Get(strKey);
|
ProtectedString ps = dict.Get(strKey);
|
||||||
if(ps == null) { Debug.Assert(false); continue; }
|
if(ps == null) { Debug.Assert(false); continue; }
|
||||||
|
|
||||||
string strValue = ps.ReadString();
|
char[] v = ps.ReadChars();
|
||||||
if(strValue.IndexOfAny(m_vNewLineChars) < 0) continue;
|
if(!IsNewLineNormalized(v, bWindows))
|
||||||
|
|
||||||
dict.Set(strKey, new ProtectedString(ps.IsProtected,
|
dict.Set(strKey, new ProtectedString(ps.IsProtected,
|
||||||
NormalizeNewLines(strValue, bWindows)));
|
NormalizeNewLines(ps.ReadString(), bWindows)));
|
||||||
|
MemUtil.ZeroArray<char>(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static bool IsNewLineNormalized(char[] v, bool bWindows)
|
||||||
|
{
|
||||||
|
if(v == null) { Debug.Assert(false); return true; }
|
||||||
|
|
||||||
|
if(bWindows)
|
||||||
|
{
|
||||||
|
int iFreeCr = -2; // Must be < -1 (for test "!= (i - 1)")
|
||||||
|
|
||||||
|
for(int i = 0; i < v.Length; ++i)
|
||||||
|
{
|
||||||
|
char ch = v[i];
|
||||||
|
|
||||||
|
if(ch == '\r')
|
||||||
|
{
|
||||||
|
if(iFreeCr >= 0) return false;
|
||||||
|
iFreeCr = i;
|
||||||
|
}
|
||||||
|
else if(ch == '\n')
|
||||||
|
{
|
||||||
|
if(iFreeCr != (i - 1)) return false;
|
||||||
|
iFreeCr = -2; // Consume \r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (iFreeCr < 0); // Ensure no \r at end
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Array.IndexOf<char>(v, '\r') < 0);
|
||||||
|
}
|
||||||
|
|
||||||
public static string GetNewLineSeq(string str)
|
public static string GetNewLineSeq(string str)
|
||||||
{
|
{
|
||||||
if(str == null) { Debug.Assert(false); return Environment.NewLine; }
|
if(str == null) { Debug.Assert(false); return MessageService.NewLine; }
|
||||||
|
|
||||||
int n = str.Length, nLf = 0, nCr = 0, nCrLf = 0;
|
int n = str.Length, nLf = 0, nCr = 0, nCrLf = 0;
|
||||||
char chLast = char.MinValue;
|
char chLast = char.MinValue;
|
||||||
@@ -1187,7 +1235,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
nLf -= nCrLf;
|
nLf -= nCrLf;
|
||||||
|
|
||||||
int nMax = Math.Max(nCrLf, Math.Max(nCr, nLf));
|
int nMax = Math.Max(nCrLf, Math.Max(nCr, nLf));
|
||||||
if(nMax == 0) return Environment.NewLine;
|
if(nMax == 0) return MessageService.NewLine;
|
||||||
|
|
||||||
if(nCrLf == nMax) return "\r\n";
|
if(nCrLf == nMax) return "\r\n";
|
||||||
return ((nLf == nMax) ? "\n" : "\r");
|
return ((nLf == nMax) ? "\n" : "\r");
|
||||||
@@ -1319,7 +1367,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
byte[] pbPlain = StrUtil.Utf8.GetBytes(strPlainText);
|
byte[] pbPlain = StrUtil.Utf8.GetBytes(strPlainText);
|
||||||
byte[] pbEnc = ProtectedData.Protect(pbPlain, m_pbOptEnt,
|
byte[] pbEnc = CryptoUtil.ProtectData(pbPlain, m_pbOptEnt,
|
||||||
DataProtectionScope.CurrentUser);
|
DataProtectionScope.CurrentUser);
|
||||||
|
|
||||||
#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT)
|
#if (!ModernKeePassLib && !KeePassLibSD && !KeePassRT)
|
||||||
@@ -1340,7 +1388,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
byte[] pbEnc = Convert.FromBase64String(strCipherText);
|
byte[] pbEnc = Convert.FromBase64String(strCipherText);
|
||||||
byte[] pbPlain = ProtectedData.Unprotect(pbEnc, m_pbOptEnt,
|
byte[] pbPlain = CryptoUtil.UnprotectData(pbEnc, m_pbOptEnt,
|
||||||
DataProtectionScope.CurrentUser);
|
DataProtectionScope.CurrentUser);
|
||||||
|
|
||||||
return StrUtil.Utf8.GetString(pbPlain, 0, pbPlain.Length);
|
return StrUtil.Utf8.GetString(pbPlain, 0, pbPlain.Length);
|
||||||
|
65
ModernKeePassLib/Utility/TypeOverridePool.cs
Normal file
65
ModernKeePassLib/Utility/TypeOverridePool.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
KeePass Password Safe - The Open-Source Password Manager
|
||||||
|
Copyright (C) 2003-2018 Dominik Reichl <dominik.reichl@t-online.de>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using ModernKeePassLib.Delegates;
|
||||||
|
|
||||||
|
namespace KeePassLib.Utility
|
||||||
|
{
|
||||||
|
public static class TypeOverridePool
|
||||||
|
{
|
||||||
|
private static Dictionary<Type, GFunc<object>> g_d =
|
||||||
|
new Dictionary<Type, GFunc<object>>();
|
||||||
|
|
||||||
|
public static void Register(Type t, GFunc<object> f)
|
||||||
|
{
|
||||||
|
if(t == null) throw new ArgumentNullException("t");
|
||||||
|
if(f == null) throw new ArgumentNullException("f");
|
||||||
|
|
||||||
|
g_d[t] = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Unregister(Type t)
|
||||||
|
{
|
||||||
|
if(t == null) throw new ArgumentNullException("t");
|
||||||
|
|
||||||
|
g_d.Remove(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsRegistered(Type t)
|
||||||
|
{
|
||||||
|
if(t == null) throw new ArgumentNullException("t");
|
||||||
|
|
||||||
|
return g_d.ContainsKey(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T CreateInstance<T>()
|
||||||
|
where T : new()
|
||||||
|
{
|
||||||
|
GFunc<object> f;
|
||||||
|
if(g_d.TryGetValue(typeof(T), out f))
|
||||||
|
return (T)(f());
|
||||||
|
|
||||||
|
return new T();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -299,7 +299,7 @@ namespace ModernKeePassLib.Utility
|
|||||||
else // Unhide
|
else // Unhide
|
||||||
{
|
{
|
||||||
fa &= ~FileAttributes.Hidden;
|
fa &= ~FileAttributes.Hidden;
|
||||||
if((long)fa == 0) fa |= FileAttributes.Normal;
|
if((long)fa == 0) fa = FileAttributes.Normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
File.SetAttributes(strFile, fa);
|
File.SetAttributes(strFile, fa);
|
||||||
@@ -635,13 +635,12 @@ namespace ModernKeePassLib.Utility
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !ModernKeePassLib
|
|
||||||
public static string GetTempPath()
|
public static string GetTempPath()
|
||||||
{
|
{
|
||||||
string strDir;
|
string strDir;
|
||||||
if(NativeLib.IsUnix())
|
if(NativeLib.IsUnix())
|
||||||
strDir = NativeMethods.GetUserRuntimeDir();
|
strDir = NativeMethods.GetUserRuntimeDir();
|
||||||
#if KeePassRT
|
#if ModernKeePassLib
|
||||||
else strDir = Windows.Storage.ApplicationData.Current.TemporaryFolder.Path;
|
else strDir = Windows.Storage.ApplicationData.Current.TemporaryFolder.Path;
|
||||||
#else
|
#else
|
||||||
else strDir = Path.GetTempPath();
|
else strDir = Path.GetTempPath();
|
||||||
@@ -655,7 +654,6 @@ namespace ModernKeePassLib.Utility
|
|||||||
|
|
||||||
return strDir;
|
return strDir;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !ModernKeePassLib && !KeePassLibSD
|
#if !ModernKeePassLib && !KeePassLibSD
|
||||||
// Structurally mostly equivalent to UrlUtil.GetFileInfos
|
// Structurally mostly equivalent to UrlUtil.GetFileInfos
|
||||||
@@ -779,5 +777,17 @@ namespace ModernKeePassLib.Utility
|
|||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static char GetDriveLetter(string strPath)
|
||||||
|
{
|
||||||
|
if(strPath == null) throw new ArgumentNullException("strPath");
|
||||||
|
|
||||||
|
Debug.Assert(default(char) == '\0');
|
||||||
|
if(strPath.Length < 3) return '\0';
|
||||||
|
if((strPath[1] != ':') || (strPath[2] != '\\')) return '\0';
|
||||||
|
|
||||||
|
char ch = char.ToUpperInvariant(strPath[0]);
|
||||||
|
return (((ch >= 'A') && (ch <= 'Z')) ? ch : '\0');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
127
ModernKeePassLib/Utility/XmlUtilEx.cs
Normal file
127
ModernKeePassLib/Utility/XmlUtilEx.cs
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
KeePass Password Safe - The Open-Source Password Manager
|
||||||
|
Copyright (C) 2003-2018 Dominik Reichl <dominik.reichl@t-online.de>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using Windows.Data.Xml.Dom;
|
||||||
|
|
||||||
|
namespace ModernKeePassLib.Utility
|
||||||
|
{
|
||||||
|
public static class XmlUtilEx
|
||||||
|
{
|
||||||
|
public static XmlDocument CreateXmlDocument()
|
||||||
|
{
|
||||||
|
XmlDocument d = new XmlDocument();
|
||||||
|
|
||||||
|
// .NET 4.5.2 and newer do not resolve external XML resources
|
||||||
|
// by default; for older .NET versions, we explicitly
|
||||||
|
// prevent resolving
|
||||||
|
#if !ModernKeePassLib
|
||||||
|
d.XmlResolver = null; // Default in old .NET: XmlUrlResolver object
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static XmlReaderSettings CreateXmlReaderSettings()
|
||||||
|
{
|
||||||
|
XmlReaderSettings xrs = new XmlReaderSettings();
|
||||||
|
|
||||||
|
xrs.CloseInput = false;
|
||||||
|
xrs.IgnoreComments = true;
|
||||||
|
xrs.IgnoreProcessingInstructions = true;
|
||||||
|
xrs.IgnoreWhitespace = true;
|
||||||
|
|
||||||
|
#if KeePassUAP || ModernKeePassLib
|
||||||
|
xrs.DtdProcessing = DtdProcessing.Prohibit;
|
||||||
|
#else
|
||||||
|
// Also see PrepMonoDev.sh script
|
||||||
|
xrs.ProhibitDtd = true; // Obsolete in .NET 4, but still there
|
||||||
|
// xrs.DtdProcessing = DtdProcessing.Prohibit; // .NET 4 only
|
||||||
|
|
||||||
|
xrs.ValidationType = ValidationType.None;
|
||||||
|
xrs.XmlResolver = null;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return xrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static XmlReader CreateXmlReader(Stream s)
|
||||||
|
{
|
||||||
|
if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); }
|
||||||
|
|
||||||
|
return XmlReader.Create(s, CreateXmlReaderSettings());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static XmlWriterSettings CreateXmlWriterSettings(bool isVersionGreaterThan4 = false)
|
||||||
|
{
|
||||||
|
XmlWriterSettings xws = new XmlWriterSettings();
|
||||||
|
|
||||||
|
xws.CloseOutput = isVersionGreaterThan4;
|
||||||
|
xws.Encoding = StrUtil.Utf8;
|
||||||
|
xws.Indent = true;
|
||||||
|
xws.IndentChars = "\t";
|
||||||
|
xws.NewLineOnAttributes = false;
|
||||||
|
#if ModernKeePassLib
|
||||||
|
// This is needed for Argon2Kdf write
|
||||||
|
xws.Async = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return xws;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static XmlWriter CreateXmlWriter(Stream s, bool isVersionGreaterThan4 = false)
|
||||||
|
{
|
||||||
|
if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); }
|
||||||
|
|
||||||
|
return XmlWriter.Create(s, CreateXmlWriterSettings(isVersionGreaterThan4));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Serialize<T>(Stream s, T t)
|
||||||
|
{
|
||||||
|
if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); }
|
||||||
|
|
||||||
|
XmlSerializer xs = new XmlSerializer(typeof(T));
|
||||||
|
using(XmlWriter xw = CreateXmlWriter(s))
|
||||||
|
{
|
||||||
|
xs.Serialize(xw, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T Deserialize<T>(Stream s)
|
||||||
|
{
|
||||||
|
if(s == null) { Debug.Assert(false); throw new ArgumentNullException("s"); }
|
||||||
|
|
||||||
|
XmlSerializer xs = new XmlSerializer(typeof(T));
|
||||||
|
|
||||||
|
T t = default(T);
|
||||||
|
using(XmlReader xr = CreateXmlReader(s))
|
||||||
|
{
|
||||||
|
t = (T)xs.Deserialize(xr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user