Skip to content

Commit 419210a

Browse files
authored
Merge pull request #909 from endlessm/T35159-validate-saved-state
collectionviews: Ignore session state if it uses the wrong format
2 parents a8dacd2 + 4743786 commit 419210a

File tree

1 file changed

+35
-8
lines changed

1 file changed

+35
-8
lines changed

kolibri_explore_plugin/collectionviews.py

+35-8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import time
77
from enum import auto
88
from enum import IntEnum
9+
from threading import RLock
910

1011
from django.utils.translation import gettext_lazy as _
1112
from kolibri.core.content.errors import InsufficientStorageSpaceError
@@ -72,6 +73,8 @@
7273
"completed": 1,
7374
}
7475

76+
ENSURE_INITIATED_RLOCK = RLock()
77+
7578

7679
class ChannelNotImported(Exception):
7780
pass
@@ -639,6 +642,20 @@ def to_state(self):
639642

640643
return state
641644

645+
def validate_state(self, state):
646+
"""Check a serialized representation of this download manager's state.
647+
648+
Returns True if the state is valid.
649+
"""
650+
651+
required_keys = (
652+
"collection_name",
653+
"collection_sequence",
654+
"stage",
655+
)
656+
657+
return all(key in state for key in required_keys)
658+
642659
def _next_task_or_stage(self, user):
643660
if not self._tasks_pending:
644661
# No more tasks pending in this stage, move to the next one
@@ -749,8 +766,9 @@ def ensure_initiated(api_function):
749766
"""Decorator to initiate only once in the first API call."""
750767

751768
def wrapper(*args, **kwargs):
752-
if _collection_download_manager is None:
753-
_read_content_manifests()
769+
with ENSURE_INITIATED_RLOCK:
770+
if _collection_download_manager is None:
771+
_read_content_manifests()
754772
return api_function(*args, **kwargs)
755773

756774
return wrapper
@@ -766,6 +784,15 @@ def _save_state_in_request_session(request):
766784
request.session["COLLECTIONS_STATE"] = new_state
767785

768786

787+
def _read_state_from_request_session(request):
788+
saved_state = request.session.get("COLLECTIONS_STATE", {})
789+
790+
if _collection_download_manager.validate_state(saved_state):
791+
return saved_state
792+
793+
return None
794+
795+
769796
def _get_collections_info_by_name_sequence(name, sequence):
770797
if name not in _collections_by_name_sequence:
771798
return None
@@ -843,7 +870,7 @@ def get_all_collections_info(request):
843870
@api_view(["GET"])
844871
def get_should_resume(request):
845872
"""Return if there is a saved state that should be resumed."""
846-
saved_state = request.session.get("COLLECTIONS_STATE")
873+
saved_state = _read_state_from_request_session(request)
847874
name = None
848875
sequence = None
849876
if saved_state is not None:
@@ -881,7 +908,7 @@ def start_download(request):
881908
collection = _collections_by_name_sequence[name][sequence]
882909

883910
# Fail if a previous download can be resumed
884-
saved_state = request.session.get("COLLECTIONS_STATE")
911+
saved_state = _read_state_from_request_session(request)
885912
if saved_state is not None:
886913
raise APIException("A previous download state was found. Resume it.")
887914

@@ -910,15 +937,15 @@ def resume_download(request):
910937
Returns download status.
911938
"""
912939

913-
saved_state = request.session.get("COLLECTIONS_STATE")
940+
saved_state = _read_state_from_request_session(request)
914941
if saved_state is None:
915942
raise APIException("No download state was found. Can't resume.")
916943

917944
# Init the download manager and start downloading
918945
try:
919946
_collection_download_manager.from_state(saved_state)
920-
name = saved_state["name"]
921-
sequence = saved_state["sequence"]
947+
name = saved_state["collection_name"]
948+
sequence = saved_state["collection_sequence"]
922949
logger.info(f"Download resumed for name={name} sequence={sequence}")
923950
logger.info(f"Resumed download state: {saved_state}")
924951
except DownloadError as err:
@@ -979,7 +1006,7 @@ def cancel_download(request):
9791006
def get_download_status(request):
9801007
"""Return the download status."""
9811008

982-
saved_state = request.session.get("COLLECTIONS_STATE")
1009+
saved_state = _read_state_from_request_session(request)
9831010
if (
9841011
_collection_download_manager.is_state_unset()
9851012
and saved_state is not None

0 commit comments

Comments
 (0)