From f06e1a58ff25a68c7be9b253ecaa28bec0474dae Mon Sep 17 00:00:00 2001 From: Giovanni Pellerano Date: Thu, 25 Aug 2022 17:15:03 +0200 Subject: [PATCH 1/2] Replace usage of python random module with python secrets module --- securedrop/loaddata.py | 13 ++++++----- securedrop/passphrases.py | 2 +- securedrop/source_user.py | 2 +- securedrop/tests/migrations/helpers.py | 9 ++++---- .../migrations/migration_48a75abc0121.py | 23 ++++++++++--------- 5 files changed, 26 insertions(+), 23 deletions(-) diff --git a/securedrop/loaddata.py b/securedrop/loaddata.py index 2e82b15142..857c12c609 100755 --- a/securedrop/loaddata.py +++ b/securedrop/loaddata.py @@ -11,6 +11,7 @@ import math import os import random +import secrets import string from itertools import cycle from pathlib import Path @@ -65,14 +66,14 @@ def random_bool() -> bool: """ Flips a coin. """ - return random.choice((True, False)) + return secrets.choice((True, False)) def random_chars(count: int, chars: str = string.ascii_letters) -> str: """ Returns a random string of len characters from the supplied list. """ - return "".join([random.choice(chars) for _ in range(count)]) + return "".join([secrets.choice(chars) for _ in range(count)]) def random_datetime(nullable: bool) -> Optional[datetime.datetime]: @@ -330,11 +331,11 @@ def add_sources(args: argparse.Namespace, journalists: Tuple[Journalist, ...]) - source, codename = add_source() for _ in range(args.messages_per_source): - submit_message(source, random.choice(journalists) if seen_message_count > 0 else None) + submit_message(source, secrets.choice(journalists) if seen_message_count > 0 else None) seen_message_count -= 1 for _ in range(args.files_per_source): - submit_file(source, random.choice(journalists) if seen_file_count > 0 else None) + submit_file(source, secrets.choice(journalists) if seen_file_count > 0 else None) seen_file_count -= 1 if i <= starred_sources_count: @@ -342,8 +343,8 @@ def add_sources(args: argparse.Namespace, journalists: Tuple[Journalist, ...]) - if i <= replied_sources_count: for _ in range(args.replies_per_source): - journalist_who_replied = random.choice([dellsberg, journalist_to_be_deleted]) - journalist_who_saw = random.choice([default_journalist, None]) + journalist_who_replied = secrets.choice([dellsberg, journalist_to_be_deleted]) + journalist_who_saw = secrets.choice([default_journalist, None]) add_reply(source, journalist_who_replied, journalist_who_saw) print( diff --git a/securedrop/passphrases.py b/securedrop/passphrases.py index c3ce21ddc2..7f88db3a51 100644 --- a/securedrop/passphrases.py +++ b/securedrop/passphrases.py @@ -1,5 +1,5 @@ from pathlib import Path -from random import SystemRandom +from secrets import SystemRandom from typing import Dict, List, NewType, Optional, Set from sdconfig import config diff --git a/securedrop/source_user.py b/securedrop/source_user.py index 862050ceb2..c477359cd9 100644 --- a/securedrop/source_user.py +++ b/securedrop/source_user.py @@ -2,7 +2,7 @@ from base64 import b32encode from functools import lru_cache from pathlib import Path -from random import SystemRandom +from secrets import SystemRandom from typing import TYPE_CHECKING, List, Optional import models diff --git a/securedrop/tests/migrations/helpers.py b/securedrop/tests/migrations/helpers.py index c658dd703a..5d685ef424 100644 --- a/securedrop/tests/migrations/helpers.py +++ b/securedrop/tests/migrations/helpers.py @@ -1,16 +1,17 @@ # -*- coding: utf-8 -*- import random +import secrets import string from datetime import datetime def random_bool(): - return bool(random.getrandbits(1)) + return bool(secrets.getrandbits(1)) def bool_or_none(): - return random.choice([None, True, False]) + return secrets.choice([None, True, False]) def random_bytes(min, max, nullable): @@ -32,11 +33,11 @@ def random_username(): def random_chars(len, chars=string.printable): - return "".join([random.choice(chars) for _ in range(len)]) + return "".join([secrets.choice(chars) for _ in range(len)]) def random_ascii_chars(len, chars=string.ascii_lowercase): - return "".join([random.choice(chars) for _ in range(len)]) + return "".join([secrets.choice(chars) for _ in range(len)]) def random_datetime(nullable): diff --git a/securedrop/tests/migrations/migration_48a75abc0121.py b/securedrop/tests/migrations/migration_48a75abc0121.py index f55dd67916..018056e1d8 100644 --- a/securedrop/tests/migrations/migration_48a75abc0121.py +++ b/securedrop/tests/migrations/migration_48a75abc0121.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import random +import secrets import string from uuid import uuid4 @@ -141,7 +142,7 @@ def add_message(source_id): "source_id": source_id, "filename": random_chars(50) + "-msg.gpg", "size": random.randint(0, 1024 * 1024 * 500), - "downloaded": random.choice([True, False]), + "downloaded": secrets.choice([True, False]), } sql = """ INSERT INTO submissions (uuid, source_id, filename, size, downloaded) @@ -156,7 +157,7 @@ def add_file(source_id): "source_id": source_id, "filename": random_chars(50) + "-doc.gz.gpg", "size": random.randint(0, 1024 * 1024 * 500), - "downloaded": random.choice([True, False]), + "downloaded": secrets.choice([True, False]), "checksum": "sha256:" + random_chars(64), } sql = """ @@ -257,14 +258,14 @@ def check_upgrade(self): # Now seen tables exist, so you should be able to mark some files, messages, and replies # as seen for submission in submissions: - if submission.filename.endswith("-doc.gz.gpg") and random.choice([0, 1]): + if submission.filename.endswith("-doc.gz.gpg") and secrets.choice([0, 1]): selected_journo_id = random.randint(0, self.JOURNO_NUM) self.mark_file_as_seen(submission.id, selected_journo_id) - elif random.choice([0, 1]): + elif secrets.choice([0, 1]): selected_journo_id = random.randint(0, self.JOURNO_NUM) self.mark_message_as_seen(submission.id, selected_journo_id) for reply in replies: - if random.choice([0, 1]): + if secrets.choice([0, 1]): selected_journo_id = random.randint(0, self.JOURNO_NUM) self.mark_reply_as_seen(reply.id, selected_journo_id) @@ -338,30 +339,30 @@ def load_data(self): sql = "SELECT * FROM submissions" submissions = db.engine.execute(text(sql)).fetchall() for submission in submissions: - if submission.filename.endswith("-doc.gz.gpg") and random.choice([0, 1]): + if submission.filename.endswith("-doc.gz.gpg") and secrets.choice([0, 1]): selected_journo_id = random.randint(0, self.JOURNO_NUM) self.mark_file_as_seen(submission.id, selected_journo_id) - elif random.choice([0, 1]): + elif secrets.choice([0, 1]): selected_journo_id = random.randint(0, self.JOURNO_NUM) self.mark_message_as_seen(submission.id, selected_journo_id) sql = "SELECT * FROM replies" replies = db.engine.execute(text(sql)).fetchall() for reply in replies: - if random.choice([0, 1]): + if secrets.choice([0, 1]): selected_journo_id = random.randint(0, self.JOURNO_NUM) self.mark_reply_as_seen(reply.id, selected_journo_id) # Mark some files, messages, and replies as seen for submission in submissions: - if submission.filename.endswith("-doc.gz.gpg") and random.choice([0, 1]): + if submission.filename.endswith("-doc.gz.gpg") and secrets.choice([0, 1]): selected_journo_id = random.randint(0, self.JOURNO_NUM) self.mark_file_as_seen(submission.id, selected_journo_id) - elif random.choice([0, 1]): + elif secrets.choice([0, 1]): selected_journo_id = random.randint(0, self.JOURNO_NUM) self.mark_message_as_seen(submission.id, selected_journo_id) for reply in replies: - if random.choice([0, 1]): + if secrets.choice([0, 1]): selected_journo_id = random.randint(0, self.JOURNO_NUM) self.mark_reply_as_seen(reply.id, selected_journo_id) From 072dfaaec56e05433983e474b1614d55de04dfb9 Mon Sep 17 00:00:00 2001 From: Giovanni Pellerano Date: Mon, 29 Aug 2022 20:51:23 +0200 Subject: [PATCH 2/2] Apply correction as for pull request review by @legoktm --- securedrop/tests/migrations/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/securedrop/tests/migrations/helpers.py b/securedrop/tests/migrations/helpers.py index 5d685ef424..96fedb1003 100644 --- a/securedrop/tests/migrations/helpers.py +++ b/securedrop/tests/migrations/helpers.py @@ -7,7 +7,7 @@ def random_bool(): - return bool(secrets.getrandbits(1)) + return bool(secrets.randbits(1)) def bool_or_none():