Commit Graph

1205 Commits

Author SHA1 Message Date
Tom Byers
0987787df6 Give map attribution links an underline
Makes them identifiable as links based on
something other than just colour.
2021-10-19 11:09:40 +01:00
Tom Byers
2b91d1d524 Fix mis-spelling of aria-describedby
This is currently spelt incorrectly though it
seemed to work nonetheless. Can only assume this
is a common error, for this attribute or all
attribute names, so browsers work it out.

This makes the spelling match the spec:

https://www.w3.org/TR/wai-aria/#aria-describedby
2021-10-19 11:09:37 +01:00
Chris Hill-Scott
975088308a Put media query after default CSS
Specificity means that the media query will always override, but this is
more obvious with the order this way around.
2021-09-30 15:07:22 +01:00
Chris Hill-Scott
eee4cdd0a7 Rewrite media queries to be mobile-first
Also adds height: 100% which forces the SVG to scale, rather than just
setting width which widens the viewbox.
2021-09-30 14:19:27 +01:00
Chris Hill-Scott
c63313e839 Give WebAuthn illustration a fixed size
The browser uses the `width` and `height` attributes of the image tag to
allocate space on the page for the image.

If these aren’t provided then the browser will assume the image takes up
no space, until it’s downloaded it and had a look at what the file’s
dimensions are. This causes the layout of the page to jump once the
image downloads.

`149 × 150px` is the native size of the image. But we don’t want it to
display at that size, so this commit also adds some extra CSS which
keeps it looking the same, namely:
- the full width of the 1/4 page column on desktop
- the full width of the column minus a `40px` gutter either side on
  mobile (by using `box-sizing: border-box` the `40px` of padding is
  subtracted from the 100% width, rather than added to it)
2021-09-30 14:19:27 +01:00
Chris Hill-Scott
bc5745c77b Fix styles for API key value not being applied
When the component was renamed from ‘API key’ to ‘Copy to clipboard’ the class for the thing to be copied changed from `api-key__key` to `copy-to-clipboard__value`. While the CSS was updated to reflect the change from `api-key` to `copy-to-clipboard` the change from `__key` to `__value` was not made.

Before: 4921e6d46e/app/templates/components/api-key.html
After: 85f6881a56/app/templates/components/copy-to-clipboard.html

This commit changes updates the CSS to reflect the latter change, so that the styles get applied properly.
2021-09-28 15:30:44 +01:00
Tom Byers
87f54d1e88 Replace diffDOM library with domdiff
A while ago diffDOM moved its code to use ES6
modules and started using various language
features specific to ES6. These two things
happened independently btw.

The result of this is that the version of diffDOM
suitable for our build pipeline, structured as an
immediately invoked function evocation (IIFE),
now requires polyfills of some ES6 features to
work in the older browsers we support, like IE11.

It's also worth noting that in the move to ES6
the maintainers of diffDOM have adopted a process
whereby users who need to support older browsers
now have to add polyfill code for any ES6 features
they choose to use.

This commmit proposes a move to the domdiff
library instead because:
- it runs on all javascript runtimes with no
  polyfills
- it is 2KB instead of diffDOM's 25KB

Domdiff takes a different approach to diffDOM, in
that it compares existing nodes and new nodes and
replaces the existing ones with the new ones if
there are differences. By contrast, diffDOM will
make in-place changes to nodes if there are enough
similarities. In other words, in most situations,
diffDOM won't change the node in $component
whereas domdiff will.

Because of this, I've had to change the
updateContent.js code to cache the data-key
attribute's value so we don't lose access to it by
overwrite the $component variable with a different
jQuery selection.
2021-09-22 12:05:47 +01:00
Leo Hemsted
a96bfdb16e remove server-side error messages for webauthn
since we are hard-coding a generic error message on the front-end, we
have no need to do anything on the back end. This is also nice as it
standardises the two flows to behave more like each other (rather than
previously where one would `flash` an error message and the other would
return CBOR for the js to decode).

Note that the register flow returns 400 while the auth flow returns 403.
The js for both just checks `response.ok` so will handle both. The JS
completely discards any body returned if the status isn't 200 now.
2021-09-15 11:43:41 +01:00
Leo Hemsted
2c55f4d0ce hard-code html error message for errorBanner
turns out that we're only using errorBanner with a static message, and
it's also full of rich html content. This means that it's probably
better to put it in the html templates with other content, rather than
hidden away in js files if we can help it.

Since there are two places, had to dupe the error message but i think
that's fine as i don't anticipate this error message being used in
significantly more places.

making it a string is a bit gross and means we don't get nice syntax
highlighting on it, but as it needs to be passed in to a jinja macro
that's the way it has to go unfortunately.
2021-09-14 18:43:27 +01:00
Leo Hemsted
0b27d7e0a9 show error message in banner rather than an alert
the banner is a nicer user experience, and consistent with how we
display errors elsewhere in notify. For now pass through the error
message from JS, but we'll probably want to change that since the erorr
messages themselves are often a bit cryptic and unhelpful
2021-09-14 18:43:26 +01:00
Leo Hemsted
c96a1dc0b7 add new error banner module for showing users js errors
this ensures it's reusable by other components, and easier to unit test
by isolating the separate concerns

note: this is not in Modules since that's designed for classes that are
then bound to an element in the DOM as indicated by a data-module
attribute. This will just live at the window.GOVUK level since we want
there to only ever be one `.banner-dangerous` warning.
2021-09-14 18:43:25 +01:00
Leo Hemsted
a231738a16 Merge pull request #3989 from alphagov/update-pricing-pages
Add a billing details page
2021-09-08 16:31:38 +01:00
Leo Hemsted
85f6881a56 rename api key component to copy_to_clipboard
does what it says on the tin, and is also consistent with prior art:
https://components.publishing.service.gov.uk/component-guide/copy_to_clipboard
2021-09-08 10:18:17 +01:00
Tom Byers
c6ecbf647a Change comment about turning part of focus style off
Co-authored-by: Ben Thorner <benthorner@users.noreply.github.com>
2021-09-07 10:10:05 +01:00
Tom Byers
87674aef08 Fixes for the comments in the map CSS
Based on a range of comments made in the
associated pull request:
- 7c2f4adfd5 (r701234728)
- 7c2f4adfd5 (r701235330)
- 7c2f4adfd5 (r701235586)
- 7c2f4adfd5 (r701242035)
- 7c2f4adfd5 (r701241659)

Co-authored-by: Ben Thorner <benthorner@users.noreply.github.com>
2021-09-03 12:13:15 +01:00
Tom Byers
c1c80802e2 Give outline reset same precedence as for focus
The CSS that cancelled outline on focus events not
fired by the :focus-visible heuristic is being
overridden by the higher precedence of the outline
style for :focus, due to its use of !important.

This adds !important to the cancelling CSS. This
brings that block up to the same level as that for
:focus, meaning the :focus-visible styles will win
because they sit lower in the stylesheet.
2021-09-03 11:20:41 +01:00
Tom Byers
6de836b2f2 Rewrite map CSS comments 2021-09-02 14:43:07 +01:00
Tom Byers
ee3e3c6c90 Change how line between map buttons is styled
There is a slight variance in how the line between
the map buttons is rendered when in forced-colors
mode and when not. This is not helped by it
alternately being rendered as either:
- a gap between buttons, showing the container
  colour
- a border-bottom on the first button

This attempts to flatten these styles so it is
only styled as a gap between the buttons so
changes to how its colour renders in different
modes can just be dealt with on the container.
2021-09-02 14:43:07 +01:00
Tom Byers
9c9e7a7c61 Fix code for map focus style
@benthorner pointed out a few things about these
styles that could do with changes:
- the outline-offset will only appear when the
  outline does, which is in forced-color mode when
  the browser assigns a colour to it, so it
  doesn't need to be assigned in a media query
  targeting forced-color mode
- the `&:focus:not(:focus-visible)` selector
  stops the focus styles showing in scenarios
  where:
  1. the browser supports :focus-visible
  2. focus comes from something other than tabbing
     to the map
  ...so we don't need to target :focus-visible
  specifically.

This applies changes to these styles to remove
those not needed and move some to a better place.

Related to this comment on the associated pull
request:

https://github.com/alphagov/notifications-admin/pull/3996#discussion_r699246969
2021-09-02 11:27:45 +01:00
Tom Byers
f52dd23e35 Correct term in map CSS comment
Co-authored-by: Ben Thorner <benthorner@users.noreply.github.com>
2021-09-01 20:38:06 +01:00
Tom Byers
a3854e49b6 Fix issue with jumping buttons
The content of the map buttons jumped on Chrome
and Safari when focused.

It turns out this was because I was testing in
Firefox which Leaflet had identified as having
touch capability (and so added the .leaflet-touch
class). Leaflet makes the buttons 30px rather than
26px for touch-capable devices/browsers so the
jumping was down to the line-height being set for
the wrong container height.

This adds styles to give a different line-height
when touch is available, to match the Leaflet
styles.
2021-08-26 16:35:13 +01:00
Tom Byers
542be8832d Turn outlines off on map control buttons
Leaflet does this anyway when they're focused
(through JS) but we found holding shift when on a
focused button, which you do when tabbing
backwards, turns this off for some reason so you
see the outline the browser applies by default.

This turns all outlines off to stop that
happening.

Worth nothing that focus is indicated by:
- a change of background colour instead when
  tabbing
- a border in forced-color mode

...so the outline is not needed.
2021-08-26 15:42:12 +01:00
Tom Byers
83bf78156b Rewrite comment on part of the focus style
The original comment doesn't describe what the
code does. Raised in this comment on the
associated pull request:

https://github.com/alphagov/notifications-admin/pull/3996#discussion_r692093945
2021-08-26 15:34:48 +01:00
Tom Byers
4950b08d71 Fix CSS that removes rounded corners on controls
Users on devices/browsers that support touch have
the rounded corners styles applied by this
selector:

.leaflet-touch .leaflet-bar a:first-child,
.leaflet-touch .leaflet-bar a:last-child

It has a higher precedence than the existing
selector we use to override it so our overrides
are ignored:

.leaflet-bar a:first-child,
.leaflet-bar a:last-child

This changes the selector for our block of styles
to include one matching the existing styles above
so devices/browsers also get our styles.

Note 1: this actually means some styles were no
longer needed so this also removes them.

Note 2: oddly, this was spotted in Firefox when
displaying high contrast mode on desktop. So not a
touch device but leaflet's JS is marking it as
such.
2021-08-26 15:31:36 +01:00
Tom Byers
8827b8802e Update comments about high contrast styles
To address the points in this comment on the
associated pull request:

04de4ed865 (diff-6c10fd1eff57bed9c68dbad652255da627ac922a2f8aabf7b17a02a5dff9d099)
2021-08-25 20:39:26 +01:00
Tom Byers
f70dcc8329 Remove rounded corners from map controls
Also includes a quick fix for high contrast mode.
The buttons are separated by a horizontal line by
default, styled as a border above the 2nd button.

Both buttons use the border when focused in high
contrast mode to provide a form of outline.
This takes away the line dividing them, because
you can only have one border.

The buttons are still separated by a 1px margin so
this just sets a background colour on the
container to simulate the divider.
2021-08-25 15:32:11 +01:00
Tom Byers
388edeef5d Accessibility fixes for map
Makes the controls and links inside it match GOVUK
Frontend styles and:
- gives the map container a focus style matching
  that for GOVUK Frontend text inputs
- makes it all work in high contrast modes (on
  Windows and Firefox)

Note: the focus style for the container is applied
with :focus-visible so only appears when it gets
focus directly, not when it does due to child
elements (like the controls or links) getting
focused. Browsers without support for
:focus-visible get the same styling for all forms
of focus.
2021-08-25 15:32:11 +01:00
Chris Hill-Scott
2d36ec8214 Add support for the operator channel
Was just in one of those meetings where it felt like writing this would
take less time than I’d already spent talking about its relative
priority…

---

In the admin app you can already set the broadcast channel as 'test', 'severe' or 'government'.

Aim:
- Add the 'operator' channel to the list of channels you can pick for the admin app broadcast services

Note:
- The API already supports this - https://github.com/alphagov/notifications-api/pull/3262
- The CBC proxy does not yet support the operator channel and this will need a separate card. That card has not yet been written because the interface has not been agreed between us and the MNOs yet.
- Will need to have the ability to select the operator channel for just a single MNO like we do for the other channels
- If we add this, we shouldn't actually start using it until the MNO in question gives us the go ahead.

---

https://www.pivotaltracker.com/story/show/178485177
2021-06-14 08:48:12 +01:00
Leo Hemsted
bb7343d846 pass nextUrl through yubikey flow
the next url comes from sign in via a query param, and needs to go to
the POST /webauthn/authenticate endpoint. That endpoint logs the user
in and returns the redirect to the browser, and will take the next from
the request query params to get there.

also moving the window mocks to beforeEach/afterEach ensures that
promise callbacks from previous tests aren't still associated in future
tests to ensure good test isolation.

unfortunately i couldn't get mocking location for a single js test to
work, but by changing the global config i was able to add some query
params that i can expect to be passed through. Don't love this at all
but not quite sure of a good way round this. I think we're not
practicing very good hygiene and best practices with our mocking and
it's really confounding me here.
2021-06-04 12:52:40 +01:00
David McDonald
0fcb7778ac Merge pull request #3893 from alphagov/allow-provider-all-channels
Allow setting provider for any channel
2021-06-03 09:36:43 +01:00
Leo Hemsted
6a21915cee add webauthn authentication js tests
notably i had to change `window.location = foo` to
`window.location.assign` so that i could have something to spy on with
jest. mocking sucks. Otherwise this is pretty similar to the
registerSecurityKey.test.js file.
2021-06-02 12:06:09 +01:00
Leo Hemsted
d05f127e41 return 200 to js instead of 302 when logging in
the js fetch function is really not designed to work with 302s. when it
receives a 302, it automatically follows it and fetches the next page.
This is awkward because I don't want js to do all this in ajax, I want
the browser to get the new URL so it can load the page.

A better approach is to view the admin endpoint as a more pure API: the
js sends a request for authentication to the admin app, and the admin
app responds with a 200 indicating success, and then a payload of
relevant data with that.

The relevant data in this case is "Which URL should I redirect to", it
might be the user's list of services page, or it might be a page telling
them that their email needs revalidating.
2021-06-02 11:51:12 +01:00
Leo Hemsted
92f78b14fe redirect on login; flash errors on failure
the js `fetch` function will follow redirects blindly and return you the
final 200 response. when there's an error, we don't want to go anywhere,
and we want to use the flask `flash` functionality to pop up an error
page (the likely reason for seeing this is using a yubikey that isn't
associated with your user). using `flash` and then
`window.location.reload()` handles this fine.

However, when the user does log in succesfully we need to properly log
them in - this includes:

* checking their account isn't over the max login count
* resetting failed login count to 0 if not
* setting a new session id in the database (so other browser windows are
  logged out)
* checking if they need to revalidate their email access (every 90 days)
* clearing old user out of the cache

This code all happens in the ajax function rather than being in a
separate redirect, so that you can't just navigate to the login flow. I
wasn't able to unit test that function due how it uses the session and
other flask globals, so moved the auth into its own function so it's
easy to stub out all that CBOR nonsense.

TODO: We still need to pass any `next` URLs through the chain from login
page all the way through the javascript AJAX calls and redirects to the
log_in_user function
2021-06-02 11:51:10 +01:00
Leo Hemsted
c26a596839 allow sign in via webauthn credentials
The flow of the code is roughly as follows:

  user clicks button on webauthn page
  js sends GET request
  python reads GET request, sets up login challenge
  python returns login challenge in response
  js reads GET response, passes login challenge to browser
  browser asks user to touch yubikey
  browser returns yubikey challenge response data to js
  js sends POST request with yubikey challenge response data
  python reads yubikey challenge and compares with users creds from db
  if its a match, python signs user in

The login challenge is a PublicKeyCredentialRequestOptions: [1]
The browser function we call is navigator.credentials.get(): [2]
The response to the challenge from the browser is a PublicKeyCredential: [3]

The python server does all the work setting those up and tearing them
back down again (and checking them against the values we have stored in
the database), but we need to do work to convert them to-and-from CBOR.

[1] https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredentialRequestOptions
[2] https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/get
[3] https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential
2021-06-01 19:08:57 +01:00
Leo Hemsted
907a7dc363 create webauthn 2fa page
if user has `webauthn_auth` as their auth type, then redirect them to an
interstitial that prompts them to click on a button which right now just
logs to the JS console, but in a future commit will open up the webauthn
browser prompt

content is unsurprisingly not final.
2021-06-01 18:44:54 +01:00
Chris Hill-Scott
268a7d1881 Make image display smaller on mobile 2021-05-28 16:20:34 +01:00
Chris Hill-Scott
88e2cc93df Add image of security key
When referring to something that’s not part of the Notify system, like a
spreadsheet or a paper letter or a security key we’ve found it’s helpful
to give people a visual representation of it. This commit does the same
for security keys.
2021-05-27 18:14:20 +01:00
Chris Hill-Scott
2d2c82ca87 Merge pull request #3885 from alphagov/live-broadcast-tour
Add a version of the tour for live services
2021-05-24 10:58:45 +01:00
Ben Thorner
c5196fbf07 Allow setting provider for any channel
Previously we could only select a provider when using the test
channel, but this is also required for others channels when we
do tests on the production network with individual MNOs.

In order to reduce duplication and improve consistency, I've reused
the new broadcast_service_name_tag macro to show the setting.
2021-05-20 14:46:04 +01:00
Ben Thorner
03295eb828 Merge pull request #3889 from alphagov/webauthn-errors
Handle errors when registration fails
2021-05-19 11:22:05 +01:00
Chris Hill-Scott
766df5d1ca Add a version of the tour for live services
At the moment if you’re invited to a live broadcast service you get the
training mode tour. This is misleading, and could make people think they
weren’t in danger of sending a real alert.

This commit adds a short, 2 step tour for users invited to a live
broadcast service.
2021-05-19 09:41:58 +01:00
Ben Thorner
c09f0f0e06 Merge pull request #3886 from alphagov/protect-no-webauthn-js
Prevent registration if WebAuthn is not supported
2021-05-18 11:59:00 +01:00
Ben Thorner
2039d3aa45 Prevent registration if WebAuthn is not supported
This hides the "Register" button and shows an error that's specific
to one of two ways a browser may not support WebAuthn:

- JavaScript is disabled (there's no possible fallback for this).
- WebAuthn API is not supported (e.g. on Internet Explorer).

We could add a similar check for the API in the JS code to handle
the button click, but hiding it seems like enough protection.

In order to avoid elements flashing when the page loads, this uses
a view macro to embed a script at the start of the body element,
which is the same approach used for the "js-enabled" class flag [1].

Tested with Chrome and IE 11.

[1]: https://github.com/alphagov/govuk-frontend/blob/main/src/govuk/template.njk#L31
2021-05-18 10:28:25 +01:00
Ben Thorner
8502827afb Handle errors when registration fails
Previously we would raise a 500 error in a variety of cases:

- If a second key was being registered simultaneously (e.g. in a
separate tab), which means the registration state could be missing
after the first registration completes. That smells like an attack.

- If the server-side verification failed e.g. origin verification,
challenge verification, etc. The library seems to use 'ValueError'
for all such errors [1] (after auditing its 'raise' statements, and
excluding AttestationError [2], since we're not doing that).

- If a key is used that attempts to sign with an unsupported
algorithm. This would normally raise a NotImplemented error as part
of verifying attestation [3], but we don't do that, so we need to
verify the algorithm is supported by the library manually.

This adds error handling to return a 400 response and error message
in these cases, since the error is not unexpected (i.e. not a 500).
A 400 seems more appropriate than a 403, since in many cases it's
not clear if the request data is valid.

I've used CBOR for the transport encoding, to match the successful
request / response encoding. Note that the ordering of then/catch
matters in JS - we don't want to catch our own throws!

[1]: 142587b3e6/fido2/server.py (L255)
[2]: c42d9628a4/fido2/attestation/base.py (L39)
[3]: c42d9628a4/fido2/cose.py (L92)
2021-05-17 12:18:24 +01:00
Chris Hill-Scott
362189d562 Merge pull request #3879 from alphagov/add-government-channel
Add an option to set a service to the government channel for emergency alerts
2021-05-13 15:10:15 +01:00
Ben Thorner
9ee01a2567 Check for response.ok in fetch calls
It's possible for a call to fetch to trigger then "then" callback
even thought the response is an error [1]. We should test for both
scenarios, since they are handled differently. To avoid duplicating
the tests, I've used Jest's parameterisation feature [2].

[1]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
[2]: https://jestjs.io/docs/api#testeachtablename-fn-timeout
2021-05-13 10:22:26 +01:00
Ben Thorner
6948f5f003 Switch to window.fetch for AJAX calls
In response to [1]. Using window.fetch means we don't get console
logs on errors, so this simplifies the error handling, although we
need to account for some errors not being a standard error object,
such as the string we get by doing Promise.reject('error').

In making this change, I've also started addressing another comment
in the PR [2], so that we reset mocked objects after the tests.

This also switches the ordering of done(), so that it's the last
statement (in response to [3]).

In the next commit we'll check for 'response.ok', but I wanted to
keep this one simple, as it's quite a large change.

[1]: https://github.com/alphagov/notifications-admin/pull/3878#discussion_r631054187
[2]: https://github.com/alphagov/notifications-admin/pull/3878#discussion_r631060116
[3]: https://github.com/alphagov/notifications-admin/pull/3878#discussion_r631061628
2021-05-13 10:22:25 +01:00
Ben Thorner
e2cf3e2c70 Support registering a new authenticator
This adds Yubico's FIDO2 library and two APIs for working with the
"navigator.credentials.create()" function in JavaScript. The GET
API uses the library to generate options for the "create()" function,
and the POST API decodes and verifies the resulting credential. While
the options and response are dict-like, CBOR is necessary to encode
some of the byte-level values, which can't be represented in JSON.

Much of the code here is based on the Yubico library example [1][2].

Implementation notes:

- There are definitely better ways to alert the user about failure, but
window.alert() will do for the time being. Using location.reload() is
also a bit jarring if the page scrolls, but not a major issue.

- Ideally we would use window.fetch() to do AJAX calls, but we don't
have a polyfill for this, and we use $.ajax() elsewhere [3]. We need
to do a few weird tricks [6] to stop jQuery trashing the data.

- The FIDO2 server doesn't serve web requests; it's just a "server" in
the sense of WebAuthn terminology. It lives in its own module, since it
needs to be initialised with the app / config.

- $.ajax returns a promise-like object. Although we've used ".fail()"
elsewhere [3], I couldn't find a stub object that supports it, so I've
gone for ".catch()", and used a Promise stub object in tests.

- WebAuthn only works over HTTPS, but there's an exception for "localhost"
[4].  However, the library is a bit too strict [5], so we have to disable
origin verification to avoid needing HTTPS for dev work.

[1]: c42d9628a4/examples/server/server.py
[2]: c42d9628a4/examples/server/static/register.html
[3]: 91453d3639/app/assets/javascripts/updateContent.js (L33)
[4]: https://stackoverflow.com/questions/55971593/navigator-credentials-is-null-on-local-server
[5]: c42d9628a4/fido2/rpid.py (L69)
[6]: https://stackoverflow.com/questions/12394622/does-jquery-ajax-or-load-allow-for-responsetype-arraybuffer
2021-05-13 10:22:23 +01:00
Chris Hill-Scott
ad0b7537de Make the government channel visually distinct
It’s really serious, so this sets it apart from the other live channels.
2021-05-12 16:22:45 +01:00
Ben Thorner
ebb82b2e80 Add page for security keys with stubbed data
This adds a new platform admin settings row, leading a page which
shows any existing keys and allows a new one to be registered. Until
the APIs for this are implemented, the user API client just returns
some stubbed data for manual testing.

This also includes a basic JavaScript module to do the main work of
registering a new authenticator, to be implemented in the next commits.

Some more minor notes:

- Setting the headings in the mapping_table is necessary to get the
horizontal rule along the top (to match the design).

- Setting caption to False in the mapping_table is necessary to stop
an extra margin appearing at the top.
2021-05-12 13:41:53 +01:00