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

fix url filter, IDN URL unit test

El RIDO 2 лет назад
Родитель
Сommit
a80bd4e4ea
6 измененных файлов с 87 добавлено и 28 удалено
  1. 1 1
      js/common.js
  2. 2 2
      js/package-lock.json
  3. 37 23
      js/privatebin.js
  4. 45 0
      js/test/PasteStatus.js
  5. 1 1
      tpl/bootstrap.php
  6. 1 1
      tpl/page.php

+ 1 - 1
js/common.js

@@ -37,7 +37,7 @@ var a2zString    = ['a','b','c','d','e','f','g','h','i','j','k','l','m',
         })
     ),
     schemas = ['ftp','http','https'],
-    supportedLanguages = ['de', 'es', 'fr', 'it', 'no', 'pl', 'pt', 'oc', 'ru', 'sl', 'zh'],
+    supportedLanguages = ['ar', 'bg', 'ca', 'co', 'cs', 'de', 'el', 'es', 'et', 'fi', 'fr', 'he', 'hu', 'id', 'it', 'ja', 'jbo', 'lt', 'no', 'nl', 'pl', 'pt', 'oc', 'ru', 'sk', 'sl', 'th', 'tr', 'uk', 'zh'],
     mimeTypes = ['image/png', 'application/octet-stream'],
     formats = ['plaintext', 'markdown', 'syntaxhighlighting'],
     mimeFile = fs.createReadStream('/etc/mime.types'),

+ 2 - 2
js/package-lock.json

@@ -1,12 +1,12 @@
 {
   "name": "privatebin",
-  "version": "1.5.2",
+  "version": "1.6.2",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "privatebin",
-      "version": "1.5.2",
+      "version": "1.6.2",
       "license": "zlib-acknowledgement",
       "devDependencies": {
         "@peculiar/webcrypto": "^1.1.1",

+ 37 - 23
js/privatebin.js

@@ -2035,29 +2035,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
                 xhrFields: {
                     withCredentials: false
                 },
-                success: function(response) {
-                    let responseString = response;
-                    if (typeof responseString === 'object') {
-                        responseString = JSON.stringify(responseString);
-                    }
-                    if (typeof responseString === 'string' && responseString.length > 0) {
-                        const shortUrlMatcher = /https?:\/\/[^\s]+/g;
-                        const shortUrl = (responseString.match(shortUrlMatcher) || []).filter(URL.canParse).sort(function(a, b) {
-                            return a.length - b.length;
-                        })[0];
-                        if (typeof shortUrl === 'string' && shortUrl.length > 0) {
-                            // we disable the button to avoid calling shortener again
-                            $shortenButton.addClass('buttondisabled');
-                            // update link
-                            $pasteUrl.text(shortUrl);
-                            $pasteUrl.prop('href', shortUrl);
-                            // we pre-select the link so that the user only has to [Ctrl]+[c] the link
-                            Helper.selectText($pasteUrl[0]);
-                            return;
-                        }
-                    }
-                    Alert.showError('Cannot parse response from URL shortener.');
-                }
+                success: PasteStatus.extractUrl
             })
             .fail(function(data, textStatus, errorThrown) {
                 console.error(textStatus, errorThrown);
@@ -2123,6 +2101,42 @@ jQuery.PrivateBin = (function($, RawDeflate) {
             Helper.selectText($pasteUrl[0]);
         };
 
+        /**
+         * extracts URLs from given string
+         *
+         * if at least one is found, it disables the shortener button and
+         * replaces the paste URL
+         *
+         * @name   PasteStatus.extractUrl
+         * @function
+         * @param  {string} response
+         */
+        me.extractUrl = function(response)
+        {
+            if (typeof response === 'object') {
+                response = JSON.stringify(response);
+            }
+            if (typeof response === 'string' && response.length > 0) {
+                const shortUrlMatcher = /https?:\/\/[^\s]+/g;
+                const shortUrl = (response.match(shortUrlMatcher) || []).filter(function(a) {
+                    return URL.canParse(a);
+                }).sort(function(a, b) {
+                    return a.length - b.length;
+                })[0];
+                if (typeof shortUrl === 'string' && shortUrl.length > 0) {
+                    // we disable the button to avoid calling shortener again
+                    $shortenButton.addClass('buttondisabled');
+                    // update link
+                    $pasteUrl.text(shortUrl);
+                    $pasteUrl.prop('href', shortUrl);
+                    // we pre-select the link so that the user only has to [Ctrl]+[c] the link
+                    Helper.selectText($pasteUrl[0]);
+                    return;
+                }
+            }
+            Alert.showError('Cannot parse response from URL shortener.');
+        };
+
         /**
          * shows the remaining time
          *

+ 45 - 0
js/test/PasteStatus.js

@@ -34,6 +34,51 @@ describe('PasteStatus', function () {
         );
     });
 
+    describe('extractUrl', function () {
+        this.timeout(30000);
+
+        jsc.property(
+            'extracts and updates URLs found in given response',
+            jsc.elements(['http','https']),
+            'nestring',
+            jsc.nearray(common.jscA2zString()),
+            jsc.array(common.jscQueryString()),
+            jsc.array(common.jscAlnumString()),
+            'string',
+            function (schema, domain, tld, query, shortid, fragment) {
+                domain = domain.replace(/\P{Letter}|[\u00AA-\u00BA]/gu,'').toLowerCase();
+                if (domain.length === 0) {
+                    domain = 'a';
+                }
+                const expected = '.' + tld.join('') + '/' + (query.length > 0 ?
+                    ('?' + encodeURI(query.join('').replace(/^&+|&+$/gm,'')) +
+                    shortid.join('')) : '') + (fragment.length > 0 ?
+                    ('#' + encodeURI(fragment)) : ''),
+                    clean = jsdom();
+
+                // not available in node before v19.9.0, v18.17.0
+                if (typeof URL.canParse !== 'function') {
+                    URL.canParse = function(a) {
+                        return true;
+                    }
+                }
+
+                $('body').html('<div><div id="pastelink"></div></div>');
+                $.PrivateBin.PasteStatus.init();
+                $.PrivateBin.PasteStatus.createPasteNotification('', '');
+                $.PrivateBin.PasteStatus.extractUrl(schema + '://' + domain + expected);
+
+                const result = $('#pasteurl')[0].href;
+                clean();
+
+                return result.endsWith(expected) && (
+                    result.startsWith(schema + '://xn--') ||
+                    result.startsWith(schema + '://' + domain)
+                );
+            }
+        );
+    });
+
     describe('showRemainingTime', function () {
         this.timeout(30000);
 

+ 1 - 1
tpl/bootstrap.php

@@ -73,7 +73,7 @@ endif;
 ?>
 		<script type="text/javascript" data-cfasync="false" src="js/purify-3.0.6.js" integrity="sha512-N3y6/HOk3pbsw3lFh4O8CKKEVwu1B2CF8kinhjURf8Yqa5OfSUt+/arozxFW+TUPOPw3TsDCRT/0u7BGRTEVUw==" crossorigin="anonymous"></script>
 		<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
-		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-FF+BJPX+fC0o672f5HNwc3Q+v6dcAeO+jT4/NgnGpgG2bjesssaqkYVSdFX3kxLe4mm1A3DZB4w75OioqBIncw==" crossorigin="anonymous"></script>
+		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-ga7H5TIOKUp1pst8C7AxGjnnuTe96WETRcjkLVY3jRjYYIlyGo+dT/sf4/6gjhMUc6tT8WHLtI5xBijTSCe6+w==" crossorigin="anonymous"></script>
 		<!-- icon -->
 		<link rel="apple-touch-icon" href="<?php echo I18n::encode($BASEPATH); ?>img/apple-touch-icon.png" sizes="180x180" />
 		<link rel="icon" type="image/png" href="img/favicon-32x32.png" sizes="32x32" />

+ 1 - 1
tpl/page.php

@@ -51,7 +51,7 @@ endif;
 ?>
 		<script type="text/javascript" data-cfasync="false" src="js/purify-3.0.6.js" integrity="sha512-N3y6/HOk3pbsw3lFh4O8CKKEVwu1B2CF8kinhjURf8Yqa5OfSUt+/arozxFW+TUPOPw3TsDCRT/0u7BGRTEVUw==" crossorigin="anonymous"></script>
 		<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
-		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-FF+BJPX+fC0o672f5HNwc3Q+v6dcAeO+jT4/NgnGpgG2bjesssaqkYVSdFX3kxLe4mm1A3DZB4w75OioqBIncw==" crossorigin="anonymous"></script>
+		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-ga7H5TIOKUp1pst8C7AxGjnnuTe96WETRcjkLVY3jRjYYIlyGo+dT/sf4/6gjhMUc6tT8WHLtI5xBijTSCe6+w==" crossorigin="anonymous"></script>
 		<!-- icon -->
 		<link rel="apple-touch-icon" href="img/apple-touch-icon.png?<?php echo rawurlencode($VERSION); ?>" sizes="180x180" />
 		<link rel="icon" type="image/png" href="img/favicon-32x32.png?<?php echo rawurlencode($VERSION); ?>" sizes="32x32" />