client/views: escape HTML

This lets client use < > in tag names.
This commit is contained in:
rr- 2016-06-23 11:41:52 +02:00
parent b957f3ae36
commit 6ea129a9ef
29 changed files with 97 additions and 85 deletions

View file

@ -1,7 +1,7 @@
<div class='comment'> <div class='comment'>
<div class='avatar'> <div class='avatar'>
<% if (ctx.comment.user.name && ctx.canViewUsers) { %> <% if (ctx.comment.user.name && ctx.canViewUsers) { %>
<a href='/user/<%= ctx.comment.user.name %>'> <a href='/user/<%- ctx.comment.user.name %>'>
<% } %> <% } %>
<%= ctx.makeThumbnail(ctx.comment.user.avatarUrl) %> <%= ctx.makeThumbnail(ctx.comment.user.avatarUrl) %>
@ -15,10 +15,10 @@
<header><!-- <header><!--
--><span class='nickname'><!-- --><span class='nickname'><!--
--><% if (ctx.comment.user.name && ctx.canViewUsers) { %><!-- --><% if (ctx.comment.user.name && ctx.canViewUsers) { %><!--
--><a href='/user/<%= ctx.comment.user.name %>'><!-- --><a href='/user/<%- ctx.comment.user.name %>'><!--
--><% } %><!-- --><% } %><!--
--><%= ctx.comment.user.name %><!-- --><%- ctx.comment.user.name %><!--
--><% if (ctx.comment.user.name && ctx.canViewUsers) { %><!-- --><% if (ctx.comment.user.name && ctx.canViewUsers) { %><!--
--></a><!-- --></a><!--

View file

@ -10,7 +10,7 @@
--></div><!-- --></div><!--
--><div class='edit tab'><!-- --><div class='edit tab'><!--
--><textarea required minlength=1><%= ctx.comment.text %></textarea><!-- --><textarea required minlength=1><%- ctx.comment.text %></textarea><!--
--></div><!-- --></div><!--
--></div> --></div>

View file

@ -4,14 +4,14 @@
--><li><!-- --><li><!--
--><div class='post-thumbnail'><!-- --><div class='post-thumbnail'><!--
--><% if (ctx.canViewPosts) { %><!-- --><% if (ctx.canViewPosts) { %><!--
--><a href='/post/<%= post.id %>'><!-- --><a href='/post/<%- post.id %>'><!--
--><% } %><!-- --><% } %><!--
--><%= ctx.makeThumbnail(post.thumbnailUrl) %><!-- --><%= ctx.makeThumbnail(post.thumbnailUrl) %><!--
--><% if (ctx.canViewPosts) { %><!-- --><% if (ctx.canViewPosts) { %><!--
--></a><!-- --></a><!--
--><% } %><!-- --><% } %><!--
--></div><!-- --></div><!--
--><div class='comments-container' data-for='<%= post.id %>'></div><!-- --><div class='comments-container' data-for='<%- post.id %>'></div><!--
--></li><!-- --></li><!--
--><% } %><!-- --><% } %><!--
--></ul> --></ul>

View file

@ -1,4 +1,4 @@
<div class='page'> <div class='page'>
<p class='page-header'><span>Page <%= ctx.page %> of <%= ctx.totalPages %></span></p> <p class='page-header'><span>Page <%- ctx.page %> of <%- ctx.totalPages %></span></p>
<div class='page-content-holder'></div> <div class='page-content-holder'></div>
</div> </div>

View file

@ -12,4 +12,4 @@
<% } %> <% } %>
<span class='vim-nav-hint'>add to favorites</span> <span class='vim-nav-hint'>add to favorites</span>
</a> </a>
<span class='value'><%= ctx.favoriteCount %></span> <span class='value'><%- ctx.favoriteCount %></span>

View file

@ -1,6 +1,6 @@
<div class='file-dropper-holder'> <div class='file-dropper-holder'>
<input type='file' id='<%= ctx.id %>'/> <input type='file' id='<%- ctx.id %>'/>
<label class='file-dropper' for='<%= ctx.id %>'> <label class='file-dropper' for='<%- ctx.id %>'>
<% if (ctx.allowMultiple) { %> <% if (ctx.allowMultiple) { %>
Drop files here! Drop files here!
<% } else { %> <% } else { %>

View file

@ -1,4 +1,4 @@
<p>By accessing <%= ctx.name %> (&ldquo;Site&rdquo;) you agree to the following <p>By accessing <%- ctx.name %> (&ldquo;Site&rdquo;) you agree to the following
Terms of Service. If you do not agree to these terms, then please do not access Terms of Service. If you do not agree to these terms, then please do not access
the Site.</p> the Site.</p>

View file

@ -1,7 +1,7 @@
<div class='content-wrapper transparent' id='home'> <div class='content-wrapper transparent' id='home'>
<div class='messages'></div> <div class='messages'></div>
<header> <header>
<h1><%= ctx.name %></h1> <h1><%- ctx.name %></h1>
<aside class='stats-container'></aside> <aside class='stats-container'></aside>
</header> </header>
<% if (ctx.canListPosts) { %> <% if (ctx.canListPosts) { %>
@ -27,7 +27,7 @@
<% } %> <% } %>
<div class='post-container'></div> <div class='post-container'></div>
<footer> <footer>
Build <a class='version' href='https://github.com/rr-/szurubooru/commits/master'><%= ctx.version %></a> Build <a class='version' href='https://github.com/rr-/szurubooru/commits/master'><%- ctx.version %></a>
from <%= ctx.makeRelativeTime(ctx.buildDate) %> from <%= ctx.makeRelativeTime(ctx.buildDate) %>
</footer> </footer>
</div> </div>

View file

@ -1 +1 @@
Serving <%= ctx.postCount %> posts (<%= ctx.makeFileSize(ctx.diskUsage) %>) Serving <%- ctx.postCount %> posts (<%= ctx.makeFileSize(ctx.diskUsage) %>)

View file

@ -2,7 +2,7 @@
<ul> <ul>
<li> <li>
<% if (ctx.prevLinkActive) { %> <% if (ctx.prevLinkActive) { %>
<a class='prev' href='<%= ctx.prevLink %>'> <a class='prev' href='<%- ctx.prevLink %>'>
<% } else { %> <% } else { %>
<a class='prev disabled'> <a class='prev disabled'>
<% } %> <% } %>
@ -20,14 +20,14 @@
<% } else { %> <% } else { %>
<li> <li>
<% } %> <% } %>
<a href='<%= page.link %>'><%= page.number %></a> <a href='<%- page.link %>'><%- page.number %></a>
</li> </li>
<% } %> <% } %>
<% } %> <% } %>
<li> <li>
<% if (ctx.nextLinkActive) { %> <% if (ctx.nextLinkActive) { %>
<a class='next' href='<%= ctx.nextLink %>'> <a class='next' href='<%- ctx.nextLink %>'>
<% } else { %> <% } else { %>
<a class='next disabled'> <a class='next disabled'>
<% } %> <% } %>

View file

@ -1,5 +1,5 @@
<div class='not-found'> <div class='not-found'>
<img src='/img/404.png' alt='404 Not found'/> <img src='/img/404.png' alt='404 Not found'/>
<p><%= ctx.path %> is not a valid URL.</p> <p><%- ctx.path %> is not a valid URL.</p>
<p><a href='/'>Back to main page</a></p> <p><a href='/'>Back to main page</a></p>
</div> </div>

View file

@ -4,9 +4,9 @@
<article class='next-post'> <article class='next-post'>
<% if (ctx.nextPostId) { %> <% if (ctx.nextPostId) { %>
<% if (ctx.searchQuery && ctx.searchQuery.text) { %> <% if (ctx.searchQuery && ctx.searchQuery.text) { %>
<a href='/post/<%= ctx.nextPostId %>/text=<%= ctx.searchQuery.text %>'> <a href='/post/<%- ctx.nextPostId %>/text=<%- ctx.searchQuery.text %>'>
<% } else { %> <% } else { %>
<a href='/post/<%= ctx.nextPostId %>'> <a href='/post/<%- ctx.nextPostId %>'>
<% } %> <% } %>
<% } else { %> <% } else { %>
<a class='inactive'> <a class='inactive'>
@ -18,9 +18,9 @@
<article class='previous-post'> <article class='previous-post'>
<% if (ctx.prevPostId) { %> <% if (ctx.prevPostId) { %>
<% if (ctx.searchQuery && ctx.searchQuery.text) { %> <% if (ctx.searchQuery && ctx.searchQuery.text) { %>
<a href='/post/<%= ctx.prevPostId %>/text=<%= ctx.searchQuery.text %>'> <a href='/post/<%- ctx.prevPostId %>/text=<%- ctx.searchQuery.text %>'>
<% } else { %> <% } else { %>
<a href='/post/<%= ctx.prevPostId %>'> <a href='/post/<%- ctx.prevPostId %>'>
<% } %> <% } %>
<% } else { %> <% } else { %>
<a class='inactive'> <a class='inactive'>
@ -31,16 +31,16 @@
</article> </article>
<article class='edit-post'> <article class='edit-post'>
<% if (ctx.editMode) { %> <% if (ctx.editMode) { %>
<a href='/post/<%= ctx.post.id %>'> <a href='/post/<%- ctx.post.id %>'>
<i class='fa fa-eye'></i> <i class='fa fa-eye'></i>
<span class='vim-nav-hint'>Back to view mode</span> <span class='vim-nav-hint'>Back to view mode</span>
</a> </a>
<% } else { %> <% } else { %>
<% if (ctx.canEditPosts) { %> <% if (ctx.canEditPosts) { %>
<% if (ctx.searchQuery && ctx.searchQuery.text) { %> <% if (ctx.searchQuery && ctx.searchQuery.text) { %>
<a href='/post/<%= ctx.post.id %>/edit/text=<%= ctx.searchQuery.text %>'> <a href='/post/<%- ctx.post.id %>/edit/text=<%- ctx.searchQuery.text %>'>
<% } else { %> <% } else { %>
<a href='/post/<%= ctx.post.id %>/edit'> <a href='/post/<%- ctx.post.id %>/edit'>
<% } %> <% } %>
<% } else { %> <% } else { %>
<a class='inactive'> <a class='inactive'>

View file

@ -1,13 +1,13 @@
<div class='post-content post-type-<%= ctx.post.type %>'> <div class='post-content post-type-<%- ctx.post.type %>'>
<% if (['image', 'animation'].includes(ctx.post.type)) { %> <% if (['image', 'animation'].includes(ctx.post.type)) { %>
<img alt='' src='<%= ctx.post.contentUrl %>'/> <img alt='' src='<%- ctx.post.contentUrl %>'/>
<% } else if (ctx.post.type === 'flash') { %> <% } else if (ctx.post.type === 'flash') { %>
<object width='<%= ctx.post.canvasWidth %>' height='<%= ctx.post.canvasHeight %>' data='<%= ctx.post.contentUrl %>'> <object width='<%- ctx.post.canvasWidth %>' height='<%- ctx.post.canvasHeight %>' data='<%- ctx.post.contentUrl %>'>
<param name='wmode' value='opaque'/> <param name='wmode' value='opaque'/>
<param name='movie' value='<%= ctx.post.contentUrl %>'/> <param name='movie' value='<%- ctx.post.contentUrl %>'/>
</object> </object>
<% } else if (ctx.post.type === 'video') { %> <% } else if (ctx.post.type === 'video') { %>
@ -18,7 +18,7 @@
<video id='video' controls> <video id='video' controls>
<% } %> <% } %>
<source type='<%= ctx.post.mimeType %>' src='<%= ctx.post.contentUrl %>'/> <source type='<%- ctx.post.mimeType %>' src='<%- ctx.post.contentUrl %>'/>
Your browser doesn't support HTML5 videos. Your browser doesn't support HTML5 videos.
</video> </video>

View file

@ -1,9 +1,9 @@
<article class='details'> <article class='details'>
<section class='download'> <section class='download'>
<a rel='external' href='<%= ctx.post.contentUrl %>'> <a rel='external' href='<%- ctx.post.contentUrl %>'>
<i class='fa fa-download'></i><!-- <i class='fa fa-download'></i><!--
--><%= ctx.makeFileSize(ctx.post.fileSize) %> <!-- --><%= ctx.makeFileSize(ctx.post.fileSize) %> <!--
--><%= { --><%- {
'image/gif': 'GIF', 'image/gif': 'GIF',
'image/jpeg': 'JPEG', 'image/jpeg': 'JPEG',
'image/png': 'PNG', 'image/png': 'PNG',
@ -11,7 +11,7 @@
'application/x-shockwave-flash': 'SWF', 'application/x-shockwave-flash': 'SWF',
}[ctx.post.mimeType] %> }[ctx.post.mimeType] %>
</a> </a>
(<%= ctx.post.canvasWidth %>x<%= ctx.post.canvasHeight %>) (<%- ctx.post.canvasWidth %>x<%- ctx.post.canvasHeight %>)
</section> </section>
<section class='upload-info'> <section class='upload-info'>
@ -20,8 +20,8 @@
</section> </section>
<section class='safety'> <section class='safety'>
<i class='fa fa-circle safety-<%= ctx.post.safety %>'></i><!-- <i class='fa fa-circle safety-<%- ctx.post.safety %>'></i><!--
--><%= ctx.post.safety[0].toUpperCase() + ctx.post.safety.slice(1) %> --><%- ctx.post.safety[0].toUpperCase() + ctx.post.safety.slice(1) %>
</section> </section>
<section class='zoom'> <section class='zoom'>
@ -33,8 +33,8 @@
<section class='search'> <section class='search'>
Search on Search on
<a href='http://iqdb.org/?url=<%= ctx.post.contentUrl %>'>IQDB</a> &middot; <a href='http://iqdb.org/?url=<%- ctx.post.contentUrl %>'>IQDB</a> &middot;
<a href='https://www.google.com/searchbyimage?&image_url=<%= ctx.post.contentUrl %>'>Google Images</a> <a href='https://www.google.com/searchbyimage?&image_url=<%- ctx.post.contentUrl %>'>Google Images</a>
</section> </section>
<section class='social'> <section class='social'>
@ -45,25 +45,25 @@
</article> </article>
<nav class='tags'> <nav class='tags'>
<h1>Tags (<%= ctx.post.tags.length %>)</h1> <h1>Tags (<%- ctx.post.tags.length %>)</h1>
<ul><!-- <ul><!--
--><% for (let tag of ctx.post.tags) { %><!-- --><% for (let tag of ctx.post.tags) { %><!--
--><li><!-- --><li><!--
--><% if (ctx.canViewTags) { %><!-- --><% if (ctx.canViewTags) { %><!--
--><a href='/tag/<%= tag %>' class='<%= ctx.makeCssName(ctx.getTagCategory(tag), 'tag') %>'><!-- --><a href='/tag/<%- tag %>' class='<%= ctx.makeCssName(ctx.getTagCategory(tag), 'tag') %>'><!--
--><i class='fa fa-tag'></i><!-- --><i class='fa fa-tag'></i><!--
--><% } %><!-- --><% } %><!--
--><% if (ctx.canListPosts) { %><!-- --><% if (ctx.canListPosts) { %><!--
--></a><!-- --></a><!--
--><% } %><!-- --><% } %><!--
--><% if (ctx.canListPosts) { %><!-- --><% if (ctx.canListPosts) { %><!--
--><a href='/posts/text=<%= tag %>' class='<%= ctx.makeCssName(ctx.getTagCategory(tag), 'tag') %>'><!-- --><a href='/posts/text=<%- tag %>' class='<%= ctx.makeCssName(ctx.getTagCategory(tag), 'tag') %>'><!--
--><% } %><!-- --><% } %><!--
--><%= tag %><!-- --><%- tag %><!--
--><% if (ctx.canListPosts) { %><!-- --><% if (ctx.canListPosts) { %><!--
--></a><!-- --></a><!--
--><% } %><!-- --><% } %><!--
--><span class='count'><%= ctx.getTagUsages(tag) %></span><!-- --><span class='count'><%- ctx.getTagUsages(tag) %></span><!--
--></li><!-- --></li><!--
--><% } %><!-- --><% } %><!--
--></ul> --></ul>

View file

@ -9,9 +9,9 @@
</div> </div>
<div class='buttons'> <div class='buttons'>
<input class='mousetrap' type='submit' value='Search'/> <input class='mousetrap' type='submit' value='Search'/>
<input data-safety=safe type='button' class='mousetrap safety safety-safe <%= ctx.settings.listPosts.safe ? '' : 'disabled' %>'/> <input data-safety=safe type='button' class='mousetrap safety safety-safe <%- ctx.settings.listPosts.safe ? '' : 'disabled' %>'/>
<input data-safety=sketchy type='button' class='mousetrap safety safety-sketchy <%= ctx.settings.listPosts.sketchy ? '' : 'disabled' %>'/> <input data-safety=sketchy type='button' class='mousetrap safety safety-sketchy <%- ctx.settings.listPosts.sketchy ? '' : 'disabled' %>'/>
<input data-safety=unsafe type='button' class='mousetrap safety safety-unsafe <%= ctx.settings.listPosts.unsafe ? '' : 'disabled' %>'/> <input data-safety=unsafe type='button' class='mousetrap safety safety-unsafe <%- ctx.settings.listPosts.unsafe ? '' : 'disabled' %>'/>
<a class='mousetrap button append' href='/help/search/posts'>Syntax help</a> <a class='mousetrap button append' href='/help/search/posts'>Syntax help</a>
</div> </div>
</form> </form>

View file

@ -5,35 +5,35 @@
<li> <li>
<% if (ctx.canViewPosts) { %> <% if (ctx.canViewPosts) { %>
<% if (ctx.searchQuery && ctx.searchQuery.text) { %> <% if (ctx.searchQuery && ctx.searchQuery.text) { %>
<a href='/post/<%= post.id %>/text=<%= ctx.searchQuery.text %>' title='@<%= post.id %> (<%= post.type %>)&#10;&#10;Tags: <%= post.tags.map(tag => '#' + tag).join(' ') %>'> <a href='/post/<%- post.id %>/text=<%- ctx.searchQuery.text %>' title='@<%- post.id %> (<%- post.type %>)&#10;&#10;Tags: <%- post.tags.map(tag => '#' + tag).join(' ') %>'>
<% } else { %> <% } else { %>
<a href='/post/<%= post.id %>' title='@<%= post.id %> (<%= post.type %>)&#10;&#10;Tags: <%= post.tags.map(tag => '#' + tag).join(' ') %>'> <a href='/post/<%- post.id %>' title='@<%- post.id %> (<%- post.type %>)&#10;&#10;Tags: <%- post.tags.map(tag => '#' + tag).join(' ') %>'>
<% } %> <% } %>
<% } else { %> <% } else { %>
<a> <a>
<% } %> <% } %>
<%= ctx.makeThumbnail(post.thumbnailUrl) %> <%= ctx.makeThumbnail(post.thumbnailUrl) %>
<span class='type' data-type='<%= post.type %>'> <span class='type' data-type='<%- post.type %>'>
<%= post.type %> <%- post.type %>
</span> </span>
<% if (post.score || post.favoriteCount || post.commentCount) { %> <% if (post.score || post.favoriteCount || post.commentCount) { %>
<span class='stats'> <span class='stats'>
<% if (post.score) { %> <% if (post.score) { %>
<span class='icon'> <span class='icon'>
<i class='fa fa-star'></i> <i class='fa fa-star'></i>
<%= post.score %> <%- post.score %>
</span> </span>
<% } %> <% } %>
<% if (post.favoriteCount) { %> <% if (post.favoriteCount) { %>
<span class='icon'> <span class='icon'>
<i class='fa fa-heart'></i> <i class='fa fa-heart'></i>
<%= post.favoriteCount %> <%- post.favoriteCount %>
</span> </span>
<% } %> <% } %>
<% if (post.commentCount) { %> <% if (post.commentCount) { %>
<span class='icon'> <span class='icon'>
<i class='fa fa-commenting'></i> <i class='fa fa-commenting'></i>
<%= post.commentCount %> <%- post.commentCount %>
</span> </span>
<% } %> <% } %>
</span> </span>

View file

@ -13,7 +13,7 @@
<i class='fa fa-thumbs-o-up'></i> <i class='fa fa-thumbs-o-up'></i>
</a> </a>
<% } %> <% } %>
<span class='value'><%= ctx.score %></span> <span class='value'><%- ctx.score %></span>
<% if (ctx.canScore) { %> <% if (ctx.canScore) { %>
<a class='downvote' href='#'> <a class='downvote' href='#'>
<% if (ctx.ownScore == -1) { %> <% if (ctx.ownScore == -1) { %>

View file

@ -1,16 +1,16 @@
<div class='content-wrapper tag'> <div class='content-wrapper tag'>
<h1><%= ctx.tag.names[0] %></h1> <h1><%- ctx.tag.names[0] %></h1>
<nav class='buttons'><!-- <nav class='buttons'><!--
--><ul><!-- --><ul><!--
--><li data-name='summary'><a href='/tag/<%= ctx.tag.names[0] %>'>Summary</a></li><!-- --><li data-name='summary'><a href='/tag/<%- ctx.tag.names[0] %>'>Summary</a></li><!--
--><% if (ctx.canMerge) { %><!-- --><% if (ctx.canMerge) { %><!--
--><li data-name='edit'><a href='/tag/<%= ctx.tag.names[0] %>/edit'>Edit</a></li><!-- --><li data-name='edit'><a href='/tag/<%- ctx.tag.names[0] %>/edit'>Edit</a></li><!--
--><% } %><!-- --><% } %><!--
--><% if (ctx.canMerge) { %><!-- --><% if (ctx.canMerge) { %><!--
--><li data-name='merge'><a href='/tag/<%= ctx.tag.names[0] %>/merge'>Merge with&hellip;</a></li><!-- --><li data-name='merge'><a href='/tag/<%- ctx.tag.names[0] %>/merge'>Merge with&hellip;</a></li><!--
--><% } %><!-- --><% } %><!--
--><% if (ctx.canDelete) { %><!-- --><% if (ctx.canDelete) { %><!--
--><li data-name='delete'><a href='/tag/<%= ctx.tag.names[0] %>/delete'>Delete</a></li><!-- --><li data-name='delete'><a href='/tag/<%- ctx.tag.names[0] %>/delete'>Delete</a></li><!--
--><% } %><!-- --><% } %><!--
--></ul><!-- --></ul><!--
--></nav> --></nav>

View file

@ -1,27 +1,27 @@
<tr data-category='<%= ctx.tagCategory.name %>' <tr data-category='<%- ctx.tagCategory.name %>'
<% if (ctx.tagCategory.isDefault) { %> class='default' <% } %> <% if (ctx.tagCategory.isDefault) { %> class='default' <% } %>
> >
<td class='name'> <td class='name'>
<% if (ctx.canEditName) { %> <% if (ctx.canEditName) { %>
<%= ctx.makeTextInput({value: ctx.tagCategory.name, required: true}) %> <%= ctx.makeTextInput({value: ctx.tagCategory.name, required: true}) %>
<% } else { %> <% } else { %>
<%= ctx.tagCategory.name %> <%- ctx.tagCategory.name %>
<% } %> <% } %>
</td> </td>
<td class='color'> <td class='color'>
<% if (ctx.canEditColor) { %> <% if (ctx.canEditColor) { %>
<%= ctx.makeColorInput({value: ctx.tagCategory.color}) %> <%= ctx.makeColorInput({value: ctx.tagCategory.color}) %>
<% } else { %> <% } else { %>
<%= ctx.tagCategory.color %> <%- ctx.tagCategory.color %>
<% } %> <% } %>
</td> </td>
<td class='usages'> <td class='usages'>
<% if (ctx.tagCategory.name) { %> <% if (ctx.tagCategory.name) { %>
<a href='/tags/text=category:<%= ctx.tagCategory.name %>'> <a href='/tags/text=category:<%- ctx.tagCategory.name %>'>
<%= ctx.tagCategory.tagCount %> <%- ctx.tagCategory.tagCount %>
</a> </a>
<% } else { %> <% } else { %>
<%= ctx.tagCategory.tagCount %> <%- ctx.tagCategory.tagCount %>
<% } %> <% } %>
</td> </td>
<% if (ctx.canDelete) { %> <% if (ctx.canDelete) { %>

View file

@ -2,7 +2,7 @@
<form> <form>
<% if (ctx.tag.postCount) { %> <% if (ctx.tag.postCount) { %>
<p>For extra <s>paranoia</s> safety, only tags that are unused can be deleted.</p> <p>For extra <s>paranoia</s> safety, only tags that are unused can be deleted.</p>
<p>Check <a href='/posts/text=<%= ctx.tag.names[0] %>'>which posts</a> are tagged with <%= ctx.tag.names[0] %>.</p> <p>Check <a href='/posts/text=<%- ctx.tag.names[0] %>'>which posts</a> are tagged with <%- ctx.tag.names[0] %>.</p>
<% } else { %> <% } else { %>
<div class='input'> <div class='input'>
<ul> <ul>

View file

@ -2,7 +2,7 @@
<section class='details'> <section class='details'>
<section> <section>
Category: Category:
<span class='<%= ctx.makeCssName(ctx.tag.category, 'tag') %>'><%= ctx.tag.category %></span> <span class='<%= ctx.makeCssName(ctx.tag.category, 'tag') %>'><%- ctx.tag.category %></span>
</section> </section>
<section> <section>

View file

@ -71,7 +71,7 @@
<% } %> <% } %>
</td> </td>
<td class='usages'> <td class='usages'>
<%= tag.postCount %> <%- tag.postCount %>
</td> </td>
<td class='edit-time'> <td class='edit-time'>
<%= ctx.makeRelativeTime(tag.lastEditTime) %> <%= ctx.makeRelativeTime(tag.lastEditTime) %>

View file

@ -2,8 +2,8 @@
--><ul><!-- --><ul><!--
--><% for (let item of ctx.items) { %><!-- --><% for (let item of ctx.items) { %><!--
--><% if (item.available) { %><!-- --><% if (item.available) { %><!--
--><li data-name='<%= item.key %>'><!-- --><li data-name='<%- item.key %>'><!--
--><a href='<%= item.url %>' accesskey='<%= item.accessKey %>'><!-- --><a href='<%- item.url %>' accesskey='<%- item.accessKey %>'><!--
--><% if (item.imageUrl) { print(ctx.makeThumbnail(item.imageUrl)); } %><!-- --><% if (item.imageUrl) { print(ctx.makeThumbnail(item.imageUrl)); } %><!--
--><span class='text'><%= ctx.makeAccessKey(item.title, item.accessKey) %></span><!-- --><span class='text'><%= ctx.makeAccessKey(item.title, item.accessKey) %></span><!--
--></a><!-- --></a><!--

View file

@ -1,13 +1,13 @@
<div class='content-wrapper' id='user'> <div class='content-wrapper' id='user'>
<h1><%= ctx.user.name %></h1> <h1><%- ctx.user.name %></h1>
<nav class='buttons'><!-- <nav class='buttons'><!--
--><ul><!-- --><ul><!--
--><li data-name='summary'><a href='/user/<%= ctx.user.name %>'>Summary</a></li><!-- --><li data-name='summary'><a href='/user/<%- ctx.user.name %>'>Summary</a></li><!--
--><% if (ctx.canEditAnything) { %><!-- --><% if (ctx.canEditAnything) { %><!--
--><li data-name='edit'><a href='/user/<%= ctx.user.name %>/edit'>Account settings</a></li><!-- --><li data-name='edit'><a href='/user/<%- ctx.user.name %>/edit'>Account settings</a></li><!--
--><% } %><!-- --><% } %><!--
--><% if (ctx.canDelete) { %><!-- --><% if (ctx.canDelete) { %><!--
--><li data-name='delete'><a href='/user/<%= ctx.user.name %>/delete'>Account deletion</a></li><!-- --><li data-name='delete'><a href='/user/<%- ctx.user.name %>/delete'>Account deletion</a></li><!--
--><% } %><!-- --><% } %><!--
--></ul><!-- --></ul><!--
--></nav> --></nav>

View file

@ -3,16 +3,16 @@
<ul class='basic-info'> <ul class='basic-info'>
<li>Registered: <%= ctx.makeRelativeTime(ctx.user.creationTime) %></li> <li>Registered: <%= ctx.makeRelativeTime(ctx.user.creationTime) %></li>
<li>Last seen: <%= ctx.makeRelativeTime(ctx.user.lastLoginTime) %></li> <li>Last seen: <%= ctx.makeRelativeTime(ctx.user.lastLoginTime) %></li>
<li>Rank: <%= ctx.user.rankName.toLowerCase() %></li> <li>Rank: <%- ctx.user.rankName.toLowerCase() %></li>
</ul> </ul>
<div> <div>
<nav> <nav>
<p><strong>Quick links</strong></p> <p><strong>Quick links</strong></p>
<ul> <ul>
<li><a href='/posts/text=submit:<%= ctx.user.name %>'><%= ctx.user.uploadedPostCount %> uploads</a></li> <li><a href='/posts/text=submit:<%- ctx.user.name %>'><%- ctx.user.uploadedPostCount %> uploads</a></li>
<li><a href='/posts/text=fav:<%= ctx.user.name %>'><%= ctx.user.favoritePostCount %> favorites</a></li> <li><a href='/posts/text=fav:<%- ctx.user.name %>'><%- ctx.user.favoritePostCount %> favorites</a></li>
<li><a href='/posts/text=comment:<%= ctx.user.name %>'><%= ctx.user.commentCount %> comments</a></li> <li><a href='/posts/text=comment:<%- ctx.user.name %>'><%- ctx.user.commentCount %> comments</a></li>
</ul> </ul>
</nav> </nav>
@ -20,8 +20,8 @@
<nav> <nav>
<p><strong>Only visible to you</strong></p> <p><strong>Only visible to you</strong></p>
<ul> <ul>
<li><a href='/posts/text=special:liked'><%= ctx.user.likedPostCount %> liked posts</a></li> <li><a href='/posts/text=special:liked'><%- ctx.user.likedPostCount %> liked posts</a></li>
<li><a href='/posts/text=special:disliked'><%= ctx.user.dislikedPostCount %> disliked posts</a></li> <li><a href='/posts/text=special:disliked'><%- ctx.user.dislikedPostCount %> disliked posts</a></li>
</ul> </ul>
</nav> </nav>
<% } %> <% } %>

View file

@ -4,7 +4,7 @@
--><li> --><li>
<div class='wrapper'> <div class='wrapper'>
<% if (ctx.canViewUsers) { %> <% if (ctx.canViewUsers) { %>
<a class='image' href='/user/<%= user.name %>'> <a class='image' href='/user/<%- user.name %>'>
<% } %> <% } %>
<%= ctx.makeThumbnail(user.avatarUrl) %> <%= ctx.makeThumbnail(user.avatarUrl) %>
<% if (ctx.canViewUsers) { %> <% if (ctx.canViewUsers) { %>
@ -12,9 +12,9 @@
<% } %> <% } %>
<div class='details'> <div class='details'>
<% if (ctx.canViewUsers) { %> <% if (ctx.canViewUsers) { %>
<a href='/user/<%= user.name %>'> <a href='/user/<%- user.name %>'>
<% } %> <% } %>
<%= user.name %> <%- user.name %>
<% if (ctx.canViewUsers) { %> <% if (ctx.canViewUsers) { %>
</a> </a>
<% } %> <% } %>

View file

@ -28,8 +28,9 @@ class TagAutoCompleteControl extends AutoCompleteControl {
return kv2[1].usages - kv1[1].usages; return kv2[1].usages - kv1[1].usages;
}) })
.map(kv => { .map(kv => {
const origName = misc.escapeHtml(
tags.getOriginalTagName(kv[0]));
const category = kv[1].category; const category = kv[1].category;
const origName = tags.getOriginalTagName(kv[0]);
const usages = kv[1].usages; const usages = kv[1].usages;
const cssName = misc.makeCssName(category, 'tag'); const cssName = misc.makeCssName(category, 'tag');
return { return {

View file

@ -224,6 +224,15 @@ function makeCssName(text, suffix) {
return suffix + '-' + text.replace(/[^a-z0-9]/g, '_'); return suffix + '-' + text.replace(/[^a-z0-9]/g, '_');
} }
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
}
module.exports = { module.exports = {
range: range, range: range,
formatSearchQuery: formatSearchQuery, formatSearchQuery: formatSearchQuery,
@ -236,5 +245,6 @@ module.exports = {
enableExitConfirmation: enableExitConfirmation, enableExitConfirmation: enableExitConfirmation,
disableExitConfirmation: disableExitConfirmation, disableExitConfirmation: disableExitConfirmation,
confirmPageExit: confirmPageExit, confirmPageExit: confirmPageExit,
escapeHtml: escapeHtml,
makeCssName: makeCssName, makeCssName: makeCssName,
}; };

View file

@ -198,7 +198,8 @@ function _serializeElement(name, attributes) {
attributes[key] === undefined) { attributes[key] === undefined) {
return ''; return '';
} }
return `${key}="${attributes[key]}"`; const attribute = misc.escapeHtml(attributes[key] || '');
return `${key}="${attribute}"`;
})) }))
.join(' '); .join(' ');
} }
@ -446,7 +447,6 @@ module.exports = {
replaceContent: replaceContent, replaceContent: replaceContent,
enableForm: enableForm, enableForm: enableForm,
disableForm: disableForm, disableForm: disableForm,
clearMessages: clearMessages,
decorateValidator: decorateValidator, decorateValidator: decorateValidator,
makeVoidElement: makeVoidElement, makeVoidElement: makeVoidElement,
makeNonVoidElement: makeNonVoidElement, makeNonVoidElement: makeNonVoidElement,
@ -454,6 +454,7 @@ module.exports = {
slideDown: slideDown, slideDown: slideDown,
slideUp: slideUp, slideUp: slideUp,
monitorNodeRemoval: monitorNodeRemoval, monitorNodeRemoval: monitorNodeRemoval,
clearMessages: clearMessages,
showError: showError, showError: showError,
showSuccess: showSuccess, showSuccess: showSuccess,
showInfo: showInfo, showInfo: showInfo,