keepass2android/src/KeePassLib2Android/Serialization/IOConnectionInfo.cs

365 lines
8.7 KiB
C#

/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using KeePassLib.Interfaces;
using KeePassLib.Utility;
namespace KeePassLib.Serialization
{
public enum IOCredSaveMode
{
/// <summary>
/// Do not remember user name or password.
/// </summary>
NoSave = 0,
/// <summary>
/// Remember the user name only, not the password.
/// </summary>
UserNameOnly,
/// <summary>
/// Save both user name and password.
/// </summary>
SaveCred
}
public enum IOCredProtMode
{
None = 0,
Obf
}
/* public enum IOFileFormatHint
{
None = 0,
Deprecated
} */
public sealed class IOConnectionInfo : IDeepCloneable<IOConnectionInfo>
{
// private IOFileFormatHint m_ioHint = IOFileFormatHint.None;
private string m_strUrl = string.Empty;
public string Path
{
get { return m_strUrl; }
set
{
Debug.Assert(value != null);
if(value == null) throw new ArgumentNullException("value");
m_strUrl = value;
}
}
private string m_strUser = string.Empty;
[DefaultValue("")]
public string UserName
{
get { return m_strUser; }
set
{
Debug.Assert(value != null);
if(value == null) throw new ArgumentNullException("value");
m_strUser = value;
}
}
private string m_strPassword = string.Empty;
[DefaultValue("")]
public string Password
{
get { return m_strPassword; }
set
{
Debug.Assert(value != null);
if(value == null) throw new ArgumentNullException("value");
m_strPassword = value;
}
}
private IOCredProtMode m_ioCredProtMode = IOCredProtMode.None;
public IOCredProtMode CredProtMode
{
get { return m_ioCredProtMode; }
set { m_ioCredProtMode = value; }
}
private IOCredSaveMode m_ioCredSaveMode = IOCredSaveMode.NoSave;
public IOCredSaveMode CredSaveMode
{
get { return m_ioCredSaveMode; }
set { m_ioCredSaveMode = value; }
}
private bool m_bComplete = false;
[XmlIgnore]
public bool IsComplete // Credentials etc. fully specified
{
get { return m_bComplete; }
set { m_bComplete = value; }
}
/* public IOFileFormatHint FileFormatHint
{
get { return m_ioHint; }
set { m_ioHint = value; }
} */
private IocProperties m_props = new IocProperties();
[XmlIgnore]
public IocProperties Properties
{
get { return m_props; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_props = value;
}
}
/// <summary>
/// For serialization only; use <c>Properties</c> in code.
/// </summary>
[DefaultValue("")]
public string PropertiesEx
{
get { return m_props.Serialize(); }
set
{
if(value == null) throw new ArgumentNullException("value");
IocProperties p = IocProperties.Deserialize(value);
Debug.Assert(p != null);
m_props = (p ?? new IocProperties());
}
}
public IOConnectionInfo CloneDeep()
{
IOConnectionInfo ioc = (IOConnectionInfo)this.MemberwiseClone();
ioc.m_props = m_props.CloneDeep();
return ioc;
}
#if DEBUG // For debugger display only
public override string ToString()
{
return GetDisplayName();
}
#endif
/// <summary>
/// Serialize the current connection info to a string. Credentials
/// are serialized based on the <c>CredSaveMode</c> property.
/// </summary>
/// <param name="iocToCompile">Input object to be serialized.</param>
/// <returns>Serialized object as string.</returns>
public static string SerializeToString(IOConnectionInfo iocToCompile)
{
Debug.Assert(iocToCompile != null);
if(iocToCompile == null) throw new ArgumentNullException("iocToCompile");
string strUrl = iocToCompile.Path;
string strUser = TransformUnreadable(iocToCompile.UserName, true);
string strPassword = TransformUnreadable(iocToCompile.Password, true);
string strAll = strUrl + strUser + strPassword + "CUN";
char chSep = StrUtil.GetUnusedChar(strAll);
if(chSep == char.MinValue) throw new FormatException();
StringBuilder sb = new StringBuilder();
sb.Append(chSep);
sb.Append(strUrl);
sb.Append(chSep);
if(iocToCompile.CredSaveMode == IOCredSaveMode.SaveCred)
{
sb.Append('C');
sb.Append(chSep);
sb.Append(strUser);
sb.Append(chSep);
sb.Append(strPassword);
}
else if(iocToCompile.CredSaveMode == IOCredSaveMode.UserNameOnly)
{
sb.Append('U');
sb.Append(chSep);
sb.Append(strUser);
sb.Append(chSep);
}
else // Don't remember credentials
{
sb.Append('N');
sb.Append(chSep);
sb.Append(chSep);
}
return sb.ToString();
}
public static IOConnectionInfo UnserializeFromString(string strToDecompile)
{
Debug.Assert(strToDecompile != null);
if(strToDecompile == null) throw new ArgumentNullException("strToDecompile");
if(strToDecompile.Length <= 1) throw new ArgumentException();
char chSep = strToDecompile[0];
string[] vParts = strToDecompile.Substring(1, strToDecompile.Length -
1).Split(new char[]{ chSep });
if(vParts.Length < 4) throw new ArgumentException();
IOConnectionInfo s = new IOConnectionInfo();
s.Path = vParts[0];
if(vParts[1] == "C")
s.CredSaveMode = IOCredSaveMode.SaveCred;
else if(vParts[1] == "U")
s.CredSaveMode = IOCredSaveMode.UserNameOnly;
else
s.CredSaveMode = IOCredSaveMode.NoSave;
s.UserName = TransformUnreadable(vParts[2], false);
s.Password = TransformUnreadable(vParts[3], false);
return s;
}
/// <summary>
/// Very simple string protection. Doesn't really encrypt the input
/// string, only encodes it that it's not readable on the first glance.
/// </summary>
/// <param name="strToEncode">The string to encode/decode.</param>
/// <param name="bEncode">If <c>true</c>, the string will be encoded,
/// otherwise it'll be decoded.</param>
/// <returns>Encoded/decoded string.</returns>
private static string TransformUnreadable(string strToEncode, bool bEncode)
{
Debug.Assert(strToEncode != null);
if(strToEncode == null) throw new ArgumentNullException("strToEncode");
if(bEncode)
{
byte[] pbUtf8 = StrUtil.Utf8.GetBytes(strToEncode);
unchecked
{
for(int iPos = 0; iPos < pbUtf8.Length; ++iPos)
pbUtf8[iPos] += (byte)(iPos * 11);
}
return Convert.ToBase64String(pbUtf8);
}
else // Decode
{
byte[] pbBase = Convert.FromBase64String(strToEncode);
unchecked
{
for(int iPos = 0; iPos < pbBase.Length; ++iPos)
pbBase[iPos] -= (byte)(iPos * 11);
}
return StrUtil.Utf8.GetString(pbBase, 0, pbBase.Length);
}
}
public string GetDisplayName()
{
string str = m_strUrl;
if(m_strUser.Length > 0)
str += (" (" + m_strUser + ")");
return str;
}
public bool IsEmpty()
{
return (m_strUrl.Length == 0);
}
public static IOConnectionInfo FromPath(string strPath)
{
IOConnectionInfo ioc = new IOConnectionInfo();
ioc.Path = strPath;
ioc.CredSaveMode = IOCredSaveMode.NoSave;
return ioc;
}
public bool CanProbablyAccess()
{
if(IsLocalFile()) return File.Exists(m_strUrl);
return true;
}
public bool IsLocalFile()
{
// Not just ":/", see e.g. AppConfigEx.ChangePathRelAbs
return (m_strUrl.IndexOf("://") < 0);
}
public void ClearCredentials(bool bDependingOnRememberMode)
{
if((bDependingOnRememberMode == false) ||
(m_ioCredSaveMode == IOCredSaveMode.NoSave))
{
m_strUser = string.Empty;
}
if((bDependingOnRememberMode == false) ||
(m_ioCredSaveMode == IOCredSaveMode.NoSave) ||
(m_ioCredSaveMode == IOCredSaveMode.UserNameOnly))
{
m_strPassword = string.Empty;
}
}
public void Obfuscate(bool bObf)
{
if(bObf && (m_ioCredProtMode == IOCredProtMode.None))
{
m_strPassword = StrUtil.Obfuscate(m_strPassword);
m_ioCredProtMode = IOCredProtMode.Obf;
}
else if(!bObf && (m_ioCredProtMode == IOCredProtMode.Obf))
{
m_strPassword = StrUtil.Deobfuscate(m_strPassword);
m_ioCredProtMode = IOCredProtMode.None;
}
}
}
}