security: implement user lockout (#1552)

* add data-types required for login security

* implement user lockout checking at login

* cleanup legacy patterns

* expose passwords in test_user

* test user lockout after bad attempts

* test user service

* bump alembic version

* save increment to database

* add locked_at to datetime transformer on import

* do proper test cleanup

* implement scheduled task

* spelling

* document env variables

* implement context manager for session

* use context manager

* implement reset script

* cleanup generator

* run generator

* implement API endpoint for resetting locked users

* add button to reset all locked users

* add info when account is locked

* use ignore instead of expect-error
This commit is contained in:
Hayden
2022-08-13 13:18:12 -08:00
committed by GitHub
parent ca64584fd1
commit b3c41a4bd0
35 changed files with 450 additions and 46 deletions

View File

@@ -1,4 +1,5 @@
from collections.abc import Generator
from contextlib import contextmanager
import sqlalchemy as sa
from sqlalchemy.orm import sessionmaker
@@ -29,6 +30,17 @@ def sql_global_init(db_url: str):
SessionLocal, engine = sql_global_init(settings.DB_URL) # type: ignore
@contextmanager
def with_session() -> Session:
global SessionLocal
sess = SessionLocal()
try:
yield sess
finally:
sess.close()
def create_session() -> Session:
global SessionLocal
return SessionLocal()

View File

@@ -1,4 +1,4 @@
from sqlalchemy import Boolean, Column, ForeignKey, String, orm
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String, orm
from mealie.core.config import get_app_settings
from mealie.db.models._model_utils.guid import GUID
@@ -36,6 +36,8 @@ class User(SqlAlchemyBase, BaseMixins):
group = orm.relationship("Group", back_populates="users")
cache_key = Column(String, default="1234")
login_attemps = Column(Integer, default=0)
locked_at = Column(DateTime, default=None)
# Group Permissions
can_manage = Column(Boolean, default=False)