mirror of
https://framagit.org/framasoft/framaspace/argos.git
synced 2025-04-28 18:02:41 +02:00
✨ — Add "Remember me" checkbox on login (#65)
This commit is contained in:
parent
91a9b27106
commit
0563cf185a
5 changed files with 64 additions and 9 deletions
|
@ -8,6 +8,7 @@
|
||||||
- ✨ — The HTTP method used by checks is now configurable
|
- ✨ — The HTTP method used by checks is now configurable
|
||||||
- ♻️ — Refactor some agent code
|
- ♻️ — Refactor some agent code
|
||||||
- 💄 — Filter form on domains list (#66)
|
- 💄 — Filter form on domains list (#66)
|
||||||
|
- ✨ — Add "Remember me" checkbox on login (#65)
|
||||||
|
|
||||||
## 0.5.0
|
## 0.5.0
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,19 @@ general:
|
||||||
# Can be "production", "dev", "test".
|
# Can be "production", "dev", "test".
|
||||||
# If not present, default value is "production"
|
# If not present, default value is "production"
|
||||||
env: "production"
|
env: "production"
|
||||||
# to get a good string for cookie_secret, run:
|
# To get a good string for cookie_secret, run:
|
||||||
# openssl rand -hex 32
|
# openssl rand -hex 32
|
||||||
cookie_secret: "foo_bar_baz"
|
cookie_secret: "foo_bar_baz"
|
||||||
|
|
||||||
|
# Session duration
|
||||||
|
# Use m for minutes, h for hours, d for days
|
||||||
|
# w for weeks, mo for months, y for years
|
||||||
|
# If not present, default value is "7d"
|
||||||
|
session_duration: "7d"
|
||||||
|
# Session opened with "Remember me" checked
|
||||||
|
# If not present, the "Remember me" feature is not available
|
||||||
|
# remember_me_duration: "1mo"
|
||||||
|
|
||||||
# Default delay for checks.
|
# Default delay for checks.
|
||||||
# Can be superseeded in domain configuration.
|
# Can be superseeded in domain configuration.
|
||||||
# For ex., to run checks every minute:
|
# For ex., to run checks every minute:
|
||||||
|
|
|
@ -175,16 +175,31 @@ class DbSettings(BaseModel):
|
||||||
class General(BaseModel):
|
class General(BaseModel):
|
||||||
"""Frequency for the checks and alerts"""
|
"""Frequency for the checks and alerts"""
|
||||||
|
|
||||||
cookie_secret: str
|
|
||||||
frequency: int
|
|
||||||
db: DbSettings
|
db: DbSettings
|
||||||
env: Environment = "production"
|
env: Environment = "production"
|
||||||
|
cookie_secret: str
|
||||||
|
session_duration: int = 10080 # 7 days
|
||||||
|
remember_me_duration: Optional[int] = None
|
||||||
|
frequency: int
|
||||||
root_path: str = ""
|
root_path: str = ""
|
||||||
alerts: Alert
|
alerts: Alert
|
||||||
mail: Optional[Mail] = None
|
mail: Optional[Mail] = None
|
||||||
gotify: Optional[List[GotifyUrl]] = None
|
gotify: Optional[List[GotifyUrl]] = None
|
||||||
apprise: Optional[Dict[str, List[str]]] = None
|
apprise: Optional[Dict[str, List[str]]] = None
|
||||||
|
|
||||||
|
@field_validator("session_duration", mode="before")
|
||||||
|
def parse_session_duration(cls, value):
|
||||||
|
"""Convert the configured session duration to minutes"""
|
||||||
|
return string_to_duration(value, "minutes")
|
||||||
|
|
||||||
|
@field_validator("remember_me_duration", mode="before")
|
||||||
|
def parse_remember_me_duration(cls, value):
|
||||||
|
"""Convert the configured session duration with remember me feature to minutes"""
|
||||||
|
if value:
|
||||||
|
return string_to_duration(value, "minutes")
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
@field_validator("frequency", mode="before")
|
@field_validator("frequency", mode="before")
|
||||||
def parse_frequency(cls, value):
|
def parse_frequency(cls, value):
|
||||||
"""Convert the configured frequency to minutes"""
|
"""Convert the configured frequency to minutes"""
|
||||||
|
|
|
@ -28,7 +28,11 @@ SEVERITY_LEVELS = {"ok": 1, "warning": 2, "critical": 3, "unknown": 4}
|
||||||
|
|
||||||
|
|
||||||
@route.get("/login")
|
@route.get("/login")
|
||||||
async def login_view(request: Request, msg: str | None = None):
|
async def login_view(
|
||||||
|
request: Request,
|
||||||
|
msg: str | None = None,
|
||||||
|
config: Config = Depends(get_config),
|
||||||
|
):
|
||||||
token = request.cookies.get("access-token")
|
token = request.cookies.get("access-token")
|
||||||
if token is not None and token != "":
|
if token is not None and token != "":
|
||||||
manager = request.app.state.manager
|
manager = request.app.state.manager
|
||||||
|
@ -44,7 +48,14 @@ async def login_view(request: Request, msg: str | None = None):
|
||||||
else:
|
else:
|
||||||
msg = None
|
msg = None
|
||||||
|
|
||||||
return templates.TemplateResponse("login.html", {"request": request, "msg": msg})
|
return templates.TemplateResponse(
|
||||||
|
"login.html",
|
||||||
|
{
|
||||||
|
"request": request,
|
||||||
|
"msg": msg,
|
||||||
|
"remember": config.general.remember_me_duration,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@route.post("/login")
|
@route.post("/login")
|
||||||
|
@ -52,6 +63,8 @@ async def post_login(
|
||||||
request: Request,
|
request: Request,
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
data: OAuth2PasswordRequestForm = Depends(),
|
data: OAuth2PasswordRequestForm = Depends(),
|
||||||
|
rememberme: Annotated[str | None, Form()] = None,
|
||||||
|
config: Config = Depends(get_config),
|
||||||
):
|
):
|
||||||
username = data.username
|
username = data.username
|
||||||
user = await queries.get_user(db, username)
|
user = await queries.get_user(db, username)
|
||||||
|
@ -70,14 +83,22 @@ async def post_login(
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
manager = request.app.state.manager
|
manager = request.app.state.manager
|
||||||
token = manager.create_access_token(
|
session_duration = config.general.session_duration
|
||||||
data={"sub": username}, expires=timedelta(days=7)
|
if config.general.remember_me_duration is not None and rememberme == "on":
|
||||||
)
|
session_duration = config.general.remember_me_duration
|
||||||
|
delta = timedelta(minutes=session_duration)
|
||||||
|
token = manager.create_access_token(data={"sub": username}, expires=delta)
|
||||||
response = RedirectResponse(
|
response = RedirectResponse(
|
||||||
request.url_for("get_severity_counts_view"),
|
request.url_for("get_severity_counts_view"),
|
||||||
status_code=status.HTTP_303_SEE_OTHER,
|
status_code=status.HTTP_303_SEE_OTHER,
|
||||||
)
|
)
|
||||||
manager.set_cookie(response, token)
|
response.set_cookie(
|
||||||
|
key=manager.cookie_name,
|
||||||
|
value=token,
|
||||||
|
httponly=True,
|
||||||
|
samesite="strict",
|
||||||
|
expires=int(delta.total_seconds()),
|
||||||
|
)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,14 @@
|
||||||
name="password"
|
name="password"
|
||||||
type="password"
|
type="password"
|
||||||
form="login">
|
form="login">
|
||||||
|
{% if remember is not none %}
|
||||||
|
<label>
|
||||||
|
<input type="checkbox"
|
||||||
|
name="rememberme"
|
||||||
|
form="login">
|
||||||
|
Remember me
|
||||||
|
</label>
|
||||||
|
{% endif %}
|
||||||
<form id="login"
|
<form id="login"
|
||||||
method="post"
|
method="post"
|
||||||
action="{{ url_for('post_login') }}">
|
action="{{ url_for('post_login') }}">
|
||||||
|
|
Loading…
Reference in a new issue