From faf596aeb75605d99a12b93a1d66fad0e300301f Mon Sep 17 00:00:00 2001 From: thororm Date: Sun, 12 Feb 2017 15:35:37 +0100 Subject: [PATCH 001/178] Added preview for - Video (HTML5) - Audio (HTML5) - PDF (Browser capabilities) attachment. Added drag & drop functionality Added attachment preview to preview before submitting --- cfg/conf.ini.sample | 2 +- css/bootstrap/privatebin.css | 15 ++- css/privatebin.css | 28 +++-- i18n/de.json | 2 + js/privatebin.js | 235 ++++++++++++++++++++++++++++------- lib/Configuration.php | 2 +- tpl/bootstrap.php | 7 +- tpl/page.php | 5 +- 8 files changed, 238 insertions(+), 58 deletions(-) diff --git a/cfg/conf.ini.sample b/cfg/conf.ini.sample index 0d251c1..22e7eaa 100644 --- a/cfg/conf.ini.sample +++ b/cfg/conf.ini.sample @@ -64,7 +64,7 @@ languageselection = false ; scripts or run your site behind certain DDoS-protection services. ; Check the documentation at https://content-security-policy.com/ ; Note: If you use a bootstrap theme, you can remove the allow-popups from the sandbox restrictions. -; cspheader = "default-src 'none'; manifest-src 'self'; connect-src *; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self' data:; referrer no-referrer; sandbox allow-same-origin allow-scripts allow-forms allow-popups" +; cspheader = "default-src 'none'; manifest-src 'self'; connect-src *; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self' data:; media-src 'self' data:; object-src 'self' data:; Referrer-Policy: 'no-referrer'" ; stay compatible with PrivateBin Alpha 0.19, less secure ; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of diff --git a/css/bootstrap/privatebin.css b/css/bootstrap/privatebin.css index 381f72d..ca447d5 100644 --- a/css/bootstrap/privatebin.css +++ b/css/bootstrap/privatebin.css @@ -64,12 +64,25 @@ body.navbar-spacing { margin-right: 8px; } -#image img { +#attachmentPreview img { max-width: 100%; height: auto; margin-bottom: 20px; } +#attachmentPreview .pdfPreview { + width: 100%; + height: 100vh; + margin-bottom: 20px; +} + +.dragAndDropFile{ + color:#777; + font-size:1em; + display:inline; +} + + #deletelink { float: right; } diff --git a/css/privatebin.css b/css/privatebin.css index d3c79b4..485dd0a 100644 --- a/css/privatebin.css +++ b/css/privatebin.css @@ -72,13 +72,13 @@ h3.title { bottom: 8px; } -#aboutbox { - color: #94a3b4; +#aboutbox { + color: #94a3b4; padding: 4px 8px 4px 16px; - position: relative; + position: relative; top: 10px; border-left: 2px solid #94a3b4; - float: right; + float: right; width: 60%; } @@ -104,17 +104,29 @@ h3.title { font-family: Consolas, "Lucida Console", "DejaVu Sans Mono", Monaco, monospace; } -#image img { +#attachmentPreview img { max-width: 100%; height: auto; } -#status { +#attachmentPreview .pdfPreview { + width: 100%; + height: 100vh; + margin-bottom: 20px; +} + +.dragAndDropFile{ + color:#777; + font-size:1em; + display:inline; +} + +#status { clear: both; padding: 5px 10px; } -#pasteresult { +#pasteresult { background-color: #1F2833; color: #fff; padding: 4px 12px; @@ -249,7 +261,7 @@ input { font-weight: bold !important; } -#image, .nonworking { +#attachmentPreview, .nonworking { background-color: #fff; color: #000; width: 100%; diff --git a/i18n/de.json b/i18n/de.json index 87f55cc..5f976da 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -131,6 +131,8 @@ "Download attachment": "Anhang herunterladen", "Cloned file attached.": "Kopierte Datei angehängt.", "Attach a file": "Datei anhängen", + "or drag & drop file": "oder per Drag & Drop einfügen", + "File too large, to display a preview. Please download the attachment.": "Datei zu groß, um als Vorschau angezeigt zu werden. Bitte Anhang herunterladen.", "Remove attachment": "Anhang entfernen", "Your browser does not support uploading encrypted files. Please use a newer browser.": "Dein Browser unterstützt das hochladen von verschlüsselten Dateien nicht. Bitte verwende einen neueren Browser.", diff --git a/js/privatebin.js b/js/privatebin.js index 4fd0e99..b6623cd 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -339,6 +339,180 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { } }; + /** + * static attachment helper methods + * + * @name helper + * @class + */ + var attachmentHelpers = { + attachmentData: undefined, + file: undefined, + + /* + * Read file data as dataURL using the FileReader API + * https://developer.mozilla.org/en-US/docs/Web/API/FileReader#readAsDataURL() + */ + readFileData: function (file) { + if (typeof FileReader === undefined) { + // revert loading status… + this.stateNewPaste(); + this.showError(i18n._('Your browser does not support uploading encrypted files. Please use a newer browser.')); + return; + } + + var fr = new FileReader(); + if (file === undefined) { + file = controller.fileInput[0].files[0]; + $('#dragAndDropFileName').text(''); + } else { + $('#dragAndDropFileName').text(file.name); + } + + attachmentHelpers.file = file; + + fr.onload = function (e) { + var dataURL = e.target.result; + attachmentHelpers.attachmentData = dataURL; + + if (controller.messagePreview.parent().hasClass('active')) { + attachmentHelpers.handleFilePreviews(controller.attachmentPreview, dataURL); + } + }; + fr.readAsDataURL(file); + }, + + /** + * Handle the preview of files. + * @argument {DOM Element} element where the preview should be appended. + * @argument {File Data} data of the file to be displayed. + */ + handleFilePreviews: function (element, data) { + if (data) { + var mimeType = this.getMimeTypeFromDataURL(data); + + if (mimeType.match(/image\//i)) { + this.showImagePreview(element, data); + } else if (mimeType.match(/video\//i)) { + this.showVideoPreview(element, data, mimeType); + } else if (mimeType.match(/audio\//i)) { + this.showAudioPreview(element, data, mimeType); + } else if (mimeType.match(/\/pdf/i)) { + this.showPDFPreview(element, data); + } + //else { + //console.log("file but no image/video/audio/pdf"); + //} + } + }, + + /** + * Get Mime Type from a DataURL + * + * @param {type} dataURL + * @returns Mime Type from a dataURL as obtained for a file using the FileReader API https://developer.mozilla.org/en-US/docs/Web/API/FileReader#readAsDataURL() + */ + getMimeTypeFromDataURL: function (dataURL) { + return dataURL.slice(dataURL.indexOf('data:') + 5, dataURL.indexOf(';base64,')); + }, + + showImagePreview: function (element, image) { + element.html( + $(document.createElement('img')) + .attr('src', image) + .attr('class', 'img-thumbnail') + ); + element.removeClass('hidden'); + }, + + showVideoPreview: function (element, video, mimeType) { + var videoPlayer = $(document.createElement('video')) + .attr('controls', 'true') + .attr('autoplay', 'true') + .attr('loop', 'true') + .attr('class', 'img-thumbnail'); + + videoPlayer.append($(document.createElement('source')) + .attr('type', mimeType) + .attr('src', video)); + element.html(videoPlayer); + element.removeClass('hidden'); + }, + + showAudioPreview: function (element, audio, mimeType) { + var audioPlayer = $(document.createElement('audio')) + .attr('controls', 'true') + .attr('autoplay', 'true'); + + audioPlayer.append($(document.createElement('source')) + .attr('type', mimeType) + .attr('src', audio)); + element.html(audioPlayer); + element.removeClass('hidden'); + }, + + showPDFPreview: function (element, pdf) { + //PDFs are only displayed if the filesize is smaller than about 1MB (after base64 encoding). + //Bigger filesizes currently cause crashes in various browsers. + //See also: https://code.google.com/p/chromium/issues/detail?id=69227 + + //Firefox crashes with files that are about 1.5MB + //The performance with 1MB files is bareable + if (pdf.length < 1398488) { + + //Fallback for browsers, that don't support the vh unit + var clientHeight = $(window).height(); + + element.html( + $(document.createElement('embed')) + .attr('src', pdf) + .attr('type', 'application/pdf') + .attr('class', 'pdfPreview') + .css('height', clientHeight) + ); + element.removeClass('hidden'); + } else { + controller.showError(i18n._('File too large, to display a preview. Please download the attachment.')); + } + }, + + addDragDropHandler: function () { + var fileInput = controller.fileInput; + + if (fileInput.length === 0) { + return; + } + + function ignoreDragDrop(e) { + e.stopPropagation(); + e.preventDefault(); + } + + function drop(e) { + e.stopPropagation(); + e.preventDefault(); + + if (fileInput) { + var file = e.dataTransfer.files[0]; + //Clear the file input: + fileInput.wrap('
').closest('form').get(0).reset(); + fileInput.unwrap(); + //Only works in Chrome: + //fileInput[0].files = e.dataTransfer.files; + + attachmentHelpers.readFileData(file); + } + } + + document.addEventListener("drop", drop, false); + document.addEventListener("dragenter", ignoreDragDrop, false); + document.addEventListener("dragover", ignoreDragDrop, false); + fileInput.on("change", function () { + attachmentHelpers.readFileData(); + }); + } + }; + /** * internationalization methods * @@ -748,18 +922,8 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { } this.attachmentLink.attr('href', attachment); this.attachment.removeClass('hidden'); + attachmentHelpers.handleFilePreviews(this.attachmentPreview, attachment); - // if the attachment is an image, display it - var imagePrefix = 'data:image/'; - if (attachment.substring(0, imagePrefix.length) === imagePrefix) - { - this.image.html( - $(document.createElement('img')) - .attr('src', attachment) - .attr('class', 'img-thumbnail') - ); - this.image.removeClass('hidden'); - } } var cleartext = filter.decipher(key, password, paste.data); if (cleartext.length === 0 && password.length === 0 && !paste.attachment) @@ -1018,11 +1182,12 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { sendData: function(event) { event.preventDefault(); - var file = document.getElementById('file'), - files = (file && file.files) ? file.files : null; // FileList object + + var fileName = attachmentHelpers.file ? attachmentHelpers.file.name : this.attachmentLink.attr('download'); + var attachmentData = attachmentHelpers.attachmentData || this.attachmentLink.attr('href'); // do not send if no data. - if (this.message.val().length === 0 && !(files && files[0])) + if (this.message.val().length === 0 && !(fileName && attachmentData)) { return; } @@ -1045,35 +1210,12 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { var randomkey = sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 0), 0), password = this.passwordInput.val(); - if(files && files[0]) + if(fileName) { - if(typeof FileReader === undefined) - { - // revert loading status… - this.stateNewPaste(); - this.showError(i18n._('Your browser does not support uploading encrypted files. Please use a newer browser.')); - return; - } - var reader = new FileReader(); - // closure to capture the file information - reader.onload = (function(theFile) - { - return function(e) { - controller.sendDataContinue( - randomkey, - filter.cipher(randomkey, password, e.target.result), - filter.cipher(randomkey, password, theFile.name) - ); - }; - })(files[0]); - reader.readAsDataURL(files[0]); - } - else if(this.attachmentLink.attr('href')) - { - this.sendDataContinue( + controller.sendDataContinue( randomkey, - filter.cipher(randomkey, password, this.attachmentLink.attr('href')), - this.attachmentLink.attr('download') + filter.cipher(randomkey, password, attachmentData), + filter.cipher(randomkey, password, fileName) ); } else @@ -1199,6 +1341,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { { this.message.text(''); this.attachment.addClass('hidden'); + this.attachmentPreview.addClass('hidden'); this.cloneButton.addClass('hidden'); this.rawTextButton.addClass('hidden'); this.remainingTime.addClass('hidden'); @@ -1317,6 +1460,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { this.preview.addClass('hidden'); } + this.attachmentPreview.removeClass('hidden'); this.pasteResult.addClass('hidden'); this.message.addClass('hidden'); this.clearText.addClass('hidden'); @@ -1547,6 +1691,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { this.message.focus(); this.stateExistingPaste(true); this.formatPaste($('#pasteFormatter').val(), this.message.val()); + attachmentHelpers.handleFilePreviews(this.attachmentPreview, attachmentHelpers.attachmentData); }, /** @@ -1602,6 +1747,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { this.message.text(''); this.changeBurnAfterReading(); this.changeOpenDisc(); + attachmentHelpers.addDragDropHandler(); }, /** @@ -1618,6 +1764,9 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { // the only way to deselect the file is to recreate the input this.fileWrap.html(this.fileWrap.html()); this.fileWrap.removeClass('hidden'); + + attachmentHelpers.file = undefined; + attachmentHelpers.attachmentData = undefined; }, /** @@ -1776,7 +1925,8 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { this.fileRemoveButton = $('#fileremovebutton'); this.fileWrap = $('#filewrap'); this.formatter = $('#formatter'); - this.image = $('#image'); + this.attachmentPreview = $('#attachmentPreview'); + this.fileInput = $('#file'); this.loadingIndicator = $('#loadingindicator'); this.message = $('#message'); this.messageEdit = $('#messageedit'); @@ -1846,6 +1996,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { return { helper: helper, + attachmentHelpers: attachmentHelpers, i18n: i18n, filter: filter, controller: controller diff --git a/lib/Configuration.php b/lib/Configuration.php index 4130a22..380d628 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -51,7 +51,7 @@ class Configuration 'languagedefault' => '', 'urlshortener' => '', 'icon' => 'identicon', - 'cspheader' => 'default-src \'none\'; manifest-src \'self\'; connect-src *; script-src \'self\'; style-src \'self\'; font-src \'self\'; img-src \'self\' data:; referrer no-referrer; sandbox allow-same-origin allow-scripts allow-forms allow-popups', + 'cspheader' => 'default-src \'none\'; manifest-src \'self\'; connect-src *; script-src \'self\'; style-src \'self\'; font-src \'self\'; img-src \'self\' data:; media-src \'self\' data:; object-src \'self\' data:; Referrer-Policy: \'no-referrer\'', 'zerobincompatibility' => false, ), 'expire' => array( diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index 4bf3ca1..8f6ad44 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -69,7 +69,7 @@ if ($MARKDOWN): - + @@ -292,8 +292,9 @@ if ($FILEUPLOAD): Date: Fri, 26 May 2017 21:52:00 +0200 Subject: [PATCH 023/178] added tests for getCipherData(), hasCipherData() & getTemplate() --- js/test.js | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/js/test.js b/js/test.js index c1eec7e..f0a4c47 100644 --- a/js/test.js +++ b/js/test.js @@ -629,6 +629,48 @@ describe('Model', function () { ); }); + describe('hasCipherData', function () { + before(function () { + $.PrivateBin.Model.reset(); + cleanup(); + }); + + jsc.property( + 'checks if the element with id "cipherdata" contains any data', + 'asciistring', + function (value) { + value = $.PrivateBin.Helper.htmlEntities(value).trim(); + $('body').html('
' + value + '
'); + $.PrivateBin.Model.init(); + var result = $.PrivateBin.Model.hasCipherData(); + $.PrivateBin.Model.reset(); + return (value.length > 0) === result; + } + ); + }); + + describe('getCipherData', function () { + before(function () { + $.PrivateBin.Model.reset(); + cleanup(); + }); + + jsc.property( + 'returns the contents of the element with id "cipherdata"', + 'asciistring', + function (value) { + value = $.PrivateBin.Helper.htmlEntities(value).trim(); + $('body').html('
' + value + '
'); + $.PrivateBin.Model.init(); + var result = $.PrivateBin.Helper.htmlEntities( + $.PrivateBin.Model.getCipherData() + ); + $.PrivateBin.Model.reset(); + return value === result; + } + ); + }); + describe('getPasteId', function () { before(function () { $.PrivateBin.Model.reset(); @@ -738,4 +780,33 @@ describe('Model', function () { } ); }); + + describe('getTemplate', function () { + before(function () { + $.PrivateBin.Model.reset(); + cleanup(); + }); + + jsc.property( + 'returns the contents of the element with id "[name]template"', + jsc.nearray(jsc.elements(alnumString)), + jsc.nearray(jsc.elements(a2zString)), + jsc.nearray(jsc.elements(alnumString)), + function (id, element, value) { + id = id.join(''); + element = element.join(''); + value = value.join('').trim(); + $('body').html( + '
<' + element + ' id="' + id + + 'template">' + value + '
' + ); + $.PrivateBin.Model.init(); + var template = '<' + element + ' id="' + id + '">' + value + + '', + result = $.PrivateBin.Model.getTemplate(id).wrap('

').parent().html(); + $.PrivateBin.Model.reset(); + return template === result; + } + ); + }); }); From 3a24e19e490861a39ad34244e2095649cf5a1701 Mon Sep 17 00:00:00 2001 From: Will Date: Sun, 28 May 2017 15:16:23 -0400 Subject: [PATCH 024/178] README: Fix some minior grammar mistakes Fixes a few more minor grammar mistakes --- README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index a259cb5..488f806 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ **PrivateBin** is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. -Data is encrypted/decrypted in the browser using 256bit AES in [Galois Counter mode](https://en.wikipedia.org/wiki/Galois/Counter_Mode). +Data is encrypted and decrypted in the browser using 256bit AES in [Galois Counter mode](https://en.wikipedia.org/wiki/Galois/Counter_Mode). This is a fork of ZeroBin, originally developed by -[Sébastien Sauvage](https://github.com/sebsauvage/ZeroBin). It was refactored -to allow easier and cleaner extensions and has now many more features than the -original. It is however still fully compatible to the original ZeroBin 0.19 -data storage scheme. Therefore such installations can be upgraded to this fork +[Sébastien Sauvage](https://github.com/sebsauvage/ZeroBin). ZeroBin was refactored +to allow easier and cleaner extensions. PrivateBin has many more features than the +original ZeroBin. It is however still fully compatible to the original ZeroBin 0.19 +data storage scheme. Therefore, such installations can be upgraded to PrivateBin without losing any data. ## What PrivateBin provides @@ -38,14 +38,14 @@ without losing any data. ## What it doesn't provide -- As a user you have to trust the server administrator, your internet provider - and any country the traffic passes not to inject any malicious javascript code. - For a basic security the PrivateBin installation *has to provide HTTPS*! +- As a user you have to trust the server administrator, your internet provider, + and any country the traffic passes through not to inject any malicious javascript code. + For basic security, the PrivateBin installation *has to provide HTTPS*! Additionally it should be secured by [HSTS](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) and ideally by [HPKP](https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning) using a - certificate either validated by a trusted third party (check the certificate - when first using a new PrivateBin instance) or self-signed by the server + certificate, either validated by a trusted third party (check the certificate + when first using a new PrivateBin instance), or self-signed by the server operator, validated using a [DNSSEC](https://en.wikipedia.org/wiki/Domain_Name_System_Security_Extensions) protected @@ -53,22 +53,22 @@ without losing any data. record. - The "key" used to encrypt the paste is part of the URL. If you publicly post - the URL of a paste that is not password-protected, everybody can read it. - Use a password if you want your paste to be private. In this case make sure to - use a strong password and do only share it privately and end-to-end-encrypted. + the URL of a paste that is not password-protected, anyone can read it. + Use a password if you want your paste to be private. In this case, make sure to + use a strong password and only share it privately and end-to-end-encrypted. - A server admin might be forced to hand over access logs to the authorities. PrivateBin encrypts your text and the discussion contents, but who accessed it first might still be disclosed via such access logs. - In case of a server breach your data is secure as it is only stored encrypted - on the server. However the server could be misused or the server admin could + on the server. However, the server could be misused or the server admin could be legally forced into sending malicious JavaScript to all web users, which - grabs the decryption key and send it to the server when a user accesses a + grabs the decryption key and sends it to the server when a user accesses a PrivateBin. - Therefore do not access any PrivateBin instance if you think it has been + Therefore, do not access any PrivateBin instance if you think it has been compromised. As long as no user accesses this instance with a previously - generated URL, the content can''t be decrypted. + generated URL, the content can't be decrypted. ## Options From 674ebbc6fb3697ec034e79175d4f5aa0a55f9605 Mon Sep 17 00:00:00 2001 From: rugk Date: Thu, 6 Jul 2017 19:14:49 +0200 Subject: [PATCH 025/178] Remove bullet point It is just useless here. --- .github/ISSUE_TEMPLATE.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index f8363e8..55fbca6 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -35,5 +35,4 @@ If you have access to the server log files, also copy them here. **PrivateBin version:** -* I can reproduce this issue on : Yes / No - +I can reproduce this issue on : Yes / No From 53a8449674293cf977c35b5c60146cb2983bf6a9 Mon Sep 17 00:00:00 2001 From: rugk Date: Thu, 10 Aug 2017 21:51:10 +0200 Subject: [PATCH 026/178] Update HTTPS part of Readme Do not advise against CAs, make clear HTTPS protects against some enumerated threats. --- README.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 488f806..cac0e32 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Data is encrypted and decrypted in the browser using 256bit AES in [Galois Count This is a fork of ZeroBin, originally developed by [Sébastien Sauvage](https://github.com/sebsauvage/ZeroBin). ZeroBin was refactored to allow easier and cleaner extensions. PrivateBin has many more features than the -original ZeroBin. It is however still fully compatible to the original ZeroBin 0.19 +original ZeroBin. It is, however, still fully compatible to the original ZeroBin 0.19 data storage scheme. Therefore, such installations can be upgraded to PrivateBin without losing any data. @@ -38,15 +38,14 @@ without losing any data. ## What it doesn't provide -- As a user you have to trust the server administrator, your internet provider, - and any country the traffic passes through not to inject any malicious javascript code. +- As a user you have to trust the server administrator. For basic security, the PrivateBin installation *has to provide HTTPS*! - Additionally it should be secured by + Otherwise you would also have to trust your internet provider, and any country + the traffic passes through not to inject any malicious javascript code. + Additionally the instance should be secured by [HSTS](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) and ideally by [HPKP](https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning) using a - certificate, either validated by a trusted third party (check the certificate - when first using a new PrivateBin instance), or self-signed by the server - operator, validated using a + certificate. It can use traditional certificate authorities and/or use [DNSSEC](https://en.wikipedia.org/wiki/Domain_Name_System_Security_Extensions) protected [DANE](https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities) @@ -58,8 +57,8 @@ without losing any data. use a strong password and only share it privately and end-to-end-encrypted. - A server admin might be forced to hand over access logs to the authorities. - PrivateBin encrypts your text and the discussion contents, but who accessed it - first might still be disclosed via such access logs. + PrivateBin encrypts your text and the discussion contents, but who accessed a + paste (first) might still be disclosed via access logs. - In case of a server breach your data is secure as it is only stored encrypted on the server. However, the server could be misused or the server admin could From 92f2d27cb7269da54f61ae200a5ff98ee6682a78 Mon Sep 17 00:00:00 2001 From: rugk Date: Thu, 10 Aug 2017 21:54:38 +0200 Subject: [PATCH 027/178] Improve Readme --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cac0e32..802942c 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,11 @@ without losing any data. ## What it doesn't provide -- As a user you have to trust the server administrator. +- As a user you have to trust the server administrator not to inject any malicious + javascript code. For basic security, the PrivateBin installation *has to provide HTTPS*! Otherwise you would also have to trust your internet provider, and any country - the traffic passes through not to inject any malicious javascript code. + the traffic passes through. Additionally the instance should be secured by [HSTS](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) and ideally by [HPKP](https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning) using a From 70b80b5bca76350d504de52a9d5a1166299a0b16 Mon Sep 17 00:00:00 2001 From: rugk Date: Thu, 10 Aug 2017 22:01:20 +0200 Subject: [PATCH 028/178] Deduplicate installation instructions Maintaining them in two places is bad and just creates problems. As they can & should be improved by the community, let's now use the wiki. --- INSTALL.md | 155 +---------------------------------------------------- 1 file changed, 1 insertion(+), 154 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index ffd5d39..7e5fa31 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,154 +1 @@ -# Installation - -**TL;DR:** Download the -[latest release archive](https://github.com/PrivateBin/PrivateBin/releases/latest) -and extract it in your web hosts folder where you want to install your PrivateBin -instance. We try to provide a safe default configuration, but we advise you to -check the options and adjust them as you see fit. - -## Basic installation - -### Requirements - -- PHP version 5.4 or above -- _one_ of the following sources of cryptographically safe randomness is required: - - PHP 7 or higher - - [Libsodium](https://download.libsodium.org/libsodium/content/installation/) and it's [PHP extension](https://paragonie.com/book/pecl-libsodium/read/00-intro.md#installing-libsodium) - - open_basedir access to `/dev/urandom` - - mcrypt extension - - com_dotnet extension - - Mcrypt needs to be able to access `/dev/urandom`. This means if `open_basedir` is set, it must include this file. -- GD extension -- some disk space or (optional) a database supported by [PDO](https://secure.php.net/manual/book.pdo.php) -- ability to create files and folders in the installation directory and the PATH -- A web browser with javascript support - -### Configuration - -In the file `cfg/conf.ini` you can configure PrivateBin. A `cfg/conf.ini.sample` -is provided containing all options and default values. You can copy it to -`cfg/conf.ini` and adapt it as needed. The config file is divided into multiple -sections, which are enclosed in square brackets. - -In the `[main]` section you can enable or disable the discussion feature, set -the limit of stored pastes and comments in bytes. The `[traffic]` section lets -you set a time limit in seconds. Users may not post more often then this limit -to your PrivateBin installation. - -More details can be found in the -[configuration documentation](https://github.com/PrivateBin/PrivateBin/wiki/Configuration). - -## Further configuration - -After (or before) setting up PrivateBin, also set up HTTPS, as without HTTPS -PrivateBin is not secure. ( -[More information](https://github.com/PrivateBin/PrivateBin/wiki/FAQ#how-should-i-setup-https)) - -If you want to use PrivateBin behind Cloudflare, make sure you disabled Rocket -loader and unchecked "Javascript" for Auto Minify, found in your domain settings, -under "Speed". (More information -[in this FAQ entry](https://github.com/PrivateBin/PrivateBin/wiki/FAQ#user-content-how-to-make-privatebin-work-when-using-cloudflare-for-ddos-protection)) - -## Advanced installation - -### Changing the path - -In the index.php you can define a different `PATH`. This is useful to secure your -installation. You can move the configuration, data files, templates and PHP -libraries (directories cfg, doc, data, lib, tpl, tst and vendor) outside of your -document root. This new location must still be accessible to your webserver / PHP -process (see also -[open_basedir setting](https://secure.php.net/manual/en/ini.core.php#ini.open-basedir)). - -> #### PATH Example -> Your PrivateBin installation lives in a subfolder called "paste" inside of -> your document root. The URL looks like this: -> https://example.com/paste/ -> -> The full path of PrivateBin on your webserver is: -> /home/example.com/htdocs/paste -> -> When setting the path like this: -> define('PATH', '../../secret/privatebin/'); -> -> PrivateBin will look for your includes / data here: -> /home/example.com/secret/privatebin - -### Web server configuration - -A `robots.txt` file is provided in the root dir of PrivateBin. It disallows all -robots from accessing your pastes. It is recommend to place it into the root of -your web directory if you have installed PrivateBin in a subdirectory. Make sure -to adjust it, so that the file paths match your installation. Of course also -adjust the file if you already use a `robots.txt`. - -A `.htaccess.disabled` file is provided in the root dir of PrivateBin. It blocks -some known robots and link-scanning bots. If you use Apache, you can rename the -file to `.htaccess` to enable this feature. If you use another webserver, you -have to configure it manually to do the same. - -### Using a database instead of flat files - -In the configuration file the `[model]` and `[model_options]` sections let you -configure your favourite way of storing the pastes and discussions on your -server. - -`Filesystem` is the default model, which stores everything in files in the -data folder. This is the recommended setup for most sites. - -Under high load, in distributed setups or if you are not allowed to store files -locally, you might want to switch to the `Database` model. This lets you -store your data in a database. Basically all databases that are supported by -[PDO](https://secure.php.net/manual/en/book.pdo.php) may be used. Automatic table -creation is provided for `pdo_ibm`, `pdo_informix`, `pdo_mssql`, `pdo_mysql`, -`pdo_oci`, `pdo_pgsql` and `pdo_sqlite`. You may want to provide a table prefix, -if you have to share the PrivateBin database with another application or you want -to use a prefix for -[security reasons](https://security.stackexchange.com/questions/119510/is-using-a-db-prefix-for-tables-more-secure). -The table prefix option is called `tbl`. - -> #### Note -> The `Database` model has only been tested with SQLite, MySQL and PostgreSQL, -> although it would not be recommended to use SQLite in a production environment. -> If you gain any experience running PrivateBin on other RDBMS, please let us -> know. - -For reference or if you want to create the table schema for yourself (replace -`prefix_` with your own table prefix and create the table schema with phpMyAdmin -or the MYSQL console): - -```sql -CREATE TABLE prefix_paste ( - dataid CHAR(16) NOT NULL, - data BLOB, - postdate INT, - expiredate INT, - opendiscussion INT, - burnafterreading INT, - meta TEXT, - attachment MEDIUMBLOB, - attachmentname BLOB, - PRIMARY KEY (dataid) -); - -CREATE TABLE prefix_comment ( - dataid CHAR(16), - pasteid CHAR(16), - parentid CHAR(16), - data BLOB, - nickname BLOB, - vizhash BLOB, - postdate INT, - PRIMARY KEY (dataid) -); -CREATE INDEX parent ON prefix_comment(pasteid); - -CREATE TABLE prefix_config ( - id CHAR(16) NOT NULL, value TEXT, PRIMARY KEY (id) -); -INSERT INTO prefix_config VALUES('VERSION', '1.1'); -``` - -In PostgreSQL the attachment column needs to be TEXT and not BLOB or MEDIUMBLOB. - +For installation instructions, see [our wiki](https://github.com/PrivateBin/PrivateBin/wiki/Installation). From 28b8f878dcca9694a5b5a3d20f44e8278c403e34 Mon Sep 17 00:00:00 2001 From: thororm Date: Sat, 12 Aug 2017 13:26:43 +0200 Subject: [PATCH 029/178] Fixed decryption of pastes without attachment, that have a password --- js/privatebin.js | 6 +++--- tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index 04eedac..9f67e1d 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -2030,7 +2030,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { /** * removes the attachment * - * This automatically hides the attachment containers to, to + * This automatically hides the attachment containers too, to * prevent an inconsistent display. * * @name AttachmentViewer.removeAttachment @@ -2043,8 +2043,8 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { } me.hideAttachment(); me.hideAttachmentPreview(); - $attachmentLink.prop('href', ''); - $attachmentLink.prop('download', ''); + $attachmentLink.removeAttr('href'); + $attachmentLink.removeAttr('download'); $attachmentPreview.html(''); file = undefined; diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index 207fc96..a898900 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -69,7 +69,7 @@ if ($MARKDOWN): - + diff --git a/tpl/page.php b/tpl/page.php index 07a1851..1704b10 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -47,7 +47,7 @@ if ($MARKDOWN): - + From 18adcca66e4f1cb5388ec4d5dab5679b921093ba Mon Sep 17 00:00:00 2001 From: Quent-in Date: Fri, 8 Sep 2017 10:15:02 +0200 Subject: [PATCH 030/178] Correction typo + new strings --- i18n/oc.json | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/i18n/oc.json b/i18n/oc.json index 9047876..cf0939e 100644 --- a/i18n/oc.json +++ b/i18n/oc.json @@ -1,9 +1,9 @@ { "PrivateBin": "PrivateBin", "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted in the browser using 256 bits AES. More information on the project page.": - "%s es un 'pastebin' (o gestionari d'extrachs de tèxte e còdi font) minimalista e open source, dins lo qual lo servidor a pas cap de coneissença de las donadas mandadas. Las donadas son chifradas/deschifradas dins lo navigator per un chiframent AES 256 bits. Mai informacions sus la pagina del projècte.", + "%s es un 'pastebin' (o gestionari d’extrachs de tèxte e còdi font) minimalista e open source, dins lo qual lo servidor a pas cap de coneissença de las donadas mandadas. Las donadas son chifradas/deschifradas dins lo navigator per un chiframent AES 256 bits. Mai informacions sus la pagina del projècte.", "Because ignorance is bliss": - "Perque l'ignorància es bonaür", + "Perque lo es l’ignorància", "en": "oc", "Paste does not exist, has expired or has been deleted.": "Lo tèxte existís pas, a expirat, o es estat suprimit.", @@ -32,11 +32,11 @@ "Paste was properly deleted.": "Lo tèxte es estat correctament suprimit.", "JavaScript is required for %s to work.
Sorry for the inconvenience.": - "JavaScript es requesit per far foncionar %s.
O planhèm per l'inconvenient.", + "JavaScript es requesit per far foncionar %s.
O planhèm per l’inconvenient.", "%s requires a modern browser to work.": "%s necessita un navigator modèrn per foncionar.", "Still using Internet Explorer? Do yourself a favor, switch to a modern browser:": - "Encora sus Internet Explorer ? Fasètz-vos una favor, passatz a un navigator modèrn :", + "Encora sus Internet Explorer ? Fasètz-vos una favor, passatz a un navigator modèrn :", "New": "Nòu", "Send": @@ -67,7 +67,7 @@ "Never": "Jamai", "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": - "Nota : Aquò es un servici d'espròva : las donadas pòdon èsser suprimidas a cada moment. De catons moriràn s'abusatz d'aqueste servici.", + "Nota : Aquò es un servici d’espròva : las donadas pòdon èsser suprimidas a cada moment. De catons moriràn s’abusatz d’aqueste servici.", "This document will expire in %d seconds.": ["Ce document expirera dans %d seconde.", "Aqueste document expirarà dins %d segondas."], "This document will expire in %d minutes.": @@ -79,21 +79,21 @@ "This document will expire in %d months.": ["Ce document expirera dans %d mois.", "Aqueste document expirarà dins %d meses."], "Please enter the password for this paste:": - "Picatz lo senhal per aqueste tèxte :", + "Picatz lo senhal per aqueste tèxte :", "Could not decrypt data (Wrong key?)": - "Impossible de deschifrar las donadas (marrida clau ?)", + "Impossible de deschifrar las donadas (marrida clau ?)", "Could not delete the paste, it was not stored in burn after reading mode.": "Impossible de suprimir lo tèxte, perque es pas estat gardat en mòde \"Escafar aprèp lectura\".", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "PER VÒSTRES UÈLHS SOLAMENT. Tampetz pas aquesta fenèstra, aqueste tèxte poirà pas mai èsser afichat.", "Could not decrypt comment; Wrong key?": - "Impossible de deschifrar lo comentari ; marrida clau ?", + "Impossible de deschifrar lo comentari ; marrida clau ?", "Reply": "Respondre", "Anonymous": "Anonime", "Avatar generated from IP address": - "Avatar anonime (Vizhash de l'adreça IP)", + "Avatar anonime (Vizhash de l’adreça IP)", "Add comment": "Apondre un comentari", "Optional nickname…": @@ -105,25 +105,25 @@ "Comment posted.": "Comentari mandat.", "Could not refresh display: %s": - "Impossible d'actualizar l'afichatge : %s", + "Impossible d’actualizar l’afichatge : %s", "unknown status": "Estatut desconegut", "server error or not responding": "Lo servidor respond pas o a rencontrat una error", "Could not post comment: %s": - "Impossible de mandar lo comentari : %s", + "Impossible de mandar lo comentari : %s", "Please move your mouse for more entropy…": "Mercés de bolegar vòstra mirga per mai entropia…", "Sending paste…": "Mandadís del tèxte…", "Your paste is %s (Hit [Ctrl]+[c] to copy)": - "Vòstre tèxte es disponible a l'adreça %s (Picatz sus [Ctrl]+[c] per copiar)", + "Vòstre tèxte es disponible a l’adreça %s (Picatz sus [Ctrl]+[c] per copiar)", "Delete data": "Supprimir las donadas del tèxte", "Could not create paste: %s": - "Impossible de crear lo tèxte : %s", + "Impossible de crear lo tèxte : %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": - "Impossible de deschifrar lo tèxte : Clau de deschiframent absenta de l'URL (Avètz utilizat un redirector o un site de reduccion d'URL que suprimís una partida de l'URL ?)", + "Impossible de deschifrar lo tèxte : Clau de deschiframent absenta de l’URL (Avètz utilizat un redirector o un site de reduccion d’URL que suprimís una partida de l’URL ?)", "B": "o", "KiB": "Kio", "MiB": "Mio", @@ -139,14 +139,14 @@ "Markdown": "Markdown", "Download attachment": "Telecargar la pèça junta", "Cloned: '%s'": "Clonar: '%s'", - "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.", + "The cloned file '%s' was attached to this paste.": "Aqueste fichièr clonat '%s' es estat ajustat a aqueste tèxte.", "Attach a file": "Juntar un fichièr ", "Remove attachment": "Levar la pèca junta", "Your browser does not support uploading encrypted files. Please use a newer browser.": - "Vòstre navigator es pas compatible amb lo mandadís de fichièrs chifrats. Mercés d'emplegar un navigator mai recent.", + "Vòstre navigator es pas compatible amb lo mandadís de fichièrs chifrats. Mercés d’emplegar un navigator mai recent.", "Invalid attachment.": "Pèça junta invalida.", "Options": "Opcions", - "Shorten URL": "Acorchir l'URL", + "Shorten URL": "Acorchir l’URL", "Editor": "Editar", "Preview": "Previsualizar", "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": @@ -159,6 +159,6 @@ "Decrypting paste…": "Decrypting paste…", "Preparing new paste…": "Preparing new paste…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": - "Se per cas aqueste messatge quita pas de s'afichar mercés de gaitar aquesta FAQ per las solucions (en Anglés).", + "Se per cas aqueste messatge quita pas de s’afichar mercés de gaitar aquesta FAQ per las solucions (en Anglés).", "+++ no paste text +++": "+++ no paste text +++" } From c42e7fdd03d25a2e9ff67ed84d815ea057bb45e8 Mon Sep 17 00:00:00 2001 From: Quent-in Date: Fri, 8 Sep 2017 10:17:03 +0200 Subject: [PATCH 031/178] Update oc.json missing word --- i18n/oc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/oc.json b/i18n/oc.json index cf0939e..c934916 100644 --- a/i18n/oc.json +++ b/i18n/oc.json @@ -3,7 +3,7 @@ "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted in the browser using 256 bits AES. More information on the project page.": "%s es un 'pastebin' (o gestionari d’extrachs de tèxte e còdi font) minimalista e open source, dins lo qual lo servidor a pas cap de coneissença de las donadas mandadas. Las donadas son chifradas/deschifradas dins lo navigator per un chiframent AES 256 bits. Mai informacions sus la pagina del projècte.", "Because ignorance is bliss": - "Perque lo es l’ignorància", + "Perque lo bonaür es l’ignorància", "en": "oc", "Paste does not exist, has expired or has been deleted.": "Lo tèxte existís pas, a expirat, o es estat suprimit.", From 5cdd1f480f49b15b5d3927040d4a62d035b6bc7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20Fabi=C3=A1n=20Altamirano=20Tena?= Date: Tue, 12 Sep 2017 17:27:51 -0500 Subject: [PATCH 032/178] Updated spanish translation --- i18n/es.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/i18n/es.json b/i18n/es.json index 427f90d..7d8de7a 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -93,7 +93,7 @@ "Anonymous": "Anónimo", "Avatar generated from IP address": - "Avatar anónimo (Vizhash de la dirección IP)", + "Avatar generado a partir de la dirección IP", "Add comment": "Añadir comentario", "Optional nickname…": @@ -130,7 +130,7 @@ "Markdown": "Markdown", "Download attachment": "Descargar adjunto", "Cloned: '%s'": "Clonado: '%s'.", - "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.", + "The cloned file '%s' was attached to this paste.": "El archivo clonado '%s' ha sido adjuntado a este texto.", "Attach a file": "Adjuntar archivo", "Remove attachment": "Remover adjunto", "Your browser does not support uploading encrypted files. Please use a newer browser.": @@ -147,9 +147,9 @@ "Enter password": "Ingrese contraseña", "Loading…": "Cargando…", - "Decrypting paste…": "Decrypting paste…", - "Preparing new paste…": "Preparing new paste…", + "Decrypting paste…": "Descifrando texto…", + "Preparing new paste…": "Preparando texto nuevo…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "En caso de que este mensaje nunca desaparezca por favor revise este FAQ para obtener información para solucionar problemas.", - "+++ no paste text +++": "+++ no paste text +++" + "+++ no paste text +++": "+++ sin texto +++" } From ba0ff3545d4b4ef4c50d4c20da60bdef9580a4dc Mon Sep 17 00:00:00 2001 From: El RIDO Date: Wed, 13 Sep 2017 07:23:56 +0200 Subject: [PATCH 033/178] started work on UiHelper tests --- js/test.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/js/test.js b/js/test.js index f0a4c47..fce63c6 100644 --- a/js/test.js +++ b/js/test.js @@ -2,6 +2,7 @@ var jsc = require('jsverify'), jsdom = require('jsdom-global'), cleanup = jsdom(), + EventEmitter = require('events'), a2zString = ['a','b','c','d','e','f','g','h','i','j','k','l','m', 'n','o','p','q','r','s','t','u','v','w','x','y','z'], @@ -810,3 +811,32 @@ describe('Model', function () { ); }); }); + +describe('UiHelper', function () { + describe('historyChange', function () { + before(function () { + $.PrivateBin.Helper.reset(); + }); + + jsc.property( + 'returns the URL without query & fragment', + jsc.elements(schemas), + jsc.nearray(jsc.elements(a2zString)), + jsc.array(jsc.elements(queryString)), + 'string', + function (schema, address, query, fragment) { + var expected = schema + '://' + address.join('') + '/', + clean = jsdom('', {url: expected + '?' + query.join('') + '#' + fragment}), + emitter = new EventEmitter(); + + $.PrivateBin.UiHelper.init(); + emitter.emit('popstate'); + var result = window.location.href; + clean(); + console.log(expected, result); + return expected === result; + } + ); + }); +}); + From cf1b6702152e1de1715ea6dab11a3f67a81814e6 Mon Sep 17 00:00:00 2001 From: Kcchouette Date: Wed, 20 Sep 2017 11:46:05 +0200 Subject: [PATCH 034/178] Update fr.json --- i18n/fr.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/i18n/fr.json b/i18n/fr.json index 5ac3424..00ca25a 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -83,7 +83,7 @@ "Could not decrypt data (Wrong key?)": "Impossible de déchiffrer les données (mauvaise clé ?)", "Could not delete the paste, it was not stored in burn after reading mode.": - "Impossible de supprimer le paste, car il n'a pas été stoclé en mode \"Effacer après lecture\".", + "Impossible de supprimer le paste, car il n'a pas été stocké en mode \"Effacer après lecture\".", "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "POUR VOS YEUX UNIQUEMENT. Ne fermez pas cette fenêtre, ce paste ne pourra plus être affiché.", "Could not decrypt comment; Wrong key?": @@ -93,7 +93,7 @@ "Anonymous": "Anonyme", "Avatar generated from IP address": - "Avatar anonyme (Vizhash de l'adresse IP)", + "Avatar généré à partir de l'adresse IP)", "Add comment": "Ajouter un commentaire", "Optional nickname…": @@ -139,7 +139,7 @@ "Markdown": "Markdown", "Download attachment": "Télécharger la pièce jointe", "Cloned: '%s'": "Cloner '%s'", - "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.", + "The cloned file '%s' was attached to this paste.": "Le fichier cloné '%s' a été attaché à ce paste.", "Attach a file": "Attacher un fichier ", "Remove attachment": "Enlever l'attachement", "Your browser does not support uploading encrypted files. Please use a newer browser.": @@ -160,5 +160,5 @@ "Preparing new paste…": "Préparation du paste…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "Si ce message ne disparaîssait pas, jetez un oeil à cette FAQ pour des idées de résolution (en Anglais).", - "+++ no paste text +++": "+++ no paste text +++" + "+++ no paste text +++": "+++ pas de paste-text +++" } From 78f9f5279ac7c88569fe6a8626c272ee69f916e5 Mon Sep 17 00:00:00 2001 From: Kcchouette Date: Thu, 21 Sep 2017 10:02:25 +0200 Subject: [PATCH 035/178] Remove the last ")" --- i18n/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/fr.json b/i18n/fr.json index 00ca25a..da9d373 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -93,7 +93,7 @@ "Anonymous": "Anonyme", "Avatar generated from IP address": - "Avatar généré à partir de l'adresse IP)", + "Avatar généré à partir de l'adresse IP", "Add comment": "Ajouter un commentaire", "Optional nickname…": From 7197705d5c91237e1f269b6cee5b649956b0ded1 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Tue, 3 Oct 2017 19:45:47 +0200 Subject: [PATCH 036/178] updating unit test in preparation for planned file name change, currently failing --- cfg/{conf.ini.sample => conf.sample.php} | 1 + tst/Bootstrap.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) rename cfg/{conf.ini.sample => conf.sample.php} (99%) diff --git a/cfg/conf.ini.sample b/cfg/conf.sample.php similarity index 99% rename from cfg/conf.ini.sample rename to cfg/conf.sample.php index d457b89..a28cdfb 100644 --- a/cfg/conf.ini.sample +++ b/cfg/conf.sample.php @@ -1,3 +1,4 @@ +; Date: Fri, 29 Sep 2017 18:59:02 +0200 Subject: [PATCH 037/178] changes the file extension to php and adds a small one-liner to stop PHP from presenting the file to any website visitor Signed-off-by: El RIDO --- lib/Configuration.php | 2 +- tst/JsonApiTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Configuration.php b/lib/Configuration.php index b6b9f6f..d9d70bf 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -100,7 +100,7 @@ class Configuration public function __construct() { $config = array(); - $configFile = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini'; + $configFile = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.php'; if (is_readable($configFile)) { $config = parse_ini_file($configFile, true); foreach (array('main', 'model', 'model_options') as $section) { diff --git a/tst/JsonApiTest.php b/tst/JsonApiTest.php index a592889..cd27cd8 100644 --- a/tst/JsonApiTest.php +++ b/tst/JsonApiTest.php @@ -283,7 +283,7 @@ class JsonApiTest extends PHPUnit_Framework_TestCase $this->reset(); $paste = Helper::getPasteWithAttachment(); $this->_model->create(Helper::getPasteId(), $paste); - $_GET['jsonld'] = '../cfg/conf.ini'; + $_GET['jsonld'] = CONF; ob_start(); new PrivateBin; $content = ob_get_contents(); From 6625a9dc59944cd47d575d8dbbeb10934595600a Mon Sep 17 00:00:00 2001 From: El RIDO Date: Tue, 3 Oct 2017 20:33:24 +0200 Subject: [PATCH 038/178] hiding INI contents from StyleCI --- cfg/conf.sample.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cfg/conf.sample.php b/cfg/conf.sample.php index a28cdfb..f52028c 100644 --- a/cfg/conf.sample.php +++ b/cfg/conf.sample.php @@ -1,4 +1,4 @@ -; Date: Tue, 3 Oct 2017 20:34:39 +0200 Subject: [PATCH 039/178] ask composer in TravisCI to use an oauth token to avoid rate limiting --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b18d048..084a76d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ install: - rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm install 4 before_script: + - composer config -g github-oauth.github.com "$GITHUB_TOKEN" - composer install -n - npm install -g mocha - cd js From ed04fe3b4ca905930b4994a0ae7120a3f10dddb9 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Tue, 3 Oct 2017 20:49:36 +0200 Subject: [PATCH 040/178] disabling two new options that do no match our style guidelines --- .styleci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.styleci.yml b/.styleci.yml index 002616b..0c7ba38 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -11,6 +11,8 @@ enabled: disabled: - blank_line_after_opening_tag - blank_line_before_return + - blank_line_before_throw + - blank_line_before_try - concat_without_spaces - declare_equal_normalize - heredoc_to_nowdoc From 6fa2bfe30e1a4fffa809bce4557cebf186edec5c Mon Sep 17 00:00:00 2001 From: El RIDO Date: Wed, 4 Oct 2017 20:05:46 +0200 Subject: [PATCH 041/178] updated documentation, incremented version --- CHANGELOG.md | 2 + INSTALL.md | 159 +++++++++++++++++++++++- README.md | 2 +- css/bootstrap/privatebin.css | 2 +- css/noscript.css | 2 +- css/privatebin.css | 2 +- js/privatebin.js | 2 +- lib/Configuration.php | 2 +- lib/Data/AbstractData.php | 2 +- lib/Data/Database.php | 2 +- lib/Data/Filesystem.php | 2 +- lib/Filter.php | 2 +- lib/I18n.php | 2 +- lib/Json.php | 2 +- lib/Model.php | 2 +- lib/Model/AbstractModel.php | 2 +- lib/Model/Comment.php | 2 +- lib/Model/Paste.php | 2 +- lib/Persistence/AbstractPersistence.php | 2 +- lib/Persistence/PurgeLimiter.php | 2 +- lib/Persistence/ServerSalt.php | 2 +- lib/Persistence/TrafficLimiter.php | 2 +- lib/PrivateBin.php | 4 +- lib/Request.php | 2 +- lib/Sjcl.php | 2 +- lib/View.php | 2 +- lib/Vizhash16x16.php | 2 +- tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 29 files changed, 188 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 964d4ee..8e77d86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ * CHANGED: Minimum required PHP version is 5.4 (#186) * CHANGED: Shipped .htaccess files were updated for Apache 2.4 (#192) * CHANGED: Cleanup of bootstrap template variants and moved icons to `img` directory + * **1.1.1 (2017-10-06)** + * CHANGED: Switched to `.php` file extension for configuration file, to avoid leaking configuration data in unprotected installation. * **1.1 (2016-12-26)** * ADDED: Translations for Italian and Russian * ADDED: Loading message displayed until decryption succeeded for slower (in terms of CPU or network) systems diff --git a/INSTALL.md b/INSTALL.md index 7e5fa31..6eebfe9 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1 +1,158 @@ -For installation instructions, see [our wiki](https://github.com/PrivateBin/PrivateBin/wiki/Installation). +# Installation + +**TL;DR:** Download the +[latest release archive](https://github.com/PrivateBin/PrivateBin/releases/latest) +and extract it in your web hosts folder where you want to install your PrivateBin +instance. We try to provide a mostly safe default configuration, but we urge you to +check the [security section](#hardening-and-security) below and the [configuration +options](#configuration) to adjust as you see fit. + +**NOTE:** See [our FAQ](https://github.com/PrivateBin/PrivateBin/wiki/FAQ#how-can-i-securely-clonedownload-your-project) for information how to securely download the PrivateBin release files. + +### Minimal requirements + +- PHP version 5.4 or above +- _one_ of the following sources of cryptographically safe randomness is required: + - PHP 7 or higher + - [Libsodium](https://download.libsodium.org/libsodium/content/installation/) and it's [PHP extension](https://paragonie.com/book/pecl-libsodium/read/00-intro.md#installing-libsodium) + - open_basedir access to `/dev/urandom` + - mcrypt extension + - com_dotnet extension + + Mcrypt needs to be able to access `/dev/urandom`. This means if `open_basedir` is set, it must include this file. +- GD extension +- some disk space or (optionally) a database supported by [PDO](https://secure.php.net/manual/book.pdo.php) +- ability to create files and folders in the installation directory and the PATH defined in index.php +- A web browser with javascript support + +## Hardening and security + +### Changing the path + +In the index.php you can define a different `PATH`. This is useful to secure your +installation. You can move the configuration, data files, templates and PHP +libraries (directories cfg, doc, data, lib, tpl, tst and vendor) outside of your +document root. This new location must still be accessible to your webserver / PHP +process (see also +[open_basedir setting](https://secure.php.net/manual/en/ini.core.php#ini.open-basedir)). + +> #### PATH Example +> Your PrivateBin installation lives in a subfolder called "paste" inside of +> your document root. The URL looks like this: +> http://example.com/paste/ +> +> The full path of PrivateBin on your webserver is: +> /home/example.com/htdocs/paste +> +> When setting the path like this: +> define('PATH', '../../secret/privatebin/'); +> +> PrivateBin will look for your includes / data here: +> /home/example.com/secret/privatebin + +### Transport security + +When setting up PrivateBin, also set up HTTPS, if you haven't already. Without HTTPS +PrivateBin is not secure, as the javascript files could be manipulated during transmission. +For more information on this, see our [FAQ entry on HTTPS setup](https://github.com/PrivateBin/PrivateBin/wiki/FAQ#how-should-i-setup-https). + +## Configuration + +In the file `cfg/conf.php` you can configure PrivateBin. A `cfg/conf.sample.php` +is provided containing all options and default values. You can copy it to +`cfg/conf.php` and adapt it as needed. The config file is divided into multiple +sections, which are enclosed in square brackets. + +In the `[main]` section you can enable or disable the discussion feature, set +the limit of stored pastes and comments in bytes. The `[traffic]` section lets +you set a time limit in seconds. Users may not post more often then this limit +to your PrivateBin installation. + +More details can be found in the +[configuration documentation](https://github.com/PrivateBin/PrivateBin/wiki/Configuration). + +## Advanced installation + +### Web server configuration + +A `robots.txt` file is provided in the root dir of PrivateBin. It disallows all +robots from accessing your pastes. It is recommend to place it into the root of +your web directory if you have installed PrivateBin in a subdirectory. Make sure +to adjust it, so that the file paths match your installation. Of course also +adjust the file if you already use a `robots.txt`. + +A `.htaccess.disabled` file is provided in the root dir of PrivateBin. It blocks +some known robots and link-scanning bots. If you use Apache, you can rename the +file to `.htaccess` to enable this feature. If you use another webserver, you +have to configure it manually to do the same. + +### On using Cloudflare + +If you want to use PrivateBin behind Cloudflare, make sure you have disabled the Rocket +loader and unchecked "Javascript" for Auto Minify, found in your domain settings, +under "Speed". (More information +[in this FAQ entry](https://github.com/PrivateBin/PrivateBin/wiki/FAQ#user-content-how-to-make-privatebin-work-when-using-cloudflare-for-ddos-protection)) + +### Using a database instead of flat files + +In the configuration file the `[model]` and `[model_options]` sections let you +configure your favourite way of storing the pastes and discussions on your +server. + +`Filesystem` is the default model, which stores everything in files in the +data folder. This is the recommended setup for most sites. + +Under high load, in distributed setups or if you are not allowed to store files +locally, you might want to switch to the `Database` model. This lets you +store your data in a database. Basically all databases that are supported by +[PDO](https://secure.php.net/manual/en/book.pdo.php) may be used. Automatic table +creation is provided for `pdo_ibm`, `pdo_informix`, `pdo_mssql`, `pdo_mysql`, +`pdo_oci`, `pdo_pgsql` and `pdo_sqlite`. You may want to provide a table prefix, +if you have to share the PrivateBin database with another application or you want +to use a prefix for +[security reasons](https://security.stackexchange.com/questions/119510/is-using-a-db-prefix-for-tables-more-secure). +The table prefix option is called `tbl`. + +> #### Note +> The `Database` model has only been tested with SQLite, MySQL and PostgreSQL, +> although it would not be recommended to use SQLite in a production environment. +> If you gain any experience running PrivateBin on other RDBMS, please let us +> know. + +For reference or if you want to create the table schema for yourself (replace +`prefix_` with your own table prefix and create the table schema with phpMyAdmin +or the MYSQL console): + +```sql +CREATE TABLE prefix_paste ( + dataid CHAR(16) NOT NULL, + data BLOB, + postdate INT, + expiredate INT, + opendiscussion INT, + burnafterreading INT, + meta TEXT, + attachment MEDIUMBLOB, + attachmentname BLOB, + PRIMARY KEY (dataid) +); + +CREATE TABLE prefix_comment ( + dataid CHAR(16), + pasteid CHAR(16), + parentid CHAR(16), + data BLOB, + nickname BLOB, + vizhash BLOB, + postdate INT, + PRIMARY KEY (dataid) +); +CREATE INDEX parent ON prefix_comment(pasteid); + +CREATE TABLE prefix_config ( + id CHAR(16) NOT NULL, value TEXT, PRIMARY KEY (id) +); +INSERT INTO prefix_config VALUES('VERSION', '1.1'); +``` + +In PostgreSQL, the attachment column needs to be TEXT and not BLOB or MEDIUMBLOB. diff --git a/README.md b/README.md index 802942c..483f081 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/094500f62abf4c9aa0c8a8a4520e4789)](https://www.codacy.com/app/PrivateBin/PrivateBin) [![Test Coverage](https://codeclimate.com/github/PrivateBin/PrivateBin/badges/coverage.svg)](https://codeclimate.com/github/PrivateBin/PrivateBin/coverage) [![Code Coverage](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/?branch=master) -*Current version: 1.1* +*Current version: 1.1.1* **PrivateBin** is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. diff --git a/css/bootstrap/privatebin.css b/css/bootstrap/privatebin.css index ded8259..d2ba47c 100644 --- a/css/bootstrap/privatebin.css +++ b/css/bootstrap/privatebin.css @@ -6,7 +6,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ body { diff --git a/css/noscript.css b/css/noscript.css index 97ef60d..26c6bad 100644 --- a/css/noscript.css +++ b/css/noscript.css @@ -6,7 +6,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.0 + * @version 1.1.1 */ /* When there is no script at all other */ diff --git a/css/privatebin.css b/css/privatebin.css index d3c79b4..077e8ba 100644 --- a/css/privatebin.css +++ b/css/privatebin.css @@ -6,7 +6,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ /* CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved. diff --git a/js/privatebin.js b/js/privatebin.js index 8cf7683..9e626e9 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -6,7 +6,7 @@ * @see {@link https://github.com/PrivateBin/PrivateBin} * @copyright 2012 Sébastien SAUVAGE ({@link http://sebsauvage.net}) * @license {@link https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License} - * @version 1.1 + * @version 1.1.1 * @name PrivateBin * @namespace */ diff --git a/lib/Configuration.php b/lib/Configuration.php index d9d70bf..a9c8a75 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin; diff --git a/lib/Data/AbstractData.php b/lib/Data/AbstractData.php index 41260f8..f4960f9 100644 --- a/lib/Data/AbstractData.php +++ b/lib/Data/AbstractData.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin\Data; diff --git a/lib/Data/Database.php b/lib/Data/Database.php index c35df3b..2c844ef 100644 --- a/lib/Data/Database.php +++ b/lib/Data/Database.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin\Data; diff --git a/lib/Data/Filesystem.php b/lib/Data/Filesystem.php index 4100e29..53508e0 100644 --- a/lib/Data/Filesystem.php +++ b/lib/Data/Filesystem.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin\Data; diff --git a/lib/Filter.php b/lib/Filter.php index 951e265..4c0a22e 100644 --- a/lib/Filter.php +++ b/lib/Filter.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin; diff --git a/lib/I18n.php b/lib/I18n.php index 2bee73e..5ae9bad 100644 --- a/lib/I18n.php +++ b/lib/I18n.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin; diff --git a/lib/Json.php b/lib/Json.php index 27993f9..ad96333 100644 --- a/lib/Json.php +++ b/lib/Json.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin; diff --git a/lib/Model.php b/lib/Model.php index d1011f1..b4f084f 100644 --- a/lib/Model.php +++ b/lib/Model.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin; diff --git a/lib/Model/AbstractModel.php b/lib/Model/AbstractModel.php index 55956b7..0ac2317 100644 --- a/lib/Model/AbstractModel.php +++ b/lib/Model/AbstractModel.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin\Model; diff --git a/lib/Model/Comment.php b/lib/Model/Comment.php index b67742d..709cdee 100644 --- a/lib/Model/Comment.php +++ b/lib/Model/Comment.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin\Model; diff --git a/lib/Model/Paste.php b/lib/Model/Paste.php index fae808e..1bac7c8 100644 --- a/lib/Model/Paste.php +++ b/lib/Model/Paste.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin\Model; diff --git a/lib/Persistence/AbstractPersistence.php b/lib/Persistence/AbstractPersistence.php index 64fb530..2e31622 100644 --- a/lib/Persistence/AbstractPersistence.php +++ b/lib/Persistence/AbstractPersistence.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin\Persistence; diff --git a/lib/Persistence/PurgeLimiter.php b/lib/Persistence/PurgeLimiter.php index 2eb0b52..c4affac 100644 --- a/lib/Persistence/PurgeLimiter.php +++ b/lib/Persistence/PurgeLimiter.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin\Persistence; diff --git a/lib/Persistence/ServerSalt.php b/lib/Persistence/ServerSalt.php index 129a099..a4d0686 100644 --- a/lib/Persistence/ServerSalt.php +++ b/lib/Persistence/ServerSalt.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin\Persistence; diff --git a/lib/Persistence/TrafficLimiter.php b/lib/Persistence/TrafficLimiter.php index 914450a..9f35e5d 100644 --- a/lib/Persistence/TrafficLimiter.php +++ b/lib/Persistence/TrafficLimiter.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin\Persistence; diff --git a/lib/PrivateBin.php b/lib/PrivateBin.php index c817445..7b53fa1 100644 --- a/lib/PrivateBin.php +++ b/lib/PrivateBin.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin; @@ -28,7 +28,7 @@ class PrivateBin * * @const string */ - const VERSION = '1.1'; + const VERSION = '1.1.1'; /** * minimal required PHP version diff --git a/lib/Request.php b/lib/Request.php index 37c0bca..f6daa50 100644 --- a/lib/Request.php +++ b/lib/Request.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin; diff --git a/lib/Sjcl.php b/lib/Sjcl.php index 4ed76b4..7efc7b2 100644 --- a/lib/Sjcl.php +++ b/lib/Sjcl.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin; diff --git a/lib/View.php b/lib/View.php index 6c04e47..8b25395 100644 --- a/lib/View.php +++ b/lib/View.php @@ -7,7 +7,7 @@ * @link https://github.com/PrivateBin/PrivateBin * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 1.1 + * @version 1.1.1 */ namespace PrivateBin; diff --git a/lib/Vizhash16x16.php b/lib/Vizhash16x16.php index e9bd5d0..3baae6d 100644 --- a/lib/Vizhash16x16.php +++ b/lib/Vizhash16x16.php @@ -8,7 +8,7 @@ * @link http://sebsauvage.net/wiki/doku.php?id=php:vizhash_gd * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License - * @version 0.0.5 beta PrivateBin 1.1 + * @version 0.0.5 beta PrivateBin 1.1.1 */ namespace PrivateBin; diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index 7993e43..103037e 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -69,7 +69,7 @@ if ($MARKDOWN): - + diff --git a/tpl/page.php b/tpl/page.php index 46b8df1..81d7c1a 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -47,7 +47,7 @@ if ($MARKDOWN): - + From b60d55236e81da053d72fbe3f910315ed6e3541e Mon Sep 17 00:00:00 2001 From: El RIDO Date: Wed, 4 Oct 2017 20:31:37 +0200 Subject: [PATCH 042/178] adding test for INI config file conversion --- tst/ConfigurationTest.php | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tst/ConfigurationTest.php b/tst/ConfigurationTest.php index 3b9b442..b98425e 100644 --- a/tst/ConfigurationTest.php +++ b/tst/ConfigurationTest.php @@ -12,7 +12,7 @@ class ConfigurationTest extends PHPUnit_Framework_TestCase { /* Setup Routine */ Helper::confBackup(); - $this->_options = configuration::getDefaults(); + $this->_options = Configuration::getDefaults(); $this->_options['model_options']['dir'] = PATH . $this->_options['model_options']['dir']; $this->_options['traffic']['dir'] = PATH . $this->_options['traffic']['dir']; $this->_options['purge']['dir'] = PATH . $this->_options['purge']['dir']; @@ -135,4 +135,26 @@ class ConfigurationTest extends PHPUnit_Framework_TestCase $conf = new Configuration; $this->assertEquals('Database', $conf->getKey('class', 'model'), 'old db class gets renamed'); } + + public function testHandleConfigFileRename() + { + $options = $this->_options; + Helper::createIniFile(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini.sample', $options); + + $options['main']['opendiscussion'] = true; + $options['main']['fileupload'] = true; + $options['main']['template'] = 'darkstrap'; + Helper::createIniFile(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini', $options); + + $conf = new Configuration; + $this->assertFileExists(CONF, 'old configuration file gets converted'); + $this->assertFileNotExists(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini', 'old configuration file gets removed'); + $this->assertFileNotExists(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini.sample', 'old configuration sample file gets removed'); + $this->assertTrue( + $conf->getKey('opendiscussion') && + $conf->getKey('fileupload') && + $conf->getKey('template') === 'darkstrap', + 'configuration values get converted' + ); + } } From 6e8eafe12938b3733a753dc59dd2f31c5501ac4d Mon Sep 17 00:00:00 2001 From: El RIDO Date: Wed, 4 Oct 2017 21:55:03 +0200 Subject: [PATCH 043/178] implemented INI cenversion functionality --- lib/Configuration.php | 28 ++++++++++++++++++++++++++++ lib/Data/Database.php | 5 ++--- tst/ConfigurationTest.php | 16 ++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/lib/Configuration.php b/lib/Configuration.php index a9c8a75..4b7d35c 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -101,6 +101,33 @@ class Configuration { $config = array(); $configFile = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.php'; + $configIni = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini'; + + // rename INI files to avoid configuration leakage + if (is_readable($configIni)) { + // don't overwrite already converted file + if (!is_file($configFile)) { + $iniUpgradeError = false; + $context = stream_context_create(); + $iniHandle = fopen($configIni, 'r', 1, $context); + $written = file_put_contents($configFile, '; $values) { // fill missing sections with default values diff --git a/lib/Data/Database.php b/lib/Data/Database.php index 2c844ef..9685edd 100644 --- a/lib/Data/Database.php +++ b/lib/Data/Database.php @@ -693,9 +693,8 @@ class Database extends AbstractData 'CREATE INDEX IF NOT EXISTS comment_parent ON ' . self::_sanitizeIdentifier('comment') . '(pasteid);' ); - // no break, continue with updates for 0.22 - case '0.22': - case '1.0': + // no break, continue with updates for 0.22 and later + default: self::_exec( 'UPDATE ' . self::_sanitizeIdentifier('config') . ' SET value = ? WHERE id = ?', diff --git a/tst/ConfigurationTest.php b/tst/ConfigurationTest.php index b98425e..55d8288 100644 --- a/tst/ConfigurationTest.php +++ b/tst/ConfigurationTest.php @@ -157,4 +157,20 @@ class ConfigurationTest extends PHPUnit_Framework_TestCase 'configuration values get converted' ); } + + public function testRenameIniSample() + { + $iniSample = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini.sample'; + $phpSample = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.sample.php'; + + Helper::createIniFile(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini', $this->_options); + if (is_file(CONF)) { + chmod(CONF, 0600); + unlink(CONF); + } + rename($phpSample, $iniSample); + new Configuration; + $this->assertFileNotExists($iniSample, 'old sample file gets removed'); + $this->assertFileExists($phpSample, 'new sample file gets created'); + } } From 62f0b95377ae72986deef0aa994c9ee83638c3bd Mon Sep 17 00:00:00 2001 From: El RIDO Date: Wed, 4 Oct 2017 22:02:27 +0200 Subject: [PATCH 044/178] making StyleCI happy --- lib/Configuration.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Configuration.php b/lib/Configuration.php index 4b7d35c..36ef91a 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -108,16 +108,16 @@ class Configuration // don't overwrite already converted file if (!is_file($configFile)) { $iniUpgradeError = false; - $context = stream_context_create(); + $context = stream_context_create(); $iniHandle = fopen($configIni, 'r', 1, $context); - $written = file_put_contents($configFile, '; Date: Wed, 4 Oct 2017 22:06:39 +0200 Subject: [PATCH 045/178] removing dead code --- lib/Configuration.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/Configuration.php b/lib/Configuration.php index 36ef91a..b7590db 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -107,9 +107,7 @@ class Configuration if (is_readable($configIni)) { // don't overwrite already converted file if (!is_file($configFile)) { - $iniUpgradeError = false; - $context = stream_context_create(); - $iniHandle = fopen($configIni, 'r', 1, $context); + $iniHandle = fopen($configIni, 'r', false, stream_context_create()); $written = file_put_contents($configFile, '; Date: Sun, 8 Oct 2017 07:03:53 +0200 Subject: [PATCH 046/178] adding correct HTTP error to response, as per @rugk's recommentation --- cfg/conf.sample.php | 2 +- lib/Configuration.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cfg/conf.sample.php b/cfg/conf.sample.php index f52028c..4db8a33 100644 --- a/cfg/conf.sample.php +++ b/cfg/conf.sample.php @@ -1,4 +1,4 @@ -; Date: Sun, 8 Oct 2017 07:46:28 +0200 Subject: [PATCH 047/178] wrote a unit test to generate old style pastes and comments and check that the purge converts them to PHP files --- tst/Data/FilesystemTest.php | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tst/Data/FilesystemTest.php b/tst/Data/FilesystemTest.php index e7e6dc8..e5b8264 100644 --- a/tst/Data/FilesystemTest.php +++ b/tst/Data/FilesystemTest.php @@ -130,4 +130,46 @@ class FilesystemTest extends PHPUnit_Framework_TestCase $this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'unable to store broken comment'); $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does still not exist'); } + + public function testOldFilesGetConverted() + { + // generate 10 (default purge batch size) pastes in the old format + $paste = Helper::getPaste(); + $comment = Helper::getComment(); + $commentid = Helper::getCommentId(); + $ids = array(); + for ($i = 0, $max = 10; $i < $max; ++$i) { + // PHPs mt_rand only supports 32 bit or up 0x7fffffff on 64 bit systems to be precise :-/ + $dataid = str_pad(dechex(mt_rand(0, mt_getrandmax())), 8, '0', STR_PAD_LEFT) . + str_pad(dechex(mt_rand(0, mt_getrandmax())), 8, '0', STR_PAD_LEFT); + $storagedir = $this->_path . DIRECTORY_SEPARATOR . substr($dataid, 0, 2) . + DIRECTORY_SEPARATOR . substr($dataid, 2, 2) . DIRECTORY_SEPARATOR; + $ids[$dataid] = $storagedir; + + if (!is_dir($storagedir)) { + mkdir($storagedir, 0700, true); + } + file_put_contents($storagedir . $dataid, json_encode($paste)); + + $storagedir .= $dataid . '.discussion' . DIRECTORY_SEPARATOR; + if (!is_dir($storagedir)) { + mkdir($storagedir, 0700, true); + } + file_put_contents($storagedir . $dataid . '.' . $commentid . '.' . $dataid, json_encode($comment)); + } + // check that all 10 pastes were converted after the purge + $this->_model->purge(10); + foreach ($ids as $dataid => $storagedir) { + $this->assertFileExists($storagedir . $dataid . '.php', "paste $dataid exists in new format"); + $this->assertFileNotExists($storagedir . $dataid, "old format paste $dataid got removed"); + $this->assertTrue($this->_model->exists($dataid), "paste $dataid exists"); + $this->assertEquals($this->_model->read($dataid), $paste, "paste $dataid wasn't modified in the conversion"); + + $storagedir .= $dataid . '.discussion' . DIRECTORY_SEPARATOR; + $this->assertFileExists($storagedir . $dataid . '.' . $commentid . '.' . $dataid . '.php', "comment of $dataid exists in new format"); + $this->assertFileNotExists($storagedir . $dataid . '.' . $commentid . '.' . $dataid, "old format comment of $dataid got removed"); + $this->assertTrue($this->_model->existsComment($dataid, $dataid, $commentid), "comment in paste $dataid exists"); + $this->assertEquals($this->_model->readComment($dataid, $dataid, $commentid), $comment, "comment of $dataid wasn't modified in the conversion"); + } + } } From 4f06feef81293ba446e76138b3aedaa642e749ce Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sun, 8 Oct 2017 11:03:17 +0200 Subject: [PATCH 048/178] implemented JSON file conversion on purge and storage in PHP files for data leak protection --- lib/Configuration.php | 26 ++++++++---- lib/Data/Filesystem.php | 77 +++++++++++++++++++++++++++++------ lib/Persistence/DataStore.php | 9 +++- tst/Bootstrap.php | 10 ++++- tst/ConfigurationTest.php | 16 +++++--- tst/Data/FilesystemTest.php | 7 +++- tst/JsonApiTest.php | 35 ++++------------ tst/ModelTest.php | 7 +--- tst/PrivateBinTest.php | 72 ++------------------------------ tst/PrivateBinWithDbTest.php | 4 -- 10 files changed, 127 insertions(+), 136 deletions(-) diff --git a/lib/Configuration.php b/lib/Configuration.php index db00ecb..baee718 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -22,6 +22,13 @@ use PDO; */ class Configuration { + /** + * First line in INI file, to hide contents + * + * @const string + */ + const PROTECTION_LINE = ';exists($pasteid)) { return false; } - $paste = json_decode( - file_get_contents(self::_dataid2path($pasteid) . $pasteid) - ); + $paste = self::_decodeFile(self::_dataid2path($pasteid) . $pasteid . '.php'); if (property_exists($paste->meta, 'attachment')) { $paste->attachment = $paste->meta->attachment; unset($paste->meta->attachment); @@ -104,8 +102,8 @@ class Filesystem extends AbstractData $pastedir = self::_dataid2path($pasteid); if (is_dir($pastedir)) { // Delete the paste itself. - if (is_file($pastedir . $pasteid)) { - unlink($pastedir . $pasteid); + if (is_file($pastedir . $pasteid . '.php')) { + unlink($pastedir . $pasteid . '.php'); } // Delete discussion if it exists. @@ -133,7 +131,41 @@ class Filesystem extends AbstractData */ public function exists($pasteid) { - return is_file(self::_dataid2path($pasteid) . $pasteid); + $basePath = self::_dataid2path($pasteid) . $pasteid; + $pastePath = $basePath . '.php'; + // convert to PHP protected files if needed + if (is_readable($basePath)) { + $context = stream_context_create(); + // don't overwrite already converted file + if (!is_file($pastePath)) { + $handle = fopen($basePath, 'r', false, $context); + file_put_contents($pastePath, DataStore::PROTECTION_LINE . PHP_EOL); + file_put_contents($pastePath, $handle, FILE_APPEND); + fclose($handle); + } + unlink($basePath); + + // convert comments, too + $discdir = self::_dataid2discussionpath($pasteid); + if (is_dir($discdir)) { + $dir = dir($discdir); + while (false !== ($filename = $dir->read())) { + if (substr($filename, -4) !== '.php' && strlen($filename) >= 16) { + $commentFilename = $discdir . $filename . '.php'; + // don't overwrite already converted file + if (!is_file($commentFilename)) { + $handle = fopen($discdir . $filename, 'r', false, $context); + file_put_contents($commentFilename, DataStore::PROTECTION_LINE . PHP_EOL); + file_put_contents($commentFilename, $handle, FILE_APPEND); + fclose($handle); + } + unlink($discdir . $filename); + } + } + $dir->close(); + } + } + return is_readable($pastePath); } /** @@ -149,7 +181,7 @@ class Filesystem extends AbstractData public function createComment($pasteid, $parentid, $commentid, $comment) { $storagedir = self::_dataid2discussionpath($pasteid); - $file = $storagedir . $pasteid . '.' . $commentid . '.' . $parentid; + $file = $storagedir . $pasteid . '.' . $commentid . '.' . $parentid . '.php'; if (is_file($file)) { return false; } @@ -171,15 +203,14 @@ class Filesystem extends AbstractData $comments = array(); $discdir = self::_dataid2discussionpath($pasteid); if (is_dir($discdir)) { - // Delete all files in discussion directory $dir = dir($discdir); while (false !== ($filename = $dir->read())) { - // Filename is in the form pasteid.commentid.parentid: + // Filename is in the form pasteid.commentid.parentid.php: // - pasteid is the paste this reply belongs to. // - commentid is the comment identifier itself. // - parentid is the comment this comment replies to (It can be pasteid) if (is_file($discdir . $filename)) { - $comment = json_decode(file_get_contents($discdir . $filename)); + $comment = self::_decodeFile($discdir . $filename); $items = explode('.', $filename); // Add some meta information not contained in file. $comment->id = $items[1]; @@ -211,7 +242,7 @@ class Filesystem extends AbstractData { return is_file( self::_dataid2discussionpath($pasteid) . - $pasteid . '.' . $commentid . '.' . $parentid + $pasteid . '.' . $commentid . '.' . $parentid . '.php' ); } @@ -253,7 +284,14 @@ class Filesystem extends AbstractData continue; } $thirdLevel = array_filter( - scandir($path), + array_map( + function($filename) { + return strlen($filename) >= 20 ? + substr($filename, 0, -4) : + $filename; + }, + scandir($path) + ), 'PrivateBin\\Model\\Paste::isValidId' ); if (count($thirdLevel) == 0) { @@ -347,4 +385,17 @@ class Filesystem extends AbstractData { return (bool) preg_match('/^[a-f0-9]{2}$/', $element); } + + /** + * Decodes a paste or comment file. + * + * @access private + * @static + * @param string $file + * @return array + */ + private static function _decodeFile($file) + { + return json_decode(substr(file_get_contents($file), strlen(DataStore::PROTECTION_LINE . PHP_EOL))); + } } diff --git a/lib/Persistence/DataStore.php b/lib/Persistence/DataStore.php index 56dde1a..0c03f27 100644 --- a/lib/Persistence/DataStore.php +++ b/lib/Persistence/DataStore.php @@ -22,6 +22,13 @@ use PrivateBin\Json; */ class DataStore extends AbstractPersistence { + /** + * First line in JSON files, to hide contents + * + * @const string + */ + const PROTECTION_LINE = 'assertTrue(copy(CONF . '.bak', CONF), 'copy default configuration file'); $conf = new Configuration; $this->assertEquals($this->_options, $conf->get(), 'default configuration is correct'); } @@ -41,7 +43,9 @@ class ConfigurationTest extends PHPUnit_Framework_TestCase public function testHandleMissingConfigFile() { - @unlink(CONF); + if (is_file(CONF)) { + unlink(CONF); + } $conf = new Configuration; $this->assertEquals($this->_options, $conf->get(), 'returns correct defaults on missing file'); } @@ -161,16 +165,16 @@ class ConfigurationTest extends PHPUnit_Framework_TestCase public function testRenameIniSample() { $iniSample = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini.sample'; - $phpSample = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.sample.php'; Helper::createIniFile(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini', $this->_options); if (is_file(CONF)) { - chmod(CONF, 0600); unlink(CONF); } - rename($phpSample, $iniSample); + rename(CONF_SAMPLE, $iniSample); new Configuration; $this->assertFileNotExists($iniSample, 'old sample file gets removed'); - $this->assertFileExists($phpSample, 'new sample file gets created'); + $this->assertFileExists(CONF_SAMPLE, 'new sample file gets created'); + $this->assertFileExists(CONF, 'old configuration file gets converted'); + $this->assertFileNotExists(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini', 'old configuration file gets removed'); } } diff --git a/tst/Data/FilesystemTest.php b/tst/Data/FilesystemTest.php index e5b8264..8b04928 100644 --- a/tst/Data/FilesystemTest.php +++ b/tst/Data/FilesystemTest.php @@ -163,13 +163,16 @@ class FilesystemTest extends PHPUnit_Framework_TestCase $this->assertFileExists($storagedir . $dataid . '.php', "paste $dataid exists in new format"); $this->assertFileNotExists($storagedir . $dataid, "old format paste $dataid got removed"); $this->assertTrue($this->_model->exists($dataid), "paste $dataid exists"); - $this->assertEquals($this->_model->read($dataid), $paste, "paste $dataid wasn't modified in the conversion"); + $this->assertEquals($this->_model->read($dataid), json_decode(json_encode($paste)), "paste $dataid wasn't modified in the conversion"); $storagedir .= $dataid . '.discussion' . DIRECTORY_SEPARATOR; $this->assertFileExists($storagedir . $dataid . '.' . $commentid . '.' . $dataid . '.php', "comment of $dataid exists in new format"); $this->assertFileNotExists($storagedir . $dataid . '.' . $commentid . '.' . $dataid, "old format comment of $dataid got removed"); $this->assertTrue($this->_model->existsComment($dataid, $dataid, $commentid), "comment in paste $dataid exists"); - $this->assertEquals($this->_model->readComment($dataid, $dataid, $commentid), $comment, "comment of $dataid wasn't modified in the conversion"); + $comment = json_decode(json_encode($comment)); + $comment->id = $commentid; + $comment->parentid = $dataid; + $this->assertEquals($this->_model->readComments($dataid), array($comment->meta->postdate => $comment), "comment of $dataid wasn't modified in the conversion"); } } } diff --git a/tst/JsonApiTest.php b/tst/JsonApiTest.php index cd27cd8..8588aca 100644 --- a/tst/JsonApiTest.php +++ b/tst/JsonApiTest.php @@ -14,30 +14,17 @@ class JsonApiTest extends PHPUnit_Framework_TestCase public function setUp() { /* Setup Routine */ - Helper::confBackup(); $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data'; $this->_model = Filesystem::getInstance(array('dir' => $this->_path)); ServerSalt::setPath($this->_path); - $this->reset(); - } - public function tearDown() - { - /* Tear Down Routine */ - Helper::confRestore(); - Helper::rmDir($this->_path); - } - - public function reset() - { $_POST = array(); $_GET = array(); $_SERVER = array(); if ($this->_model->exists(Helper::getPasteId())) { $this->_model->delete(Helper::getPasteId()); } - Helper::confRestore(); - $options = parse_ini_file(CONF, true); + $options = parse_ini_file(CONF_SAMPLE, true); $options['purge']['dir'] = $this->_path; $options['traffic']['dir'] = $this->_path; $options['model_options']['dir'] = $this->_path; @@ -45,15 +32,21 @@ class JsonApiTest extends PHPUnit_Framework_TestCase Helper::createIniFile(CONF, $options); } + public function tearDown() + { + /* Tear Down Routine */ + unlink(CONF); + Helper::confRestore(); + Helper::rmDir($this->_path); + } + /** * @runInSeparateProcess */ public function testCreate() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getPaste(); $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest'; @@ -80,10 +73,8 @@ class JsonApiTest extends PHPUnit_Framework_TestCase */ public function testPut() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $paste = Helper::getPaste(); unset($paste['meta']); @@ -117,7 +108,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase */ public function testDelete() { - $this->reset(); $this->_model->create(Helper::getPasteId(), Helper::getPaste()); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data'); $paste = $this->_model->read(Helper::getPasteId()); @@ -144,7 +134,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase */ public function testDeleteWithPost() { - $this->reset(); $this->_model->create(Helper::getPasteId(), Helper::getPaste()); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data'); $paste = $this->_model->read(Helper::getPasteId()); @@ -168,7 +157,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase */ public function testRead() { - $this->reset(); $paste = Helper::getPasteWithAttachment(); $paste['meta']['attachment'] = $paste['attachment']; $paste['meta']['attachmentname'] = $paste['attachmentname']; @@ -200,7 +188,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase */ public function testJsonLdPaste() { - $this->reset(); $paste = Helper::getPasteWithAttachment(); $this->_model->create(Helper::getPasteId(), $paste); $_GET['jsonld'] = 'paste'; @@ -220,7 +207,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase */ public function testJsonLdComment() { - $this->reset(); $paste = Helper::getPasteWithAttachment(); $this->_model->create(Helper::getPasteId(), $paste); $_GET['jsonld'] = 'comment'; @@ -240,7 +226,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase */ public function testJsonLdPasteMeta() { - $this->reset(); $paste = Helper::getPasteWithAttachment(); $this->_model->create(Helper::getPasteId(), $paste); $_GET['jsonld'] = 'pastemeta'; @@ -260,7 +245,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase */ public function testJsonLdCommentMeta() { - $this->reset(); $paste = Helper::getPasteWithAttachment(); $this->_model->create(Helper::getPasteId(), $paste); $_GET['jsonld'] = 'commentmeta'; @@ -280,7 +264,6 @@ class JsonApiTest extends PHPUnit_Framework_TestCase */ public function testJsonLdInvalid() { - $this->reset(); $paste = Helper::getPasteWithAttachment(); $this->_model->create(Helper::getPasteId(), $paste); $_GET['jsonld'] = CONF; diff --git a/tst/ModelTest.php b/tst/ModelTest.php index 4d314f7..a41ed00 100644 --- a/tst/ModelTest.php +++ b/tst/ModelTest.php @@ -20,13 +20,12 @@ class ModelTest extends PHPUnit_Framework_TestCase public function setUp() { /* Setup Routine */ - Helper::confRestore(); $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data'; if (!is_dir($this->_path)) { mkdir($this->_path); } ServerSalt::setPath($this->_path); - $options = parse_ini_file(CONF, true); + $options = parse_ini_file(CONF_SAMPLE, true); $options['purge']['limit'] = 0; $options['model'] = array( 'class' => 'Database', @@ -47,6 +46,7 @@ class ModelTest extends PHPUnit_Framework_TestCase public function tearDown() { /* Tear Down Routine */ + unlink(CONF); Helper::confRestore(); Helper::rmDir($this->_path); } @@ -327,7 +327,6 @@ class ModelTest extends PHPUnit_Framework_TestCase 'pwd' => null, 'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION), ); - Helper::confBackup(); Helper::createIniFile(CONF, $options); $model = new Model(new Configuration); @@ -382,7 +381,6 @@ class ModelTest extends PHPUnit_Framework_TestCase 'pwd' => null, 'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION), ); - Helper::confBackup(); Helper::createIniFile(CONF, $options); $model = new Model(new Configuration); @@ -420,7 +418,6 @@ class ModelTest extends PHPUnit_Framework_TestCase 'pwd' => null, 'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION), ); - Helper::confBackup(); Helper::createIniFile(CONF, $options); $model = new Model(new Configuration); diff --git a/tst/PrivateBinTest.php b/tst/PrivateBinTest.php index 44df563..e1f3113 100644 --- a/tst/PrivateBinTest.php +++ b/tst/PrivateBinTest.php @@ -16,13 +16,13 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase /* Setup Routine */ $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data'; $this->_model = Filesystem::getInstance(array('dir' => $this->_path)); - ServerSalt::setPath($this->_path); $this->reset(); } public function tearDown() { /* Tear Down Routine */ + unlink(CONF); Helper::confRestore(); Helper::rmDir($this->_path); } @@ -35,13 +35,13 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase if ($this->_model->exists(Helper::getPasteId())) { $this->_model->delete(Helper::getPasteId()); } - Helper::confRestore(); - $options = parse_ini_file(CONF, true); + $options = parse_ini_file(CONF_SAMPLE, true); $options['purge']['dir'] = $this->_path; $options['traffic']['dir'] = $this->_path; $options['model_options']['dir'] = $this->_path; Helper::confBackup(); Helper::createIniFile(CONF, $options); + ServerSalt::setPath($this->_path); } /** @@ -49,7 +49,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testView() { - $this->reset(); ob_start(); new PrivateBin; $content = ob_get_contents(); @@ -71,10 +70,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testViewLanguageSelection() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['main']['languageselection'] = true; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_COOKIE['lang'] = 'de'; ob_start(); @@ -93,11 +90,9 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testViewForceLanguageDefault() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['main']['languageselection'] = false; $options['main']['languagedefault'] = 'fr'; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_COOKIE['lang'] = 'de'; ob_start(); @@ -117,10 +112,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase public function testViewUrlShortener() { $shortener = 'https://shortener.example.com/api?link='; - $this->reset(); $options = parse_ini_file(CONF, true); $options['main']['urlshortener'] = $shortener; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_COOKIE['lang'] = 'de'; ob_start(); @@ -139,7 +132,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testHtaccess() { - $this->reset(); $file = $this->_path . DIRECTORY_SEPARATOR . '.htaccess'; @unlink($file); @@ -160,8 +152,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testConf() { - $this->reset(); - Helper::confBackup(); file_put_contents(CONF, ''); new PrivateBin; } @@ -171,10 +161,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreate() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getPaste(); $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest'; @@ -200,10 +188,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateInvalidTimelimit() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getPaste(array('expire' => 25)); $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest'; @@ -230,11 +216,9 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateInvalidSize() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['main']['sizelimit'] = 10; $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getPaste(); $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest'; @@ -254,10 +238,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateProxyHeader() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['header'] = 'X_FORWARDED_FOR'; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getPaste(); $_SERVER['HTTP_X_FORWARDED_FOR'] = '::2'; @@ -284,10 +266,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateDuplicateId() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $this->_model->create(Helper::getPasteId(), Helper::getPaste()); $_POST = Helper::getPaste(); @@ -308,10 +288,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateValidExpire() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getPaste(); $_POST['expire'] = '5min'; @@ -341,10 +319,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateValidExpireWithDiscussion() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getPaste(); $_POST['expire'] = '5min'; @@ -375,10 +351,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateInvalidExpire() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getPaste(); $_POST['expire'] = 'foo'; @@ -405,10 +379,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateInvalidBurn() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getPaste(); $_POST['burnafterreading'] = 'neither 1 nor 0'; @@ -429,10 +401,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateInvalidOpenDiscussion() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getPaste(); $_POST['opendiscussion'] = 'neither 1 nor 0'; @@ -453,11 +423,9 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateAttachment() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; $options['main']['fileupload'] = true; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getPasteWithAttachment(); $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest'; @@ -491,11 +459,9 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateBrokenAttachmentUpload() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; $options['main']['fileupload'] = true; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getPasteWithAttachment(); unset($_POST['attachment']); @@ -517,7 +483,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateTooSoon() { - $this->reset(); $_POST = Helper::getPaste(); $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest'; $_SERVER['REQUEST_METHOD'] = 'POST'; @@ -540,10 +505,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateValidNick() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getPaste(); $_POST['nickname'] = Helper::getComment()['meta']['nickname']; @@ -570,10 +533,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateInvalidNick() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getCommentPost(); $_POST['pasteid'] = Helper::getPasteId(); @@ -597,10 +558,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateComment() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getCommentPost(); $_POST['pasteid'] = Helper::getPasteId(); @@ -623,10 +582,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateInvalidComment() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getCommentPost(); $_POST['pasteid'] = Helper::getPasteId(); @@ -649,10 +606,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateCommentDiscussionDisabled() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getCommentPost(); $_POST['pasteid'] = Helper::getPasteId(); @@ -676,10 +631,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateCommentInvalidPaste() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $_POST = Helper::getCommentPost(); $_POST['pasteid'] = Helper::getPasteId(); @@ -701,10 +654,8 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testCreateDuplicateComment() { - $this->reset(); $options = parse_ini_file(CONF, true); $options['traffic']['limit'] = 0; - Helper::confBackup(); Helper::createIniFile(CONF, $options); $this->_model->create(Helper::getPasteId(), Helper::getPaste()); $this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment()); @@ -729,7 +680,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testRead() { - $this->reset(); $this->_model->create(Helper::getPasteId(), Helper::getPaste()); $_SERVER['QUERY_STRING'] = Helper::getPasteId(); ob_start(); @@ -750,7 +700,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testReadInvalidId() { - $this->reset(); $_SERVER['QUERY_STRING'] = 'foo'; ob_start(); new PrivateBin; @@ -768,7 +717,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testReadNonexisting() { - $this->reset(); $_SERVER['QUERY_STRING'] = Helper::getPasteId(); ob_start(); new PrivateBin; @@ -786,7 +734,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testReadExpired() { - $this->reset(); $expiredPaste = Helper::getPaste(array('expire_date' => 1344803344)); $this->_model->create(Helper::getPasteId(), $expiredPaste); $_SERVER['QUERY_STRING'] = Helper::getPasteId(); @@ -806,7 +753,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testReadBurn() { - $this->reset(); $burnPaste = Helper::getPaste(array('burnafterreading' => true)); $this->_model->create(Helper::getPasteId(), $burnPaste); $_SERVER['QUERY_STRING'] = Helper::getPasteId(); @@ -860,7 +806,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testReadJson() { - $this->reset(); $paste = Helper::getPaste(); $this->_model->create(Helper::getPasteId(), $paste); $_SERVER['QUERY_STRING'] = Helper::getPasteId(); @@ -886,7 +831,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testReadInvalidJson() { - $this->reset(); $_SERVER['QUERY_STRING'] = Helper::getPasteId(); $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest'; ob_start(); @@ -902,7 +846,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testReadOldSyntax() { - $this->reset(); $oldPaste = Helper::getPaste(); $meta = array( 'syntaxcoloring' => true, @@ -931,7 +874,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testReadOldFormat() { - $this->reset(); $oldPaste = Helper::getPaste(); unset($oldPaste['meta']['formatter']); $this->_model->create(Helper::getPasteId(), $oldPaste); @@ -956,7 +898,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testDelete() { - $this->reset(); $this->_model->create(Helper::getPasteId(), Helper::getPaste()); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data'); $paste = $this->_model->read(Helper::getPasteId()); @@ -979,7 +920,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testDeleteInvalidId() { - $this->reset(); $this->_model->create(Helper::getPasteId(), Helper::getPaste()); $_GET['pasteid'] = 'foo'; $_GET['deletetoken'] = 'bar'; @@ -1000,7 +940,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testDeleteInexistantId() { - $this->reset(); $_GET['pasteid'] = Helper::getPasteId(); $_GET['deletetoken'] = 'bar'; ob_start(); @@ -1019,7 +958,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testDeleteInvalidToken() { - $this->reset(); $this->_model->create(Helper::getPasteId(), Helper::getPaste()); $_GET['pasteid'] = Helper::getPasteId(); $_GET['deletetoken'] = 'bar'; @@ -1040,7 +978,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testDeleteBurnAfterReading() { - $this->reset(); $burnPaste = Helper::getPaste(array('burnafterreading' => true)); $this->_model->create(Helper::getPasteId(), $burnPaste); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data'); @@ -1062,7 +999,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testDeleteInvalidBurnAfterReading() { - $this->reset(); $this->_model->create(Helper::getPasteId(), Helper::getPaste()); $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data'); $_POST['deletetoken'] = 'burnafterreading'; @@ -1083,7 +1019,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testDeleteExpired() { - $this->reset(); $expiredPaste = Helper::getPaste(array('expire_date' => 1000)); $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not exist before being created'); $this->_model->create(Helper::getPasteId(), $expiredPaste); @@ -1107,7 +1042,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testDeleteMissingPerPasteSalt() { - $this->reset(); $paste = Helper::getPaste(); unset($paste['meta']['salt']); $this->_model->create(Helper::getPasteId(), $paste); diff --git a/tst/PrivateBinWithDbTest.php b/tst/PrivateBinWithDbTest.php index 2ed3846..a6ec2e0 100644 --- a/tst/PrivateBinWithDbTest.php +++ b/tst/PrivateBinWithDbTest.php @@ -23,7 +23,6 @@ class PrivateBinWithDbTest extends PrivateBinTest if (!is_dir($this->_path)) { mkdir($this->_path); } - ServerSalt::setPath($this->_path); $this->_options['dsn'] = 'sqlite:' . $this->_path . DIRECTORY_SEPARATOR . 'tst.sq3'; $this->_model = Database::getInstance($this->_options); $this->reset(); @@ -37,10 +36,7 @@ class PrivateBinWithDbTest extends PrivateBinTest $options['model'] = array( 'class' => 'Database', ); - $options['purge']['dir'] = $this->_path; - $options['traffic']['dir'] = $this->_path; $options['model_options'] = $this->_options; - Helper::confBackup(); Helper::createIniFile(CONF, $options); } } From 9f26894b2e7a6416b26f05e049f13a5b6cc51d2e Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sun, 8 Oct 2017 11:31:41 +0200 Subject: [PATCH 049/178] PHP < 5.6 compatibility and StyleCI recommendations --- lib/Configuration.php | 6 +++--- lib/Data/Filesystem.php | 19 +++---------------- lib/Persistence/DataStore.php | 13 +++++++++++++ tst/Data/FilesystemTest.php | 8 ++++---- tst/PrivateBinTest.php | 2 +- tst/PrivateBinWithDbTest.php | 1 - 6 files changed, 24 insertions(+), 25 deletions(-) diff --git a/lib/Configuration.php b/lib/Configuration.php index baee718..5b8813d 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -27,7 +27,7 @@ class Configuration * * @const string */ - const PROTECTION_LINE = ';exists($pasteid)) { return false; } - $paste = self::_decodeFile(self::_dataid2path($pasteid) . $pasteid . '.php'); + $paste = DataStore::get(self::_dataid2path($pasteid) . $pasteid . '.php'); if (property_exists($paste->meta, 'attachment')) { $paste->attachment = $paste->meta->attachment; unset($paste->meta->attachment); @@ -210,7 +210,7 @@ class Filesystem extends AbstractData // - commentid is the comment identifier itself. // - parentid is the comment this comment replies to (It can be pasteid) if (is_file($discdir . $filename)) { - $comment = self::_decodeFile($discdir . $filename); + $comment = DataStore::get($discdir . $filename); $items = explode('.', $filename); // Add some meta information not contained in file. $comment->id = $items[1]; @@ -285,7 +285,7 @@ class Filesystem extends AbstractData } $thirdLevel = array_filter( array_map( - function($filename) { + function ($filename) { return strlen($filename) >= 20 ? substr($filename, 0, -4) : $filename; @@ -385,17 +385,4 @@ class Filesystem extends AbstractData { return (bool) preg_match('/^[a-f0-9]{2}$/', $element); } - - /** - * Decodes a paste or comment file. - * - * @access private - * @static - * @param string $file - * @return array - */ - private static function _decodeFile($file) - { - return json_decode(substr(file_get_contents($file), strlen(DataStore::PROTECTION_LINE . PHP_EOL))); - } } diff --git a/lib/Persistence/DataStore.php b/lib/Persistence/DataStore.php index 0c03f27..c5f14ff 100644 --- a/lib/Persistence/DataStore.php +++ b/lib/Persistence/DataStore.php @@ -51,4 +51,17 @@ class DataStore extends AbstractPersistence return false; } } + + /** + * get the data + * + * @access public + * @static + * @param string $filename + * @return array $data + */ + public static function get($filename) + { + return json_decode(substr(file_get_contents($filename), strlen(self::PROTECTION_LINE . PHP_EOL))); + } } diff --git a/tst/Data/FilesystemTest.php b/tst/Data/FilesystemTest.php index 8b04928..0a122f0 100644 --- a/tst/Data/FilesystemTest.php +++ b/tst/Data/FilesystemTest.php @@ -134,15 +134,15 @@ class FilesystemTest extends PHPUnit_Framework_TestCase public function testOldFilesGetConverted() { // generate 10 (default purge batch size) pastes in the old format - $paste = Helper::getPaste(); - $comment = Helper::getComment(); + $paste = Helper::getPaste(); + $comment = Helper::getComment(); $commentid = Helper::getCommentId(); - $ids = array(); + $ids = array(); for ($i = 0, $max = 10; $i < $max; ++$i) { // PHPs mt_rand only supports 32 bit or up 0x7fffffff on 64 bit systems to be precise :-/ $dataid = str_pad(dechex(mt_rand(0, mt_getrandmax())), 8, '0', STR_PAD_LEFT) . str_pad(dechex(mt_rand(0, mt_getrandmax())), 8, '0', STR_PAD_LEFT); - $storagedir = $this->_path . DIRECTORY_SEPARATOR . substr($dataid, 0, 2) . + $storagedir = $this->_path . DIRECTORY_SEPARATOR . substr($dataid, 0, 2) . DIRECTORY_SEPARATOR . substr($dataid, 2, 2) . DIRECTORY_SEPARATOR; $ids[$dataid] = $storagedir; diff --git a/tst/PrivateBinTest.php b/tst/PrivateBinTest.php index e1f3113..5c5e145 100644 --- a/tst/PrivateBinTest.php +++ b/tst/PrivateBinTest.php @@ -111,7 +111,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase */ public function testViewUrlShortener() { - $shortener = 'https://shortener.example.com/api?link='; + $shortener = 'https://shortener.example.com/api?link='; $options = parse_ini_file(CONF, true); $options['main']['urlshortener'] = $shortener; Helper::createIniFile(CONF, $options); diff --git a/tst/PrivateBinWithDbTest.php b/tst/PrivateBinWithDbTest.php index a6ec2e0..a438d4c 100644 --- a/tst/PrivateBinWithDbTest.php +++ b/tst/PrivateBinWithDbTest.php @@ -1,7 +1,6 @@ Date: Sun, 8 Oct 2017 12:27:37 +0200 Subject: [PATCH 050/178] adapting configuration test generator to new INI model and point release support --- tst/ConfigurationTestGenerator.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tst/ConfigurationTestGenerator.php b/tst/ConfigurationTestGenerator.php index a011bed..aec2a73 100755 --- a/tst/ConfigurationTestGenerator.php +++ b/tst/ConfigurationTestGenerator.php @@ -159,7 +159,7 @@ new ConfigurationTestGenerator(array( array( 'type' => 'RegExp', 'args' => array( - '#]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d+\.\d+"[^>]*/>#', + '#]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#', '$content', 'outputs "page" stylesheet correctly', ), @@ -179,7 +179,7 @@ new ConfigurationTestGenerator(array( array( 'type' => 'NotRegExp', 'args' => array( - '#]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d+\.\d+"[^>]*/>#', + '#]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#', '$content', 'removes "page" stylesheet correctly', ), @@ -344,7 +344,7 @@ class ConfigurationTestGenerator */ private function _writeConfigurationTest() { - $defaultOptions = parse_ini_file(CONF, true); + $defaultOptions = parse_ini_file(CONF_SAMPLE, true); $code = $this->_getHeader(); foreach ($this->_configurations as $key => $conf) { $fullOptions = array_replace_recursive($defaultOptions, $conf['options']); @@ -425,7 +425,7 @@ class ConfigurationCombinationsTest extends PHPUnit_Framework_TestCase { /* Setup Routine */ Helper::confBackup(); - $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data'; + $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data'; $this->_model = Filesystem::getInstance(array('dir' => $this->_path)); ServerSalt::setPath($this->_path); TrafficLimiter::setPath($this->_path); @@ -435,9 +435,10 @@ class ConfigurationCombinationsTest extends PHPUnit_Framework_TestCase public function tearDown() { /* Tear Down Routine */ + unlink(CONF); Helper::confRestore(); Helper::rmDir($this->_path); -} + } public function reset($configuration = array()) { From 81ac232710a9621a27649e6893c1f33e13aed391 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sun, 8 Oct 2017 17:29:07 +0200 Subject: [PATCH 051/178] increasing timeouts for travisCI, that seems to have gotten slower --- js/test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/js/test.js b/js/test.js index 3f24a2e..807d29d 100644 --- a/js/test.js +++ b/js/test.js @@ -78,6 +78,7 @@ describe('Helper', function () { // this test is not yet meaningful using jsdom, as it does not contain getSelection support. // TODO: This needs to be tested using a browser. describe('selectText', function () { + this.timeout(30000); jsc.property( 'selection contains content of given ID', jsc.nearray(jsc.nearray(jsc.elements(alnumString))), @@ -271,6 +272,7 @@ describe('Helper', function () { }); describe('getCookie', function () { + this.timeout(30000); jsc.property( 'returns the requested cookie', 'nearray asciinestring', @@ -299,6 +301,7 @@ describe('Helper', function () { }); describe('baseUri', function () { + this.timeout(30000); before(function () { $.PrivateBin.Helper.reset(); }); @@ -413,6 +416,7 @@ describe('I18n', function () { // loading of JSON via AJAX needs to be tested in the browser, this just mocks it // TODO: This needs to be tested using a browser. describe('loadTranslations', function () { + this.timeout(30000); before(function () { $.PrivateBin.I18n.reset(); }); @@ -596,6 +600,7 @@ describe('Model', function () { }); describe('getPasteId', function () { + this.timeout(30000); before(function () { $.PrivateBin.Model.reset(); cleanup(); @@ -644,6 +649,7 @@ describe('Model', function () { }); describe('getPasteKey', function () { + this.timeout(30000); jsc.property( 'returns the fragment of the URL', jsc.nearray(jsc.elements(a2zString)), From a5d5f6066a531f631a4a9d00396abe5f403fc47e Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sun, 8 Oct 2017 19:16:09 +0200 Subject: [PATCH 052/178] refactoring as recommended by Scrutinizer --- lib/Configuration.php | 29 ++++------------------------- lib/Data/Filesystem.php | 21 +++------------------ lib/Persistence/DataStore.php | 26 ++++++++++++++++++++++++-- tst/PrivateBinTest.php | 1 - 4 files changed, 31 insertions(+), 46 deletions(-) diff --git a/lib/Configuration.php b/lib/Configuration.php index 5b8813d..571ef56 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -12,6 +12,7 @@ namespace PrivateBin; +use PrivateBin\Persistence\DataStore; use Exception; use PDO; @@ -22,13 +23,6 @@ use PDO; */ class Configuration { - /** - * First line in INI file, to hide contents - * - * @const string - */ - const PROTECTION_LINE = ';read())) { if (substr($filename, -4) !== '.php' && strlen($filename) >= 16) { $commentFilename = $discdir . $filename . '.php'; - // don't overwrite already converted file - if (!is_file($commentFilename)) { - $handle = fopen($discdir . $filename, 'r', false, $context); - file_put_contents($commentFilename, DataStore::PROTECTION_LINE . PHP_EOL); - file_put_contents($commentFilename, $handle, FILE_APPEND); - fclose($handle); - } - unlink($discdir . $filename); + DataStore::prependRename($discdir . $filename, $commentFilename); } } $dir->close(); diff --git a/lib/Persistence/DataStore.php b/lib/Persistence/DataStore.php index c5f14ff..d14453a 100644 --- a/lib/Persistence/DataStore.php +++ b/lib/Persistence/DataStore.php @@ -23,7 +23,7 @@ use PrivateBin\Json; class DataStore extends AbstractPersistence { /** - * First line in JSON files, to hide contents + * first line in file, to protect its contents * * @const string */ @@ -58,10 +58,32 @@ class DataStore extends AbstractPersistence * @access public * @static * @param string $filename - * @return array $data + * @return stdClass|false $data */ public static function get($filename) { return json_decode(substr(file_get_contents($filename), strlen(self::PROTECTION_LINE . PHP_EOL))); } + + /** + * rename a file, prepending the protection line at the beginning + * + * @access public + * @static + * @param string $srcFile + * @param string $destFile + * @param string $prefix (optional) + * @return void + */ + public static function prependRename($srcFile, $destFile, $prefix = '') + { + // don't overwrite already converted file + if (!is_readable($destFile)) { + $handle = fopen($srcFile, 'r', false, stream_context_create()); + file_put_contents($destFile, $prefix . DataStore::PROTECTION_LINE . PHP_EOL); + file_put_contents($destFile, $handle, FILE_APPEND); + fclose($handle); + } + unlink($srcFile); + } } diff --git a/tst/PrivateBinTest.php b/tst/PrivateBinTest.php index 5c5e145..72ee679 100644 --- a/tst/PrivateBinTest.php +++ b/tst/PrivateBinTest.php @@ -39,7 +39,6 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase $options['purge']['dir'] = $this->_path; $options['traffic']['dir'] = $this->_path; $options['model_options']['dir'] = $this->_path; - Helper::confBackup(); Helper::createIniFile(CONF, $options); ServerSalt::setPath($this->_path); } From 502e96c129c2004aa30f81339797bd343c4af677 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sun, 8 Oct 2017 19:23:33 +0200 Subject: [PATCH 053/178] StyleCI recommendations --- lib/Configuration.php | 2 +- lib/Persistence/DataStore.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Configuration.php b/lib/Configuration.php index 571ef56..274743e 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -12,9 +12,9 @@ namespace PrivateBin; -use PrivateBin\Persistence\DataStore; use Exception; use PDO; +use PrivateBin\Persistence\DataStore; /** * Configuration diff --git a/lib/Persistence/DataStore.php b/lib/Persistence/DataStore.php index d14453a..7ab4af5 100644 --- a/lib/Persistence/DataStore.php +++ b/lib/Persistence/DataStore.php @@ -80,7 +80,7 @@ class DataStore extends AbstractPersistence // don't overwrite already converted file if (!is_readable($destFile)) { $handle = fopen($srcFile, 'r', false, stream_context_create()); - file_put_contents($destFile, $prefix . DataStore::PROTECTION_LINE . PHP_EOL); + file_put_contents($destFile, $prefix . self::PROTECTION_LINE . PHP_EOL); file_put_contents($destFile, $handle, FILE_APPEND); fclose($handle); } From 6dbb098d7aca1783e5117aefb81712e429009c89 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sun, 22 Oct 2017 09:56:44 +0200 Subject: [PATCH 054/178] had to introduce a mock function to test the historyChange state --- js/privatebin.js | 15 ++++++++++++++- js/test.js | 9 ++++----- tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index 9e626e9..3d8ddd1 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -866,7 +866,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { { var currentLocation = Helper.baseUri(); if (event.originalEvent.state === null && // no state object passed - event.originalEvent.target.location.href === currentLocation && // target location is home page + event.target.location.href === currentLocation && // target location is home page window.location.href === currentLocation // and we are not already on the home page ) { // redirect to home page @@ -958,6 +958,19 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { }); } + /** + * trigger a history (pop) state change + * + * used to test the UiHelper.historyChange private function + * + * @name UiHelper.mockHistoryChange + * @function + */ + me.mockHistoryChange = function() + { + historyChange($.Event('popstate', {originalEvent: new PopStateEvent('popstate', {state: null}), target: window})); + } + /** * initialize * diff --git a/js/test.js b/js/test.js index bedcd4a..66752db 100644 --- a/js/test.js +++ b/js/test.js @@ -2,7 +2,6 @@ var jsc = require('jsverify'), jsdom = require('jsdom-global'), cleanup = jsdom(), - EventEmitter = require('events'), a2zString = ['a','b','c','d','e','f','g','h','i','j','k','l','m', 'n','o','p','q','r','s','t','u','v','w','x','y','z'], @@ -824,6 +823,8 @@ describe('UiHelper', function () { $.PrivateBin.Helper.reset(); }); + // TODO: As per https://github.com/tmpvar/jsdom/issues/1565 there is no navigation support in jsdom, yet. + // for now we use a mock function to trigger the event jsc.property( 'returns the URL without query & fragment', jsc.elements(schemas), @@ -832,11 +833,9 @@ describe('UiHelper', function () { 'string', function (schema, address, query, fragment) { var expected = schema + '://' + address.join('') + '/', - clean = jsdom('', {url: expected + '?' + query.join('') + '#' + fragment}), - emitter = new EventEmitter(); + clean = jsdom('', {url: expected + '?' + query.join('') + '#' + fragment}); - $.PrivateBin.UiHelper.init(); - emitter.emit('popstate'); + $.PrivateBin.UiHelper.mockHistoryChange(); var result = window.location.href; clean(); console.log(expected, result); diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index c3e1ba4..b6e7560 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -69,7 +69,7 @@ if ($MARKDOWN): - + diff --git a/tpl/page.php b/tpl/page.php index 81d7c1a..d774d05 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -47,7 +47,7 @@ if ($MARKDOWN): - + From 414693fa90d4326aff1ea4a5ed9ddcfd26ae909e Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sun, 22 Oct 2017 10:39:18 +0200 Subject: [PATCH 055/178] testing both cases of the logic required for #167 --- .gitattributes | 2 -- js/privatebin.js | 8 ++++++-- js/test.js | 30 ++++++++++++++++++++++-------- tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/.gitattributes b/.gitattributes index daef8b1..3c39546 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,8 +2,6 @@ doc/ export-ignore tst/ export-ignore js/.istanbul.yml export-ignore js/test.js export-ignore -js/mocha-3.2.0.js export-ignore -css/mocha-3.2.0.css export-ignore .codeclimate.yml export-ignore .csslintrc export-ignore .dockerignore export-ignore diff --git a/js/privatebin.js b/js/privatebin.js index 3d8ddd1..3db3fae 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -965,10 +965,14 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { * * @name UiHelper.mockHistoryChange * @function + * @param {string} state (optional) state to mock */ - me.mockHistoryChange = function() + me.mockHistoryChange = function(state) { - historyChange($.Event('popstate', {originalEvent: new PopStateEvent('popstate', {state: null}), target: window})); + if (typeof state === 'undefined') { + state = null; + } + historyChange($.Event('popstate', {originalEvent: new PopStateEvent('popstate', {state: state}), target: window})); } /** diff --git a/js/test.js b/js/test.js index 66752db..044c6c6 100644 --- a/js/test.js +++ b/js/test.js @@ -818,27 +818,41 @@ describe('Model', function () { }); describe('UiHelper', function () { + // TODO: As per https://github.com/tmpvar/jsdom/issues/1565 there is no navigation support in jsdom, yet. + // for now we use a mock function to trigger the event describe('historyChange', function () { before(function () { $.PrivateBin.Helper.reset(); }); - // TODO: As per https://github.com/tmpvar/jsdom/issues/1565 there is no navigation support in jsdom, yet. - // for now we use a mock function to trigger the event jsc.property( - 'returns the URL without query & fragment', + 'redirects to home, when the state is null', jsc.elements(schemas), jsc.nearray(jsc.elements(a2zString)), - jsc.array(jsc.elements(queryString)), - 'string', - function (schema, address, query, fragment) { + function (schema, address) { var expected = schema + '://' + address.join('') + '/', - clean = jsdom('', {url: expected + '?' + query.join('') + '#' + fragment}); + clean = jsdom('', {url: expected}); $.PrivateBin.UiHelper.mockHistoryChange(); var result = window.location.href; clean(); - console.log(expected, result); + return expected === result; + } + ); + + jsc.property( + 'does not redirect to home, when a new paste is created', + jsc.elements(schemas), + jsc.nearray(jsc.elements(a2zString)), + jsc.array(jsc.elements(queryString)), + jsc.nearray(jsc.elements(base64String)), + function (schema, address, query, fragment) { + var expected = schema + '://' + address.join('') + '/' + '?' + query.join('') + '#' + fragment.join(''), + clean = jsdom('', {url: expected}); + + $.PrivateBin.UiHelper.mockHistoryChange([{type: 'newpaste'}, '', expected]); + var result = window.location.href; + clean(); return expected === result; } ); diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index b6e7560..4fbd6c0 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -69,7 +69,7 @@ if ($MARKDOWN): - + diff --git a/tpl/page.php b/tpl/page.php index d774d05..2fa90ce 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -47,7 +47,7 @@ if ($MARKDOWN): - + From 4cb21350a09be5fc2df91a5a3ae6f49ea80a1c81 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sun, 22 Oct 2017 10:45:41 +0200 Subject: [PATCH 056/178] TravisCI can be a bit slow (locally this test takes 386ms) --- js/test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/test.js b/js/test.js index 044c6c6..dde1874 100644 --- a/js/test.js +++ b/js/test.js @@ -821,6 +821,7 @@ describe('UiHelper', function () { // TODO: As per https://github.com/tmpvar/jsdom/issues/1565 there is no navigation support in jsdom, yet. // for now we use a mock function to trigger the event describe('historyChange', function () { + this.timeout(30000); before(function () { $.PrivateBin.Helper.reset(); }); From cbcc26ec37964478bd765858c69210f9af894810 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sun, 22 Oct 2017 10:55:28 +0200 Subject: [PATCH 057/178] fixing false positive with RNG state 0bc96fe3b8d170254a --- js/test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/js/test.js b/js/test.js index dde1874..6ac4210 100644 --- a/js/test.js +++ b/js/test.js @@ -802,6 +802,12 @@ describe('Model', function () { id = id.join(''); element = element.join(''); value = value.join('').trim(); + + //
tags can't contain strings, so test with a

instead + if (element == 'br') { + element = 'p'; + } + $('body').html( '

<' + element + ' id="' + id + 'template">' + value + '
' From 4410ddcd840388707ebfd89cff4abd4486cd519a Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sun, 22 Oct 2017 13:39:23 +0200 Subject: [PATCH 058/178] adding tests for UiHelper.reloadHome, making UiHelper unit testable and handling JSVerify RNG states 846932d5afb10ce748 & 012c1f9483adb6e750 --- js/privatebin.js | 6 ++---- js/test.js | 46 ++++++++++++++++++++++++++++++++++++++++++++-- tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index 3db3fae..74db28c 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -845,11 +845,9 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { * everything directly UI-related, which fits nowhere else * * @name UiHelper - * @param {object} window - * @param {object} document * @class */ - var UiHelper = (function (window, document) { + var UiHelper = (function () { var me = {}; /** @@ -990,7 +988,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { } return me; - })(window, document); + })(); /** * Alert/error manager diff --git a/js/test.js b/js/test.js index 6ac4210..e14cdde 100644 --- a/js/test.js +++ b/js/test.js @@ -803,8 +803,8 @@ describe('Model', function () { element = element.join(''); value = value.join('').trim(); - //
tags can't contain strings, so test with a

instead - if (element == 'br') { + //
tags can't contain strings, table tags can't be alone, so test with a

instead + if (['br', 'tr', 'td', 'th'].indexOf(element) >= 0) { element = 'p'; } @@ -840,7 +840,13 @@ describe('UiHelper', function () { var expected = schema + '://' + address.join('') + '/', clean = jsdom('', {url: expected}); + // make window.location.href writable + Object.defineProperty(window.location, 'href', { + writable: true, + value: window.location.href + }); $.PrivateBin.UiHelper.mockHistoryChange(); + $.PrivateBin.Helper.reset(); var result = window.location.href; clean(); return expected === result; @@ -857,7 +863,43 @@ describe('UiHelper', function () { var expected = schema + '://' + address.join('') + '/' + '?' + query.join('') + '#' + fragment.join(''), clean = jsdom('', {url: expected}); + // make window.location.href writable + Object.defineProperty(window.location, 'href', { + writable: true, + value: window.location.href + }); $.PrivateBin.UiHelper.mockHistoryChange([{type: 'newpaste'}, '', expected]); + $.PrivateBin.Helper.reset(); + var result = window.location.href; + clean(); + return expected === result; + } + ); + }); + + describe('reloadHome', function () { + this.timeout(30000); + before(function () { + $.PrivateBin.Helper.reset(); + }); + + jsc.property( + 'redirects to home', + jsc.elements(schemas), + jsc.nearray(jsc.elements(a2zString)), + jsc.array(jsc.elements(queryString)), + jsc.nearray(jsc.elements(base64String)), + function (schema, address, query, fragment) { + var expected = schema + '://' + address.join('') + '/', + clean = jsdom('', {url: expected + '?' + query.join('') + '#' + fragment.join('')}); + + // make window.location.href writable + Object.defineProperty(window.location, 'href', { + writable: true, + value: window.location.href + }); + $.PrivateBin.UiHelper.reloadHome(); + $.PrivateBin.Helper.reset(); var result = window.location.href; clean(); return expected === result; diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index 4fbd6c0..609ccb7 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -69,7 +69,7 @@ if ($MARKDOWN): - + diff --git a/tpl/page.php b/tpl/page.php index 2fa90ce..8b8fcad 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -47,7 +47,7 @@ if ($MARKDOWN): - + From ef6b6816b0fc576e1aa43b91cfb8c4cd3f2feef3 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sun, 22 Oct 2017 16:26:41 +0200 Subject: [PATCH 059/178] implemented test, but again not supported yet by jsdom --- js/test.js | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/js/test.js b/js/test.js index e14cdde..50fe2ed 100644 --- a/js/test.js +++ b/js/test.js @@ -860,7 +860,8 @@ describe('UiHelper', function () { jsc.array(jsc.elements(queryString)), jsc.nearray(jsc.elements(base64String)), function (schema, address, query, fragment) { - var expected = schema + '://' + address.join('') + '/' + '?' + query.join('') + '#' + fragment.join(''), + var expected = schema + '://' + address.join('') + '/' + '?' + + query.join('') + '#' + fragment.join(''), clean = jsdom('', {url: expected}); // make window.location.href writable @@ -868,7 +869,9 @@ describe('UiHelper', function () { writable: true, value: window.location.href }); - $.PrivateBin.UiHelper.mockHistoryChange([{type: 'newpaste'}, '', expected]); + $.PrivateBin.UiHelper.mockHistoryChange([ + {type: 'newpaste'}, '', expected + ]); $.PrivateBin.Helper.reset(); var result = window.location.href; clean(); @@ -891,7 +894,9 @@ describe('UiHelper', function () { jsc.nearray(jsc.elements(base64String)), function (schema, address, query, fragment) { var expected = schema + '://' + address.join('') + '/', - clean = jsdom('', {url: expected + '?' + query.join('') + '#' + fragment.join('')}); + clean = jsdom('', { + url: expected + '?' + query.join('') + '#' + fragment.join('') + }); // make window.location.href writable Object.defineProperty(window.location, 'href', { @@ -906,5 +911,29 @@ describe('UiHelper', function () { } ); }); + + describe('isVisible', function () { + before(function () { + $.PrivateBin.Helper.reset(); + }); + + jsc.property( + 'detect visible elements', + jsc.nearray(jsc.elements(alnumString)), + jsc.nearray(jsc.elements(a2zString)), + function (id, element) { + id = id.join(''); + element = element.join(''); + var clean = jsdom( + '<' + element + ' id="' + id + '">' + ); + // TODO As per https://github.com/tmpvar/jsdom/issues/1048 there is no layout support in jsdom, yet. + // remove the "true || " below, once it is supported or a workaround is found + var result = true || $.PrivateBin.UiHelper.isVisible($('#' + id)); + clean(); + return result; + } + ); + }); }); From d75cea856ae458acb3297362ca319d1c9c9a6420 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Mon, 23 Oct 2017 05:34:55 +0200 Subject: [PATCH 060/178] concluding UiHelper tests that are possible in headless jsdom at this time --- js/test.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/js/test.js b/js/test.js index 50fe2ed..6a67972 100644 --- a/js/test.js +++ b/js/test.js @@ -913,6 +913,9 @@ describe('UiHelper', function () { }); describe('isVisible', function () { + // TODO As per https://github.com/tmpvar/jsdom/issues/1048 there is no layout support in jsdom, yet. + // once it is supported or a workaround is found, uncomment the section below + /* before(function () { $.PrivateBin.Helper.reset(); }); @@ -927,13 +930,16 @@ describe('UiHelper', function () { var clean = jsdom( '<' + element + ' id="' + id + '">' ); - // TODO As per https://github.com/tmpvar/jsdom/issues/1048 there is no layout support in jsdom, yet. - // remove the "true || " below, once it is supported or a workaround is found - var result = true || $.PrivateBin.UiHelper.isVisible($('#' + id)); + var result = $.PrivateBin.UiHelper.isVisible($('#' + id)); clean(); return result; } ); + */ + }); + + describe('scrollTo', function () { + // TODO Did not find a way to test that, see isVisible test above }); }); From 9c6aec86c42bdd248c21088014acd72e5d665e1a Mon Sep 17 00:00:00 2001 From: El RIDO Date: Mon, 23 Oct 2017 21:33:07 +0200 Subject: [PATCH 061/178] making Alert class resetable and adding first tests for it --- js/privatebin.js | 14 ++++---- js/test.js | 90 +++++++++++++++++++++++++++++++++++++++++++++++ tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 4 files changed, 100 insertions(+), 8 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index 74db28c..f818b98 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -1004,12 +1004,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { $statusMessage, $remainingTime; - var currentIcon = [ - 'glyphicon-time', // loading icon - 'glyphicon-info-sign', // status icon - '', // resevered for warning, not used yet - 'glyphicon-alert' // error icon - ]; + var currentIcon; var alertType = [ 'loading', // not in bootstrap, but using a good value here @@ -1253,6 +1248,13 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { $loadingIndicator = $('#loadingindicator'); $statusMessage = $('#status'); $remainingTime = $('#remainingtime'); + + currentIcon = [ + 'glyphicon-time', // loading icon + 'glyphicon-info-sign', // status icon + '', // reserved for warning, not used yet + 'glyphicon-alert' // error icon + ]; } return me; diff --git a/js/test.js b/js/test.js index 6a67972..63b6ba4 100644 --- a/js/test.js +++ b/js/test.js @@ -943,3 +943,93 @@ describe('UiHelper', function () { }); }); +describe('Alert', function () { + describe('showStatus', function () { + before(function () { + cleanup(); + }); + + jsc.property( + 'shows a status message', + jsc.array(jsc.elements(alnumString)), + jsc.array(jsc.elements(alnumString)), + function (icon, message) { + icon = icon.join(''); + message = message.join(''); + var expected = '

'; + $('body').html( + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showStatus(message, icon); + var result = $('body').html(); + return expected === result; + } + ); + }); + + describe('showError', function () { + before(function () { + cleanup(); + }); + + jsc.property( + 'shows an error message', + jsc.array(jsc.elements(alnumString)), + jsc.array(jsc.elements(alnumString)), + function (icon, message) { + icon = icon.join(''); + message = message.join(''); + var expected = ''; + $('body').html( + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showError(message, icon); + var result = $('body').html(); + return expected === result; + } + ); + }); + + describe('showRemaining', function () { + before(function () { + cleanup(); + }); + + jsc.property( + 'shows remaining time', + jsc.array(jsc.elements(alnumString)), + jsc.array(jsc.elements(alnumString)), + 'integer', + function (message, string, number) { + message = message.join(''); + string = string.join(''); + var expected = ''; + $('body').html( + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]); + var result = $('body').html(); + return expected === result; + } + ); + }); +}); + diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index 609ccb7..036452e 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -69,7 +69,7 @@ if ($MARKDOWN): - + diff --git a/tpl/page.php b/tpl/page.php index 8b8fcad..1cae6b3 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -47,7 +47,7 @@ if ($MARKDOWN): - + From 87e88e3159e3584094393c7d1e36cdf70f02e60f Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sun, 29 Oct 2017 08:09:27 +0100 Subject: [PATCH 062/178] linking to pastebin wiki article for explanation --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 483f081..b24dc31 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ *Current version: 1.1.1* -**PrivateBin** is a minimalist, open source online pastebin where the server has -zero knowledge of pasted data. +**PrivateBin** is a minimalist, open source online [pastebin](https://en.wikipedia.org/wiki/Pastebin) +where the server has zero knowledge of pasted data. Data is encrypted and decrypted in the browser using 256bit AES in [Galois Counter mode](https://en.wikipedia.org/wiki/Galois/Counter_Mode). From 751731414e15fc079dfab12a61ce230878ec1b51 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Mon, 30 Oct 2017 06:53:15 +0100 Subject: [PATCH 063/178] adding test for loading indicator --- js/test.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/js/test.js b/js/test.js index 63b6ba4..bd0fb02 100644 --- a/js/test.js +++ b/js/test.js @@ -1031,5 +1031,40 @@ describe('Alert', function () { } ); }); + + describe('showLoading', function () { + before(function () { + cleanup(); + }); + + jsc.property( + 'shows a loding message', + jsc.array(jsc.elements(alnumString)), + jsc.array(jsc.elements(alnumString)), + 'integer', + function (icon, message, number) { + icon = icon.join(''); + message = message.join(''); + var default_message = 'Loading…'; + if (message.length == 0) { + message = default_message; + } + var expected = ''; + $('body').html( + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showLoading(message, number, icon); + var result = $('body').html(); + return expected === result; + } + ); + }); }); From 29419d03cd645c7ce2949e6d11738543bb534d89 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Mon, 30 Oct 2017 07:04:59 +0100 Subject: [PATCH 064/178] avoid logs polluting the unit test output --- js/privatebin.js | 16 ++++++++-------- js/test.js | 4 ++-- tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index f818b98..c9ff5a8 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -414,7 +414,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { var orgArguments = arguments; $(document).on(languageLoadedEvent, function () { // log to show that the previous error could be mitigated - console.log('Fix missing translation of \'' + messageId + '\' with now loaded language ' + language); + console.warn('Fix missing translation of \'' + messageId + '\' with now loaded language ' + language); // re-execute this function me.translate.apply(this, orgArguments); }); @@ -1100,7 +1100,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { */ me.showStatus = function(message, icon, dismissable, autoclose) { - console.log('status shown: ', message); + console.info('status shown: ', message); // @TODO: implement dismissable // @TODO: implement autoclose @@ -1143,7 +1143,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { */ me.showRemaining = function(message) { - console.log('remaining message shown: ', message); + console.info('remaining message shown: ', message); handleNotification(1, $remainingTime, message); } @@ -1161,7 +1161,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { me.showLoading = function(message, percentage, icon) { if (typeof message !== 'undefined' && message !== null) { - console.log('status changed: ', message); + console.info('status changed: ', message); } // default message text @@ -2656,7 +2656,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { me.showViewButtons = function() { if (viewButtonsDisplayed) { - console.log('showViewButtons: view buttons are already displayed'); + console.warn('showViewButtons: view buttons are already displayed'); return; } @@ -2676,7 +2676,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { me.hideViewButtons = function() { if (!viewButtonsDisplayed) { - console.log('hideViewButtons: view buttons are already hidden'); + console.warn('hideViewButtons: view buttons are already hidden'); return; } @@ -2708,7 +2708,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { me.showCreateButtons = function() { if (createButtonsDisplayed) { - console.log('showCreateButtons: create buttons are already displayed'); + console.warn('showCreateButtons: create buttons are already displayed'); return; } @@ -2733,7 +2733,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { me.hideCreateButtons = function() { if (!createButtonsDisplayed) { - console.log('hideCreateButtons: create buttons are already hidden'); + console.warn('hideCreateButtons: create buttons are already hidden'); return; } diff --git a/js/test.js b/js/test.js index bd0fb02..03b817b 100644 --- a/js/test.js +++ b/js/test.js @@ -25,8 +25,8 @@ global.RawDeflate.inflate = require('./rawinflate-0.3').RawDeflate.inflate; require('./privatebin'); // redirect console messages to log file -console.warn = console.error = function (msg) { - logFile.write(msg + '\n'); +console.info = console.warn = console.error = function () { + logFile.write(Array.prototype.slice.call(arguments).join('') + '\n'); } describe('Helper', function () { diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index 036452e..3695fd2 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -69,7 +69,7 @@ if ($MARKDOWN): - + diff --git a/tpl/page.php b/tpl/page.php index 1cae6b3..1f75a60 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -47,7 +47,7 @@ if ($MARKDOWN): - + From 1fd13981d4d18e6a9eef3bee7e9187c25766d6a8 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sat, 4 Nov 2017 07:40:26 +0100 Subject: [PATCH 065/178] adding test for hiding loading indicator --- js/test.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/js/test.js b/js/test.js index 03b817b..2462cc2 100644 --- a/js/test.js +++ b/js/test.js @@ -1038,7 +1038,7 @@ describe('Alert', function () { }); jsc.property( - 'shows a loding message', + 'shows a loading message', jsc.array(jsc.elements(alnumString)), jsc.array(jsc.elements(alnumString)), 'integer', @@ -1066,5 +1066,28 @@ describe('Alert', function () { } ); }); + + describe('hideLoading', function () { + before(function () { + cleanup(); + }); + + it( + 'hides the loading message', + function() { + $('body').html( + '' + ); + $('body').addClass('loading'); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.hideLoading(); + return !$('body').hasClass('loading') && + $('#loadingindicator').hasClass('hidden'); + } + ); + }); }); From c6e0f2d22347ae7f9b45482c65c2b307d20e2586 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sat, 4 Nov 2017 07:44:42 +0100 Subject: [PATCH 066/178] adding test for hiding messages --- js/test.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/js/test.js b/js/test.js index 2462cc2..f5100af 100644 --- a/js/test.js +++ b/js/test.js @@ -1089,5 +1089,29 @@ describe('Alert', function () { } ); }); + + describe('hideMessages', function () { + before(function () { + cleanup(); + }); + + it( + 'hides all messages', + function() { + $('body').html( + '' + + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.hideMessages(); + return $('#statusmessage').hasClass('hidden') && + $('#errormessage').hasClass('hidden'); + } + ); + }); }); From 01a6c0142a1a4b4f099a13a585b0bef576fe09b7 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sat, 4 Nov 2017 08:59:31 +0100 Subject: [PATCH 067/178] adding test for alert handler --- js/test.js | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/js/test.js b/js/test.js index f5100af..78eeb5e 100644 --- a/js/test.js +++ b/js/test.js @@ -1113,5 +1113,53 @@ describe('Alert', function () { } ); }); + + describe('setCustomHandler', function () { + before(function () { + cleanup(); + }); + + jsc.property( + 'calls a given handler function', + 'nat 3', + jsc.array(jsc.elements(alnumString)), + function (trigger, message) { + message = message.join(''); + var handlerCalled = false, + default_message = 'Loading…', + functions = [ + $.PrivateBin.Alert.showStatus, + $.PrivateBin.Alert.showError, + $.PrivateBin.Alert.showRemaining, + $.PrivateBin.Alert.showLoading + ]; + if (message.length == 0) { + message = default_message; + } + $('body').html( + '' + + '' + + '' + + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.setCustomHandler(function(id, $element) { + handlerCalled = true; + return true; + }); + functions[trigger](message); + return handlerCalled; + } + ); + }); }); From 9af4a4e2f5581642177dd961d0bf7e5b4dd954e1 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sat, 4 Nov 2017 09:02:05 +0100 Subject: [PATCH 068/178] handling JSVerify RNG states 08a8fd9e23076415bc & 8623a0cde74fb19568 --- js/test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/test.js b/js/test.js index 78eeb5e..cf28b40 100644 --- a/js/test.js +++ b/js/test.js @@ -803,8 +803,8 @@ describe('Model', function () { element = element.join(''); value = value.join('').trim(); - //
tags can't contain strings, table tags can't be alone, so test with a

instead - if (['br', 'tr', 'td', 'th'].indexOf(element) >= 0) { + //
,


and tags can't contain strings, table tags can't be alone, so test with a

instead + if (['br', 'hr', 'tr', 'td', 'th', 'wbr'].indexOf(element) >= 0) { element = 'p'; } From e51aa7c80fc46b90bf42e3c56f9c8b4f08638b85 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Mon, 13 Nov 2017 20:44:11 +0100 Subject: [PATCH 069/178] increasing coverage (by three lines) --- js/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/test.js b/js/test.js index cf28b40..3ae74c0 100644 --- a/js/test.js +++ b/js/test.js @@ -1154,7 +1154,7 @@ describe('Alert', function () { $.PrivateBin.Alert.init(); $.PrivateBin.Alert.setCustomHandler(function(id, $element) { handlerCalled = true; - return true; + return jsc.random(0, 1) ? true : $element; }); functions[trigger](message); return handlerCalled; From 6c8f57f91f00b727d2079d616eeaf72d8972d4f6 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Mon, 13 Nov 2017 21:57:49 +0100 Subject: [PATCH 070/178] making PasteStatus testable, adding test for paste creation notification --- js/privatebin.js | 9 +++------ js/test.js | 37 +++++++++++++++++++++++++++++++++++++ tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index c9ff5a8..b673b3c 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -124,7 +124,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { range = document.body.createTextRange(); range.moveToElementText(element); range.select(); - } else if (window.getSelection){ + } else if (window.getSelection) { selection = window.getSelection(); range = document.createRange(); range.selectNodeContents(element); @@ -302,8 +302,6 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { * internationalization module * * @name I18n - * @param {object} window - * @param {object} document * @class */ var I18n = (function () { @@ -1264,10 +1262,9 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { * handles paste status/result * * @name PasteStatus - * @param {object} window * @class */ - var PasteStatus = (function (window) { + var PasteStatus = (function () { var me = {}; var $pasteSuccess, @@ -1410,7 +1407,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { } return me; - })(window); + })(); /** * password prompt diff --git a/js/test.js b/js/test.js index 3ae74c0..316b1a3 100644 --- a/js/test.js +++ b/js/test.js @@ -1163,3 +1163,40 @@ describe('Alert', function () { }); }); +describe('PasteStatus', function () { + describe('createPasteNotification', function () { + this.timeout(30000); + before(function () { + cleanup(); + }); + + jsc.property( + 'creates a notification after a successfull paste upload', + jsc.elements(schemas), + jsc.nearray(jsc.elements(a2zString)), + jsc.array(jsc.elements(queryString)), + 'string', + jsc.elements(schemas), + jsc.nearray(jsc.elements(a2zString)), + jsc.array(jsc.elements(queryString)), + function ( + schema1, address1, query1, fragment1, + schema2, address2, query2 + ) { + var expected1 = schema1 + '://' + address1.join('') + '/?' + + encodeURI(query1.join('') + '#' + fragment1), + expected2 = schema2 + '://' + address2.join('') + '/?' + + encodeURI(query2.join('')), + clean = jsdom(); + $('body').html('

'); + $.PrivateBin.PasteStatus.init(); + $.PrivateBin.PasteStatus.createPasteNotification(expected1, expected2); + var result1 = $('#pasteurl')[0].href, + result2 = $('#deletelink a')[0].href; + clean(); + return result1 == expected1 && result2 == expected2; + } + ); + }); +}); + diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index 3695fd2..8c6958b 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -69,7 +69,7 @@ if ($MARKDOWN): - + diff --git a/tpl/page.php b/tpl/page.php index 1f75a60..dc15e28 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -47,7 +47,7 @@ if ($MARKDOWN): - + From 0cfb0196157594841b6028fccdedf94aa6cd6932 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Mon, 13 Nov 2017 22:00:26 +0100 Subject: [PATCH 071/178] handling JSVerify RNG state 0b2b38c4ef690d1a57 --- js/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/test.js b/js/test.js index 316b1a3..73962dc 100644 --- a/js/test.js +++ b/js/test.js @@ -804,7 +804,7 @@ describe('Model', function () { value = value.join('').trim(); //
,
and tags can't contain strings, table tags can't be alone, so test with a

instead - if (['br', 'hr', 'tr', 'td', 'th', 'wbr'].indexOf(element) >= 0) { + if (['br', 'col', 'hr', 'tr', 'td', 'th', 'wbr'].indexOf(element) >= 0) { element = 'p'; } From 478cf288b4869df5d5dd3a60347d30f296aacb7d Mon Sep 17 00:00:00 2001 From: El RIDO Date: Mon, 13 Nov 2017 22:05:29 +0100 Subject: [PATCH 072/178] implementing StyleCI recommendations --- tst/ConfigurationTest.php | 2 +- tst/I18nTest.php | 4 ++-- tst/PrivateBinWithDbTest.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tst/ConfigurationTest.php b/tst/ConfigurationTest.php index 66acece..15b7fd2 100644 --- a/tst/ConfigurationTest.php +++ b/tst/ConfigurationTest.php @@ -142,7 +142,7 @@ class ConfigurationTest extends PHPUnit_Framework_TestCase public function testHandleConfigFileRename() { - $options = $this->_options; + $options = $this->_options; Helper::createIniFile(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini.sample', $options); $options['main']['opendiscussion'] = true; diff --git a/tst/I18nTest.php b/tst/I18nTest.php index c7ded0e..de16349 100644 --- a/tst/I18nTest.php +++ b/tst/I18nTest.php @@ -150,8 +150,8 @@ class I18nTest extends PHPUnit_Framework_TestCase $dir = dir(PATH . 'i18n'); while (false !== ($file = $dir->read())) { if (strlen($file) === 7) { - $language = substr($file, 0, 2); - $languageMessageIds = array_keys( + $language = substr($file, 0, 2); + $languageMessageIds = array_keys( json_decode( file_get_contents(PATH . 'i18n' . DIRECTORY_SEPARATOR . $file), true diff --git a/tst/PrivateBinWithDbTest.php b/tst/PrivateBinWithDbTest.php index a438d4c..25e6082 100644 --- a/tst/PrivateBinWithDbTest.php +++ b/tst/PrivateBinWithDbTest.php @@ -35,7 +35,7 @@ class PrivateBinWithDbTest extends PrivateBinTest $options['model'] = array( 'class' => 'Database', ); - $options['model_options'] = $this->_options; + $options['model_options'] = $this->_options; Helper::createIniFile(CONF, $options); } } From 4652b5af7bf1b7132a50026f4d2cde575f73b702 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Mon, 13 Nov 2017 22:12:31 +0100 Subject: [PATCH 073/178] preferring pre-increment StyleCI recommendation --- .styleci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.styleci.yml b/.styleci.yml index 0c7ba38..8a62bd5 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -3,10 +3,11 @@ preset: recommended risky: false enabled: - - no_empty_comment - align_equals - - long_array_syntax - concat_with_spaces + - long_array_syntax + - no_empty_comment + - pre_increment disabled: - blank_line_after_opening_tag @@ -23,6 +24,7 @@ disabled: - phpdoc_separation - phpdoc_single_line_var_spacing - phpdoc_summary + - post_increment - short_array_syntax - single_line_after_imports - unalign_equals From 86ecdb1155f98019ef88be5ba3cd1096abb8491c Mon Sep 17 00:00:00 2001 From: El RIDO Date: Mon, 13 Nov 2017 22:15:14 +0100 Subject: [PATCH 074/178] fixing post increment --- lib/Filter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Filter.php b/lib/Filter.php index 4c0a22e..302c84c 100644 --- a/lib/Filter.php +++ b/lib/Filter.php @@ -64,7 +64,7 @@ class Filter $i = 0; while (($size / 1024) >= 1) { $size = $size / 1024; - $i++; + ++$i; } return number_format($size, ($i ? 2 : 0), '.', ' ') . ' ' . I18n::_($iec[$i]); } @@ -82,7 +82,7 @@ class Filter public static function slowEquals($a, $b) { $diff = strlen($a) ^ strlen($b); - for ($i = 0; $i < strlen($a) && $i < strlen($b); $i++) { + for ($i = 0; $i < strlen($a) && $i < strlen($b); ++$i) { $diff |= ord($a[$i]) ^ ord($b[$i]); } return $diff === 0; From 73bc6851785e2880864b05213e99e8820a70424d Mon Sep 17 00:00:00 2001 From: El RIDO Date: Tue, 14 Nov 2017 06:52:12 +0100 Subject: [PATCH 075/178] fixing error message display revealed by testing remaining time display function --- js/privatebin.js | 4 ++-- js/test.js | 42 ++++++++++++++++++++++++++++++++++++++++++ tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index b673b3c..b130edd 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -1365,7 +1365,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { ]; Alert.showRemaining([expirationLabel, expiration[0]]); - $remainingTime.removeClass('foryoureyesonly') + $remainingTime.removeClass('foryoureyesonly'); } else { // never expires return; @@ -3982,7 +3982,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { Uploader.setUnencryptedData('deletetoken', deleteToken); Uploader.setFailure(function () { - Controller.showError(I18n._('Could not delete the paste, it was not stored in burn after reading mode.')); + Alert.showError(I18n._('Could not delete the paste, it was not stored in burn after reading mode.')); }) Uploader.run(); } diff --git a/js/test.js b/js/test.js index 73962dc..4d9b6eb 100644 --- a/js/test.js +++ b/js/test.js @@ -1198,5 +1198,47 @@ describe('PasteStatus', function () { } ); }); + + describe('showRemainingTime', function () { + this.timeout(30000); + before(function () { + cleanup(); + }); + + jsc.property( + 'shows burn after reading message or remaining time', + 'bool', + 'nat', + jsc.nearray(jsc.elements(a2zString)), + jsc.nearray(jsc.elements(a2zString)), + jsc.array(jsc.elements(queryString)), + 'string', + function ( + burnafterreading, remaining_time, + schema, address, query, fragment + ) { + var clean = jsdom('', { + url: schema.join('') + '://' + address.join('') + + '/?' + queryString + '#' + fragment + }); + $('body').html('

'); + $.PrivateBin.PasteStatus.init(); + $.PrivateBin.PasteStatus.showRemainingTime({ + 'burnafterreading': burnafterreading, + 'remaining_time': remaining_time, + 'expire_date': ((new Date()).getTime() / 1000) + remaining_time + }); + if (burnafterreading) { + var result = $('#remainingtime').hasClass('foryoureyesonly') && + !$('#remainingtime').hasClass('hidden'); + } else { + var result =!$('#remainingtime').hasClass('foryoureyesonly') && + !$('#remainingtime').hasClass('hidden'); + } + clean(); + return result; + } + ); + }); }); diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index 8c6958b..f722ee8 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -69,7 +69,7 @@ if ($MARKDOWN): - + diff --git a/tpl/page.php b/tpl/page.php index dc15e28..0c01437 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -47,7 +47,7 @@ if ($MARKDOWN): - + From b1e18788615c8eb8248e3026a3e48bd1af8d3f6a Mon Sep 17 00:00:00 2001 From: El RIDO Date: Thu, 16 Nov 2017 08:50:38 +0100 Subject: [PATCH 076/178] fully testing remaining time display function --- js/test.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/js/test.js b/js/test.js index 4d9b6eb..dfbeb38 100644 --- a/js/test.js +++ b/js/test.js @@ -1226,14 +1226,17 @@ describe('PasteStatus', function () { $.PrivateBin.PasteStatus.showRemainingTime({ 'burnafterreading': burnafterreading, 'remaining_time': remaining_time, - 'expire_date': ((new Date()).getTime() / 1000) + remaining_time + 'expire_date': remaining_time ? ((new Date()).getTime() / 1000) + remaining_time : 0 }); if (burnafterreading) { var result = $('#remainingtime').hasClass('foryoureyesonly') && !$('#remainingtime').hasClass('hidden'); - } else { + } else if (remaining_time) { var result =!$('#remainingtime').hasClass('foryoureyesonly') && !$('#remainingtime').hasClass('hidden'); + } else { + var result = $('#remainingtime').hasClass('hidden') && + !$('#remainingtime').hasClass('foryoureyesonly'); } clean(); return result; From 9d1a9a0da7fdc97c9862ecf95e68a66b6c3f8f66 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Thu, 16 Nov 2017 08:57:08 +0100 Subject: [PATCH 077/178] fixing paste success message handling in page template --- js/privatebin.js | 2 +- tpl/bootstrap.php | 4 ++-- tpl/page.php | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index b130edd..60db54f 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -1397,7 +1397,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) { */ me.init = function() { - $pasteSuccess = $('#pasteSuccess'); + $pasteSuccess = $('#pastesuccess'); // $pasteUrl is saved in me.createPasteNotification() after creation $remainingTime = $('#remainingtime'); $shortenButton = $('#shortenbutton'); diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index f722ee8..aa57490 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -69,7 +69,7 @@ if ($MARKDOWN): - + @@ -434,7 +434,7 @@ endif; Opera, Chrome… -