public function Prepend() { if (!empty($_POST['data'])) { /* 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,5min,10min,1hour,1day,1week,1month,1year,burn) (default:never) opendiscusssion (optional) = is the discussion allowed on this paste ? (0/1) (default:0) syntaxcoloring (optional) = should this paste use syntax coloring when displaying. 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(PLX_ROOT . 'data/zb')) { mkdir(PLX_ROOT . 'data/zb', 0705); file_put_contents(PLX_ROOT . 'data/zb/.htaccess', "Allow from none\nDeny from all\n", LOCK_EX); } // Make sure last paste from the IP address was more than 10 seconds ago. if (!cmp_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 (!cmp_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 == '5min') { $meta['expire_date'] = time() + 5 * 60; } elseif ($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 == '1week') { $meta['expire_date'] = time() + 7 * 24 * 60 * 60; } elseif ($expire == '1month') { $meta['expire_date'] = time() + 30 * 24 * 60 * 60; } elseif ($expire == '1year') { $meta['expire_date'] = time() + 365 * 24 * 60 * 60; } } // Destroy the paste when it is read. if (!empty($_POST['burnafterreading'])) { $burnafterreading = $_POST['burnafterreading']; if ($burnafterreading != '0' && $burnafterreading != '1') { $error = true; } if ($burnafterreading != '0') { $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; } } // Should we use syntax coloring when displaying ? if (!empty($_POST['syntaxcoloring'])) { $syntaxcoloring = $_POST['syntaxcoloring']; if ($syntaxcoloring != '0' && $syntaxcoloring != '1') { $error = true; } if ($syntaxcoloring != '0') { $meta['syntaxcoloring'] = 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 (!cmp_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 cmp_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) { $pasteid = $_POST['pasteid']; $parentid = $_POST['parentid']; if (!preg_match('/\\A[a-f\\d]{16}\\z/', $pasteid)) { echo json_encode(array('status' => 1, 'message' => 'Invalid data.')); exit; } if (!preg_match('/\\A[a-f\\d]{16}\\z/', $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']); unset($storage['syntaxcoloring']); // Make sure paste exists. $storagedir = cmp_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 = cmp_dataid2discussionpath($pasteid); $filename = $pasteid . '.' . $dataid . '.' . $parentid; if (!is_dir($discdir)) { mkdir($discdir, $mode = 0705, $recursive = true); } if (is_file($discdir . $filename)) { echo json_encode(array('status' => 1, 'message' => 'You are unlucky. Try again.')); exit; } file_put_contents($discdir . $filename, json_encode($storage), LOCK_EX); echo json_encode(array('status' => 0, 'id' => $dataid)); // 0 = no error exit; } else { $storagedir = cmp_dataid2path($dataid); if (!is_dir($storagedir)) { mkdir($storagedir, $mode = 0705, $recursive = true); } if (is_file($storagedir . $dataid)) { echo json_encode(array('status' => 1, 'message' => 'You are unlucky. Try again.')); exit; } // New paste file_put_contents($storagedir . $dataid, json_encode($storage), LOCK_EX); // Generate the "delete" token. // The token is the hmac of the pasteid signed with the server salt. // The paste can be delete by calling http://myserver.com/zerobin/?pasteid=<pasteid>&deletetoken=<deletetoken> $deletetoken = hash_hmac('sha1', $dataid, cmp_getServerSalt()); echo json_encode(array('status' => 0, 'id' => $dataid, 'deletetoken' => $deletetoken)); // 0 = no error exit; } echo json_encode(array('status' => 1, 'message' => 'Server error.')); exit; } }
function __construct() { $this->width = 16; $this->height = 16; $this->salt = cmp_getServerSalt(); }