generated from bisco/codex-bootstrap
fix(security): separate booking and check-in tokens
This commit is contained in:
@@ -98,17 +98,12 @@ def _get_reservation_for_check_in_token(raw_token, *, lock_token=False):
|
||||
try:
|
||||
token = queryset.get(
|
||||
token_hash=ReservationToken.hash_token(raw_token),
|
||||
purpose=ReservationToken.Purpose.CHECK_IN,
|
||||
)
|
||||
except ReservationToken.DoesNotExist as exc:
|
||||
raise InvalidToken("Check-in token is invalid.") from exc
|
||||
|
||||
if token.purpose == ReservationToken.Purpose.CHECK_IN:
|
||||
if token.used_at is not None or token.is_expired:
|
||||
raise InvalidToken("Check-in token is invalid.")
|
||||
elif token.purpose == ReservationToken.Purpose.CONFIRMATION:
|
||||
if token.reservation.status != Reservation.Status.CONFIRMED:
|
||||
raise InvalidToken("Check-in token is invalid.")
|
||||
else:
|
||||
if token.used_at is not None or token.is_expired:
|
||||
raise InvalidToken("Check-in token is invalid.")
|
||||
|
||||
return token.reservation
|
||||
|
||||
@@ -87,6 +87,24 @@ class CheckInApiTests(APITestCase):
|
||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||
self.assertEqual(response.data["status"], "invalid_token")
|
||||
|
||||
def test_preview_rejects_confirmation_token(self):
|
||||
reservation = self.create_reservation()
|
||||
_, raw_token = ReservationToken.create_token(
|
||||
reservation=reservation,
|
||||
purpose=ReservationToken.Purpose.CONFIRMATION,
|
||||
expires_at=timezone.now() + timedelta(hours=2),
|
||||
)
|
||||
self.client.force_authenticate(user=self.staff_user)
|
||||
|
||||
response = self.client.post(
|
||||
reverse("api-check-in-preview"),
|
||||
{"token": raw_token},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||
self.assertEqual(response.data["status"], "invalid_token")
|
||||
|
||||
def test_check_in_success_as_staff_user(self):
|
||||
reservation = self.create_reservation()
|
||||
_, raw_token = self.create_check_in_token(reservation)
|
||||
@@ -171,6 +189,25 @@ class CheckInApiTests(APITestCase):
|
||||
self.assertEqual(second_response.data["status"], "already_checked_in")
|
||||
self.assertEqual(CheckIn.objects.filter(reservation=reservation).count(), 1)
|
||||
|
||||
def test_check_in_rejects_confirmation_token(self):
|
||||
reservation = self.create_reservation()
|
||||
_, raw_token = ReservationToken.create_token(
|
||||
reservation=reservation,
|
||||
purpose=ReservationToken.Purpose.CONFIRMATION,
|
||||
expires_at=timezone.now() + timedelta(hours=2),
|
||||
)
|
||||
self.client.force_authenticate(user=self.staff_user)
|
||||
|
||||
response = self.client.post(
|
||||
reverse("api-check-in-confirm"),
|
||||
{"token": raw_token},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||
self.assertEqual(response.data["status"], "invalid_token")
|
||||
self.assertFalse(CheckIn.objects.filter(reservation=reservation).exists())
|
||||
|
||||
def create_reservation(self, **overrides):
|
||||
data = {
|
||||
"performance": self.performance,
|
||||
|
||||
@@ -62,6 +62,17 @@ class CheckInServiceTests(TestCase):
|
||||
with self.assertRaises(InvalidToken):
|
||||
preview_check_in_token("invalid-token", staff_user=self.staff_user)
|
||||
|
||||
def test_preview_rejects_confirmation_token_even_for_confirmed_reservation(self):
|
||||
reservation = self.create_reservation()
|
||||
_, raw_token = ReservationToken.create_token(
|
||||
reservation=reservation,
|
||||
purpose=ReservationToken.Purpose.CONFIRMATION,
|
||||
expires_at=timezone.now() + timedelta(hours=2),
|
||||
)
|
||||
|
||||
with self.assertRaises(InvalidToken):
|
||||
preview_check_in_token(raw_token, staff_user=self.staff_user)
|
||||
|
||||
def test_check_in_succeeds_for_confirmed_reservation(self):
|
||||
reservation = self.create_reservation()
|
||||
_, raw_token = self.create_check_in_token(reservation)
|
||||
@@ -114,6 +125,17 @@ class CheckInServiceTests(TestCase):
|
||||
with self.assertRaises(MissingStaffUser):
|
||||
confirm_check_in_from_token(raw_token, staff_user=None)
|
||||
|
||||
def test_check_in_rejects_confirmation_token_even_for_confirmed_reservation(self):
|
||||
reservation = self.create_reservation()
|
||||
_, raw_token = ReservationToken.create_token(
|
||||
reservation=reservation,
|
||||
purpose=ReservationToken.Purpose.CONFIRMATION,
|
||||
expires_at=timezone.now() + timedelta(hours=2),
|
||||
)
|
||||
|
||||
with self.assertRaises(InvalidToken):
|
||||
confirm_check_in_from_token(raw_token, staff_user=self.staff_user)
|
||||
|
||||
def create_reservation(self, **overrides):
|
||||
data = {
|
||||
"performance": self.performance,
|
||||
|
||||
Reference in New Issue
Block a user