add keystroke analyzer

This commit is contained in:
Paul Pan 2023-11-03 21:11:37 +08:00
parent 3e70825234
commit 0a1db4e1ae
4 changed files with 131 additions and 0 deletions

View File

@ -58,7 +58,9 @@ include_directories(password-analyzer PRIVATE ${CMAKE_BINARY_DIR}/external)
set(COMMON_SOURCES
defs.hpp
utils.cpp
stat_keystroke.cpp
stat_length.cpp
stat_struct.cpp
)
set(COMMON_LIBRARIES
magic_enum::magic_enum

View File

@ -16,10 +16,18 @@ using std::operator""sv;
enum class DataSource { CSDN, YAHOO };
struct Cord {
int x, y;
bool operator==(const Cord &rhs) const { return x == rhs.x && y == rhs.y; }
};
bool is_num(char c);
bool is_alpha(char c);
std::generator<std::string> passwords(const DataSource &source);
void stat_keystroke(const DataSource &source);
void stat_length(const DataSource &source);
void stat_struct(const DataSource &source);
#endif // DEFS_HPP

79
stat_keystroke.cpp Normal file
View File

@ -0,0 +1,79 @@
#include <algorithm>
#include <map>
#include <vector>
#include "defs.hpp"
const char keyboard[2][4][15] = {{"`1234567890-=", "\0qwertyuiop[]\\", "\0asdfghjkl;'", "\0zxcvbnm,./"},
{"~!@#$%^&*()_+", "\0QWERTYUIOP{}|", "\0ASDFGHJKL:\"", "\0ZXCVBNM<>?"}};
auto string_to_cord(const std::string &password) -> std::vector<Cord> {
std::vector<Cord> ret;
for (auto ch : password) {
for (const auto &kbd : keyboard) {
for (int j = 0; j < 4; ++j) {
auto bgn = kbd[j][0] == '\0' ? 1 : 0;
auto pos = std::strchr(kbd[j] + bgn, ch);
if (pos) {
ret.push_back({j, static_cast<int>(pos - kbd[j])});
break;
}
}
}
}
return ret;
}
auto cord_to_string(const std::vector<Cord> &cords) -> std::string {
std::ostringstream ret;
for (auto cord : cords) {
auto ch = keyboard[0][cord.x][cord.y]; // only consider not shifted keyboard
if (ch != '\0')
ret << ch;
else
spdlog::warn("cord_to_string: invalid cord: ({}, {})", cord.x, cord.y);
}
return ret.str();
}
auto is_neighbour(const Cord &a, const Cord &b) -> bool {
auto [x1, y1] = a;
auto [x2, y2] = b;
auto same = x1 == x2 && y1 == y2; // NOTE: consider the case of `same` is true
return !same && std::abs(x1 - x2) <= 1 && std::abs(y1 - y2) <= 1;
}
void stat_keystroke(const DataSource &source) {
spdlog::info("stat_keystroke({})", magic_enum::enum_name(source));
std::map<std::string, size_t> stat;
for (auto const &password : passwords(source)) {
if (password.size() <= 1) continue;
auto cords = string_to_cord(password);
if (cords.size() <= 1) continue;
std::string longest;
size_t max_len = 0, cur_len = 1;
for (int i = 0; i < cords.size() - 1; i++) {
auto ok = is_neighbour(cords[i], cords[i + 1]);
if (ok) {
cur_len++;
} else {
if (cur_len > max_len) {
max_len = cur_len;
longest = cord_to_string(
std::vector<Cord>(cords.begin() + (int)(i - cur_len + 1), cords.begin() + i + 1));
}
cur_len = 1;
}
}
if (max_len >= 4) stat[longest]++;
}
std::vector<std::pair<std::string, size_t>> vec(stat.begin(), stat.end());
std::sort(vec.begin(), vec.end(), [](auto const &lhs, auto const &rhs) { return lhs.second > rhs.second; });
for (auto const &[length, count] : vec | std::views::take(10)) spdlog::info("{}: {}", length, count);
}

42
stat_struct.cpp Normal file
View File

@ -0,0 +1,42 @@
#include <algorithm>
#include <map>
#include <sstream>
#include <vector>
#include "defs.hpp"
std::string get_struct(const std::string &password) {
auto mapper = [](char c) {
if (is_num(c))
return 'D';
else if (is_alpha(c))
return 'L';
else
return 'S';
};
auto v = password | std::views::transform(mapper);
std::ostringstream ret;
for (auto cur = v.begin(); cur != v.end();) {
auto ch = *cur;
auto nxt = std::adjacent_find(cur, v.end(), std::not_equal_to<>());
auto end = nxt == v.end();
ret << ch << std::distance(cur, nxt) + !end;
cur = end ? nxt : std::next(nxt);
}
return ret.str();
}
void stat_struct(const DataSource &source) {
spdlog::info("stat_struct({})", magic_enum::enum_name(source));
std::map<std::string, size_t> stat;
for (auto const &password : passwords(source)) ++stat[get_struct(password)];
std::vector<std::pair<std::string, size_t>> vec(stat.begin(), stat.end());
std::sort(vec.begin(), vec.end(), [](auto const &lhs, auto const &rhs) { return lhs.second > rhs.second; });
for (auto const &[struct_, count] : vec | std::views::take(10)) spdlog::info("{}: {}", struct_, count);
}