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.IO; 25 using System.Text; 26 27 using KeePass.Resources; 28 using KeePass.Util; 29 30 using KeePassLib; 31 using KeePassLib.Interfaces; 32 using KeePassLib.Utility; 33 34 namespace KeePass.DataExchange.Formats 35 { 36 // 16.0.0+ 37 internal sealed class KeeperJson16 : FileFormatProvider 38 { 39 public override bool SupportsImport { get { return true; } } 40 public override bool SupportsExport { get { return false; } } 41 42 public override string FormatName { get { return "Keeper JSON"; } } 43 public override string DefaultExtension { get { return "json"; } } 44 public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } 45 46 public override Image SmallIcon 47 { 48 get { return KeePass.Properties.Resources.B16x16_Imp_Keeper; } 49 } 50 Import(PwDatabase pwStorage, Stream sInput, IStatusLogger slLogger)51 public override void Import(PwDatabase pwStorage, Stream sInput, 52 IStatusLogger slLogger) 53 { 54 using(StreamReader sr = new StreamReader(sInput, StrUtil.Utf8, true)) 55 { 56 string str = sr.ReadToEnd(); 57 if(string.IsNullOrEmpty(str)) { Debug.Assert(false); return; } 58 59 CharStream cs = new CharStream(str); 60 JsonObject joRoot = new JsonObject(cs); 61 62 JsonObject[] v = joRoot.GetValueArray<JsonObject>("records"); 63 ImportRecords(v, pwStorage); 64 } 65 } 66 ImportRecords(JsonObject[] v, PwDatabase pd)67 private static void ImportRecords(JsonObject[] v, PwDatabase pd) 68 { 69 if(v == null) { Debug.Assert(false); return; } 70 71 Dictionary<string, PwGroup> dGroups = new Dictionary<string, PwGroup>(); 72 string strGroupSep = MemUtil.ByteArrayToHexString(Guid.NewGuid().ToByteArray()); 73 string strBackspCode = MemUtil.ByteArrayToHexString(Guid.NewGuid().ToByteArray()); 74 75 foreach(JsonObject jo in v) 76 { 77 if(jo == null) { Debug.Assert(false); continue; } 78 79 PwEntry pe = new PwEntry(true, true); 80 81 ImportUtil.AppendToField(pe, PwDefs.TitleField, 82 jo.GetValue<string>("title"), pd); 83 ImportUtil.AppendToField(pe, PwDefs.UserNameField, 84 jo.GetValue<string>("login"), pd); 85 ImportUtil.AppendToField(pe, PwDefs.PasswordField, 86 jo.GetValue<string>("password"), pd); 87 ImportUtil.AppendToField(pe, PwDefs.UrlField, 88 jo.GetValue<string>("login_url"), pd); 89 ImportUtil.AppendToField(pe, PwDefs.NotesField, 90 jo.GetValue<string>("notes"), pd); 91 92 JsonObject joCustom = jo.GetValue<JsonObject>("custom_fields"); 93 if(joCustom != null) 94 { 95 foreach(KeyValuePair<string, object> kvp in joCustom.Items) 96 { 97 string strValue = (kvp.Value as string); 98 if(strValue == null) { Debug.Assert(false); continue; } 99 100 if(kvp.Key == "TFC:Keeper") 101 EntryUtil.ImportOtpAuth(pe, strValue, pd); 102 else ImportUtil.AppendToField(pe, kvp.Key, strValue, pd); 103 } 104 } 105 106 PwGroup pg = null; 107 JsonObject[] vFolders = jo.GetValueArray<JsonObject>("folders"); 108 if((vFolders != null) && (vFolders.Length >= 1)) 109 { 110 JsonObject joFolder = vFolders[0]; 111 if(joFolder != null) 112 { 113 string strGroup = joFolder.GetValue<string>("folder"); 114 if(!string.IsNullOrEmpty(strGroup)) 115 { 116 strGroup = strGroup.Replace("\\\\", strBackspCode); 117 strGroup = strGroup.Replace("\\", strGroupSep); 118 strGroup = strGroup.Replace(strBackspCode, "\\"); 119 120 if(!dGroups.TryGetValue(strGroup, out pg)) 121 { 122 pg = pd.RootGroup.FindCreateSubTree(strGroup, 123 new string[] { strGroupSep }, true); 124 dGroups[strGroup] = pg; 125 } 126 } 127 else { Debug.Assert(false); } 128 } 129 else { Debug.Assert(false); } 130 } 131 if(pg == null) pg = pd.RootGroup; 132 133 pg.AddEntry(pe, true); 134 } 135 } 136 } 137 } 138