Skip to content

Commit

Permalink
UUID primary key & refresh optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
na-stewart committed Dec 2, 2024
1 parent a125738 commit 89655c7
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 48 deletions.
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "sanic-security"
version = "1.14.1"
version = "1.15.0"
requires-python = ">=3.8"
dependencies = [
"tortoise-orm>=0.17.0",
Expand All @@ -13,7 +13,6 @@ dependencies = [
"pillow>=9.5.0",
"argon2-cffi>=20.1.0",
"sanic>=21.3.0",
"secure>=1.0.1"
]
description = "An async security library for the Sanic framework."
authors = [
Expand Down
17 changes: 7 additions & 10 deletions sanic_security/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
AuditWarning,
)
from sanic_security.models import Account, AuthenticationSession, Role, TwoStepSession
from sanic_security.utils import get_ip, password_hasher, secure_headers
from sanic_security.utils import get_ip, password_hasher

"""
Copyright (c) 2020-present Nicholas Aidan Stewart
Expand Down Expand Up @@ -284,7 +284,7 @@ def validate_password(password: str) -> str:

def initialize_security(app: Sanic, create_root=True) -> None:
"""
Audits configuration, creates root administrator account, and attaches response handler middleware.
Audits configuration, creates root administrator account, and attaches refresh encoder middleware.
Args:
app (Sanic): The main Sanic application instance.
Expand Down Expand Up @@ -356,11 +356,8 @@ async def create_root_account(app, loop):
logger.info("Initial admin account created.")

@app.on_response
async def response_handler_middleware(request, response):
if hasattr(request.ctx, "session"):
secure_headers.set_headers(response)
if (
hasattr(request.ctx.session, "is_refresh")
and request.ctx.session.is_refresh
):
request.ctx.session.encode(response)
async def refresh_encoder_middleware(request, response):
if hasattr(request.ctx, "session") and getattr(
request.ctx.session, "is_refresh", False
):
request.ctx.session.encode(response)
9 changes: 0 additions & 9 deletions sanic_security/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,6 @@ def __init__(self):
super().__init__("Session has expired.")


class NotExpiredError(SessionError):
"""
Raised when session needs to be expired.
"""

def __init__(self):
super().__init__("Session has not expired yet.", 403)


class SecondFactorRequiredError(SessionError):
"""
Raised when authentication session two-factor requirement isn't met.
Expand Down
39 changes: 14 additions & 25 deletions sanic_security/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
get_expiration_date,
image_generator,
audio_generator,
get_id,
is_expired,
)

"""
Expand Down Expand Up @@ -56,7 +58,7 @@ class BaseModel(Model):
deleted (bool): Renders the model filterable without removing from the database.
"""

id: int = fields.IntField(pk=True)
id: str = fields.CharField(pk=True, max_length=36, default=get_id)
date_created: datetime.datetime = fields.DatetimeField(auto_now_add=True)
date_updated: datetime.datetime = fields.DatetimeField(auto_now=True)
deleted: bool = fields.BooleanField(default=False)
Expand Down Expand Up @@ -323,10 +325,7 @@ def validate(self) -> None:
raise DeletedError("Session has been deleted.")
elif not self.active:
raise DeactivatedError
elif (
self.expiration_date
and datetime.datetime.now(datetime.timezone.utc) >= self.expiration_date
):
elif is_expired(self.expiration_date):
raise ExpiredError

async def deactivate(self):
Expand Down Expand Up @@ -626,36 +625,26 @@ def validate(self) -> None:

async def refresh(self, request: Request):
"""
Refreshes session if expired and within refresh date.
Refreshes session if within refresh date.
Args:
request (Request): Sanic request parameter.
Raises:
DeletedError
ExpiredError
DeactivatedError
SecondFactorRequiredError
NotExpiredError
Returns:
session
"""
try:
self.validate()
raise NotExpiredError
except ExpiredError as e:
if (
self.refresh_expiration_date
and datetime.datetime.now(datetime.timezone.utc)
<= self.refresh_expiration_date
):
self.active = False
await self.save(update_fields=["active"])
logging.warning(f"Client {get_ip(request)} has refreshed authentication session {self.id}.")
return await self.new(request, self.bearer, True)
else:
raise e
if not is_expired(self.refresh_expiration_date):
self.active = False
await self.save(update_fields=["active"])
logging.warning(
f"Client {get_ip(request)} has refreshed authentication session {self.id}."
)
return await self.new(request, self.bearer, True)
else:
raise ExpiredError

@classmethod
async def new(
Expand Down
2 changes: 0 additions & 2 deletions sanic_security/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from captcha.image import ImageCaptcha
from sanic.request import Request
from sanic.response import json as sanic_json, HTTPResponse
from secure import Secure

from sanic_security.configuration import config

Expand Down Expand Up @@ -39,7 +38,6 @@
)
audio_generator = AudioCaptcha(voicedir=config.CAPTCHA_VOICE)
password_hasher = PasswordHasher()
secure_headers = Secure.with_default_headers()


def get_ip(request: Request) -> str:
Expand Down

0 comments on commit 89655c7

Please sign in to comment.