Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ data/
tmp/
# Ignore for safety
.htaccess
.htpasswd
.htpasswd
config.inc.php
4 changes: 4 additions & 0 deletions config.inc.php.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?php

// Set translation language
$language='fr';
65 changes: 47 additions & 18 deletions index.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
require_once "lib/serversalt.php";
require_once "lib/vizhash_gd_zero.php";

// Load config.inc.php file if exists
if (file_exists('config.inc.php')) include('config.inc.php');

// In case stupid admin has left magic_quotes enabled in php.ini:
if (get_magic_quotes_gpc())
{
Expand All @@ -17,6 +20,26 @@ function stripslashes_deep($value) { $value = is_array($value) ? array_map('stri
$_COOKIE = array_map('stripslashes_deep', $_COOKIE);
}

// Manage translation
$js_lang_file="";


if (isset($language)) {
if (file_exists("lang/".$language.".php")) {
include "lang/".$language.".php";
}
if (file_exists("lang/".$language.".js")) {
$js_lang_file="lang/".$language.".js";
}
}

/*Take a string in paramater and if a translation exist return the string translated*/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

he she it ....

function translate($str, $modifier = null) {
global $lang;
if (isset($lang[$str])) return $lang[$str];
return $str;
}

// 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)
Expand Down Expand Up @@ -158,16 +181,16 @@ function deletePaste($pasteid)

// 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; }
{ echo json_encode(array('status'=>1,'message'=>translate('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; }
{ echo json_encode(array('status'=>1,'message'=>translate('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; }
{ echo json_encode(array('status'=>1,'message'=>translate('Invalid data.'))); exit; }

// Read additional meta-information.
$meta=array();
Expand Down Expand Up @@ -237,7 +260,7 @@ function deletePaste($pasteid)

if ($error)
{
echo json_encode(array('status'=>1,'message'=>'Invalid data.'));
echo json_encode(array('status'=>1,'message'=>translate('Invalid data.')));
exit;
}

Expand All @@ -255,27 +278,27 @@ function deletePaste($pasteid)
{
$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; }
if (!preg_match('/\A[a-f\d]{16}\z/',$pasteid)) { echo json_encode(array('status'=>1,'message'=>translate('Invalid data.'))); exit; }
if (!preg_match('/\A[a-f\d]{16}\z/',$parentid)) { echo json_encode(array('status'=>1,'message'=>translate('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 = dataid2path($pasteid);
if (!is_file($storagedir.$pasteid)) { echo json_encode(array('status'=>1,'message'=>'Invalid data.')); exit; }
if (!is_file($storagedir.$pasteid)) { echo json_encode(array('status'=>1,'message'=>translate('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; }
if (!$paste->meta->opendiscussion) { echo json_encode(array('status'=>1,'message'=>translate('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.'));
echo json_encode(array('status'=>1,'message'=>translate('You are unlucky. Try again.')));
exit;
}

Expand All @@ -289,7 +312,7 @@ function deletePaste($pasteid)
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.'));
echo json_encode(array('status'=>1,'message'=>translate('You are unlucky. Try again.')));
exit;
}
// New paste
Expand All @@ -304,36 +327,39 @@ function deletePaste($pasteid)
exit;
}

echo json_encode(array('status'=>1,'message'=>'Server error.'));
echo json_encode(array('status'=>1,'message'=>translate('Server error.')));
exit;
}


/* Process a paste deletion request.
Returns an array ('',$ERRORMESSAGE,$STATUS)
*/

function processPasteDelete($pasteid,$deletetoken)
{
if (preg_match('/\A[a-f\d]{16}\z/',$pasteid)) // Is this a valid paste identifier ?
{
$filename = dataid2path($pasteid).$pasteid;
if (!is_file($filename)) // Check that paste exists.
{
return array('','Paste does not exist, has expired or has been deleted.','');
return array('',translate('Paste does not exist, has expired or has been deleted.'),'');
}
}
else
{
return array('','Invalid data','');
return array('',translate('Invalid data'),'');
}

if (!slow_equals($deletetoken, hash_hmac('sha1', $pasteid , getServerSalt()))) // Make sure token is valid.
{
return array('','Wrong deletion token. Paste was not deleted.','');
return array('',translate('Wrong deletion token. Paste was not deleted.'),'');
}

// Paste exists and deletion token is valid: Delete the paste.
deletePaste($pasteid);
return array('','','Paste was properly deleted.');
//return array('','','Paste was properly deleted.');
return array('','',translate('Paste was properly deleted.'));
}

/* Process a paste fetch request.
Expand All @@ -346,12 +372,12 @@ function processPasteFetch($pasteid)
$filename = dataid2path($pasteid).$pasteid;
if (!is_file($filename)) // Check that paste exists.
{
return array('','Paste does not exist, has expired or has been deleted.','');
return array('',translate('Paste does not exist, has expired or has been deleted.'),'');
}
}
else
{
return array('','Invalid data','');
return array('',translate('Invalid data'),'');
}

// Get the paste itself.
Expand All @@ -361,7 +387,7 @@ function processPasteFetch($pasteid)
if (isset($paste->meta->expire_date) && $paste->meta->expire_date<time())
{
deletePaste($pasteid); // Delete the paste
return array('','Paste does not exist, has expired or has been deleted.','');
return array('',translate('Paste does not exist, has expired or has been deleted.'),'');
}


Expand Down Expand Up @@ -425,5 +451,8 @@ function processPasteFetch($pasteid)
$page->assign('VERSION',$VERSION);
$page->assign('ERRORMESSAGE',$ERRORMESSAGE);
$page->assign('STATUS',$STATUS);

$page->assign('lang_file',$js_lang_file);

$page->draw('page');
?>
61 changes: 35 additions & 26 deletions js/zerobin.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
* @author sebsauvage
*/

function translate(msg) {
if (typeof(lang) == "object" && typeof(lang[msg]) == "string") return lang[msg];
return msg;
}

// Immediately start random number generator collector.
sjcl.random.startCollectors();

Expand All @@ -16,12 +21,15 @@ sjcl.random.startCollectors();
*/
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':''); }
//FIXME add optionnal s at the end of time word according to the language
//set two version plural et singular and set a flag for the use of one or another
if (seconds<60) { var v=Math.floor(seconds); return v+' '+translate('second')+((v>1)?'s':''); }
if (seconds<60*60) { var v=Math.floor(seconds/60); return v+' '+translate('minute')+((v>1)?'s':''); }
if (seconds<60*60*24) { var v=Math.floor(seconds/(60*60)); return v+' '+translate('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':'');
if (seconds<60*60*24*60) { var v=Math.floor(seconds/(60*60*24)); return v+' '+translate('day')+((v>1)?'s':''); }
//FIXME if french add exeption for month
var v=Math.floor(seconds/(60*60*24*30)); return v+' '+translate('month')+((v>1)?'s':'');
}

/**
Expand Down Expand Up @@ -195,7 +203,7 @@ function displayMessages(key, comments) {
} catch(err) {
$('div#cleartext').hide();
$('button#clonebutton').hide();
showError('Could not decrypt data (Wrong key ?)');
showError(translate('Could not decrypt data (Wrong key ?)'));
return;
}
setElementText($('div#cleartext'), cleartext);
Expand All @@ -206,9 +214,9 @@ function displayMessages(key, comments) {
if (comments[0].meta.syntaxcoloring) applySyntaxColoring();

// 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.expire_date) $('div#remainingtime').removeClass('foryoureyesonly').text(translate('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();
$('div#remainingtime').addClass('foryoureyesonly').text(translate('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).
}

Expand All @@ -232,7 +240,7 @@ function displayMessages(key, comments) {
}
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>'
+ '<button onclick="open_reply($(this),\'' + comment.meta.commentid + '\');return false;">'+translate('Reply')+'</button>'
+ '</div>');
setElementText(divComment.find('div.commentdata'), cleartext);
// Convert URLs to clickable links in comment.
Expand All @@ -252,7 +260,7 @@ function displayMessages(key, comments) {

place.append(divComment);
}
$('div#comments').append('<div class="comment"><button onclick="open_reply($(this),\'' + pasteID() + '\');return false;">Add comment</button></div>');
$('div#comments').append('<div class="comment"><button onclick="open_reply($(this),\'' + pasteID() + '\');return false;">'+translate('Add comment')+'</button></div>');
$('div#discussion').show();
}
}
Expand All @@ -265,9 +273,9 @@ function displayMessages(key, comments) {
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..." />'
+ '<input type="text" id="nickname" title="Optional nickname..." value="'+translate('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>'
+ '<br><button id="replybutton" onclick="send_comment(\'' + commentid + '\');return false;">'+translate('Post comment')+'</button>'
+ '<div id="replystatus">&nbsp;</div>'
+ '</div>');
$('input#nickname').focus(function() {
Expand All @@ -289,11 +297,11 @@ function send_comment(parentid) {
return;
}

showStatus('Sending comment...', spin=true);
showStatus(translate('Sending comment')+'...', spin=true);
var cipherdata = zeroCipher(pageKey(), $('textarea#replymessage').val());
var ciphernickname = '';
var nick=$('input#nickname').val();
if (nick != '' && nick != 'Optional nickname...') {
if (nick != '' && nick != translate('Optional nickname')+'...') {
ciphernickname = zeroCipher(pageKey(), nick);
}
var data_to_send = { data:cipherdata,
Expand All @@ -304,18 +312,18 @@ function send_comment(parentid) {

$.post(scriptLocation(), data_to_send, 'json')
.error(function() {
showError('Comment could not be sent (serveur error or not responding).');
showError(translate('Comment could not be sent (serveur error or not responding).'));
})
.success(function(data) {
if (data.status == 0) {
showStatus('Comment posted.');
showStatus(translate('Comment posted.'));
location.reload();
}
else if (data.status==1) {
showError('Could not post comment: '+data.message);
showError(translate('Could not post comment')+': '+data.message);
}
else {
showError('Could not post comment.');
showError(translate('Could not post comment')+'.');
}
});
}
Expand All @@ -333,12 +341,12 @@ function send_data() {
// If sjcl has not collected enough entropy yet, display a message.
if (!sjcl.random.isReady())
{
showStatus('Sending paste (Please move your mouse for more entropy)...', spin=true);
showStatus(translate('Sending paste (Please move your mouse for more entropy)'+'...'), spin=true);
sjcl.random.addEventListener('seeded', function(){ send_data(); });
return;
}

showStatus('Sending paste...', spin=true);
showStatus(translate('Sending paste'+'...'), spin=true);

var randomkey = sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 0), 0);
var cipherdata = zeroCipher(randomkey, $('textarea#message').val());
Expand All @@ -350,7 +358,7 @@ function send_data() {
};
$.post(scriptLocation(), data_to_send, 'json')
.error(function() {
showError('Data could not be sent (serveur error or not responding).');
showError(translate('Data could not be sent (serveur error or not responding)')+'.');
})
.success(function(data) {
if (data.status == 0) {
Expand All @@ -359,8 +367,8 @@ function send_data() {
var deleteUrl = scriptLocation() + "?pasteid=" + data.id + '&deletetoken=' + data.deletetoken;
showStatus('');

$('div#pastelink').html('Your paste is <a id="pasteurl" href="' + url + '">' + url + '</a> <span id="copyhint">(Hit CTRL+C to copy)</span>');
$('div#deletelink').html('<a href="' + deleteUrl + '">Delete link</a>');
$('div#pastelink').html(translate('Your paste is')+' <a id="pasteurl" href="' + url + '">' + url + '</a> <span id="copyhint">('+translate('Hit CTRL+C to copy')+')</span>');
$('div#deletelink').html('<a href="' + deleteUrl + '">'+translate('Delete link')+'</a>');
$('div#pasteresult').show();
selectText('pasteurl'); // We pre-select the link so that the user only has to CTRL+C the link.

Expand All @@ -373,10 +381,10 @@ function send_data() {
showStatus('');
}
else if (data.status==1) {
showError('Could not create paste: '+data.message);
showError(translate('Could not create paste')+': '+data.message);
}
else {
showError('Could not create paste.');
showError(translate('Could not create paste')+'.');
}
});
}
Expand Down Expand Up @@ -486,6 +494,7 @@ function newPaste() {
* (We use the same function for paste and reply to comments)
*/
function showError(message) {
message=translate(message);
$('div#status').addClass('errorMessage').text(message);
$('div#replystatus').addClass('errorMessage').text(message);
}
Expand Down Expand Up @@ -585,7 +594,7 @@ $(function() {
if ($('div#cipherdata').text().length > 1) {
// Missing decryption key in URL ?
if (window.location.hash.length == 0) {
showError('Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL ?)');
showError(translate('Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL ?)'));
return;
}

Expand Down
Loading