Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Carry next URL through authentication #4347

Draft
wants to merge 49 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
f6969a2
Fixes the copyright notice label.
ajrbyers Sep 13, 2024
d75ddef
Add Dutch translation for copyright help text #4409
joemull Sep 16, 2024
81020ae
Reverts account and frozen author fields to charfields.
ajrbyers Sep 13, 2024
4123003
Adds a button_classes var to style ORCID reg btn
ajrbyers Sep 13, 2024
5a26ba1
#4405: Adds plain text sanitizer for model/forms
mauromsl Sep 17, 2024
8dc372d
#4405: Flag models to use new HTML sanitizer
mauromsl Sep 17, 2024
8fc72f4
#4405: Update validators on migrations
mauromsl Sep 17, 2024
99b66a3
#4405: Adds unit tests
mauromsl Sep 17, 2024
dc7a7a7
4405: Adds acceptance tests
mauromsl Sep 17, 2024
4d5dec8
Sets default class for orcid reg button.
ajrbyers Sep 18, 2024
dae095c
#3337: Undo orcid login template breaking change
mauromsl Sep 17, 2024
cce7179
#4412 Combine recommendation display checks into one.
ajrbyers Sep 18, 2024
ac63374
#4412 include reviews_small in previous change.
ajrbyers Sep 18, 2024
a2527d7
Update default typesetting guide openlibhums/typesetting#31
joemull Sep 23, 2024
aed1e6b
Fixes a bug where submit_info would clear CI.
ajrbyers Sep 24, 2024
2123e63
Reverts previous change. Adds new subclass that adds competing_intere…
ajrbyers Sep 24, 2024
83a1314
Remove import.
ajrbyers Sep 24, 2024
fcd6ce7
Initial WIP. Adds setting and filter.
ajrbyers Sep 20, 2024
279c6aa
Moves to securitytags, adds checks.
ajrbyers Sep 20, 2024
ec1ed8e
#4417 adds a tag for PII can_see_pii_tag
ajrbyers Sep 20, 2024
88b0e36
#4417 applies filter/tags to metadata screen.
ajrbyers Sep 20, 2024
f3f4acd
#4417 adds checks to edit/metadata.html
ajrbyers Sep 20, 2024
8517f05
#4417 anonymises the edit metadata template
ajrbyers Sep 20, 2024
5c5aecc
#4417 anonymises the article log
ajrbyers Sep 20, 2024
ec9d353
Moves logic to logic.py module
mauromsl Sep 24, 2024
9ac9dff
Adds new security decorator for SE PII check
mauromsl Sep 24, 2024
d665aa9
Use new decorator on document manager
mauromsl Sep 24, 2024
abb2f28
Adds security decorator test case
mauromsl Sep 24, 2024
e5b2a1c
Adds utility for cleanly overriding janeway setting in test
mauromsl Sep 24, 2024
b98714c
Fix wrong logic on new SE PII checks
mauromsl Sep 24, 2024
d035bd4
Fix test
mauromsl Sep 24, 2024
134004c
#4417 include STAGE_ASSIGNED in list of stages
ajrbyers Sep 24, 2024
e12635c
#4417 include securitytags as a builtin tag set
ajrbyers Sep 24, 2024
f48bbc3
#4417 add se screening filter to draft templates
ajrbyers Sep 24, 2024
578ed7b
#4417 adds filter to revision complete updates pii filter description
ajrbyers Sep 24, 2024
a4118de
#4417 add custom_reply_to to send_revisions_complete
ajrbyers Sep 24, 2024
e137592
#4417 addd migration to add pii filter to templates
ajrbyers Sep 24, 2024
ae03ef9
#4417 adds a test for edited views.
ajrbyers Sep 25, 2024
b88d0b4
#4417 change setting description
ajrbyers Sep 25, 2024
e77d7a7
#4417 fix typo
ajrbyers Sep 25, 2024
fafc5ce
#4417 changes wording and marks for translation
ajrbyers Sep 25, 2024
dc710dd
#4417 updates test.
ajrbyers Sep 25, 2024
e439093
#4417 Add security decorator to file_history view.
ajrbyers Sep 25, 2024
9a400a8
#4417 fix visible pii.
ajrbyers Sep 25, 2024
26b8d1c
#4417 include department in checks.
ajrbyers Sep 25, 2024
2e7b1b1
#4417 adds additional PII to test.
ajrbyers Sep 26, 2024
ecc05d4
Fix bug that double-encoded URL query #4291 #3899
joemull Jun 24, 2024
5c1d67c
Fix bug that garbled redirect query string #4042 #3899
joemull Jun 24, 2024
b15a1a9
WIP
joemull Aug 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/core/janeway_global_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@
],
'builtins': [
'core.templatetags.fqdn',
'security.templatetags.securitytags',
'django.templatetags.i18n',
]
},
Expand Down
2 changes: 1 addition & 1 deletion src/core/locales/cy/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ msgstr ""

#: src/core/views.py:355
msgid ""
"Your account has been created, please follow theinstructions in the email "
"Your account has been created. Please follow theinstructions in the email "
"that has been sent to you."
msgstr ""

Expand Down
2 changes: 1 addition & 1 deletion src/core/locales/de/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ msgstr "Falls Ihr Konto gefunden wurde, wurde Ihnen eine E-Mail geschickt."

#: src/core/views.py:355
msgid ""
"Your account has been created, please follow theinstructions in the email "
"Your account has been created. Please follow the instructions in the email "
"that has been sent to you."
msgstr ""
"Ihr Konto wurde angelegt. Bitte folgen Sie den Anweisungen aus der E-Mail, "
Expand Down
2 changes: 1 addition & 1 deletion src/core/locales/en_us/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ msgstr ""

#: src/core/views.py:355
msgid ""
"Your account has been created, please follow theinstructions in the email "
"Your account has been created. Please follow the instructions in the email "
"that has been sent to you."
msgstr ""

Expand Down
4 changes: 3 additions & 1 deletion src/core/locales/es/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -4440,7 +4440,9 @@ msgid "\n"
msgstr ""

#: src/core/views.py:355
msgid "Your account has been created, please follow theinstructions in the email that has been sent to you."
msgid ""
"Your account has been created. Please follow the instructions in the email "
"that has been sent to you."
msgstr ""

#: src/core/views.py:400
Expand Down
2 changes: 1 addition & 1 deletion src/core/locales/fr/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ msgstr ""

#: src/core/views.py:355
msgid ""
"Your account has been created, please follow theinstructions in the email "
"Your account has been created. Please follow the instructions in the email "
"that has been sent to you."
msgstr ""

Expand Down
2 changes: 1 addition & 1 deletion src/core/locales/it/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ msgstr ""

#: src/core/views.py:355
msgid ""
"Your account has been created, please follow theinstructions in the email "
"Your account has been created. Please follow the instructions in the email "
"that has been sent to you."
msgstr ""

Expand Down
8 changes: 5 additions & 3 deletions src/core/locales/nl/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ msgstr ""

#: src/core/views.py:355
msgid ""
"Your account has been created, please follow theinstructions in the email "
"Your account has been created. Please follow the instructions in the email "
"that has been sent to you."
msgstr ""

Expand Down Expand Up @@ -2435,13 +2435,15 @@ msgstr ""
msgid ""
"All authors must agree to the below statements in order to submit an article "
"to"
msgstr ""
msgstr "Alle auteurs moeten zich akkoord verklaren met onderstaande stellingen "
"om een artikel te publiceren in"

#: src/templates/admin/submission/start.html:24
msgid ""
"If you do not agree with these terms you will be unable to proceed with your "
"submission."
msgstr ""
msgstr "Als je je niet akkoord verklaart met deze voorwaarden "
"kan je niet verdergaan met deze inzending."

#: src/templates/admin/submission/start.html:29
msgid "Publication Fees"
Expand Down
139 changes: 87 additions & 52 deletions src/core/logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@
import operator
import re
from functools import reduce
from urllib.parse import unquote, urlparse

from django.conf import settings
from django.contrib.auth import logout
from django.contrib import messages
from django.template.loader import get_template
from django.db.models import Q
from django.http import JsonResponse
from django.http import JsonResponse, QueryDict
from django.forms.models import model_to_dict
from django.shortcuts import reverse
from django.utils import timezone
Expand All @@ -35,81 +36,117 @@
logger = get_logger(__name__)


def get_raw_next_url(next_url, request):
"""
Get the next_url passed in or the 'next' on the request, as raw unicode.
:param next_url: an optional string with the path and query parts of
a destination URL -- overrides any 'next' in request data
:param request: HttpRequest, optionally containing 'next' in GET or POST
"""
if not next_url:
next_url = request.GET.get('next', '') or request.POST.get('next', '')
return unquote(next_url)


def reverse_with_next(url_name, request, next_url='', args=None, kwargs=None):
"""
Reverse a URL but keep the 'next' parameter that exists on the request
or that the caller wants to introduce.
The value of 'next' on the request or 'next_url' can be in raw unicode or
it can have been percent-encoded one time.
:param request: HttpRequest, optionally containing 'next' in GET or POST
:param next_url: an optional string with the path and query parts of
a destination URL -- overrides any 'next' in request data
:param args: args to pass to django.shortcuts.reverse, if no kwargs
:param kwargs: kwargs to pass to django.shortcuts.reverse, if no args
"""
# reverse can only accept either args or kwargs
if args:
reversed_url = reverse(url_name, args=args)
elif kwargs:
reversed_url = reverse(url_name, kwargs=kwargs)
else:
reversed_url = reverse(url_name)

raw_next_url = get_raw_next_url(next_url, request)

if not raw_next_url:
return reversed_url

if reversed_url == raw_next_url:
# Avoid circular next URLs
return reversed_url

# Parse the reversed URL string enough to safely update the query parameters.
# Then re-encode them into a query string and generate the final URL.
parsed_url = urlparse(reversed_url) # ParseResult
parsed_query = QueryDict(parsed_url.query, mutable=True) # mutable QueryDict
parsed_query.update({'next': raw_next_url})
# We treat / as safe to match the default behavior
# of the |urlencode template filter,
# which is where many next URLs are created
new_query_string = parsed_query.urlencode(safe="/") # Full percent-encoded query string
return parsed_url._replace(query=new_query_string).geturl()


def send_reset_token(request, reset_token):
core_reset_password_url = request.site_type.site_url(
reverse(
'core_reset_password',
kwargs={'token': reset_token.token},
)
),
query={'next': get_raw_next_url('', request)},
)
context = {
'reset_token': reset_token,
'core_reset_password_url': core_reset_password_url,
}
log_dict = {'level': 'Info', 'types': 'Reset Token', 'target': None}
if not request.journal:
message = render_template.get_message_content(
request,
context,
request.press.password_reset_text,
template_is_setting=True,
)
else:
message = render_template.get_message_content(
request,
context,
'password_reset',
)

subject = 'subject_password_reset'

notify_helpers.send_email_with_body_from_user(
notify_helpers.send_email_with_body_from_setting_template(
request,
subject,
'password_reset',
'subject_password_reset',
reset_token.account.email,
message,
context,
log_dict=log_dict,
)


def send_confirmation_link(request, new_user):
core_confirm_account_url = request.site_type.site_url(
def get_confirm_account_url(request, user, next_url=''):
return request.site_type.site_url(
reverse(
'core_confirm_account',
kwargs={'token': new_user.confirmation_code},
)
kwargs={'token': user.confirmation_code},
),
query={'next': get_raw_next_url(next_url, request)},
)


def send_confirmation_link(request, new_user):
core_confirm_account_url = get_confirm_account_url(request, new_user)
if request.journal:
site_name = request.journal.name
elif request.repository:
site_name = request.repository.name
else:
site_name = request.press.name
context = {
'user': new_user,
'site_name': site_name,
'core_confirm_account_url': core_confirm_account_url,
}
if not request.journal:
message = render_template.get_message_content(
request,
context,
request.press.registration_text,
template_is_setting=True,
)
else:
message = render_template.get_message_content(
request,
context,
'new_user_registration',
)

subject = 'subject_new_user_registration'

notify_helpers.send_slack(
request,
'New registration: {0}'.format(new_user.full_name()),
['slack_admins'],
)
log_dict = {'level': 'Info', 'types': 'Account Confirmation', 'target': None}
notify_helpers.send_email_with_body_from_user(
notify_helpers.send_email_with_body_from_setting_template(
request,
subject,
'new_user_registration',
'subject_new_user_registration',
new_user.email,
message,
context,
log_dict=log_dict,
)

Expand Down Expand Up @@ -644,20 +681,18 @@ def handle_article_thumb_image_file(uploaded_file, article, request):
article.save()


def handle_email_change(request, email_address):
def handle_email_change(request, email_address, next_url=''):
request.user.email = email_address
request.user.is_active = False
request.user.confirmation_code = uuid.uuid4()
request.user.clean()
request.user.save()

core_confirm_account_url = request.site_type.site_url(
reverse(
'core_confirm_account',
kwargs={'token': request.user.confirmation_code},
)
core_confirm_account_url = get_confirm_account_url(
request,
request.user,
next_url=next_url,
)

context = {
'user': request.user,
'core_confirm_account_url': core_confirm_account_url,
Expand Down Expand Up @@ -868,7 +903,7 @@ def check_for_bad_login_attempts(request):
time = timezone.now() - timedelta(minutes=10)

attempts = models.LoginAttempt.objects.filter(user_agent=user_agent, ip_address=ip_address, timestamp__gte=time)
print(time, attempts.count())
logger.debug(f'Bad login attempt {attempts.count()+1} at {time}')
return attempts.count()


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import core.model_utils
from django.db import migrations, models

import utils


class Migration(migrations.Migration):

Expand All @@ -19,32 +21,32 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='account',
name='department',
field=core.model_utils.JanewayBleachCharField(blank=True, max_length=300, verbose_name='Department'),
field=models.CharField(blank=True, max_length=300, verbose_name='Department', validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='account',
name='first_name',
field=core.model_utils.JanewayBleachCharField(max_length=300, verbose_name='First name'),
field=models.CharField(max_length=300, verbose_name='First name', validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='account',
name='institution',
field=core.model_utils.JanewayBleachCharField(blank=True, max_length=1000, verbose_name='Institution'),
field=models.CharField(blank=True, max_length=1000, verbose_name='Institution', validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='account',
name='last_name',
field=core.model_utils.JanewayBleachCharField(max_length=300, verbose_name='Last name'),
field=models.CharField(max_length=300, verbose_name='Last name', validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='account',
name='middle_name',
field=core.model_utils.JanewayBleachCharField(blank=True, max_length=300, verbose_name='Middle name'),
field=models.CharField(blank=True, max_length=300, verbose_name='Middle name', validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='account',
name='salutation',
field=core.model_utils.JanewayBleachCharField(blank=True, choices=[('Miss', 'Miss'), ('Ms', 'Ms'), ('Mrs', 'Mrs'), ('Mr', 'Mr'), ('Mx', 'Mx'), ('Dr', 'Dr'), ('Prof.', 'Prof.')], max_length=10, verbose_name='Salutation'),
field=models.CharField(blank=True, choices=[('Miss', 'Miss'), ('Ms', 'Ms'), ('Mrs', 'Mrs'), ('Mr', 'Mr'), ('Mx', 'Mx'), ('Dr', 'Dr'), ('Prof.', 'Prof.')], max_length=10, verbose_name='Salutation', validators=[utils.forms.plain_text_validator]),
),
migrations.AlterField(
model_name='account',
Expand All @@ -54,6 +56,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='account',
name='suffix',
field=core.model_utils.JanewayBleachCharField(blank=True, max_length=300, verbose_name='Name suffix'),
field=models.CharField(blank=True, max_length=300, verbose_name='Name suffix', validators=[utils.forms.plain_text_validator]),
),
]
Loading