Skip to content

Commit

Permalink
[client] Fix creating session file
Browse files Browse the repository at this point in the history
If we run multiple CodeChecker commands (login, store) which uses the same
home directory and the CodeChecker session file (`~/.codechecker.session.json`)
does not exist yet the following scenario is possible:
- The first command recognizes that this file doesn't exist yet so it will open
  this file for writing.
- Before the first command writes data to the file the second command will be run.
  It recognizes that the file exists, so it will read up the file. It expects that
  the file is a valid json file but it is empty. So the `token_dict` variable
  will be an empty dict, we try to get the `tokens` member of this empty
  dictionary (`self.__tokens`) which will be `None`, and when we will try to
  iterate over this directory (which is `None` in our case) the CodeChecker will
  raise an exception.

To solve this problem we will use `portalocker` after we opened the file to
lock it, so only one process will be able to read/write this file simultaneously.
Also we will handle the use case when this file is still empty.
  • Loading branch information
csordasmarton committed Feb 25, 2021
1 parent 6788bf4 commit a91b7b8
Showing 1 changed file with 20 additions and 14 deletions.
34 changes: 20 additions & 14 deletions web/client/codechecker_client/credential_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,22 +98,28 @@ def __init__(self):
self.token_file = get_session_file()
LOG.info("Checking for local valid sessions.")

if os.path.exists(self.token_file):
token_dict = load_json_or_empty(self.token_file, {},
"user authentication")
check_file_owner_rw(self.token_file)

self.__tokens = token_dict.get('tokens')
LOG.debug("Found session information for these hosts:")
for k, _ in self.__tokens.items():
LOG.debug(" %s", k)
else:
with open(self.token_file, 'w',
encoding="utf-8", errors="ignore") as f:
with open(self.token_file, 'a+',
encoding="utf-8", errors="ignore") as f:
f.seek(0)

portalocker.lock(f, portalocker.LOCK_EX)

try:
token_dict = json.loads(f.read())

check_file_owner_rw(self.token_file)

self.__tokens = token_dict.get('tokens', {})
LOG.debug("Found session information for these hosts:")
for k, _ in self.__tokens.items():
LOG.debug(" %s", k)
except json.JSONDecodeError:
json.dump({'tokens': {}}, f)
os.chmod(self.token_file, stat.S_IRUSR | stat.S_IWUSR)
os.chmod(self.token_file, stat.S_IRUSR | stat.S_IWUSR)

self.__tokens = {}

self.__tokens = {}
portalocker.unlock(f)

def is_autologin_enabled(self):
return self.__autologin
Expand Down

0 comments on commit a91b7b8

Please sign in to comment.