Browse Source

Added hook to validate links

pull/14/head
Vitaly Puzrin 10 years ago
parent
commit
81778ecdba
  1. 4
      README.md
  2. 2
      lib/links.js
  3. 8
      lib/parser_inline.js
  4. 19
      lib/rules_inline/autolink.js
  5. 9
      lib/rules_typographer/linkify.js

4
README.md

@ -8,13 +8,13 @@ remarkable
Markdown parser done right. Fast and easy to extend. Markdown parser done right. Fast and easy to extend.
__[Live demo](http://jonschlinkert.github.io/remarkable/demo/)__
- Configurable syntax! You can add new rules and even replace existing ones. - Configurable syntax! You can add new rules and even replace existing ones.
- Implements [CommonMark](http://commonmark.org/) spec + extentions - Implements [CommonMark](http://commonmark.org/) spec + extentions
(strikethrough, tables, URL autolinking, typographer). (strikethrough, tables, URL autolinking, typographer).
- Very high speed. - Very high speed.
__[Live demo](http://jonschlinkert.github.io/remarkable/demo/)__
## Install ## Install

2
lib/links.js

@ -124,6 +124,8 @@ function parseLinkDestination(state, pos) {
if (!href.length) { return false; } if (!href.length) { return false; }
if (!state.parser.validateLink(href)) { return false; }
state.pos = pos; state.pos = pos;
state.link_content = href; state.link_content = href;
return true; return true;

8
lib/parser_inline.js

@ -25,6 +25,10 @@ rules.push(require('./rules_inline/htmltag'));
rules.push(require('./rules_inline/entity')); rules.push(require('./rules_inline/entity'));
rules.push(require('./rules_inline/escape_html_char')); rules.push(require('./rules_inline/escape_html_char'));
function validateLink(url) {
if (url.indexOf('javas' + 'cript:') === 0) { return false; }
return true;
}
// Inline Parser class // Inline Parser class
// //
@ -36,6 +40,10 @@ function ParserInline() {
// - '<>"' added for internal html escaping // - '<>"' added for internal html escaping
this.textMatch = /^[^\n\\`*_\[\]!&{}$%@<>"~]+/; this.textMatch = /^[^\n\\`*_\[\]!&{}$%@<>"~]+/;
// By default CommonMark allows too much in links
// If you need to restrict it - override this with your validator.
this.validateLink = validateLink;
this.ruler = new Ruler(this.rulesUpdate.bind(this)); this.ruler = new Ruler(this.rulesUpdate.bind(this));
for (var i = 0; i < rules.length; i++) { for (var i = 0; i < rules.length; i++) {

19
lib/rules_inline/autolink.js

@ -11,7 +11,7 @@ var AUTOLINK_RE = /^<([a-zA-Z.\-]{1,25}):([^<>\x00-\x20]*)>/;
module.exports = function autolink(state) { module.exports = function autolink(state) {
var tail, linkMatch, emailMatch, pos = state.pos; var tail, linkMatch, emailMatch, url, pos = state.pos;
if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; } if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; }
@ -24,14 +24,18 @@ module.exports = function autolink(state) {
if (linkMatch) { if (linkMatch) {
if (url_schemas.indexOf(linkMatch[1].toLowerCase()) < 0) { return false; } if (url_schemas.indexOf(linkMatch[1].toLowerCase()) < 0) { return false; }
url = linkMatch[0].slice(1, -1);
if (!state.parser.validateLink(url)) { return false; }
state.push({ state.push({
type: 'link_open', type: 'link_open',
href: linkMatch[0].slice(1, -1), href: url,
level: state.level level: state.level
}); });
state.push({ state.push({
type: 'text', type: 'text',
content: escapeHtml(linkMatch[0].slice(1, -1)), content: escapeHtml(url),
level: state.level + 1 level: state.level + 1
}); });
state.push({ type: 'link_close', level: state.level }); state.push({ type: 'link_close', level: state.level });
@ -43,14 +47,19 @@ module.exports = function autolink(state) {
emailMatch = tail.match(EMAIL_RE); emailMatch = tail.match(EMAIL_RE);
if (emailMatch) { if (emailMatch) {
url = emailMatch[0].slice(1, -1);
if (!state.parser.validateLink('mailto:' + url)) { return false; }
state.push({ state.push({
type: 'link_open', type: 'link_open',
href: 'mailto:' + emailMatch[0].slice(1, -1), href: 'mailto:' + url,
level: state.level level: state.level
}); });
state.push({ state.push({
type: 'text', type: 'text',
content: escapeHtml(emailMatch[0].slice(1, -1)), content: escapeHtml(url),
level: state.level + 1 level: state.level + 1
}); });
state.push({ type: 'link_close', level: state.level }); state.push({ type: 'link_close', level: state.level });

9
lib/rules_typographer/linkify.js

@ -14,12 +14,8 @@ var autolinker = new Autolinker({
stripPrefix: false, stripPrefix: false,
replaceFn: function (autolinker, match) { replaceFn: function (autolinker, match) {
// Only collect matched strings but don't change anything. // Only collect matched strings but don't change anything.
var url;
if (match.getType() === 'url') { if (match.getType() === 'url') {
url = match.getUrl(); links.push(match.getUrl());
if (/^(http|https|ftp|git)/.test(url)) {
links.push(url);
}
} }
return false; return false;
} }
@ -57,6 +53,9 @@ module.exports = function linkify(t, state) {
level = token.level; level = token.level;
for (ln = 0; ln < links.length; ln++) { for (ln = 0; ln < links.length; ln++) {
if (!state.parser.validateLink(links[ln])) { continue; }
pos = text.indexOf(links[ln]); pos = text.indexOf(links[ln]);
if (pos) { if (pos) {
level = level; level = level;

Loading…
Cancel
Save