* The CSS styles were leaking information about tunnels, even for
things like the login page, which can be sent to anyone.
* Tokens could be created for any user by any user.
Debugging notes:
* The act of refreshing a page can delete tunnels created by other UI
sessions, I think because it has local CSS checkbox state.
* Happens on firefox desktop and mobile. Here's how to reproduce:
1. Load the UI in Chrome and FF.
2. Delete the last tunnel from FF.
3. Add it back in Chrome.
4. Refresh FF. The tunnel will be silently deleted.
* I'm pretty sure this is bugged behavior in FF, because the checkboxes have
completely unique ids, but it's treating them like the same checkbox.
* Setting autocomplete='off' on the input elements seems to fix the problem.
Not sure if it will work correctly in all browsers.
Learned about the :target CSS selector, which can be used to
replace content depending on the current URL hash. This allows
making a sort of single page app without JavaScript.
Currently experimenting with returning all the pages in a single
request, then switching between them with :target. Seems to be
working quite well so far.
API is now the central control point for making authorized
requests. The current architecture is:
* db simply returns all data
* api uses tokens to filter data from db. It includes methods for
returning objects, and HTTP endpoints for return JSON.
* ui calls the api functions to get filtered data.