/* KeePass Password Safe - The Open-Source Password Manager Copyright (C) 2003-2016 Dominik Reichl 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 { /// /// Do not remember user name or password. /// NoSave = 0, /// /// Remember the user name only, not the password. /// UserNameOnly, /// /// Save both user name and password. /// SaveCred } public enum IOCredProtMode { None = 0, Obf } /* public enum IOFileFormatHint { None = 0, Deprecated } */ public sealed class IOConnectionInfo : IDeepCloneable { // 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; } } /// /// For serialization only; use Properties in code. /// [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 /* /// /// Serialize the current connection info to a string. Credentials /// are serialized based on the CredSaveMode property. /// /// Input object to be serialized. /// Serialized object as string. 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; } */ /* /// /// Very simple string protection. Doesn't really encrypt the input /// string, only encodes it that it's not readable on the first glance. /// /// The string to encode/decode. /// If true, the string will be encoded, /// otherwise it'll be decoded. /// Encoded/decoded string. 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; } } } }