pax_global_header00006660000000000000000000000064147576644530014537gustar00rootroot0000000000000052 comment=faeea49e33c971f28b505c2d8ba8384b56802f27 djangorestframework-simplejwt-5.5.0/000077500000000000000000000000001475766445300176405ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/.coveragerc000066400000000000000000000002001475766445300217510ustar00rootroot00000000000000[run] omit = rest_framework_simplejwt/token_blacklist/admin.py rest_framework_simplejwt/token_blacklist/apps.py djangorestframework-simplejwt-5.5.0/.github/000077500000000000000000000000001475766445300212005ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/.github/dependabot.yaml000066400000000000000000000003171475766445300241720ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "daily" assignees: - "djangorestframework-simplejwt" labels: - "dependencies" djangorestframework-simplejwt-5.5.0/.github/workflows/000077500000000000000000000000001475766445300232355ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/.github/workflows/i18n.yml000066400000000000000000000023271475766445300245430ustar00rootroot00000000000000name: Update locale files on: push: branches: - main - master jobs: locale-updater: permissions: pull-requests: write contents: write if: github.repository == 'jazzband/djangorestframework-simplejwt' name: Locale updater runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.12' cache: 'pip' cache-dependency-path: setup.py - name: Install dependencies run: | sudo apt-get install -y gettext python -m pip install --upgrade pip wheel setuptools pip install -e .[dev] - name: Run locale Update Script working-directory: rest_framework_simplejwt run: python ../scripts/i18n_updater.py - name: Create Pull Request uses: peter-evans/create-pull-request@v7 with: branch: i18n-auto-update title: "[i18n] Update" body: "Updated locale files on trunk" commit-message: "Update locale files" add-paths: rest_framework_simplejwt/locale/** delete-branch: true djangorestframework-simplejwt-5.5.0/.github/workflows/release.yml000066400000000000000000000026131475766445300254020ustar00rootroot00000000000000name: Release on: push: tags: - '*' jobs: build: if: github.repository == 'jazzband/djangorestframework-simplejwt' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.9' - name: Install dependencies run: | sudo apt-get install -y gettext python -m pip install -U pip python -m pip install -U setuptools twine wheel pip install -e .[dev] - name: Check locale working-directory: rest_framework_simplejwt run: | echo "Checking if locale files need updating. If they do, cd rest_framework_simplejwt && run python ../scripts/i18n_updater.py" python ../scripts/i18n_updater.py git diff --exit-code - name: Build package run: | python setup.py --version python setup.py sdist --format=gztar bdist_wheel twine check dist/* - name: Upload packages to Jazzband if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') uses: pypa/gh-action-pypi-publish@release/v1 with: user: jazzband password: ${{ secrets.JAZZBAND_RELEASE_KEY }} repository_url: https://jazzband.co/projects/djangorestframework-simplejwt/upload djangorestframework-simplejwt-5.5.0/.github/workflows/test.yml000066400000000000000000000031311475766445300247350ustar00rootroot00000000000000name: Test on: push: branches: - main - master pull_request: jobs: build: name: build (Python ${{ matrix.python-version }}, Django ${{ matrix.django-version }}, DRF ${{ matrix.drf-version }}) runs-on: ubuntu-latest strategy: fail-fast: false max-parallel: 5 matrix: python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] django-version: ['4.2', '5.0', '5.1'] drf-version: ['3.14', '3.15'] exclude: - drf-version: '3.14' django-version: '5.0' - drf-version: '3.14' django-version: '5.1' steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Get pip cache dir id: pip-cache run: | echo "::set-output name=dir::$(pip cache dir)" - name: Cache uses: actions/cache@v4 with: path: ${{ steps.pip-cache.outputs.dir }} key: ${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.py') }} restore-keys: | ${{ matrix.python-version }}-v1- - name: Install dependencies run: | python -m pip install --upgrade pip python -m pip install --upgrade tox tox-gh-actions - name: Tox tests run: | tox -v env: DJANGO: ${{ matrix.django-version }} DRF: ${{ matrix.drf-version }} - name: Upload coverage uses: codecov/codecov-action@v5 with: name: Python ${{ matrix.python-version }} djangorestframework-simplejwt-5.5.0/.gitignore000066400000000000000000000040311475766445300216260ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ cover/ # Translations # *.mo Needs to come with the package *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder .pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # PEP 582; used by e.g. github.com/David-OConnor/pyflow __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ .idea/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # pytype static type analyzer .pytype/ # Cython debug symbols cython_debug/ djangorestframework-simplejwt-5.5.0/.pre-commit-config.yaml000066400000000000000000000027441475766445300241300ustar00rootroot00000000000000repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: 'v5.0.0' hooks: - id: check-merge-conflict - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.9.7 hooks: - id: ruff types_or: [ python, pyi ] args: [--select, I, --fix,] files: "^tests/|^rest_framework_simplejwt/" - id: ruff-format types_or: [python, pyi] files: "^tests/|^rest_framework_simplejwt/" - repo: https://github.com/asottile/yesqa rev: v1.5.0 hooks: - id: yesqa - repo: https://github.com/pre-commit/pre-commit-hooks rev: 'v5.0.0' hooks: - id: end-of-file-fixer exclude: >- ^docs/[^/]*\.svg$ - id: requirements-txt-fixer - id: trailing-whitespace types: [python] - id: file-contents-sorter files: | CONTRIBUTORS.txt| docs/spelling_wordlist.txt| .gitignore| .gitattributes - id: check-case-conflict - id: check-json - id: check-xml - id: check-executables-have-shebangs - id: check-toml - id: check-xml - id: check-yaml - id: debug-statements - id: check-added-large-files - id: check-symlinks - id: debug-statements - id: detect-aws-credentials args: ['--allow-missing-credentials'] - id: detect-private-key exclude: ^tests/ - repo: https://github.com/asottile/pyupgrade rev: 'v3.19.1' hooks: - id: pyupgrade args: ['--py39-plus', '--keep-mock'] - repo: https://github.com/Lucas-C/pre-commit-hooks-markup rev: v1.0.1 hooks: - id: rst-linter files: >- ^[^/]+[.]rst$ djangorestframework-simplejwt-5.5.0/.readthedocs.yml000066400000000000000000000006451475766445300227330ustar00rootroot00000000000000version: 2 # Set the version of Python and other tools you might need build: os: ubuntu-20.04 tools: python: "3.12" python: install: # Install dependencies from setup.py . - method: setuptools path: . # Build documentation in the docs/ directory with Sphinx sphinx: configuration: docs/conf.py # If using Sphinx, optionally build your docs in additional formats such as PDF formats: - pdf djangorestframework-simplejwt-5.5.0/CHANGELOG.md000066400000000000000000000430351475766445300214560ustar00rootroot00000000000000## 5.5.0 * Cap PyJWT version to <2.10.0 to avoid incompatibility with subject claim type requirement by @grayver in https://github.com/jazzband/djangorestframework-simplejwt/pull/843 * Add specific "token expired" exceptions by @vainu-arto in https://github.com/jazzband/djangorestframework-simplejwt/pull/830 * Fix user_id type mismatch when user claim is not pk by @jdg-journeyfront in https://github.com/jazzband/djangorestframework-simplejwt/pull/851 * Caching signing key by @henryfool91 in https://github.com/jazzband/djangorestframework-simplejwt/pull/859 * Adds new refresh tokens to OutstandingToken db. by @thecarpetjasp in https://github.com/jazzband/djangorestframework-simplejwt/pull/866 ## 5.4.0 * Changed string formatting in views by @Egor-oop in https://github.com/jazzband/djangorestframework-simplejwt/pull/750 * Enhance BlacklistMixin with Generic Type for Accurate Type Inference by @Dresdn in https://github.com/jazzband/djangorestframework-simplejwt/pull/768 * Improve type of `Token.for_user` to allow subclasses by @sterliakov in https://github.com/jazzband/djangorestframework-simplejwt/pull/776 * Fix the `Null` value of the `OutstandingToken` of the `BlacklistMixin.blacklist` by @JaeHyuckSa in https://github.com/jazzband/djangorestframework-simplejwt/pull/806 * Fix: Disable refresh token for inactive user. by @ajay09 in https://github.com/jazzband/djangorestframework-simplejwt/pull/814 * Add option to allow inactive user authentication and token generation by @zxkeyy in https://github.com/jazzband/djangorestframework-simplejwt/pull/834 * Drop Django <4.2, DRF <3.14, Python <3.9 by @Andrew-Chen-Wang in https://github.com/jazzband/djangorestframework-simplejwt/pull/839 * Note, many deprecated versions are only officially not supported but probably still work fine. * Add support for EdDSA and other algorithms in jwt.algorithms.requires_cryptography (#822) https://github.com/jazzband/djangorestframework-simplejwt/pull/823 ## 5.3.1 ## What's Changed * Remove EOL Python, Django and DRF version support by @KOliver94 in [#754](https://github.com/jazzband/djangorestframework-simplejwt/pull/754) * Declare support for type checking (closes #664) by @PedroPerpetua in [#760](https://github.com/jazzband/djangorestframework-simplejwt/pull/760) * Remove usages of deprecated datetime.utcnow() and datetime.utcfromtimestamp() in [#765](https://github.com/jazzband/djangorestframework-simplejwt/pull/765) #### Translation Updates: * Update Korean translations by @TGoddessana in https://github.com/jazzband/djangorestframework-simplejwt/pull/753 ## 5.3.0 #### Notable Changes: * Added support for Python 3.11 by @joshuadavidthomas [#636](https://github.com/jazzband/djangorestframework-simplejwt/pull/636) * Added support for Django 4.2 by @johnthagen [#711](https://github.com/jazzband/djangorestframework-simplejwt/pull/711) * Added support for DRF 3.14 by @Andrew-Chen-Wang [#623](https://github.com/jazzband/djangorestframework-simplejwt/pull/623) * Added Inlang to facilitate community translations by @jannesblobel [#662](https://github.com/jazzband/djangorestframework-simplejwt/pull/662) * Revoke access token if user password is changed by @mahdirahimi1999 [#719](https://github.com/jazzband/djangorestframework-simplejwt/pull/719) * Added type hints by @abczzz13 [#683](https://github.com/jazzband/djangorestframework-simplejwt/pull/683) * Improved testing by @kiraware [#688](https://github.com/jazzband/djangorestframework-simplejwt/pull/688) * Removed support for Django 2.2 by @kiraware [#688](https://github.com/jazzband/djangorestframework-simplejwt/pull/688) #### Documentation: * Added write_only=True to TokenBlacklistSerializer's refresh field for better doc generation by @Yaser-Amiri [#699](https://github.com/jazzband/djangorestframework-simplejwt/pull/699) * Updated docs on serializer customization by @2ykwang [#668](https://github.com/jazzband/djangorestframework-simplejwt/pull/668) #### Translation Updates: * Updated translations for Persian (fa) language by @mahdirahimi1999 [#723](https://github.com/jazzband/djangorestframework-simplejwt/pull/723) and https://github.com/jazzband/djangorestframework-simplejwt/pull/708 * Updated translations for Indonesian (id) language by @kiraware [#685](https://github.com/jazzband/djangorestframework-simplejwt/pull/685) * Added Arabic language translations by @iamjazzar [#690](https://github.com/jazzband/djangorestframework-simplejwt/pull/690) * Added Hebrew language translations by @elam91 [#679](https://github.com/jazzband/djangorestframework-simplejwt/pull/679) * Added Slovenian language translations by @banDeveloper [#645](https://github.com/jazzband/djangorestframework-simplejwt/pull/645) ## Version 5.2.2 Major security release * Revert #605 [#629](https://github.com/jazzband/djangorestframework-simplejwt/pull/629) * Fix typo in blacklist_app.rst by @cbscsm [#593](https://github.com/jazzband/djangorestframework-simplejwt/pull/593) ## Version 5.2.1 * Add Swedish translations by @PasinduPrabhashitha [#579](https://github.com/jazzband/djangorestframework-simplejwt/pull/579) * Fixed issue #543 by @armenak-baburyan [#586](https://github.com/jazzband/djangorestframework-simplejwt/pull/586) * Fix uncaught exception with JWK by @jerr0328 [#600](https://github.com/jazzband/djangorestframework-simplejwt/pull/600) * Test on Django 4.1 by @2ykwang [#604](https://github.com/jazzband/djangorestframework-simplejwt/pull/604) ## Version 5.2.0 * Remove the JWTTokenUserAuthentication from the Experimental Features #546 by @byrpatrick [#547](https://github.com/jazzband/djangorestframework-simplejwt/pull/547) * Fix leeway type error by @2ykwang [#554](https://github.com/jazzband/djangorestframework-simplejwt/pull/554) * Add info on TokenBlacklistView to the docs by @inti7ary [#558](https://github.com/jazzband/djangorestframework-simplejwt/pull/558) * Update JWTStatelessUserAuthentication docs by @2ykwang [#561](https://github.com/jazzband/djangorestframework-simplejwt/pull/561) * Allow none jti claim token type claim by @denniskeends [#567](https://github.com/jazzband/djangorestframework-simplejwt/pull/567) * Allow customizing token JSON encoding by @vainu-arto [#568](https://github.com/jazzband/djangorestframework-simplejwt/pull/568) ## Version 5.1.0 * Add back support for PyJWT 1.7.1 ([#536](https://github.com/jazzband/djangorestframework-simplejwt/pull/536)) * Make the token serializer configurable ([#521](https://github.com/jazzband/djangorestframework-simplejwt/pull/521)) * Simplify using custom token classes in serializers ([#517](https://github.com/jazzband/djangorestframework-simplejwt/pull/517)) * Fix default_app_config deprecation ([#415](https://github.com/jazzband/djangorestframework-simplejwt/pull/415)) * Add missing integration instructions for drf-yasg ([#505](https://github.com/jazzband/djangorestframework-simplejwt/pull/505)) * Add blacklist view to log out users ([#306](https://github.com/jazzband/djangorestframework-simplejwt/pull/306)) * Set default verifying key to empty str ([#487](https://github.com/jazzband/djangorestframework-simplejwt/pull/487)) * Add docs about TOKEN_USER_CLASS ([#455](https://github.com/jazzband/djangorestframework-simplejwt/pull/440)) Meta: * Add auto locale updater ([#456](https://github.com/jazzband/djangorestframework-simplejwt/pull/456)) Translations: * Added Korean translations ([#501](https://github.com/jazzband/djangorestframework-simplejwt/pull/501)) * Added Turkish translations ([#508](https://github.com/jazzband/djangorestframework-simplejwt/pull/508)) ## Version 5.0.0 #### Breaking * Set BLACKLIST_AFTER_ROTATION by default to False ([#455](https://github.com/jazzband/djangorestframework-simplejwt/pull/455)) #### Updates * Remove verify from jwt.decode to follow PyJWT v2.2.0 ([#472](https://github.com/jazzband/djangorestframework-simplejwt/pull/472)) * Updated import list ([#459](https://github.com/jazzband/djangorestframework-simplejwt/pull/459)) * Repair generation of OpenAPI with Spectacular ([#452](https://github.com/jazzband/djangorestframework-simplejwt/pull/452)) * Add "iat" claim to token ([#192](https://github.com/jazzband/djangorestframework-simplejwt/pull/192)) * Add blacklist view to log out users ([#306](https://github.com/jazzband/djangorestframework-simplejwt/pull/306)) ## Version 4.8.0 * Add integration instructions for drf-yasg ([#145](https://github.com/jazzband/djangorestframework-simplejwt/pull/145)) * Verify Serializer Should Honour Blacklist ([#239](https://github.com/jazzband/djangorestframework-simplejwt/pull/239)) * Added missing import in getting_started docs ([#431](https://github.com/jazzband/djangorestframework-simplejwt/pull/431)) * Use import_string for token_backend ([#435](https://github.com/jazzband/djangorestframework-simplejwt/pull/435)) * Add JWKS support ([#437](https://github.com/jazzband/djangorestframework-simplejwt/pull/435)) * Use pathlib instead of open in setup.py ([#339](https://github.com/jazzband/djangorestframework-simplejwt/pull/339)) * Optimize default_user_authentication_rule ([#441](https://github.com/jazzband/djangorestframework-simplejwt/pull/441)) * Add Leeway option to decode ([#445](https://github.com/jazzband/djangorestframework-simplejwt/pull/445)) ## Version 4.7.2 * Fix BrowsableAPIRenderer needing `media_type` ([#426](https://github.com/jazzband/django-rest-framework-simplejwt/pull/426)) * Fix blacklist migrations for multiple databases ([#429](https://github.com/jazzband/django-rest-framework-simplejwt/pull/429)) * Fix Django 3.2 `default_app_config` deprecation ([#415](https://github.com/jazzband/django-rest-framework-simplejwt/pull/415)) * Fix docs specifying `INSTALLED_APPS` for SimpleJWT iff you want translations ([#420](https://github.com/jazzband/django-rest-framework-simplejwt/pull/420)) * Fix drf-yasg API Schema generation for `TokenRefreshSerializer` ([#396](https://github.com/jazzband/django-rest-framework-simplejwt/pull/396)) * Fix invalid syntax in docs for `INSTALLED_APPS` ([#416](https://github.com/jazzband/django-rest-framework-simplejwt/pull/416)) Translations: * Added Dutch translations ([#422](https://github.com/jazzband/django-rest-framework-simplejwt/pull/422)) * Added Ukrainian translations ([#423](https://github.com/jazzband/django-rest-framework-simplejwt/pull/423)) * Added Simplified Chinese translations ([#427](https://github.com/jazzband/django-rest-framework-simplejwt/pull/427)) ## Version 4.7.1 * Fixed user-generated migration file bug in token_blacklist ([#411](https://github.com/jazzband/django-rest-framework-simplejwt/pull/411)) ## Version 4.7.0 * Added support for Django 3.2 and drop Django 3.0 ([#404](https://github.com/jazzband/django-rest-framework-simplejwt/pull/404)) * Added Italian translations ([#342](https://github.com/jazzband/django-rest-framework-simplejwt/pull/342)) * Fixed DRF app registry bug, specifically `django.core.exceptions.AppRegistryNotReady` ([#331](https://github.com/jazzband/django-rest-framework-simplejwt/pull/331)) * Fixed support for PyJWT>=2.0.0 ([#376](https://github.com/jazzband/django-rest-framework-simplejwt/pull/376)) * Migrated blacklist app models to use BigAutoField IDs for Django>=3.2. ([#404](https://github.com/jazzband/django-rest-framework-simplejwt/pull/404)) ## Version 4.6 * Added support for PyJWT>=2.0.0 ([#329](https://github.com/jazzband/django-rest-framework-simplejwt/pull/329)) * Restored Python 3.7 support ([#332](https://github.com/jazzband/django-rest-framework-simplejwt/pull/332)) * Fixed Django 4.0 re_path deprecation ([#280](https://github.com/jazzband/django-rest-framework-simplejwt/pull/280)) Translations: * Added Indonesian translations ([#316](https://github.com/jazzband/django-rest-framework-simplejwt/pull/316)) ## Version 4.5 * Added `AUTH_HEADER_NAME` to settings ([#309](https://github.com/jazzband/django-rest-framework-simplejwt/pull/309)) * Added `USER_AUTHENTICATION_RULE` to settings ([#279](https://github.com/jazzband/django-rest-framework-simplejwt/pull/279)) * Added `UPDATE_LAST_LOGIN` to settings ([#238](https://github.com/jazzband/django-rest-framework-simplejwt/pull/238)) * Fixed packaging of locale folder for installation ([#117](https://github.com/jazzband/django-rest-framework-simplejwt/pull/117)) * Allowed TokenUser to be configurable ([#172](https://github.com/jazzband/django-rest-framework-simplejwt/pull/172)) * Dropped Python 3.7 and below (restored Python 3.7 but not 3.6 in next version) * Improved error message if cryptography isn't installed when developer tries to use a certain algorithm that needs the package ([#285](https://github.com/jazzband/django-rest-framework-simplejwt/pull/285)) * Fixed Django 4.0 ugettext_lazy deprecation warnings ([#186](https://github.com/jazzband/django-rest-framework-simplejwt/pull/186)) * Remove upper bound of Python version ([#225](https://github.com/jazzband/django-rest-framework-simplejwt/pull/225)) * Added DRF 3.11 support ([#230](https://github.com/jazzband/django-rest-framework-simplejwt/pull/230)) Translations: * Added French translations ([#314](https://github.com/jazzband/django-rest-framework-simplejwt/pull/314)) * Added Spanish translations ([#294](https://github.com/jazzband/django-rest-framework-simplejwt/pull/294)) * Added Argentinian Spanish translations ([#244](https://github.com/jazzband/django-rest-framework-simplejwt/pull/244)) * Added Persian translations ([#220](https://github.com/jazzband/django-rest-framework-simplejwt/pull/220)) * Added German translations ([#198](https://github.com/jazzband/django-rest-framework-simplejwt/pull/198)) * Added Czech translations ([#188](https://github.com/jazzband/django-rest-framework-simplejwt/pull/188)) * Added Polish translations ([#166](https://github.com/jazzband/django-rest-framework-simplejwt/pull/166)) * Fixed incorrect language encoding from de_CH to es_CL ([#299](https://github.com/jazzband/django-rest-framework-simplejwt/pull/299)) ## Version 4.4 * Added official support for Python 3.8 and Django 3.0. * Added settings for expected audience and issuer claims. * Documentation updates. * Updated package/python version support (check the README to see what new versions are supported and what old ones are no longer supported!) * Added Chilean Spanish language support. * Added Russian language support. ## Version 4.3 * Added `JTI_CLAIM` setting to allow storing token identifiers under a different claim. ## Version 4.2 * We now return HTTP 401 for user not found or inactive. ## Version 4.1.5 * Restricted `setup.py` config to Python 3 only. ## Version 4.1.4 * Included translation files in release package. ## Version 4.1.3 * Updated `python-jose` version requirement. ## Version 4.1.2 * Fixed `KeyError` in `TokenObtainSerializer.validate`. ## Version 4.1.1 * Added request pass-through on `django.contrib.auth.authenticate` call in `TokenObtainSerializer`. * Updated `TokenObtainSerializer` to use `fail` API from parent class. ## Version 4.1 * Added language support for Brazilian Portuguese. * Added support for automatic username lookup in `TokenUser`. ## Version 4.0 * Removed Python 2 support. * Fixed crash when empty AUTHORIZATION header is sent. * Fixed testing DB transaction issues. * Simplified/improved testing and dev setup. * Switched to using bumpversion for release process. ## Version 3.3 * Removed official support for Python 3.4. * Added support for Python 3.7. * Added support for Django 2.1. * Added support for DRF 3.9. ## Version 3.2.3 * Fixed issue with `WWW-Authenticate` header not being included in 401 responses. ## Version 3.2.2 * Added missing method `get` on `Token` base class. ## Version 3.2.1 * Simplified some blacklist app code. * Resolved possible race condition. ## Version 3.2 * Added ``TokenObtainSerializer.get_token`` method to facilitate customization of token claims. * Added ``TokenVerifyView`` to allow verification of HMAC-signed tokens by API users who have no access to the signing key. * Renamed ``AUTH_HEADER_TYPE`` setting to ``AUTH_HEADER_TYPES``. This setting now contains either a single valid auth header type or a list or tuple of valid auth header types. If authentication fails, and more than one string is present in this tuple or list, the first item in the list will be used to build the "WWW-Authenticate" header in the response. ## Version 3.1 * Moved handling of TokenError exceptions from inside of serializer `validate` methods into token view `post` methods. ## Version 3.0 * Added support for refresh token rotation via ``ROTATE_REFRESH_TOKENS`` and ``BLACKLIST_AFTER_ROTATION`` settings. See README for details. * Added `BlacklistMixin.blacklist` method to make it easier to blacklist tokens regardless of whether or not they are present in the outstanding token list. * In token blacklist app, changed `OutstandingToken.jti` field to char field to better reflect JWT spec. * Renamed `AUTH_TOKEN_CLASS` setting to `AUTH_TOKEN_CLASSES`. This setting now specifies a list of token classes (or class paths) which are used to verify tokens which are submitted for authorization. This will hopefully help anyone wishing to gradually migrate between using different token types. * Removed support for extensible JWT backends. We're just going to use PyJWT exclusively to simplify things. * Added support for more crypto algorithms. All HMAC and RSA variants from PyJWT now supported. * Renamed `SECRET_KEY` setting to `SIGNING_KEY`. * The renamed `SIGNING_KEY` setting now acts doubly as a symmetric signing/verification key for HMAC algorithms and as a private key for RSA algorithms. * Added `VERIFYING_KEY` setting for use with RSA algorithms. * Removed undocumented `TOKEN_BACKEND_CLASS` setting. ## Version 2.1 * Switched to using [PyJWT](https://github.com/jpadilla/pyjwt) as the underlying library for signing and verifying tokens. djangorestframework-simplejwt-5.5.0/CODE_OF_CONDUCT.md000066400000000000000000000045071475766445300224450ustar00rootroot00000000000000# Code of Conduct As contributors and maintainers of the Jazzband projects, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. We are committed to making participation in the Jazzband a harassment-free experience for everyone, regardless of the level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery - Personal attacks - Trolling or insulting/derogatory comments - Public or private harassment - Publishing other's private information, such as physical or electronic addresses, without explicit permission - Other unethical or unprofessional conduct The Jazzband roadies have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. By adopting this Code of Conduct, the roadies commit themselves to fairly and consistently applying these principles to every aspect of managing the jazzband projects. Roadies who do not follow or enforce the Code of Conduct may be permanently removed from the Jazzband roadies. This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the roadies at `roadies@jazzband.co`. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Roadies are obligated to maintain confidentiality with regard to the reporter of an incident. This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.3.0, available at [https://contributor-covenant.org/version/1/3/0/][version] [homepage]: https://contributor-covenant.org [version]: https://contributor-covenant.org/version/1/3/0/ djangorestframework-simplejwt-5.5.0/CONTRIBUTING.rst000066400000000000000000000005221475766445300223000ustar00rootroot00000000000000.. image:: https://jazzband.co/static/img/jazzband.svg :target: https://jazzband.co/ :alt: Jazzband This is a `Jazzband `_ project. By contributing you agree to abide by the `Contributor Code of Conduct `_ and follow the `guidelines `_. djangorestframework-simplejwt-5.5.0/LICENSE.txt000066400000000000000000000020351475766445300214630ustar00rootroot00000000000000Copyright 2017 David Sanders Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. djangorestframework-simplejwt-5.5.0/MANIFEST.in000066400000000000000000000003741475766445300214020ustar00rootroot00000000000000include README.rst include LICENSE.txt include rest_framework_simplejwt/py.typed recursive-include rest_framework_simplejwt/locale *.mo recursive-include rest_framework_simplejwt/locale *.po recursive-exclude * __pycache__ recursive-exclude * *.py[co] djangorestframework-simplejwt-5.5.0/Makefile000066400000000000000000000022731475766445300213040ustar00rootroot00000000000000.PHONY: clean clean: clean-build clean-pyc .PHONY: clean-build clean-build: rm -fr build/ rm -fr dist/ rm -fr *.egg-info .PHONY: clean-pyc clean-pyc: find . -name '*.pyc' -exec rm -f {} + find . -name '*.pyo' -exec rm -f {} + find . -name '*~' -exec rm -f {} + .PHONY: lint lint: tox -e lint .PHONY: lint-roll lint-roll: isort rest_framework_simplejwt tests $(MAKE) lint .PHONY: tests test: pytest tests .PHONY: test-all test-all: tox .PHONY: build-docs build-docs: sphinx-apidoc -o docs/ . \ setup.py \ *confest* \ tests/* \ rest_framework_simplejwt/token_blacklist/* \ rest_framework_simplejwt/backends.py \ rest_framework_simplejwt/exceptions.py \ rest_framework_simplejwt/settings.py \ rest_framework_simplejwt/state.py $(MAKE) -C docs clean $(MAKE) -C docs html $(MAKE) -C docs doctest .PHONY: docs docs: build-docs open docs/_build/html/index.html .PHONY: linux-docs linux-docs: build-docs xdg-open docs/_build/html/index.html .PHONY: pushversion pushversion: git push upstream && git push upstream --tags .PHONY: publish publish: python setup.py sdist bdist_wheel twine upload dist/* .PHONY: dist dist: clean python setup.py sdist bdist_wheel ls -l dist djangorestframework-simplejwt-5.5.0/README.rst000066400000000000000000000030601475766445300213260ustar00rootroot00000000000000Simple JWT ========== .. image:: https://jazzband.co/static/img/badge.svg :target: https://jazzband.co/ :alt: Jazzband .. image:: https://github.com/jazzband/djangorestframework-simplejwt/workflows/Test/badge.svg :target: https://github.com/jazzband/djangorestframework-simplejwt/actions :alt: GitHub Actions .. image:: https://codecov.io/gh/jazzband/djangorestframework-simplejwt/branch/master/graph/badge.svg :target: https://codecov.io/gh/jazzband/djangorestframework-simplejwt .. image:: https://img.shields.io/pypi/v/djangorestframework-simplejwt.svg :target: https://pypi.python.org/pypi/djangorestframework-simplejwt .. image:: https://img.shields.io/pypi/pyversions/djangorestframework-simplejwt.svg :target: https://pypi.python.org/pypi/djangorestframework-simplejwt .. image:: https://img.shields.io/pypi/djversions/djangorestframework-simplejwt.svg :target: https://pypi.python.org/pypi/djangorestframework-simplejwt .. image:: https://readthedocs.org/projects/django-rest-framework-simplejwt/badge/?version=latest :target: https://django-rest-framework-simplejwt.readthedocs.io/en/latest/ Abstract -------- Simple JWT is a JSON Web Token authentication plugin for the `Django REST Framework `__. For full documentation, visit `django-rest-framework-simplejwt.readthedocs.io `__. Translations ------------ Contribute translations directly with PRs or via inlang https://inlang.com/editor/github.com/jazzband/djangorestframework-simplejwt djangorestframework-simplejwt-5.5.0/codecov.yml000066400000000000000000000002431475766445300220040ustar00rootroot00000000000000coverage: status: project: default: informational: true patch: default: informational: true changes: false comment: off djangorestframework-simplejwt-5.5.0/docs/000077500000000000000000000000001475766445300205705ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/docs/Makefile000066400000000000000000000152621475766445300222360ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/rest_framework_simplejwt.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/rest_framework_simplejwt.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/rest_framework_simplejwt" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/rest_framework_simplejwt" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." djangorestframework-simplejwt-5.5.0/docs/blacklist_app.rst000066400000000000000000000051241475766445300241340ustar00rootroot00000000000000.. _blacklist_app: Blacklist app ============= Simple JWT includes an app that provides token blacklist functionality. To use this app, include it in your list of installed apps in ``settings.py``: .. code-block:: python # Django project settings.py ... INSTALLED_APPS = ( ... 'rest_framework_simplejwt.token_blacklist', ... ) Also, make sure to run ``python manage.py migrate`` to run the app's migrations. If the blacklist app is detected in ``INSTALLED_APPS``, Simple JWT will add any generated refresh or sliding tokens to a list of outstanding tokens. It will also check that any refresh or sliding token does not appear in a blacklist of tokens before it considers it as valid. The Simple JWT blacklist app implements its outstanding and blacklisted token lists using two models: ``OutstandingToken`` and ``BlacklistedToken``. Model admins are defined for both of these models. To add a token to the blacklist, find its corresponding ``OutstandingToken`` record in the admin and use the admin again to create a ``BlacklistedToken`` record that points to the ``OutstandingToken`` record. Alternatively, you can blacklist a token by creating a ``BlacklistMixin`` subclass instance and calling the instance's ``blacklist`` method: .. code-block:: python from rest_framework_simplejwt.tokens import RefreshToken token = RefreshToken(base64_encoded_token_string) token.blacklist() This will create unique outstanding token and blacklist records for the token's "jti" claim or whichever claim is specified by the ``JTI_CLAIM`` setting. In a ``urls.py`` file, you can also include a route for ``TokenBlacklistView``: .. code-block:: python from rest_framework_simplejwt.views import TokenBlacklistView urlpatterns = [ ... path('api/token/blacklist/', TokenBlacklistView.as_view(), name='token_blacklist'), ... ] It allows API users to blacklist tokens sending them to ``/api/token/blacklist/``, for example using curl: .. code-block:: bash curl \ -X POST \ -H "Content-Type: application/json" \ -d '{"refresh":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY1MDI5NTEwOCwiaWF0IjoxNjUwMjA4NzA4LCJqdGkiOiJhYTY3ZDUxNzkwMGY0MTEyYTY5NTE0MTNmNWQ4NDk4NCIsInVzZXJfaWQiOjF9.tcj1_OcO1BRDfFyw4miHD7mqFdWKxmP7BJDRmxwCzrg"}' \ http://localhost:8000/api/token/blacklist/ The blacklist app also provides a management command, ``flushexpiredtokens``, which will delete any tokens from the outstanding list and blacklist that have expired. You should set up a cron job on your server or hosting platform which runs this command daily. djangorestframework-simplejwt-5.5.0/docs/conf.py000066400000000000000000000226361475766445300221000ustar00rootroot00000000000000# # Simple JWT documentation build configuration file, created by # sphinx-quickstart on Thu Oct 16 20:43:24 2014. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. from pkg_resources import get_distribution # -- General configuration ------------------------------------------------ def django_configure(): from django.conf import settings settings.configure( SECRET_KEY="a random key to use", INSTALLED_APPS=( "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.sites", "django.contrib.staticfiles", "rest_framework", "rest_framework_simplejwt", "rest_framework_simplejwt.token_blacklist", ), ) try: import django django.setup() except AttributeError: pass django_configure() # If your documentation needs a minimal Sphinx version, state it here. # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ "sphinx.ext.autodoc", "sphinx.ext.doctest", "sphinx.ext.intersphinx", ] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] # The suffix of source filenames. source_suffix = ".rst" # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = "index" # General information about the project. project = "Simple JWT" copyright = "2020, David Sanders" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The full version, including alpha/beta/rc tags. release = get_distribution("djangorestframework_simplejwt").version # The short X.Y version. version = ".".join(release.split(".")[:2]) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [ "_build", "modules.rst", ] # The reST default role (used for this markup: `text`) to use for all # documents. # default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. # keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". # html_title = None # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ["_static"] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. # html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. # html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = {} # If false, no module index is generated. # html_domain_indices = True # If false, no index is generated. # html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = "rest_framework_simplejwtdoc" # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ( "index", "rest_framework_simplejwt.tex", "Simple JWT Documentation", "David Sanders", "manual", ), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # If true, show page references after internal links. # latex_show_pagerefs = False # If true, show URL addresses after external links. # latex_show_urls = False # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ( "index", "rest_framework_simplejwt", "Simple JWT Documentation", ["David Sanders"], 1, ) ] # If true, show URL addresses after external links. # man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ( "index", "Simple JWT", "Simple JWT", "David Sanders", "Simple JWT", "A JSON Web Token authentication plugin for the Django REST Framework.", "Miscellaneous", ), ] # Documents to append as an appendix to all manuals. # texinfo_appendices = [] # If false, no module index is generated. # texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. # texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. # texinfo_no_detailmenu = False # -- Intersphinx configuration ------------------------------------------------ intersphinx_mapping = { "python": ("https://docs.python.org/3.8", None), } # -- Doctest configuration ---------------------------------------- import doctest doctest_default_flags = ( 0 | doctest.DONT_ACCEPT_TRUE_FOR_1 | doctest.ELLIPSIS | doctest.IGNORE_EXCEPTION_DETAIL | doctest.NORMALIZE_WHITESPACE ) djangorestframework-simplejwt-5.5.0/docs/creating_tokens_manually.rst000066400000000000000000000012701475766445300264030ustar00rootroot00000000000000.. _creating_tokens_manually: Creating tokens manually ======================== Sometimes, you may wish to manually create a token for a user. This could be done as follows: .. code-block:: python from rest_framework_simplejwt.tokens import RefreshToken def get_tokens_for_user(user): refresh = RefreshToken.for_user(user) return { 'refresh': str(refresh), 'access': str(refresh.access_token), } The above function ``get_tokens_for_user`` will return the serialized representations of new refresh and access tokens for the given user. In general, a token for any subclass of ``rest_framework_simplejwt.tokens.Token`` can be created in this way. djangorestframework-simplejwt-5.5.0/docs/customizing_token_claims.rst000066400000000000000000000027671475766445300264410ustar00rootroot00000000000000.. _customizing_token_claims: Customizing token claims ======================== If you wish to customize the claims contained in web tokens which are generated by the ``TokenObtainPairView`` and ``TokenObtainSlidingView`` views, create a subclass for the desired view as well as a subclass for its corresponding serializer. Here's an example of how to customize the claims in tokens generated by the ``TokenObtainPairView``: .. code-block:: python from rest_framework_simplejwt.serializers import TokenObtainPairSerializer from rest_framework_simplejwt.views import TokenObtainPairView class MyTokenObtainPairSerializer(TokenObtainPairSerializer): @classmethod def get_token(cls, user): token = super().get_token(user) # Add custom claims token['name'] = user.name # ... return token .. code-block:: python # Django project settings.py ... SIMPLE_JWT = { # It will work instead of the default serializer(TokenObtainPairSerializer). "TOKEN_OBTAIN_SERIALIZER": "my_app.serializers.MyTokenObtainPairSerializer", # ... } Note that the example above will cause the customized claims to be present in both refresh *and* access tokens which are generated by the view. This follows from the fact that the ``get_token`` method above produces the *refresh* token for the view, which is in turn used to generate the view's access token. As with the standard token views, you'll also need to include a url route to your subclassed view. djangorestframework-simplejwt-5.5.0/docs/development_and_contributing.rst000066400000000000000000000021201475766445300272500ustar00rootroot00000000000000.. _development_and_contributing: Development and contributing ============================ To do development work for Simple JWT, make your own fork on Github, clone it locally, make and activate a virtualenv for it, then from within the project directory: .. code-block:: bash pip install --upgrade pip setuptools pip install -e .[dev] If you're running a Mac and/or with zsh, you need to escape the brackets: .. code-block:: bash pip install -e .\[dev\] To run the tests: .. code-block:: bash pytest To run the tests in all supported environments with tox, first `install pyenv `__. Next, install the relevant Python minor versions and create a ``.python-version`` file in the project directory: .. code-block:: bash pyenv install 3.9.x cat > .python-version <`__. ------------------------------------------------------------------------------- Simple JWT provides a JSON Web Token authentication backend for the Django REST Framework. It aims to cover the most common use cases of JWTs by offering a conservative set of default features. It also aims to be easily extensible in case a desired feature is not present. Acknowledgments --------------- This project borrows code from the `Django REST Framework `__ as well as concepts from the implementation of another JSON web token library for the Django REST Framework, `django-rest-framework-jwt `__. The licenses from both of those projects have been included in this repository in the "licenses" directory. Contents -------- .. toctree:: :maxdepth: 3 getting_started settings customizing_token_claims creating_tokens_manually token_types blacklist_app stateless_user_authentication development_and_contributing drf_yasg_integration rest_framework_simplejwt Indices and tables ------------------ * :ref:`genindex` * :ref:`modindex` djangorestframework-simplejwt-5.5.0/docs/rest_framework_simplejwt.rst000066400000000000000000000025611475766445300264560ustar00rootroot00000000000000rest\_framework\_simplejwt package ================================== Submodules ---------- rest\_framework\_simplejwt.authentication module ------------------------------------------------ .. automodule:: rest_framework_simplejwt.authentication :members: :undoc-members: :show-inheritance: rest\_framework\_simplejwt.models module ---------------------------------------- .. automodule:: rest_framework_simplejwt.models :members: :undoc-members: :show-inheritance: rest\_framework\_simplejwt.serializers module --------------------------------------------- .. automodule:: rest_framework_simplejwt.serializers :members: :undoc-members: :show-inheritance: rest\_framework\_simplejwt.tokens module ---------------------------------------- .. automodule:: rest_framework_simplejwt.tokens :members: :undoc-members: :show-inheritance: rest\_framework\_simplejwt.utils module --------------------------------------- .. automodule:: rest_framework_simplejwt.utils :members: :undoc-members: :show-inheritance: rest\_framework\_simplejwt.views module --------------------------------------- .. automodule:: rest_framework_simplejwt.views :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: rest_framework_simplejwt :members: :undoc-members: :show-inheritance: djangorestframework-simplejwt-5.5.0/docs/settings.rst000066400000000000000000000267041475766445300231730ustar00rootroot00000000000000.. _settings: Settings ======== Some of Simple JWT's behavior can be customized through settings variables in ``settings.py``: .. code-block:: python # Django project settings.py from datetime import timedelta ... SIMPLE_JWT = { "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), "REFRESH_TOKEN_LIFETIME": timedelta(days=1), "ROTATE_REFRESH_TOKENS": False, "BLACKLIST_AFTER_ROTATION": False, "UPDATE_LAST_LOGIN": False, "ALGORITHM": "HS256", "SIGNING_KEY": settings.SECRET_KEY, "VERIFYING_KEY": "", "AUDIENCE": None, "ISSUER": None, "JSON_ENCODER": None, "JWK_URL": None, "LEEWAY": 0, "AUTH_HEADER_TYPES": ("Bearer",), "AUTH_HEADER_NAME": "HTTP_AUTHORIZATION", "USER_ID_FIELD": "id", "USER_ID_CLAIM": "user_id", "USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule", "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",), "TOKEN_TYPE_CLAIM": "token_type", "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser", "JTI_CLAIM": "jti", "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp", "SLIDING_TOKEN_LIFETIME": timedelta(minutes=5), "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1), "TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer", "TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer", "TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer", "TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer", "SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer", "SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer", } Above, the default values for these settings are shown. ``ACCESS_TOKEN_LIFETIME`` ------------------------- A ``datetime.timedelta`` object which specifies how long access tokens are valid. This ``timedelta`` value is added to the current UTC time during token generation to obtain the token's default "exp" claim value. ``REFRESH_TOKEN_LIFETIME`` -------------------------- A ``datetime.timedelta`` object which specifies how long refresh tokens are valid. This ``timedelta`` value is added to the current UTC time during token generation to obtain the token's default "exp" claim value. ``ROTATE_REFRESH_TOKENS`` ------------------------- When set to ``True``, if a refresh token is submitted to the ``TokenRefreshView``, a new refresh token will be returned along with the new access token. This new refresh token will be supplied via a "refresh" key in the JSON response. New refresh tokens will have a renewed expiration time which is determined by adding the timedelta in the ``REFRESH_TOKEN_LIFETIME`` setting to the current time when the request is made. If the blacklist app is in use and the ``BLACKLIST_AFTER_ROTATION`` setting is set to ``True``, refresh tokens submitted to the refresh view will be added to the blacklist. ``BLACKLIST_AFTER_ROTATION`` ---------------------------- When set to ``True``, causes refresh tokens submitted to the ``TokenRefreshView`` to be added to the blacklist if the blacklist app is in use and the ``ROTATE_REFRESH_TOKENS`` setting is set to ``True``. You need to add ``'rest_framework_simplejwt.token_blacklist',`` to your ``INSTALLED_APPS`` in the settings file to use this setting. Learn more about :doc:`/blacklist_app`. ``UPDATE_LAST_LOGIN`` ---------------------------- When set to ``True``, last_login field in the auth_user table is updated upon login (TokenObtainPairView). Warning: Updating last_login will dramatically increase the number of database transactions. People abusing the views could slow the server and this could be a security vulnerability. If you really want this, throttle the endpoint with DRF at the very least. ``ALGORITHM`` ------------- The algorithm from the PyJWT library which will be used to perform signing/verification operations on tokens. To use symmetric HMAC signing and verification, the following algorithms may be used: ``'HS256'``, ``'HS384'``, ``'HS512'``. When an HMAC algorithm is chosen, the ``SIGNING_KEY`` setting will be used as both the signing key and the verifying key. In that case, the ``VERIFYING_KEY`` setting will be ignored. To use asymmetric RSA signing and verification, the following algorithms may be used: ``'RS256'``, ``'RS384'``, ``'RS512'``. When an RSA algorithm is chosen, the ``SIGNING_KEY`` setting must be set to a string that contains an RSA private key. Likewise, the ``VERIFYING_KEY`` setting must be set to a string that contains an RSA public key. ``SIGNING_KEY`` --------------- The signing key that is used to sign the content of generated tokens. For HMAC signing, this should be a random string with at least as many bits of data as is required by the signing protocol. For RSA signing, this should be a string that contains an RSA private key that is 2048 bits or longer. Since Simple JWT defaults to using 256-bit HMAC signing, the ``SIGNING_KEY`` setting defaults to the value of the ``SECRET_KEY`` setting for your django project. Although this is the most reasonable default that Simple JWT can provide, it is recommended that developers change this setting to a value that is independent from the django project secret key. This will make changing the signing key used for tokens easier in the event that it is compromised. ``VERIFYING_KEY`` ----------------- The verifying key which is used to verify the content of generated tokens. If an HMAC algorithm has been specified by the ``ALGORITHM`` setting, the ``VERIFYING_KEY`` setting will be ignored and the value of the ``SIGNING_KEY`` setting will be used. If an RSA algorithm has been specified by the ``ALGORITHM`` setting, the ``VERIFYING_KEY`` setting must be set to a string that contains an RSA public key. ``AUDIENCE`` ------------- The audience claim to be included in generated tokens and/or validated in decoded tokens. When set to ``None``, this field is excluded from tokens and is not validated. ``ISSUER`` ---------- The issuer claim to be included in generated tokens and/or validated in decoded tokens. When set to ``None``, this field is excluded from tokens and is not validated. ``JWK_URL`` ---------- The JWK_URL is used to dynamically resolve the public keys needed to verify the signing of tokens. When using Auth0 for example you might set this to 'https://yourdomain.auth0.com/.well-known/jwks.json'. When set to ``None``, this field is excluded from the token backend and is not used during validation. ``LEEWAY`` ---------- Leeway is used to give some margin to the expiration time. This can be an integer for seconds or a ``datetime.timedelta``. Please reference https://pyjwt.readthedocs.io/en/latest/usage.html#expiration-time-claim-exp for more information. ``AUTH_HEADER_TYPES`` --------------------- The authorization header type(s) that will be accepted for views that require authentication. For example, a value of ``'Bearer'`` means that views requiring authentication would look for a header with the following format: ``Authorization: Bearer ``. This setting may also contain a list or tuple of possible header types (e.g. ``('Bearer', 'JWT')``). If a list or tuple is used in this way, and authentication fails, the first item in the collection will be used to build the "WWW-Authenticate" header in the response. ``AUTH_HEADER_NAME`` ---------------------------- The authorization header name to be used for authentication. The default is ``HTTP_AUTHORIZATION`` which will accept the ``Authorization`` header in the request. For example if you'd like to use ``X-Access-Token`` in the header of your requests please specify the ``AUTH_HEADER_NAME`` to be ``HTTP_X_ACCESS_TOKEN`` in your settings. ``USER_ID_FIELD`` ----------------- The database field from the user model that will be included in generated tokens to identify users. It is recommended that the value of this setting specifies a field that does not normally change once its initial value is chosen. For example, specifying a "username" or "email" field would be a poor choice since an account's username or email might change depending on how account management in a given service is designed. This could allow a new account to be created with an old username while an existing token is still valid which uses that username as a user identifier. ``USER_ID_CLAIM`` ----------------- The claim in generated tokens which will be used to store user identifiers. For example, a setting value of ``'user_id'`` would mean generated tokens include a "user_id" claim that contains the user's identifier. ``USER_AUTHENTICATION_RULE`` ---------------------------- Callable to determine if the user is permitted to authenticate. This rule is applied after a valid token is processed. The user object is passed to the callable as an argument. The default rule is to check that the ``is_active`` flag is still ``True``. The callable must return a boolean, ``True`` if authorized, ``False`` otherwise resulting in a 401 status code. ``AUTH_TOKEN_CLASSES`` ---------------------- A list of dot paths to classes that specify the types of token that are allowed to prove authentication. More about this in the "Token types" section below. ``TOKEN_TYPE_CLAIM`` -------------------- The claim name that is used to store a token's type. More about this in the "Token types" section below. ``JTI_CLAIM`` ------------- The claim name that is used to store a token's unique identifier. This identifier is used to identify revoked tokens in the blacklist app. It may be necessary in some cases to use another claim besides the default "jti" claim to store such a value. ``TOKEN_USER_CLASS`` -------------------- A stateless user object which is backed by a validated token. Used only for the JWTStatelessUserAuthentication authentication backend. The value is a dotted path to your subclass of ``rest_framework_simplejwt.models.TokenUser``, which also is the default. ``SLIDING_TOKEN_LIFETIME`` -------------------------- A ``datetime.timedelta`` object which specifies how long sliding tokens are valid to prove authentication. This ``timedelta`` value is added to the current UTC time during token generation to obtain the token's default "exp" claim value. More about this in the "Sliding tokens" section below. ``SLIDING_TOKEN_REFRESH_LIFETIME`` ---------------------------------- A ``datetime.timedelta`` object which specifies how long sliding tokens are valid to be refreshed. This ``timedelta`` value is added to the current UTC time during token generation to obtain the token's default "exp" claim value. More about this in the "Sliding tokens" section below. ``SLIDING_TOKEN_REFRESH_EXP_CLAIM`` ----------------------------------- The claim name that is used to store the expiration time of a sliding token's refresh period. More about this in the "Sliding tokens" section below. ``CHECK_REVOKE_TOKEN`` -------------------- If this field is set to ``True``, the system will verify whether the token has been revoked or not by comparing the md5 hash of the user's current password with the value stored in the REVOKE_TOKEN_CLAIM field within the payload of the JWT token. ``REVOKE_TOKEN_CLAIM`` -------------------- The claim name that is used to store a user hash password. If the value of this CHECK_REVOKE_TOKEN field is ``True``, this field will be included in the JWT payload. djangorestframework-simplejwt-5.5.0/docs/stateless_user_authentication.rst000066400000000000000000000023331475766445300274670ustar00rootroot00000000000000.. _stateless_user_authentication: Stateless User Authentication ===================== JWTStatelessUserAuthentication backend ---------------------------------- The ``JWTStatelessUserAuthentication`` backend's ``authenticate`` method does not perform a database lookup to obtain a user instance. Instead, it returns a ``rest_framework_simplejwt.models.TokenUser`` instance which acts as a stateless user object backed only by a validated token instead of a record in a database. This can facilitate developing single sign-on functionality between separately hosted Django apps which all share the same token secret key. To use this feature, add the ``rest_framework_simplejwt.authentication.JWTStatelessUserAuthentication`` backend (instead of the default ``JWTAuthentication`` backend) to the Django REST Framework's ``DEFAULT_AUTHENTICATION_CLASSES`` config setting: .. code-block:: python REST_FRAMEWORK = { ... 'DEFAULT_AUTHENTICATION_CLASSES': ( ... 'rest_framework_simplejwt.authentication.JWTStatelessUserAuthentication', ) ... } v5.1.0 has renamed ``JWTTokenUserAuthentication`` to ``JWTStatelessUserAuthentication``, but both names are supported for backwards compatibility djangorestframework-simplejwt-5.5.0/docs/token_types.rst000066400000000000000000000055171475766445300236760ustar00rootroot00000000000000.. _token_types: Token types =========== Simple JWT provides two different token types that can be used to prove authentication. In a token's payload, its type can be identified by the value of its token type claim, which is "token_type" by default. This may have a value of "access", "sliding", or "refresh" however refresh tokens are not considered valid for authentication at this time. The claim name used to store the type can be customized by changing the ``TOKEN_TYPE_CLAIM`` setting. By default, Simple JWT expects an "access" token to prove authentication. The allowed auth token types are determined by the value of the ``AUTH_TOKEN_CLASSES`` setting. This setting contains a list of dot paths to token classes. It includes the ``'rest_framework_simplejwt.tokens.AccessToken'`` dot path by default but may also include the ``'rest_framework_simplejwt.tokens.SlidingToken'`` dot path. Either or both of those dot paths may be present in the list of auth token classes. If they are both present, then both of those token types may be used to prove authentication. Sliding tokens -------------- Sliding tokens offer a more convenient experience to users of tokens with the trade-offs of being less secure and, in the case that the blacklist app is being used, less performant. A sliding token is one which contains both an expiration claim and a refresh expiration claim. As long as the timestamp in a sliding token's expiration claim has not passed, it can be used to prove authentication. Additionally, as long as the timestamp in its refresh expiration claim has not passed, it may also be submitted to a refresh view to get another copy of itself with a renewed expiration claim. If you want to use sliding tokens, change the ``AUTH_TOKEN_CLASSES`` setting to ``('rest_framework_simplejwt.tokens.SlidingToken',)``. (Alternatively, the ``AUTH_TOKEN_CLASSES`` setting may include dot paths to both the ``AccessToken`` and ``SlidingToken`` token classes in the ``rest_framework_simplejwt.tokens`` module if you want to allow both token types to be used for authentication.) Also, include urls for the sliding token specific ``TokenObtainSlidingView`` and ``TokenRefreshSlidingView`` views alongside or in place of urls for the access token specific ``TokenObtainPairView`` and ``TokenRefreshView`` views: .. code-block:: python from rest_framework_simplejwt.views import ( TokenObtainSlidingView, TokenRefreshSlidingView, ) urlpatterns = [ ... path('api/token/', TokenObtainSlidingView.as_view(), name='token_obtain'), path('api/token/refresh/', TokenRefreshSlidingView.as_view(), name='token_refresh'), ... ] Be aware that, if you are using the blacklist app, Simple JWT will validate all sliding tokens against the blacklist for each authenticated request. This will reduce the performance of authenticated API views. djangorestframework-simplejwt-5.5.0/inlang.config.js000066400000000000000000000020271475766445300227130ustar00rootroot00000000000000// filename: inlang.config.js export async function defineConfig(env) { // importing a plugin const plugin = await env.$import( "https://cdn.jsdelivr.net/gh/jannesblobel/inlang-plugin-po@1/dist/index.js" ); // most plugins require additional config, read the plugins documentation // for the required config and correct usage. const pluginConfig = { pathPattern: "./rest_framework_simplejwt/locale/{language}/LC_MESSAGES/django.po", referenceResourcePath: null, }; return { referenceLanguage: "en", languages: [ "en", "cs", "de", "es", "es_AR", "es_CL", "fa_IR", "fr", "id_ID", "it_IT", "ko_KR", "nl_NL", "pl_PL", "pt_BR", "ro", "ru_RU", "sl", "sv", "tr", "uk_UA", "zh_Hans", ], readResources: (args) => plugin.readResources({ ...args, ...env, pluginConfig }), writeResources: (args) => plugin.writeResources({ ...args, ...env, pluginConfig }), }; } djangorestframework-simplejwt-5.5.0/licenses/000077500000000000000000000000001475766445300214455ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/licenses/LICENSE-django-rest-framework-jwt000066400000000000000000000020711475766445300274620ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2014-2017 Blimp LLC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. djangorestframework-simplejwt-5.5.0/licenses/LICENSE-django-rest-framework.md000066400000000000000000000024241475766445300272610ustar00rootroot00000000000000# License Copyright (c) 2011-2017, Tom Christie All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. djangorestframework-simplejwt-5.5.0/pytest.ini000066400000000000000000000002471475766445300216740ustar00rootroot00000000000000[pytest] addopts= -v --showlocals --durations 10 python_paths= . xfail_strict=true [pytest-watch] runner= pytest --failed-first --maxfail=1 --no-success-flaky-report djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/000077500000000000000000000000001475766445300247705ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/__init__.py000066400000000000000000000003211475766445300270750ustar00rootroot00000000000000from importlib.metadata import PackageNotFoundError, version try: __version__ = version("djangorestframework_simplejwt") except PackageNotFoundError: # package is not installed __version__ = None djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/authentication.py000066400000000000000000000142521475766445300303650ustar00rootroot00000000000000from typing import Optional, TypeVar from django.contrib.auth import get_user_model from django.contrib.auth.models import AbstractBaseUser from django.utils.translation import gettext_lazy as _ from rest_framework import HTTP_HEADER_ENCODING, authentication from rest_framework.request import Request from .exceptions import AuthenticationFailed, InvalidToken, TokenError from .models import TokenUser from .settings import api_settings from .tokens import Token from .utils import get_md5_hash_password AUTH_HEADER_TYPES = api_settings.AUTH_HEADER_TYPES if not isinstance(api_settings.AUTH_HEADER_TYPES, (list, tuple)): AUTH_HEADER_TYPES = (AUTH_HEADER_TYPES,) AUTH_HEADER_TYPE_BYTES: set[bytes] = { h.encode(HTTP_HEADER_ENCODING) for h in AUTH_HEADER_TYPES } AuthUser = TypeVar("AuthUser", AbstractBaseUser, TokenUser) class JWTAuthentication(authentication.BaseAuthentication): """ An authentication plugin that authenticates requests through a JSON web token provided in a request header. """ www_authenticate_realm = "api" media_type = "application/json" def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.user_model = get_user_model() def authenticate(self, request: Request) -> Optional[tuple[AuthUser, Token]]: header = self.get_header(request) if header is None: return None raw_token = self.get_raw_token(header) if raw_token is None: return None validated_token = self.get_validated_token(raw_token) return self.get_user(validated_token), validated_token def authenticate_header(self, request: Request) -> str: return '{} realm="{}"'.format( AUTH_HEADER_TYPES[0], self.www_authenticate_realm, ) def get_header(self, request: Request) -> bytes: """ Extracts the header containing the JSON web token from the given request. """ header = request.META.get(api_settings.AUTH_HEADER_NAME) if isinstance(header, str): # Work around django test client oddness header = header.encode(HTTP_HEADER_ENCODING) return header def get_raw_token(self, header: bytes) -> Optional[bytes]: """ Extracts an unvalidated JSON web token from the given "Authorization" header value. """ parts = header.split() if len(parts) == 0: # Empty AUTHORIZATION header sent return None if parts[0] not in AUTH_HEADER_TYPE_BYTES: # Assume the header does not contain a JSON web token return None if len(parts) != 2: raise AuthenticationFailed( _("Authorization header must contain two space-delimited values"), code="bad_authorization_header", ) return parts[1] def get_validated_token(self, raw_token: bytes) -> Token: """ Validates an encoded JSON web token and returns a validated token wrapper object. """ messages = [] for AuthToken in api_settings.AUTH_TOKEN_CLASSES: try: return AuthToken(raw_token) except TokenError as e: messages.append( { "token_class": AuthToken.__name__, "token_type": AuthToken.token_type, "message": e.args[0], } ) raise InvalidToken( { "detail": _("Given token not valid for any token type"), "messages": messages, } ) def get_user(self, validated_token: Token) -> AuthUser: """ Attempts to find and return a user using the given validated token. """ try: user_id = validated_token[api_settings.USER_ID_CLAIM] except KeyError: raise InvalidToken(_("Token contained no recognizable user identification")) try: user = self.user_model.objects.get(**{api_settings.USER_ID_FIELD: user_id}) except self.user_model.DoesNotExist: raise AuthenticationFailed(_("User not found"), code="user_not_found") if api_settings.CHECK_USER_IS_ACTIVE and not user.is_active: raise AuthenticationFailed(_("User is inactive"), code="user_inactive") if api_settings.CHECK_REVOKE_TOKEN: if validated_token.get( api_settings.REVOKE_TOKEN_CLAIM ) != get_md5_hash_password(user.password): raise AuthenticationFailed( _("The user's password has been changed."), code="password_changed" ) return user class JWTStatelessUserAuthentication(JWTAuthentication): """ An authentication plugin that authenticates requests through a JSON web token provided in a request header without performing a database lookup to obtain a user instance. """ def get_user(self, validated_token: Token) -> AuthUser: """ Returns a stateless user object which is backed by the given validated token. """ if api_settings.USER_ID_CLAIM not in validated_token: # The TokenUser class assumes tokens will have a recognizable user # identifier claim. raise InvalidToken(_("Token contained no recognizable user identification")) return api_settings.TOKEN_USER_CLASS(validated_token) JWTTokenUserAuthentication = JWTStatelessUserAuthentication def default_user_authentication_rule(user: AuthUser) -> bool: # Prior to Django 1.10, inactive users could be authenticated with the # default `ModelBackend`. As of Django 1.10, the `ModelBackend` # prevents inactive users from authenticating. App designers can still # allow inactive users to authenticate by opting for the new # `AllowAllUsersModelBackend`. However, we explicitly prevent inactive # users from authenticating to enforce a reasonable policy and provide # sensible backwards compatibility with older Django versions. return user is not None and ( not api_settings.CHECK_USER_IS_ACTIVE or user.is_active ) djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/backends.py000066400000000000000000000131551475766445300271210ustar00rootroot00000000000000import json from collections.abc import Iterable from datetime import timedelta from functools import cached_property from typing import Any, Optional, Union import jwt from django.utils.translation import gettext_lazy as _ from jwt import ( ExpiredSignatureError, InvalidAlgorithmError, InvalidTokenError, algorithms, ) from .exceptions import TokenBackendError, TokenBackendExpiredToken from .tokens import Token from .utils import format_lazy try: from jwt import PyJWKClient, PyJWKClientError JWK_CLIENT_AVAILABLE = True except ImportError: JWK_CLIENT_AVAILABLE = False ALLOWED_ALGORITHMS = { "HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", }.union(algorithms.requires_cryptography) class TokenBackend: def __init__( self, algorithm: str, signing_key: Optional[str] = None, verifying_key: str = "", audience: Union[str, Iterable, None] = None, issuer: Optional[str] = None, jwk_url: Optional[str] = None, leeway: Union[float, int, timedelta, None] = None, json_encoder: Optional[type[json.JSONEncoder]] = None, ) -> None: self._validate_algorithm(algorithm) self.algorithm = algorithm self.signing_key = signing_key self.verifying_key = verifying_key self.audience = audience self.issuer = issuer if JWK_CLIENT_AVAILABLE: self.jwks_client = PyJWKClient(jwk_url) if jwk_url else None else: self.jwks_client = None self.leeway = leeway self.json_encoder = json_encoder @cached_property def prepared_signing_key(self) -> Any: return self._prepare_key(self.signing_key) @cached_property def prepared_verifying_key(self) -> Any: return self._prepare_key(self.verifying_key) def _prepare_key(self, key: Optional[str]) -> Any: # Support for PyJWT 1.7.1 or empty signing key if key is None or not getattr(jwt.PyJWS, "get_algorithm_by_name", None): return key jws_alg = jwt.PyJWS().get_algorithm_by_name(self.algorithm) return jws_alg.prepare_key(key) def _validate_algorithm(self, algorithm: str) -> None: """ Ensure that the nominated algorithm is recognized, and that cryptography is installed for those algorithms that require it """ if algorithm not in ALLOWED_ALGORITHMS: raise TokenBackendError( format_lazy(_("Unrecognized algorithm type '{}'"), algorithm) ) if algorithm in algorithms.requires_cryptography and not algorithms.has_crypto: raise TokenBackendError( format_lazy( _("You must have cryptography installed to use {}."), algorithm ) ) def get_leeway(self) -> timedelta: if self.leeway is None: return timedelta(seconds=0) elif isinstance(self.leeway, (int, float)): return timedelta(seconds=self.leeway) elif isinstance(self.leeway, timedelta): return self.leeway else: raise TokenBackendError( format_lazy( _( "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." ), type(self.leeway), ) ) def get_verifying_key(self, token: Token) -> Any: if self.algorithm.startswith("HS"): return self.prepared_signing_key if self.jwks_client: try: return self.jwks_client.get_signing_key_from_jwt(token).key except PyJWKClientError as ex: raise TokenBackendError(_("Token is invalid")) from ex return self.prepared_verifying_key def encode(self, payload: dict[str, Any]) -> str: """ Returns an encoded token for the given payload dictionary. """ jwt_payload = payload.copy() if self.audience is not None: jwt_payload["aud"] = self.audience if self.issuer is not None: jwt_payload["iss"] = self.issuer token = jwt.encode( jwt_payload, self.prepared_signing_key, algorithm=self.algorithm, json_encoder=self.json_encoder, ) if isinstance(token, bytes): # For PyJWT <= 1.7.1 return token.decode("utf-8") # For PyJWT >= 2.0.0a1 return token def decode(self, token: Token, verify: bool = True) -> dict[str, Any]: """ Performs a validation of the given token and returns its payload dictionary. Raises a `TokenBackendError` if the token is malformed, if its signature check fails, or if its 'exp' claim indicates it has expired. """ try: return jwt.decode( token, self.get_verifying_key(token), algorithms=[self.algorithm], audience=self.audience, issuer=self.issuer, leeway=self.get_leeway(), options={ "verify_aud": self.audience is not None, "verify_signature": verify, }, ) except InvalidAlgorithmError as ex: raise TokenBackendError(_("Invalid algorithm specified")) from ex except ExpiredSignatureError as ex: raise TokenBackendExpiredToken(_("Token is expired")) from ex except InvalidTokenError as ex: raise TokenBackendError(_("Token is invalid")) from ex djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/exceptions.py000066400000000000000000000024241475766445300275250ustar00rootroot00000000000000from typing import Any, Optional, Union from django.utils.translation import gettext_lazy as _ from rest_framework import exceptions, status class TokenError(Exception): pass class ExpiredTokenError(TokenError): pass class TokenBackendError(Exception): pass class TokenBackendExpiredToken(TokenBackendError): pass class DetailDictMixin: default_detail: str default_code: str def __init__( self, detail: Union[dict[str, Any], str, None] = None, code: Optional[str] = None, ) -> None: """ Builds a detail dictionary for the error to give more information to API users. """ detail_dict = {"detail": self.default_detail, "code": self.default_code} if isinstance(detail, dict): detail_dict.update(detail) elif detail is not None: detail_dict["detail"] = detail if code is not None: detail_dict["code"] = code super().__init__(detail_dict) # type: ignore class AuthenticationFailed(DetailDictMixin, exceptions.AuthenticationFailed): pass class InvalidToken(AuthenticationFailed): status_code = status.HTTP_401_UNAUTHORIZED default_detail = _("Token is invalid or expired") default_code = "token_not_valid" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/000077500000000000000000000000001475766445300262275ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ar/000077500000000000000000000000001475766445300266315ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ar/LC_MESSAGES/000077500000000000000000000000001475766445300304165ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ar/LC_MESSAGES/django.mo000066400000000000000000000060611475766445300322200ustar00rootroot00000000000000Þ•ä%¬@<A,~(«Ô2ðO#s3 Ôìü#8 TIu¿Ð/ß  %)a.`Jñ\<2™OÌ:œ5×g 4u 'ª %Ò 'ø > N_ 2® …á g 0„ Fµ ü         Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'Unrecognized type '{}', 'leeway' must be of type int, float or timedelta.User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: Last-Translator: Ahmed Jazzar Language: ar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5; يجب أن يحتوي رأس التÙويض على قيمتين Ù…ÙØµÙˆÙ„تين Ø¨Ù…Ø³Ø§ÙØ§ØªÙ„ا يمكن إنشاء تأشيرة مرور بدون نوع أو عمرتأشيرة المرور غير صالحة لأي نوع من أنواع التأشيراتتم تحديد خوارزمية غير صالحةلم يتم العثور على حساب نشط للبيانات المقدمةتمت إزالة الإعداد '{}'. يرجى الرجوع إلى '{}' للتعر٠على الإعدادات المتاحة.انتهى عمر المطالبة بالتأشيرة '{}'قائمة تأشيرات المرور السوداءلا تحتوي تأشيرة المرور على هوية مستخدم يمكن التعر٠عليهاالتأشيرة ليس لديها مطالبة '{}'التأشيرة ليس لها Ù…Ø¹Ø±ÙØ§Ù„تأشيرة ليس لها نوعالتأشيرة لها نوع خاطئالتأشيرة مدرجة ÙÙŠ القائمة السوداءتأشيرة المرور غير صالحة أو منتهية الصلاحيةنوع الخوارزمية غير معرو٠'{}'نوع غير معرو٠'{}'. يجب أن تكون 'leeway' عددًا صحيحًا أو عددًا نسبيًا أو ÙØ±Ù‚ وقت.الحساب غير Ù…ÙØ¹Ù„لم يتم العثور على المستخدميجب أن يكون لديك تشÙير مثبت لاستخدام {}.أنشئت Ùيتنتهي ÙÙŠjtiالمستخدمdjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ar/LC_MESSAGES/django.po000066400000000000000000000105741475766445300322270ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 2019. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-03-20 17:30+0100\n" "Last-Translator: Ahmed Jazzar \n" "Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " "&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "يجب أن يحتوي رأس التÙويض على قيمتين Ù…ÙØµÙˆÙ„تين Ø¨Ù…Ø³Ø§ÙØ§Øª" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "تأشيرة المرور غير صالحة لأي نوع من أنواع التأشيرات" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "لا تحتوي تأشيرة المرور على هوية مستخدم يمكن التعر٠عليها" #: authentication.py:132 msgid "User not found" msgstr "لم يتم العثور على المستخدم" #: authentication.py:135 msgid "User is inactive" msgstr "الحساب غير Ù…ÙØ¹Ù„" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "نوع الخوارزمية غير معرو٠'{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "يجب أن يكون لديك تشÙير مثبت لاستخدام {}." #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" "نوع غير معرو٠'{}'. يجب أن تكون 'leeway' عددًا صحيحًا أو عددًا نسبيًا أو ÙØ±Ù‚ وقت." #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "تأشيرة المرور غير صالحة أو منتهية الصلاحية" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "تم تحديد خوارزمية غير صالحة" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "تأشيرة المرور غير صالحة أو منتهية الصلاحية" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "تأشيرة المرور غير صالحة أو منتهية الصلاحية" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "لم يتم العثور على حساب نشط للبيانات المقدمة" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "لم يتم العثور على حساب نشط للبيانات المقدمة" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "" "تمت إزالة الإعداد '{}'. يرجى الرجوع إلى '{}' للتعر٠على الإعدادات المتاحة." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "المستخدم" #: token_blacklist/admin.py:91 msgid "created at" msgstr "أنشئت ÙÙŠ" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "تنتهي ÙÙŠ" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "قائمة تأشيرات المرور السوداء" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "لا يمكن إنشاء تأشيرة مرور بدون نوع أو عمر" #: tokens.py:126 msgid "Token has no id" msgstr "التأشيرة ليس لها معرÙ" #: tokens.py:138 msgid "Token has no type" msgstr "التأشيرة ليس لها نوع" #: tokens.py:141 msgid "Token has wrong type" msgstr "التأشيرة لها نوع خاطئ" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "التأشيرة ليس لديها مطالبة '{}'" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "انتهى عمر المطالبة بالتأشيرة '{}'" #: tokens.py:292 msgid "Token is blacklisted" msgstr "التأشيرة مدرجة ÙÙŠ القائمة السوداء" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/cs/000077500000000000000000000000001475766445300266345ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/cs/LC_MESSAGES/000077500000000000000000000000001475766445300304215ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/cs/LC_MESSAGES/django.mo000066400000000000000000000040021475766445300322140ustar00rootroot00000000000000Þ•Ì|ð<ñ,.([2„O·$34h€¢·Ì è  ) 4?CàHG)9q2«7ÞBYwA‡!É#ë(?1\ Ž¯È Ü êô ø    Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'User is inactiveUser not foundcreated atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: Last-Translator: Lukáš Rod Language: cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AutorizaÄní hlaviÄka musí obsahovat dvÄ› hodnoty oddÄ›lené mezerouNelze vytvoÅ™it token bez zadaného typu nebo životnostiDaný token není validní pro žádný typ tokenuŽádný aktivní úÄet s danými údaji nebyl nalezenNastavení '{}' bylo odstranÄ›no. Dostupná nastavení jsou v '{}'Hodnota tokenu '{}' vyprÅ¡elaToken BlacklistToken neobsahoval žádnou rozpoznatelnou identifikaci uživateleToken nemá žádnou hodnotu '{}'Token nemá žádný identifikátorToken nemá žádný typToken má Å¡patný typToken je na Äerné listinÄ›Token není validní nebo vyprÅ¡ela jeho platnostNerozpoznaný typ algoritmu '{}'Uživatel není aktivníUživatel nenalezenvytvoÅ™ený vplatí dojtiuživateldjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/cs/LC_MESSAGES/django.po000066400000000000000000000067271475766445300322370ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 2019. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-02-22 17:30+0100\n" "Last-Translator: Lukáš Rod \n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "AutorizaÄní hlaviÄka musí obsahovat dvÄ› hodnoty oddÄ›lené mezerou" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "Daný token není validní pro žádný typ tokenu" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "Token neobsahoval žádnou rozpoznatelnou identifikaci uživatele" #: authentication.py:132 msgid "User not found" msgstr "Uživatel nenalezen" #: authentication.py:135 msgid "User is inactive" msgstr "Uživatel není aktivní" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Nerozpoznaný typ algoritmu '{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "" #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "Token není validní nebo vyprÅ¡ela jeho platnost" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "Token není validní nebo vyprÅ¡ela jeho platnost" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "Token není validní nebo vyprÅ¡ela jeho platnost" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "Žádný aktivní úÄet s danými údaji nebyl nalezen" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "Žádný aktivní úÄet s danými údaji nebyl nalezen" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "Nastavení '{}' bylo odstranÄ›no. Dostupná nastavení jsou v '{}'" #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "uživatel" #: token_blacklist/admin.py:91 msgid "created at" msgstr "vytvoÅ™ený v" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "platí do" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Token Blacklist" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "Nelze vytvoÅ™it token bez zadaného typu nebo životnosti" #: tokens.py:126 msgid "Token has no id" msgstr "Token nemá žádný identifikátor" #: tokens.py:138 msgid "Token has no type" msgstr "Token nemá žádný typ" #: tokens.py:141 msgid "Token has wrong type" msgstr "Token má Å¡patný typ" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "Token nemá žádnou hodnotu '{}'" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "Hodnota tokenu '{}' vyprÅ¡ela" #: tokens.py:292 msgid "Token is blacklisted" msgstr "Token je na Äerné listinÄ›" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/de/000077500000000000000000000000001475766445300266175ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/de/LC_MESSAGES/000077500000000000000000000000001475766445300304045ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/de/LC_MESSAGES/django.mo000066400000000000000000000040111475766445300321770ustar00rootroot00000000000000Þ•Ì|ð<ñ,.([2„O·$34h€¢·Ì è  ) 4?CHGN>–*Õ5X6"²6Âù&;V#t˜¸Ë ã ïü    Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'User is inactiveUser not foundcreated atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: Last-Translator: rene Language: de_CH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n > 1); Der Authorizationheader muss zwei leerzeichen-getrennte Werte enthaltenEin Token ohne Typ oder Lebensdauer kann nicht erstellt werdenDer Token ist für keinen Tokentyp gültigKein aktiver Account mit diesen Zugangsdaten gefundenDie Einstellung '{}' wurde gelöscht. Bitte beachte '{}' für verfügbare Einstellungen.Das Tokenrecht '{}' ist abgelaufenToken BlacklistToken enthält keine erkennbare BenutzeridentifikationToken hat kein '{}' RechtToken hat keine IdToken hat keinen TypToken hat den falschen TypToken steht auf der BlacklistUngültiger oder abgelaufener TokenUnerkannter Algorithmustyp '{}'Inaktiver BenutzerBenutzer nicht gefundenerstellt amläuft ab amjtiBenutzerdjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/de/LC_MESSAGES/django.po000066400000000000000000000067141475766445300322160ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 2020. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-02-22 17:30+0100\n" "Last-Translator: rene \n" "Language: de_CH\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "" "Der Authorizationheader muss zwei leerzeichen-getrennte Werte enthalten" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "Der Token ist für keinen Tokentyp gültig" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "Token enthält keine erkennbare Benutzeridentifikation" #: authentication.py:132 msgid "User not found" msgstr "Benutzer nicht gefunden" #: authentication.py:135 msgid "User is inactive" msgstr "Inaktiver Benutzer" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Unerkannter Algorithmustyp '{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "" #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "Ungültiger oder abgelaufener Token" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "Ungültiger oder abgelaufener Token" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "Ungültiger oder abgelaufener Token" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "Kein aktiver Account mit diesen Zugangsdaten gefunden" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "Kein aktiver Account mit diesen Zugangsdaten gefunden" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "" "Die Einstellung '{}' wurde gelöscht. Bitte beachte '{}' für verfügbare " "Einstellungen." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "Benutzer" #: token_blacklist/admin.py:91 msgid "created at" msgstr "erstellt am" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "läuft ab am" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Token Blacklist" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "Ein Token ohne Typ oder Lebensdauer kann nicht erstellt werden" #: tokens.py:126 msgid "Token has no id" msgstr "Token hat keine Id" #: tokens.py:138 msgid "Token has no type" msgstr "Token hat keinen Typ" #: tokens.py:141 msgid "Token has wrong type" msgstr "Token hat den falschen Typ" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "Token hat kein '{}' Recht" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "Das Tokenrecht '{}' ist abgelaufen" #: tokens.py:292 msgid "Token is blacklisted" msgstr "Token steht auf der Blacklist" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/es/000077500000000000000000000000001475766445300266365ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/es/LC_MESSAGES/000077500000000000000000000000001475766445300304235ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/es/LC_MESSAGES/django.mo000066400000000000000000000044561475766445300322330ustar00rootroot00000000000000Þ•Ü%œ0<1,n(›Ä2àOc€3ÄÜìþ( Dev/… µ ÀËÏ ÔLÞ7+4c!˜:ºaõ(W€<–$Óø !$F#d$ˆ­Ç0Ý   " &      Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: Last-Translator: zeack Language: es MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1); El encabezado 'Authorization' debe contener valores delimitados por espaciosNo se puede crear un token sin tipo o de tan larga vidaEl token dado no es valido para ningun tipo de tokenAlgoritmo especificado no válidoLa combinación de credenciales no tiene una cuenta activaLa configuración '{}' fue removida. Por favor, refiérase a '{}' para consultar las disponibles.El privilegio '{}' del token ha expiradoLista negra de TokensEl token no contenía identificación de usuario reconocibleEl token no tiene el privilegio '{}'El token no tiene idEl token no tiene tipoEl token tiene un tipo incorrectoEl token está en lista negraEl token es inválido o ha expiradoTipo de algoritmo no reconocido '{}'El usuario está inactivoUsuario no encontradoDebe tener criptografía instalada para usar {}.creado enexpira enjtiusuariodjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/es/LC_MESSAGES/django.po000066400000000000000000000071551475766445300322350ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 2020. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-02-22 17:30+0100\n" "Last-Translator: zeack \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "" "El encabezado 'Authorization' debe contener valores delimitados por espacios" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "El token dado no es valido para ningun tipo de token" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "El token no contenía identificación de usuario reconocible" #: authentication.py:132 msgid "User not found" msgstr "Usuario no encontrado" #: authentication.py:135 msgid "User is inactive" msgstr "El usuario está inactivo" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Tipo de algoritmo no reconocido '{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "Debe tener criptografía instalada para usar {}." #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "El token es inválido o ha expirado" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "Algoritmo especificado no válido" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "El token es inválido o ha expirado" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "El token es inválido o ha expirado" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "La combinación de credenciales no tiene una cuenta activa" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "La combinación de credenciales no tiene una cuenta activa" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "" "La configuración '{}' fue removida. Por favor, refiérase a '{}' para " "consultar las disponibles." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "usuario" #: token_blacklist/admin.py:91 msgid "created at" msgstr "creado en" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "expira en" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Lista negra de Tokens" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "No se puede crear un token sin tipo o de tan larga vida" #: tokens.py:126 msgid "Token has no id" msgstr "El token no tiene id" #: tokens.py:138 msgid "Token has no type" msgstr "El token no tiene tipo" #: tokens.py:141 msgid "Token has wrong type" msgstr "El token tiene un tipo incorrecto" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "El token no tiene el privilegio '{}'" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "El privilegio '{}' del token ha expirado" #: tokens.py:292 msgid "Token is blacklisted" msgstr "El token está en lista negra" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/es_AR/000077500000000000000000000000001475766445300272205ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/es_AR/LC_MESSAGES/000077500000000000000000000000001475766445300310055ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/es_AR/LC_MESSAGES/django.mo000066400000000000000000000041661475766445300326130ustar00rootroot00000000000000Þ•Ì|ð<ñ,.([2„O·$34h€¢·Ì è  ) 4?CHL\6©6àHq`(Òû7$Inƒ!š ¼#Ý$&@ V `jn    Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'User is inactiveUser not foundcreated atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: Last-Translator: Ariel Torti Language: es_AR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1); El header de autorización debe contener dos valores delimitados por espacioNo es posible crear un token sin tipo o tiempo de vidaEl token dado no es válido para ningún tipo de tokenNo se encontró una cuenta de usuario activa para las credenciales dadasLa configuración '{}' fue removida. Por favor, refiérase a '{}' para consultar las configuraciones disponibles.El privilegio '{}' del token ha expiradoLista negra de TokensEl token no contiene ninguna identificación de usuarioEl token no tiene el privilegio '{}'El token no tiene idEl token no tiene tipoEl token tiene un tipo incorrectoEl token está en la lista negraEl token es inválido o ha expiradoTipo de algoritmo no reconocido '{}'El usuario está inactivoUsuario no encontradocreado enexpira enjtiusuariodjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/es_AR/LC_MESSAGES/django.po000066400000000000000000000072501475766445300326130ustar00rootroot00000000000000# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Translators: # Ariel Torti , 2020. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-02-22 17:30+0100\n" "Last-Translator: Ariel Torti \n" "Language: es_AR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "" "El header de autorización debe contener dos valores delimitados por espacio" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "El token dado no es válido para ningún tipo de token" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "El token no contiene ninguna identificación de usuario" #: authentication.py:132 msgid "User not found" msgstr "Usuario no encontrado" #: authentication.py:135 msgid "User is inactive" msgstr "El usuario está inactivo" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Tipo de algoritmo no reconocido '{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "" #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "El token es inválido o ha expirado" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "El token es inválido o ha expirado" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "El token es inválido o ha expirado" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "" "No se encontró una cuenta de usuario activa para las credenciales dadas" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "" "No se encontró una cuenta de usuario activa para las credenciales dadas" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "" "La configuración '{}' fue removida. Por favor, refiérase a '{}' para " "consultar las configuraciones disponibles." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "usuario" #: token_blacklist/admin.py:91 msgid "created at" msgstr "creado en" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "expira en" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Lista negra de Tokens" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "No es posible crear un token sin tipo o tiempo de vida" #: tokens.py:126 msgid "Token has no id" msgstr "El token no tiene id" #: tokens.py:138 msgid "Token has no type" msgstr "El token no tiene tipo" #: tokens.py:141 msgid "Token has wrong type" msgstr "El token tiene un tipo incorrecto" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "El token no tiene el privilegio '{}'" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "El privilegio '{}' del token ha expirado" #: tokens.py:292 msgid "Token is blacklisted" msgstr "El token está en la lista negra" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/es_CL/000077500000000000000000000000001475766445300272145ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/es_CL/LC_MESSAGES/000077500000000000000000000000001475766445300310015ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/es_CL/LC_MESSAGES/django.mo000066400000000000000000000041201475766445300325750ustar00rootroot00000000000000Þ•Ì|ð<ñ,.([2„O·$34h€¢·Ì è  ) 4?CHL]6ª:áLci+Íù; EdvФÀ$Û 0 :DH    Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'User is inactiveUser not foundcreated atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: Last-Translator: Alfonso Pola Language: es_CL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n > 1); El header de autorización debe contener dos valores delimitados por espacioNo es posible crear un token sin tipo o tiempo de vidaEl token provisto no es válido para ningún tipo de tokenNo se encontró una cuenta de usuario activa para las credenciales provistasLa configuración '{}' fue removida. Por favor, refiérase a '{}' para configuraciones disponibles.El provilegio '{}' del token está expiradoToken BlacklistEl token no contiene identificación de usuario reconocibleToken no tiene privilegio '{}'Token no tiene idToken no tiene tipoToken tiene tipo erróneoToken está en la blacklistToken inválido o expiradoTipo de algoritmo no reconocido '{}'El usuario está inactivoUsuario no encontradocreado enexpira enjtiUsuariodjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/es_CL/LC_MESSAGES/django.po000066400000000000000000000070451475766445300326110ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 2019. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-02-22 17:30+0100\n" "Last-Translator: Alfonso Pola \n" "Language: es_CL\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "" "El header de autorización debe contener dos valores delimitados por espacio" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "El token provisto no es válido para ningún tipo de token" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "El token no contiene identificación de usuario reconocible" #: authentication.py:132 msgid "User not found" msgstr "Usuario no encontrado" #: authentication.py:135 msgid "User is inactive" msgstr "El usuario está inactivo" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Tipo de algoritmo no reconocido '{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "" #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "Token inválido o expirado" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "Token inválido o expirado" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "Token inválido o expirado" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "" "No se encontró una cuenta de usuario activa para las credenciales provistas" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "" "No se encontró una cuenta de usuario activa para las credenciales provistas" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "" "La configuración '{}' fue removida. Por favor, refiérase a '{}' para " "configuraciones disponibles." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "Usuario" #: token_blacklist/admin.py:91 msgid "created at" msgstr "creado en" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "expira en" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Token Blacklist" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "No es posible crear un token sin tipo o tiempo de vida" #: tokens.py:126 msgid "Token has no id" msgstr "Token no tiene id" #: tokens.py:138 msgid "Token has no type" msgstr "Token no tiene tipo" #: tokens.py:141 msgid "Token has wrong type" msgstr "Token tiene tipo erróneo" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "Token no tiene privilegio '{}'" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "El provilegio '{}' del token está expirado" #: tokens.py:292 msgid "Token is blacklisted" msgstr "Token está en la blacklist" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/fa/000077500000000000000000000000001475766445300266155ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/fa/LC_MESSAGES/000077500000000000000000000000001475766445300304025ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/fa/LC_MESSAGES/django.mo000066400000000000000000000056761475766445300322170ustar00rootroot00000000000000Þ•ì%¼P<Q,Ž(»ä2O3%ƒ©Æ3Ö "2DYn ŠI«õ/ E P[_-dd’K÷WC6›TÒv'5ž%ÔúR 0h ™ ° 'Ë /ó <# -` aŽ ð  Z, ‡ › ¯ ³     Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.The user's password has been changed.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'Unrecognized type '{}', 'leeway' must be of type int, float or timedelta.User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: PACKAGE VERSION Report-Msgid-Bugs-To: PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: Mahdi Rahimi Language: fa MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n > 1); هدر اعتبارسنجی باید شامل دو مقدار جدا شده با ÙØ§ØµÙ„Ù‡ باشدتوکن بدون هیچ نوع Ùˆ طول عمر قابل ساخت نیستتوکن داده شده برای هیچ نوع توکنی معتبر نمی‌باشدالگوریتم نامعتبر مشخص شده استهیچ اکانت ÙØ¹Ø§Ù„ÛŒ برای اطلاعات داده شده ÛŒØ§ÙØª نشدتنظیمات '{}' حذ٠شده است. Ù„Ø·ÙØ§ به '{}' برای تنظیمات موجود مراجعه کنید.رمز عبور کاربر تغییر کرده است'{}' claim توکن منقضی شدهلیست سیاه توکنتوکن شامل هیچ شناسه قابل تشخیصی از کاربر نیستتوکن دارای '{}' claim نمی‌باشدتوکن id نداردتوکن نوع نداردتوکن نوع اشتباهی داردتوکن به لیست سیاه Ø±ÙØªÙ‡ استتوکن نامعتبر است یا منقضی شده استنوع الگوریتم ناشناخته '{}'نوع ناشناخته '{}'ØŒ 'leeway' باید از نوع intØŒ float یا timedelta باشد.کاربر ØºÛŒØ±ÙØ¹Ø§Ù„ استکاربر ÛŒØ§ÙØª نشدبرای Ø§Ø³ØªÙØ§Ø¯Ù‡ از {} باید رمزنگاری را نصب کرده باشید.زمان ایجادزمان انقضاjtiکاربرdjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/fa/LC_MESSAGES/django.po000066400000000000000000000104211475766445300322020ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR \>, 2023. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-07-04 09:31+0330\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Mahdi Rahimi \n" "Language: fa\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "هدر اعتبارسنجی باید شامل دو مقدار جدا شده با ÙØ§ØµÙ„Ù‡ باشد" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "توکن داده شده برای هیچ نوع توکنی معتبر نمی‌باشد" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "توکن شامل هیچ شناسه قابل تشخیصی از کاربر نیست" #: authentication.py:132 msgid "User not found" msgstr "کاربر ÛŒØ§ÙØª نشد" #: authentication.py:135 msgid "User is inactive" msgstr "کاربر ØºÛŒØ±ÙØ¹Ø§Ù„ است" #: authentication.py:142 msgid "The user's password has been changed." msgstr "رمز عبور کاربر تغییر کرده است" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "نوع الگوریتم ناشناخته '{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "برای Ø§Ø³ØªÙØ§Ø¯Ù‡ از {} باید رمزنگاری را نصب کرده باشید." #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "نوع ناشناخته '{}'ØŒ 'leeway' باید از نوع intØŒ float یا timedelta باشد." #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "توکن نامعتبر است یا منقضی شده است" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "الگوریتم نامعتبر مشخص شده است" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "توکن نامعتبر است یا منقضی شده است" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "توکن نامعتبر است یا منقضی شده است" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "هیچ اکانت ÙØ¹Ø§Ù„ÛŒ برای اطلاعات داده شده ÛŒØ§ÙØª نشد" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "هیچ اکانت ÙØ¹Ø§Ù„ÛŒ برای اطلاعات داده شده ÛŒØ§ÙØª نشد" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "تنظیمات '{}' حذ٠شده است. Ù„Ø·ÙØ§ به '{}' برای تنظیمات موجود مراجعه کنید." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "کاربر" #: token_blacklist/admin.py:91 msgid "created at" msgstr "زمان ایجاد" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "زمان انقضا" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "لیست سیاه توکن" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "توکن بدون هیچ نوع Ùˆ طول عمر قابل ساخت نیست" #: tokens.py:126 msgid "Token has no id" msgstr "توکن id ندارد" #: tokens.py:138 msgid "Token has no type" msgstr "توکن نوع ندارد" #: tokens.py:141 msgid "Token has wrong type" msgstr "توکن نوع اشتباهی دارد" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "توکن دارای '{}' claim نمی‌باشد" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "'{}' claim توکن منقضی شده" #: tokens.py:292 msgid "Token is blacklisted" msgstr "توکن به لیست سیاه Ø±ÙØªÙ‡ است" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/fa_IR/000077500000000000000000000000001475766445300272075ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/fa_IR/LC_MESSAGES/000077500000000000000000000000001475766445300307745ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/fa_IR/LC_MESSAGES/django.mo000066400000000000000000000055751475766445300326070ustar00rootroot00000000000000Þ•ì%¼P<Q,Ž(»ä2O3%ƒ©Æ3Ö "2DYn ŠI«õ/ E P[_ìddQK¶W6ZT‘væ5]%“¹RÔ0' X o 'Š /² <â - aM ¯ Ð Zë F Z n r     Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.The user's password has been changed.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'Unrecognized type '{}', 'leeway' must be of type int, float or timedelta.User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: Last-Translator: Mahdi Rahimi Language: fa_IR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit هدر اعتبارسنجی باید شامل دو مقدار جدا شده با ÙØ§ØµÙ„Ù‡ باشدتوکن بدون هیچ نوع Ùˆ طول عمر قابل ساخت نیستتوکن داده شده برای هیچ نوع توکنی معتبر نمی‌باشدالگوریتم نامعتبر مشخص شده استهیچ اکانت ÙØ¹Ø§Ù„ÛŒ برای اطلاعات داده شده ÛŒØ§ÙØª نشدتنظیمات '{}' حذ٠شده است. Ù„Ø·ÙØ§ به '{}' برای تنظیمات موجود مراجعه کنید.رمز عبور کاربر تغییر کرده است'{}' claim توکن منقضی شدهلیست سیاه توکنتوکن شامل هیچ شناسه قابل تشخیصی از کاربر نیستتوکن دارای '{}' claim نمی‌باشدتوکن id نداردتوکن نوع نداردتوکن نوع اشتباهی داردتوکن به لیست سیاه Ø±ÙØªÙ‡ استتوکن نامعتبر است یا منقضی شده استنوع الگوریتم ناشناخته '{}'نوع ناشناخته '{}'ØŒ 'leeway' باید از نوع intØŒ float یا timedelta باشد.کاربر ØºÛŒØ±ÙØ¹Ø§Ù„ استکاربر ÛŒØ§ÙØª نشدبرای Ø§Ø³ØªÙØ§Ø¯Ù‡ از {} باید رمزنگاری را نصب کرده باشید.زمان ایجادزمان انقضاjtiکاربرdjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/fa_IR/LC_MESSAGES/django.po000066400000000000000000000101561475766445300326010ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 2020. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-07-06 12:57+0330\n" "Last-Translator: Mahdi Rahimi \n" "Language: fa_IR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "هدر اعتبارسنجی باید شامل دو مقدار جدا شده با ÙØ§ØµÙ„Ù‡ باشد" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "توکن داده شده برای هیچ نوع توکنی معتبر نمی‌باشد" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "توکن شامل هیچ شناسه قابل تشخیصی از کاربر نیست" #: authentication.py:132 msgid "User not found" msgstr "کاربر ÛŒØ§ÙØª نشد" #: authentication.py:135 msgid "User is inactive" msgstr "کاربر ØºÛŒØ±ÙØ¹Ø§Ù„ است" #: authentication.py:142 msgid "The user's password has been changed." msgstr "رمز عبور کاربر تغییر کرده است" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "نوع الگوریتم ناشناخته '{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "برای Ø§Ø³ØªÙØ§Ø¯Ù‡ از {} باید رمزنگاری را نصب کرده باشید." #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "نوع ناشناخته '{}'ØŒ 'leeway' باید از نوع intØŒ float یا timedelta باشد." #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "توکن نامعتبر است یا منقضی شده است" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "الگوریتم نامعتبر مشخص شده است" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "توکن نامعتبر است یا منقضی شده است" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "توکن نامعتبر است یا منقضی شده است" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "هیچ اکانت ÙØ¹Ø§Ù„ÛŒ برای اطلاعات داده شده ÛŒØ§ÙØª نشد" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "هیچ اکانت ÙØ¹Ø§Ù„ÛŒ برای اطلاعات داده شده ÛŒØ§ÙØª نشد" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "تنظیمات '{}' حذ٠شده است. Ù„Ø·ÙØ§ به '{}' برای تنظیمات موجود مراجعه کنید." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "کاربر" #: token_blacklist/admin.py:91 msgid "created at" msgstr "زمان ایجاد" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "زمان انقضا" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "لیست سیاه توکن" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "توکن بدون هیچ نوع Ùˆ طول عمر قابل ساخت نیست" #: tokens.py:126 msgid "Token has no id" msgstr "توکن id ندارد" #: tokens.py:138 msgid "Token has no type" msgstr "توکن نوع ندارد" #: tokens.py:141 msgid "Token has wrong type" msgstr "توکن نوع اشتباهی دارد" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "توکن دارای '{}' claim نمی‌باشد" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "'{}' claim توکن منقضی شده" #: tokens.py:292 msgid "Token is blacklisted" msgstr "توکن به لیست سیاه Ø±ÙØªÙ‡ است" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/fr/000077500000000000000000000000001475766445300266365ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/fr/LC_MESSAGES/000077500000000000000000000000001475766445300304235ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/fr/LC_MESSAGES/django.mo000066400000000000000000000044601475766445300322260ustar00rootroot00000000000000Þ•Ü%œ0<1,n(›Ä2àOc€3ÄÜìþ( Dev/… µ ÀËÏöÔPË6(S$|B¡Zä%?eM}#Ëï9 P"q”#²5Ö   $      Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: Last-Translator: Stéphane Malta e Sousa Language: fr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L'en-tête 'Authorization' doit contenir deux valeurs séparées par des espacesNe peut pas créer de jeton sans type ni durée de vieLe type de jeton fourni n'est pas valideL'algorithme spécifié est invalideAucun compte actif n'a été trouvé avec les identifiants fournisLe paramètre '{}' a été supprimé. Voir '{}' pour la liste des paramètres disponibles.Le privilège '{}' du jeton a expiréListe des jetons bannisLe jeton ne contient aucune information permettant d'identifier l'utilisateurLe jeton n'a pas le privilège '{}'Le jeton n'a pas d'idLe jeton n'a pas de typeLe jeton a un type erronéLe jeton a été banniLe jeton est invalide ou expiréType d'algorithme non reconnu '{}'L'utilisateur est désactivéL'utilisateur n'a pas été trouvéVous devez installer cryptography afin d'utiliser {}.Créé leExpire lejtiUtilisateurdjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/fr/LC_MESSAGES/django.po000066400000000000000000000071661475766445300322370ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 2020. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-02-22 17:30+0100\n" "Last-Translator: Stéphane Malta e Sousa \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "" "L'en-tête 'Authorization' doit contenir deux valeurs séparées par des espaces" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "Le type de jeton fourni n'est pas valide" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "" "Le jeton ne contient aucune information permettant d'identifier l'utilisateur" #: authentication.py:132 msgid "User not found" msgstr "L'utilisateur n'a pas été trouvé" #: authentication.py:135 msgid "User is inactive" msgstr "L'utilisateur est désactivé" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Type d'algorithme non reconnu '{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "Vous devez installer cryptography afin d'utiliser {}." #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "Le jeton est invalide ou expiré" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "L'algorithme spécifié est invalide" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "Le jeton est invalide ou expiré" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "Le jeton est invalide ou expiré" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "Aucun compte actif n'a été trouvé avec les identifiants fournis" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "Aucun compte actif n'a été trouvé avec les identifiants fournis" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "" "Le paramètre '{}' a été supprimé. Voir '{}' pour la liste des paramètres " "disponibles." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "Utilisateur" #: token_blacklist/admin.py:91 msgid "created at" msgstr "Créé le" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "Expire le" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Liste des jetons bannis" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "Ne peut pas créer de jeton sans type ni durée de vie" #: tokens.py:126 msgid "Token has no id" msgstr "Le jeton n'a pas d'id" #: tokens.py:138 msgid "Token has no type" msgstr "Le jeton n'a pas de type" #: tokens.py:141 msgid "Token has wrong type" msgstr "Le jeton a un type erroné" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "Le jeton n'a pas le privilège '{}'" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "Le privilège '{}' du jeton a expiré" #: tokens.py:292 msgid "Token is blacklisted" msgstr "Le jeton a été banni" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/he_IL/000077500000000000000000000000001475766445300272075ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/he_IL/LC_MESSAGES/000077500000000000000000000000001475766445300307745ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/he_IL/LC_MESSAGES/django.mo000066400000000000000000000053201475766445300325730ustar00rootroot00000000000000Þ•ä%¬@<A,~(«Ô2ðO#s3 Ôìü#8 TIu¿Ð/ß  %)Q.V€F×>']8…r¾1%MDs¸%Ïõ$ %3 3Y , ]º  7 GP ˜ ª Á Å      Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'Unrecognized type '{}', 'leeway' must be of type int, float or timedelta.User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: PO-Revision-Date: Last-Translator: Language-Team: Language: he MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n==2 ? 1 : n>10 && n%10==0 ? 2 : 3); X-Generator: Poedit 3.2.2 Authorization Header חייבת להכיל שני ×¢×¨×›×™× ×ž×•×¤×¨×“×™× ×‘×¨×•×•×—×œ× × ×™×ª×Ÿ ליצור מזהה ×œ×œ× ×¡×•×’ ×ו ×ורך ×—×™×™×המזהה הנתון ×ינו תקף עבור ××£ סיווגצוין ××œ×’×•×¨×™×ª× ×œ× ×—×•×§×™×œ× × ×ž×¦× ×—×©×‘×•×Ÿ ×¢× ×¤×¨×˜×™ זיהוי ×לוההגדרה '{}' הוסרה. בבקשה קר×ו ×›×ן: '{}' בשביל לר×ות הגדרות ×פשרויותמזהה '{}' פג תוקףרשימה שחורה של מזהי×המזהה ×œ× ×”×›×™×œ זיהוי משתמש שניתן לזהותלמזהה ×ין '{}'למזהה ×ין מספר זיהוילמזהה ×ין סוגלמזהה יש סוג ×œ× × ×›×•×Ÿ×”×ž×–×”×” ברשימה השחורה.המזהה ×ינו חוקי ×ו שפג תוקפוסוג ××œ×’×•×¨×™×ª× ×œ× ×ž×–×•×”×” '{}'סוג ×œ× ×ž×–×•×”×” '{}', 'leeway' חייב להיות מסוג int, float ×ו timedelta.המשתמש ×ינו פעילמשתמש ×œ× × ×ž×¦×עליך להתקין קריפטוגרפיה כדי להשתמש ב-{}.נוצר בשעהפג תוקף בשעהjtiמשתמשdjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/he_IL/LC_MESSAGES/django.po000066400000000000000000000077301475766445300326050ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 2020. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-02-22 17:30+0100\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" "Language: he\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n==2 ? 1 : n>10 && n%10==0 ? " "2 : 3);\n" "X-Generator: Poedit 3.2.2\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "Authorization Header חייבת להכיל שני ×¢×¨×›×™× ×ž×•×¤×¨×“×™× ×‘×¨×•×•×—" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "המזהה הנתון ×ינו תקף עבור ××£ סיווג" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "המזהה ×œ× ×”×›×™×œ זיהוי משתמש שניתן לזהות" #: authentication.py:132 msgid "User not found" msgstr "משתמש ×œ× × ×ž×¦×" #: authentication.py:135 msgid "User is inactive" msgstr "המשתמש ×ינו פעיל" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "סוג ××œ×’×•×¨×™×ª× ×œ× ×ž×–×•×”×” '{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "עליך להתקין קריפטוגרפיה כדי להשתמש ב-{}." #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "סוג ×œ× ×ž×–×•×”×” '{}', 'leeway' חייב להיות מסוג int, float ×ו timedelta." #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "המזהה ×ינו חוקי ×ו שפג תוקפו" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "צוין ××œ×’×•×¨×™×ª× ×œ× ×—×•×§×™" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "המזהה ×ינו חוקי ×ו שפג תוקפו" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "המזהה ×ינו חוקי ×ו שפג תוקפו" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "×œ× × ×ž×¦× ×—×©×‘×•×Ÿ ×¢× ×¤×¨×˜×™ זיהוי ×לו" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "×œ× × ×ž×¦× ×—×©×‘×•×Ÿ ×¢× ×¤×¨×˜×™ זיהוי ×לו" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "ההגדרה '{}' הוסרה. בבקשה קר×ו ×›×ן: '{}' בשביל לר×ות הגדרות ×פשרויות" #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "משתמש" #: token_blacklist/admin.py:91 msgid "created at" msgstr "נוצר בשעה" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "פג תוקף בשעה" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "רשימה שחורה של מזהי×" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "×œ× × ×™×ª×Ÿ ליצור מזהה ×œ×œ× ×¡×•×’ ×ו ×ורך ×—×™×™×" #: tokens.py:126 msgid "Token has no id" msgstr "למזהה ×ין מספר זיהוי" #: tokens.py:138 msgid "Token has no type" msgstr "למזהה ×ין סוג" #: tokens.py:141 msgid "Token has wrong type" msgstr "למזהה יש סוג ×œ× × ×›×•×Ÿ" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "למזהה ×ין '{}'" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "מזהה '{}' פג תוקף" #: tokens.py:292 msgid "Token is blacklisted" msgstr "המזהה ברשימה השחורה." djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/id_ID/000077500000000000000000000000001475766445300271775ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/id_ID/LC_MESSAGES/000077500000000000000000000000001475766445300307645ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/id_ID/LC_MESSAGES/django.mo000066400000000000000000000047401475766445300325700ustar00rootroot00000000000000Þ•ä%¬@<A,~(«Ô2ðO#s3 Ôìü#8 TIu¿Ð/ß  %)1.=`4ž8Ó% D2Sw"Ëî@Bbz”¦"¿"âL R g 6€ ·  Ó ×      Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'Unrecognized type '{}', 'leeway' must be of type int, float or timedelta.User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: PO-Revision-Date: 2023-03-09 08:14+0000 Last-Translator: Kira Language: id_ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n > 1); Header otorisasi harus berisi dua nilai yang dipisahkan spasiTidak dapat membuat token tanpa tipe atau masa pakaiToken yang diberikan tidak valid untuk semua jenis tokenAlgoritma yang ditentukan tidak validTidak ada akun aktif yang ditemukan dengan kredensial yang diberikanSetelan '{}' telah dihapus. Silakan merujuk ke '{}' untuk pengaturan yang tersedia.Klaim token '{}' telah kedaluwarsaDaftar Hitam TokenToken tidak mengandung identifikasi pengguna yang dapat dikenaliToken tidak memiliki klaim '{}'Token tidak memiliki idToken tidak memiliki tipeJenis token salahToken masuk daftar hitamToken tidak valid atau kedaluwarsaJenis algoritma tidak dikenal '{}'Tipe '{}' tidak dikenali, 'leeway' harus bertipe int, float, atau timedelta.Pengguna tidak aktifPengguna tidak ditemukanAnda harus memasang cryptography untuk menggunakan {}.created atkedaluwarsa padajtipenggunadjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/id_ID/LC_MESSAGES/django.po000066400000000000000000000073711475766445300325760ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # # Translators: # , 2020 # Kira , 2023 msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-02-22 17:30+0100\n" "PO-Revision-Date: 2023-03-09 08:14+0000\n" "Last-Translator: Kira \n" "Language: id_ID\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "Header otorisasi harus berisi dua nilai yang dipisahkan spasi" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "Token yang diberikan tidak valid untuk semua jenis token" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "Token tidak mengandung identifikasi pengguna yang dapat dikenali" #: authentication.py:132 msgid "User not found" msgstr "Pengguna tidak ditemukan" #: authentication.py:135 msgid "User is inactive" msgstr "Pengguna tidak aktif" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Jenis algoritma tidak dikenal '{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "Anda harus memasang cryptography untuk menggunakan {}." #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" "Tipe '{}' tidak dikenali, 'leeway' harus bertipe int, float, atau timedelta." #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "Token tidak valid atau kedaluwarsa" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "Algoritma yang ditentukan tidak valid" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "Token tidak valid atau kedaluwarsa" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "Token tidak valid atau kedaluwarsa" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "Tidak ada akun aktif yang ditemukan dengan kredensial yang diberikan" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "Tidak ada akun aktif yang ditemukan dengan kredensial yang diberikan" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "" "Setelan '{}' telah dihapus. Silakan merujuk ke '{}' untuk pengaturan yang " "tersedia." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "pengguna" #: token_blacklist/admin.py:91 msgid "created at" msgstr "created at" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "kedaluwarsa pada" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Daftar Hitam Token" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "Tidak dapat membuat token tanpa tipe atau masa pakai" #: tokens.py:126 msgid "Token has no id" msgstr "Token tidak memiliki id" #: tokens.py:138 msgid "Token has no type" msgstr "Token tidak memiliki tipe" #: tokens.py:141 msgid "Token has wrong type" msgstr "Jenis token salah" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "Token tidak memiliki klaim '{}'" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "Klaim token '{}' telah kedaluwarsa" #: tokens.py:292 msgid "Token is blacklisted" msgstr "Token masuk daftar hitam" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/it_IT/000077500000000000000000000000001475766445300272375ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/it_IT/LC_MESSAGES/000077500000000000000000000000001475766445300310245ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/it_IT/LC_MESSAGES/django.mo000066400000000000000000000046011475766445300326240ustar00rootroot00000000000000Þ•Ü%œ0<1,n(›Ä2àOc€3ÄÜìþ( Dev/… µ ÀËÏQÔM&/t7¤%Ü4g7&ŸÆEÚ' H^v*”#¿'ã  20 c m v z      Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: PO-Revision-Date: Last-Translator: Adriano Di Dio <95adriano@gmail.com> Language-Team: Language: it_IT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Generator: Poedit 2.0.6 Plural-Forms: nplurals=2; plural=(n != 1); L'header di autorizzazione deve contenere due valori delimitati da uno spazioImpossibile creare un token senza tipo o durataIl token dato non è valido per qualsiasi tipo di tokenL'algoritmo specificato non è validoNessun account attivo trovato con queste credenzialiL'impostazione '{}' è stata rimossa. Per favore utilizza '{}' per visualizzare le impostazioni valide.Il parametro '{}' del token è scadutoBlacklist dei tokenIl token non conteneva nessuna informazione riconoscibile dell'utenteIl token non contiene il parametro '{}'Il token non ha un idIl token non ha un tipoIl token ha un tipo sbagliatoIl token è stato inserito nella blacklistIl token non è valido o è scadutoAlgoritmo di tipo '{}' non riconosciutoUtente non attivoUtente non trovatoDevi avere installato cryptography per usare '{}'.creato ilscade iljtiutentedjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/it_IT/LC_MESSAGES/django.po000066400000000000000000000073051475766445300326330ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <95adriano@gmail.com>, 2020. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-02-22 17:30+0100\n" "PO-Revision-Date: \n" "Last-Translator: Adriano Di Dio <95adriano@gmail.com>\n" "Language-Team: \n" "Language: it_IT\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.0.6\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "" "L'header di autorizzazione deve contenere due valori delimitati da uno spazio" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "Il token dato non è valido per qualsiasi tipo di token" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "Il token non conteneva nessuna informazione riconoscibile dell'utente" #: authentication.py:132 msgid "User not found" msgstr "Utente non trovato" #: authentication.py:135 msgid "User is inactive" msgstr "Utente non attivo" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Algoritmo di tipo '{}' non riconosciuto" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "Devi avere installato cryptography per usare '{}'." #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "Il token non è valido o è scaduto" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "L'algoritmo specificato non è valido" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "Il token non è valido o è scaduto" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "Il token non è valido o è scaduto" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "Nessun account attivo trovato con queste credenziali" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "Nessun account attivo trovato con queste credenziali" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "" "L'impostazione '{}' è stata rimossa. Per favore utilizza '{}' per " "visualizzare le impostazioni valide." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "utente" #: token_blacklist/admin.py:91 msgid "created at" msgstr "creato il" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "scade il" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Blacklist dei token" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "Impossibile creare un token senza tipo o durata" #: tokens.py:126 msgid "Token has no id" msgstr "Il token non ha un id" #: tokens.py:138 msgid "Token has no type" msgstr "Il token non ha un tipo" #: tokens.py:141 msgid "Token has wrong type" msgstr "Il token ha un tipo sbagliato" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "Il token non contiene il parametro '{}'" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "Il parametro '{}' del token è scaduto" #: tokens.py:292 msgid "Token is blacklisted" msgstr "Il token è stato inserito nella blacklist" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ko_KR/000077500000000000000000000000001475766445300272345ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ko_KR/LC_MESSAGES/000077500000000000000000000000001475766445300310215ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ko_KR/LC_MESSAGES/django.mo000066400000000000000000000055401475766445300326240ustar00rootroot00000000000000Þ•ì%¼P<Q,Ž(»ä2O3%ƒ©Æ3Ö "2DYn ŠI«õ/ E P[_dWwCÏI/]Y\ç0D.u¤A»(ý3& -Z ˆ ,© 0Ö 4 l< "© $Ì Dñ 6 D R V     Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.The user's password has been changed.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'Unrecognized type '{}', 'leeway' must be of type int, float or timedelta.User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: Last-Translator: 정재균 Language: ko_KR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=1; plural=0; ì¸ì¦ í—¤ë”ì—는 공백으로 구분 ëœ ë‘ ê°œì˜ ê°’ì´ í¬í•¨ë˜ì–´ì•¼ 합니다타입 ë˜ëŠ” ìˆ˜ëª…ì´ ì—†ëŠ” 토í°ì„ ìƒì„±í•  수 ì—†ìŠµë‹ˆë‹¤ì´ í† í°ì€ 모든 íƒ€ìž…ì˜ í† í°ì— 대해 유효하지 ì•ŠìŠµë‹ˆë‹¤ìž˜ëª»ëœ ì•Œê³ ë¦¬ì¦˜ì´ ì§€ì •ë˜ì—ˆìŠµë‹ˆë‹¤ì§€ì •ëœ ìžê²© ì¦ëª…ì— í•´ë‹¹í•˜ëŠ” í™œì„±í™”ëœ ì‚¬ìš©ìžë¥¼ ì°¾ì„ ìˆ˜ 없습니다'{}' ì„¤ì •ì´ ì œê±°ë˜ì—ˆìŠµë‹ˆë‹¤. 사용 가능한 ì„¤ì •ì€ '{}'ì„ ì°¸ì¡°í•˜ì‹­ì‹œì˜¤.사용ìžì˜ 비밀번호가 바뀌었습니다.í† í° '{}' í´ë ˆìž„ì´ ë§Œë£Œë˜ì—ˆìŠµë‹ˆë‹¤í† í° ë¸”ëž™ë¦¬ìŠ¤íŠ¸í† í°ì— ì‚¬ìš©ìž ì‹ë³„ìžê°€ í¬í•¨ë˜ì–´ 있지 않습니다토í°ì— '{}' í´ë ˆìž„ì´ ì—†ìŠµë‹ˆë‹¤í† í°ì— ì‹ë³„ìžê°€ 주어지지 ì•Šì•˜ìŠµë‹ˆë‹¤í† í° íƒ€ìž…ì´ ì£¼ì–´ì§€ì§€ ì•Šì•˜ìŠµë‹ˆë‹¤ìž˜ëª»ëœ í† í° íƒ€ìž…ìž…ë‹ˆë‹¤ë¸”ëž™ë¦¬ìŠ¤íŠ¸ì— ì¶”ê°€ëœ í† í°ìž…니다유효하지 않거나 ë§Œë£Œëœ í† í°ìž…니다'{}' 는 알 수 없는 알고리즘 유형입니다알 수 없는 타입 '{}', 'leeway' ê°’ì€ ë°˜ë“œì‹œ int, float ë˜ëŠ” timedelta 타입ì´ì–´ì•¼ 합니다.ë¹„í™œì„±í™”ëœ ì‚¬ìš©ìžìž…ë‹ˆë‹¤ì°¾ì„ ìˆ˜ 없는 사용ìžìž…니다{}를 사용하려면 암호화가 설치ë˜ì–´ 있어야 합니다.ìƒì„± 시간만료 시간jti사용ìždjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ko_KR/LC_MESSAGES/django.po000066400000000000000000000101171475766445300326230ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR ì–‘ì˜ê´‘ , 2022. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-01-05 06:48+0900\n" "Last-Translator: 정재균 \n" "Language: ko_KR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "ì¸ì¦ í—¤ë”ì—는 공백으로 구분 ëœ ë‘ ê°œì˜ ê°’ì´ í¬í•¨ë˜ì–´ì•¼ 합니다" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "ì´ í† í°ì€ 모든 íƒ€ìž…ì˜ í† í°ì— 대해 유효하지 않습니다" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "토í°ì— ì‚¬ìš©ìž ì‹ë³„ìžê°€ í¬í•¨ë˜ì–´ 있지 않습니다" #: authentication.py:132 msgid "User not found" msgstr "ì°¾ì„ ìˆ˜ 없는 사용ìžìž…니다" #: authentication.py:135 msgid "User is inactive" msgstr "ë¹„í™œì„±í™”ëœ ì‚¬ìš©ìžìž…니다" #: authentication.py:142 msgid "The user's password has been changed." msgstr "사용ìžì˜ 비밀번호가 바뀌었습니다." #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "'{}' 는 알 수 없는 알고리즘 유형입니다" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "{}를 사용하려면 암호화가 설치ë˜ì–´ 있어야 합니다." #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" "알 수 없는 타입 '{}', 'leeway' ê°’ì€ ë°˜ë“œì‹œ int, float ë˜ëŠ” timedelta 타입ì´ì–´" "야 합니다." #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "유효하지 않거나 ë§Œë£Œëœ í† í°ìž…니다" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "ìž˜ëª»ëœ ì•Œê³ ë¦¬ì¦˜ì´ ì§€ì •ë˜ì—ˆìŠµë‹ˆë‹¤" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "유효하지 않거나 ë§Œë£Œëœ í† í°ìž…니다" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "유효하지 않거나 ë§Œë£Œëœ í† í°ìž…니다" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "ì§€ì •ëœ ìžê²© ì¦ëª…ì— í•´ë‹¹í•˜ëŠ” í™œì„±í™”ëœ ì‚¬ìš©ìžë¥¼ ì°¾ì„ ìˆ˜ 없습니다" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "ì§€ì •ëœ ìžê²© ì¦ëª…ì— í•´ë‹¹í•˜ëŠ” í™œì„±í™”ëœ ì‚¬ìš©ìžë¥¼ ì°¾ì„ ìˆ˜ 없습니다" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "'{}' ì„¤ì •ì´ ì œê±°ë˜ì—ˆìŠµë‹ˆë‹¤. 사용 가능한 ì„¤ì •ì€ '{}'ì„ ì°¸ì¡°í•˜ì‹­ì‹œì˜¤." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "사용ìž" #: token_blacklist/admin.py:91 msgid "created at" msgstr "ìƒì„± 시간" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "만료 시간" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "í† í° ë¸”ëž™ë¦¬ìŠ¤íŠ¸" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "타입 ë˜ëŠ” ìˆ˜ëª…ì´ ì—†ëŠ” 토í°ì„ ìƒì„±í•  수 없습니다" #: tokens.py:126 msgid "Token has no id" msgstr "토í°ì— ì‹ë³„ìžê°€ 주어지지 않았습니다" #: tokens.py:138 msgid "Token has no type" msgstr "í† í° íƒ€ìž…ì´ ì£¼ì–´ì§€ì§€ 않았습니다" #: tokens.py:141 msgid "Token has wrong type" msgstr "ìž˜ëª»ëœ í† í° íƒ€ìž…ìž…ë‹ˆë‹¤" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "토í°ì— '{}' í´ë ˆìž„ì´ ì—†ìŠµë‹ˆë‹¤" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "í† í° '{}' í´ë ˆìž„ì´ ë§Œë£Œë˜ì—ˆìŠµë‹ˆë‹¤" #: tokens.py:292 msgid "Token is blacklisted" msgstr "ë¸”ëž™ë¦¬ìŠ¤íŠ¸ì— ì¶”ê°€ëœ í† í°ìž…니다" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/nl_NL/000077500000000000000000000000001475766445300272315ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/nl_NL/LC_MESSAGES/000077500000000000000000000000001475766445300310165ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/nl_NL/LC_MESSAGES/django.mo000066400000000000000000000037051475766445300326220ustar00rootroot00000000000000Þ•Ì|ð<ñ,.([2„O·$34h€¢·Ì è  ) 4?CäHJ-.x.§/ÖKRo3³Ïãù .Oo…  «· »    Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'User is inactiveUser not foundcreated atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: Last-Translator: rene Language: nl_NL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Authorisatie header moet twee waarden bevatten, gescheiden door een spatieKan geen token maken zonder type of levensduurHet token is voor geen enkel token-type geldigGeen actief account gevonden voor deze gegevensDe '{}' instelling bestaat niet meer. Zie '{}' for beschikbareinstellingen.Token '{}' recht is verlopenToken BlacklistToken bevat geen herkenbare gebruikersidentificatieToken heeft geen '{}' rechtToken heeft geen idToken heeft geen typeToken heeft het verkeerde typeToken is ge-blacklistToken is niet geldig of verlopenNiet herkend algoritme type '{}Gebruiker is inactiefGebruiker niet gevondenaangemaakt opverloopt opjtigebruikerdjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/nl_NL/LC_MESSAGES/django.po000066400000000000000000000065761475766445300326360ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 2020. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-06-17 11:06+0200\n" "Last-Translator: rene \n" "Language: nl_NL\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "" "Authorisatie header moet twee waarden bevatten, gescheiden door een spatie" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "Het token is voor geen enkel token-type geldig" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "Token bevat geen herkenbare gebruikersidentificatie" #: authentication.py:132 msgid "User not found" msgstr "Gebruiker niet gevonden" #: authentication.py:135 msgid "User is inactive" msgstr "Gebruiker is inactief" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Niet herkend algoritme type '{}" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "" #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "Token is niet geldig of verlopen" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "Token is niet geldig of verlopen" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "Token is niet geldig of verlopen" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "Geen actief account gevonden voor deze gegevens" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "Geen actief account gevonden voor deze gegevens" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "" "De '{}' instelling bestaat niet meer. Zie '{}' for beschikbareinstellingen." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "gebruiker" #: token_blacklist/admin.py:91 msgid "created at" msgstr "aangemaakt op" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "verloopt op" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Token Blacklist" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "Kan geen token maken zonder type of levensduur" #: tokens.py:126 msgid "Token has no id" msgstr "Token heeft geen id" #: tokens.py:138 msgid "Token has no type" msgstr "Token heeft geen type" #: tokens.py:141 msgid "Token has wrong type" msgstr "Token heeft het verkeerde type" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "Token heeft geen '{}' recht" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "Token '{}' recht is verlopen" #: tokens.py:292 msgid "Token is blacklisted" msgstr "Token is ge-blacklist" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/pl_PL/000077500000000000000000000000001475766445300272355ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/pl_PL/LC_MESSAGES/000077500000000000000000000000001475766445300310225ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/pl_PL/LC_MESSAGES/django.mo000066400000000000000000000040721475766445300326240ustar00rootroot00000000000000Þ•Ì|ð<ñ,.([2„O·$34h€¢·Ì è  ) 4?CèHH1>z3¹GíM5"ƒ¦=¶$ô*D['r"š ½Þú !* .    Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'User is inactiveUser not foundcreated atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: Last-Translator: Mateusz Slisz Language: pl_PL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nagłówek autoryzacji musi zawierać dwie wartoÅ›ci rodzielone spacjamiNie można utworzyć tokena bez podanego typu lub żywotnoÅ›ciPodany token jest błędny dla każdego typu tokenaNie znaleziono aktywnego konta dla podanych danych uwierzytelniajÄ…cychUstawienie '{}' zostaÅ‚o usuniÄ™te. DostÄ™pne ustawienia znajdujÄ… sie w '{}'Upoważnienie tokena '{}' wygasÅ‚oToken BlacklistToken nie zawieraÅ‚ rozpoznawalnej identyfikacji użytkownikaToken nie posiada upoważnienia '{}'Token nie posiada numeru identyfikacyjnegoToken nie posiada typuToken posiada zÅ‚y typToken znajdujÄ™ siÄ™ na czarnej liÅ›cieToken jest niepoprawny lub wygasÅ‚Nierozpoznany typ algorytmu '{}'Użytkownik jest nieaktywnyUżytkownik nie znalezionystworzony wwygasa ojtiużytkownikdjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/pl_PL/LC_MESSAGES/django.po000066400000000000000000000070071475766445300326300ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 2019. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-02-22 17:30+0100\n" "Last-Translator: Mateusz Slisz \n" "Language: pl_PL\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "Nagłówek autoryzacji musi zawierać dwie wartoÅ›ci rodzielone spacjami" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "Podany token jest błędny dla każdego typu tokena" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "Token nie zawieraÅ‚ rozpoznawalnej identyfikacji użytkownika" #: authentication.py:132 msgid "User not found" msgstr "Użytkownik nie znaleziony" #: authentication.py:135 msgid "User is inactive" msgstr "Użytkownik jest nieaktywny" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Nierozpoznany typ algorytmu '{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "" #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "Token jest niepoprawny lub wygasÅ‚" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "Token jest niepoprawny lub wygasÅ‚" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "Token jest niepoprawny lub wygasÅ‚" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "Nie znaleziono aktywnego konta dla podanych danych uwierzytelniajÄ…cych" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "Nie znaleziono aktywnego konta dla podanych danych uwierzytelniajÄ…cych" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "" "Ustawienie '{}' zostaÅ‚o usuniÄ™te. DostÄ™pne ustawienia znajdujÄ… sie w '{}'" #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "użytkownik" #: token_blacklist/admin.py:91 msgid "created at" msgstr "stworzony w" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "wygasa o" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Token Blacklist" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "Nie można utworzyć tokena bez podanego typu lub żywotnoÅ›ci" #: tokens.py:126 msgid "Token has no id" msgstr "Token nie posiada numeru identyfikacyjnego" #: tokens.py:138 msgid "Token has no type" msgstr "Token nie posiada typu" #: tokens.py:141 msgid "Token has wrong type" msgstr "Token posiada zÅ‚y typ" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "Token nie posiada upoważnienia '{}'" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "Upoważnienie tokena '{}' wygasÅ‚o" #: tokens.py:292 msgid "Token is blacklisted" msgstr "Token znajdujÄ™ siÄ™ na czarnej liÅ›cie" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/pt_BR/000077500000000000000000000000001475766445300272355ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/pt_BR/LC_MESSAGES/000077500000000000000000000000001475766445300310225ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/pt_BR/LC_MESSAGES/django.mo000066400000000000000000000044241475766445300326250ustar00rootroot00000000000000Þ•Ü%œ0<1,n(›Ä2àOc€3ÄÜìþ( Dev/… µ ÀËÏÔLç74=l ª Ë[ì#HlG‚Êêü- F'g¦3¿ ó ý       Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: Last-Translator: Bruno Ducraux Language: pt_BR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n > 1); Cabeçalho de autorização deve conter dois valores delimitados por espaçoNão é possível criar token sem tipo ou tempo de vidaO token informado não é válido para qualquer tipo de tokenAlgoritmo inválido especificadoUsuário e/ou senha incorreto(s)A configuração '{}' foi removida. Por favor, consulte '{}' para disponível definições.O privilégio '{}' do token expirouLista negra de TokensO token não continha nenhuma identificação reconhecível do usuárioToken não tem '{}' privilégioToken não tem idToken não tem nenhum tipoToken tem tipo erradoToken está na blacklistO token é inválido ou expiradoTipo de algoritmo '{}' não reconhecidoUsuário está inativoUsuário não encontradoVocê deve ter criptografia instalada para usar {}.criado emexpira emjtiusuáriodjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/pt_BR/LC_MESSAGES/django.po000066400000000000000000000070611475766445300326300ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 2019. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-02-22 17:30+0100\n" "Last-Translator: Bruno Ducraux \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "" "Cabeçalho de autorização deve conter dois valores delimitados por espaço" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "O token informado não é válido para qualquer tipo de token" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "O token não continha nenhuma identificação reconhecível do usuário" #: authentication.py:132 msgid "User not found" msgstr "Usuário não encontrado" #: authentication.py:135 msgid "User is inactive" msgstr "Usuário está inativo" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Tipo de algoritmo '{}' não reconhecido" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "Você deve ter criptografia instalada para usar {}." #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "O token é inválido ou expirado" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "Algoritmo inválido especificado" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "O token é inválido ou expirado" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "O token é inválido ou expirado" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "Usuário e/ou senha incorreto(s)" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "Usuário e/ou senha incorreto(s)" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "" "A configuração '{}' foi removida. Por favor, consulte '{}' para disponível " "definições." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "usuário" #: token_blacklist/admin.py:91 msgid "created at" msgstr "criado em" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "expira em" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Lista negra de Tokens" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "Não é possível criar token sem tipo ou tempo de vida" #: tokens.py:126 msgid "Token has no id" msgstr "Token não tem id" #: tokens.py:138 msgid "Token has no type" msgstr "Token não tem nenhum tipo" #: tokens.py:141 msgid "Token has wrong type" msgstr "Token tem tipo errado" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "Token não tem '{}' privilégio" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "O privilégio '{}' do token expirou" #: tokens.py:292 msgid "Token is blacklisted" msgstr "Token está na blacklist" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ro/000077500000000000000000000000001475766445300266475ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ro/LC_MESSAGES/000077500000000000000000000000001475766445300304345ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ro/LC_MESSAGES/django.mo000066400000000000000000000047641475766445300322460ustar00rootroot00000000000000Þ•ä%¬@<A,~(«Ô2ðO#s3 Ôìü#8 TIu¿Ð/ß  %).YA8›4Ô ;%La$®Ó9ï)I[n+ˆ!´)ÖX Y s ?‘ Ñ Ú å é      Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'Unrecognized type '{}', 'leeway' must be of type int, float or timedelta.User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: Last-Translator: Daniel Cuznetov Language: ro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=1; plural=0; Header-ul(antetul) de autorizare trebuie să conÈ›ină două valori separate prin spaÈ›iuNu se poate crea token fără tip sau durată de viațăTokenul dat nu este valid pentru niciun tip de tokenAlgoritm nevalid specificatNu a fost găsit cont activ cu aceste date de autentificareSetarea '{}' a fost È™tearsă. ReferaÈ›i la '{}' pentru setări disponibile.ReclamaÈ›ia tokenului '{}' a expiratListă de token-uri blocateTokenul nu conÈ›ine date de identificare a utilizatoruluiTokenul nu are reclamaÈ›ia '{}'Tokenul nu are idTokenul nu are tipTokenul are tipul greÈ™itTokenul este în listă de tokenuri blocateToken nu este valid sau a expiratTipul de algoritm '{}' nu este recunoscutTipul '{}' nu este recunoscut, 'leeway' trebuie să fie de tip int, float sau timedelta.Utilizatorul este inactivUtilizatorul nu a fost găsitTrebuie să aveÈ›i instalată criptografia pentru a utiliza {}.creat laexpiră lajtiutilizatordjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ro/LC_MESSAGES/django.po000066400000000000000000000073611475766445300322450ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR Daniel Cuznetov , 2022. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-07-13 10:45+0100\n" "Last-Translator: Daniel Cuznetov \n" "Language: ro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "" "Header-ul(antetul) de autorizare trebuie să conÈ›ină două valori separate " "prin spaÈ›iu" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "Tokenul dat nu este valid pentru niciun tip de token" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "Tokenul nu conÈ›ine date de identificare a utilizatorului" #: authentication.py:132 msgid "User not found" msgstr "Utilizatorul nu a fost găsit" #: authentication.py:135 msgid "User is inactive" msgstr "Utilizatorul este inactiv" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Tipul de algoritm '{}' nu este recunoscut" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "Trebuie să aveÈ›i instalată criptografia pentru a utiliza {}." #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" "Tipul '{}' nu este recunoscut, 'leeway' trebuie să fie de tip int, float sau " "timedelta." #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "Token nu este valid sau a expirat" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "Algoritm nevalid specificat" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "Token nu este valid sau a expirat" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "Token nu este valid sau a expirat" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "Nu a fost găsit cont activ cu aceste date de autentificare" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "Nu a fost găsit cont activ cu aceste date de autentificare" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "" "Setarea '{}' a fost È™tearsă. ReferaÈ›i la '{}' pentru setări disponibile." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "utilizator" #: token_blacklist/admin.py:91 msgid "created at" msgstr "creat la" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "expiră la" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Listă de token-uri blocate" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "Nu se poate crea token fără tip sau durată de viață" #: tokens.py:126 msgid "Token has no id" msgstr "Tokenul nu are id" #: tokens.py:138 msgid "Token has no type" msgstr "Tokenul nu are tip" #: tokens.py:141 msgid "Token has wrong type" msgstr "Tokenul are tipul greÈ™it" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "Tokenul nu are reclamaÈ›ia '{}'" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "ReclamaÈ›ia tokenului '{}' a expirat" #: tokens.py:292 msgid "Token is blacklisted" msgstr "Tokenul este în listă de tokenuri blocate" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ru_RU/000077500000000000000000000000001475766445300272635ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ru_RU/LC_MESSAGES/000077500000000000000000000000001475766445300310505ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ru_RU/LC_MESSAGES/django.mo000066400000000000000000000053401475766445300326510ustar00rootroot00000000000000Þ•Ì|ð<ñ,.([2„O·$34h€¢·Ì è  ) 4?C£HŠì_w^×g6œžD;€T%å3 #? 5c 6™ AÐ ; +N *z ¥ ² à Ç     Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'User is inactiveUser not foundcreated atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: PO-Revision-Date: Last-Translator: Sergey Ozeranskiy Language-Team: Language: ru_RU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2); X-Generator: Poedit 2.2.1 Заголовок авторизации должен Ñодержать два значениÑ, разделенных пробеломÐевозможно Ñоздать токен без типа или времени жизниДанный токен недейÑтвителен Ð´Ð»Ñ Ð»ÑŽÐ±Ð¾Ð³Ð¾ типа токенаÐе найдено активной учетной запиÑи Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼Ð¸ даннымиПараметр '{}' был удален. ПожалуйÑта, обратитеÑÑŒ к '{}' Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра доÑтупных наÑтроек.Токен имеет проÑроченное значение '{}'Token BlacklistТокен не Ñодержит идентификатор пользователÑТокен не Ñодержит '{}'У токена нет идентификатораТокен не имеет типаТокен имеет неправильный типТокен занеÑен в черный ÑпиÑокТокен недейÑтвителен или проÑроченÐераÑпознанный тип алгоритма '{}'Пользователь неактивенПользователь не найденÑозданиÑтекаетjtiпользовательdjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/ru_RU/LC_MESSAGES/django.po000066400000000000000000000104431475766445300326540ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 2019. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-02-22 17:30+0100\n" "PO-Revision-Date: \n" "Last-Translator: Sergey Ozeranskiy \n" "Language-Team: \n" "Language: ru_RU\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" "X-Generator: Poedit 2.2.1\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "" "Заголовок авторизации должен Ñодержать два значениÑ, разделенных пробелом" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "Данный токен недейÑтвителен Ð´Ð»Ñ Ð»ÑŽÐ±Ð¾Ð³Ð¾ типа токена" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "Токен не Ñодержит идентификатор пользователÑ" #: authentication.py:132 msgid "User not found" msgstr "Пользователь не найден" #: authentication.py:135 msgid "User is inactive" msgstr "Пользователь неактивен" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "ÐераÑпознанный тип алгоритма '{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "" #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "Токен недейÑтвителен или проÑрочен" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "Токен недейÑтвителен или проÑрочен" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "Токен недейÑтвителен или проÑрочен" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "Ðе найдено активной учетной запиÑи Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼Ð¸ данными" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "Ðе найдено активной учетной запиÑи Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼Ð¸ данными" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "" "Параметр '{}' был удален. ПожалуйÑта, обратитеÑÑŒ к '{}' Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра " "доÑтупных наÑтроек." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "пользователь" #: token_blacklist/admin.py:91 msgid "created at" msgstr "Ñоздан" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "иÑтекает" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Token Blacklist" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "Ðевозможно Ñоздать токен без типа или времени жизни" #: tokens.py:126 msgid "Token has no id" msgstr "У токена нет идентификатора" #: tokens.py:138 msgid "Token has no type" msgstr "Токен не имеет типа" #: tokens.py:141 msgid "Token has wrong type" msgstr "Токен имеет неправильный тип" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "Токен не Ñодержит '{}'" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "Токен имеет проÑроченное значение '{}'" #: tokens.py:292 msgid "Token is blacklisted" msgstr "Токен занеÑен в черный ÑпиÑок" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/sl/000077500000000000000000000000001475766445300266455ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/sl/LC_MESSAGES/000077500000000000000000000000001475766445300304325ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/sl/LC_MESSAGES/django.mo000066400000000000000000000047351475766445300322420ustar00rootroot00000000000000Þ•ä%¬@<A,~(«Ô2ðO#s3 Ôìü#8 TIu¿Ð/ß  %)L.H{=Ä031S[… á8Qk}’« Ç èK U l 6€ · Ä Ï Ó      Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'Unrecognized type '{}', 'leeway' must be of type int, float or timedelta.User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: PO-Revision-Date: Last-Translator: Urban Prevc Language-Team: Language: sl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Generator: Poedit 2.0.6 Plural-Forms: nplurals=2; plural=(n != 1); Glava 'Authorization' mora vsebovati dve vrednosti, loÄeni s presledkomNi mogoÄe ustvariti žetona brez vrste ali življenjske dobePodan žeton ni veljaven za nobeno vrsto žetonaNaveden algoritem je neveljavenAktiven raÄun s podanimi poverilnicami ni najdenNastavitev '{}' je bila odstranjena. Prosimo, oglejte si '{}' za razpoložljive nastavitve.'{}' zahtevek žetona je potekelÄŒrni seznam žetonovŽeton ni vseboval prepoznavne identifikacije uporabnikaŽeton nima '{}' zahtevkaŽetonu manjka idŽetonu manjka vrstaŽeton je napaÄne vrsteŽeton je na Ärnem seznamuŽeton je neveljaven ali potekelNeprepoznana vrsta algoritma'{}'Neprepoznana vrsta '{}', 'leeway' mora biti vrste int, float ali timedelta.Uporabnik je neaktivenUporabnik ni najdenZa uporabo '{}' je potrebna namestitev 'cryptography'.ustvarjen obpoteÄe objtiuporabnikdjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/sl/LC_MESSAGES/django.po000066400000000000000000000073011475766445300322350ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 2022. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-11-19 20:46+0100\n" "PO-Revision-Date: \n" "Last-Translator: Urban Prevc \n" "Language-Team: \n" "Language: sl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.0.6\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "" "Glava 'Authorization' mora vsebovati dve vrednosti, loÄeni s presledkom" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "Podan žeton ni veljaven za nobeno vrsto žetona" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "Žeton ni vseboval prepoznavne identifikacije uporabnika" #: authentication.py:132 msgid "User not found" msgstr "Uporabnik ni najden" #: authentication.py:135 msgid "User is inactive" msgstr "Uporabnik je neaktiven" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Neprepoznana vrsta algoritma'{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "Za uporabo '{}' je potrebna namestitev 'cryptography'." #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" "Neprepoznana vrsta '{}', 'leeway' mora biti vrste int, float ali timedelta." #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "Žeton je neveljaven ali potekel" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "Naveden algoritem je neveljaven" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "Žeton je neveljaven ali potekel" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "Žeton je neveljaven ali potekel" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "Aktiven raÄun s podanimi poverilnicami ni najden" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "Aktiven raÄun s podanimi poverilnicami ni najden" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "" "Nastavitev '{}' je bila odstranjena. Prosimo, oglejte si '{}' za " "razpoložljive nastavitve." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "uporabnik" #: token_blacklist/admin.py:91 msgid "created at" msgstr "ustvarjen ob" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "poteÄe ob" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "ÄŒrni seznam žetonov" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "Ni mogoÄe ustvariti žetona brez vrste ali življenjske dobe" #: tokens.py:126 msgid "Token has no id" msgstr "Žetonu manjka id" #: tokens.py:138 msgid "Token has no type" msgstr "Žetonu manjka vrsta" #: tokens.py:141 msgid "Token has wrong type" msgstr "Žeton je napaÄne vrste" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "Žeton nima '{}' zahtevka" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "'{}' zahtevek žetona je potekel" #: tokens.py:292 msgid "Token is blacklisted" msgstr "Žeton je na Ärnem seznamu" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/sv/000077500000000000000000000000001475766445300266575ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/sv/LC_MESSAGES/000077500000000000000000000000001475766445300304445ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/sv/LC_MESSAGES/django.mo000066400000000000000000000043511475766445300322460ustar00rootroot00000000000000Þ•Ü%œ0<1,n(›Ä2àOc€3ÄÜìþ( Dev/… µ ÀËÏÔKè.41c•?²Nò"Ad2t§ÅØìþ$9Qi@ƒ Ä ÏÚ Þ     Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: Last-Translator: Pasindu Language: sv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n != 1); Auktoriseringshuvudet mÃ¥ste innehÃ¥lla tvÃ¥ mellanslagsavgränsade värdenKan inte skapa token utan typ eller livslängdGivet token är inte giltigt för nÃ¥gon tokentypOgiltig algoritm har angettsInget aktivt konto hittades med de angivna användaruppgifternaInställningen '{}' har tagits bort. Se '{}' för tillgängliga inställningarToken '{}'-ansprÃ¥ket har löpt utToken svartlistToken innehöll ingen identifiering av användarenToken har inget '{}'-ansprÃ¥kToken har inget idToken har ingen typToken har fel typToken är svartlistadToken är ogiltig eller har löpt utOkänd algoritmtyp '{}'Användaren är inaktivAnvändaren hittades inteDu mÃ¥ste ha kryptografi installerad för att kunna använda {}.skapad vidgÃ¥r ut kljtianvändaredjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/sv/LC_MESSAGES/django.po000066400000000000000000000070711475766445300322530ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR Pasindu , 2022. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-05-29 17:30+0100\n" "Last-Translator: Pasindu \n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "Auktoriseringshuvudet mÃ¥ste innehÃ¥lla tvÃ¥ mellanslagsavgränsade värden" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "Givet token är inte giltigt för nÃ¥gon tokentyp" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "Token innehöll ingen identifiering av användaren" #: authentication.py:132 msgid "User not found" msgstr "Användaren hittades inte" #: authentication.py:135 msgid "User is inactive" msgstr "Användaren är inaktiv" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Okänd algoritmtyp '{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "Du mÃ¥ste ha kryptografi installerad för att kunna använda {}." #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "Token är ogiltig eller har löpt ut" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "Ogiltig algoritm har angetts" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "Token är ogiltig eller har löpt ut" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "Token är ogiltig eller har löpt ut" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "Inget aktivt konto hittades med de angivna användaruppgifterna" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "Inget aktivt konto hittades med de angivna användaruppgifterna" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "" "Inställningen '{}' har tagits bort. Se '{}' för tillgängliga inställningar" #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "användare" #: token_blacklist/admin.py:91 msgid "created at" msgstr "skapad vid" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "gÃ¥r ut kl" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Token svartlist" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "Kan inte skapa token utan typ eller livslängd" #: tokens.py:126 msgid "Token has no id" msgstr "Token har inget id" #: tokens.py:138 msgid "Token has no type" msgstr "Token har ingen typ" #: tokens.py:141 msgid "Token has wrong type" msgstr "Token har fel typ" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "Token har inget '{}'-ansprÃ¥k" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "Token '{}'-ansprÃ¥ket har löpt ut" #: tokens.py:292 msgid "Token is blacklisted" msgstr "Token är svartlistad" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/tr/000077500000000000000000000000001475766445300266545ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/tr/LC_MESSAGES/000077500000000000000000000000001475766445300304415ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/tr/LC_MESSAGES/django.mo000066400000000000000000000044261475766445300322460ustar00rootroot00000000000000Þ•Ü%œ0<1,n(›Ä2àOc€3ÄÜìþ( Dev/… µ ÀËÏÔVé:@6{²7ÑK Uu6ˆ¿Ùìþ%3Yy’6ªáõ      Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: Last-Translator: Åžuayip Üzülmez Language: tr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n > 1); Yetkilendirme header'i boÅŸlukla sınırlandırılmış iki deÄŸer bulundurmak zorundaTipi veya geçerlilik süresi olmayan token oluÅŸturulamazVerilen token hiçbir token tipi için geçerli deÄŸilGeçersiz algoritma belirtildiVerilen kimlik bilgileriyle aktif bir hesap bulunamadı'{}' ayarı kaldırıldı. Mevcut ayarlar için '{}' adresini ziyaret edin.Token'in '{}' claim'i sona erdiToken Kara ListesiToken tanınabilir bir kullanıcı kimliÄŸi içermiyorToken'in '{}' claim'i yokToken'in id'si yokToken'in tipi yokToken'in tipi yanlışToken kara listeye alınmışToken geçersiz veya süresi geçmiÅŸTanınmayan algortima tipi '{}'Kullanıcı etkin deÄŸilKullanıcı bulunamadı{} kullanmak için cryptography yüklemeniz gerekiyor.oluÅŸturulma tarihisona erme tarihijtikullanıcıdjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/tr/LC_MESSAGES/django.po000066400000000000000000000071231475766445300322460ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , 2022. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-01-13 23:05+0300\n" "Last-Translator: Åžuayip Üzülmez \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "" "Yetkilendirme header'i boÅŸlukla sınırlandırılmış iki deÄŸer bulundurmak " "zorunda" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "Verilen token hiçbir token tipi için geçerli deÄŸil" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "Token tanınabilir bir kullanıcı kimliÄŸi içermiyor" #: authentication.py:132 msgid "User not found" msgstr "Kullanıcı bulunamadı" #: authentication.py:135 msgid "User is inactive" msgstr "Kullanıcı etkin deÄŸil" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Tanınmayan algortima tipi '{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "{} kullanmak için cryptography yüklemeniz gerekiyor." #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "Token geçersiz veya süresi geçmiÅŸ" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "Geçersiz algoritma belirtildi" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "Token geçersiz veya süresi geçmiÅŸ" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "Token geçersiz veya süresi geçmiÅŸ" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "Verilen kimlik bilgileriyle aktif bir hesap bulunamadı" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "Verilen kimlik bilgileriyle aktif bir hesap bulunamadı" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "'{}' ayarı kaldırıldı. Mevcut ayarlar için '{}' adresini ziyaret edin." #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "kullanıcı" #: token_blacklist/admin.py:91 msgid "created at" msgstr "oluÅŸturulma tarihi" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "sona erme tarihi" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Token Kara Listesi" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "Tipi veya geçerlilik süresi olmayan token oluÅŸturulamaz" #: tokens.py:126 msgid "Token has no id" msgstr "Token'in id'si yok" #: tokens.py:138 msgid "Token has no type" msgstr "Token'in tipi yok" #: tokens.py:141 msgid "Token has wrong type" msgstr "Token'in tipi yanlış" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "Token'in '{}' claim'i yok" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "Token'in '{}' claim'i sona erdi" #: tokens.py:292 msgid "Token is blacklisted" msgstr "Token kara listeye alınmış" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/uk_UA/000077500000000000000000000000001475766445300272335ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/uk_UA/LC_MESSAGES/000077500000000000000000000000001475766445300310205ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/uk_UA/LC_MESSAGES/django.mo000066400000000000000000000057371475766445300326330ustar00rootroot00000000000000Þ•Ü%œ0<1,n(›Ä2àOc€3ÄÜìþ( Dev/… µ ÀËÏ3ÔYŠVä2;xnqç8Y(’n»?* 7j ;¢ ;Þ : ZU :° )ë , WB š ° Æ Ê      Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: Artiukhov Artem Language-Team: LANGUAGE Language: uk_UA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ðвторизаційний заголовок має міÑтити два Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ€Ð¾Ð·Ð´Ñ–Ð»ÐµÐ½Ñ– пробіломÐеможливо Ñтворити токен без типу або Ñтроку діїÐаданий токен не відповідає жодному типу ключаВказаний невірний алгоритмÐе знайдено жодного облікового запиÑу по наданих облікових данихÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ '{}' видалене. ПодивітьÑÑ Ñƒ '{}' Ð´Ð»Ñ Ñ–Ð½ÑˆÐ¸Ñ… доÑтупнихЗаголовок '{}' токена не дійÑнийЧорний ÑпиÑок токенівÐаданий токен не мітить жодної ідентифікаційної інформаціїУ токені не міÑтитьÑÑ '{}' заголовкуУ ключі доÑтупу не міÑтитьÑÑ idУ ключі доÑтупу не міÑтитьÑÑ Ñ‚Ð¸Ð¿Ñ‚Ð¾ÐºÐµÐ½ позначений невірним типомТокен занеÑений у чорний ÑпиÑокТокен некоректний або термін його дії вичерпанийТип алгоритму '{}' не розпізнанийКориÑтувач неактивнийКориÑтувач не знайденийВÑтановіть модуль cryptography щоб викориÑтовувати {}Ñтворений одійÑтний поjtiкориÑтувачdjangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/uk_UA/LC_MESSAGES/django.po000066400000000000000000000107171475766445300326300ustar00rootroot00000000000000# This file is distributed under the same license as the PACKAGE package. # Artiukhov Artem , 2021. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-06-17 12:32+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Artiukhov Artem \n" "Language-Team: LANGUAGE \n" "Language: uk_UA\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "Ðвторизаційний заголовок має міÑтити два Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ€Ð¾Ð·Ð´Ñ–Ð»ÐµÐ½Ñ– пробілом" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "Ðаданий токен не відповідає жодному типу ключа" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "Ðаданий токен не мітить жодної ідентифікаційної інформації" #: authentication.py:132 msgid "User not found" msgstr "КориÑтувач не знайдений" #: authentication.py:135 msgid "User is inactive" msgstr "КориÑтувач неактивний" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "Тип алгоритму '{}' не розпізнаний" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "Ð’Ñтановіть модуль cryptography щоб викориÑтовувати {}" #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "Токен некоректний або термін його дії вичерпаний" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "Вказаний невірний алгоритм" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "Токен некоректний або термін його дії вичерпаний" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "Токен некоректний або термін його дії вичерпаний" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "Ðе знайдено жодного облікового запиÑу по наданих облікових даних" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "Ðе знайдено жодного облікового запиÑу по наданих облікових даних" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ '{}' видалене. ПодивітьÑÑ Ñƒ '{}' Ð´Ð»Ñ Ñ–Ð½ÑˆÐ¸Ñ… доÑтупних" #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "кориÑтувач" #: token_blacklist/admin.py:91 msgid "created at" msgstr "Ñтворений о" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "дійÑтний по" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "Чорний ÑпиÑок токенів" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "Ðеможливо Ñтворити токен без типу або Ñтроку дії" #: tokens.py:126 msgid "Token has no id" msgstr "У ключі доÑтупу не міÑтитьÑÑ id" #: tokens.py:138 msgid "Token has no type" msgstr "У ключі доÑтупу не міÑтитьÑÑ Ñ‚Ð¸Ð¿" #: tokens.py:141 msgid "Token has wrong type" msgstr "токен позначений невірним типом" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "У токені не міÑтитьÑÑ '{}' заголовку" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "Заголовок '{}' токена не дійÑний" #: tokens.py:292 msgid "Token is blacklisted" msgstr "Токен занеÑений у чорний ÑпиÑок" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/zh_Hans/000077500000000000000000000000001475766445300276215ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/zh_Hans/LC_MESSAGES/000077500000000000000000000000001475766445300314065ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/zh_Hans/LC_MESSAGES/django.mo000066400000000000000000000041621475766445300332100ustar00rootroot00000000000000Þ•Ü%œ0<1,n(›Ä2àOc€3ÄÜìþ( Dev/… µ ÀËÏ*Ô0ÿ-0'^†*œBÇ &6Un„—ªÆß÷ / M Zgk     Authorization header must contain two space-delimited valuesCannot create token with no type or lifetimeGiven token not valid for any token typeInvalid algorithm specifiedNo active account found with the given credentialsThe '{}' setting has been removed. Please refer to '{}' for available settings.Token '{}' claim has expiredToken BlacklistToken contained no recognizable user identificationToken has no '{}' claimToken has no idToken has no typeToken has wrong typeToken is blacklistedToken is invalid or expiredUnrecognized algorithm type '{}'User is inactiveUser not foundYou must have cryptography installed to use {}.created atexpires atjtiuserProject-Id-Version: djangorestframework_simplejwt Report-Msgid-Bugs-To: PO-Revision-Date: 2021-06-23 13:29+080 Last-Translator: zengqiu Language: zh_Hans MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=1; plural=0; 授æƒå¤´å¿…须包å«ä¸¤ä¸ªç”¨ç©ºæ ¼åˆ†éš”的值无法创建没有类型或生存期的令牌此令牌对任何类型的令牌无效指定的算法无效找ä¸åˆ°æŒ‡å®šå‡­æ®å¯¹åº”的有效用户'{}' é…置已被移除。 请å‚阅 '{}' 获å–å¯ç”¨çš„é…置。令牌 '{}' 声明已过期令牌黑åå•令牌未包å«ç”¨æˆ·æ ‡è¯†ç¬¦ä»¤ç‰Œæ²¡æœ‰ '{}' 声明令牌没有标识符令牌没有类型令牌类型错误令牌已被加入黑åå•令牌无效或已过期未知算法类型 '{}'该用户已ç¦ç”¨æœªæ‰¾åˆ°è¯¥ç”¨æˆ·ä½ å¿…须安装 cryptography æ‰èƒ½ä½¿ç”¨ {}。创建时间过期时间jti用户djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/locale/zh_Hans/LC_MESSAGES/django.po000066400000000000000000000066551475766445300332240ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) 2021 # This file is distributed under the same license as the Simple JWT package. # zengqiu , 2021. msgid "" msgstr "" "Project-Id-Version: djangorestframework_simplejwt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-06-23 13:29+0800\n" "PO-Revision-Date: 2021-06-23 13:29+080\n" "Last-Translator: zengqiu \n" "Language: zh_Hans\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" #: authentication.py:89 msgid "Authorization header must contain two space-delimited values" msgstr "授æƒå¤´å¿…须包å«ä¸¤ä¸ªç”¨ç©ºæ ¼åˆ†éš”的值" #: authentication.py:115 msgid "Given token not valid for any token type" msgstr "此令牌对任何类型的令牌无效" #: authentication.py:127 authentication.py:162 msgid "Token contained no recognizable user identification" msgstr "令牌未包å«ç”¨æˆ·æ ‡è¯†ç¬¦" #: authentication.py:132 msgid "User not found" msgstr "未找到该用户" #: authentication.py:135 msgid "User is inactive" msgstr "该用户已ç¦ç”¨" #: authentication.py:142 msgid "The user's password has been changed." msgstr "" #: backends.py:90 msgid "Unrecognized algorithm type '{}'" msgstr "未知算法类型 '{}'" #: backends.py:96 msgid "You must have cryptography installed to use {}." msgstr "你必须安装 cryptography æ‰èƒ½ä½¿ç”¨ {}。" #: backends.py:111 msgid "" "Unrecognized type '{}', 'leeway' must be of type int, float or timedelta." msgstr "" #: backends.py:125 backends.py:177 tokens.py:68 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is invalid" msgstr "令牌无效或已过期" #: backends.py:173 msgid "Invalid algorithm specified" msgstr "指定的算法无效" #: backends.py:175 tokens.py:66 #, fuzzy #| msgid "Token is invalid or expired" msgid "Token is expired" msgstr "令牌无效或已过期" #: exceptions.py:55 msgid "Token is invalid or expired" msgstr "令牌无效或已过期" #: serializers.py:35 msgid "No active account found with the given credentials" msgstr "找ä¸åˆ°æŒ‡å®šå‡­æ®å¯¹åº”的有效用户" #: serializers.py:108 #, fuzzy #| msgid "No active account found with the given credentials" msgid "No active account found for the given token." msgstr "找ä¸åˆ°æŒ‡å®šå‡­æ®å¯¹åº”的有效用户" #: settings.py:74 msgid "" "The '{}' setting has been removed. Please refer to '{}' for available " "settings." msgstr "'{}' é…置已被移除。 请å‚阅 '{}' 获å–å¯ç”¨çš„é…置。" #: token_blacklist/admin.py:79 msgid "jti" msgstr "jti" #: token_blacklist/admin.py:85 msgid "user" msgstr "用户" #: token_blacklist/admin.py:91 msgid "created at" msgstr "创建时间" #: token_blacklist/admin.py:97 msgid "expires at" msgstr "过期时间" #: token_blacklist/apps.py:7 msgid "Token Blacklist" msgstr "令牌黑åå•" #: tokens.py:52 msgid "Cannot create token with no type or lifetime" msgstr "无法创建没有类型或生存期的令牌" #: tokens.py:126 msgid "Token has no id" msgstr "令牌没有标识符" #: tokens.py:138 msgid "Token has no type" msgstr "令牌没有类型" #: tokens.py:141 msgid "Token has wrong type" msgstr "令牌类型错误" #: tokens.py:200 msgid "Token has no '{}' claim" msgstr "令牌没有 '{}' 声明" #: tokens.py:205 msgid "Token '{}' claim has expired" msgstr "令牌 '{}' 声明已过期" #: tokens.py:292 msgid "Token is blacklisted" msgstr "令牌已被加入黑åå•" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/models.py000066400000000000000000000067071475766445300266370ustar00rootroot00000000000000from typing import TYPE_CHECKING, Any, Optional, Union from django.contrib.auth import models as auth_models from django.db.models.manager import EmptyManager from django.utils.functional import cached_property from .settings import api_settings if TYPE_CHECKING: from .tokens import Token class TokenUser: """ A dummy user class modeled after django.contrib.auth.models.AnonymousUser. Used in conjunction with the `JWTStatelessUserAuthentication` backend to implement single sign-on functionality across services which share the same secret key. `JWTStatelessUserAuthentication` will return an instance of this class instead of a `User` model instance. Instances of this class act as stateless user objects which are backed by validated tokens. """ # User is always active since Simple JWT will never issue a token for an # inactive user is_active = True _groups = EmptyManager(auth_models.Group) _user_permissions = EmptyManager(auth_models.Permission) def __init__(self, token: "Token") -> None: self.token = token def __str__(self) -> str: return f"TokenUser {self.id}" @cached_property def id(self) -> Union[int, str]: return self.token[api_settings.USER_ID_CLAIM] @cached_property def pk(self) -> Union[int, str]: return self.id @cached_property def username(self) -> str: return self.token.get("username", "") @cached_property def is_staff(self) -> bool: return self.token.get("is_staff", False) @cached_property def is_superuser(self) -> bool: return self.token.get("is_superuser", False) def __eq__(self, other: object) -> bool: if not isinstance(other, TokenUser): return NotImplemented return self.id == other.id def __ne__(self, other: object) -> bool: return not self.__eq__(other) def __hash__(self) -> int: return hash(self.id) def save(self) -> None: raise NotImplementedError("Token users have no DB representation") def delete(self) -> None: raise NotImplementedError("Token users have no DB representation") def set_password(self, raw_password: str) -> None: raise NotImplementedError("Token users have no DB representation") def check_password(self, raw_password: str) -> None: raise NotImplementedError("Token users have no DB representation") @property def groups(self) -> auth_models.Group: return self._groups @property def user_permissions(self) -> auth_models.Permission: return self._user_permissions def get_group_permissions(self, obj: Optional[object] = None) -> set: return set() def get_all_permissions(self, obj: Optional[object] = None) -> set: return set() def has_perm(self, perm: str, obj: Optional[object] = None) -> bool: return False def has_perms(self, perm_list: list[str], obj: Optional[object] = None) -> bool: return False def has_module_perms(self, module: str) -> bool: return False @property def is_anonymous(self) -> bool: return False @property def is_authenticated(self) -> bool: return True def get_username(self) -> str: return self.username def __getattr__(self, attr: str) -> Optional[Any]: """This acts as a backup attribute getter for custom claims defined in Token serializers.""" return self.token.get(attr, None) djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/py.typed000066400000000000000000000000001475766445300264550ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/serializers.py000066400000000000000000000136601475766445300277040ustar00rootroot00000000000000from typing import Any, Optional, TypeVar from django.conf import settings from django.contrib.auth import authenticate, get_user_model from django.contrib.auth.models import AbstractBaseUser, update_last_login from django.utils.translation import gettext_lazy as _ from rest_framework import exceptions, serializers from rest_framework.exceptions import AuthenticationFailed, ValidationError from .models import TokenUser from .settings import api_settings from .tokens import RefreshToken, SlidingToken, Token, UntypedToken AuthUser = TypeVar("AuthUser", AbstractBaseUser, TokenUser) if api_settings.BLACKLIST_AFTER_ROTATION: from .token_blacklist.models import BlacklistedToken class PasswordField(serializers.CharField): def __init__(self, *args, **kwargs) -> None: kwargs.setdefault("style", {}) kwargs["style"]["input_type"] = "password" kwargs["write_only"] = True super().__init__(*args, **kwargs) class TokenObtainSerializer(serializers.Serializer): username_field = get_user_model().USERNAME_FIELD token_class: Optional[type[Token]] = None default_error_messages = { "no_active_account": _("No active account found with the given credentials") } def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.fields[self.username_field] = serializers.CharField(write_only=True) self.fields["password"] = PasswordField() def validate(self, attrs: dict[str, Any]) -> dict[Any, Any]: authenticate_kwargs = { self.username_field: attrs[self.username_field], "password": attrs["password"], } try: authenticate_kwargs["request"] = self.context["request"] except KeyError: pass self.user = authenticate(**authenticate_kwargs) if not api_settings.USER_AUTHENTICATION_RULE(self.user): raise exceptions.AuthenticationFailed( self.error_messages["no_active_account"], "no_active_account", ) return {} @classmethod def get_token(cls, user: AuthUser) -> Token: return cls.token_class.for_user(user) # type: ignore class TokenObtainPairSerializer(TokenObtainSerializer): token_class = RefreshToken def validate(self, attrs: dict[str, Any]) -> dict[str, str]: data = super().validate(attrs) refresh = self.get_token(self.user) data["refresh"] = str(refresh) data["access"] = str(refresh.access_token) if api_settings.UPDATE_LAST_LOGIN: update_last_login(None, self.user) return data class TokenObtainSlidingSerializer(TokenObtainSerializer): token_class = SlidingToken def validate(self, attrs: dict[str, Any]) -> dict[str, str]: data = super().validate(attrs) token = self.get_token(self.user) data["token"] = str(token) if api_settings.UPDATE_LAST_LOGIN: update_last_login(None, self.user) return data class TokenRefreshSerializer(serializers.Serializer): refresh = serializers.CharField() access = serializers.CharField(read_only=True) token_class = RefreshToken default_error_messages = { "no_active_account": _("No active account found for the given token.") } def validate(self, attrs: dict[str, Any]) -> dict[str, str]: refresh = self.token_class(attrs["refresh"]) user_id = refresh.payload.get(api_settings.USER_ID_CLAIM, None) if user_id and ( user := get_user_model().objects.get( **{api_settings.USER_ID_FIELD: user_id} ) ): if not api_settings.USER_AUTHENTICATION_RULE(user): raise AuthenticationFailed( self.error_messages["no_active_account"], "no_active_account", ) data = {"access": str(refresh.access_token)} if api_settings.ROTATE_REFRESH_TOKENS: if api_settings.BLACKLIST_AFTER_ROTATION: try: # Attempt to blacklist the given refresh token refresh.blacklist() except AttributeError: # If blacklist app not installed, `blacklist` method will # not be present pass refresh.set_jti() refresh.set_exp() refresh.set_iat() refresh.outstand() data["refresh"] = str(refresh) return data class TokenRefreshSlidingSerializer(serializers.Serializer): token = serializers.CharField() token_class = SlidingToken def validate(self, attrs: dict[str, Any]) -> dict[str, str]: token = self.token_class(attrs["token"]) # Check that the timestamp in the "refresh_exp" claim has not # passed token.check_exp(api_settings.SLIDING_TOKEN_REFRESH_EXP_CLAIM) # Update the "exp" and "iat" claims token.set_exp() token.set_iat() return {"token": str(token)} class TokenVerifySerializer(serializers.Serializer): token = serializers.CharField(write_only=True) def validate(self, attrs: dict[str, None]) -> dict[Any, Any]: token = UntypedToken(attrs["token"]) if ( api_settings.BLACKLIST_AFTER_ROTATION and "rest_framework_simplejwt.token_blacklist" in settings.INSTALLED_APPS ): jti = token.get(api_settings.JTI_CLAIM) if BlacklistedToken.objects.filter(token__jti=jti).exists(): raise ValidationError("Token is blacklisted") return {} class TokenBlacklistSerializer(serializers.Serializer): refresh = serializers.CharField(write_only=True) token_class = RefreshToken def validate(self, attrs: dict[str, Any]) -> dict[Any, Any]: refresh = self.token_class(attrs["refresh"]) try: refresh.blacklist() except AttributeError: pass return {} djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/settings.py000066400000000000000000000065211475766445300272060ustar00rootroot00000000000000from datetime import timedelta from typing import Any from django.conf import settings from django.test.signals import setting_changed from django.utils.translation import gettext_lazy as _ from rest_framework.settings import APISettings as _APISettings from .utils import format_lazy USER_SETTINGS = getattr(settings, "SIMPLE_JWT", None) DEFAULTS = { "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), "REFRESH_TOKEN_LIFETIME": timedelta(days=1), "ROTATE_REFRESH_TOKENS": False, "BLACKLIST_AFTER_ROTATION": False, "UPDATE_LAST_LOGIN": False, "ALGORITHM": "HS256", "SIGNING_KEY": settings.SECRET_KEY, "VERIFYING_KEY": "", "AUDIENCE": None, "ISSUER": None, "JSON_ENCODER": None, "JWK_URL": None, "LEEWAY": 0, "AUTH_HEADER_TYPES": ("Bearer",), "AUTH_HEADER_NAME": "HTTP_AUTHORIZATION", "USER_ID_FIELD": "id", "USER_ID_CLAIM": "user_id", "USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule", "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",), "TOKEN_TYPE_CLAIM": "token_type", "JTI_CLAIM": "jti", "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser", "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp", "SLIDING_TOKEN_LIFETIME": timedelta(minutes=5), "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1), "TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer", "TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer", "TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer", "TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer", "SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer", "SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer", "CHECK_REVOKE_TOKEN": False, "REVOKE_TOKEN_CLAIM": "hash_password", "CHECK_USER_IS_ACTIVE": True, } IMPORT_STRINGS = ( "AUTH_TOKEN_CLASSES", "JSON_ENCODER", "TOKEN_USER_CLASS", "USER_AUTHENTICATION_RULE", ) REMOVED_SETTINGS = ( "AUTH_HEADER_TYPE", "AUTH_TOKEN_CLASS", "SECRET_KEY", "TOKEN_BACKEND_CLASS", ) class APISettings(_APISettings): # pragma: no cover def __check_user_settings(self, user_settings: dict[str, Any]) -> dict[str, Any]: SETTINGS_DOC = "https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html" for setting in REMOVED_SETTINGS: if setting in user_settings: raise RuntimeError( format_lazy( _( "The '{}' setting has been removed. Please refer to '{}' for available settings." ), setting, SETTINGS_DOC, ) ) return user_settings api_settings = APISettings(USER_SETTINGS, DEFAULTS, IMPORT_STRINGS) def reload_api_settings(*args, **kwargs) -> None: # pragma: no cover global api_settings setting, value = kwargs["setting"], kwargs["value"] if setting == "SIMPLE_JWT": api_settings = APISettings(value, DEFAULTS, IMPORT_STRINGS) setting_changed.connect(reload_api_settings) djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/state.py000066400000000000000000000005071475766445300264640ustar00rootroot00000000000000from .backends import TokenBackend from .settings import api_settings token_backend = TokenBackend( api_settings.ALGORITHM, api_settings.SIGNING_KEY, api_settings.VERIFYING_KEY, api_settings.AUDIENCE, api_settings.ISSUER, api_settings.JWK_URL, api_settings.LEEWAY, api_settings.JSON_ENCODER, ) djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/000077500000000000000000000000001475766445300301405ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/__init__.py000066400000000000000000000002371475766445300322530ustar00rootroot00000000000000from django import VERSION if VERSION < (3, 2): default_app_config = ( "rest_framework_simplejwt.token_blacklist.apps.TokenBlacklistConfig" ) djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/admin.py000066400000000000000000000055751475766445300316160ustar00rootroot00000000000000from datetime import datetime from typing import Any, Optional, TypeVar from django.contrib import admin from django.contrib.auth.models import AbstractBaseUser from django.db.models import QuerySet from django.utils.translation import gettext_lazy as _ from rest_framework.request import Request from ..models import TokenUser from .models import BlacklistedToken, OutstandingToken AuthUser = TypeVar("AuthUser", AbstractBaseUser, TokenUser) class OutstandingTokenAdmin(admin.ModelAdmin): list_display = ( "jti", "user", "created_at", "expires_at", ) search_fields = ( "user__id", "jti", ) ordering = ("user",) def get_queryset(self, *args, **kwargs) -> QuerySet: qs = super().get_queryset(*args, **kwargs) return qs.select_related("user") # Read-only behavior defined below actions = None def get_readonly_fields(self, *args, **kwargs) -> list[Any]: return [f.name for f in self.model._meta.fields] def has_add_permission(self, *args, **kwargs) -> bool: return False def has_delete_permission(self, *args, **kwargs) -> bool: return False def has_change_permission( self, request: Request, obj: Optional[object] = None ) -> bool: return request.method in ["GET", "HEAD"] and super().has_change_permission( request, obj ) admin.site.register(OutstandingToken, OutstandingTokenAdmin) class BlacklistedTokenAdmin(admin.ModelAdmin): list_display = ( "token_jti", "token_user", "token_created_at", "token_expires_at", "blacklisted_at", ) search_fields = ( "token__user__id", "token__jti", ) ordering = ("token__user",) def get_queryset(self, *args, **kwargs) -> QuerySet: qs = super().get_queryset(*args, **kwargs) return qs.select_related("token__user") def token_jti(self, obj: BlacklistedToken) -> str: return obj.token.jti token_jti.short_description = _("jti") # type: ignore token_jti.admin_order_field = "token__jti" # type: ignore def token_user(self, obj: BlacklistedToken) -> AuthUser: return obj.token.user token_user.short_description = _("user") # type: ignore token_user.admin_order_field = "token__user" # type: ignore def token_created_at(self, obj: BlacklistedToken) -> datetime: return obj.token.created_at token_created_at.short_description = _("created at") # type: ignore token_created_at.admin_order_field = "token__created_at" # type: ignore def token_expires_at(self, obj: BlacklistedToken) -> datetime: return obj.token.expires_at token_expires_at.short_description = _("expires at") # type: ignore token_expires_at.admin_order_field = "token__expires_at" # type: ignore admin.site.register(BlacklistedToken, BlacklistedTokenAdmin) djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/apps.py000066400000000000000000000004311475766445300314530ustar00rootroot00000000000000from django.apps import AppConfig from django.utils.translation import gettext_lazy as _ class TokenBlacklistConfig(AppConfig): name = "rest_framework_simplejwt.token_blacklist" verbose_name = _("Token Blacklist") default_auto_field = "django.db.models.BigAutoField" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/management/000077500000000000000000000000001475766445300322545ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/management/__init__.py000066400000000000000000000000001475766445300343530ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/management/commands/000077500000000000000000000000001475766445300340555ustar00rootroot00000000000000__init__.py000066400000000000000000000000001475766445300360750ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/management/commandsflushexpiredtokens.py000066400000000000000000000005721475766445300403020ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/management/commandsfrom django.core.management.base import BaseCommand from rest_framework_simplejwt.utils import aware_utcnow from ...models import OutstandingToken class Command(BaseCommand): help = "Flushes any expired tokens in the outstanding token list" def handle(self, *args, **kwargs) -> None: OutstandingToken.objects.filter(expires_at__lte=aware_utcnow()).delete() djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/migrations/000077500000000000000000000000001475766445300323145ustar00rootroot000000000000000001_initial.py000066400000000000000000000037231475766445300347050ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/migrationsimport django.db.models.deletion from django.conf import settings from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( name="BlacklistedToken", fields=[ ( "id", models.AutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("blacklisted_at", models.DateTimeField(auto_now_add=True)), ], ), migrations.CreateModel( name="OutstandingToken", fields=[ ( "id", models.AutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("jti", models.UUIDField(unique=True)), ("token", models.TextField()), ("created_at", models.DateTimeField()), ("expires_at", models.DateTimeField()), ( "user", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, ), ), ], options={ "ordering": ("user",), }, ), migrations.AddField( model_name="blacklistedtoken", name="token", field=models.OneToOneField( on_delete=django.db.models.deletion.CASCADE, to="token_blacklist.OutstandingToken", ), ), ] 0002_outstandingtoken_jti_hex.py000066400000000000000000000005561475766445300403700ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/migrationsfrom django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ("token_blacklist", "0001_initial"), ] operations = [ migrations.AddField( model_name="outstandingtoken", name="jti_hex", field=models.CharField(blank=True, null=True, max_length=255), ), ] 0003_auto_20171017_2007.py000066400000000000000000000016121475766445300356530ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/migrationsfrom uuid import UUID from django.db import migrations def populate_jti_hex(apps, schema_editor): OutstandingToken = apps.get_model("token_blacklist", "OutstandingToken") db_alias = schema_editor.connection.alias for token in OutstandingToken.objects.using(db_alias).all(): token.jti_hex = token.jti.hex token.save() def reverse_populate_jti_hex(apps, schema_editor): # pragma: no cover OutstandingToken = apps.get_model("token_blacklist", "OutstandingToken") db_alias = schema_editor.connection.alias for token in OutstandingToken.objects.using(db_alias).all(): token.jti = UUID(hex=token.jti_hex) token.save() class Migration(migrations.Migration): dependencies = [ ("token_blacklist", "0002_outstandingtoken_jti_hex"), ] operations = [ migrations.RunPython(populate_jti_hex, reverse_populate_jti_hex), ] 0004_auto_20171017_2013.py000066400000000000000000000005611475766445300356530ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/migrationsfrom django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ("token_blacklist", "0003_auto_20171017_2007"), ] operations = [ migrations.AlterField( model_name="outstandingtoken", name="jti_hex", field=models.CharField(unique=True, max_length=255), ), ] 0005_remove_outstandingtoken_jti.py000066400000000000000000000004451475766445300411010ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/migrationsfrom django.db import migrations class Migration(migrations.Migration): dependencies = [ ("token_blacklist", "0004_auto_20171017_2013"), ] operations = [ migrations.RemoveField( model_name="outstandingtoken", name="jti", ), ] 0006_auto_20171017_2113.py000066400000000000000000000005221475766445300356530ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/migrationsfrom django.db import migrations class Migration(migrations.Migration): dependencies = [ ("token_blacklist", "0005_remove_outstandingtoken_jti"), ] operations = [ migrations.RenameField( model_name="outstandingtoken", old_name="jti_hex", new_name="jti", ), ] 0007_auto_20171017_2214.py000066400000000000000000000013671475766445300356660ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/migrationsimport django.db.models.deletion from django.conf import settings from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ("token_blacklist", "0006_auto_20171017_2113"), ] operations = [ migrations.AlterField( model_name="outstandingtoken", name="created_at", field=models.DateTimeField(blank=True, null=True), ), migrations.AlterField( model_name="outstandingtoken", name="user", field=models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, ), ), ] 0008_migrate_to_bigautofield.py000066400000000000000000000012631475766445300401300ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/migrationsfrom django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ("token_blacklist", "0007_auto_20171017_2214"), ] operations = [ migrations.AlterField( model_name="blacklistedtoken", name="id", field=models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID" ), ), migrations.AlterField( model_name="outstandingtoken", name="id", field=models.BigAutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID" ), ), ] 0010_fix_migrate_to_bigautofield.py000066400000000000000000000012641475766445300407700ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/migrations# Generated by Django 3.2.3 on 2021-05-27 17:46 from pathlib import Path from django.db import migrations, models parent_dir = Path(__file__).resolve(strict=True).parent class Migration(migrations.Migration): dependencies = [ ("token_blacklist", "0008_migrate_to_bigautofield"), ] operations = [ migrations.AlterField( model_name="blacklistedtoken", name="id", field=models.BigAutoField(primary_key=True, serialize=False), ), migrations.AlterField( model_name="outstandingtoken", name="id", field=models.BigAutoField(primary_key=True, serialize=False), ), ] 0011_linearizes_history.py000066400000000000000000000011021475766445300371700ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/migrationsimport fnmatch import os from pathlib import Path from django.db import migrations, models # noqa F401 parent_dir = Path(__file__).resolve(strict=True).parent class Migration(migrations.Migration): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.dependencies = [("token_blacklist", "0010_fix_migrate_to_bigautofield")] _m = sorted(fnmatch.filter(os.listdir(parent_dir), "000*.py")) if len(_m) == 9: self.dependencies.insert(0, ("token_blacklist", os.path.splitext(_m[8])[0])) operations = [] 0012_alter_outstandingtoken_user.py000066400000000000000000000012721475766445300411000ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/migrations# Generated by Django 3.2.10 on 2022-01-24 06:42 import django.db.models.deletion from django.conf import settings from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ("token_blacklist", "0011_linearizes_history"), ] operations = [ migrations.AlterField( model_name="outstandingtoken", name="user", field=models.ForeignKey( blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, ), ), ] djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/migrations/__init__.py000066400000000000000000000000001475766445300344130ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/token_blacklist/models.py000066400000000000000000000032031475766445300317730ustar00rootroot00000000000000from django.conf import settings from django.db import models class OutstandingToken(models.Model): id = models.BigAutoField(primary_key=True, serialize=False) user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True ) jti = models.CharField(unique=True, max_length=255) token = models.TextField() created_at = models.DateTimeField(null=True, blank=True) expires_at = models.DateTimeField() class Meta: # Work around for a bug in Django: # https://code.djangoproject.com/ticket/19422 # # Also see corresponding ticket: # https://github.com/encode/django-rest-framework/issues/705 abstract = ( "rest_framework_simplejwt.token_blacklist" not in settings.INSTALLED_APPS ) ordering = ("user",) def __str__(self) -> str: return "Token for {} ({})".format( self.user, self.jti, ) class BlacklistedToken(models.Model): id = models.BigAutoField(primary_key=True, serialize=False) token = models.OneToOneField(OutstandingToken, on_delete=models.CASCADE) blacklisted_at = models.DateTimeField(auto_now_add=True) class Meta: # Work around for a bug in Django: # https://code.djangoproject.com/ticket/19422 # # Also see corresponding ticket: # https://github.com/encode/django-rest-framework/issues/705 abstract = ( "rest_framework_simplejwt.token_blacklist" not in settings.INSTALLED_APPS ) def __str__(self) -> str: return f"Blacklisted token for {self.token.user}" djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/tokens.py000066400000000000000000000325511475766445300266530ustar00rootroot00000000000000from datetime import datetime, timedelta from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar from uuid import uuid4 from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.auth.models import AbstractBaseUser from django.utils.module_loading import import_string from django.utils.translation import gettext_lazy as _ from .exceptions import ( ExpiredTokenError, TokenBackendError, TokenBackendExpiredToken, TokenError, ) from .models import TokenUser from .settings import api_settings from .token_blacklist.models import BlacklistedToken, OutstandingToken from .utils import ( aware_utcnow, datetime_from_epoch, datetime_to_epoch, format_lazy, get_md5_hash_password, ) if TYPE_CHECKING: from .backends import TokenBackend T = TypeVar("T", bound="Token") AuthUser = TypeVar("AuthUser", AbstractBaseUser, TokenUser) class Token: """ A class which validates and wraps an existing JWT or can be used to build a new JWT. """ token_type: Optional[str] = None lifetime: Optional[timedelta] = None def __init__(self, token: Optional["Token"] = None, verify: bool = True) -> None: """ !!!! IMPORTANT !!!! MUST raise a TokenError with a user-facing error message if the given token is invalid, expired, or otherwise not safe to use. """ if self.token_type is None or self.lifetime is None: raise TokenError(_("Cannot create token with no type or lifetime")) self.token = token self.current_time = aware_utcnow() # Set up token if token is not None: # An encoded token was provided token_backend = self.get_token_backend() # Decode token try: self.payload = token_backend.decode(token, verify=verify) except TokenBackendExpiredToken: raise ExpiredTokenError(_("Token is expired")) except TokenBackendError: raise TokenError(_("Token is invalid")) if verify: self.verify() else: # New token. Skip all the verification steps. self.payload = {api_settings.TOKEN_TYPE_CLAIM: self.token_type} # Set "exp" and "iat" claims with default value self.set_exp(from_time=self.current_time, lifetime=self.lifetime) self.set_iat(at_time=self.current_time) # Set "jti" claim self.set_jti() def __repr__(self) -> str: return repr(self.payload) def __getitem__(self, key: str): return self.payload[key] def __setitem__(self, key: str, value: Any) -> None: self.payload[key] = value def __delitem__(self, key: str) -> None: del self.payload[key] def __contains__(self, key: str) -> Any: return key in self.payload def get(self, key: str, default: Optional[Any] = None) -> Any: return self.payload.get(key, default) def __str__(self) -> str: """ Signs and returns a token as a base64 encoded string. """ return self.get_token_backend().encode(self.payload) def verify(self) -> None: """ Performs additional validation steps which were not performed when this token was decoded. This method is part of the "public" API to indicate the intention that it may be overridden in subclasses. """ # According to RFC 7519, the "exp" claim is OPTIONAL # (https://tools.ietf.org/html/rfc7519#section-4.1.4). As a more # correct behavior for authorization tokens, we require an "exp" # claim. We don't want any zombie tokens walking around. self.check_exp() # If the defaults are not None then we should enforce the # requirement of these settings.As above, the spec labels # these as optional. if ( api_settings.JTI_CLAIM is not None and api_settings.JTI_CLAIM not in self.payload ): raise TokenError(_("Token has no id")) if api_settings.TOKEN_TYPE_CLAIM is not None: self.verify_token_type() def verify_token_type(self) -> None: """ Ensures that the token type claim is present and has the correct value. """ try: token_type = self.payload[api_settings.TOKEN_TYPE_CLAIM] except KeyError: raise TokenError(_("Token has no type")) if self.token_type != token_type: raise TokenError(_("Token has wrong type")) def set_jti(self) -> None: """ Populates the configured jti claim of a token with a string where there is a negligible probability that the same string will be chosen at a later time. See here: https://tools.ietf.org/html/rfc7519#section-4.1.7 """ self.payload[api_settings.JTI_CLAIM] = uuid4().hex def set_exp( self, claim: str = "exp", from_time: Optional[datetime] = None, lifetime: Optional[timedelta] = None, ) -> None: """ Updates the expiration time of a token. See here: https://tools.ietf.org/html/rfc7519#section-4.1.4 """ if from_time is None: from_time = self.current_time if lifetime is None: lifetime = self.lifetime self.payload[claim] = datetime_to_epoch(from_time + lifetime) def set_iat(self, claim: str = "iat", at_time: Optional[datetime] = None) -> None: """ Updates the time at which the token was issued. See here: https://tools.ietf.org/html/rfc7519#section-4.1.6 """ if at_time is None: at_time = self.current_time self.payload[claim] = datetime_to_epoch(at_time) def check_exp( self, claim: str = "exp", current_time: Optional[datetime] = None ) -> None: """ Checks whether a timestamp value in the given claim has passed (since the given datetime value in `current_time`). Raises a TokenError with a user-facing error message if so. """ if current_time is None: current_time = self.current_time try: claim_value = self.payload[claim] except KeyError: raise TokenError(format_lazy(_("Token has no '{}' claim"), claim)) claim_time = datetime_from_epoch(claim_value) leeway = self.get_token_backend().get_leeway() if claim_time <= current_time - leeway: raise TokenError(format_lazy(_("Token '{}' claim has expired"), claim)) def outstand(self) -> OutstandingToken: """ Ensures this token is included in the outstanding token list and adds it to the outstanding token list if not. """ jti = self.payload[api_settings.JTI_CLAIM] exp = self.payload["exp"] user_id = self.payload.get(api_settings.USER_ID_CLAIM) User = get_user_model() try: user = User.objects.get(**{api_settings.USER_ID_FIELD: user_id}) except User.DoesNotExist: user = None # Ensure outstanding token exists with given jti return OutstandingToken.objects.get_or_create( jti=jti, defaults={ "user": user, "created_at": self.current_time, "token": str(self), "expires_at": datetime_from_epoch(exp), }, ) @classmethod def for_user(cls: type[T], user: AuthUser) -> T: """ Returns an authorization token for the given user that will be provided after authenticating the user's credentials. """ user_id = getattr(user, api_settings.USER_ID_FIELD) if not isinstance(user_id, int): user_id = str(user_id) token = cls() token[api_settings.USER_ID_CLAIM] = user_id if api_settings.CHECK_REVOKE_TOKEN: token[api_settings.REVOKE_TOKEN_CLAIM] = get_md5_hash_password( user.password ) return token _token_backend: Optional["TokenBackend"] = None @property def token_backend(self) -> "TokenBackend": if self._token_backend is None: self._token_backend = import_string( "rest_framework_simplejwt.state.token_backend" ) return self._token_backend def get_token_backend(self) -> "TokenBackend": # Backward compatibility. return self.token_backend class BlacklistMixin(Generic[T]): """ If the `rest_framework_simplejwt.token_blacklist` app was configured to be used, tokens created from `BlacklistMixin` subclasses will insert themselves into an outstanding token list and also check for their membership in a token blacklist. """ payload: dict[str, Any] if "rest_framework_simplejwt.token_blacklist" in settings.INSTALLED_APPS: def verify(self, *args, **kwargs) -> None: self.check_blacklist() super().verify(*args, **kwargs) # type: ignore def check_blacklist(self) -> None: """ Checks if this token is present in the token blacklist. Raises `TokenError` if so. """ jti = self.payload[api_settings.JTI_CLAIM] if BlacklistedToken.objects.filter(token__jti=jti).exists(): raise TokenError(_("Token is blacklisted")) def blacklist(self) -> BlacklistedToken: """ Ensures this token is included in the outstanding token list and adds it to the blacklist. """ jti = self.payload[api_settings.JTI_CLAIM] exp = self.payload["exp"] user_id = self.payload.get(api_settings.USER_ID_CLAIM) User = get_user_model() try: user = User.objects.get(**{api_settings.USER_ID_FIELD: user_id}) except User.DoesNotExist: user = None # Ensure outstanding token exists with given jti token, _ = OutstandingToken.objects.get_or_create( jti=jti, defaults={ "user": user, "created_at": self.current_time, "token": str(self), "expires_at": datetime_from_epoch(exp), }, ) return BlacklistedToken.objects.get_or_create(token=token) @classmethod def for_user(cls: type[T], user: AuthUser) -> T: """ Adds this token to the outstanding token list. """ token = super().for_user(user) # type: ignore jti = token[api_settings.JTI_CLAIM] exp = token["exp"] OutstandingToken.objects.create( user=user, jti=jti, token=str(token), created_at=token.current_time, expires_at=datetime_from_epoch(exp), ) return token class SlidingToken(BlacklistMixin["SlidingToken"], Token): token_type = "sliding" lifetime = api_settings.SLIDING_TOKEN_LIFETIME def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) if self.token is None: # Set sliding refresh expiration claim if new token self.set_exp( api_settings.SLIDING_TOKEN_REFRESH_EXP_CLAIM, from_time=self.current_time, lifetime=api_settings.SLIDING_TOKEN_REFRESH_LIFETIME, ) class AccessToken(Token): token_type = "access" lifetime = api_settings.ACCESS_TOKEN_LIFETIME class RefreshToken(BlacklistMixin["RefreshToken"], Token): token_type = "refresh" lifetime = api_settings.REFRESH_TOKEN_LIFETIME no_copy_claims = ( api_settings.TOKEN_TYPE_CLAIM, "exp", # Both of these claims are included even though they may be the same. # It seems possible that a third party token might have a custom or # namespaced JTI claim as well as a default "jti" claim. In that case, # we wouldn't want to copy either one. api_settings.JTI_CLAIM, "jti", ) access_token_class = AccessToken @property def access_token(self) -> AccessToken: """ Returns an access token created from this refresh token. Copies all claims present in this refresh token to the new access token except those claims listed in the `no_copy_claims` attribute. """ access = self.access_token_class() # Use instantiation time of refresh token as relative timestamp for # access token "exp" claim. This ensures that both a refresh and # access token expire relative to the same time if they are created as # a pair. access.set_exp(from_time=self.current_time) no_copy = self.no_copy_claims for claim, value in self.payload.items(): if claim in no_copy: continue access[claim] = value return access class UntypedToken(Token): token_type = "untyped" lifetime = timedelta(seconds=0) def verify_token_type(self) -> None: """ Untyped tokens do not verify the "token_type" claim. This is useful when performing general validation of a token's signature and other properties which do not relate to the token's intended use. """ pass djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/utils.py000066400000000000000000000020501475766445300264770ustar00rootroot00000000000000import hashlib from calendar import timegm from datetime import datetime, timezone from typing import Callable from django.conf import settings from django.utils.functional import lazy def get_md5_hash_password(password: str) -> str: """ Returns MD5 hash of the given password """ return hashlib.md5(password.encode()).hexdigest().upper() def make_utc(dt: datetime) -> datetime: if settings.USE_TZ and dt.tzinfo is None: return dt.replace(tzinfo=timezone.utc) return dt def aware_utcnow() -> datetime: dt = datetime.now(tz=timezone.utc) if not settings.USE_TZ: dt = dt.replace(tzinfo=None) return dt def datetime_to_epoch(dt: datetime) -> int: return timegm(dt.utctimetuple()) def datetime_from_epoch(ts: float) -> datetime: dt = datetime.fromtimestamp(ts, tz=timezone.utc) if not settings.USE_TZ: dt = dt.replace(tzinfo=None) return dt def format_lazy(s: str, *args, **kwargs) -> str: return s.format(*args, **kwargs) format_lazy: Callable = lazy(format_lazy, str) djangorestframework-simplejwt-5.5.0/rest_framework_simplejwt/views.py000066400000000000000000000064651475766445300265120ustar00rootroot00000000000000from django.utils.module_loading import import_string from rest_framework import generics, status from rest_framework.request import Request from rest_framework.response import Response from rest_framework.serializers import Serializer from .authentication import AUTH_HEADER_TYPES from .exceptions import InvalidToken, TokenError from .settings import api_settings class TokenViewBase(generics.GenericAPIView): permission_classes = () authentication_classes = () serializer_class = None _serializer_class = "" www_authenticate_realm = "api" def get_serializer_class(self) -> Serializer: """ If serializer_class is set, use it directly. Otherwise get the class from settings. """ if self.serializer_class: return self.serializer_class try: return import_string(self._serializer_class) except ImportError: msg = f"Could not import serializer '{self._serializer_class}'" raise ImportError(msg) def get_authenticate_header(self, request: Request) -> str: return '{} realm="{}"'.format( AUTH_HEADER_TYPES[0], self.www_authenticate_realm, ) def post(self, request: Request, *args, **kwargs) -> Response: serializer = self.get_serializer(data=request.data) try: serializer.is_valid(raise_exception=True) except TokenError as e: raise InvalidToken(e.args[0]) return Response(serializer.validated_data, status=status.HTTP_200_OK) class TokenObtainPairView(TokenViewBase): """ Takes a set of user credentials and returns an access and refresh JSON web token pair to prove the authentication of those credentials. """ _serializer_class = api_settings.TOKEN_OBTAIN_SERIALIZER token_obtain_pair = TokenObtainPairView.as_view() class TokenRefreshView(TokenViewBase): """ Takes a refresh type JSON web token and returns an access type JSON web token if the refresh token is valid. """ _serializer_class = api_settings.TOKEN_REFRESH_SERIALIZER token_refresh = TokenRefreshView.as_view() class TokenObtainSlidingView(TokenViewBase): """ Takes a set of user credentials and returns a sliding JSON web token to prove the authentication of those credentials. """ _serializer_class = api_settings.SLIDING_TOKEN_OBTAIN_SERIALIZER token_obtain_sliding = TokenObtainSlidingView.as_view() class TokenRefreshSlidingView(TokenViewBase): """ Takes a sliding JSON web token and returns a new, refreshed version if the token's refresh period has not expired. """ _serializer_class = api_settings.SLIDING_TOKEN_REFRESH_SERIALIZER token_refresh_sliding = TokenRefreshSlidingView.as_view() class TokenVerifyView(TokenViewBase): """ Takes a token and indicates if it is valid. This view provides no information about a token's fitness for a particular use. """ _serializer_class = api_settings.TOKEN_VERIFY_SERIALIZER token_verify = TokenVerifyView.as_view() class TokenBlacklistView(TokenViewBase): """ Takes a token and blacklists it. Must be used with the `rest_framework_simplejwt.token_blacklist` app installed. """ _serializer_class = api_settings.TOKEN_BLACKLIST_SERIALIZER token_blacklist = TokenBlacklistView.as_view() djangorestframework-simplejwt-5.5.0/scripts/000077500000000000000000000000001475766445300213275ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/scripts/i18n_updater.py000066400000000000000000000027721475766445300242140ustar00rootroot00000000000000import contextlib import os import subprocess def get_list_of_files(dir_name: str, extension: str): file_list = os.listdir(dir_name) result = [] for entry in file_list: full_path = os.path.join(dir_name, entry) if os.path.isdir(full_path): result = result + get_list_of_files(full_path, extension) else: if entry[-len(extension) : len(entry)] == extension: result.append(full_path) return result @contextlib.contextmanager def cache_creation(): # DO NOT cache the line number; the file may change cache: dict[str, str] = {} for file in get_list_of_files("./", ".po"): if os.path.isdir(file): continue with open(file) as f: for line in f.readlines(): if line.startswith('"POT-Creation-Date: '): cache[file] = line break yield for file, line_cache in cache.items(): with open(file, "r+") as f: lines = f.readlines() # clear file f.seek(0) f.truncate() # find line index = [ lines.index(x) for x in lines if x.startswith('"POT-Creation-Date: ') ][0] lines[index] = line_cache f.writelines(lines) def main(): with cache_creation(): subprocess.run(["django-admin", "makemessages", "-a"]) subprocess.run(["django-admin", "compilemessages"]) if __name__ == "__main__": main() djangorestframework-simplejwt-5.5.0/setup.cfg000066400000000000000000000000461475766445300214610ustar00rootroot00000000000000[metadata] license_file = LICENSE.txt djangorestframework-simplejwt-5.5.0/setup.py000077500000000000000000000045661475766445300213700ustar00rootroot00000000000000#!/usr/bin/env python from pathlib import Path from setuptools import find_packages, setup extras_require = { "test": [ "cryptography", "freezegun", "pytest-cov", "pytest-django", "pytest-xdist", "pytest", "tox", ], "lint": [ "ruff", "yesqa", "pyupgrade", "pre-commit", ], "doc": [ "Sphinx>=1.6.5,<2", "sphinx_rtd_theme>=0.1.9", ], "dev": [ "pytest-watch", "wheel", "twine", "ipython", ], "python-jose": [ "python-jose==3.3.0", ], "crypto": [ "cryptography>=3.3.1", ], } extras_require["dev"] = ( extras_require["dev"] + extras_require["test"] + extras_require["lint"] + extras_require["doc"] + extras_require["python-jose"] ) setup( name="djangorestframework_simplejwt", use_scm_version={"version_scheme": "post-release"}, setup_requires=["setuptools_scm"], url="https://github.com/jazzband/djangorestframework-simplejwt", license="MIT", description="A minimal JSON Web Token authentication plugin for Django REST Framework", long_description=Path("README.rst").read_text(encoding="utf-8"), author="David Sanders", author_email="davesque@gmail.com", install_requires=[ "django>=4.2", "djangorestframework>=3.14", "pyjwt>=1.7.1,<2.10.0", ], python_requires=">=3.9", extras_require=extras_require, packages=find_packages(exclude=["tests", "tests.*", "licenses", "requirements"]), include_package_data=True, zip_safe=False, classifiers=[ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Framework :: Django :: 4.2", "Framework :: Django :: 5.0", "Framework :: Django :: 5.1", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Internet :: WWW/HTTP", ], ) djangorestframework-simplejwt-5.5.0/tests/000077500000000000000000000000001475766445300210025ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/tests/__init__.py000066400000000000000000000000001475766445300231010ustar00rootroot00000000000000djangorestframework-simplejwt-5.5.0/tests/conftest.py000066400000000000000000000031351475766445300232030ustar00rootroot00000000000000def pytest_configure(): from django.conf import settings MIDDLEWARE = ( "django.middleware.common.CommonMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", ) settings.configure( DEBUG_PROPAGATE_EXCEPTIONS=True, DATABASES={ "default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}, "other": {"ENGINE": "django.db.backends.sqlite3", "NAME": "other"}, }, SITE_ID=1, SECRET_KEY="not very secret in tests", USE_I18N=True, STATIC_URL="/static/", ROOT_URLCONF="tests.urls", TEMPLATES=[ { "BACKEND": "django.template.backends.django.DjangoTemplates", "APP_DIRS": True, }, ], MIDDLEWARE=MIDDLEWARE, MIDDLEWARE_CLASSES=MIDDLEWARE, INSTALLED_APPS=( "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.sites", "django.contrib.staticfiles", "rest_framework", "rest_framework_simplejwt", "rest_framework_simplejwt.token_blacklist", "tests", ), PASSWORD_HASHERS=("django.contrib.auth.hashers.MD5PasswordHasher",), SIMPLE_JWT={ "BLACKLIST_AFTER_ROTATION": True, }, ) try: import django django.setup() except AttributeError: pass djangorestframework-simplejwt-5.5.0/tests/keys.py000066400000000000000000000151041475766445300223300ustar00rootroot00000000000000PRIVATE_KEY = """ -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEA3xMJfyl8TOdrsjDLSIodsArJ/NnQB3ZdfbFC5onxATDfRLLA CHFo3ye694doBKeSe1NFYbfXPvahl6ODX1a23oQyoRQwlL+M99cLcdCa0gGuJXdb AaF6Em8E+7uSb3290mI+rZmjqyc7gMtKVWKL4e5i2PerFFBoYkZ7E90KOp2t0ZAD x2uqF4VTOfYLHG0cPgSw9/ptDStJqJVAOiRRqbv0j0GOFMDYNcN0mDlnpryhQFbQ iMqn4IJIURZUVBJujFSa45cJPvSmMb6NrzZ1crg5UN6/5Mu2mxQzAi21+vpgGL+E EuekUd7sRgEAjTHjLKzotLAGo7EGa8sL1vMSFwIDAQABAoIBAQCGGWabF/BONswq CWUazVR9cG7uXm3NHp2jIr1p40CLC7scDCyeprZ5d+PQS4j/S1Ema++Ih8CQbCjG BJjD5lf2OhhJdt6hfOkcUBzkJZf8aOAsS6zctRqyHCUtwxuLhFZpM4AkUfjuuZ3u lcawv5YBkpG/hltE0fV+Jop0bWtpwiKxVsHXVcS0WEPXic0lsOTBCw8m81JXqjir PCBOnkxgNpHSt69S1xnW3l9fPUWVlduO3EIZ5PZG2BxU081eZW31yIlKsDJhfgm6 R5Vlr5DynqeojAd6SNliCzNXZP28GOpQBrYIeVQWA1yMANvkvd4apz9GmDrjF/Fd g8Chah+5AoGBAPc/+zyuDZKVHK7MxwLPlchCm5Zb4eou4ycbwEB+P3gDS7MODGu4 qvx7cstTZMuMavNRcJsfoiMMrke9JrqGe4rFGiKRFLVBY2Xwr+95pKNC11EWI1lF 5qDAmreDsj2alVJT5yZ9hsAWTsk2i+xj+/XHWYVkr67pRvOPRAmGMB+NAoGBAOb4 CBHe184Hn6Ie+gSD4OjewyUVmr3JDJ41s8cjb1kBvDJ/wv9Rvo9yz2imMr2F0YGc ytHraM77v8KOJuJWpvGjEg8I0a/rSttxWQ+J0oYJSIPn+eDpAijNWfOp1aKRNALT pboCXcnSn+djJFKkNJ2hR7R/vrrM6Jyly1jcVS0zAoGAQpdt4Cr0pt0YS5AFraEh Mz2VUArRLtSQA3F69yPJjlY85i3LdJvZGYVaJp8AT74y8/OkQ3NipNP+gH3WV3hu /7IUVukCTcsdrVAE4pe9mucevM0cmie0dOlLAlArCmJ/Axxr7jbyuvuHHrRdPT60 lr6pQr8afh6AKIsWhQYqIeUCgYA+v9IJcN52hhGzjPDl+yJGggbIc3cn6pA4B2UB TDo7F0KXAajrjrzT4iBBUS3l2Y5SxVNA9tDxsumlJNOhmGMgsOn+FapKPgWHWuMU WqBMdAc0dvinRwakKS4wCcsVsJdN0UxsHap3Y3a3+XJr1VrKHIALpM0fmP31WQHG 8Y1eiwKBgF6AYXxo0FzZacAommZrAYoxFZT1u4/rE/uvJ2K9HYRxLOVKZe+89ki3 D7AOmrxe/CAc/D+nNrtUIv3RFGfadfSBWzyLw36ekW76xPdJgqJsSz5XJ/FgzDW+ WNC5oOtiPOMCymP75oKOjuZJZ2SPLRmiuO/qvI5uAzBHxRC1BKdt -----END RSA PRIVATE KEY----- """ PUBLIC_KEY = """ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3xMJfyl8TOdrsjDLSIod sArJ/NnQB3ZdfbFC5onxATDfRLLACHFo3ye694doBKeSe1NFYbfXPvahl6ODX1a2 3oQyoRQwlL+M99cLcdCa0gGuJXdbAaF6Em8E+7uSb3290mI+rZmjqyc7gMtKVWKL 4e5i2PerFFBoYkZ7E90KOp2t0ZADx2uqF4VTOfYLHG0cPgSw9/ptDStJqJVAOiRR qbv0j0GOFMDYNcN0mDlnpryhQFbQiMqn4IJIURZUVBJujFSa45cJPvSmMb6NrzZ1 crg5UN6/5Mu2mxQzAi21+vpgGL+EEuekUd7sRgEAjTHjLKzotLAGo7EGa8sL1vMS FwIDAQAB -----END PUBLIC KEY----- """ PRIVATE_KEY_2 = """ -----BEGIN RSA PRIVATE KEY----- MIIJKQIBAAKCAgEAwpwcivLRv5T/2pb9zZpfh4Fy1vla3vm5N2WtkhjB0DX1HmOh SN9O1Q3byW9VLQtuNAdZ8+hc2jU5DIVApFF+b1Uo1C76qZWOLLwK/yvweACTdT4M ISeYHaUd/B7YUNtUQEZF0xxjMM8jRXEuI902pLEUBx9cd2d8KzCgXyC2dsNIt3zg WCu6RhL1V10lhBXMwl0N1+DAIRsXjCazwaxBMrTNOsXrex98aaPk3++V1KkPbLnV Zk8I7dbpt9EYSvMB7DaXFiLL4XySamFfYmtq9n9bxKXxnzpObolWkD0SbioaxkCq vEFyy2/y4ZIxYC1mHhRgTtSicnk8WGOgv6Ax1sRHpbRVDtXMmDHn7oiJdd8YCGvT 9AQoibeccPUZbwaiuiULSVjphKErXLg7nH6/ct8bVYZnh0GnYTljC3O0f3/D1A9Z PxLHJPc9K2GCmZ+TNMmDDmGbLz/TgFiSZE3CQEORxbGyNh5MZuIrGub9xaKB4Hon Rf8HXwVa/zL4dKxpzYzHNBH8wqPOWCLXjp65lcMW7JBAnrqshI0wOCEbk13uLudB aNL4k/h9M9RKaEW24tKpg29XsWu9II3Bt94x7gwhokE7gICsycUSQWTGaBovbvn0 C8k4gkPq6teGAD6AJ6/YV2hiPbdoRL5EkMS3E01hmaHk9xlOpo73IjUxhXUCAwEA AQKCAgEAjEfNx1cbXNdBysa2cuOJYvsr1cxu9XXbThRsFnjkFHsgkuRMWWQmxis0 ODKZmlu396co70mazOw6kEzpeMkJs6UWRkULCP02PAbcgm2g7E+1+3hbc/a/jvb7 80Yktbw0MhS1tmSrF37otODN2qpV/kdq4Wt40tV0ywlFQO0qudcw7psEeGok3uhB k9Uf+uNf8uby2J84v2RxB+TKBJxvbuanXWtXwCvFGb07eTSRs3aeGMioDBSCojcd yBPgR/59b1E2fY1dm8+ZFzfTcvVtZ/wMIWdhEV8NNF6pWFW9mE2feTMaH5Op9P1g fbtM/kAbcSlM9uYNpyi/GBPQxvDpmttbBVyuSx2G7ct9EeMjJQ0QjC6DWG3zwz/b S8f9y/K2pnzKZdUrQBI9RRYu2OqHlfLQ/RWnr2/mRvFr9bd3pZEYchnB/PyKKvZB eS0X3LibP7ktmSFyB/xtsap/S/qHf9acY5Uu7w0gSXoNFTAG1zW/cHTXMYC0oYlD L8F3fO7ddo2nx2YOxEm5e5GDgc3V952GTgFZclsc6jn6AkOVyzoPYEfJy3JjPyTv doDrK5lPJ5ekmdyTdMhw376dHmkSB4D+27U/WMHN0EgMCmJznoWhvGuLG/mLbK+q d/K3Cy3ipUJDhb3OrDzfJ+Ps7E8BYBxZp69yhV5gV1T40pgG/WECggEBAPtF+3Uh CBh5amhFQOHc4hMR8UGTOBWF/uz15+PImzLcpN/gpgoWaIExQsrbQCStemMO7hhi N3/pf1+V0hbRb8cLN/B/BG/31pw3bCJKB+nYr1elCHOhS9+1txekcoqA3pVdmyZ0 TcyTczgFluXmWurIJqj9dp+KOJlh6Q6qehKNX6D/E9RszuZiHOeKzgaDCy+WI3DK bxtthfddasBxBYji6ObRn0BY6RjUnkHAra6Lib3M8Y8qxJnQozjBuWCwf2bflN++ 2tcO/m5s2tksNDWfu4q+ruh2zWGPbaEvhEs0o2z0kucCukEBqqbMT+p9HdFbkom4 XJOT4ZUCJfCdGIkCggEBAMZFQ3BW4I18TVRaMQMv/5ivp9/Qd/Ls/jU+wfiiZnq9 zT5a/9LkI/rWq4G+gT93KxRtH43FpJlo1N+1e4sEYf6a0gcgo8inyE2MZCJFuN7g GbOU/qgzLmCtHmbUjyHNzBk/+SK2Jh4PpF3DLOSU8+AWmI8aF9Cl7UojXDTLGhmR qS7MBv/jNUT93xTJUrSvkp2HWF8GOwrVd9CUo6zNnFb3nIP3fUARCpa/aurPaiim U+mv7NlpK/wUiP8dWUu3+hqa3yPE9WGHixdfMd6o4KfAyqMb5WErR1laU3wbl0B1 FzFxECn5Dkt9p93LzXMIn58eT2ZeneNdzWKQn0BOco0CggEBAOoN9/rUt+vEPR+/ Un6Q92z4C5gff+Bcnmcvb783v4kTCekYItHGqbWdoy++JvODPDtFTvcblcLqRyFM NxPWJp5rjsHQLtv1Kcz9uxX9i32Bv2KOcV7z4e8SHuhA4AivnaXYOYsKTuW+e1a1 rieb+Rg1M/25i2N0puAI2cQ1e9wIIAmhUGFQsTDcNzxeiSZ7rlG3Mm//wJr13BHc zHFRVex6IKPQotyXdRkSBBAPYDjz9Wv8mQ3YsqTsOP3HRdwQy7uRi+UWrFYiu1E0 yG3+xOsmTNUiZV5YO1si9OVtk3dSIuB8uNHCMqgW21Tff5lWzg2TlN4AAwvcdgYM qDaGvrECggEAOT+IkGhVYCTzAxcjrcLvLzwQ4dwEtlzdrawYP91Mb8Zb+9Q0p8T9 6pCPZuAF27hh9PzpLntR4oXVaV6ydFponSZA3JP9FpPzjwipZQfysE/Ou/6aZSCa FIoIDDL1vRH6C5RgMDid2vIzSGtxi/LCVALSPAeRtsoiMNTy6791IsrfKcb5gmst V2ViQ1M6ETfcwqVwy8c1xxQKC2zPsbaQnL/ULnqIbLY+83YDvhbzlRcphYEph0EJ 1ThsshTcUrOlgIcVRPO60lVbwPzYnmzuqSFOoTgNzDe92zvsfRpOWus0Li9yNlxW V0/J543QHZXw2PXcgTdyqVLNWddeVCgShQKCAQBp63G+/O26R/jYjh74FCg0PQ6r yAk2kmjHLsIPRFIiW/u6DXn5hufk2wM/JTQf/9LRXhjLdzqehOoQasQSJAR+wiOx CeTDD91sHtMqQb0sAbQyLGKsDBG3dfnB1BEGQccfZnDZKx7N7kvzkN5/4CYpscWn CNnBq6IE9iu31w3VEKxAc0bdLxPdOw79NhgwzW1JgysFBQAEdtZ1qlMPQOj9IMnB eszY1HhshLbaaUwuG8SUDvKzZUpEEq711yQoW4y1yzOrcMmTYzRFuMczcB4v0tqe /sno2/CDUEKR5SsDgnqB9hPzFJDclfN/MPdpx9X29JF1RlGsz8RJS29ztWyh -----END RSA PRIVATE KEY----- """ PUBLIC_KEY_2 = """ -----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwpwcivLRv5T/2pb9zZpf h4Fy1vla3vm5N2WtkhjB0DX1HmOhSN9O1Q3byW9VLQtuNAdZ8+hc2jU5DIVApFF+ b1Uo1C76qZWOLLwK/yvweACTdT4MISeYHaUd/B7YUNtUQEZF0xxjMM8jRXEuI902 pLEUBx9cd2d8KzCgXyC2dsNIt3zgWCu6RhL1V10lhBXMwl0N1+DAIRsXjCazwaxB MrTNOsXrex98aaPk3++V1KkPbLnVZk8I7dbpt9EYSvMB7DaXFiLL4XySamFfYmtq 9n9bxKXxnzpObolWkD0SbioaxkCqvEFyy2/y4ZIxYC1mHhRgTtSicnk8WGOgv6Ax 1sRHpbRVDtXMmDHn7oiJdd8YCGvT9AQoibeccPUZbwaiuiULSVjphKErXLg7nH6/ ct8bVYZnh0GnYTljC3O0f3/D1A9ZPxLHJPc9K2GCmZ+TNMmDDmGbLz/TgFiSZE3C QEORxbGyNh5MZuIrGub9xaKB4HonRf8HXwVa/zL4dKxpzYzHNBH8wqPOWCLXjp65 lcMW7JBAnrqshI0wOCEbk13uLudBaNL4k/h9M9RKaEW24tKpg29XsWu9II3Bt94x 7gwhokE7gICsycUSQWTGaBovbvn0C8k4gkPq6teGAD6AJ6/YV2hiPbdoRL5EkMS3 E01hmaHk9xlOpo73IjUxhXUCAwEAAQ== -----END PUBLIC KEY----- """ ES256_PRIVATE_KEY = """ -----BEGIN EC PRIVATE KEY----- MHcCAQEEIMtBPxiLHcJCrAGdz4jHvTtAh6Rw7351AckG3whXq2WOoAoGCCqGSM49 AwEHoUQDQgAEMZHyNxbkr7+zqQ1dQk/zug2pwYdztmjhpC+XqK88q5NfIS1cBYYt zhHUS4vGpazNqbW8HA3ZIvJRmx4L96O6/w== -----END EC PRIVATE KEY----- """ ES256_PUBLIC_KEY = """ -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMZHyNxbkr7+zqQ1dQk/zug2pwYdz tmjhpC+XqK88q5NfIS1cBYYtzhHUS4vGpazNqbW8HA3ZIvJRmx4L96O6/w== -----END PUBLIC KEY----- """ djangorestframework-simplejwt-5.5.0/tests/models.py000066400000000000000000000000221475766445300226310ustar00rootroot00000000000000# Add models here djangorestframework-simplejwt-5.5.0/tests/test_authentication.py000066400000000000000000000226731475766445300254440ustar00rootroot00000000000000from datetime import timedelta from importlib import reload from django.contrib.auth import get_user_model from django.test import TestCase from rest_framework.test import APIRequestFactory from rest_framework_simplejwt import authentication from rest_framework_simplejwt.exceptions import AuthenticationFailed, InvalidToken from rest_framework_simplejwt.models import TokenUser from rest_framework_simplejwt.settings import api_settings from rest_framework_simplejwt.tokens import AccessToken, SlidingToken from rest_framework_simplejwt.utils import get_md5_hash_password from .utils import override_api_settings User = get_user_model() AuthToken = api_settings.AUTH_TOKEN_CLASSES[0] class TestJWTAuthentication(TestCase): def setUp(self): self.factory = APIRequestFactory() self.backend = authentication.JWTAuthentication() self.fake_token = b"TokenMcTokenface" self.fake_header = b"Bearer " + self.fake_token def test_get_header(self): # Should return None if no authorization header request = self.factory.get("/test-url/") self.assertIsNone(self.backend.get_header(request)) # Should pull correct header off request request = self.factory.get("/test-url/", HTTP_AUTHORIZATION=self.fake_header) self.assertEqual(self.backend.get_header(request), self.fake_header) # Should work for unicode headers request = self.factory.get( "/test-url/", HTTP_AUTHORIZATION=self.fake_header.decode("utf-8") ) self.assertEqual(self.backend.get_header(request), self.fake_header) @override_api_settings(AUTH_HEADER_NAME="HTTP_X_ACCESS_TOKEN") def test_get_header_x_access_token(self): # Should pull correct header off request when using X_ACCESS_TOKEN request = self.factory.get("/test-url/", HTTP_X_ACCESS_TOKEN=self.fake_header) self.assertEqual(self.backend.get_header(request), self.fake_header) # Should work for unicode headers when using request = self.factory.get( "/test-url/", HTTP_X_ACCESS_TOKEN=self.fake_header.decode("utf-8") ) self.assertEqual(self.backend.get_header(request), self.fake_header) def test_get_raw_token(self): reload(authentication) # Should return None if an empty AUTHORIZATION header is sent self.assertIsNone(self.backend.get_raw_token(b"")) # Should raise error if header is malformed with self.assertRaises(AuthenticationFailed): self.backend.get_raw_token(b"Bearer one two") with self.assertRaises(AuthenticationFailed): self.backend.get_raw_token(b"Bearer") # Otherwise, should return unvalidated token in header self.assertEqual(self.backend.get_raw_token(self.fake_header), self.fake_token) @override_api_settings(AUTH_HEADER_TYPES="JWT") def test_get_raw_token_incorrect_header_keyword(self): # Should return None if header lacks correct type keyword # AUTH_HEADER_TYPES is "JWT", but header is "Bearer" reload(authentication) self.assertIsNone(self.backend.get_raw_token(self.fake_header)) @override_api_settings(AUTH_HEADER_TYPES=("JWT", "Bearer")) def test_get_raw_token_multi_header_keyword(self): # Should return token if header has one of many valid token types reload(authentication) self.assertEqual( self.backend.get_raw_token(self.fake_header), self.fake_token, ) def test_get_validated_token(self): # Should raise InvalidToken if token not valid token = AuthToken() token.set_exp(lifetime=-timedelta(days=1)) with self.assertRaises(InvalidToken): self.backend.get_validated_token(str(token)) # Otherwise, should return validated token token.set_exp() self.assertEqual( self.backend.get_validated_token(str(token)).payload, token.payload ) @override_api_settings( AUTH_TOKEN_CLASSES=("rest_framework_simplejwt.tokens.AccessToken",), ) def test_get_validated_token_reject_unknown_token(self): # Should not accept tokens not included in AUTH_TOKEN_CLASSES sliding_token = SlidingToken() with self.assertRaises(InvalidToken) as e: self.backend.get_validated_token(str(sliding_token)) messages = e.exception.detail["messages"] self.assertEqual(1, len(messages)) self.assertEqual( { "token_class": "AccessToken", "token_type": "access", "message": "Token has wrong type", }, messages[0], ) @override_api_settings( AUTH_TOKEN_CLASSES=( "rest_framework_simplejwt.tokens.AccessToken", "rest_framework_simplejwt.tokens.SlidingToken", ), ) def test_get_validated_token_accept_known_token(self): # Should accept tokens included in AUTH_TOKEN_CLASSES access_token = AccessToken() sliding_token = SlidingToken() self.backend.get_validated_token(str(access_token)) self.backend.get_validated_token(str(sliding_token)) def test_get_user(self): payload = {"some_other_id": "foo"} # Should raise error if no recognizable user identification with self.assertRaises(InvalidToken): self.backend.get_user(payload) payload[api_settings.USER_ID_CLAIM] = 42 # Should raise exception if user not found with self.assertRaises(AuthenticationFailed): self.backend.get_user(payload) u = User.objects.create_user(username="markhamill") u.is_active = False u.save() payload[api_settings.USER_ID_CLAIM] = getattr(u, api_settings.USER_ID_FIELD) # Should raise exception if user is inactive with self.assertRaises(AuthenticationFailed): self.backend.get_user(payload) u.is_active = True u.save() # Otherwise, should return correct user self.assertEqual(self.backend.get_user(payload).id, u.id) @override_api_settings( CHECK_USER_IS_ACTIVE=False, ) def test_get_inactive_user(self): payload = {"some_other_id": "foo"} # Should raise error if no recognizable user identification with self.assertRaises(InvalidToken): self.backend.get_user(payload) payload[api_settings.USER_ID_CLAIM] = 42 # Should raise exception if user not found with self.assertRaises(AuthenticationFailed): self.backend.get_user(payload) u = User.objects.create_user(username="markhamill") u.is_active = False u.save() payload[api_settings.USER_ID_CLAIM] = getattr(u, api_settings.USER_ID_FIELD) # should return correct user self.assertEqual(self.backend.get_user(payload).id, u.id) @override_api_settings( CHECK_REVOKE_TOKEN=True, REVOKE_TOKEN_CLAIM="revoke_token_claim" ) def test_get_user_with_check_revoke_token(self): payload = {"some_other_id": "foo"} # Should raise error if no recognizable user identification with self.assertRaises(InvalidToken): self.backend.get_user(payload) payload[api_settings.USER_ID_CLAIM] = 42 # Should raise exception if user not found with self.assertRaises(AuthenticationFailed): self.backend.get_user(payload) u = User.objects.create_user(username="markhamill") u.is_active = False u.save() payload[api_settings.USER_ID_CLAIM] = getattr(u, api_settings.USER_ID_FIELD) # Should raise exception if user is inactive with self.assertRaises(AuthenticationFailed): self.backend.get_user(payload) u.is_active = True u.save() # Should raise exception if hash password is different with self.assertRaises(AuthenticationFailed): self.backend.get_user(payload) if api_settings.CHECK_REVOKE_TOKEN: payload[api_settings.REVOKE_TOKEN_CLAIM] = get_md5_hash_password(u.password) # Otherwise, should return correct user self.assertEqual(self.backend.get_user(payload).id, u.id) class TestJWTStatelessUserAuthentication(TestCase): def setUp(self): self.backend = authentication.JWTStatelessUserAuthentication() def test_get_user(self): payload = {"some_other_id": "foo"} # Should raise error if no recognizable user identification with self.assertRaises(InvalidToken): self.backend.get_user(payload) payload[api_settings.USER_ID_CLAIM] = 42 # Otherwise, should return a token user object user = self.backend.get_user(payload) self.assertIsInstance(user, TokenUser) self.assertEqual(user.id, 42) def test_custom_tokenuser(self): from django.utils.functional import cached_property class BobSaget(TokenUser): @cached_property def username(self): return "bsaget" temp = api_settings.TOKEN_USER_CLASS api_settings.TOKEN_USER_CLASS = BobSaget # Should return a token user object payload = {api_settings.USER_ID_CLAIM: 42} user = self.backend.get_user(payload) self.assertIsInstance(user, api_settings.TOKEN_USER_CLASS) self.assertEqual(user.id, 42) self.assertEqual(user.username, "bsaget") # Restore default TokenUser for future tests api_settings.TOKEN_USER_CLASS = temp djangorestframework-simplejwt-5.5.0/tests/test_backends.py000066400000000000000000000521511475766445300241710ustar00rootroot00000000000000import builtins import uuid from datetime import datetime, timedelta from importlib import reload from json import JSONEncoder from unittest import mock from unittest.mock import patch import jwt import pytest from django.test import TestCase from jwt import PyJWS, algorithms from jwt import __version__ as jwt_version from rest_framework_simplejwt.backends import JWK_CLIENT_AVAILABLE, TokenBackend from rest_framework_simplejwt.exceptions import ( TokenBackendError, TokenBackendExpiredToken, ) from rest_framework_simplejwt.utils import aware_utcnow, datetime_to_epoch, make_utc from tests.keys import ( ES256_PRIVATE_KEY, ES256_PUBLIC_KEY, PRIVATE_KEY, PRIVATE_KEY_2, PUBLIC_KEY, PUBLIC_KEY_2, ) SECRET = "not_secret" AUDIENCE = "openid-client-id" ISSUER = "https://www.myoidcprovider.com" JWK_URL = "https://randomstring.auth0.com/.well-known/jwks.json" LEEWAY = 100 IS_OLD_JWT = jwt_version == "1.7.1" class UUIDJSONEncoder(JSONEncoder): def default(self, obj): if isinstance(obj, uuid.UUID): return str(obj) return super().default(obj) class TestTokenBackend(TestCase): def setUp(self): self.realimport = builtins.__import__ self.hmac_token_backend = TokenBackend("HS256", SECRET) self.hmac_leeway_token_backend = TokenBackend("HS256", SECRET, leeway=LEEWAY) self.rsa_token_backend = TokenBackend("RS256", PRIVATE_KEY, PUBLIC_KEY) self.aud_iss_token_backend = TokenBackend( "RS256", PRIVATE_KEY, PUBLIC_KEY, AUDIENCE, ISSUER ) self.payload = {"foo": "bar"} self.backends = ( self.hmac_token_backend, self.rsa_token_backend, TokenBackend("ES256", ES256_PRIVATE_KEY, ES256_PUBLIC_KEY), TokenBackend("ES384", ES256_PRIVATE_KEY, ES256_PUBLIC_KEY), TokenBackend("ES512", ES256_PRIVATE_KEY, ES256_PUBLIC_KEY), ) def test_init(self): # Should reject unknown algorithms with self.assertRaises(TokenBackendError): TokenBackend("oienarst oieanrsto i", "not_secret") TokenBackend("HS256", "not_secret") @patch.object(algorithms, "has_crypto", new=False) def test_init_fails_for_rs_algorithms_when_crypto_not_installed(self): for algo in ("RS256", "RS384", "RS512", "ES256"): with self.assertRaisesRegex( TokenBackendError, f"You must have cryptography installed to use {algo}.", ): TokenBackend(algo, "not_secret") def test_jwk_client_not_available(self): from rest_framework_simplejwt import backends def myimport(name, globals=None, locals=None, fromlist=(), level=0): if name == "jwt" and fromlist == ("PyJWKClient", "PyJWKClientError"): raise ImportError return self.realimport(name, globals, locals, fromlist, level) builtins.__import__ = myimport # Reload backends, mock jwk client is not available reload(backends) self.assertEqual(backends.JWK_CLIENT_AVAILABLE, False) self.assertEqual(backends.TokenBackend("HS256").jwks_client, None) builtins.__import__ = self.realimport @patch("jwt.encode", mock.Mock(return_value=b"test")) def test_token_encode_should_return_str_for_old_PyJWT(self): self.assertIsInstance(TokenBackend("HS256").encode({}), str) def test_encode_hmac(self): # Should return a JSON web token for the given payload payload = {"exp": make_utc(datetime(year=2000, month=1, day=1))} hmac_token = self.hmac_token_backend.encode(payload) # Token could be one of two depending on header dict ordering self.assertIn( hmac_token, ( "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjk0NjY4NDgwMH0.NHpdD2X8ub4SE_MZLBedWa57FCpntGaN_r6f8kNKdUs", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjk0NjY4NDgwMH0.jvxQgXCSDToR8uKoRJcMT-LmMJJn2-NM76nfSR2FOgs", ), ) def test_encode_rsa(self): # Should return a JSON web token for the given payload payload = {"exp": make_utc(datetime(year=2000, month=1, day=1))} rsa_token = self.rsa_token_backend.encode(payload) # Token could be one of two depending on header dict ordering self.assertIn( rsa_token, ( "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJleHAiOjk0NjY4NDgwMH0.cuE6ocmdxVHXVrGufzn-_ZbXDV475TPPb5jtSacvJsnR3s3tLIm9yR7MF4vGcCAUGJn2hU_JgSOhs9sxntPPVjdwvC3-sxAwfUQ5AgUCEAF5XC7wTvGhmvufzhAgEG_DNsactCh79P8xRnc0iugtlGNyFp_YK582-ZrlfQEp-7C0L9BNG_JCS2J9DsGR7ojO2xGFkFfzezKRkrVTJMPLwpl0JAiZ0iqbQE-Tex7redCrGI388_mgh52GLsNlSIvW2gQMqCVMYndMuYx32Pd5tuToZmLUQ2PJ9RyAZ4fOMApTzoshItg4lGqtnt9CDYzypHULJZohJIPcxFVZZfHxhw", "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjk0NjY4NDgwMH0.pzHTOaVvKJMMkSqksGh-NdeEvQy8Thre3hBM3smUW5Sohtg77KnHpaUYjq30DyRmYQRmPSjEVprh1Yvic_-OeAXPW8WVsF-r4YdJuxWUpuZbIPwJ9E-cMfTZkDkOl18z1zOdlsLtsP2kXyAlptyy9QQsM7AxoqM6cyXoQ5TI0geWccgoahTy3cBtA6pmjm7H0nfeDGqpqYQBhtaFmRuIWn-_XtdN9C6NVmRCcZwyjH-rP3oEm6wtuKJEN25sVWlZm8YRQ-rj7A7SNqBB5tFK2anM_iv4rmBlIEkmr_f2s_WqMxn2EWUSNeqbqiwabR6CZUyJtKx1cPG0B2PqOTcZsg", ), ) def test_encode_aud_iss(self): # Should return a JSON web token for the given payload original_payload = {"exp": make_utc(datetime(year=2000, month=1, day=1))} payload = original_payload.copy() rsa_token = self.aud_iss_token_backend.encode(payload) # Assert that payload has not been mutated by the encode() function self.assertEqual(payload, original_payload) # Token could be one of 12 depending on header dict ordering self.assertIn( rsa_token, ( "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJleHAiOjk0NjY4NDgwMCwiYXVkIjoib3BlbmlkLWNsaWVudC1pZCIsImlzcyI6Imh0dHBzOi8vd3d3Lm15b2lkY3Byb3ZpZGVyLmNvbSJ9.kSz7KyUZgpKaeQHYSQlhsE-UFLG2zhBiJ2MFCIvhstA4lSIKj3U1fdP1OhEDg7X66EquRRIZrby6M7RncqCdsjRwKrEIaL74KgC4s5PDXa_HC6dtpi2GhXqaLz8YxfCPaNGZ_9q9rs4Z4O6WpwBLNmMQrTxNno9p0uT93Z2yKj5hGih8a9C_CSf_rKtsHW9AJShWGoKpR6qQFKVNP1GAwQOQ6IeEvZenq_LSEywnrfiWp4Y5UF7xi42wWx7_YPQtM9_Bp5sB-DbrKg_8t0zSc-OHeVDgH0TKqygGEea09W0QkmJcROkaEbxt2LxJg9OuSdXgudVytV8ewpgNtWNE4g", "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJleHAiOjk0NjY4NDgwMCwiaXNzIjoiaHR0cHM6Ly93d3cubXlvaWRjcHJvdmlkZXIuY29tIiwiYXVkIjoib3BlbmlkLWNsaWVudC1pZCJ9.l-sJR5VKGKNrEn5W8sfO4tEpPq4oQ-Fm5ttQyqUkF6FRJHmCfS1TZIUSXieDLHmarnb4hdIGLr5y-EAbykiqYaTn8d25oT2_zIPlCYHt0DxxeuOliGad5l3AXbWee0qPoZL7YCV8FaSdv2EjtMDOEiJBG5yTkaqZlRmSkbfqu1_y2DRErv3X5LpfEHuKoum4jv5YpoCS6wAWDaWJ9cXMPQaGc4gXg4cuSQxb_EjiQ3QYyztHhG37gOu1J-r_rudaiiIk_VZQdYNfCcirp8isS0z2dcNij_0bELp_oOaipsF7uwzc6WfNGR7xP50X1a_K6EBZzVs0eXFxvl9b3C_d8A", "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJvcGVuaWQtY2xpZW50LWlkIiwiZXhwIjo5NDY2ODQ4MDAsImlzcyI6Imh0dHBzOi8vd3d3Lm15b2lkY3Byb3ZpZGVyLmNvbSJ9.aTwQEIxSzhI5fN4ffQMzZ6h61Ur-Gzh_gPkgOyyWvMX890Z18tC2RisEjXeL5xDGKe2XiEAVtuJa9CjXB9eJoCxNN1k05C-ph82cco-0m_TbMbs0d1MFnfC9ESr4JKynP_Klxi8bi0iZMazduT15pH4UhRkEGsnp8rOKtlt_8_8UOGBJAzG34161lM4JbZqrZDit1DvQdGxaC0lmMgosKg3NDMECfkPe3pGLJ5F_su5yhQk0xyKNCjYyE2FNlilWoDV2KkGiCWdsFOgRMAJwHZ-cdgPg8Vyh2WthBNblsbRVfDrGtfPX0VuW5B0RhBhvI5Iut34P9kkxKRFo3NaiEg", "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJvcGVuaWQtY2xpZW50LWlkIiwiaXNzIjoiaHR0cHM6Ly93d3cubXlvaWRjcHJvdmlkZXIuY29tIiwiZXhwIjo5NDY2ODQ4MDB9.w46s7u28LgsnmK6K_5O15q1SFkKeRgkkplFLi5idq1z7qJjXUi45qpXIyQw3W8a0k1fwa22WB_0XC1MTo22OK3Z0aGNCI2ZCBxvZGOAc1WcCUae44a9LckPHp80q0Hs03NvjsuRVLGXRwDVHrYxuGnFxQSEMbZ650-MQkfVFIXVzMOOAn5Yl4ntjigLcw8iPEqJPnDLdFUSnObZjRzK1M6mJf0-125pqcFsCJaa49rjdbTtnN-VuGnKmv9wV1GwevRQPWjx2vinETURVO9IyZCDtdaLJkvL7Z5IpToK5jrZPc1UWAR0VR8WeWfussFoHzJF86LxVxnqIeXnqOhq5SQ", "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL3d3dy5teW9pZGNwcm92aWRlci5jb20iLCJhdWQiOiJvcGVuaWQtY2xpZW50LWlkIiwiZXhwIjo5NDY2ODQ4MDB9.Np_SJYye14vz0cvALvfYNqZXvXMD_gY6kIaxA458kbeu6veC_Ds45uWgjJFhTSYFAFWd3TB6M7qZbWgiO0ycION2-B9Yfgaf82WzNtPfgDhu51w1cbLnvuOSRvgX69Q6Z2i1SByewKaSDw25BaMv9Ty4DBdoCbG62qELnNKjDSQvuHlz8cRJv2I6xJBeOYgZV-YN8Zmxsles44a57Vvcj-DjVouHj5m4LperIxb9islNUQBPRTbvw1d_tR8O8ny0mQqbsWL7e2J-wfwdduVf1kVCPePkhHMM6GLhPIrSoTgMzZuRYLBJ61yphuDK98zTknNBM-Jtn5cMyBwP9JBJvA", "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL3d3dy5teW9pZGNwcm92aWRlci5jb20iLCJleHAiOjk0NjY4NDgwMCwiYXVkIjoib3BlbmlkLWNsaWVudC1pZCJ9.KJcWZtEluPrkRbYj2i_QmdWpZqGZt63Q8nO4QAJ4B4418ZfmgB6A54_vUmWd3Xc18DYgReLoNPlaOuRXtR7rzlMk0-ADjV0bsca5NwTNAV2F-gR9Xsr9iFlcPMNAYf4CAs85gg7deMIxlbGTAaoft__58ah2_vdd8o_nem1PdzsPC198AYtcwnIV206qpeCNR8S_ZTU46OaHwCoySVRx9E7tNG13YSCmGvBaEqgQHKH82qLXo0KivFrjGmGP0xePFG1B8HCZl-LH1euXGGCp6S48q-tmepX5GJwvzaZNBam4pfxQ0GIHa7z11e7sEN-196iDPCK8NzDcXFwHOAnyaA", "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjk0NjY4NDgwMCwiYXVkIjoib3BlbmlkLWNsaWVudC1pZCIsImlzcyI6Imh0dHBzOi8vd3d3Lm15b2lkY3Byb3ZpZGVyLmNvbSJ9.MfhVcFN-9Rd0j11CLtxopzREKdyJH1loSpD4ibjP6Aco4-iM5C99B6gliPgOldtuevhneXV2I7NGhmZFULaYhulcLrAgKe3Gj_TK-sHvwb62e14ArugmK_FAhN7UqbX8hU9wP42LaWXqA7ps4kkJSx-sfgHqMzCKewlAZWwyZBoFgWEgoheKZ7ILkSGf0jzBZlS_1R0jFRSrlYD9rI1S4Px-HllS0t32wRCSbzkp6aVMRs46S0ePrN1mK3spsuQXtYhE2913ZC7p2KwyTGfC2FOOeJdRJknh6kI3Z7pTcsjN2jnQN3o8vPEkN3wl7MbAgAsHcUV45pvyxn4SNBmTMQ", "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjk0NjY4NDgwMCwiaXNzIjoiaHR0cHM6Ly93d3cubXlvaWRjcHJvdmlkZXIuY29tIiwiYXVkIjoib3BlbmlkLWNsaWVudC1pZCJ9.3NjgS14SGFyJ6cix2XJZFPlcyeSu4LSduEMUIH0grJuCljbhalyoib5s4JnBaK4slKrQv1WHlhnKB737hX1FF7_EwQM3toCf--DBjrIuq5cYK3rzcn71JDe_op3CvClwpVyxd2vQZtQfP_tWqN6cNTuWF8ZQ0rJGug6Zb-NeE5h68YK_9tXLZC_i5anyjjAVONOc3Nd-TeIUBaLQKQXOddw0gcTcA7vg3uS0gXTEDq-_ZkF-v9bn1ua4_lgRPbuaYvrBFbXSCEdvNORPfPz4zfL3XU09q0gmnmXC9nxjUFVX4BjkP_YiCCO42sqUKY4y7STTB_IkK_04e2wntonVZA", "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3d3dy5teW9pZGNwcm92aWRlci5jb20iLCJleHAiOjk0NjY4NDgwMCwiYXVkIjoib3BlbmlkLWNsaWVudC1pZCJ9.b4pdohov81oqzLyCIp4y7e4VYz7LSez7bH0t1o0Zwzau1uXPYXcasT9lxxNMEEiZwHIovPLyWQ6XvF0bMWTk9vc4PyIpkLqsLBJPsuQ-wYUOD04fECmqUX_JaINqm2pPbohTcOQwl0xsE1UMIKTFBZDL1hEXGEMdW9lrPcXilhbC1ikyMpzsmVh55Q_wL2GqydssnOOcDQTqEkWoKvELJJhBcE-YuQkUp8jEVhF3VZ4jEZkzCErTlyXcfe1qXZHkWtw2QNo9s_SfLuRy_fACOo8XE9pHBoE7rqiSm-FmISgiLO1Jj3Pqq-abjN4SnAbU7PZWcV3fUoO1eYLGORmAcw", "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3d3dy5teW9pZGNwcm92aWRlci5jb20iLCJhdWQiOiJvcGVuaWQtY2xpZW50LWlkIiwiZXhwIjo5NDY2ODQ4MDB9.yDGMBeee4hj8yDtEvVtIsS4tnkPjDMQADTkNh74wtb3oYPgQNqMRWKngXiwjvW2FmnsCUue2cFzLgTbpqlDq0QKcBP0i_UwBiXk9m2wLo0WRFtgw2zNHYSsowu26sFoEjKLgpPZzKrPlU4pnxqa8u3yqg8vIcSTlpX8t3uDqNqhUKP6x-w6wb25h67XDmnORiMwhaOZE_Gs9-H6uWnKdguTIlU1Tj4CjUEnZgZN7dJORiDnO_vHiAyL5yvRjhp5YK0Pq-TtCj5kWoJsjQiKc4laIcgofAKoq_b62Psns8MhxzAxwM7i0rbQZXXYB0VKMUho88uHlpbSWCZxu415lWw", "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJvcGVuaWQtY2xpZW50LWlkIiwiaXNzIjoiaHR0cHM6Ly93d3cubXlvaWRjcHJvdmlkZXIuY29tIiwiZXhwIjo5NDY2ODQ4MDB9.BHSCjFeXS6B7KFJi1LpQMEd3ib4Bp9FY3WcB-v7dtP3Ay0SxQZz_gxIbi-tYiNCBQIlfKcfq6vELOjE1WJ5zxPDQM8uV0Pjl41hqYBu3qFv4649a-o2Cd-MaSPUSUogPxzTh2Bk4IdM3sG1Zbd_At4DR_DQwWJDuChA8duA5yG2XPkZr0YF1ZJ326O_jEowvCJiZpzOpH9QsLVPbiX49jtWTwqQGhvpKEj3ztTLFo8VHO-p8bhOGEph2F73F6-GB0XqiWk2Dm1yKAunJCMsM4qXooWfaX6gj-WFhPI9kEXNFfGmPal5i1gb17YoeinbdV2kjN42oxast2Iaa3CMldw", "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJvcGVuaWQtY2xpZW50LWlkIiwiZXhwIjo5NDY2ODQ4MDAsImlzcyI6Imh0dHBzOi8vd3d3Lm15b2lkY3Byb3ZpZGVyLmNvbSJ9.s6sElpfKL8WHWfbD_Kbwiy_ip4O082V8ElZqwugvDpS-7yQ3FTvQ3WXqtVAJc-fBZe4ZsBnrXUWwZV0Nhoe6iWKjEjTPjonQWbWL_WUJmIC2HVz18AOISnqReV2rcuLSHQ2ckhsyktlE9K1Rfj-Hi6f3HzzzePEgTsL2ZdBH6GrcmJVDFKqLLrkvOHShoPp7rcwuFBr0J_S1oqYac5O0B-u0OVnxBXTwij0ThrTGMgVCp2rn6Hk0NvtF6CE49Eu4XP8Ue-APT8l5_SjqX9GcrjkJp8Gif_oyBheL-zRg_v-cU60X6qY9wVolO8WodVPSnlE02XyYhLVxvfK-w5129A", ), ) def test_decode_with_no_expiry(self): for backend in self.backends: with self.subTest("Test decode with no expiry for f{backend.algorithm}"): no_exp_token = jwt.encode( self.payload, backend.signing_key, algorithm=backend.algorithm ) backend.decode(no_exp_token) def test_decode_with_no_expiry_no_verify(self): for backend in self.backends: with self.subTest( "Test decode with no expiry and no verify for f{backend.algorithm}" ): no_exp_token = jwt.encode( self.payload, backend.signing_key, algorithm=backend.algorithm ) self.assertEqual( backend.decode(no_exp_token, verify=False), self.payload, ) def test_decode_with_expiry(self): self.payload["exp"] = aware_utcnow() - timedelta(seconds=1) for backend in self.backends: with self.subTest("Test decode with expiry for f{backend.algorithm}"): expired_token = jwt.encode( self.payload, backend.signing_key, algorithm=backend.algorithm ) with self.assertRaises(TokenBackendExpiredToken): backend.decode(expired_token) def test_decode_with_invalid_sig(self): self.payload["exp"] = aware_utcnow() - timedelta(seconds=1) for backend in self.backends: with self.subTest(f"Test decode with invalid sig for {backend.algorithm}"): payload = self.payload.copy() payload["exp"] = aware_utcnow() + timedelta(days=1) token_1 = jwt.encode( payload, backend.signing_key, algorithm=backend.algorithm ) payload["foo"] = "baz" token_2 = jwt.encode( payload, backend.signing_key, algorithm=backend.algorithm ) if IS_OLD_JWT: token_1 = token_1.decode("utf-8") token_2 = token_2.decode("utf-8") token_2_payload = token_2.rsplit(".", 1)[0] token_1_sig = token_1.rsplit(".", 1)[-1] invalid_token = token_2_payload + "." + token_1_sig with self.assertRaises(TokenBackendError): backend.decode(invalid_token) def test_decode_with_invalid_sig_no_verify(self): self.payload["exp"] = aware_utcnow() + timedelta(days=1) for backend in self.backends: with self.subTest("Test decode with invalid sig for f{backend.algorithm}"): payload = self.payload.copy() token_1 = jwt.encode( payload, backend.signing_key, algorithm=backend.algorithm ) payload["foo"] = "baz" token_2 = jwt.encode( payload, backend.signing_key, algorithm=backend.algorithm ) if IS_OLD_JWT: token_1 = token_1.decode("utf-8") token_2 = token_2.decode("utf-8") else: # Payload copied payload["exp"] = datetime_to_epoch(payload["exp"]) token_2_payload = token_2.rsplit(".", 1)[0] token_1_sig = token_1.rsplit(".", 1)[-1] invalid_token = token_2_payload + "." + token_1_sig self.assertEqual( backend.decode(invalid_token, verify=False), payload, ) def test_decode_success(self): self.payload["exp"] = aware_utcnow() + timedelta(days=1) self.payload["foo"] = "baz" for backend in self.backends: with self.subTest("Test decode success for f{backend.algorithm}"): token = jwt.encode( self.payload, backend.signing_key, algorithm=backend.algorithm ) if IS_OLD_JWT: token = token.decode("utf-8") payload = self.payload else: # Payload copied payload = self.payload.copy() payload["exp"] = datetime_to_epoch(self.payload["exp"]) self.assertEqual(backend.decode(token), payload) def test_decode_aud_iss_success(self): self.payload["exp"] = aware_utcnow() + timedelta(days=1) self.payload["foo"] = "baz" self.payload["aud"] = AUDIENCE self.payload["iss"] = ISSUER token = jwt.encode(self.payload, PRIVATE_KEY, algorithm="RS256") if IS_OLD_JWT: token = token.decode("utf-8") else: # Payload copied self.payload["exp"] = datetime_to_epoch(self.payload["exp"]) self.assertEqual(self.aud_iss_token_backend.decode(token), self.payload) @pytest.mark.skipif( not JWK_CLIENT_AVAILABLE, reason="PyJWT 1.7.1 doesn't have JWK client", ) def test_decode_rsa_aud_iss_jwk_success(self): self.payload["exp"] = aware_utcnow() + timedelta(days=1) self.payload["foo"] = "baz" self.payload["aud"] = AUDIENCE self.payload["iss"] = ISSUER token = jwt.encode( self.payload, PRIVATE_KEY_2, algorithm="RS256", headers={"kid": "230498151c214b788dd97f22b85410a5"}, ) # Payload copied self.payload["exp"] = datetime_to_epoch(self.payload["exp"]) with patch("rest_framework_simplejwt.backends.PyJWKClient") as mock_jwk_module: mock_jwk_client = mock.MagicMock() mock_signing_key = mock.MagicMock() mock_jwk_module.return_value = mock_jwk_client mock_jwk_client.get_signing_key_from_jwt.return_value = mock_signing_key type(mock_signing_key).key = mock.PropertyMock(return_value=PUBLIC_KEY_2) # Note the PRIV,PUB care is intentially the original pairing jwk_token_backend = TokenBackend( "RS256", PRIVATE_KEY, PUBLIC_KEY, AUDIENCE, ISSUER, JWK_URL ) self.assertEqual(jwk_token_backend.decode(token), self.payload) @pytest.mark.skipif( not JWK_CLIENT_AVAILABLE, reason="PyJWT 1.7.1 doesn't have JWK client", ) def test_decode_jwk_missing_key_raises_tokenbackenderror(self): self.payload["exp"] = aware_utcnow() + timedelta(days=1) self.payload["foo"] = "baz" self.payload["aud"] = AUDIENCE self.payload["iss"] = ISSUER token = jwt.encode( self.payload, PRIVATE_KEY_2, algorithm="RS256", headers={"kid": "230498151c214b788dd97f22b85410a5"}, ) with patch("rest_framework_simplejwt.backends.PyJWKClient") as mock_jwk_module: mock_jwk_client = mock.MagicMock() mock_jwk_module.return_value = mock_jwk_client mock_jwk_client.get_signing_key_from_jwt.side_effect = jwt.PyJWKClientError( "Unable to find a signing key that matches" ) # Note the PRIV,PUB care is intentially the original pairing jwk_token_backend = TokenBackend( "RS256", PRIVATE_KEY, PUBLIC_KEY, AUDIENCE, ISSUER, JWK_URL ) with self.assertRaisesRegex(TokenBackendError, "Token is invalid"): jwk_token_backend.decode(token) def test_decode_when_algorithm_not_available(self): token = jwt.encode(self.payload, PRIVATE_KEY, algorithm="RS256") if IS_OLD_JWT: token = token.decode("utf-8") pyjwt_without_rsa = PyJWS() pyjwt_without_rsa.unregister_algorithm("RS256") def _decode(jwt, key, algorithms, options, audience, issuer, leeway): return pyjwt_without_rsa.decode(jwt, key, algorithms, options) with patch.object(jwt, "decode", new=_decode): with self.assertRaisesRegex( TokenBackendError, "Invalid algorithm specified" ): self.rsa_token_backend.decode(token) def test_decode_when_token_algorithm_does_not_match(self): token = jwt.encode(self.payload, PRIVATE_KEY, algorithm="RS256") if IS_OLD_JWT: token = token.decode("utf-8") with self.assertRaisesRegex(TokenBackendError, "Invalid algorithm specified"): self.hmac_token_backend.decode(token) def test_decode_leeway_hmac_fail(self): self.payload["exp"] = datetime_to_epoch( aware_utcnow() - timedelta(seconds=LEEWAY * 2) ) expired_token = jwt.encode(self.payload, SECRET, algorithm="HS256") with self.assertRaises(TokenBackendError): self.hmac_leeway_token_backend.decode(expired_token) def test_decode_leeway_hmac_success(self): self.payload["exp"] = datetime_to_epoch( aware_utcnow() - timedelta(seconds=LEEWAY / 2) ) expired_token = jwt.encode(self.payload, SECRET, algorithm="HS256") self.assertEqual( self.hmac_leeway_token_backend.decode(expired_token), self.payload, ) def test_custom_JSONEncoder(self): backend = TokenBackend("HS256", SECRET, json_encoder=UUIDJSONEncoder) unique = uuid.uuid4() self.payload["uuid"] = unique token = backend.encode(self.payload) decoded = backend.decode(token) self.assertEqual(decoded["uuid"], str(unique)) djangorestframework-simplejwt-5.5.0/tests/test_init.py000066400000000000000000000011071475766445300233550ustar00rootroot00000000000000from importlib import reload from importlib.metadata import PackageNotFoundError from unittest.mock import Mock, patch from django.test import SimpleTestCase class TestInit(SimpleTestCase): def test_package_is_not_installed(self): with patch( "importlib.metadata.version", Mock(side_effect=PackageNotFoundError) ): import rest_framework_simplejwt.__init__ self.assertEqual(rest_framework_simplejwt.__init__.__version__, None) # Restore origin package without mock reload(rest_framework_simplejwt.__init__) djangorestframework-simplejwt-5.5.0/tests/test_integration.py000066400000000000000000000075351475766445300247500ustar00rootroot00000000000000from datetime import timedelta from django.contrib.auth import get_user_model from django.urls import reverse from rest_framework.status import HTTP_200_OK, HTTP_401_UNAUTHORIZED from rest_framework_simplejwt.settings import api_settings from rest_framework_simplejwt.tokens import AccessToken from .utils import APIViewTestCase, override_api_settings User = get_user_model() class TestTestView(APIViewTestCase): view_name = "test_view" def setUp(self): self.username = "test_user" self.password = "test_password" self.user = User.objects.create_user( username=self.username, password=self.password, ) def test_no_authorization(self): res = self.view_get() self.assertEqual(res.status_code, HTTP_401_UNAUTHORIZED) self.assertIn("credentials were not provided", res.data["detail"]) def test_wrong_auth_type(self): res = self.client.post( reverse("token_obtain_sliding"), data={ User.USERNAME_FIELD: self.username, "password": self.password, }, ) token = res.data["token"] self.authenticate_with_token("Wrong", token) res = self.view_get() self.assertEqual(res.status_code, HTTP_401_UNAUTHORIZED) self.assertIn("credentials were not provided", res.data["detail"]) @override_api_settings( AUTH_TOKEN_CLASSES=("rest_framework_simplejwt.tokens.AccessToken",), ) def test_expired_token(self): old_lifetime = AccessToken.lifetime AccessToken.lifetime = timedelta(seconds=0) try: res = self.client.post( reverse("token_obtain_pair"), data={ User.USERNAME_FIELD: self.username, "password": self.password, }, ) finally: AccessToken.lifetime = old_lifetime access = res.data["access"] self.authenticate_with_token(api_settings.AUTH_HEADER_TYPES[0], access) res = self.view_get() self.assertEqual(res.status_code, HTTP_401_UNAUTHORIZED) self.assertEqual("token_not_valid", res.data["code"]) @override_api_settings( AUTH_TOKEN_CLASSES=("rest_framework_simplejwt.tokens.SlidingToken",), ) def test_user_can_get_sliding_token_and_use_it(self): res = self.client.post( reverse("token_obtain_sliding"), data={ User.USERNAME_FIELD: self.username, "password": self.password, }, ) token = res.data["token"] self.authenticate_with_token(api_settings.AUTH_HEADER_TYPES[0], token) res = self.view_get() self.assertEqual(res.status_code, HTTP_200_OK) self.assertEqual(res.data["foo"], "bar") @override_api_settings( AUTH_TOKEN_CLASSES=("rest_framework_simplejwt.tokens.AccessToken",), ) def test_user_can_get_access_and_refresh_tokens_and_use_them(self): res = self.client.post( reverse("token_obtain_pair"), data={ User.USERNAME_FIELD: self.username, "password": self.password, }, ) access = res.data["access"] refresh = res.data["refresh"] self.authenticate_with_token(api_settings.AUTH_HEADER_TYPES[0], access) res = self.view_get() self.assertEqual(res.status_code, HTTP_200_OK) self.assertEqual(res.data["foo"], "bar") res = self.client.post( reverse("token_refresh"), data={"refresh": refresh}, ) access = res.data["access"] self.authenticate_with_token(api_settings.AUTH_HEADER_TYPES[0], access) res = self.view_get() self.assertEqual(res.status_code, HTTP_200_OK) self.assertEqual(res.data["foo"], "bar") djangorestframework-simplejwt-5.5.0/tests/test_models.py000066400000000000000000000073671475766445300237130ustar00rootroot00000000000000from importlib import reload from unittest.mock import patch from django.test import TestCase from rest_framework_simplejwt.models import TokenUser from rest_framework_simplejwt.settings import api_settings AuthToken = api_settings.AUTH_TOKEN_CLASSES[0] class TestTokenUser(TestCase): def setUp(self): self.token = AuthToken() self.token[api_settings.USER_ID_CLAIM] = 42 self.token["username"] = "deep-thought" self.token["some_other_stuff"] = "arstarst" self.user = TokenUser(self.token) def test_type_checking(self): from rest_framework_simplejwt import models with patch("typing.TYPE_CHECKING", True): # Reload models, mock type checking reload(models) self.assertEqual(models.TYPE_CHECKING, True) # Restore origin module without mock reload(models) def test_username(self): self.assertEqual(self.user.username, "deep-thought") def test_is_active(self): self.assertTrue(self.user.is_active) def test_str(self): self.assertEqual(str(self.user), "TokenUser 42") def test_id(self): self.assertEqual(self.user.id, 42) def test_pk(self): self.assertEqual(self.user.pk, 42) def test_is_staff(self): payload = {api_settings.USER_ID_CLAIM: 42} user = TokenUser(payload) self.assertFalse(user.is_staff) payload["is_staff"] = True user = TokenUser(payload) self.assertTrue(user.is_staff) def test_is_superuser(self): payload = {api_settings.USER_ID_CLAIM: 42} user = TokenUser(payload) self.assertFalse(user.is_superuser) payload["is_superuser"] = True user = TokenUser(payload) self.assertTrue(user.is_superuser) def test_eq(self): user1 = TokenUser({api_settings.USER_ID_CLAIM: 1}) user2 = TokenUser({api_settings.USER_ID_CLAIM: 2}) user3 = TokenUser({api_settings.USER_ID_CLAIM: 1}) self.assertNotEqual(user1, user2) self.assertEqual(user1, user3) def test_eq_not_implemented(self): user1 = TokenUser({api_settings.USER_ID_CLAIM: 1}) user2 = "user2" self.assertFalse(user1 == user2) def test_hash(self): self.assertEqual(hash(self.user), hash(self.user.id)) def test_not_implemented(self): with self.assertRaises(NotImplementedError): self.user.save() with self.assertRaises(NotImplementedError): self.user.delete() with self.assertRaises(NotImplementedError): self.user.set_password("arst") with self.assertRaises(NotImplementedError): self.user.check_password("arst") def test_groups(self): self.assertFalse(self.user.groups.exists()) def test_user_permissions(self): self.assertFalse(self.user.user_permissions.exists()) def test_get_group_permissions(self): self.assertEqual(len(self.user.get_group_permissions()), 0) def test_get_all_permissions(self): self.assertEqual(len(self.user.get_all_permissions()), 0) def test_has_perm(self): self.assertFalse(self.user.has_perm("test_perm")) def test_has_perms(self): self.assertFalse(self.user.has_perms(["test_perm"])) def test_has_module_perms(self): self.assertFalse(self.user.has_module_perms("test_module")) def test_is_anonymous(self): self.assertFalse(self.user.is_anonymous) def test_is_authenticated(self): self.assertTrue(self.user.is_authenticated) def test_get_username(self): self.assertEqual(self.user.get_username(), "deep-thought") def test_get_custom_claims_through_backup_getattr(self): self.assertEqual(self.user.some_other_stuff, "arstarst") djangorestframework-simplejwt-5.5.0/tests/test_serializers.py000066400000000000000000000476341475766445300247650ustar00rootroot00000000000000from datetime import timedelta from importlib import reload from unittest.mock import MagicMock, patch from django.conf import settings from django.contrib.auth import get_user_model from django.core import exceptions as django_exceptions from django.test import TestCase, override_settings from rest_framework import exceptions as drf_exceptions from rest_framework_simplejwt.exceptions import TokenError from rest_framework_simplejwt.serializers import ( TokenBlacklistSerializer, TokenObtainPairSerializer, TokenObtainSerializer, TokenObtainSlidingSerializer, TokenRefreshSerializer, TokenRefreshSlidingSerializer, TokenVerifySerializer, ) from rest_framework_simplejwt.settings import api_settings from rest_framework_simplejwt.token_blacklist.models import ( BlacklistedToken, OutstandingToken, ) from rest_framework_simplejwt.tokens import AccessToken, RefreshToken, SlidingToken from rest_framework_simplejwt.utils import ( aware_utcnow, datetime_from_epoch, datetime_to_epoch, ) from .utils import override_api_settings User = get_user_model() class TestTokenObtainSerializer(TestCase): def setUp(self): self.username = "test_user" self.password = "test_password" self.user = User.objects.create_user( username=self.username, password=self.password, ) def test_it_should_not_validate_if_any_fields_missing(self): s = TokenObtainSerializer(data={}) self.assertFalse(s.is_valid()) self.assertIn(s.username_field, s.errors) self.assertIn("password", s.errors) s = TokenObtainSerializer( data={ TokenObtainSerializer.username_field: "oieanrst", } ) self.assertFalse(s.is_valid()) self.assertIn("password", s.errors) s = TokenObtainSerializer( data={ "password": "oieanrst", } ) self.assertFalse(s.is_valid()) self.assertIn(s.username_field, s.errors) def test_it_should_not_validate_if_user_not_found(self): s = TokenObtainSerializer( context=MagicMock(), data={ TokenObtainSerializer.username_field: "missing", "password": "pass", }, ) with self.assertRaises(drf_exceptions.AuthenticationFailed): s.is_valid() def test_it_should_pass_validate_if_request_not_in_context(self): s = TokenObtainSerializer( context={}, data={ "username": self.username, "password": self.password, }, ) s.is_valid() def test_it_should_raise_if_user_not_active(self): self.user.is_active = False self.user.save() s = TokenObtainSerializer( context=MagicMock(), data={ TokenObtainSerializer.username_field: self.username, "password": self.password, }, ) with self.assertRaises(drf_exceptions.AuthenticationFailed): s.is_valid() @override_settings( AUTHENTICATION_BACKENDS=[ "django.contrib.auth.backends.AllowAllUsersModelBackend", "django.contrib.auth.backends.ModelBackend", ] ) @override_api_settings( CHECK_USER_IS_ACTIVE=False, ) def test_it_should_validate_if_user_inactive_but_rule_allows(self): self.user.is_active = False self.user.save() s = TokenObtainSerializer( context=MagicMock(), data={ TokenObtainSerializer.username_field: self.username, "password": self.password, }, ) self.assertTrue(s.is_valid()) class TestTokenObtainSlidingSerializer(TestCase): def setUp(self): self.username = "test_user" self.password = "test_password" self.user = User.objects.create_user( username=self.username, password=self.password, ) def test_it_should_produce_a_json_web_token_when_valid(self): s = TokenObtainSlidingSerializer( context=MagicMock(), data={ TokenObtainSlidingSerializer.username_field: self.username, "password": self.password, }, ) self.assertTrue(s.is_valid()) self.assertIn("token", s.validated_data) # Expecting token type claim to be correct for sliding token. If this # is the case, instantiating a `SlidingToken` instance with encoded # token should not raise an exception. SlidingToken(s.validated_data["token"]) class TestTokenObtainPairSerializer(TestCase): def setUp(self): self.username = "test_user" self.password = "test_password" self.user = User.objects.create_user( username=self.username, password=self.password, ) def test_it_should_produce_a_json_web_token_when_valid(self): s = TokenObtainPairSerializer( context=MagicMock(), data={ TokenObtainPairSerializer.username_field: self.username, "password": self.password, }, ) self.assertTrue(s.is_valid()) self.assertIn("access", s.validated_data) self.assertIn("refresh", s.validated_data) # Expecting token type claim to be correct for both tokens. If this is # the case, instantiating appropriate token subclass instances with # encoded tokens should not raise an exception. AccessToken(s.validated_data["access"]) RefreshToken(s.validated_data["refresh"]) class TestTokenRefreshSlidingSerializer(TestCase): def test_it_should_not_validate_if_token_invalid(self): token = SlidingToken() del token["exp"] s = TokenRefreshSlidingSerializer(data={"token": str(token)}) with self.assertRaises(TokenError) as e: s.is_valid() self.assertIn("has no 'exp' claim", e.exception.args[0]) token.set_exp(lifetime=-timedelta(days=1)) s = TokenRefreshSlidingSerializer(data={"token": str(token)}) with self.assertRaises(TokenError) as e: s.is_valid() self.assertIn("expired", e.exception.args[0]) def test_it_should_raise_token_error_if_token_has_no_refresh_exp_claim(self): token = SlidingToken() del token[api_settings.SLIDING_TOKEN_REFRESH_EXP_CLAIM] s = TokenRefreshSlidingSerializer(data={"token": str(token)}) with self.assertRaises(TokenError) as e: s.is_valid() self.assertIn( f"has no '{api_settings.SLIDING_TOKEN_REFRESH_EXP_CLAIM}' claim", e.exception.args[0], ) def test_it_should_raise_token_error_if_token_has_refresh_period_expired(self): token = SlidingToken() token.set_exp( api_settings.SLIDING_TOKEN_REFRESH_EXP_CLAIM, lifetime=-timedelta(days=1) ) s = TokenRefreshSlidingSerializer(data={"token": str(token)}) with self.assertRaises(TokenError) as e: s.is_valid() self.assertIn( "'{}' claim has expired".format( api_settings.SLIDING_TOKEN_REFRESH_EXP_CLAIM ), e.exception.args[0], ) def test_it_should_raise_token_error_if_token_has_wrong_type(self): token = SlidingToken() token[api_settings.TOKEN_TYPE_CLAIM] = "wrong_type" s = TokenRefreshSlidingSerializer(data={"token": str(token)}) with self.assertRaises(TokenError) as e: s.is_valid() self.assertIn("wrong type", e.exception.args[0]) def test_it_should_update_token_exp_claim_if_everything_ok(self): old_token = SlidingToken() lifetime = api_settings.SLIDING_TOKEN_LIFETIME - timedelta(seconds=1) old_exp = old_token.current_time + lifetime old_token.set_exp(lifetime=lifetime) # Serializer validates s = TokenRefreshSlidingSerializer(data={"token": str(old_token)}) self.assertTrue(s.is_valid()) # Expiration claim has moved into future new_token = SlidingToken(s.validated_data["token"]) new_exp = datetime_from_epoch(new_token["exp"]) self.assertTrue(old_exp < new_exp) class TestTokenRefreshSerializer(TestCase): def setUp(self): self.username = "test_user" self.password = "test_password" self.user = User.objects.create_user( username=self.username, password=self.password, ) def test_it_should_raise_error_for_deleted_users(self): refresh = RefreshToken.for_user(self.user) self.user.delete() s = TokenRefreshSerializer(data={"refresh": str(refresh)}) with self.assertRaises(django_exceptions.ObjectDoesNotExist) as e: s.is_valid() self.assertIn("does not exist", str(e.exception)) def test_it_should_raise_error_for_inactive_users(self): refresh = RefreshToken.for_user(self.user) self.user.is_active = False self.user.save() s = TokenRefreshSerializer(data={"refresh": str(refresh)}) with self.assertRaises(drf_exceptions.AuthenticationFailed) as e: s.is_valid() self.assertIn("No active account", e.exception.args[0]) def test_it_should_return_access_token_for_active_users(self): refresh = RefreshToken.for_user(self.user) s = TokenRefreshSerializer(data={"refresh": str(refresh)}) now = aware_utcnow() - api_settings.ACCESS_TOKEN_LIFETIME / 2 with patch("rest_framework_simplejwt.tokens.aware_utcnow") as fake_aware_utcnow: fake_aware_utcnow.return_value = now s.is_valid() access = AccessToken(s.validated_data["access"]) self.assertEqual( access["exp"], datetime_to_epoch(now + api_settings.ACCESS_TOKEN_LIFETIME) ) def test_it_should_raise_token_error_if_token_invalid(self): token = RefreshToken() del token["exp"] s = TokenRefreshSerializer(data={"refresh": str(token)}) with self.assertRaises(TokenError) as e: s.is_valid() self.assertIn("has no 'exp' claim", e.exception.args[0]) token.set_exp(lifetime=-timedelta(days=1)) s = TokenRefreshSerializer(data={"refresh": str(token)}) with self.assertRaises(TokenError) as e: s.is_valid() self.assertIn("expired", e.exception.args[0]) def test_it_should_raise_token_error_if_token_has_wrong_type(self): token = RefreshToken() token[api_settings.TOKEN_TYPE_CLAIM] = "wrong_type" s = TokenRefreshSerializer(data={"refresh": str(token)}) with self.assertRaises(TokenError) as e: s.is_valid() self.assertIn("wrong type", e.exception.args[0]) def test_it_should_return_access_token_if_everything_ok(self): refresh = RefreshToken() refresh["test_claim"] = "arst" # Serializer validates s = TokenRefreshSerializer(data={"refresh": str(refresh)}) now = aware_utcnow() - api_settings.ACCESS_TOKEN_LIFETIME / 2 with patch("rest_framework_simplejwt.tokens.aware_utcnow") as fake_aware_utcnow: fake_aware_utcnow.return_value = now self.assertTrue(s.is_valid()) access = AccessToken(s.validated_data["access"]) self.assertEqual(refresh["test_claim"], access["test_claim"]) self.assertEqual( access["exp"], datetime_to_epoch(now + api_settings.ACCESS_TOKEN_LIFETIME) ) @override_api_settings( ROTATE_REFRESH_TOKENS=True, BLACKLIST_AFTER_ROTATION=False, ) def test_it_should_return_refresh_token_if_tokens_should_be_rotated(self): refresh = RefreshToken() refresh["test_claim"] = "arst" old_jti = refresh["jti"] old_exp = refresh["exp"] # Serializer validates ser = TokenRefreshSerializer(data={"refresh": str(refresh)}) now = aware_utcnow() - api_settings.ACCESS_TOKEN_LIFETIME / 2 with patch("rest_framework_simplejwt.tokens.aware_utcnow") as fake_aware_utcnow: fake_aware_utcnow.return_value = now self.assertTrue(ser.is_valid()) access = AccessToken(ser.validated_data["access"]) new_refresh = RefreshToken(ser.validated_data["refresh"]) self.assertEqual(refresh["test_claim"], access["test_claim"]) self.assertEqual(refresh["test_claim"], new_refresh["test_claim"]) self.assertNotEqual(old_jti, new_refresh["jti"]) self.assertNotEqual(old_exp, new_refresh["exp"]) self.assertEqual( access["exp"], datetime_to_epoch(now + api_settings.ACCESS_TOKEN_LIFETIME) ) self.assertEqual( new_refresh["exp"], datetime_to_epoch(now + api_settings.REFRESH_TOKEN_LIFETIME), ) @override_api_settings( ROTATE_REFRESH_TOKENS=True, BLACKLIST_AFTER_ROTATION=True, ) def test_it_should_blacklist_refresh_token_if_tokens_should_be_rotated_and_blacklisted( self, ): self.assertEqual(OutstandingToken.objects.count(), 0) self.assertEqual(BlacklistedToken.objects.count(), 0) refresh = RefreshToken() refresh["test_claim"] = "arst" old_jti = refresh["jti"] old_exp = refresh["exp"] # Serializer validates ser = TokenRefreshSerializer(data={"refresh": str(refresh)}) now = aware_utcnow() - api_settings.ACCESS_TOKEN_LIFETIME / 2 with patch("rest_framework_simplejwt.tokens.aware_utcnow") as fake_aware_utcnow: fake_aware_utcnow.return_value = now self.assertTrue(ser.is_valid()) access = AccessToken(ser.validated_data["access"]) new_refresh = RefreshToken(ser.validated_data["refresh"]) self.assertEqual(refresh["test_claim"], access["test_claim"]) self.assertEqual(refresh["test_claim"], new_refresh["test_claim"]) self.assertNotEqual(old_jti, new_refresh["jti"]) self.assertNotEqual(old_exp, new_refresh["exp"]) self.assertEqual( access["exp"], datetime_to_epoch(now + api_settings.ACCESS_TOKEN_LIFETIME) ) self.assertEqual( new_refresh["exp"], datetime_to_epoch(now + api_settings.REFRESH_TOKEN_LIFETIME), ) self.assertEqual(OutstandingToken.objects.count(), 2) self.assertEqual(BlacklistedToken.objects.count(), 1) # Assert old refresh token is blacklisted self.assertEqual(BlacklistedToken.objects.first().token.jti, old_jti) @override_api_settings( ROTATE_REFRESH_TOKENS=True, BLACKLIST_AFTER_ROTATION=True, ) def test_blacklist_app_not_installed_should_pass(self): from rest_framework_simplejwt import serializers, tokens # Remove blacklist app new_apps = list(settings.INSTALLED_APPS) new_apps.remove("rest_framework_simplejwt.token_blacklist") with self.settings(INSTALLED_APPS=tuple(new_apps)): # Reload module that blacklist app not installed reload(tokens) reload(serializers) refresh = tokens.RefreshToken() # Serializer validates ser = serializers.TokenRefreshSerializer(data={"refresh": str(refresh)}) ser.validate({"refresh": str(refresh)}) # Restore origin module without mock reload(tokens) reload(serializers) class TestTokenVerifySerializer(TestCase): def test_it_should_raise_token_error_if_token_invalid(self): token = RefreshToken() del token["exp"] s = TokenVerifySerializer(data={"token": str(token)}) with self.assertRaises(TokenError) as e: s.is_valid() self.assertIn("has no 'exp' claim", e.exception.args[0]) token.set_exp(lifetime=-timedelta(days=1)) s = TokenVerifySerializer(data={"token": str(token)}) with self.assertRaises(TokenError) as e: s.is_valid() self.assertIn("expired", e.exception.args[0]) def test_it_should_not_raise_token_error_if_token_has_wrong_type(self): token = RefreshToken() token[api_settings.TOKEN_TYPE_CLAIM] = "wrong_type" s = TokenVerifySerializer(data={"token": str(token)}) self.assertTrue(s.is_valid()) def test_it_should_return_given_token_if_everything_ok(self): refresh = RefreshToken() refresh["test_claim"] = "arst" # Serializer validates s = TokenVerifySerializer(data={"token": str(refresh)}) now = aware_utcnow() - api_settings.ACCESS_TOKEN_LIFETIME / 2 with patch("rest_framework_simplejwt.tokens.aware_utcnow") as fake_aware_utcnow: fake_aware_utcnow.return_value = now self.assertTrue(s.is_valid()) self.assertEqual(len(s.validated_data), 0) class TestTokenBlacklistSerializer(TestCase): def test_it_should_raise_token_error_if_token_invalid(self): token = RefreshToken() del token["exp"] s = TokenBlacklistSerializer(data={"refresh": str(token)}) with self.assertRaises(TokenError) as e: s.is_valid() self.assertIn("has no 'exp' claim", e.exception.args[0]) token.set_exp(lifetime=-timedelta(days=1)) s = TokenBlacklistSerializer(data={"refresh": str(token)}) with self.assertRaises(TokenError) as e: s.is_valid() self.assertIn("expired", e.exception.args[0]) def test_it_should_raise_token_error_if_token_has_wrong_type(self): token = RefreshToken() token[api_settings.TOKEN_TYPE_CLAIM] = "wrong_type" s = TokenBlacklistSerializer(data={"refresh": str(token)}) with self.assertRaises(TokenError) as e: s.is_valid() self.assertIn("wrong type", e.exception.args[0]) def test_it_should_return_nothing_if_everything_ok(self): refresh = RefreshToken() refresh["test_claim"] = "arst" # Serializer validates s = TokenBlacklistSerializer(data={"refresh": str(refresh)}) now = aware_utcnow() - api_settings.ACCESS_TOKEN_LIFETIME / 2 with patch("rest_framework_simplejwt.tokens.aware_utcnow") as fake_aware_utcnow: fake_aware_utcnow.return_value = now self.assertTrue(s.is_valid()) self.assertDictEqual(s.validated_data, {}) def test_it_should_blacklist_refresh_token_if_everything_ok(self): self.assertEqual(OutstandingToken.objects.count(), 0) self.assertEqual(BlacklistedToken.objects.count(), 0) refresh = RefreshToken() refresh["test_claim"] = "arst" old_jti = refresh["jti"] # Serializer validates ser = TokenBlacklistSerializer(data={"refresh": str(refresh)}) now = aware_utcnow() - api_settings.ACCESS_TOKEN_LIFETIME / 2 with patch("rest_framework_simplejwt.tokens.aware_utcnow") as fake_aware_utcnow: fake_aware_utcnow.return_value = now self.assertTrue(ser.is_valid()) self.assertEqual(OutstandingToken.objects.count(), 1) self.assertEqual(BlacklistedToken.objects.count(), 1) # Assert old refresh token is blacklisted self.assertEqual(BlacklistedToken.objects.first().token.jti, old_jti) def test_blacklist_app_not_installed_should_pass(self): from rest_framework_simplejwt import serializers, tokens # Remove blacklist app new_apps = list(settings.INSTALLED_APPS) new_apps.remove("rest_framework_simplejwt.token_blacklist") with self.settings(INSTALLED_APPS=tuple(new_apps)): # Reload module that blacklist app not installed reload(tokens) reload(serializers) refresh = tokens.RefreshToken() # Serializer validates ser = serializers.TokenBlacklistSerializer(data={"refresh": str(refresh)}) ser.validate({"refresh": str(refresh)}) # Restore origin module without mock reload(tokens) reload(serializers) djangorestframework-simplejwt-5.5.0/tests/test_token_blacklist.py000066400000000000000000000310771475766445300255730ustar00rootroot00000000000000from importlib import reload from unittest.mock import patch from django.contrib.auth.models import User from django.core.management import call_command from django.db.models import BigAutoField from django.test import TestCase from django.utils import timezone from rest_framework_simplejwt.exceptions import TokenError from rest_framework_simplejwt.serializers import TokenVerifySerializer from rest_framework_simplejwt.settings import api_settings from rest_framework_simplejwt.token_blacklist.models import ( BlacklistedToken, OutstandingToken, ) from rest_framework_simplejwt.tokens import AccessToken, RefreshToken, SlidingToken from rest_framework_simplejwt.utils import aware_utcnow, datetime_from_epoch from .utils import MigrationTestCase, override_api_settings class TestTokenBlacklist(TestCase): def setUp(self): self.user = User.objects.create( username="test_user", password="test_password", ) def test_token_blacklist_old_django(self): with patch("django.VERSION", (3, 1)): # Import package mock blacklist old django import rest_framework_simplejwt.token_blacklist.__init__ as blacklist self.assertEqual( blacklist.default_app_config, ("rest_framework_simplejwt.token_blacklist.apps.TokenBlacklistConfig"), ) # Restore origin module without mock reload(blacklist) def test_sliding_tokens_are_added_to_outstanding_list(self): token = SlidingToken.for_user(self.user) qs = OutstandingToken.objects.all() outstanding_token = qs.first() self.assertEqual(qs.count(), 1) self.assertEqual(outstanding_token.user, self.user) self.assertEqual(outstanding_token.jti, token["jti"]) self.assertEqual(outstanding_token.token, str(token)) self.assertEqual(outstanding_token.created_at, token.current_time) self.assertEqual( outstanding_token.expires_at, datetime_from_epoch(token["exp"]) ) def test_refresh_tokens_are_added_to_outstanding_list(self): token = RefreshToken.for_user(self.user) qs = OutstandingToken.objects.all() outstanding_token = qs.first() self.assertEqual(qs.count(), 1) self.assertEqual(outstanding_token.user, self.user) self.assertEqual(outstanding_token.jti, token["jti"]) self.assertEqual(outstanding_token.token, str(token)) self.assertEqual(outstanding_token.created_at, token.current_time) self.assertEqual( outstanding_token.expires_at, datetime_from_epoch(token["exp"]) ) def test_access_tokens_are_not_added_to_outstanding_list(self): AccessToken.for_user(self.user) qs = OutstandingToken.objects.all() self.assertFalse(qs.exists()) def test_token_will_not_validate_if_blacklisted(self): token = RefreshToken.for_user(self.user) outstanding_token = OutstandingToken.objects.first() # Should raise no exception RefreshToken(str(token)) # Add token to blacklist BlacklistedToken.objects.create(token=outstanding_token) with self.assertRaises(TokenError) as e: # Should raise exception RefreshToken(str(token)) self.assertIn("blacklisted", e.exception.args[0]) def test_tokens_can_be_manually_blacklisted(self): token = RefreshToken.for_user(self.user) # Should raise no exception RefreshToken(str(token)) self.assertEqual(OutstandingToken.objects.count(), 1) # Add token to blacklist blacklisted_token, created = token.blacklist() # Should not add token to outstanding list if already present self.assertEqual(OutstandingToken.objects.count(), 1) # Should return blacklist record and boolean to indicate creation self.assertEqual(blacklisted_token.token.jti, token["jti"]) self.assertTrue(created) with self.assertRaises(TokenError) as e: # Should raise exception RefreshToken(str(token)) self.assertIn("blacklisted", e.exception.args[0]) # If blacklisted token already exists, indicate no creation through # boolean blacklisted_token, created = token.blacklist() self.assertEqual(blacklisted_token.token.jti, token["jti"]) self.assertFalse(created) # Should add token to outstanding list if not already present new_token = RefreshToken() blacklisted_token, created = new_token.blacklist() self.assertEqual(blacklisted_token.token.jti, new_token["jti"]) self.assertTrue(created) self.assertEqual(OutstandingToken.objects.count(), 2) def test_outstanding_token_and_blacklisted_token_expected_str(self): outstanding = OutstandingToken.objects.create( user=self.user, jti="abc", token="xyz", expires_at=timezone.now(), ) blacklisted = BlacklistedToken.objects.create(token=outstanding) expected_outstanding_str = "Token for {} ({})".format( outstanding.user, outstanding.jti ) expected_blacklisted_str = f"Blacklisted token for {blacklisted.token.user}" self.assertEqual(str(outstanding), expected_outstanding_str) self.assertEqual(str(blacklisted), expected_blacklisted_str) def test_outstanding_token_and_blacklisted_token_created_at(self): token = RefreshToken.for_user(self.user) token.blacklist() outstanding_token = OutstandingToken.objects.get(token=token) self.assertEqual(outstanding_token.created_at, token.current_time) def test_outstanding_token_and_blacklisted_token_user(self): token = RefreshToken.for_user(self.user) token.blacklist() outstanding_token = OutstandingToken.objects.get(token=token) self.assertEqual(outstanding_token.user, self.user) @override_api_settings(USER_ID_FIELD="email", USER_ID_CLAIM="email") def test_outstanding_token_and_blacklisted_token_created_at_with_modified_user_id_field( self, ): token = RefreshToken.for_user(self.user) token.blacklist() outstanding_token = OutstandingToken.objects.get(token=token) self.assertEqual(outstanding_token.created_at, token.current_time) @override_api_settings(USER_ID_FIELD="email", USER_ID_CLAIM="email") def test_outstanding_token_and_blacklisted_token_user_with_modifed_user_id_field( self, ): token = RefreshToken.for_user(self.user) token.blacklist() outstanding_token = OutstandingToken.objects.get(token=token) self.assertEqual(outstanding_token.user, self.user) @override_api_settings(USER_ID_FIELD="email", USER_ID_CLAIM="email") def test_outstanding_token_with_deleted_user_and_modifed_user_id_field(self): self.assertFalse(BlacklistedToken.objects.exists()) token = RefreshToken.for_user(self.user) self.user.delete() token.blacklist() self.assertTrue(BlacklistedToken.objects.count(), 1) class TestTokenBlacklistFlushExpiredTokens(TestCase): def setUp(self): self.user = User.objects.create( username="test_user", password="test_password", ) def test_it_should_delete_any_expired_tokens(self): # Make some tokens that won't expire soon not_expired_1 = RefreshToken.for_user(self.user) not_expired_2 = RefreshToken.for_user(self.user) not_expired_3 = RefreshToken() # Blacklist fresh tokens not_expired_2.blacklist() not_expired_3.blacklist() # Make tokens with fake exp time that will expire soon fake_now = aware_utcnow() - api_settings.REFRESH_TOKEN_LIFETIME with patch("rest_framework_simplejwt.tokens.aware_utcnow") as fake_aware_utcnow: fake_aware_utcnow.return_value = fake_now expired_1 = RefreshToken.for_user(self.user) expired_2 = RefreshToken() # Blacklist expired tokens expired_1.blacklist() expired_2.blacklist() # Make another token that won't expire soon not_expired_4 = RefreshToken.for_user(self.user) # Should be certain number of outstanding tokens and blacklisted # tokens self.assertEqual(OutstandingToken.objects.count(), 6) self.assertEqual(BlacklistedToken.objects.count(), 4) call_command("flushexpiredtokens") # Expired outstanding *and* blacklisted tokens should be gone self.assertEqual(OutstandingToken.objects.count(), 4) self.assertEqual(BlacklistedToken.objects.count(), 2) self.assertEqual( [i.jti for i in OutstandingToken.objects.order_by("id")], [ not_expired_1["jti"], not_expired_2["jti"], not_expired_3["jti"], not_expired_4["jti"], ], ) self.assertEqual( [i.token.jti for i in BlacklistedToken.objects.order_by("id")], [not_expired_2["jti"], not_expired_3["jti"]], ) def test_token_blacklist_will_not_be_removed_on_User_delete(self): token = RefreshToken.for_user(self.user) outstanding_token = OutstandingToken.objects.first() # Should raise no exception RefreshToken(str(token)) # Add token to blacklist BlacklistedToken.objects.create(token=outstanding_token) with self.assertRaises(TokenError) as e: # Should raise exception RefreshToken(str(token)) self.assertIn("blacklisted", e.exception.args[0]) # Delete the User and try again self.user.delete() with self.assertRaises(TokenError) as e: # Should raise exception RefreshToken(str(token)) self.assertIn("blacklisted", e.exception.args[0]) class TestPopulateJtiHexMigration(MigrationTestCase): migrate_from = ("token_blacklist", "0002_outstandingtoken_jti_hex") migrate_to = ("token_blacklist", "0003_auto_20171017_2007") def setUp(self): self.user = User.objects.create( username="test_user", password="test_password", ) super().setUp() def setUpBeforeMigration(self, apps): # Ensure some tokens are present in the outstanding list RefreshToken.for_user(self.user) RefreshToken.for_user(self.user) OutstandingToken = apps.get_model("token_blacklist", "OutstandingToken") self.expected_hexes = [i.jti.hex for i in OutstandingToken.objects.all()] def test_jti_field_should_contain_uuid_hex_strings(self): OutstandingToken = self.apps.get_model("token_blacklist", "OutstandingToken") actual_hexes = [i.jti_hex for i in OutstandingToken.objects.all()] self.assertEqual(actual_hexes, self.expected_hexes) class TokenVerifySerializerShouldHonourBlacklist(MigrationTestCase): migrate_from = ("token_blacklist", "0002_outstandingtoken_jti_hex") migrate_to = ("token_blacklist", "0003_auto_20171017_2007") def setUp(self): self.user = User.objects.create( username="test_user", password="test_password", ) super().setUp() @override_api_settings(BLACKLIST_AFTER_ROTATION=True) def test_token_verify_serializer_should_honour_blacklist_if_blacklisting_enabled( self, ): refresh_token = RefreshToken.for_user(self.user) refresh_token.blacklist() serializer = TokenVerifySerializer(data={"token": str(refresh_token)}) self.assertFalse(serializer.is_valid()) @override_api_settings(BLACKLIST_AFTER_ROTATION=False) def test_token_verify_serializer_should_not_honour_blacklist_if_blacklisting_not_enabled( self, ): refresh_token = RefreshToken.for_user(self.user) refresh_token.blacklist() serializer = TokenVerifySerializer(data={"token": str(refresh_token)}) self.assertTrue(serializer.is_valid()) class TestBigAutoFieldIDMigration(MigrationTestCase): migrate_from = ("token_blacklist", "0007_auto_20171017_2214") migrate_to = ("token_blacklist", "0008_migrate_to_bigautofield") def test_outstandingtoken_id_field_is_biagauto_field(self): OutstandingToken = self.apps.get_model("token_blacklist", "OutstandingToken") assert isinstance(OutstandingToken._meta.get_field("id"), BigAutoField) def test_blacklistedtoken_id_field_is_biagauto_field(self): BlacklistedToken = self.apps.get_model("token_blacklist", "BlacklistedToken") assert isinstance(BlacklistedToken._meta.get_field("id"), BigAutoField) djangorestframework-simplejwt-5.5.0/tests/test_tokens.py000066400000000000000000000364161475766445300237300ustar00rootroot00000000000000from datetime import datetime, timedelta from importlib import reload from unittest.mock import patch from django.contrib.auth import get_user_model from django.test import TestCase from jose import jwt from rest_framework_simplejwt.exceptions import ( ExpiredTokenError, TokenBackendError, TokenError, ) from rest_framework_simplejwt.settings import api_settings from rest_framework_simplejwt.state import token_backend from rest_framework_simplejwt.tokens import ( AccessToken, RefreshToken, SlidingToken, Token, UntypedToken, ) from rest_framework_simplejwt.utils import aware_utcnow, datetime_to_epoch, make_utc from .utils import override_api_settings User = get_user_model() class MyToken(Token): token_type = "test" lifetime = timedelta(days=1) class TestToken(TestCase): def setUp(self): self.token = MyToken() @classmethod def setUpTestData(cls): cls.username = "test_user" cls.user = User.objects.create_user( username=cls.username, password="test_password", ) def test_type_checking(self): from rest_framework_simplejwt import tokens with patch("typing.TYPE_CHECKING", True): # Reload tokens, mock type checking reload(tokens) self.assertEqual(tokens.TYPE_CHECKING, True) # Restore origin module without mock reload(tokens) def test_init_no_token_type_or_lifetime(self): class MyTestToken(Token): pass with self.assertRaises(TokenError): MyTestToken() MyTestToken.token_type = "test" with self.assertRaises(TokenError): MyTestToken() del MyTestToken.token_type MyTestToken.lifetime = timedelta(days=1) with self.assertRaises(TokenError): MyTestToken() MyTestToken.token_type = "test" MyTestToken() def test_init_no_token_given(self): now = make_utc(datetime(year=2000, month=1, day=1)) with patch("rest_framework_simplejwt.tokens.aware_utcnow") as fake_aware_utcnow: fake_aware_utcnow.return_value = now t = MyToken() self.assertEqual(t.current_time, now) self.assertIsNone(t.token) self.assertEqual(len(t.payload), 4) self.assertEqual(t.payload["exp"], datetime_to_epoch(now + MyToken.lifetime)) self.assertEqual(t.payload["iat"], datetime_to_epoch(now)) self.assertIn("jti", t.payload) self.assertEqual(t.payload[api_settings.TOKEN_TYPE_CLAIM], MyToken.token_type) def test_init_token_given(self): # Test successful instantiation original_now = aware_utcnow() with patch("rest_framework_simplejwt.tokens.aware_utcnow") as fake_aware_utcnow: fake_aware_utcnow.return_value = original_now good_token = MyToken() good_token["some_value"] = "arst" encoded_good_token = str(good_token) now = aware_utcnow() # Create new token from encoded token with patch("rest_framework_simplejwt.tokens.aware_utcnow") as fake_aware_utcnow: fake_aware_utcnow.return_value = now # Should raise no exception t = MyToken(encoded_good_token) # Should have expected properties self.assertEqual(t.current_time, now) self.assertEqual(t.token, encoded_good_token) self.assertEqual(len(t.payload), 5) self.assertEqual(t["some_value"], "arst") self.assertEqual(t["exp"], datetime_to_epoch(original_now + MyToken.lifetime)) self.assertEqual(t["iat"], datetime_to_epoch(original_now)) self.assertEqual(t[api_settings.TOKEN_TYPE_CLAIM], MyToken.token_type) self.assertIn("jti", t.payload) def test_init_bad_sig_token_given(self): # Test backend rejects encoded token (expired or bad signature) payload = {"foo": "bar"} payload["exp"] = aware_utcnow() + timedelta(days=1) token_1 = jwt.encode(payload, api_settings.SIGNING_KEY, algorithm="HS256") payload["foo"] = "baz" token_2 = jwt.encode(payload, api_settings.SIGNING_KEY, algorithm="HS256") token_2_payload = token_2.rsplit(".", 1)[0] token_1_sig = token_1.rsplit(".", 1)[-1] invalid_token = token_2_payload + "." + token_1_sig with self.assertRaises(TokenError): MyToken(invalid_token) def test_init_bad_sig_token_given_no_verify(self): # Test backend rejects encoded token (expired or bad signature) payload = {"foo": "bar"} payload["exp"] = aware_utcnow() + timedelta(days=1) token_1 = jwt.encode(payload, api_settings.SIGNING_KEY, algorithm="HS256") payload["foo"] = "baz" token_2 = jwt.encode(payload, api_settings.SIGNING_KEY, algorithm="HS256") token_2_payload = token_2.rsplit(".", 1)[0] token_1_sig = token_1.rsplit(".", 1)[-1] invalid_token = token_2_payload + "." + token_1_sig t = MyToken(invalid_token, verify=False) self.assertEqual( t.payload, payload, ) def test_init_expired_token_given(self): t = MyToken() t.set_exp(lifetime=-timedelta(seconds=1)) with self.assertRaises(ExpiredTokenError): MyToken(str(t)) def test_init_no_type_token_given(self): t = MyToken() del t[api_settings.TOKEN_TYPE_CLAIM] with self.assertRaises(TokenError): MyToken(str(t)) def test_init_wrong_type_token_given(self): t = MyToken() t[api_settings.TOKEN_TYPE_CLAIM] = "wrong_type" with self.assertRaises(TokenError): MyToken(str(t)) def test_init_no_jti_token_given(self): t = MyToken() del t["jti"] with self.assertRaises(TokenError): MyToken(str(t)) def test_str(self): token = MyToken() token.set_exp( from_time=make_utc(datetime(year=2000, month=1, day=1)), lifetime=timedelta(seconds=0), ) # Delete all but one claim. We want our lives to be easy and for there # to only be a couple of possible encodings. We're only testing that a # payload is successfully encoded here, not that it has specific # content. del token[api_settings.TOKEN_TYPE_CLAIM] del token["jti"] del token["iat"] # Should encode the given token encoded_token = str(token) # Token could be one of two depending on header dict ordering self.assertIn( encoded_token, ( "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjk0NjY4NDgwMH0.VKoOnMgmETawjDZwxrQaHG0xHdo6xBodFy6FXJzTVxs", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjk0NjY4NDgwMH0.iqxxOHV63sjeqNR1GDxX3LPvMymfVB76sOIDqTbjAgk", ), ) def test_repr(self): self.assertEqual(repr(self.token), repr(self.token.payload)) def test_getitem(self): self.assertEqual(self.token["exp"], self.token.payload["exp"]) def test_setitem(self): self.token["test"] = 1234 self.assertEqual(self.token.payload["test"], 1234) def test_delitem(self): self.token["test"] = 1234 self.assertEqual(self.token.payload["test"], 1234) del self.token["test"] self.assertNotIn("test", self.token) def test_contains(self): self.assertIn("exp", self.token) def test_get(self): self.token["test"] = 1234 self.assertEqual(1234, self.token.get("test")) self.assertEqual(1234, self.token.get("test", 2345)) self.assertIsNone(self.token.get("does_not_exist")) self.assertEqual(1234, self.token.get("does_not_exist", 1234)) def test_set_jti(self): token = MyToken() old_jti = token["jti"] token.set_jti() self.assertIn("jti", token) self.assertNotEqual(old_jti, token["jti"]) @override_api_settings(JTI_CLAIM=None) def test_optional_jti(self): token = MyToken() self.assertNotIn("jti", token) @override_api_settings(TOKEN_TYPE_CLAIM=None) def test_optional_type_token(self): token = MyToken() self.assertNotIn("type", token) def test_set_exp(self): now = make_utc(datetime(year=2000, month=1, day=1)) token = MyToken() token.current_time = now # By default, should add 'exp' claim to token using `self.current_time` # and the TOKEN_LIFETIME setting token.set_exp() self.assertEqual(token["exp"], datetime_to_epoch(now + MyToken.lifetime)) # Should allow overriding of beginning time, lifetime, and claim name token.set_exp(claim="refresh_exp", from_time=now, lifetime=timedelta(days=1)) self.assertIn("refresh_exp", token) self.assertEqual( token["refresh_exp"], datetime_to_epoch(now + timedelta(days=1)) ) def test_set_iat(self): now = make_utc(datetime(year=2000, month=1, day=1)) token = MyToken() token.current_time = now # By default, should add 'iat' claim to token using `self.current_time` token.set_iat() self.assertEqual(token["iat"], datetime_to_epoch(now)) # Should allow overriding of time and claim name token.set_iat(claim="refresh_iat", at_time=now + timedelta(days=1)) self.assertIn("refresh_iat", token) self.assertEqual( token["refresh_iat"], datetime_to_epoch(now + timedelta(days=1)) ) def test_check_exp(self): token = MyToken() # Should raise an exception if no claim of given kind with self.assertRaises(TokenError): token.check_exp("non_existent_claim") current_time = token.current_time lifetime = timedelta(days=1) exp = token.current_time + lifetime token.set_exp(lifetime=lifetime) # By default, checks 'exp' claim against `self.current_time`. Should # raise an exception if claim has expired. token.current_time = exp with self.assertRaises(TokenError): token.check_exp() token.current_time = exp + timedelta(seconds=1) with self.assertRaises(TokenError): token.check_exp() # Otherwise, should raise no exception token.current_time = current_time token.check_exp() # Should allow specification of claim to be examined and timestamp to # compare against # Default claim with self.assertRaises(TokenError): token.check_exp(current_time=exp) token.set_exp("refresh_exp", lifetime=timedelta(days=1)) # Default timestamp token.check_exp("refresh_exp") # Given claim and timestamp with self.assertRaises(TokenError): token.check_exp( "refresh_exp", current_time=current_time + timedelta(days=1) ) with self.assertRaises(TokenError): token.check_exp( "refresh_exp", current_time=current_time + timedelta(days=2) ) def test_check_token_not_expired_if_in_leeway(self): token = MyToken() token.set_exp("refresh_exp", lifetime=timedelta(days=1)) datetime_in_leeway = token.current_time + timedelta(days=1) with self.assertRaises(TokenError): token.check_exp("refresh_exp", current_time=datetime_in_leeway) # a token 1 day expired is valid if leeway is 2 days # float (seconds) token.token_backend.leeway = timedelta(days=2).total_seconds() token.check_exp("refresh_exp", current_time=datetime_in_leeway) # timedelta token.token_backend.leeway = timedelta(days=2) token.check_exp("refresh_exp", current_time=datetime_in_leeway) # integer (seconds) token.token_backend.leeway = 10 token.check_exp("refresh_exp", current_time=datetime_in_leeway) token.token_backend.leeway = 0 def test_check_token_if_wrong_type_leeway(self): token = MyToken() token.set_exp("refresh_exp", lifetime=timedelta(days=1)) datetime_in_leeway = token.current_time + timedelta(days=1) token.token_backend.leeway = "1" with self.assertRaises(TokenBackendError): token.check_exp("refresh_exp", current_time=datetime_in_leeway) token.token_backend.leeway = 0 def test_for_user(self): token = MyToken.for_user(self.user) user_id = getattr(self.user, api_settings.USER_ID_FIELD) if not isinstance(user_id, int): user_id = str(user_id) self.assertEqual(token[api_settings.USER_ID_CLAIM], user_id) @override_api_settings(USER_ID_FIELD="username") def test_for_user_with_username(self): # Test with non-int user id token = MyToken.for_user(self.user) self.assertEqual(token[api_settings.USER_ID_CLAIM], self.username) @override_api_settings(CHECK_REVOKE_TOKEN=True) def test_revoke_token_claim_included_in_authorization_token(self): token = MyToken.for_user(self.user) self.assertIn(api_settings.REVOKE_TOKEN_CLAIM, token) def test_get_token_backend(self): token = MyToken() self.assertEqual(token.get_token_backend(), token_backend) class TestSlidingToken(TestCase): def test_init(self): # Should set sliding refresh claim and token type claim token = SlidingToken() self.assertEqual( token[api_settings.SLIDING_TOKEN_REFRESH_EXP_CLAIM], datetime_to_epoch( token.current_time + api_settings.SLIDING_TOKEN_REFRESH_LIFETIME ), ) self.assertEqual(token[api_settings.TOKEN_TYPE_CLAIM], "sliding") class TestAccessToken(TestCase): def test_init(self): # Should set token type claim token = AccessToken() self.assertEqual(token[api_settings.TOKEN_TYPE_CLAIM], "access") class TestRefreshToken(TestCase): def test_init(self): # Should set token type claim token = RefreshToken() self.assertEqual(token[api_settings.TOKEN_TYPE_CLAIM], "refresh") def test_access_token(self): # Should create an access token from a refresh token refresh = RefreshToken() refresh["test_claim"] = "arst" access = refresh.access_token self.assertIsInstance(access, AccessToken) self.assertEqual(access[api_settings.TOKEN_TYPE_CLAIM], "access") # Should keep all copyable claims from refresh token self.assertEqual(refresh["test_claim"], access["test_claim"]) # Should not copy certain claims from refresh token for claim in RefreshToken.no_copy_claims: self.assertNotEqual(refresh[claim], access[claim]) class TestUntypedToken(TestCase): def test_it_should_accept_and_verify_any_type_of_token(self): access_token = AccessToken() refresh_token = RefreshToken() sliding_token = SlidingToken() for t in (access_token, refresh_token, sliding_token): untyped_token = UntypedToken(str(t)) self.assertEqual( t.payload, untyped_token.payload, ) def test_it_should_expire_immediately_if_made_from_scratch(self): t = UntypedToken() self.assertEqual(t[api_settings.TOKEN_TYPE_CLAIM], "untyped") with self.assertRaises(TokenError): t.check_exp() djangorestframework-simplejwt-5.5.0/tests/test_utils.py000066400000000000000000000060561475766445300235620ustar00rootroot00000000000000from datetime import datetime, timedelta, timezone from django.test import TestCase from freezegun import freeze_time from rest_framework_simplejwt.utils import ( aware_utcnow, datetime_from_epoch, datetime_to_epoch, format_lazy, make_utc, ) class TestMakeUtc(TestCase): def test_it_should_return_the_correct_values(self): # It should make a naive datetime into an aware, utc datetime if django # is configured to use timezones and the datetime doesn't already have # a timezone # Naive datetime dt = datetime(year=1970, month=12, day=1) with self.settings(USE_TZ=False): dt = make_utc(dt) self.assertTrue(dt.tzinfo is None) with self.settings(USE_TZ=True): dt = make_utc(dt) self.assertTrue(dt.tzinfo is not None) self.assertEqual(dt.utcoffset(), timedelta(seconds=0)) class TestAwareUtcnow(TestCase): def test_it_should_return_the_correct_value(self): now = datetime.now(tz=timezone.utc).replace(tzinfo=None) with freeze_time(now): # Should return aware utcnow if USE_TZ == True with self.settings(USE_TZ=True): self.assertEqual(now.replace(tzinfo=timezone.utc), aware_utcnow()) # Should return naive utcnow if USE_TZ == False with self.settings(USE_TZ=False): self.assertEqual(now, aware_utcnow()) class TestDatetimeToEpoch(TestCase): def test_it_should_return_the_correct_values(self): self.assertEqual(datetime_to_epoch(datetime(year=1970, month=1, day=1)), 0) self.assertEqual( datetime_to_epoch(datetime(year=1970, month=1, day=1, second=1)), 1 ) self.assertEqual( datetime_to_epoch(datetime(year=2000, month=1, day=1)), 946684800 ) class TestDatetimeFromEpoch(TestCase): def test_it_should_return_the_correct_values(self): with self.settings(USE_TZ=False): self.assertEqual( datetime_from_epoch(0), datetime(year=1970, month=1, day=1) ) self.assertEqual( datetime_from_epoch(1), datetime(year=1970, month=1, day=1, second=1) ) self.assertEqual( datetime_from_epoch(946684800), datetime(year=2000, month=1, day=1), 946684800, ) with self.settings(USE_TZ=True): self.assertEqual( datetime_from_epoch(0), make_utc(datetime(year=1970, month=1, day=1)) ) self.assertEqual( datetime_from_epoch(1), make_utc(datetime(year=1970, month=1, day=1, second=1)), ) self.assertEqual( datetime_from_epoch(946684800), make_utc(datetime(year=2000, month=1, day=1)), ) class TestFormatLazy(TestCase): def test_it_should_work(self): obj = format_lazy("{} {}", "arst", "zxcv") self.assertNotIsInstance(obj, str) self.assertEqual(str(obj), "arst zxcv") djangorestframework-simplejwt-5.5.0/tests/test_views.py000066400000000000000000000343241475766445300235560ustar00rootroot00000000000000from datetime import timedelta from unittest.mock import patch from django.contrib.auth import get_user_model from django.utils import timezone from rest_framework.test import APIRequestFactory from rest_framework_simplejwt import serializers from rest_framework_simplejwt.settings import api_settings from rest_framework_simplejwt.tokens import AccessToken, RefreshToken, SlidingToken from rest_framework_simplejwt.utils import ( aware_utcnow, datetime_from_epoch, datetime_to_epoch, ) from rest_framework_simplejwt.views import TokenViewBase from .utils import APIViewTestCase, override_api_settings User = get_user_model() class TestTokenObtainPairView(APIViewTestCase): view_name = "token_obtain_pair" def setUp(self): self.username = "test_user" self.password = "test_password" self.user = User.objects.create_user( username=self.username, password=self.password, ) def test_fields_missing(self): res = self.view_post(data={}) self.assertEqual(res.status_code, 400) self.assertIn(User.USERNAME_FIELD, res.data) self.assertIn("password", res.data) res = self.view_post(data={User.USERNAME_FIELD: self.username}) self.assertEqual(res.status_code, 400) self.assertIn("password", res.data) res = self.view_post(data={"password": self.password}) self.assertEqual(res.status_code, 400) self.assertIn(User.USERNAME_FIELD, res.data) def test_credentials_wrong(self): res = self.view_post( data={ User.USERNAME_FIELD: self.username, "password": "test_user", } ) self.assertEqual(res.status_code, 401) self.assertIn("detail", res.data) def test_user_inactive(self): self.user.is_active = False self.user.save() res = self.view_post( data={ User.USERNAME_FIELD: self.username, "password": self.password, } ) self.assertEqual(res.status_code, 401) self.assertIn("detail", res.data) def test_success(self): res = self.view_post( data={ User.USERNAME_FIELD: self.username, "password": self.password, } ) self.assertEqual(res.status_code, 200) self.assertIn("access", res.data) self.assertIn("refresh", res.data) def test_update_last_login(self): self.view_post( data={ User.USERNAME_FIELD: self.username, "password": self.password, } ) # verify last_login is not updated user = User.objects.get(username=self.username) self.assertEqual(user.last_login, None) @override_api_settings(UPDATE_LAST_LOGIN=True) def test_update_last_login_updated(self): # verify last_login is updated self.view_post( data={ User.USERNAME_FIELD: self.username, "password": self.password, } ) user = User.objects.get(username=self.username) self.assertIsNotNone(user.last_login) self.assertGreaterEqual(timezone.now(), user.last_login) class TestTokenRefreshView(APIViewTestCase): view_name = "token_refresh" def setUp(self): self.username = "test_user" self.password = "test_password" self.user = User.objects.create_user( username=self.username, password=self.password, ) def test_fields_missing(self): res = self.view_post(data={}) self.assertEqual(res.status_code, 400) self.assertIn("refresh", res.data) def test_it_should_return_401_if_token_invalid(self): token = RefreshToken() del token["exp"] res = self.view_post(data={"refresh": str(token)}) self.assertEqual(res.status_code, 401) self.assertEqual(res.data["code"], "token_not_valid") token.set_exp(lifetime=-timedelta(seconds=1)) res = self.view_post(data={"refresh": str(token)}) self.assertEqual(res.status_code, 401) self.assertEqual(res.data["code"], "token_not_valid") def test_it_should_return_access_token_if_everything_ok(self): refresh = RefreshToken() refresh["test_claim"] = "arst" # View returns 200 now = aware_utcnow() - api_settings.ACCESS_TOKEN_LIFETIME / 2 with patch("rest_framework_simplejwt.tokens.aware_utcnow") as fake_aware_utcnow: fake_aware_utcnow.return_value = now res = self.view_post(data={"refresh": str(refresh)}) self.assertEqual(res.status_code, 200) access = AccessToken(res.data["access"]) self.assertEqual(refresh["test_claim"], access["test_claim"]) self.assertEqual( access["exp"], datetime_to_epoch(now + api_settings.ACCESS_TOKEN_LIFETIME) ) class TestTokenObtainSlidingView(APIViewTestCase): view_name = "token_obtain_sliding" def setUp(self): self.username = "test_user" self.password = "test_password" self.user = User.objects.create_user( username=self.username, password=self.password, ) def test_fields_missing(self): res = self.view_post(data={}) self.assertEqual(res.status_code, 400) self.assertIn(User.USERNAME_FIELD, res.data) self.assertIn("password", res.data) res = self.view_post(data={User.USERNAME_FIELD: self.username}) self.assertEqual(res.status_code, 400) self.assertIn("password", res.data) res = self.view_post(data={"password": self.password}) self.assertEqual(res.status_code, 400) self.assertIn(User.USERNAME_FIELD, res.data) def test_credentials_wrong(self): res = self.view_post( data={ User.USERNAME_FIELD: self.username, "password": "test_user", } ) self.assertEqual(res.status_code, 401) self.assertIn("detail", res.data) def test_user_inactive(self): self.user.is_active = False self.user.save() res = self.view_post( data={ User.USERNAME_FIELD: self.username, "password": self.password, } ) self.assertEqual(res.status_code, 401) self.assertIn("detail", res.data) def test_success(self): res = self.view_post( data={ User.USERNAME_FIELD: self.username, "password": self.password, } ) self.assertEqual(res.status_code, 200) self.assertIn("token", res.data) def test_update_last_login(self): self.view_post( data={ User.USERNAME_FIELD: self.username, "password": self.password, } ) # verify last_login is not updated user = User.objects.get(username=self.username) self.assertEqual(user.last_login, None) @override_api_settings(UPDATE_LAST_LOGIN=True) def test_update_last_login_updated(self): # verify last_login is updated self.view_post( data={ User.USERNAME_FIELD: self.username, "password": self.password, } ) user = User.objects.get(username=self.username) self.assertIsNotNone(user.last_login) self.assertGreaterEqual(timezone.now(), user.last_login) class TestTokenRefreshSlidingView(APIViewTestCase): view_name = "token_refresh_sliding" def setUp(self): self.username = "test_user" self.password = "test_password" self.user = User.objects.create_user( username=self.username, password=self.password, ) def test_fields_missing(self): res = self.view_post(data={}) self.assertEqual(res.status_code, 400) self.assertIn("token", res.data) def test_it_should_return_401_if_token_invalid(self): token = SlidingToken() del token["exp"] res = self.view_post(data={"token": str(token)}) self.assertEqual(res.status_code, 401) self.assertEqual(res.data["code"], "token_not_valid") token.set_exp(lifetime=-timedelta(seconds=1)) res = self.view_post(data={"token": str(token)}) self.assertEqual(res.status_code, 401) self.assertEqual(res.data["code"], "token_not_valid") def test_it_should_return_401_if_token_has_no_refresh_exp_claim(self): token = SlidingToken() del token[api_settings.SLIDING_TOKEN_REFRESH_EXP_CLAIM] res = self.view_post(data={"token": str(token)}) self.assertEqual(res.status_code, 401) self.assertEqual(res.data["code"], "token_not_valid") def test_it_should_return_401_if_token_has_refresh_period_expired(self): token = SlidingToken() token.set_exp( api_settings.SLIDING_TOKEN_REFRESH_EXP_CLAIM, lifetime=-timedelta(seconds=1) ) res = self.view_post(data={"token": str(token)}) self.assertEqual(res.status_code, 401) self.assertEqual(res.data["code"], "token_not_valid") def test_it_should_update_token_exp_claim_if_everything_ok(self): now = aware_utcnow() token = SlidingToken() exp = now + api_settings.SLIDING_TOKEN_LIFETIME - timedelta(seconds=1) token.set_exp( from_time=now, lifetime=api_settings.SLIDING_TOKEN_LIFETIME - timedelta(seconds=1), ) # View returns 200 res = self.view_post(data={"token": str(token)}) self.assertEqual(res.status_code, 200) # Expiration claim has moved into future new_token = SlidingToken(res.data["token"]) new_exp = datetime_from_epoch(new_token["exp"]) self.assertTrue(exp < new_exp) class TestTokenVerifyView(APIViewTestCase): view_name = "token_verify" def setUp(self): self.username = "test_user" self.password = "test_password" self.user = User.objects.create_user( username=self.username, password=self.password, ) def test_fields_missing(self): res = self.view_post(data={}) self.assertEqual(res.status_code, 400) self.assertIn("token", res.data) def test_it_should_return_401_if_token_invalid(self): token = SlidingToken() del token["exp"] res = self.view_post(data={"token": str(token)}) self.assertEqual(res.status_code, 401) self.assertEqual(res.data["code"], "token_not_valid") token.set_exp(lifetime=-timedelta(seconds=1)) res = self.view_post(data={"token": str(token)}) self.assertEqual(res.status_code, 401) self.assertEqual(res.data["code"], "token_not_valid") def test_it_should_return_200_if_everything_okay(self): token = RefreshToken() res = self.view_post(data={"token": str(token)}) self.assertEqual(res.status_code, 200) self.assertEqual(len(res.data), 0) def test_it_should_ignore_token_type(self): token = RefreshToken() token[api_settings.TOKEN_TYPE_CLAIM] = "fake_type" res = self.view_post(data={"token": str(token)}) self.assertEqual(res.status_code, 200) self.assertEqual(len(res.data), 0) class TestTokenBlacklistView(APIViewTestCase): view_name = "token_blacklist" def setUp(self): self.username = "test_user" self.password = "test_password" self.user = User.objects.create_user( username=self.username, password=self.password, ) def test_fields_missing(self): res = self.view_post(data={}) self.assertEqual(res.status_code, 400) self.assertIn("refresh", res.data) def test_it_should_return_401_if_token_invalid(self): token = RefreshToken() del token["exp"] res = self.view_post(data={"refresh": str(token)}) self.assertEqual(res.status_code, 401) self.assertEqual(res.data["code"], "token_not_valid") token.set_exp(lifetime=-timedelta(seconds=1)) res = self.view_post(data={"refresh": str(token)}) self.assertEqual(res.status_code, 401) self.assertEqual(res.data["code"], "token_not_valid") def test_it_should_return_if_everything_ok(self): refresh = RefreshToken() refresh["test_claim"] = "arst" # View returns 200 now = aware_utcnow() - api_settings.ACCESS_TOKEN_LIFETIME / 2 with patch("rest_framework_simplejwt.tokens.aware_utcnow") as fake_aware_utcnow: fake_aware_utcnow.return_value = now res = self.view_post(data={"refresh": str(refresh)}) self.assertEqual(res.status_code, 200) self.assertDictEqual(res.data, {}) def test_it_should_return_401_if_token_is_blacklisted(self): refresh = RefreshToken() refresh["test_claim"] = "arst" # View returns 200 now = aware_utcnow() - api_settings.ACCESS_TOKEN_LIFETIME / 2 with patch("rest_framework_simplejwt.tokens.aware_utcnow") as fake_aware_utcnow: fake_aware_utcnow.return_value = now res = self.view_post(data={"refresh": str(refresh)}) self.assertEqual(res.status_code, 200) self.view_name = "token_refresh" res = self.view_post(data={"refresh": str(refresh)}) # make sure other tests are not affected del self.view_name self.assertEqual(res.status_code, 401) class TestCustomTokenView(APIViewTestCase): def test_custom_view_class(self): class CustomTokenView(TokenViewBase): serializer_class = serializers.TokenObtainPairSerializer factory = APIRequestFactory() view = CustomTokenView.as_view() request = factory.post("/", {}, format="json") res = view(request) self.assertEqual(res.status_code, 400) class TestTokenViewBase(APIViewTestCase): def test_serializer_class_not_set_in_settings_and_class_attribute_or_wrong_path( self, ): view = TokenViewBase() msg = "Could not import serializer '%s'" % view._serializer_class with self.assertRaises(ImportError) as e: view.get_serializer_class() self.assertEqual(e.exception.msg, msg) djangorestframework-simplejwt-5.5.0/tests/urls.py000066400000000000000000000014031475766445300223370ustar00rootroot00000000000000from django.urls import re_path from rest_framework_simplejwt import views as jwt_views from . import views urlpatterns = [ re_path(r"^token/pair/$", jwt_views.token_obtain_pair, name="token_obtain_pair"), re_path(r"^token/refresh/$", jwt_views.token_refresh, name="token_refresh"), re_path( r"^token/sliding/$", jwt_views.token_obtain_sliding, name="token_obtain_sliding" ), re_path( r"^token/sliding/refresh/$", jwt_views.token_refresh_sliding, name="token_refresh_sliding", ), re_path(r"^token/verify/$", jwt_views.token_verify, name="token_verify"), re_path(r"^token/blacklist/$", jwt_views.token_blacklist, name="token_blacklist"), re_path(r"^test-view/$", views.test_view, name="test_view"), ] djangorestframework-simplejwt-5.5.0/tests/utils.py000066400000000000000000000056371475766445300225270ustar00rootroot00000000000000import contextlib from django.db import connection from django.db.migrations.executor import MigrationExecutor from django.test import TestCase, TransactionTestCase from django.urls import reverse from rest_framework.test import APIClient from rest_framework_simplejwt.settings import api_settings def client_action_wrapper(action): def wrapper_method(self, *args, **kwargs): if self.view_name is None: raise ValueError("Must give value for `view_name` property") reverse_args = kwargs.pop("reverse_args", tuple()) reverse_kwargs = kwargs.pop("reverse_kwargs", dict()) query_string = kwargs.pop("query_string", None) url = reverse(self.view_name, args=reverse_args, kwargs=reverse_kwargs) if query_string is not None: url = url + f"?{query_string}" return getattr(self.client, action)(url, *args, **kwargs) return wrapper_method class APIViewTestCase(TestCase): client_class = APIClient def authenticate_with_token(self, type, token): """ Authenticates requests with the given token. """ self.client.credentials(HTTP_AUTHORIZATION=f"{type} {token}") view_name = None view_post = client_action_wrapper("post") view_get = client_action_wrapper("get") @contextlib.contextmanager def override_api_settings(**settings): old_settings = {} for k, v in settings.items(): # Save settings try: old_settings[k] = api_settings.user_settings[k] except KeyError: pass # Install temporary settings api_settings.user_settings[k] = v # Delete any cached settings try: delattr(api_settings, k) except AttributeError: pass try: yield finally: for k in settings.keys(): # Delete temporary settings api_settings.user_settings.pop(k) # Restore saved settings try: api_settings.user_settings[k] = old_settings[k] except KeyError: pass # Delete any cached settings try: delattr(api_settings, k) except AttributeError: pass class MigrationTestCase(TransactionTestCase): migrate_from = None migrate_to = None def setUp(self): self.migrate_from = [self.migrate_from] self.migrate_to = [self.migrate_to] # Reverse to the original migration executor = MigrationExecutor(connection) executor.migrate(self.migrate_from) old_apps = executor.loader.project_state(self.migrate_from).apps self.setUpBeforeMigration(old_apps) # Run the migration to test executor.loader.build_graph() executor.migrate(self.migrate_to) self.apps = executor.loader.project_state(self.migrate_to).apps def setUpBeforeMigration(self, apps): pass djangorestframework-simplejwt-5.5.0/tests/views.py000066400000000000000000000006541475766445300225160ustar00rootroot00000000000000from rest_framework import permissions from rest_framework.response import Response from rest_framework.views import APIView from rest_framework_simplejwt import authentication class TestView(APIView): permission_classes = (permissions.IsAuthenticated,) authentication_classes = (authentication.JWTAuthentication,) def get(self, request): return Response({"foo": "bar"}) test_view = TestView.as_view() djangorestframework-simplejwt-5.5.0/tox.ini000066400000000000000000000016011475766445300211510ustar00rootroot00000000000000[tox] envlist= py{39,310,311,312}-dj42-drf{314,315}-pyjwt{171,2}-tests py{310,311,312}-dj50-drf315-pyjwt{171,2}-tests py{310,311,312,313}-dj51-drf315-pyjwt{171,2}-tests docs [gh-actions] python= 3.9: py39 3.10: py310 3.11: py311 3.12: py312, docs 3.13: py313 [gh-actions:env] DJANGO= 4.2: dj42 5.0: dj50 5.1: dj51 DRF= 3.14: drf314 3.15: drf315 [testenv] commands = pytest {posargs:tests} --cov-append --cov-report=xml --cov=rest_framework_simplejwt extras= test python-jose setenv= PYTHONDONTWRITEBYTECODE=1 deps= dj42: Django>=4.2,<4.3 dj50: Django>=5.0,<5.1 dj51: Django>=5.1,<5.2 drf314: djangorestframework>=3.14,<3.15 drf315: djangorestframework>=3.15,<3.16 pyjwt171: pyjwt>=1.7.1,<1.8 pyjwt2: pyjwt>=2,<2.10.0 allowlist_externals=make [testenv:docs] extras = doc commands = make build-docs