Commit MetaInfo

修订版eadd98560ad77723c7a8fc54f165fb45400a6fe0 (tree)
时间2018-03-23 01:43:05
作者umorigu <umorigu@gmai...>
Commiterumorigu

Log Message

BugTrack/2247 External link cushion page - Control Referer etc.

* New plugin: external_link.inc.php
* New config: $external_link_cushion_page, $external_link_cushion

You can set "internal domains", on these host, you don't need to
see cushion page.

更改概述

差异

--- a/en.lng.php
+++ b/en.lng.php
@@ -446,3 +446,11 @@ $_loginform_messages = array(
446446 'login' => 'Log in',
447447 'invalid_username_or_password' => 'The username or password you entered is incorrect'
448448 );
449+
450+///////////////////////////////////////
451+// external_link.inc.php
452+$_external_link_messages = array(
453+ 'page_title' => 'External link: %s',
454+ 'desc' => 'The selected URL is not the contents of this site.',
455+ 'wait_n_seconds' => 'It will move to the page automatically after %s seconds.',
456+);
Binary files /dev/null and b/image/external-link.png differ
--- a/ja.lng.php
+++ b/ja.lng.php
@@ -448,3 +448,11 @@ $_loginform_messages = array(
448448 'login' => 'ログイン',
449449 'invalid_username_or_password' => 'ユーザー名またはパスワードが違います'
450450 );
451+
452+///////////////////////////////////////
453+// external_link.inc.php
454+$_external_link_messages = array(
455+ 'page_title' => '外部リンク: %s',
456+ 'desc' => '選択されたURLは本サイトのコンテンツではありません。',
457+ 'wait_n_seconds' => '%s 秒後に自動的に移動します。',
458+);
--- a/lib/html.php
+++ b/lib/html.php
@@ -219,6 +219,7 @@ function _decorate_Nth_word($matches)
219219 function get_html_scripting_data()
220220 {
221221 global $ticket_link_sites, $plugin;
222+ global $external_link_cushion_page, $external_link_cushion;
222223 if (!isset($ticket_link_sites) || !is_array($ticket_link_sites)) {
223224 return '';
224225 }
@@ -261,11 +262,21 @@ EOS;
261262 $ticketlink_data = <<<EOS
262263 <input type="hidden" class="ticketlink-def" value="$h_ticket_link_sites" />
263264 EOS;
265+ // External link cushion page
266+ $external_link_cushion_data = '';
267+ if ($external_link_cushion_page) {
268+ $h_cushion = htmlsc(json_encode($external_link_cushion,
269+ JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
270+ $external_link_cushion_data = <<<EOS
271+<input type="hidden" class="external-link-cushion" value="$h_cushion" />
272+EOS;
273+ }
264274 $data = <<<EOS
265275 <div id="pukiwiki-site-properties" style="display:none;">
266276 $site_props
267277 $plugin_prop
268278 $ticketlink_data
279+$external_link_cushion_data
269280 </div>
270281 EOS;
271282 return $data;
--- a/pukiwiki.ini.php
+++ b/pukiwiki.ini.php
@@ -314,6 +314,26 @@ $ticket_link_sites = array(
314314 );
315315
316316 /////////////////////////////////////////////////
317+// Show External Link Cushion Page
318+// 0: Disabled
319+// 1: Enabled
320+$external_link_cushion_page = 0;
321+$external_link_cushion = array(
322+ // Wait N seconds before jumping to an external site
323+ 'wait_seconds' => 5,
324+ // Internal site domain list
325+ 'internal_domains' => array(
326+ 'localhost',
327+ // '*.example.com',
328+ ),
329+ // Don't show extenal link icons on these domains
330+ 'silent_external_domains' => array(
331+ 'pukiwiki.osdn.jp',
332+ 'pukiwiki.example.com',
333+ ),
334+);
335+
336+/////////////////////////////////////////////////
317337 // $whatsnew: Max number of RecentChanges
318338 $maxshow = 500;
319339
--- a/skin/main.js
+++ b/skin/main.js
@@ -370,8 +370,105 @@ window.addEventListener && window.addEventListener('DOMContentLoaded', function(
370370 }
371371 });
372372 }
373+ function convertExternalLinkToCushionPageLink() {
374+ function domainQuote(domain) {
375+ return domain.replace(/\./g, '\\.');
376+ }
377+ function domainsToRegex(domains) {
378+ var regexList = [];
379+ domains.forEach(function(domain) {
380+ if (domain.substr(0, 2) === '*.') {
381+ // Wildcard domain
382+ var apex = domain.substr(2);
383+ var r = new RegExp('((^.*\\.)|^)' + domainQuote(apex) + '$', 'i');
384+ regexList.push(r);
385+ } else {
386+ // Normal domain
387+ regexList.push(new RegExp('^' + domainQuote(domain) + '$', 'i'));
388+ }
389+ });
390+ return regexList;
391+ }
392+ function domainMatch(domain, regexList) {
393+ for (var i = 0, n = regexList.length; i < n; i++) {
394+ if (regexList[i].test(domain)) {
395+ return true;
396+ }
397+ }
398+ return false;
399+ }
400+ function removeCushionPageLinks() {
401+ var links = document.querySelectorAll('a.external-link');
402+ forEach(links, function(link) {
403+ var originalUrl = link.getAttribute('data-original-url');
404+ if (originalUrl) {
405+ link.setAttribute('href', originalUrl);
406+ }
407+ });
408+ }
409+ if (!document.querySelector || !JSON) return;
410+ if (!Array || !Array.prototype || !Array.prototype.indexOf) return;
411+ var extLinkDef = document.querySelector('#pukiwiki-site-properties .external-link-cushion');
412+ if (!extLinkDef || !extLinkDef.value) return;
413+ var extLinkInfo = JSON.parse(extLinkDef.value);
414+ if (!extLinkInfo) return;
415+ var refInternalDomains = extLinkInfo.internal_domains;
416+ var silentExternalDomains = extLinkInfo.silent_external_domains;
417+ if (!Array.isArray(refInternalDomains)) {
418+ refInternalDomains = [];
419+ }
420+ var internalDomains = refInternalDomains.slice();
421+ var location = document.location;
422+ if (location.protocol === 'file:') {
423+ removeCushionPageLinks();
424+ return;
425+ }
426+ if (location.protocol !== 'http:' && location.protocol !== 'https:') return;
427+ if (internalDomains.indexOf(location.hostname) < 0) {
428+ internalDomains.push(location.hostname);
429+ }
430+ if (!Array.isArray(silentExternalDomains)) {
431+ silentExternalDomains = [];
432+ }
433+ var propsE = document.querySelector('#pukiwiki-site-properties .site-props');
434+ if (!propsE || !propsE.value) return;
435+ var siteProps = JSON.parse(propsE.value);
436+ var sitePathname = siteProps && siteProps.base_uri_pathname;
437+ if (!sitePathname) return;
438+ var internalDomainsR = domainsToRegex(internalDomains);
439+ var silentExternalDomainsR = domainsToRegex(silentExternalDomains);
440+ var links = document.querySelectorAll('a:not(.external-link):not(.internal-link)');
441+ var classListEnabled = null;
442+ forEach(links, function(link) {
443+ if (classListEnabled === null) {
444+ classListEnabled = link.classList && link.classList.add && true;
445+ }
446+ if (!classListEnabled) return;
447+ var href = link.getAttribute('href');
448+ var m = href.match(/^https?:\/\/([0-9a-zA-Z.-]+)(:\d+)?/);
449+ if (m) {
450+ var host = m[1];
451+ if (domainMatch(host, internalDomainsR)) {
452+ link.classList.add('internal-link');
453+ } else {
454+ if (domainMatch(host, silentExternalDomainsR) ||
455+ link.innerText.replace(/\s+/g, '') === '') {
456+ // Don't show extenal link icons on these domains
457+ link.classList.add('external-link-silent');
458+ }
459+ link.classList.add('external-link');
460+ link.setAttribute('title', href);
461+ link.setAttribute('data-original-url', href);
462+ link.setAttribute('href', sitePathname + '?cmd=external_link&url=' + encodeURIComponent(href));
463+ }
464+ } else {
465+ link.classList.add('internal-link');
466+ }
467+ });
468+ }
373469 setYourName();
374470 autoTicketLink();
375471 confirmEditFormLeaving();
376472 showPagePassage();
473+ convertExternalLinkToCushionPageLink();
377474 });
--- a/skin/pukiwiki.css
+++ b/skin/pukiwiki.css
@@ -47,6 +47,11 @@ a:hover {
4747 text-decoration:underline;
4848 }
4949
50+a.external-link:not(.external-link-silent)::after {
51+ content:url(../image/external-link.png);
52+ margin:3px;
53+}
54+
5055 h1, h2 {
5156 font-family:verdana, arial, helvetica, Sans-Serif;
5257 color:inherit;
--- a/skin/tdiary.css
+++ b/skin/tdiary.css
@@ -30,6 +30,11 @@ img { border: 0 }
3030 /* --------------------- */
3131 /* PukiWiki original CSS */
3232
33+a.external-link:not(.external-link-silent)::after {
34+ content:url(../image/external-link.png);
35+ margin:3px;
36+}
37+
3338 pre {
3439 white-space:pre-wrap;
3540 word-wrap:break-word;
Show on old repository browser