Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
max-parallel: 4
matrix:
# move to 3.11 soon
python-version: [ 3.8 ]
python-version: [ 3.8, 3.11 ]

steps:
- uses: actions/checkout@v3
Expand Down
16 changes: 11 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
exclude: .+/migrations/.+\.py
repos:
- repo: https://github.com/psf/black
rev: 23.11.0
hooks:
- id: black

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
Expand All @@ -19,3 +14,14 @@ repos:
hooks:
- id: isort
args: [ "--profile", "black" ]

- repo: https://github.com/adamchainz/django-upgrade
rev: 1.15.0
hooks:
- id: django-upgrade
args: [ --target-version, "4.2" ]

- repo: https://github.com/psf/black
rev: 23.11.0
hooks:
- id: black
11 changes: 1 addition & 10 deletions HisabKitab/custom_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@

REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
"DEFAULT_AUTHENTICATION_CLASSES": ("drfaddons.auth.JSONWebTokenAuthenticationQS",),
"DEFAULT_AUTHENTICATION_CLASSES": ("core.auth.JSONWebTokenAuthenticationQS",),
"DEFAULT_PARSER_CLASSES": ("rest_framework.parsers.JSONParser",),
"DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",),
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
Expand Down Expand Up @@ -122,15 +122,6 @@

STATIC_ROOT = "static"

JET_THEMES = [
{"theme": "default", "color": "#47bac1", "title": "Default"},
{"theme": "green", "color": "#44b78b", "title": "Green"},
{"theme": "light-green", "color": "#2faa60", "title": "Light Green"},
{"theme": "light-violet", "color": "#a464c4", "title": "Light Violet"},
{"theme": "light-blue", "color": "#5EADDE", "title": "Light Blue"},
{"theme": "light-gray", "color": "#222", "title": "Light Gray"},
]

# Sentry
# ------------------------------------------------------------------------------
SENTRY_DSN = env("SENTRY_DSN")
Expand Down
4 changes: 1 addition & 3 deletions HisabKitab/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
# Application definition

INSTALLED_APPS = [
"jet.dashboard",
"jet",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
Expand Down Expand Up @@ -88,4 +86,4 @@

USE_I18N = True

USE_L10N = True
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
4 changes: 1 addition & 3 deletions HisabKitab/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

INSTALLED_APPS = (
"jet.dashboard",
"jet",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
Expand Down Expand Up @@ -107,7 +105,7 @@

REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
"DEFAULT_AUTHENTICATION_CLASSES": ("drfaddons.auth.JSONWebTokenAuthenticationQS",),
"DEFAULT_AUTHENTICATION_CLASSES": ("core.auth.JSONWebTokenAuthenticationQS",),
"DEFAULT_PARSER_CLASSES": ("rest_framework.parsers.JSONParser",),
"DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",),
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
Expand Down
12 changes: 4 additions & 8 deletions HisabKitab/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,13 @@
schema_view.without_ui(cache_timeout=None),
name="schema-json",
),
re_path(
"swagger/$",
path(
"swagger/",
schema_view.with_ui("swagger", cache_timeout=None),
name="schema-swagger-ui",
),
re_path(
"redoc/$", schema_view.with_ui("redoc", cache_timeout=None), name="schema-redoc"
),
path("jet/", include("jet.urls", "jet")), # Django JET URLSz
path(
"jet/dashboard/", include("jet.dashboard.urls", "jet-dashboard")
), # Django JET dashboard URLS
"redoc/", schema_view.with_ui("redoc", cache_timeout=None), name="schema-redoc"
),
path("", admin.site.urls),
]
146 changes: 146 additions & 0 deletions core/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import jwt
from django.conf import settings
from django.contrib.auth import get_user_model
from django.utils.encoding import smart_str
from django.utils.translation import gettext as _
from rest_framework import HTTP_HEADER_ENCODING, exceptions
from rest_framework.authentication import BaseAuthentication
from rest_framework_jwt.settings import api_settings
from six import text_type

jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
jwt_get_username_from_payload = api_settings.JWT_PAYLOAD_GET_USERNAME_HANDLER


class JSONWebTokenAuthenticationQS(BaseAuthentication):
"""
Token based authentication using the JSON Web Token standard.

This is a custom JWT Authentication class. The traditional one
can only authenticate from Header with a specific key only.

This model will first look into HEADER and if the key is not found
there, it looks for key in the body.
Key is also changeable and can be set in Django settings as
JWT_AUTH_KEY with default value of Authorization.

"""

key = getattr(settings, "JWT_AUTH_KEY", "Authorization")
header_key = "HTTP_" + key.upper()
prefix = api_settings.JWT_AUTH_HEADER_PREFIX
cookie = api_settings.JWT_AUTH_COOKIE

def get_authorization(self, request):
"""
This function extracts the authorization JWT string. It first
looks for specified key in header and then looks
for the same in body part.

Parameters
----------
request: HttpRequest
This is the raw request that user has sent.

Returns
-------
auth: str
Return request's 'JWT_AUTH_KEY:' content from body or
Header, as a bytestring.

Hide some test client ickyness where the header can be unicode.
"""

auth = request.META.get(self.header_key, b"")

if isinstance(auth, text_type):
# Work around django test client oddness
auth = auth.encode(HTTP_HEADER_ENCODING)
return auth

def get_jwt_value(self, request):
"""
This function has been overloaded and it returns the proper JWT
auth string.
Parameters
----------
request: HttpRequest
This is the request that is received by DJango in the view.
Returns
-------
str
This returns the extracted JWT auth token string.

"""

auth = self.get_authorization(request).split()
auth_header_prefix = self.prefix.lower() or ""

if not auth:
return request.COOKIES.get(self.cookie) if self.cookie else None
if auth_header_prefix is None or len(auth_header_prefix) < 1:
auth.append("")
auth.reverse()

if smart_str(auth[0].lower()) != auth_header_prefix:
return None

if len(auth) == 1:
msg = _("Invalid Authorization header. No credentials provided.")
raise exceptions.AuthenticationFailed(msg)

elif len(auth) > 2:
msg = _(
"Invalid Authorization header. Credentials string "
"should not contain spaces."
)
raise exceptions.AuthenticationFailed(msg)

return auth[1]

def authenticate(self, request):
"""
Returns a two-tuple of `User` and token if a valid signature has been
supplied using JWT-based authentication. Otherwise returns `None`.
"""
jwt_value = self.get_jwt_value(request)
if jwt_value is None:
return None

try:
payload = jwt_decode_handler(jwt_value)
except jwt.ExpiredSignature:
msg = _("Signature has expired.")
raise exceptions.AuthenticationFailed(msg)
except jwt.DecodeError:
msg = _("Error decoding signature.")
raise exceptions.AuthenticationFailed(msg)
except jwt.InvalidTokenError:
raise exceptions.AuthenticationFailed()

user = self.authenticate_credentials(payload)

return (user, jwt_value)

def authenticate_credentials(self, payload):
"""
Returns an active user that matches the payload's user id and email.
"""
User = get_user_model()
username = jwt_get_username_from_payload(payload)

if not username:
msg = _("Invalid payload.")
raise exceptions.AuthenticationFailed(msg)

try:
user = User.objects.get_by_natural_key(username)
except User.DoesNotExist:
msg = _("Invalid signature.")
raise exceptions.AuthenticationFailed(msg)

if not user.is_active:
msg = _("User account is disabled.")
raise exceptions.AuthenticationFailed(msg)

return user
2 changes: 0 additions & 2 deletions drf_account/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,3 @@
__version__ = "0.0.2"
__author__ = "Civil Machines Technologies Private Limited"
__license__ = "GPLv3"

default_app_config = "drf_account.apps.DRFAccountConfig"
2 changes: 0 additions & 2 deletions drf_contact/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,3 @@
__version__ = "0.0.2"
__author__ = "Civil Machines Technologies Private Limited"
__license__ = "GPLv3"

default_app_config = "drf_contact.apps.DRFContactConfig"
6 changes: 3 additions & 3 deletions drf_contact/urls.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.conf.urls import url
from django.urls import re_path

from . import views

Expand All @@ -7,7 +7,7 @@

urlpatterns = [
# ex: api/contacts/show/
url(r"^show/", views.ShowContacts.as_view(), name="show_contact"),
re_path(r"^show/", views.ShowContacts.as_view(), name="show_contact"),
# ex: api/contacts/add/
url(r"^add/", views.AddContacts.as_view(), name="add_contact"),
re_path(r"^add/", views.AddContacts.as_view(), name="add_contact"),
]
2 changes: 0 additions & 2 deletions drf_transaction/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,3 @@
__version__ = "0.0.3"
__author__ = "Civil Machines Technologies Private Limited"
__license__ = "GPLv3"

default_app_config = "drf_transaction.apps.DRFTransactionConfig"
6 changes: 3 additions & 3 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-r requirements.txt
coverage==7.0.5
factory_boy==3.2.1
fakeredis[lua]==2.7.1
coverage==7.3.2
factory_boy==3.3.0
fakeredis[lua]==2.20.0
27 changes: 13 additions & 14 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
Django==2.2.28
django-braces==1.13.0
django-cors-headers==3.2.1
Django==4.2.7
django-braces==1.15.0
django-cors-headers==4.3.1
django-cors-middleware==1.5.0
django-environ==0.4.5
django-jet==1.0.8
django-sendsms==0.3.1
djangorestframework==3.11.2
django-environ==0.11.2
django-sendsms==0.5
djangorestframework==3.14.0
djangorestframework-jwt==1.11.0
drf-user==0.0.8
drf-yasg==1.17.1
drf-user==1.1.0
drf-yasg==1.21.7
drfaddons==0.1.4
huey==2.4.4
pre-commit==2.20.0
psycopg2-binary==2.8.6
huey==2.5.0
pre-commit==3.5.0
psycopg2-binary==2.9.9
python-dateutil==2.8.2
redis==4.4.4
sentry-sdk==1.14.0
redis==5.0.1
sentry-sdk==1.38.0
six==1.16.0
2 changes: 1 addition & 1 deletion users/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
from .models import *


@admin.register(User)
class AuthorAdmin(admin.ModelAdmin):
readonly_fields = ("password",)


admin.site.register(User, AuthorAdmin)
admin.site.register(OTPValidation)
admin.site.register(AuthTransaction)