1 /* 2 KeePass Password Safe - The Open-Source Password Manager 3 Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 using System; 21 using System.Collections.Generic; 22 using System.Diagnostics; 23 using System.Drawing; 24 using System.Globalization; 25 using System.IO; 26 using System.Text; 27 using System.Text.RegularExpressions; 28 29 using KeePass.Resources; 30 31 using KeePassLib; 32 using KeePassLib.Interfaces; 33 using KeePassLib.Utility; 34 35 namespace KeePass.DataExchange.Formats 36 { 37 // 6.2039.0+ 38 internal sealed class DashlaneJson6 : FileFormatProvider 39 { 40 public override bool SupportsImport { get { return true; } } 41 public override bool SupportsExport { get { return false; } } 42 43 public override string FormatName { get { return "Dashlane JSON (\u2265 6)"; } } 44 public override string DefaultExtension { get { return "json"; } } 45 public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } 46 47 public override bool ImportAppendsToRootGroupOnly { get { return true; } } 48 49 public override Image SmallIcon 50 { 51 get { return KeePass.Properties.Resources.B16x16_Imp_Dashlane; } 52 } 53 Import(PwDatabase pwStorage, Stream sInput, IStatusLogger slLogger)54 public override void Import(PwDatabase pwStorage, Stream sInput, 55 IStatusLogger slLogger) 56 { 57 using(StreamReader sr = new StreamReader(sInput, StrUtil.Utf8, true)) 58 { 59 string str = sr.ReadToEnd(); 60 if(!string.IsNullOrEmpty(str)) 61 { 62 CharStream cs = new CharStream(str); 63 ImportRoot(new JsonObject(cs), pwStorage); 64 } 65 } 66 } 67 ImportRoot(JsonObject jo, PwDatabase pd)68 private static void ImportRoot(JsonObject jo, PwDatabase pd) 69 { 70 foreach(string strType in jo.Items.Keys) 71 { 72 if(strType == null) { Debug.Assert(false); continue; } 73 string strTypeNorm = strType.Trim().ToLower(); 74 75 JsonObject[] vEntries = jo.GetValueArray<JsonObject>(strType); 76 if(vEntries == null) { Debug.Assert(false); continue; } 77 78 foreach(JsonObject joEntry in vEntries) 79 { 80 if(joEntry == null) { Debug.Assert(false); continue; } 81 ImportEntry(joEntry, pd, strTypeNorm); 82 } 83 } 84 } 85 ImportEntry(JsonObject jo, PwDatabase pd, string strTypeNorm)86 private static void ImportEntry(JsonObject jo, PwDatabase pd, string strTypeNorm) 87 { 88 PwEntry pe = new PwEntry(true, true); 89 pd.RootGroup.AddEntry(pe, true); 90 91 if(strTypeNorm.StartsWith("paymentmean")) 92 strTypeNorm = "paymentmean"; 93 94 switch(strTypeNorm) 95 { 96 case "bankstatement": 97 case "fiscalstatement": 98 pe.IconId = PwIcon.Homebanking; 99 break; 100 101 case "driverlicence": 102 case "idcard": 103 case "passport": 104 case "socialsecuritystatement": 105 pe.IconId = PwIcon.Identity; 106 break; 107 108 case "email": 109 pe.IconId = PwIcon.EMail; 110 break; 111 112 case "identity": 113 pe.IconId = PwIcon.UserCommunication; 114 break; 115 116 case "paymentmean": 117 pe.IconId = PwIcon.Money; 118 break; 119 120 default: 121 Debug.Assert(strTypeNorm == "authentifiant"); 122 break; 123 } 124 125 foreach(KeyValuePair<string, object> kvp in jo.Items) 126 { 127 string strValue = (kvp.Value as string); 128 if(strValue == null) 129 { 130 Debug.Assert(false); 131 if(kvp.Value != null) strValue = kvp.Value.ToString(); 132 } 133 if(strValue == null) { Debug.Assert(false); continue; } 134 135 // Ignore GUIDs 136 if(Regex.IsMatch(strValue, "^\\{\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}\\}$", 137 RegexOptions.Singleline)) 138 continue; 139 140 string strKey = kvp.Key; 141 if(strKey == null) { Debug.Assert(false); continue; } 142 strKey = strKey.Trim(); 143 if(string.IsNullOrEmpty(strKey)) { Debug.Assert(false); continue; } 144 if(strKey.StartsWith("BankAccount", StrUtil.CaseIgnoreCmp) && 145 (strKey.Length > 11)) 146 strKey = strKey.Substring(11); 147 if(strKey.IndexOf("Number", StrUtil.CaseIgnoreCmp) >= 0) 148 strKey = PwDefs.UserNameField; 149 strKey = (new string(char.ToUpper(strKey[0]), 1)) + 150 strKey.Substring(1); 151 152 string strNorm = strKey.ToLower(); 153 switch(strNorm) 154 { 155 case "fullname": 156 case "name": 157 case "socialsecurityfullname": 158 strKey = PwDefs.TitleField; 159 break; 160 161 case "domain": 162 strKey = PwDefs.UrlField; 163 break; 164 165 case "expiredate": 166 DateTime? odt = ParseDate(strValue); 167 if(odt.HasValue) 168 { 169 pe.Expires = true; 170 pe.ExpiryTime = odt.Value; 171 strValue = string.Empty; 172 } 173 break; 174 175 case "secondarylogin": 176 strKey = KPRes.UserName + " 2"; 177 break; 178 179 default: 180 if(!strNorm.Contains("date") && !strNorm.Contains("time")) 181 { 182 string strStd = ImportUtil.MapNameToStandardField(strKey, true); 183 if(!string.IsNullOrEmpty(strStd)) strKey = strStd; 184 } 185 break; 186 } 187 188 if(strKey == PwDefs.UrlField) 189 strValue = ImportUtil.FixUrl(strValue); 190 else if(strNorm.Contains("time")) 191 strValue = TryConvertTime(strValue); 192 193 if(!string.IsNullOrEmpty(strValue)) 194 ImportUtil.AppendToField(pe, strKey, strValue, pd); 195 } 196 } 197 ParseDate(string str)198 private static DateTime? ParseDate(string str) 199 { 200 if(string.IsNullOrEmpty(str)) { Debug.Assert(false); return null; } 201 202 DateTime dt; 203 if(DateTime.TryParseExact(str.Trim(), "yyyy'-'M'-'d", 204 NumberFormatInfo.InvariantInfo, DateTimeStyles.AssumeLocal, out dt)) 205 return TimeUtil.ToUtc(dt, false); 206 207 Debug.Assert(false); 208 return null; 209 } 210 TryConvertTime(string str)211 private static string TryConvertTime(string str) 212 { 213 if(string.IsNullOrEmpty(str)) return string.Empty; 214 215 try 216 { 217 if(Regex.IsMatch(str, "^\\d+$", RegexOptions.Singleline)) 218 { 219 ulong u; 220 if(ulong.TryParse(str, out u)) 221 { 222 DateTime dt = TimeUtil.ConvertUnixTime(u); 223 if(dt > TimeUtil.UnixRoot) 224 return TimeUtil.ToDisplayString(dt); 225 } 226 else { Debug.Assert(false); } 227 } 228 } 229 catch(Exception) { Debug.Assert(false); } 230 231 return str; 232 } 233 } 234 } 235