diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 59aaa6b..f9ec440 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,27 +7,25 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [2.7, 3.6, 3.7, 3.8, 3.9] + python-version: + ["3.8.*", "3.9.*", "3.10.*", "3.11.*", "3.12.*", "3.13.*"] steps: - - uses: actions/checkout@master - - name: set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -U setuptools - pip install -r requirements.txt - pip install . - - name: Run mypy - if: "matrix.python-version != '2.7' && matrix.python-version != 'pypy2'" - run: | + - uses: actions/checkout@master + - name: set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -U setuptools + pip install -r requirements.txt + pip install . + pip install tox + - name: Run mypy + run: | pip install -U mypy mypy -p zxcvbn --ignore-missing-imports - - name: Run tests - run: | - pytest -v - - name: Test Compatibility - run: | - python tests/test_compatibility.py tests/password_expected_value.json + - name: Run tests + run: | + tox diff --git a/README.rst b/README.rst index fb3d411..6c0a08b 100644 --- a/README.rst +++ b/README.rst @@ -16,7 +16,7 @@ time. Features -------- -- **Tested in Python versions 2.7, 3.6-3.9** +- **Tested in Python versions 3.8-3.13** - Accepts user data to be added to the dictionaries that are tested against (name, birthdate, etc) - Gives a score to the password, from 0 (terrible) to 4 (great) - Provides feedback on the password and ways to improve it @@ -103,6 +103,18 @@ Output: }], } +Another optional argument is ``max_length``, allowing override of the default max password length of 72. +.. code:: python + + from zxcvbn import zxcvbn + + results = zxcvbn('JohnSmith321', user_inputs=['John', 'Smith'], max_length=88) + +.. warning:: + + We strongly advise against setting ``max_length`` greater than 72, + as it can lead to long processing times and may leave server-side applications open + to denial-of-service scenarios. Custom Ranked Dictionaries -------------------------- @@ -121,6 +133,7 @@ In order to support more languages or just add password dictionaries of your own These lists will be added to the current ones, but you can also overwrite the current ones if you wish. The lists you add should be in order of how common the word is used with the most common words appearing first. + CLI ~~~ @@ -128,11 +141,13 @@ You an also use zxcvbn from the command line:: echo 'password' | zxcvbn --user-input | jq +You can include a ``--max-length`` argument:: + echo '' | zxcvbn --max-length 142 + You can also execute the zxcvbn module:: echo 'password' | python -m zxcvbn --user-input | jq - Contribute ---------- diff --git a/requirements.txt b/requirements.txt index e0fa86f..5ac1407 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,5 @@ -pytest==3.5.0 +# For older Python versions < 3.6 install Pytest 3.5.0 +pytest==3.5.0; python_version < "3.6" + +# For Python 3.6+, install a more modern Pytest: +pytest==7.4.2; python_version >= "3.6" diff --git a/tests/l33t_exploit_test.py b/tests/l33t_exploit_test.py new file mode 100644 index 0000000..362d204 --- /dev/null +++ b/tests/l33t_exploit_test.py @@ -0,0 +1,12 @@ +import pytest +from zxcvbn import zxcvbn + +# Test ACsploit-generated password targeting zxcvbn's l33t matching algorithm +# (see https://github.com/GoSimpleLLC/nbvcxz/issues/60) +def test_l33t_exploit(): + + password = "4@8({[ max_length: + raise ValueError(f"Password exceeds max length of {max_length} characters.") + try: # Python 2 string types basestring = (str, unicode) diff --git a/zxcvbn/__main__.py b/zxcvbn/__main__.py index 8738197..0f4ee91 100644 --- a/zxcvbn/__main__.py +++ b/zxcvbn/__main__.py @@ -16,6 +16,12 @@ help='user data to be added to the dictionaries that are tested against ' '(name, birthdate, etc)', ) +parser.add_argument( + '--max-length', + default=72, + type=int, + help='Override password max length (default: 72)' +) class JSONEncoder(json.JSONEncoder): def default(self, o): @@ -36,7 +42,7 @@ def cli(): else: password = getpass.getpass() - res = zxcvbn(password, user_inputs=args.user_input) + res = zxcvbn(password, user_inputs=args.user_input, max_length=args.max_length) json.dump(res, sys.stdout, indent=2, cls=JSONEncoder) sys.stdout.write('\n')