config: Create cache database files with 0o600 mode.

I wasn't too worried about this earlier because the cache mainly stores
a bunch of numbers, but there's a little more than that: the generated
URLs also include original attachment filenames, which might be sensitive
(referencing people's names, bank names, etc.). Tighten security
accordingly.
This commit is contained in:
Brett Smith 2020-03-27 10:55:30 -04:00
parent a8407c7b6a
commit 33cb734b19
2 changed files with 20 additions and 3 deletions

View file

@ -134,7 +134,13 @@ class Config:
credentials.user, credentials.user,
urlparse.quote(str(credentials.server), ''), urlparse.quote(str(credentials.server), ''),
) )
cache_db = rtutil.RTLinkCache.setup(cache_dir_path / cache_name) cache_path = cache_dir_path / cache_name
try:
cache_path.touch(0o600)
except OSError:
# RTLinkCache.setup() will handle the problem.
pass
cache_db = rtutil.RTLinkCache.setup(cache_path)
return rtutil.RT(wrapper_client, cache_db) return rtutil.RT(wrapper_client, cache_db)
def rt_wrapper(self, def rt_wrapper(self,

View file

@ -74,6 +74,14 @@ def update_environ(**kwargs):
finally: finally:
_update_environ(revert) _update_environ(revert)
@contextlib.contextmanager
def update_umask(mask):
old_mask = os.umask(mask)
try:
yield old_mask
finally:
os.umask(old_mask)
def test_repository_from_environment(): def test_repository_from_environment():
config = config_mod.Config() config = config_mod.Config()
assert config.repository_path() == testutil.test_path('repository') assert config.repository_path() == testutil.test_path('repository')
@ -208,12 +216,15 @@ def test_rt_wrapper_cache_responds_to_external_credential_changes(rt_environ):
assert rt1 is not rt2 assert rt1 is not rt2
def test_rt_wrapper_has_cache(tmp_path): def test_rt_wrapper_has_cache(tmp_path):
with update_environ(XDG_CACHE_DIR=tmp_path): with update_environ(XDG_CACHE_DIR=tmp_path), update_umask(0o002):
config = config_mod.Config() config = config_mod.Config()
rt = config.rt_wrapper(None, testutil.RTClient) rt = config.rt_wrapper(None, testutil.RTClient)
rt.exists(1) rt.exists(1)
expected = 'conservancy_beancount/{}@*.sqlite3'.format(RT_FILE_CREDS[1]) expected = 'conservancy_beancount/{}@*.sqlite3'.format(RT_FILE_CREDS[1])
assert any(tmp_path.glob(expected)) actual = None
for actual in tmp_path.glob(expected):
assert not actual.stat().st_mode & 0o177
assert actual is not None, "did not find any generated cache file"
def test_rt_wrapper_without_cache(tmp_path): def test_rt_wrapper_without_cache(tmp_path):
tmp_path.chmod(0) tmp_path.chmod(0)