Compare commits

...

43 Commits

Author SHA1 Message Date
El RIDO
91e5038242 incrementing version 2020-02-16 10:46:43 +01:00
El RIDO
dd12fbf3a3 upgrade DOMpurify to 2.0.8 2020-02-16 09:13:36 +01:00
El RIDO
d2d471278c fix FAQ links, tweaking the subtext display, add link to modern browser FAQ, fixes #577 2020-02-16 09:08:52 +01:00
El RIDO
4058558399 document backport of server side HTML encoding fixes 2020-02-16 08:59:57 +01:00
El RIDO
ba2363d66b apply StyleCI recommendation 2020-02-16 08:57:32 +01:00
El RIDO
35be3aabf8 ensuring consistent use of php side encoding, testing all encoding cases, correctly report the language in the <html> tag 2020-02-16 08:57:28 +01:00
El RIDO
d3082c36d7 add HTML entity encoding to PHP translation logic, remove exception to allow <br/> tags in DOMpurify by eliminating the single case that made use of it 2020-02-16 08:49:47 +01:00
El RIDO
79d30c9410 adding test that expects parameters of php translation to get HTML entities to get encoded 2020-02-16 08:42:57 +01:00
rugk
e56edb6c6b Feature FAQ link in Readme & remove legacy things
* remove old ZeroBin 0.19 guide, this is so old already, few people will benefit from a direct link in the Readme. It stays in the wiki for those, who need it.
* add direct link to the FAQ - it's one of our best documentation/sources, so it's a shame it is not featured more prominently 😉
2020-02-16 08:42:00 +01:00
El RIDO
6ccbad612d backporting double encoding fixes from #560 2020-02-16 08:37:33 +01:00
El RIDO
2a5f622580 fixing travis CI builds for php 5.5, which require trusty 2020-01-11 13:30:14 +01:00
El RIDO
1b966b35fc Merge branch 'master' into webcrypto, fix nvm 2020-01-11 13:28:48 +01:00
El RIDO
c28b134067 implementing web crypto API for encryption 2020-01-11 13:24:16 +01:00
El RIDO
a6d5254662 incrementing version 2020-01-08 19:19:12 +01:00
El RIDO
7c66ba9de6 documenting changes for 1.2.2 2020-01-07 21:23:41 +01:00
El RIDO
1a77f25000 upgrading SJCL to 1.0.8 2020-01-07 21:22:34 +01:00
El RIDO
71029f7d3d upgrading showdown to released 1.9.1 version 2020-01-07 21:14:06 +01:00
El RIDO
1f5d237806 address new fixer in StyleCI causing false positives in templates 2020-01-07 21:08:48 +01:00
El RIDO
2caddf985f more general solution addressing #554, kudos @rugk for the suggestions 2020-01-07 21:08:11 +01:00
El RIDO
6a3a8a395a updating DOMpurify library, fixes #523 2020-01-07 20:31:44 +01:00
El RIDO
b21d0a6cb7 fixing font paths 2020-01-07 20:27:40 +01:00
El RIDO
f70ffe3864 updated kjua library 2020-01-07 20:27:22 +01:00
El RIDO
9acddb530f revert bootstraps JS to 3.3.7 as 3.4.1 breaks the navbar toggle 2020-01-07 20:26:27 +01:00
El RIDO
85d2cea504 upgrade jQuery library 2020-01-07 20:23:59 +01:00
El RIDO
1935dee6b7 upgrading bootstrap CSS 2020-01-07 20:19:35 +01:00
El RIDO
8db98becb7 upgrading DOMpurify library 2018-08-11 19:45:57 +02:00
El RIDO
b5ebc4a3d7 incrementing version 2018-08-11 19:29:58 +02:00
El RIDO
fb6a9ccf09 document changes 2018-08-11 08:17:08 +02:00
El RIDO
10201dc463 expanded unit tests to cover mega links, reverted regex to old one, but fixed to cover mega links, just to prove it works 2018-08-11 07:33:33 +02:00
El RIDO
c468b74b9b Merge branch 'master' into linkregex 2018-08-11 06:56:02 +02:00
El RIDO
e4cc9ef4f6 Merge branch 'r4sas-update-ru' 2018-08-06 19:40:17 +02:00
R4SAS
9a5be5521b update ru translation 2018-08-06 20:24:59 +03:00
El RIDO
0319a16b15 support older browsers correctly and ensure the paranoia setting for the sjcl.random.isReady call matches paranoia level 10 instead of the default 6 2018-08-04 13:25:31 +02:00
El RIDO
1be1047a94 while we do start the collection of randomness even before initializing our logic, raising the 'paranoia' parameter to 10 ensures that in legacy browsers not yet supporting the webcrypto API we would get an exception, instead of a weak key 2018-08-01 21:56:23 +02:00
El RIDO
a5e8eeaaf9 StyleCI: Obey the alphabet #342 2018-07-29 16:15:52 +02:00
El RIDO
4a35428499 cleanup of PurgeLimiter #342 2018-07-29 16:05:57 +02:00
El RIDO
3470dcd9a8 more compact ServerSalt #342 2018-07-29 15:50:36 +02:00
El RIDO
5db3412b69 cleanup of TrafficLimiter #342 2018-07-29 15:43:28 +02:00
El RIDO
f9c8441edb renaming controller #342 2018-07-29 15:17:35 +02:00
El RIDO
90e83ddb30 bump changelog, fixes #344 2018-07-24 20:32:18 +02:00
rugk
c3c1473dc9 Allow one-letter TLDs/host names 2018-07-01 19:49:21 +02:00
rugk
676a02619d Fix magnet links 2018-07-01 16:31:40 +02:00
rugk
119c3931cc Try new RegEx for creating links 2018-07-01 15:13:24 +02:00
80 changed files with 762 additions and 458 deletions

View File

@@ -19,6 +19,7 @@ disabled:
- heredoc_to_nowdoc
- method_argument_space
- new_with_braces
- no_alternative_syntax
- phpdoc_align
- phpdoc_no_access
- phpdoc_separation

View File

@@ -1,5 +1,7 @@
language: php
sudo: false
# only needed for PHP 5.5 support as of 2019-07
dist: trusty
php:
- '5.4'
- '5.5'
@@ -7,16 +9,17 @@ php:
- '7.0'
- '7.1'
- '7.2'
- '7.3'
# as this is a php project, node.js v4 (for JS unit testing) isn't installed
# as this is a php project, node.js (for JS unit testing) isn't installed
install:
- if [ ! -d "$HOME/.nvm" ]; then mkdir -p $HOME/.nvm && curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | NVM_METHOD=script bash; fi
- source ~/.nvm/nvm.sh && nvm install 4
- if [ ! -d "$HOME/.nvm" ]; then mkdir -p $HOME/.nvm && curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | NVM_METHOD=script bash; fi
- source ~/.nvm/nvm.sh && nvm install --lts
before_script:
- composer install -n
- npm install -g mocha
- cd js && npm install jsverify jsdom@9 jsdom-global@2 mime-types
- cd js && npm install
script:
- mocha

View File

@@ -1,6 +1,20 @@
# PrivateBin version history
* **1.2 (not yet released)**
* **1.2.3 (2020-02-16)**
* CHANGED: Upgrading libraries to: DOMpurify 2.0.8
* CHANGED: Introduce HTML entity encoding on server side (#581)
* FIXED: HTML entity double encoding issues introduced in 1.3.2 (#560)
* **1.2.2 (2020-01-11)**
* CHANGED: Upgrading libraries to: bootstrap 3.4.1, DOMpurify 2.0.7, jQuery 3.4.1, kjua 0.6.0, Showdown 1.9.1 & SJCL 1.0.8
* FIXED: HTML injection via unescaped attachment filename (#554)
* **1.2.1 (2018-08-11)**
* ADDED: Add support for mega.nz links in pastes and comments (#331)
* CHANGED: Added some missing Russian translations (#348)
* CHANGED: Minor PHP refactoring: Rename PrivateBin class to Controller, improved logic of some persistence classes (#342)
* CHANGED: Upgrading DOMpurify library to 1.0.7
* FIXED: Ensure legacy browsers without webcrypto support can't create paste keys with insufficient entropy (#346)
* FIXED: Re-add support for old browsers (Firefox&lt;21, Chrome&lt;31, Safari&lt;7, IE&lt;11), broken in 1.2, will be removed again in 1.3
* **1.2 (2018-07-22)**
* ADDED: Translations for Spanish, Occitan, Norwegian, Portuguese, Dutch and Hungarian
* ADDED: Option in configuration to change the default "PrivateBin" title of the site
* ADDED: Added display of video, audio & PDF, drag & drop, preview of attachments (#182)

View File

@@ -165,7 +165,7 @@ 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.2');
INSERT INTO prefix_config VALUES('VERSION', '1.2.3');
```
In **PostgreSQL**, the data, attachment, nickname and vizhash columns needs to be TEXT and not BLOB or MEDIUMBLOB.

View File

@@ -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.2*
*Current version: 1.2.3*
**PrivateBin** is a minimalist, open source online [pastebin](https://en.wikipedia.org/wiki/Pastebin)
where the server has zero knowledge of pasted data.
@@ -102,9 +102,9 @@ file](https://github.com/PrivateBin/PrivateBin/wiki/Configuration):
## Further resources
* [Installation guide](https://github.com/PrivateBin/PrivateBin/blob/master/INSTALL.md#installation)
* [FAQ](https://github.com/PrivateBin/PrivateBin/wiki/FAQ)
* [Upgrading from ZeroBin 0.19 Alpha](https://github.com/PrivateBin/PrivateBin/wiki/Upgrading-from-ZeroBin-0.19-Alpha)
* [Installation guide](https://github.com/PrivateBin/PrivateBin/blob/master/INSTALL.md#installation)
* [Configuration guide](https://github.com/PrivateBin/PrivateBin/wiki/Configuration)

View File

@@ -3,13 +3,13 @@
"description": "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 256 bit AES in Galois Counter mode (GCM).",
"type": "project",
"keywords": ["private", "secure", "end-to-end-encrypted", "e2e", "paste", "pastebin", "zero", "zero-knowledge", "encryption", "encrypted", "AES"],
"homepage": "https://github.com/PrivateBin",
"homepage": "https://privatebin.info/",
"license":"zlib-acknowledgement",
"support": {
"issues": "https://github.com/PrivateBin/PrivateBin/issues",
"wiki": "https://github.com/PrivateBin/PrivateBin/wiki",
"source": "https://github.com/PrivateBin/PrivateBin",
"docs": "https://zerobin.dssr.ch/documentation/"
"docs": "https://privatebin.info/codedoc/"
},
"require": {
"php": "^5.4.0 || ^7.0",

File diff suppressed because one or more lines are too long

5
css/bootstrap/bootstrap-3.4.1.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -315,8 +315,8 @@ th {
}
@font-face {
font-family: 'Glyphicons Halflings';
src: url(fonts/../fonts/glyphicons-halflings-regular.eot?1445975532);
src: url(fonts/../fonts/glyphicons-halflings-regular.eot?&1445975532#iefix) format("embedded-opentype"), url(fonts/../fonts/glyphicons-halflings-regular.woff2?1445975532) format("woff2"), url(fonts/../fonts/glyphicons-halflings-regular.woff?1445975532) format("woff"), url(fonts/../fonts/glyphicons-halflings-regular.ttf?1445975532) format("truetype"), url(fonts/../fonts/glyphicons-halflings-regular.svg?1445975532#glyphicons_halflingsregular) format("svg");
src: url(fonts/glyphicons-halflings-regular.eot?1445975532);
src: url(fonts/glyphicons-halflings-regular.eot?&1445975532#iefix) format("embedded-opentype"), url(fonts/glyphicons-halflings-regular.woff2?1445975532) format("woff2"), url(fonts/glyphicons-halflings-regular.woff?1445975532) format("woff"), url(fonts/glyphicons-halflings-regular.ttf?1445975532) format("truetype"), url(fonts/glyphicons-halflings-regular.svg?1445975532#glyphicons_halflingsregular) format("svg");
}
.glyphicon {
position: relative;

View File

@@ -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.2
* @version 1.2.3
*/
body {

View File

@@ -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.2
* @version 1.2.3
*/
/* When there is no script at all other */

View File

@@ -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.2
* @version 1.2.3
*/
/* CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved.

View File

@@ -31,8 +31,8 @@
"Falscher Lösch-Code. Text wurde nicht gelöscht.",
"Paste was properly deleted.":
"Text wurde erfolgreich gelöscht.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"JavaScript ist eine Voraussetzung, um %s zu nutzen.<br />Bitte entschuldige die Unannehmlichkeiten.",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"JavaScript ist eine Voraussetzung, um %s zu nutzen. Bitte entschuldige die Unannehmlichkeiten.",
"%s requires a modern browser to work.":
"%s setzt einen modernen Browser voraus, um funktionieren zu können.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":

View File

@@ -31,8 +31,8 @@
"Token de eliminación erróneo. El texto no fue eliminado.",
"Paste was properly deleted.":
"El texto se ha eliminado correctamente.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"JavaScript es necesario para que %s funcione.<br />Sentimos los inconvenientes ocasionados.",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"JavaScript es necesario para que %s funcione. Sentimos los inconvenientes ocasionados.",
"%s requires a modern browser to work.":
"%s requiere un navegador moderno para funcionar.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":

View File

@@ -31,8 +31,8 @@
"Jeton de suppression incorrect. Le paste n'a pas été supprimé.",
"Paste was properly deleted.":
"Le paste a été correctement supprimé.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"JavaScript est requis pour faire fonctionner %s. <br />Désolé pour cet inconvénient.",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"JavaScript est requis pour faire fonctionner %s. Désolé pour cet inconvénient.",
"%s requires a modern browser to work.":
"%s nécessite un navigateur moderne pour fonctionner.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":

View File

@@ -31,7 +31,7 @@
"Hibás törlési azonosító. A bejegyzés nem lett törölve.",
"Paste was properly deleted.":
"A bejegyzés sikeresen törölve.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"JavaScript szükséges a %s működéséhez. Elnézést a fennakadásért.",
"%s requires a modern browser to work.":
"A %s működéséhez a jelenleginél újabb böngészőre van szükség.",

View File

@@ -31,8 +31,8 @@
"Codice cancellazione errato. Il messaggio NON è stato cancellato.",
"Paste was properly deleted.":
"Il messaggio è stato correttamente cancellato.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"%s funziona solo con JavaScript attivo.<br />Ci dispiace per l'inconveniente.",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"%s funziona solo con JavaScript attivo. Ci dispiace per l'inconveniente.",
"%s requires a modern browser to work.":
"%s richiede un browser moderno e aggiornato per funzionare.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":

View File

@@ -31,8 +31,8 @@
"Foutieve verwijdercode. Geplakte tekst is niet verwijderd.",
"Paste was properly deleted.":
"Geplakte tekst is correct verwijderd.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"JavaScript vereist om %s te laten werken.<br />Sorry voor het ongemak.",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"JavaScript vereist om %s te laten werken. Sorry voor het ongemak.",
"%s requires a modern browser to work.":
"%s vereist een moderne browser om te kunnen werken ",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":

View File

@@ -31,8 +31,8 @@
"Feil slettingsnøkkel. Innlegg ble ikke fjernet.",
"Paste was properly deleted.":
"Innlegget er slettet.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"Javascript kreves for at %s skal fungere<br />Beklager.",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"Javascript kreves for at %s skal fungere. Beklager.",
"%s requires a modern browser to work.":
"%s krever en moderne nettleser for å fungere.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":

View File

@@ -31,8 +31,8 @@
"Geton de supression incorrècte. Lo tèxte es pas estat suprimit.",
"Paste was properly deleted.":
"Lo tèxte es estat correctament suprimit.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"JavaScript es requesit per far foncionar %s. <br />O planhèm per linconvenient.",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"JavaScript es requesit per far foncionar %s. O planhèm per linconvenient.",
"%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:":

View File

@@ -31,7 +31,7 @@
"Nieprawidłowy token usuwania. Wklejka nie została usunięta.",
"Paste was properly deleted.":
"Wklejka usunięta poprawnie.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"Do działania %sa jest wymagany JavaScript. Przepraszamy za tę niedogodność.",
"%s requires a modern browser to work.":
"%s wymaga do działania nowoczesnej przeglądarki.",

View File

@@ -31,8 +31,8 @@
"Token de remoção inválido. A cópia não foi excluída.",
"Paste was properly deleted.":
"A cópia foi devidamente excluída.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"JavaScript é necessário para que %s funcione.<br />Pedimos desculpas pela inconveniência.",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"JavaScript é necessário para que %s funcione. Pedimos desculpas pela inconveniência.",
"%s requires a modern browser to work.":
"%s requer um navegador moderno para funcionar.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":

View File

@@ -31,8 +31,8 @@
"Неверный ключ удаления записи. Запись не удалена",
"Paste was properly deleted.":
"Запись была успешно удалена.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"Для работы %s требуется включенный JavaScript.<br />Приносим извинения за неудобства.",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"Для работы %s требуется включенный JavaScript. Приносим извинения за неудобства.",
"%s requires a modern browser to work.":
"Для работы %s требуется более современный браузер.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
@@ -142,8 +142,8 @@
"The cloned file '%s' was attached to this paste.":
"Дубликат файла '%s' был прикреплен к этой записи.",
"Attach a file": "Прикрепить файл",
"alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard",
"File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.",
"alternatively drag & drop a file or paste an image from the clipboard": "так же можно перенести файл в окно браузера или вставить изображение из буфера",
"File too large, to display a preview. Please download the attachment.": "Файл слишком большой для отображения предпросмотра. Пожалуйста скачайте прикрепленный файл.",
"Remove attachment": "Удалить вложение",
"Your browser does not support uploading encrypted files. Please use a newer browser.":
"Ваш браузер не поддерживает отправку зашифрованных файлов. Используйте более новый браузер.",
@@ -165,5 +165,5 @@
"Если данное сообщение не исчезает длительное время, посмотрите <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">этот FAQ с информацией о возможном решении проблемы (на английском)</a>.",
"+++ no paste text +++": "+++ в записи нет текста +++",
"Could not get paste data: %s":
"Could not get paste data: %s"
}
"Не удалось получить данные записи: %s"
}

View File

@@ -31,8 +31,8 @@
"Napačen token za izbris. Prilepek ni bil izbrisan..",
"Paste was properly deleted.":
"Prilepek je uspešno izbrisan.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"Da %s deluje, moraš vklopiti JavaScript.<br />Oprosti za povročene nevšečnosti.",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"Da %s deluje, moraš vklopiti JavaScript. Oprosti za povročene nevšečnosti.",
"%s requires a modern browser to work.":
"%s za svoje delovanje potrebuje moderen brskalnik.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":

View File

@@ -31,8 +31,8 @@
"错误的删除token粘贴没有被删除。",
"Paste was properly deleted.":
"粘贴已被正确删除。",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"%s需要JavaScript来进行加解密。<br />带来的不便敬请谅解。",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"%s需要JavaScript来进行加解密。 给你带来的不便敬请谅解。",
"%s requires a modern browser to work.":
"%s需要工作于现代化的浏览器。",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":

View File

@@ -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.2
* @version 1.2.3
*/
// change this, if your php files and data is outside of your webservers document root
@@ -15,4 +15,4 @@ define('PATH', '');
define('PUBLIC_PATH', __DIR__);
require PATH . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
new PrivateBin\PrivateBin;
new PrivateBin\Controller;

View File

@@ -8,16 +8,16 @@ global.cleanup = global.jsdom();
global.fs = require('fs');
// application libraries to test
global.$ = global.jQuery = require('./jquery-3.3.1');
global.sjcl = require('./sjcl-1.0.7');
global.$ = global.jQuery = require('./jquery-3.4.1');
global.sjcl = require('./sjcl-1.0.8');
global.Base64 = require('./base64-2.4.5').Base64;
global.RawDeflate = require('./rawdeflate-0.5').RawDeflate;
global.RawDeflate.inflate = require('./rawinflate-0.3').RawDeflate.inflate;
require('./prettify');
global.prettyPrint = window.PR.prettyPrint;
global.prettyPrintOne = window.PR.prettyPrintOne;
global.showdown = require('./showdown-1.8.6');
global.DOMPurify = require('./purify-1.0.5');
global.showdown = require('./showdown-1.9.1');
global.DOMPurify = require('./purify-2.0.8');
require('./bootstrap-3.3.7');
require('./privatebin');
@@ -26,30 +26,16 @@ var 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'],
alnumString = a2zString.concat(['0','1','2','3','4','5','6','7','8','9']),
queryString = alnumString.concat(['+','%','&','.','*','-','_']),
hashString = queryString.concat(['!']),
base64String = alnumString.concat(['+','/','=']).concat(
a2zString.map(function(c) {
return c.toUpperCase();
})
),
schemas = ['ftp','gopher','http','https','ws','wss'],
schemas = ['ftp','http','https'],
supportedLanguages = ['de', 'es', 'fr', 'it', 'no', 'pl', 'pt', 'oc', 'ru', 'sl', 'zh'],
mimeTypes = ['image/png', 'application/octet-stream'],
formats = ['plaintext', 'markdown', 'syntaxhighlighting'],
/**
* character to HTML entity lookup table
*
* @see {@link https://github.com/janl/mustache.js/blob/master/mustache.js#L60}
*/
entityMap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'/': '&#x2F;',
'`': '&#x60;',
'=': '&#x3D;'
},
logFile = fs.createWriteStream('test.log'),
mimeFile = fs.createReadStream('/etc/mime.types'),
mimeLine = '';
@@ -96,22 +82,6 @@ function parseMime(line) {
// common testing helper functions
/**
* convert all applicable characters to HTML entities
*
* @see {@link https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet#RULE_.231_-_HTML_Escape_Before_Inserting_Untrusted_Data_into_HTML_Element_Content}
* @name htmlEntities
* @function
* @param {string} str
* @return {string} escaped HTML
*/
exports.htmlEntities = function(str) {
return String(str).replace(
/[&<>"'`=\/]/g, function(s) {
return entityMap[s];
});
};
// provides random lowercase characters from a to z
exports.jscA2zString = function() {
return jsc.elements(a2zString);
@@ -127,6 +97,11 @@ exports.jscQueryString = function() {
return jsc.elements(queryString);
};
// provides random characters allowed in hash queries
exports.jscHashString = function() {
return jsc.elements(hashString);
};
// provides random characters allowed in base64 encoded strings
exports.jscBase64String = function() {
return jsc.elements(base64String);

2
js/jquery-3.3.1.js vendored

File diff suppressed because one or more lines are too long

2
js/jquery-3.4.1.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
js/kjua-0.6.0.js Normal file

File diff suppressed because one or more lines are too long

43
js/package.json Normal file
View File

@@ -0,0 +1,43 @@
{
"name": "privatebin",
"version": "1.2.1",
"description": "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 256 bit AES in Galois Counter mode (GCM).",
"main": "privatebin.js",
"directories": {
"test": "test"
},
"dependencies": {},
"devDependencies": {
"jsdom": "^9.12.0",
"jsdom-global": "^2.1.1",
"jsverify": "^0.8.3",
"mime-types": "^2.1.20",
"node-webcrypto-ossl": "^1.0.37"
},
"scripts": {
"test": "mocha"
},
"repository": {
"type": "git",
"url": "git+https://github.com/PrivateBin/PrivateBin.git"
},
"keywords": [
"private",
"secure",
"end-to-end-encrypted",
"e2e",
"paste",
"pastebin",
"zero",
"zero-knowledge",
"encryption",
"encrypted",
"AES"
],
"author": "",
"license": "zlib-acknowledgement",
"bugs": {
"url": "https://github.com/PrivateBin/PrivateBin/issues"
},
"homepage": "https://privatebin.info/"
}

View File

@@ -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.2
* @version 1.2.3
* @name PrivateBin
* @namespace
*/
@@ -25,6 +25,8 @@
// Immediately start random number generator collector.
sjcl.random.startCollectors();
// Setting this to 10 ensures 1024 bits of entropy get collected before generating the paste key
sjcl.random.setDefaultParanoia(10);
// main application start, called when DOM is fully loaded
jQuery(document).ready(function() {
@@ -66,6 +68,26 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
*/
var baseUri = null;
/**
* character to HTML entity lookup table
*
* @see {@link https://github.com/janl/mustache.js/blob/master/mustache.js#L60}
* @name Helper.entityMap
* @private
* @enum {Object}
* @readonly
*/
var entityMap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'/': '&#x2F;',
'`': '&#x60;',
'=': '&#x3D;'
};
/**
* converts a duration (in seconds) into human friendly approximation
*
@@ -145,7 +167,7 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
me.urls2links = function(html)
{
return html.replace(
/(((http|https|ftp):\/\/[\w?=&.\/-;#@~%+*-]+(?![\w\s?&.\/;#~%"=-]*>))|((magnet):[\w?=&.\/-;#@~%+*-]+))/ig,
/(((https?|ftp):\/\/[\w?!=&.\/-;#@~%+*-]+(?![\w\s?!&.\/;#~%"=-]*>))|((magnet):[\w?=&.\/-;#@~%+*-]+))/ig,
'<a href="$1" rel="nofollow">$1</a>'
);
};
@@ -169,19 +191,12 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
var format = args[0],
i = 1;
return format.replace(/%(s|d)/g, function (m) {
// m is the matched format, e.g. %s, %d
var val = args[i];
// A switch statement so that the formatter can be extended.
switch (m)
{
case '%d':
val = parseFloat(val);
if (isNaN(val)) {
val = 0;
}
break;
default:
// Default is %s
if (m === '%d') {
val = parseFloat(val);
if (isNaN(val)) {
val = 0;
}
}
++i;
return val;
@@ -229,20 +244,27 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
return baseUri;
}
baseUri = window.location.origin + window.location.pathname;
// window.location.origin is a newer alternative, but requires FF 21 / Chrome 31 / Safari 7 / IE 11
baseUri = window.location.protocol + '//' + window.location.host + window.location.pathname;
return baseUri;
};
/**
* resets state, used for unit testing
* convert all applicable characters to HTML entities
*
* @name Helper.reset
* @see {@link https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html}
* @name Helper.htmlEntities
* @function
* @param {string} str
* @return {string} escaped HTML
*/
me.reset = function()
{
baseUri = null;
};
me.htmlEntities = function(str) {
return String(str).replace(
/[&<>"'`=\/]/g, function(s) {
return entityMap[s];
}
);
}
/**
* checks whether this is a bot we dislike
@@ -264,6 +286,17 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
return false;
}
/**
* resets state, used for unit testing
*
* @name Helper.reset
* @function
*/
me.reset = function()
{
baseUri = null;
};
return me;
})();
@@ -334,10 +367,14 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
*
* Optionally pass a jQuery element as the first parameter, to automatically
* let the text of this element be replaced. In case the (asynchronously
* loaded) language is not downloadet yet, this will make sure the string
* is replaced when it is actually loaded.
* So for easy translations passing the jQuery object to apply it to is
* more save, especially when they are loaded in the beginning.
* loaded) language is not downloaded yet, this will make sure the string
* is replaced when it eventually gets loaded. Using this is both simpler
* and more secure, as it avoids potential XSS when inserting text.
* The next parameter is the message ID, matching the ones found in
* the translation files under the i18n directory.
* Any additional parameters will get inserted into the message ID in
* place of %s (strings) or %d (digits), applying the appropriate plural
* in case of digits. See also Helper.sprintf().
*
* @name I18n.translate
* @function
@@ -416,18 +453,40 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
args[0] = translations[messageId];
}
// messageID may contain links, but should be from a trusted source (code or translation JSON files)
var containsLinks = args[0].indexOf('<a') !== -1;
// prevent double encoding, when we insert into a text node
if (containsLinks || $element === null) {
for (var i = 0; i < args.length; ++i) {
// parameters (i > 0) may never contain HTML as they may come from untrusted parties
if ((containsLinks ? i > 1 : i > 0) || !containsLinks) {
args[i] = Helper.htmlEntities(args[i]);
}
}
}
// format string
var output = Helper.sprintf.apply(this, args);
// if $element is given, apply text to element
if (containsLinks) {
// only allow tags/attributes we actually use in translations
output = DOMPurify.sanitize(
output, {
ALLOWED_TAGS: ['a', 'i', 'span'],
ALLOWED_ATTR: ['href', 'id']
}
);
}
// if $element is given, insert translation
if ($element !== null) {
// get last text node of element
var content = $element.contents();
if (content.length > 1) {
content[content.length - 1].nodeValue = ' ' + output;
if (containsLinks) {
$element.html(output);
} else {
// text node takes care of entity encoding
$element.text(output);
}
return '';
}
return output;
@@ -640,7 +699,7 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
*/
me.getSymmetricKey = function()
{
return sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 0), 0);
return sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 10), 0);
};
return me;
@@ -1049,28 +1108,35 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
icon = null; // icons not supported in this case
}
}
var $translationTarget = $element;
// handle icon
if (icon !== null && // icon was passed
icon !== currentIcon[id] // and it differs from current icon
) {
var $glyphIcon = $element.find(':first');
// handle icon, if template uses one
var $glyphIcon = $element.find(':first');
if ($glyphIcon.length) {
// if there is an icon, we need to provide an inner element
// to translate the message into, instead of the parent
$translationTarget = $('<span>');
$element.html(' ').prepend($glyphIcon).append($translationTarget);
// remove (previous) icon
$glyphIcon.removeClass(currentIcon[id]);
if (icon !== null && // icon was passed
icon !== currentIcon[id] // and it differs from current icon
) {
// remove (previous) icon
$glyphIcon.removeClass(currentIcon[id]);
// any other thing as a string (e.g. 'null') (only) removes the icon
if (typeof icon === 'string') {
// set new icon
currentIcon[id] = 'glyphicon-' + icon;
$glyphIcon.addClass(currentIcon[id]);
// any other thing as a string (e.g. 'null') (only) removes the icon
if (typeof icon === 'string') {
// set new icon
currentIcon[id] = 'glyphicon-' + icon;
$glyphIcon.addClass(currentIcon[id]);
}
}
}
// show text
if (args !== null) {
// add jQuery object to it as first parameter
args.unshift($element);
args.unshift($translationTarget);
// pass it to I18n
I18n._.apply(this, args);
}
@@ -1292,11 +1358,10 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
*/
me.createPasteNotification = function(url, deleteUrl)
{
$('#pastelink').html(
I18n._(
'Your paste is <a id="pasteurl" href="%s">%s</a> <span id="copyhint">(Hit [Ctrl]+[c] to copy)</span>',
url, url
)
I18n._(
$('#pastelink'),
'Your paste is <a id="pasteurl" href="%s">%s</a> <span id="copyhint">(Hit [Ctrl]+[c] to copy)</span>',
url, url
);
// save newly created element
$pasteUrl = $('#pasteurl');
@@ -1304,7 +1369,8 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
$pasteUrl.click(pasteLinkClick);
// shorten button
$('#deletelink').html('<a href="' + deleteUrl + '">' + I18n._('Delete data') + '</a>');
$('#deletelink').html('<a href="' + deleteUrl + '"></a>');
I18n._($('#deletelink a').first(), 'Delete data');
// show result
$pasteSuccess.removeClass('hidden');
@@ -1760,10 +1826,13 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
}
// escape HTML entities, link URLs, sanitize
var escapedLinkedText = Helper.urls2links(
$('<div />').text(text).html()
),
sanitizedLinkedText = DOMPurify.sanitize(escapedLinkedText);
var escapedLinkedText = Helper.urls2links(text),
sanitizedLinkedText = DOMPurify.sanitize(
escapedLinkedText, {
ALLOWED_TAGS: ['a'],
ALLOWED_ATTR: ['href', 'rel']
}
);
$plainText.html(sanitizedLinkedText);
$prettyPrint.html(sanitizedLinkedText);
@@ -2575,7 +2644,10 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
// set & parse text
$commentEntryData.html(
DOMPurify.sanitize(
Helper.urls2links(commentText)
Helper.urls2links(commentText), {
ALLOWED_TAGS: ['a'],
ALLOWED_ATTR: ['href', 'rel']
}
)
);
@@ -2891,7 +2963,7 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
for (var i = 0; i < $head.length; i++) {
newDoc.write($head[i].outerHTML);
}
newDoc.write('</head><body><pre>' + DOMPurify.sanitize(paste) + '</pre></body></html>');
newDoc.write('</head><body><pre>' + DOMPurify.sanitize(Helper.htmlEntities(paste)) + '</pre></body></html>');
newDoc.close();
}
@@ -4368,9 +4440,7 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
Uploader.setUnencryptedData('deletetoken', deleteToken);
Uploader.setFailure(function () {
Alert.showError(
I18n._('Could not delete the paste, it was not stored in burn after reading mode.')
);
Alert.showError('Could not delete the paste, it was not stored in burn after reading mode.');
});
Uploader.run();
};
@@ -4386,7 +4456,10 @@ jQuery.PrivateBin = (function($, sjcl, Base64, RawDeflate) {
// first load translations
I18n.loadTranslations();
DOMPurify.setConfig({SAFE_FOR_JQUERY: true});
DOMPurify.setConfig({
ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|magnet):)/i,
SAFE_FOR_JQUERY: true
});
// initialize other modules/"classes"
Alert.init();

File diff suppressed because one or more lines are too long

1
js/purify-2.0.8.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
js/showdown-1.9.1.js Normal file

File diff suppressed because one or more lines are too long

View File

@@ -3,21 +3,56 @@ var common = require('../common');
describe('Alert', function () {
describe('showStatus', function () {
before(function () {
cleanup();
});
jsc.property(
'shows a status message',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
icon = icon.join('');
message = message.join('');
var expected = '<div id="status">' + message + '</div>';
$('body').html(
'<div id="status"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showStatus(message, icon);
var result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows a status message (bootstrap)',
jsc.array(common.jscAlnumString()),
function (message) {
message = message.join('');
var expected = '<div id="status" role="alert" ' +
'class="statusmessage alert alert-info"><span ' +
'class="glyphicon glyphicon-info-sign" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
'<div id="status" role="alert" class="statusmessage ' +
'alert alert-info hidden"><span class="glyphicon ' +
'glyphicon-info-sign" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showStatus(message);
var result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows a status message (bootstrap, custom icon)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
icon = icon.join('');
message = message.join('');
var expected = '<div id="status" role="alert" ' +
'class="statusmessage alert alert-info"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> ' + message + '</div>';
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
'<div id="status" role="alert" class="statusmessage ' +
'alert alert-info hidden"><span class="glyphicon ' +
@@ -32,12 +67,48 @@ describe('Alert', function () {
});
describe('showError', function () {
before(function () {
cleanup();
});
jsc.property(
'shows an error message (basic)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
icon = icon.join('');
message = message.join('');
var expected = '<div id="errormessage">' + message + '</div>';
$('body').html(
'<div id="errormessage"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showError(message, icon);
var result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows an error message',
'shows an error message (bootstrap)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
message = message.join('');
var expected = '<div id="errormessage" role="alert" ' +
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-alert" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showError(message);
var result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows an error message (bootstrap, custom icon)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
@@ -46,7 +117,7 @@ describe('Alert', function () {
var expected = '<div id="errormessage" role="alert" ' +
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> ' + message + '</div>';
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
@@ -61,12 +132,27 @@ describe('Alert', function () {
});
describe('showRemaining', function () {
before(function () {
cleanup();
});
jsc.property(
'shows remaining time (basic)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
'integer',
function (message, string, number) {
message = message.join('');
string = string.join('');
var expected = '<div id="remainingtime" class="">' + string + message + number + '</div>';
$('body').html(
'<div id="remainingtime" class="hidden"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]);
var result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows remaining time',
'shows remaining time (bootstrap)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
'integer',
@@ -76,7 +162,7 @@ describe('Alert', function () {
var expected = '<div id="remainingtime" role="alert" ' +
'class="alert alert-info"><span ' +
'class="glyphicon glyphicon-fire" aria-hidden="true">' +
'</span> ' + string + message + number + '</div>';
'</span> <span>' + string + message + number + '</span></div>';
$('body').html(
'<div id="remainingtime" role="alert" class="hidden ' +
'alert alert-info"><span class="glyphicon ' +
@@ -91,12 +177,30 @@ describe('Alert', function () {
});
describe('showLoading', function () {
before(function () {
cleanup();
});
jsc.property(
'shows a loading message (basic)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (message, icon) {
message = message.join('');
icon = icon.join('');
var defaultMessage = 'Loading…';
if (message.length === 0) {
message = defaultMessage;
}
var expected = '<div id="loadingindicator" class="">' + message + '</div>';
$('body').html(
'<div id="loadingindicator" class="hidden">' + defaultMessage + '</div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showLoading(message, icon);
var result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows a loading message',
'shows a loading message (bootstrap)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (message, icon) {
@@ -109,7 +213,7 @@ describe('Alert', function () {
var expected = '<ul class="nav navbar-nav"><li ' +
'id="loadingindicator" class="navbar-text"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> ' + message + '</li></ul>';
'" aria-hidden="true"></span> <span>' + message + '</span></li></ul>';
$('body').html(
'<ul class="nav navbar-nav"><li id="loadingindicator" ' +
'class="navbar-text hidden"><span class="glyphicon ' +
@@ -125,10 +229,6 @@ describe('Alert', function () {
});
describe('hideLoading', function () {
before(function () {
cleanup();
});
it(
'hides the loading message',
function() {
@@ -150,10 +250,6 @@ describe('Alert', function () {
});
describe('hideMessages', function () {
before(function () {
cleanup();
});
it(
'hides all messages',
function() {
@@ -176,10 +272,6 @@ describe('Alert', function () {
});
describe('setCustomHandler', function () {
before(function () {
cleanup();
});
jsc.property(
'calls a given handler function',
'nat 3',

View File

@@ -4,28 +4,26 @@ var common = require('../common');
describe('AttachmentViewer', function () {
describe('setAttachment, showAttachment, removeAttachment, hideAttachment, hideAttachmentPreview, hasAttachment, getAttachment & moveAttachmentTo', function () {
this.timeout(30000);
before(function () {
cleanup();
});
jsc.property(
'displays & hides data as requested',
common.jscMimeTypes(),
jsc.nearray(common.jscBase64String()),
'string',
'string',
'string',
function (mimeType, base64, filename, prefix, postfix) {
var clean = jsdom(),
data = 'data:' + mimeType + ';base64,' + base64.join(''),
'string',
function (mimeType, rawdata, filename, prefix, postfix) {
let clean = jsdom(),
data = 'data:' + mimeType + ';base64,' + btoa(rawdata),
previewSupported = (
mimeType.substring(0, 6) === 'image/' ||
mimeType.substring(0, 6) === 'audio/' ||
mimeType.substring(0, 6) === 'video/' ||
mimeType.match(/\/pdf/i)
),
results = [];
prefix = prefix.replace(/%(s|d)/g, '%%');
results = [],
result = '';
prefix = prefix.replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%');
$('body').html(
'<div id="attachment" role="alert" class="hidden alert ' +
@@ -45,7 +43,7 @@ describe('AttachmentViewer', function () {
} else {
$.PrivateBin.AttachmentViewer.setAttachment(data);
}
var attachment = $.PrivateBin.AttachmentViewer.getAttachment();
const attachment = $.PrivateBin.AttachmentViewer.getAttachment();
results.push(
$.PrivateBin.AttachmentViewer.hasAttachment() &&
$('#attachment').hasClass('hidden') &&
@@ -72,13 +70,24 @@ describe('AttachmentViewer', function () {
!$('#attachment').hasClass('hidden') &&
(previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden'))
);
var element = $('<div></div>');
let element = $('<div>');
$.PrivateBin.AttachmentViewer.moveAttachmentTo(element, prefix + '%s' + postfix);
// messageIDs with links get a relaxed treatment
if (prefix.indexOf('<a') === -1 && postfix.indexOf('<a') === -1) {
result = $('<textarea>').text((prefix + filename + postfix)).text();
} else {
result = DOMPurify.sanitize(
prefix + $.PrivateBin.Helper.htmlEntities(filename) + postfix, {
ALLOWED_TAGS: ['a', 'i', 'span'],
ALLOWED_ATTR: ['href', 'id']
}
);
}
if (filename.length) {
results.push(
element.children()[0].href === data &&
element.children()[0].getAttribute('download') === filename &&
element.children()[0].text === prefix + filename + postfix
element.children()[0].text === result
);
} else {
results.push(element.children()[0].href === data);

View File

@@ -4,9 +4,6 @@ var common = require('../common');
describe('DiscussionViewer', function () {
describe('handleNotification, prepareNewDiscussion, addComment, finishDiscussion, getReplyMessage, getReplyNickname, getReplyCommentId & highlightComment', function () {
this.timeout(30000);
before(function () {
cleanup();
});
jsc.property(
'displays & hides comments as requested',

View File

@@ -4,9 +4,6 @@ require('../common');
describe('Editor', function () {
describe('show, hide, getText, setText & isPreview', function () {
this.timeout(30000);
before(function () {
cleanup();
});
jsc.property(
'returns text fed into the textarea, handles editor tabs',

View File

@@ -3,10 +3,6 @@ var common = require('../common');
describe('Helper', function () {
describe('secondsToHuman', function () {
after(function () {
cleanup();
});
jsc.property('returns an array with a number and a word', 'integer', function (number) {
var result = $.PrivateBin.Helper.secondsToHuman(number);
return Array.isArray(result) &&
@@ -57,11 +53,11 @@ describe('Helper', function () {
'nearray string',
function (ids, contents) {
var html = '',
result = true;
result = true,
clean = jsdom(html);
ids.forEach(function(item, i) {
html += '<div id="' + item.join('') + '">' + common.htmlEntities(contents[i] || contents[0]) + '</div>';
html += '<div id="' + item.join('') + '">' + $.PrivateBin.Helper.htmlEntities(contents[i] || contents[0]) + '</div>';
});
var clean = jsdom(html);
// TODO: As per https://github.com/tmpvar/jsdom/issues/321 there is no getSelection in jsdom, yet.
// Once there is one, uncomment the block below to actually check the result.
/*
@@ -77,8 +73,8 @@ describe('Helper', function () {
});
describe('urls2links', function () {
after(function () {
cleanup();
before(function () {
cleanup = jsdom();
});
jsc.property(
@@ -94,14 +90,14 @@ describe('Helper', function () {
jsc.elements(['http', 'https', 'ftp']),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
jsc.array(common.jscQueryString()),
jsc.array(common.jscHashString()),
'string',
function (prefix, schema, address, query, fragment, postfix) {
var query = query.join(''),
fragment = fragment.join(''),
url = schema + '://' + address.join('') + '/?' + query + '#' + fragment,
prefix = common.htmlEntities(prefix),
postfix = ' ' + common.htmlEntities(postfix);
query = query.join('');
fragment = fragment.join('');
prefix = $.PrivateBin.Helper.htmlEntities(prefix);
postfix = ' ' + $.PrivateBin.Helper.htmlEntities(postfix);
let url = schema + '://' + address.join('') + '/?' + query + '#' + fragment;
// special cases: When the query string and fragment imply the beginning of an HTML entity, eg. &#0 or &#x
if (
@@ -122,19 +118,15 @@ describe('Helper', function () {
jsc.array(common.jscQueryString()),
'string',
function (prefix, query, postfix) {
var url = 'magnet:?' + query.join('').replace(/^&+|&+$/gm,''),
prefix = common.htmlEntities(prefix),
postfix = common.htmlEntities(postfix);
prefix = $.PrivateBin.Helper.htmlEntities(prefix);
postfix = $.PrivateBin.Helper.htmlEntities(postfix);
let url = 'magnet:?' + query.join('').replace(/^&+|&+$/gm,'');
return prefix + '<a href="' + url + '" rel="nofollow">' + url + '</a> ' + postfix === $.PrivateBin.Helper.urls2links(prefix + url + ' ' + postfix);
}
);
});
describe('sprintf', function () {
after(function () {
cleanup();
});
jsc.property(
'replaces %s in strings with first given parameter',
'string',
@@ -183,9 +175,9 @@ describe('Helper', function () {
'string',
'string',
function (prefix, uint, middle, string, postfix) {
prefix = prefix.replace(/%(s|d)/g, '%%');
middle = middle.replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%');
prefix = prefix.replace(/%(s|d)/g, '');
middle = middle.replace(/%(s|d)/g, '');
postfix = postfix.replace(/%(s|d)/g, '');
var params = [prefix + '%d' + middle + '%s' + postfix, uint, string],
result = prefix + uint + middle + string + postfix;
return result === $.PrivateBin.Helper.sprintf.apply(this, params);
@@ -199,9 +191,9 @@ describe('Helper', function () {
'string',
'string',
function (prefix, uint, middle, string, postfix) {
prefix = prefix.replace(/%(s|d)/g, '%%');
middle = middle.replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%');
prefix = prefix.replace(/%(s|d)/g, '');
middle = middle.replace(/%(s|d)/g, '');
postfix = postfix.replace(/%(s|d)/g, '');
var params = [prefix + '%s' + middle + '%d' + postfix, string, uint],
result = prefix + string + middle + uint + postfix;
return result === $.PrivateBin.Helper.sprintf.apply(this, params);
@@ -211,17 +203,20 @@ describe('Helper', function () {
describe('getCookie', function () {
this.timeout(30000);
before(function () {
cleanup();
});
jsc.property(
'returns the requested cookie',
'nearray asciinestring',
'nearray asciistring',
jsc.nearray(jsc.nearray(common.jscAlnumString())),
jsc.nearray(jsc.nearray(common.jscAlnumString())),
function (labels, values) {
var selectedKey = '', selectedValue = '',
cookieArray = [];
labels.forEach(function(item, i) {
// deliberatly using a non-ascii key for replacing invalid characters
var key = item.replace(/[\s;,=]/g, Array(i+2).join('£')),
value = (values[i] || values[0]).replace(/[\s;,=]/g, '');
var key = item.join(''),
value = (values[i] || values[0]).join('');
cookieArray.push(key + '=' + value);
if (Math.random() < 1 / i || selectedKey === key)
{
@@ -231,6 +226,7 @@ describe('Helper', function () {
});
var clean = jsdom('', {cookie: cookieArray}),
result = $.PrivateBin.Helper.getCookie(selectedKey);
$.PrivateBin.Helper.reset();
clean();
return result === selectedValue;
}
@@ -239,21 +235,19 @@ describe('Helper', function () {
describe('baseUri', function () {
this.timeout(30000);
before(function () {
$.PrivateBin.Helper.reset();
});
jsc.property(
'returns the URL without query & fragment',
common.jscSchemas(),
jsc.elements(['http', 'https']),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscA2zString()),
jsc.array(common.jscQueryString()),
'string',
function (schema, address, query, fragment) {
var expected = schema + '://' + address.join('') + '/',
function (schema, address, path, query, fragment) {
$.PrivateBin.Helper.reset();
var path = path.join('') + (path.length > 0 ? '/' : ''),
expected = schema + '://' + address.join('') + '/' + path,
clean = jsdom('', {url: expected + '?' + query.join('') + '#' + fragment}),
result = $.PrivateBin.Helper.baseUri();
$.PrivateBin.Helper.reset();
clean();
return expected === result;
}
@@ -261,16 +255,16 @@ describe('Helper', function () {
});
describe('htmlEntities', function () {
after(function () {
cleanup();
before(function () {
cleanup = jsdom();
});
jsc.property(
'removes all HTML entities from any given string',
'string',
function (string) {
var result = common.htmlEntities(string);
return !(/[<>"'`=\/]/.test(result)) && !(string.indexOf('&') > -1 && !(/&amp;/.test(result)));
var result = $.PrivateBin.Helper.htmlEntities(string);
return !(/[<>]/.test(result)) && !(string.indexOf('&') > -1 && !(/&amp;/.test(result)));
}
);
});

View File

@@ -3,6 +3,7 @@ var common = require('../common');
describe('I18n', function () {
describe('translate', function () {
this.timeout(30000);
before(function () {
$.PrivateBin.I18n.reset();
});
@@ -32,13 +33,41 @@ describe('I18n', function () {
var fakeAlias = $.PrivateBin.I18n._(fake);
$.PrivateBin.I18n.reset();
if (messageId.indexOf('<a') === -1) {
messageId = $.PrivateBin.Helper.htmlEntities(messageId);
} else {
messageId = DOMPurify.sanitize(
messageId, {
ALLOWED_TAGS: ['a', 'i', 'span'],
ALLOWED_ATTR: ['href', 'id']
}
);
}
return messageId === result && messageId === alias &&
messageId === pluralResult && messageId === pluralAlias &&
messageId === fakeResult && messageId === fakeAlias;
}
);
jsc.property(
'replaces %s in strings with first given parameter',
'replaces %s in strings with first given parameter, encoding all, when no link is in the messageID',
'string',
'(small nearray) string',
'string',
function (prefix, params, postfix) {
prefix = prefix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
params[0] = params[0].replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
const translation = $.PrivateBin.Helper.htmlEntities(prefix + params[0] + postfix);
params.unshift(prefix + '%s' + postfix);
const result = $.PrivateBin.I18n.translate.apply(this, params);
$.PrivateBin.I18n.reset();
const alias = $.PrivateBin.I18n._.apply(this, params);
$.PrivateBin.I18n.reset();
return translation === result && translation === alias;
}
);
jsc.property(
'replaces %s in strings with first given parameter, encoding params only, when a link is part of the messageID',
'string',
'(small nearray) string',
'string',
@@ -46,15 +75,83 @@ describe('I18n', function () {
prefix = prefix.replace(/%(s|d)/g, '%%');
params[0] = params[0].replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%');
var translation = prefix + params[0] + postfix;
params.unshift(prefix + '%s' + postfix);
var result = $.PrivateBin.I18n.translate.apply(this, params);
const translation = DOMPurify.sanitize(
prefix + '<a href="' + params[0] + '"></a>' + postfix, {
ALLOWED_TAGS: ['a', 'i', 'span'],
ALLOWED_ATTR: ['href', 'id']
}
);
params.unshift(prefix + '<a href="%s"></a>' + postfix);
const result = $.PrivateBin.I18n.translate.apply(this, params);
$.PrivateBin.I18n.reset();
var alias = $.PrivateBin.I18n._.apply(this, params);
const alias = $.PrivateBin.I18n._.apply(this, params);
$.PrivateBin.I18n.reset();
return translation === result && translation === alias;
}
);
jsc.property(
'replaces %s in strings with first given parameter into an element, encoding all, when no link is in the messageID',
'string',
'(small nearray) string',
'string',
function (prefix, params, postfix) {
prefix = prefix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
params[0] = params[0].replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
const translation = $('<textarea>').text((prefix + params[0] + postfix)).text();
let args = Array.prototype.slice.call(params);
args.unshift(prefix + '%s' + postfix);
let clean = jsdom();
$('body').html('<div id="i18n"></div>');
args.unshift($('#i18n'));
$.PrivateBin.I18n.translate.apply(this, args);
const result = $('#i18n').text();
$.PrivateBin.I18n.reset();
clean();
clean = jsdom();
$('body').html('<div id="i18n"></div>');
args[0] = $('#i18n');
$.PrivateBin.I18n._.apply(this, args);
const alias = $('#i18n').text();
$.PrivateBin.I18n.reset();
clean();
return translation === result && translation === alias;
}
);
jsc.property(
'replaces %s in strings with first given parameter into an element, encoding params only, when a link is part of the messageID inserted',
'string',
'(small nearray) string',
'string',
function (prefix, params, postfix) {
prefix = prefix.replace(/%(s|d)/g, '%%').trim();
params[0] = params[0].replace(/%(s|d)/g, '%%').trim();
postfix = postfix.replace(/%(s|d)/g, '%%').trim();
const translation = DOMPurify.sanitize(
prefix + '<a href="' + params[0] + '"></a>' + postfix, {
ALLOWED_TAGS: ['a', 'i', 'span'],
ALLOWED_ATTR: ['href', 'id']
}
);
let args = Array.prototype.slice.call(params);
args.unshift(prefix + '<a href="%s"></a>' + postfix);
let clean = jsdom();
$('body').html('<div id="i18n"></div>');
args.unshift($('#i18n'));
$.PrivateBin.I18n.translate.apply(this, args);
const result = $('#i18n').html();
$.PrivateBin.I18n.reset();
clean();
clean = jsdom();
$('body').html('<div id="i18n"></div>');
args[0] = $('#i18n');
$.PrivateBin.I18n._.apply(this, args);
const alias = $('#i18n').html();
$.PrivateBin.I18n.reset();
clean();
return translation === result && translation === alias;
}
);
});
describe('getPluralForm', function () {
@@ -87,14 +184,17 @@ describe('I18n', function () {
'downloads and handles any supported language',
common.jscSupportedLanguages(),
function(language) {
var clean = jsdom('', {url: 'https://privatebin.net/', cookie: ['lang=' + language]});
// cleanup
var clean = jsdom('', {cookie: ['lang=en']});
$.PrivateBin.I18n.reset('en');
$.PrivateBin.I18n.loadTranslations();
clean();
// mock
clean = jsdom('', {cookie: ['lang=' + language]});
$.PrivateBin.I18n.reset(language, require('../../i18n/' + language + '.json'));
var result = $.PrivateBin.I18n.translate('en'),
alias = $.PrivateBin.I18n._('en');
clean();
return language === result && language === alias;
}

View File

@@ -5,18 +5,18 @@ describe('Model', function () {
describe('getExpirationDefault', function () {
before(function () {
$.PrivateBin.Model.reset();
cleanup();
cleanup = jsdom();
});
jsc.property(
'returns the contents of the element with id "pasteExpiration"',
'array asciinestring',
'nearray asciinestring',
'string',
'small nat',
function (keys, value, key) {
keys = keys.map(common.htmlEntities);
value = common.htmlEntities(value);
var content = keys.length > key ? keys[key] : (keys.length > 0 ? keys[0] : 'null'),
keys = keys.map($.PrivateBin.Helper.htmlEntities);
value = $.PrivateBin.Helper.htmlEntities(value);
var content = keys.length > key ? keys[key] : keys[0],
contents = '<select id="pasteExpiration" name="pasteExpiration">';
keys.forEach(function(item) {
contents += '<option value="' + item + '"';
@@ -27,7 +27,7 @@ describe('Model', function () {
});
contents += '</select>';
$('body').html(contents);
var result = common.htmlEntities(
var result = $.PrivateBin.Helper.htmlEntities(
$.PrivateBin.Model.getExpirationDefault()
);
$.PrivateBin.Model.reset();
@@ -39,18 +39,20 @@ describe('Model', function () {
describe('getFormatDefault', function () {
before(function () {
$.PrivateBin.Model.reset();
});
after(function () {
cleanup();
});
jsc.property(
'returns the contents of the element with id "pasteFormatter"',
'array asciinestring',
'nearray asciinestring',
'string',
'small nat',
function (keys, value, key) {
keys = keys.map(common.htmlEntities);
value = common.htmlEntities(value);
var content = keys.length > key ? keys[key] : (keys.length > 0 ? keys[0] : 'null'),
keys = keys.map($.PrivateBin.Helper.htmlEntities);
value = $.PrivateBin.Helper.htmlEntities(value);
var content = keys.length > key ? keys[key] : keys[0],
contents = '<select id="pasteFormatter" name="pasteFormatter">';
keys.forEach(function(item) {
contents += '<option value="' + item + '"';
@@ -61,7 +63,7 @@ describe('Model', function () {
});
contents += '</select>';
$('body').html(contents);
var result = common.htmlEntities(
var result = $.PrivateBin.Helper.htmlEntities(
$.PrivateBin.Model.getFormatDefault()
);
$.PrivateBin.Model.reset();
@@ -74,14 +76,13 @@ describe('Model', function () {
this.timeout(30000);
before(function () {
$.PrivateBin.Model.reset();
cleanup();
});
jsc.property(
'returns the query string without separator, if any',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscQueryString()),
jsc.nearray(common.jscHashString()),
'string',
function (schema, address, query, fragment) {
var queryString = query.join(''),
@@ -145,7 +146,7 @@ describe('Model', function () {
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
jsc.nearray(common.jscBase64String()),
jsc.array(common.jscQueryString()),
jsc.array(common.jscHashString()),
function (schema, address, query, fragment, trail) {
var fragmentString = fragment.join(''),
clean = jsdom('', {
@@ -185,7 +186,6 @@ describe('Model', function () {
describe('getTemplate', function () {
before(function () {
$.PrivateBin.Model.reset();
cleanup();
});
jsc.property(

View File

@@ -4,9 +4,6 @@ var common = require('../common');
describe('PasteStatus', function () {
describe('createPasteNotification', function () {
this.timeout(30000);
before(function () {
cleanup();
});
jsc.property(
'creates a notification after a successfull paste upload',
@@ -24,7 +21,7 @@ describe('PasteStatus', function () {
var expected1 = schema1 + '://' + address1.join('') + '/?' +
encodeURI(query1.join('').replace(/^&+|&+$/gm,'') + '#' + fragment1),
expected2 = schema2 + '://' + address2.join('') + '/?' +
encodeURI(query2.join('')),
encodeURI(query2.join('').replace(/^&+|&+$/gm,'')),
clean = jsdom();
$('body').html('<div><div id="deletelink"></div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
@@ -39,9 +36,6 @@ describe('PasteStatus', function () {
describe('showRemainingTime', function () {
this.timeout(30000);
before(function () {
cleanup();
});
jsc.property(
'shows burn after reading message or remaining time',
@@ -84,10 +78,6 @@ describe('PasteStatus', function () {
});
describe('hideMessages', function () {
before(function () {
cleanup();
});
it(
'hides all messages',
function() {

View File

@@ -4,9 +4,6 @@ var common = require('../common');
describe('PasteViewer', function () {
describe('run, hide, getText, setText, getFormat, setFormat & isPrettyPrinted', function () {
this.timeout(30000);
before(function () {
cleanup();
});
jsc.property(
'displays text according to format',

View File

@@ -6,10 +6,6 @@ describe('Prompt', function () {
// in nodejs -> replace the prompt in the "page" template with a modal
describe('requestPassword & getPassword', function () {
this.timeout(30000);
before(function () {
$.PrivateBin.Model.reset();
cleanup();
});
jsc.property(
'returns the password fed into the dialog',
@@ -26,6 +22,7 @@ describe('Prompt', function () {
'password"></div><button type="submit">Decrypt</button>' +
'</form></div></div></div></div>'
);
$.PrivateBin.Model.reset();
$.PrivateBin.Model.init();
$.PrivateBin.Prompt.init();
$.PrivateBin.Prompt.requestPassword();

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin;

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin;
@@ -17,18 +17,18 @@ use PrivateBin\Persistence\ServerSalt;
use PrivateBin\Persistence\TrafficLimiter;
/**
* PrivateBin
* Controller
*
* Controller, puts it all together.
* Puts it all together.
*/
class PrivateBin
class Controller
{
/**
* version
*
* @const string
*/
const VERSION = '1.2';
const VERSION = '1.2.3';
/**
* minimal required PHP version
@@ -151,7 +151,7 @@ class PrivateBin
}
/**
* initialize privatebin
* initialize PrivateBin
*
* @access private
*/
@@ -368,7 +368,7 @@ class PrivateBin
}
/**
* Display PrivateBin frontend.
* Display frontend.
*
* @access private
*/

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin\Data;

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin\Data;
@@ -15,7 +15,7 @@ namespace PrivateBin\Data;
use Exception;
use PDO;
use PDOException;
use PrivateBin\PrivateBin;
use PrivateBin\Controller;
use stdClass;
/**
@@ -122,7 +122,7 @@ class Database extends AbstractData
}
// create config table if necessary
$db_version = PrivateBin::VERSION;
$db_version = Controller::VERSION;
if (!in_array(self::_sanitizeIdentifier('config'), $tables)) {
self::_createConfigTable();
// if we only needed to create the config table, the DB is older then 0.22
@@ -134,7 +134,7 @@ class Database extends AbstractData
}
// update database structure if necessary
if (version_compare($db_version, PrivateBin::VERSION, '<')) {
if (version_compare($db_version, Controller::VERSION, '<')) {
self::_upgradeDatabase($db_version);
}
} else {
@@ -623,7 +623,7 @@ class Database extends AbstractData
self::_exec(
'INSERT INTO ' . self::_sanitizeIdentifier('config') .
' VALUES(?,?)',
array('VERSION', PrivateBin::VERSION)
array('VERSION', Controller::VERSION)
);
}
@@ -698,7 +698,7 @@ class Database extends AbstractData
self::_exec(
'UPDATE ' . self::_sanitizeIdentifier('config') .
' SET value = ? WHERE id = ?',
array(PrivateBin::VERSION, 'VERSION')
array(Controller::VERSION, 'VERSION')
);
}
}

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin\Data;

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin;

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin;
@@ -125,9 +125,31 @@ class I18n
} else {
$args[0] = self::$_translations[$messageId];
}
// encode any non-integer arguments and the message ID, if it doesn't contain a link
$argsCount = count($args);
if ($argsCount > 1) {
for ($i = 0; $i < $argsCount; ++$i) {
if (($i > 0 && !is_int($args[$i])) || strpos($args[0], '<a') === false) {
$args[$i] = self::encode($args[$i]);
}
}
}
return call_user_func_array('sprintf', $args);
}
/**
* encode HTML entities for output into an HTML5 document
*
* @access public
* @static
* @param string $string
* @return string
*/
public static function encode($string)
{
return htmlspecialchars($string, ENT_QUOTES | ENT_HTML5 | ENT_DISALLOWED, 'UTF-8', false);
}
/**
* loads translations
*

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin;

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin;

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin\Model;

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin\Model;

View File

@@ -7,14 +7,14 @@
* @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.2
* @version 1.2.3
*/
namespace PrivateBin\Model;
use Exception;
use PrivateBin\Controller;
use PrivateBin\Persistence\ServerSalt;
use PrivateBin\PrivateBin;
use PrivateBin\Sjcl;
/**
@@ -35,14 +35,14 @@ class Paste extends AbstractModel
{
$data = $this->_store->read($this->getId());
if ($data === false) {
throw new Exception(PrivateBin::GENERIC_ERROR, 64);
throw new Exception(Controller::GENERIC_ERROR, 64);
}
// check if paste has expired and delete it if neccessary.
if (property_exists($data->meta, 'expire_date')) {
if ($data->meta->expire_date < time()) {
$this->delete();
throw new Exception(PrivateBin::GENERIC_ERROR, 63);
throw new Exception(Controller::GENERIC_ERROR, 63);
}
// We kindly provide the remaining time before expiration (in seconds)
$data->meta->remaining_time = $data->meta->expire_date - time();

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin\Persistence;

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin\Persistence;
@@ -70,23 +70,18 @@ class PurgeLimiter extends AbstractPersistence
return true;
}
$file = 'purge_limiter.php';
$now = time();
$content = '<?php' . PHP_EOL . '$GLOBALS[\'purge_limiter\'] = ' . $now . ';' . PHP_EOL;
if (!self::_exists($file)) {
self::_store($file, $content);
$now = time();
$file = 'purge_limiter.php';
if (self::_exists($file)) {
require self::getPath($file);
$pl = $GLOBALS['purge_limiter'];
if ($pl + self::$_limit >= $now) {
return false;
}
}
$path = self::getPath($file);
require $path;
$pl = $GLOBALS['purge_limiter'];
if ($pl + self::$_limit >= $now) {
$result = false;
} else {
$result = true;
self::_store($file, $content);
}
return $result;
$content = '<?php' . PHP_EOL . '$GLOBALS[\'purge_limiter\'] = ' . $now . ';';
self::_store($file, $content);
return true;
}
}

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin\Persistence;
@@ -83,7 +83,7 @@ class ServerSalt extends AbstractPersistence
self::$_salt = self::generate();
self::_store(
self::$_file,
'<?php /* |' . self::$_salt . '| */ ?>'
'<?php # |' . self::$_salt . '|'
);
}
return self::$_salt;

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin\Persistence;
@@ -101,27 +101,22 @@ class TrafficLimiter extends AbstractPersistence
}
$file = 'traffic_limiter.php';
if (!self::_exists($file)) {
self::_store(
$file,
'<?php' . PHP_EOL .
'$GLOBALS[\'traffic_limiter\'] = array();' . PHP_EOL
);
if (self::_exists($file)) {
require self::getPath($file);
$tl = $GLOBALS['traffic_limiter'];
} else {
$tl = array();
}
$path = self::getPath($file);
require $path;
$now = time();
$tl = $GLOBALS['traffic_limiter'];
// purge file of expired hashes to keep it small
$now = time();
foreach ($tl as $key => $time) {
if ($time + self::$_limit < $now) {
unset($tl[$key]);
}
}
// this hash is used as an array key, hence a shorter hash is used
// this hash is used as an array key, hence a shorter algo is used
$hash = self::getHash('sha256');
if (array_key_exists($hash, $tl) && ($tl[$hash] + self::$_limit >= $now)) {
$result = false;
@@ -132,8 +127,7 @@ class TrafficLimiter extends AbstractPersistence
self::_store(
$file,
'<?php' . PHP_EOL .
'$GLOBALS[\'traffic_limiter\'] = ' .
var_export($tl, true) . ';' . PHP_EOL
'$GLOBALS[\'traffic_limiter\'] = ' . var_export($tl, true) . ';'
);
return $result;
}

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin;

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin;

View File

@@ -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.2
* @version 1.2.3
*/
namespace PrivateBin;

View File

@@ -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.2
* @version 0.0.5 beta PrivateBin 1.2.3
*/
namespace PrivateBin;

View File

@@ -4,7 +4,7 @@ $isCpct = substr($template, 9, 8) === '-compact';
$isDark = substr($template, 9, 5) === '-dark';
$isPage = substr($template, -5) === '-page';
?><!DOCTYPE html>
<html>
<html lang="<?php echo I18n::_('en'); ?>">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
@@ -15,11 +15,11 @@ $isPage = substr($template, -5) === '-page';
<?php
if (!$isDark):
?>
<link type="text/css" rel="stylesheet" href="css/bootstrap/bootstrap-3.3.5.css" />
<link type="text/css" rel="stylesheet" href="css/bootstrap/bootstrap-3.4.1.css" />
<?php
endif;
?>
<link type="text/css" rel="stylesheet" href="css/bootstrap/bootstrap-theme-3.3.5.css" />
<link type="text/css" rel="stylesheet" href="css/bootstrap/bootstrap-theme-3.4.1.css" />
<?php
if ($isDark):
?>
@@ -41,12 +41,12 @@ if ($SYNTAXHIGHLIGHTING):
endif;
?>
<noscript><link type="text/css" rel="stylesheet" href="css/noscript.css" /></noscript>
<script type="text/javascript" data-cfasync="false" src="js/jquery-3.3.1.js" integrity="sha512-+NqPlbbtM1QqiK8ZAo4Yrj2c4lNQoGv8P79DPtKzj++l5jnN39rHA/xsqn8zE9l0uSoxaCdrOgFs6yjyfbBxSg==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/sjcl-1.0.7.js" integrity="sha512-J2eNenPwyfXkMVNMFz9Q54kKfYi5AA3mQWpNgtjSJzsKHtpbhUt/7bvcjGwwmzE8ZUVWMI/ndagIX1lG+SfxGA==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/jquery-3.4.1.js" integrity="sha512-bnIvzh6FU75ZKxp0GXLH9bewza/OIw6dLVh9ICg0gogclmYGguQJWl8U30WpbsGTqbIiAwxTsbe76DErLq5EDQ==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/sjcl-1.0.8.js" integrity="sha512-J2eNenPwyfXkMVNMFz9Q54kKfYi5AA3mQWpNgtjSJzsKHtpbhUt/7bvcjGwwmzE8ZUVWMI/ndagIX1lG+SfxGA==" crossorigin="anonymous"></script>
<?php
if ($QRCODE):
?>
<script async type="text/javascript" data-cfasync="false" src="js/kjua-0.1.2.js" integrity="sha512-hmvfOhcr4J8bjQ2GuNVzfSbuulv72wgQCJpgnXc2+cCHKqvYo8pK2nc0Q4Esem2973zo1radyIMTEkt+xJlhBA==" crossorigin="anonymous"></script>
<script async type="text/javascript" data-cfasync="false" src="js/kjua-0.6.0.js" integrity="sha512-GEEIHvphDt1NmaxzX8X1ZkBiGKXCv+Ofzwi8SMEH5wQVWqdGIvBO/fnxxKZ90RU1bVp6srS68nHIpZo6iVcG9g==" crossorigin="anonymous"></script>
<?php
endif;
if ($ZEROBINCOMPATIBILITY):
@@ -70,12 +70,12 @@ if ($SYNTAXHIGHLIGHTING):
endif;
if ($MARKDOWN):
?>
<script type="text/javascript" data-cfasync="false" src="js/showdown-1.8.6.js" integrity="sha512-YFg2sBCGT00I6X5KzgCLP4VqRlmPMRhkVvJS9oJKk5LxiUzzcjzV5m4fNf6mQMctLrhgS5LFKiFF3vzIuXbjAw==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.5.js" integrity="sha512-IpCJCwlqipmuhbr7fdEOTA4ENcBURsQSDAqXqbr/3dcA2swwJon7D6IStGUQntycGCNCdIM/FdPciBq0gUrLJA==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/showdown-1.9.1.js" integrity="sha512-nRri7kqh3iRLdHbhtjfe8w9eAQPmt+ubH5U88UZyKbz6O9Q0q4haaXF0krOUclKmRJou/kKZYulgBHvHXPqOvg==" crossorigin="anonymous"></script>
<?php
endif;
?>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-C/vlB/eumPPeHhG1yef+INPYUqgFX2wZqKEXTdexDscnUfhXQZxQBvmrURPAgMhElJqlk9Tfn+jILk0d2Ds1DQ==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/purify-2.0.8.js" integrity="sha512-QwcEKGuEmKtMguCO9pqNtUtZqq9b/tJ8gNr5qhY8hykq3zKTlDOvpZAmf6Rs8yH35Bz1ZdctUjj2qEWxT5aXCg==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LqJqykq4XPBKgf0fiUu/4NmxGI7oioFgQFeU2wTF9IHOdQ7wUlsSHw9L5vr40rGj0UBjJaX/u5dF62FSF+GNvg==" crossorigin="anonymous"></script>
<!--[if lt IE 10]>
<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
<![endif]-->
@@ -422,7 +422,7 @@ if (strlen($NOTICE)):
?>
<div role="alert" class="alert alert-info">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
<?php echo htmlspecialchars($NOTICE), PHP_EOL; ?>
<?php echo I18n::encode($NOTICE), PHP_EOL; ?>
</div>
<?php
endif;
@@ -442,11 +442,11 @@ endif;
?>
<div id="status" role="alert" class="statusmessage alert alert-info<?php echo empty($STATUS) ? ' hidden' : '' ?>">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
<?php echo htmlspecialchars($STATUS), PHP_EOL; ?>
<?php echo I18n::encode($STATUS), PHP_EOL; ?>
</div>
<div id="errormessage" role="alert" class="statusmessage<?php echo empty($ERROR) ? ' hidden' : '' ?> alert alert-danger">
<span class="glyphicon glyphicon-alert" aria-hidden="true"></span>
<?php echo htmlspecialchars($ERROR), PHP_EOL; ?>
<?php echo I18n::encode($ERROR), PHP_EOL; ?>
</div>
<noscript>
<div id="noscript" role="alert" class="nonworking alert alert-<?php echo $isDark ? 'error' : 'warning'; ?>">
@@ -463,7 +463,8 @@ endif;
<?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'), PHP_EOL; ?>
<a href="https://www.mozilla.org/firefox/">Firefox</a>,
<a href="https://www.opera.com/">Opera</a>,
<a href="https://www.google.com/chrome">Chrome</a>…
<a href="https://www.google.com/chrome">Chrome</a>…<br />
<span class="small"><?php echo I18n::_('For more information <a href="%s">see this FAQ entry</a>.', 'https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-it-show-me-the-error-privatebin-requires-a-modern-browser-to-work'); ?></span>
</div>
<div id="pastesuccess" role="alert" class="hidden alert alert-success">
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
@@ -472,7 +473,7 @@ endif;
<?php
if (strlen($URLSHORTENER)):
?>
<button id="shortenbutton" data-shortener="<?php echo htmlspecialchars($URLSHORTENER); ?>" type="button" class="btn btn-<?php echo $isDark ? 'warning' : 'primary'; ?>">
<button id="shortenbutton" data-shortener="<?php echo I18n::encode($URLSHORTENER); ?>" type="button" class="btn btn-<?php echo $isDark ? 'warning' : 'primary'; ?>">
<span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'), PHP_EOL; ?>
</button>
<?php
@@ -505,7 +506,7 @@ endif;
<div id="noscript" role="alert" class="nonworking alert alert-info noscript-hide">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<?php echo I18n::_('Loading…'); ?><br />
<span class="small"><?php echo I18n::_('In case this message never disappears please have a look at <a href="https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away">this FAQ for information to troubleshoot</a>.'); ?></span>
<span class="small"><?php echo I18n::_('In case this message never disappears please have a look at <a href="%s">this FAQ for information to troubleshoot</a>.', 'https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-the-loading-message-not-go-away'); ?></span>
</div>
</section>
<footer class="container">

View File

@@ -1,7 +1,7 @@
<?php
use PrivateBin\I18n;
?><!DOCTYPE html>
<html lang="en">
<html lang="<?php echo I18n::_('en'); ?>">
<head>
<meta charset="utf-8" />
<meta name="robots" content="noindex" />
@@ -20,12 +20,12 @@ if ($SYNTAXHIGHLIGHTING):
endif;
endif;
?>
<script type="text/javascript" data-cfasync="false" src="js/jquery-3.3.1.js" integrity="sha512-+NqPlbbtM1QqiK8ZAo4Yrj2c4lNQoGv8P79DPtKzj++l5jnN39rHA/xsqn8zE9l0uSoxaCdrOgFs6yjyfbBxSg==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/sjcl-1.0.7.js" integrity="sha512-J2eNenPwyfXkMVNMFz9Q54kKfYi5AA3mQWpNgtjSJzsKHtpbhUt/7bvcjGwwmzE8ZUVWMI/ndagIX1lG+SfxGA==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/jquery-3.4.1.js" integrity="sha512-bnIvzh6FU75ZKxp0GXLH9bewza/OIw6dLVh9ICg0gogclmYGguQJWl8U30WpbsGTqbIiAwxTsbe76DErLq5EDQ==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/sjcl-1.0.8.js" integrity="sha512-J2eNenPwyfXkMVNMFz9Q54kKfYi5AA3mQWpNgtjSJzsKHtpbhUt/7bvcjGwwmzE8ZUVWMI/ndagIX1lG+SfxGA==" crossorigin="anonymous"></script>
<?php
if ($QRCODE):
?>
<script async type="text/javascript" data-cfasync="false" src="js/kjua-0.1.2.js" integrity="sha512-hmvfOhcr4J8bjQ2GuNVzfSbuulv72wgQCJpgnXc2+cCHKqvYo8pK2nc0Q4Esem2973zo1radyIMTEkt+xJlhBA==" crossorigin="anonymous"></script>
<script async type="text/javascript" data-cfasync="false" src="js/kjua-0.6.0.js" integrity="sha512-GEEIHvphDt1NmaxzX8X1ZkBiGKXCv+Ofzwi8SMEH5wQVWqdGIvBO/fnxxKZ90RU1bVp6srS68nHIpZo6iVcG9g==" crossorigin="anonymous"></script>
<?php
endif;
if ($ZEROBINCOMPATIBILITY):
@@ -48,12 +48,12 @@ if ($SYNTAXHIGHLIGHTING):
endif;
if ($MARKDOWN):
?>
<script type="text/javascript" data-cfasync="false" src="js/showdown-1.8.6.js" integrity="sha512-YFg2sBCGT00I6X5KzgCLP4VqRlmPMRhkVvJS9oJKk5LxiUzzcjzV5m4fNf6mQMctLrhgS5LFKiFF3vzIuXbjAw==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.5.js" integrity="sha512-IpCJCwlqipmuhbr7fdEOTA4ENcBURsQSDAqXqbr/3dcA2swwJon7D6IStGUQntycGCNCdIM/FdPciBq0gUrLJA==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/showdown-1.9.1.js" integrity="sha512-nRri7kqh3iRLdHbhtjfe8w9eAQPmt+ubH5U88UZyKbz6O9Q0q4haaXF0krOUclKmRJou/kKZYulgBHvHXPqOvg==" crossorigin="anonymous"></script>
<?php
endif;
?>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-C/vlB/eumPPeHhG1yef+INPYUqgFX2wZqKEXTdexDscnUfhXQZxQBvmrURPAgMhElJqlk9Tfn+jILk0d2Ds1DQ==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/purify-2.0.8.js" integrity="sha512-QwcEKGuEmKtMguCO9pqNtUtZqq9b/tJ8gNr5qhY8hykq3zKTlDOvpZAmf6Rs8yH35Bz1ZdctUjj2qEWxT5aXCg==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LqJqykq4XPBKgf0fiUu/4NmxGI7oioFgQFeU2wTF9IHOdQ7wUlsSHw9L5vr40rGj0UBjJaX/u5dF62FSF+GNvg==" crossorigin="anonymous"></script>
<!--[if lt IE 10]>
<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
<![endif]-->
@@ -73,26 +73,28 @@ endif;
<?php
if (strlen($NOTICE)):
?>
<span class="blink">▶</span> <?php echo htmlspecialchars($NOTICE);
<span class="blink">▶</span> <?php echo I18n::encode($NOTICE);
endif;
?>
</div>
<h1 class="title reloadlink"><?php echo I18n::_($NAME); ?></h1><br />
<h2 class="title"><?php echo I18n::_('Because ignorance is bliss'); ?></h2><br />
<h3 class="title"><?php echo $VERSION; ?></h3>
<noscript><div id="noscript" class="nonworking"><?php echo I18n::_('JavaScript is required for %s to work.<br />Sorry for the inconvenience.', I18n::_($NAME)); ?></div></noscript>
<noscript><div id="noscript" class="nonworking"><?php echo I18n::_('JavaScript is required for %s to work. Sorry for the inconvenience.', I18n::_($NAME)); ?></div></noscript>
<div id="oldienotice" class="nonworking"><?php echo I18n::_('%s requires a modern browser to work.', I18n::_($NAME)); ?></div>
<div id="ienotice"><?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'), PHP_EOL; ?>
<div id="ienotice">
<?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'), PHP_EOL; ?>
<a href="https://www.mozilla.org/firefox/">Firefox</a>,
<a href="https://www.opera.com/">Opera</a>,
<a href="https://www.google.com/chrome">Chrome</a>…
<a href="https://www.google.com/chrome">Chrome</a>…<br />
<span class="small"><?php echo I18n::_('For more information <a href="%s">see this FAQ entry</a>.', 'https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-it-show-me-the-error-privatebin-requires-a-modern-browser-to-work'); ?></span>
</div>
</header>
<section>
<article>
<div id="loadingindicator" class="hidden"><?php echo I18n::_('Loading…'); ?></div>
<div id="status"><?php echo htmlspecialchars($STATUS); ?></div>
<div id="errormessage" class="hidden"><?php echo htmlspecialchars($ERROR); ?></div>
<div id="status"><?php echo I18n::encode($STATUS); ?></div>
<div id="errormessage" class="hidden"><?php echo I18n::encode($ERROR); ?></div>
<div id="toolbar">
<button id="newbutton" class="reloadlink hidden"><img src="img/icon_new.png" width="11" height="15" alt="" /><?php echo I18n::_('New'); ?></button>
<button id="retrybutton" class="reloadlink hidden"><?php echo I18n::_('Retry'), PHP_EOL; ?></button>
@@ -200,7 +202,7 @@ endif;
<?php
if (strlen($URLSHORTENER)):
?>
<button id="shortenbutton" data-shortener="<?php echo htmlspecialchars($URLSHORTENER); ?>"><img src="img/icon_shorten.png" width="13" height="15" /><?php echo I18n::_('Shorten URL'); ?></button>
<button id="shortenbutton" data-shortener="<?php echo I18n::encode($URLSHORTENER); ?>"><img src="img/icon_shorten.png" width="13" height="15" /><?php echo I18n::_('Shorten URL'); ?></button>
<?php
endif;
?>
@@ -252,7 +254,7 @@ endif;
<section class="container">
<div id="noscript" role="alert" class="nonworking alert alert-info noscript-hide"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true">
<span> <?php echo I18n::_('Loading…'); ?></span><br>
<span class="small"><?php echo I18n::_('In case this message never disappears please have a look at <a href="https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away">this FAQ for information to troubleshoot</a>.'); ?></span>
<span class="small"><?php echo I18n::_('In case this message never disappears please have a look at <a href="%s">this FAQ for information to troubleshoot</a>.', 'https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-the-loading-message-not-go-away'); ?></span>
</div>
</section>
</body>

View File

@@ -1,11 +1,11 @@
<?php
use PrivateBin\Controller;
use PrivateBin\Data\Filesystem;
use PrivateBin\Persistence\ServerSalt;
use PrivateBin\Persistence\TrafficLimiter;
use PrivateBin\PrivateBin;
class PrivateBinTest extends PHPUnit_Framework_TestCase
class ControllerTest extends PHPUnit_Framework_TestCase
{
protected $_model;
@@ -49,7 +49,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
public function testView()
{
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertContains(
@@ -74,7 +74,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
Helper::createIniFile(CONF, $options);
$_COOKIE['lang'] = 'de';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertContains(
@@ -95,7 +95,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
Helper::createIniFile(CONF, $options);
$_COOKIE['lang'] = 'de';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertContains(
@@ -116,7 +116,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
Helper::createIniFile(CONF, $options);
$_COOKIE['lang'] = 'de';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertRegExp(
@@ -139,7 +139,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new PrivateBin;
new Controller;
ob_end_clean();
$this->assertFileExists($file, 'htaccess recreated');
@@ -152,7 +152,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
public function testConf()
{
file_put_contents(CONF, '');
new PrivateBin;
new Controller;
}
/**
@@ -168,7 +168,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -196,7 +196,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REMOTE_ADDR'] = '::1';
TrafficLimiter::canPass();
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -224,7 +224,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -246,7 +246,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -274,7 +274,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -298,7 +298,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REMOTE_ADDR'] = '::1';
$time = time();
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -329,7 +329,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REMOTE_ADDR'] = '::1';
$time = time();
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -359,7 +359,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -387,7 +387,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -409,7 +409,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -432,7 +432,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REMOTE_ADDR'] = '::1';
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not exists before posting data');
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -469,7 +469,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REMOTE_ADDR'] = '::1';
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not exists before posting data');
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -487,11 +487,11 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new PrivateBin;
new Controller;
ob_end_clean();
$this->_model->delete(Helper::getPasteId());
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -513,7 +513,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -544,7 +544,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REMOTE_ADDR'] = '::1';
$this->_model->create(Helper::getPasteId(), Helper::getPaste());
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -568,7 +568,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REMOTE_ADDR'] = '::1';
$this->_model->create(Helper::getPasteId(), Helper::getPaste());
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -592,7 +592,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REMOTE_ADDR'] = '::1';
$this->_model->create(Helper::getPasteId(), Helper::getPaste());
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -617,7 +617,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$paste = Helper::getPaste(array('opendiscussion' => false));
$this->_model->create(Helper::getPasteId(), $paste);
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -640,7 +640,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -666,7 +666,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -682,7 +682,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['QUERY_STRING'] = 'foo';
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -698,7 +698,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['QUERY_STRING'] = Helper::getPasteId();
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -716,7 +716,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['QUERY_STRING'] = Helper::getPasteId();
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -734,7 +734,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['QUERY_STRING'] = Helper::getPasteId();
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -762,7 +762,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['QUERY_STRING'] = Helper::getPasteId();
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -792,7 +792,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['QUERY_STRING'] = Helper::getPasteId();
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -818,7 +818,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_GET['pasteid'] = Helper::getPasteId();
$_GET['deletetoken'] = hash_hmac('sha256', Helper::getPasteId(), $paste->meta->salt);
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertRegExp(
@@ -838,7 +838,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_GET['pasteid'] = 'foo';
$_GET['deletetoken'] = 'bar';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertRegExp(
@@ -857,7 +857,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_GET['pasteid'] = Helper::getPasteId();
$_GET['deletetoken'] = 'bar';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertRegExp(
@@ -876,7 +876,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_GET['pasteid'] = Helper::getPasteId();
$_GET['deletetoken'] = 'bar';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertRegExp(
@@ -900,7 +900,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
$_SERVER['REQUEST_METHOD'] = 'POST';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -920,7 +920,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
$_SERVER['REQUEST_METHOD'] = 'POST';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -940,7 +940,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_GET['pasteid'] = Helper::getPasteId();
$_GET['deletetoken'] = 'does not matter in this context, but has to be set';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertRegExp(
@@ -963,7 +963,7 @@ class PrivateBinTest extends PHPUnit_Framework_TestCase
$_GET['pasteid'] = Helper::getPasteId();
$_GET['deletetoken'] = hash_hmac('sha256', Helper::getPasteId(), ServerSalt::get());
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertRegExp(

View File

@@ -2,9 +2,9 @@
use PrivateBin\Data\Database;
require_once 'PrivateBinTest.php';
require_once 'ControllerTest.php';
class PrivateBinWithDbTest extends PrivateBinTest
class ControllerWithDbTest extends ControllerTest
{
private $_options = array(
'usr' => null,

View File

@@ -1,7 +1,7 @@
<?php
use PrivateBin\Controller;
use PrivateBin\Data\Database;
use PrivateBin\PrivateBin;
class DatabaseTest extends PHPUnit_Framework_TestCase
{
@@ -318,7 +318,7 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
$statement->execute(array('VERSION'));
$result = $statement->fetch(PDO::FETCH_ASSOC);
$statement->closeCursor();
$this->assertEquals(PrivateBin::VERSION, $result['value']);
$this->assertEquals(Controller::VERSION, $result['value']);
Helper::rmDir($this->_path);
}
}

View File

@@ -143,6 +143,17 @@ class I18nTest extends PHPUnit_Framework_TestCase
$this->assertEquals('some string + 1', I18n::_('some %s + %d', 'string', 1), 'browser language en');
}
public function testHtmlEntityEncoding()
{
$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'foobar';
I18n::loadTranslations();
$input = '&<>"\'/`=';
$result = htmlspecialchars($input, ENT_QUOTES | ENT_HTML5 | ENT_DISALLOWED, 'UTF-8', false);
$this->assertEquals($result, I18n::encode($input), 'encodes HTML entities');
$this->assertEquals('<a>some ' . $result . ' + 1</a>', I18n::_('<a>some %s + %d</a>', $input, 1), 'encodes parameters in translations');
$this->assertEquals($result . $result, I18n::_($input . '%s', $input), 'encodes message ID as well, when no link');
}
public function testMessageIdsExistInAllLanguages()
{
$messageIds = array();

View File

@@ -1,8 +1,8 @@
<?php
use PrivateBin\Controller;
use PrivateBin\Data\Filesystem;
use PrivateBin\Persistence\ServerSalt;
use PrivateBin\PrivateBin;
use PrivateBin\Request;
class JsonApiTest extends PHPUnit_Framework_TestCase
@@ -53,7 +53,7 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -86,7 +86,7 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
$_SERVER['REQUEST_METHOD'] = 'PUT';
$_SERVER['REMOTE_ADDR'] = '::1';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
unlink($file);
@@ -120,7 +120,7 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
$_SERVER['REQUEST_METHOD'] = 'DELETE';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
unlink($file);
@@ -144,7 +144,7 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
$_SERVER['REQUEST_METHOD'] = 'POST';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -166,7 +166,7 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
$_SERVER['QUERY_STRING'] = Helper::getPasteId();
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$response = json_decode($content, true);
@@ -192,7 +192,7 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
$this->_model->create(Helper::getPasteId(), $paste);
$_GET['jsonld'] = 'paste';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertEquals(str_replace(
@@ -211,7 +211,7 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
$this->_model->create(Helper::getPasteId(), $paste);
$_GET['jsonld'] = 'comment';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertEquals(str_replace(
@@ -230,7 +230,7 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
$this->_model->create(Helper::getPasteId(), $paste);
$_GET['jsonld'] = 'pastemeta';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertEquals(str_replace(
@@ -249,7 +249,7 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
$this->_model->create(Helper::getPasteId(), $paste);
$_GET['jsonld'] = 'commentmeta';
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertEquals(str_replace(
@@ -268,7 +268,7 @@ class JsonApiTest extends PHPUnit_Framework_TestCase
$this->_model->create(Helper::getPasteId(), $paste);
$_GET['jsonld'] = CONF;
ob_start();
new PrivateBin;
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertEquals('{}', $content, 'does not output nasty data');

View File

@@ -25,10 +25,10 @@ class PurgeLimiterTest extends PHPUnit_Framework_TestCase
public function testLimit()
{
// initialize it
PurgeLimiter::setLimit(1);
PurgeLimiter::canPurge();
// try setting it
PurgeLimiter::setLimit(1);
$this->assertEquals(false, PurgeLimiter::canPurge());
sleep(2);
$this->assertEquals(true, PurgeLimiter::canPurge());

View File

@@ -69,6 +69,12 @@ $ npm install jsverify jsdom@9 jsdom-global@2 mime-types
Note: If you use a distribution that provides nodeJS >= 6, then you can install
the latest jsdom and jsdom-global packages and don't need to use @9 and @2.
Note: When running Ubuntu 18.04, there is [a bug](https://bugs.launchpad.net/ubuntu/+source/nodejs/+bug/1779863)
due to the mismatch of nodejs 8 and OpenSSL 1.1 library it was compiled against.
Until this is solved, you may have to use [a PPA of nodejs, compiled against
OpenSSL 1.0](https://launchpad.net/~ddstreet/+archive/ubuntu/lp1779863) or use
nodejs 10 or later from a different source.
To run the tests, just change into the `js` directory and run istanbul:
```console
$ cd PrivateBin/js

View File

@@ -12,6 +12,7 @@ return array(
'Identicon\\Generator\\ImageMagickGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/ImageMagickGenerator.php',
'Identicon\\Identicon' => $vendorDir . '/yzalis/identicon/src/Identicon/Identicon.php',
'PrivateBin\\Configuration' => $baseDir . '/lib/Configuration.php',
'PrivateBin\\Controller' => $baseDir . '/lib/Controller.php',
'PrivateBin\\Data\\AbstractData' => $baseDir . '/lib/Data/AbstractData.php',
'PrivateBin\\Data\\Database' => $baseDir . '/lib/Data/Database.php',
'PrivateBin\\Data\\Filesystem' => $baseDir . '/lib/Data/Filesystem.php',
@@ -27,7 +28,6 @@ return array(
'PrivateBin\\Persistence\\PurgeLimiter' => $baseDir . '/lib/Persistence/PurgeLimiter.php',
'PrivateBin\\Persistence\\ServerSalt' => $baseDir . '/lib/Persistence/ServerSalt.php',
'PrivateBin\\Persistence\\TrafficLimiter' => $baseDir . '/lib/Persistence/TrafficLimiter.php',
'PrivateBin\\PrivateBin' => $baseDir . '/lib/PrivateBin.php',
'PrivateBin\\Request' => $baseDir . '/lib/Request.php',
'PrivateBin\\Sjcl' => $baseDir . '/lib/Sjcl.php',
'PrivateBin\\View' => $baseDir . '/lib/View.php',

View File

@@ -41,6 +41,7 @@ class ComposerStaticInitDontChange
'Identicon\\Generator\\ImageMagickGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/ImageMagickGenerator.php',
'Identicon\\Identicon' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Identicon.php',
'PrivateBin\\Configuration' => __DIR__ . '/../..' . '/lib/Configuration.php',
'PrivateBin\\Controller' => __DIR__ . '/../..' . '/lib/Controller.php',
'PrivateBin\\Data\\AbstractData' => __DIR__ . '/../..' . '/lib/Data/AbstractData.php',
'PrivateBin\\Data\\Database' => __DIR__ . '/../..' . '/lib/Data/Database.php',
'PrivateBin\\Data\\Filesystem' => __DIR__ . '/../..' . '/lib/Data/Filesystem.php',
@@ -56,7 +57,6 @@ class ComposerStaticInitDontChange
'PrivateBin\\Persistence\\PurgeLimiter' => __DIR__ . '/../..' . '/lib/Persistence/PurgeLimiter.php',
'PrivateBin\\Persistence\\ServerSalt' => __DIR__ . '/../..' . '/lib/Persistence/ServerSalt.php',
'PrivateBin\\Persistence\\TrafficLimiter' => __DIR__ . '/../..' . '/lib/Persistence/TrafficLimiter.php',
'PrivateBin\\PrivateBin' => __DIR__ . '/../..' . '/lib/PrivateBin.php',
'PrivateBin\\Request' => __DIR__ . '/../..' . '/lib/Request.php',
'PrivateBin\\Sjcl' => __DIR__ . '/../..' . '/lib/Sjcl.php',
'PrivateBin\\View' => __DIR__ . '/../..' . '/lib/View.php',