Slide 1

Slide 1 text

Content editing in Symfony

Slide 2

Slide 2 text

Hello! I am Titouan Galopin Symfony UX initiative lead Selency // Citipo 2

Slide 3

Slide 3 text

Agenda 1. Know your content 2. Security concerns 3. Choosing an editor 4. The state of the art: block-based editors 5. Live editing with Symfony UX and Mercure 3

Slide 4

Slide 4 text

1 Know your content 4

Slide 5

Slide 5 text

Content editing isn’t a technical challenge, it’s an architecture one 5

Slide 6

Slide 6 text

● Article comments ● Restaurant reviews ● Social post ● Document writing ● CMS ● … Many use cases 6

Slide 7

Slide 7 text

⬡ Stylable content vs Plain text? Should your users be able to insert bold/italic? Links? Images? … Questions to ask yourself 7

Slide 8

Slide 8 text

Questions to ask yourself 8 ⬡ Stylable content vs Plain text? ⬡ Feature-rich content vs Markdown? Markdown is great but it’s difficult to use for non-technical users, and will it be enough?

Slide 9

Slide 9 text

Questions to ask yourself 9 ⬡ Stylable content vs Plain text? ⬡ Feature-rich content vs Markdown? ⬡ Programmatic content manipulation? Will you need to manipulate the content programmatically (move elements, migrate to a new editor, upgrade your current editor, …)? (Most likely yes)

Slide 10

Slide 10 text

Questions to ask yourself 10 ⬡ Stylable content vs Plain text? ⬡ Feature-rich content vs Markdown? ⬡ Programmatic content manipulation? ⬡ Translation? Automatic/manual content translation?

Slide 11

Slide 11 text

Questions to ask yourself 11 ⬡ Stylable content vs Plain text? ⬡ Feature-rich content vs Markdown? ⬡ Programmatic content manipulation? ⬡ Translation? ⬡ Different display on mobile vs desktop? Should some blocks have a different structure on mobile?

Slide 12

Slide 12 text

Questions to ask yourself 12 ⬡ Stylable content vs Plain text? ⬡ Feature-rich content vs Markdown? ⬡ Programmatic content manipulation? ⬡ Translation? ⬡ Different display on mobile vs desktop? ⬡ Display in non-Web contexts (mobile/desktop app, …)?

Slide 13

Slide 13 text

Answers to these questions are both technical and human Content editors are one of the most complex UX challenge 13

Slide 14

Slide 14 text

2 Security concerns 14

Slide 15

Slide 15 text

A content editor is a big security risk You must implement dedicated security 15

Slide 16

Slide 16 text

Biggest risk: Cross-site scripting Inject JavaScript code into Web pages viewed by other users to extract information (session cookie, password, emails, …) from your users. 16

Slide 17

Slide 17 text

But also … CSS display attack Inject CSS into pages to render them unusable or log the keystrokes of visitors. 17

Slide 18

Slide 18 text

But also … Click-hijacking attack Inject HTML/CSS into pages to change the target of a legitimate link somewhere in the page (for instance the login button) to a phishing page. 18

Slide 19

Slide 19 text

But also … DDoS attacks Libraries to sanitize user content are complex and CPU-intensive (HTML parsing and manipulation). It’s a great place to DDoS a platform. 19

Slide 20

Slide 20 text

20 Implementing security

Slide 21

Slide 21 text

Simplest option Twig escape filter (or htmlentities) if you don’t need to accept HTML (plain text/markdown/…). You should use this when you can. 21

Slide 22

Slide 22 text

HTML sanitizing When you need to accept HTML (rich-content), you need to distinguish safe from unsafe HTML. This is what’s called HTML Sanitizing. 22

Slide 23

Slide 23 text

Symfony HtmlSanitizer The HTML Sanitizer component aims at sanitizing untrusted HTML code (e.g. created by a WYSIWYG editor in the browser) into HTML that can be trusted. 23

Slide 24

Slide 24 text

HtmlSanitizer is useful to: ● Prevent security issues (XSS, CSRF, data extraction, …) ● Prevent display problems (ensure content consistency) ● Output valid, standard HTML from potentially invalid WYSIWYG editor one 24

Slide 25

Slide 25 text

Usage 25

Slide 26

Slide 26 text

26

Slide 27

Slide 27 text

27 As a service

Slide 28

Slide 28 text

28 In a form

Slide 29

Slide 29 text

29 As a Twig filter

Slide 30

Slide 30 text

Configuration 30

Slide 31

Slide 31 text

31 Create a custom sanitizer

Slide 32

Slide 32 text

32 Configure allowed …

Slide 33

Slide 33 text

33 Configure allowed … and forbidden elements

Slide 34

Slide 34 text

34 Configure allowed links to prevent phishing and privacy issues

Slide 35

Slide 35 text

35 Configure allowed media to prevent phishing and privacy issues

Slide 36

Slide 36 text

Tip: you should apply sanitizing before storing and before display 36

Slide 37

Slide 37 text

Before storing To store safe HTML in the database 37

Slide 38

Slide 38 text

Before displaying Because: 1. Content can be manipulated from outside your application (manually, script missing the sanitizer, …) 2. Because some databases have unpredictable behaviors Ex: MySQL transforms UTF-8 character ⟨ to ASCII < when storing in a non-UTF8 field 38

Slide 39

Slide 39 text

3 Choosing an editor 39

Slide 40

Slide 40 text

The editor you choose should match your technical and UX needs 40

Slide 41

Slide 41 text

41 Plain-text

Slide 42

Slide 42 text

Simplest option (textarea) ● Easy-to-use for everyone ● Can be enough, especially with modern emoji support ● Very limited styling 42

Slide 43

Slide 43 text

Implementation ● Editor: standard textarea ● Display: Twig + escape filter 43

Slide 44

Slide 44 text

44 Markup language

Slide 45

Slide 45 text

Great for technical users ● Great UX for tech users (ex: Markdown + CodeMirror) ● Flexible without too much JavaScript complexity ● Not usable by non-tech users ● Requires HTML sanitization for security 45

Slide 46

Slide 46 text

46 Implementation Editor: ● TextareaType + HtmlSanitizer

Slide 47

Slide 47 text

47 Implementation Editor: ● TextareaType + HtmlSanitizer ● Symfony UX + CodeMirror

Slide 48

Slide 48 text

48 Implementation Editor: ● TextareaType + HtmlSanitizer ● Symfony UX + CodeMirror

Slide 49

Slide 49 text

49 Implementation Display: ● Twig + league/ commonmark + HtmlSanitizer

Slide 50

Slide 50 text

50 WYSIWYG

Slide 51

Slide 51 text

UX-friendly for everyone ● Easy-to-use by anyone ● Requires a complex JavaScript library ● Requires HTML sanitization for security ● Difficult to manipulate the generated content 51

Slide 52

Slide 52 text

52 Implementation Editor: ● TextareaType + HtmlSanitizer

Slide 53

Slide 53 text

53 Implementation Editor: ● TextareaType + HtmlSanitizer ● Symfony UX + CKEditor

Slide 54

Slide 54 text

54 Implementation Editor: ● TextareaType + HtmlSanitizer ● Symfony UX + CKEditor

Slide 55

Slide 55 text

55 Implementation Display: ● Twig + HtmlSanitizer

Slide 56

Slide 56 text

Problems 1. How can I add a
around tweets on display? 2. How can I upgrade my editor version without breaking existing content? 3. How can I display content in a non-Web context? 4. How can I allow multiple people to edit collaboratively? 56

Slide 57

Slide 57 text

HTML is not easy to manipulate 57

Slide 58

Slide 58 text

4 The state of the art: block-based editors 58

Slide 59

Slide 59 text

The idea Content is stored as JSON blocks, containing HTML only when necessary 59

Slide 60

Slide 60 text

The rendered HTML is only built at display 60

Slide 61

Slide 61 text

By using JSON blocks: ● Easier to manipulate (“add a
around tweets”) ● Can display content outside the Web ● Ease content migration during upgrades ● Make live collaboration possible 61

Slide 62

Slide 62 text

Example: Quill Rich Text Editor 62

Slide 63

Slide 63 text

63

Slide 64

Slide 64 text

Deltas Deltas are an expressive format to describe Quill’s contents and changes 64

Slide 65

Slide 65 text

65 Describes content…

Slide 66

Slide 66 text

66 …but also changes

Slide 67

Slide 67 text

Security Blocks content should still be: ● Escaped (Twig/htmlentities) if they won’t contain any HTML ● Sanitized if they will 67

Slide 68

Slide 68 text

Implementation Very similar to CKEditor: Symfony UX to instantiate, Symfony Form to extract the data 68

Slide 69

Slide 69 text

Storage Store the content as JSON in your database: easy manipulation! 69

Slide 70

Slide 70 text

Display Use Quill JS library to render blocks as safe HTML … or implement your own logic to display on other platforms! 70

Slide 71

Slide 71 text

Solutions 1. How can I add a
around tweets on display? 2. How can I upgrade my editor version without breaking existing content? 3. How can I display content in a non-Web context? => Now very easy! 4. How can I allow multiple people to edit the same content collaboratively? … 71

Slide 72

Slide 72 text

5 Live editing with Symfony UX and Mercure 72

Slide 73

Slide 73 text

Deltas allow us to live stream changes across users! 73

Slide 74

Slide 74 text

74 Collaborative editor

Slide 75

Slide 75 text

75 Collaborative editor This is a Delta change: small, easy bit to synchronize the editor state between users

Slide 76

Slide 76 text

Conclusion 76

Slide 77

Slide 77 text

Conclusion ● For simple needs: plain text + escape is enough (a content editor isn’t necessarily worth it) 77

Slide 78

Slide 78 text

Conclusion ● For simple needs: plain text + escape is enough (a content editor isn’t necessarily worth it) ● For tech users: Markdown + HtmlSanitizer with a code editor is great and flexible 78

Slide 79

Slide 79 text

Conclusion ● For simple needs: plain text + escape is enough (a content editor isn’t necessarily worth it) ● For tech users: Markdown + HtmlSanitizer with a code editor is great and flexible ● Otherwise: always choose a block-based editor (much more flexible) and use sanitization 79

Slide 80

Slide 80 text

80 Thanks! Any questions? You can find me at: @tgalopin [email protected] Slides design by SlidesCarnival