55{
56 PasswordLeakResult result;
57
58 if (password.empty())
59 return result;
60
62 if (hash.size() != 40)
63 return result;
64
65 const std::string prefix = hash.substr(0, 5);
66 const std::string suffix = hash.substr(5);
67
68 const std::string url =
69 "https://api.pwnedpasswords.com/range/" + prefix;
70
71 std::map<std::string, std::string> headers;
72 headers["User-Agent"] = "BastionGuard/IdentityLeak";
73 headers["Accept"] = "text/plain";
74 headers["Add-Padding"] = "true";
75
78 return result;
79
80 std::istringstream stream(resp.
body);
82
83 while (std::getline(stream, line)) {
85
86 const auto pos =
line.find(
':');
87 if (pos == std::string::npos)
88 continue;
89
90 const std::string_view lineSuffix(
line.data(), pos);
91 if (lineSuffix.size() != suffix.size())
92 continue;
93
94 if (lineSuffix == suffix) {
95
96 std::string_view countPart(
line.data() + pos + 1,
97 line.size() - (pos + 1));
98
99 unsigned long long count = 0;
100 for (char ch : countPart) {
101 if (!std::isdigit(static_cast<unsigned char>(ch)))
102 break;
103 count = count * 10ULL + static_cast<unsigned long long>(ch - '0');
104 }
105
107 result.
count = count;
108 break;
109 }
110 }
111
112 return result;
113}
static std::string sha1HexUpper(const std::string &input)
static void rtrim_crlf(std::string &s)
static HttpResponse get(const std::string &url, const std::map< std::string, std::string > &headers={}, long timeoutSeconds=20)