TEST_F(ItemDataTest, PasswordHistory) { size_t pwh_max, num_err; PWHistList pwhl; const StringX pw1(L"banana-0rchid"); const StringX pw2(L"banana-1rchid"); const StringX pw3(L"banana-2rchid"); const StringX pw4(L"banana-5rchid"); PWSprefs *prefs = PWSprefs::GetInstance(); prefs->SetPref(PWSprefs::SavePasswordHistory, true); prefs->SetPref(PWSprefs::NumPWHistoryDefault, 3); CItemData di; di.SetCTime(); di.SetPassword(pw1); // first time must be Set, not Update! di.UpdatePassword(pw2); EXPECT_FALSE(di.GetPWHistory().empty()); EXPECT_TRUE(CreatePWHistoryList(di.GetPWHistory(), pwh_max, num_err, pwhl, PWSUtil::TMC_ASC_UNKNOWN)); EXPECT_EQ(0, num_err); EXPECT_EQ(3, pwh_max); EXPECT_EQ(1, pwhl.size()); EXPECT_EQ(pw1, pwhl[0].password); di.UpdatePassword(pw3); EXPECT_TRUE(CreatePWHistoryList(di.GetPWHistory(), pwh_max, num_err, pwhl, PWSUtil::TMC_ASC_UNKNOWN)); EXPECT_EQ(0, num_err); EXPECT_EQ(3, pwh_max); EXPECT_EQ(2, pwhl.size()); EXPECT_EQ(pw1, pwhl[0].password); EXPECT_EQ(pw2, pwhl[1].password); di.UpdatePassword(pw4); EXPECT_TRUE(CreatePWHistoryList(di.GetPWHistory(), pwh_max, num_err, pwhl, PWSUtil::TMC_ASC_UNKNOWN)); EXPECT_EQ(0, num_err); EXPECT_EQ(3, pwh_max); EXPECT_EQ(3, pwhl.size()); EXPECT_EQ(pw1, pwhl[0].password); EXPECT_EQ(pw2, pwhl[1].password); EXPECT_EQ(pw3, pwhl[2].password); di.UpdatePassword(L"Last1"); EXPECT_TRUE(CreatePWHistoryList(di.GetPWHistory(), pwh_max, num_err, pwhl, PWSUtil::TMC_ASC_UNKNOWN)); EXPECT_EQ(0, num_err); EXPECT_EQ(3, pwh_max); EXPECT_EQ(3, pwhl.size()); EXPECT_EQ(pw2, pwhl[0].password); EXPECT_EQ(pw3, pwhl[1].password); EXPECT_EQ(pw4, pwhl[2].password); }
void PasswordSafeSearch::FindMatches(const StringX& searchText, bool fCaseSensitive, SearchPointer& searchPtr, const CItemData::FieldBits& bsFields, bool fUseSubgroups, const wxString& subgroupText, CItemData::FieldType subgroupObject, PWSMatch::MatchRule subgroupFunction, bool subgroupFunctionCaseSensitive, Iter begin, Iter end, Accessor afn) { if (searchText.empty()) return; searchPtr.Clear(); typedef StringX (CItemData::*ItemDataFuncT)() const; struct { CItemData::FieldType type; ItemDataFuncT func; } ItemDataFields[] = { {CItemData::GROUP, &CItemData::GetGroup}, {CItemData::TITLE, &CItemData::GetTitle}, {CItemData::USER, &CItemData::GetUser}, {CItemData::PASSWORD, &CItemData::GetPassword}, // {CItemData::NOTES, &CItemData::GetNotes}, {CItemData::URL, &CItemData::GetURL}, {CItemData::EMAIL, &CItemData::GetEmail}, {CItemData::RUNCMD, &CItemData::GetRunCommand}, {CItemData::AUTOTYPE, &CItemData::GetAutoType}, {CItemData::XTIME_INT, &CItemData::GetXTimeInt}, }; for ( Iter itr = begin; itr != end; ++itr) { const int fn = (subgroupFunctionCaseSensitive? -subgroupFunction: subgroupFunction); if (fUseSubgroups && !afn(itr).Matches(stringT(subgroupText.c_str()), subgroupObject, fn)) continue; bool found = false; for (size_t idx = 0; idx < NumberOf(ItemDataFields) && !found; ++idx) { if (bsFields.test(ItemDataFields[idx].type)) { const StringX str = (afn(itr).*ItemDataFields[idx].func)(); found = fCaseSensitive? str.find(searchText) != StringX::npos: FindNoCase(searchText, str); } } if (!found && bsFields.test(CItemData::NOTES)) { StringX str = afn(itr).GetNotes(); found = fCaseSensitive? str.find(searchText) != StringX::npos: FindNoCase(searchText, str); } if (!found && bsFields.test(CItemData::PWHIST)) { size_t pwh_max, err_num; PWHistList pwhistlist; CreatePWHistoryList(afn(itr).GetPWHistory(), pwh_max, err_num, pwhistlist, PWSUtil::TMC_XML); for (PWHistList::iterator iter = pwhistlist.begin(); iter != pwhistlist.end(); iter++) { PWHistEntry pwshe = *iter; found = fCaseSensitive? pwshe.password.find(searchText) != StringX::npos: FindNoCase(searchText, pwshe.password ); if (found) break; // break out of for loop } pwhistlist.clear(); } if (found) { uuid_array_t uuid; afn(itr).GetUUID(uuid); searchPtr.Add(pws_os::CUUID(uuid)); } } }