Skip to content

Commit

Permalink
Add configuration options in JI for length and codename checks.
Browse files Browse the repository at this point in the history
  • Loading branch information
zenmonkeykstop committed Feb 28, 2022
1 parent 7d152ea commit 2a37036
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 13 deletions.
24 changes: 21 additions & 3 deletions securedrop/journalist_app/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ def index() -> str:
def manage_config() -> Union[str, werkzeug.Response]:
# The UI prompt ("prevent") is the opposite of the setting ("allow"):
submission_preferences_form = SubmissionPreferencesForm(
prevent_document_uploads=not InstanceConfig.get_default().allow_document_uploads)
prevent_document_uploads=not InstanceConfig.get_default().allow_document_uploads,
min_message_length=InstanceConfig.get_default().initial_message_min_len,
reject_codename_messages=InstanceConfig.get_default().reject_message_with_codename
)
organization_name_form = OrgNameForm(
organization_name=InstanceConfig.get_default().organization_name)
logo_form = LogoForm()
Expand Down Expand Up @@ -75,9 +78,24 @@ def update_submission_preferences() -> Optional[werkzeug.Response]:
form = SubmissionPreferencesForm()
if form.validate_on_submit():
# The UI prompt ("prevent") is the opposite of the setting ("allow"):
allow_uploads = not form.prevent_document_uploads.data

try:
msg_length = form.min_message_length.data

if isinstance(msg_length, int):
int_length = msg_length
elif isinstance(msg_length, str):
int_length = int(msg_length)
else:
int_length = 0
except ValueError:
int_length = 0

reject_codenames = form.reject_codename_messages.data

InstanceConfig.update_submission_prefs(allow_uploads, int_length, reject_codenames)
flash(gettext("Preferences saved."), "submission-preferences-success")
value = not bool(request.form.get('prevent_document_uploads'))
InstanceConfig.set_allow_document_uploads(value)
return redirect(url_for('admin.manage_config') + "#config-preventuploads")
else:
for field, errors in list(form.errors.items()):
Expand Down
21 changes: 19 additions & 2 deletions securedrop/journalist_app/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed, FileRequired
from wtforms import Field
from wtforms import (TextAreaField, StringField, BooleanField, HiddenField,
from wtforms import (TextAreaField, StringField, BooleanField, HiddenField, IntegerField,
ValidationError)
from wtforms.validators import InputRequired, Optional, DataRequired, StopValidation

Expand Down Expand Up @@ -89,6 +89,12 @@ def check_invalid_usernames(form: FlaskForm, field: Field) -> None:
"This username is invalid because it is reserved for internal use by the software."))


def check_message_length(form: FlaskForm, field: Field) -> None:
msg_len = field.data
if not isinstance(msg_len, int) or msg_len < 0:
raise ValidationError(gettext("Please specify an integer value greater than 0."))


class NewUserForm(FlaskForm):
username = StringField('username', validators=[
InputRequired(message=gettext('This field is required.')),
Expand Down Expand Up @@ -121,7 +127,18 @@ class ReplyForm(FlaskForm):


class SubmissionPreferencesForm(FlaskForm):
prevent_document_uploads = BooleanField('prevent_document_uploads')
prevent_document_uploads = BooleanField(
'prevent_document_uploads',
false_values=('false', 'False', '')
)
min_message_length = IntegerField('min_message_length', validators=[check_message_length],
render_kw={
'aria-describedby': 'message-length-notes',
'class': 'short_int_field'})
reject_codename_messages = BooleanField(
'reject_codename_messages',
false_values=('false', 'False', '')
)


class OrgNameForm(FlaskForm):
Expand Down
18 changes: 16 additions & 2 deletions securedrop/journalist_templates/config.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,23 @@ <h2 id="config-preventuploads">{{ gettext('Submission Preferences') }}</h2>

<form action="{{ url_for('admin.update_submission_preferences') }}" method="post">
<input name="csrf_token" type="hidden" value="{{ csrf_token() }}">
{{ submission_preferences_form.prevent_document_uploads() }}
<label
<div class="config_form_element">
{{ submission_preferences_form.prevent_document_uploads() }}
<label
for="prevent_document_uploads">{{ gettext('Prevent sources from uploading documents. Sources will still be able to send messages.') }}</label>
</div>

<div class="config_form_element">
{{ submission_preferences_form.min_message_length() }}
<label
for="min_message_length">{{ gettext('Minimum message length in chars for sources\' first submission if no document included. Set to 0 to disable.') }}</label>
</div>

<div class="config_form_element">
{{ submission_preferences_form.reject_codename_messages() }}
<label
for="reject_codename_messages">{{ gettext('Prevent sources from submitting their codename as a message') }}</label>
</div>
<div class="section-spacing">
<button type="submit" id="submit-submission-preferences" class="icon icon-edit"
aria-label="{{ gettext('Update Submission Preferences') }}">
Expand Down
13 changes: 10 additions & 3 deletions securedrop/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1019,17 +1019,24 @@ def set_organization_name(cls, name: str) -> None:
db.session.commit()

@classmethod
def set_allow_document_uploads(cls, value: bool) -> None:
def update_submission_prefs(
cls,
allow_uploads: bool,
min_length: int,
reject_codenames: bool
) -> None:
'''Invalidate the current configuration and append a new one with the
requested change.
updated submission preferences.
'''

old = cls.get_current()
old.valid_until = datetime.datetime.utcnow()
db.session.add(old)

new = old.copy()
new.allow_document_uploads = value
new.allow_document_uploads = allow_uploads
new.initial_message_min_len = min_length
new.reject_message_with_codename = reject_codenames
db.session.add(new)

db.session.commit()
Expand Down
7 changes: 6 additions & 1 deletion securedrop/tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,8 @@ def test_prevent_document_uploads(source_app, journalist_app, test_admin):
with journalist_app.test_client() as app:
_login_user(app, test_admin)
form = journalist_app_module.forms.SubmissionPreferencesForm(
prevent_document_uploads=True)
prevent_document_uploads=True,
min_message_length=0)
resp = app.post('/admin/update-submission-preferences',
data=form.data,
follow_redirects=True)
Expand Down Expand Up @@ -712,7 +713,11 @@ def test_no_prevent_document_uploads(source_app, journalist_app, test_admin):
# Set allow_document_uploads = True:
with journalist_app.test_client() as app:
_login_user(app, test_admin)
form = journalist_app_module.forms.SubmissionPreferencesForm(
prevent_document_uploads=False,
min_message_length=0)
resp = app.post('/admin/update-submission-preferences',
data=form.data,
follow_redirects=True)
assert resp.status_code == 200

Expand Down
10 changes: 8 additions & 2 deletions securedrop/tests/test_journalist.py
Original file line number Diff line number Diff line change
Expand Up @@ -1813,7 +1813,8 @@ def test_prevent_document_uploads(config, journalist_app, test_admin, locale):
_login_user(app, test_admin['username'], test_admin['password'],
test_admin['otp_secret'])
form = journalist_app_module.forms.SubmissionPreferencesForm(
prevent_document_uploads=True)
prevent_document_uploads=True,
min_message_length=0)
app.post(url_for('admin.update_submission_preferences'),
data=form.data,
follow_redirects=True)
Expand All @@ -1836,12 +1837,16 @@ def test_no_prevent_document_uploads(config, journalist_app, test_admin, locale)
with journalist_app.test_client() as app:
_login_user(app, test_admin['username'], test_admin['password'],
test_admin['otp_secret'])
form = journalist_app_module.forms.SubmissionPreferencesForm(
min_message_length=0)
app.post(url_for('admin.update_submission_preferences'),
data=form.data,
follow_redirects=True)
assert InstanceConfig.get_current().allow_document_uploads is True
with InstrumentedApp(journalist_app) as ins:
resp = app.post(
url_for('admin.update_submission_preferences', l=locale),
data=form.data,
follow_redirects=True
)
assert InstanceConfig.get_current().allow_document_uploads is True
Expand All @@ -1856,7 +1861,8 @@ def test_prevent_document_uploads_invalid(journalist_app, test_admin):
_login_user(app, test_admin['username'], test_admin['password'],
test_admin['otp_secret'])
form_true = journalist_app_module.forms.SubmissionPreferencesForm(
prevent_document_uploads=True)
prevent_document_uploads=True,
min_message_length=0)
app.post(url_for('admin.update_submission_preferences'),
data=form_true.data,
follow_redirects=True)
Expand Down

0 comments on commit 2a37036

Please sign in to comment.