mirror of
https://github.com/PrivateBin/PrivateBin.git
synced 2025-09-26 19:20:57 -04:00
Merge pull request #1591 from PrivateBin/drop-legacy-zerobin-support
drop legacy paste format support
This commit is contained in:
commit
7888107e4e
33 changed files with 391 additions and 2010 deletions
|
@ -15,14 +15,12 @@ coding_style:
|
|||
additive: false
|
||||
concatenation: true
|
||||
build:
|
||||
image: default-bionic
|
||||
environment:
|
||||
php:
|
||||
version: 7.4
|
||||
version: 8.2
|
||||
tests:
|
||||
override:
|
||||
-
|
||||
command: 'composer require google/cloud-storage && cd tst && ../vendor/bin/phpunit'
|
||||
- command: 'composer require google/cloud-storage && cd tst && XDEBUG_MODE=coverage ../vendor/bin/phpunit'
|
||||
coverage:
|
||||
file: 'tst/log/coverage-clover.xml'
|
||||
format: 'clover'
|
||||
|
|
|
@ -2,7 +2,12 @@
|
|||
|
||||
## 2.0.0 (not yet released)
|
||||
* ADDED: Error logging in database and filesystem backend (#1554)
|
||||
* CHANGED: Remove page template (#265)
|
||||
* ADDED: Statistics on v1 pastes in administration script and option to delete them
|
||||
* CHANGED: Removed page template (#265)
|
||||
* CHANGED: Removed support for ZeroBin & v1 pastes - since release 1.3 the v2 format is used (#551)
|
||||
* CHANGED: Removed use of base64 & rawinflate libraries (#551)
|
||||
* CHANGED: Removed support for `privatebin_data`, `privatebin_db` & `zerobin_db` model class configurations, must be replaced with `Filesystem` or `Database` in `cfg/conf.php`, if still present
|
||||
* CHANGED: Removed unused columns in database schema of tables `paste` & `comment`
|
||||
* CHANGED: Jdenticons are now used as the default icons
|
||||
* CHANGED: Upgrading libraries to: jdenticon 2.0.0
|
||||
* CHANGED: Minimum required PHP version is 7.4, due to a change in the jdenticon library
|
||||
|
|
|
@ -12,9 +12,7 @@ Data is encrypted and decrypted in the browser using 256bit AES in
|
|||
This is a fork of ZeroBin, originally developed by
|
||||
[Sébastien Sauvage](https://github.com/sebsauvage/ZeroBin). PrivateBin was
|
||||
refactored to allow easier and cleaner extensions and has many additional
|
||||
features. It is, however, still fully compatible to the original ZeroBin 0.19
|
||||
data storage scheme. Therefore, such installations can be upgraded to PrivateBin
|
||||
without losing any data.
|
||||
features.
|
||||
|
||||
## What PrivateBin provides
|
||||
|
||||
|
|
|
@ -72,20 +72,6 @@ class Administration
|
|||
exit("paste $pasteId successfully deleted" . PHP_EOL);
|
||||
}
|
||||
|
||||
/**
|
||||
* lists all stored paste IDs
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
private function _list_ids()
|
||||
{
|
||||
$ids = $this->_store->getAllPastes();
|
||||
foreach ($ids as $pasteid) {
|
||||
echo $pasteid, PHP_EOL;
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes all stored pastes (regardless of expiration)
|
||||
*
|
||||
|
@ -101,6 +87,29 @@ class Administration
|
|||
exit("All pastes successfully deleted" . PHP_EOL);
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes all unsupported v1 pastes (regardless of expiration)
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
private function _delete_v1()
|
||||
{
|
||||
$ids = $this->_store->getAllPastes();
|
||||
foreach ($ids as $pasteid) {
|
||||
try {
|
||||
$paste = $this->_store->read($pasteid);
|
||||
} catch (Exception $e) {
|
||||
echo "Error reading paste {$pasteid}: ", $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
if (array_key_exists('adata', $paste)) {
|
||||
continue;
|
||||
}
|
||||
echo "Deleting v1 paste ID: $pasteid" . PHP_EOL;
|
||||
$this->_store->delete($pasteid);
|
||||
}
|
||||
exit("All unsupported legacy v1 pastes successfully deleted" . PHP_EOL);
|
||||
}
|
||||
|
||||
/**
|
||||
* removes empty directories, if current storage model uses Filesystem
|
||||
*
|
||||
|
@ -153,11 +162,13 @@ class Administration
|
|||
{
|
||||
echo <<<'EOT'
|
||||
Usage:
|
||||
administration [--delete <paste id> | --delete-all | --empty-dirs | --help | --list-ids | --purge | --statistics]
|
||||
administration [--delete <paste id> | --delete-all | --delete-v1 |
|
||||
--empty-dirs | --help | --list-ids | --purge | --statistics]
|
||||
|
||||
Options:
|
||||
-d, --delete deletes the requested paste ID
|
||||
--delete-all deletes all paste IDs
|
||||
--delete-all deletes all pastes
|
||||
--delete-v1 deletes all unsupported v1 pastes
|
||||
-e, --empty-dirs removes empty directories (only if Filesystem storage is
|
||||
configured)
|
||||
-h, --help displays this help message
|
||||
|
@ -168,6 +179,20 @@ EOT, PHP_EOL;
|
|||
exit($code);
|
||||
}
|
||||
|
||||
/**
|
||||
* lists all stored paste IDs
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
private function _list_ids()
|
||||
{
|
||||
$ids = $this->_store->getAllPastes();
|
||||
foreach ($ids as $pasteid) {
|
||||
echo $pasteid, PHP_EOL;
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* return option for given short or long keyname, if it got set
|
||||
*
|
||||
|
@ -208,7 +233,7 @@ EOT, PHP_EOL;
|
|||
self::_help(2);
|
||||
}
|
||||
|
||||
$this->_opts = getopt('hd:epsl', array('help', 'delete:', 'empty-dirs', 'purge', 'statistics', 'list-ids', 'delete-all'));
|
||||
$this->_opts = getopt('hd:elps', array('help', 'delete:', 'delete-all', 'delete-v1', 'empty-dirs', 'list-ids', 'purge', 'statistics'));
|
||||
|
||||
if (!$this->_opts) {
|
||||
self::_error_echo('unsupported arguments given');
|
||||
|
@ -229,6 +254,7 @@ EOT, PHP_EOL;
|
|||
'damaged' => 0,
|
||||
'discussion' => 0,
|
||||
'expired' => 0,
|
||||
'legacy' => 0,
|
||||
'md' => 0,
|
||||
'percent' => 1,
|
||||
'plain' => 0,
|
||||
|
@ -265,13 +291,12 @@ EOT, PHP_EOL;
|
|||
}
|
||||
|
||||
if (array_key_exists('adata', $paste)) {
|
||||
$format = $paste['adata'][1];
|
||||
$discussion = $paste['adata'][2];
|
||||
$burn = $paste['adata'][3];
|
||||
$format = $paste['adata'][Paste::ADATA_FORMATTER];
|
||||
$discussion = $paste['adata'][Paste::ADATA_OPEN_DISCUSSION];
|
||||
$burn = $paste['adata'][Paste::ADATA_BURN_AFTER_READING];
|
||||
} else {
|
||||
$format = array_key_exists('formatter', $paste['meta']) ? $paste['meta']['formatter'] : 'plaintext';
|
||||
$discussion = array_key_exists('opendiscussion', $paste['meta']) ? $paste['meta']['opendiscussion'] : false;
|
||||
$burn = array_key_exists('burnafterreading', $paste['meta']) ? $paste['meta']['burnafterreading'] : false;
|
||||
echo "Unsupported v1 paste ", $pasteid, PHP_EOL;
|
||||
++$counters['legacy'];
|
||||
}
|
||||
|
||||
if ($format === 'plaintext') {
|
||||
|
@ -308,6 +333,9 @@ Plain Text:\t\t{$counters['plain']}
|
|||
Source Code:\t\t{$counters['syntax']}
|
||||
Markdown:\t\t{$counters['md']}
|
||||
EOT, PHP_EOL;
|
||||
if ($counters['legacy'] > 0) {
|
||||
echo "Legacy v1:\t\t{$counters['legacy']}", PHP_EOL;
|
||||
}
|
||||
if ($counters['damaged'] > 0) {
|
||||
echo "Damaged:\t\t{$counters['damaged']}", PHP_EOL;
|
||||
}
|
||||
|
@ -340,14 +368,20 @@ EOT, PHP_EOL;
|
|||
$class = 'PrivateBin\\Data\\' . $this->_conf->getKey('class', 'model');
|
||||
$this->_store = new $class($this->_conf->getSection('model_options'));
|
||||
|
||||
if ($this->_option('l', 'list-ids') !== null) {
|
||||
$this->_list_ids();
|
||||
if (($pasteId = $this->_option('d', 'delete')) !== null) {
|
||||
$this->_delete($pasteId);
|
||||
}
|
||||
|
||||
if ($this->_option(null, 'delete-all') !== null) {
|
||||
$this->_delete_all();
|
||||
}
|
||||
if (($pasteId = $this->_option('d', 'delete')) !== null) {
|
||||
$this->_delete($pasteId);
|
||||
|
||||
if ($this->_option(null, 'delete-v1') !== null) {
|
||||
$this->_delete_v1();
|
||||
}
|
||||
|
||||
if ($this->_option('l', 'list-ids') !== null) {
|
||||
$this->_list_ids();
|
||||
}
|
||||
|
||||
if ($this->_option('p', 'purge') !== null) {
|
||||
|
|
|
@ -124,11 +124,6 @@ languageselection = false
|
|||
; The recommended and default used CSP is:
|
||||
; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'wasm-unsafe-eval'; style-src 'self'; font-src 'self'; frame-ancestors 'none'; frame-src blob:; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-modals allow-downloads"
|
||||
|
||||
; stay compatible with PrivateBin Alpha 0.19, less secure
|
||||
; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of
|
||||
; sha256 in HMAC for the deletion token
|
||||
; zerobincompatibility = false
|
||||
|
||||
; Enable or disable the warning message when the site is served over an insecure
|
||||
; connection (insecure HTTP instead of HTTPS), defaults to true.
|
||||
; Secure transport methods like Tor and I2P domains are automatically whitelisted.
|
||||
|
|
|
@ -177,11 +177,7 @@ CREATE TABLE prefix_paste (
|
|||
dataid CHAR(16) NOT NULL,
|
||||
data MEDIUMBLOB,
|
||||
expiredate INT,
|
||||
opendiscussion INT,
|
||||
burnafterreading INT,
|
||||
meta TEXT,
|
||||
attachment MEDIUMBLOB,
|
||||
attachmentname BLOB,
|
||||
PRIMARY KEY (dataid)
|
||||
);
|
||||
|
||||
|
@ -190,7 +186,6 @@ CREATE TABLE prefix_comment (
|
|||
pasteid CHAR(16),
|
||||
parentid CHAR(16),
|
||||
data BLOB,
|
||||
nickname BLOB,
|
||||
vizhash BLOB,
|
||||
postdate INT,
|
||||
PRIMARY KEY (dataid)
|
||||
|
|
237
js/base64-1.7.js
237
js/base64-1.7.js
|
@ -1,237 +0,0 @@
|
|||
/*
|
||||
* $Id: base64.js,v 1.7 2012/08/23 10:30:18 dankogai Exp dankogai $
|
||||
*
|
||||
* Licensed under the MIT license.
|
||||
* https://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
* References:
|
||||
* https://en.wikipedia.org/wiki/Base64
|
||||
*/
|
||||
|
||||
(function(global){
|
||||
|
||||
var b64chars
|
||||
= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
|
||||
var b64charcodes = function(){
|
||||
var a = [];
|
||||
var codeA = 'A'.charCodeAt(0);
|
||||
var codea = 'a'.charCodeAt(0);
|
||||
var code0 = '0'.charCodeAt(0);
|
||||
for (var i = 0; i < 26; i ++) a.push(codeA + i);
|
||||
for (var i = 0; i < 26; i ++) a.push(codea + i);
|
||||
for (var i = 0; i < 10; i ++) a.push(code0 + i);
|
||||
a.push('+'.charCodeAt(0));
|
||||
a.push('/'.charCodeAt(0));
|
||||
return a;
|
||||
}();
|
||||
|
||||
var b64tab = function(bin){
|
||||
var t = {};
|
||||
for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i;
|
||||
return t;
|
||||
}(b64chars);
|
||||
|
||||
var stringToArray = function(s){
|
||||
var a = [];
|
||||
for (var i = 0, l = s.length; i < l; i ++) a[i] = s.charCodeAt(i);
|
||||
return a;
|
||||
};
|
||||
|
||||
var convertUTF8ArrayToBase64 = function(bin){
|
||||
var padlen = 0;
|
||||
while (bin.length % 3){
|
||||
bin.push(0);
|
||||
padlen++;
|
||||
};
|
||||
var b64 = [];
|
||||
for (var i = 0, l = bin.length; i < l; i += 3){
|
||||
var c0 = bin[i], c1 = bin[i+1], c2 = bin[i+2];
|
||||
if (c0 >= 256 || c1 >= 256 || c2 >= 256)
|
||||
throw 'unsupported character found';
|
||||
var n = (c0 << 16) | (c1 << 8) | c2;
|
||||
b64.push(
|
||||
b64charcodes[ n >>> 18],
|
||||
b64charcodes[(n >>> 12) & 63],
|
||||
b64charcodes[(n >>> 6) & 63],
|
||||
b64charcodes[ n & 63]
|
||||
);
|
||||
}
|
||||
while (padlen--) b64[b64.length - padlen - 1] = '='.charCodeAt(0);
|
||||
return chunkStringFromCharCodeApply(b64);
|
||||
};
|
||||
|
||||
var convertBase64ToUTF8Array = function(b64){
|
||||
b64 = b64.replace(/[^A-Za-z0-9+\/]+/g, '');
|
||||
var bin = [];
|
||||
var padlen = b64.length % 4;
|
||||
for (var i = 0, l = b64.length; i < l; i += 4){
|
||||
var n = ((b64tab[b64.charAt(i )] || 0) << 18)
|
||||
| ((b64tab[b64.charAt(i+1)] || 0) << 12)
|
||||
| ((b64tab[b64.charAt(i+2)] || 0) << 6)
|
||||
| ((b64tab[b64.charAt(i+3)] || 0));
|
||||
bin.push(
|
||||
( n >> 16 ),
|
||||
( (n >> 8) & 0xff ),
|
||||
( n & 0xff )
|
||||
);
|
||||
}
|
||||
bin.length -= [0,0,2,1][padlen];
|
||||
return bin;
|
||||
};
|
||||
|
||||
var convertUTF16ArrayToUTF8Array = function(uni){
|
||||
var bin = [];
|
||||
for (var i = 0, l = uni.length; i < l; i++){
|
||||
var n = uni[i];
|
||||
if (n < 0x80)
|
||||
bin.push(n);
|
||||
else if (n < 0x800)
|
||||
bin.push(
|
||||
0xc0 | (n >>> 6),
|
||||
0x80 | (n & 0x3f));
|
||||
else
|
||||
bin.push(
|
||||
0xe0 | ((n >>> 12) & 0x0f),
|
||||
0x80 | ((n >>> 6) & 0x3f),
|
||||
0x80 | (n & 0x3f));
|
||||
}
|
||||
return bin;
|
||||
};
|
||||
|
||||
var convertUTF8ArrayToUTF16Array = function(bin){
|
||||
var uni = [];
|
||||
for (var i = 0, l = bin.length; i < l; i++){
|
||||
var c0 = bin[i];
|
||||
if (c0 < 0x80){
|
||||
uni.push(c0);
|
||||
}else{
|
||||
var c1 = bin[++i];
|
||||
if (c0 < 0xe0){
|
||||
uni.push(((c0 & 0x1f) << 6) | (c1 & 0x3f));
|
||||
}else{
|
||||
var c2 = bin[++i];
|
||||
uni.push(
|
||||
((c0 & 0x0f) << 12) | ((c1 & 0x3f) << 6) | (c2 & 0x3f)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return uni;
|
||||
};
|
||||
|
||||
var convertUTF8StringToBase64 = function(bin){
|
||||
return convertUTF8ArrayToBase64(stringToArray(bin));
|
||||
};
|
||||
|
||||
var convertBase64ToUTF8String = function(b64){
|
||||
return chunkStringFromCharCodeApply(convertBase64ToUTF8Array(b64));
|
||||
};
|
||||
|
||||
var convertUTF8StringToUTF16Array = function(bin){
|
||||
return convertUTF8ArrayToUTF16Array(stringToArray(bin));
|
||||
};
|
||||
|
||||
var convertUTF8ArrayToUTF16String = function(bin){
|
||||
return chunkStringFromCharCodeApply(convertUTF8ArrayToUTF16Array(bin));
|
||||
};
|
||||
|
||||
var convertUTF8StringToUTF16String = function(bin){
|
||||
return chunkStringFromCharCodeApply(
|
||||
convertUTF8ArrayToUTF16Array(stringToArray(bin))
|
||||
);
|
||||
};
|
||||
|
||||
var convertUTF16StringToUTF8Array = function(uni){
|
||||
return convertUTF16ArrayToUTF8Array(stringToArray(uni));
|
||||
};
|
||||
|
||||
var convertUTF16ArrayToUTF8String = function(uni){
|
||||
return chunkStringFromCharCodeApply(convertUTF16ArrayToUTF8Array(uni));
|
||||
};
|
||||
|
||||
var convertUTF16StringToUTF8String = function(uni){
|
||||
return chunkStringFromCharCodeApply(
|
||||
convertUTF16ArrayToUTF8Array(stringToArray(uni))
|
||||
);
|
||||
};
|
||||
|
||||
/*
|
||||
* String.fromCharCode.apply will only handle arrays as big as 65536,
|
||||
* after that it'll return a truncated string with no warning.
|
||||
*/
|
||||
var chunkStringFromCharCodeApply = function(arr){
|
||||
var strs = [], i;
|
||||
for (i = 0; i < arr.length; i += 65536){
|
||||
strs.push(String.fromCharCode.apply(String, arr.slice(i, i+65536)));
|
||||
}
|
||||
return strs.join('');
|
||||
};
|
||||
|
||||
if (global.btoa){
|
||||
var btoa = global.btoa;
|
||||
var convertUTF16StringToBase64 = function (uni){
|
||||
return btoa(convertUTF16StringToUTF8String(uni));
|
||||
};
|
||||
}
|
||||
else {
|
||||
var btoa = convertUTF8StringToBase64;
|
||||
var convertUTF16StringToBase64 = function (uni){
|
||||
return convertUTF8ArrayToBase64(convertUTF16StringToUTF8Array(uni));
|
||||
};
|
||||
}
|
||||
|
||||
if (global.atob){
|
||||
var atob = global.atob;
|
||||
var convertBase64ToUTF16String = function (b64){
|
||||
return convertUTF8StringToUTF16String(atob(b64));
|
||||
};
|
||||
}
|
||||
else {
|
||||
var atob = convertBase64ToUTF8String;
|
||||
var convertBase64ToUTF16String = function (b64){
|
||||
return convertUTF8ArrayToUTF16String(convertBase64ToUTF8Array(b64));
|
||||
};
|
||||
}
|
||||
|
||||
global.Base64 = {
|
||||
convertUTF8ArrayToBase64:convertUTF8ArrayToBase64,
|
||||
convertByteArrayToBase64:convertUTF8ArrayToBase64,
|
||||
convertBase64ToUTF8Array:convertBase64ToUTF8Array,
|
||||
convertBase64ToByteArray:convertBase64ToUTF8Array,
|
||||
convertUTF16ArrayToUTF8Array:convertUTF16ArrayToUTF8Array,
|
||||
convertUTF16ArrayToByteArray:convertUTF16ArrayToUTF8Array,
|
||||
convertUTF8ArrayToUTF16Array:convertUTF8ArrayToUTF16Array,
|
||||
convertByteArrayToUTF16Array:convertUTF8ArrayToUTF16Array,
|
||||
convertUTF8StringToBase64:convertUTF8StringToBase64,
|
||||
convertBase64ToUTF8String:convertBase64ToUTF8String,
|
||||
convertUTF8StringToUTF16Array:convertUTF8StringToUTF16Array,
|
||||
convertUTF8ArrayToUTF16String:convertUTF8ArrayToUTF16String,
|
||||
convertByteArrayToUTF16String:convertUTF8ArrayToUTF16String,
|
||||
convertUTF8StringToUTF16String:convertUTF8StringToUTF16String,
|
||||
convertUTF16StringToUTF8Array:convertUTF16StringToUTF8Array,
|
||||
convertUTF16StringToByteArray:convertUTF16StringToUTF8Array,
|
||||
convertUTF16ArrayToUTF8String:convertUTF16ArrayToUTF8String,
|
||||
convertUTF16StringToUTF8String:convertUTF16StringToUTF8String,
|
||||
convertUTF16StringToBase64:convertUTF16StringToBase64,
|
||||
convertBase64ToUTF16String:convertBase64ToUTF16String,
|
||||
fromBase64:convertBase64ToUTF8String,
|
||||
toBase64:convertUTF8StringToBase64,
|
||||
atob:atob,
|
||||
btoa:btoa,
|
||||
utob:convertUTF16StringToUTF8String,
|
||||
btou:convertUTF8StringToUTF16String,
|
||||
encode:convertUTF16StringToBase64,
|
||||
encodeURI:function(u){
|
||||
return convertUTF16StringToBase64(u).replace(/[+\/]/g, function(m0){
|
||||
return m0 == '+' ? '-' : '_';
|
||||
}).replace(/=+$/, '');
|
||||
},
|
||||
decode:function(a){
|
||||
return convertBase64ToUTF16String(a.replace(/[-_]/g, function(m0){
|
||||
return m0 == '-' ? '+' : '/';
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
})(this);
|
|
@ -10,7 +10,6 @@ global.WebCrypto = require('@peculiar/webcrypto').Crypto;
|
|||
|
||||
// application libraries to test
|
||||
global.$ = global.jQuery = require('./jquery-3.7.1');
|
||||
global.RawDeflate = require('./rawinflate-0.3').RawDeflate;
|
||||
global.zlib = require('./zlib-1.3.1-1').zlib;
|
||||
require('./prettify');
|
||||
global.prettyPrint = window.PR.prettyPrint;
|
||||
|
|
171
js/privatebin.js
171
js/privatebin.js
|
@ -10,7 +10,7 @@
|
|||
* @namespace
|
||||
*/
|
||||
|
||||
// global Base64, DOMPurify, FileReader, RawDeflate, history, navigator, prettyPrint, prettyPrintOne, showdown, kjua
|
||||
// global Base64, DOMPurify, FileReader, history, navigator, prettyPrint, prettyPrintOne, showdown, kjua
|
||||
|
||||
jQuery.fn.draghover = function() {
|
||||
'use strict';
|
||||
|
@ -41,7 +41,7 @@ jQuery(document).ready(function() {
|
|||
$.PrivateBin.Controller.init();
|
||||
});
|
||||
|
||||
jQuery.PrivateBin = (function($, RawDeflate) {
|
||||
jQuery.PrivateBin = (function($) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
|
@ -91,7 +91,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
* @class
|
||||
*/
|
||||
function CryptoData(data) {
|
||||
this.v = 1;
|
||||
// store all keys in the default locations for drop-in replacement
|
||||
for (let key in data) {
|
||||
this[key] = data[key];
|
||||
|
@ -102,11 +101,11 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
*
|
||||
* @name CryptoData.getCipherData
|
||||
* @function
|
||||
* @return {Array}|{string}
|
||||
* @return {Array}
|
||||
*/
|
||||
this.getCipherData = function()
|
||||
{
|
||||
return this.v === 1 ? this.data : [this.ct, this.adata];
|
||||
return [this.ct, this.adata];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,7 +130,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
*/
|
||||
this.getFormat = function()
|
||||
{
|
||||
return this.v === 1 ? this.meta.formatter : this.adata[1];
|
||||
return this.adata[1];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -145,7 +144,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
*/
|
||||
this.getTimeToLive = function()
|
||||
{
|
||||
return (this.v === 1 ? this.meta.remaining_time : this.meta.time_to_live) || 0;
|
||||
return this.meta.time_to_live || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -157,7 +156,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
*/
|
||||
this.isBurnAfterReadingEnabled = function()
|
||||
{
|
||||
return (this.v === 1 ? this.meta.burnafterreading : this.adata[3]);
|
||||
return this.adata[3];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -169,7 +168,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
*/
|
||||
this.isDiscussionEnabled = function()
|
||||
{
|
||||
return (this.v === 1 ? this.meta.opendiscussion : this.adata[2]);
|
||||
return this.adata[2];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,7 +193,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
*/
|
||||
this.getCreated = function()
|
||||
{
|
||||
return this.meta[this.v === 1 ? 'postdate' : 'created'] || 0;
|
||||
return this.meta['created'] || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -206,7 +205,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
*/
|
||||
this.getIcon = function()
|
||||
{
|
||||
return this.meta[this.v === 1 ? 'vizhash' : 'icon'] || '';
|
||||
return this.meta['icon'] || '';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1119,39 +1118,17 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
*/
|
||||
async function decompress(data, mode, zlib)
|
||||
{
|
||||
if (mode === 'zlib' || mode === 'none') {
|
||||
if (mode === 'zlib') {
|
||||
if (typeof zlib === 'undefined') {
|
||||
throw 'Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.'
|
||||
}
|
||||
data = zlib.inflate(
|
||||
new Uint8Array(data)
|
||||
).buffer;
|
||||
if (mode === 'zlib') {
|
||||
if (typeof zlib === 'undefined') {
|
||||
throw 'Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.'
|
||||
}
|
||||
return utf8To16(
|
||||
arraybufferToString(data)
|
||||
);
|
||||
}
|
||||
// detect presence of Base64.js, indicating legacy ZeroBin paste
|
||||
if (typeof Base64 === 'undefined') {
|
||||
return utf8To16(
|
||||
RawDeflate.inflate(
|
||||
utf8To16(
|
||||
atob(
|
||||
arraybufferToString(data)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
return Base64.btou(
|
||||
RawDeflate.inflate(
|
||||
Base64.fromBase64(
|
||||
arraybufferToString(data)
|
||||
)
|
||||
)
|
||||
);
|
||||
data = zlib.inflate(
|
||||
new Uint8Array(data)
|
||||
).buffer;
|
||||
}
|
||||
return utf8To16(
|
||||
arraybufferToString(data)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1191,19 +1168,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
{
|
||||
let keyArray = stringToArraybuffer(key);
|
||||
if (password.length > 0) {
|
||||
// version 1 pastes did append the passwords SHA-256 hash in hex
|
||||
if (spec[7] === 'rawdeflate') {
|
||||
let passwordBuffer = await window.crypto.subtle.digest(
|
||||
{name: 'SHA-256'},
|
||||
stringToArraybuffer(
|
||||
utf16To8(password)
|
||||
)
|
||||
).catch(Alert.showError);
|
||||
password = Array.prototype.map.call(
|
||||
new Uint8Array(passwordBuffer),
|
||||
x => ('00' + x.toString(16)).slice(-2)
|
||||
).join('');
|
||||
}
|
||||
let passwordArray = stringToArraybuffer(password),
|
||||
newKeyArray = new Uint8Array(keyArray.length + passwordArray.length);
|
||||
newKeyArray.set(keyArray, 0);
|
||||
|
@ -1337,21 +1301,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
// clone the array instead of passing the reference
|
||||
spec = (data[1][0] instanceof Array ? data[1][0] : data[1]).slice();
|
||||
cipherMessage = data[0];
|
||||
} else if (typeof data === 'string') {
|
||||
// version 1
|
||||
let object = JSON.parse(data);
|
||||
adataString = atob(object.adata);
|
||||
spec = [
|
||||
object.iv,
|
||||
object.salt,
|
||||
object.iter,
|
||||
object.ks,
|
||||
object.ts,
|
||||
object.cipher,
|
||||
object.mode,
|
||||
'rawdeflate'
|
||||
];
|
||||
cipherMessage = object.ct;
|
||||
} else {
|
||||
throw 'unsupported message format';
|
||||
}
|
||||
|
@ -1598,7 +1547,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
// string, so we re-add them if necessary
|
||||
symmetricKey = CryptTool.base58decode(newKey).padStart(32, '\u0000');
|
||||
} catch(e) {
|
||||
symmetricKey = newKey;
|
||||
throw 'encryption key of unsupported format given or incomplete, mangled URL';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5369,7 +5318,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
*/
|
||||
async function decryptPaste(paste, key, password)
|
||||
{
|
||||
let pastePlain = await decryptOrPromptPassword(
|
||||
const pastePlain = await decryptOrPromptPassword(
|
||||
key, password,
|
||||
paste.getCipherData()
|
||||
);
|
||||
|
@ -5385,36 +5334,21 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
}
|
||||
}
|
||||
|
||||
if (paste.v > 1) {
|
||||
// version 2 paste
|
||||
const pasteMessage = JSON.parse(pastePlain);
|
||||
if (pasteMessage.hasOwnProperty('attachment') && pasteMessage.hasOwnProperty('attachment_name')) {
|
||||
if (Array.isArray(pasteMessage.attachment) && Array.isArray(pasteMessage.attachment_name)) {
|
||||
pasteMessage.attachment.forEach((attachment, key) => {
|
||||
const attachment_name = pasteMessage.attachment_name[key];
|
||||
AttachmentViewer.setAttachment(attachment, attachment_name);
|
||||
});
|
||||
} else {
|
||||
// Continue to process attachment parameters as strings to ensure backward compatibility
|
||||
AttachmentViewer.setAttachment(pasteMessage.attachment, pasteMessage.attachment_name);
|
||||
}
|
||||
AttachmentViewer.showAttachment();
|
||||
}
|
||||
pastePlain = pasteMessage.paste;
|
||||
} else {
|
||||
// version 1 paste
|
||||
if (paste.hasOwnProperty('attachment') && paste.hasOwnProperty('attachmentname')) {
|
||||
Promise.all([
|
||||
CryptTool.decipher(key, password, paste.attachment),
|
||||
CryptTool.decipher(key, password, paste.attachmentname)
|
||||
]).then((attachment) => {
|
||||
AttachmentViewer.setAttachment(attachment[0], attachment[1]);
|
||||
AttachmentViewer.showAttachment();
|
||||
const pasteMessage = JSON.parse(pastePlain);
|
||||
if (pasteMessage.hasOwnProperty('attachment') && pasteMessage.hasOwnProperty('attachment_name')) {
|
||||
if (Array.isArray(pasteMessage.attachment) && Array.isArray(pasteMessage.attachment_name)) {
|
||||
pasteMessage.attachment.forEach((attachment, key) => {
|
||||
const attachment_name = pasteMessage.attachment_name[key];
|
||||
AttachmentViewer.setAttachment(attachment, attachment_name);
|
||||
});
|
||||
} else {
|
||||
// Continue to process attachment parameters as strings to ensure backward compatibility
|
||||
AttachmentViewer.setAttachment(pasteMessage.attachment, pasteMessage.attachment_name);
|
||||
}
|
||||
AttachmentViewer.showAttachment();
|
||||
}
|
||||
PasteViewer.setFormat(paste.getFormat());
|
||||
PasteViewer.setText(pastePlain);
|
||||
PasteViewer.setText(pasteMessage.paste);
|
||||
PasteViewer.run();
|
||||
}
|
||||
|
||||
|
@ -5441,28 +5375,15 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
const comment = new Comment(paste.comments[i]),
|
||||
commentPromise = CryptTool.decipher(key, password, comment.getCipherData());
|
||||
paste.comments[i] = comment;
|
||||
if (comment.v > 1) {
|
||||
// version 2 comment
|
||||
commentDecryptionPromises.push(
|
||||
commentPromise.then(function (commentJson) {
|
||||
const commentMessage = JSON.parse(commentJson);
|
||||
return [
|
||||
commentMessage.comment || '',
|
||||
commentMessage.nickname || ''
|
||||
];
|
||||
})
|
||||
);
|
||||
} else {
|
||||
// version 1 comment
|
||||
commentDecryptionPromises.push(
|
||||
Promise.all([
|
||||
commentPromise,
|
||||
paste.comments[i].meta.hasOwnProperty('nickname') ?
|
||||
CryptTool.decipher(key, password, paste.comments[i].meta.nickname) :
|
||||
Promise.resolve('')
|
||||
])
|
||||
);
|
||||
}
|
||||
commentDecryptionPromises.push(
|
||||
commentPromise.then(function (commentJson) {
|
||||
const commentMessage = JSON.parse(commentJson);
|
||||
return [
|
||||
commentMessage.comment || '',
|
||||
commentMessage.nickname || ''
|
||||
];
|
||||
})
|
||||
);
|
||||
}
|
||||
return Promise.all(commentDecryptionPromises).then(function (plaintexts) {
|
||||
for (let i = 0; i < paste.comments.length; ++i) {
|
||||
|
@ -5806,12 +5727,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
Model.getPasteKey();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
// missing decryption key (or paste ID) in URL?
|
||||
if (window.location.hash.length === 0) {
|
||||
Alert.showError('Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)');
|
||||
return;
|
||||
}
|
||||
Alert.showError('Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)');
|
||||
return;
|
||||
}
|
||||
|
||||
// check if we should request loading confirmation
|
||||
|
@ -6046,4 +5963,4 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
CopyToClipboard: CopyToClipboard,
|
||||
Controller: Controller
|
||||
};
|
||||
})(jQuery, RawDeflate);
|
||||
})(jQuery);
|
||||
|
|
|
@ -1,755 +0,0 @@
|
|||
/*
|
||||
* $Id: rawinflate.js,v 0.3 2013/04/09 14:25:38 dankogai Exp dankogai $
|
||||
*
|
||||
* GNU General Public License, version 2 (GPL-2.0)
|
||||
* https://opensource.org/licenses/GPL-2.0
|
||||
* original:
|
||||
* http://www.onicos.com/staff/iz/amuse/javascript/expert/inflate.txt
|
||||
*/
|
||||
|
||||
(function(ctx){
|
||||
|
||||
/* Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
|
||||
* Version: 1.0.0.1
|
||||
* LastModified: Dec 25 1999
|
||||
*/
|
||||
|
||||
/* Interface:
|
||||
* data = zip_inflate(src);
|
||||
*/
|
||||
|
||||
/* constant parameters */
|
||||
var zip_WSIZE = 32768; // Sliding Window size
|
||||
var zip_STORED_BLOCK = 0;
|
||||
var zip_STATIC_TREES = 1;
|
||||
var zip_DYN_TREES = 2;
|
||||
|
||||
/* for inflate */
|
||||
var zip_lbits = 9; // bits in base literal/length lookup table
|
||||
var zip_dbits = 6; // bits in base distance lookup table
|
||||
var zip_INBUFSIZ = 32768; // Input buffer size
|
||||
var zip_INBUF_EXTRA = 64; // Extra buffer
|
||||
|
||||
/* variables (inflate) */
|
||||
var zip_slide;
|
||||
var zip_wp; // current position in slide
|
||||
var zip_fixed_tl = null; // inflate static
|
||||
var zip_fixed_td; // inflate static
|
||||
var zip_fixed_bl, fixed_bd; // inflate static
|
||||
var zip_bit_buf; // bit buffer
|
||||
var zip_bit_len; // bits in bit buffer
|
||||
var zip_method;
|
||||
var zip_eof;
|
||||
var zip_copy_leng;
|
||||
var zip_copy_dist;
|
||||
var zip_tl, zip_td; // literal/length and distance decoder tables
|
||||
var zip_bl, zip_bd; // number of bits decoded by tl and td
|
||||
|
||||
var zip_inflate_data;
|
||||
var zip_inflate_pos;
|
||||
|
||||
|
||||
/* constant tables (inflate) */
|
||||
var zip_MASK_BITS = new Array(
|
||||
0x0000,
|
||||
0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
|
||||
0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff);
|
||||
// Tables for deflate from PKZIP's appnote.txt.
|
||||
var zip_cplens = new Array( // Copy lengths for literal codes 257..285
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
|
||||
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0);
|
||||
/* note: see note #13 above about the 258 in this list. */
|
||||
var zip_cplext = new Array( // Extra bits for literal codes 257..285
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99); // 99==invalid
|
||||
var zip_cpdist = new Array( // Copy offsets for distance codes 0..29
|
||||
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
|
||||
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
|
||||
8193, 12289, 16385, 24577);
|
||||
var zip_cpdext = new Array( // Extra bits for distance codes
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
|
||||
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
|
||||
12, 12, 13, 13);
|
||||
var zip_border = new Array( // Order of the bit length code lengths
|
||||
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15);
|
||||
/* objects (inflate) */
|
||||
|
||||
var zip_HuftList = function() {
|
||||
this.next = null;
|
||||
this.list = null;
|
||||
}
|
||||
|
||||
var zip_HuftNode = function() {
|
||||
this.e = 0; // number of extra bits or operation
|
||||
this.b = 0; // number of bits in this code or subcode
|
||||
|
||||
// union
|
||||
this.n = 0; // literal, length base, or distance base
|
||||
this.t = null; // (zip_HuftNode) pointer to next level of table
|
||||
}
|
||||
|
||||
var zip_HuftBuild = function(b, // code lengths in bits (all assumed <= BMAX)
|
||||
n, // number of codes (assumed <= N_MAX)
|
||||
s, // number of simple-valued codes (0..s-1)
|
||||
d, // list of base values for non-simple codes
|
||||
e, // list of extra bits for non-simple codes
|
||||
mm // maximum lookup bits
|
||||
) {
|
||||
this.BMAX = 16; // maximum bit length of any code
|
||||
this.N_MAX = 288; // maximum number of codes in any set
|
||||
this.status = 0; // 0: success, 1: incomplete table, 2: bad input
|
||||
this.root = null; // (zip_HuftList) starting table
|
||||
this.m = 0; // maximum lookup bits, returns actual
|
||||
|
||||
/* Given a list of code lengths and a maximum table size, make a set of
|
||||
tables to decode that set of codes. Return zero on success, one if
|
||||
the given code set is incomplete (the tables are still built in this
|
||||
case), two if the input is invalid (all zero length codes or an
|
||||
oversubscribed set of lengths), and three if not enough memory.
|
||||
The code with value 256 is special, and the tables are constructed
|
||||
so that no bits beyond that code are fetched when that code is
|
||||
decoded. */
|
||||
{
|
||||
var a; // counter for codes of length k
|
||||
var c = new Array(this.BMAX+1); // bit length count table
|
||||
var el; // length of EOB code (value 256)
|
||||
var f; // i repeats in table every f entries
|
||||
var g; // maximum code length
|
||||
var h; // table level
|
||||
var i; // counter, current code
|
||||
var j; // counter
|
||||
var k; // number of bits in current code
|
||||
var lx = new Array(this.BMAX+1); // stack of bits per table
|
||||
var p; // pointer into c[], b[], or v[]
|
||||
var pidx; // index of p
|
||||
var q; // (zip_HuftNode) points to current table
|
||||
var r = new zip_HuftNode(); // table entry for structure assignment
|
||||
var u = new Array(this.BMAX); // zip_HuftNode[BMAX][] table stack
|
||||
var v = new Array(this.N_MAX); // values in order of bit length
|
||||
var w;
|
||||
var x = new Array(this.BMAX+1);// bit offsets, then code stack
|
||||
var xp; // pointer into x or c
|
||||
var y; // number of dummy codes added
|
||||
var z; // number of entries in current table
|
||||
var o;
|
||||
var tail; // (zip_HuftList)
|
||||
|
||||
tail = this.root = null;
|
||||
for(i = 0; i < c.length; i++)
|
||||
c[i] = 0;
|
||||
for(i = 0; i < lx.length; i++)
|
||||
lx[i] = 0;
|
||||
for(i = 0; i < u.length; i++)
|
||||
u[i] = null;
|
||||
for(i = 0; i < v.length; i++)
|
||||
v[i] = 0;
|
||||
for(i = 0; i < x.length; i++)
|
||||
x[i] = 0;
|
||||
|
||||
// Generate counts for each bit length
|
||||
el = n > 256 ? b[256] : this.BMAX; // set length of EOB code, if any
|
||||
p = b; pidx = 0;
|
||||
i = n;
|
||||
do {
|
||||
c[p[pidx]]++; // assume all entries <= BMAX
|
||||
pidx++;
|
||||
} while(--i > 0);
|
||||
if(c[0] == n) { // null input--all zero length codes
|
||||
this.root = null;
|
||||
this.m = 0;
|
||||
this.status = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Find minimum and maximum length, bound *m by those
|
||||
for(j = 1; j <= this.BMAX; j++)
|
||||
if(c[j] != 0)
|
||||
break;
|
||||
k = j; // minimum code length
|
||||
if(mm < j)
|
||||
mm = j;
|
||||
for(i = this.BMAX; i != 0; i--)
|
||||
if(c[i] != 0)
|
||||
break;
|
||||
g = i; // maximum code length
|
||||
if(mm > i)
|
||||
mm = i;
|
||||
|
||||
// Adjust last length count to fill out codes, if needed
|
||||
for(y = 1 << j; j < i; j++, y <<= 1)
|
||||
if((y -= c[j]) < 0) {
|
||||
this.status = 2; // bad input: more codes than bits
|
||||
this.m = mm;
|
||||
return;
|
||||
}
|
||||
if((y -= c[i]) < 0) {
|
||||
this.status = 2;
|
||||
this.m = mm;
|
||||
return;
|
||||
}
|
||||
c[i] += y;
|
||||
|
||||
// Generate starting offsets into the value table for each length
|
||||
x[1] = j = 0;
|
||||
p = c;
|
||||
pidx = 1;
|
||||
xp = 2;
|
||||
while(--i > 0) // note that i == g from above
|
||||
x[xp++] = (j += p[pidx++]);
|
||||
|
||||
// Make a table of values in order of bit lengths
|
||||
p = b; pidx = 0;
|
||||
i = 0;
|
||||
do {
|
||||
if((j = p[pidx++]) != 0)
|
||||
v[x[j]++] = i;
|
||||
} while(++i < n);
|
||||
n = x[g]; // set n to length of v
|
||||
|
||||
// Generate the Huffman codes and for each, make the table entries
|
||||
x[0] = i = 0; // first Huffman code is zero
|
||||
p = v; pidx = 0; // grab values in bit order
|
||||
h = -1; // no tables yet--level -1
|
||||
w = lx[0] = 0; // no bits decoded yet
|
||||
q = null; // ditto
|
||||
z = 0; // ditto
|
||||
|
||||
// go through the bit lengths (k already is bits in shortest code)
|
||||
for(; k <= g; k++) {
|
||||
a = c[k];
|
||||
while(a-- > 0) {
|
||||
// here i is the Huffman code of length k bits for value p[pidx]
|
||||
// make tables up to required level
|
||||
while(k > w + lx[1 + h]) {
|
||||
w += lx[1 + h]; // add bits already decoded
|
||||
h++;
|
||||
|
||||
// compute minimum size table less than or equal to *m bits
|
||||
z = (z = g - w) > mm ? mm : z; // upper limit
|
||||
if((f = 1 << (j = k - w)) > a + 1) { // try a k-w bit table
|
||||
// too few codes for k-w bit table
|
||||
f -= a + 1; // deduct codes from patterns left
|
||||
xp = k;
|
||||
while(++j < z) { // try smaller tables up to z bits
|
||||
if((f <<= 1) <= c[++xp])
|
||||
break; // enough codes to use up j bits
|
||||
f -= c[xp]; // else deduct codes from patterns
|
||||
}
|
||||
}
|
||||
if(w + j > el && w < el)
|
||||
j = el - w; // make EOB code end at table
|
||||
z = 1 << j; // table entries for j-bit table
|
||||
lx[1 + h] = j; // set table size in stack
|
||||
|
||||
// allocate and link in new table
|
||||
q = new Array(z);
|
||||
for(o = 0; o < z; o++) {
|
||||
q[o] = new zip_HuftNode();
|
||||
}
|
||||
|
||||
if(tail == null)
|
||||
tail = this.root = new zip_HuftList();
|
||||
else
|
||||
tail = tail.next = new zip_HuftList();
|
||||
tail.next = null;
|
||||
tail.list = q;
|
||||
u[h] = q; // table starts after link
|
||||
|
||||
/* connect to last table, if there is one */
|
||||
if(h > 0) {
|
||||
x[h] = i; // save pattern for backing up
|
||||
r.b = lx[h]; // bits to dump before this table
|
||||
r.e = 16 + j; // bits in this table
|
||||
r.t = q; // pointer to this table
|
||||
j = (i & ((1 << w) - 1)) >> (w - lx[h]);
|
||||
u[h-1][j].e = r.e;
|
||||
u[h-1][j].b = r.b;
|
||||
u[h-1][j].n = r.n;
|
||||
u[h-1][j].t = r.t;
|
||||
}
|
||||
}
|
||||
|
||||
// set up table entry in r
|
||||
r.b = k - w;
|
||||
if(pidx >= n)
|
||||
r.e = 99; // out of values--invalid code
|
||||
else if(p[pidx] < s) {
|
||||
r.e = (p[pidx] < 256 ? 16 : 15); // 256 is end-of-block code
|
||||
r.n = p[pidx++]; // simple code is just the value
|
||||
} else {
|
||||
r.e = e[p[pidx] - s]; // non-simple--look up in lists
|
||||
r.n = d[p[pidx++] - s];
|
||||
}
|
||||
|
||||
// fill code-like entries with r //
|
||||
f = 1 << (k - w);
|
||||
for(j = i >> w; j < z; j += f) {
|
||||
q[j].e = r.e;
|
||||
q[j].b = r.b;
|
||||
q[j].n = r.n;
|
||||
q[j].t = r.t;
|
||||
}
|
||||
|
||||
// backwards increment the k-bit code i
|
||||
for(j = 1 << (k - 1); (i & j) != 0; j >>= 1)
|
||||
i ^= j;
|
||||
i ^= j;
|
||||
|
||||
// backup over finished tables
|
||||
while((i & ((1 << w) - 1)) != x[h]) {
|
||||
w -= lx[h]; // don't need to update q
|
||||
h--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* return actual size of base table */
|
||||
this.m = lx[1];
|
||||
|
||||
/* Return true (1) if we were given an incomplete table */
|
||||
this.status = ((y != 0 && g != 1) ? 1 : 0);
|
||||
} /* end of constructor */
|
||||
}
|
||||
|
||||
|
||||
/* routines (inflate) */
|
||||
|
||||
var zip_GET_BYTE = function() {
|
||||
if(zip_inflate_data.length == zip_inflate_pos)
|
||||
return -1;
|
||||
return zip_inflate_data.charCodeAt(zip_inflate_pos++) & 0xff;
|
||||
}
|
||||
|
||||
var zip_NEEDBITS = function(n) {
|
||||
while(zip_bit_len < n) {
|
||||
zip_bit_buf |= zip_GET_BYTE() << zip_bit_len;
|
||||
zip_bit_len += 8;
|
||||
}
|
||||
}
|
||||
|
||||
var zip_GETBITS = function(n) {
|
||||
return zip_bit_buf & zip_MASK_BITS[n];
|
||||
}
|
||||
|
||||
var zip_DUMPBITS = function(n) {
|
||||
zip_bit_buf >>= n;
|
||||
zip_bit_len -= n;
|
||||
}
|
||||
|
||||
var zip_inflate_codes = function(buff, off, size) {
|
||||
/* inflate (decompress) the codes in a deflated (compressed) block.
|
||||
Return an error code or zero if it all goes ok. */
|
||||
var e; // table entry flag/number of extra bits
|
||||
var t; // (zip_HuftNode) pointer to table entry
|
||||
var n;
|
||||
|
||||
if(size == 0)
|
||||
return 0;
|
||||
|
||||
// inflate the coded data
|
||||
n = 0;
|
||||
for(;;) { // do until end of block
|
||||
zip_NEEDBITS(zip_bl);
|
||||
t = zip_tl.list[zip_GETBITS(zip_bl)];
|
||||
e = t.e;
|
||||
while(e > 16) {
|
||||
if(e == 99)
|
||||
return -1;
|
||||
zip_DUMPBITS(t.b);
|
||||
e -= 16;
|
||||
zip_NEEDBITS(e);
|
||||
t = t.t[zip_GETBITS(e)];
|
||||
e = t.e;
|
||||
}
|
||||
zip_DUMPBITS(t.b);
|
||||
|
||||
if(e == 16) { // then it's a literal
|
||||
zip_wp &= zip_WSIZE - 1;
|
||||
buff[off + n++] = zip_slide[zip_wp++] = t.n;
|
||||
if(n == size)
|
||||
return size;
|
||||
continue;
|
||||
}
|
||||
|
||||
// exit if end of block
|
||||
if(e == 15)
|
||||
break;
|
||||
|
||||
// it's an EOB or a length
|
||||
|
||||
// get length of block to copy
|
||||
zip_NEEDBITS(e);
|
||||
zip_copy_leng = t.n + zip_GETBITS(e);
|
||||
zip_DUMPBITS(e);
|
||||
|
||||
// decode distance of block to copy
|
||||
zip_NEEDBITS(zip_bd);
|
||||
t = zip_td.list[zip_GETBITS(zip_bd)];
|
||||
e = t.e;
|
||||
|
||||
while(e > 16) {
|
||||
if(e == 99)
|
||||
return -1;
|
||||
zip_DUMPBITS(t.b);
|
||||
e -= 16;
|
||||
zip_NEEDBITS(e);
|
||||
t = t.t[zip_GETBITS(e)];
|
||||
e = t.e;
|
||||
}
|
||||
zip_DUMPBITS(t.b);
|
||||
zip_NEEDBITS(e);
|
||||
zip_copy_dist = zip_wp - t.n - zip_GETBITS(e);
|
||||
zip_DUMPBITS(e);
|
||||
|
||||
// do the copy
|
||||
while(zip_copy_leng > 0 && n < size) {
|
||||
zip_copy_leng--;
|
||||
zip_copy_dist &= zip_WSIZE - 1;
|
||||
zip_wp &= zip_WSIZE - 1;
|
||||
buff[off + n++] = zip_slide[zip_wp++]
|
||||
= zip_slide[zip_copy_dist++];
|
||||
}
|
||||
|
||||
if(n == size)
|
||||
return size;
|
||||
}
|
||||
|
||||
zip_method = -1; // done
|
||||
return n;
|
||||
}
|
||||
|
||||
var zip_inflate_stored = function(buff, off, size) {
|
||||
/* "decompress" an inflated type 0 (stored) block. */
|
||||
var n;
|
||||
|
||||
// go to byte boundary
|
||||
n = zip_bit_len & 7;
|
||||
zip_DUMPBITS(n);
|
||||
|
||||
// get the length and its complement
|
||||
zip_NEEDBITS(16);
|
||||
n = zip_GETBITS(16);
|
||||
zip_DUMPBITS(16);
|
||||
zip_NEEDBITS(16);
|
||||
if(n != ((~zip_bit_buf) & 0xffff))
|
||||
return -1; // error in compressed data
|
||||
zip_DUMPBITS(16);
|
||||
|
||||
// read and output the compressed data
|
||||
zip_copy_leng = n;
|
||||
|
||||
n = 0;
|
||||
while(zip_copy_leng > 0 && n < size) {
|
||||
zip_copy_leng--;
|
||||
zip_wp &= zip_WSIZE - 1;
|
||||
zip_NEEDBITS(8);
|
||||
buff[off + n++] = zip_slide[zip_wp++] =
|
||||
zip_GETBITS(8);
|
||||
zip_DUMPBITS(8);
|
||||
}
|
||||
|
||||
if(zip_copy_leng == 0)
|
||||
zip_method = -1; // done
|
||||
return n;
|
||||
}
|
||||
|
||||
var zip_inflate_fixed = function(buff, off, size) {
|
||||
/* decompress an inflated type 1 (fixed Huffman codes) block. We should
|
||||
either replace this with a custom decoder, or at least precompute the
|
||||
Huffman tables. */
|
||||
|
||||
// if first time, set up tables for fixed blocks
|
||||
if(zip_fixed_tl == null) {
|
||||
var i; // temporary variable
|
||||
var l = new Array(288); // length list for huft_build
|
||||
var h; // zip_HuftBuild
|
||||
|
||||
// literal table
|
||||
for(i = 0; i < 144; i++)
|
||||
l[i] = 8;
|
||||
for(; i < 256; i++)
|
||||
l[i] = 9;
|
||||
for(; i < 280; i++)
|
||||
l[i] = 7;
|
||||
for(; i < 288; i++) // make a complete, but wrong code set
|
||||
l[i] = 8;
|
||||
zip_fixed_bl = 7;
|
||||
|
||||
h = new zip_HuftBuild(l, 288, 257, zip_cplens, zip_cplext,
|
||||
zip_fixed_bl);
|
||||
if(h.status != 0) {
|
||||
alert("HufBuild error: "+h.status);
|
||||
return -1;
|
||||
}
|
||||
zip_fixed_tl = h.root;
|
||||
zip_fixed_bl = h.m;
|
||||
|
||||
// distance table
|
||||
for(i = 0; i < 30; i++) // make an incomplete code set
|
||||
l[i] = 5;
|
||||
zip_fixed_bd = 5;
|
||||
|
||||
h = new zip_HuftBuild(l, 30, 0, zip_cpdist, zip_cpdext, zip_fixed_bd);
|
||||
if(h.status > 1) {
|
||||
zip_fixed_tl = null;
|
||||
alert("HufBuild error: "+h.status);
|
||||
return -1;
|
||||
}
|
||||
zip_fixed_td = h.root;
|
||||
zip_fixed_bd = h.m;
|
||||
}
|
||||
|
||||
zip_tl = zip_fixed_tl;
|
||||
zip_td = zip_fixed_td;
|
||||
zip_bl = zip_fixed_bl;
|
||||
zip_bd = zip_fixed_bd;
|
||||
return zip_inflate_codes(buff, off, size);
|
||||
}
|
||||
|
||||
var zip_inflate_dynamic = function(buff, off, size) {
|
||||
// decompress an inflated type 2 (dynamic Huffman codes) block.
|
||||
var i; // temporary variables
|
||||
var j;
|
||||
var l; // last length
|
||||
var n; // number of lengths to get
|
||||
var t; // (zip_HuftNode) literal/length code table
|
||||
var nb; // number of bit length codes
|
||||
var nl; // number of literal/length codes
|
||||
var nd; // number of distance codes
|
||||
var ll = new Array(286+30); // literal/length and distance code lengths
|
||||
var h; // (zip_HuftBuild)
|
||||
|
||||
for(i = 0; i < ll.length; i++)
|
||||
ll[i] = 0;
|
||||
|
||||
// read in table lengths
|
||||
zip_NEEDBITS(5);
|
||||
nl = 257 + zip_GETBITS(5); // number of literal/length codes
|
||||
zip_DUMPBITS(5);
|
||||
zip_NEEDBITS(5);
|
||||
nd = 1 + zip_GETBITS(5); // number of distance codes
|
||||
zip_DUMPBITS(5);
|
||||
zip_NEEDBITS(4);
|
||||
nb = 4 + zip_GETBITS(4); // number of bit length codes
|
||||
zip_DUMPBITS(4);
|
||||
if(nl > 286 || nd > 30)
|
||||
return -1; // bad lengths
|
||||
|
||||
// read in bit-length-code lengths
|
||||
for(j = 0; j < nb; j++)
|
||||
{
|
||||
zip_NEEDBITS(3);
|
||||
ll[zip_border[j]] = zip_GETBITS(3);
|
||||
zip_DUMPBITS(3);
|
||||
}
|
||||
for(; j < 19; j++)
|
||||
ll[zip_border[j]] = 0;
|
||||
|
||||
// build decoding table for trees--single level, 7 bit lookup
|
||||
zip_bl = 7;
|
||||
h = new zip_HuftBuild(ll, 19, 19, null, null, zip_bl);
|
||||
if(h.status != 0)
|
||||
return -1; // incomplete code set
|
||||
|
||||
zip_tl = h.root;
|
||||
zip_bl = h.m;
|
||||
|
||||
// read in literal and distance code lengths
|
||||
n = nl + nd;
|
||||
i = l = 0;
|
||||
while(i < n) {
|
||||
zip_NEEDBITS(zip_bl);
|
||||
t = zip_tl.list[zip_GETBITS(zip_bl)];
|
||||
j = t.b;
|
||||
zip_DUMPBITS(j);
|
||||
j = t.n;
|
||||
if(j < 16) // length of code in bits (0..15)
|
||||
ll[i++] = l = j; // save last length in l
|
||||
else if(j == 16) { // repeat last length 3 to 6 times
|
||||
zip_NEEDBITS(2);
|
||||
j = 3 + zip_GETBITS(2);
|
||||
zip_DUMPBITS(2);
|
||||
if(i + j > n)
|
||||
return -1;
|
||||
while(j-- > 0)
|
||||
ll[i++] = l;
|
||||
} else if(j == 17) { // 3 to 10 zero length codes
|
||||
zip_NEEDBITS(3);
|
||||
j = 3 + zip_GETBITS(3);
|
||||
zip_DUMPBITS(3);
|
||||
if(i + j > n)
|
||||
return -1;
|
||||
while(j-- > 0)
|
||||
ll[i++] = 0;
|
||||
l = 0;
|
||||
} else { // j == 18: 11 to 138 zero length codes
|
||||
zip_NEEDBITS(7);
|
||||
j = 11 + zip_GETBITS(7);
|
||||
zip_DUMPBITS(7);
|
||||
if(i + j > n)
|
||||
return -1;
|
||||
while(j-- > 0)
|
||||
ll[i++] = 0;
|
||||
l = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// build the decoding tables for literal/length and distance codes
|
||||
zip_bl = zip_lbits;
|
||||
h = new zip_HuftBuild(ll, nl, 257, zip_cplens, zip_cplext, zip_bl);
|
||||
if(zip_bl == 0) // no literals or lengths
|
||||
h.status = 1;
|
||||
if(h.status != 0) {
|
||||
if(h.status == 1)
|
||||
;// **incomplete literal tree**
|
||||
return -1; // incomplete code set
|
||||
}
|
||||
zip_tl = h.root;
|
||||
zip_bl = h.m;
|
||||
|
||||
for(i = 0; i < nd; i++)
|
||||
ll[i] = ll[i + nl];
|
||||
zip_bd = zip_dbits;
|
||||
h = new zip_HuftBuild(ll, nd, 0, zip_cpdist, zip_cpdext, zip_bd);
|
||||
zip_td = h.root;
|
||||
zip_bd = h.m;
|
||||
|
||||
if(zip_bd == 0 && nl > 257) { // lengths but no distances
|
||||
// **incomplete distance tree**
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(h.status == 1) {
|
||||
;// **incomplete distance tree**
|
||||
}
|
||||
if(h.status != 0)
|
||||
return -1;
|
||||
|
||||
// decompress until an end-of-block code
|
||||
return zip_inflate_codes(buff, off, size);
|
||||
}
|
||||
|
||||
var zip_inflate_start = function() {
|
||||
var i;
|
||||
|
||||
if(zip_slide == null)
|
||||
zip_slide = new Array(2 * zip_WSIZE);
|
||||
zip_wp = 0;
|
||||
zip_bit_buf = 0;
|
||||
zip_bit_len = 0;
|
||||
zip_method = -1;
|
||||
zip_eof = false;
|
||||
zip_copy_leng = zip_copy_dist = 0;
|
||||
zip_tl = null;
|
||||
}
|
||||
|
||||
var zip_inflate_internal = function(buff, off, size) {
|
||||
// decompress an inflated entry
|
||||
var n, i;
|
||||
|
||||
n = 0;
|
||||
while(n < size) {
|
||||
if(zip_eof && zip_method == -1)
|
||||
return n;
|
||||
|
||||
if(zip_copy_leng > 0) {
|
||||
if(zip_method != zip_STORED_BLOCK) {
|
||||
// STATIC_TREES or DYN_TREES
|
||||
while(zip_copy_leng > 0 && n < size) {
|
||||
zip_copy_leng--;
|
||||
zip_copy_dist &= zip_WSIZE - 1;
|
||||
zip_wp &= zip_WSIZE - 1;
|
||||
buff[off + n++] = zip_slide[zip_wp++] =
|
||||
zip_slide[zip_copy_dist++];
|
||||
}
|
||||
} else {
|
||||
while(zip_copy_leng > 0 && n < size) {
|
||||
zip_copy_leng--;
|
||||
zip_wp &= zip_WSIZE - 1;
|
||||
zip_NEEDBITS(8);
|
||||
buff[off + n++] = zip_slide[zip_wp++] = zip_GETBITS(8);
|
||||
zip_DUMPBITS(8);
|
||||
}
|
||||
if(zip_copy_leng == 0)
|
||||
zip_method = -1; // done
|
||||
}
|
||||
if(n == size)
|
||||
return n;
|
||||
}
|
||||
|
||||
if(zip_method == -1) {
|
||||
if(zip_eof)
|
||||
break;
|
||||
|
||||
// read in last block bit
|
||||
zip_NEEDBITS(1);
|
||||
if(zip_GETBITS(1) != 0)
|
||||
zip_eof = true;
|
||||
zip_DUMPBITS(1);
|
||||
|
||||
// read in block type
|
||||
zip_NEEDBITS(2);
|
||||
zip_method = zip_GETBITS(2);
|
||||
zip_DUMPBITS(2);
|
||||
zip_tl = null;
|
||||
zip_copy_leng = 0;
|
||||
}
|
||||
|
||||
switch(zip_method) {
|
||||
case 0: // zip_STORED_BLOCK
|
||||
i = zip_inflate_stored(buff, off + n, size - n);
|
||||
break;
|
||||
|
||||
case 1: // zip_STATIC_TREES
|
||||
if(zip_tl != null)
|
||||
i = zip_inflate_codes(buff, off + n, size - n);
|
||||
else
|
||||
i = zip_inflate_fixed(buff, off + n, size - n);
|
||||
break;
|
||||
|
||||
case 2: // zip_DYN_TREES
|
||||
if(zip_tl != null)
|
||||
i = zip_inflate_codes(buff, off + n, size - n);
|
||||
else
|
||||
i = zip_inflate_dynamic(buff, off + n, size - n);
|
||||
break;
|
||||
|
||||
default: // error
|
||||
i = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(i == -1) {
|
||||
if(zip_eof)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
n += i;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
var zip_inflate = function(str) {
|
||||
var i, j;
|
||||
|
||||
zip_inflate_start();
|
||||
zip_inflate_data = str;
|
||||
zip_inflate_pos = 0;
|
||||
|
||||
var buff = new Array(1024);
|
||||
var aout = [];
|
||||
while((i = zip_inflate_internal(buff, 0, buff.length)) > 0) {
|
||||
var cbuf = new Array(i);
|
||||
for(j = 0; j < i; j++){
|
||||
cbuf[j] = String.fromCharCode(buff[j]);
|
||||
}
|
||||
aout[aout.length] = cbuf.join("");
|
||||
}
|
||||
zip_inflate_data = null; // G.C.
|
||||
return aout.join("");
|
||||
}
|
||||
|
||||
if (! ctx.RawDeflate) ctx.RawDeflate = {};
|
||||
ctx.RawDeflate.inflate = zip_inflate;
|
||||
|
||||
})(this);
|
|
@ -40,191 +40,6 @@ describe('CryptTool', function () {
|
|||
{tests: 3});
|
||||
});
|
||||
|
||||
// The below static unit tests are included to ensure deciphering of "classic"
|
||||
// SJCL based pastes still works
|
||||
it(
|
||||
'supports PrivateBin v1 ciphertext with password (SJCL & browser atob)',
|
||||
async function () {
|
||||
delete global.Base64;
|
||||
const clean = jsdom();
|
||||
Object.defineProperty(window, 'crypto', {
|
||||
value: new WebCrypto(),
|
||||
writeable: false,
|
||||
});
|
||||
global.atob = common.atob;
|
||||
|
||||
// Of course you can easily decipher the following texts, if you like.
|
||||
// Bonus points for finding their sources and hidden meanings.
|
||||
const paste = await $.PrivateBin.CryptTool.decipher(
|
||||
'6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=',
|
||||
// -- "That's amazing. I've got the same combination on my luggage."
|
||||
Array.apply(0, Array(6)).map((_,b) => b + 1).join(''),
|
||||
'{"iv":"4HNFIl7eYbCh6HuShctTIA==","v":1,"iter":10000,"ks"' +
|
||||
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
|
||||
'lt":"u0lQvePq6L0=","ct":"fGPUVrDyaVr1ZDGb+kqQ3CPEW8x4YKG' +
|
||||
'fzHDmA0Vjkh250aWNe7Cnigkps9aaFVMX9AaerrTp3yZbojJtNqVGMfL' +
|
||||
'dUTu+53xmZHqRKxCCqSfDNSNoW4Oxk5OVgAtRyuG4bXHDsWTXDNz2xce' +
|
||||
'qzVFqhkwTwlUchrV7uuFK/XUKTNjPFM744moivIcBbfM2FOeKlIFs8RY' +
|
||||
'PYuvqQhp2rMLlNGwwKh//4kykQsHMQDeSDuJl8stMQzgWR/btUBZuwNZ' +
|
||||
'EydkMH6IPpTdf5WTSrZ+wC2OK0GutCm4UaEe6txzaTMfu+WRVu4PN6q+' +
|
||||
'N+2zljWJ1XdpVcN/i0Sv4QVMym0Xa6y0eccEhj/69o47PmExmMMeEwEx' +
|
||||
'ImPalMNT9JUSiZdOZJ/GdzwrwoIuq1mdQR6vSH+XJ/8jXJQ7bjjJVJYX' +
|
||||
'TcT0Di5jixArI2Kpp1GGlGVFbLgPugwU1wczg+byqeDOAECXRRnQcoge' +
|
||||
'aJtVcRwXwfy4j3ORFcblYMilxyHqKBewcYPRVBGtBs50cVjSIkAfR84r' +
|
||||
'nc1nfvnxK/Gmm+4VBNHI6ODWNpRolVMCzXjbKYnV3Are5AgSpsTqaGl4' +
|
||||
'1VJGpcco6cAwi4K0Bys1seKR+bLSdUgqRrkEqSRSdu3/VTu9HhEk8an0' +
|
||||
'rjTE4CBB5/LMn16p0TGLoOb32odKFIEtpanVvLjeyiVMvSxcgYLNnTi/' +
|
||||
'5FiaAC4pJxRD+AZHedU1FICUeEXxIcac/4E5qjkHjX9SpQtLl80QLIVn' +
|
||||
'jNliZm7QLB/nKu7W8Jb0+/CiTdV3Q9LhxlH4ciprnX+W0B00BKYFHnL9' +
|
||||
'jRVzKdXhf1EHydbXMAfpCjHAXIVCkFakJinQBDIIw/SC6Yig0u0ddEID' +
|
||||
'2B7LYAP1iE4RZwzTrxCB+ke2jQr8c20Jj6u6ShFOPC9DCw9XupZ4HAal' +
|
||||
'VG00kSgjus+b8zrVji3/LKEhb4EBzp1ctBJCFTeXwej8ZETLoXTylev5' +
|
||||
'dlwZSYAbuBPPcbFR/xAIPx3uDabd1E1gTqUc68ICIGhd197Mb2eRWiSv' +
|
||||
'Hr5SPsASerMxId6XA6+iQlRiI+NDR+TGVNmCnfxSlyPFMOHGTmslXOGI' +
|
||||
'qGfBR8l4ft8YVZ70lCwmwTuViGc75ULSf9mM57/LmRzQFMYQtvI8IFK9' +
|
||||
'JaQEMY5xz0HLtR4iyQUUdwR9e0ytBNdWF2a2WPDEnJuY/QJo4GzTlgv4' +
|
||||
'QUxMXI5htsn2rf0HxCFu7Po8DNYLxTS+67hYjDIYWYaEIc8LXWMLyDm9' +
|
||||
'C5fARPJ4F2BIWgzgzkNj+dVjusft2XnziamWdbS5u3kuRlVuz5LQj+R5' +
|
||||
'imnqQAincdZTkTT1nYx+DatlOLllCYIHffpI="}'
|
||||
);
|
||||
clean();
|
||||
const result = typeof paste === 'string' && paste.includes('securely packed in iron');
|
||||
if (!result) console.log(paste);
|
||||
assert.ok(result);
|
||||
}
|
||||
);
|
||||
|
||||
it(
|
||||
'supports PrivateBin v1 ciphertext no password (SJCL & browser atob)',
|
||||
async function () {
|
||||
delete global.Base64;
|
||||
const clean = jsdom();
|
||||
// ensure zlib is getting loaded
|
||||
$.PrivateBin.Controller.initZ();
|
||||
Object.defineProperty(window, 'crypto', {
|
||||
value: new WebCrypto(),
|
||||
writeable: false,
|
||||
});
|
||||
global.atob = common.atob;
|
||||
|
||||
// Of course you can easily decipher the following texts, if you like.
|
||||
// Bonus points for finding their sources and hidden meanings.
|
||||
const paste = await $.PrivateBin.CryptTool.decipher(
|
||||
's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
|
||||
'', // no password
|
||||
'{"iv":"WA42mdxIVXUwBqZu7JYNiw==","v":1,"iter":10000,"ks"' +
|
||||
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
|
||||
'lt":"jN6CjbQMJCM=","ct":"kYYMo5DFG1+w0UHiYXT5pdV0IUuXxzO' +
|
||||
'lslkW/c3DRCbGFROCVkAskHce7HoRczee1N9c5MhHjVMJUIZE02qIS8U' +
|
||||
'yHdJ/GqcPVidTUcj9rnDNWsTXkjVv8jCwHS/cwmAjDTWpwp5ThECN+ov' +
|
||||
'/wNp/NdtTj8Qj7f/T3rfZIOCWfwLH9s4Des35UNcUidfPTNQ1l0Gm0X+' +
|
||||
'r98CCUSYZjQxkZc6hRZBLPQ8EaNVooUwd5eP4GiYlmSDNA0wOSA+5isP' +
|
||||
'YxomVCt+kFf58VBlNhpfNi7BLYAUTPpXT4SfH5drR9+C7NTeZ+tTCYjb' +
|
||||
'U94PzYItOpu8vgnB1/a6BAM5h3m9w+giUb0df4hgTWeZnZxLjo5BN8WV' +
|
||||
'+kdTXMj3/Vv0gw0DQrDcCuX/cBAjpy3lQGwlAN1vXoOIyZJUjMpQRrOL' +
|
||||
'dKvLB+zcmVNtGDbgnfP2IYBzk9NtodpUa27ne0T0ZpwOPlVwevsIVZO2' +
|
||||
'24WLa+iQmmHOWDFFpVDlS0t0fLfOk7Hcb2xFsTxiCIiyKMho/IME1Du3' +
|
||||
'X4e6BVa3hobSSZv0rRtNgY1KcyYPrUPW2fxZ+oik3y9SgGvb7XpjVIta' +
|
||||
'8DWlDWRfZ9kzoweWEYqz9IA8Xd373RefpyuWI25zlHoX3nwljzsZU6dC' +
|
||||
'//h/Dt2DNr+IAvKO3+u23cWoB9kgcZJ2FJuqjLvVfCF+OWcig7zs2pTY' +
|
||||
'JW6Rg6lqbBCxiUUlae6xJrjfv0pzD2VYCLY7v1bVTagppwKzNI3WaluC' +
|
||||
'OrdDYUCxUSe56yd1oAoLPRVbYvomRboUO6cjQhEknERyvt45og2kORJO' +
|
||||
'EJayHW+jZgR0Y0jM3Nk17ubpij2gHxNx9kiLDOiCGSV5mn9mV7qd3HHc' +
|
||||
'OMSykiBgbyzjobi96LT2dIGLeDXTIdPOog8wyobO4jWq0GGs0vBB8oSY' +
|
||||
'XhHvixZLcSjX2KQuHmEoWzmJcr3DavdoXZmAurGWLKjzEdJc5dSD/eNr' +
|
||||
'99gjHX7wphJ6umKMM+fn6PcbYJkhDh2GlJL5COXjXfm/5aj/vuyaRRWZ' +
|
||||
'MZtmnYpGAtAPg7AUG"}'
|
||||
);
|
||||
clean();
|
||||
const result = typeof paste === 'string' && paste.includes('Sol is right');
|
||||
if (!result) console.log(paste);
|
||||
assert.ok(result);
|
||||
}
|
||||
);
|
||||
|
||||
it(
|
||||
'supports ZeroBin ciphertext with password (SJCL & Base64 1.7)',
|
||||
async function () {
|
||||
global.Base64 = require('../base64-1.7').Base64;
|
||||
const clean = jsdom();
|
||||
Object.defineProperty(window, 'crypto', {
|
||||
value: new WebCrypto(),
|
||||
writeable: false,
|
||||
});
|
||||
global.atob = common.atob;
|
||||
|
||||
// Of course you can easily decipher the following texts, if you like.
|
||||
// Bonus points for finding their sources and hidden meanings.
|
||||
const paste = await $.PrivateBin.CryptTool.decipher(
|
||||
'6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=',
|
||||
// -- "That's amazing. I've got the same combination on my luggage."
|
||||
Array.apply(0, Array(6)).map((_,b) => b + 1).join(''),
|
||||
'{"iv":"aTnR2qBL1CAmLX8FdWe3VA==","v":1,"iter":10000,"ks"' +
|
||||
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
|
||||
'lt":"u0lQvePq6L0=","ct":"A3nBTvICZtYy6xqbIJE0c8Veored5lM' +
|
||||
'JUGgGUm4581wjrPFlU0Q0tUZSf+RUUoZj2jqDa4kiyyZ5YNMe30hNMV0' +
|
||||
'oVSalNhRgD9svVMnPuF162IbyhVCwr7ULjT981CHxVlGNqGqmIU6L/Xi' +
|
||||
'xgdArxAA8x1GCrfAkBWWGeq8Qw5vJPG/RCHpwR4Wy3azrluqeyERBzma' +
|
||||
'OQjO/kM35TiI6IrLYFyYyL7upYlxAaxS0XBMZvN8QU8Lnerwvh5JVC6O' +
|
||||
'kkKrhogajTJIKozCF79yI78c50LUh7tTuI3Yoh7+fXxhoODvQdYFmoiU' +
|
||||
'lrutN7Y5ZMRdITvVu8fTYtX9c7Fiufmcq5icEimiHp2g1bvfpOaGOsFT' +
|
||||
'+XNFgC9215jcp5mpBdN852xs7bUtw+nDrf+LsDEX6iRpRZ+PYgLDN5xQ' +
|
||||
'T1ByEtYbeP+tO38pnx72oZdIB3cj8UkOxnxdNiZM5YB5egn4jUj1fHot' +
|
||||
'1I69WoTiUJipZ5PIATv7ScymRB+AYzjxjurQ9lVfX9QtAbEH2dhdmoUo' +
|
||||
'3IDRSXpWNCe9RC1aUIyWfZO7oI7FEohNscHNTLEcT+wFnFUPByLlXmjN' +
|
||||
'Z7FKeNpvUm3jTY4t4sbZH8o2dUl624PAw1INcJ6FKqWGWwoFT2j1MYC+' +
|
||||
'YV/LkLTdjuWfayvwLMh27G/FfKCRbW36vqinegqpPDylsx9+3oFkEw3y' +
|
||||
'5Z8+44oN91rE/4Md7JhPJeRVlFC9TNCj4dA+EVhbbQqscvSnIH2uHkMw' +
|
||||
'7mNNo7xba/YT9KoPDaniqnYqb+q2pX1WNWE7dLS2wfroMAS3kh8P22DA' +
|
||||
'V37AeiNoD2PcI6ZcHbRdPa+XRrRcJhSPPW7UQ0z4OvBfjdu/w390QxAx' +
|
||||
'SxvZewoh49fKKB6hTsRnZb4tpHkjlww=="}'
|
||||
);
|
||||
clean();
|
||||
delete global.Base64;
|
||||
const result = typeof paste === 'string' && paste.includes('securely packed in iron');
|
||||
if (!result) console.log(paste);
|
||||
assert.ok(result);
|
||||
}
|
||||
);
|
||||
|
||||
it(
|
||||
'supports ZeroBin ciphertext no password (SJCL & Base64 1.7)',
|
||||
async function () {
|
||||
global.Base64 = require('../base64-1.7').Base64;
|
||||
const clean = jsdom();
|
||||
Object.defineProperty(window, 'crypto', {
|
||||
value: new WebCrypto(),
|
||||
writeable: false,
|
||||
});
|
||||
global.atob = common.atob;
|
||||
|
||||
const paste = await $.PrivateBin.CryptTool.decipher(
|
||||
's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
|
||||
'', // no password
|
||||
'{"iv":"Z7lAZQbkrqGMvruxoSm6Pw==","v":1,"iter":10000,"ks"' +
|
||||
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
|
||||
'lt":"jN6CjbQMJCM=","ct":"PuOPWB3i2FPcreSrLYeQf84LdE8RHjs' +
|
||||
'c+MGtiOr4b7doNyWKYtkNorbRadxaPnEee2/Utrp1MIIfY5juJSy8RGw' +
|
||||
'EPX5ciWcYe6EzsXWznsnvhmpKNj9B7eIIrfSbxfy8E2e/g7xav1nive+' +
|
||||
'ljToka3WT1DZ8ILQd/NbnJeHWaoSEOfvz8+d8QJPb1tNZvs7zEY95Dum' +
|
||||
'QwbyOsIMKAvcZHJ9OJNpujXzdMyt6DpcFcqlldWBZ/8q5rAUTw0HNx/r' +
|
||||
'CgbhAxRYfNoTLIcMM4L0cXbPSgCjwf5FuO3EdE13mgEDhcClW79m0Qvc' +
|
||||
'nIh8xgzYoxLbp0+AwvC/MbZM8savN/0ieWr2EKkZ04ggiOIEyvfCUuNp' +
|
||||
'rQBYO+y8kKduNEN6by0Yf4LRCPfmwN+GezDLuzTnZIMhPbGqUAdgV6Ex' +
|
||||
'qK2ULEEIrQEMoOuQIxfoMhqLlzG79vXGt2O+BY+4IiYfvmuRLks4UXfy' +
|
||||
'HqxPXTJg48IYbGs0j4TtJPUgp3523EyYLwEGyVTAuWhYAmVIwd/hoV7d' +
|
||||
'7tmfcF73w9dufDFI3LNca2KxzBnWNPYvIZKBwWbq8ncxkb191dP6mjEi' +
|
||||
'7NnhqVk5A6vIBbu4AC5PZf76l6yep4xsoy/QtdDxCMocCXeAML9MQ9uP' +
|
||||
'QbuspOKrBvMfN5igA1kBqasnxI472KBNXsdZnaDddSVUuvhTcETM="}'
|
||||
);
|
||||
clean();
|
||||
delete global.Base64;
|
||||
const result = typeof paste === 'string' && paste.includes('Sol is right');
|
||||
if (!result) console.log(paste);
|
||||
assert.ok(result);
|
||||
}
|
||||
);
|
||||
|
||||
it('does not truncate messages', async function () {
|
||||
const message = fs.readFileSync('test/compression-sample.txt', 'ascii').trim(),
|
||||
clean = jsdom();
|
||||
|
|
|
@ -104,8 +104,8 @@ describe('Model', function () {
|
|||
'throws exception on empty query string',
|
||||
common.jscUrl(true, false),
|
||||
function (url) {
|
||||
let clean = jsdom('', {url: common.urlToString(url)}),
|
||||
result = false;
|
||||
const clean = jsdom('', {url: common.urlToString(url)});
|
||||
let result = false;
|
||||
try {
|
||||
$.PrivateBin.Model.getPasteId();
|
||||
}
|
||||
|
@ -126,15 +126,21 @@ describe('Model', function () {
|
|||
});
|
||||
|
||||
jsc.property(
|
||||
'returns the fragment of a v1 URL',
|
||||
'throws exception on v1 URLs',
|
||||
common.jscUrl(),
|
||||
function (url) {
|
||||
url.fragment = '0OIl'; // any non-base58 string
|
||||
const clean = jsdom('', {url: common.urlToString(url)}),
|
||||
result = $.PrivateBin.Model.getPasteKey();
|
||||
const clean = jsdom('', {url: common.urlToString(url)});
|
||||
let result = false;
|
||||
try {
|
||||
$.PrivateBin.Model.getPasteId();
|
||||
}
|
||||
catch(err) {
|
||||
result = true;
|
||||
}
|
||||
$.PrivateBin.Model.reset();
|
||||
clean();
|
||||
return url.fragment === result;
|
||||
return result;
|
||||
}
|
||||
);
|
||||
jsc.property(
|
||||
|
|
|
@ -177,36 +177,7 @@ describe('PasteStatus', function () {
|
|||
this.timeout(30000);
|
||||
|
||||
jsc.property(
|
||||
'shows burn after reading message or remaining time v1',
|
||||
'bool',
|
||||
'nat',
|
||||
common.jscUrl(),
|
||||
function (burnafterreading, remainingTime, url) {
|
||||
let clean = jsdom('', {url: common.urlToString(url)}),
|
||||
result;
|
||||
$('body').html('<div id="remainingtime" class="hidden"></div>');
|
||||
$.PrivateBin.PasteStatus.init();
|
||||
$.PrivateBin.PasteStatus.showRemainingTime($.PrivateBin.Helper.PasteFactory({'meta': {
|
||||
'burnafterreading': burnafterreading,
|
||||
'remaining_time': remainingTime
|
||||
}}));
|
||||
if (burnafterreading) {
|
||||
result = $('#remainingtime').hasClass('foryoureyesonly') &&
|
||||
!$('#remainingtime').hasClass('hidden');
|
||||
} else if (remainingTime) {
|
||||
result =!$('#remainingtime').hasClass('foryoureyesonly') &&
|
||||
!$('#remainingtime').hasClass('hidden');
|
||||
} else {
|
||||
result = $('#remainingtime').hasClass('hidden') &&
|
||||
!$('#remainingtime').hasClass('foryoureyesonly');
|
||||
}
|
||||
clean();
|
||||
return result;
|
||||
}
|
||||
);
|
||||
|
||||
jsc.property(
|
||||
'shows burn after reading message or remaining time v2',
|
||||
'shows burn after reading message or remaining time',
|
||||
'bool',
|
||||
'nat',
|
||||
common.jscUrl(),
|
||||
|
|
|
@ -731,7 +731,7 @@ describe('TopNav', function () {
|
|||
it(
|
||||
'displays raw text view correctly',
|
||||
function () {
|
||||
const clean = jsdom('', {url: 'https://privatebin.net/?0123456789abcdef#0'});
|
||||
const clean = jsdom('', {url: 'https://privatebin.net/?0123456789abcdef#1'});
|
||||
$('body').html('<button id="rawtextbutton"></button>');
|
||||
const sample = 'example';
|
||||
$.PrivateBin.PasteViewer.setText(sample);
|
||||
|
|
|
@ -65,7 +65,6 @@ class Configuration
|
|||
'email' => true,
|
||||
'icon' => 'jdenticon',
|
||||
'cspheader' => 'default-src \'none\'; base-uri \'self\'; form-action \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'wasm-unsafe-eval\'; style-src \'self\'; font-src \'self\'; frame-ancestors \'none\'; frame-src blob:; img-src \'self\' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-modals allow-downloads',
|
||||
'zerobincompatibility' => false,
|
||||
'httpwarning' => true,
|
||||
'compression' => 'zlib',
|
||||
),
|
||||
|
@ -110,7 +109,6 @@ class Configuration
|
|||
// update this array when adding/changing/removing js files
|
||||
'sri' => array(
|
||||
'js/base-x-4.0.0.js' => 'sha512-nNPg5IGCwwrveZ8cA/yMGr5HiRS5Ps2H+s0J/mKTPjCPWUgFGGw7M5nqdnPD3VsRwCVysUh3Y8OWjeSKGkEQJQ==',
|
||||
'js/base64-1.7.js' => 'sha512-JdwsSP3GyHR+jaCkns9CL9NTt4JUJqm/BsODGmYhBcj5EAPKcHYh+OiMfyHbcDLECe17TL0hjXADFkusAqiYgA==',
|
||||
'js/bootstrap-3.4.1.js' => 'sha512-oBTprMeNEKCnqfuqKd6sbvFzmFQtlXS3e0C/RGFV0hD6QzhHV+ODfaQbAlmY6/q0ubbwlAM/nCJjkrgA3waLzg==',
|
||||
'js/bootstrap-5.3.3.js' => 'sha512-in2rcOpLTdJ7/pw5qjF4LWHFRtgoBDxXCy49H4YGOcVdGiPaQucGIbOqxt1JvmpvOpq3J/C7VTa0FlioakB2gQ==',
|
||||
'js/dark-mode-switch.js' => 'sha512-BhY7dNU14aDN5L+muoUmA66x0CkYUWkQT0nxhKBLP/o2d7jE025+dvWJa4OiYffBGEFgmhrD/Sp+QMkxGMTz2g==',
|
||||
|
@ -118,9 +116,8 @@ class Configuration
|
|||
'js/kjua-0.9.0.js' => 'sha512-CVn7af+vTMBd9RjoS4QM5fpLFEOtBCoB0zPtaqIDC7sF4F8qgUSRFQQpIyEDGsr6yrjbuOLzdf20tkHHmpaqwQ==',
|
||||
'js/legacy.js' => 'sha512-UxW/TOZKon83n6dk/09GsYKIyeO5LeBHokxyIq+r7KFS5KMBeIB/EM7NrkVYIezwZBaovnyNtY2d9tKFicRlXg==',
|
||||
'js/prettify.js' => 'sha512-puO0Ogy++IoA2Pb9IjSxV1n4+kQkKXYAEUtVzfZpQepyDPyXk8hokiYDS7ybMogYlyyEIwMLpZqVhCkARQWLMg==',
|
||||
'js/privatebin.js' => 'sha512-mPPCBJRbTT7LCOhjv2xL01yhJqwKOgwalktUuQVgsno14vXAs8iAr7qQ6aYh9jUqTarUoXpZJSqxijpziSzhuA==',
|
||||
'js/privatebin.js' => 'sha512-FSrG36x5zv0ERkagznlfQSE4Dpnvf0Sm6F1a21Qn874ALt9OxqUObUTe7D8tmTBCo0jh5i2B4dh8wIa4HSWB8Q==',
|
||||
'js/purify-3.2.6.js' => 'sha512-zqwL4OoBLFx89QPewkz4Lz5CSA2ktU+f31fuECkF0iK3Id5qd3Zpq5dMby8KwHjIEpsUgOqwF58cnmcaNem0EA==',
|
||||
'js/rawinflate-0.3.js' => 'sha512-g8uelGgJW9A/Z1tB6Izxab++oj5kdD7B4qC7DHwZkB6DGMXKyzx7v5mvap2HXueI2IIn08YlRYM56jwWdm2ucQ==',
|
||||
'js/showdown-2.1.0.js' => 'sha512-WYXZgkTR0u/Y9SVIA4nTTOih0kXMEd8RRV6MLFdL6YU8ymhR528NLlYQt1nlJQbYz4EW+ZsS0fx1awhiQJme1Q==',
|
||||
'js/zlib-1.3.1-1.js' => 'sha512-5bU9IIP4PgBrOKLZvGWJD4kgfQrkTz8Z3Iqeu058mbQzW3mCumOU6M3UVbVZU9rrVoVwaW4cZK8U8h5xjF88eQ==',
|
||||
),
|
||||
|
@ -165,10 +162,8 @@ class Configuration
|
|||
}
|
||||
// provide different defaults for database model
|
||||
elseif (
|
||||
$section == 'model_options' && in_array(
|
||||
$this->_configuration['model']['class'],
|
||||
array('Database', 'privatebin_db', 'zerobin_db')
|
||||
)
|
||||
$section == 'model_options' &&
|
||||
$this->_configuration['model']['class'] === 'Database'
|
||||
) {
|
||||
$values = array(
|
||||
'dsn' => 'sqlite:' . PATH . 'data' . DIRECTORY_SEPARATOR . 'db.sq3',
|
||||
|
@ -178,10 +173,8 @@ class Configuration
|
|||
'opt' => array(),
|
||||
);
|
||||
} elseif (
|
||||
$section == 'model_options' && in_array(
|
||||
$this->_configuration['model']['class'],
|
||||
array('GoogleCloudStorage')
|
||||
)
|
||||
$section == 'model_options' &&
|
||||
$this->_configuration['model']['class'] === 'GoogleCloudStorage'
|
||||
) {
|
||||
$values = array(
|
||||
'bucket' => getenv('PRIVATEBIN_GCS_BUCKET') ? getenv('PRIVATEBIN_GCS_BUCKET') : null,
|
||||
|
@ -189,10 +182,8 @@ class Configuration
|
|||
'uniformacl' => false,
|
||||
);
|
||||
} elseif (
|
||||
$section == 'model_options' && in_array(
|
||||
$this->_configuration['model']['class'],
|
||||
array('S3Storage')
|
||||
)
|
||||
$section == 'model_options' &&
|
||||
$this->_configuration['model']['class'] === 'S3Storage'
|
||||
) {
|
||||
$values = array(
|
||||
'region' => null,
|
||||
|
@ -253,18 +244,6 @@ class Configuration
|
|||
}
|
||||
}
|
||||
|
||||
// support for old config file format, before the fork was renamed and PSR-4 introduced
|
||||
$this->_configuration['model']['class'] = str_replace(
|
||||
'zerobin_', 'privatebin_',
|
||||
$this->_configuration['model']['class']
|
||||
);
|
||||
|
||||
$this->_configuration['model']['class'] = str_replace(
|
||||
array('privatebin_data', 'privatebin_db'),
|
||||
array('Filesystem', 'Database'),
|
||||
$this->_configuration['model']['class']
|
||||
);
|
||||
|
||||
// ensure a valid expire default key is set
|
||||
if (!array_key_exists($this->_configuration['expire']['default'], $this->_configuration['expire_options'])) {
|
||||
$this->_configuration['expire']['default'] = key($this->_configuration['expire_options']);
|
||||
|
|
|
@ -239,19 +239,15 @@ class Controller
|
|||
/**
|
||||
* Store new paste or comment
|
||||
*
|
||||
* POST contains one or both:
|
||||
* data = json encoded FormatV2 encrypted text (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
|
||||
* attachment = json encoded FormatV2 encrypted text (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
|
||||
*
|
||||
* All optional data will go to meta information:
|
||||
* expire (optional) = expiration delay (never,5min,10min,1hour,1day,1week,1month,1year,burn) (default:never)
|
||||
* formatter (optional) = format to display the paste as (plaintext,syntaxhighlighting,markdown) (default:syntaxhighlighting)
|
||||
* burnafterreading (optional) = if this paste may only viewed once ? (0/1) (default:0)
|
||||
* opendiscusssion (optional) = is the discussion allowed on this paste ? (0/1) (default:0)
|
||||
* attachmentname = json encoded FormatV2 encrypted text (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
|
||||
* nickname (optional) = in discussion, encoded FormatV2 encrypted text nickname of author of comment (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
|
||||
* parentid (optional) = in discussion, which comment this comment replies to.
|
||||
* pasteid (optional) = in discussion, which paste this comment belongs to.
|
||||
* POST contains:
|
||||
* JSON encoded object with mandatory keys:
|
||||
* v = 2 (version)
|
||||
* adata (array)
|
||||
* ct (base64 encoded, encrypted text)
|
||||
* meta (optional):
|
||||
* expire = expiration delay (never,5min,10min,1hour,1day,1week,1month,1year,burn) (default:1week)
|
||||
* parentid (optional) = in discussions, which comment this comment replies to.
|
||||
* pasteid (optional) = in discussions, which paste this comment belongs to.
|
||||
*
|
||||
* @access private
|
||||
* @return string
|
||||
|
@ -323,7 +319,8 @@ class Controller
|
|||
$paste->setData($data);
|
||||
$paste->store();
|
||||
} catch (Exception $e) {
|
||||
return $this->_return_message(1, $e->getMessage());
|
||||
$this->_return_message(1, $e->getMessage());
|
||||
return;
|
||||
}
|
||||
$this->_return_message(0, $paste->getId(), array('deletetoken' => $paste->getDeleteToken()));
|
||||
}
|
||||
|
@ -473,7 +470,6 @@ class Controller
|
|||
$page->assign('BURNAFTERREADINGSELECTED', $this->_conf->getKey('burnafterreadingselected'));
|
||||
$page->assign('PASSWORD', $this->_conf->getKey('password'));
|
||||
$page->assign('FILEUPLOAD', $this->_conf->getKey('fileupload'));
|
||||
$page->assign('ZEROBINCOMPATIBILITY', $this->_conf->getKey('zerobincompatibility'));
|
||||
$page->assign('LANGUAGESELECTION', $languageselection);
|
||||
$page->assign('LANGUAGES', I18n::getLanguageLabels(I18n::getAvailableLanguages()));
|
||||
$page->assign('TEMPLATESELECTION', $templateselection);
|
||||
|
|
|
@ -171,44 +171,28 @@ abstract class AbstractData
|
|||
abstract public function getAllPastes();
|
||||
|
||||
/**
|
||||
* Get next free slot for comment from postdate.
|
||||
* Get next free slot for comment from the creation timestamp
|
||||
*
|
||||
* The creation timestamp is usually a unix timestamp in seconds, but if a
|
||||
* comment already exists at that timestamp, a number, separated by a dot is
|
||||
* appended to it and incremented, then the function recurses until a free
|
||||
* slot is found.
|
||||
*
|
||||
* @access protected
|
||||
* @param array $comments
|
||||
* @param int|string $postdate
|
||||
* @param int|string $created
|
||||
* @return int|string
|
||||
*/
|
||||
protected function getOpenSlot(array &$comments, $postdate)
|
||||
protected function getOpenSlot(array &$comments, $created)
|
||||
{
|
||||
if (array_key_exists($postdate, $comments)) {
|
||||
$parts = explode('.', (string) $postdate, 2);
|
||||
if (array_key_exists($created, $comments)) {
|
||||
$parts = explode('.', (string) $created, 2);
|
||||
if (!array_key_exists(1, $parts)) {
|
||||
$parts[1] = 0;
|
||||
}
|
||||
++$parts[1];
|
||||
return $this->getOpenSlot($comments, implode('.', $parts));
|
||||
}
|
||||
return $postdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade pre-version 1 pastes with attachment to version 1 format.
|
||||
*
|
||||
* @access protected
|
||||
* @static
|
||||
* @param array $paste
|
||||
* @return array
|
||||
*/
|
||||
protected static function upgradePreV1Format(array &$paste)
|
||||
{
|
||||
if (array_key_exists('attachment', $paste['meta'])) {
|
||||
$paste['attachment'] = $paste['meta']['attachment'];
|
||||
unset($paste['meta']['attachment']);
|
||||
if (array_key_exists('attachmentname', $paste['meta'])) {
|
||||
$paste['attachmentname'] = $paste['meta']['attachmentname'];
|
||||
unset($paste['meta']['attachmentname']);
|
||||
}
|
||||
}
|
||||
return $paste;
|
||||
return $created;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,52 +143,24 @@ class Database extends AbstractData
|
|||
public function create($pasteid, array &$paste)
|
||||
{
|
||||
$expire_date = 0;
|
||||
$opendiscussion = $burnafterreading = false;
|
||||
$attachment = $attachmentname = null;
|
||||
$meta = $paste['meta'];
|
||||
$isVersion1 = array_key_exists('data', $paste);
|
||||
if (array_key_exists('expire_date', $meta)) {
|
||||
$expire_date = (int) $meta['expire_date'];
|
||||
unset($meta['expire_date']);
|
||||
}
|
||||
if (array_key_exists('opendiscussion', $meta)) {
|
||||
$opendiscussion = $meta['opendiscussion'];
|
||||
unset($meta['opendiscussion']);
|
||||
}
|
||||
if (array_key_exists('burnafterreading', $meta)) {
|
||||
$burnafterreading = $meta['burnafterreading'];
|
||||
unset($meta['burnafterreading']);
|
||||
}
|
||||
if ($isVersion1) {
|
||||
if (array_key_exists('attachment', $meta)) {
|
||||
$attachment = $meta['attachment'];
|
||||
unset($meta['attachment']);
|
||||
}
|
||||
if (array_key_exists('attachmentname', $meta)) {
|
||||
$attachmentname = $meta['attachmentname'];
|
||||
unset($meta['attachmentname']);
|
||||
}
|
||||
} else {
|
||||
$opendiscussion = $paste['adata'][2];
|
||||
$burnafterreading = $paste['adata'][3];
|
||||
}
|
||||
try {
|
||||
return $this->_exec(
|
||||
'INSERT INTO "' . $this->_sanitizeIdentifier('paste') .
|
||||
'" VALUES(?,?,?,?,?,?,?,?)',
|
||||
'" VALUES(?,?,?,?)',
|
||||
array(
|
||||
$pasteid,
|
||||
$isVersion1 ? $paste['data'] : Json::encode($paste),
|
||||
Json::encode($paste),
|
||||
$expire_date,
|
||||
(int) $opendiscussion,
|
||||
(int) $burnafterreading,
|
||||
Json::encode($meta),
|
||||
$attachment,
|
||||
$attachmentname,
|
||||
)
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
error_log('Error while attempting to insert a paste into the database: ' . $e->getMessage() . PHP_EOL);
|
||||
error_log('Error while attempting to insert a paste into the database: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -214,38 +186,17 @@ class Database extends AbstractData
|
|||
return false;
|
||||
}
|
||||
// create array
|
||||
$data = Json::decode($row['data']);
|
||||
$isVersion2 = array_key_exists('v', $data) && $data['v'] >= 2;
|
||||
$paste = $isVersion2 ? $data : array('data' => $row['data']);
|
||||
$paste = Json::decode($row['data']);
|
||||
|
||||
try {
|
||||
$row['meta'] = Json::decode($row['meta']);
|
||||
$paste['meta'] = Json::decode($row['meta']);
|
||||
} catch (Exception $e) {
|
||||
$row['meta'] = array();
|
||||
$paste['meta'] = array();
|
||||
}
|
||||
$row = self::upgradePreV1Format($row);
|
||||
$paste['meta'] = $row['meta'];
|
||||
$expire_date = (int) $row['expiredate'];
|
||||
$expire_date = (int) $row['expiredate'];
|
||||
if ($expire_date > 0) {
|
||||
$paste['meta']['expire_date'] = $expire_date;
|
||||
}
|
||||
if ($isVersion2) {
|
||||
return $paste;
|
||||
}
|
||||
|
||||
// support v1 attachments
|
||||
if (array_key_exists('attachment', $row) && !empty($row['attachment'])) {
|
||||
$paste['attachment'] = $row['attachment'];
|
||||
if (array_key_exists('attachmentname', $row) && !empty($row['attachmentname'])) {
|
||||
$paste['attachmentname'] = $row['attachmentname'];
|
||||
}
|
||||
}
|
||||
if ($row['opendiscussion']) {
|
||||
$paste['meta']['opendiscussion'] = true;
|
||||
}
|
||||
if ($row['burnafterreading']) {
|
||||
$paste['meta']['burnafterreading'] = true;
|
||||
}
|
||||
|
||||
return $paste;
|
||||
}
|
||||
|
@ -300,41 +251,31 @@ class Database extends AbstractData
|
|||
*/
|
||||
public function createComment($pasteid, $parentid, $commentid, array &$comment)
|
||||
{
|
||||
if (array_key_exists('data', $comment)) {
|
||||
$version = 1;
|
||||
$data = $comment['data'];
|
||||
} else {
|
||||
try {
|
||||
$version = 2;
|
||||
$data = Json::encode($comment);
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$data = Json::encode($comment);
|
||||
} catch (Exception $e) {
|
||||
error_log('Error while attempting to insert a comment into the database: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
list($createdKey, $iconKey) = $this->_getVersionedKeys($version);
|
||||
$meta = $comment['meta'];
|
||||
unset($comment['meta']);
|
||||
foreach (array('nickname', $iconKey) as $key) {
|
||||
if (!array_key_exists($key, $meta)) {
|
||||
$meta[$key] = null;
|
||||
}
|
||||
$meta = $comment['meta'];
|
||||
if (!array_key_exists('icon', $meta)) {
|
||||
$meta['icon'] = null;
|
||||
}
|
||||
try {
|
||||
return $this->_exec(
|
||||
'INSERT INTO "' . $this->_sanitizeIdentifier('comment') .
|
||||
'" VALUES(?,?,?,?,?,?,?)',
|
||||
'" VALUES(?,?,?,?,?,?)',
|
||||
array(
|
||||
$commentid,
|
||||
$pasteid,
|
||||
$parentid,
|
||||
$data,
|
||||
$meta['nickname'],
|
||||
$meta[$iconKey],
|
||||
$meta[$createdKey],
|
||||
$meta['icon'],
|
||||
$meta['created'],
|
||||
)
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
error_log('Error while attempting to insert a comment into the database: ' . $e->getMessage() . PHP_EOL);
|
||||
error_log('Error while attempting to insert a comment into the database: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -355,25 +296,15 @@ class Database extends AbstractData
|
|||
|
||||
// create comment list
|
||||
$comments = array();
|
||||
if (is_array($rows) && count($rows)) {
|
||||
if (count($rows)) {
|
||||
foreach ($rows as $row) {
|
||||
$i = $this->getOpenSlot($comments, (int) $row['postdate']);
|
||||
$data = Json::decode($row['data']);
|
||||
if (array_key_exists('v', $data) && $data['v'] >= 2) {
|
||||
$version = 2;
|
||||
$comments[$i] = $data;
|
||||
} else {
|
||||
$version = 1;
|
||||
$comments[$i] = array('data' => $row['data']);
|
||||
}
|
||||
list($createdKey, $iconKey) = $this->_getVersionedKeys($version);
|
||||
$i = $this->getOpenSlot($comments, (int) $row['postdate']);
|
||||
$comments[$i] = Json::decode($row['data']);
|
||||
$comments[$i]['id'] = $row['dataid'];
|
||||
$comments[$i]['parentid'] = $row['parentid'];
|
||||
$comments[$i]['meta'] = array($createdKey => (int) $row['postdate']);
|
||||
foreach (array('nickname' => 'nickname', 'vizhash' => $iconKey) as $rowKey => $commentKey) {
|
||||
if (array_key_exists($rowKey, $row) && !empty($row[$rowKey])) {
|
||||
$comments[$i]['meta'][$commentKey] = $row[$rowKey];
|
||||
}
|
||||
$comments[$i]['meta'] = array('created' => (int) $row['postdate']);
|
||||
if (array_key_exists('vizhash', $row) && !empty($row['vizhash'])) {
|
||||
$comments[$i]['meta']['icon'] = $row['vizhash'];
|
||||
}
|
||||
}
|
||||
ksort($comments);
|
||||
|
@ -455,7 +386,7 @@ class Database extends AbstractData
|
|||
$fs = new Filesystem(array('dir' => 'data'));
|
||||
$value = $fs->getValue('salt');
|
||||
$this->setValue($value, 'salt');
|
||||
@unlink($file);
|
||||
unlink($file);
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
@ -536,7 +467,7 @@ class Database extends AbstractData
|
|||
* @param array $params
|
||||
* @param bool $firstOnly if only the first row should be returned
|
||||
* @throws PDOException
|
||||
* @return array|false
|
||||
* @return array
|
||||
*/
|
||||
private function _select($sql, array $params, $firstOnly = false)
|
||||
{
|
||||
|
@ -544,6 +475,10 @@ class Database extends AbstractData
|
|||
$statement->execute($params);
|
||||
if ($firstOnly) {
|
||||
$result = $statement->fetch(PDO::FETCH_ASSOC);
|
||||
if ($this->_type === 'oci' && is_array($result)) {
|
||||
// returned CLOB values are streams, convert these into strings
|
||||
$result = array_map('PrivateBin\Data\Database::_sanitizeClob', $result);
|
||||
}
|
||||
} elseif ($this->_type === 'oci') {
|
||||
// workaround for https://bugs.php.net/bug.php?id=46728
|
||||
$result = array();
|
||||
|
@ -554,30 +489,9 @@ class Database extends AbstractData
|
|||
$result = $statement->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
$statement->closeCursor();
|
||||
if ($this->_type === 'oci' && is_array($result)) {
|
||||
// returned CLOB values are streams, convert these into strings
|
||||
$result = $firstOnly ?
|
||||
array_map('PrivateBin\Data\Database::_sanitizeClob', $result) :
|
||||
$result;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* get version dependent key names
|
||||
*
|
||||
* @access private
|
||||
* @param int $version
|
||||
* @return array
|
||||
*/
|
||||
private function _getVersionedKeys($version)
|
||||
{
|
||||
if ($version === 1) {
|
||||
return array('postdate', 'vizhash');
|
||||
}
|
||||
return array('created', 'icon');
|
||||
}
|
||||
|
||||
/**
|
||||
* get table list query, depending on the database type
|
||||
*
|
||||
|
@ -731,7 +645,6 @@ class Database extends AbstractData
|
|||
private function _createPasteTable()
|
||||
{
|
||||
list($main_key, $after_key) = $this->_getPrimaryKeyClauses();
|
||||
$dataType = $this->_getDataType();
|
||||
$attachmentType = $this->_getAttachmentType();
|
||||
$metaType = $this->_getMetaType();
|
||||
$this->_db->exec(
|
||||
|
@ -739,16 +652,12 @@ class Database extends AbstractData
|
|||
"\"dataid\" CHAR(16) NOT NULL$main_key, " .
|
||||
"\"data\" $attachmentType, " .
|
||||
'"expiredate" INT, ' .
|
||||
'"opendiscussion" INT, ' .
|
||||
'"burnafterreading" INT, ' .
|
||||
"\"meta\" $metaType, " .
|
||||
"\"attachment\" $attachmentType, " .
|
||||
"\"attachmentname\" $dataType$after_key )"
|
||||
"\"meta\" $metaType$after_key )"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* create the paste table
|
||||
* create the comment table
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
|
@ -762,7 +671,6 @@ class Database extends AbstractData
|
|||
'"pasteid" CHAR(16), ' .
|
||||
'"parentid" CHAR(16), ' .
|
||||
"\"data\" $dataType, " .
|
||||
"\"nickname\" $dataType, " .
|
||||
"\"vizhash\" $dataType, " .
|
||||
"\"postdate\" INT$after_key )"
|
||||
);
|
||||
|
@ -791,7 +699,7 @@ class Database extends AbstractData
|
|||
}
|
||||
|
||||
/**
|
||||
* create the paste table
|
||||
* create the config table
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
|
@ -841,6 +749,26 @@ class Database extends AbstractData
|
|||
return preg_replace('/[^A-Za-z0-9_]+/', '', $this->_prefix . $identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the current database type supports dropping columns
|
||||
*
|
||||
* @access private
|
||||
* @return bool
|
||||
*/
|
||||
private function _supportsDropColumn()
|
||||
{
|
||||
$supportsDropColumn = true;
|
||||
if ($this->_type === 'sqlite') {
|
||||
try {
|
||||
$row = $this->_select('SELECT sqlite_version() AS "v"', array(), true);
|
||||
$supportsDropColumn = (bool) version_compare($row['v'], '3.35.0', '>=');
|
||||
} catch (PDOException $e) {
|
||||
$supportsDropColumn = false;
|
||||
}
|
||||
}
|
||||
return $supportsDropColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* upgrade the database schema from an old version
|
||||
*
|
||||
|
@ -912,26 +840,37 @@ class Database extends AbstractData
|
|||
}
|
||||
}
|
||||
if (version_compare($oldversion, '1.7.1', '<=')) {
|
||||
$supportsDropColumn = true;
|
||||
if ($this->_type === 'sqlite') {
|
||||
try {
|
||||
$row = $this->_select('SELECT sqlite_version() AS "v"', array(), true);
|
||||
$supportsDropColumn = version_compare($row['v'], '3.35.0', '>=');
|
||||
if (!$supportsDropColumn) {
|
||||
error_log('Error: the available SQLite version (' . $row['v'] . ') does not support dropping columns. SQLite version 3.35.0 or later is necessary. The migration will not be fully complete, and you will need to delete the "postdate" column of the "paste" table yourself!');
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$supportsDropColumn = false;
|
||||
error_log('Error while checking the SQLite version. The migration will not be fully complete, and you will need to delete the "postdate" column of the "paste" table yourself!');
|
||||
}
|
||||
}
|
||||
if ($supportsDropColumn) {
|
||||
if ($this->_supportsDropColumn()) {
|
||||
$this->_db->exec(
|
||||
'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') .
|
||||
'" DROP COLUMN "postdate"'
|
||||
);
|
||||
}
|
||||
}
|
||||
if (version_compare($oldversion, '1.7.8', '<=')) {
|
||||
if ($this->_supportsDropColumn()) {
|
||||
$this->_db->exec(
|
||||
'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') .
|
||||
'" DROP COLUMN "opendiscussion"'
|
||||
);
|
||||
$this->_db->exec(
|
||||
'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') .
|
||||
'" DROP COLUMN "burnafterreading"'
|
||||
);
|
||||
$this->_db->exec(
|
||||
'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') .
|
||||
'" DROP COLUMN "attachment"'
|
||||
);
|
||||
$this->_db->exec(
|
||||
'ALTER TABLE "' . $this->_sanitizeIdentifier('paste') .
|
||||
'" DROP COLUMN "attachmentname"'
|
||||
);
|
||||
$this->_db->exec(
|
||||
'ALTER TABLE "' . $this->_sanitizeIdentifier('comment') .
|
||||
'" DROP COLUMN "nickname"'
|
||||
);
|
||||
}
|
||||
}
|
||||
$this->_exec(
|
||||
'UPDATE "' . $this->_sanitizeIdentifier('config') .
|
||||
'" SET "value" = ? WHERE "id" = ?',
|
||||
|
|
|
@ -69,10 +69,7 @@ class Filesystem extends AbstractData
|
|||
public function __construct(array $options)
|
||||
{
|
||||
// if given update the data directory
|
||||
if (
|
||||
is_array($options) &&
|
||||
array_key_exists('dir', $options)
|
||||
) {
|
||||
if (array_key_exists('dir', $options)) {
|
||||
$this->_path = $options['dir'];
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +110,7 @@ class Filesystem extends AbstractData
|
|||
) {
|
||||
return false;
|
||||
}
|
||||
return self::upgradePreV1Format($paste);
|
||||
return $paste;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -229,9 +226,7 @@ class Filesystem extends AbstractData
|
|||
// Store in array
|
||||
$key = $this->getOpenSlot(
|
||||
$comments,
|
||||
(int) array_key_exists('created', $comment['meta']) ?
|
||||
$comment['meta']['created'] : // v2 comments
|
||||
$comment['meta']['postdate'] // v1 comments
|
||||
$comment['meta']['created']
|
||||
);
|
||||
$comments[$key] = $comment;
|
||||
}
|
||||
|
@ -317,7 +312,7 @@ class Filesystem extends AbstractData
|
|||
$file = $this->_path . DIRECTORY_SEPARATOR . 'salt.php';
|
||||
if (is_readable($file)) {
|
||||
$items = explode('|', file_get_contents($file));
|
||||
if (is_array($items) && count($items) == 3) {
|
||||
if (count($items) == 3) {
|
||||
return $items[1];
|
||||
}
|
||||
}
|
||||
|
@ -456,7 +451,7 @@ class Filesystem extends AbstractData
|
|||
self::PROTECTION_LINE . PHP_EOL . Json::encode($data)
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
error_log('Error while trying to store data to the filesystem at path "' . $filename . '": ' . $e->getMessage() . PHP_EOL);
|
||||
error_log('Error while trying to store data to the filesystem at path "' . $filename . '": ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -507,7 +502,7 @@ class Filesystem extends AbstractData
|
|||
if ($fileCreated === false || $writtenBytes === false || $writtenBytes < strlen($data)) {
|
||||
return false;
|
||||
}
|
||||
@chmod($filename, 0640); // protect file from access by other users on the host
|
||||
chmod($filename, 0640); // protect file from access by other users on the host
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,13 +62,13 @@ class GoogleCloudStorage extends AbstractData
|
|||
if (getenv('PRIVATEBIN_GCS_BUCKET')) {
|
||||
$bucket = getenv('PRIVATEBIN_GCS_BUCKET');
|
||||
}
|
||||
if (is_array($options) && array_key_exists('bucket', $options)) {
|
||||
if (array_key_exists('bucket', $options)) {
|
||||
$bucket = $options['bucket'];
|
||||
}
|
||||
if (is_array($options) && array_key_exists('prefix', $options)) {
|
||||
if (array_key_exists('prefix', $options)) {
|
||||
$this->_prefix = $options['prefix'];
|
||||
}
|
||||
if (is_array($options) && array_key_exists('uniformacl', $options)) {
|
||||
if (array_key_exists('uniformacl', $options)) {
|
||||
$this->_uniformacl = $options['uniformacl'];
|
||||
}
|
||||
|
||||
|
@ -98,8 +98,7 @@ class GoogleCloudStorage extends AbstractData
|
|||
/**
|
||||
* Uploads the payload in the $this->_bucket under the specified key.
|
||||
* The entire payload is stored as a JSON document. The metadata is replicated
|
||||
* as the GCS object's metadata except for the fields attachment, attachmentname
|
||||
* and salt.
|
||||
* as the GCS object's metadata except for the field salt.
|
||||
*
|
||||
* @param $key string to store the payload under
|
||||
* @param $payload array to store
|
||||
|
@ -108,7 +107,7 @@ class GoogleCloudStorage extends AbstractData
|
|||
private function _upload($key, &$payload)
|
||||
{
|
||||
$metadata = array_key_exists('meta', $payload) ? $payload['meta'] : array();
|
||||
unset($metadata['attachment'], $metadata['attachmentname'], $metadata['salt']);
|
||||
unset($metadata['salt']);
|
||||
foreach ($metadata as $k => $v) {
|
||||
$metadata[$k] = strval($v);
|
||||
}
|
||||
|
|
|
@ -81,33 +81,31 @@ class S3Storage extends AbstractData
|
|||
*/
|
||||
public function __construct(array $options)
|
||||
{
|
||||
if (is_array($options)) {
|
||||
// AWS SDK will try to load credentials from environment if credentials are not passed via configuration
|
||||
// ref: https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_credentials.html#default-credential-chain
|
||||
if (isset($options['accesskey']) && isset($options['secretkey'])) {
|
||||
$this->_options['credentials'] = array();
|
||||
// AWS SDK will try to load credentials from environment if credentials are not passed via configuration
|
||||
// ref: https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_credentials.html#default-credential-chain
|
||||
if (isset($options['accesskey']) && isset($options['secretkey'])) {
|
||||
$this->_options['credentials'] = array();
|
||||
|
||||
$this->_options['credentials']['key'] = $options['accesskey'];
|
||||
$this->_options['credentials']['secret'] = $options['secretkey'];
|
||||
}
|
||||
if (array_key_exists('region', $options)) {
|
||||
$this->_options['region'] = $options['region'];
|
||||
}
|
||||
if (array_key_exists('version', $options)) {
|
||||
$this->_options['version'] = $options['version'];
|
||||
}
|
||||
if (array_key_exists('endpoint', $options)) {
|
||||
$this->_options['endpoint'] = $options['endpoint'];
|
||||
}
|
||||
if (array_key_exists('use_path_style_endpoint', $options)) {
|
||||
$this->_options['use_path_style_endpoint'] = filter_var($options['use_path_style_endpoint'], FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
if (array_key_exists('bucket', $options)) {
|
||||
$this->_bucket = $options['bucket'];
|
||||
}
|
||||
if (array_key_exists('prefix', $options)) {
|
||||
$this->_prefix = $options['prefix'];
|
||||
}
|
||||
$this->_options['credentials']['key'] = $options['accesskey'];
|
||||
$this->_options['credentials']['secret'] = $options['secretkey'];
|
||||
}
|
||||
if (array_key_exists('region', $options)) {
|
||||
$this->_options['region'] = $options['region'];
|
||||
}
|
||||
if (array_key_exists('version', $options)) {
|
||||
$this->_options['version'] = $options['version'];
|
||||
}
|
||||
if (array_key_exists('endpoint', $options)) {
|
||||
$this->_options['endpoint'] = $options['endpoint'];
|
||||
}
|
||||
if (array_key_exists('use_path_style_endpoint', $options)) {
|
||||
$this->_options['use_path_style_endpoint'] = filter_var($options['use_path_style_endpoint'], FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
if (array_key_exists('bucket', $options)) {
|
||||
$this->_bucket = $options['bucket'];
|
||||
}
|
||||
if (array_key_exists('prefix', $options)) {
|
||||
$this->_prefix = $options['prefix'];
|
||||
}
|
||||
|
||||
$this->_client = new S3Client($this->_options);
|
||||
|
@ -158,8 +156,7 @@ class S3Storage extends AbstractData
|
|||
/**
|
||||
* Uploads the payload in the $this->_bucket under the specified key.
|
||||
* The entire payload is stored as a JSON document. The metadata is replicated
|
||||
* as the S3 object's metadata except for the fields attachment, attachmentname
|
||||
* and salt.
|
||||
* as the S3 object's metadata except for the field salt.
|
||||
*
|
||||
* @param $key string to store the payload under
|
||||
* @param $payload array to store
|
||||
|
@ -168,7 +165,7 @@ class S3Storage extends AbstractData
|
|||
private function _upload($key, &$payload)
|
||||
{
|
||||
$metadata = array_key_exists('meta', $payload) ? $payload['meta'] : array();
|
||||
unset($metadata['attachment'], $metadata['attachmentname'], $metadata['salt']);
|
||||
unset($metadata['salt']);
|
||||
foreach ($metadata as $k => $v) {
|
||||
$metadata[$k] = strval($v);
|
||||
}
|
||||
|
@ -286,7 +283,8 @@ class S3Storage extends AbstractData
|
|||
'Bucket' => $this->_bucket,
|
||||
'Key' => $entry['Key'],
|
||||
));
|
||||
$body = JSON::decode($object['Body']->getContents());
|
||||
$data = $object['Body']->getContents();
|
||||
$body = JSON::decode($data);
|
||||
$items = explode('/', $entry['Key']);
|
||||
$body['id'] = $items[3];
|
||||
$body['parentid'] = $items[2];
|
||||
|
|
|
@ -22,6 +22,27 @@ use PrivateBin\Persistence\ServerSalt;
|
|||
*/
|
||||
class Paste extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* authenticated data index of paste formatter (plaintext/syntaxhighlighting/markdown)
|
||||
*
|
||||
* @const int
|
||||
*/
|
||||
const ADATA_FORMATTER = 1;
|
||||
|
||||
/**
|
||||
* authenticated data index of open-discussion flag (0/1)
|
||||
*
|
||||
* @const int
|
||||
*/
|
||||
const ADATA_OPEN_DISCUSSION = 2;
|
||||
|
||||
/**
|
||||
* authenticated data index of burn-after-reading flag (0/1)
|
||||
*
|
||||
* @const int
|
||||
*/
|
||||
const ADATA_BURN_AFTER_READING = 3;
|
||||
|
||||
/**
|
||||
* Get paste data.
|
||||
*
|
||||
|
@ -38,42 +59,27 @@ class Paste extends AbstractModel
|
|||
|
||||
// check if paste has expired and delete it if necessary.
|
||||
if (array_key_exists('expire_date', $data['meta'])) {
|
||||
if ($data['meta']['expire_date'] < time()) {
|
||||
$now = time();
|
||||
if ($data['meta']['expire_date'] < $now) {
|
||||
$this->delete();
|
||||
throw new Exception(Controller::GENERIC_ERROR, 63);
|
||||
}
|
||||
// We kindly provide the remaining time before expiration (in seconds)
|
||||
$data['meta']['time_to_live'] = $data['meta']['expire_date'] - time();
|
||||
$data['meta']['time_to_live'] = $data['meta']['expire_date'] - $now;
|
||||
unset($data['meta']['expire_date']);
|
||||
}
|
||||
foreach (array('created', 'postdate') as $key) {
|
||||
if (array_key_exists($key, $data['meta'])) {
|
||||
unset($data['meta'][$key]);
|
||||
}
|
||||
if (array_key_exists('created', $data['meta'])) {
|
||||
unset($data['meta']['created']);
|
||||
}
|
||||
|
||||
// check if non-expired burn after reading paste needs to be deleted
|
||||
if (
|
||||
(array_key_exists('adata', $data) && $data['adata'][3] === 1) ||
|
||||
(array_key_exists('burnafterreading', $data['meta']) && $data['meta']['burnafterreading'])
|
||||
array_key_exists('adata', $data) &&
|
||||
$data['adata'][self::ADATA_BURN_AFTER_READING] === 1
|
||||
) {
|
||||
$this->delete();
|
||||
}
|
||||
|
||||
// set formatter for the view in version 1 pastes.
|
||||
if (array_key_exists('data', $data) && !array_key_exists('formatter', $data['meta'])) {
|
||||
// support < 0.21 syntax highlighting
|
||||
if (array_key_exists('syntaxcoloring', $data['meta']) && $data['meta']['syntaxcoloring'] === true) {
|
||||
$data['meta']['formatter'] = 'syntaxhighlighting';
|
||||
} else {
|
||||
$data['meta']['formatter'] = $this->_conf->getKey('defaultformatter');
|
||||
}
|
||||
}
|
||||
|
||||
// support old paste format with server wide salt
|
||||
if (!array_key_exists('salt', $data['meta'])) {
|
||||
$data['meta']['salt'] = ServerSalt::get();
|
||||
}
|
||||
$data['comments'] = array_values($this->getComments());
|
||||
$data['comment_count'] = count($data['comments']);
|
||||
$data['comment_offset'] = 0;
|
||||
|
@ -166,10 +172,8 @@ class Paste extends AbstractModel
|
|||
return $this->_store->readComments($this->getId());
|
||||
}
|
||||
return array_map(function ($comment) {
|
||||
foreach (array('created', 'postdate') as $key) {
|
||||
if (array_key_exists($key, $comment['meta'])) {
|
||||
unset($comment['meta'][$key]);
|
||||
}
|
||||
if (array_key_exists('created', $comment['meta'])) {
|
||||
unset($comment['meta']['created']);
|
||||
}
|
||||
return $comment;
|
||||
}, $this->_store->readComments($this->getId()));
|
||||
|
@ -190,11 +194,7 @@ class Paste extends AbstractModel
|
|||
if (!array_key_exists('salt', $this->_data['meta'])) {
|
||||
$this->get();
|
||||
}
|
||||
return hash_hmac(
|
||||
$this->_conf->getKey('zerobincompatibility') ? 'sha1' : 'sha256',
|
||||
$this->getId(),
|
||||
$this->_data['meta']['salt']
|
||||
);
|
||||
return hash_hmac('sha256', $this->getId(), $this->_data['meta']['salt']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -209,9 +209,8 @@ class Paste extends AbstractModel
|
|||
if (!array_key_exists('adata', $this->_data) && !array_key_exists('data', $this->_data)) {
|
||||
$this->get();
|
||||
}
|
||||
return
|
||||
(array_key_exists('adata', $this->_data) && $this->_data['adata'][2] === 1) ||
|
||||
(array_key_exists('opendiscussion', $this->_data['meta']) && $this->_data['meta']['opendiscussion']);
|
||||
return array_key_exists('adata', $this->_data) &&
|
||||
$this->_data['adata'][self::ADATA_OPEN_DISCUSSION] === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -246,23 +245,26 @@ class Paste extends AbstractModel
|
|||
protected function _validate(array &$data)
|
||||
{
|
||||
// reject invalid or disabled formatters
|
||||
if (!array_key_exists($data['adata'][1], $this->_conf->getSection('formatter_options'))) {
|
||||
if (!array_key_exists($data['adata'][self::ADATA_FORMATTER], $this->_conf->getSection('formatter_options'))) {
|
||||
throw new Exception('Invalid data.', 75);
|
||||
}
|
||||
|
||||
// discussion requested, but disabled in config or burn after reading requested as well, or invalid integer
|
||||
if (
|
||||
($data['adata'][2] === 1 && ( // open discussion flag
|
||||
($data['adata'][self::ADATA_OPEN_DISCUSSION] === 1 && (
|
||||
!$this->_conf->getKey('discussion') ||
|
||||
$data['adata'][3] === 1 // burn after reading flag
|
||||
$data['adata'][self::ADATA_BURN_AFTER_READING] === 1
|
||||
)) ||
|
||||
($data['adata'][2] !== 0 && $data['adata'][2] !== 1)
|
||||
($data['adata'][self::ADATA_OPEN_DISCUSSION] !== 0 && $data['adata'][self::ADATA_OPEN_DISCUSSION] !== 1)
|
||||
) {
|
||||
throw new Exception('Invalid data.', 74);
|
||||
}
|
||||
|
||||
// reject invalid burn after reading
|
||||
if ($data['adata'][3] !== 0 && $data['adata'][3] !== 1) {
|
||||
if (
|
||||
$data['adata'][self::ADATA_BURN_AFTER_READING] !== 0 &&
|
||||
$data['adata'][self::ADATA_BURN_AFTER_READING] !== 1
|
||||
) {
|
||||
throw new Exception('Invalid data.', 73);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,6 +93,9 @@ class Vizhash16x16
|
|||
|
||||
// Then use these integers to drive the creation of an image.
|
||||
$image = imagecreatetruecolor($this->width, $this->height);
|
||||
if ($image === false) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$r = $r0 = $this->getInt();
|
||||
$g = $g0 = $this->getInt();
|
||||
|
@ -168,11 +171,11 @@ class Vizhash16x16
|
|||
* @link https://www.supportduweb.com/scripts_tutoriaux-code-source-41-gd-faire-un-degrade-en-php-gd-fonction-degrade-imagerie.html
|
||||
*
|
||||
* @access private
|
||||
* @param resource $img
|
||||
* @param resource|\GdImage $img
|
||||
* @param string $direction
|
||||
* @param array $color1
|
||||
* @param array $color2
|
||||
* @return resource
|
||||
* @return resource|\GdImage
|
||||
*/
|
||||
private function degrade($img, $direction, $color1, $color2)
|
||||
{
|
||||
|
@ -205,7 +208,7 @@ class Vizhash16x16
|
|||
* Draw a shape
|
||||
*
|
||||
* @access private
|
||||
* @param resource $image
|
||||
* @param resource|\GdImage $image
|
||||
* @param int $action
|
||||
* @param int $color
|
||||
*/
|
||||
|
|
|
@ -49,15 +49,9 @@ if ($QRCODE) :
|
|||
<?php $this->_scriptTag('js/kjua-0.9.0.js', 'async'); ?>
|
||||
<?php
|
||||
endif;
|
||||
if ($ZEROBINCOMPATIBILITY) :
|
||||
?>
|
||||
<?php $this->_scriptTag('js/base64-1.7.js', 'async'); ?>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<?php $this->_scriptTag('js/zlib-1.3.1-1.js', 'async'); ?>
|
||||
<?php $this->_scriptTag('js/base-x-4.0.0.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/rawinflate-0.3.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/bootstrap-3.4.1.js', 'defer'); ?>
|
||||
<?php
|
||||
if ($SYNTAXHIGHLIGHTING) :
|
||||
|
|
|
@ -32,15 +32,9 @@ if ($QRCODE) :
|
|||
<?php $this->_scriptTag('js/kjua-0.9.0.js', 'async'); ?>
|
||||
<?php
|
||||
endif;
|
||||
if ($ZEROBINCOMPATIBILITY) :
|
||||
?>
|
||||
<?php $this->_scriptTag('js/base64-1.7.js', 'defer'); ?>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<?php $this->_scriptTag('js/zlib-1.3.1-1.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/base-x-4.0.0.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/rawinflate-0.3.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/bootstrap-5.3.3.js', 'async'); ?>
|
||||
<?php $this->_scriptTag('js/dark-mode-switch.js', 'defer'); ?>
|
||||
<?php
|
||||
|
|
|
@ -39,22 +39,6 @@ class Helper
|
|||
*/
|
||||
private static $pasteid = '5b65a01b43987bc2';
|
||||
|
||||
/**
|
||||
* example paste version 1
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $pasteV1 = array(
|
||||
'data' => '{"iv":"EN39/wd5Nk8HAiSG2K5AsQ","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"QKN1DBXe5PI","ct":"8hA83xDdXjD7K2qfmw5NdA"}',
|
||||
'attachment' => '{"iv":"Pd4pOKWkmDTT9uPwVwd5Ag","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"6nOCU3peNDclDDpFtJEBKA"}',
|
||||
'attachmentname' => '{"iv":"76MkAtOGC4oFogX/aSMxRA","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"b6Ae/U1xJdsX/+lATud4sQ"}',
|
||||
'meta' => array(
|
||||
'formatter' => 'plaintext',
|
||||
'postdate' => 1344803344,
|
||||
'opendiscussion' => true,
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* example paste version 2
|
||||
*
|
||||
|
@ -91,17 +75,13 @@ class Helper
|
|||
private static $commentid = '5a52eebf11c4c94b';
|
||||
|
||||
/**
|
||||
* example comment
|
||||
* example comment meta data
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $commentV1 = array(
|
||||
'data' => '{"iv":"Pd4pOKWkmDTT9uPwVwd5Ag","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"6nOCU3peNDclDDpFtJEBKA"}',
|
||||
'meta' => array(
|
||||
'nickname' => '{"iv":"76MkAtOGC4oFogX/aSMxRA","v":1,"iter":1000,"ks":128,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"ZIUhFTliVz4","ct":"b6Ae/U1xJdsX/+lATud4sQ"}',
|
||||
'vizhash' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGUlEQVQokWOsl5/94983CNKQMjnxaOePf98MeKwPfNjkLZ3AgARab6b9+PeNEVnDj3/ff/z7ZiHnzsDA8Pv7H2TVPJw8EAYLAwb48OaVgIgYKycLsrYv378wMDB8//qdCVMDRA9EKSsnCwRBxNsepaLboMFlyMDAICAi9uHNK24GITQ/MDAwoNhgIGMLtwGrzegaLjw5jMz9+vUdnN17uwDCQDhJgk0O07yvX9+teDX1x79v6DYIsIjgcgMaYGFgYOBg4kJx2JejkAiBxAw+PzAwMNz4dp6wDXDw4MdNNOl0rWYsNkD89OLXI/xmo9sgzatJjAYmBgYGDiauD3/ePP18nVgb4MF89+M5ZX6js293wUMpnr8KTQMAxsCJnJ30apMAAAAASUVORK5CYII=',
|
||||
'postdate' => 1344803528,
|
||||
),
|
||||
private static $commentV2 = array(
|
||||
'icon' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGUlEQVQokWOsl5/94983CNKQMjnxaOePf98MeKwPfNjkLZ3AgARab6b9+PeNEVnDj3/ff/z7ZiHnzsDA8Pv7H2TVPJw8EAYLAwb48OaVgIgYKycLsrYv378wMDB8//qdCVMDRA9EKSsnCwRBxNsepaLboMFlyMDAICAi9uHNK24GITQ/MDAwoNhgIGMLtwGrzegaLjw5jMz9+vUdnN17uwDCQDhJgk0O07yvX9+teDX1x79v6DYIsIjgcgMaYGFgYOBg4kJx2JejkAiBxAw+PzAwMNz4dp6wDXDw4MdNNOl0rWYsNkD89OLXI/xmo9sgzatJjAYmBgYGDiauD3/ePP18nVgb4MF89+M5ZX6js293wUMpnr8KTQMAxsCJnJ30apMAAAAASUVORK5CYII=',
|
||||
'created' => 1344803528,
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -124,30 +104,12 @@ class Helper
|
|||
/**
|
||||
* get example paste, as stored on server
|
||||
*
|
||||
* @param int $version
|
||||
* @param array $meta
|
||||
* @return array
|
||||
*/
|
||||
public static function getPaste($version = 2, array $meta = array()): array
|
||||
public static function getPaste(array $meta = array()): array
|
||||
{
|
||||
$example = self::getPasteWithAttachment($version, $meta);
|
||||
// v1 has the attachment stored in a separate property
|
||||
if ($version === 1) {
|
||||
unset($example['attachment'], $example['attachmentname']);
|
||||
}
|
||||
return $example;
|
||||
}
|
||||
|
||||
/**
|
||||
* get example paste with attachment, as stored on server
|
||||
*
|
||||
* @param int $version
|
||||
* @param array $meta
|
||||
* @return array
|
||||
*/
|
||||
public static function getPasteWithAttachment($version = 2, array $meta = array()): array
|
||||
{
|
||||
$example = $version === 1 ? self::$pasteV1 : self::$pasteV2;
|
||||
$example = self::$pasteV2;
|
||||
$example['meta']['salt'] = ServerSalt::generate();
|
||||
$example['meta'] = array_merge($example['meta'], $meta);
|
||||
return $example;
|
||||
|
@ -156,31 +118,25 @@ class Helper
|
|||
/**
|
||||
* get example paste, as decoded from POST by the request object
|
||||
*
|
||||
* @param int $version
|
||||
* @param array $meta
|
||||
* @return array
|
||||
*/
|
||||
public static function getPastePost($version = 2, array $meta = array()): array
|
||||
public static function getPastePost(array $meta = array()): array
|
||||
{
|
||||
$example = self::getPaste($version, $meta);
|
||||
if ($version == 2) {
|
||||
$example['meta'] = array('expire' => $example['meta']['expire']);
|
||||
} else {
|
||||
unset($example['meta']['postdate']);
|
||||
}
|
||||
$example = self::getPaste($meta);
|
||||
$example['meta'] = array('expire' => $example['meta']['expire']);
|
||||
return $example;
|
||||
}
|
||||
|
||||
/**
|
||||
* get example paste, as received via POST by the user
|
||||
*
|
||||
* @param int $version
|
||||
* @param array $meta
|
||||
* @return string
|
||||
*/
|
||||
public static function getPasteJson($version = 2, array $meta = array()): string
|
||||
public static function getPasteJson(array $meta = array()): string
|
||||
{
|
||||
return json_encode(self::getPastePost($version, $meta));
|
||||
return json_encode(self::getPastePost($meta));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -196,20 +152,16 @@ class Helper
|
|||
/**
|
||||
* get example comment, as stored on server
|
||||
*
|
||||
* @param int $version
|
||||
* @param array $meta
|
||||
* @return array
|
||||
*/
|
||||
public static function getComment($version = 2, array $meta = array()): array
|
||||
public static function getComment(array $meta = array()): array
|
||||
{
|
||||
$example = $version === 1 ? self::$commentV1 : self::$pasteV2;
|
||||
if ($version === 2) {
|
||||
$example['adata'] = $example['adata'][0];
|
||||
$example['pasteid'] = $example['parentid'] = self::getPasteId();
|
||||
$example['meta']['created'] = self::$commentV1['meta']['postdate'];
|
||||
$example['meta']['icon'] = self::$commentV1['meta']['vizhash'];
|
||||
unset($example['meta']['expire']);
|
||||
}
|
||||
$example = self::$pasteV2;
|
||||
$example['adata'] = $example['adata'][0];
|
||||
$example['pasteid'] = $example['parentid'] = self::getPasteId();
|
||||
unset($example['meta']['expire']);
|
||||
$example['meta'] = array_merge($example['meta'], self::$commentV2);
|
||||
$example['meta'] = array_merge($example['meta'], $meta);
|
||||
return $example;
|
||||
}
|
||||
|
@ -217,7 +169,6 @@ class Helper
|
|||
/**
|
||||
* get example comment, as decoded from POST by the request object
|
||||
*
|
||||
* @param int $version
|
||||
* @return array
|
||||
*/
|
||||
public static function getCommentPost(): array
|
||||
|
@ -230,7 +181,6 @@ class Helper
|
|||
/**
|
||||
* get example comment, as received via POST by user
|
||||
*
|
||||
* @param int $version
|
||||
* @return string
|
||||
*/
|
||||
public static function getCommentJson(): string
|
||||
|
|
|
@ -132,20 +132,6 @@ class ConfigurationTest extends TestCase
|
|||
$this->assertEquals($options, $conf->get(), 'not overriding "missing" subkeys');
|
||||
}
|
||||
|
||||
public function testHandlePreRenameConfig()
|
||||
{
|
||||
$options = $this->_options;
|
||||
$options['model']['class'] = 'zerobin_data';
|
||||
Helper::createIniFile(CONF, $options);
|
||||
$conf = new Configuration;
|
||||
$this->assertEquals('Filesystem', $conf->getKey('class', 'model'), 'old data class gets renamed');
|
||||
|
||||
$options['model']['class'] = 'zerobin_db';
|
||||
Helper::createIniFile(CONF, $options);
|
||||
$conf = new Configuration;
|
||||
$this->assertEquals('Database', $conf->getKey('class', 'model'), 'old db class gets renamed');
|
||||
}
|
||||
|
||||
public function testConfigPath()
|
||||
{
|
||||
// setup
|
||||
|
|
|
@ -201,7 +201,7 @@ class ControllerTest extends TestCase
|
|||
$options = parse_ini_file(CONF, true);
|
||||
$options['traffic']['limit'] = 0;
|
||||
Helper::createIniFile(CONF, $options);
|
||||
$paste = Helper::getPasteJson(2, array('expire' => 25));
|
||||
$paste = Helper::getPasteJson(array('expire' => 25));
|
||||
$file = tempnam(sys_get_temp_dir(), 'FOO');
|
||||
file_put_contents($file, $paste);
|
||||
Request::setInputStream($file);
|
||||
|
@ -379,7 +379,7 @@ class ControllerTest extends TestCase
|
|||
$options = parse_ini_file(CONF, true);
|
||||
$options['traffic']['limit'] = 0;
|
||||
Helper::createIniFile(CONF, $options);
|
||||
$paste = Helper::getPasteJson(2, array('expire' => 'foo'));
|
||||
$paste = Helper::getPasteJson(array('expire' => 'foo'));
|
||||
$file = tempnam(sys_get_temp_dir(), 'FOO');
|
||||
file_put_contents($file, $paste);
|
||||
Request::setInputStream($file);
|
||||
|
@ -510,7 +510,7 @@ class ControllerTest extends TestCase
|
|||
$options['traffic']['limit'] = 0;
|
||||
Helper::createIniFile(CONF, $options);
|
||||
$file = tempnam(sys_get_temp_dir(), 'FOO');
|
||||
file_put_contents($file, Helper::getPasteJson(1));
|
||||
file_put_contents($file, '{"data":"","meta":{}}');
|
||||
Request::setInputStream($file);
|
||||
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
|
||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||
|
@ -696,7 +696,7 @@ class ControllerTest extends TestCase
|
|||
*/
|
||||
public function testReadExpired()
|
||||
{
|
||||
$expiredPaste = Helper::getPaste(2, array('expire_date' => 1344803344));
|
||||
$expiredPaste = Helper::getPaste(array('expire_date' => 1344803344));
|
||||
$this->_data->create(Helper::getPasteId(), $expiredPaste);
|
||||
$_SERVER['QUERY_STRING'] = Helper::getPasteId();
|
||||
$_GET[Helper::getPasteId()] = '';
|
||||
|
@ -767,37 +767,6 @@ class ControllerTest extends TestCase
|
|||
$this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly');
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testReadOldSyntax()
|
||||
{
|
||||
$paste = Helper::getPaste(1);
|
||||
$paste['meta'] = array(
|
||||
'syntaxcoloring' => true,
|
||||
'postdate' => $paste['meta']['postdate'],
|
||||
'opendiscussion' => $paste['meta']['opendiscussion'],
|
||||
);
|
||||
$this->_data->create(Helper::getPasteId(), $paste);
|
||||
$_SERVER['QUERY_STRING'] = Helper::getPasteId();
|
||||
$_GET[Helper::getPasteId()] = '';
|
||||
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
|
||||
ob_start();
|
||||
new Controller;
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$response = json_decode($content, true);
|
||||
$this->assertEquals(0, $response['status'], 'outputs success status');
|
||||
$this->assertEquals(Helper::getPasteId(), $response['id'], 'outputs data correctly');
|
||||
$this->assertStringEndsWith('?' . $response['id'], $response['url'], 'returned URL points to new paste');
|
||||
$this->assertEquals($paste['data'], $response['data'], 'outputs data correctly');
|
||||
$this->assertEquals('syntaxhighlighting', $response['meta']['formatter'], 'outputs format correctly');
|
||||
$this->assertFalse(array_key_exists('postdate', $response['meta']), 'does not output postdate');
|
||||
$this->assertEquals($paste['meta']['opendiscussion'], $response['meta']['opendiscussion'], 'outputs opendiscussion correctly');
|
||||
$this->assertEquals(0, $response['comment_count'], 'outputs comment_count correctly');
|
||||
$this->assertEquals(0, $response['comment_offset'], 'outputs comment_offset correctly');
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
|
@ -933,7 +902,7 @@ class ControllerTest extends TestCase
|
|||
*/
|
||||
public function testDeleteExpired()
|
||||
{
|
||||
$expiredPaste = Helper::getPaste(2, array('expire_date' => 1000));
|
||||
$expiredPaste = Helper::getPaste(array('expire_date' => 1000));
|
||||
$this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste does not exist before being created');
|
||||
$this->_data->create(Helper::getPasteId(), $expiredPaste);
|
||||
$this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data');
|
||||
|
@ -950,27 +919,4 @@ class ControllerTest extends TestCase
|
|||
);
|
||||
$this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste successfully deleted');
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testDeleteMissingPerPasteSalt()
|
||||
{
|
||||
$paste = Helper::getPaste();
|
||||
unset($paste['meta']['salt']);
|
||||
$this->_data->create(Helper::getPasteId(), $paste);
|
||||
$this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data');
|
||||
$_GET['pasteid'] = Helper::getPasteId();
|
||||
$_GET['deletetoken'] = hash_hmac('sha256', Helper::getPasteId(), ServerSalt::get());
|
||||
ob_start();
|
||||
new Controller;
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$this->assertMatchesRegularExpression(
|
||||
'#<div[^>]*id="status"[^>]*>.*Paste was properly deleted\.#s',
|
||||
$content,
|
||||
'outputs deleted status correctly'
|
||||
);
|
||||
$this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste successfully deleted');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ class DatabaseTest extends TestCase
|
|||
|
||||
public function testDatabaseBasedDataStoreWorks()
|
||||
{
|
||||
$error_log_setting = ini_get('error_log');
|
||||
$this->_model->delete(Helper::getPasteId());
|
||||
|
||||
// storing pastes
|
||||
|
@ -56,20 +57,22 @@ class DatabaseTest extends TestCase
|
|||
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
|
||||
$this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
|
||||
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
|
||||
ini_set('error_log', '/dev/null');
|
||||
$this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store the same paste twice');
|
||||
ini_set('error_log', $error_log_setting);
|
||||
$this->assertEquals($paste, $this->_model->read(Helper::getPasteId()));
|
||||
|
||||
// storing comments
|
||||
$comment1 = Helper::getComment(1);
|
||||
$comment2 = Helper::getComment(2);
|
||||
$comment1 = Helper::getComment();
|
||||
$comment2 = Helper::getComment();
|
||||
$meta1 = $comment1['meta'];
|
||||
$meta2 = $comment2['meta'];
|
||||
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'v1 comment does not yet exist');
|
||||
$this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment1) !== false, 'store v1 comment');
|
||||
$this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'v1 comment exists after storing it');
|
||||
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'v2 comment does not yet exist');
|
||||
$this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId(), $comment2) !== false, 'store v2 comment');
|
||||
$this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'v2 comment exists after storing it');
|
||||
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment 1 does not yet exist');
|
||||
$this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment1) !== false, 'store comment 1');
|
||||
$this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment 2 exists after storing it');
|
||||
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'comment 2 does not yet exist');
|
||||
$this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId(), $comment2) !== false, 'store comment 2');
|
||||
$this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'comment 2 exists after storing it');
|
||||
$comment1['id'] = Helper::getCommentId();
|
||||
$comment1['parentid'] = Helper::getPasteId();
|
||||
$comment1['meta'] = $meta1;
|
||||
|
@ -78,7 +81,7 @@ class DatabaseTest extends TestCase
|
|||
$comment2['meta'] = $meta2;
|
||||
$this->assertEquals(
|
||||
array(
|
||||
$comment1['meta']['postdate'] => $comment1,
|
||||
$comment1['meta']['created'] => $comment1,
|
||||
$comment2['meta']['created'] . '.1' => $comment2,
|
||||
),
|
||||
$this->_model->readComments(Helper::getPasteId())
|
||||
|
@ -93,17 +96,16 @@ class DatabaseTest extends TestCase
|
|||
|
||||
public function testDatabaseBasedAttachmentStoreWorks()
|
||||
{
|
||||
// this assumes a version 1 formatted paste
|
||||
$error_log_setting = ini_get('error_log');
|
||||
$this->_model->delete(Helper::getPasteId());
|
||||
$original = $paste = Helper::getPasteWithAttachment(1, array('expire_date' => 1344803344));
|
||||
$original = $paste = Helper::getPaste(array('expire_date' => 1344803344));
|
||||
$paste['meta']['burnafterreading'] = $original['meta']['burnafterreading'] = true;
|
||||
$paste['meta']['attachment'] = $paste['attachment'];
|
||||
$paste['meta']['attachmentname'] = $paste['attachmentname'];
|
||||
unset($paste['attachment'], $paste['attachmentname']);
|
||||
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
|
||||
$this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
|
||||
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
|
||||
ini_set('error_log', '/dev/null');
|
||||
$this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store the same paste twice');
|
||||
ini_set('error_log', $error_log_setting);
|
||||
$this->assertEquals($original, $this->_model->read(Helper::getPasteId()));
|
||||
}
|
||||
|
||||
|
@ -113,8 +115,8 @@ class DatabaseTest extends TestCase
|
|||
public function testPurge()
|
||||
{
|
||||
$this->_model->delete(Helper::getPasteId());
|
||||
$expired = Helper::getPaste(2, array('expire_date' => 1344803344));
|
||||
$paste = Helper::getPaste(2, array('expire_date' => time() + 3600));
|
||||
$expired = Helper::getPaste(array('expire_date' => 1344803344));
|
||||
$paste = Helper::getPaste(array('expire_date' => time() + 3600));
|
||||
$keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z');
|
||||
$ids = array();
|
||||
foreach ($keys as $key) {
|
||||
|
@ -144,23 +146,29 @@ class DatabaseTest extends TestCase
|
|||
|
||||
public function testErrorDetection()
|
||||
{
|
||||
$error_log_setting = ini_get('error_log');
|
||||
$this->_model->delete(Helper::getPasteId());
|
||||
$paste = Helper::getPaste(2, array('expire' => "Invalid UTF-8 sequence: \xB1\x31"));
|
||||
$paste = Helper::getPaste(array('expire' => "Invalid UTF-8 sequence: \xB1\x31"));
|
||||
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
|
||||
ini_set('error_log', '/dev/null');
|
||||
$this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
|
||||
ini_set('error_log', $error_log_setting);
|
||||
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist');
|
||||
}
|
||||
|
||||
public function testCommentErrorDetection()
|
||||
{
|
||||
$error_log_setting = ini_get('error_log');
|
||||
$this->_model->delete(Helper::getPasteId());
|
||||
$data = Helper::getPaste();
|
||||
$comment = Helper::getComment(2, array('nickname' => "Invalid UTF-8 sequence: \xB1\x31"));
|
||||
$comment = Helper::getComment(array('icon' => "Invalid UTF-8 sequence: \xB1\x31"));
|
||||
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
|
||||
$this->assertTrue($this->_model->create(Helper::getPasteId(), $data), 'store new paste');
|
||||
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
|
||||
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist');
|
||||
ini_set('error_log', '/dev/null');
|
||||
$this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'unable to store broken comment');
|
||||
ini_set('error_log', $error_log_setting);
|
||||
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does still not exist');
|
||||
}
|
||||
|
||||
|
@ -263,91 +271,6 @@ class DatabaseTest extends TestCase
|
|||
new Database($options);
|
||||
}
|
||||
|
||||
public function testOldAttachments()
|
||||
{
|
||||
mkdir($this->_path);
|
||||
$path = $this->_path . DIRECTORY_SEPARATOR . 'attachement-test.sq3';
|
||||
if (is_file($path)) {
|
||||
unlink($path);
|
||||
}
|
||||
$this->_options['dsn'] = 'sqlite:' . $path;
|
||||
$this->_options['tbl'] = 'bar_';
|
||||
$model = new Database($this->_options);
|
||||
|
||||
$original = $paste = Helper::getPasteWithAttachment(1, array('expire_date' => 1344803344));
|
||||
$meta = $paste['meta'];
|
||||
$meta['attachment'] = $paste['attachment'];
|
||||
$meta['attachmentname'] = $paste['attachmentname'];
|
||||
unset($paste['attachment'], $paste['attachmentname']);
|
||||
|
||||
$db = new PDO(
|
||||
$this->_options['dsn'],
|
||||
$this->_options['usr'],
|
||||
$this->_options['pwd'],
|
||||
$this->_options['opt']
|
||||
);
|
||||
$statement = $db->prepare('INSERT INTO bar_paste VALUES(?,?,?,?,?,?,?,?)');
|
||||
$statement->execute(
|
||||
array(
|
||||
Helper::getPasteId(),
|
||||
$paste['data'],
|
||||
$paste['meta']['expire_date'],
|
||||
0,
|
||||
0,
|
||||
json_encode($meta),
|
||||
null,
|
||||
null,
|
||||
)
|
||||
);
|
||||
$statement->closeCursor();
|
||||
|
||||
$this->assertTrue($model->exists(Helper::getPasteId()), 'paste exists after storing it');
|
||||
$this->assertEquals($original, $model->read(Helper::getPasteId()));
|
||||
|
||||
Helper::rmDir($this->_path);
|
||||
}
|
||||
|
||||
public function testCorruptMeta()
|
||||
{
|
||||
mkdir($this->_path);
|
||||
$path = $this->_path . DIRECTORY_SEPARATOR . 'meta-test.sq3';
|
||||
if (is_file($path)) {
|
||||
unlink($path);
|
||||
}
|
||||
$this->_options['dsn'] = 'sqlite:' . $path;
|
||||
$this->_options['tbl'] = 'baz_';
|
||||
$model = new Database($this->_options);
|
||||
$paste = Helper::getPaste(1, array('expire_date' => 1344803344));
|
||||
unset($paste['meta']['formatter'], $paste['meta']['opendiscussion'], $paste['meta']['postdate'], $paste['meta']['salt']);
|
||||
$model->delete(Helper::getPasteId());
|
||||
|
||||
$db = new PDO(
|
||||
$this->_options['dsn'],
|
||||
$this->_options['usr'],
|
||||
$this->_options['pwd'],
|
||||
$this->_options['opt']
|
||||
);
|
||||
$statement = $db->prepare('INSERT INTO baz_paste VALUES(?,?,?,?,?,?,?,?)');
|
||||
$statement->execute(
|
||||
array(
|
||||
Helper::getPasteId(),
|
||||
$paste['data'],
|
||||
$paste['meta']['expire_date'],
|
||||
0,
|
||||
0,
|
||||
'{',
|
||||
null,
|
||||
null,
|
||||
)
|
||||
);
|
||||
$statement->closeCursor();
|
||||
|
||||
$this->assertTrue($model->exists(Helper::getPasteId()), 'paste exists after storing it');
|
||||
$this->assertEquals($paste, $model->read(Helper::getPasteId()));
|
||||
|
||||
Helper::rmDir($this->_path);
|
||||
}
|
||||
|
||||
public function testTableUpgrade()
|
||||
{
|
||||
mkdir($this->_path);
|
||||
|
|
|
@ -37,7 +37,7 @@ class FilesystemTest extends TestCase
|
|||
$this->_model->delete(Helper::getPasteId());
|
||||
|
||||
// storing pastes
|
||||
$paste = Helper::getPaste(2, array('expire_date' => 1344803344));
|
||||
$paste = Helper::getPaste(array('expire_date' => 1344803344));
|
||||
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
|
||||
$this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
|
||||
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
|
||||
|
@ -67,10 +67,7 @@ class FilesystemTest extends TestCase
|
|||
public function testFileBasedAttachmentStoreWorks()
|
||||
{
|
||||
$this->_model->delete(Helper::getPasteId());
|
||||
$original = $paste = Helper::getPasteWithAttachment(1, array('expire_date' => 1344803344));
|
||||
$paste['meta']['attachment'] = $paste['attachment'];
|
||||
$paste['meta']['attachmentname'] = $paste['attachmentname'];
|
||||
unset($paste['attachment'], $paste['attachmentname']);
|
||||
$original = $paste = Helper::getPaste(array('expire_date' => 1344803344));
|
||||
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
|
||||
$this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
|
||||
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
|
||||
|
@ -84,8 +81,8 @@ class FilesystemTest extends TestCase
|
|||
public function testPurge()
|
||||
{
|
||||
mkdir($this->_path . DIRECTORY_SEPARATOR . '00', 0777, true);
|
||||
$expired = Helper::getPaste(2, array('expire_date' => 1344803344));
|
||||
$paste = Helper::getPaste(2, array('expire_date' => time() + 3600));
|
||||
$expired = Helper::getPaste(array('expire_date' => 1344803344));
|
||||
$paste = Helper::getPaste(array('expire_date' => time() + 3600));
|
||||
$keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z');
|
||||
$ids = array();
|
||||
foreach ($keys as $key) {
|
||||
|
@ -114,24 +111,30 @@ class FilesystemTest extends TestCase
|
|||
|
||||
public function testErrorDetection()
|
||||
{
|
||||
$error_log_setting = ini_get('error_log');
|
||||
$this->_model->delete(Helper::getPasteId());
|
||||
$paste = Helper::getPaste(2, array('expire' => "Invalid UTF-8 sequence: \xB1\x31"));
|
||||
$paste = Helper::getPaste(array('expire' => "Invalid UTF-8 sequence: \xB1\x31"));
|
||||
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
|
||||
ini_set('error_log', '/dev/null');
|
||||
$this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
|
||||
ini_set('error_log', $error_log_setting);
|
||||
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist');
|
||||
$this->assertFalse($this->_model->setValue('foo', 'non existing namespace'), 'rejects setting value in non existing namespace');
|
||||
}
|
||||
|
||||
public function testCommentErrorDetection()
|
||||
{
|
||||
$error_log_setting = ini_get('error_log');
|
||||
$this->_model->delete(Helper::getPasteId());
|
||||
$data = Helper::getPaste();
|
||||
$comment = Helper::getComment(1, array('nickname' => "Invalid UTF-8 sequence: \xB1\x31"));
|
||||
$comment = Helper::getComment(array('icon' => "Invalid UTF-8 sequence: \xB1\x31"));
|
||||
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
|
||||
$this->assertTrue($this->_model->create(Helper::getPasteId(), $data), 'store new paste');
|
||||
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
|
||||
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist');
|
||||
ini_set('error_log', '/dev/null');
|
||||
$this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'unable to store broken comment');
|
||||
ini_set('error_log', $error_log_setting);
|
||||
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does still not exist');
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ class GoogleCloudStorageTest extends TestCase
|
|||
{
|
||||
private static $_client;
|
||||
private static $_bucket;
|
||||
private $_model;
|
||||
|
||||
public static function setUpBeforeClass(): void
|
||||
{
|
||||
|
@ -50,7 +51,7 @@ class GoogleCloudStorageTest extends TestCase
|
|||
$this->_model->delete(Helper::getPasteId());
|
||||
|
||||
// storing pastes
|
||||
$paste = Helper::getPaste(2, array('expire_date' => 1344803344));
|
||||
$paste = Helper::getPaste(array('expire_date' => 1344803344));
|
||||
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
|
||||
$this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
|
||||
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
|
||||
|
@ -82,8 +83,8 @@ class GoogleCloudStorageTest extends TestCase
|
|||
*/
|
||||
public function testPurge()
|
||||
{
|
||||
$expired = Helper::getPaste(2, array('expire_date' => 1344803344));
|
||||
$paste = Helper::getPaste(2, array('expire_date' => time() + 3600));
|
||||
$expired = Helper::getPaste(array('expire_date' => 1344803344));
|
||||
$paste = Helper::getPaste(array('expire_date' => time() + 3600));
|
||||
$keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z');
|
||||
$ids = array();
|
||||
foreach ($keys as $key) {
|
||||
|
@ -113,7 +114,7 @@ class GoogleCloudStorageTest extends TestCase
|
|||
public function testErrorDetection()
|
||||
{
|
||||
$this->_model->delete(Helper::getPasteId());
|
||||
$paste = Helper::getPaste(2, array('expire' => "Invalid UTF-8 sequence: \xB1\x31"));
|
||||
$paste = Helper::getPaste(array('expire' => "Invalid UTF-8 sequence: \xB1\x31"));
|
||||
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
|
||||
$this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
|
||||
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist');
|
||||
|
@ -123,7 +124,7 @@ class GoogleCloudStorageTest extends TestCase
|
|||
{
|
||||
$this->_model->delete(Helper::getPasteId());
|
||||
$data = Helper::getPaste();
|
||||
$comment = Helper::getComment(1, array('nickname' => "Invalid UTF-8 sequence: \xB1\x31"));
|
||||
$comment = Helper::getComment(array('icon' => "Invalid UTF-8 sequence: \xB1\x31"));
|
||||
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
|
||||
$this->assertTrue($this->_model->create(Helper::getPasteId(), $data), 'store new paste');
|
||||
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
|
||||
|
|
|
@ -103,57 +103,6 @@ class ModelTest extends TestCase
|
|||
$this->assertEquals(array(), $paste->getComments(), 'comment was deleted with paste');
|
||||
}
|
||||
|
||||
public function testPasteV1()
|
||||
{
|
||||
$pasteData = Helper::getPaste(1);
|
||||
unset($pasteData['meta']['formatter']);
|
||||
|
||||
$path = $this->_path . DIRECTORY_SEPARATOR . 'v1-test.sq3';
|
||||
if (is_file($path)) {
|
||||
unlink($path);
|
||||
}
|
||||
$options = parse_ini_file(CONF_SAMPLE, true);
|
||||
$options['purge']['limit'] = 0;
|
||||
$options['model'] = array(
|
||||
'class' => 'Database',
|
||||
);
|
||||
$options['model_options'] = array(
|
||||
'dsn' => 'sqlite:' . $path,
|
||||
'usr' => null,
|
||||
'pwd' => null,
|
||||
'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
|
||||
);
|
||||
Helper::createIniFile(CONF, $options);
|
||||
$model = new Model(new Configuration);
|
||||
$model->getPaste('0000000000000000')->exists(); // triggers database table creation
|
||||
$model->getPaste(Helper::getPasteId())->delete(); // deletes the cache
|
||||
|
||||
$db = new PDO(
|
||||
$options['model_options']['dsn'],
|
||||
$options['model_options']['usr'],
|
||||
$options['model_options']['pwd'],
|
||||
$options['model_options']['opt']
|
||||
);
|
||||
$statement = $db->prepare('INSERT INTO paste VALUES(?,?,?,?,?,?,?,?)');
|
||||
$statement->execute(
|
||||
array(
|
||||
Helper::getPasteId(),
|
||||
$pasteData['data'],
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
json_encode($pasteData['meta']),
|
||||
null,
|
||||
null,
|
||||
)
|
||||
);
|
||||
$statement->closeCursor();
|
||||
|
||||
$paste = $model->getPaste(Helper::getPasteId());
|
||||
$this->assertNotEmpty($paste->getDeleteToken(), 'excercise the condition to load the data from storage');
|
||||
$this->assertEquals('plaintext', $paste->get()['meta']['formatter'], 'paste got created with default formatter');
|
||||
}
|
||||
|
||||
public function testCommentDefaults()
|
||||
{
|
||||
$class = 'PrivateBin\\Data\\' . $this->_conf->getKey('class', 'model');
|
||||
|
@ -435,8 +384,8 @@ class ModelTest extends TestCase
|
|||
$conf = new Configuration;
|
||||
$store = new Database($conf->getSection('model_options'));
|
||||
$store->delete(Helper::getPasteId());
|
||||
$expired = Helper::getPaste(2, array('expire_date' => 1344803344));
|
||||
$paste = Helper::getPaste(2, array('expire_date' => time() + 3600));
|
||||
$expired = Helper::getPaste(array('expire_date' => 1344803344));
|
||||
$paste = Helper::getPaste(array('expire_date' => time() + 3600));
|
||||
$keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'x', 'y', 'z');
|
||||
$ids = array();
|
||||
foreach ($keys as $key) {
|
||||
|
@ -543,6 +492,6 @@ class ModelTest extends TestCase
|
|||
$vz = new Vizhash16x16();
|
||||
$pngdata = 'data:image/png;base64,' . base64_encode($vz->generate(TrafficLimiter::getHash()));
|
||||
$comment = current($this->_model->getPaste(Helper::getPasteId())->get()['comments']);
|
||||
$this->assertEquals($pngdata, $comment['meta']['icon'], 'nickname triggers vizhash to be set');
|
||||
$this->assertEquals($pngdata, $comment['meta']['icon'], 'vizhash was generated');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@ class ViewTest extends TestCase
|
|||
$page->assign('BURNAFTERREADINGSELECTED', false);
|
||||
$page->assign('PASSWORD', true);
|
||||
$page->assign('FILEUPLOAD', false);
|
||||
$page->assign('ZEROBINCOMPATIBILITY', false);
|
||||
$page->assign('INFO', 'example');
|
||||
$page->assign('NOTICE', 'example');
|
||||
$page->assign('LANGUAGESELECTION', '');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue