Initial commit of version 0.15 alpha.
This commit is contained in:
commit
52630374e5
|
@ -0,0 +1,33 @@
|
||||||
|
ZeroBin 0.15 Alpha
|
||||||
|
=== THIS IS ALPHA SOFTWARE - USE AT YOUR OWN RISKS ====
|
||||||
|
|
||||||
|
ZeroBin is a minimalist, opensource online pastebin where the server
|
||||||
|
has zero knowledge of pasted data. Data is encrypted/decrypted in the
|
||||||
|
browser using 256 bits AES.
|
||||||
|
|
||||||
|
More information on the project page:
|
||||||
|
http://sebsauvage.net/wiki/doku.php?id=php:zerobin
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2012 Sébastien SAUVAGE (sebsauvage.net)
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
In no event will the authors be held liable for any damages arising from
|
||||||
|
the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must
|
||||||
|
not claim that you wrote the original software. If you use this
|
||||||
|
software in a product, an acknowledgment in the product documentation
|
||||||
|
would be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and must
|
||||||
|
not be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
|
@ -0,0 +1,339 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
ZeroBin - a zero-knowledge paste bin
|
||||||
|
Please see project page: http://sebsauvage.net/wiki/doku.php?id=php:zerobin
|
||||||
|
*/
|
||||||
|
$VERSION='Alpha 0.15';
|
||||||
|
if (version_compare(PHP_VERSION, '5.2.6') < 0) die('ZeroBin requires php 5.2.6 or above to work. Sorry.');
|
||||||
|
require_once "lib/vizhash_gd_zero.php";
|
||||||
|
|
||||||
|
// In case stupid admin has left magic_quotes enabled in php.ini:
|
||||||
|
if (get_magic_quotes_gpc())
|
||||||
|
{
|
||||||
|
function stripslashes_deep($value) { $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); return $value; }
|
||||||
|
$_POST = array_map('stripslashes_deep', $_POST);
|
||||||
|
$_GET = array_map('stripslashes_deep', $_GET);
|
||||||
|
$_COOKIE = array_map('stripslashes_deep', $_COOKIE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// trafic_limiter : Make sure the IP address makes at most 1 request every 10 seconds.
|
||||||
|
// Will return false if IP address made a call less than 10 seconds ago.
|
||||||
|
function trafic_limiter_canPass($ip)
|
||||||
|
{
|
||||||
|
$tfilename='./data/trafic_limiter.php';
|
||||||
|
if (!is_file($tfilename))
|
||||||
|
{
|
||||||
|
file_put_contents($tfilename,"<?php\n\$GLOBALS['trafic_limiter']=array();\n?>");
|
||||||
|
chmod($tfilename,0705);
|
||||||
|
}
|
||||||
|
require $tfilename;
|
||||||
|
$tl=$GLOBALS['trafic_limiter'];
|
||||||
|
if (!empty($tl[$ip]) && ($tl[$ip]+10>=time()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
// FIXME: purge file of expired IPs to keep it small
|
||||||
|
}
|
||||||
|
$tl[$ip]=time();
|
||||||
|
file_put_contents($tfilename, "<?php\n\$GLOBALS['trafic_limiter']=".var_export($tl,true).";\n?>");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert paste id to storage path.
|
||||||
|
The idea is to creates subdirectories in order to limit the number of files per directory.
|
||||||
|
(A high number of files in a single directory can slow things down.)
|
||||||
|
eg. "f468483c313401e8" will be stored in "data/f4/68/f468483c313401e8"
|
||||||
|
High-trafic websites may want to deepen the directory structure (like Squid does).
|
||||||
|
|
||||||
|
eg. input 'e3570978f9e4aa90' --> output 'data/e3/57/'
|
||||||
|
*/
|
||||||
|
function dataid2path($dataid)
|
||||||
|
{
|
||||||
|
return 'data/'.substr($dataid,0,2).'/'.substr($dataid,2,2).'/';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert paste id to discussion storage path.
|
||||||
|
eg. 'e3570978f9e4aa90' --> 'data/e3/57/e3570978f9e4aa90.discussion/'
|
||||||
|
*/
|
||||||
|
function dataid2discussionpath($dataid)
|
||||||
|
{
|
||||||
|
return dataid2path($dataid).$dataid.'.discussion/';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if a json string is a proper SJCL encrypted message.
|
||||||
|
// False if format is incorrect.
|
||||||
|
function validSJCL($jsonstring)
|
||||||
|
{
|
||||||
|
$accepted_keys=array('iv','salt','ct');
|
||||||
|
|
||||||
|
// Make sure content is valid json
|
||||||
|
$decoded = json_decode($jsonstring);
|
||||||
|
if ($decoded==null) return false;
|
||||||
|
$decoded = (array)$decoded;
|
||||||
|
|
||||||
|
// Make sure required fields are present and that they are base64 data.
|
||||||
|
foreach($accepted_keys as $k)
|
||||||
|
{
|
||||||
|
if (!array_key_exists($k,$decoded)) { return false; }
|
||||||
|
if (base64_decode($decoded[$k],$strict=true)==null) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure no additionnal keys were added.
|
||||||
|
if (count(array_intersect(array_keys($decoded),$accepted_keys))!=3) { return false; }
|
||||||
|
|
||||||
|
// FIXME: Reject data if entropy is too low ?
|
||||||
|
|
||||||
|
// Make sure some fields have a reasonable size.
|
||||||
|
if (strlen($decoded['iv'])>24) return false;
|
||||||
|
if (strlen($decoded['salt'])>14) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete a paste and its discussion.
|
||||||
|
// Input: $pasteid : the paste identifier.
|
||||||
|
function deletePaste($pasteid)
|
||||||
|
{
|
||||||
|
// Delete the paste itself
|
||||||
|
unlink(dataid2path($pasteid).$pasteid);
|
||||||
|
|
||||||
|
// Delete discussion if it exists.
|
||||||
|
$discdir = dataid2discussionpath($pasteid);
|
||||||
|
if (is_dir($discdir))
|
||||||
|
{
|
||||||
|
// Delete all files in discussion directory
|
||||||
|
$dhandle = opendir($discdir);
|
||||||
|
while (false !== ($filename = readdir($dhandle)))
|
||||||
|
{
|
||||||
|
if (is_file($discdir.$filename)) unlink($discdir.$filename);
|
||||||
|
}
|
||||||
|
closedir($dhandle);
|
||||||
|
|
||||||
|
// Delete the discussion directory.
|
||||||
|
rmdir($discdir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($_POST['data'])) // Create new paste/comment
|
||||||
|
{
|
||||||
|
/* POST contains:
|
||||||
|
data (mandatory) = json encoded SJCL encrypted text (containing keys: iv,salt,ct)
|
||||||
|
|
||||||
|
All optional data will go to meta information:
|
||||||
|
expire (optional) = expiration delay (never,10min,1hour,1day,1month,1year,burn) (default:never)
|
||||||
|
opendiscusssion (optional) = is the discussion allowed on this paste ? (0/1) (default:0)
|
||||||
|
nickname (optional) = son encoded SJCL encrypted text nickname of author of comment (containing keys: iv,salt,ct)
|
||||||
|
parentid (optional) = in discussion, which comment this comment replies to.
|
||||||
|
pasteid (optional) = in discussion, which paste this comment belongs to.
|
||||||
|
*/
|
||||||
|
|
||||||
|
header('Content-type: application/json');
|
||||||
|
$error = false;
|
||||||
|
|
||||||
|
// Create storage directory if it does not exist.
|
||||||
|
if (!is_dir('data'))
|
||||||
|
{
|
||||||
|
mkdir('data',0705);
|
||||||
|
file_put_contents('data/.htaccess',"Allow from none\nDeny from all\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure last paste from the IP address was more than 10 seconds ago.
|
||||||
|
if (!trafic_limiter_canPass($_SERVER['REMOTE_ADDR']))
|
||||||
|
{ echo json_encode(array('status'=>1,'message'=>'Please wait 10 seconds between each post.')); exit; }
|
||||||
|
|
||||||
|
// Make sure content is not too big.
|
||||||
|
$data = $_POST['data'];
|
||||||
|
if (strlen($data)>2000000)
|
||||||
|
{ echo json_encode(array('status'=>1,'message'=>'Paste is limited to 2 Mb of encrypted data.')); exit; }
|
||||||
|
|
||||||
|
// Make sure format is correct.
|
||||||
|
if (!validSJCL($data))
|
||||||
|
{ echo json_encode(array('status'=>1,'message'=>'Invalid data.')); exit; }
|
||||||
|
|
||||||
|
// Read additional meta-information.
|
||||||
|
$meta=array();
|
||||||
|
|
||||||
|
// Read expiration date
|
||||||
|
if (!empty($_POST['expire']))
|
||||||
|
{
|
||||||
|
$expire=$_POST['expire'];
|
||||||
|
if ($expire=='10min') $meta['expire_date']=time()+10*60;
|
||||||
|
elseif ($expire=='1hour') $meta['expire_date']=time()+60*60;
|
||||||
|
elseif ($expire=='1day') $meta['expire_date']=time()+24*60*60;
|
||||||
|
elseif ($expire=='1month') $meta['expire_date']=time()+30*24*60*60; // Well this is not *exactly* one month, it's 30 days.
|
||||||
|
elseif ($expire=='1year') $meta['expire_date']=time()+365*24*60*60;
|
||||||
|
elseif ($expire=='burn') $meta['burnafterreading']=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read open discussion flag
|
||||||
|
if (!empty($_POST['opendiscussion']))
|
||||||
|
{
|
||||||
|
$opendiscussion = $_POST['opendiscussion'];
|
||||||
|
if ($opendiscussion!='0' && $opendiscussion!='1') { $error=true; }
|
||||||
|
if ($opendiscussion!='0') { $meta['opendiscussion']=true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can't have an open discussion on a "Burn after reading" paste:
|
||||||
|
if (isset($meta['burnafterreading'])) unset($meta['opendiscussion']);
|
||||||
|
|
||||||
|
// Optional nickname for comments
|
||||||
|
if (!empty($_POST['nickname']))
|
||||||
|
{
|
||||||
|
$nick = $_POST['nickname'];
|
||||||
|
if (!validSJCL($nick))
|
||||||
|
{
|
||||||
|
$error=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$meta['nickname']=$nick;
|
||||||
|
|
||||||
|
// Generation of the anonymous avatar (Vizhash):
|
||||||
|
// If a nickname is provided, we generate a Vizhash.
|
||||||
|
// (We assume that if the user did not enter a nickname, he/she wants
|
||||||
|
// to be anonymous and we will not generate the vizhash.)
|
||||||
|
$vz = new vizhash16x16();
|
||||||
|
$pngdata = $vz->generate($_SERVER['REMOTE_ADDR']);
|
||||||
|
if ($pngdata!='') $meta['vizhash'] = 'data:image/png;base64,'.base64_encode($pngdata);
|
||||||
|
// Once the avatar is generated, we do not keep the IP address, nor its hash.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($error)
|
||||||
|
{
|
||||||
|
echo json_encode(array('status'=>1,'message'=>'Invalid data.'));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add post date to meta.
|
||||||
|
$meta['postdate']=time();
|
||||||
|
|
||||||
|
// We just want a small hash to avoid collisions: Half-MD5 (64 bits) will do the trick
|
||||||
|
$dataid = substr(hash('md5',$data),0,16);
|
||||||
|
|
||||||
|
$is_comment = (!empty($_POST['parentid']) && !empty($_POST['pasteid'])); // Is this post a comment ?
|
||||||
|
$storage = array('data'=>$data);
|
||||||
|
if (count($meta)>0) $storage['meta'] = $meta; // Add meta-information only if necessary.
|
||||||
|
|
||||||
|
if ($is_comment) // The user posts a comment.
|
||||||
|
{
|
||||||
|
$pasteid = $_POST['pasteid'];
|
||||||
|
$parentid = $_POST['parentid'];
|
||||||
|
if (!preg_match('/[a-f\d]{16}/',$pasteid)) { echo json_encode(array('status'=>1,'message'=>'Invalid data.')); exit; }
|
||||||
|
if (!preg_match('/[a-f\d]{16}/',$parentid)) { echo json_encode(array('status'=>1,'message'=>'Invalid data.')); exit; }
|
||||||
|
|
||||||
|
unset($storage['expire_date']); // Comment do not expire (it's the paste that expires)
|
||||||
|
unset($storage['opendiscussion']);
|
||||||
|
|
||||||
|
// Make sure paste exists.
|
||||||
|
$storagedir = dataid2path($pasteid);
|
||||||
|
if (!is_file($storagedir.$pasteid)) { echo json_encode(array('status'=>1,'message'=>'Invalid data.')); exit; }
|
||||||
|
|
||||||
|
// Make sure the discussion is opened in this paste.
|
||||||
|
$paste=json_decode(file_get_contents($storagedir.$pasteid));
|
||||||
|
if (!$paste->meta->opendiscussion) { echo json_encode(array('status'=>1,'message'=>'Invalid data.')); exit; }
|
||||||
|
|
||||||
|
$discdir = dataid2discussionpath($pasteid);
|
||||||
|
$filename = $pasteid.'.'.$dataid.'.'.$parentid;
|
||||||
|
if (!is_dir($discdir)) mkdir($discdir,$mode=0705,$recursive=true);
|
||||||
|
if (is_file($discdir.$filename)) // Oups... improbable collision.
|
||||||
|
{
|
||||||
|
echo json_encode(array('status'=>1,'message'=>'You are unlucky. Try again.'));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents($discdir.$filename,json_encode($storage));
|
||||||
|
echo json_encode(array('status'=>0,'id'=>$dataid)); // 0 = no error
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
else // a standard paste.
|
||||||
|
{
|
||||||
|
$storagedir = dataid2path($dataid);
|
||||||
|
if (!is_dir($storagedir)) mkdir($storagedir,$mode=0705,$recursive=true);
|
||||||
|
if (is_file($storagedir.$dataid)) // Oups... improbable collision.
|
||||||
|
{
|
||||||
|
echo json_encode(array('status'=>1,'message'=>'You are unlucky. Try again.'));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
// New paste
|
||||||
|
file_put_contents($storagedir.$dataid,json_encode($storage));
|
||||||
|
echo json_encode(array('status'=>0,'id'=>$dataid)); // 0 = no error
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode(array('status'=>1,'message'=>'Server error.'));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$CIPHERDATA='';
|
||||||
|
$ERRORMESSAGE='';
|
||||||
|
if (!empty($_SERVER['QUERY_STRING'])) // Display an existing paste.
|
||||||
|
{
|
||||||
|
$dataid = $_SERVER['QUERY_STRING'];
|
||||||
|
if (preg_match('/[a-f\d]{16}/',$dataid)) // Is this a valid paste identifier ?
|
||||||
|
{
|
||||||
|
$filename = dataid2path($dataid).$dataid;
|
||||||
|
if (is_file($filename)) // Check that paste exists.
|
||||||
|
{
|
||||||
|
// Get the paste itself.
|
||||||
|
$paste=json_decode(file_get_contents($filename));
|
||||||
|
|
||||||
|
// See if paste has expired.
|
||||||
|
if (isset($paste->meta->expire_date) && $paste->meta->expire_date<time())
|
||||||
|
{
|
||||||
|
deletePaste($dataid); // Delete the paste
|
||||||
|
$ERRORMESSAGE='Paste does not exist or has expired.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ERRORMESSAGE=='') // If no error, return the paste.
|
||||||
|
{
|
||||||
|
// We kindly provide the remaining time before expiration (in seconds)
|
||||||
|
if ($paste->meta->expire_date) $paste->meta->remaining_time = $paste->meta->expire_date - time();
|
||||||
|
|
||||||
|
$messages = array($paste); // The paste itself is the first in the list of encrypted messages.
|
||||||
|
// If it's a discussion, get all comments.
|
||||||
|
if ($paste->meta->opendiscussion)
|
||||||
|
{
|
||||||
|
$comments=array();
|
||||||
|
$datadir = dataid2discussionpath($dataid);
|
||||||
|
if (!is_dir($datadir)) mkdir($datadir,$mode=0705,$recursive=true);
|
||||||
|
$dhandle = opendir($datadir);
|
||||||
|
while (false !== ($filename = readdir($dhandle)))
|
||||||
|
{
|
||||||
|
if (is_file($datadir.$filename))
|
||||||
|
{
|
||||||
|
$comment=json_decode(file_get_contents($datadir.$filename));
|
||||||
|
// Filename is in the form pasteid.commentid.parentid:
|
||||||
|
// - pasteid is the paste this reply belongs to.
|
||||||
|
// - commentid is the comment identifier itself.
|
||||||
|
// - parentid is the comment this comment replies to (It can be pasteid)
|
||||||
|
$items=explode('.',$filename);
|
||||||
|
$comment->meta->commentid=$items[1]; // Add some meta information not contained in file.
|
||||||
|
$comment->meta->parentid=$items[2];
|
||||||
|
$comments[$comment->meta->postdate]=$comment; // Store in table
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir($dhandle);
|
||||||
|
ksort($comments); // Sort comments by date, oldest first.
|
||||||
|
$messages = array_merge($messages, $comments);
|
||||||
|
}
|
||||||
|
$CIPHERDATA = json_encode($messages);
|
||||||
|
|
||||||
|
// If the paste was meant to be read only once, delete it.
|
||||||
|
if ($paste->meta->burnafterreading) deletePaste($dataid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$ERRORMESSAGE='Paste does not exist or has expired.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
require_once "lib/rain.tpl.class.php";
|
||||||
|
header('Content-Type: text/html; charset=utf-8');
|
||||||
|
$page = new RainTPL;
|
||||||
|
$page->assign('CIPHERDATA',htmlspecialchars($CIPHERDATA,ENT_NOQUOTES)); // We escape it here because ENT_NOQUOTES can't be used in RainTPL templates.
|
||||||
|
$page->assign('VERSION',$VERSION);
|
||||||
|
$page->assign('ERRORMESSAGE',$ERRORMESSAGE);
|
||||||
|
$page->draw('page');
|
||||||
|
?>
|
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
* $Id: base64.js,v 1.2 2011/12/27 14:34:49 dankogai Exp dankogai $
|
||||||
|
*
|
||||||
|
* Licensed under the MIT license.
|
||||||
|
* http://www.opensource.org/licenses/mit-license.php
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function(global){
|
||||||
|
|
||||||
|
if (global.Base64) return;
|
||||||
|
|
||||||
|
var b64chars
|
||||||
|
= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||||
|
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 sub_toBase64 = function(m){
|
||||||
|
var n = (m.charCodeAt(0) << 16)
|
||||||
|
| (m.charCodeAt(1) << 8)
|
||||||
|
| (m.charCodeAt(2) );
|
||||||
|
return b64chars.charAt( n >>> 18)
|
||||||
|
+ b64chars.charAt((n >>> 12) & 63)
|
||||||
|
+ b64chars.charAt((n >>> 6) & 63)
|
||||||
|
+ b64chars.charAt( n & 63);
|
||||||
|
};
|
||||||
|
|
||||||
|
var toBase64 = function(bin){
|
||||||
|
if (bin.match(/[^\x00-\xFF]/)) throw 'unsupported character found' ;
|
||||||
|
var padlen = 0;
|
||||||
|
while(bin.length % 3) {
|
||||||
|
bin += '\0';
|
||||||
|
padlen++;
|
||||||
|
};
|
||||||
|
var b64 = bin.replace(/[\x00-\xFF]{3}/g, sub_toBase64);
|
||||||
|
if (!padlen) return b64;
|
||||||
|
b64 = b64.substr(0, b64.length - padlen);
|
||||||
|
while(padlen--) b64 += '=';
|
||||||
|
return b64;
|
||||||
|
};
|
||||||
|
|
||||||
|
var btoa = global.btoa || toBase64;
|
||||||
|
|
||||||
|
var sub_fromBase64 = function(m){
|
||||||
|
var n = (b64tab[ m.charAt(0) ] << 18)
|
||||||
|
| (b64tab[ m.charAt(1) ] << 12)
|
||||||
|
| (b64tab[ m.charAt(2) ] << 6)
|
||||||
|
| (b64tab[ m.charAt(3) ]);
|
||||||
|
return String.fromCharCode( n >> 16 )
|
||||||
|
+ String.fromCharCode( (n >> 8) & 0xff )
|
||||||
|
+ String.fromCharCode( n & 0xff );
|
||||||
|
};
|
||||||
|
|
||||||
|
var fromBase64 = function(b64){
|
||||||
|
b64 = b64.replace(/[^A-Za-z0-9\+\/]/g, '');
|
||||||
|
var padlen = 0;
|
||||||
|
while(b64.length % 4){
|
||||||
|
b64 += 'A';
|
||||||
|
padlen++;
|
||||||
|
}
|
||||||
|
var bin = b64.replace(/[A-Za-z0-9\+\/]{4}/g, sub_fromBase64);
|
||||||
|
if (padlen >= 2)
|
||||||
|
bin = bin.substring(0, bin.length - [0,0,2,1][padlen]);
|
||||||
|
return bin;
|
||||||
|
};
|
||||||
|
|
||||||
|
var atob = global.atob || fromBase64;
|
||||||
|
|
||||||
|
var re_char_nonascii = /[^\x00-\x7F]/g;
|
||||||
|
|
||||||
|
var sub_char_nonascii = function(m){
|
||||||
|
var n = m.charCodeAt(0);
|
||||||
|
return n < 0x800 ? String.fromCharCode(0xc0 | (n >>> 6))
|
||||||
|
+ String.fromCharCode(0x80 | (n & 0x3f))
|
||||||
|
: String.fromCharCode(0xe0 | ((n >>> 12) & 0x0f))
|
||||||
|
+ String.fromCharCode(0x80 | ((n >>> 6) & 0x3f))
|
||||||
|
+ String.fromCharCode(0x80 | (n & 0x3f))
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
var utob = function(uni){
|
||||||
|
return uni.replace(re_char_nonascii, sub_char_nonascii);
|
||||||
|
};
|
||||||
|
|
||||||
|
var re_bytes_nonascii
|
||||||
|
= /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g;
|
||||||
|
|
||||||
|
var sub_bytes_nonascii = function(m){
|
||||||
|
var c0 = m.charCodeAt(0);
|
||||||
|
var c1 = m.charCodeAt(1);
|
||||||
|
if(c0 < 0xe0){
|
||||||
|
return String.fromCharCode(((c0 & 0x1f) << 6) | (c1 & 0x3f));
|
||||||
|
}else{
|
||||||
|
var c2 = m.charCodeAt(2);
|
||||||
|
return String.fromCharCode(
|
||||||
|
((c0 & 0x0f) << 12) | ((c1 & 0x3f) << 6) | (c2 & 0x3f)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var btou = function(bin){
|
||||||
|
return bin.replace(re_bytes_nonascii, sub_bytes_nonascii);
|
||||||
|
};
|
||||||
|
|
||||||
|
global.Base64 = {
|
||||||
|
fromBase64:fromBase64,
|
||||||
|
toBase64:toBase64,
|
||||||
|
atob:atob,
|
||||||
|
btoa:btoa,
|
||||||
|
utob:utob,
|
||||||
|
btou:btou,
|
||||||
|
encode:function(u){ return btoa(utob(u)) },
|
||||||
|
encodeURI:function(u){
|
||||||
|
return btoa(utob(u)).replace(/[+\/]/g, function(m0){
|
||||||
|
return m0 == '+' ? '-' : '_';
|
||||||
|
}).replace(/=+$/, '');
|
||||||
|
},
|
||||||
|
decode:function(a){
|
||||||
|
return btou(atob(a.replace(/[-_]/g, function(m0){
|
||||||
|
return m0 == '-' ? '+' : '/';
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
})(this);
|
Binary file not shown.
After Width: | Height: | Size: 671 B |
Binary file not shown.
After Width: | Height: | Size: 391 B |
Binary file not shown.
After Width: | Height: | Size: 209 B |
Binary file not shown.
After Width: | Height: | Size: 261 B |
Binary file not shown.
After Width: | Height: | Size: 262 B |
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,753 @@
|
||||||
|
/*
|
||||||
|
* $Id: rawinflate.js,v 0.2 2009/03/01 18:32:24 dankogai Exp $
|
||||||
|
*
|
||||||
|
* original:
|
||||||
|
* http://www.onicos.com/staff/iz/amuse/javascript/expert/inflate.txt
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/* 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 (! window.RawDeflate) RawDeflate = {};
|
||||||
|
RawDeflate.inflate = zip_inflate;
|
||||||
|
|
||||||
|
})();
|
|
@ -0,0 +1,41 @@
|
||||||
|
"use strict";var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return"CORRUPT: "+this.message};this.message=a},invalid:function(a){this.toString=function(){return"INVALID: "+this.message};this.message=a},bug:function(a){this.toString=function(){return"BUG: "+this.message};this.message=a},notReady:function(a){this.toString=function(){return"NOT READY: "+this.message};this.message=a}}};
|
||||||
|
if(typeof module!="undefined"&&module.exports)module.exports=sjcl;
|
||||||
|
sjcl.cipher.aes=function(a){this.h[0][0][0]||this.w();var b,c,d,e,f=this.h[0][4],g=this.h[1];b=a.length;var h=1;if(b!==4&&b!==6&&b!==8)throw new sjcl.exception.invalid("invalid aes key size");this.a=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(a%b===0||b===8&&a%b===4){c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255];if(a%b===0){c=c<<8^c>>>24^h<<24;h=h<<1^(h>>7)*283}}d[a]=d[a-b]^c}for(b=0;a;b++,a--){c=d[b&3?a:a-4];e[b]=a<=4||b<4?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^
|
||||||
|
g[3][f[c&255]]}};
|
||||||
|
sjcl.cipher.aes.prototype={encrypt:function(a){return this.H(a,0)},decrypt:function(a){return this.H(a,1)},h:[[[],[],[],[],[]],[[],[],[],[],[]]],w:function(){var a=this.h[0],b=this.h[1],c=a[4],d=b[4],e,f,g,h=[],i=[],k,j,l,m;for(e=0;e<0x100;e++)i[(h[e]=e<<1^(e>>7)*283)^e]=e;for(f=g=0;!c[f];f^=k||1,g=i[g]||1){l=g^g<<1^g<<2^g<<3^g<<4;l=l>>8^l&255^99;c[f]=l;d[l]=f;j=h[e=h[k=h[f]]];m=j*0x1010101^e*0x10001^k*0x101^f*0x1010100;j=h[l]*0x101^l*0x1010100;for(e=0;e<4;e++){a[e][f]=j=j<<24^j>>>8;b[e][l]=m=m<<24^m>>>8}}for(e=
|
||||||
|
0;e<5;e++){a[e]=a[e].slice(0);b[e]=b[e].slice(0)}},H:function(a,b){if(a.length!==4)throw new sjcl.exception.invalid("invalid aes block size");var c=this.a[b],d=a[0]^c[0],e=a[b?3:1]^c[1],f=a[2]^c[2];a=a[b?1:3]^c[3];var g,h,i,k=c.length/4-2,j,l=4,m=[0,0,0,0];g=this.h[b];var n=g[0],o=g[1],p=g[2],q=g[3],r=g[4];for(j=0;j<k;j++){g=n[d>>>24]^o[e>>16&255]^p[f>>8&255]^q[a&255]^c[l];h=n[e>>>24]^o[f>>16&255]^p[a>>8&255]^q[d&255]^c[l+1];i=n[f>>>24]^o[a>>16&255]^p[d>>8&255]^q[e&255]^c[l+2];a=n[a>>>24]^o[d>>16&
|
||||||
|
255]^p[e>>8&255]^q[f&255]^c[l+3];l+=4;d=g;e=h;f=i}for(j=0;j<4;j++){m[b?3&-j:j]=r[d>>>24]<<24^r[e>>16&255]<<16^r[f>>8&255]<<8^r[a&255]^c[l++];g=d;d=e;e=f;f=a;a=g}return m}};
|
||||||
|
sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.P(a.slice(b/32),32-(b&31)).slice(1);return c===undefined?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<<c)-1},concat:function(a,b){if(a.length===0||b.length===0)return a.concat(b);var c=a[a.length-1],d=sjcl.bitArray.getPartial(c);return d===32?a.concat(b):sjcl.bitArray.P(b,d,c|0,a.slice(0,a.length-1))},bitLength:function(a){var b=a.length;
|
||||||
|
if(b===0)return 0;return(b-1)*32+sjcl.bitArray.getPartial(a[b-1])},clamp:function(a,b){if(a.length*32<b)return a;a=a.slice(0,Math.ceil(b/32));var c=a.length;b&=31;if(c>0&&b)a[c-1]=sjcl.bitArray.partial(b,a[c-1]&2147483648>>b-1,1);return a},partial:function(a,b,c){if(a===32)return b;return(c?b|0:b<<32-a)+a*0x10000000000},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return false;var c=0,d;for(d=0;d<a.length;d++)c|=
|
||||||
|
a[d]^b[d];return c===0},P:function(a,b,c,d){var e;e=0;if(d===undefined)d=[];for(;b>=32;b-=32){d.push(c);c=0}if(b===0)return d.concat(a);for(e=0;e<a.length;e++){d.push(c|a[e]>>>b);c=a[e]<<32-b}e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,b+a>32?c:d.pop(),1));return d},k:function(a,b){return[a[0]^b[0],a[1]^b[1],a[2]^b[2],a[3]^b[3]]}};
|
||||||
|
sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d<c/8;d++){if((d&3)===0)e=a[d/4];b+=String.fromCharCode(e>>>24);e<<=8}return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c<a.length;c++){d=d<<8|a.charCodeAt(c);if((c&3)===3){b.push(d);d=0}}c&3&&b.push(sjcl.bitArray.partial(8*(c&3),d));return b}};
|
||||||
|
sjcl.codec.hex={fromBits:function(a){var b="",c;for(c=0;c<a.length;c++)b+=((a[c]|0)+0xf00000000000).toString(16).substr(4);return b.substr(0,sjcl.bitArray.bitLength(a)/4)},toBits:function(a){var b,c=[],d;a=a.replace(/\s|0x/g,"");d=a.length;a+="00000000";for(b=0;b<a.length;b+=8)c.push(parseInt(a.substr(b,8),16)^0);return sjcl.bitArray.clamp(c,d*4)}};
|
||||||
|
sjcl.codec.base64={D:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fromBits:function(a,b,c){var d="",e=0,f=sjcl.codec.base64.D,g=0,h=sjcl.bitArray.bitLength(a);if(c)f=f.substr(0,62)+"-_";for(c=0;d.length*6<h;){d+=f.charAt((g^a[c]>>>e)>>>26);if(e<6){g=a[c]<<6-e;e+=26;c++}else{g<<=6;e-=6}}for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d=0,e=sjcl.codec.base64.D,f=0,g;if(b)e=e.substr(0,62)+"-_";for(b=0;b<a.length;b++){g=e.indexOf(a.charAt(b));
|
||||||
|
if(g<0)throw new sjcl.exception.invalid("this isn't base64!");if(d>26){d-=26;c.push(f^g>>>d);f=g<<32-d}else{d+=6;f^=g<<32-d}}d&56&&c.push(sjcl.bitArray.partial(d&56,f,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.a[0]||this.w();if(a){this.n=a.n.slice(0);this.i=a.i.slice(0);this.e=a.e}else this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()};
|
||||||
|
sjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.n=this.N.slice(0);this.i=[];this.e=0;return this},update:function(a){if(typeof a==="string")a=sjcl.codec.utf8String.toBits(a);var b,c=this.i=sjcl.bitArray.concat(this.i,a);b=this.e;a=this.e=b+sjcl.bitArray.bitLength(a);for(b=512+b&-512;b<=a;b+=512)this.C(c.splice(0,16));return this},finalize:function(){var a,b=this.i,c=this.n;b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.e/
|
||||||
|
4294967296));for(b.push(this.e|0);b.length;)this.C(b.splice(0,16));this.reset();return c},N:[],a:[],w:function(){function a(e){return(e-Math.floor(e))*0x100000000|0}var b=0,c=2,d;a:for(;b<64;c++){for(d=2;d*d<=c;d++)if(c%d===0)continue a;if(b<8)this.N[b]=a(Math.pow(c,0.5));this.a[b]=a(Math.pow(c,1/3));b++}},C:function(a){var b,c,d=a.slice(0),e=this.n,f=this.a,g=e[0],h=e[1],i=e[2],k=e[3],j=e[4],l=e[5],m=e[6],n=e[7];for(a=0;a<64;a++){if(a<16)b=d[a];else{b=d[a+1&15];c=d[a+14&15];b=d[a&15]=(b>>>7^b>>>18^
|
||||||
|
b>>>3^b<<25^b<<14)+(c>>>17^c>>>19^c>>>10^c<<15^c<<13)+d[a&15]+d[a+9&15]|0}b=b+n+(j>>>6^j>>>11^j>>>25^j<<26^j<<21^j<<7)+(m^j&(l^m))+f[a];n=m;m=l;l=j;j=k+b|0;k=i;i=h;h=g;g=b+(h&i^k&(h^i))+(h>>>2^h>>>13^h>>>22^h<<30^h<<19^h<<10)|0}e[0]=e[0]+g|0;e[1]=e[1]+h|0;e[2]=e[2]+i|0;e[3]=e[3]+k|0;e[4]=e[4]+j|0;e[5]=e[5]+l|0;e[6]=e[6]+m|0;e[7]=e[7]+n|0}};
|
||||||
|
sjcl.mode.ccm={name:"ccm",encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,i=h.bitLength(c)/8,k=h.bitLength(g)/8;e=e||64;d=d||[];if(i<7)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(f=2;f<4&&k>>>8*f;f++);if(f<15-i)f=15-i;c=h.clamp(c,8*(15-f));b=sjcl.mode.ccm.G(a,b,c,d,e,f);g=sjcl.mode.ccm.I(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),i=f.clamp(b,h-e),k=f.bitSlice(b,
|
||||||
|
h-e);h=(h-e)/8;if(g<7)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(b=2;b<4&&h>>>8*b;b++);if(b<15-g)b=15-g;c=f.clamp(c,8*(15-b));i=sjcl.mode.ccm.I(a,i,c,k,e,b);a=sjcl.mode.ccm.G(a,i.data,c,d,e,b);if(!f.equal(i.tag,a))throw new sjcl.exception.corrupt("ccm: tag doesn't match");return i.data},G:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,i=h.k;e/=8;if(e%2||e<4||e>16)throw new sjcl.exception.invalid("ccm: invalid tag length");if(d.length>0xffffffff||b.length>0xffffffff)throw new sjcl.exception.bug("ccm: can't deal with 4GiB or more data");
|
||||||
|
f=[h.partial(8,(d.length?64:0)|e-2<<2|f-1)];f=h.concat(f,c);f[3]|=h.bitLength(b)/8;f=a.encrypt(f);if(d.length){c=h.bitLength(d)/8;if(c<=65279)g=[h.partial(16,c)];else if(c<=0xffffffff)g=h.concat([h.partial(16,65534)],[c]);g=h.concat(g,d);for(d=0;d<g.length;d+=4)f=a.encrypt(i(f,g.slice(d,d+4).concat([0,0,0])))}for(d=0;d<b.length;d+=4)f=a.encrypt(i(f,b.slice(d,d+4).concat([0,0,0])));return h.clamp(f,e*8)},I:function(a,b,c,d,e,f){var g,h=sjcl.bitArray;g=h.k;var i=b.length,k=h.bitLength(b);c=h.concat([h.partial(8,
|
||||||
|
f-1)],c).concat([0,0,0]).slice(0,4);d=h.bitSlice(g(d,a.encrypt(c)),0,e);if(!i)return{tag:d,data:[]};for(g=0;g<i;g+=4){c[3]++;e=a.encrypt(c);b[g]^=e[0];b[g+1]^=e[1];b[g+2]^=e[2];b[g+3]^=e[3]}return{tag:d,data:h.clamp(b,k)}}};
|
||||||
|
sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){if(sjcl.bitArray.bitLength(c)!==128)throw new sjcl.exception.invalid("ocb iv must be 128 bits");var g,h=sjcl.mode.ocb2.A,i=sjcl.bitArray,k=i.k,j=[0,0,0,0];c=h(a.encrypt(c));var l,m=[];d=d||[];e=e||64;for(g=0;g+4<b.length;g+=4){l=b.slice(g,g+4);j=k(j,l);m=m.concat(k(c,a.encrypt(k(c,l))));c=h(c)}l=b.slice(g);b=i.bitLength(l);g=a.encrypt(k(c,[0,0,0,b]));l=i.clamp(k(l.concat([0,0,0]),g),b);j=k(j,k(l.concat([0,0,0]),g));j=a.encrypt(k(j,k(c,h(c))));
|
||||||
|
if(d.length)j=k(j,f?d:sjcl.mode.ocb2.pmac(a,d));return m.concat(i.concat(l,i.clamp(j,e)))},decrypt:function(a,b,c,d,e,f){if(sjcl.bitArray.bitLength(c)!==128)throw new sjcl.exception.invalid("ocb iv must be 128 bits");e=e||64;var g=sjcl.mode.ocb2.A,h=sjcl.bitArray,i=h.k,k=[0,0,0,0],j=g(a.encrypt(c)),l,m,n=sjcl.bitArray.bitLength(b)-e,o=[];d=d||[];for(c=0;c+4<n/32;c+=4){l=i(j,a.decrypt(i(j,b.slice(c,c+4))));k=i(k,l);o=o.concat(l);j=g(j)}m=n-c*32;l=a.encrypt(i(j,[0,0,0,m]));l=i(l,h.clamp(b.slice(c),
|
||||||
|
m).concat([0,0,0]));k=i(k,l);k=a.encrypt(i(k,i(j,g(j))));if(d.length)k=i(k,f?d:sjcl.mode.ocb2.pmac(a,d));if(!h.equal(h.clamp(k,e),h.bitSlice(b,n)))throw new sjcl.exception.corrupt("ocb: tag doesn't match");return o.concat(h.clamp(l,m))},pmac:function(a,b){var c,d=sjcl.mode.ocb2.A,e=sjcl.bitArray,f=e.k,g=[0,0,0,0],h=a.encrypt([0,0,0,0]);h=f(h,d(d(h)));for(c=0;c+4<b.length;c+=4){h=d(h);g=f(g,a.encrypt(f(h,b.slice(c,c+4))))}b=b.slice(c);if(e.bitLength(b)<128){h=f(h,d(h));b=e.concat(b,[2147483648|0,0,
|
||||||
|
0,0])}g=f(g,b);return a.encrypt(f(d(f(h,d(h))),g))},A:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^(a[0]>>>31)*135]}};sjcl.misc.hmac=function(a,b){this.M=b=b||sjcl.hash.sha256;var c=[[],[]],d=b.prototype.blockSize/32;this.l=[new b,new b];if(a.length>d)a=b.hash(a);for(b=0;b<d;b++){c[0][b]=a[b]^909522486;c[1][b]=a[b]^1549556828}this.l[0].update(c[0]);this.l[1].update(c[1])};
|
||||||
|
sjcl.misc.hmac.prototype.encrypt=sjcl.misc.hmac.prototype.mac=function(a,b){a=(new this.M(this.l[0])).update(a,b).finalize();return(new this.M(this.l[1])).update(a).finalize()};
|
||||||
|
sjcl.misc.pbkdf2=function(a,b,c,d,e){c=c||1E3;if(d<0||c<0)throw sjcl.exception.invalid("invalid params to pbkdf2");if(typeof a==="string")a=sjcl.codec.utf8String.toBits(a);e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,i,k=[],j=sjcl.bitArray;for(i=1;32*k.length<(d||1);i++){e=f=a.encrypt(j.concat(b,[i]));for(g=1;g<c;g++){f=a.encrypt(f);for(h=0;h<f.length;h++)e[h]^=f[h]}k=k.concat(e)}if(d)k=j.clamp(k,d);return k};
|
||||||
|
sjcl.random={randomWords:function(a,b){var c=[];b=this.isReady(b);var d;if(b===0)throw new sjcl.exception.notReady("generator isn't seeded");else b&2&&this.U(!(b&1));for(b=0;b<a;b+=4){(b+1)%0x10000===0&&this.L();d=this.u();c.push(d[0],d[1],d[2],d[3])}this.L();return c.slice(0,a)},setDefaultParanoia:function(a){this.t=a},addEntropy:function(a,b,c){c=c||"user";var d,e,f=(new Date).valueOf(),g=this.q[c],h=this.isReady();d=this.F[c];if(d===undefined)d=this.F[c]=this.R++;if(g===undefined)g=this.q[c]=0;this.q[c]=
|
||||||
|
(this.q[c]+1)%this.b.length;switch(typeof a){case "number":break;case "object":if(b===undefined)for(c=b=0;c<a.length;c++)for(e=a[c];e>0;){b++;e>>>=1}this.b[g].update([d,this.J++,2,b,f,a.length].concat(a));break;case "string":if(b===undefined)b=a.length;this.b[g].update([d,this.J++,3,b,f,a.length]);this.b[g].update(a);break;default:throw new sjcl.exception.bug("random: addEntropy only supports number, array or string");}this.j[g]+=b;this.f+=b;if(h===0){this.isReady()!==0&&this.K("seeded",Math.max(this.g,
|
||||||
|
this.f));this.K("progress",this.getProgress())}},isReady:function(a){a=this.B[a!==undefined?a:this.t];return this.g&&this.g>=a?this.j[0]>80&&(new Date).valueOf()>this.O?3:1:this.f>=a?2:0},getProgress:function(a){a=this.B[a?a:this.t];return this.g>=a?1["0"]:this.f>a?1["0"]:this.f/a},startCollectors:function(){if(!this.m){if(window.addEventListener){window.addEventListener("load",this.o,false);window.addEventListener("mousemove",this.p,false)}else if(document.attachEvent){document.attachEvent("onload",
|
||||||
|
this.o);document.attachEvent("onmousemove",this.p)}else throw new sjcl.exception.bug("can't attach event");this.m=true}},stopCollectors:function(){if(this.m){if(window.removeEventListener){window.removeEventListener("load",this.o,false);window.removeEventListener("mousemove",this.p,false)}else if(window.detachEvent){window.detachEvent("onload",this.o);window.detachEvent("onmousemove",this.p)}this.m=false}},addEventListener:function(a,b){this.r[a][this.Q++]=b},removeEventListener:function(a,b){var c;
|
||||||
|
a=this.r[a];var d=[];for(c in a)a.hasOwnProperty(c)&&a[c]===b&&d.push(c);for(b=0;b<d.length;b++){c=d[b];delete a[c]}},b:[new sjcl.hash.sha256],j:[0],z:0,q:{},J:0,F:{},R:0,g:0,f:0,O:0,a:[0,0,0,0,0,0,0,0],d:[0,0,0,0],s:undefined,t:6,m:false,r:{progress:{},seeded:{}},Q:0,B:[0,48,64,96,128,192,0x100,384,512,768,1024],u:function(){for(var a=0;a<4;a++){this.d[a]=this.d[a]+1|0;if(this.d[a])break}return this.s.encrypt(this.d)},L:function(){this.a=this.u().concat(this.u());this.s=new sjcl.cipher.aes(this.a)},
|
||||||
|
T:function(a){this.a=sjcl.hash.sha256.hash(this.a.concat(a));this.s=new sjcl.cipher.aes(this.a);for(a=0;a<4;a++){this.d[a]=this.d[a]+1|0;if(this.d[a])break}},U:function(a){var b=[],c=0,d;this.O=b[0]=(new Date).valueOf()+3E4;for(d=0;d<16;d++)b.push(Math.random()*0x100000000|0);for(d=0;d<this.b.length;d++){b=b.concat(this.b[d].finalize());c+=this.j[d];this.j[d]=0;if(!a&&this.z&1<<d)break}if(this.z>=1<<this.b.length){this.b.push(new sjcl.hash.sha256);this.j.push(0)}this.f-=c;if(c>this.g)this.g=c;this.z++;
|
||||||
|
this.T(b)},p:function(a){sjcl.random.addEntropy([a.x||a.clientX||a.offsetX,a.y||a.clientY||a.offsetY],2,"mouse")},o:function(){sjcl.random.addEntropy(new Date,2,"loadtime")},K:function(a,b){var c;a=sjcl.random.r[a];var d=[];for(c in a)a.hasOwnProperty(c)&&d.push(a[c]);for(c=0;c<d.length;c++)d[c](b)}};try{var s=new Uint32Array(32);crypto.getRandomValues(s);sjcl.random.addEntropy(s,1024,"crypto['getRandomValues']")}catch(t){}
|
||||||
|
sjcl.json={defaults:{v:1,iter:1E3,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},encrypt:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.c({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.c(f,c);c=f.adata;if(typeof f.salt==="string")f.salt=sjcl.codec.base64.toBits(f.salt);if(typeof f.iv==="string")f.iv=sjcl.codec.base64.toBits(f.iv);if(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||typeof a==="string"&&f.iter<=100||f.ts!==64&&f.ts!==96&&f.ts!==128||f.ks!==128&&f.ks!==192&&f.ks!==0x100||f.iv.length<
|
||||||
|
2||f.iv.length>4)throw new sjcl.exception.invalid("json encrypt: invalid parameters");if(typeof a==="string"){g=sjcl.misc.cachedPbkdf2(a,f);a=g.key.slice(0,f.ks/32);f.salt=g.salt}if(typeof b==="string")b=sjcl.codec.utf8String.toBits(b);if(typeof c==="string")c=sjcl.codec.utf8String.toBits(c);g=new sjcl.cipher[f.cipher](a);e.c(d,f);d.key=a;f.ct=sjcl.mode[f.mode].encrypt(g,b,f.iv,c,f.ts);return e.encode(e.V(f,e.defaults))},decrypt:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json;b=e.c(e.c(e.c({},e.defaults),
|
||||||
|
e.decode(b)),c,true);var f;c=b.adata;if(typeof b.salt==="string")b.salt=sjcl.codec.base64.toBits(b.salt);if(typeof b.iv==="string")b.iv=sjcl.codec.base64.toBits(b.iv);if(!sjcl.mode[b.mode]||!sjcl.cipher[b.cipher]||typeof a==="string"&&b.iter<=100||b.ts!==64&&b.ts!==96&&b.ts!==128||b.ks!==128&&b.ks!==192&&b.ks!==0x100||!b.iv||b.iv.length<2||b.iv.length>4)throw new sjcl.exception.invalid("json decrypt: invalid parameters");if(typeof a==="string"){f=sjcl.misc.cachedPbkdf2(a,b);a=f.key.slice(0,b.ks/32);
|
||||||
|
b.salt=f.salt}if(typeof c==="string")c=sjcl.codec.utf8String.toBits(c);f=new sjcl.cipher[b.cipher](a);c=sjcl.mode[b.mode].decrypt(f,b.ct,b.iv,c,b.ts);e.c(d,b);d.key=a;return sjcl.codec.utf8String.fromBits(c)},encode:function(a){var b,c="{",d="";for(b in a)if(a.hasOwnProperty(b)){if(!b.match(/^[a-z0-9]+$/i))throw new sjcl.exception.invalid("json encode: invalid property name");c+=d+'"'+b+'":';d=",";switch(typeof a[b]){case "number":case "boolean":c+=a[b];break;case "string":c+='"'+escape(a[b])+'"';
|
||||||
|
break;case "object":c+='"'+sjcl.codec.base64.fromBits(a[b],1)+'"';break;default:throw new sjcl.exception.bug("json encode: unsupported type");}}return c+"}"},decode:function(a){a=a.replace(/\s/g,"");if(!a.match(/^\{.*\}$/))throw new sjcl.exception.invalid("json decode: this isn't json!");a=a.replace(/^\{|\}$/g,"").split(/,/);var b={},c,d;for(c=0;c<a.length;c++){if(!(d=a[c].match(/^(?:(["']?)([a-z][a-z0-9]*)\1):(?:(\d+)|"([a-z0-9+\/%*_.@=\-]*)")$/i)))throw new sjcl.exception.invalid("json decode: this isn't json!");
|
||||||
|
b[d[2]]=d[3]?parseInt(d[3],10):d[2].match(/^(ct|salt|iv)$/)?sjcl.codec.base64.toBits(d[4]):unescape(d[4])}return b},c:function(a,b,c){if(a===undefined)a={};if(b===undefined)return a;var d;for(d in b)if(b.hasOwnProperty(d)){if(c&&a[d]!==undefined&&a[d]!==b[d])throw new sjcl.exception.invalid("required parameter overridden");a[d]=b[d]}return a},V:function(a,b){var c={},d;for(d in a)if(a.hasOwnProperty(d)&&a[d]!==b[d])c[d]=a[d];return c},W:function(a,b){var c={},d;for(d=0;d<b.length;d++)if(a[b[d]]!==
|
||||||
|
undefined)c[b[d]]=a[b[d]];return c}};sjcl.encrypt=sjcl.json.encrypt;sjcl.decrypt=sjcl.json.decrypt;sjcl.misc.S={};sjcl.misc.cachedPbkdf2=function(a,b){var c=sjcl.misc.S,d;b=b||{};d=b.iter||1E3;c=c[a]=c[a]||{};d=c[d]=c[d]||{firstSalt:b.salt&&b.salt.length?b.salt.slice(0):sjcl.random.randomWords(2,0)};c=b.salt===undefined?d.firstSalt:b.salt;d[c]=d[c]||sjcl.misc.pbkdf2(a,c,b.iter);return{key:d[c].slice(0),salt:c.slice(0)}};
|
|
@ -0,0 +1,158 @@
|
||||||
|
<?php
|
||||||
|
// VizHash_GD 0.0.4 beta ZeroBin 0.15
|
||||||
|
// Visual Hash implementation in php4+GD, stripped down and modified version for ZeroBin
|
||||||
|
// See: http://sebsauvage.net/wiki/doku.php?id=php:vizhash_gd
|
||||||
|
// This is free software under the zlib/libpng licence
|
||||||
|
// http://www.opensource.org/licenses/zlib-license.php
|
||||||
|
/* Example:
|
||||||
|
$vz = new vizhash16x16();
|
||||||
|
$data = $vz->generate('hello');
|
||||||
|
header('Content-type: image/png');
|
||||||
|
echo $data;
|
||||||
|
exit;
|
||||||
|
*/
|
||||||
|
class vizhash16x16
|
||||||
|
{
|
||||||
|
private $VALUES;
|
||||||
|
private $VALUES_INDEX;
|
||||||
|
private $width;
|
||||||
|
private $height;
|
||||||
|
private $salt;
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
$this->width=16;
|
||||||
|
$this->height=16;
|
||||||
|
|
||||||
|
// Read salt from file (and create it if does not exist).
|
||||||
|
// The salt will make vizhash avatar unique on each ZeroBin installation
|
||||||
|
// to prevent IP checking.
|
||||||
|
$saltfile = 'data/salt.php';
|
||||||
|
if (!is_file($saltfile))
|
||||||
|
file_put_contents($saltfile,'<?php /* |'.$this->randomSalt().'| */ ?>');
|
||||||
|
$items=explode('|',file_get_contents($saltfile));
|
||||||
|
$this->salt = $items[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a 16x16 png corresponding to $text.
|
||||||
|
// Input: $text (string)
|
||||||
|
// Output: PNG data. Or empty string if GD is not available.
|
||||||
|
function generate($text)
|
||||||
|
{
|
||||||
|
if (!function_exists('gd_info')) return '';
|
||||||
|
|
||||||
|
// We hash the input string.
|
||||||
|
$hash=hash('sha1',$text.$this->salt).hash('md5',$text.$this->salt);
|
||||||
|
$hash=$hash.strrev($hash); # more data to make graphics
|
||||||
|
|
||||||
|
// We convert the hash into an array of integers.
|
||||||
|
$this->VALUES=array();
|
||||||
|
for($i=0; $i<strlen($hash); $i=$i+2){ array_push($this->VALUES,hexdec(substr($hash,$i,2))); }
|
||||||
|
$this->VALUES_INDEX=0; // to walk the array.
|
||||||
|
|
||||||
|
// Then use these integers to drive the creation of an image.
|
||||||
|
$image = imagecreatetruecolor($this->width,$this->height);
|
||||||
|
|
||||||
|
$r0 = $this->getInt();$r=$r0;
|
||||||
|
$g0 = $this->getInt();$g=$g0;
|
||||||
|
$b0 = $this->getInt();$b=$b0;
|
||||||
|
|
||||||
|
// First, create an image with a specific gradient background.
|
||||||
|
$op='v'; if (($this->getInt()%2)==0) { $op='h'; };
|
||||||
|
$image = $this->degrade($image,$op,array($r0,$g0,$b0),array(0,0,0));
|
||||||
|
|
||||||
|
for($i=0; $i<7; $i=$i+1)
|
||||||
|
{
|
||||||
|
$action=$this->getInt();
|
||||||
|
$color = imagecolorallocate($image, $r,$g,$b);
|
||||||
|
$r = ($r0 + $this->getInt()/25)%256;
|
||||||
|
$g = ($g0 + $this->getInt()/25)%256;
|
||||||
|
$b = ($b0 + $this->getInt()/25)%256;
|
||||||
|
$r0=$r; $g0=$g; $b0=$b;
|
||||||
|
$this->drawshape($image,$action,$color);
|
||||||
|
}
|
||||||
|
|
||||||
|
$color = imagecolorallocate($image,$this->getInt(),$this->getInt(),$this->getInt());
|
||||||
|
$this->drawshape($image,$this->getInt(),$color);
|
||||||
|
ob_start();
|
||||||
|
imagepng($image);
|
||||||
|
$imagedata = ob_get_contents();
|
||||||
|
ob_end_clean();
|
||||||
|
imagedestroy($image);
|
||||||
|
|
||||||
|
return $imagedata;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a large random hexadecimal salt.
|
||||||
|
private function randomSalt()
|
||||||
|
{
|
||||||
|
$randomSalt='';
|
||||||
|
for($i=0;$i<6;$i++) { $randomSalt.=base_convert(mt_rand(),10,16); }
|
||||||
|
return $randomSalt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function getInt() // Returns a single integer from the $VALUES array (0...255)
|
||||||
|
{
|
||||||
|
$v= $this->VALUES[$this->VALUES_INDEX];
|
||||||
|
$this->VALUES_INDEX++;
|
||||||
|
$this->VALUES_INDEX %= count($this->VALUES); // Warp around the array
|
||||||
|
return $v;
|
||||||
|
}
|
||||||
|
private function getX() // Returns a single integer from the array (roughly mapped to image width)
|
||||||
|
{
|
||||||
|
return $this->width*$this->getInt()/256;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getY() // Returns a single integer from the array (roughly mapped to image height)
|
||||||
|
{
|
||||||
|
return $this->height*$this->getInt()/256;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Gradient function taken from:
|
||||||
|
# http://www.supportduweb.com/scripts_tutoriaux-code-source-41-gd-faire-un-degrade-en-php-gd-fonction-degrade-imagerie.html
|
||||||
|
private function degrade($img,$direction,$color1,$color2)
|
||||||
|
{
|
||||||
|
if($direction=='h') { $size = imagesx($img); $sizeinv = imagesy($img); }
|
||||||
|
else { $size = imagesy($img); $sizeinv = imagesx($img);}
|
||||||
|
$diffs = array(
|
||||||
|
(($color2[0]-$color1[0])/$size),
|
||||||
|
(($color2[1]-$color1[1])/$size),
|
||||||
|
(($color2[2]-$color1[2])/$size)
|
||||||
|
);
|
||||||
|
for($i=0;$i<$size;$i++)
|
||||||
|
{
|
||||||
|
$r = $color1[0]+($diffs[0]*$i);
|
||||||
|
$g = $color1[1]+($diffs[1]*$i);
|
||||||
|
$b = $color1[2]+($diffs[2]*$i);
|
||||||
|
if($direction=='h') { imageline($img,$i,0,$i,$sizeinv,imagecolorallocate($img,$r,$g,$b)); }
|
||||||
|
else { imageline($img,0,$i,$sizeinv,$i,imagecolorallocate($img,$r,$g,$b)); }
|
||||||
|
}
|
||||||
|
return $img;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function drawshape($image,$action,$color)
|
||||||
|
{
|
||||||
|
switch($action%7)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
ImageFilledRectangle ($image,$this->getX(),$this->getY(),$this->getX(),$this->getY(),$color);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
ImageFilledEllipse ($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(), $color);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
$points = array($this->getX(), $this->getY(), $this->getX(), $this->getY(), $this->getX(), $this->getY(),$this->getX(), $this->getY());
|
||||||
|
ImageFilledPolygon ($image, $points, 4, $color);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
$start=$this->getInt()*360/256; $end=$start+$this->getInt()*180/256;
|
||||||
|
ImageFilledArc ($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(),$start,$end,$color,IMG_ARC_PIE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,357 @@
|
||||||
|
/* ZeroBin 0.15 - http://sebsauvage.net/wiki/doku.php?id=php:zerobin */
|
||||||
|
|
||||||
|
/* Hé, t'as vu Idleman, j'ai fait un effort sur les CSS ! ;-) */
|
||||||
|
|
||||||
|
/* 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,ol,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));
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
font-size: 0.8em;
|
||||||
|
margin-bottom:15px;
|
||||||
|
padding-left:60px; padding-right:60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a { color:#0F388F; }
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size:3.5em;
|
||||||
|
font-weight:700;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
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;}
|
||||||
|
|
||||||
|
#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%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#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%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
button:disabled, .buttondisabled {
|
||||||
|
background:#ccc;
|
||||||
|
color:#888;
|
||||||
|
top:0px;
|
||||||
|
}
|
||||||
|
button img {
|
||||||
|
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 ? */
|
||||||
|
}
|
||||||
|
div#expiration select, div#language select {
|
||||||
|
color:#eee;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div#expiration select option, div#language select option {
|
||||||
|
color:#eee;
|
||||||
|
background: #414D5A;
|
||||||
|
background-color:#414D5A;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#remainingtime {
|
||||||
|
color: #94a3b4;
|
||||||
|
display:inline;
|
||||||
|
font-size:0.85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foryoureyesonly {
|
||||||
|
color: yellow !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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#ienotice a {
|
||||||
|
color:black;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#oldienotice {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.errorMessage {
|
||||||
|
background-color:#FF7979 !important;
|
||||||
|
color:#FF0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* --- discussion related CSS ------- */
|
||||||
|
|
||||||
|
|
||||||
|
div#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.comment input {
|
||||||
|
padding:2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea#replymessage {
|
||||||
|
margin-top:5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.commentmeta {
|
||||||
|
color: #fff;
|
||||||
|
background-color:#8EA0B2;
|
||||||
|
margin-bottom:3px;
|
||||||
|
padding:0px 0px 0px 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.commentdate {
|
||||||
|
color: #BFCEDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.vizhash {
|
||||||
|
width:16px;
|
||||||
|
height:16px;
|
||||||
|
position:relative;
|
||||||
|
top:2px;
|
||||||
|
left:-3px;
|
||||||
|
}
|
|
@ -0,0 +1,364 @@
|
||||||
|
/* ZeroBin 0.15 - http://sebsauvage.net/wiki/doku.php?id=php:zerobin */
|
||||||
|
|
||||||
|
// Immediately start random number generator collector.
|
||||||
|
sjcl.random.startCollectors();
|
||||||
|
|
||||||
|
// Converts a duration (in seconds) into human readable format.
|
||||||
|
function secondsToHuman(seconds)
|
||||||
|
{
|
||||||
|
if (seconds<60) { var v=Math.floor(seconds); return v+' second'+((v>1)?'s':''); }
|
||||||
|
if (seconds<60*60) { var v=Math.floor(seconds/60); return v+' minute'+((v>1)?'s':''); }
|
||||||
|
if (seconds<60*60*24) { var v=Math.floor(seconds/(60*60)); return v+' hour'+((v>1)?'s':''); }
|
||||||
|
// If less than 2 months, display in days:
|
||||||
|
if (seconds<60*60*24*60) { var v=Math.floor(seconds/(60*60*24)); return v+' day'+((v>1)?'s':''); }
|
||||||
|
var v=Math.floor(seconds/(60*60*24*30)); return v+' month'+((v>1)?'s':'');
|
||||||
|
}
|
||||||
|
// Compress a message (deflate compression). Returns base64 encoded data.
|
||||||
|
function compress(message) { return Base64.toBase64(RawDeflate.deflate(Base64.utob(message))); }
|
||||||
|
|
||||||
|
// Decompress a message compressed with compress().
|
||||||
|
function decompress(data) { return Base64.btou(RawDeflate.inflate(Base64.fromBase64(data))) }
|
||||||
|
|
||||||
|
// Compress, then encrypt message with key.
|
||||||
|
function zeroCipher(key,message)
|
||||||
|
{
|
||||||
|
return sjcl.encrypt(key,compress(message));
|
||||||
|
}
|
||||||
|
// Decrypt message with key, then decompress.
|
||||||
|
function zeroDecipher(key,data)
|
||||||
|
{
|
||||||
|
return decompress(sjcl.decrypt(key,data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the current script location (without search or hash part of the URL).
|
||||||
|
// eg. http://server.com/zero/?aaaa#bbbb --> http://server.com/zero/
|
||||||
|
function scriptLocation()
|
||||||
|
{
|
||||||
|
return window.location.href.substring(0,window.location.href.length
|
||||||
|
-window.location.search.length -window.location.hash.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the paste unique identifier from the URL
|
||||||
|
// eg. 'c05354954c49a487'
|
||||||
|
function pasteID()
|
||||||
|
{
|
||||||
|
return window.location.search.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set text of a DOM element (required for IE)
|
||||||
|
// This is equivalent to element.text(text)
|
||||||
|
// Input: element : a DOM element.
|
||||||
|
// text : the text to enter.
|
||||||
|
function setElementText(element,text)
|
||||||
|
{
|
||||||
|
if ($('div#oldienotice').is(":visible")) // For IE<10.
|
||||||
|
{
|
||||||
|
// 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>"));
|
||||||
|
}
|
||||||
|
else // for other (sane) browsers:
|
||||||
|
{
|
||||||
|
element.text(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show decrypted text in the display area, including discussion (if open)
|
||||||
|
// Input: messages (Array) : Array of messages to display (items = array with keys ('data','meta')
|
||||||
|
// key (string): decryption key
|
||||||
|
function displayMessages(key,comments)
|
||||||
|
{
|
||||||
|
try { // Try to decrypt the paste.
|
||||||
|
var cleartext = zeroDecipher(key,comments[0].data);
|
||||||
|
} catch(err) {
|
||||||
|
$('div#cleartext').hide();
|
||||||
|
$('button#clonebutton').hide();
|
||||||
|
showError('Could not decrypt data (Wrong key ?)');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setElementText($('div#cleartext'),cleartext);
|
||||||
|
urls2links($('div#cleartext')); // Convert URLs to clickable links.
|
||||||
|
|
||||||
|
// Display paste expiration.
|
||||||
|
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).
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the discussion is opened on this paste, display it.
|
||||||
|
if (comments[0].meta.opendiscussion)
|
||||||
|
{
|
||||||
|
$('div#comments').html('');
|
||||||
|
for (var i = 1; i < comments.length; i++) // For each comment.
|
||||||
|
{
|
||||||
|
var comment=comments[i];
|
||||||
|
var cleartext="[Could not decrypt comment ; Wrong key ?]";
|
||||||
|
try { cleartext = zeroDecipher(key,comment.data); } catch(err) { }
|
||||||
|
var place = $('div#comments');
|
||||||
|
// If parent comment exists, display below (CSS will automatically shift it right.)
|
||||||
|
var cname = 'div#comment_'+comment.meta.parentid
|
||||||
|
if ($(cname).length) place = $(cname); // If the element exists in page
|
||||||
|
var divComment = $('<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>');
|
||||||
|
setElementText(divComment.find('div.commentdata'),cleartext);
|
||||||
|
urls2links(divComment.find('div.commentdata')); // Convert URLs to clickable links in comment.
|
||||||
|
divComment.find('span.nickname').html('<i>(Anonymous)</i>');
|
||||||
|
// Try to get optional nickname:
|
||||||
|
try { divComment.find('span.nickname').text(zeroDecipher(key,comment.meta.nickname));} catch(err) { }
|
||||||
|
divComment.find('span.commentdate').text(' ('+(new Date(comment.meta.postdate*1000).toUTCString())+')').attr('title','CommentID: '+comment.meta.commentid);
|
||||||
|
// If an avatar is available, display it.
|
||||||
|
if (comment.meta.vizhash)
|
||||||
|
divComment.find('span.nickname').before('<img src="'+comment.meta.vizhash+'" class="vizhash" title="Anonymous avatar (Vizhash of the IP address)" />');
|
||||||
|
place.append(divComment);
|
||||||
|
}
|
||||||
|
$('div#comments').append('<div class="comment"><button onclick="open_reply($(this),\''+pasteID()+'\');return false;">Add comment</button></div>');
|
||||||
|
$('div#discussion').show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the comment entry when clicking the "Reply" button of a comment.
|
||||||
|
// source = element which emitted the event.
|
||||||
|
// commentid = identifier of the comment we want to reply to.
|
||||||
|
function open_reply(source,commentid)
|
||||||
|
{
|
||||||
|
$('div.reply').remove(); // Remove any other reply area.
|
||||||
|
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>'
|
||||||
|
+'</div>');
|
||||||
|
$('input#nickname').focus(function() {
|
||||||
|
$(this).css('color', '#000');
|
||||||
|
if($(this).val()==$(this).attr('title')) $(this).val('');
|
||||||
|
});
|
||||||
|
$('textarea#replymessage').focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a reply in a discussion.
|
||||||
|
// Input: parentid : the comment identifier we want to send a reply to.
|
||||||
|
function send_comment(parentid)
|
||||||
|
{
|
||||||
|
if ($('textarea#replymessage').val().length==0) return; // Do not send if no data.
|
||||||
|
showStatus('Sending comment...',spin=true);
|
||||||
|
var cipherdata=zeroCipher(pageKey(), $('textarea#replymessage').val());
|
||||||
|
var ciphernickname='';
|
||||||
|
var nick=$('input#nickname').val();
|
||||||
|
if (nick!='' && nick!='Optional nickname...') ciphernickname=ciphernickname=zeroCipher(pageKey(),nick);
|
||||||
|
var data_to_send = { data:cipherdata,
|
||||||
|
parentid: parentid,
|
||||||
|
pasteid: pasteID(),
|
||||||
|
nickname: ciphernickname
|
||||||
|
};
|
||||||
|
$.post(scriptLocation(), data_to_send ,'json' )
|
||||||
|
.error( function() { showError('Comment could not be sent (serveur error or not responding).'); } )
|
||||||
|
.success(function(data)
|
||||||
|
{
|
||||||
|
if (data.status==0)
|
||||||
|
{
|
||||||
|
showStatus('Comment posted.');
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
else if (data.status==1)
|
||||||
|
{
|
||||||
|
showError('Could not post comment: '+data.message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
showError('Could not post comment.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a new paste to server
|
||||||
|
function send_data()
|
||||||
|
{
|
||||||
|
if ($('textarea#message').val().length==0) return; // Do not send if no data.
|
||||||
|
showStatus('Sending paste...',spin=true);
|
||||||
|
var randomkey = sjcl.codec.base64.fromBits(sjcl.random.randomWords(8,0),0);
|
||||||
|
var cipherdata = zeroCipher(randomkey,$('textarea#message').val());
|
||||||
|
var data_to_send = { data:cipherdata,
|
||||||
|
expire:$('select#pasteExpiration').val(),
|
||||||
|
opendiscussion:$('input#opendiscussion').is(':checked')?1:0
|
||||||
|
};
|
||||||
|
$.post(scriptLocation(), data_to_send ,'json' )
|
||||||
|
.error( function() { showError('Data could not be sent (serveur error or not responding).'); } )
|
||||||
|
.success(function(data)
|
||||||
|
{
|
||||||
|
if (data.status==0)
|
||||||
|
{
|
||||||
|
stateExistingPaste();
|
||||||
|
var url=scriptLocation()+"?"+data.id+'#'+randomkey;
|
||||||
|
showStatus('');
|
||||||
|
$('div#pastelink').html('Your paste is <a href="'+url+'">'+url+'</a>');
|
||||||
|
$('div#pastelink').append(' <button id="shortenbutton" onclick="document.location=\''+shortenUrl(url)+'\'"><img src="lib/icon_shorten.png" width="13" height="15" />Shorten URL</button>').show();
|
||||||
|
setElementText($('div#cleartext'),$('textarea#message').val());
|
||||||
|
urls2links($('div#cleartext'));
|
||||||
|
showStatus('');
|
||||||
|
}
|
||||||
|
else if (data.status==1)
|
||||||
|
{
|
||||||
|
showError('Could not create paste: '+data.message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
showError('Could not create paste.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
$('textarea#message').text('');
|
||||||
|
$('textarea#message').show();
|
||||||
|
$('div#cleartext').hide();
|
||||||
|
$('div#message').focus();
|
||||||
|
$('div#discussion').hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put the screen in "Existing paste" mode.
|
||||||
|
function stateExistingPaste()
|
||||||
|
{
|
||||||
|
$('button#sendbutton').hide();
|
||||||
|
if (!$('div#oldienotice').is(":visible")) $('button#clonebutton').show(); // No "clone" for IE<10.
|
||||||
|
$('button#clonebutton').show();// FIXME
|
||||||
|
$('div#expiration').hide();
|
||||||
|
$('div#language').hide();
|
||||||
|
$('input#password').hide();
|
||||||
|
$('div#opendisc').hide();
|
||||||
|
$('button#newbutton').show();
|
||||||
|
$('div#pastelink').hide();
|
||||||
|
$('textarea#message').hide();
|
||||||
|
$('div#cleartext').show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone the current paste.
|
||||||
|
function clonePaste()
|
||||||
|
{
|
||||||
|
stateNewPaste();
|
||||||
|
showStatus('');
|
||||||
|
$('textarea#message').text($('div#cleartext').text());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new paste.
|
||||||
|
function newPaste()
|
||||||
|
{
|
||||||
|
stateNewPaste();
|
||||||
|
showStatus('');
|
||||||
|
$('textarea#message').text('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display an error message
|
||||||
|
// (We use the same function for paste and reply to comments)
|
||||||
|
function showError(message)
|
||||||
|
{
|
||||||
|
$('div#status').addClass('errorMessage').text(message);
|
||||||
|
$('div#replystatus').addClass('errorMessage').text(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display status
|
||||||
|
// (We use the same function for paste and reply to comments)
|
||||||
|
// message (string) = text to display
|
||||||
|
// spin (boolean, optional) = tell if the "spinning" animation should be displayed.
|
||||||
|
function showStatus(message,spin)
|
||||||
|
{
|
||||||
|
$('div#replystatus').removeClass('errorMessage');
|
||||||
|
$('div#replystatus').text(message);
|
||||||
|
if (!message) { $('div#status').html(' '); return; }
|
||||||
|
if (message=='') { $('div#status').html(' '); return; }
|
||||||
|
$('div#status').removeClass('errorMessage');
|
||||||
|
$('div#status').text(message);
|
||||||
|
if (spin)
|
||||||
|
{
|
||||||
|
var img = '<img src="lib/busy.gif" style="width:16px;height:9px;margin:0px 4px 0px 0px;" />';
|
||||||
|
$('div#status').prepend(img);
|
||||||
|
$('div#replystatus').prepend(img);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate link to URL shortener.
|
||||||
|
function shortenUrl(url)
|
||||||
|
{
|
||||||
|
return 'http://snipurl.com/site/snip?link='+encodeURIComponent(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert URLs to clickable links.
|
||||||
|
// Input: element : a jQuery DOM element.
|
||||||
|
// Example URLs to handle:
|
||||||
|
// magnet:?xt.1=urn:sha1:YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C&xt.2=urn:sha1:TXGCZQTH26NL6OUQAJJPFALHG2LTGBC7
|
||||||
|
// http://localhost:8800/zero/?6f09182b8ea51997#WtLEUO5Epj9UHAV9JFs+6pUQZp13TuspAUjnF+iM+dM=
|
||||||
|
// http://user:password@localhost:8800/zero/?6f09182b8ea51997#WtLEUO5Epj9UHAV9JFs+6pUQZp13TuspAUjnF+iM+dM=
|
||||||
|
// FIXME: add ppa & apt links.
|
||||||
|
function urls2links(element)
|
||||||
|
{
|
||||||
|
var re = /((http|https|ftp):\/\/[\w?=&.\/-;#@~%+-]+(?![\w\s?&.\/;#~%"=-]*>))/ig;
|
||||||
|
element.html(element.html().replace(re,'<a href="$1" rel="nofollow">$1</a>'));
|
||||||
|
var re = /((magnet):[\w?=&.\/-;#@~%+-]+)/ig;
|
||||||
|
element.html(element.html().replace(re,'<a href="$1">$1</a>'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the deciphering key stored in anchor part of the URL
|
||||||
|
function pageKey()
|
||||||
|
{
|
||||||
|
var key = window.location.hash.substring(1); // Get key
|
||||||
|
|
||||||
|
// Some stupid web 2.0 services and redirectors add data AFTER the anchor
|
||||||
|
// (such as &utm_source=...).
|
||||||
|
// We will strip any additional data.
|
||||||
|
|
||||||
|
// First, strip everything after the equal sign (=) which signals end of base64 string.
|
||||||
|
i = key.indexOf('='); if (i>-1) { key = key.substring(0,i+1); }
|
||||||
|
|
||||||
|
// If the equal sign was not present, some parameters may remain:
|
||||||
|
i = key.indexOf('&'); if (i>-1) { key = key.substring(0,i); }
|
||||||
|
|
||||||
|
// Then add trailing equal sign if it's missing
|
||||||
|
if (key.charAt(key.length-1)!=='=') key+='=';
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
$('select#pasteExpiration').change(function() {
|
||||||
|
if ($(this).val()=='burn') { $('div#opendisc').addClass('buttondisabled'); $('input#opendiscussion').attr('disabled',true); }
|
||||||
|
else { $('div#opendisc').removeClass('buttondisabled'); $('input#opendiscussion').removeAttr('disabled'); }
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if ($('div#cipherdata').text().length>1) // Display an existing paste
|
||||||
|
{
|
||||||
|
if (window.location.hash.length==0) // Missing decryption key in URL ?
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
var messages = jQuery.parseJSON($('div#cipherdata').text()); // List of messages to display
|
||||||
|
stateExistingPaste(); // Show proper elements on screen.
|
||||||
|
displayMessages(pageKey(),messages);
|
||||||
|
}
|
||||||
|
else if ($('div#errormessage').text().length>1) // Display error message from php code.
|
||||||
|
{
|
||||||
|
showError($('div#errormessage').text());
|
||||||
|
}
|
||||||
|
else // Create a new paste.
|
||||||
|
{
|
||||||
|
newPaste();
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,81 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>ZeroBin</title>
|
||||||
|
<link type="text/css" rel="stylesheet" href="lib/zerobin.css?{$VERSION|rawurlencode}#" />
|
||||||
|
<script src="lib/jquery.js#"></script>
|
||||||
|
<script src="lib/sjcl.js#"></script>
|
||||||
|
<script src="lib/base64.js#"></script>
|
||||||
|
<script src="lib/rawdeflate.js#"></script>
|
||||||
|
<script src="lib/rawinflate.js#"></script>
|
||||||
|
<script src="lib/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="lib/icon_new.png#" width="11" height="15" />New</button>
|
||||||
|
<button id="sendbutton" onclick="send_data();return false;" style="display:none;"><img src="lib/icon_send.png#" width="18" height="15" />Send</button>
|
||||||
|
<button id="clonebutton" onclick="clonePaste();return false;" style="display:none;"><img src="lib/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="10min">10 minutes</option>
|
||||||
|
<option value="1hour">1 hour</option>
|
||||||
|
<option value="1day">1 day</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" />
|
||||||
|
<label for="opendiscussion">Open discussion</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="pastelink" style="display:none;"></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>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue