removed leftovers from submodule uglifyjs, added credits file,
cleaned up CSS, changed template to output clean XHTML 5, added unit tests for 60% of the code, found a few bugs by doing that and fixed them
This commit is contained in:
parent
f37303d858
commit
907538875b
32 changed files with 961 additions and 511 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,6 +1,7 @@
|
|||
# Ignore data/ and tmp/
|
||||
data/
|
||||
tmp/
|
||||
tst/log/
|
||||
.settings/
|
||||
.buildpath
|
||||
.project
|
||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -1,3 +0,0 @@
|
|||
[submodule "uglifyjs"]
|
||||
path = uglifyjs
|
||||
url = https://github.com/mishoo/UglifyJS.git
|
8
CREDITS.md
Normal file
8
CREDITS.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
Credits
|
||||
=======
|
||||
Sébastien Sauvage - original idea and main developer
|
||||
|
||||
Alexey Gladkov - syntax highlighting
|
||||
Greg Knaddison - robots.txt
|
||||
MrKooky - XHTML5 markup, CSS cleanup
|
||||
Simon Rupf - MVC refactoring, configuration support and unit tests
|
29
INSTALL.md
29
INSTALL.md
|
@ -1,13 +1,13 @@
|
|||
Documentation
|
||||
=============
|
||||
Installation
|
||||
============
|
||||
|
||||
For Administrators
|
||||
------------------
|
||||
|
||||
In the index.php in the main folder you can define a different PATH. This is
|
||||
useful if you want to secure your installation and want to move the
|
||||
configuration, data files, templates and PHP libraries (directories cfg, lib
|
||||
and tpl) outside of your document root. This new location must still be
|
||||
configuration, data files, templates and PHP libraries (directories cfg, data,
|
||||
lib and tpl) outside of your document root. This new location must still be
|
||||
accessible to your webserver / PHP process.
|
||||
|
||||
> ### PATH Example ###
|
||||
|
@ -26,7 +26,7 @@ In the file "cfg/conf.ini" you can configure ZeroBin. The config file is
|
|||
divided into multiple sections, which are enclosed in square brackets. In the
|
||||
"[main]" section you can enable or disable the discussion feature, set the
|
||||
limit of stored pastes and comments in bytes. The "[traffic]" section lets you
|
||||
set a time limit in seconds. Users may not post more often the this limit to
|
||||
set a time limit in seconds. Users may not post more often then this limit to
|
||||
your ZeroBin.
|
||||
|
||||
Finally the "[model]" and "[model_options]" sections let you configure your
|
||||
|
@ -35,16 +35,16 @@ favourite way of storing the pastes and discussions on your server.
|
|||
data folder. This is the recommended setup for low traffic sites. Under high
|
||||
load, in distributed setups or if you are not allowed to store files locally,
|
||||
you might want to switch to the "zerobin_db" model. This lets you store your
|
||||
data in a database. Basically all databases, that are supported by PDO (PHP
|
||||
data in a database. Basically all databases that are supported by PDO (PHP
|
||||
data objects) may be used. Automatic table creation is provided for pdo_ibm,
|
||||
pdo_informix, pdo_mssql, pdo_mysql, pdo_oci, pdo_pgsql and pdo_sqlite. You may
|
||||
want to provide a table prefix, if you have to share the zerobin database with
|
||||
another application. The table prefix option is called "tbl".
|
||||
|
||||
> ### Note ###
|
||||
> The "zerobin_db" model has only been tested with sqlite and MySQL, although
|
||||
> it would not be recommended to use sqlite in a production environment. If you
|
||||
> gain any experience running ZeroBin on other RDBMS, let us know.
|
||||
> The "zerobin_db" model has only been tested with SQLite and MySQL, although
|
||||
> it would not be recommended to use SQLite in a production environment. If you
|
||||
> gain any experience running ZeroBin on other RDBMS, please let us know.
|
||||
|
||||
For reference or if you want to create the table schema for yourself:
|
||||
|
||||
|
@ -69,7 +69,8 @@ For reference or if you want to create the table schema for yourself:
|
|||
|
||||
For Developers
|
||||
--------------
|
||||
If you want to create your own data models, you might want to know how the arrays, that you have to store, look like:
|
||||
If you want to create your own data models, you might want to know how the
|
||||
arrays, that you have to store, look like:
|
||||
|
||||
public function create($pasteid, $paste)
|
||||
{
|
||||
|
@ -88,9 +89,9 @@ If you want to create your own data models, you might want to know how the array
|
|||
$parentid // the id of the parent of this comment, may be the paste id itself
|
||||
$commentid = substr(hash('md5', $paste['data']), 0, 16);
|
||||
|
||||
$paste['data'] // text
|
||||
$paste['meta']['nickname'] // text or null (if anonymous)
|
||||
$paste['meta']['vizhash'] // text or null (if anonymous)
|
||||
$paste['meta']['postdate'] // int UNIX timestamp
|
||||
$comment['data'] // text
|
||||
$comment['meta']['nickname'] // text or null (if anonymous)
|
||||
$comment['meta']['vizhash'] // text or null (if anonymous)
|
||||
$comment['meta']['postdate'] // int UNIX timestamp
|
||||
}
|
||||
|
||||
|
|
|
@ -38,8 +38,8 @@ dir = PATH "data"
|
|||
|
||||
;[model]
|
||||
; example of DB configuration for SQLite
|
||||
;[model_options]
|
||||
;class = zerobin_db
|
||||
;[model_options]
|
||||
;dsn = "sqlite:" PATH "data/db.sq3"
|
||||
;usr = null
|
||||
;pwd = null
|
||||
|
|
|
@ -32,14 +32,20 @@
|
|||
}
|
||||
|
||||
/* Put a border around prettyprinted code snippets. */
|
||||
pre.prettyprint { padding: 2px; border: 1px solid #888; background-color:white; white-space:pre-wrap; }
|
||||
.prettyprint {
|
||||
padding: 2px;
|
||||
border: 1px solid #888;
|
||||
background-color: white;
|
||||
white-space: pre-wrap;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* Specify class=linenums on a pre to get line numbering */
|
||||
ol.linenums {
|
||||
color: black;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
list-style: decimal outside;
|
||||
color: black;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
list-style: decimal outside;
|
||||
} /* IE indents via margin-left */
|
||||
/*
|
||||
li.L0,
|
||||
|
|
558
css/zerobin.css
558
css/zerobin.css
|
@ -4,354 +4,374 @@
|
|||
|
||||
/* CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved.
|
||||
Licensed under the BSD License. - http://yuilibrary.com/license/ */
|
||||
html{color:#000;background:#FFF}body,div,dl,dt,dd,ul,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0}table{border-collapse:collapse;border-spacing:0}fieldset,img{border:0}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal}ol,ul{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}q:before,q:after{content:''}abbr,acronym{border:0;font-variant:normal}sup{vertical-align:text-top}sub{vertical-align:text-bottom}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit}input,textarea,select{*font-size:100%}legend{color:#000}
|
||||
html{color:#000;background:#fff}body,div,dl,dt,dd,ul,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0}table{border-collapse:collapse;border-spacing:0}fieldset,img{border:0}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal}ol,ul{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}q:before,q:after{content:''}abbr,acronym{border:0;font-variant:normal}sup{vertical-align:text-top}sub{vertical-align:text-bottom}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit}input,textarea,select{*font-size:100%}legend{color:#000}
|
||||
|
||||
html {
|
||||
background-color:#455463;
|
||||
color:white;
|
||||
min-height:100%;
|
||||
background-image: linear-gradient(bottom, #0F1823 0%, #455463 100%);
|
||||
background-image: -o-linear-gradient(bottom, #0F1823 0%, #455463 100%);
|
||||
background-image: -moz-linear-gradient(bottom, #0F1823 0%, #455463 100%);
|
||||
background-image: -webkit-linear-gradient(bottom, #0F1823 0%, #455463 100%);
|
||||
background-image: -ms-linear-gradient(bottom, #0F1823 0%, #455463 100%);
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #0F1823), color-stop(1, #455463));
|
||||
html {
|
||||
background-color: #455463;
|
||||
color: #fff;
|
||||
min-height: 100%;
|
||||
background-image: linear-gradient(bottom, #0f1823 0%, #455463 100%);
|
||||
background-image: -o-linear-gradient(bottom, #0f1823 0%, #455463 100%);
|
||||
background-image: -moz-linear-gradient(bottom, #0f1823 0%, #455463 100%);
|
||||
background-image: -webkit-linear-gradient(bottom, #0f1823 0%, #455463 100%);
|
||||
background-image: -ms-linear-gradient(bottom, #0f1823 0%, #455463 100%);
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #0f1823), color-stop(1, #455463));
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 0.8em;
|
||||
margin-bottom:15px;
|
||||
padding-left:60px; padding-right:60px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 0.8em;
|
||||
margin-bottom: 15px;
|
||||
padding-left: 60px;
|
||||
padding-right: 60px;
|
||||
}
|
||||
|
||||
a { color:#0F388F; }
|
||||
a { color: #0f388f; }
|
||||
|
||||
h1 {
|
||||
font-size:3.5em;
|
||||
font-weight:700;
|
||||
color:#000;
|
||||
position:relative;
|
||||
display:inline;
|
||||
cursor:pointer;
|
||||
font-size: 3.5em;
|
||||
font-weight: bold;
|
||||
color: #000;
|
||||
position: relative;
|
||||
display: inline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
h1:before {
|
||||
content:attr(title);
|
||||
position:absolute;
|
||||
color:rgba(255,255,255,0.15);
|
||||
top:1px;
|
||||
left:1px;
|
||||
cursor:pointer;
|
||||
content: attr(title);
|
||||
position: absolute;
|
||||
color: rgba(255,255,255,0.15);
|
||||
top: 1px;
|
||||
left: 1px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color:#000;
|
||||
font-size:1em;
|
||||
display:inline;
|
||||
font-style:italic;
|
||||
font-weight:bold;
|
||||
position:relative;
|
||||
bottom:8px;}
|
||||
color: #000;
|
||||
font-size: 1em;
|
||||
display: inline;
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
bottom: 8px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color:#94a3b4;
|
||||
font-size:0.7em;
|
||||
display:inline;
|
||||
position:relative;
|
||||
bottom:8px;}
|
||||
color: #94a3b4;
|
||||
font-size: 0.7em;
|
||||
display: inline;
|
||||
margin-top: 10px;
|
||||
position: relative;
|
||||
bottom: 8px;
|
||||
}
|
||||
|
||||
#aboutbox {
|
||||
font-size:0.85em;
|
||||
color: #94a3b4;
|
||||
padding: 4px 8px 4px 16px;
|
||||
position:relative;
|
||||
top:10px;
|
||||
border-left: 2px solid #94a3b4;
|
||||
float:right;
|
||||
width:60%;
|
||||
font-size: 0.85em;
|
||||
color: #94a3b4;
|
||||
padding: 4px 8px 4px 16px;
|
||||
position: relative;
|
||||
top: 10px;
|
||||
border-left: 2px solid #94a3b4;
|
||||
float: right;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
div#aboutbox a { color: #94a3b4; }
|
||||
#aboutbox a { color: #94a3b4; }
|
||||
|
||||
textarea#message,div#cleartext,.replymessage {
|
||||
clear:both;
|
||||
color:black;
|
||||
background-color:#fff;
|
||||
white-space:pre-wrap;
|
||||
font-family:Consolas,"Lucida Console","DejaVu Sans Mono",Monaco,monospace;
|
||||
font-size:9pt;
|
||||
border: 1px solid #28343F;
|
||||
padding:5px;
|
||||
box-sizing:border-box;
|
||||
-webkit-box-sizing:border-box;
|
||||
-moz-box-sizing:border-box;
|
||||
-ms-box-sizing:border-box;
|
||||
-o-box-sizing:border-box;
|
||||
width:100%;
|
||||
#message, #cleartext, .replymessage {
|
||||
clear: both;
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
white-space: pre-wrap;
|
||||
font-family: Consolas, "Lucida Console", "DejaVu Sans Mono", Monaco, monospace;
|
||||
font-size: 9pt;
|
||||
border: 1px solid #28343F;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-ms-box-sizing: border-box;
|
||||
-o-box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div#status {
|
||||
clear:both;
|
||||
padding:5px 10px;
|
||||
#status {
|
||||
clear: both;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
|
||||
div#pastelink {
|
||||
background-color:#1F2833;
|
||||
color:white;
|
||||
padding:4px 12px;
|
||||
clear:both;
|
||||
-moz-box-shadow: inset 0px 2px 2px #000;
|
||||
-webkit-box-shadow: inset 0px 2px 2px #000;
|
||||
box-shadow: inset 0px 2px 5px #000;
|
||||
#pastelink {
|
||||
background-color: #1F2833;
|
||||
color: #fff;
|
||||
padding: 4px 12px;
|
||||
clear: both;
|
||||
-moz-box-shadow: inset 0 2px 2px #000;
|
||||
-webkit-box-shadow: inset 0 2px 2px #000;
|
||||
box-shadow: inset 0 2px 2px #000;
|
||||
}
|
||||
div#pastelink a { color:white; }
|
||||
div#pastelink button { margin-left:11px }
|
||||
div#toolbar, div#status { margin-bottom:5px; }
|
||||
|
||||
button,.button,div#expiration,div#language {
|
||||
color:#fff;
|
||||
background-color:#323B47;
|
||||
background-repeat:no-repeat;
|
||||
background-position:center left;
|
||||
padding:4px 8px;
|
||||
font-size:1em;
|
||||
margin-right:5px;
|
||||
display:inline;
|
||||
background-image: linear-gradient(bottom, #323B47 0%, #51606E 100%);
|
||||
background-image: -o-linear-gradient(bottom, #323B47 0%, #51606E 100%);
|
||||
background-image: -moz-linear-gradient(bottom, #323B47 0%, #51606E 100%);
|
||||
background-image: -webkit-linear-gradient(bottom, #323B47 0%, #51606E 100%);
|
||||
background-image: -ms-linear-gradient(bottom, #323B47 0%, #51606E 100%);
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #323B47), color-stop(1, #51606E));
|
||||
border: 1px solid #28343F;
|
||||
-moz-box-shadow: inset 0px 1px 2px #647384;
|
||||
-webkit-box-shadow: inset 0px 1px 2px #647384;
|
||||
box-shadow: inset 0px 1px 2px #647384;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-moz-background-clip: padding; -webkit-background-clip: padding-box; background-clip: padding-box;
|
||||
#pastelink a { color: #fff; }
|
||||
|
||||
#pastelink button { margin-left: 11px }
|
||||
|
||||
#toolbar, #status { margin-bottom: 5px; }
|
||||
|
||||
button, .button, #expiration, #language {
|
||||
color: #fff;
|
||||
background-color: #323b47;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center left;
|
||||
padding: 4px 8px;
|
||||
font-size: 1em;
|
||||
margin-right: 5px;
|
||||
display: inline;
|
||||
background-image: linear-gradient(bottom, #323b47 0, #51606e 100%);
|
||||
background-image: -o-linear-gradient(bottom, #323b47 0, #51606e 100%);
|
||||
background-image: -moz-linear-gradient(bottom, #323b47 0, #51606e 100%);
|
||||
background-image: -webkit-linear-gradient(bottom, #323b47 0, #51606e 100%);
|
||||
background-image: -ms-linear-gradient(bottom, #323b47 0, #51606e 100%);
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #323b47), color-stop(1, #51606e));
|
||||
border: 1px solid #28343F;
|
||||
-moz-box-shadow: inset 0 1px 2px #647384;
|
||||
-webkit-box-shadow: inset 0 1px 2px #647384;
|
||||
box-shadow: inset 0 1px 2px #647384;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-moz-background-clip: padding;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-image: linear-gradient(bottom, #424B57 0%, #61707E 100%);
|
||||
background-image: -o-linear-gradient(bottom, #424B57 0%, #61707E 100%);
|
||||
background-image: -moz-linear-gradient(bottom, #424B57 0%, #61707E 100%);
|
||||
background-image: -webkit-linear-gradient(bottom, #424B57 0%, #61707E 100%);
|
||||
background-image: -ms-linear-gradient(bottom, #424B57 0%, #61707E 100%);
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #424B57), color-stop(1, #61707E));
|
||||
background-image: linear-gradient(bottom, #424b57 0%, #61707e 100%);
|
||||
background-image: -o-linear-gradient(bottom, #424b57 0%, #61707e 100%);
|
||||
background-image: -moz-linear-gradient(bottom, #424b57 0%, #61707e 100%);
|
||||
background-image: -webkit-linear-gradient(bottom, #424b57 0%, #61707e 100%);
|
||||
background-image: -ms-linear-gradient(bottom, #424b57 0%, #61707e 100%);
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #424b57), color-stop(1, #61707e));
|
||||
}
|
||||
|
||||
button:active {
|
||||
background-image: linear-gradient(bottom, #51606E 0%, #323B47 100%);
|
||||
background-image: -o-linear-gradient(bottom, #51606E 0%, #323B47 100%);
|
||||
background-image: -moz-linear-gradient(bottom, #51606E 0%, #323B47 100%);
|
||||
background-image: -webkit-linear-gradient(bottom, #51606E 0%, #323B47 100%);
|
||||
background-image: -ms-linear-gradient(bottom, #51606E 0%, #323B47 100%);
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #51606E), color-stop(1, #323B47));
|
||||
position:relative;
|
||||
top:1px;
|
||||
background-image: linear-gradient(bottom, #51606e 0, #323b47 100%);
|
||||
background-image: -o-linear-gradient(bottom, #51606e 0, #323b47 100%);
|
||||
background-image: -moz-linear-gradient(bottom, #51606e 0, #323b47 100%);
|
||||
background-image: -webkit-linear-gradient(bottom, #51606e 0, #323b47 100%);
|
||||
background-image: -ms-linear-gradient(bottom, #51606e 0, #323b47 100%);
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #51606e), color-stop(1, #323b47));
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
|
||||
button:disabled, .buttondisabled {
|
||||
background:#ccc;
|
||||
color:#888;
|
||||
top:0px;
|
||||
background: #ccc;
|
||||
color: #888;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
button img {
|
||||
margin-right:8px;
|
||||
position:relative;
|
||||
top:2px;
|
||||
margin-right: 8px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
div#expiration, div#language, div#opendisc {
|
||||
background-color:#414D5A;
|
||||
padding:6px 8px;
|
||||
margin:0px 5px 0px 0px;;
|
||||
position: relative;
|
||||
bottom:1px; /* WTF ? Why is this shifted by 1 pixel ? */
|
||||
#expiration, #language, #opendisc {
|
||||
background-color: #414d5a;
|
||||
padding: 6px 8px;
|
||||
margin: 0 5px 0 0;
|
||||
position: relative;
|
||||
bottom: 1px; /* WTF ? Why is this shifted by 1 pixel ? */
|
||||
}
|
||||
div#expiration select, div#language select {
|
||||
color:#eee;
|
||||
background: transparent;
|
||||
border: none;
|
||||
|
||||
#expiration select, #language select {
|
||||
color: #eee;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
div#expiration select option, div#language select option {
|
||||
color:#eee;
|
||||
background: #414D5A;
|
||||
background-color:#414D5A;
|
||||
#expiration select option, #language select option {
|
||||
color:#eee;
|
||||
background: #414d5a;
|
||||
}
|
||||
|
||||
div#remainingtime {
|
||||
color: #94a3b4;
|
||||
display:inline;
|
||||
font-size:0.85em;
|
||||
#remainingtime {
|
||||
color: #94a3b4;
|
||||
display: inline;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
#newbutton {
|
||||
float: right;
|
||||
margin-right: 0;
|
||||
margin-bottom: 5px;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
input {
|
||||
color: #777;
|
||||
font-size: 1em;
|
||||
padding: 6px;
|
||||
border: 1px solid #28343f;
|
||||
}
|
||||
|
||||
.blink {
|
||||
text-decoration: blink;
|
||||
font-size: 0.8em;
|
||||
color: #a4b3c4;
|
||||
}
|
||||
|
||||
.foryoureyesonly {
|
||||
color: yellow !important;
|
||||
font-size: 1em !important;
|
||||
font-weight:bold !important;
|
||||
color: #ff0 !important;
|
||||
font-size: 1em !important;
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
button#newbutton { float:right; margin-right:0px;margin-bottom:5px; display:inline; }
|
||||
input { color:#777; font-size:1em; padding:6px; border: 1px solid #28343F; }
|
||||
|
||||
.nonworking {
|
||||
background-color:#fff;
|
||||
color:#000;
|
||||
width:100%;
|
||||
text-align:center;
|
||||
font-weight:bold;
|
||||
font-size:10pt;
|
||||
-webkit-border-radius:4px;
|
||||
-moz-border-radius:4px;
|
||||
border-radius:4px;
|
||||
padding:5px;
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 10pt;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
div#ienotice {
|
||||
background-color:#7E98AF;
|
||||
color:#000;
|
||||
font-size:0.85em;
|
||||
padding:3px 5px;
|
||||
text-align:center;
|
||||
-webkit-border-radius:4px;
|
||||
-moz-border-radius:4px;
|
||||
border-radius:4px;
|
||||
display:none;
|
||||
.hidden { display: none !important; }
|
||||
|
||||
#ienotice {
|
||||
background-color: #7e98af;
|
||||
color: #000;
|
||||
font-size: 0.85em;
|
||||
padding: 3px 5px;
|
||||
text-align: center;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
div#ienotice a {
|
||||
color:black;
|
||||
}
|
||||
#ienotice a { color: #000; }
|
||||
|
||||
div#oldienotice {
|
||||
display:none;
|
||||
}
|
||||
#oldienotice { display: none; }
|
||||
|
||||
.errorMessage {
|
||||
background-color:#FF7979 !important;
|
||||
color:#FF0;
|
||||
background-color: #f77 !important;
|
||||
color:#ff0;
|
||||
}
|
||||
|
||||
|
||||
/* --- discussion related CSS ------- */
|
||||
|
||||
|
||||
div#discussion { /* Discussion container */
|
||||
margin-top:20px;
|
||||
width:100%;
|
||||
margin-left:-30px;
|
||||
min-width:200px;
|
||||
#discussion { /* Discussion container */
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
margin-left: -30px;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size:1.2em;
|
||||
color: #94A3B4;
|
||||
font-style:italic;
|
||||
font-weight:bold;
|
||||
position:relative;
|
||||
margin-left:30px;
|
||||
font-size: 1.2em;
|
||||
color: #94a3b4;
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
|
||||
div.comment /* One single reply */
|
||||
.comment /* One single reply */
|
||||
{
|
||||
background-color:#CECED6;
|
||||
color:#000;
|
||||
white-space:pre-wrap;
|
||||
font-family:Consolas,"Lucida Console","DejaVu Sans Mono",Monaco,monospace;
|
||||
font-size:9pt;
|
||||
border-left: 1px solid #859AAE;
|
||||
border-top: 1px solid #859AAE;
|
||||
padding:5px 0px 5px 5px;
|
||||
margin-left:30px;
|
||||
-moz-box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
|
||||
-webkit-box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
|
||||
box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
|
||||
min-width:200px;
|
||||
overflow:auto;
|
||||
}
|
||||
/* FIXME: Add min-width */
|
||||
|
||||
div.reply {
|
||||
margin: 5px 0px 0px 30px;
|
||||
background-color: #ceced6;
|
||||
color: #000;
|
||||
white-space: pre-wrap;
|
||||
font-family: Consolas,"Lucida Console","DejaVu Sans Mono",Monaco,monospace;
|
||||
font-size: 9pt;
|
||||
border-left: 1px solid #859AAE;
|
||||
border-top: 1px solid #859AAE;
|
||||
padding: 5px 0px 5px 5px;
|
||||
margin-left: 30px;
|
||||
-moz-box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
|
||||
-webkit-box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
|
||||
box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
|
||||
min-width: 200px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
div#replystatus {
|
||||
display:inline;
|
||||
padding:1px 7px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
.reply { margin: 5px 0 0 30px; }
|
||||
|
||||
#replystatus {
|
||||
display: inline;
|
||||
padding: 1px 7px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
div.comment button {
|
||||
color:#446;
|
||||
background-color:#aab;
|
||||
background-repeat:no-repeat;
|
||||
background-position:center left;
|
||||
padding:0px 2px;
|
||||
font-size:0.73em;
|
||||
margin: 3px 5px 3px 0px;
|
||||
display:inline;
|
||||
background-image: linear-gradient(bottom, #aab 0%, #ccc 100%);
|
||||
background-image: -o-linear-gradient(bottom, #aab 0%, #ccc 100%);
|
||||
background-image: -moz-linear-gradient(bottom, #aab 0%, #ccc 100%);
|
||||
background-image: -webkit-linear-gradient(bottom, #aab 0%, #ccc 100%);
|
||||
background-image: -ms-linear-gradient(bottom, #aab 0%, #ccc 100%);
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #aab), color-stop(1, #ccc));
|
||||
border: 1px solid #ccd;
|
||||
-moz-box-shadow: inset 0px 1px 2px #ddd;
|
||||
-webkit-box-shadow: inset 0px 1px 2px #fff;
|
||||
box-shadow: inset 0px 1px 2px #eee;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-moz-background-clip: padding; -webkit-background-clip: padding-box; background-clip: padding-box;
|
||||
}
|
||||
div.comment button:hover {
|
||||
background-image: linear-gradient(bottom, #ccd 0%, #fff 100%);
|
||||
background-image: -o-linear-gradient(bottom, #ccd 0%, #fff 100%);
|
||||
background-image: -moz-linear-gradient(bottom, #ccd 0%, #fff 100%);
|
||||
background-image: -webkit-linear-gradient(bottom, #ccd 0%, #fff 100%);
|
||||
background-image: -ms-linear-gradient(bottom, #ccd 0%, #fff 100%);
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccd), color-stop(1, #fff));
|
||||
}
|
||||
div.comment button:active {
|
||||
background-image: linear-gradient(bottom, #fff 0%, #889 100%);
|
||||
background-image: -o-linear-gradient(bottom, #fff 0%, #889 100%);
|
||||
background-image: -moz-linear-gradient(bottom, #fff 0%, #889 100%);
|
||||
background-image: -webkit-linear-gradient(bottom, #fff 0%, #889 100%);
|
||||
background-image: -ms-linear-gradient(bottom, #fff 0%, #889 100%);
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(1, #889));
|
||||
position:relative;
|
||||
top:1px;
|
||||
.comment button {
|
||||
color: #446;
|
||||
background-color: #aab;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center left;
|
||||
padding: 0 2px;
|
||||
font-size: 0.73em;
|
||||
margin: 3px 5px 3px 0;
|
||||
display: inline;
|
||||
background-image: linear-gradient(bottom, #aab 0, #ccc 100%);
|
||||
background-image: -o-linear-gradient(bottom, #aab 0, #ccc 100%);
|
||||
background-image: -moz-linear-gradient(bottom, #aab 0, #ccc 100%);
|
||||
background-image: -webkit-linear-gradient(bottom, #aab 0, #ccc 100%);
|
||||
background-image: -ms-linear-gradient(bottom, #aab 0, #ccc 100%);
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #aab), color-stop(1, #ccc));
|
||||
border: 1px solid #ccd;
|
||||
-moz-box-shadow: inset 0 1px 2px #ddd;
|
||||
-webkit-box-shadow: inset 0 1px 2px #fff;
|
||||
box-shadow: inset 0 1px 2px #eee;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-moz-background-clip: padding;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
div.comment input {
|
||||
padding:2px;
|
||||
.comment button:hover {
|
||||
background-image: linear-gradient(bottom, #ccd 0, #fff 100%);
|
||||
background-image: -o-linear-gradient(bottom, #ccd 0, #fff 100%);
|
||||
background-image: -moz-linear-gradient(bottom, #ccd 0, #fff 100%);
|
||||
background-image: -webkit-linear-gradient(bottom, #ccd 0, #fff 100%);
|
||||
background-image: -ms-linear-gradient(bottom, #ccd 0, #fff 100%);
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccd), color-stop(1, #fff));
|
||||
}
|
||||
|
||||
textarea#replymessage {
|
||||
margin-top:5px;
|
||||
.comment button:active {
|
||||
background-image: linear-gradient(bottom, #fff 0, #889 100%);
|
||||
background-image: -o-linear-gradient(bottom, #fff 0, #889 100%);
|
||||
background-image: -moz-linear-gradient(bottom, #fff 0, #889 100%);
|
||||
background-image: -webkit-linear-gradient(bottom, #fff 0, #889 100%);
|
||||
background-image: -ms-linear-gradient(bottom, #fff 0, #889 100%);
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(1, #889));
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
|
||||
div.commentmeta {
|
||||
color: #fff;
|
||||
background-color:#8EA0B2;
|
||||
margin-bottom:3px;
|
||||
padding:0px 0px 0px 3px;
|
||||
.comment input { padding: 2px; }
|
||||
|
||||
#replymessage { margin-top: 5px; }
|
||||
|
||||
.commentmeta {
|
||||
color: #fff;
|
||||
background-color: #8ea0b2;
|
||||
margin-bottom: 3px;
|
||||
padding: 0 0 0 3px;
|
||||
}
|
||||
|
||||
span.commentdate {
|
||||
color: #BFCEDE;
|
||||
}
|
||||
.commentdate { color: #bfcede; }
|
||||
|
||||
img.vizhash {
|
||||
width:16px;
|
||||
height:16px;
|
||||
position:relative;
|
||||
top:2px;
|
||||
left:-3px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
left: -3px;
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 391 B After Width: | Height: | Size: 381 B |
39
install.sh
39
install.sh
|
@ -1,39 +0,0 @@
|
|||
#!/bin/sh -eu
|
||||
|
||||
myname="$(readlink -ev "$0")"
|
||||
compiler='uglifyjs/bin/uglifyjs'
|
||||
|
||||
SOURCES='cfg css img lib tpl index.php'
|
||||
JSDIR='js'
|
||||
|
||||
if [ "$#" -eq 0 ]; then
|
||||
printf 'Usage: %s <destdir>\n' "${0##*/}"
|
||||
exit
|
||||
fi
|
||||
|
||||
destdir="$1"
|
||||
shift
|
||||
|
||||
if [ ! -d "$destdir" ]; then
|
||||
printf 'Error: %s: Not directory\n' "$destdir"
|
||||
exit 1
|
||||
fi
|
||||
destdir="$(readlink -ev "$destdir")"
|
||||
|
||||
cd "${myname%/*}"
|
||||
cp -aurt "$destdir" -- $SOURCES
|
||||
|
||||
mkdir -p -- "$destdir/js"
|
||||
for src in "$JSDIR"/*.js; do
|
||||
[ -f "$src" ] ||
|
||||
continue
|
||||
printf 'Processing %s ... ' "$src"
|
||||
|
||||
rc='done'
|
||||
$compiler -nc -c -o "$destdir/js/${src##*/}" "$src" || rc='fail'
|
||||
|
||||
printf '%s\n' "$rc"
|
||||
|
||||
[ "$rc" = 'done' ] ||
|
||||
exit 1
|
||||
done
|
|
@ -1347,7 +1347,7 @@ var REGEXP_PRECEDER_PATTERN = '(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&
|
|||
function prettyPrint(opt_whenDone) {
|
||||
function byTagName(tn) { return document.getElementsByTagName(tn); }
|
||||
// fetch a list of nodes to rewrite
|
||||
var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')];
|
||||
var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp'), byTagName('div')];
|
||||
var elements = [];
|
||||
for (var i = 0; i < codeSegments.length; ++i) {
|
||||
for (var j = 0, n = codeSegments[i].length; j < n; ++j) {
|
||||
|
|
|
@ -94,7 +94,7 @@ function setElementText(element, text) {
|
|||
if ($('div#oldienotice').is(":visible")) {
|
||||
// IE<10 do not support white-space:pre-wrap; so we have to do this BIG UGLY STINKING THING.
|
||||
element.text(text.replace(/\n/ig,'{BIG_UGLY_STINKING_THING__OH_GOD_I_HATE_IE}'));
|
||||
element.html(element.text().replace(/{BIG_UGLY_STINKING_THING__OH_GOD_I_HATE_IE}/ig,"\r\n<br>"));
|
||||
element.html(element.text().replace(/{BIG_UGLY_STINKING_THING__OH_GOD_I_HATE_IE}/ig,"\n<br />"));
|
||||
}
|
||||
// for other (sane) browsers:
|
||||
else {
|
||||
|
@ -112,9 +112,9 @@ function displayMessages(key, comments) {
|
|||
try { // Try to decrypt the paste.
|
||||
var cleartext = zeroDecipher(key, comments[0].data);
|
||||
} catch(err) {
|
||||
$('div#cleartext').hide();
|
||||
$('div#prettymessage').hide();
|
||||
$('button#clonebutton').hide();
|
||||
$('div#cleartext').addClass('hidden');
|
||||
$('div#prettymessage').addClass('hidden');
|
||||
$('button#clonebutton').addClass('hidden');
|
||||
showError('Could not decrypt data (Wrong key ?)');
|
||||
return;
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ function displayMessages(key, comments) {
|
|||
if (comments[0].meta.expire_date) $('div#remainingtime').removeClass('foryoureyesonly').text('This document will expire in '+secondsToHuman(comments[0].meta.remaining_time)+'.').show();
|
||||
if (comments[0].meta.burnafterreading) {
|
||||
$('div#remainingtime').addClass('foryoureyesonly').text('FOR YOUR EYES ONLY. Don\'t close this window, this message can\'t be displayed again.').show();
|
||||
$('button#clonebutton').hide(); // Discourage cloning (as it can't really be prevented).
|
||||
$('button#clonebutton').addClass('hidden'); // Discourage cloning (as it can't really be prevented).
|
||||
}
|
||||
|
||||
// If the discussion is opened on this paste, display it.
|
||||
|
@ -148,10 +148,10 @@ function displayMessages(key, comments) {
|
|||
if ($(cname).length) {
|
||||
place = $(cname);
|
||||
}
|
||||
var divComment = $('<div class="comment" id="comment_' + comment.meta.commentid+'">'
|
||||
var divComment = $('<article><div class="comment" id="comment_' + comment.meta.commentid+'">'
|
||||
+ '<div class="commentmeta"><span class="nickname"></span><span class="commentdate"></span></div><div class="commentdata"></div>'
|
||||
+ '<button onclick="open_reply($(this),\'' + comment.meta.commentid + '\');return false;">Reply</button>'
|
||||
+ '</div>');
|
||||
+ '</div></article>');
|
||||
setElementText(divComment.find('div.commentdata'), cleartext);
|
||||
// Convert URLs to clickable links in comment.
|
||||
urls2links(divComment.find('div.commentdata'));
|
||||
|
@ -171,7 +171,7 @@ function displayMessages(key, comments) {
|
|||
place.append(divComment);
|
||||
}
|
||||
$('div#comments').append('<div class="comment"><button onclick="open_reply($(this),\'' + pasteID() + '\');return false;">Add comment</button></div>');
|
||||
$('div#discussion').show();
|
||||
$('div#discussion').removeClass('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,8 +185,8 @@ function open_reply(source, commentid) {
|
|||
source.after('<div class="reply">'
|
||||
+ '<input type="text" id="nickname" title="Optional nickname..." value="Optional nickname..." />'
|
||||
+ '<textarea id="replymessage" class="replymessage" cols="80" rows="7"></textarea>'
|
||||
+ '<br><button id="replybutton" onclick="send_comment(\'' + commentid + '\');return false;">Post comment</button>'
|
||||
+ '<div id="replystatus"> </div>'
|
||||
+ '<br /><button id="replybutton" onclick="send_comment(\'' + commentid + '\');return false;">Post comment</button>'
|
||||
+ '<div id="replystatus"> </div>'
|
||||
+ '</div>');
|
||||
$('input#nickname').focus(function() {
|
||||
if ($(this).val() == $(this).attr('title')) {
|
||||
|
@ -281,46 +281,46 @@ function send_data() {
|
|||
* Put the screen in "New paste" mode.
|
||||
*/
|
||||
function stateNewPaste() {
|
||||
$('button#sendbutton').show();
|
||||
$('button#clonebutton').hide();
|
||||
$('div#expiration').show();
|
||||
$('div#remainingtime').hide();
|
||||
$('div#language').hide(); // $('#language').show();
|
||||
$('input#password').hide(); //$('#password').show();
|
||||
$('div#opendisc').show();
|
||||
$('button#newbutton').show();
|
||||
$('div#pastelink').hide();
|
||||
$('button#sendbutton').removeClass('hidden');
|
||||
$('button#clonebutton').addClass('hidden');
|
||||
$('div#expiration').removeClass('hidden');
|
||||
$('div#remainingtime').addClass('hidden');
|
||||
$('div#language').addClass('hidden'); // $('#language').removeClass('hidden');
|
||||
$('input#password').addClass('hidden'); //$('#password').removeClass('hidden');
|
||||
$('div#opendisc').removeClass('hidden');
|
||||
$('button#newbutton').removeClass('hidden');
|
||||
$('div#pastelink').addClass('hidden');
|
||||
$('textarea#message').text('');
|
||||
$('textarea#message').show();
|
||||
$('div#cleartext').hide();
|
||||
$('div#message').focus();
|
||||
$('div#discussion').hide();
|
||||
$('div#prettymessage').hide();
|
||||
$('textarea#message').removeClass('hidden');
|
||||
$('div#cleartext').addClass('hidden');
|
||||
$('textarea#message').focus();
|
||||
$('div#discussion').addClass('hidden');
|
||||
$('div#prettymessage').addClass('hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the screen in "Existing paste" mode.
|
||||
*/
|
||||
function stateExistingPaste() {
|
||||
$('button#sendbutton').hide();
|
||||
$('button#sendbutton').addClass('hidden');
|
||||
|
||||
// No "clone" for IE<10.
|
||||
if ($('div#oldienotice').is(":visible")) {
|
||||
$('button#clonebutton').hide();
|
||||
$('button#clonebutton').addClass('hidden');
|
||||
}
|
||||
else {
|
||||
$('button#clonebutton').show();
|
||||
$('button#clonebutton').removeClass('hidden');
|
||||
}
|
||||
|
||||
$('div#expiration').hide();
|
||||
$('div#language').hide();
|
||||
$('input#password').hide();
|
||||
$('div#opendisc').hide();
|
||||
$('button#newbutton').show();
|
||||
$('div#pastelink').hide();
|
||||
$('textarea#message').hide();
|
||||
$('div#cleartext').hide();
|
||||
$('div#prettymessage').show();
|
||||
$('div#expiration').addClass('hidden');
|
||||
$('div#language').addClass('hidden');
|
||||
$('input#password').addClass('hidden');
|
||||
$('div#opendisc').addClass('hidden');
|
||||
$('button#newbutton').removeClass('hidden');
|
||||
$('div#pastelink').addClass('hidden');
|
||||
$('textarea#message').addClass('hidden');
|
||||
$('div#cleartext').addClass('hidden');
|
||||
$('div#prettymessage').removeClass('hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -361,11 +361,11 @@ function showStatus(message, spin) {
|
|||
$('div#replystatus').removeClass('errorMessage');
|
||||
$('div#replystatus').text(message);
|
||||
if (!message) {
|
||||
$('div#status').html(' ');
|
||||
$('div#status').html(' ');
|
||||
return;
|
||||
}
|
||||
if (message == '') {
|
||||
$('div#status').html(' ');
|
||||
$('div#status').html(' ');
|
||||
return;
|
||||
}
|
||||
$('div#status').removeClass('errorMessage');
|
||||
|
@ -419,6 +419,9 @@ function pageKey() {
|
|||
}
|
||||
|
||||
$(function() {
|
||||
// hide "no javascript" message
|
||||
$('#noscript').hide();
|
||||
|
||||
$('select#pasteExpiration').change(function() {
|
||||
if ($(this).val() == 'burn') {
|
||||
$('div#opendisc').addClass('buttondisabled');
|
||||
|
@ -430,7 +433,6 @@ $(function() {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
// Display an existing paste
|
||||
if ($('div#cipherdata').text().length > 1) {
|
||||
// Missing decryption key in URL ?
|
||||
|
|
|
@ -29,7 +29,10 @@ class auto
|
|||
*/
|
||||
public static function loader($class_name)
|
||||
{
|
||||
require_once PATH . 'lib/' . str_replace('_', '/', $class_name) . '.php';
|
||||
$filename = PATH . 'lib/' . str_replace('_', '/', $class_name) . '.php';
|
||||
if(is_readable($filename)) {
|
||||
return include $filename;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,12 +42,12 @@ class filter
|
|||
*/
|
||||
public static function size_humanreadable($size)
|
||||
{
|
||||
$i = 0;
|
||||
$iec = array('B', 'kiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB');
|
||||
while ( ( $size / 1024 ) > 1 ) {
|
||||
$i = 0;
|
||||
while ( ( $size / 1024 ) >= 1 ) {
|
||||
$size = $size / 1024;
|
||||
$i++;
|
||||
}
|
||||
return number_format($size, 2, ".", " ") . ' ' . $iec[$i];
|
||||
return number_format($size, ($i ? 2 : 0), '.', ' ') . ' ' . $iec[$i];
|
||||
}
|
||||
}
|
||||
|
|
13
lib/sjcl.php
13
lib/sjcl.php
|
@ -39,18 +39,15 @@ class sjcl
|
|||
// Make sure required fields are present and contain base64 data.
|
||||
foreach($accepted_keys as $k)
|
||||
{
|
||||
if (!array_key_exists($k, $decoded)) return false;
|
||||
if (is_null(base64_decode($decoded[$k], $strict=true))) return false;
|
||||
if (!(
|
||||
array_key_exists($k, $decoded) &&
|
||||
base64_decode($decoded[$k], $strict=true)
|
||||
)) return false;
|
||||
}
|
||||
|
||||
// Make sure no additionnal keys were added.
|
||||
if (
|
||||
count(
|
||||
array_intersect(
|
||||
array_keys($decoded),
|
||||
$accepted_keys
|
||||
)
|
||||
) != 3
|
||||
count(array_keys($decoded)) != count($accepted_keys)
|
||||
) return false;
|
||||
|
||||
// FIXME: Reject data if entropy is too low?
|
||||
|
|
|
@ -92,18 +92,19 @@ class trafficlimiter
|
|||
}
|
||||
|
||||
require $file;
|
||||
$now = time();
|
||||
$tl = $GLOBALS['traffic_limiter'];
|
||||
|
||||
// purge file of expired IPs to keep it small
|
||||
foreach($tl as $key => $time)
|
||||
{
|
||||
if ($time + 10 < time())
|
||||
if ($time + self::$_limit < $now)
|
||||
{
|
||||
unset($tl[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists($ip, $tl) && ($tl[$ip] + 10 >= time()))
|
||||
if (array_key_exists($ip, $tl) && ($tl[$ip] + self::$_limit >= $now))
|
||||
{
|
||||
$result = false;
|
||||
} else {
|
||||
|
|
|
@ -397,7 +397,21 @@ class zerobin
|
|||
*/
|
||||
private function _view()
|
||||
{
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
// set headers to disable caching and return valid XHTML, if supported
|
||||
$content = (
|
||||
array_key_exists('HTTP_ACCEPT', $_SERVER) &&
|
||||
!empty($_SERVER['HTTP_ACCEPT']) &&
|
||||
stristr($_SERVER['HTTP_ACCEPT'], 'application/xhtml+xml') !== false
|
||||
) ? 'application/xhtml+xml' : 'text/html';
|
||||
$time = gmdate('D, d M Y H:i:s \G\M\T');
|
||||
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Pragma: no-cache');
|
||||
header('Expires: ' . $time);
|
||||
header('Last-Modified: ' . $time);
|
||||
header('Vary: Accept');
|
||||
header('Content-Type: ' . $content . ';charset=UTF-8');
|
||||
|
||||
$page = new RainTPL;
|
||||
// We escape it here because ENT_NOQUOTES can't be used in RainTPL templates.
|
||||
$page->assign('CIPHERDATA', htmlspecialchars($this->_data, ENT_NOQUOTES));
|
||||
|
|
|
@ -51,7 +51,7 @@ abstract class zerobin_abstract
|
|||
* @static
|
||||
* @return zerobin_abstract
|
||||
*/
|
||||
abstract public static function getInstance($options);
|
||||
public static function getInstance($options) {}
|
||||
|
||||
/**
|
||||
* Create a paste.
|
||||
|
|
|
@ -37,13 +37,13 @@ class zerobin_data extends zerobin_abstract
|
|||
if (
|
||||
is_array($options) &&
|
||||
array_key_exists('dir', $options)
|
||||
) self::$_dir = $options['dir'] . '/';
|
||||
) self::$_dir = $options['dir'] . DIRECTORY_SEPARATOR;
|
||||
// if needed initialize the singleton
|
||||
if(null === parent::$_instance) {
|
||||
parent::$_instance = new self;
|
||||
if(!(self::$_instance instanceof zerobin_data)) {
|
||||
self::$_instance = new self;
|
||||
self::_init();
|
||||
}
|
||||
return parent::$_instance;
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,7 +59,7 @@ class zerobin_data extends zerobin_abstract
|
|||
$storagedir = self::_dataid2path($pasteid);
|
||||
if (is_file($storagedir . $pasteid)) return false;
|
||||
if (!is_dir($storagedir)) mkdir($storagedir, 0705, true);
|
||||
return file_put_contents($storagedir . $pasteid, json_encode($paste));
|
||||
return (bool) file_put_contents($storagedir . $pasteid, json_encode($paste));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,13 +67,11 @@ class zerobin_data extends zerobin_abstract
|
|||
*
|
||||
* @access public
|
||||
* @param string $pasteid
|
||||
* @return string
|
||||
* @return stdClass|false
|
||||
*/
|
||||
public function read($pasteid)
|
||||
{
|
||||
if(!$this->exists($pasteid)) return json_decode(
|
||||
'{"data":"","meta":{"burnafterreading":true,"postdate":0}}'
|
||||
);
|
||||
if(!$this->exists($pasteid)) return false;
|
||||
return json_decode(
|
||||
file_get_contents(self::_dataid2path($pasteid) . $pasteid)
|
||||
);
|
||||
|
@ -193,7 +191,7 @@ class zerobin_data extends zerobin_abstract
|
|||
{
|
||||
return is_file(
|
||||
self::_dataid2discussionpath($pasteid) .
|
||||
$pasteid . '.' . $dataid . '.' . $parentid
|
||||
$pasteid . '.' . $commentid . '.' . $parentid
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -56,8 +56,8 @@ class zerobin_db extends zerobin_abstract
|
|||
public static function getInstance($options = null)
|
||||
{
|
||||
// if needed initialize the singleton
|
||||
if(null === self::$_instance) {
|
||||
parent::$_instance = new self;
|
||||
if(!(self::$_instance instanceof zerobin_db)) {
|
||||
self::$_instance = new self;
|
||||
}
|
||||
|
||||
if (is_array($options))
|
||||
|
@ -175,6 +175,16 @@ class zerobin_db extends zerobin_abstract
|
|||
*/
|
||||
public function create($pasteid, $paste)
|
||||
{
|
||||
if (
|
||||
array_key_exists($pasteid, self::$_cache)
|
||||
) {
|
||||
if(false !== self::$_cache[$pasteid]) {
|
||||
return false;
|
||||
} else {
|
||||
unset(self::$_cache[$pasteid]);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!array_key_exists('opendiscussion', $paste['meta'])
|
||||
) $paste['meta']['opendiscussion'] = false;
|
||||
|
@ -199,31 +209,36 @@ class zerobin_db extends zerobin_abstract
|
|||
*
|
||||
* @access public
|
||||
* @param string $pasteid
|
||||
* @return string
|
||||
* @return stdClass|false
|
||||
*/
|
||||
public function read($pasteid)
|
||||
{
|
||||
if (
|
||||
!array_key_exists($pasteid, self::$_cache)
|
||||
) self::$_cache[$pasteid] = self::_select(
|
||||
'SELECT * FROM ' . self::$_prefix . 'paste WHERE dataid = ?',
|
||||
array($pasteid), true
|
||||
);
|
||||
) {
|
||||
self::$_cache[$pasteid] = false;
|
||||
$paste = self::_select(
|
||||
'SELECT * FROM ' . self::$_prefix . 'paste WHERE dataid = ?',
|
||||
array($pasteid), true
|
||||
);
|
||||
|
||||
// create object
|
||||
$paste = new stdClass;
|
||||
$paste->data = self::$_cache[$pasteid]['data'];
|
||||
$paste->meta = new stdClass;
|
||||
$paste->meta->postdate = (int) self::$_cache[$pasteid]['postdate'];
|
||||
$paste->meta->expire_date = (int) self::$_cache[$pasteid]['expiredate'];
|
||||
if (
|
||||
self::$_cache[$pasteid]['opendiscussion']
|
||||
) $paste->meta->opendiscussion = true;
|
||||
if (
|
||||
self::$_cache[$pasteid]['burnafterreading']
|
||||
) $paste->meta->burnafterreading = true;
|
||||
if(false !== $paste) {
|
||||
// create object
|
||||
self::$_cache[$pasteid] = new stdClass;
|
||||
self::$_cache[$pasteid]->data = $paste['data'];
|
||||
self::$_cache[$pasteid]->meta = new stdClass;
|
||||
self::$_cache[$pasteid]->meta->postdate = (int) $paste['postdate'];
|
||||
self::$_cache[$pasteid]->meta->expire_date = (int) $paste['expiredate'];
|
||||
if (
|
||||
$paste['opendiscussion']
|
||||
) self::$_cache[$pasteid]->meta->opendiscussion = true;
|
||||
if (
|
||||
$paste['burnafterreading']
|
||||
) self::$_cache[$pasteid]->meta->burnafterreading = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $paste;
|
||||
return self::$_cache[$pasteid];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -243,6 +258,9 @@ class zerobin_db extends zerobin_abstract
|
|||
'DELETE FROM ' . self::$_prefix . 'comment WHERE pasteid = ?',
|
||||
array($pasteid)
|
||||
);
|
||||
if (
|
||||
array_key_exists($pasteid, self::$_cache)
|
||||
) unset(self::$_cache[$pasteid]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -256,10 +274,7 @@ class zerobin_db extends zerobin_abstract
|
|||
{
|
||||
if (
|
||||
!array_key_exists($pasteid, self::$_cache)
|
||||
) self::$_cache[$pasteid] = self::_select(
|
||||
'SELECT * FROM ' . self::$_prefix . 'paste WHERE dataid = ?',
|
||||
array($pasteid), true
|
||||
);
|
||||
) self::$_cache[$pasteid] = $this->read($pasteid);
|
||||
return (bool) self::$_cache[$pasteid];
|
||||
}
|
||||
|
||||
|
@ -278,9 +293,9 @@ class zerobin_db extends zerobin_abstract
|
|||
return self::_exec(
|
||||
'INSERT INTO ' . self::$_prefix . 'comment VALUES(?,?,?,?,?,?,?)',
|
||||
array(
|
||||
$commentid,
|
||||
$pasteid,
|
||||
$parentid,
|
||||
$commentid,
|
||||
$comment['data'],
|
||||
$comment['meta']['nickname'],
|
||||
$comment['meta']['vizhash'],
|
||||
|
|
180
tpl/page.html
180
tpl/page.html
|
@ -1,88 +1,96 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>ZeroBin</title>
|
||||
<link type="text/css" rel="stylesheet" href="css/zerobin.css?{$VERSION|rawurlencode}#" />
|
||||
<link type="text/css" rel="stylesheet" href="css/prettify.css?{$VERSION|rawurlencode}#" />
|
||||
<script src="js/jquery.js#"></script>
|
||||
<script src="js/sjcl.js#"></script>
|
||||
<script src="js/base64.js#"></script>
|
||||
<script src="js/rawdeflate.js#"></script>
|
||||
<script src="js/rawinflate.js#"></script>
|
||||
<script src="js/prettify.js#"></script>
|
||||
<script src="js/zerobin.js?{$VERSION|rawurlencode}#"></script>
|
||||
|
||||
<!--[if lt IE 10]>
|
||||
<style> body {padding-left:60px;padding-right:60px;} div#ienotice {display:block;} </style>
|
||||
<![endif]-->
|
||||
|
||||
<!--[if lt IE 10]>
|
||||
<style> div#ienotice {display:block; } div#oldienotice {display:block; } </style>
|
||||
<![endif]-->
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="aboutbox">
|
||||
ZeroBin is a minimalist, opensource online pastebin where the server has zero knowledge of pasted data.
|
||||
Data is encrypted/decrypted <i>in the browser</i> using 256 bits AES.
|
||||
More information on the <a href="http://sebsauvage.net/wiki/doku.php?id=php:zerobin">project page</a>.<br />
|
||||
<span style="text-decoration:blink;font-size:10pt;color:#a4b3c4;">▶</span> Note: This is a test service:
|
||||
Data may be deleted anytime. Kittens will die if you abuse this service.
|
||||
</div>
|
||||
<h1 title="ZeroBin" onclick="window.location.href=scriptLocation();return false;">ZeroBin</h1><br>
|
||||
<h2>Because ignorance is bliss</h2><br>
|
||||
<h3>{$VERSION}</h3>
|
||||
<noscript><div class="nonworking">Javascript is required for ZeroBin to work.<br>Sorry for the inconvenience.</div></noscript>
|
||||
<div id="oldienotice" class="nonworking">ZeroBin requires a modern browser to work.</div>
|
||||
<div id="ienotice">Still using Internet Explorer ? Do yourself a favor, switch to a modern browser:
|
||||
<a href="http://www.mozilla.org/firefox/">Firefox</a>,
|
||||
<a href="http://www.opera.com/">Opera</a>,
|
||||
<a href="http://www.google.com/chrome">Chrome</a>,
|
||||
<a href="http://www.apple.com/safari">Safari</a>...
|
||||
</div>
|
||||
<div id="status"> </div>
|
||||
<div id="errormessage" style="display:none">{$ERRORMESSAGE|htmlspecialchars}</div>
|
||||
<div id="toolbar">
|
||||
<button id="newbutton" onclick="window.location.href=scriptLocation();return false;" style="display:none;"><img src="img/icon_new.png#" width="11" height="15" />New</button>
|
||||
<button id="sendbutton" onclick="send_data();return false;" style="display:none;"><img src="img/icon_send.png#" width="18" height="15" />Send</button>
|
||||
<button id="clonebutton" onclick="clonePaste();return false;" style="display:none;"><img src="img/icon_clone.png#" width="15" height="17" />Clone</button>
|
||||
<div id="expiration" style="display:none;">Expire:
|
||||
<select id="pasteExpiration" name="pasteExpiration">
|
||||
<option value="burn">Burn after reading</option>
|
||||
<option value="5min">5 minutes</option>
|
||||
<option value="10min">10 minutes</option>
|
||||
<option value="1hour">1 hour</option>
|
||||
<option value="1day">1 day</option>
|
||||
<option value="1week">1 week</option>
|
||||
<option value="1month" selected="selected">1 month</option>
|
||||
<option value="1year">1 year</option>
|
||||
<option value="never">Never</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="remainingtime" style="display:none;"></div>
|
||||
<div id="language" style="display:none;">
|
||||
<select name="language">
|
||||
<option value="language" selected="selected">Language</option>
|
||||
<option value="C/C++">C/C++</option>
|
||||
<option value="php">php</option>
|
||||
<option value="python">Python</option>
|
||||
</select>
|
||||
</div>
|
||||
<input id="password" value="Optional password..." style="display:none;" />
|
||||
<div id="opendisc" class="button" style="display:none;">
|
||||
<input type="checkbox" id="opendiscussion" name="opendiscussion" {if="!$OPENDISCUSSION"} disabled="disabled"{/if} />
|
||||
<label for="opendiscussion">Open discussion</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="pastelink" style="display:none;"></div>
|
||||
<div id="prettymessage" style="display:none;">
|
||||
<pre id="prettyprint" class="prettyprint linenums:1"></pre>
|
||||
</div>
|
||||
<div id="cleartext" style="display:none;"></div>
|
||||
<textarea id="message" name="message" cols="80" rows="25" style="display:none;"></textarea>
|
||||
<div id="discussion" style="display:none;">
|
||||
<h4>Discussion</h4>
|
||||
<div id="comments"></div>
|
||||
</div>
|
||||
<div id="cipherdata" style="display:none;">{$CIPHERDATA}</div>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>ZeroBin</title>
|
||||
<link type="text/css" rel="stylesheet" href="css/zerobin.css?{$VERSION|rawurlencode}#" />
|
||||
<link type="text/css" rel="stylesheet" href="css/prettify.css?{$VERSION|rawurlencode}#" />
|
||||
<script src="js/jquery.js#"></script>
|
||||
<script src="js/sjcl.js#"></script>
|
||||
<script src="js/base64.js#"></script>
|
||||
<script src="js/rawdeflate.js#"></script>
|
||||
<script src="js/rawinflate.js#"></script>
|
||||
<script src="js/prettify.js#"></script>
|
||||
<script src="js/zerobin.js?{$VERSION|rawurlencode}#"></script>
|
||||
<!--[if lt IE 10]>
|
||||
<style> body {padding-left:60px;padding-right:60px;} div#ienotice {display:block;} </style>
|
||||
<![endif]-->
|
||||
<!--[if lt IE 10]>
|
||||
<style> div#ienotice {display:block; } div#oldienotice {display:block; } </style>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div id="aboutbox">
|
||||
ZeroBin is a minimalist, opensource online pastebin where the server has zero knowledge of pasted data.
|
||||
Data is encrypted/decrypted <i>in the browser</i> using 256 bits AES.
|
||||
More information on the <a href="http://sebsauvage.net/wiki/doku.php?id=php:zerobin">project page</a>.<br />
|
||||
<span class="blink">▶</span> Note: This is a test service:
|
||||
Data may be deleted anytime. Kittens will die if you abuse this service.
|
||||
</div>
|
||||
<h1 title="ZeroBin" onclick="window.location.href=scriptLocation();return false;">ZeroBin</h1><br />
|
||||
<h2>Because ignorance is bliss</h2><br />
|
||||
<h3>{$VERSION}</h3>
|
||||
<div id="noscript" class="nonworking">Javascript is required for ZeroBin to work.<br />Sorry for the inconvenience.</div>
|
||||
<div id="oldienotice" class="nonworking">ZeroBin requires a modern browser to work.</div>
|
||||
<div id="ienotice">Still using Internet Explorer ? Do yourself a favor, switch to a modern browser:
|
||||
<a href="http://www.mozilla.org/firefox/">Firefox</a>,
|
||||
<a href="http://www.opera.com/">Opera</a>,
|
||||
<a href="http://www.google.com/chrome">Chrome</a>,
|
||||
<a href="http://www.apple.com/safari">Safari</a>...
|
||||
</div>
|
||||
</header>
|
||||
<section>
|
||||
<article>
|
||||
<div id="status"> </div>
|
||||
<div id="errormessage" class="hidden">{$ERRORMESSAGE|htmlspecialchars}</div>
|
||||
<div id="toolbar">
|
||||
<button id="newbutton" onclick="window.location.href=scriptLocation();return false;" class="hidden"><img src="img/icon_new.png#" width="11" height="15" />New</button>
|
||||
<button id="sendbutton" onclick="send_data();return false;" class="hidden"><img src="img/icon_send.png#" width="18" height="15" />Send</button>
|
||||
<button id="clonebutton" onclick="clonePaste();return false;" class="hidden"><img src="img/icon_clone.png#" width="15" height="17" />Clone</button>
|
||||
<div id="expiration" class="hidden">Expire:
|
||||
<select id="pasteExpiration" name="pasteExpiration">
|
||||
<option value="burn">Burn after reading</option>
|
||||
<option value="5min">5 minutes</option>
|
||||
<option value="10min">10 minutes</option>
|
||||
<option value="1hour">1 hour</option>
|
||||
<option value="1day">1 day</option>
|
||||
<option value="1week">1 week</option>
|
||||
<option value="1month" selected="selected">1 month</option>
|
||||
<option value="1year">1 year</option>
|
||||
<option value="never">Never</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="remainingtime" class="hidden"></div>
|
||||
<div id="language" class="hidden">
|
||||
<select name="language">
|
||||
<option value="language" selected="selected">Language</option>
|
||||
<option value="C/C++">C/C++</option>
|
||||
<option value="php">php</option>
|
||||
<option value="python">Python</option>
|
||||
</select>
|
||||
</div>
|
||||
<input id="password" value="Optional password..." class="hidden" />
|
||||
<div id="opendisc" class="button" class="hidden">
|
||||
<input type="checkbox" id="opendiscussion" name="opendiscussion" {if="!$OPENDISCUSSION"} disabled="disabled"{/if} />
|
||||
<label for="opendiscussion">Open discussion</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="pastelink" class="hidden"></div>
|
||||
<div id="prettymessage" class="hidden">
|
||||
<div id="prettyprint" class="prettyprint linenums:1"></div>
|
||||
</div>
|
||||
<div id="cleartext" class="hidden"></div>
|
||||
<textarea id="message" name="message" cols="80" rows="25" class="hidden"></textarea>
|
||||
</article>
|
||||
</section>
|
||||
<section>
|
||||
<div id="discussion" class="hidden">
|
||||
<h4>Discussion</h4>
|
||||
<div id="comments"></div>
|
||||
</div>
|
||||
</section>
|
||||
<div id="cipherdata" class="hidden">{$CIPHERDATA}</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
16
tst/README.md
Normal file
16
tst/README.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
Running unit tests
|
||||
==================
|
||||
|
||||
In order to run these tests, you will need to install the following packages
|
||||
and its dependencies:
|
||||
* phpunit
|
||||
* php5-gd
|
||||
* php5-sqlite
|
||||
* php5-xdebug
|
||||
|
||||
Example for Debian and Ubuntu:
|
||||
$ sudo aptitude install phpunit php5-mysql php5-xdebug
|
||||
|
||||
To run the tests, just change into this directory and run phpunit:
|
||||
$ cd ZeroBin/tst
|
||||
$ phpunit
|
77
tst/RainTPL.php
Normal file
77
tst/RainTPL.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
class RainTPLTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
private static $data = '{"iv":"EN39/wd5Nk8HAiSG2K5AsQ","salt":"QKN1DBXe5PI","ct":"8hA83xDdXjD7K2qfmw5NdA"}';
|
||||
|
||||
private static $error = 'foo bar';
|
||||
|
||||
private static $version = 'Version 1.2.3';
|
||||
|
||||
private $_content;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
/* Setup Routine */
|
||||
$page = new RainTPL;
|
||||
$page::configure(array('cache_dir' => 'tmp/'));
|
||||
// We escape it here because ENT_NOQUOTES can't be used in RainTPL templates.
|
||||
$page->assign('CIPHERDATA', htmlspecialchars(self::$data, ENT_NOQUOTES));
|
||||
$page->assign('ERRORMESSAGE', self::$error);
|
||||
$page->assign('OPENDISCUSSION', false);
|
||||
$page->assign('VERSION', self::$version);
|
||||
ob_start();
|
||||
$page->draw('page');
|
||||
$this->_content = ob_get_contents();
|
||||
// run a second time from cache
|
||||
$page->cache('page');
|
||||
$page->draw('page');
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
/* Tear Down Routine */
|
||||
helper::rmdir(PATH . 'tmp');
|
||||
}
|
||||
|
||||
public function testTemplateRendersCorrectly()
|
||||
{
|
||||
$this->assertTag(
|
||||
array(
|
||||
'id' => 'cipherdata',
|
||||
'content' => htmlspecialchars(self::$data, ENT_NOQUOTES)
|
||||
),
|
||||
$this->_content,
|
||||
'outputs data correctly'
|
||||
);
|
||||
$this->assertTag(
|
||||
array(
|
||||
'id' => 'errormessage',
|
||||
'content' => self::$error
|
||||
),
|
||||
$this->_content,
|
||||
'outputs error correctly'
|
||||
);
|
||||
$this->assertTag(
|
||||
array(
|
||||
'id' => 'opendiscussion',
|
||||
'attributes' => array(
|
||||
'disabled' => 'disabled'
|
||||
),
|
||||
),
|
||||
$this->_content,
|
||||
'disables discussions if configured'
|
||||
);
|
||||
// testing version number in JS address, since other instances may not be present in different templates
|
||||
$this->assertTag(
|
||||
array(
|
||||
'tag' => 'script',
|
||||
'attributes' => array(
|
||||
'src' => 'js/zerobin.js?' . rawurlencode(self::$version)
|
||||
),
|
||||
),
|
||||
$this->_content,
|
||||
'outputs version correctly'
|
||||
);
|
||||
}
|
||||
}
|
8
tst/auto.php
Normal file
8
tst/auto.php
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
class autoTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testAutoloaderReturnsFalseWhenCallingNonExistingClass()
|
||||
{
|
||||
$this->assertFalse(auto::loader('foo2501bar42'), 'calling non existent class');
|
||||
}
|
||||
}
|
31
tst/bootstrap.php
Normal file
31
tst/bootstrap.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
error_reporting( E_ALL | E_STRICT );
|
||||
|
||||
// change this, if your php files and data is outside of your webservers document root
|
||||
define('PATH', '..' . DIRECTORY_SEPARATOR);
|
||||
|
||||
require PATH . 'lib/auto.php';
|
||||
|
||||
class helper
|
||||
{
|
||||
public static function rmdir($path)
|
||||
{
|
||||
$path .= DIRECTORY_SEPARATOR;
|
||||
$dir = dir($path);
|
||||
while(false !== ($file = $dir->read())) {
|
||||
if($file != '.' && $file != '..') {
|
||||
if(is_dir($path . $file)) {
|
||||
self::rmdir($path . $file);
|
||||
} elseif(is_file($path . $file)) {
|
||||
if(!@unlink($path . $file)) {
|
||||
throw new Exception('Error deleting file "' . $path . $file . '".');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$dir->close();
|
||||
if(!@rmdir($path)) {
|
||||
throw new Exception('Error deleting directory "' . $path . '".');
|
||||
}
|
||||
}
|
||||
}
|
47
tst/filter.php
Normal file
47
tst/filter.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
class filterTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testFilterStripsSlashesDeeply()
|
||||
{
|
||||
$this->assertEquals(
|
||||
array("f'oo", "b'ar", array("fo'o", "b'ar")),
|
||||
filter::stripslashes_deep(array("f\\'oo", "b\\'ar", array("fo\\'o", "b\\'ar")))
|
||||
);
|
||||
}
|
||||
|
||||
public function testFilterMakesSizesHumanlyReadable()
|
||||
{
|
||||
$this->assertEquals('1 B', filter::size_humanreadable(1));
|
||||
$this->assertEquals('1 000 B', filter::size_humanreadable(1000));
|
||||
$this->assertEquals('1.00 kiB', filter::size_humanreadable(1024));
|
||||
$this->assertEquals('1.21 kiB', filter::size_humanreadable(1234));
|
||||
$exponent = 1024;
|
||||
$this->assertEquals('1 000.00 kiB', filter::size_humanreadable(1000 * $exponent));
|
||||
$this->assertEquals('1.00 MiB', filter::size_humanreadable(1024 * $exponent));
|
||||
$this->assertEquals('1.21 MiB', filter::size_humanreadable(1234 * $exponent));
|
||||
$exponent *= 1024;
|
||||
$this->assertEquals('1 000.00 MiB', filter::size_humanreadable(1000 * $exponent));
|
||||
$this->assertEquals('1.00 GiB', filter::size_humanreadable(1024 * $exponent));
|
||||
$this->assertEquals('1.21 GiB', filter::size_humanreadable(1234 * $exponent));
|
||||
$exponent *= 1024;
|
||||
$this->assertEquals('1 000.00 GiB', filter::size_humanreadable(1000 * $exponent));
|
||||
$this->assertEquals('1.00 TiB', filter::size_humanreadable(1024 * $exponent));
|
||||
$this->assertEquals('1.21 TiB', filter::size_humanreadable(1234 * $exponent));
|
||||
$exponent *= 1024;
|
||||
$this->assertEquals('1 000.00 TiB', filter::size_humanreadable(1000 * $exponent));
|
||||
$this->assertEquals('1.00 PiB', filter::size_humanreadable(1024 * $exponent));
|
||||
$this->assertEquals('1.21 PiB', filter::size_humanreadable(1234 * $exponent));
|
||||
$exponent *= 1024;
|
||||
$this->assertEquals('1 000.00 PiB', filter::size_humanreadable(1000 * $exponent));
|
||||
$this->assertEquals('1.00 EiB', filter::size_humanreadable(1024 * $exponent));
|
||||
$this->assertEquals('1.21 EiB', filter::size_humanreadable(1234 * $exponent));
|
||||
$exponent *= 1024;
|
||||
$this->assertEquals('1 000.00 EiB', filter::size_humanreadable(1000 * $exponent));
|
||||
$this->assertEquals('1.00 ZiB', filter::size_humanreadable(1024 * $exponent));
|
||||
$this->assertEquals('1.21 ZiB', filter::size_humanreadable(1234 * $exponent));
|
||||
$exponent *= 1024;
|
||||
$this->assertEquals('1 000.00 ZiB', filter::size_humanreadable(1000 * $exponent));
|
||||
$this->assertEquals('1.00 YiB', filter::size_humanreadable(1024 * $exponent));
|
||||
$this->assertEquals('1.21 YiB', filter::size_humanreadable(1234 * $exponent));
|
||||
}
|
||||
}
|
17
tst/phpunit.xml
Normal file
17
tst/phpunit.xml
Normal file
|
@ -0,0 +1,17 @@
|
|||
<phpunit bootstrap="bootstrap.php" colors="true">
|
||||
<testsuite name="ZeroBin Test Suite">
|
||||
<directory suffix=".php">./</directory>
|
||||
</testsuite>
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">../lib</directory>
|
||||
<exclude>
|
||||
<file>../lib/zerobin/abstract.php</file>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
<logging>
|
||||
<log type="coverage-html" target="log/coverage-report" charset="UTF-8" yui="true" highlight="true" lowUpperBound="50" highLowerBound="80" />
|
||||
<log type="testdox-html" target="log/testdox.html" />
|
||||
</logging>
|
||||
</phpunit>
|
14
tst/sjcl.php
Normal file
14
tst/sjcl.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
class sjclTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testSjclValidatorValidatesCorrectly()
|
||||
{
|
||||
$this->assertTrue(sjcl::isValid('{"iv":"83Ax/OdUav3SanDW9dcQPg","salt":"Gx1vA2/gQ3U","ct":"j7ImByuE5xCqD2YXm6aSyA"}'), 'valid sjcl');
|
||||
$this->assertFalse(sjcl::isValid('{"iv":"$","salt":"Gx1vA2/gQ3U","ct":"j7ImByuE5xCqD2YXm6aSyA"}'), 'invalid base64 encoding of iv');
|
||||
$this->assertFalse(sjcl::isValid('{"iv":"83Ax/OdUav3SanDW9dcQPg","salt":"$","ct":"j7ImByuE5xCqD2YXm6aSyA"}'), 'invalid base64 encoding of salt');
|
||||
$this->assertFalse(sjcl::isValid('{"iv":"83Ax/OdUav3SanDW9dcQPg","salt":"Gx1vA2/gQ3U","ct":"$"}'), 'invalid base64 encoding of ct');
|
||||
$this->assertFalse(sjcl::isValid('{"iv":"MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=","salt":"Gx1vA2/gQ3U","ct":"j7ImByuE5xCqD2YXm6aSyA"}'), 'iv to long');
|
||||
$this->assertFalse(sjcl::isValid('{"iv":"83Ax/OdUav3SanDW9dcQPg","salt":"MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=","ct":"j7ImByuE5xCqD2YXm6aSyA"}'), 'salt to long');
|
||||
$this->assertFalse(sjcl::isValid('{"iv":"83Ax/OdUav3SanDW9dcQPg","salt":"Gx1vA2/gQ3U","ct":"j7ImByuE5xCqD2YXm6aSyA","foo":"MTIzNDU2Nzg5MDEyMzQ1Njc4OTA="}'), 'invalid additional key');
|
||||
}
|
||||
}
|
30
tst/trafficlimiter.php
Normal file
30
tst/trafficlimiter.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
class trafficlimiterTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
private $_path;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
/* Setup Routine */
|
||||
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'trafficlimit' . DIRECTORY_SEPARATOR;
|
||||
trafficlimiter::setPath($this->_path);
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
/* Tear Down Routine */
|
||||
helper::rmdir($this->_path);
|
||||
}
|
||||
|
||||
public function testTrafficGetsLimited()
|
||||
{
|
||||
trafficlimiter::setLimit(4);
|
||||
$this->assertTrue(trafficlimiter::canPass('127.0.0.1'), 'first request may pass');
|
||||
sleep(2);
|
||||
$this->assertFalse(trafficlimiter::canPass('127.0.0.1'), 'second request is to fast, may not pass');
|
||||
sleep(3);
|
||||
$this->assertTrue(trafficlimiter::canPass('127.0.0.1'), 'third request waited long enough and may pass');
|
||||
$this->assertTrue(trafficlimiter::canPass('2001:1620:2057:dead:beef::cafe:babe'), 'fourth request has different ip and may pass');
|
||||
$this->assertFalse(trafficlimiter::canPass('127.0.0.1'), 'fifth request is to fast, may not pass');
|
||||
}
|
||||
}
|
41
tst/vizhash16x16.php
Normal file
41
tst/vizhash16x16.php
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
class vizhash16x16Test extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
private $_dataDirCreated;
|
||||
|
||||
private $_file;
|
||||
|
||||
private $_path;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
/* Setup Routine */
|
||||
$this->_path = PATH . 'data' . DIRECTORY_SEPARATOR;
|
||||
$this->_dataDirCreated = !is_dir($this->_path);
|
||||
if($this->_dataDirCreated) mkdir($this->_path);
|
||||
$this->_file = $this->_path . 'vizhash.png';
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
/* Tear Down Routine */
|
||||
if($this->_dataDirCreated) {
|
||||
helper::rmdir($this->_path);
|
||||
} else {
|
||||
if(!@unlink($this->_file)) {
|
||||
throw new Exception('Error deleting file "' . $this->_file . '".');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testVizhashGeneratesUniquePngsPerIp()
|
||||
{
|
||||
$vz = new vizhash16x16();
|
||||
$pngdata = $vz->generate('127.0.0.1');
|
||||
file_put_contents($this->_file, $pngdata);
|
||||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||||
$this->assertEquals('image/png', $finfo->file($this->_file));
|
||||
$this->assertNotEquals($pngdata, $vz->generate('2001:1620:2057:dead:beef::cafe:babe'));
|
||||
$this->assertEquals($pngdata, $vz->generate('127.0.0.1'));
|
||||
}
|
||||
}
|
70
tst/zerobin/data.php
Normal file
70
tst/zerobin/data.php
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
class zerobin_dataTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
private static $pasteid = '501f02e9eeb8bcec';
|
||||
|
||||
private static $paste = array(
|
||||
'data' => '{"iv":"EN39/wd5Nk8HAiSG2K5AsQ","salt":"QKN1DBXe5PI","ct":"8hA83xDdXjD7K2qfmw5NdA"}',
|
||||
'meta' => array(
|
||||
'postdate' => 1344803344,
|
||||
'expire_date' => 1344803644,
|
||||
'opendiscussion' => true,
|
||||
),
|
||||
);
|
||||
|
||||
private static $commentid = 'c47efb4741195f42';
|
||||
|
||||
private static $comment = array(
|
||||
'data' => '{"iv":"Pd4pOKWkmDTT9uPwVwd5Ag","salt":"ZIUhFTliVz4","ct":"6nOCU3peNDclDDpFtJEBKA"}',
|
||||
'meta' => array(
|
||||
'nickname' => '{"iv":"76MkAtOGC4oFogX/aSMxRA","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 $_model;
|
||||
|
||||
private $_path;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
/* Setup Routine */
|
||||
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'zerobin_data';
|
||||
$this->_model = zerobin_data::getInstance(array('dir' => $this->_path));
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
/* Tear Down Routine */
|
||||
helper::rmdir($this->_path);
|
||||
}
|
||||
|
||||
public function testFileBasedDataStoreWorks()
|
||||
{
|
||||
// storing pastes
|
||||
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste does not yet exist');
|
||||
$this->assertTrue($this->_model->create(self::$pasteid, self::$paste), 'store new paste');
|
||||
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste exists after storing it');
|
||||
$this->assertFalse($this->_model->create(self::$pasteid, self::$paste), 'unable to store the same paste twice');
|
||||
$this->assertEquals(json_decode(json_encode(self::$paste)), $this->_model->read(self::$pasteid));
|
||||
|
||||
// storing comments
|
||||
$this->assertFalse($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'comment does not yet exist');
|
||||
$this->assertTrue($this->_model->createComment(self::$pasteid, self::$pasteid, self::$commentid, self::$comment) !== false, 'store comment');
|
||||
$this->assertTrue($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'comment exists after storing it');
|
||||
$comment = json_decode(json_encode(self::$comment));
|
||||
$comment->meta->commentid = self::$commentid;
|
||||
$comment->meta->parentid = self::$pasteid;
|
||||
$this->assertEquals(
|
||||
array($comment->meta->postdate => $comment),
|
||||
$this->_model->readComments(self::$pasteid)
|
||||
);
|
||||
|
||||
// deleting pastes
|
||||
$this->_model->delete(self::$pasteid);
|
||||
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste successfully deleted');
|
||||
$this->assertFalse($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'comment was deleted with paste');
|
||||
$this->assertFalse($this->_model->read(self::$pasteid), 'paste can no longer be found');
|
||||
}
|
||||
}
|
68
tst/zerobin/db.php
Normal file
68
tst/zerobin/db.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
class zerobin_dbTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
private static $pasteid = '501f02e9eeb8bcec';
|
||||
|
||||
private static $paste = array(
|
||||
'data' => '{"iv":"EN39/wd5Nk8HAiSG2K5AsQ","salt":"QKN1DBXe5PI","ct":"8hA83xDdXjD7K2qfmw5NdA"}',
|
||||
'meta' => array(
|
||||
'postdate' => 1344803344,
|
||||
'expire_date' => 1344803644,
|
||||
'opendiscussion' => true,
|
||||
),
|
||||
);
|
||||
|
||||
private static $commentid = 'c47efb4741195f42';
|
||||
|
||||
private static $comment = array(
|
||||
'data' => '{"iv":"Pd4pOKWkmDTT9uPwVwd5Ag","salt":"ZIUhFTliVz4","ct":"6nOCU3peNDclDDpFtJEBKA"}',
|
||||
'meta' => array(
|
||||
'nickname' => '{"iv":"76MkAtOGC4oFogX/aSMxRA","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 $_model;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
/* Setup Routine */
|
||||
$this->_model = zerobin_db::getInstance(
|
||||
array(
|
||||
'dsn' => 'sqlite::memory:',
|
||||
'usr' => null,
|
||||
'pwd' => null,
|
||||
'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function testDatabaseBasedDataStoreWorks()
|
||||
{
|
||||
// storing pastes
|
||||
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste does not yet exist');
|
||||
$this->assertTrue($this->_model->create(self::$pasteid, self::$paste), 'store new paste');
|
||||
$this->assertTrue($this->_model->exists(self::$pasteid), 'paste exists after storing it');
|
||||
$this->assertFalse($this->_model->create(self::$pasteid, self::$paste), 'unable to store the same paste twice');
|
||||
$this->assertEquals(json_decode(json_encode(self::$paste)), $this->_model->read(self::$pasteid));
|
||||
|
||||
// storing comments
|
||||
$this->assertFalse($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'comment does not yet exist');
|
||||
$this->assertTrue($this->_model->createComment(self::$pasteid, self::$pasteid, self::$commentid, self::$comment) !== false, 'store comment');
|
||||
$this->assertTrue($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'comment exists after storing it');
|
||||
$comment = json_decode(json_encode(self::$comment));
|
||||
$comment->meta->commentid = self::$commentid;
|
||||
$comment->meta->parentid = self::$pasteid;
|
||||
$this->assertEquals(
|
||||
array($comment->meta->postdate => $comment),
|
||||
$this->_model->readComments(self::$pasteid)
|
||||
);
|
||||
|
||||
// deleting pastes
|
||||
$this->_model->delete(self::$pasteid);
|
||||
$this->assertFalse($this->_model->exists(self::$pasteid), 'paste successfully deleted');
|
||||
$this->assertFalse($this->_model->existsComment(self::$pasteid, self::$pasteid, self::$commentid), 'comment was deleted with paste');
|
||||
$this->assertFalse($this->_model->read(self::$pasteid), 'paste can no longer be found');
|
||||
}
|
||||
}
|
1
uglifyjs
1
uglifyjs
|
@ -1 +0,0 @@
|
|||
Subproject commit ef4d776aedee6cbc8959a8e76403b82523615d3a
|
Loading…
Reference in a new issue