2017-09-11 15:13:04 +02:00
|
|
|
/*
|
|
|
|
KeePass Password Safe - The Open-Source Password Manager
|
2017-09-22 15:40:24 +02:00
|
|
|
Copyright (C) 2003-2014 Dominik Reichl <dominik.reichl@t-online.de>
|
2017-09-11 15:13:04 +02:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
|
2017-09-11 15:13:04 +02:00
|
|
|
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;
|
2017-09-22 15:40:24 +02:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Text;
|
2017-09-11 15:13:04 +02:00
|
|
|
using System.IO;
|
2017-09-22 15:40:24 +02:00
|
|
|
using System.Net;
|
|
|
|
using System.Reflection;
|
|
|
|
using System.Diagnostics;
|
2017-09-11 15:13:04 +02:00
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
#if (!PCL && !KeePassLibSD && !KeePassRT)
|
2017-09-11 15:13:04 +02:00
|
|
|
using System.Net.Cache;
|
|
|
|
using System.Net.Security;
|
|
|
|
#endif
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
#if !PCL && !KeePassRT
|
|
|
|
using System.Security.Cryptography.X509Certificates;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if PCL
|
|
|
|
using Windows.Storage;
|
|
|
|
#endif
|
|
|
|
|
2017-09-11 15:13:04 +02:00
|
|
|
using ModernKeePassLib.Utility;
|
|
|
|
|
|
|
|
namespace ModernKeePassLib.Serialization
|
|
|
|
{
|
2017-09-22 15:40:24 +02:00
|
|
|
#if (!PCL && !KeePassLibSD && !KeePassRT)
|
|
|
|
internal sealed class IOWebClient : WebClient
|
2017-09-11 15:13:04 +02:00
|
|
|
{
|
|
|
|
protected override WebRequest GetWebRequest(Uri address)
|
|
|
|
{
|
|
|
|
WebRequest request = base.GetWebRequest(address);
|
|
|
|
IOConnection.ConfigureWebRequest(request);
|
|
|
|
return request;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
#if !PCL
|
|
|
|
internal abstract class WrapperStream : Stream
|
|
|
|
{
|
|
|
|
private readonly Stream m_s;
|
|
|
|
protected Stream BaseStream
|
|
|
|
{
|
|
|
|
get { return m_s; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool CanRead
|
|
|
|
{
|
|
|
|
get { return m_s.CanRead; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool CanSeek
|
|
|
|
{
|
|
|
|
get { return m_s.CanSeek; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool CanTimeout
|
|
|
|
{
|
|
|
|
get { return m_s.CanTimeout; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public override bool CanWrite
|
|
|
|
{
|
|
|
|
get { return m_s.CanWrite; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public override long Length
|
|
|
|
{
|
|
|
|
get { return m_s.Length; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public override long Position
|
|
|
|
{
|
|
|
|
get { return m_s.Position; }
|
|
|
|
set { m_s.Position = value; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public override int ReadTimeout
|
|
|
|
{
|
|
|
|
get { return m_s.ReadTimeout; }
|
|
|
|
set { m_s.ReadTimeout = value; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public override int WriteTimeout
|
|
|
|
{
|
|
|
|
get { return m_s.WriteTimeout; }
|
|
|
|
set { m_s.WriteTimeout = value; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public WrapperStream(Stream sBase) : base()
|
|
|
|
{
|
|
|
|
if(sBase == null) throw new ArgumentNullException("sBase");
|
|
|
|
|
|
|
|
m_s = sBase;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override IAsyncResult BeginRead(byte[] buffer, int offset,
|
|
|
|
int count, AsyncCallback callback, object state)
|
|
|
|
{
|
|
|
|
return m_s.BeginRead(buffer, offset, count, callback, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override IAsyncResult BeginWrite(byte[] buffer, int offset,
|
|
|
|
int count, AsyncCallback callback, object state)
|
|
|
|
{
|
|
|
|
return BeginWrite(buffer, offset, count, callback, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void Close()
|
|
|
|
{
|
|
|
|
m_s.Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
public override int EndRead(IAsyncResult asyncResult)
|
|
|
|
{
|
|
|
|
return m_s.EndRead(asyncResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void EndWrite(IAsyncResult asyncResult)
|
|
|
|
{
|
|
|
|
m_s.EndWrite(asyncResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void Flush()
|
|
|
|
{
|
|
|
|
m_s.Flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
public override int Read(byte[] buffer, int offset, int count)
|
|
|
|
{
|
|
|
|
return m_s.Read(buffer, offset, count);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override int ReadByte()
|
|
|
|
{
|
|
|
|
return m_s.ReadByte();
|
|
|
|
}
|
|
|
|
|
|
|
|
public override long Seek(long offset, SeekOrigin origin)
|
|
|
|
{
|
|
|
|
return m_s.Seek(offset, origin);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void SetLength(long value)
|
|
|
|
{
|
|
|
|
m_s.SetLength(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void Write(byte[] buffer, int offset, int count)
|
|
|
|
{
|
|
|
|
m_s.Write(buffer, offset, count);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void WriteByte(byte value)
|
|
|
|
{
|
|
|
|
m_s.WriteByte(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal sealed class IocStream : WrapperStream
|
|
|
|
{
|
|
|
|
private readonly bool m_bWrite; // Initially opened for writing
|
|
|
|
|
|
|
|
public IocStream(Stream sBase) : base(sBase)
|
|
|
|
{
|
|
|
|
m_bWrite = sBase.CanWrite;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void Close()
|
|
|
|
{
|
|
|
|
base.Close();
|
|
|
|
|
|
|
|
if(MonoWorkarounds.IsRequired(10163) && m_bWrite)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
Stream s = this.BaseStream;
|
|
|
|
Type t = s.GetType();
|
|
|
|
if(t.Name == "WebConnectionStream")
|
|
|
|
{
|
|
|
|
PropertyInfo pi = t.GetProperty("Request",
|
|
|
|
BindingFlags.Instance | BindingFlags.NonPublic);
|
|
|
|
if(pi != null)
|
|
|
|
{
|
|
|
|
WebRequest wr = (pi.GetValue(s, null) as WebRequest);
|
|
|
|
if(wr != null)
|
|
|
|
IOConnection.DisposeResponse(wr.GetResponse(), false);
|
|
|
|
else { Debug.Assert(false); }
|
|
|
|
}
|
|
|
|
else { Debug.Assert(false); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(Exception) { Debug.Assert(false); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Stream WrapIfRequired(Stream s)
|
|
|
|
{
|
|
|
|
if(s == null) { Debug.Assert(false); return null; }
|
|
|
|
|
|
|
|
if(MonoWorkarounds.IsRequired(10163) && s.CanWrite)
|
|
|
|
return new IocStream(s);
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
public static class IOConnection
|
2017-09-11 15:13:04 +02:00
|
|
|
{
|
2017-09-22 15:40:24 +02:00
|
|
|
#if (!PCL && !KeePassLibSD && !KeePassRT)
|
2017-09-11 15:13:04 +02:00
|
|
|
private static ProxyServerType m_pstProxyType = ProxyServerType.System;
|
|
|
|
private static string m_strProxyAddr = string.Empty;
|
|
|
|
private static string m_strProxyPort = string.Empty;
|
|
|
|
private static string m_strProxyUserName = string.Empty;
|
|
|
|
private static string m_strProxyPassword = string.Empty;
|
2017-09-22 15:40:24 +02:00
|
|
|
|
|
|
|
private static bool m_bSslCertsAcceptInvalid = false;
|
|
|
|
internal static bool SslCertsAcceptInvalid
|
|
|
|
{
|
|
|
|
// get { return m_bSslCertsAcceptInvalid; }
|
|
|
|
set { m_bSslCertsAcceptInvalid = value; }
|
|
|
|
}
|
2017-09-11 15:13:04 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// Web request methods
|
|
|
|
public const string WrmDeleteFile = "DELETEFILE";
|
|
|
|
public const string WrmMoveFile = "MOVEFILE";
|
|
|
|
|
|
|
|
// Web request headers
|
|
|
|
public const string WrhMoveFileTo = "MoveFileTo";
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
public static event EventHandler<IOAccessEventArgs> IOAccessPre;
|
|
|
|
|
|
|
|
#if (!PCL && !KeePassLibSD && !KeePassRT)
|
2017-09-11 15:13:04 +02:00
|
|
|
// Allow self-signed certificates, expired certificates, etc.
|
2017-09-22 15:40:24 +02:00
|
|
|
private static bool AcceptCertificate(object sender,
|
2017-09-11 15:13:04 +02:00
|
|
|
X509Certificate certificate, X509Chain chain,
|
|
|
|
SslPolicyErrors sslPolicyErrors)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
internal static void SetProxy(ProxyServerType pst, string strAddr,
|
2017-09-11 15:13:04 +02:00
|
|
|
string strPort, string strUserName, string strPassword)
|
|
|
|
{
|
|
|
|
m_pstProxyType = pst;
|
|
|
|
m_strProxyAddr = (strAddr ?? string.Empty);
|
|
|
|
m_strProxyPort = (strPort ?? string.Empty);
|
|
|
|
m_strProxyUserName = (strUserName ?? string.Empty);
|
|
|
|
m_strProxyPassword = (strPassword ?? string.Empty);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static void ConfigureWebRequest(WebRequest request)
|
|
|
|
{
|
|
|
|
if(request == null) { Debug.Assert(false); return; } // No throw
|
|
|
|
|
|
|
|
// WebDAV support
|
|
|
|
if(request is HttpWebRequest)
|
|
|
|
{
|
|
|
|
request.PreAuthenticate = true; // Also auth GET
|
|
|
|
if(request.Method == WebRequestMethods.Http.Post)
|
|
|
|
request.Method = WebRequestMethods.Http.Put;
|
|
|
|
}
|
|
|
|
// else if(request is FtpWebRequest)
|
|
|
|
// {
|
|
|
|
// Debug.Assert(((FtpWebRequest)request).UsePassive);
|
|
|
|
// }
|
|
|
|
|
|
|
|
// Not implemented and ignored in Mono < 2.10
|
|
|
|
try
|
|
|
|
{
|
|
|
|
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
|
|
|
|
}
|
|
|
|
catch(NotImplementedException) { }
|
|
|
|
catch(Exception) { Debug.Assert(false); }
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
IWebProxy prx;
|
|
|
|
if(GetWebProxy(out prx)) request.Proxy = prx;
|
|
|
|
}
|
|
|
|
catch(Exception) { Debug.Assert(false); }
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static void ConfigureWebClient(WebClient wc)
|
|
|
|
{
|
|
|
|
// Not implemented and ignored in Mono < 2.10
|
|
|
|
try
|
|
|
|
{
|
|
|
|
wc.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
|
|
|
|
}
|
|
|
|
catch(NotImplementedException) { }
|
|
|
|
catch(Exception) { Debug.Assert(false); }
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
IWebProxy prx;
|
|
|
|
if(GetWebProxy(out prx)) wc.Proxy = prx;
|
|
|
|
}
|
|
|
|
catch(Exception) { Debug.Assert(false); }
|
|
|
|
}
|
|
|
|
|
|
|
|
private static bool GetWebProxy(out IWebProxy prx)
|
|
|
|
{
|
|
|
|
prx = null;
|
|
|
|
|
|
|
|
if(m_pstProxyType == ProxyServerType.None)
|
|
|
|
return true; // Use null proxy
|
|
|
|
if(m_pstProxyType == ProxyServerType.Manual)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if(m_strProxyPort.Length > 0)
|
|
|
|
prx = new WebProxy(m_strProxyAddr, int.Parse(m_strProxyPort));
|
|
|
|
else prx = new WebProxy(m_strProxyAddr);
|
|
|
|
|
|
|
|
if((m_strProxyUserName.Length > 0) || (m_strProxyPassword.Length > 0))
|
|
|
|
prx.Credentials = new NetworkCredential(m_strProxyUserName,
|
|
|
|
m_strProxyPassword);
|
|
|
|
|
|
|
|
return true; // Use manual proxy
|
|
|
|
}
|
|
|
|
catch(Exception exProxy)
|
|
|
|
{
|
|
|
|
string strInfo = m_strProxyAddr;
|
|
|
|
if(m_strProxyPort.Length > 0) strInfo += ":" + m_strProxyPort;
|
|
|
|
MessageService.ShowWarning(strInfo, exProxy.Message);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false; // Use default
|
|
|
|
}
|
|
|
|
|
|
|
|
if((m_strProxyUserName.Length == 0) && (m_strProxyPassword.Length == 0))
|
|
|
|
return false; // Use default proxy, no auth
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
prx = WebRequest.DefaultWebProxy;
|
|
|
|
if(prx == null) prx = WebRequest.GetSystemWebProxy();
|
|
|
|
if(prx == null) throw new InvalidOperationException();
|
|
|
|
|
|
|
|
prx.Credentials = new NetworkCredential(m_strProxyUserName,
|
|
|
|
m_strProxyPassword);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
catch(Exception) { Debug.Assert(false); }
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void PrepareWebAccess()
|
|
|
|
{
|
2017-09-22 15:40:24 +02:00
|
|
|
if(m_bSslCertsAcceptInvalid)
|
|
|
|
ServicePointManager.ServerCertificateValidationCallback =
|
|
|
|
IOConnection.AcceptCertificate;
|
|
|
|
else
|
|
|
|
ServicePointManager.ServerCertificateValidationCallback = null;
|
2017-09-11 15:13:04 +02:00
|
|
|
}
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
private static IOWebClient CreateWebClient(IOConnectionInfo ioc)
|
|
|
|
{
|
|
|
|
PrepareWebAccess();
|
2017-09-11 15:13:04 +02:00
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
IOWebClient wc = new IOWebClient();
|
|
|
|
ConfigureWebClient(wc);
|
2017-09-11 15:13:04 +02:00
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
if((ioc.UserName.Length > 0) || (ioc.Password.Length > 0))
|
|
|
|
wc.Credentials = new NetworkCredential(ioc.UserName, ioc.Password);
|
|
|
|
else if(NativeLib.IsUnix()) // Mono requires credentials
|
|
|
|
wc.Credentials = new NetworkCredential("anonymous", string.Empty);
|
|
|
|
|
|
|
|
return wc;
|
|
|
|
}
|
2017-09-11 15:13:04 +02:00
|
|
|
|
|
|
|
private static WebRequest CreateWebRequest(IOConnectionInfo ioc)
|
|
|
|
{
|
|
|
|
PrepareWebAccess();
|
|
|
|
|
|
|
|
WebRequest req = WebRequest.Create(ioc.Path);
|
|
|
|
ConfigureWebRequest(req);
|
|
|
|
|
|
|
|
if((ioc.UserName.Length > 0) || (ioc.Password.Length > 0))
|
|
|
|
req.Credentials = new NetworkCredential(ioc.UserName, ioc.Password);
|
|
|
|
else if(NativeLib.IsUnix()) // Mono requires credentials
|
|
|
|
req.Credentials = new NetworkCredential("anonymous", string.Empty);
|
|
|
|
|
|
|
|
return req;
|
|
|
|
}
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
public static Stream OpenRead(IOConnectionInfo ioc)
|
2017-09-11 15:13:04 +02:00
|
|
|
{
|
2017-09-22 15:40:24 +02:00
|
|
|
RaiseIOAccessPreEvent(ioc, IOAccessType.Read);
|
|
|
|
|
2017-09-11 15:13:04 +02:00
|
|
|
if(StrUtil.IsDataUri(ioc.Path))
|
|
|
|
{
|
|
|
|
byte[] pbData = StrUtil.DataUriToData(ioc.Path);
|
|
|
|
if(pbData != null) return new MemoryStream(pbData, false);
|
|
|
|
}
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
if(ioc.IsLocalFile()) return OpenReadLocal(ioc);
|
2017-09-11 15:13:04 +02:00
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
return IocStream.WrapIfRequired(CreateWebClient(ioc).OpenRead(
|
|
|
|
new Uri(ioc.Path)));
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
public static Stream OpenRead(IOConnectionInfo ioc)
|
|
|
|
{
|
|
|
|
RaiseIOAccessPreEvent(ioc, IOAccessType.Read);
|
2017-09-11 15:13:04 +02:00
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
return OpenReadLocal(ioc);
|
|
|
|
}
|
|
|
|
#endif
|
2017-09-11 15:13:04 +02:00
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
private static Stream OpenReadLocal(IOConnectionInfo ioc)
|
2017-09-11 15:13:04 +02:00
|
|
|
{
|
2017-09-22 15:40:24 +02:00
|
|
|
#if PCL
|
|
|
|
/*var file = FileSystem.Current.GetFileFromPathAsync(ioc.Path).Result;
|
|
|
|
return file.OpenAsync(PCLStorage.FileAccess.Read).Result;*/
|
|
|
|
return ioc.StorageFile.OpenAsync(FileAccessMode.Read).GetResults().AsStream();
|
|
|
|
#else
|
|
|
|
return new FileStream(ioc.Path, FileMode.Open, FileAccess.Read,
|
|
|
|
FileShare.Read);
|
|
|
|
#endif
|
2017-09-11 15:13:04 +02:00
|
|
|
}
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
#if (!PCL && !KeePassLibSD && !KeePassRT)
|
2017-09-11 15:13:04 +02:00
|
|
|
public static Stream OpenWrite(IOConnectionInfo ioc)
|
|
|
|
{
|
|
|
|
if(ioc == null) { Debug.Assert(false); return null; }
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
RaiseIOAccessPreEvent(ioc, IOAccessType.Write);
|
|
|
|
|
2017-09-11 15:13:04 +02:00
|
|
|
if(ioc.IsLocalFile()) return OpenWriteLocal(ioc);
|
|
|
|
|
|
|
|
Uri uri = new Uri(ioc.Path);
|
2017-09-22 15:40:24 +02:00
|
|
|
Stream s;
|
2017-09-11 15:13:04 +02:00
|
|
|
|
|
|
|
// Mono does not set HttpWebRequest.Method to POST for writes,
|
|
|
|
// so one needs to set the method to PUT explicitly
|
|
|
|
if(NativeLib.IsUnix() && (uri.Scheme.Equals(Uri.UriSchemeHttp,
|
|
|
|
StrUtil.CaseIgnoreCmp) || uri.Scheme.Equals(Uri.UriSchemeHttps,
|
|
|
|
StrUtil.CaseIgnoreCmp)))
|
2017-09-22 15:40:24 +02:00
|
|
|
s = CreateWebClient(ioc).OpenWrite(uri, WebRequestMethods.Http.Put);
|
|
|
|
else s = CreateWebClient(ioc).OpenWrite(uri);
|
2017-09-11 15:13:04 +02:00
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
return IocStream.WrapIfRequired(s);
|
2017-09-11 15:13:04 +02:00
|
|
|
}
|
|
|
|
#else
|
2017-09-22 15:40:24 +02:00
|
|
|
public static Stream OpenWrite(IOConnectionInfo ioc)
|
2017-09-11 15:13:04 +02:00
|
|
|
{
|
2017-09-22 15:40:24 +02:00
|
|
|
RaiseIOAccessPreEvent(ioc, IOAccessType.Write);
|
|
|
|
|
|
|
|
return OpenWriteLocal(ioc);
|
2017-09-11 15:13:04 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
private static Stream OpenWriteLocal(IOConnectionInfo ioc)
|
2017-09-11 15:13:04 +02:00
|
|
|
{
|
2017-09-22 15:40:24 +02:00
|
|
|
#if PCL
|
|
|
|
return ioc.StorageFile.OpenAsync(FileAccessMode.ReadWrite).GetResults().AsStream();
|
|
|
|
/*var file = FileSystem.Current.GetFileFromPathAsync(ioc.Path).Result;
|
|
|
|
return file.OpenAsync(FileAccess.ReadAndWrite).Result;*/
|
|
|
|
#else
|
|
|
|
return new FileStream(ioc.Path, FileMode.Create, FileAccess.Write,
|
|
|
|
FileShare.None);
|
|
|
|
#endif
|
|
|
|
}
|
2017-09-11 15:13:04 +02:00
|
|
|
|
|
|
|
public static bool FileExists(IOConnectionInfo ioc)
|
|
|
|
{
|
2017-09-22 15:40:24 +02:00
|
|
|
return FileExists(ioc, false);
|
2017-09-11 15:13:04 +02:00
|
|
|
}
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
public static bool FileExists(IOConnectionInfo ioc, bool bThrowErrors)
|
|
|
|
{
|
2017-09-11 15:13:04 +02:00
|
|
|
if(ioc == null) { Debug.Assert(false); return false; }
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
RaiseIOAccessPreEvent(ioc, IOAccessType.Exists);
|
|
|
|
|
|
|
|
#if PCL
|
|
|
|
if(ioc.IsLocalFile())
|
|
|
|
return ioc.StorageFile.IsAvailable;
|
|
|
|
#else
|
|
|
|
if(ioc.IsLocalFile()) return File.Exists(ioc.Path);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if (!PCL && !KeePassLibSD && !KeePassRT)
|
|
|
|
if(ioc.Path.StartsWith("ftp://", StrUtil.CaseIgnoreCmp))
|
|
|
|
{
|
|
|
|
bool b = SendCommand(ioc, WebRequestMethods.Ftp.GetDateTimestamp);
|
|
|
|
if(!b && bThrowErrors) throw new InvalidOperationException();
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
#endif
|
2017-09-11 15:13:04 +02:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
Stream s = OpenRead(ioc);
|
|
|
|
if(s == null) throw new FileNotFoundException();
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
try { s.ReadByte(); }
|
|
|
|
catch(Exception) { }
|
|
|
|
|
|
|
|
// We didn't download the file completely; close may throw
|
|
|
|
// an exception -- that's okay
|
|
|
|
try { s.Dispose(); }
|
2017-09-11 15:13:04 +02:00
|
|
|
catch(Exception) { }
|
|
|
|
}
|
|
|
|
catch(Exception)
|
|
|
|
{
|
|
|
|
if(bThrowErrors) throw;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2017-09-22 15:40:24 +02:00
|
|
|
}
|
2017-09-11 15:13:04 +02:00
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
public static void DeleteFile(IOConnectionInfo ioc)
|
2017-09-11 15:13:04 +02:00
|
|
|
{
|
2017-09-22 15:40:24 +02:00
|
|
|
RaiseIOAccessPreEvent(ioc, IOAccessType.Delete);
|
|
|
|
|
|
|
|
#if PCL
|
|
|
|
if(ioc.IsLocalFile()) {
|
|
|
|
/*var file = FileSystem.Current.GetFileFromPathAsync(ioc.Path).Result;
|
|
|
|
file.DeleteAsync().RunSynchronously();*/
|
|
|
|
ioc.StorageFile.DeleteAsync(StorageDeleteOption.Default).GetResults();
|
2017-09-20 18:45:37 +02:00
|
|
|
}
|
2017-09-22 15:40:24 +02:00
|
|
|
#else
|
|
|
|
if(ioc.IsLocalFile()) { File.Delete(ioc.Path); return; }
|
|
|
|
#endif
|
2017-09-11 15:13:04 +02:00
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
#if (!PCL && !KeePassLibSD && !KeePassRT)
|
2017-09-11 15:13:04 +02:00
|
|
|
WebRequest req = CreateWebRequest(ioc);
|
|
|
|
if(req != null)
|
|
|
|
{
|
|
|
|
if(req is HttpWebRequest) req.Method = "DELETE";
|
2017-09-22 15:40:24 +02:00
|
|
|
else if(req is FtpWebRequest)
|
|
|
|
req.Method = WebRequestMethods.Ftp.DeleteFile;
|
2017-09-11 15:13:04 +02:00
|
|
|
else if(req is FileWebRequest)
|
|
|
|
{
|
|
|
|
File.Delete(UrlUtil.FileUrlToPath(ioc.Path));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else req.Method = WrmDeleteFile;
|
|
|
|
|
|
|
|
DisposeResponse(req.GetResponse(), true);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Rename/move a file. For local file system and WebDAV, the
|
|
|
|
/// specified file is moved, i.e. the file destination can be
|
|
|
|
/// in a different directory/path. In contrast, for FTP the
|
|
|
|
/// file is renamed, i.e. its destination must be in the same
|
|
|
|
/// directory/path.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="iocFrom">Source file path.</param>
|
|
|
|
/// <param name="iocTo">Target file path.</param>
|
2017-09-22 15:40:24 +02:00
|
|
|
public static void RenameFile(IOConnectionInfo iocFrom, IOConnectionInfo iocTo)
|
2017-09-11 15:13:04 +02:00
|
|
|
{
|
2017-09-22 15:40:24 +02:00
|
|
|
RaiseIOAccessPreEvent(iocFrom, iocTo, IOAccessType.Move);
|
|
|
|
|
|
|
|
#if PCL
|
|
|
|
if(iocFrom.IsLocalFile()) {
|
|
|
|
/*var file = FileSystem.Current.GetFileFromPathAsync(iocFrom.Path).Result;
|
|
|
|
file.MoveAsync(iocTo.Path).RunSynchronously();*/
|
|
|
|
iocFrom.StorageFile.RenameAsync(iocTo.Path).GetResults();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if(iocFrom.IsLocalFile()) { File.Move(iocFrom.Path, iocTo.Path); return; }
|
|
|
|
#endif
|
2017-09-11 15:13:04 +02:00
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
#if (!PCL && !KeePassLibSD && !KeePassRT)
|
2017-09-11 15:13:04 +02:00
|
|
|
WebRequest req = CreateWebRequest(iocFrom);
|
|
|
|
if(req != null)
|
|
|
|
{
|
|
|
|
if(req is HttpWebRequest)
|
|
|
|
{
|
|
|
|
req.Method = "MOVE";
|
|
|
|
req.Headers.Set("Destination", iocTo.Path); // Full URL supported
|
|
|
|
}
|
|
|
|
else if(req is FtpWebRequest)
|
|
|
|
{
|
|
|
|
req.Method = WebRequestMethods.Ftp.Rename;
|
2017-09-22 15:40:24 +02:00
|
|
|
string strTo = UrlUtil.GetFileName(iocTo.Path);
|
|
|
|
|
|
|
|
// We're affected by .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
|
|
|
|
// Prepending "./", "%2E/" or "Dummy/../" doesn't work.
|
|
|
|
|
|
|
|
((FtpWebRequest)req).RenameTo = strTo;
|
2017-09-11 15:13:04 +02:00
|
|
|
}
|
|
|
|
else if(req is FileWebRequest)
|
|
|
|
{
|
|
|
|
File.Move(UrlUtil.FileUrlToPath(iocFrom.Path),
|
|
|
|
UrlUtil.FileUrlToPath(iocTo.Path));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
req.Method = WrmMoveFile;
|
|
|
|
req.Headers.Set(WrhMoveFileTo, iocTo.Path);
|
|
|
|
}
|
|
|
|
|
|
|
|
DisposeResponse(req.GetResponse(), true);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// using(Stream sIn = IOConnection.OpenRead(iocFrom))
|
|
|
|
// {
|
|
|
|
// using(Stream sOut = IOConnection.OpenWrite(iocTo))
|
|
|
|
// {
|
|
|
|
// MemUtil.CopyStream(sIn, sOut);
|
|
|
|
// sOut.Close();
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// sIn.Close();
|
|
|
|
// }
|
|
|
|
// DeleteFile(iocFrom);
|
|
|
|
}
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
#if (!PCL && !KeePassLibSD && !KeePassRT)
|
|
|
|
private static bool SendCommand(IOConnectionInfo ioc, string strMethod)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
WebRequest req = CreateWebRequest(ioc);
|
|
|
|
req.Method = strMethod;
|
|
|
|
DisposeResponse(req.GetResponse(), true);
|
|
|
|
}
|
|
|
|
catch(Exception) { return false; }
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
internal static void DisposeResponse(WebResponse wr, bool bGetStream)
|
2017-09-11 15:13:04 +02:00
|
|
|
{
|
|
|
|
if(wr == null) return;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if(bGetStream)
|
|
|
|
{
|
|
|
|
Stream s = wr.GetResponseStream();
|
2017-09-22 15:40:24 +02:00
|
|
|
if(s != null) s.Dispose();
|
2017-09-11 15:13:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(Exception) { Debug.Assert(false); }
|
|
|
|
|
2017-09-22 15:40:24 +02:00
|
|
|
try { wr.Dispose(); }
|
2017-09-11 15:13:04 +02:00
|
|
|
catch(Exception) { Debug.Assert(false); }
|
|
|
|
}
|
|
|
|
|
|
|
|
public static byte[] ReadFile(IOConnectionInfo ioc)
|
|
|
|
{
|
|
|
|
Stream sIn = null;
|
|
|
|
MemoryStream ms = null;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
sIn = IOConnection.OpenRead(ioc);
|
|
|
|
if(sIn == null) return null;
|
|
|
|
|
|
|
|
ms = new MemoryStream();
|
|
|
|
MemUtil.CopyStream(sIn, ms);
|
|
|
|
|
|
|
|
return ms.ToArray();
|
|
|
|
}
|
|
|
|
catch(Exception) { }
|
|
|
|
finally
|
|
|
|
{
|
2017-09-22 15:40:24 +02:00
|
|
|
if(sIn != null) sIn.Dispose();
|
|
|
|
if(ms != null) ms.Dispose();
|
2017-09-11 15:13:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
2017-09-22 15:40:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private static void RaiseIOAccessPreEvent(IOConnectionInfo ioc, IOAccessType t)
|
|
|
|
{
|
|
|
|
RaiseIOAccessPreEvent(ioc, null, t);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void RaiseIOAccessPreEvent(IOConnectionInfo ioc,
|
|
|
|
IOConnectionInfo ioc2, IOAccessType t)
|
|
|
|
{
|
|
|
|
if(ioc == null) { Debug.Assert(false); return; }
|
|
|
|
// ioc2 may be null
|
|
|
|
|
|
|
|
if(IOConnection.IOAccessPre != null)
|
|
|
|
{
|
|
|
|
IOConnectionInfo ioc2Lcl = ((ioc2 != null) ? ioc2.CloneDeep() : null);
|
|
|
|
IOAccessEventArgs e = new IOAccessEventArgs(ioc.CloneDeep(), ioc2Lcl, t);
|
|
|
|
IOConnection.IOAccessPre(null, e);
|
|
|
|
}
|
|
|
|
}
|
2017-09-11 15:13:04 +02:00
|
|
|
}
|
|
|
|
}
|