Răsfoiți Sursa

Merge remote-tracking branch 'origin/master' into php8

github-actions[bot] 4 ani în urmă
părinte
comite
50fb12e3b3

+ 1 - 0
CHANGELOG.md

@@ -8,6 +8,7 @@
     * ADDED: Configuration option to exempt IPs from the rate-limiter (#787)
     * ADDED: Configuration option to exempt IPs from the rate-limiter (#787)
     * ADDED: Google Cloud Storage backend support (#795)
     * ADDED: Google Cloud Storage backend support (#795)
     * ADDED: Oracle database support (#868)
     * ADDED: Oracle database support (#868)
+    * ADDED: Configuration option to limit paste creation and commenting to certain IPs (#883)
     * CHANGED: Language selection cookie only transmitted over HTTPS (#472)
     * CHANGED: Language selection cookie only transmitted over HTTPS (#472)
     * CHANGED: Upgrading libraries to: base-x 4.0.0, bootstrap 3.4.1 (JS), DOMpurify 2.3.6, ip-lib 1.18.0, jQuery 3.6.0, random_compat 2.0.21 & Showdown 2.0.0
     * CHANGED: Upgrading libraries to: base-x 4.0.0, bootstrap 3.4.1 (JS), DOMpurify 2.3.6, ip-lib 1.18.0, jQuery 3.6.0, random_compat 2.0.21 & Showdown 2.0.0
     * CHANGED: Removed automatic `.ini` configuration file migration (#808)
     * CHANGED: Removed automatic `.ini` configuration file migration (#808)

+ 11 - 3
cfg/conf.sample.php

@@ -135,9 +135,17 @@ markdown = "Markdown"
 ; Set this to 0 to disable rate limiting.
 ; Set this to 0 to disable rate limiting.
 limit = 10
 limit = 10
 
 
-; Set ips (v4|v6) which should be exempted for the rate-limit. CIDR also supported. Needed to be comma separated.
-; Unset for enabling and invalid values will be ignored
-; eg: exemptedIp = '1.2.3.4,10.10.10/24'
+; (optional) Set IPs adresses (v4 or v6) or subnets (CIDR) which are exempted
+; from the rate-limit. Invalid IPs will be ignored. If multiple values are to
+; be exempted, the list needs to be comma separated. Leave unset to disable
+; exemptions.
+; exempted = "1.2.3.4,10.10.10/24"
+
+; (optional) If you want only some source IP addresses (v4 or v6) or subnets
+; (CIDR) to be allowed to create pastes, set these here. Invalid IPs will be
+; ignored. If multiple values are to be exempted, the list needs to be comma
+; separated. Leave unset to allow anyone to create pastes.
+; creators = "1.2.3.4,10.10.10/24"
 
 
 ; (optional) if your website runs behind a reverse proxy or load balancer,
 ; (optional) if your website runs behind a reverse proxy or load balancer,
 ; set the HTTP header containing the visitors IP address, i.e. X_FORWARDED_FOR
 ; set the HTTP header containing the visitors IP address, i.e. X_FORWARDED_FOR

+ 2 - 1
i18n/ar.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/bg.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/ca.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/co.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Nota cifrata nant’à PrivateBin",
     "Encrypted note on PrivateBin": "Nota cifrata nant’à PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visitate stu liame per vede a nota. Date l’indirizzu à qualunque li permette d’accede à a nota dinù.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visitate stu liame per vede a nota. Date l’indirizzu à qualunque li permette d’accede à a nota dinù.",
     "URL shortener may expose your decrypt key in URL.": "Un ammuzzatore d’indirizzu pò palisà a vostra chjave di dicifratura in l’indirizzu.",
     "URL shortener may expose your decrypt key in URL.": "Un ammuzzatore d’indirizzu pò palisà a vostra chjave di dicifratura in l’indirizzu.",
-    "Save paste": "Arregistrà l’appiccicu"
+    "Save paste": "Arregistrà l’appiccicu",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/cs.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Šifrovaná poznámka ve službě PrivateBin",
     "Encrypted note on PrivateBin": "Šifrovaná poznámka ve službě PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Navštivte tento odkaz pro zobrazení poznámky. Přeposláním URL umožníte také jiným lidem přístup.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Navštivte tento odkaz pro zobrazení poznámky. Přeposláním URL umožníte také jiným lidem přístup.",
     "URL shortener may expose your decrypt key in URL.": "Zkracovač URL může odhalit váš dešifrovací klíč v URL.",
     "URL shortener may expose your decrypt key in URL.": "Zkracovač URL může odhalit váš dešifrovací klíč v URL.",
-    "Save paste": "Uložit příspěvek"
+    "Save paste": "Uložit příspěvek",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/de.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Verschlüsselte Notiz auf PrivateBin",
     "Encrypted note on PrivateBin": "Verschlüsselte Notiz auf PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Besuche diesen Link um das Dokument zu sehen. Wird die URL an eine andere Person gegeben, so kann diese Person ebenfalls auf dieses Dokument zugreifen.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Besuche diesen Link um das Dokument zu sehen. Wird die URL an eine andere Person gegeben, so kann diese Person ebenfalls auf dieses Dokument zugreifen.",
     "URL shortener may expose your decrypt key in URL.": "Der URL-Verkürzer kann den Schlüssel in der URL enthüllen.",
     "URL shortener may expose your decrypt key in URL.": "Der URL-Verkürzer kann den Schlüssel in der URL enthüllen.",
-    "Save paste": "Text speichern"
+    "Save paste": "Text speichern",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/el.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/en.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/es.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Nota cifrada en PrivateBin",
     "Encrypted note on PrivateBin": "Nota cifrada en PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visite este enlace para ver la nota. Dar la URL a cualquier persona también les permite acceder a la nota.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visite este enlace para ver la nota. Dar la URL a cualquier persona también les permite acceder a la nota.",
     "URL shortener may expose your decrypt key in URL.": "El acortador de URL puede exponer su clave de descifrado en el URL.",
     "URL shortener may expose your decrypt key in URL.": "El acortador de URL puede exponer su clave de descifrado en el URL.",
-    "Save paste": "Guardar \"paste\""
+    "Save paste": "Guardar \"paste\"",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/et.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Krüpteeritud kiri PrivateBin-is",
     "Encrypted note on PrivateBin": "Krüpteeritud kiri PrivateBin-is",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Kirja nägemiseks külasta seda linki. Teistele URL-i andmine lubab ka neil ligi pääseda kirjale.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Kirja nägemiseks külasta seda linki. Teistele URL-i andmine lubab ka neil ligi pääseda kirjale.",
     "URL shortener may expose your decrypt key in URL.": "URL-i lühendaja võib paljastada sinu dekrüpteerimisvõtme URL-is.",
     "URL shortener may expose your decrypt key in URL.": "URL-i lühendaja võib paljastada sinu dekrüpteerimisvõtme URL-is.",
-    "Save paste": "Salvesta kleebe"
+    "Save paste": "Salvesta kleebe",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/fi.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Salattu viesti PrivateBinissä",
     "Encrypted note on PrivateBin": "Salattu viesti PrivateBinissä",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Käy tässä linkissä nähdäksesi viestin. URL:n antaminen kenellekään antaa heidänkin päästä katsomeen viestiä. ",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Käy tässä linkissä nähdäksesi viestin. URL:n antaminen kenellekään antaa heidänkin päästä katsomeen viestiä. ",
     "URL shortener may expose your decrypt key in URL.": "URL-lyhentäjä voi paljastaa purkuavaimesi URL:ssä.",
     "URL shortener may expose your decrypt key in URL.": "URL-lyhentäjä voi paljastaa purkuavaimesi URL:ssä.",
-    "Save paste": "Tallenna paste"
+    "Save paste": "Tallenna paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/fr.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Message chiffré sur PrivateBin",
     "Encrypted note on PrivateBin": "Message chiffré sur PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visiter ce lien pour voir la note. Donner l'URL à une autre personne lui permet également d'accéder à la note.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visiter ce lien pour voir la note. Donner l'URL à une autre personne lui permet également d'accéder à la note.",
     "URL shortener may expose your decrypt key in URL.": "Raccourcir l'URL peut exposer votre clé de déchiffrement dans l'URL.",
     "URL shortener may expose your decrypt key in URL.": "Raccourcir l'URL peut exposer votre clé de déchiffrement dans l'URL.",
-    "Save paste": "Sauver le paste"
+    "Save paste": "Sauver le paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/he.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "הערה מוצפנת ב־PrivateBin",
     "Encrypted note on PrivateBin": "הערה מוצפנת ב־PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "נא לבקר בקישור כדי לצפות בהערה. מסירת הקישור לאנשים כלשהם תאפשר גם להם לגשת להערה.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "נא לבקר בקישור כדי לצפות בהערה. מסירת הקישור לאנשים כלשהם תאפשר גם להם לגשת להערה.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/hi.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/hu.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Titkosított jegyzet a PrivateBinen",
     "Encrypted note on PrivateBin": "Titkosított jegyzet a PrivateBinen",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Látogasd meg ezt a hivatkozást a bejegyzés megtekintéséhez. Ha mások számára is megadod ezt a linket, azzal hozzáférnek ők is.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Látogasd meg ezt a hivatkozást a bejegyzés megtekintéséhez. Ha mások számára is megadod ezt a linket, azzal hozzáférnek ők is.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/id.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Catatan ter-ekrip di PrivateBin",
     "Encrypted note on PrivateBin": "Catatan ter-ekrip di PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Kunjungi tautan ini untuk melihat catatan. Memberikan alamat URL pada siapapun juga, akan mengizinkan mereka untuk mengakses catatan, so pasti gitu loh Kaka.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Kunjungi tautan ini untuk melihat catatan. Memberikan alamat URL pada siapapun juga, akan mengizinkan mereka untuk mengakses catatan, so pasti gitu loh Kaka.",
     "URL shortener may expose your decrypt key in URL.": "Pemendek URL mungkin akan menampakkan kunci dekrip Anda dalam URL.",
     "URL shortener may expose your decrypt key in URL.": "Pemendek URL mungkin akan menampakkan kunci dekrip Anda dalam URL.",
-    "Save paste": "Simpan paste"
+    "Save paste": "Simpan paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/it.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Nota crittografata su PrivateBin",
     "Encrypted note on PrivateBin": "Nota crittografata su PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visita questo collegamento per vedere la nota. Dare l'URL a chiunque consente anche a loro di accedere alla nota.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visita questo collegamento per vedere la nota. Dare l'URL a chiunque consente anche a loro di accedere alla nota.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener può esporre la tua chiave decrittografata nell'URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener può esporre la tua chiave decrittografata nell'URL.",
-    "Save paste": "Salva il messagio"
+    "Save paste": "Salva il messagio",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/ja.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/jbo.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": ".i lo lo notci ku mifra cu zvati sivlolnitvanku'a",
     "Encrypted note on PrivateBin": ".i lo lo notci ku mifra cu zvati sivlolnitvanku'a",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "rejgau fukpi"
+    "Save paste": "rejgau fukpi",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/ku.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/la.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/lt.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Šifruoti užrašai ties PrivateBin",
     "Encrypted note on PrivateBin": "Šifruoti užrašai ties PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Norėdami matyti užrašus, aplankykite šį tinklalapį. Pasidalinus šiuo URL adresu su kitais žmonėmis, jiems taip pat bus leidžiama prieiga prie šių užrašų.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Norėdami matyti užrašus, aplankykite šį tinklalapį. Pasidalinus šiuo URL adresu su kitais žmonėmis, jiems taip pat bus leidžiama prieiga prie šių užrašų.",
     "URL shortener may expose your decrypt key in URL.": "URL trumpinimo įrankis gali atskleisti URL adrese jūsų iššifravimo raktą.",
     "URL shortener may expose your decrypt key in URL.": "URL trumpinimo įrankis gali atskleisti URL adrese jūsų iššifravimo raktą.",
-    "Save paste": "Įrašyti įdėjimą"
+    "Save paste": "Įrašyti įdėjimą",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/nl.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/no.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Kryptert notat på PrivateBin",
     "Encrypted note on PrivateBin": "Kryptert notat på PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Besøk denne lenken for å se notatet. Hvis lenken deles med andre, vil de også kunne se notatet.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Besøk denne lenken for å se notatet. Hvis lenken deles med andre, vil de også kunne se notatet.",
     "URL shortener may expose your decrypt key in URL.": "URL forkorter kan avsløre dekrypteringsnøkkelen.",
     "URL shortener may expose your decrypt key in URL.": "URL forkorter kan avsløre dekrypteringsnøkkelen.",
-    "Save paste": "Lagre utklipp"
+    "Save paste": "Lagre utklipp",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/oc.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Nòtas chifradas sus PrivateBin",
     "Encrypted note on PrivateBin": "Nòtas chifradas sus PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visitatz aqueste ligam per veire la nòta. Fornir lo ligam a qualqu’un mai li permet tanben d’accedir a la nòta.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visitatz aqueste ligam per veire la nòta. Fornir lo ligam a qualqu’un mai li permet tanben d’accedir a la nòta.",
     "URL shortener may expose your decrypt key in URL.": "Los espleches d’acorchiment d’URL pòdon expausar la clau de deschiframent dins l’URL.",
     "URL shortener may expose your decrypt key in URL.": "Los espleches d’acorchiment d’URL pòdon expausar la clau de deschiframent dins l’URL.",
-    "Save paste": "Enregistrar lo tèxt"
+    "Save paste": "Enregistrar lo tèxt",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/pl.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/pt.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Nota criptografada no PrivateBin",
     "Encrypted note on PrivateBin": "Nota criptografada no PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visite esse link para ver a nota. Dar a URL para qualquer um permite que eles também acessem a nota.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visite esse link para ver a nota. Dar a URL para qualquer um permite que eles também acessem a nota.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/ru.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Зашифрованная запись на PrivateBin",
     "Encrypted note on PrivateBin": "Зашифрованная запись на PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Посетите эту ссылку чтобы просмотреть запись. Передача ссылки кому либо позволит им получить доступ к записи тоже.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Посетите эту ссылку чтобы просмотреть запись. Передача ссылки кому либо позволит им получить доступ к записи тоже.",
     "URL shortener may expose your decrypt key in URL.": "Сервис сокращения ссылок может получить ваш ключ расшифровки из ссылки.",
     "URL shortener may expose your decrypt key in URL.": "Сервис сокращения ссылок может получить ваш ключ расшифровки из ссылки.",
-    "Save paste": "Сохранить запись"
+    "Save paste": "Сохранить запись",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/sl.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/sv.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/tr.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/uk.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Encrypted note on PrivateBin": "Encrypted note on PrivateBin",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
     "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
-    "Save paste": "Save paste"
+    "Save paste": "Save paste",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 2 - 1
i18n/zh.json

@@ -185,5 +185,6 @@
     "Encrypted note on PrivateBin": "PrivateBin 上的加密笔记",
     "Encrypted note on PrivateBin": "PrivateBin 上的加密笔记",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "访问此链接来查看该笔记。将此 URL 发送给任何人即可允许其访问该笔记。",
     "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "访问此链接来查看该笔记。将此 URL 发送给任何人即可允许其访问该笔记。",
     "URL shortener may expose your decrypt key in URL.": "短链接服务可能会暴露您在 URL 中的解密密钥。",
     "URL shortener may expose your decrypt key in URL.": "短链接服务可能会暴露您在 URL 中的解密密钥。",
-    "Save paste": "保存内容"
+    "Save paste": "保存内容",
+    "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes."
 }
 }

+ 4 - 3
lib/Configuration.php

@@ -78,9 +78,10 @@ class Configuration
             'markdown'           => 'Markdown',
             'markdown'           => 'Markdown',
         ),
         ),
         'traffic' => array(
         'traffic' => array(
-            'limit'      => 10,
-            'header'     => null,
-            'exemptedIp' => null,
+            'limit'     => 10,
+            'header'    => '',
+            'exempted'  => '',
+            'creators'  => '',
         ),
         ),
         'purge' => array(
         'purge' => array(
             'limit'     => 300,
             'limit'     => 300,

+ 4 - 7
lib/Controller.php

@@ -199,13 +199,10 @@ class Controller
         ServerSalt::setStore($this->_model->getStore());
         ServerSalt::setStore($this->_model->getStore());
         TrafficLimiter::setConfiguration($this->_conf);
         TrafficLimiter::setConfiguration($this->_conf);
         TrafficLimiter::setStore($this->_model->getStore());
         TrafficLimiter::setStore($this->_model->getStore());
-        if (!TrafficLimiter::canPass()) {
-            $this->_return_message(
-                1, I18n::_(
-                    'Please wait %d seconds between each post.',
-                    $this->_conf->getKey('limit', 'traffic')
-                )
-            );
+        try {
+            TrafficLimiter::canPass();
+        } catch (Exception $e) {
+            $this->_return_message(1, $e->getMessage());
             return;
             return;
         }
         }
 
 

+ 78 - 36
lib/Persistence/TrafficLimiter.php

@@ -13,8 +13,11 @@
 
 
 namespace PrivateBin\Persistence;
 namespace PrivateBin\Persistence;
 
 
+use Exception;
 use IPLib\Factory;
 use IPLib\Factory;
+use IPLib\ParseStringFlag;
 use PrivateBin\Configuration;
 use PrivateBin\Configuration;
+use PrivateBin\I18n;
 
 
 /**
 /**
  * TrafficLimiter
  * TrafficLimiter
@@ -24,22 +27,22 @@ use PrivateBin\Configuration;
 class TrafficLimiter extends AbstractPersistence
 class TrafficLimiter extends AbstractPersistence
 {
 {
     /**
     /**
-     * time limit in seconds, defaults to 10s
+     * listed IPs are the only ones allowed to create, defaults to null
      *
      *
      * @access private
      * @access private
      * @static
      * @static
-     * @var    int
+     * @var    string|null
      */
      */
-    private static $_limit = 10;
+    private static $_creators = null;
 
 
     /**
     /**
-     * listed ips are exempted from limits, defaults to null
+     * listed IPs are exempted from limits, defaults to null
      *
      *
      * @access private
      * @access private
      * @static
      * @static
      * @var    string|null
      * @var    string|null
      */
      */
-    private static $_exemptedIp = null;
+    private static $_exempted = null;
 
 
     /**
     /**
      * key to fetch IP address
      * key to fetch IP address
@@ -51,47 +54,69 @@ class TrafficLimiter extends AbstractPersistence
     private static $_ipKey = 'REMOTE_ADDR';
     private static $_ipKey = 'REMOTE_ADDR';
 
 
     /**
     /**
-     * set the time limit in seconds
+     * time limit in seconds, defaults to 10s
+     *
+     * @access private
+     * @static
+     * @var    int
+     */
+    private static $_limit = 10;
+
+    /**
+     * set configuration options of the traffic limiter
      *
      *
      * @access public
      * @access public
      * @static
      * @static
-     * @param  int $limit
+     * @param Configuration $conf
      */
      */
-    public static function setLimit($limit)
+    public static function setConfiguration(Configuration $conf)
     {
     {
-        self::$_limit = $limit;
+        self::setCreators($conf->getKey('creators', 'traffic'));
+        self::setExempted($conf->getKey('exempted', 'traffic'));
+        self::setLimit($conf->getKey('limit', 'traffic'));
+
+        if (($option = $conf->getKey('header', 'traffic')) !== '') {
+            $httpHeader = 'HTTP_' . $option;
+            if (array_key_exists($httpHeader, $_SERVER) && !empty($_SERVER[$httpHeader])) {
+                self::$_ipKey = $httpHeader;
+            }
+        }
     }
     }
 
 
     /**
     /**
-     * set a list of ip(ranges) as string
+     * set a list of creator IP(-ranges) as string
      *
      *
      * @access public
      * @access public
      * @static
      * @static
-     * @param string $exemptedIps
+     * @param string $creators
      */
      */
-    public static function setExemptedIp($exemptedIp)
+    public static function setCreators($creators)
     {
     {
-        self::$_exemptedIp = $exemptedIp;
+        self::$_creators = $creators;
     }
     }
 
 
     /**
     /**
-     * set configuration options of the traffic limiter
+     * set a list of exempted IP(-ranges) as string
      *
      *
      * @access public
      * @access public
      * @static
      * @static
-     * @param Configuration $conf
+     * @param string $exempted
      */
      */
-    public static function setConfiguration(Configuration $conf)
+    public static function setExempted($exempted)
     {
     {
-        self::setLimit($conf->getKey('limit', 'traffic'));
-        self::setExemptedIp($conf->getKey('exemptedIp', 'traffic'));
+        self::$_exempted = $exempted;
+    }
 
 
-        if (($option = $conf->getKey('header', 'traffic')) !== null) {
-            $httpHeader = 'HTTP_' . $option;
-            if (array_key_exists($httpHeader, $_SERVER) && !empty($_SERVER[$httpHeader])) {
-                self::$_ipKey = $httpHeader;
-            }
-        }
+    /**
+     * set the time limit in seconds
+     *
+     * @access public
+     * @static
+     * @param  int $limit
+     */
+    public static function setLimit($limit)
+    {
+        self::$_limit = $limit;
     }
     }
 
 
     /**
     /**
@@ -108,7 +133,7 @@ class TrafficLimiter extends AbstractPersistence
     }
     }
 
 
     /**
     /**
-     * Validate $_ipKey against configured ipranges. If matched we will ignore the ip
+     * validate $_ipKey against configured ipranges. If matched we will ignore the ip
      *
      *
      * @access private
      * @access private
      * @static
      * @static
@@ -120,8 +145,8 @@ class TrafficLimiter extends AbstractPersistence
         if (is_string($ipRange)) {
         if (is_string($ipRange)) {
             $ipRange = trim($ipRange);
             $ipRange = trim($ipRange);
         }
         }
-        $address = Factory::addressFromString($_SERVER[self::$_ipKey]);
-        $range   = Factory::rangeFromString($ipRange);
+        $address = Factory::parseAddressString($_SERVER[self::$_ipKey]);
+        $range   = Factory::parseRangeString($ipRange, ParseStringFlag::IPV4_MAYBE_NON_DECIMAL);
 
 
         // address could not be parsed, we might not be in IP space and try a string comparison instead
         // address could not be parsed, we might not be in IP space and try a string comparison instead
         if (is_null($address)) {
         if (is_null($address)) {
@@ -136,24 +161,35 @@ class TrafficLimiter extends AbstractPersistence
     }
     }
 
 
     /**
     /**
-     * traffic limiter
-     *
-     * Make sure the IP address makes at most 1 request every 10 seconds.
+     * make sure the IP address is allowed to perfom a request
      *
      *
      * @access public
      * @access public
      * @static
      * @static
-     * @return bool
+     * @throws Exception
+     * @return true
      */
      */
     public static function canPass()
     public static function canPass()
     {
     {
+        // if creators are defined, the traffic limiter will only allow creation
+        // for these, with no limits, and skip any other rules
+        if (!empty(self::$_creators)) {
+            $creatorIps = explode(',', self::$_creators);
+            foreach ($creatorIps as $ipRange) {
+                if (self::matchIp($ipRange) === true) {
+                    return true;
+                }
+            }
+            throw new Exception(I18n::_('Your IP is not authorized to create pastes.'));
+        }
+
         // disable limits if set to less then 1
         // disable limits if set to less then 1
         if (self::$_limit < 1) {
         if (self::$_limit < 1) {
             return true;
             return true;
         }
         }
 
 
-        // Check if $_ipKey is exempted from ratelimiting
-        if (!is_null(self::$_exemptedIp)) {
-            $exIp_array = explode(',', self::$_exemptedIp);
+        // check if $_ipKey is exempted from ratelimiting
+        if (!empty(self::$_exempted)) {
+            $exIp_array = explode(',', self::$_exempted);
             foreach ($exIp_array as $ipRange) {
             foreach ($exIp_array as $ipRange) {
                 if (self::matchIp($ipRange) === true) {
                 if (self::matchIp($ipRange) === true) {
                     return true;
                     return true;
@@ -161,7 +197,7 @@ class TrafficLimiter extends AbstractPersistence
             }
             }
         }
         }
 
 
-        // this hash is used as an array key, hence a shorter algo is used
+        // used as array key, which are limited in length, hence using algo with shorter range
         $hash = self::getHash('sha256');
         $hash = self::getHash('sha256');
         $now  = time();
         $now  = time();
         $tl   = (int) self::$_store->getValue('traffic_limiter', $hash);
         $tl   = (int) self::$_store->getValue('traffic_limiter', $hash);
@@ -175,6 +211,12 @@ class TrafficLimiter extends AbstractPersistence
         if (!self::$_store->setValue((string) $tl, 'traffic_limiter', $hash)) {
         if (!self::$_store->setValue((string) $tl, 'traffic_limiter', $hash)) {
             error_log('failed to store the traffic limiter, it probably contains outdated information');
             error_log('failed to store the traffic limiter, it probably contains outdated information');
         }
         }
-        return $result;
+        if ($result) {
+            return true;
+        }
+        throw new Exception(I18n::_(
+            'Please wait %d seconds between each post.',
+            self::$_limit
+        ));
     }
     }
 }
 }

+ 1 - 1
tpl/bootstrap.php

@@ -72,7 +72,7 @@ endif;
 ?>
 ?>
 		<script type="text/javascript" data-cfasync="false" src="js/purify-2.3.6.js" integrity="sha512-N1GGPjbqLbwK821ZN7C925WuTwU4aDxz2CEEOXQ6/s6m6MBwVj8fh5fugiE2hzsm0xud3q7jpjZQ4ILnpMREYQ==" crossorigin="anonymous"></script>
 		<script type="text/javascript" data-cfasync="false" src="js/purify-2.3.6.js" integrity="sha512-N1GGPjbqLbwK821ZN7C925WuTwU4aDxz2CEEOXQ6/s6m6MBwVj8fh5fugiE2hzsm0xud3q7jpjZQ4ILnpMREYQ==" crossorigin="anonymous"></script>
 		<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
 		<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
-		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-PTOcxIWIPWCnb5vC4fmQDMqYGerwsu3AndVyPxn9NlQffIWYMPf/p28Z9SIygXsmcYjmTRmUiW5y7df63mNTfg==" crossorigin="anonymous"></script>
+		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-EdUms2nI12Cmtv014stIEBlyPjeKMHlkg7NiBJup1b7jJF5amKhev2RwTaldINXK4UaWbZtQ6hGuMPNvvNQZFA==" crossorigin="anonymous"></script>
 		<!-- icon -->
 		<!-- icon -->
 		<link rel="apple-touch-icon" href="<?php echo I18n::encode($BASEPATH); ?>img/apple-touch-icon.png" sizes="180x180" />
 		<link rel="apple-touch-icon" href="<?php echo I18n::encode($BASEPATH); ?>img/apple-touch-icon.png" sizes="180x180" />
 		<link rel="icon" type="image/png" href="img/favicon-32x32.png" sizes="32x32" />
 		<link rel="icon" type="image/png" href="img/favicon-32x32.png" sizes="32x32" />

+ 1 - 1
tpl/page.php

@@ -50,7 +50,7 @@ endif;
 ?>
 ?>
 		<script type="text/javascript" data-cfasync="false" src="js/purify-2.3.6.js" integrity="sha512-N1GGPjbqLbwK821ZN7C925WuTwU4aDxz2CEEOXQ6/s6m6MBwVj8fh5fugiE2hzsm0xud3q7jpjZQ4ILnpMREYQ==" crossorigin="anonymous"></script>
 		<script type="text/javascript" data-cfasync="false" src="js/purify-2.3.6.js" integrity="sha512-N1GGPjbqLbwK821ZN7C925WuTwU4aDxz2CEEOXQ6/s6m6MBwVj8fh5fugiE2hzsm0xud3q7jpjZQ4ILnpMREYQ==" crossorigin="anonymous"></script>
 		<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
 		<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
-		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-PTOcxIWIPWCnb5vC4fmQDMqYGerwsu3AndVyPxn9NlQffIWYMPf/p28Z9SIygXsmcYjmTRmUiW5y7df63mNTfg==" crossorigin="anonymous"></script>
+		<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-EdUms2nI12Cmtv014stIEBlyPjeKMHlkg7NiBJup1b7jJF5amKhev2RwTaldINXK4UaWbZtQ6hGuMPNvvNQZFA==" crossorigin="anonymous"></script>
 		<!-- icon -->
 		<!-- icon -->
 		<link rel="apple-touch-icon" href="img/apple-touch-icon.png?<?php echo rawurlencode($VERSION); ?>" sizes="180x180" />
 		<link rel="apple-touch-icon" href="img/apple-touch-icon.png?<?php echo rawurlencode($VERSION); ?>" sizes="180x180" />
 		<link rel="icon" type="image/png" href="img/favicon-32x32.png?<?php echo rawurlencode($VERSION); ?>" sizes="32x32" />
 		<link rel="icon" type="image/png" href="img/favicon-32x32.png?<?php echo rawurlencode($VERSION); ?>" sizes="32x32" />

+ 55 - 8
tst/Persistence/TrafficLimiterTest.php

@@ -39,27 +39,74 @@ class TrafficLimiterTest extends TestCase
         $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
         $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
         $this->assertTrue(TrafficLimiter::canPass(), 'first request may pass');
         $this->assertTrue(TrafficLimiter::canPass(), 'first request may pass');
         sleep(1);
         sleep(1);
-        $this->assertFalse(TrafficLimiter::canPass(), 'second request is to fast, may not pass');
+        try {
+            $this->assertFalse(TrafficLimiter::canPass(), 'expected an exception');
+        } catch (Exception $e) {
+            $this->assertEquals($e->getMessage(), 'Please wait 4 seconds between each post.', 'second request is to fast, may not pass');
+        }
         sleep(4);
         sleep(4);
         $this->assertTrue(TrafficLimiter::canPass(), 'third request waited long enough and may pass');
         $this->assertTrue(TrafficLimiter::canPass(), 'third request waited long enough and may pass');
         $_SERVER['REMOTE_ADDR'] = '2001:1620:2057:dead:beef::cafe:babe';
         $_SERVER['REMOTE_ADDR'] = '2001:1620:2057:dead:beef::cafe:babe';
         $this->assertTrue(TrafficLimiter::canPass(), 'fourth request has different ip and may pass');
         $this->assertTrue(TrafficLimiter::canPass(), 'fourth request has different ip and may pass');
         $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
         $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
-        $this->assertFalse(TrafficLimiter::canPass(), 'fifth request is to fast, may not pass');
+        try {
+            $this->assertFalse(TrafficLimiter::canPass(), 'expected an exception');
+        } catch (Exception $e) {
+            $this->assertEquals($e->getMessage(), 'Please wait 4 seconds between each post.', 'fifth request is to fast, may not pass');
+        }
+    }
 
 
-        // exempted IPs configuration
-        TrafficLimiter::setExemptedIp('1.2.3.4,10.10.10.0/24,2001:1620:2057::/48');
-        $this->assertFalse(TrafficLimiter::canPass(), 'still too fast and not exempted');
+    public function testTrafficLimitExempted()
+    {
+        TrafficLimiter::setExempted('1.2.3.4,10.10.10.0/24,2001:1620:2057::/48');
+        $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
+        $this->assertTrue(TrafficLimiter::canPass(), 'first request may pass');
+        try {
+            $this->assertFalse(TrafficLimiter::canPass(), 'expected an exception');
+        } catch (Exception $e) {
+            $this->assertEquals($e->getMessage(), 'Please wait 4 seconds between each post.', 'not exempted');
+        }
         $_SERVER['REMOTE_ADDR'] = '10.10.10.10';
         $_SERVER['REMOTE_ADDR'] = '10.10.10.10';
         $this->assertTrue(TrafficLimiter::canPass(), 'IPv4 in exempted range');
         $this->assertTrue(TrafficLimiter::canPass(), 'IPv4 in exempted range');
         $this->assertTrue(TrafficLimiter::canPass(), 'request is to fast, but IPv4 in exempted range');
         $this->assertTrue(TrafficLimiter::canPass(), 'request is to fast, but IPv4 in exempted range');
         $_SERVER['REMOTE_ADDR'] = '2001:1620:2057:dead:beef::cafe:babe';
         $_SERVER['REMOTE_ADDR'] = '2001:1620:2057:dead:beef::cafe:babe';
         $this->assertTrue(TrafficLimiter::canPass(), 'IPv6 in exempted range');
         $this->assertTrue(TrafficLimiter::canPass(), 'IPv6 in exempted range');
         $this->assertTrue(TrafficLimiter::canPass(), 'request is to fast, but IPv6 in exempted range');
         $this->assertTrue(TrafficLimiter::canPass(), 'request is to fast, but IPv6 in exempted range');
-        TrafficLimiter::setExemptedIp('127.*,foobar');
-        $this->assertFalse(TrafficLimiter::canPass(), 'request is to fast, invalid range');
+        TrafficLimiter::setExempted('127.*,foobar');
+        $this->assertTrue(TrafficLimiter::canPass(), 'first cached request may pass');
+        try {
+            $this->assertFalse(TrafficLimiter::canPass(), 'expected an exception');
+        } catch (Exception $e) {
+            $this->assertEquals($e->getMessage(), 'Please wait 4 seconds between each post.', 'request is too fast, invalid range');
+        }
+        $_SERVER['REMOTE_ADDR'] = 'foobar';
+        $this->assertTrue(TrafficLimiter::canPass(), 'non-IP address');
+        $this->assertTrue(TrafficLimiter::canPass(), 'request is too fast, but non-IP address matches exempted range');
+    }
+
+    public function testTrafficLimitCreators()
+    {
+        TrafficLimiter::setCreators('1.2.3.4,10.10.10.0/24,2001:1620:2057::/48');
+        $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
+        try {
+            $this->assertFalse(TrafficLimiter::canPass(), 'expected an exception');
+        } catch (Exception $e) {
+            $this->assertEquals($e->getMessage(), 'Your IP is not authorized to create pastes.', 'not a creator');
+        }
+        $_SERVER['REMOTE_ADDR'] = '10.10.10.10';
+        $this->assertTrue(TrafficLimiter::canPass(), 'IPv4 in creator range');
+        $this->assertTrue(TrafficLimiter::canPass(), 'request is too fast, but IPv4 in creator range');
+        $_SERVER['REMOTE_ADDR'] = '2001:1620:2057:dead:beef::cafe:babe';
+        $this->assertTrue(TrafficLimiter::canPass(), 'IPv6 in creator range');
+        $this->assertTrue(TrafficLimiter::canPass(), 'request is too fast, but IPv6 in creator range');
+        TrafficLimiter::setCreators('127.*,foobar');
+        try {
+            $this->assertFalse(TrafficLimiter::canPass(), 'expected an exception');
+        } catch (Exception $e) {
+            $this->assertEquals($e->getMessage(), 'Your IP is not authorized to create pastes.', 'request is to fast, not a creator');
+        }
         $_SERVER['REMOTE_ADDR'] = 'foobar';
         $_SERVER['REMOTE_ADDR'] = 'foobar';
         $this->assertTrue(TrafficLimiter::canPass(), 'non-IP address');
         $this->assertTrue(TrafficLimiter::canPass(), 'non-IP address');
-        $this->assertTrue(TrafficLimiter::canPass(), 'request is to fast, but non-IP address matches exempted range');
+        $this->assertTrue(TrafficLimiter::canPass(), 'request is to fast, but non-IP address matches creator');
     }
     }
 }
 }