Просмотр исходного кода

Merge branch 'master' into feat/tag-list-page-for-master-merge

yusuketk 7 лет назад
Родитель
Сommit
bd97f5d225

+ 5 - 0
CHANGES.md

@@ -2,8 +2,13 @@
 
 
 ## 3.4.5-RC
 ## 3.4.5-RC
 
 
+* Improvement: Pass autolink through the XSS filter according to CommonMark Spec
+* Fix: Update ElasticSearch index when deleting/duplicating pages
+* Fix: Xss filter breaks PlantUML arrows
+* Support: Support growi-plugin-lsx@2.2.0
 * Support: Upgrade libs
 * Support: Upgrade libs
     * growi-commons
     * growi-commons
+    * xss
 
 
 ## 3.4.4
 ## 3.4.4
 
 

+ 2 - 2
package.json

@@ -88,7 +88,7 @@
     "express-webpack-assets": "^0.1.0",
     "express-webpack-assets": "^0.1.0",
     "googleapis": "^39.1.0",
     "googleapis": "^39.1.0",
     "graceful-fs": "^4.1.11",
     "graceful-fs": "^4.1.11",
-    "growi-commons": "^4.0.0",
+    "growi-commons": "^4.0.1",
     "helmet": "^3.13.0",
     "helmet": "^3.13.0",
     "i18next": "^15.0.9",
     "i18next": "^15.0.9",
     "i18next-express-middleware": "^1.4.1",
     "i18next-express-middleware": "^1.4.1",
@@ -124,7 +124,7 @@
     "swig-templates": "^2.0.2",
     "swig-templates": "^2.0.2",
     "uglifycss": "^0.0.29",
     "uglifycss": "^0.0.29",
     "url-join": "^4.0.0",
     "url-join": "^4.0.0",
-    "xss": "^1.0.3"
+    "xss": "^1.0.6"
   },
   },
   "devDependencies": {
   "devDependencies": {
     "@alienfast/i18next-loader": "^1.0.16",
     "@alienfast/i18next-loader": "^1.0.16",

+ 20 - 4
src/client/styles/scss/_search.scss

@@ -19,6 +19,7 @@
 
 
 .search-typeahead {
 .search-typeahead {
   position: relative;
   position: relative;
+
   .search-clear {
   .search-clear {
     position: absolute;
     position: absolute;
     top: 4px;
     top: 4px;
@@ -29,6 +30,7 @@
     padding: 0;
     padding: 0;
     color: #999;
     color: #999;
   }
   }
+
   .rbt-menu {
   .rbt-menu {
     margin-top: 3px;
     margin-top: 3px;
 
 
@@ -38,10 +40,12 @@
         padding: 0 4px;
         padding: 0 4px;
         color: inherit;
         color: inherit;
       }
       }
+
       .page-list-meta {
       .page-list-meta {
         font-size: 0.9em;
         font-size: 0.9em;
         color: #999;
         color: #999;
-        > span {
+
+        >span {
           margin-right: 0.3rem;
           margin-right: 0.3rem;
         }
         }
       }
       }
@@ -66,6 +70,7 @@
     border-top-left-radius: 40px;
     border-top-left-radius: 40px;
     border-bottom-left-radius: 40px;
     border-bottom-left-radius: 40px;
   }
   }
+
   // using react-bootstrap-typeahead
   // using react-bootstrap-typeahead
   // see: https://github.com/ericgio/react-bootstrap-typeahead
   // see: https://github.com/ericgio/react-bootstrap-typeahead
   .rbt-input.form-control {
   .rbt-input.form-control {
@@ -78,13 +83,16 @@
       margin-left: 8px;
       margin-left: 8px;
     }
     }
   }
   }
+
   .btn-group-submit-search {
   .btn-group-submit-search {
     position: absolute;
     position: absolute;
     top: 0;
     top: 0;
     right: 0;
     right: 0;
+
     .btn {
     .btn {
       padding: 4px 10px;
       padding: 4px 10px;
     }
     }
+
     z-index: 3;
     z-index: 3;
   }
   }
 }
 }
@@ -97,6 +105,7 @@
   .rbt-input.form-control {
   .rbt-input.form-control {
     width: 200px;
     width: 200px;
     transition: 0.3s ease-out;
     transition: 0.3s ease-out;
+
     // focus
     // focus
     &.focus {
     &.focus {
       width: 300px;
       width: 300px;
@@ -105,12 +114,14 @@
 }
 }
 
 
 .search-sidebar {
 .search-sidebar {
+
   .search-form,
   .search-form,
   .form-group,
   .form-group,
   .rbt-input.form-control,
   .rbt-input.form-control,
   .input-group {
   .input-group {
     width: 100%;
     width: 100%;
   }
   }
+
   .btn-group-submit-search {
   .btn-group-submit-search {
     right: 30px;
     right: 30px;
   }
   }
@@ -135,6 +146,7 @@
   .search-result-list {
   .search-result-list {
     nav {
     nav {
       padding-right: 0;
       padding-right: 0;
+
       &.affix {
       &.affix {
         top: 58px;
         top: 58px;
         width: 33%;
         width: 33%;
@@ -143,9 +155,11 @@
         padding-bottom: 50px;
         padding-bottom: 50px;
         overflow-y: scroll;
         overflow-y: scroll;
       }
       }
+
       .nav {
       .nav {
-        > li {
+        >li {
           padding: 2px 8px;
           padding: 2px 8px;
+
           &.active {
           &.active {
             padding-right: 5px;
             padding-right: 5px;
             border-right: solid 3px transparent;
             border-right: solid 3px transparent;
@@ -173,11 +187,12 @@
       // adjust for anchor links by the height of fixed .search-page-input
       // adjust for anchor links by the height of fixed .search-page-input
       margin-top: -48px;
       margin-top: -48px;
 
 
-      > h2 {
+      >h2 {
         font-size: 20px;
         font-size: 20px;
         line-height: 1em;
         line-height: 1em;
       }
       }
-      &:first-child > h2 {
+
+      &:first-child>h2 {
         margin-top: 0;
         margin-top: 0;
       }
       }
 
 
@@ -196,6 +211,7 @@
   top: 0;
   top: 0;
   z-index: 99;
   z-index: 99;
   padding: 10px 0;
   padding: 10px 0;
+
   .input-group-btn .btn {
   .input-group-btn .btn {
     height: 34px;
     height: 34px;
     padding: 0px 10px;
     padding: 0px 10px;

+ 42 - 0
src/lib/service/xss/commonmark-spec.js

@@ -0,0 +1,42 @@
+/**
+ * Valid schemes
+ * @see https://spec.commonmark.org/0.16/#autolinks
+ */
+const schemesForAutolink = [
+  'coap', 'doi', 'javascript', 'aaa', 'aaas', 'about', 'acap', 'cap', 'cid', 'crid', 'data', 'dav', 'dict', 'dns',
+  'file', 'ftp', 'geo', 'go', 'gopher', 'h323', 'http', 'https', 'iax', 'icap', 'im', 'imap', 'info', 'ipp', 'iris',
+  'iris.beep', 'iris.xpc', 'iris.xpcs', 'iris.lwz', 'ldap', 'mailto', 'mid', 'msrp', 'msrps', 'mtqp', 'mupdate',
+  'news', 'nfs', 'ni', 'nih', 'nntp', 'opaquelocktoken', 'pop', 'pres', 'rtsp', 'service', 'session', 'shttp',
+  'sieve', 'sip', 'sips', 'sms', 'snmp,soap.beep', 'soap.beeps', 'tag', 'tel', 'telnet', 'tftp', 'thismessage',
+  'tn3270', 'tip', 'tv', 'urn', 'vemmi', 'ws', 'wss', 'xcon', 'xcon-userid', 'xmlrpc.beep', 'xmlrpc.beeps', 'xmpp',
+  'z39.50r', 'z39.50s', 'adiumxtra', 'afp', 'afs', 'aim', 'apt,attachment', 'aw', 'beshare', 'bitcoin', 'bolo',
+  'callto', 'chrome,chrome-extension', 'com-eventbrite-attendee', 'content', 'cvs,dlna-playsingle', 'dlna-playcontainer',
+  'dtn', 'dvb', 'ed2k', 'facetime', 'feed', 'finger', 'fish', 'gg', 'git', 'gizmoproject', 'gtalk', 'hcp', 'icon',
+  'ipn', 'irc', 'irc6', 'ircs', 'itms', 'jar', 'jms', 'keyparc', 'lastfm', 'ldaps', 'magnet', 'maps', 'market,message',
+  'mms', 'ms-help', 'msnim', 'mumble', 'mvn', 'notes', 'oid', 'palm', 'paparazzi', 'platform', 'proxy', 'psyc',
+  'query', 'res', 'resource', 'rmi', 'rsync', 'rtmp', 'secondlife', 'sftp', 'sgn', 'skype', 'smb', 'soldat', 'spotify',
+  'ssh', 'steam', 'svn', 'teamspeak', 'things', 'udp', 'unreal', 'ut2004', 'ventrilo', 'view-source', 'webcal',
+  'wtai', 'wyciwyg', 'xfire', 'xri', 'ymsgr',
+];
+const schemesCondition = schemesForAutolink.join('|');
+
+/**
+ * RegExp for URI
+ * @type {RegExp}
+ * @see https://spec.commonmark.org/0.16/#autolinks
+ */
+const uriAutolinkRegexp = new RegExp(`^(${schemesCondition}):\\/\\/.+$`);
+
+/**
+ * RegExp for email
+ * @type {RegExp}
+ * @see https://spec.commonmark.org/0.16/#autolinks
+ */
+// eslint-disable-next-line max-len
+const emailAutolinkRegexp = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
+
+
+module.exports = {
+  uriAutolinkRegexp,
+  emailAutolinkRegexp,
+};

+ 9 - 1
src/lib/service/xss/index.js

@@ -1,7 +1,9 @@
+const xss = require('xss');
+const commonmarkSpec = require('./commonmark-spec');
+
 class Xss {
 class Xss {
 
 
   constructor(xssOption) {
   constructor(xssOption) {
-    const xss = require('xss');
 
 
     xssOption = xssOption || {}; // eslint-disable-line no-param-reassign
     xssOption = xssOption || {}; // eslint-disable-line no-param-reassign
 
 
@@ -17,6 +19,12 @@ class Xss {
       css: false,
       css: false,
       whiteList: whiteListContent,
       whiteList: whiteListContent,
       escapeHtml: (html) => { return html }, // resolve https://github.com/weseek/growi/issues/221
       escapeHtml: (html) => { return html }, // resolve https://github.com/weseek/growi/issues/221
+      onTag: (tag, html, options) => {
+        // pass autolink
+        if (tag.match(commonmarkSpec.uriAutolinkRegexp) || tag.match(commonmarkSpec.emailAutolinkRegexp)) {
+          return html;
+        }
+      },
     };
     };
 
 
     tagWhiteList.forEach((tag) => {
     tagWhiteList.forEach((tag) => {

+ 1 - 1
src/lib/service/xss/recommendedXssWhiteList.js → src/lib/service/xss/recommended-whitelist.js

@@ -5,7 +5,7 @@
  */
  */
 
 
 const tags = [
 const tags = [
-  'a', 'b', 'blockquote', 'blockquote', 'code', 'del', 'dd', 'dl', 'dt', 'em',
+  '-', 'a', 'b', 'blockquote', 'blockquote', 'code', 'del', 'dd', 'dl', 'dt', 'em',
   'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'i', 'img', 'kbd', 'li', 'ol', 'p', 'pre',
   'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'i', 'img', 'kbd', 'li', 'ol', 'p', 'pre',
   's', 'sup', 'sub', 'strong', 'strike', 'ul', 'br', 'hr', 'span', 'div', 'iframe',
   's', 'sup', 'sub', 'strong', 'strike', 'ul', 'br', 'hr', 'span', 'div', 'iframe',
   'table', 'thead', 'tbody', 'tfoot', 'th', 'td', 'tr', 'colgroup', 'col',
   'table', 'thead', 'tbody', 'tfoot', 'th', 'td', 'tr', 'colgroup', 'col',

+ 3 - 3
src/lib/service/xss/xssOption.js

@@ -1,12 +1,12 @@
 class XssOption {
 class XssOption {
 
 
   constructor(config) {
   constructor(config) {
-    const recommendedXssWhiteList = require('./recommendedXssWhiteList');
+    const recommendedWhitelist = require('./recommended-whitelist');
     const initializedConfig = (config != null) ? config : {};
     const initializedConfig = (config != null) ? config : {};
 
 
     this.isEnabledXssPrevention = initializedConfig.isEnabledXssPrevention || true;
     this.isEnabledXssPrevention = initializedConfig.isEnabledXssPrevention || true;
-    this.tagWhiteList = initializedConfig.tagWhiteList || recommendedXssWhiteList.tags;
-    this.attrWhiteList = initializedConfig.attrWhiteList || recommendedXssWhiteList.attrs;
+    this.tagWhiteList = initializedConfig.tagWhiteList || recommendedWhitelist.tags;
+    this.attrWhiteList = initializedConfig.attrWhiteList || recommendedWhitelist.attrs;
   }
   }
 
 
 }
 }

+ 3 - 3
src/server/models/config.js

@@ -7,7 +7,7 @@ module.exports = function(crowi) {
   const mongoose = require('mongoose');
   const mongoose = require('mongoose');
   const debug = require('debug')('growi:models:config');
   const debug = require('debug')('growi:models:config');
   const uglifycss = require('uglifycss');
   const uglifycss = require('uglifycss');
-  const recommendedXssWhiteList = require('@commons/service/xss/recommendedXssWhiteList');
+  const recommendedWhitelist = require('@commons/service/xss/recommended-whitelist');
 
 
   const SECURITY_RESTRICT_GUEST_MODE_DENY = 'Deny';
   const SECURITY_RESTRICT_GUEST_MODE_DENY = 'Deny';
   const SECURITY_RESTRICT_GUEST_MODE_READONLY = 'Readonly';
   const SECURITY_RESTRICT_GUEST_MODE_READONLY = 'Readonly';
@@ -430,7 +430,7 @@ module.exports = function(crowi) {
           return [];
           return [];
 
 
         case 2: // recommended
         case 2: // recommended
-          return recommendedXssWhiteList.tags;
+          return recommendedWhitelist.tags;
 
 
         case 3: // custom white list
         case 3: // custom white list
           return config.markdown[key];
           return config.markdown[key];
@@ -453,7 +453,7 @@ module.exports = function(crowi) {
           return [];
           return [];
 
 
         case 2: // recommended
         case 2: // recommended
-          return recommendedXssWhiteList.attrs;
+          return recommendedWhitelist.attrs;
 
 
         case 3: // custom white list
         case 3: // custom white list
           return config.markdown[key];
           return config.markdown[key];

+ 2 - 2
src/server/routes/admin.js

@@ -14,7 +14,7 @@ module.exports = function(crowi, app) {
   const GlobalNotificationMailSetting = models.GlobalNotificationMailSetting;
   const GlobalNotificationMailSetting = models.GlobalNotificationMailSetting;
   const GlobalNotificationSlackSetting = models.GlobalNotificationSlackSetting; // eslint-disable-line no-unused-vars
   const GlobalNotificationSlackSetting = models.GlobalNotificationSlackSetting; // eslint-disable-line no-unused-vars
 
 
-  const recommendedXssWhiteList = require('@commons/service/xss/recommendedXssWhiteList');
+  const recommendedWhitelist = require('@commons/service/xss/recommended-whitelist');
   const PluginUtils = require('../plugins/plugin-utils');
   const PluginUtils = require('../plugins/plugin-utils');
   const ApiResponse = require('../util/apiResponse');
   const ApiResponse = require('../util/apiResponse');
   const importer = require('../util/importer')(crowi);
   const importer = require('../util/importer')(crowi);
@@ -117,7 +117,7 @@ module.exports = function(crowi, app) {
 
 
     return res.render('admin/markdown', {
     return res.render('admin/markdown', {
       markdownSetting,
       markdownSetting,
-      recommendedXssWhiteList,
+      recommendedWhitelist,
     });
     });
   };
   };
 
 

+ 2 - 2
src/server/views/admin/markdown.html

@@ -193,11 +193,11 @@
               <p class="font-weight-bold">{{ t('markdown_setting.Recommended setting') }}</p>
               <p class="font-weight-bold">{{ t('markdown_setting.Recommended setting') }}</p>
               <div class="m-t-15">
               <div class="m-t-15">
                 {{ t('markdown_setting.Tag names') }}
                 {{ t('markdown_setting.Tag names') }}
-                <textarea class="form-control xss-list" name="recommendedTags" rows="6" cols="40" readonly>{{ recommendedXssWhiteList.tags }}</textarea>
+                <textarea class="form-control xss-list" name="recommendedTags" rows="6" cols="40" readonly>{{ recommendedWhitelist.tags }}</textarea>
               </div>
               </div>
               <div class="m-t-15">
               <div class="m-t-15">
                 {{ t('markdown_setting.Tag attributes') }}
                 {{ t('markdown_setting.Tag attributes') }}
-                <textarea class="form-control xss-list" name="recommendedAttrs" rows="6" cols="40" readonly>{{ recommendedXssWhiteList.attrs }}</textarea>
+                <textarea class="form-control xss-list" name="recommendedAttrs" rows="6" cols="40" readonly>{{ recommendedWhitelist.attrs }}</textarea>
               </div>
               </div>
             </label>
             </label>
           </div>
           </div>

+ 8 - 7
yarn.lock

@@ -4826,10 +4826,10 @@ graceful-fs@^4.1.15:
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
   integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
   integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
 
 
-growi-commons@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/growi-commons/-/growi-commons-4.0.0.tgz#f0c0b0f2bac218111555869d7d405e235fb053c6"
-  integrity sha512-5y0pX8efYW8Abov+9MnLypFWIXPSNb4C81VsRbDWAEIUOiFjEn8Tp7PBzxtT51pk9WMenljFMo7rGOxuDgkDzw==
+growi-commons@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/growi-commons/-/growi-commons-4.0.1.tgz#e0e71c9c286f493e11c0703c809385bcdc6a97a9"
+  integrity sha512-haH4Av1WuQIHic4Jv2RRwDprbKecRKF/3C0wVk9ssBzWtB3V6Oghj5gksajDpYOd7tOKdvkVEqqkFfIV4JQUyQ==
 
 
 growl@1.10.5:
 growl@1.10.5:
   version "1.10.5"
   version "1.10.5"
@@ -11601,9 +11601,10 @@ xpath@0.0.27:
   version "0.0.27"
   version "0.0.27"
   resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.27.tgz#dd3421fbdcc5646ac32c48531b4d7e9d0c2cfa92"
   resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.27.tgz#dd3421fbdcc5646ac32c48531b4d7e9d0c2cfa92"
 
 
-xss@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.3.tgz#d04bd2558fd6c29c46113824d5e8b2a910054e23"
+xss@^1.0.6:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.6.tgz#eaf11e9fc476e3ae289944a1009efddd8a124b51"
+  integrity sha512-6Q9TPBeNyoTRxgZFk5Ggaepk/4vUOYdOsIUYvLehcsIZTFjaavbVnsuAkLA5lIFuug5hw8zxcB9tm01gsjph2A==
   dependencies:
   dependencies:
     commander "^2.9.0"
     commander "^2.9.0"
     cssfilter "0.0.10"
     cssfilter "0.0.10"