-
-
Notifications
You must be signed in to change notification settings - Fork 432
Conversation
So it turns out this allows access to (probably sensitive) session data from anywhere in the server. I would argue that I tried leaking session and page data and indeed it's easy. Too easy. So I definitely agree that session data should not be readable from anywhere but the request itself. What if the session and page data would be reset before and after the page renders? Render is synchronous so I think no other code can do a drive-by and steal any data. // server.mjs:2330
stores.page.set({
path: req.path,
query: req.query,
params: params
});
stores.session.set(session);
const { html, head, css } = App.render(props);
stores.session.set(false);
stores.page.set(false); To block any subscribers from listening where they shouldn't, we must unsubscribe all listeners on every import { writable } from 'svelte/store';
import { noop } from 'svelte/internal';
export const stores = {
session: process.browser ? writable(false) : frozen(false),
preloading: writable(false),
page: process.browser ? writable(null) : frozen(null)
};
export const CONTEXT_KEY = {};
export const preload = () => ({});
function frozen (value) {
function reset(newValue) {
value = newValue;
}
function subscribe(run) {
run(value);
return noop;
}
return { reset, subscribe };
} The new drawback is that you cannot change the session during initialisation. I have tested this code and I can't break it as easily. |
e0b81e0
to
d57d82f
Compare
It's still possible to override stores.session and undoing the protection.
|
1400ee3
to
e3f74c8
Compare
e3f74c8
to
c6d1eb8
Compare
Updated so that preload runs again when the session is updated. |
Thanks for this — finally getting round to merging PRs ahead of the v3-friendly Sapper release. I definitely much prefer the ergonomics of this approach. Makes it much easier to e.g. have a login helper outside the component hierarchy. My one hesitation in all this is it basically commits us to always doing sync SSR, even if we support async or streaming SSR in future. Is there a way to reconcile the two? In any case, should Also, would it be taking things too far to replace |
Now that I think about it, the same logic applies to the So as I see it our choices are:
The API for option 2 would presumably be something like this: <script>
import { stores } from '@sapper/app';
const { page, session } = stores();
</script> Calling |
@Rich-Harris this second approach, while more verbose, sort of spells out better where things are coming from. (I like it, in other words.) |
The more I think about this, the more I think that using the context API (for all the stores — <script>
import { stores } from '@sapper/app';
const { page, preloading, session } = stores();
</script> Does anyone have strong objections, or suggestions for a better (and safe) alternative? |
I used sapper a lot for the past two months and now agree with the suggested approach. I built lots of stores and it turns out that they don't play well with Maybe option 4 is syntactic sugar, but that would introduce another thing to learn. |
I'm probably missing something, but this makes it much easier to handle sessions. Right?