fix(auth): fix timezone issues with recovery tokens
continuous-integration/drone/push Build is failing Details

autobackup-errors
Houkime 2023-11-13 09:15:12 -07:00
parent 1bbb804919
commit e414f3b8fd
5 changed files with 22 additions and 16 deletions

View File

@ -7,7 +7,9 @@ def ensure_tz_aware(dt: datetime) -> datetime:
assumes utc on naive datetime input assumes utc on naive datetime input
""" """
if dt.tzinfo is None: if dt.tzinfo is None:
dt = dt.astimezone(timezone.utc) # astimezone() is dangerous, it makes an implicit assumption that
# the time is localtime
dt = dt.replace(tzinfo=timezone.utc)
return dt return dt

View File

@ -36,6 +36,10 @@ class NearFuture(datetime):
def now(cls, tz=None): def now(cls, tz=None):
return datetime.now(tz) + timedelta(minutes=13) return datetime.now(tz) + timedelta(minutes=13)
@classmethod
def utcnow(cls):
return datetime.utcnow() + timedelta(minutes=13)
def read_json(file_path): def read_json(file_path):
with open(file_path, "r", encoding="utf-8") as file: with open(file_path, "r", encoding="utf-8") as file:

View File

@ -6,16 +6,16 @@ ORIGINAL_DEVICES = TOKENS_FILE_CONTENTS["tokens"]
def assert_ok(response, request): def assert_ok(response, request):
data = assert_data(response) data = assert_data(response)
data[request]["success"] is True assert data[request]["success"] is True
data[request]["message"] is not None assert data[request]["message"] is not None
data[request]["code"] == 200 assert data[request]["code"] == 200
def assert_errorcode(response, request, code): def assert_errorcode(response, request, code):
data = assert_data(response) data = assert_data(response)
data[request]["success"] is False assert data[request]["success"] is False
data[request]["message"] is not None assert data[request]["message"] is not None
data[request]["code"] == code assert data[request]["code"] == code
def assert_empty(response): def assert_empty(response):

View File

@ -177,9 +177,9 @@ def test_graphql_generate_recovery_key_with_expiration_date(
assert_recovery_recent(status["creationDate"]) assert_recovery_recent(status["creationDate"])
# timezone-aware comparison. Should pass regardless of server's tz # timezone-aware comparison. Should pass regardless of server's tz
assert datetime.fromisoformat( assert datetime.fromisoformat(status["expirationDate"]) == expiration_date.replace(
status["expirationDate"] tzinfo=timezone.utc
) == expiration_date.astimezone(timezone.utc) )
assert status["usesLeft"] is None assert status["usesLeft"] is None
@ -208,9 +208,9 @@ def test_graphql_use_recovery_key_after_expiration(
assert_recovery_recent(status["creationDate"]) assert_recovery_recent(status["creationDate"])
# timezone-aware comparison. Should pass regardless of server's tz # timezone-aware comparison. Should pass regardless of server's tz
assert datetime.fromisoformat( assert datetime.fromisoformat(status["expirationDate"]) == expiration_date.replace(
status["expirationDate"] tzinfo=timezone.utc
) == expiration_date.astimezone(timezone.utc) )
assert status["usesLeft"] is None assert status["usesLeft"] is None

View File

@ -12,8 +12,8 @@ from tests.common import (
NearFuture, NearFuture,
assert_recovery_recent, assert_recovery_recent,
) )
from tests.common import five_minutes_into_future_naive as five_minutes_into_future from tests.common import five_minutes_into_future_naive_utc as five_minutes_into_future
from tests.common import five_minutes_into_past_naive as five_minutes_into_past from tests.common import five_minutes_into_past_naive_utc as five_minutes_into_past
DATE_FORMATS = [ DATE_FORMATS = [
"%Y-%m-%dT%H:%M:%S.%fZ", "%Y-%m-%dT%H:%M:%S.%fZ",
@ -338,7 +338,7 @@ def test_generate_recovery_token_with_expiration_date(
"exists": True, "exists": True,
"valid": True, "valid": True,
"date": time_generated, "date": time_generated,
"expiration": expiration_date.astimezone(timezone.utc).isoformat(), "expiration": expiration_date.replace(tzinfo=timezone.utc).isoformat(),
"uses_left": None, "uses_left": None,
} }