Skip to content

Conversation

@ashirley
Copy link
Contributor

@ashirley ashirley commented Oct 20, 2025

There is still a lot to tidy up here but wanted to get some opinions sooner rather than later about iFrame layout options

Add a long_description field to villages. This is markdown from untrusted users and is rendered using nh3 and a sandboxed iFrame in order to limit the untrusted HTML.

There are 2 layout options for the iFrame:

The first uses javascript to resize the iFrame to prevent scrolling within the iFrame.

vivaldi_2gFsXcJgpn

The second uses a static size for the iFrame which scrolls for long content.

vivaldi_UirExic3aR

The advantage of the second is that we can remove the allow-scripts privilege from the iFrame.

fixes #1816

@wlcx
Copy link
Member

wlcx commented Oct 20, 2025

unexpected status from HEAD request to https://registry-1.docker.io/v2/library/node/manifests/12-alpine: 500 Internal Server Error

us-east-1 detected

Copy link
Member

@wlcx wlcx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is partially a draft PR, sorry if you already had any of these on your list!

  • Looks like the migration needs "rebasing" onto the newest HEAD migration.
  • My humble request would be for new code to have type annotations. Very happy to help if there's any mypy gnarliness.
  • From a UX perspective I think we should state the markdown limitations (i.e. images disabled) in the form.

I'll leave the security considerations to someone with more experience in that area 😅

<a href="{{ village.map_link }}">📍&nbsp;Map</a>
{% endif %}

{# TODO: Can we show what's on at the village venues here? #}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to say that I'm not sure whether there's a link between Venue and Village, but on closer look Venue has a village_id field :)

@SamLR is this planned to still be the case?

@ashirley ashirley force-pushed the village-long-description branch 2 times, most recently from 8b17a7b to 3ad70e8 Compare December 9, 2025 22:46
@marksteward marksteward mentioned this pull request Jan 3, 2026
8 tasks
@ashirley ashirley force-pushed the village-long-description branch from df508ac to 911877f Compare January 26, 2026 21:24
tags=(nh3.ALLOWED_TAGS - {"img"}),
link_rel="noopener nofollow", # default includes noreferrer but not nofollow
)
innerHtml = render_template("sandboxed-iframe.html", body=Markup(contentHtml))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably inner_html to keep with the snake-case standard?

link_rel="noopener nofollow", # default includes noreferrer but not nofollow
)
innerHtml = render_template("sandboxed-iframe.html", body=Markup(contentHtml))
iFrameHtml = f'<iframe sandbox="allow-scripts" class="embedded-content" srcdoc="{html.escape(innerHtml, True)}" onload="javascript:window.listenForFrameResizedMessages(this);"></iframe>'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The javascript: prefix here is unnecessary. It technically works, but I suspect that's only because it's treated as a label of javascript.

link_rel="noopener nofollow", # default includes noreferrer but not nofollow
)
innerHtml = render_template("sandboxed-iframe.html", body=Markup(contentHtml))
iFrameHtml = f'<iframe sandbox="allow-scripts" class="embedded-content" srcdoc="{html.escape(innerHtml, True)}" onload="javascript:window.listenForFrameResizedMessages(this);"></iframe>'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really like having onload here; is it possible to move attaching the message handler elsewhere?

There are a few things which are a bit weird about doing this in onload anyway:

  • The attached handler is on window anyway, so it can be attached at ~any time.
  • What happens if there's more than one of these iframes on the page?

You'll probably need to do some iterating over the available iframe.embedded-contents to find the one where the contentWindow matches the event.source, but it'll make it more robust, I think.

url("../static/fonts/raleway-v22-latin-ext_latin-700.woff2") format("woff2"),
url("../static/fonts/raleway-v22-latin-ext_latin-700.woff") format("woff");
}
} No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: please leave the ending newline in.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/me glares at the .editorconfig

}

window.listenForFrameResizedMessages = listenForFrameResizedMessages;
window.sendFrameResizedMessage = sendFrameResizedMessage; No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: trailing newline please

Comment on lines +11 to +15
// Do we trust the sender of this message?
// origin of sandboxed iframes is null but is this a useful check?
// if (evt.origin !== null) {
// return;
// }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think we just ignore the origin here anyway - in any case, as per the other comment we probably want to check on evt.source.

{% endblock -%}
{% block head -%}{% endblock -%}
</head>
<body itemscope itemtype="http://schema.org/WebPage" {% block body_class %}{% endblock %} onload="javascript:window.sendFrameResizedMessage()" style="overflow: hidden;">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably want some other mechanism here (other than onload). Possibly split the resize JS into two (one for the parent, one for the child)?

}

window.listenForFrameResizedMessages = listenForFrameResizedMessages;
window.sendFrameResizedMessage = sendFrameResizedMessage; No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might also want to bind a ResizeObserver to the body so that we can catch change in the width of the iframe or similar - I don't actually recall if the iframe size will change much if e.g. the user is on desktop and resizes the window.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Village details page

4 participants