/// <summary> /// Quick way to load a new file /// </summary> /// <param name="profile">Profile with the signon file</param> public static FirefoxSignonsFile Create(FirefoxProfile profile, string password) { FirefoxSignonsFile file = new FirefoxSignonsFile(); file.Load(profile, password); return file; }
/// <summary> /// load this object with signon data related to the supplied profile /// </summary> /// <param name="profile"></param> public void Load(FirefoxProfile profile, string password) { Profile = profile; if (Profile.ProfilePath == null) { throw new Exception("Failed to determine the location of the default Firefox Profile"); } SECStatus result1 = NSS3.NSS_Init(Profile.ProfilePath); // init for profile if (result1 != SECStatus.Success) { Int32 error = NSPR4.PR_GetError(); string errorName = NSPR4.PR_ErrorToName(error); throw new Exception("Failed to initialise profile for load at " + Profile.ProfilePath + " reason " + errorName); } try { IntPtr slot = NSS3.PK11_GetInternalKeySlot(); // get a slot to work with if (slot == IntPtr.Zero) { throw new Exception("Failed to GetInternalKeySlot"); } try { SECStatus result2 = NSS3.PK11_CheckUserPassword(slot, password); if (result2 != SECStatus.Success) { Int32 error = NSPR4.PR_GetError(); string errorName = NSPR4.PR_ErrorToName(error); throw new Exception("Failed to Validate Password: "******"signons.sqlite"); if (File.Exists(signonSqlLitePath)) { if (_SQLite == null) { if (KeePassUtilities.Is64Bit) { _SQLite = Assembly.LoadFrom(Application.StartupPath + @"\WebSiteAdvantageKeePassFirefox-SQLite\4x64\System.Data.SQLite.dll"); } else { _SQLite = Assembly.LoadFrom(Application.StartupPath + @"\WebSiteAdvantageKeePassFirefox-SQLite\4x32\System.Data.SQLite.DLL"); } } IDbConnection connection = (IDbConnection)_SQLite.CreateInstance("System.Data.SQLite.SQLiteConnection"); connection.ConnectionString = "Data Source=" + signonSqlLitePath + ";Version=3;New=False;Compress=True;"; // SQLiteConnection connection = new SQLiteConnection("Data Source=" + signonSqlLitePath + ";Version=3;New=False;Compress=True;"); try { connection.Open(); // SQLiteCommand command = new SQLiteCommand("select id, desc from mains", connection); Type adapterType = _SQLite.GetType("System.Data.SQLite.SQLiteDataAdapter"); IDataAdapter adapter = (IDataAdapter)Activator.CreateInstance(adapterType, new object[] { "SELECT " + "id, hostname, httpRealm, formSubmitURL, usernameField, passwordField, encryptedUsername, encryptedPassword, guid, encType " + "FROM moz_logins ORDER BY hostname", connection }); //SQLiteDataAdapter adapter = new SQLiteDataAdapter( // "SELECT "+ // "id, hostname, httpRealm, formSubmitURL, usernameField, passwordField, encryptedUsername, encryptedPassword, guid, encType "+ // "FROM moz_logins ORDER BY hostname", connection); DataSet dataSet = new DataSet(); adapter.Fill(dataSet); foreach (DataRow row in dataSet.Tables[0].Rows) { FirefoxSignonSite signonSite = null; foreach (DataColumn column in dataSet.Tables[0].Columns) { Debug.WriteLine(column.ColumnName + "=" + (row.IsNull(column) ? "NULL" : row[column].ToString())); } string hostname = row["hostname"].ToString(); if (signonSite == null || signonSite.Site != hostname) { signonSite = new FirefoxSignonSite(); signonSite.Site = hostname; this.SignonSites.Add(signonSite); } ; FirefoxSignon signon = new FirefoxSignon(); signonSite.Signons.Add(signon); string u = NSS3.DecodeAndDecrypt(row["encryptedUsername"].ToString()); Debug.WriteLine("U=" + u); signon.UserName = u; signon.UserNameField = row.IsNull("usernameField") ? String.Empty : row["usernameField"].ToString(); string p = NSS3.DecodeAndDecrypt(row["encryptedPassword"].ToString()); Debug.WriteLine("P=" + p); signon.Password = p; signon.PasswordField = row.IsNull("passwordField") ? String.Empty : row["passwordField"].ToString(); signon.LoginFormDomain = row.IsNull("formSubmitURL") ? String.Empty : row["formSubmitURL"].ToString(); } } finally { connection.Close(); } } else { int version = 3; while (signonFile == null && version > 0) { string signonPath = Path.Combine(Profile.ProfilePath, SignonFileNames[version]); if (File.Exists(signonPath)) { signonFile = signonPath; header = SignonHeaderValues[version]; } else { version--; } } Version = version; if (version == 0) { throw new Exception("Cound not find a signon file to process"); } StreamReader reader = File.OpenText(signonFile); try { // first line is header string line = reader.ReadLine(); if (line == null) { throw new Exception("signon file is empty"); } if (line != header) { throw new Exception("signon file contains an invalid header"); } // lines till the first dot are host excludes while ((line = reader.ReadLine()) != null && line != ".") { Debug.WriteLine("# " + line); Debug.WriteLine("ExcludeHost: " + line); this.ExcludeHosts.Add(line); } FirefoxSignonSite signonSite = null; // read each entry while (line != null) { Debug.WriteLine("## " + line); // here after any dot (.) therefore new site // all new lines pass through if they contain a dot (.) signonSite = null; while ((line = reader.ReadLine()) != null && line != ".") { Debug.WriteLine("# " + line); // first line is host // subsequent lines are pairs of name value // if name starts with * then its a password // values are encrypted if (signonSite == null) // site is reset to null after each dot (.) { signonSite = new FirefoxSignonSite(); signonSite.Site = line; this.SignonSites.Add(signonSite); Debug.WriteLine("Site: " + line); line = reader.ReadLine(); // move to the next line Debug.WriteLine("# " + line); } // else stick to the same line for the next parser, second site entries dont have a dot (.) nor site line if (line != null && line != ".") { FirefoxSignon signon = new FirefoxSignon(); signonSite.Signons.Add(signon); // User field signon.UserNameField = line; Debug.WriteLine("UserNameField: " + signon.UserNameField); if ((line = reader.ReadLine()) != null && line != ".") { Debug.WriteLine("# " + line); // User Value string u = NSS3.DecodeAndDecrypt(line); signon.UserName = u; Debug.WriteLine("UserName: "******".") { Debug.WriteLine("# " + line); // Password field signon.PasswordField = line.TrimStart(new char[] { '*' }); Debug.WriteLine("PasswordField: " + signon.PasswordField); if ((line = reader.ReadLine()) != null && line != ".") { Debug.WriteLine("# " + line); // Password Value string p = NSS3.DecodeAndDecrypt(line); signon.Password = p; Debug.WriteLine("Password: "******".") { Debug.WriteLine("# " + line); // Domain signon.LoginFormDomain = line; Debug.WriteLine("LoginFormDomain: " + signon.LoginFormDomain); if ((line = reader.ReadLine()) != null && line != ".") { Debug.WriteLine("# " + line); // Filler Debug.WriteLine("Filler: " + line); } // note: if there is not a dot (.) after this then its a subsequent entry for the same site } } } } } } } } finally { reader.Close(); } } } finally { NSS3.PK11_FreeSlot(slot); } } finally { NSS3.NSS_Shutdown(); } }
/// <summary> /// load this object with signon data related to the supplied profile /// </summary> /// <param name="profile"></param> public void Load(FirefoxProfile profile,string password) { Profile = profile; if (Profile.ProfilePath == null) throw new Exception("Failed to determine the location of the default Firefox Profile"); SECStatus result1; try { result1 = NSS3.NSS_Init(Profile.ProfilePath); // init for profile } catch (Exception ex) { throw new Exception("Failed to Init Profile: " + ex.Message, ex); } if (result1 != SECStatus.Success) { Int32 error = NSPR4.PR_GetError(); string errorName = NSPR4.PR_ErrorToName(error); throw new Exception("Failed to initialise profile for load at " + Profile.ProfilePath + " reason " + errorName); } try { IntPtr slot = NSS3.PK11_GetInternalKeySlot(); // get a slot to work with if (slot == IntPtr.Zero) throw new Exception("Failed to GetInternalKeySlot"); try { SECStatus result2 = NSS3.PK11_CheckUserPassword(slot, password); if (result2 != SECStatus.Success) { Int32 error = NSPR4.PR_GetError(); string errorName = NSPR4.PR_ErrorToName(error); throw new Exception("Failed to Validate Password: "******"logins.json"); if (File.Exists(loginsJsonPath)) { JObject responseJson = (JObject)JsonConvert.DeserializeObject(File.ReadAllText(loginsJsonPath)); foreach (JObject login in responseJson["logins"]) { FirefoxSignonSite signonSite = null; string hostname = login["hostname"].ToString(); foreach (FirefoxSignonSite site in this.SignonSites) { if (site.Site == hostname) { signonSite = site; break; } } if (signonSite == null) { signonSite = new FirefoxSignonSite(); signonSite.Site = hostname; this.SignonSites.Add(signonSite); } FirefoxSignon signon = new FirefoxSignon(); signonSite.Signons.Add(signon); signon.UserName = NSS3.DecodeAndDecrypt(login["encryptedUsername"].ToString()); signon.UserNameField = login["usernameField"].ToString(); signon.Password = NSS3.DecodeAndDecrypt(login["encryptedPassword"].ToString()); signon.PasswordField = login["passwordField"].ToString(); signon.LoginFormDomain = login["formSubmitURL"].ToString(); Debug.WriteLine(login["id"].ToString()); Debug.WriteLine(login["httpRealm"].ToString()); // null? Debug.WriteLine(login["guid"].ToString()); Debug.WriteLine(login["encType"].ToString()); Debug.WriteLine(login["timeCreated"].ToString()); Debug.WriteLine(login["timeLastUsed"].ToString()); Debug.WriteLine(login["timePasswordChanged"].ToString()); Debug.WriteLine(login["timesUsed"].ToString()); } } else { string signonSqlLitePath = Path.Combine(Profile.ProfilePath, "signons.sqlite"); if (File.Exists(signonSqlLitePath)) { if (_SQLite == null) { if (KeePassUtilities.Is64Bit) { if (!File.Exists(Application.StartupPath + @"\WebSiteAdvantageKeePassFirefox-SQLite\4x64\System.Data.SQLite.dll")) throw new Exception("Failed to find " + Application.StartupPath + @"\WebSiteAdvantageKeePassFirefox-SQLite\4x64\System.Data.SQLite.dll Please re-check the installation process"); try { _SQLite = Assembly.LoadFrom(Application.StartupPath + @"\WebSiteAdvantageKeePassFirefox-SQLite\4x64\System.Data.SQLite.dll"); } catch (Exception ex) { throw new Exception("Failed to load SQLite 64: " + ex.Message, ex); } } else { if (!File.Exists(Application.StartupPath + @"\WebSiteAdvantageKeePassFirefox-SQLite\4x32\System.Data.SQLite.dll")) throw new Exception("Failed to find " + Application.StartupPath + @"\WebSiteAdvantageKeePassFirefox-SQLite\4x32\System.Data.SQLite.dll Please re-check the installation process"); try { _SQLite = Assembly.LoadFrom(Application.StartupPath + @"\WebSiteAdvantageKeePassFirefox-SQLite\4x32\System.Data.SQLite.dll"); } catch (Exception ex) { throw new Exception("Failed to load SQLite 32: " + ex.Message, ex); } } } IDbConnection connection = (IDbConnection)_SQLite.CreateInstance("System.Data.SQLite.SQLiteConnection"); connection.ConnectionString = "Data Source=" + signonSqlLitePath + ";Version=3;New=False;Compress=True;"; // SQLiteConnection connection = new SQLiteConnection("Data Source=" + signonSqlLitePath + ";Version=3;New=False;Compress=True;"); try { connection.Open(); // SQLiteCommand command = new SQLiteCommand("select id, desc from mains", connection); Type adapterType = _SQLite.GetType("System.Data.SQLite.SQLiteDataAdapter"); IDataAdapter adapter = (IDataAdapter)Activator.CreateInstance(adapterType, new object[] {"SELECT "+ "id, hostname, httpRealm, formSubmitURL, usernameField, passwordField, encryptedUsername, encryptedPassword, guid, encType "+ "FROM moz_logins ORDER BY hostname", connection}); //SQLiteDataAdapter adapter = new SQLiteDataAdapter( // "SELECT "+ // "id, hostname, httpRealm, formSubmitURL, usernameField, passwordField, encryptedUsername, encryptedPassword, guid, encType "+ // "FROM moz_logins ORDER BY hostname", connection); DataSet dataSet = new DataSet(); adapter.Fill(dataSet); int rowNumber = 0; foreach (DataRow row in dataSet.Tables[0].Rows) { rowNumber++; FirefoxSignonSite signonSite = null; //foreach (DataColumn column in dataSet.Tables[0].Columns) //{ // Debug.WriteLine(column.ColumnName + "=" + (row.IsNull(column) ? "NULL" : row[column].ToString())); //} string hostname = row["hostname"].ToString(); if (signonSite == null || signonSite.Site != hostname) { signonSite = new FirefoxSignonSite(); signonSite.Site = hostname; this.SignonSites.Add(signonSite); }; string getting = "username"; try { FirefoxSignon signon = new FirefoxSignon(); signonSite.Signons.Add(signon); string u = NSS3.DecodeAndDecrypt(row["encryptedUsername"].ToString()); Debug.WriteLine("U=" + u); signon.UserName = u; getting = "usernamefield for " + u; signon.UserNameField = row.IsNull("usernameField") ? String.Empty : row["usernameField"].ToString(); getting = "password for " + u; string p = NSS3.DecodeAndDecrypt(row["encryptedPassword"].ToString()); Debug.WriteLine("P=" + p); signon.Password = p; getting = "passwordfield for " + u; signon.PasswordField = row.IsNull("passwordField") ? String.Empty : row["passwordField"].ToString(); getting = "formurl for " + u; signon.LoginFormDomain = row.IsNull("formSubmitURL") ? String.Empty : row["formSubmitURL"].ToString(); } catch (Exception ex) { throw new Exception("Could not get " + getting + " on " + hostname + " : " + ex.Message, ex); } } } catch (Exception ex) { throw new Exception("Failed to Query Firefox: " + ex.Message, ex); } finally { connection.Close(); } } else { int version = 3; while (signonFile == null && version > 0) { string signonPath = Path.Combine(Profile.ProfilePath, SignonFileNames[version]); if (File.Exists(signonPath)) { signonFile = signonPath; header = SignonHeaderValues[version]; } else version--; } Version = version; if (version == 0) throw new Exception("Could not find a signon file to process"); StreamReader reader = File.OpenText(signonFile); try { // first line is header string line = reader.ReadLine(); if (line == null) throw new Exception("signon file is empty"); if (line != header) throw new Exception("signon file contains an invalid header"); // lines till the first dot are host excludes while ((line = reader.ReadLine()) != null && line != ".") { Debug.WriteLine("# " + line); Debug.WriteLine("ExcludeHost: " + line); this.ExcludeHosts.Add(line); } FirefoxSignonSite signonSite = null; // read each entry while (line != null) { Debug.WriteLine("## " + line); // here after any dot (.) therefore new site // all new lines pass through if they contain a dot (.) signonSite = null; while ((line = reader.ReadLine()) != null && line != ".") { Debug.WriteLine("# " + line); // first line is host // subsequent lines are pairs of name value // if name starts with * then its a password // values are encrypted if (signonSite == null) // site is reset to null after each dot (.) { signonSite = new FirefoxSignonSite(); signonSite.Site = line; this.SignonSites.Add(signonSite); Debug.WriteLine("Site: " + line); line = reader.ReadLine(); // move to the next line Debug.WriteLine("# " + line); } // else stick to the same line for the next parser, second site entries dont have a dot (.) nor site line if (line != null && line != ".") { FirefoxSignon signon = new FirefoxSignon(); signonSite.Signons.Add(signon); // User field signon.UserNameField = line; Debug.WriteLine("UserNameField: " + signon.UserNameField); if ((line = reader.ReadLine()) != null && line != ".") { Debug.WriteLine("# " + line); // User Value string u = NSS3.DecodeAndDecrypt(line); signon.UserName = u; Debug.WriteLine("UserName: "******".") { Debug.WriteLine("# " + line); // Password field signon.PasswordField = line.TrimStart(new char[] { '*' }); Debug.WriteLine("PasswordField: " + signon.PasswordField); if ((line = reader.ReadLine()) != null && line != ".") { Debug.WriteLine("# " + line); // Password Value string p = NSS3.DecodeAndDecrypt(line); signon.Password = p; Debug.WriteLine("Password: "******".") { Debug.WriteLine("# " + line); // Domain signon.LoginFormDomain = line; Debug.WriteLine("LoginFormDomain: " + signon.LoginFormDomain); if ((line = reader.ReadLine()) != null && line != ".") { Debug.WriteLine("# " + line); // Filler Debug.WriteLine("Filler: " + line); } // note: if there is not a dot (.) after this then its a subsequent entry for the same site } } } } } } } } finally { reader.Close(); } } } } finally { NSS3.PK11_FreeSlot(slot); } } finally { NSS3.NSS_Shutdown(); } }
/// <summary> /// The main routine, called when import is selected /// </summary> /// <param name="pwStorage"></param> /// <param name="sInput"></param> /// <param name="slLogger"></param> public override void Import(PwDatabase pwStorage, System.IO.Stream sInput, KeePassLib.Interfaces.IStatusLogger slLogger) { try { Form1 form = new Form1(); form.Initialise(pwStorage); if (form.ShowDialog() == DialogResult.OK) { // return; bool overwritePassword = form.Overwrite; bool searchWeb = form.GetTitles; bool checkMatches = form.Merge; string masterPassword = form.Password; bool addAutoType = form.AddAutoType; PwIcon iconId = (PwIcon)Enum.Parse(typeof(PwIcon), form.IconName); string profilePath = form.ProfilePath; if (String.IsNullOrEmpty(profilePath)) { MessageBox.Show("No Profile Selected. Use Load More Profiles", "Profile Required", MessageBoxButtons.OK, MessageBoxIcon.Error); Import(pwStorage, sInput, slLogger); // bit of a hack! return; } PwGroup group = form.Group; if (group == null) group = pwStorage.RootGroup; // return; try { InternetAccessor internetAccessor = new InternetAccessor(); slLogger.StartLogging("Importing Firefox Passwords", false); slLogger.SetText("Logging In", LogStatusType.Info); FirefoxProfile profile = new FirefoxProfile(profilePath); profile.Login(masterPassword); slLogger.SetText("Reading Signon file", LogStatusType.Info); FirefoxSignonsFile signonsFile = profile.GetSignonsFile(masterPassword); slLogger.SetText("Processing Passwords", LogStatusType.Info); int count = signonsFile.SignonSites.Count; int pos = 0; // return; // Loop each entry and add it to KeePass foreach (FirefoxSignonSite signonSite in signonsFile.SignonSites) { // keep the user informed of progress pos++; foreach (FirefoxSignon signon in signonSite.Signons) { if (!slLogger.ContinueWork()) // Check if process has been cancelled by the user break; slLogger.SetProgress((uint)(100 * ((double)pos) / ((double)count))); string notes = String.Empty; if (form.IncludeImportNotes) { notes += "Imported from FireFox by the Web Site Advantage FireFox to KeePass Importer" + Environment.NewLine; } // gather the data to import string title = signonSite.Site; string url = signonSite.Site; if (!String.IsNullOrEmpty(signon.LoginFormDomain)) { title = signon.LoginFormDomain; url = signon.LoginFormDomain; } string host = url; try { Uri uri = new Uri(url); host = uri.Host; } catch { } slLogger.SetText(title, LogStatusType.Info); string username = signon.UserName; bool newEntry = true; PwEntry pe = null; if (checkMatches) pe = KeePassHelper.FindMatchingEntry(pwStorage.RootGroup, url, username); if (pe == null) { // create a new entry pe = new PwEntry(true, true); group.AddEntry(pe, true); slLogger.SetText("Created new entry", LogStatusType.AdditionalInfo); } else { newEntry = false; slLogger.SetText("Found matching entry", LogStatusType.AdditionalInfo); } if (newEntry || overwritePassword) { // set the password pe.Strings.Set(PwDefs.PasswordField, new ProtectedString(pwStorage.MemoryProtection.ProtectPassword, signon.Password)); } if (newEntry) { // set all fields pe.Strings.Set(PwDefs.TitleField, new ProtectedString(pwStorage.MemoryProtection.ProtectTitle, title)); pe.Strings.Set(PwDefs.UserNameField, new ProtectedString(pwStorage.MemoryProtection.ProtectUserName, username)); pe.Strings.Set(PwDefs.UrlField, new ProtectedString(pwStorage.MemoryProtection.ProtectUrl, url)); if (!String.IsNullOrEmpty(notes)) pe.Strings.Set(PwDefs.NotesField, new ProtectedString(pwStorage.MemoryProtection.ProtectNotes, notes)); pe.Expires = false; pe.IconId = iconId; // Gatter any extra information... if (!String.IsNullOrEmpty(signon.UserNameField)) pe.Strings.Set("UserNameField", new ProtectedString(false, signon.UserNameField)); if (!String.IsNullOrEmpty(signon.PasswordField)) pe.Strings.Set("PasswordField", new ProtectedString(false, signon.PasswordField)); if (!String.IsNullOrEmpty(signon.LoginFormDomain)) pe.Strings.Set("LoginFormDomain", new ProtectedString(false, signon.LoginFormDomain)); } string webTitle = null; // if new or the title is the same as the url then we should try and get the title if (searchWeb) { // test if new or entry has url as title if ((newEntry || pe.Strings.Get(PwDefs.TitleField).ReadString() == pe.Strings.Get(PwDefs.UrlField).ReadString())) { // get the pages title slLogger.SetText("Accessing website for title", LogStatusType.AdditionalInfo); webTitle = internetAccessor.ScrapeTitle(url); if (!String.IsNullOrEmpty(webTitle)) { slLogger.SetText("Title set from internet to " + webTitle, LogStatusType.AdditionalInfo); pe.Strings.Set(PwDefs.TitleField, new ProtectedString(pwStorage.MemoryProtection.ProtectTitle, webTitle)); } } //else //{ // // Entry has a good title, keep it incase there are other ones for this site // title = pe.Strings.Get(PwDefs.TitleField).ReadString(); //} } // return; if (addAutoType) KeePassHelper.InsertAutoType(pe, "*" + host + "*", KeePassUtilities.AutoTypeSequence()); // return; if (webTitle != null && addAutoType) KeePassHelper.InsertAutoType(pe, KeePassUtilities.AutoTypeWindow(webTitle), KeePassUtilities.AutoTypeSequence()); } } } finally { slLogger.EndLogging(); } } } catch (Exception ex) { ErrorMessage.ShowErrorMessage("Importer", "Import Failed", ex); } }
/// <summary> /// generates a keepass xml file by directly accessing firefoxes passwords /// designed to be used in a thread /// uses the thread /// </summary> private void GenerateUsingFirefox() { try { InternetAccessor internetAccessor = new InternetAccessor(); FirefoxProfile profile = new FirefoxProfile(this.ProfilePath); profile.Login(this.FirefoxMasterPassword); FirefoxSignonsFile signonsFile = profile.GetSignonsFile(this.FirefoxMasterPassword); // the group to store the passwords // the output xml document XmlDocument keePassDocument = new XmlDocument(); XmlElement keePassRootElement = keePassDocument.CreateElement("pwlist"); keePassDocument.AppendChild(keePassRootElement); int current = 0; int max = signonsFile.SignonSites.Count; // loop each input password and generate the output password foreach (FirefoxSignonSite signonSite in signonsFile.SignonSites) { current++; string siteTitle = null; if (GetTitles) siteTitle = internetAccessor.ScrapeTitle(signonSite.Site); foreach (FirefoxSignon signon in signonSite.Signons) { string title = siteTitle == null ? signonSite.Site : siteTitle; if (!String.IsNullOrEmpty(signon.LoginFormDomain)) title = signon.LoginFormDomain; string host = null; try { Uri uri = new Uri(signonSite.Site); host = uri.Host; } catch { } if (GetTitles) { // get the pages title string internetTitle = null; if (String.IsNullOrEmpty(signon.LoginFormDomain) || signon.LoginFormDomain == signonSite.Site) internetTitle = siteTitle; else internetTitle = internetAccessor.ScrapeTitle(signon.LoginFormDomain); if (!String.IsNullOrEmpty(internetTitle)) { title = internetTitle; } } string notes = String.Empty; if (checkBoxIncludeImportNotes.Checked) { notes += "Imported from FireFox by the Web Site Advantage Firefox To KeePass" + Environment.NewLine; } if (GenerateAutoType) { if (this.GetTitles) { notes += Environment.NewLine + "Auto-Type: " + KeePassUtilities.AutoTypeSequence() + Environment.NewLine + (String.IsNullOrEmpty(host) ? String.Empty : "Auto-Type-Window: *" + host + "*" + Environment.NewLine) + "Auto-Type-Window: " + KeePassUtilities.AutoTypeWindow(title) + Environment.NewLine; } else { if (!String.IsNullOrEmpty(host)) { notes += Environment.NewLine + "Auto-Type: " + KeePassUtilities.AutoTypeSequence() + Environment.NewLine + "Auto-Type-Window: *" + host + "*" + Environment.NewLine; } } } string now = XmlConvert.ToString(DateTime.Now, "yyyy-MM-ddTHH:mm:ss"); // create xml XmlElement keePassEntryElement = keePassDocument.CreateElement("pwentry"); keePassRootElement.AppendChild(keePassEntryElement); XmlElement keePassGroupElement = keePassDocument.CreateElement("group"); keePassEntryElement.AppendChild(keePassGroupElement); keePassGroupElement.InnerText = GroupName; // set the group the password gets stored in if (!String.IsNullOrEmpty(GroupName)) keePassGroupElement.SetAttribute("tree", GroupName); XmlElement keePassTitleElement = keePassDocument.CreateElement("title"); keePassEntryElement.AppendChild(keePassTitleElement); keePassTitleElement.InnerText = title; XmlElement keePassUserNameElement = keePassDocument.CreateElement("username"); keePassEntryElement.AppendChild(keePassUserNameElement); keePassUserNameElement.InnerText = signon.UserName; XmlElement keePassURLElement = keePassDocument.CreateElement("url"); keePassEntryElement.AppendChild(keePassURLElement); keePassURLElement.InnerText = signonSite.Site; XmlElement keePassPasswordElement = keePassDocument.CreateElement("password"); keePassEntryElement.AppendChild(keePassPasswordElement); keePassPasswordElement.InnerText = signon.Password; if (!String.IsNullOrEmpty(notes)) { // put other stuff in the notes XmlElement keePassNotesElement = keePassDocument.CreateElement("notes"); keePassEntryElement.AppendChild(keePassNotesElement); // keePassNotesElement.InnerText = XmlCDataSection cd = keePassDocument.CreateCDataSection(notes); keePassNotesElement.AppendChild(cd); } XmlElement keePassUuidElement = keePassDocument.CreateElement("uuid"); keePassEntryElement.AppendChild(keePassUuidElement); keePassUuidElement.InnerText = Guid.NewGuid().ToString().Replace("-", "").ToLower(); // condensed guid XmlElement keePassImageElement = keePassDocument.CreateElement("image"); keePassEntryElement.AppendChild(keePassImageElement); keePassImageElement.InnerText = IconId.ToString(); XmlElement keePassCreatedElement = keePassDocument.CreateElement("creationtime"); keePassEntryElement.AppendChild(keePassCreatedElement); keePassCreatedElement.InnerText = now; XmlElement keePassModifiedElement = keePassDocument.CreateElement("lastmodtime"); keePassEntryElement.AppendChild(keePassModifiedElement); keePassModifiedElement.InnerText = now; XmlElement keePassAccessedElement = keePassDocument.CreateElement("lastaccesstime"); keePassEntryElement.AppendChild(keePassAccessedElement); keePassAccessedElement.InnerText = now; // so it does not expire XmlElement keePassExpiresElement = keePassDocument.CreateElement("expiretime"); keePassEntryElement.AppendChild(keePassExpiresElement); keePassExpiresElement.SetAttribute("expires", "false"); keePassExpiresElement.InnerText = "2999-12-28T23:59:59"; LogProgress((int)((double)(current) * 100 / (double)max)); } } // save the xml. this way the encoding header is included... XmlTextWriter writer = new XmlTextWriter(KeePassFile, Encoding.UTF8); try { writer.Formatting = Formatting.Indented; keePassDocument.Save(writer); } finally { writer.Close(); } this.ThreadFinished(null); } catch (Exception ex) { this.ThreadFinished(ex); } }