private Account[] ParseAccounts(List <ParserHelper.Chunk> chunks, byte[] encryptionKey) { var accounts = new List <Account>(chunks.Count(i => i.Id == "ACCT")); SharedFolder folder = null; var rsaKey = new RSAParameters(); foreach (var i in chunks) { switch (i.Id) { case "ACCT": var account = ParserHelper.Parse_ACCT(i, folder == null ? encryptionKey : folder.EncryptionKey, folder); if (account != null) { accounts.Add(account); } break; case "PRIK": rsaKey = ParserHelper.Parse_PRIK(i, encryptionKey); break; case "SHAR": folder = ParserHelper.Parse_SHAR(i, encryptionKey, rsaKey); break; } } return(accounts.ToArray()); }
public static string MakeAccountPath(string group, SharedFolder folder) { if (folder == null) { return(string.IsNullOrEmpty(group) ? "(none)" : group); } return(string.IsNullOrEmpty(group) ? folder.Name : string.Format("{0}\\{1}", folder.Name, group)); }
// May return null when the chunk does not represent an account. // All secure notes are ACCTs but not all of them store account information. // // TODO: Add a test for the folder case! // TODO: Add a test case that covers secure note account! public static Account Parse_ACCT(Chunk chunk, byte[] encryptionKey, SharedFolder folder = null) { Debug.Assert(chunk.Id == "ACCT"); return(WithBytes(chunk.Payload, reader => { var placeholder = "decryption failed"; // Read all items var id = ReadItem(reader).ToUtf8(); var name = DecryptAes256Plain(ReadItem(reader), encryptionKey, placeholder); var group = DecryptAes256Plain(ReadItem(reader), encryptionKey, placeholder); var url = ReadItem(reader).ToUtf8().DecodeHex().ToUtf8(); // Ignore "group" accounts. They have no credentials. if (url == "http://group") { return null; } var notes = DecryptAes256Plain(ReadItem(reader), encryptionKey, placeholder); 2.Times(() => SkipItem(reader)); var username = DecryptAes256Plain(ReadItem(reader), encryptionKey, placeholder); var password = DecryptAes256Plain(ReadItem(reader), encryptionKey, placeholder); 2.Times(() => SkipItem(reader)); var secureNoteMarker = ReadItem(reader).ToUtf8(); // Parse secure note if (secureNoteMarker == "1") { var type = ""; ParseSecureNoteServer(notes, ref type, ref url, ref username, ref password); // Only the some secure notes contain account-like information if (!AllowedSecureNoteTypes.Contains(type)) { return null; } } // Adjust the path to include the group and the shared folder, if any. var path = MakeAccountPath(group, folder); return new Account(id, name, username, password, url, path); })); }
// May return null when the chunk does not represent an account. // All secure notes are ACCTs but not all of them store account information. // // TODO: Add a test for the folder case! // TODO: Add a test case that covers secure note account! public static Account Parse_ACCT(Chunk chunk, byte[] encryptionKey, SharedFolder folder = null) { Debug.Assert(chunk.Id == "ACCT"); return(WithBytes(chunk.Payload, reader => { var placeholder = "decryption failed"; // Read all items var id = ReadItem(reader).ToUtf8(); var name = DecryptAes256Plain(ReadItem(reader), encryptionKey, placeholder); var group = DecryptAes256Plain(ReadItem(reader), encryptionKey, placeholder); var url = ReadItem(reader).ToUtf8().DecodeHex().ToUtf8(); var notes = DecryptAes256Plain(ReadItem(reader), encryptionKey, placeholder); 2.Times(() => SkipItem(reader)); var username = DecryptAes256Plain(ReadItem(reader), encryptionKey, placeholder); var password = DecryptAes256Plain(ReadItem(reader), encryptionKey, placeholder); 2.Times(() => SkipItem(reader)); var secureNoteMarker = ReadItem(reader).ToUtf8(); // Parse secure note if (secureNoteMarker == "1") { var type = ""; ParseSecureNoteServer(notes, ref type, ref url, ref username, ref password); // Only the some secure notes contain account-like information if (!AllowedSecureNoteTypes.Contains(type)) { return null; } } // Override the group name with the shared folder name if any. if (folder != null) { group = folder.Name; } return new Account(id, name, username, password, url, group); })); }