flow icon indicating copy to clipboard operation
flow copied to clipboard

The server-to-client communication works inconsistently when the element is hidden

Open vursen opened this issue 3 years ago • 0 comments

Motivation

The current Flow concept is that, if you hide an element with setVisible(false), Flow postpones the commands you send from the server to the client for this element until the element becomes visible. This behavior has apparently some security reasons behind it.

However, the way it works is not consistent:

Flow DOM manipulations:

👍 getElement().setAttribute(...) is postponed and is applied right after the element becomes visible.

Manual JavaScript execution:

👎 getElement().executeJs(...) is executed immediately regardless of whether the element is visible or not.

When can it be an issue?

Let's say you a Flow component with a JS connector. The component has a method e.g.:

void setTheme(String theme) {
  getElement().setAttribute("theme", theme);
  getElement().executeJs("$connector.render()");
}
$connector.render = () => {
  const theme = element.getAttribute('theme');
  ...
}

Now, when you call setTheme(...) on a hidden element, $connector.render() will be invoked immediately, but the attribute is set only after the element becomes visible, and since the connector relies on the attribute, calling it in that sequence will cause an unexpected result.

Possible solutions

Based on the internal discussion with @Legioth, there are several options:

  1. Make executeJS consistent with everything else so that such invocations would also remain enqueued on the server if targeting hidden components.
  2. Provide a way of opting in for specific state changes to be sent to the client even though the component is hidden. I don't have any good idea for what the API would look like for this since there are so many different APIs that lead to state changes.
  3. Enhance beforeClientResponse to also support visibility changes to supplement what's already there for dealing with being initially sent to the client.

Additional context

Also by @Legioth:

This might actually be seen as a security feature and not only an optimization. Developers might reasonably think "out of sight, out of mind" and e.g. always populate sensitive data into a component while relying on the component being hidden for users that shouldn't see the sensitive data. This is obviously something that one should never do, but I'm quite sure there are plenty of applications out there who do it in that way today since it happened to work (i.e. they even checked that the sensitives values don't end up in the DOM). If we now would change it to eagerly pass that state to the client, then we might introduce vulnerabilities.

vursen avatar May 10 '22 08:05 vursen