Merge branch 'better-feature-detection'

This commit is contained in:
El RIDO 2019-09-20 06:18:10 +02:00
commit b496ae42fd
No known key found for this signature in database
GPG Key ID: 0F5C940A6BD81F92
31 changed files with 857 additions and 475 deletions

View File

@ -1,3 +1,4 @@
---
parserOptions: parserOptions:
ecmaVersion: 2017 ecmaVersion: 2017
@ -11,17 +12,16 @@ env:
es6: true es6: true
jquery: true jquery: true
node: true node: true
mocha: true
globals: globals:
DOMPurify: false DOMPurify: readonly
after: true cleanup: writable
before: true describe: readonly
cleanup: true jsc: readonly
describe: false jsdom: writable
it: false kjua: writable
jsc: false WebCrypto: writable
jsdom: true
kjua: true
# http://eslint.org/docs/rules/ # http://eslint.org/docs/rules/
rules: rules:

View File

@ -68,8 +68,17 @@ languageselection = false
; custom scripts from third-party domains to your templates, e.g. tracking ; custom scripts from third-party domains to your templates, e.g. tracking
; scripts or run your site behind certain DDoS-protection services. ; scripts or run your site behind certain DDoS-protection services.
; Check the documentation at https://content-security-policy.com/ ; Check the documentation at https://content-security-policy.com/
; Note: If you use a bootstrap theme, you can remove the allow-popups from the sandbox restrictions. ; Notes:
; By default this disallows to load images from third-party servers, e.g. when they are embedded in pastes. If you wish to allow that, you can adjust the policy here. See https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-it-load-embedded-images for details. ; - If you use a bootstrap theme, you can remove the allow-popups from the
; sandbox restrictions.
; - By default this disallows to load images from third-party servers, e.g. when
; they are embedded in pastes. If you wish to allow that, you can adjust the
; policy here. See https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-it-load-embedded-images
; for details.
; - The 'unsafe-eval' is used in two cases; to check if the browser supports
; async functions and display an error if not and for Chrome to enable
; webassembly support (used for zlib compression). You can remove it if Chrome
; doesn't need to be supported and old browsers don't need to be warned.
; cspheader = "default-src 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'unsafe-eval'; style-src 'self'; font-src 'self'; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals" ; cspheader = "default-src 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'unsafe-eval'; style-src 'self'; font-src 'self'; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals"
; stay compatible with PrivateBin Alpha 0.19, less secure ; stay compatible with PrivateBin Alpha 0.19, less secure

View File

@ -35,8 +35,6 @@
"Услугата %s се нуждае от JavaScript, за да работи.<br />Съжаляваме за неудобството.", "Услугата %s се нуждае от JavaScript, за да работи.<br />Съжаляваме за неудобството.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.":
"%s се нуждае от съвременен браузър за да работи.", "%s се нуждае от съвременен браузър за да работи.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Все още използваш Internet Explorer? Направи си услуга и го смени с модерен браузър:",
"New": "New":
"Създаване", "Създаване",
"Send": "Send":
@ -155,11 +153,12 @@
"Could not get paste data: %s": "Could not get paste data: %s":
"Взимането на информацията беше неуспешно: %s", "Взимането на информацията беше неуспешно: %s",
"QR code": "QR код", "QR code": "QR код",
"I love you too, bot…": "И аз те обичам, бот…",
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.":
"Този сайт използва несигурна HTTP връзка. Моля използвайте само за проби.", "Този сайт използва несигурна HTTP връзка. Моля използвайте само за проби.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.":
"<a href=\"%s\">Вижте тази страница</a> за повече информация.", "<a href=\"%s\">Вижте тази страница</a> за повече информация.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Браузъра ви може да се нуждае от HTTPS връзка за да използва WebCrypto API. Пробвай <a href=\"%s\">да минеш на HTTPS</a>." "Браузъра ви може да се нуждае от HTTPS връзка за да използва WebCrypto API. Пробвай <a href=\"%s\">да минеш на HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
} }

View File

@ -35,8 +35,6 @@
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.", "JavaScript is required for %s to work.<br />Sorry for the inconvenience.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.":
"%%s requires a modern browser to work.", "%%s requires a modern browser to work.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:",
"New": "New":
"Nový", "Nový",
"Send": "Send":
@ -155,11 +153,12 @@
"Could not get paste data: %s": "Could not get paste data: %s":
"Could not get paste data: %s", "Could not get paste data: %s",
"QR code": "QR code", "QR code": "QR code",
"I love you too, bot…": "I love you too, bot…",
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.":
"This website is using an insecure HTTP connection! Please use it only for testing.", "This website is using an insecure HTTP connection! Please use it only for testing.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</a>.", "For more information <a href=\"%s\">see this FAQ entry</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>." "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
} }

View File

@ -35,8 +35,6 @@
"JavaScript ist eine Voraussetzung, um %s zu nutzen.<br />Bitte entschuldige die Unannehmlichkeiten.", "JavaScript ist eine Voraussetzung, um %s zu nutzen.<br />Bitte entschuldige die Unannehmlichkeiten.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.":
"%s setzt einen modernen Browser voraus, um funktionieren zu können.", "%s setzt einen modernen Browser voraus, um funktionieren zu können.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Du benutzt immer noch den Internet Explorer? Tu Dir einen Gefallen und wechsle zu einem moderneren Browser:",
"New": "New":
"Neu", "Neu",
"Send": "Send":
@ -155,11 +153,12 @@
"Could not get paste data: %s": "Could not get paste data: %s":
"Text konnte nicht geladen werden: %s", "Text konnte nicht geladen werden: %s",
"QR code": "QR code", "QR code": "QR code",
"I love you too, bot…": "Ich mag Dich auch, bot…",
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.":
"Diese Webseite verwendet eine unsichere HTTP Verbindung! Bitte benutze sie nur zum Testen.", "Diese Webseite verwendet eine unsichere HTTP Verbindung! Bitte benutze sie nur zum Testen.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.":
"<a href=\"%s\">Besuche diesen FAQ Eintrag</a> für weitere Informationen dazu.", "<a href=\"%s\">Besuche diesen FAQ Eintrag</a> für weitere Informationen dazu.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Dein Browser benötigt möglicherweise eine HTTPS Verbindung um das WebCrypto API nutzen zu können. Versuche <a href=\"%s\">auf HTTPS zu wechseln</a>." "Dein Browser benötigt möglicherweise eine HTTPS Verbindung um das WebCrypto API nutzen zu können. Versuche <a href=\"%s\">auf HTTPS zu wechseln</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Dein Browser unterstützt WebAssembly nicht, welches für zlib Komprimierung benötigt wird. Du kannst unkomprimierte Dokumente erzeugen, aber keine komprimierten lesen."
} }

View File

@ -35,8 +35,6 @@
"JavaScript es necesario para que %s funcione.<br />Sentimos los inconvenientes ocasionados.", "JavaScript es necesario para que %s funcione.<br />Sentimos los inconvenientes ocasionados.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.":
"%s requiere un navegador moderno para funcionar.", "%s requiere un navegador moderno para funcionar.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"¿Sigues usando Internet Explorer? Hazte un favor, cambia a un navegador moderno:",
"New": "New":
"Nuevo", "Nuevo",
"Send": "Send":
@ -155,11 +153,12 @@
"Could not get paste data: %s": "Could not get paste data: %s":
"No se pudieron obtener los datos: %s", "No se pudieron obtener los datos: %s",
"QR code": "Código QR", "QR code": "Código QR",
"I love you too, bot…": "I love you too, bot…",
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.":
"This website is using an insecure HTTP connection! Please use it only for testing.", "This website is using an insecure HTTP connection! Please use it only for testing.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</a>.", "For more information <a href=\"%s\">see this FAQ entry</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>." "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
} }

View File

@ -35,8 +35,6 @@
"JavaScript est requis pour faire fonctionner %s. <br />Désolé pour cet inconvénient.", "JavaScript est requis pour faire fonctionner %s. <br />Désolé pour cet inconvénient.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.":
"%s nécessite un navigateur moderne pour fonctionner.", "%s nécessite un navigateur moderne pour fonctionner.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Encore sur Internet Explorer ? Faites-vous une faveur, passez à un navigateur moderne :",
"New": "New":
"Nouveau", "Nouveau",
"Send": "Send":
@ -164,11 +162,12 @@
"Could not get paste data: %s": "Could not get paste data: %s":
"Impossible d'obtenir les données du paste: %s", "Impossible d'obtenir les données du paste: %s",
"QR code": "QR code", "QR code": "QR code",
"I love you too, bot…": "Je taime aussi, bot…",
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.":
"Ce site web utilise une connexion HTTP non sécurisée ! Veuillez lutiliser uniquement pour des tests.", "Ce site web utilise une connexion HTTP non sécurisée ! Veuillez lutiliser uniquement pour des tests.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.":
"Pour plus d'informations <a href=\"%s\">consultez cette rubrique de la FAQ</a>.", "Pour plus d'informations <a href=\"%s\">consultez cette rubrique de la FAQ</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Votre navigateur peut nécessiter une connexion HTTPS pour prendre en charge lAPI WebCrypto. Essayez <a href=\"%s\">de passer en HTTPS</a>." "Votre navigateur peut nécessiter une connexion HTTPS pour prendre en charge lAPI WebCrypto. Essayez <a href=\"%s\">de passer en HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
} }

View File

@ -35,8 +35,6 @@
"JavaScript szükséges a %s működéséhez. Elnézést a fennakadásért.", "JavaScript szükséges a %s működéséhez. Elnézést a fennakadásért.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.":
"A %s működéséhez a jelenleginél újabb böngészőre van szükség.", "A %s működéséhez a jelenleginél újabb böngészőre van szükség.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Még mindig Internet Explorert használsz? Ideje váltani:",
"New": "New":
"Új", "Új",
"Send": "Send":
@ -155,11 +153,12 @@
"Could not get paste data: %s": "Could not get paste data: %s":
"Could not get paste data: %s", "Could not get paste data: %s",
"QR code": "QR code", "QR code": "QR code",
"I love you too, bot…": "I love you too, bot…",
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.":
"This website is using an insecure HTTP connection! Please use it only for testing.", "This website is using an insecure HTTP connection! Please use it only for testing.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</a>.", "For more information <a href=\"%s\">see this FAQ entry</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>." "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
} }

View File

@ -35,8 +35,6 @@
"%s funziona solo con JavaScript attivo.<br />Ci dispiace per l'inconveniente.", "%s funziona solo con JavaScript attivo.<br />Ci dispiace per l'inconveniente.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.":
"%s richiede un browser moderno e aggiornato per funzionare.", "%s richiede un browser moderno e aggiornato per funzionare.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Usi ancora Internet Explorer? Ti consigliamo di passare ad un browser più sicuro:",
"New": "New":
"Nuovo", "Nuovo",
"Send": "Send":
@ -155,11 +153,12 @@
"Could not get paste data: %s": "Could not get paste data: %s":
"Could not get paste data: %s", "Could not get paste data: %s",
"QR code": "QR code", "QR code": "QR code",
"I love you too, bot…": "I love you too, bot…",
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.":
"This website is using an insecure HTTP connection! Please use it only for testing.", "This website is using an insecure HTTP connection! Please use it only for testing.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</a>.", "For more information <a href=\"%s\">see this FAQ entry</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>." "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
} }

View File

@ -35,8 +35,6 @@
"JavaScript vereist om %s te laten werken.<br />Sorry voor het ongemak.", "JavaScript vereist om %s te laten werken.<br />Sorry voor het ongemak.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.":
"%s vereist een moderne browser om te kunnen werken ", "%s vereist een moderne browser om te kunnen werken ",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Gebruik je nog steeds Internet explorer? Doe jezelf een plezier en maak gebruik van een moderne browser:",
"New": "New":
"Nieuw", "Nieuw",
"Send": "Send":
@ -155,11 +153,12 @@
"Could not get paste data: %s": "Could not get paste data: %s":
"Could not get paste data: %s", "Could not get paste data: %s",
"QR code": "QR code", "QR code": "QR code",
"I love you too, bot…": "I love you too, bot…",
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.":
"This website is using an insecure HTTP connection! Please use it only for testing.", "This website is using an insecure HTTP connection! Please use it only for testing.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</a>.", "For more information <a href=\"%s\">see this FAQ entry</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>." "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
} }

View File

@ -35,8 +35,6 @@
"Javascript kreves for at %s skal fungere<br />Beklager.", "Javascript kreves for at %s skal fungere<br />Beklager.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.":
"%s krever en moderne nettleser for å fungere.", "%s krever en moderne nettleser for å fungere.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Fortsatt bruker av Internet Explorer? Gjør deg selv en tjeneste og bytt til en moderne nettleser:",
"New": "New":
"Ny", "Ny",
"Send": "Send":
@ -155,11 +153,12 @@
"Could not get paste data: %s": "Could not get paste data: %s":
"Kunne ikke hente utklippsdata: %s", "Kunne ikke hente utklippsdata: %s",
"QR code": "QR kode", "QR code": "QR kode",
"I love you too, bot…": "Jeg elsker deg også, bot…",
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.":
"Denne websiden bruker usikker HTTP tilkobling! Bruk den kun for testing.", "Denne websiden bruker usikker HTTP tilkobling! Bruk den kun for testing.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.":
"For mer informasjon <a href=\"%s\">se ofte stilte spørsmål</a>.", "For mer informasjon <a href=\"%s\">se ofte stilte spørsmål</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Din nettleser har behov for HTTPS tilkobling for å støtte WebCrypto biblioteket. Prøv å <a href=\"%s\">bytt til HTTPS</a>." "Din nettleser har behov for HTTPS tilkobling for å støtte WebCrypto biblioteket. Prøv å <a href=\"%s\">bytt til HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
} }

View File

@ -35,8 +35,6 @@
"JavaScript es requesit per far foncionar %s. <br />O planhèm per linconvenient.", "JavaScript es requesit per far foncionar %s. <br />O planhèm per linconvenient.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.":
"%s necessita un navigator modèrn per foncionar.", "%s necessita un navigator modèrn per foncionar.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Encora sus Internet Explorer?Fasètz-vos una favor, passatz a un navigator modèrn:",
"New": "New":
"Nòu", "Nòu",
"Send": "Send":
@ -164,11 +162,12 @@
"Could not get paste data: %s": "Could not get paste data: %s":
"Recuperacion impossibla de las donadas copiadas: %s", "Recuperacion impossibla de las donadas copiadas: %s",
"QR code": "Còdi QR", "QR code": "Còdi QR",
"I love you too, bot…": "Taimi tanben, robòt…",
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.":
"Aqueste site utiliza una connexion HTTP pas segura ! Mercés de lutilizar pas que per densages.", "Aqueste site utiliza una connexion HTTP pas segura ! Mercés de lutilizar pas que per densages.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.":
"Per mai dinformacions <a href=\"%s\">vejatz aqueste article de FAQ</a>.", "Per mai dinformacions <a href=\"%s\">vejatz aqueste article de FAQ</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Se pòt que vòstre navigator faga besonh duna connexion HTTPS per èsser compatible amb lAPI WebCrypto. Ensajatz de <a href=\"%s\">passar al HTTPS</a>." "Se pòt que vòstre navigator faga besonh duna connexion HTTPS per èsser compatible amb lAPI WebCrypto. Ensajatz de <a href=\"%s\">passar al HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
} }

View File

@ -35,8 +35,6 @@
"Do działania %sa jest wymagany JavaScript. Przepraszamy za tę niedogodność.", "Do działania %sa jest wymagany JavaScript. Przepraszamy za tę niedogodność.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.":
"%s wymaga do działania nowoczesnej przeglądarki.", "%s wymaga do działania nowoczesnej przeglądarki.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Cały czas używasz Internet Explorera? Zrób sobie przysługę, przesiądź się na nowoczesną przeglądarkę:",
"New": "New":
"Nowa", "Nowa",
"Send": "Send":
@ -155,11 +153,12 @@
"Could not get paste data: %s": "Could not get paste data: %s":
"Nie można było pobrać danych wklejki: %s", "Nie można było pobrać danych wklejki: %s",
"QR code": "Kod QR", "QR code": "Kod QR",
"I love you too, bot…": "I love you too, bot…",
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.":
"This website is using an insecure HTTP connection! Please use it only for testing.", "This website is using an insecure HTTP connection! Please use it only for testing.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</a>.", "For more information <a href=\"%s\">see this FAQ entry</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>." "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
} }

View File

@ -35,8 +35,6 @@
"JavaScript é necessário para que %s funcione.<br />Pedimos desculpas pela inconveniência.", "JavaScript é necessário para que %s funcione.<br />Pedimos desculpas pela inconveniência.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.":
"%s requer um navegador moderno para funcionar.", "%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": "New":
"Novo", "Novo",
"Send": "Send":
@ -155,11 +153,12 @@
"Could not get paste data: %s": "Could not get paste data: %s":
"Could not get paste data: %s", "Could not get paste data: %s",
"QR code": "QR code", "QR code": "QR code",
"I love you too, bot…": "I love you too, bot…",
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.":
"This website is using an insecure HTTP connection! Please use it only for testing.", "This website is using an insecure HTTP connection! Please use it only for testing.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</a>.", "For more information <a href=\"%s\">see this FAQ entry</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>." "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
} }

View File

@ -35,8 +35,6 @@
"Для работы %s требуется включенный JavaScript.<br />Приносим извинения за неудобства.", "Для работы %s требуется включенный JavaScript.<br />Приносим извинения за неудобства.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.":
"Для работы %s требуется более современный браузер.", "Для работы %s требуется более современный браузер.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"До сих пор используете Internet Explorer? Пожалейте себя, перейдите на более современный браузер:",
"New": "New":
"Новая запись", "Новая запись",
"Send": "Send":
@ -165,11 +163,12 @@
"Could not get paste data: %s": "Could not get paste data: %s":
"Не удалось получить данные записи: %s", "Не удалось получить данные записи: %s",
"QR code": "QR код", "QR code": "QR код",
"I love you too, bot…": "Я тоже люблю тебя, бот…",
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.":
"Данный сайт использует незащищенное HTTP подключение! Пожалуйста используйте его только для тестирования.", "Данный сайт использует незащищенное HTTP подключение! Пожалуйста используйте его только для тестирования.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.":
"Для продробностей <a href=\"%s\">прочтите информацию в FAQ</a>.", "Для продробностей <a href=\"%s\">прочтите информацию в FAQ</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Ваш браузер требует использования HTTPS подключения для поддержки WebCrypto API. Попробуйте <a href=\"%s\">переключиться на HTTPS</a>." "Ваш браузер требует использования HTTPS подключения для поддержки WebCrypto API. Попробуйте <a href=\"%s\">переключиться на HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
} }

View File

@ -35,8 +35,6 @@
"Da %s deluje, moraš vklopiti JavaScript.<br />Oprosti za povročene nevšečnosti.", "Da %s deluje, moraš vklopiti JavaScript.<br />Oprosti za povročene nevšečnosti.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.":
"%s za svoje delovanje potrebuje moderen brskalnik.", "%s za svoje delovanje potrebuje moderen brskalnik.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Še vedno uporabljaš Internet Explorer? Naredi si uslugo, preklopi na moderen brskalnik:",
"New": "New":
"Nov prilepek", "Nov prilepek",
"Send": "Send":
@ -164,11 +162,12 @@
"Could not get paste data: %s": "Could not get paste data: %s":
"Could not get paste data: %s", "Could not get paste data: %s",
"QR code": "QR code", "QR code": "QR code",
"I love you too, bot…": "I love you too, bot…",
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.":
"This website is using an insecure HTTP connection! Please use it only for testing.", "This website is using an insecure HTTP connection! Please use it only for testing.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</a>.", "For more information <a href=\"%s\">see this FAQ entry</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>." "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
} }

View File

@ -35,8 +35,6 @@
"%s需要JavaScript来进行加解密。<br />给你带来的不便敬请谅解。", "%s需要JavaScript来进行加解密。<br />给你带来的不便敬请谅解。",
"%s requires a modern browser to work.": "%s requires a modern browser to work.":
"%s需要在现代浏览器上工作。", "%s需要在现代浏览器上工作。",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"还在使用Internet Explorer对自己好点换一个现代浏览器",
"New": "New":
"新建", "新建",
"Send": "Send":
@ -155,11 +153,12 @@
"Could not get paste data: %s": "Could not get paste data: %s":
"无法获取粘贴数据:%s", "无法获取粘贴数据:%s",
"QR code": "二维码", "QR code": "二维码",
"I love you too, bot…": "I love you too, bot…",
"This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.":
"This website is using an insecure HTTP connection! Please use it only for testing.", "This website is using an insecure HTTP connection! Please use it only for testing.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</a>.", "For more information <a href=\"%s\">see this FAQ entry</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>." "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
} }

View File

@ -19,6 +19,7 @@ global.prettyPrintOne = window.PR.prettyPrintOne;
global.showdown = require('./showdown-1.9.1'); global.showdown = require('./showdown-1.9.1');
global.DOMPurify = require('./purify-2.0.1'); global.DOMPurify = require('./purify-2.0.1');
global.baseX = require('./base-x-3.0.5.1').baseX; global.baseX = require('./base-x-3.0.5.1').baseX;
global.Legacy = require('./legacy').Legacy;
require('./bootstrap-3.3.7'); require('./bootstrap-3.3.7');
require('./privatebin'); require('./privatebin');

309
js/legacy.js Normal file
View File

@ -0,0 +1,309 @@
/**
* PrivateBin
*
* a zero-knowledge paste bin
*
* @see {@link https://github.com/PrivateBin/PrivateBin}
* @copyright 2012 Sébastien SAUVAGE ({@link http://sebsauvage.net})
* @license {@link https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License}
* @version 1.3
* @name Legacy
* @namespace
*
* IMPORTANT NOTICE FOR DEVELOPERS:
* The logic in this file is intended to run in legacy browsers. Avoid any use of:
* - jQuery (doesn't work in older browsers)
* - ES5 or newer in general
* - const/let, use the traditional var declarations instead
* - async/await or Promises, use traditional callbacks
* - shorthand function notation "() => output", use the full "function() {return output;}" style
* - IE doesn't support:
* - URL(), use the traditional window.location object
* - endsWith(), use indexof()
* - yes, this logic needs to support IE 6, to at least display the error message
*/
'use strict';
(function() {
/**
* compatibility check
*
* @name Check
* @class
*/
var Check = (function () {
var me = {};
/**
* Status of the initial check, true means it passed
*
* @private
* @prop {bool}
*/
var status = false;
/**
* Initialization check did run
*
* @private
* @prop {bool}
*/
var init = false;
/**
* blacklist of UserAgents (parts) known to belong to a bot
*
* @private
* @enum {Array}
* @readonly
*/
var badBotUA = [
'Bot',
'bot'
];
/**
* whitelist of top level domains to consider a secure context,
* regardless of protocol
*
* @private
* @enum {Array}
* @readonly
*/
var tld = [
'.onion',
'.i2p'
];
/**
* whitelist of hostnames to consider a secure context,
* regardless of protocol
*
* @private
* @enum {Array}
* @readonly
*/
// whitelists of TLDs & local hostnames
var hostname = [
'localhost',
'127.0.0.1',
'[::1]'
];
/**
* check if the context is secure
*
* @private
* @name Check.isSecureContext
* @function
* @return {bool}
*/
function isSecureContext()
{
// use .isSecureContext if available
if (window.isSecureContext === true || window.isSecureContext === false) {
return window.isSecureContext;
}
// HTTP is obviously insecure
if (window.location.protocol !== 'http:') {
return true;
}
// filter out actually secure connections over HTTP
for (var i = 0; i < tld.length; i++) {
if (
window.location.hostname.indexOf(
tld[i],
window.location.hostname.length - tld[i].length
) !== -1
) {
return true;
}
}
// whitelist localhost for development
for (var j = 0; j < hostname.length; j++) {
if (window.location.hostname === hostname[j]) {
return true;
}
}
// totally INSECURE http protocol!
return false;
}
/**
* checks whether this is a bot we dislike
*
* @private
* @name Check.isBadBot
* @function
* @return {bool}
*/
function isBadBot() {
// check whether a bot user agent part can be found in the current
// user agent
for (var i = 0; i < badBotUA.length; i++) {
if (navigator.userAgent.indexOf(badBotUA[i]) !== -1) {
return true;
}
}
return false;
}
/**
* checks whether this is an unsupported browser, via feature detection
*
* @private
* @name Check.isOldBrowser
* @function
* @return {bool}
*/
function isOldBrowser() {
// webcrypto support
if (!(
'crypto' in window &&
'getRandomValues' in window.crypto &&
'subtle' in window.crypto &&
'encrypt' in window.crypto.subtle &&
'decrypt' in window.crypto.subtle &&
'Uint8Array' in window &&
'Uint32Array' in window
)) {
return true;
}
// async & ES6 support
try {
eval('async () => {}');
} catch (e) {
if (e instanceof SyntaxError) {
return true;
} else {
throw e; // throws CSP error
}
}
return false;
}
/**
* shows an error message
*
* @private
* @name Check.showError
* @param {string} message
* @function
*/
function showError(message)
{
var element = document.getElementById('errormessage');
if (message.indexOf('<a') === -1) {
element.appendChild(
document.createTextNode(message)
);
} else {
element.innerHTML = message;
}
removeHiddenFromId('errormessage');
}
/**
* removes "hidden" CSS class from element with given ID
*
* @private
* @name Check.removeHiddenFromId
* @param {string} id
* @function
*/
function removeHiddenFromId(id)
{
var element = document.getElementById(id);
if (element) {
element.className = element.className.replace(/\bhidden\b/g, '');
}
}
/**
* returns if the check has concluded
*
* @name Check.getInit
* @function
* @return {bool}
*/
me.getInit = function()
{
return init;
};
/**
* returns the current status of the check
*
* @name Check.getStatus
* @function
* @return {bool}
*/
me.getStatus = function()
{
return status;
};
/**
* init on application start, returns an all-clear signal
*
* @name Check.init
* @function
*/
me.init = function()
{
// prevent bots from viewing a paste and potentially deleting data
// when burn-after-reading is set
if (isBadBot()) {
showError('I love you too, bot…');
init = true;
return;
}
if (isOldBrowser()) {
// some browsers (Chrome based ones) would have webcrypto support if using HTTPS
if (!isSecureContext()) {
removeHiddenFromId('insecurecontextnotice');
}
removeHiddenFromId('oldnotice');
init = true;
return;
}
if (!isSecureContext()) {
removeHiddenFromId('httpnotice');
}
init = true;
// only if everything passed, we set the status to true
status = true;
};
return me;
})();
// main application start, called when DOM is fully loaded
if (document.readyState === 'complete' || (!document.attachEvent && document.readyState === 'interactive')) {
Check.init();
} else {
if (document.addEventListener) {
// first choice is DOMContentLoaded event
document.addEventListener('DOMContentLoaded', Check.init, false);
// backup is window load event
window.addEventListener('load', Check.init, false);
} else {
// must be IE
document.attachEvent('onreadystatechange', Check.init);
window.attachEvent('onload', Check.init);
}
}
this.Legacy = {
Check: Check
};
}).call(this);

View File

@ -9,20 +9,12 @@
* @version 1.3 * @version 1.3
* @name PrivateBin * @name PrivateBin
* @namespace * @namespace
*
* global Base64, DOMPurify, FileReader, RawDeflate, history, navigator, prettyPrint, prettyPrintOne, showdown, kjua
*/ */
/** global: Base64 */
/** global: DOMPurify */
/** global: FileReader */
/** global: RawDeflate */
/** global: history */
/** global: navigator */
/** global: prettyPrint */
/** global: prettyPrintOne */
/** global: showdown */
/** global: kjua */
jQuery.fn.draghover = function() { jQuery.fn.draghover = function() {
'use strict';
return this.each(function() { return this.each(function() {
let collection = $(), let collection = $(),
self = $(this); self = $(this);
@ -566,12 +558,11 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// if $element is given, apply text to element // if $element is given, apply text to element
if ($element !== null) { if ($element !== null) {
// get last text node of element // avoid HTML entity encoding if translation contains link
let content = $element.contents(); if (output.indexOf('<a') === -1) {
if (content.length > 1) {
content[content.length - 1].nodeValue = ' ' + output;
} else {
$element.text(output); $element.text(output);
} else {
$element.html(output);
} }
} }
@ -781,15 +772,20 @@ jQuery.PrivateBin = (function($, RawDeflate) {
* @private * @private
* @param {string} message * @param {string} message
* @param {string} mode * @param {string} mode
* @param {object} zlib
* @throws {string}
* @return {ArrayBuffer} data * @return {ArrayBuffer} data
*/ */
async function compress(message, mode) async function compress(message, mode, zlib)
{ {
message = stringToArraybuffer( message = stringToArraybuffer(
utf16To8(message) utf16To8(message)
); );
if (mode === 'zlib') { if (mode === 'zlib') {
return z.deflate(message).buffer; if (typeof zlib === 'undefined') {
throw 'Error compressing paste, due to missing WebAssembly support.'
}
return zlib.deflate(message).buffer;
} }
return message; return message;
} }
@ -803,13 +799,18 @@ jQuery.PrivateBin = (function($, RawDeflate) {
* @private * @private
* @param {ArrayBuffer} data * @param {ArrayBuffer} data
* @param {string} mode * @param {string} mode
* @param {object} zlib
* @throws {string}
* @return {string} message * @return {string} message
*/ */
async function decompress(data, mode) async function decompress(data, mode, zlib)
{ {
if (mode === 'zlib' || mode === 'none') { if (mode === 'zlib' || mode === 'none') {
if (mode === 'zlib') { if (mode === 'zlib') {
data = z.inflate( if (typeof zlib === 'undefined') {
throw 'Error decompressing paste, due to missing WebAssembly support.'
}
data = zlib.inflate(
new Uint8Array(data) new Uint8Array(data)
).buffer; ).buffer;
} }
@ -883,7 +884,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
stringToArraybuffer( stringToArraybuffer(
utf16To8(password) utf16To8(password)
) )
); ).catch(Alert.showError);
password = Array.prototype.map.call( password = Array.prototype.map.call(
new Uint8Array(passwordBuffer), new Uint8Array(passwordBuffer),
x => ('00' + x.toString(16)).slice(-2) x => ('00' + x.toString(16)).slice(-2)
@ -903,7 +904,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
{name: 'PBKDF2'}, // we use PBKDF2 for key derivation {name: 'PBKDF2'}, // we use PBKDF2 for key derivation
false, // the key may not be exported false, // the key may not be exported
['deriveKey'] // we may only use it for key derivation ['deriveKey'] // we may only use it for key derivation
); ).catch(Alert.showError);
// derive a stronger key for use with AES // derive a stronger key for use with AES
return window.crypto.subtle.deriveKey( return window.crypto.subtle.deriveKey(
@ -920,7 +921,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
}, },
false, // the key may not be exported false, // the key may not be exported
['encrypt', 'decrypt'] // we may only use it for en- and decryption ['encrypt', 'decrypt'] // we may only use it for en- and decryption
); ).catch(Alert.showError);
} }
/** /**
@ -957,18 +958,24 @@ jQuery.PrivateBin = (function($, RawDeflate) {
*/ */
me.cipher = async function(key, password, message, adata) me.cipher = async function(key, password, message, adata)
{ {
let zlib = (await z);
// AES in Galois Counter Mode, keysize 256 bit, // AES in Galois Counter Mode, keysize 256 bit,
// authentication tag 128 bit, 10000 iterations in key derivation // authentication tag 128 bit, 10000 iterations in key derivation
const spec = [ const compression = (
getRandomBytes(16), // initialization vector typeof zlib === 'undefined' ?
getRandomBytes(8), // salt 'none' : // client lacks support for WASM
100000, // iterations ($('body').data('compression') || 'zlib')
256, // key size ),
128, // tag size spec = [
'aes', // algorithm getRandomBytes(16), // initialization vector
'gcm', // algorithm mode getRandomBytes(8), // salt
$('body').data('compression') || 'zlib' // compression 100000, // iterations
], encodedSpec = []; 256, // key size
128, // tag size
'aes', // algorithm
'gcm', // algorithm mode
compression // compression
], encodedSpec = [];
for (let i = 0; i < spec.length; ++i) { for (let i = 0; i < spec.length; ++i) {
encodedSpec[i] = i < 2 ? btoa(spec[i]) : spec[i]; encodedSpec[i] = i < 2 ? btoa(spec[i]) : spec[i];
} }
@ -987,8 +994,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
await window.crypto.subtle.encrypt( await window.crypto.subtle.encrypt(
cryptoSettings(JSON.stringify(adata), spec), cryptoSettings(JSON.stringify(adata), spec),
await deriveKey(key, password, spec), await deriveKey(key, password, spec),
await compress(message, spec[7]) await compress(message, compression, zlib)
) ).catch(Alert.showError)
) )
), ),
adata adata
@ -1008,7 +1015,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
*/ */
me.decipher = async function(key, password, data) me.decipher = async function(key, password, data)
{ {
let adataString, spec, cipherMessage; let adataString, spec, cipherMessage, plaintext;
let zlib = (await z);
if (data instanceof Array) { if (data instanceof Array) {
// version 2 // version 2
adataString = JSON.stringify(data[1]); adataString = JSON.stringify(data[1]);
@ -1035,20 +1043,29 @@ jQuery.PrivateBin = (function($, RawDeflate) {
} }
spec[0] = atob(spec[0]); spec[0] = atob(spec[0]);
spec[1] = atob(spec[1]); spec[1] = atob(spec[1]);
if (spec[7] === 'zlib') {
if (typeof zlib === 'undefined') {
throw 'Error decompressing paste, due to missing WebAssembly support.'
}
}
try { try {
return await decompress( plaintext = await window.crypto.subtle.decrypt(
await window.crypto.subtle.decrypt( cryptoSettings(adataString, spec),
cryptoSettings(adataString, spec), await deriveKey(key, password, spec),
await deriveKey(key, password, spec), stringToArraybuffer(
stringToArraybuffer( atob(cipherMessage)
atob(cipherMessage) )
)
),
spec[7]
); );
} catch(err) { } catch(err) {
console.error(err);
return ''; return '';
} }
try {
return await decompress(plaintext, spec[7], zlib);
} catch(err) {
Alert.showError(err);
return err;
}
}; };
/** /**
@ -1194,7 +1211,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
me.getPasteId = function() me.getPasteId = function()
{ {
const idRegEx = /^[a-z0-9]{16}$/; const idRegEx = /^[a-z0-9]{16}$/;
const idRegExFind = /[a-z0-9]{16}/;
// return cached value // return cached value
if (id !== null) { if (id !== null) {
@ -1483,7 +1499,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
const alertType = [ const alertType = [
'loading', // not in bootstrap CSS, but using a plausible value here 'loading', // not in bootstrap CSS, but using a plausible value here
'info', // status icon 'info', // status icon
'warning', // not used yet 'warning', // warning icon
'danger' // error icon 'danger' // error icon
]; ];
@ -1527,28 +1543,35 @@ jQuery.PrivateBin = (function($, RawDeflate) {
icon = null; // icons not supported in this case icon = null; // icons not supported in this case
} }
} }
let $translationTarget = $element;
// handle icon // handle icon, if template uses one
if (icon !== null && // icon was passed const $glyphIcon = $element.find(':first');
icon !== currentIcon[id] // and it differs from current icon if ($glyphIcon.length) {
) { // if there is an icon, we need to provide an inner element
let $glyphIcon = $element.find(':first'); // to translate the message into, instead of the parent
$translationTarget = $('<span>');
$element.html(' ').prepend($glyphIcon).append($translationTarget);
// remove (previous) icon if (icon !== null && // icon was passed
$glyphIcon.removeClass(currentIcon[id]); icon !== currentIcon[id] // and it differs from current icon
) {
// remove (previous) icon
$glyphIcon.removeClass(currentIcon[id]);
// any other thing as a string (e.g. 'null') (only) removes the icon // any other thing as a string (e.g. 'null') (only) removes the icon
if (typeof icon === 'string') { if (typeof icon === 'string') {
// set new icon // set new icon
currentIcon[id] = 'glyphicon-' + icon; currentIcon[id] = 'glyphicon-' + icon;
$glyphIcon.addClass(currentIcon[id]); $glyphIcon.addClass(currentIcon[id]);
}
} }
} }
// show text // show text
if (args !== null) { if (args !== null) {
// add jQuery object to it as first parameter // add jQuery object to it as first parameter
args.unshift($element); args.unshift($translationTarget);
// pass it to I18n // pass it to I18n
I18n._.apply(this, args); I18n._.apply(this, args);
} }
@ -1573,6 +1596,25 @@ jQuery.PrivateBin = (function($, RawDeflate) {
handleNotification(1, $statusMessage, message, icon); handleNotification(1, $statusMessage, message, icon);
}; };
/**
* display a warning message
*
* This automatically passes the text to I18n for translation.
*
* @name Alert.showWarning
* @function
* @param {string|array} message string, use an array for %s/%d options
* @param {string|null} icon optional, the icon to show, default:
* leave previous icon
*/
me.showWarning = function(message, icon)
{
$errorMessage.find(':first')
.removeClass(currentIcon[3])
.addClass(currentIcon[2]);
handleNotification(2, $errorMessage, message, icon);
};
/** /**
* display an error message * display an error message
* *
@ -1699,7 +1741,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
currentIcon = [ currentIcon = [
'glyphicon-time', // loading icon 'glyphicon-time', // loading icon
'glyphicon-info-sign', // status icon 'glyphicon-info-sign', // status icon
'', // reserved for warning, not used yet 'glyphicon-warning-sign', // warning icon
'glyphicon-alert' // error icon 'glyphicon-alert' // error icon
]; ];
}; };
@ -1768,14 +1810,14 @@ jQuery.PrivateBin = (function($, RawDeflate) {
return; return;
} }
} }
Alert.showError( Alert.showError('Cannot parse response from URL shortener.');
I18n._('Cannot parse response from URL shortener.')
);
} }
}) })
.fail(function(data, textStatus, errorThrown) { .fail(function(data, textStatus, errorThrown) {
console.error(textStatus, errorThrown); console.error(textStatus, errorThrown);
// we don't know why it failed, could be CORS of the external server not setup properly, in which case we follow old behavior to open it in new tab // we don't know why it failed, could be CORS of the external
// server not setup properly, in which case we follow old
// behavior to open it in new tab
window.open( window.open(
`${$shortenButton.data('shortener')}${encodeURIComponent($pasteUrl.attr('href'))}`, `${$shortenButton.data('shortener')}${encodeURIComponent($pasteUrl.attr('href'))}`,
'_blank', '_blank',
@ -2731,9 +2773,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// revert loading status… // revert loading status…
me.hideAttachment(); me.hideAttachment();
me.hideAttachmentPreview(); me.hideAttachmentPreview();
Alert.showError( Alert.showWarning('Your browser does not support uploading encrypted files. Please use a newer browser.');
I18n._('Your browser does not support uploading encrypted files. Please use a newer browser.')
);
return; return;
} }
@ -2965,11 +3005,11 @@ jQuery.PrivateBin = (function($, RawDeflate) {
me.init = function() me.init = function()
{ {
$attachment = $('#attachment'); $attachment = $('#attachment');
if($attachment.length){ $dragAndDropFileName = $('#dragAndDropFileName');
$dropzone = $('#dropzone');
if($attachment.length) {
$attachmentLink = $('#attachment a'); $attachmentLink = $('#attachment a');
$attachmentPreview = $('#attachmentPreview'); $attachmentPreview = $('#attachmentPreview');
$dragAndDropFileName = $('#dragAndDropFileName');
$dropzone = $('#dropzone');
$fileInput = $('#file'); $fileInput = $('#file');
addDragDropHandler(); addDragDropHandler();
@ -4194,8 +4234,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
const PasteEncrypter = (function () { const PasteEncrypter = (function () {
const me = {}; const me = {};
let requirementsChecked = false;
/** /**
* called after successful paste upload * called after successful paste upload
* *
@ -4428,16 +4466,13 @@ jQuery.PrivateBin = (function($, RawDeflate) {
}); });
cipherMessage['attachment'] = await fileReading; cipherMessage['attachment'] = await fileReading;
} else { } else {
Alert.showError( const error = 'Cannot process attachment data.';
I18n._('Cannot process attachment data.') Alert.showError(error);
); throw new TypeError(error);
throw new TypeError('Cannot process attachment data.');
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
Alert.showError( Alert.showError('Cannot retrieve attachment.');
I18n._('Cannot retrieve attachment.')
);
throw error; throw error;
} }
} }
@ -4494,7 +4529,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// if all tries failed, we can only return an error // if all tries failed, we can only return an error
if (plaindata.length === 0) { if (plaindata.length === 0) {
throw 'failed to decipher data'; return false;
} }
return plaindata; return plaindata;
@ -4523,13 +4558,14 @@ jQuery.PrivateBin = (function($, RawDeflate) {
if (password.length === 0) { if (password.length === 0) {
throw 'waiting on user to provide a password'; throw 'waiting on user to provide a password';
} else { } else {
displayDecryptionError('failed to decipher paste text: Incorrect password?'); Alert.hideLoading();
throw 'waiting on user to provide correct password'; // reset password, so it can be re-entered
Prompt.reset();
TopNav.showRetryButton();
throw 'Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.';
} }
} }
let format = '',
text = '';
if (paste.v > 1) { if (paste.v > 1) {
// version 2 paste // version 2 paste
const pasteMessage = JSON.parse(pastePlain); const pasteMessage = JSON.parse(pastePlain);
@ -4616,29 +4652,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
}); });
} }
/**
* displays and logs decryption errors
*
* @name PasteDecrypter.displayDecryptionError
* @private
* @function
* @param {string} message
*/
function displayDecryptionError(message)
{
Alert.hideLoading();
// log detailed error, but display generic translation
console.error(message);
Alert.showError(
I18n._('Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.')
);
// reset password, so it can be re-entered
Prompt.reset();
TopNav.showRetryButton();
}
/** /**
* show decrypted text in the display area, including discussion (if open) * show decrypted text in the display area, including discussion (if open)
* *
@ -4690,170 +4703,13 @@ jQuery.PrivateBin = (function($, RawDeflate) {
.catch((err) => { .catch((err) => {
// wait for the user to type in the password, // wait for the user to type in the password,
// then PasteDecrypter.run will be called again // then PasteDecrypter.run will be called again
console.error(err); Alert.showError(err);
}); });
}; };
return me; return me;
})(); })();
/**
* initial (security) check
*
* @name InitialCheck
* @param {object} window
* @param {object} document
* @class
*/
const InitialCheck = (function () {
const me = {};
/**
* blacklist of UserAgents (parts) known to belong to a bot
*
* @private
* @enum {Array}
* @readonly
*/
const badBotUA = [
'Bot',
'bot'
];
/**
* check if the connection is insecure
*
* @private
* @name InitialCheck.isInsecureConnection
* @function
* @return {bool}
*/
function isInsecureConnection()
{
// use .isSecureContext if available
if (window.isSecureContext === true || window.isSecureContext === false) {
return !window.isSecureContext;
}
const url = new URL(window.location);
// HTTP is obviously insecure
if (url.protocol !== 'http:') {
return false;
}
// filter out actually secure connections over HTTP
for (const tld of ['.onion', '.i2p']) {
if (url.hostname.endsWith(tld)) {
return false;
}
}
// whitelist localhost for development
for (const hostname of ['localhost', '127.0.0.1', '[::1]']) {
if (url.hostname === hostname) {
return false;
}
}
// totally INSECURE http protocol!
return true;
}
/**
* checks whether this is a bot we dislike
*
* @private
* @name InitialCheck.isBadBot
* @function
* @return {bool}
*/
function isBadBot() {
// check whether a bot user agent part can be found in the current
// user agent
for (const UAfragment of badBotUA) {
if (navigator.userAgent.indexOf(UAfragment) >= 0) {
return true;
}
}
return false;
}
/**
* checks whether this is an unsupported browser, via feature detection
*
* @private
* @name InitialCheck.isOldBrowser
* @function
* @return {bool}
*/
function isOldBrowser() {
// webcrypto support
if (typeof window.crypto !== 'object') {
return true;
}
if (typeof WebAssembly !== 'object' && typeof WebAssembly.instantiate !== 'function') {
return true;
}
try {
// [\0, 'a', 's', 'm', (uint_32) 1] - smallest valid wasm module
const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
if (
!(
module instanceof WebAssembly.Module &&
new WebAssembly.Instance(module) instanceof WebAssembly.Instance
)
) {
return true;
}
} catch (e) {
return true;
}
// not checking for async/await, ES6, Promise or Uint8Array support,
// as most browsers introduced these earlier then webassembly and webcrypto:
// https://github.com/PrivateBin/PrivateBin/pull/431#issuecomment-493129359
return false;
}
/**
* init on application start, returns an all-clear signal
*
* @name InitialCheck.init
* @function
* @return {bool}
*/
me.init = function()
{
// prevent bots from viewing a paste and potentially deleting data
// when burn-after-reading is set
if (isBadBot()) {
Alert.showError('I love you too, bot…');
return false;
}
if (isOldBrowser()) {
// some browsers (Chrome based ones) would have webcrypto support if using HTTPS
if (isInsecureConnection()) {
Alert.showError(['Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href="%s">switching to HTTPS</a>.', 'https' + window.location.href.slice(4)]);
}
$('#oldnotice').removeClass('hidden');
return false;
}
if (isInsecureConnection()) {
$('#httpnotice').removeClass('hidden');
}
return true;
}
return me;
})();
/** /**
* (controller) main PrivateBin logic * (controller) main PrivateBin logic
* *
@ -4926,9 +4782,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// missing decryption key (or paste ID) in URL? // missing decryption key (or paste ID) in URL?
if (window.location.hash.length === 0) { if (window.location.hash.length === 0) {
Alert.showError( Alert.showError('Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)');
I18n._('Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)')
);
return; return;
} }
} }
@ -5030,13 +4884,29 @@ jQuery.PrivateBin = (function($, RawDeflate) {
DiscussionViewer.prepareNewDiscussion(); DiscussionViewer.prepareNewDiscussion();
}; };
/**
* try initializing zlib or display a warning if it fails,
* extracted from main init to allow unit testing
*
* @name Controller.initZ
* @function
*/
me.initZ = function()
{
z = zlib.catch(function () {
if ($('body').data('compression') !== 'none') {
Alert.showWarning('Your browser doesn\'t support WebAssembly, used for zlib compression. You can create uncompressed documents, but can\'t read compressed ones.');
}
});
}
/** /**
* application start * application start
* *
* @name Controller.init * @name Controller.init
* @function * @function
*/ */
me.init = async function() me.init = function()
{ {
// first load translations // first load translations
I18n.loadTranslations(); I18n.loadTranslations();
@ -5054,11 +4924,18 @@ jQuery.PrivateBin = (function($, RawDeflate) {
Prompt.init(); Prompt.init();
TopNav.init(); TopNav.init();
UiHelper.init(); UiHelper.init();
z = (await zlib);
if (!InitialCheck.init()) { // check for legacy browsers before going any further
if (!Legacy.Check.getInit()) {
// Legacy check didn't complete, wait and try again
setTimeout(init, 500);
return;
}
if (!Legacy.Check.getStatus()) {
// something major is wrong, stop right away // something major is wrong, stop right away
return; return;
} }
me.initZ();
// check whether existing paste needs to be shown // check whether existing paste needs to be shown
try { try {
@ -5098,7 +4975,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
ServerInteraction: ServerInteraction, ServerInteraction: ServerInteraction,
PasteEncrypter: PasteEncrypter, PasteEncrypter: PasteEncrypter,
PasteDecrypter: PasteDecrypter, PasteDecrypter: PasteDecrypter,
InitialCheck: InitialCheck,
Controller: Controller Controller: Controller
}; };
})(jQuery, RawDeflate); })(jQuery, RawDeflate);

View File

@ -4,16 +4,55 @@ var common = require('../common');
describe('Alert', function () { describe('Alert', function () {
describe('showStatus', function () { describe('showStatus', function () {
jsc.property( jsc.property(
'shows a status message', 'shows a status message (basic)',
jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()),
function (icon, message) { function (icon, message) {
icon = icon.join(''); icon = icon.join('');
message = message.join(''); message = message.join('');
var expected = '<div id="status" role="alert" ' + const expected = '<div id="status">' + message + '</div>';
$('body').html(
'<div id="status"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showStatus(message, icon);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows a status message (bootstrap)',
jsc.array(common.jscAlnumString()),
function (message) {
message = message.join('');
const expected = '<div id="status" role="alert" ' +
'class="statusmessage alert alert-info"><span ' +
'class="glyphicon glyphicon-info-sign" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
'<div id="status" role="alert" class="statusmessage ' +
'alert alert-info hidden"><span class="glyphicon ' +
'glyphicon-info-sign" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showStatus(message);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows a status message (bootstrap, custom icon)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
icon = icon.join('');
message = message.join('');
const expected = '<div id="status" role="alert" ' +
'class="statusmessage alert alert-info"><span ' + 'class="statusmessage alert alert-info"><span ' +
'class="glyphicon glyphicon-' + icon + 'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> ' + message + '</div>'; '" aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html( $('body').html(
'<div id="status" role="alert" class="statusmessage ' + '<div id="status" role="alert" class="statusmessage ' +
'alert alert-info hidden"><span class="glyphicon ' + 'alert alert-info hidden"><span class="glyphicon ' +
@ -21,7 +60,76 @@ describe('Alert', function () {
); );
$.PrivateBin.Alert.init(); $.PrivateBin.Alert.init();
$.PrivateBin.Alert.showStatus(message, icon); $.PrivateBin.Alert.showStatus(message, icon);
var result = $('body').html(); const result = $('body').html();
return expected === result;
}
);
});
describe('showWarning', function () {
before(function () {
cleanup();
});
jsc.property(
'shows a warning message (basic)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
icon = icon.join('');
message = message.join('');
const expected = '<div id="errormessage">' + message + '</div>';
$('body').html(
'<div id="errormessage"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showWarning(message, icon);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows a warning message (bootstrap)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (message) {
message = message.join('');
const expected = '<div id="errormessage" role="alert" ' +
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-warning-sign" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showWarning(message);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows a warning message (bootstrap, custom icon)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
icon = icon.join('');
message = message.join('');
const expected = '<div id="errormessage" role="alert" ' +
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showWarning(message, icon);
const result = $('body').html();
return expected === result; return expected === result;
} }
); );
@ -33,16 +141,56 @@ describe('Alert', function () {
}); });
jsc.property( jsc.property(
'shows an error message', 'shows an error message (basic)',
jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()),
function (icon, message) { function (icon, message) {
icon = icon.join(''); icon = icon.join('');
message = message.join(''); message = message.join('');
var expected = '<div id="errormessage" role="alert" ' + const expected = '<div id="errormessage">' + message + '</div>';
$('body').html(
'<div id="errormessage"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showError(message, icon);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows an error message (bootstrap)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
message = message.join('');
const expected = '<div id="errormessage" role="alert" ' +
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-alert" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showError(message);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows an error message (bootstrap, custom icon)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
icon = icon.join('');
message = message.join('');
const expected = '<div id="errormessage" role="alert" ' +
'class="statusmessage alert alert-danger"><span ' + 'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-' + icon + 'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> ' + message + '</div>'; '" aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html( $('body').html(
'<div id="errormessage" role="alert" class="statusmessage ' + '<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' + 'alert alert-danger hidden"><span class="glyphicon ' +
@ -50,7 +198,7 @@ describe('Alert', function () {
); );
$.PrivateBin.Alert.init(); $.PrivateBin.Alert.init();
$.PrivateBin.Alert.showError(message, icon); $.PrivateBin.Alert.showError(message, icon);
var result = $('body').html(); const result = $('body').html();
return expected === result; return expected === result;
} }
); );
@ -62,17 +210,36 @@ describe('Alert', function () {
}); });
jsc.property( jsc.property(
'shows remaining time', 'shows remaining time (basic)',
jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()),
'integer', 'integer',
function (message, string, number) { function (message, string, number) {
message = message.join(''); message = message.join('');
string = string.join(''); string = string.join('');
var expected = '<div id="remainingtime" role="alert" ' + const expected = '<div id="remainingtime" class="">' + string + message + number + '</div>';
$('body').html(
'<div id="remainingtime" class="hidden"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows remaining time (bootstrap)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
'integer',
function (message, string, number) {
message = message.join('');
string = string.join('');
const expected = '<div id="remainingtime" role="alert" ' +
'class="alert alert-info"><span ' + 'class="alert alert-info"><span ' +
'class="glyphicon glyphicon-fire" aria-hidden="true">' + 'class="glyphicon glyphicon-fire" aria-hidden="true">' +
'</span> ' + string + message + number + '</div>'; '</span> <span>' + string + message + number + '</span></div>';
$('body').html( $('body').html(
'<div id="remainingtime" role="alert" class="hidden ' + '<div id="remainingtime" role="alert" class="hidden ' +
'alert alert-info"><span class="glyphicon ' + 'alert alert-info"><span class="glyphicon ' +
@ -80,7 +247,7 @@ describe('Alert', function () {
); );
$.PrivateBin.Alert.init(); $.PrivateBin.Alert.init();
$.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]); $.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]);
var result = $('body').html(); const result = $('body').html();
return expected === result; return expected === result;
} }
); );
@ -92,20 +259,42 @@ describe('Alert', function () {
}); });
jsc.property( jsc.property(
'shows a loading message', 'shows a loading message (basic)',
jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()),
function (message, icon) { function (message, icon) {
message = message.join(''); message = message.join('');
icon = icon.join(''); icon = icon.join('');
var defaultMessage = 'Loading…'; const defaultMessage = 'Loading…';
if (message.length === 0) { if (message.length === 0) {
message = defaultMessage; message = defaultMessage;
} }
var expected = '<ul class="nav navbar-nav"><li ' + const expected = '<div id="loadingindicator" class="">' + message + '</div>';
$('body').html(
'<div id="loadingindicator" class="hidden">' + defaultMessage + '</div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showLoading(message, icon);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows a loading message (bootstrap)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (message, icon) {
message = message.join('');
icon = icon.join('');
const defaultMessage = 'Loading…';
if (message.length === 0) {
message = defaultMessage;
}
const expected = '<ul class="nav navbar-nav"><li ' +
'id="loadingindicator" class="navbar-text"><span ' + 'id="loadingindicator" class="navbar-text"><span ' +
'class="glyphicon glyphicon-' + icon + 'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> ' + message + '</li></ul>'; '" aria-hidden="true"></span> <span>' + message + '</span></li></ul>';
$('body').html( $('body').html(
'<ul class="nav navbar-nav"><li id="loadingindicator" ' + '<ul class="nav navbar-nav"><li id="loadingindicator" ' +
'class="navbar-text hidden"><span class="glyphicon ' + 'class="navbar-text hidden"><span class="glyphicon ' +
@ -114,7 +303,7 @@ describe('Alert', function () {
); );
$.PrivateBin.Alert.init(); $.PrivateBin.Alert.init();
$.PrivateBin.Alert.showLoading(message, icon); $.PrivateBin.Alert.showLoading(message, icon);
var result = $('body').html(); const result = $('body').html();
return expected === result; return expected === result;
} }
); );
@ -182,7 +371,7 @@ describe('Alert', function () {
jsc.array(common.jscAlnumString()), jsc.array(common.jscAlnumString()),
function (trigger, message) { function (trigger, message) {
message = message.join(''); message = message.join('');
var handlerCalled = false, let handlerCalled = false,
defaultMessage = 'Loading…', defaultMessage = 'Loading…',
functions = [ functions = [
$.PrivateBin.Alert.showStatus, $.PrivateBin.Alert.showStatus,

83
js/test/Check.js Normal file
View File

@ -0,0 +1,83 @@
'use strict';
var common = require('../common');
/* global Legacy, WebCrypto */
describe('Check', function () {
describe('init', function () {
this.timeout(30000);
before(function () {
cleanup();
});
it('returns false and shows error, if a bot UA is detected', function () {
jsc.assert(jsc.forall(
'string',
jsc.elements(['Bot', 'bot']),
'string',
function (prefix, botBit, suffix) {
const clean = jsdom(
'<html><body><div id="errormessage" class="hidden"></div>' +
'</body></html>', {
'userAgent': prefix + botBit + suffix
}
);
Legacy.Check.init();
const result1 = Legacy.Check.getInit() && !Legacy.Check.getStatus(),
result2 = (document.getElementById('errormessage').className !== 'hidden');
clean();
return result1 && result2;
}
),
{tests: 10});
});
jsc.property(
'shows error, if no webcrypto is detected',
'bool',
jsc.elements(['localhost', '127.0.0.1', '[::1]', '']),
jsc.nearray(common.jscA2zString()),
jsc.elements(['.onion', '.i2p', '']),
function (secureProtocol, localhost, domain, tld) {
const isDomain = localhost === '',
isSecureContext = secureProtocol || !isDomain || tld.length > 0,
clean = jsdom(
'<html><body><div id="errormessage" class="hidden"></div>' +
'<div id="oldnotice" class="hidden"></div>' +
'<div id="insecurecontextnotice" class="hidden"></div></body></html>',
{
'url': (secureProtocol ? 'https' : 'http' ) + '://' +
(isDomain ? domain.join('') + tld : localhost) + '/'
}
);
Legacy.Check.init();
const result1 = Legacy.Check.getInit() && !Legacy.Check.getStatus(),
result2 = isSecureContext === (document.getElementById('insecurecontextnotice').className === 'hidden'),
result3 = (document.getElementById('oldnotice').className !== 'hidden');
clean();
return result1 && result2 && result3;
}
);
jsc.property(
'shows error, if HTTP only site is detected',
'bool',
jsc.nearray(common.jscA2zString()),
function (secureProtocol, domain) {
const clean = jsdom(
'<html><body><div id="httpnotice" class="hidden"></div>' +
'</body></html>',
{
'url': (secureProtocol ? 'https' : 'http' ) + '://' + domain.join('') + '/'
}
);
window.crypto = new WebCrypto();
Legacy.Check.init();
const result1 = Legacy.Check.getInit() && Legacy.Check.getStatus(),
result2 = secureProtocol === (document.getElementById('httpnotice').className === 'hidden');
clean();
return result1 && result2;
}
);
});
});

View File

@ -18,13 +18,15 @@ describe('CryptTool', function () {
// pause to let async functions conclude // pause to let async functions conclude
await new Promise(resolve => setTimeout(resolve, 300)); await new Promise(resolve => setTimeout(resolve, 300));
let clean = jsdom(); let clean = jsdom();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
window.crypto = new WebCrypto(); window.crypto = new WebCrypto();
message = message.trim(); message = message.trim();
let cipherMessage = await $.PrivateBin.CryptTool.cipher( let cipherMessage = await $.PrivateBin.CryptTool.cipher(
key, password, message, [] key, password, message, []
), ),
plaintext = await $.PrivateBin.CryptTool.decipher( plaintext = await $.PrivateBin.CryptTool.decipher(
key, password, cipherMessage key, password, cipherMessage
); );
clean(); clean();
return message === plaintext; return message === plaintext;
@ -179,6 +181,8 @@ describe('CryptTool', function () {
let message = fs.readFileSync('test/compression-sample.txt', 'utf8'), let message = fs.readFileSync('test/compression-sample.txt', 'utf8'),
clean = jsdom(); clean = jsdom();
window.crypto = new WebCrypto(); window.crypto = new WebCrypto();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
let cipherMessage = await $.PrivateBin.CryptTool.cipher( let cipherMessage = await $.PrivateBin.CryptTool.cipher(
'foo', 'bar', message, [] 'foo', 'bar', message, []
), ),
@ -222,6 +226,8 @@ isWhile : interp (while expr sBody) (MemElem mem) =
conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem)) conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
`; `;
let clean = jsdom(); let clean = jsdom();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
window.crypto = new WebCrypto(); window.crypto = new WebCrypto();
let cipherMessage = await $.PrivateBin.CryptTool.cipher( let cipherMessage = await $.PrivateBin.CryptTool.cipher(
key, password, message, [] key, password, message, []

View File

@ -183,9 +183,9 @@ describe('Helper', function () {
'string', 'string',
'string', 'string',
function (prefix, uint, middle, string, postfix) { function (prefix, uint, middle, string, postfix) {
prefix = prefix.replace(/%(s|d)/g, '%%'); prefix = prefix.replace(/%(s|d)/g, '');
middle = middle.replace(/%(s|d)/g, '%%'); middle = middle.replace(/%(s|d)/g, '');
postfix = postfix.replace(/%(s|d)/g, '%%'); postfix = postfix.replace(/%(s|d)/g, '');
var params = [prefix + '%d' + middle + '%s' + postfix, uint, string], var params = [prefix + '%d' + middle + '%s' + postfix, uint, string],
result = prefix + uint + middle + string + postfix; result = prefix + uint + middle + string + postfix;
return result === $.PrivateBin.Helper.sprintf.apply(this, params); return result === $.PrivateBin.Helper.sprintf.apply(this, params);
@ -199,9 +199,9 @@ describe('Helper', function () {
'string', 'string',
'string', 'string',
function (prefix, uint, middle, string, postfix) { function (prefix, uint, middle, string, postfix) {
prefix = prefix.replace(/%(s|d)/g, '%%'); prefix = prefix.replace(/%(s|d)/g, '');
middle = middle.replace(/%(s|d)/g, '%%'); middle = middle.replace(/%(s|d)/g, '');
postfix = postfix.replace(/%(s|d)/g, '%%'); postfix = postfix.replace(/%(s|d)/g, '');
var params = [prefix + '%s' + middle + '%d' + postfix, string, uint], var params = [prefix + '%s' + middle + '%d' + postfix, string, uint],
result = prefix + string + middle + uint + postfix; result = prefix + string + middle + uint + postfix;
return result === $.PrivateBin.Helper.sprintf.apply(this, params); return result === $.PrivateBin.Helper.sprintf.apply(this, params);

View File

@ -1,88 +0,0 @@
'use strict';
var common = require('../common');
describe('InitialCheck', function () {
describe('init', function () {
this.timeout(30000);
before(function () {
cleanup();
});
it('returns false and shows error, if a bot UA is detected', function () {
jsc.assert(jsc.forall(
'string',
jsc.elements(['Bot', 'bot']),
'string',
function (prefix, botBit, suffix) {
const clean = jsdom('', {
'userAgent': prefix + botBit + suffix
});
$('body').html(
'<html><body><div id="errormessage" class="hidden"></div>' +
'</body></html>'
);
$.PrivateBin.Alert.init();
window.crypto = null;
const result1 = !$.PrivateBin.InitialCheck.init(),
result2 = !$('#errormessage').hasClass('hidden');
clean();
return result1 && result2;
}
),
{tests: 10});
});
jsc.property(
'shows error, if no webcrypto is detected',
'bool',
jsc.elements(['localhost', '127.0.0.1', '[::1]', '']),
jsc.nearray(common.jscA2zString()),
jsc.elements(['.onion', '.i2p', '']),
function (secureProtocol, localhost, domain, tld) {
const isDomain = localhost === '',
isSecureContext = secureProtocol || !isDomain || tld.length > 0,
clean = jsdom('', {
'url': (secureProtocol ? 'https' : 'http' ) + '://' +
(isDomain ? domain.join('') + tld : localhost) + '/'
});
$('body').html(
'<html><body><div id="errormessage" class="hidden"></div>'+
'<div id="oldnotice" class="hidden"></div></body></html>'
);
$.PrivateBin.Alert.init();
const result1 = !$.PrivateBin.InitialCheck.init(),
result2 = isSecureContext === $('#errormessage').hasClass('hidden'),
result3 = !$('#oldnotice').hasClass('hidden');
clean();
return result1 && result2 && result3;
}
);
jsc.property(
'shows error, if HTTP only site is detected',
'bool',
jsc.elements(['localhost', '127.0.0.1', '[::1]', '']),
jsc.nearray(common.jscA2zString()),
jsc.elements(['.onion', '.i2p', '']),
function (secureProtocol, localhost, domain, tld) {
const isDomain = localhost === '',
isSecureContext = secureProtocol || !isDomain || tld.length > 0,
clean = jsdom('', {
'url': (secureProtocol ? 'https' : 'http' ) + '://' +
(isDomain ? domain.join('') + tld : localhost) + '/'
});
$('body').html(
'<html><body><div id="httpnotice" class="hidden"></div>'+
'</body></html>'
);
$.PrivateBin.Alert.init();
window.crypto = null;
const result1 = $.PrivateBin.InitialCheck.init(),
result2 = isSecureContext === $('#httpnotice').hasClass('hidden');
clean();
return result1 && result2;
}
);
});
});

View File

@ -388,6 +388,7 @@ class Controller
$page->assign('URLSHORTENER', $this->_conf->getKey('urlshortener')); $page->assign('URLSHORTENER', $this->_conf->getKey('urlshortener'));
$page->assign('QRCODE', $this->_conf->getKey('qrcode')); $page->assign('QRCODE', $this->_conf->getKey('qrcode'));
$page->assign('HTTPWARNING', $this->_conf->getKey('httpwarning')); $page->assign('HTTPWARNING', $this->_conf->getKey('httpwarning'));
$page->assign('HTTPSLINK', 'https://' . $this->_request->getHost() . $this->_request->getRequestUri());
$page->assign('COMPRESSION', $this->_conf->getKey('compression')); $page->assign('COMPRESSION', $this->_conf->getKey('compression'));
$page->draw($this->_conf->getKey('template')); $page->draw($this->_conf->getKey('template'));
} }

View File

@ -193,6 +193,19 @@ class Request
$this->_params[$param] : $default; $this->_params[$param] : $default;
} }
/**
* Get host as requested by the client
*
* @access public
* @return string
*/
public function getHost()
{
return array_key_exists('HTTP_HOST', $_SERVER) ?
htmlspecialchars($_SERVER['HTTP_HOST']) :
'localhost';
}
/** /**
* Get request URI * Get request URI
* *
@ -202,8 +215,8 @@ class Request
public function getRequestUri() public function getRequestUri()
{ {
return array_key_exists('REQUEST_URI', $_SERVER) ? return array_key_exists('REQUEST_URI', $_SERVER) ?
htmlspecialchars( htmlspecialchars(
parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
) : '/'; ) : '/';
} }

View File

@ -5,5 +5,4 @@
# directory. # directory.
User-agent: * User-agent: *
Allow: /index.php
Disallow: / Disallow: /

View File

@ -71,10 +71,8 @@ if ($MARKDOWN):
endif; endif;
?> ?>
<script type="text/javascript" data-cfasync="false" src="js/purify-2.0.1.js" integrity="sha512-ddI36MdUoXp/o7yhQtr9/qj4G3oFwCRga4jCGaoUYtORg0PPmFKVKG4Ess3fIknYzxwwKMlrIL9o4NwuPTCc1Q==" crossorigin="anonymous"></script> <script type="text/javascript" data-cfasync="false" src="js/purify-2.0.1.js" integrity="sha512-ddI36MdUoXp/o7yhQtr9/qj4G3oFwCRga4jCGaoUYtORg0PPmFKVKG4Ess3fIknYzxwwKMlrIL9o4NwuPTCc1Q==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-86VTqw2HsaCQ0DAunK2MH68P+8RLbbaK7HZP8nwDtwNoF44usxDCptmD8TC+zwQc7HM46AkrvVFb3ZkIb6VhMQ==" crossorigin="anonymous"></script> <script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-dReLYyMJO3kV7/etVKlGWSbmJoWavMpbgG8Hg3759MNHv0mYuonh4Azif3y0F0oopKKlz3vtj8XZV7VY+e6dSQ==" crossorigin="anonymous"></script>
<!--[if IE]> <script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-4iMFqnyyoJ/FJ33aHov+QeItaZ0JegMUjx7J5pXeknEwjXzx4oLw9F9ePI3WK/h3sUYTOK+hdv2JINNGMwi2Vg==" crossorigin="anonymous"></script>
<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;}</style>
<![endif]-->
<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" />
<link rel="icon" type="image/png" href="img/favicon-16x16.png?<?php echo rawurlencode($VERSION); ?>" sizes="16x16" /> <link rel="icon" type="image/png" href="img/favicon-16x16.png?<?php echo rawurlencode($VERSION); ?>" sizes="16x16" />
@ -446,10 +444,6 @@ endif;
<div id="oldnotice" role="alert" class="hidden alert alert-danger"> <div id="oldnotice" role="alert" class="hidden alert alert-danger">
<span class="glyphicon glyphicon-alert" aria-hidden="true"></span> <span class="glyphicon glyphicon-alert" aria-hidden="true"></span>
<?php echo I18n::_('%s requires a modern browser to work.', I18n::_($NAME)), PHP_EOL; ?> <?php echo I18n::_('%s requires a modern browser to work.', I18n::_($NAME)), PHP_EOL; ?>
</div>
<div id="ienotice" role="alert" class="hidden alert alert-danger">
<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.mozilla.org/firefox/">Firefox</a>,
<a href="https://www.opera.com/">Opera</a>, <a href="https://www.opera.com/">Opera</a>,
<a href="https://www.google.com/chrome">Chrome</a> <a href="https://www.google.com/chrome">Chrome</a>
@ -462,6 +456,10 @@ if ($HTTPWARNING):
<?php echo I18n::_('This website is using an insecure connection! Please only use it for testing.'), PHP_EOL; ?><br /> <?php echo I18n::_('This website is using an insecure connection! Please only use it for testing.'), PHP_EOL; ?><br />
<span class="small"><?php echo I18n::_('For more information <a href="%s">see this FAQ entry</a>.', 'https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-it-show-me-an-error-about-an-insecure-connection'); ?></span> <span class="small"><?php echo I18n::_('For more information <a href="%s">see this FAQ entry</a>.', 'https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-it-show-me-an-error-about-an-insecure-connection'); ?></span>
</div> </div>
<div id="insecurecontextnotice" role="alert" class="hidden alert alert-danger">
<span class="glyphicon glyphicon-alert" aria-hidden="true"></span>
<?php echo I18n::_('Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href="%s">switching to HTTPS</a>.', $HTTPSLINK); ?>
</div>
<?php <?php
endif; endif;
?> ?>

View File

@ -49,10 +49,8 @@ if ($MARKDOWN):
endif; endif;
?> ?>
<script type="text/javascript" data-cfasync="false" src="js/purify-2.0.1.js" integrity="sha512-ddI36MdUoXp/o7yhQtr9/qj4G3oFwCRga4jCGaoUYtORg0PPmFKVKG4Ess3fIknYzxwwKMlrIL9o4NwuPTCc1Q==" crossorigin="anonymous"></script> <script type="text/javascript" data-cfasync="false" src="js/purify-2.0.1.js" integrity="sha512-ddI36MdUoXp/o7yhQtr9/qj4G3oFwCRga4jCGaoUYtORg0PPmFKVKG4Ess3fIknYzxwwKMlrIL9o4NwuPTCc1Q==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-86VTqw2HsaCQ0DAunK2MH68P+8RLbbaK7HZP8nwDtwNoF44usxDCptmD8TC+zwQc7HM46AkrvVFb3ZkIb6VhMQ==" crossorigin="anonymous"></script> <script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-dReLYyMJO3kV7/etVKlGWSbmJoWavMpbgG8Hg3759MNHv0mYuonh4Azif3y0F0oopKKlz3vtj8XZV7VY+e6dSQ==" crossorigin="anonymous"></script>
<!--[if IE]> <script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-4iMFqnyyoJ/FJ33aHov+QeItaZ0JegMUjx7J5pXeknEwjXzx4oLw9F9ePI3WK/h3sUYTOK+hdv2JINNGMwi2Vg==" crossorigin="anonymous"></script>
<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;}</style>
<![endif]-->
<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" />
<link rel="icon" type="image/png" href="img/favicon-16x16.png?<?php echo rawurlencode($VERSION); ?>" sizes="16x16" /> <link rel="icon" type="image/png" href="img/favicon-16x16.png?<?php echo rawurlencode($VERSION); ?>" sizes="16x16" />
@ -77,8 +75,7 @@ endif;
<h2 class="title"><?php echo I18n::_('Because ignorance is bliss'); ?></h2><br /> <h2 class="title"><?php echo I18n::_('Because ignorance is bliss'); ?></h2><br />
<h3 class="title"><?php echo $VERSION; ?></h3> <h3 class="title"><?php echo $VERSION; ?></h3>
<noscript><div id="noscript" class="nonworking"><?php echo I18n::_('JavaScript is required for %s to work.<br />Sorry for the inconvenience.', I18n::_($NAME)); ?></div></noscript> <noscript><div id="noscript" class="nonworking"><?php echo I18n::_('JavaScript is required for %s to work.<br />Sorry for the inconvenience.', I18n::_($NAME)); ?></div></noscript>
<div id="oldnotice" class="nonworking"><?php echo I18n::_('%s requires a modern browser to work.', I18n::_($NAME)); ?></div> <div id="oldnotice" class="nonworking hidden"><?php echo I18n::_('%s requires a modern browser to work.', I18n::_($NAME)), PHP_EOL; ?>
<div id="ienotice" class="nonworking"><?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.mozilla.org/firefox/">Firefox</a>,
<a href="https://www.opera.com/">Opera</a>, <a href="https://www.opera.com/">Opera</a>,
<a href="https://www.google.com/chrome">Chrome</a> <a href="https://www.google.com/chrome">Chrome</a>
@ -86,10 +83,13 @@ endif;
<?php <?php
if ($HTTPWARNING): if ($HTTPWARNING):
?> ?>
<div id="httpnotice" class="errorMessage"> <div id="httpnotice" class="errorMessage hidden">
<?php echo I18n::_('This website is using an insecure connection! Please only use it for testing.'); ?> <?php echo I18n::_('This website is using an insecure connection! Please only use it for testing.'); ?>
<span class="small"><?php echo I18n::_('For more information <a href="%s">see this FAQ entry</a>.', 'https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-it-show-me-an-error-about-an-insecure-connection'); ?></span> <span class="small"><?php echo I18n::_('For more information <a href="%s">see this FAQ entry</a>.', 'https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-it-show-me-an-error-about-an-insecure-connection'); ?></span>
</div> </div>
<div id="insecurecontextnotice" class="errorMessage hidden">
<?php echo I18n::_('Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href="%s">switching to HTTPS</a>.', $HTTPSLINK); ?>
</div>
<?php <?php
endif; endif;
?> ?>

View File

@ -56,6 +56,7 @@ class ViewTest extends PHPUnit_Framework_TestCase
$page->assign('URLSHORTENER', ''); $page->assign('URLSHORTENER', '');
$page->assign('QRCODE', true); $page->assign('QRCODE', true);
$page->assign('HTTPWARNING', true); $page->assign('HTTPWARNING', true);
$page->assign('HTTPSLINK', 'https://example.com/');
$page->assign('COMPRESSION', 'zlib'); $page->assign('COMPRESSION', 'zlib');
$dir = dir(PATH . 'tpl'); $dir = dir(PATH . 'tpl');