htmx icon indicating copy to clipboard operation
htmx copied to clipboard

Data URLs do not work when selfRequestsOnly is enabled.

Open nedaras opened this issue 1 year ago • 3 comments

Code below will throw htmx:invalidPath when htmx.config.selfRequestsOnly is set to true.

<button
  hx-get="data:text/plain,"
  hx-swap="outerHTML"
>
  Delete me.
</button>

nedaras avatar Aug 18 '24 20:08 nedaras

to allow custom control of the url validation see https://htmx.org/events/#htmx:validateUrl

You can for example set the selfRequestsOnly to false which will allow any url to be accessed and not just local server requests only. And then you can add the below event listener script to run on the validate url htmx event and lock your requests down to just the URL's you want to keep your site more secure.

  document.body.addEventListener('htmx:validateUrl', function (evt) {
    // only allow requests to the current server or data:*
    if (!evt.detail.sameHost && evt.detail.url.href.indexOf('data:') !== 0) {
      evt.preventDefault();
    }
  });

If they wanted to fix this in htmx and make all data:* urls treated as sameHost internally then the change required would be to add this:

 if (startsWith(path, 'data:')) {
        sameHost = true
      }

To the verifyPath function:

    function verifyPath(elt, path, requestConfig) {
      let sameHost
      let url
      if (typeof URL === 'function') {
        url = new URL(path, document.location.href)
        const origin = document.location.origin
        sameHost = origin === url.origin
      } else {
      // IE11 doesn't support URL
        url = path
        sameHost = startsWith(path, document.location.origin)
      }
      if (startsWith(path, 'data:')) {
        sameHost = true
      }
  
      if (htmx.config.selfRequestsOnly) {
        if (!sameHost) {
          return false
        }
      }
      return triggerEvent(elt, 'htmx:validateUrl', mergeObjects({ url, sameHost }, requestConfig))
    }

MichaelWest22 avatar Aug 19 '24 12:08 MichaelWest22

That is nice.

nedaras avatar Aug 25 '24 01:08 nedaras

Sorry looks like I made a mistake in my example handler as I had === 0 when it should have been !==0

The correct script would be

  document.body.addEventListener('htmx:validateUrl', function (evt) {
    // only allow requests to the current server or data:*
    if (!evt.detail.sameHost && evt.detail.url.href.indexOf('data:') !== 0) {
      evt.preventDefault();
    }
  });

MichaelWest22 avatar Aug 25 '24 12:08 MichaelWest22