max / makenotwork
| 1 | //! Rendering a creator's markdown back to them before it is saved. |
| 2 | //! |
| 3 | //! The described markdown field (`crate::quasi::rich_field`) emits a Preview |
| 4 | //! pane and nothing that fills it: `makeover-webview` never turns a value into |
| 5 | //! markup, on the stated grounds that a host with its own sanitiser and its own |
| 6 | //! content-security posture still owns both. This server has both, so this is |
| 7 | //! where the pane is filled. |
| 8 | //! |
| 9 | //! # Why the server and not the browser |
| 10 | //! |
| 11 | //! The four hand-written editors this replaces had one preview between them, |
| 12 | //! and it was a regex pass over h1-h3, bold, italic and inline code |
| 13 | //! (`static/partial-item-text-editor.js`, before this landed). It was safe -- |
| 14 | //! it escaped first and substituted after -- and it was not what publishes. A |
| 15 | //! creator reading it learned what that regex did, not what |
| 16 | //! `render_creator_markdown` does, so tables, links, lists and media rewriting |
| 17 | //! all appeared for the first time after save. |
| 18 | //! |
| 19 | //! Rendering here answers with the pipeline that actually publishes, ammonia |
| 20 | //! and media-host restriction included, which is both the honest preview and |
| 21 | //! the one place the sanitising stays. See `crate::markdown` for the policy. |
| 22 | |
| 23 | use ; |
| 24 | use ; |
| 25 | |
| 26 | use crate:: |
| 27 | AuthUser, |
| 28 | Config, |
| 29 | Result, |
| 30 | , |
| 31 | ; |
| 32 | |
| 33 | /// What the editor is holding right now. |
| 34 | |
| 35 | pub |
| 36 | /// The markdown source, unsaved. |
| 37 | pub markdown: String, |
| 38 | |
| 39 | |
| 40 | /// The pane's contents. |
| 41 | |
| 42 | pub |
| 43 | /// Sanitised markup, ready for the pane. Named `html` rather than `body` |
| 44 | /// because nothing here is a resource and there is nothing else to return. |
| 45 | html: String, |
| 46 | |
| 47 | |
| 48 | /// Render unsaved markdown the way saving it would. |
| 49 | /// |
| 50 | /// Authenticated because the media rewriting is per-creator: relative image |
| 51 | /// paths resolve under the asking user's CDN prefix, which is the same thing |
| 52 | /// `render_creator_markdown` does at save time. Stores nothing. |
| 53 | |
| 54 | pub async |
| 55 | State: , |
| 56 | AuthUser: AuthUser, |
| 57 | Json: , |
| 58 | |
| 59 | // The same bound the save path applies, so a body too long to store is |
| 60 | // refused here rather than previewed and then rejected. `ITEM_TEXT_BODY_MAX` |
| 61 | // is the largest of the four surfaces' limits; a shorter one is caught by |
| 62 | // its own endpoint on save. |
| 63 | if req.markdown.chars.count > ITEM_TEXT_BODY_MAX |
| 64 | return Err |
| 65 | "Content must be {} characters or less" |
| 66 | ITEM_TEXT_BODY_MAX |
| 67 | ); |
| 68 | |
| 69 | reject_control_chars_multiline?; |
| 70 | |
| 71 | let html = craterender_creator_markdown |
| 72 | &req.markdown, |
| 73 | user.id, |
| 74 | config.cdn_base_url.as_str, |
| 75 | ; |
| 76 | |
| 77 | Ok |
| 78 | |
| 79 |