From 5bae00b3fe1ce4c31ac9d6881844133e3fc6f725 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Thu, 9 Feb 2023 12:49:05 +0000 Subject: [PATCH 1/4] Expand TOTP validity window --- bookwyrm/forms/landing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/forms/landing.py b/bookwyrm/forms/landing.py index bd9884bc3..132f3ba71 100644 --- a/bookwyrm/forms/landing.py +++ b/bookwyrm/forms/landing.py @@ -108,7 +108,7 @@ class Confirm2FAForm(CustomForm): otp = self.data.get("otp") totp = pyotp.TOTP(self.instance.otp_secret) - if not totp.verify(otp): + if not totp.verify(otp, valid_window=2): if self.instance.hotp_secret: # maybe it's a backup code? From 867b2ff542ddbd5c171570cc35795b6a4fd7c674 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Mon, 13 Feb 2023 15:17:54 +0000 Subject: [PATCH 2/4] Specify TOTP validity window in settings.py --- bookwyrm/forms/landing.py | 3 ++- bookwyrm/settings.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bookwyrm/forms/landing.py b/bookwyrm/forms/landing.py index 132f3ba71..1da4fc4f1 100644 --- a/bookwyrm/forms/landing.py +++ b/bookwyrm/forms/landing.py @@ -8,6 +8,7 @@ import pyotp from bookwyrm import models from bookwyrm.settings import DOMAIN +from bookwyrm.settings import TWO_FACTOR_LOGIN_VALIDITY_WINDOW from .custom_form import CustomForm @@ -108,7 +109,7 @@ class Confirm2FAForm(CustomForm): otp = self.data.get("otp") totp = pyotp.TOTP(self.instance.otp_secret) - if not totp.verify(otp, valid_window=2): + if not totp.verify(otp, valid_window=TWO_FACTOR_LOGIN_VALIDITY_WINDOW): if self.instance.hotp_secret: # maybe it's a backup code? diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index 61240dbfa..d8c554742 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -369,6 +369,7 @@ OTEL_EXPORTER_OTLP_HEADERS = env("OTEL_EXPORTER_OTLP_HEADERS", None) OTEL_SERVICE_NAME = env("OTEL_SERVICE_NAME", None) TWO_FACTOR_LOGIN_MAX_SECONDS = 60 +TWO_FACTOR_LOGIN_VALIDITY_WINDOW = 2 HTTP_X_FORWARDED_PROTO = env.bool("SECURE_PROXY_SSL_HEADER", False) if HTTP_X_FORWARDED_PROTO: From 94605530867bbe522fa0300cc47661612676b632 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Fri, 17 Feb 2023 09:40:31 +0000 Subject: [PATCH 3/4] Read TOTP variables from .env --- .env.example | 6 ++++++ bookwyrm/settings.py | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 4c1c2eefe..b47c683c5 100644 --- a/.env.example +++ b/.env.example @@ -120,3 +120,9 @@ OTEL_SERVICE_NAME= # for your instance: # https://docs.djangoproject.com/en/3.2/ref/settings/#secure-proxy-ssl-header HTTP_X_FORWARDED_PROTO=false + +# TOTP settings +# TWO_FACTOR_LOGIN_VALIDITY_WINDOW sets the number of codes either side +# which will be accepted. +TWO_FACTOR_LOGIN_VALIDITY_WINDOW=2 +TWO_FACTOR_LOGIN_MAX_SECONDS=60 diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index d8c554742..fc83fba9b 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -368,8 +368,8 @@ OTEL_EXPORTER_OTLP_ENDPOINT = env("OTEL_EXPORTER_OTLP_ENDPOINT", None) OTEL_EXPORTER_OTLP_HEADERS = env("OTEL_EXPORTER_OTLP_HEADERS", None) OTEL_SERVICE_NAME = env("OTEL_SERVICE_NAME", None) -TWO_FACTOR_LOGIN_MAX_SECONDS = 60 -TWO_FACTOR_LOGIN_VALIDITY_WINDOW = 2 +TWO_FACTOR_LOGIN_MAX_SECONDS = env.int("TWO_FACTOR_LOGIN_MAX_SECONDS") +TWO_FACTOR_LOGIN_VALIDITY_WINDOW = env.int("TWO_FACTOR_LOGIN_VALIDITY_WINDOW") HTTP_X_FORWARDED_PROTO = env.bool("SECURE_PROXY_SSL_HEADER", False) if HTTP_X_FORWARDED_PROTO: From d123cc6b0c52db4b20ecec45bec64b51b94ca96c Mon Sep 17 00:00:00 2001 From: Chris Young Date: Fri, 17 Feb 2023 11:36:21 +0000 Subject: [PATCH 4/4] Add default values if not in .env --- bookwyrm/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index fc83fba9b..51f3fe8a7 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -368,8 +368,8 @@ OTEL_EXPORTER_OTLP_ENDPOINT = env("OTEL_EXPORTER_OTLP_ENDPOINT", None) OTEL_EXPORTER_OTLP_HEADERS = env("OTEL_EXPORTER_OTLP_HEADERS", None) OTEL_SERVICE_NAME = env("OTEL_SERVICE_NAME", None) -TWO_FACTOR_LOGIN_MAX_SECONDS = env.int("TWO_FACTOR_LOGIN_MAX_SECONDS") -TWO_FACTOR_LOGIN_VALIDITY_WINDOW = env.int("TWO_FACTOR_LOGIN_VALIDITY_WINDOW") +TWO_FACTOR_LOGIN_MAX_SECONDS = env.int("TWO_FACTOR_LOGIN_MAX_SECONDS", 60) +TWO_FACTOR_LOGIN_VALIDITY_WINDOW = env.int("TWO_FACTOR_LOGIN_VALIDITY_WINDOW", 2) HTTP_X_FORWARDED_PROTO = env.bool("SECURE_PROXY_SSL_HEADER", False) if HTTP_X_FORWARDED_PROTO: