Просмотр исходного кода

Merge branch 'master' into jsrefactor and fixing baseUri unit test

El RIDO 9 лет назад
Родитель
Сommit
fb99d5bb93
13 измененных файлов с 195 добавлено и 51 удалено
  1. 2 1
      CHANGELOG.md
  2. 1 0
      CREDITS.md
  3. 1 1
      i18n/es.json
  4. 151 0
      i18n/pt.json
  5. 24 10
      js/privatebin.js
  6. 9 0
      js/test.js
  7. 0 15
      lib/Filter.php
  8. 1 1
      lib/I18n.php
  9. 2 2
      lib/PrivateBin.php
  10. 0 7
      lib/Request.php
  11. 2 3
      tpl/bootstrap.php
  12. 2 3
      tpl/page.php
  13. 0 8
      tst/FilterTest.php

+ 2 - 1
CHANGELOG.md

@@ -1,8 +1,9 @@
 # PrivateBin version history
 
   * **next (not yet released)**
-    * ADDED: Translations for Spanish, Occitan and Norwegian
+    * ADDED: Translations for Spanish, Occitan, Norwegian and Portuguese
     * ADDED: Option in configuration to change the default "PrivateBin" title of the site
+    * CHANGED: Minimum required PHP version is 5.4 (#186)
     * CHANGED: Cleanup of bootstrap template variants and moved icons to `img` directory
   * **1.1 (2016-12-26)**
     * ADDED: Translations for Italian and Russian

+ 1 - 0
CREDITS.md

@@ -35,3 +35,4 @@ Sébastien Sauvage - original idea and main developer
 * Alfredo Fabián Altamirano Tena - Spanish
 * Quent-in - Occitan
 * idarlund - Norwegian
+* Tulio Leao - Portuguese

+ 1 - 1
i18n/es.json

@@ -10,7 +10,7 @@
     "%s requires php 5.3.0 or above to work. Sorry.":
         "%s requiere php 5.3.0 o superior para funcionar. Lo siento.",
     "%s requires configuration section [%s] to be present in configuration file.":
-        "%s requiere que la sección de configuración [% s] esté presente en el archivo de configuración.",
+        "%s requiere que la sección de configuración [%s] esté presente en el archivo de configuración.",
     "Please wait %d seconds between each post.":
         "Por favor espere %d segundos entre cada publicación.",
     "Paste is limited to %s of encrypted data.":

+ 151 - 0
i18n/pt.json

@@ -0,0 +1,151 @@
+{
+    "PrivateBin": "PrivateBin",
+    "%s is a minimalist, open source 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=\"https://privatebin.info/\">project page</a>.":
+        "%s é um serviço minimalista e de código aberto do tipo \"pastebin\", em que o servidor tem zero conhecimento dos dados copiados. Os dados são cifrados e decifrados <i>no navegador</i> usando 256 bits AES. Mais informações na <a href=\"https://privatebin.info/\">página do projeto</a>.",
+    "Because ignorance is bliss":
+        "Porque a ignorância é uma benção",
+    "en": "pt",
+    "Paste does not exist, has expired or has been deleted.":
+        "A cópia não existe, expirou ou já foi excluída.",
+    "%s requires php 5.3.0 or above to work. Sorry.":
+        "%s requer php 5.3.0 ou superior para funcionar. Desculpa.",
+    "%s requires configuration section [%s] to be present in configuration file.":
+        "%s requer que a seção de configuração [% s] esteja no arquivo de configuração.",
+    "Please wait %d seconds between each post.":
+        "Por favor espere %d segundos entre cada publicação.",
+    "Paste is limited to %s of encrypted data.":
+        "A cópia está limitada a %s de dados cifrados.",
+    "Invalid data.":
+        "Dados inválidos.",
+    "You are unlucky. Try again.":
+        "Você é azarado. Tente novamente",
+    "Error saving comment. Sorry.":
+        "Erro ao salvar comentário. Desculpa.",
+    "Error saving paste. Sorry.":
+        "Erro ao salvar cópia. Desculpa.",
+    "Invalid paste ID.":
+        "ID de cópia inválido.",
+    "Paste is not of burn-after-reading type.":
+        "Cópia não é do tipo \"queime após ler\".",
+    "Wrong deletion token. Paste was not deleted.":
+        "Token de remoção inválido. A cópia não foi excluída.",
+    "Paste was properly deleted.":
+        "A cópia foi devidamente excluída.",
+    "JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
+        "JavaScript é necessário para que %s funcione.<br />Pedimos desculpas pela inconveniência.",
+    "%s requires a modern browser to work.":
+        "%s requer um navegador moderno para funcionar.",
+    "Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
+        "Ainda usando Internet Explorer? Faça-se um favor, mude para um navegador moderno:",
+    "New":
+        "Novo",
+    "Send":
+        "Enviar",
+    "Clone":
+        "Clonar",
+    "Raw text":
+        "Texto sem formato",
+    "Expires":
+        "Expirar em",
+    "Burn after reading":
+        "Queime após ler",
+    "Open discussion":
+        "Discussão aberta",
+    "Password (recommended)":
+        "Senha (recomendada)",
+    "Discussion":
+        "Discussão",
+    "Toggle navigation":
+        "Mudar navegação",
+    "%d seconds": ["%d segundo", "%d segundos"],
+    "%d minutes": ["%d minuto", "%d minutos"],
+    "%d hours": ["%d hora", "%d horas"],
+    "%d days": ["%d dia", "%d dias"],
+    "%d weeks": ["%d semana", "%d semanas"],
+    "%d months": ["%d mês", "%d meses"],
+    "%d years": ["%d ano", "%d anos"],
+    "Never":
+        "Nunca",
+    "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.":
+        "Nota: Este é um serviço de teste. Dados podem ser perdidos a qualquer momento. Gatinhos morrerão se você abusar desse serviço.",
+    "This document will expire in %d seconds.":
+        ["Este documento irá expirar em um segundo.", "Este documento irá expirar em %d segundos."],
+    "This document will expire in %d minutes.":
+        ["Este documento irá expirar em um minuto.", "Este documento irá expirar em %d minutos."],
+    "This document will expire in %d hours.":
+        ["Este documento irá expirar em uma hora.", "Este documento irá expirar em %d horas."],
+    "This document will expire in %d days.":
+        ["Este documento irá expirar em um dia.", "Este documento irá expirar em %d dias."],
+    "This document will expire in %d months.":
+        ["Este documento irá expirar em um mês.", "Este documento irá expirar em %d meses."],
+    "Please enter the password for this paste:":
+        "Por favor, digite a senha para essa cópia:",
+    "Could not decrypt data (Wrong key?)":
+        "Não foi possível decifrar os dados (Chave errada?)",
+    "Could not delete the paste, it was not stored in burn after reading mode.":
+        "Não foi possível excluir a cópia, ela não foi salva no modo de \"queime após ler\".",
+    "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.":
+        "APENAS PARA SEUS OLHOS. Não feche essa janela, essa mensagem não pode ser exibida novamente.",
+    "Could not decrypt comment; Wrong key?":
+        "Não foi possível decifrar o comentário; Chave errada?",
+    "Reply":
+        "Responder",
+    "Anonymous":
+        "Anônimo",
+    "Avatar generated from IP address":
+        "Avatar (do endereço IP)",
+    "Add comment":
+        "Adicionar comentário",
+    "Optional nickname…":
+        "Apelido opcional…",
+    "Post comment":
+        "Publicar comentário",
+    "Sending comment…":
+        "Enviando comentário…",
+    "Comment posted.":
+        "Comentário publicado.",
+    "Could not refresh display: %s":
+        "Não foi possível atualizar a tela: %s",
+    "unknown status":
+        "Estado desconhecido",
+    "server error or not responding":
+        "Servidor em erro ou não responsivo",
+    "Could not post comment: %s":
+        "Não foi possível publicar o comentário: %s",
+    "Please move your mouse for more entropy…":
+        "Por favor, mova o mouse para maior entropia…",
+    "Sending paste…":
+        "Enviando cópia…",
+    "Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
+        "Sua cópia é <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Pressione [Ctrl]+[c] para copiar)</span>",
+    "Delete data":
+        "Excluir dados",
+    "Could not create paste: %s":
+        "Não foi possível criar cópia: %s",
+    "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)":
+        "Não foi possível decifrar a cópia: chave de decriptografia ausente na URL (Você utilizou um redirecionador ou encurtador de URL que removeu parte dela?)",
+    "Format": "Formato",
+    "Plain Text": "Texto sem formato",
+    "Source Code": "Código fonte",
+    "Markdown": "Markdown",
+    "Download attachment": "Baixar anexo",
+    "Cloned: '%s'": "Clonado: '%s'",
+    "Attach a file": "Anexar um arquivo",
+    "Remove attachment": "Remover anexo",
+    "Your browser does not support uploading encrypted files. Please use a newer browser.":
+        "Seu navegador não permite subir arquivos cifrados. Por favor, utilize um navegador mais recente.",
+    "Invalid attachment.": "Anexo inválido.",
+    "Options": "Opções",
+    "Shorten URL": "Encurtar URL",
+    "Editor": "Editor",
+    "Preview": "Visualizar",
+    "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.":
+        "%s requer que o PATH termine em \"%s\". Por favor, atualize o PATH em seu index.php.",
+    "Decrypt":
+        "Decifrar",
+    "Enter password":
+        "Digite a senha",
+    "Loading…": "Carregando…",
+    "In case this message never disappears please have a look at <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">this FAQ for information to troubleshoot</a>.":
+        "Caso essa mensagem nunca desapareça, por favor veja <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">este FAQ para saber como resolver os problemas</a>."
+}

+ 24 - 10
js/privatebin.js

@@ -36,11 +36,9 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
     /**
      * static Helper methods
      *
-     * @param  {object} window
-     * @param  {object} document
      * @class
      */
-    var Helper = (function (window, document) {
+    var Helper = (function () {
         var me = {};
 
         /**
@@ -278,14 +276,19 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
                 return baseUri;
             }
 
-            // get official base uri string, from base tag in head of HTML
-            baseUri = document.baseURI;
+            // window.baseURI isn't emulated by JSdom
+            var loc = window.location;
+            baseUri = loc.href.substring(
+                0,
+                loc.href.length - loc.search.length - loc.hash.length
+            );
 
             // if base uri contains query string (when no base tag is present),
             // it is unwanted
-            if (baseUri.indexOf('?')) {
+            var queryIndex = baseUri.indexOf('?');
+            if (queryIndex !== -1) {
                 // so we built our own baseuri
-                baseUri = window.location.origin + window.location.pathname;
+                baseUri = baseUri.substring(0, queryIndex);
             }
 
             return baseUri;
@@ -307,8 +310,19 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
                 });
         }
 
+        /**
+         * resets state, used for unit testing
+         *
+         * @name   Model.reset
+         * @function
+         */
+        me.reset = function()
+        {
+            baseUri = null;
+        }
+
         return me;
-    })(window, document);
+    })();
 
     /**
      * internationalization module
@@ -336,7 +350,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
          * @prop   {string[]}
          * @readonly
          */
-        var supportedLanguages = ['de', 'es', 'fr', 'it', 'no', 'pl', 'oc', 'ru', 'sl', 'zh'];
+        var supportedLanguages = ['de', 'es', 'fr', 'it', 'no', 'pl', 'pt', 'oc', 'ru', 'sl', 'zh'];
 
         /**
          * built in language
@@ -491,7 +505,7 @@ jQuery.PrivateBin = function($, sjcl, Base64, RawDeflate) {
                     return (n % 10 === 1 && n % 100 !== 11 ? 0 : (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2));
                 case 'sl':
                     return (n % 100 === 1 ? 1 : (n % 100 === 2 ? 2 : (n % 100 === 3 || n % 100 === 4 ? 3 : 0)));
-                // de, en, es, it, no
+                // de, en, es, it, no, pt
                 default:
                     return (n !== 1 ? 1 : 0);
             }

+ 9 - 0
js/test.js

@@ -67,6 +67,10 @@ describe('Helper', function () {
     });
 
     describe('baseUri', function () {
+        before(function () {
+            $.PrivateBin.Helper.reset();
+        });
+
         jsc.property(
             'returns the URL without query & fragment',
             jsc.nearray(jsc.elements(a2zString)),
@@ -77,6 +81,7 @@ describe('Helper', function () {
                 var expected = schema.join('') + '://' + address.join('') + '/',
                     clean = jsdom('', {url: expected + '?' + query.join('') + '#' + fragment}),
                     result = $.PrivateBin.Helper.baseUri();
+                $.PrivateBin.Helper.reset();
                 clean();
                 return expected === result;
             }
@@ -101,6 +106,10 @@ describe('Helper', function () {
 
 describe('Model', function () {
     describe('getPasteId', function () {
+        before(function () {
+            $.PrivateBin.Model.reset();
+        });
+
         jsc.property(
             'returns the query string without separator, if any',
             jsc.nearray(jsc.elements(a2zString)),

+ 0 - 15
lib/Filter.php

@@ -21,21 +21,6 @@ use Exception;
  */
 class Filter
 {
-    /**
-     * strips slashes deeply
-     *
-     * @access public
-     * @static
-     * @param  mixed $value
-     * @return mixed
-     */
-    public static function stripslashesDeep($value)
-    {
-        return is_array($value) ?
-            array_map('self::stripslashesDeep', $value) :
-            stripslashes($value);
-    }
-
     /**
      * format a given time string into a human readable label (localized)
      *

+ 1 - 1
lib/I18n.php

@@ -304,7 +304,7 @@ class I18n
                 return $n % 10 == 1 && $n % 100 != 11 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
             case 'sl':
                 return $n % 100 == 1 ? 1 : ($n % 100 == 2 ? 2 : ($n % 100 == 3 || $n % 100 == 4 ? 3 : 0));
-            // de, en, es, it, no
+            // de, en, es, it, no, pt
             default:
                 return $n != 1 ? 1 : 0;
         }

+ 2 - 2
lib/PrivateBin.php

@@ -120,8 +120,8 @@ class PrivateBin
      */
     public function __construct()
     {
-        if (version_compare(PHP_VERSION, '5.3.0') < 0) {
-            throw new Exception(I18n::_('%s requires php 5.3.0 or above to work. Sorry.', I18n::_('PrivateBin')), 1);
+        if (version_compare(PHP_VERSION, '5.4.0') < 0) {
+            throw new Exception(I18n::_('%s requires php 5.4.0 or above to work. Sorry.', I18n::_('PrivateBin')), 1);
         }
         if (strlen(PATH) < 0 && substr(PATH, -1) !== DIRECTORY_SEPARATOR) {
             throw new Exception(I18n::_('%s requires the PATH to end in a "%s". Please update the PATH in your index.php.', I18n::_('PrivateBin'), DIRECTORY_SEPARATOR), 5);

+ 0 - 7
lib/Request.php

@@ -80,13 +80,6 @@ class Request
      */
     public function __construct()
     {
-        // in case stupid admin has left magic_quotes enabled in php.ini (for PHP < 5.4)
-        if (version_compare(PHP_VERSION, '5.4.0') < 0 && get_magic_quotes_gpc()) {
-            $_POST   = array_map('PrivateBin\\Filter::stripslashesDeep', $_POST);
-            $_GET    = array_map('PrivateBin\\Filter::stripslashesDeep', $_GET);
-            $_COOKIE = array_map('PrivateBin\\Filter::stripslashesDeep', $_COOKIE);
-        }
-
         // decide if we are in JSON API or HTML context
         $this->_isJsonApi = $this->_detectJsonRequest();
 

+ 2 - 3
tpl/bootstrap.php

@@ -69,7 +69,7 @@ if ($MARKDOWN):
 <?php
 endif;
 ?>
-		<script type="text/javascript" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-iGFkRUeioseXBM4QLP9xFBK9RaGHPqTnl4NgVhjw0wm0xURcjpL5HE9WP+XJRY0UF3VbIoiuyFXSp0JpxSbc+A==" crossorigin="anonymous"></script>
+		<script type="text/javascript" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-BqQUrn7gw41w/GPvE28nN9ANnl59EAuo0xdcfzSIkw/b/SzT7WF0PS1SNs4hSc6hU6S1eJzS8qjgOI+8qt//RQ==" crossorigin="anonymous"></script>
 		<!--[if lt IE 10]>
 		<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
 		<![endif]-->
@@ -406,8 +406,7 @@ endif;
 				<div id="ienotice" role="alert" class="hidden alert alert-<?php echo $isDark ? 'error' : 'warning'; ?>"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span><?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'), PHP_EOL; ?>
 					<a href="https://www.mozilla.org/firefox/">Firefox</a>,
 					<a href="https://www.opera.com/">Opera</a>,
-					<a href="https://www.google.com/chrome">Chrome</a>,
-					<a href="https://www.apple.com/safari">Safari</a>...
+					<a href="https://www.google.com/chrome">Chrome</a>…
 				</div>
 				<div id="pasteSuccess" role="alert" class="hidden alert alert-success">
 					<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>

+ 2 - 3
tpl/page.php

@@ -47,7 +47,7 @@ if ($MARKDOWN):
 <?php
 endif;
 ?>
-		<script type="text/javascript" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-iGFkRUeioseXBM4QLP9xFBK9RaGHPqTnl4NgVhjw0wm0xURcjpL5HE9WP+XJRY0UF3VbIoiuyFXSp0JpxSbc+A==" crossorigin="anonymous"></script>
+		<script type="text/javascript" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-BqQUrn7gw41w/GPvE28nN9ANnl59EAuo0xdcfzSIkw/b/SzT7WF0PS1SNs4hSc6hU6S1eJzS8qjgOI+8qt//RQ==" crossorigin="anonymous"></script>
 		<!--[if lt IE 10]>
 		<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
 		<![endif]-->
@@ -79,8 +79,7 @@ endif;
 			<div id="ienotice"><?php echo I18n::_('Still using Internet Explorer? Do yourself a favor, switch to a modern browser:'), PHP_EOL; ?>
 				<a href="https://www.mozilla.org/firefox/">Firefox</a>,
 				<a href="https://www.opera.com/">Opera</a>,
-				<a href="https://www.google.com/chrome">Chrome</a>,
-				<a href="https://www.apple.com/safari">Safari</a>...
+				<a href="https://www.google.com/chrome">Chrome</a>…
 			</div>
 		</header>
 		<section>

+ 0 - 8
tst/FilterTest.php

@@ -4,14 +4,6 @@ use PrivateBin\Filter;
 
 class FilterTest extends PHPUnit_Framework_TestCase
 {
-    public function testFilterStripsSlashesDeeply()
-    {
-        $this->assertEquals(
-            array("f'oo", "b'ar", array("fo'o", "b'ar")),
-            Filter::stripslashesDeep(array("f\\'oo", "b\\'ar", array("fo\\'o", "b\\'ar")))
-        );
-    }
-
     public function testFilterMakesTimesHumanlyReadable()
     {
         $this->assertEquals('5 minutes', Filter::formatHumanReadableTime('5min'));