Skip to content

Commit

Permalink
fix: external link ignore mailto: & javascript: (hexojs#3812)
Browse files Browse the repository at this point in the history
* fix: external link ignore mailto: & javascript:
Close hexojs#3796

* refactor: use startsWith instead of regex

* refactor(external_link): use whatwg url

* fix(external_link): handle whatwg url api
Apply code suggestions from code review by @curbengh
  • Loading branch information
SukkaW authored Oct 28, 2019
1 parent 71d91af commit 91a4784
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 21 deletions.
19 changes: 14 additions & 5 deletions lib/plugins/filter/after_post_render/external_link.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
'use strict';

const { parse } = require('url');
const { URL } = require('url');

const urlObj = (str) => {
try {
return new URL(str);
} catch (err) {
return str;
}
};

const isExternal = (url, config) => {
const exclude = Array.isArray(config.external_link.exclude) ? config.external_link.exclude :
[config.external_link.exclude];
const data = parse(url);
const data = urlObj(url);
const host = data.hostname;
const sitehost = parse(config.url).hostname || config.url;
const sitehost = typeof urlObj(config.url) === 'object' ? urlObj(config.url).hostname : config.url;

if (!data.protocol || !sitehost) return false;
if (!sitehost || typeof data === 'string') return false;
if (data.origin === 'null') return false;

if (exclude && exclude.length) {
for (const i of exclude) {
Expand All @@ -34,7 +43,7 @@ function externalLinkFilter(data) {
}, config.external_link);
}
if (config.external_link === false || config.external_link.enable === false ||
config.external_link.field !== 'post') return;
config.external_link.field !== 'post') return;

data.content = data.content.replace(/<a.*?(href=['"](.*?)['"]).*?>/gi, (str, hrefStr, href) => {
if (/target=/gi.test(str) || !isExternal(href, config)) return str;
Expand Down
17 changes: 13 additions & 4 deletions lib/plugins/filter/after_render/external_link.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
'use strict';

const { parse } = require('url');
const { URL } = require('url');

const urlObj = (str) => {
try {
return new URL(str);
} catch (err) {
return str;
}
};

/**
* Check whether the link is external
Expand All @@ -11,11 +19,12 @@ const { parse } = require('url');
const isExternal = (url, config) => {
const exclude = Array.isArray(config.external_link.exclude) ? config.external_link.exclude :
[config.external_link.exclude];
const data = parse(url);
const data = urlObj(url);
const host = data.hostname;
const sitehost = parse(config.url).hostname || config.url;
const sitehost = typeof urlObj(config.url) === 'object' ? urlObj(config.url).hostname : config.url;

if (!data.protocol || !sitehost) return false;
if (!sitehost || typeof data === 'string') return false;
if (data.origin === 'null') return false;

if (exclude && exclude.length) {
for (const i of exclude) {
Expand Down
32 changes: 20 additions & 12 deletions test/scripts/filters/external_link.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,23 +208,27 @@ describe('External link - post', () => {
'# External link test',
'1. External link',
'<a href="https://hexo.io/">Hexo</a>',
'2. External link with "rel" Attribute',
'2. Link with hash (#), mailto: , javascript: shouldn\'t be processed',
'<a href="#top">Hexo</a>',
'<a href="mailto:[email protected]">Hexo</a>',
'<a href="javascript:alert(\'Hexo is awesome!\');">Hexo</a>',
'3. External link with "rel" Attribute',
'<a rel="external" href="https://hexo.io/">Hexo</a>',
'<a href="https://hexo.io/" rel="external">Hexo</a>',
'<a rel="noopenner" href="https://hexo.io/">Hexo</a>',
'<a href="https://hexo.io/" rel="noopenner">Hexo</a>',
'<a rel="external noopenner" href="https://hexo.io/">Hexo</a>',
'<a href="https://hexo.io/" rel="external noopenner">Hexo</a>',
'3. External link with Other Attributes',
'4. External link with Other Attributes',
'<a class="img" href="https://hexo.io/">Hexo</a>',
'<a href="https://hexo.io/" class="img">Hexo</a>',
'4. Internal link',
'5. Internal link',
'<a href="/archives/foo.html">Link</a>',
'5. Ignore links have "target" attribute',
'6. Ignore links have "target" attribute',
'<a href="https://hexo.io/" target="_blank">Hexo</a>',
'6. Ignore links don\'t have "href" attribute',
'7. Ignore links don\'t have "href" attribute',
'<a>Anchor</a>',
'7. Ignore links whose hostname is same as config',
'8. Ignore links whose hostname is same as config',
'<a href="https://example.com">Example Domain</a>'
].join('\n');

Expand All @@ -235,23 +239,27 @@ describe('External link - post', () => {
'# External link test',
'1. External link',
'<a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>',
'2. External link with "rel" Attribute',
'2. Link with hash (#), mailto: , javascript: shouldn\'t be processed',
'<a href="#top">Hexo</a>',
'<a href="mailto:[email protected]">Hexo</a>',
'<a href="javascript:alert(\'Hexo is awesome!\');">Hexo</a>',
'3. External link with "rel" Attribute',
'<a rel="external noopener" href="https://hexo.io/" target="_blank">Hexo</a>',
'<a href="https://hexo.io/" target="_blank" rel="external noopener">Hexo</a>',
'<a rel="noopenner" href="https://hexo.io/" target="_blank">Hexo</a>',
'<a href="https://hexo.io/" target="_blank" rel="noopenner">Hexo</a>',
'<a rel="external noopenner" href="https://hexo.io/" target="_blank">Hexo</a>',
'<a href="https://hexo.io/" target="_blank" rel="external noopenner">Hexo</a>',
'3. External link with Other Attributes',
'4. External link with Other Attributes',
'<a class="img" href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>',
'<a href="https://hexo.io/" target="_blank" rel="noopener" class="img">Hexo</a>',
'4. Internal link',
'5. Internal link',
'<a href="/archives/foo.html">Link</a>',
'5. Ignore links have "target" attribute',
'6. Ignore links have "target" attribute',
'<a href="https://hexo.io/" target="_blank">Hexo</a>',
'6. Ignore links don\'t have "href" attribute',
'7. Ignore links don\'t have "href" attribute',
'<a>Anchor</a>',
'7. Ignore links whose hostname is same as config',
'8. Ignore links whose hostname is same as config',
'<a href="https://example.com">Example Domain</a>'
].join('\n'));
});
Expand Down

0 comments on commit 91a4784

Please sign in to comment.