Skip to content
This repository has been archived by the owner on Sep 12, 2018. It is now read-only.

Commit

Permalink
Markdown: Change renderer for html and link
Browse files Browse the repository at this point in the history
- Add rel='noreferrer' to external link when application.noreferrer is true.
- An 'external link' is a link whose domain part of the url differs from location.hostname.
- When create link tag, value of href attibute replace to '#'
  instead of delete when used 'javascript:' in href of attribute for defence xss attack
  • Loading branch information
insanehong committed Sep 4, 2014
1 parent 2373dce commit 531c212
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 1 deletion.
1 change: 1 addition & 0 deletions app/views/common/markdown.scala.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
htOptions.sIssuesUrl = "@routes.IssueApp.issues(project.owner, project.name)";
htOptions.sProjectUrl = "@routes.ProjectApp.project(project.owner, project.name)";
htOptions.sApplicationContext = "@play.Configuration.root().getString("application.context")";
htOptions.bNoReferrer = "@play.Configuration.root().getString("application.noreferrer")"
}

// Reusable markdown renderer
Expand Down
74 changes: 74 additions & 0 deletions public/javascripts/common/yobi.Markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ yobi.Markdown = (function(htOptions){

_initVar(htOptions);
_enableMarkdown(htOptions.aTarget);
_initializeMarkdownRenderer();
}

/**
Expand All @@ -42,11 +43,13 @@ yobi.Markdown = (function(htOptions){
htVar.sProjectUrl = htOptions.sProjectUrl;
htVar.bBreaks = htOptions.bBreaks;
htVar.sApplicationContext = htOptions.sApplicationContext;
htVar.bNoReferrer = htOptions.bNoReferrer;
htVar.sUserRules = '[a-zA-Z0-9_\\-\\.\\/]';
htVar.sProjecRules = '[a-zA-Z0-9_\\-\\.]';
htVar.sIssueRules = '\\d';
htVar.sSha1Rules = '[a-f0-9]{7,40}';
htVar.htFilter = new Filter();

htVar.htMarkedOption = {
"gfm" : true,
"tables" : true,
Expand All @@ -68,6 +71,72 @@ yobi.Markdown = (function(htOptions){
};
}

function _initializeMarkdownRenderer() {
var renderer = new marked.Renderer();
renderer.link = function(href, title, text) {

var link = $('<a/>', {
href : _removeJavascript2Href(href),
title : title,
text: text
});

if(htVar.bNoReferrer && !isInternalLink(href)) link.attr('rel', "noreferrer");

return $('<div>').append(link.clone()).remove().html();
};

renderer.html = function(html) {
var tag = $(html);

if (tag.prop("href")) {

tag.attr("href", _removeJavascript2Href(tag.attr("href")));

if(htVar.bNoReferrer && !isInternalLink(tag.attr("href"))) {
tag.attr("rel", function(i, val) {
return _addUniqeValue2Attr(val, "noreferrer");
});
}

html = $('<div>').append(tag.clone()).remove().html().split(">")[0]+">";
}

return html;
};

htVar.htMarkedOption.renderer = renderer;
}

function _addUniqeValue2Attr(origin, value) {
if(!origin) return value;

var origins = origin.split(" ");
var values = [value];

$.each(origins, function(i, val){
if(val !== value) values.push(val);
});

return values.join(" ");
}

function _removeJavascript2Href(href) {
try {
var wordString = decodeURIComponent(unescape(href))
.replace(/[^\w:]/g, '')
.toLowerCase();
} catch (e) {
href = '#';
}

if (wordString.indexOf('javascript:') === 0) {
href = '#';
}

return href;
}

/**
* Render as Markdown document
*
Expand Down Expand Up @@ -265,6 +334,11 @@ yobi.Markdown = (function(htOptions){
return (sTagName === "TEXTAREA" || sTagName === "INPUT" || elTarget.contentEditable == "true");
}

function isInternalLink(url) {
var linkHostname = $('<a/>').attr('href', url).prop('hostname');
return (linkHostname === document.location.hostname);
}

// public interface
return {
"init" : _init,
Expand Down
2 changes: 1 addition & 1 deletion public/javascripts/lib/marked.js
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ InlineLexer.prototype.output = function(src) {
src = src.substring(cap[0].length);
out += this.options.sanitize
? escape(cap[0])
: cap[0];
: this.renderer.html(cap[0]);
continue;
}

Expand Down

0 comments on commit 531c212

Please sign in to comment.