From 405479642ffeec59fed70aaa37a90c94f38fc20a Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sun, 7 Jan 2024 17:45:01 +0100 Subject: [PATCH] add YOURLS API samples for extractUrl validation --- js/common.js | 4 +- js/privatebin.js | 4 +- js/test/Helper.js | 18 +++---- js/test/PasteStatus.js | 117 ++++++++++++++++++++++++++++++++++++++++- tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 6 files changed, 130 insertions(+), 17 deletions(-) diff --git a/js/common.js b/js/common.js index c14a76ca..d3953d36 100644 --- a/js/common.js +++ b/js/common.js @@ -113,8 +113,8 @@ exports.jscBase64String = function() { }; // provides a random URL schema supported by the whatwg-url library -exports.jscSchemas = function() { - return jsc.elements(schemas); +exports.jscSchemas = function(withFtp = true) { + return jsc.elements(withFtp ? schemas : schemas.slice(1)); }; // provides a random supported language string diff --git a/js/privatebin.js b/js/privatebin.js index 4e370e91..9196ca5f 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -2117,7 +2117,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { response = JSON.stringify(response); } if (typeof response === 'string' && response.length > 0) { - const shortUrlMatcher = /https?:\/\/[^\s]+/g; + const shortUrlMatcher = /https?:\/\/[^\s"<]+/g; // JSON API will have URL in quotes, XML in tags const shortUrl = (response.match(shortUrlMatcher) || []).filter(function(urlRegExMatch) { if (typeof URL.canParse === 'function') { return URL.canParse(urlRegExMatch); @@ -2129,7 +2129,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { return false; } }).sort(function(a, b) { - return a.length - b.length; + return a.length - b.length; // shortest first })[0]; if (typeof shortUrl === 'string' && shortUrl.length > 0) { // we disable the button to avoid calling shortener again diff --git a/js/test/Helper.js b/js/test/Helper.js index 434cd3e5..95ae5709 100644 --- a/js/test/Helper.js +++ b/js/test/Helper.js @@ -259,16 +259,16 @@ describe('Helper', function () { this.timeout(30000); jsc.property( 'returns the URL without query & fragment', - jsc.elements(['http', 'https']), - jsc.nearray(common.jscA2zString()), - jsc.array(common.jscA2zString()), - jsc.array(common.jscQueryString()), - 'string', - function (schema, address, path, query, fragment) { + common.jscSchemas(false), + common.jscUrl(), + function (schema, url) { + url.schema = schema; + const fullUrl = common.urlToString(url); + delete(url.query); + delete(url.fragment); $.PrivateBin.Helper.reset(); - var path = path.join('') + (path.length > 0 ? '/' : ''), - expected = schema + '://' + address.join('') + '/' + path, - clean = jsdom('', {url: expected + '?' + query.join('') + '#' + fragment}), + const expected = common.urlToString(url), + clean = jsdom('', {url: fullUrl}), result = $.PrivateBin.Helper.baseUri(); clean(); return expected === result; diff --git a/js/test/PasteStatus.js b/js/test/PasteStatus.js index 8b19c75b..2e8e6dc7 100644 --- a/js/test/PasteStatus.js +++ b/js/test/PasteStatus.js @@ -1,6 +1,23 @@ 'use strict'; var common = require('../common'); +function urlStrings(schema, longUrl, shortUrl) { + longUrl.schema = schema; + shortUrl.schema = schema; + let longUrlString = common.urlToString(longUrl), + shortUrlString = common.urlToString(shortUrl); + // ensure the two random URLs actually are sorted as expected + if (longUrlString.length <= shortUrlString.length) { + if (longUrlString.length === shortUrlString.length) { + longUrl.address.unshift('a'); + longUrlString = common.urlToString(longUrl); + } else { + [longUrlString, shortUrlString] = [shortUrlString, longUrlString]; + } + } + return [longUrlString, shortUrlString]; +} + describe('PasteStatus', function () { describe('createPasteNotification', function () { this.timeout(30000); @@ -28,8 +45,8 @@ describe('PasteStatus', function () { this.timeout(30000); jsc.property( - 'extracts and updates URLs found in given response', - jsc.elements(['http','https']), + 'extracts and updates IDN URLs found in given response', + common.jscSchemas(false), 'nestring', common.jscUrl(), function (schema, domain, url) { @@ -58,6 +75,102 @@ describe('PasteStatus', function () { ); } ); + + // YOURLS API samples from: https://yourls.org/readme.html#API;apireturn + jsc.property( + 'extracts and updates URLs found in YOURLS API JSON response', + common.jscSchemas(false), + common.jscUrl(), + common.jscUrl(false), + function (schema, longUrl, shortUrl) { + const [longUrlString, shortUrlString] = urlStrings(schema, longUrl, shortUrl), + yourlsResponse = { + url: { + keyword: longUrl.address.join(''), + url: longUrlString, + title: "example title", + date: "2014-10-24 16:01:39", + ip: "127.0.0.1" + }, + status: "success", + message: longUrlString + " added to database", + title: "example title", + shorturl: shortUrlString, + statusCode: 200 + }, + clean = jsdom(); + + $('body').html('
'); + $.PrivateBin.PasteStatus.init(); + $.PrivateBin.PasteStatus.createPasteNotification('', ''); + $.PrivateBin.PasteStatus.extractUrl(JSON.stringify(yourlsResponse, undefined, 4)); + + const result = $('#pasteurl')[0].href; + clean(); + + return result === shortUrlString; + } + ); + jsc.property( + 'extracts and updates URLs found in YOURLS API XML response', + common.jscSchemas(false), + common.jscUrl(), + common.jscUrl(false), + function (schema, longUrl, shortUrl) { + const [longUrlString, shortUrlString] = urlStrings(schema, longUrl, shortUrl), + yourlsResponse = '\n' + + ' ' + longUrl.address.join('') + '\n' + + ' ' + shortUrlString + '\n' + + ' ' + longUrlString + '\n' + + ' success\n' + + ' 200\n' + + '', + clean = jsdom(); + + $('body').html('
'); + $.PrivateBin.PasteStatus.init(); + $.PrivateBin.PasteStatus.createPasteNotification('', ''); + $.PrivateBin.PasteStatus.extractUrl(yourlsResponse); + + const result = $('#pasteurl')[0].href; + clean(); + + return result === shortUrlString; + } + ); + jsc.property( + 'extracts and updates URLs found in YOURLS proxy HTML response', + common.jscSchemas(false), + common.jscUrl(), + common.jscUrl(false), + function (schema, longUrl, shortUrl) { + const [longUrlString, shortUrlString] = urlStrings(schema, longUrl, shortUrl), + yourlsResponse = '\n' + + '\n' + + '\t\n' + + '\t\t\n' + + '\t\t\n' + + '\t\t\n' + + '\t\t\n' + + '\t\tPrivateBin\n' + + '\t\n' + + '\t\n' + + '\t\t

Your paste is ' + shortUrlString + ' (Hit [Ctrl]+[c] to copy)

\n' + + '\t\n' + + '', + clean = jsdom(); + + $('body').html('
'); + $.PrivateBin.PasteStatus.init(); + $.PrivateBin.PasteStatus.createPasteNotification('', ''); + $.PrivateBin.PasteStatus.extractUrl(yourlsResponse); + + const result = $('#pasteurl')[0].href; + clean(); + + return result === shortUrlString; + } + ); }); describe('showRemainingTime', function () { diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index d1a54fcb..0cf27f5f 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -73,7 +73,7 @@ endif; ?> - + diff --git a/tpl/page.php b/tpl/page.php index b0b9cc1a..7e62f37e 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -51,7 +51,7 @@ endif; ?> - +