Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 15 additions & 0 deletions packages/hidp/hidp/accounts/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,21 @@ class Meta:
model = UserModel
fields = (UserModel.USERNAME_FIELD,)

def __init__(self, *args, request=None, **kwargs):
super().__init__(*args, **kwargs)
self.request = request

def get_context(self):
context = super().get_context()

# the request context processor does not add the request into form contexts
# manually add request into context for form templates to use
# (for example for csp nonce)
if self.request:
context["request"] = self.request

return context

def _get_validation_exclusions(self):
# Exclude email from model validation (unique constraint),
# This will make the form valid even if the email is already in use.
Expand Down
7 changes: 7 additions & 0 deletions packages/hidp/hidp/accounts/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ def _build_provider_url_list(
label=label or _("Sign up using {provider}"),
)

def get_form_kwargs(self):
kwargs = super().get_form_kwargs()

# provide request object to form so it can be added to template context
kwargs["request"] = self.request
return kwargs

def get_context_data(self, **kwargs):
login_url = resolve_url(settings.LOGIN_URL) + (
f"?{urlencode({'next': redirect_url})}"
Expand Down
5 changes: 4 additions & 1 deletion packages/hidp/hidp/csp/templatetags/csp_nonce.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@

@register.simple_tag(takes_context=True)
def csp_nonce(context):
return getattr(context.request, "hidp_csp_nonce", None)
# if it's not an attribute on the context object,
# try looking for manually inserted request object
request = getattr(context, "request", None) or context["request"]
return getattr(request, "hidp_csp_nonce", None)
Original file line number Diff line number Diff line change
@@ -1 +1,107 @@
{% extends 'hidp/includes/forms/base_form.html' %}

{% load csp_nonce %}

{% block form %}

{% comment %}
the following is a modified version of /django/forms/templates/django/forms/div.html
{% endcomment %}
<style>
form label {
display: inline-block;
}

#info-tooltip,
#info-tooltip summary {
display: inline;
}

#info-tooltip svg {
width: 1rem;
height: 1rem;
vertical-align: sub;
cursor: pointer;
user-select: none;
}
</style>

{{ errors }}
{% if errors and not fields %}
<div>{% for field in hidden_fields %}{{ field }}{% endfor %}</div>
{% endif %}
{% for field, errors in fields %}
<div
{% with classes=field.css_classes %}
{% if classes %}
class="{{ classes }} input-div"
{% else %}
class="input-div"
{% endif %}
{% endwith %}
>
{% if field.use_fieldset %}
<fieldset>
{% if field.label %}{{ field.legend_tag }}{% endif %}
{% else %}
{% if field.label %}{{ field.label_tag }}{% endif %}
{% endif %}

{% if field.name == "password1" %}
<details id="info-tooltip">
<summary>
{% comment %} inline svg so stroke can pick up the "currentColor" {% endcomment %}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<!-- Icon from IconaMoon by Dariush Habibpour - https://creativecommons.org/licenses/by/4.0/ -->
<g fill="none" stroke="currentColor" stroke-linejoin="round">
<circle cx="12" cy="12" r="9" stroke-linecap="round" stroke-width="1.5"/>
<path stroke-width="2.25" d="M12 8h.01v.01H12z"/>
<path stroke-linecap="round" stroke-width="1.5" d="M12 12v4"/>
</g>
</svg>
</summary>
<div class="helptext">{{ field.help_text|safe }}</div>
</details>
<script nonce="{% csp_nonce %}" defer>
let openedByHover = false
const toolTipElement = document.getElementById('info-tooltip')

toolTipElement.addEventListener('mouseenter', () => {
if (!toolTipElement.open) {
toolTipElement.open = true
openedByHover = true
}
})

toolTipElement.addEventListener('mouseleave', () => {
if (toolTipElement.open && openedByHover) {
toolTipElement.removeAttribute('open')
openedByHover = false
}
})

toolTipElement.addEventListener('click', (event) => {
// if opened by hover and click, keep it open and mark it as not opened by hover
if (openedByHover) {
event.stopPropagation()
event.preventDefault()
openedByHover = false
}
})
</script>
{% elif field.help_text %}
<div class="helptext">{{ field.help_text|safe }}</div>
{% endif %}

{{ errors }}
{{ field }}
{% if field.use_fieldset %}</fieldset>{% endif %}
{% if forloop.last %}
{% for field in hidden_fields %}{{ field }}{% endfor %}
{% endif %}
</div>
{% endfor %}
{% if not fields and not errors %}
{% for field in hidden_fields %}{{ field }}{% endfor %}
{% endif %}
{% endblock %}
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
{% extends 'django/forms/div.html' %}
{% block form %}
{% include 'django/forms/div.html' %}
{% endblock form %}