torchbox / tbxforms

A Torchbox-flavoured template pack for django-crispy-forms, adapted from crispy-forms-gds.

Home Page:https://pypi.org/project/tbxforms/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Code review notes

thibaudcolas opened this issue · comments

Follow-up to #5, this time focusing on things I spotted in our integration.

Wagtail functionality

There is Wagtail-specific functionality here:

from wagtail.contrib.forms.forms import FormBuilder

Do we really want Wagtail to be a dependency of tbxforms? It feels a bit odd to me, and makes the template pack somewhat harder to reuse and maintain since anyone using this will have to make sure their dependencies are compatible with those of Wagtail. Could we instead conditionally have this code (and the import) only run if wagtail.contrib.forms is in INSTALLED_APPS?

XSS injection vectors

The templates make a lot of use of |safe, which makes me feel wary at the very least, and will be a source of XSS vulnerabilities when forms are defined via user input (the Wagtail form builder in particular).

Testing the current implementation of BaseWagtailFormBuilder and the templates,

  • This makes it possible do an XSS injection via the fields’ label
  • The buttons label also allows XSS injection (input.value|safe in button.html)
  • The injection via help_text is prevented by WAGTAILFORMS_HELP_TEXT_ALLOW_HTML – so we’re good, but it’d be nice if similarly usage of |safe for help text was configurable within the template pack (rather than trusting it’s done upstream).
  • For sites that make it possible to do fieldsets and legends (with implementations like wagtailstreamforms), I’m pretty sure there would be more injection opportunities.

So – I’d suggest:

  1. Removing the |safe for anything that doesn’t strictly need it
  2. For things that do need it, checking whether there might be more bespoke sanitisation we could introduce
  3. Documenting which things we’d expect implementers of the template pack to sanitise themselves

IE11 compatibility

The conditional fields don’t work for me in IE11. There is ES6+ syntax used in the published code, which creates a syntax error in IE11:

class TbxForms {
  static selector() {
    return "form.tbxforms";
  }

It looks like Vite (esbuild) unfortunately doesn’t support compiling down to ES5 (what we’d need for IE11 compatibility), the build.target only goes down to es2015 (ES6).

The simplest way to fix this would be to rewrite the JS code to not use the class syntax (which isn’t that good to start with, and doesn’t do much for this project – just make a function initTbxForms(node) {}, and a separate clearInput function. I think this should work as long as esbuild doesn’t do any minification. We’ll need to make sure no other part of the code uses ES6+ syntax either (template literals, arrow functions, const, etc.).

Alternatively – we could switch over to Babel for the production build. For a single file like this, the setup is very straightforward with Rollup. See for example https://github.com/thibaudcolas/draftjs-filters/blob/main/rollup.config.js.

Note due to this I haven’t been able to test the things I was worried about initially (dispatchEvent).

Conditional fields

I could spot a number of issues with this:

Reliance on JS

  • The way fields are implemented, they will be visible if JS fails to execute on the page. It’s unclear to me whether this is intended or not.
  • Due to this approach, when the page loads the conditional parts of the form are visible for a moment. I think it would be better if the fields were hidden on page load.

Clear hidden fields on submit

This doesn’t seem to be working. Looking at the code, I think this is because the [hidden=true] selector won’t work, should be [hidden].

In addition,

  • Clearing the value on submit and reset inputs won’t be very desirable. It seems unlikely for us to use either, but I’d still prefer we don’t remove their label
  • I haven’t been able to test it but I don’t think clearing a radio or checkbox works like the code suggests - you’d need to find which input is checked, then .checked = false.
  • For select – the node.type I get select-one, and I think it would be better to set selectedIndex to 0.

ARIA

  • The fields’ aria-describedby has the help text first, error messages second, while in the template we show the error messages first. I think both should match. I like the idea of having errors first, so the beginning of the field’s description is "Error:". Means we don’t need to additionally have aria-invalid="true".

Styles

  • We should use the American spelling color for the API / variables, so it matches CSS. We tend to avoid british spellings for things that have corresponding CSS keywords or property names.

Thanks, @thibaudcolas. I've added some comments/questions inline and split a few of your suggestions into separate Issues so they can be individually tracked.

Wagtail functionality

Do we really want Wagtail to be a dependency of tbxforms?

No, good spot - this needs fixing. Created #8 to track this.

XSS injection vectors

The templates make a lot of use of |safe, which makes me feel wary at the very least, and will be a source of XSS vulnerabilities when forms are defined via user input (the Wagtail form builder in particular).

Good thinking. The current implementation matches how Crispy Forms work out of the box (https://github.com/django-crispy-forms/django-crispy-forms/search?q=%7Csafe), though that doesn't assume the forms are editable via a CMS.

One to review and improve for sure. Created #9 to track this.

IE11 compatibility

Which solution would you recommend - switching to Babel or rewriting tbxforms.js?

Conditional fields

Reliance on JS

The way fields are implemented, they will be visible if JS fails to execute on the page. It’s unclear to me whether this is intended or not.

This is intentional. Currently, if the JS fails to successfully execute then we still show the complete form that can be submitted, which matches how GOV.UK handle conditional fields.

Clear hidden fields on submit

Good spot. Created #10 to track this.

ARIA

The fields’ aria-describedby has the help text first, error messages second, while in the template we show the error messages first. I think both should match. I like the idea of having errors first, so the beginning of the field’s description is "Error:". Means we don’t need to additionally have aria-invalid="true".

Good spot. Created #11 to track this.

Styles

We should use the American spelling color for the API / variables, so it matches CSS. We tend to avoid british spellings for things that have corresponding CSS keywords or property names.

https://github.com/alphagov/govuk-design-system and https://github.com/wildfish/crispy-forms-gds both use colour, and while changing this within tbxforms would be minimal effort, it would make tracking changes to either package harder.

👍 all seems sensible to me Kyle! Re the spelling, I think I’d like to hear from others about this.

Closing this in favour of the separate issues now created.