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 29 using KeePassLib; 30 using KeePassLib.Interfaces; 31 using KeePassLib.Utility; 32 33 namespace KeePass.DataExchange.Formats 34 { 35 // 2.0.2-4.65.0.5+ 36 internal sealed class LastPassCsv2 : FileFormatProvider 37 { 38 public override bool SupportsImport { get { return true; } } 39 public override bool SupportsExport { get { return false; } } 40 41 public override string FormatName { get { return "LastPass CSV"; } } 42 public override string DefaultExtension { get { return "csv"; } } 43 public override string ApplicationGroup { get { return KPRes.PasswordManagers; } } 44 45 public override bool ImportAppendsToRootGroupOnly { get { return false; } } 46 47 public override Image SmallIcon 48 { 49 get { return KeePass.Properties.Resources.B16x16_Imp_LastPass; } 50 } 51 Import(PwDatabase pwStorage, Stream sInput, IStatusLogger slLogger)52 public override void Import(PwDatabase pwStorage, Stream sInput, 53 IStatusLogger slLogger) 54 { 55 StreamReader sr = new StreamReader(sInput, StrUtil.Utf8, true); 56 string strData = sr.ReadToEnd(); 57 sr.Close(); 58 59 // The Chrome extension of LastPass 4.1.35 encodes some 60 // special characters as XML entities; the web version and 61 // the Firefox extension do not do this 62 strData = strData.Replace(@"<", @"<"); 63 strData = strData.Replace(@">", @">"); 64 strData = strData.Replace(@"&", @"&"); 65 66 CsvOptions opt = new CsvOptions(); 67 opt.BackslashIsEscape = false; 68 69 CsvStreamReaderEx csr = new CsvStreamReaderEx(strData, opt); 70 ImportCsv(csr, pwStorage); 71 } 72 ImportCsv(CsvStreamReaderEx csr, PwDatabase pd)73 private static void ImportCsv(CsvStreamReaderEx csr, PwDatabase pd) 74 { 75 CsvTableEntryReader ctr = new CsvTableEntryReader(pd); 76 77 const string strColUrl = "url"; 78 79 Predicate<string[]> fIsSecNote = delegate(string[] vRow) 80 { 81 string str = ctr.GetData(vRow, strColUrl, string.Empty); 82 return str.Equals("http://sn", StrUtil.CaseIgnoreCmp); 83 }; 84 85 ctr.SetDataAppend("name", PwDefs.TitleField); 86 ctr.SetDataAppend("username", PwDefs.UserNameField); 87 ctr.SetDataAppend("password", PwDefs.PasswordField); 88 89 ctr.SetDataHandler(strColUrl, delegate(string str, PwEntry pe, 90 string[] vContextRow) 91 { 92 if(!fIsSecNote(vContextRow)) 93 ImportUtil.AppendToField(pe, PwDefs.UrlField, str, pd); 94 }); 95 96 ctr.SetDataHandler("extra", delegate(string str, PwEntry pe, 97 string[] vContextRow) 98 { 99 if(fIsSecNote(vContextRow) && str.StartsWith("NoteType:", 100 StrUtil.CaseIgnoreCmp)) 101 { 102 AddNoteFields(pe, str, pd); 103 return; 104 } 105 106 ImportUtil.AppendToField(pe, PwDefs.NotesField, str, pd); 107 }); 108 109 ctr.SetDataHandler("grouping", delegate(string str, PwEntry pe, 110 string[] vContextRow) 111 { 112 if(str.Length == 0) return; 113 114 PwGroup pg = pd.RootGroup.FindCreateSubTree(str, 115 new string[1] { "\\" }, true); 116 pg.AddEntry(pe, true); 117 }); 118 119 ctr.SetDataHandler("fav", delegate(string str, PwEntry pe, 120 string[] vContextRow) 121 { 122 if(StrUtil.StringToBool(str)) pe.AddTag(PwDefs.FavoriteTag); 123 }); 124 125 ctr.Read(csr); 126 } 127 AddNoteFields(PwEntry pe, string strNotes, PwDatabase pd)128 private static void AddNoteFields(PwEntry pe, string strNotes, 129 PwDatabase pd) 130 { 131 string strData = StrUtil.NormalizeNewLines(strNotes, false); 132 string[] vLines = strData.Split('\n'); 133 134 string strFieldName = PwDefs.NotesField; 135 bool bNotesFound = false; 136 foreach(string strLine in vLines) 137 { 138 int iFieldLen = strLine.IndexOf(':'); 139 int iDataOffset = 0; 140 if((iFieldLen > 0) && !bNotesFound) 141 { 142 string strRaw = strLine.Substring(0, iFieldLen).Trim(); 143 string strField = ImportUtil.MapNameToStandardField(strRaw, false); 144 if(string.IsNullOrEmpty(strField)) strField = strRaw; 145 146 if(strField.Length != 0) 147 { 148 strFieldName = strField; 149 iDataOffset = iFieldLen + 1; 150 151 bNotesFound |= (strRaw == "Notes"); // Not PwDefs.NotesField 152 } 153 } 154 155 ImportUtil.AppendToField(pe, strFieldName, strLine.Substring( 156 iDataOffset), pd); 157 } 158 } 159 } 160 } 161