Skip to content

Commit

Permalink
Fix source_app.utils.normalize_timestamps
Browse files Browse the repository at this point in the history
  • Loading branch information
rmol committed Jan 20, 2021
1 parent cbcc894 commit dcb7551
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 6 deletions.
10 changes: 5 additions & 5 deletions securedrop/source_app/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,15 @@ def async_genkey(crypto_util_: CryptoUtil,

def normalize_timestamps(filesystem_id: str) -> None:
"""
Update the timestamps on all of the source's submissions to match that of
the latest submission. This minimizes metadata that could be useful to
investigators. See #301.
Update the timestamps on all of the source's submissions. This
minimizes metadata that could be useful to investigators. See
#301.
"""
sub_paths = [current_app.storage.path(filesystem_id, submission.filename)
for submission in g.source.submissions]
if len(sub_paths) > 1:
args = ["touch"]
args.extend(sub_paths[:-1])
args = ["touch", "--no-create"]
args.extend(sub_paths)
rc = subprocess.call(args)
if rc != 0:
current_app.logger.warning(
Expand Down
69 changes: 68 additions & 1 deletion securedrop/tests/test_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import shutil

from io import BytesIO, StringIO
from pathlib import Path

from flask import session, escape, url_for, g, request
from mock import patch, ANY

Expand All @@ -21,7 +23,7 @@
from models import InstanceConfig, Source, Reply
from source_app import main as source_app_main
from source_app import api as source_app_api
from .utils.db_helper import new_codename
from .utils.db_helper import new_codename, submit
from .utils.instrument import InstrumentedApp
from sdconfig import config

Expand Down Expand Up @@ -652,6 +654,71 @@ def test_login_with_overly_long_codename(source_app):
"Called hash_codename for codename w/ invalid length"


def test_normalize_timestamps(source_app):
"""
Check function of source_app.utils.normalize_timestamps.
All submissions for a source should have the same timestamp. Any
existing submissions' files that did not exist at the time of a
new submission should not be created by normalize_timestamps.
"""
with source_app.test_client() as app:
# create a source
source, codename = utils.db_helper.init_source()

# create one submission
first_submission = submit(source, 1)[0]

# delete the submission's file from the store
first_submission_path = Path(
source_app.storage.path(source.filesystem_id, first_submission.filename)
)
first_submission_path.unlink()
assert not first_submission_path.exists()

# log in as the source
resp = app.post(url_for('main.login'),
data=dict(codename=codename),
follow_redirects=True)
assert resp.status_code == 200
text = resp.data.decode('utf-8')
assert "Submit Files" in text
assert session['logged_in'] is True

# submit another message
resp = _dummy_submission(app)
assert resp.status_code == 200
text = resp.data.decode('utf-8')
assert "Thanks! We received your message" in text

# sleep to ensure timestamps would differ
time.sleep(1)

# submit another message
resp = _dummy_submission(app)
assert resp.status_code == 200
text = resp.data.decode('utf-8')
assert "Thanks! We received your message" in text

# only two of the source's three submissions should have files in the store
assert 3 == len(source.submissions)
submission_paths = [
Path(source_app.storage.path(source.filesystem_id, s.filename))
for s in source.submissions
]
extant_paths = [p for p in submission_paths if p.exists()]
assert 2 == len(extant_paths)

# verify that the deleted file has not been recreated
assert not first_submission_path.exists()
assert first_submission_path not in extant_paths

# and the timestamps of all existing files should match exactly
assert extant_paths[0].stat().st_atime_ns == extant_paths[1].stat().st_atime_ns
assert extant_paths[0].stat().st_ctime_ns == extant_paths[1].stat().st_ctime_ns
assert extant_paths[0].stat().st_mtime_ns == extant_paths[1].stat().st_mtime_ns


def test_failed_normalize_timestamps_logs_warning(source_app):
"""If a normalize timestamps event fails, the subprocess that calls
touch will fail and exit 1. When this happens, the submission should
Expand Down

0 comments on commit dcb7551

Please sign in to comment.