Skip to content

Commit f829808

Browse files
committed
pwned-passwords 1.0.0
0 parents  commit f829808

21 files changed

+4333
-0
lines changed

.vscode/settings.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"python.testing.unittestArgs": [
3+
"-v",
4+
"-s",
5+
"./tests",
6+
"-p",
7+
"test_*.py"
8+
],
9+
"python.testing.pytestEnabled": false,
10+
"python.testing.unittestEnabled": true,
11+
"[python]": {
12+
"editor.defaultFormatter": "charliermarsh.ruff"
13+
},
14+
"[toml]": {
15+
"editor.formatOnSave": true
16+
}
17+
}

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 Caleb
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# pwned-passwords
2+
> Pwned Passwords API wrapper
3+
4+
## Purpose
5+
This project provides a simple Python API around the
6+
[Pwned Passwords API](https://haveibeenpwned.com/API/v3#PwnedPasswords).
7+
8+
## Usage
9+
```py
10+
import pwned_passwords
11+
12+
13+
# Check a password for pwned-ness
14+
# password: bytes | str
15+
result: pwned_passwords.PwnedResults = pwned_passwords.check("password")
16+
17+
# Check the results
18+
print(result.is_pwned) # bool
19+
print(result.times_pwned) # int
20+
21+
# options: pwned_passwords.PwnedOptions | None
22+
result: pwned_passwords.PwnedResults = pwned_passwords.check(
23+
"password",
24+
options=pwned_passwords.PwnedOptions(
25+
add_padding=True, # Pad the API response with empty records
26+
mode="ntlm", # Get NTLM hashes instead of SHA-1
27+
get_hashes=True, # By default, the response hashes are not provided
28+
),
29+
)
30+
31+
# Print all of the hashes
32+
print(result.hashes) # list[pwned_passwords.PwnedHash]
33+
```
34+
35+
**Note**: NTLM hash support is dependent on platform support, with fallback support provided by [pyspnego](https://pypi.org/project/pyspnego/). It is recommended to stick with the SHA-1 hash default.
36+
37+
38+
## License
39+
Pwned Passwords API, created and maintained at [Have I Been Pwned](https://haveibeenpwned.com/).
40+
41+
Have I Been Pwned is not affiliated with nor endorses this project.
42+
43+
2023 [MIT](LICENSE)
4.66 KB
Binary file not shown.

poetry.lock

Lines changed: 319 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pwned_passwords/__init__.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from . import _utils
2+
3+
# Re-export the structs for easier library consumption
4+
from ._structs import PwnedHash, PwnedOptions, PwnedResults
5+
6+
7+
__all__ = ["check", "check_async", "PwnedHash", "PwnedOptions", "PwnedResults"]
8+
9+
10+
def check(password: bytes | str, /, options: PwnedOptions | None = None) -> PwnedResults:
11+
"""Check a password against the Pwned Passwords API.
12+
13+
https://haveibeenpwned.com/API/v3#PwnedPasswords
14+
"""
15+
# If API options are not given, use the defaults
16+
if not isinstance(options, PwnedOptions):
17+
options = PwnedOptions()
18+
19+
# The mode option not only changes the format the hashes are returned in,
20+
# but also which format we must provide. This means we technically can have
21+
# a mismatch in has sent vs received, but we don't want that, truly
22+
hash = _utils.generate_hash(options.mode, password)
23+
24+
# Get the password out of memory now that we have the hash
25+
del password
26+
27+
# Build out the API calling options
28+
headers, params = _utils.build_request_options(options)
29+
30+
# Call out to the API and parse out the results
31+
response_text = _utils.make_request(hash[:5], headers=headers, params=params)
32+
return _utils.parse_response(hash, response_text, options.get_hashes)
1.3 KB
Binary file not shown.
1.44 KB
Binary file not shown.
4.5 KB
Binary file not shown.

pwned_passwords/_structs.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from typing import NamedTuple
2+
3+
4+
__all__ = ["PwnedHash", "PwnedOptions", "PwnedResults"]
5+
6+
7+
class PwnedHash(NamedTuple):
8+
"""Returned a hash from a Pwned Passwords API check."""
9+
10+
suffix: str
11+
count: int
12+
13+
14+
class PwnedOptions(NamedTuple):
15+
"""Pwned Passwords API options."""
16+
17+
add_padding: bool = False
18+
mode: str = "sha1"
19+
20+
# Library-specific option
21+
get_hashes: bool = False
22+
23+
24+
class PwnedResults(NamedTuple):
25+
"""Report the Pwned Passwords results."""
26+
27+
is_pwned: bool
28+
times_pwned: int
29+
hashes: list[PwnedHash]

0 commit comments

Comments
 (0)