Compare commits

..

48 Commits

Author SHA1 Message Date
rugk
e207f5a0b7 test: remove not required classes 2026-03-25 17:40:32 +00:00
rugk
0de2b52550 chore: improve/guard function if invalid paameter is given 2026-03-25 17:39:20 +00:00
rugk
a1b54fda25 test: fix actual tets problem not using/having a loadig indicator in HTML set 2026-03-25 17:38:54 +00:00
rugk
5acdafaa23 wipfix(devcontainer): fix/use new URL for mocha feature 2026-03-20 16:52:06 +00:00
rugk
a02257a0a3 test: remove asliased cleanup function 2026-03-20 10:22:19 +00:00
rugk
7d09d66b06 test: strengthen PasteStatus test 2026-03-20 09:06:55 +00:00
rugk
13ecf7e7cb test: fix PasteStatus tests by creating pastesuccess notification 2026-03-20 09:06:35 +00:00
rugk
c2bfcc17fd test: explicitly include fs dependency 2026-03-20 08:16:04 +00:00
rugk
045a356c09 test: remove one more jQuery call 2026-03-19 17:23:09 +00:00
rugk
543dc39202 test: remove jQuery from CopyToClipboard even more
Co-Authored-By: Copilot
2026-03-19 17:18:17 +00:00
rugk
fbd697245d refactor: remove jQuery from initializers 2026-03-19 17:15:46 +00:00
rugk
e094c39186 fix: fix nullable problems found via AttachmentViewer test 2026-03-19 17:03:09 +00:00
rugk
784f381e28 test: change all other tests to not use jQuery 2026-03-19 16:53:30 +00:00
rugk
414a87c025 test: use native non jquery for TopNav too fixing most tests of it 2026-03-18 16:09:46 +00:00
rugk
cc431a3f14 test: use document.documentElement.innerHTML for setting test HTML 2026-03-18 14:09:15 +00:00
rugk
3820fdf765 style: remove manual cleanup 2026-03-18 13:58:49 +00:00
rugk
0f3831b423 style: use web APIs to set document instead of jQuery for compatibility 2026-03-18 13:58:24 +00:00
rugk
2cf32c1c75 style(jsdoc): fix typing 2026-03-18 13:57:21 +00:00
rugk
1104873830 test: fix tests error again 2026-03-18 13:57:09 +00:00
rugk
2678d2c2b2 test: fix test & implementation error with missing buttons (ids) in UI 2026-03-03 11:08:45 +00:00
rugk
3de6dc9f68 test: use cleanup function everywhere instead of jsdom manually 2026-03-03 11:01:30 +00:00
rugk
778df44b0b test: manually remove useless cleanup stuff 2026-03-03 11:00:25 +00:00
rugk
69533d493b Merge branch 'master' of https://github.com/PrivateBin/PrivateBin into js/removeJQuery 2026-03-03 10:28:27 +00:00
rugk
dbd380332c style: fix ESLint no-return-assign 2026-03-03 10:12:32 +00:00
rugk
d5bf7674ff style: use template literal 2026-03-03 10:07:52 +00:00
rugk
3a08f1866d chore: use correct base href 2026-03-03 10:02:22 +00:00
rugk
194eb93d00 chore: stay on ES2018 for now 2026-03-03 10:00:48 +00:00
rugk
bbeab997c4 chore: ignore jsconfig.json when exporting 2026-03-03 09:58:48 +00:00
rugk
0155f99e58 test: import privatebin.js 2026-03-01 18:41:16 +00:00
rugk
47aa7aae36 test: Copilot generated new simpler test cases 2026-03-01 16:30:07 +00:00
rugk
b11541a8e4 test: more test fixes
Co-Authored-By: Copliot
2026-03-01 16:19:34 +00:00
rugk
ea4f5ba920 test: Copilots tries at fixing tests 2026-03-01 15:22:05 +00:00
rugk
48678638d0 refactor: more null checks introduced by Copilot for fixing tests 2026-03-01 15:20:20 +00:00
rugk
71c6efd3bb wipfeat(i18n): improve error logging for missing translation 2026-03-01 15:16:05 +00:00
rugk
8d360cd6be wipfix: fix more nullabe problems 2026-03-01 15:05:44 +00:00
rugk
38baa8edbe wipfix(i18n): make sure to check for string
Likely introdued in https://github.com/PrivateBin/PrivateBin/pull/1730
2026-03-01 15:04:22 +00:00
rugk
393eb070e9 fix: manually fix exceptions occuring when loading main page 2026-03-01 14:58:18 +00:00
rugk
8bca112251 wipfix: fix variable shadowing problem 2026-03-01 14:29:38 +00:00
rugk
5b008ac5d9 refactor: remove more jQuery references 2026-03-01 14:26:41 +00:00
rugk
d8b377dd80 style: remove JQuery fallback 2026-03-01 15:03:16 +01:00
rugk
a4ca27d9a3 Potential fix for pull request finding 'Duplicate character in character class'
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
2026-02-26 17:57:04 +01:00
rugk
7528639fde Potential fix for pull request finding 'Duplicate character in character class'
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
2026-02-26 17:55:31 +01:00
rugk
d285a9dfee refactor: remove more jQuery
Co-Authored-By: CoPilot
2026-02-25 20:04:32 +00:00
rugk
84e7cbdfbf test: guard due to test error (fatal memory crash)
Co-Authored-By: Copilot
2026-02-25 18:58:50 +00:00
rugk
0fe51a91a4 test: add npm lint command 2026-02-25 18:57:30 +00:00
rugk
a6e250f825 refactor: remove more jQuery stuff 2026-02-25 10:09:14 +00:00
rugk
14cba7f4c1 refactor: first step removing jQuery
You are a Frontend engineer specialized in refactoring legacy codebases.
Your task is to solve https://github.com/PrivateBin/PrivateBin/issues/198 aka refactor the JavaScript Frontend code to remove all uses of jQuery in order to modernize the codebase.

**Important notes:**
 - The file to modify is #file:privatebin.js.
 - The mocha tests should stay compatible and continue to run.
 - Do not refactor anything else except what is needed for removing jQuery.

Co-Authored-By: Copilot
2026-02-25 09:53:04 +00:00
rugk
e2d900eb02 test: add basic JSConfig to make VSCode type-check the JS file 2026-02-25 09:51:16 +00:00
33 changed files with 2099 additions and 1995 deletions

View File

@@ -36,7 +36,7 @@
}
},
"features": {
"ghcr.io/devcontainers-contrib/features/mocha:2": {},
"ghcr.io/devcontainers-extra/features/mocha:2": {},
"ghcr.io/yassinedoghri/devcontainers/php-extensions-installer:1": {
"extensions": "gd"
}

1
.gitattributes vendored
View File

@@ -9,6 +9,7 @@ js/.nycrc.yml export-ignore
js/common.js export-ignore
js/eslint.config.js export-ignore
js/test/ export-ignore
js/jsconfig.json export-ignore
.codeclimate.yml export-ignore
.csslintrc export-ignore
.devcontainer export-ignore

View File

@@ -6,10 +6,3 @@ Have a look at our [contributing guide](https://github.com/PrivateBin/PrivateBin
If you want to translate PrivateBin into your language have a look at the [translation guide](https://github.com/PrivateBin/PrivateBin/wiki/Translation).
Except this also opening [issues](https://github.com/PrivateBin/PrivateBin/issues) helps much. Just describe your problem detailed enough and fill out our template.
## Guidelines for pull requests
Please note that we, as per our pull request template, **require users to disclose the use of an AI/LLM tool**. We would be glad about details such as the exact used tool/relevant chat snippets or a full (link to the) chat conversation. In any case, please take care to manually test and review your pull request.
For Frontend adjustments or other changes visible visually in the PrivateBin web UI, please _always_ attach at least **a screenshot** of how it looks like with your changes applied. You may only omit that for invisible changes or _very_ obvious little changes like fixing typographic mistakes or translations etc.
If possible, especially for bigger or interactive changes, please also attach a link to a working test instance.

View File

@@ -1,4 +1,4 @@
<!--Please honor our guidelines as written in the CONTRIBUTING.md file. To emphasize: it is required to disclose the usage of an LLM tool. -->
<!-- This is a template for your Pull Request. This are just some suggestions for you. You do not have to use all of them. -->
<!-- If your PR fixes an issue, mention it here. You can also just copy the URL - GitHub will convert it for you.
If this PR fixes several issues, please prepend each issue url/number with the word "fix"/"fixes" or "close"/"closes" as this automatically closes the issues you mentioned when the PR is merged.
@@ -6,12 +6,11 @@ If this PR fixes several issues, please prepend each issue url/number with the w
This PR fixes
## Changes
<!-- List all the changes you have done. This section is just an example and may be removed if irrelevant. -->
<!-- List all the changes you have done -->
*
*
## ToDo
<!-- This section is just an example and may be removed if irrelevant, e.g. if you have completely implemented the PR. -->
* [ ]
* [ ]
* [ ]

View File

@@ -25,7 +25,7 @@ jobs:
steps:
- name: Download and Extract Artifacts
uses: dawidd6/action-download-artifact@8a338493df3d275e4a7a63bcff3b8fe97e51a927
uses: dawidd6/action-download-artifact@2536c51d3d126276eb39f74d6bc9c72ac6ef30d3
with:
run_id: ${{ github.event.workflow_run.id }}
path: artifacts

View File

@@ -4,7 +4,7 @@
* ADDED: Translations for Swedish & Persian
* CHANGED: Deduplicate JSON error message translations
* CHANGED: Refactored translation of exception messages
* CHANGED: Upgrading libraries to: DOMpurify 3.3.2, ip-lib 1.22.0 & polyfill-php80 1.33.0
* CHANGED: Upgrading libraries to: ip-lib 1.22.0 & polyfill-php80 1.33.0
* FIXED: Some exceptions not getting translated
* FIXED: Attachment disappears after a "paste" in the message area (#1731)
* FIXED: The content format is not reset when creating a new document (#1707)

View File

@@ -1,6 +1,6 @@
{
"PrivateBin": "PrivateBin",
"%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s je minimalističen, odprtokodni spletni 'pastebin', kjer strežnik ne ve ničesar o prilepljenih podatkih. Podatki so šifrirani/dešifrirani %sv brskalniku%s z uporabo 256 bitnega AES.",
"%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s je minimalističen, odprtokodni spletni 'pastebin', kjer server ne ve ničesar o prilepljenih podatkih. Podatki so zakodirani/odkodirani %sv brskalniku%s z uporabo 256 bitnega AES.",
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "Več informacij na <a href=\"https://privatebin.info/\">spletni strani projekta.</a>.",
"Because ignorance is bliss": "Ker kar ne veš ne boli.",
"Document does not exist, has expired or has been deleted.": "Prilepek ne obstaja, mu je potekla življenjska doba, ali pa je izbrisan.",
@@ -154,7 +154,7 @@
"Your document is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit <kbd>Ctrl</kbd>+<kbd>c</kbd> to copy)</span>": "Tvoj prilepek je dostopen na naslovu: <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Pritisni <kbd>Ctrl</kbd>+<kbd>c</kbd> ali [Cmd] + [c] in skopiraj)</span>",
"Delete data": "Izbriši podatke",
"Could not create document: %s": "Ne morem ustvariti prilepka: %s",
"Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Prilepka ni mogoče odkodirati: v URL-ju manjka ključ. Ali je bil uporabljen krajšalnik URL-jev, ki odstrani del URL-ja?",
"Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Ne morem odkodirati prilepka: V URL-ju manjka ključ (A si uporabil krajšalnik URL-jev, ki odstrani del URL-ja?)",
"B": "o",
"kB": "kB",
"MB": "MB",
@@ -191,17 +191,17 @@
"+++ no document text +++": "+++ ni besedila dokumenta +++",
"Could not get document data: %s": "Podatkov dokumenta ni bilo mogoče pridobiti: %s",
"QR code": "QR koda",
"This website is using an insecure HTTP connection! Please use it only for testing.": "To spletno mesto uporablja nezaščiteno povezavo HTTP! Prosim, uporabite jo samo za testiranje.",
"This website is using an insecure HTTP connection! Please use it only for testing.": "To spletno mesto uporablja nezaščiteno povezavo HTTP! Prosimo, uporabite jo samo za testiranje.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "Za več informacij <a href=\"%s\">glejte ta vnos s pogostimi vprašanji</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Vaš brskalnik morda zahteva povezavo HTTPS za podporo API-ja WebCrypto. Poskusite <a href=\"%s\">preklopiti na HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Vaš brskalnik ne podpira WebAssembly, ki se uporablja za stiskanje z zlib. Lahko ustvarite nestisnjene dokumente, vendar stisnjenih ne morete odpreti.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Vaš brskalnik ne podpira WebAssemblyja, ki se uporablja za stiskanje zlib. Nestisnjene dokumente lahko ustvarite, stisnjenih pa ne morete brati.",
"waiting on user to provide a password": "čakanje na uporabnika, da vnese geslo",
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Podatkov ni bilo mogoče dešifrirati. Ste vnesli napačno geslo? Poskusite znova z gumbom na vrhu.",
"Retry": "Poskusi ponovno",
"Showing raw text…": "Prikaz surovega besedila…",
"Notice:": "Obvestilo:",
"This link will expire after %s.": "Ta povezava bo potekla čez %s.",
"This link can only be accessed once, do not use back or refresh button in your browser.": "Ta povezava je dostopna samo enkrat; v brskalniku ne uporabljajte gumba »Nazaj« ali »Osveži«.",
"This link can only be accessed once, do not use back or refresh button in your browser.": "Do te povezave lahko dostopate samo enkrat, ne uporabljajte gumba za nazaj ali osvežitev v brskalniku.",
"Link:": "Povezava:",
"Recipient may become aware of your timezone, convert time to UTC?": "Prejemnik lahko izve vaš časovni pas in pretvori čas v UTC?",
"Use Current Timezone": "Uporabi trenutni časovni pas",
@@ -213,14 +213,14 @@
"URL shortener is enabled by default.": "Okrajševalec URL-jev je privzeto omogočen.",
"Save document": "Shrani dokument",
"Your IP is not authorized to create documents.": "Vaš IP ni pooblaščen za ustvarjanje dokumentov.",
"Trying to shorten a URL that isn't pointing at our instance.": "Poskus krajšanja URL-ja, ki ne kaže na našo instanco.",
"Trying to shorten a URL that isn't pointing at our instance.": "Poskus skrajšanja URL, ki ne kaže na naš primerek.",
"Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Napaka posredniškega strežnika: URL posredniškega strežnika je prazen. To je lahko težava s konfiguracijo, na primer napačni ali manjkajoči konfiguracijski ključi.",
"Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Napaka posredniškega strežnika: Napaka pri razčlenjevanju odgovora posredniškega strežnika. To je lahko težava s konfiguracijo, na primer napačni ali manjkajoči konfiguracijski ključi.",
"Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Napaka posredniškega strežnika: Slab odgovor. To je lahko težava s konfiguracijo, na primer napačni ali manjkajoči konfiguracijski ključi ali začasni izpad.",
"This secret message can only be displayed once. Would you like to see it now?": "To skrivno sporočilo je mogoče prikazati samo enkrat. Ali ga želite videti zdaj?",
"Yes, see it": "Da, pokaži",
"Dark Mode": "Temni način",
"Error compressing document, due to missing WebAssembly support.": "Napaka pri stiskanju pripleka zaradi manjkajoče podpore za WebAssembly.",
"Error compressing document, due to missing WebAssembly support.": "Napaka pri stiskanju dokumenta zaradi manjkajoče podpore za WebAssembly.",
"Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Napaka pri razpakiranju dokumenta, vaš brskalnik ne podpira WebAssembly. Za ogled tega dokumenta uporabite drug brskalnik.",
"Start over": "Začni znova",
"Document copied to clipboard": "Dokument kopiran v odložišče",

View File

@@ -4,7 +4,46 @@
global.assert = require('assert');
global.jsc = require('jsverify');
global.jsdom = require('jsdom-global');
global.cleanup = global.jsdom();
// initial DOM environment created by jsdom-global
let currentCleanup = global.jsdom();
// wrap cleanup so that calling it recreates a fresh jsdom environment
global.cleanup = function (...args) {
// remove previous environment
if (typeof currentCleanup === 'function') {
currentCleanup();
}
// create a new jsdom environment
currentCleanup = global.jsdom(...args);
// Make sure window and document are available in global scope for module loading
// jsdom-global sets them, but we need to ensure they're accessible
if (typeof window === 'undefined') {
throw new Error('jsdom-global failed to set up window');
}
if (typeof document === 'undefined') {
throw new Error('jsdom-global failed to set up document');
}
// Clear module cache to ensure modules are re-evaluated with new jsdom environment
delete require.cache[require.resolve('./privatebin')];
delete require.cache[require.resolve('./legacy')];
require('./privatebin');
if (typeof PrivateBin === 'undefined') {
throw new Error('PrivateBin module did not load correctly');
}
// also re-export the PrivateBin namespace if available
if (typeof window !== 'undefined' && window.PrivateBin) {
global.PrivateBin = window.PrivateBin;
if (global.$) {
global.$.PrivateBin = window.PrivateBin;
}
}
return global.cleanup;
};
global.fs = require('fs');
global.WebCrypto = require('@peculiar/webcrypto').Crypto;
@@ -12,14 +51,23 @@ global.WebCrypto = require('@peculiar/webcrypto').Crypto;
global.$ = global.jQuery = require('./jquery-3.7.1');
global.zlib = require('./zlib-1.3.1-2').zlib;
require('./prettify');
global.prettyPrint = window.PR.prettyPrint;
global.prettyPrintOne = window.PR.prettyPrintOne;
global.prettyPrint = window.PR ? window.PR.prettyPrint : function() {};
global.prettyPrintOne = window.PR ? window.PR.prettyPrintOne : function() {};
global.showdown = require('./showdown-2.1.0');
global.DOMPurify = require('./purify-3.3.2');
global.DOMPurify = require('./purify-3.3.0');
global.baseX = require('./base-x-5.0.1').baseX;
global.Legacy = require('./legacy').Legacy;
require('./privatebin');
// provide global access to the namespace so tests can reference it directly
if (typeof window !== 'undefined' && window.PrivateBin) {
global.PrivateBin = window.PrivateBin;
// keep the old jQuery alias around just in case some tests still use it
if (global.$) {
global.$.PrivateBin = window.PrivateBin;
}
}
// internal variables
var a2zString = ['a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z'],

22
js/jsconfig.json Normal file
View File

@@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "es2018",
"module": "NodeNext",
"moduleResolution": "nodenext",
"resolveJsonModule": true,
"checkJs": true,
"strict": true,
"noImplicitAny": false,
"forceConsistentCasingInFileNames": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"baseUrl": "./js",
"paths": {
"/*": ["./*"],
}
},
"exclude": [
"node_modules",
"**/node_modules/*"
]
}

15
js/package-lock.json generated
View File

@@ -1853,10 +1853,11 @@
}
},
"node_modules/flatted": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
"dev": true
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
"dev": true,
"license": "ISC"
},
"node_modules/foreground-child": {
"version": "3.3.1",
@@ -5735,9 +5736,9 @@
}
},
"flatted": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
"dev": true
},
"foreground-child": {

View File

@@ -16,6 +16,7 @@
"nyc": "^17.1.0"
},
"scripts": {
"lint": "eslint",
"test": "mocha",
"ci-test": "mocha --reporter xunit --reporter-option output=mocha-results.xml"
},

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -11,12 +11,11 @@ describe('Alert', function () {
icon = icon.join('');
message = message.join('');
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();
document.body.innerHTML =
'<div id="status"></div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showStatus(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -30,14 +29,13 @@ describe('Alert', function () {
'class="statusmessage alert alert-info"><span ' +
'class="glyphicon glyphicon-info-sign" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
document.body.innerHTML =
'<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();
'glyphicon-info-sign" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showStatus(message);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -53,14 +51,13 @@ describe('Alert', function () {
'class="statusmessage alert alert-info"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
document.body.innerHTML =
'<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, icon);
const result = $('body').html();
'glyphicon-info-sign" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showStatus(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -75,12 +72,11 @@ describe('Alert', function () {
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();
document.body.innerHTML =
'<div id="errormessage"></div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showWarning(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -95,14 +91,13 @@ describe('Alert', function () {
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-warning-sign" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
document.body.innerHTML =
'<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();
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showWarning(message);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -118,14 +113,13 @@ describe('Alert', function () {
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
document.body.innerHTML =
'<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();
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showWarning(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -140,12 +134,11 @@ describe('Alert', function () {
icon = icon.join('');
message = message.join('');
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();
document.body.innerHTML =
'<div id="errormessage"></div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showError(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -160,14 +153,13 @@ describe('Alert', function () {
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-alert" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
document.body.innerHTML =
'<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();
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showError(message);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -183,14 +175,13 @@ describe('Alert', function () {
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
document.body.innerHTML =
'<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, icon);
const result = $('body').html();
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showError(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -206,12 +197,11 @@ describe('Alert', function () {
message = message.join('');
string = string.join('');
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();
document.body.innerHTML =
'<div id="remainingtime" class="hidden"></div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -228,14 +218,13 @@ describe('Alert', function () {
'class="alert alert-info"><span ' +
'class="glyphicon glyphicon-fire" aria-hidden="true">' +
'</span> <span>' + string + message + number + '</span></div>';
$('body').html(
document.body.innerHTML =
'<div id="remainingtime" role="alert" class="hidden ' +
'alert alert-info"><span class="glyphicon ' +
'glyphicon-fire" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]);
const result = $('body').html();
'glyphicon-fire" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -254,12 +243,11 @@ describe('Alert', function () {
message = defaultMessage;
}
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();
document.body.innerHTML =
'<div id="loadingindicator" class="hidden">' + defaultMessage + '</div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showLoading(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -279,15 +267,14 @@ describe('Alert', function () {
'id="loadingindicator" class="navbar-text"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> <span>' + message + '</span></li></ul>';
$('body').html(
document.body.innerHTML =
'<ul class="nav navbar-nav"><li id="loadingindicator" ' +
'class="navbar-text hidden"><span class="glyphicon ' +
'glyphicon-time" aria-hidden="true"></span> ' +
defaultMessage + '</li></ul>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showLoading(message, icon);
const result = $('body').html();
defaultMessage + '</li></ul>';
PrivateBin.Alert.init();
PrivateBin.Alert.showLoading(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -297,17 +284,16 @@ describe('Alert', function () {
it(
'hides the loading message',
function() {
$('body').html(
document.body.innerHTML =
'<ul class="nav navbar-nav"><li id="loadingindicator" ' +
'class="navbar-text"><span class="glyphicon ' +
'glyphicon-time" aria-hidden="true"></span> ' +
'Loading…</li></ul>'
);
$('body').addClass('loading');
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.hideLoading();
assert.ok(!$('body').hasClass('loading'));
assert.ok($('#loadingindicator').hasClass('hidden'));
'Loading…</li></ul>';
document.body.classList.add('loading');
PrivateBin.Alert.init();
PrivateBin.Alert.hideLoading();
assert.ok(!document.body.classList.contains('loading'));
assert.ok(document.getElementById('loadingindicator').classList.contains('hidden'));
}
);
});
@@ -316,18 +302,17 @@ describe('Alert', function () {
it(
'hides all messages',
function() {
$('body').html(
document.body.innerHTML =
'<div id="status" role="alert" class="statusmessage ' +
'alert alert-info"><span class="glyphicon ' +
'glyphicon-info-sign" aria-hidden="true"></span> </div>' +
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.hideMessages();
assert.ok($('#status').hasClass('hidden'));
assert.ok($('#errormessage').hasClass('hidden'));
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.hideMessages();
assert.ok(document.getElementById('status').classList.contains('hidden'));
assert.ok(document.getElementById('errormessage').classList.contains('hidden'));
}
);
});
@@ -342,15 +327,15 @@ describe('Alert', function () {
let handlerCalled = false,
defaultMessage = 'Loading…',
functions = [
$.PrivateBin.Alert.showStatus,
$.PrivateBin.Alert.showError,
$.PrivateBin.Alert.showRemaining,
$.PrivateBin.Alert.showLoading
PrivateBin.Alert.showStatus,
PrivateBin.Alert.showError,
PrivateBin.Alert.showRemaining,
PrivateBin.Alert.showLoading
];
if (message.length === 0) {
message = defaultMessage;
}
$('body').html(
document.body.innerHTML =
'<ul class="nav navbar-nav"><li id="loadingindicator" ' +
'class="navbar-text hidden"><span class="glyphicon ' +
'glyphicon-time" aria-hidden="true"></span> ' +
@@ -363,15 +348,14 @@ describe('Alert', function () {
'glyphicon-info-sign" aria-hidden="true"></span> </div>' +
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.setCustomHandler(function(id, $element) {
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.setCustomHandler(function(id, element) {
handlerCalled = true;
return jsc.random(0, 1) ? true : $element;
return jsc.random(0, 1) ? true : element;
});
functions[trigger](message);
$.PrivateBin.Alert.setCustomHandler(null);
PrivateBin.Alert.setCustomHandler(null);
return handlerCalled;
}
);

View File

@@ -14,7 +14,7 @@ describe('AttachmentViewer', function () {
'string',
// eslint-disable-next-line complexity
function (mimeType, rawdata, filename, prefix, postfix) {
let clean = jsdom(),
let clean = globalThis.cleanup(),
data = 'data:' + mimeType + ';base64,' + common.btoa(rawdata),
mimePrefix = mimeType.substring(0, 6),
previewSupported = (
@@ -31,7 +31,7 @@ describe('AttachmentViewer', function () {
}
prefix = prefix.replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%').replace(/<|>/g, '');
$('body').html(
document.body.innerHTML = (
'<div id="attachmentPreview" class="col-md-12 text-center hidden"></div>' +
'<div id="attachment" class="hidden"></div>' +
'<div id="templates">' +
@@ -51,60 +51,62 @@ describe('AttachmentViewer', function () {
}}
);
}
$.PrivateBin.AttachmentViewer.init();
$.PrivateBin.Model.init();
PrivateBin.AttachmentViewer.init();
PrivateBin.Model.init();
results.push(
!$.PrivateBin.AttachmentViewer.hasAttachment() &&
$('#attachment').hasClass('hidden') &&
$('#attachment').children().length === 0 &&
$('#attachmenttemplate').hasClass('hidden') &&
$('#attachmentPreview').hasClass('hidden')
!PrivateBin.AttachmentViewer.hasAttachment() &&
document.getElementById('attachment').classList.contains('hidden') &&
document.getElementById('attachment').children.length === 0 &&
document.getElementById('attachmenttemplate').classList.contains('hidden') &&
document.getElementById('attachmentPreview').classList.contains('hidden')
);
global.atob = common.atob;
if (filename.length) {
$.PrivateBin.AttachmentViewer.setAttachment(data, filename);
PrivateBin.AttachmentViewer.setAttachment(data, filename);
} else {
$.PrivateBin.AttachmentViewer.setAttachment(data);
PrivateBin.AttachmentViewer.setAttachment(data);
}
// // beyond this point we will get the blob URL instead of the data
data = window.URL.createObjectURL(data);
const attachment = $.PrivateBin.AttachmentViewer.getAttachments();
const attachment = PrivateBin.AttachmentViewer.getAttachments();
results.push(
$.PrivateBin.AttachmentViewer.hasAttachment() &&
$('#attachment').hasClass('hidden') &&
$('#attachment').children().length > 0 &&
$('#attachmentPreview').hasClass('hidden') &&
PrivateBin.AttachmentViewer.hasAttachment() &&
document.getElementById('attachment').classList.contains('hidden') &&
document.getElementById('attachment').children.length > 0 &&
document.getElementById('attachmentPreview').classList.contains('hidden') &&
attachment[0][0] === data &&
attachment[0][1] === filename
);
$.PrivateBin.AttachmentViewer.showAttachment();
PrivateBin.AttachmentViewer.showAttachment();
results.push(
!$('#attachment').hasClass('hidden') &&
$('#attachment').children().length > 0 &&
(previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden'))
!document.getElementById('attachment').classList.contains('hidden') &&
document.getElementById('attachment').children.length > 0 &&
(previewSupported ? !document.getElementById('attachmentPreview').classList.contains('hidden') : document.getElementById('attachmentPreview').classList.contains('hidden'))
);
$.PrivateBin.AttachmentViewer.hideAttachment();
PrivateBin.AttachmentViewer.hideAttachment();
results.push(
$('#attachment').hasClass('hidden') &&
(previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden'))
document.getElementById('attachment').classList.contains('hidden') &&
(previewSupported ? !document.getElementById('attachmentPreview').classList.contains('hidden') : document.getElementById('attachmentPreview').classList.contains('hidden'))
);
if (previewSupported) {
$.PrivateBin.AttachmentViewer.hideAttachmentPreview();
results.push($('#attachmentPreview').hasClass('hidden'));
PrivateBin.AttachmentViewer.hideAttachmentPreview();
results.push(document.getElementById('attachmentPreview').classList.contains('hidden'));
}
$.PrivateBin.AttachmentViewer.showAttachment();
PrivateBin.AttachmentViewer.showAttachment();
results.push(
!$('#attachment').hasClass('hidden') &&
(previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden'))
!document.getElementById('attachment').classList.contains('hidden') &&
(previewSupported ? !document.getElementById('attachmentPreview').classList.contains('hidden') : document.getElementById('attachmentPreview').classList.contains('hidden'))
);
let element = $('<div>');
$.PrivateBin.AttachmentViewer.moveAttachmentTo(element, attachment[0], prefix + '%s' + postfix);
let element = document.createElement('div');
PrivateBin.AttachmentViewer.moveAttachmentTo(element, attachment[0], prefix + '%s' + postfix);
// messageIDs with links get a relaxed treatment
if (prefix.indexOf('<a') === -1 && postfix.indexOf('<a') === -1) {
result = $('<textarea>').text((prefix + filename + postfix)).text();
const tempTA = document.createElement('textarea');
tempTA.textContent = (prefix + filename + postfix);
result = tempTA.textContent;
} else {
result = DOMPurify.sanitize(
prefix + $.PrivateBin.Helper.htmlEntities(filename) + postfix, {
prefix + PrivateBin.Helper.htmlEntities(filename) + postfix, {
ALLOWED_TAGS: ['a', 'i', 'span'],
ALLOWED_ATTR: ['href', 'id']
}
@@ -112,18 +114,18 @@ describe('AttachmentViewer', function () {
}
if (filename.length) {
results.push(
element.find('a')[0].href === data &&
element.find('a')[0].getAttribute('download') === filename &&
element.find('a')[0].text === result
element.querySelector('a').href === data &&
element.querySelector('a').getAttribute('download') === filename &&
element.querySelector('a').textContent === result
);
} else {
results.push(element.find('a')[0].href === data);
results.push(element.querySelector('a').href === data);
}
$.PrivateBin.AttachmentViewer.removeAttachment();
PrivateBin.AttachmentViewer.removeAttachment();
results.push(
$('#attachment').hasClass('hidden') &&
$('#attachment').children().length === 0 &&
$('#attachmentPreview').hasClass('hidden')
document.getElementById('attachment').classList.contains('hidden') &&
document.getElementById('attachment').children.length === 0 &&
document.getElementById('attachmentPreview').classList.contains('hidden')
);
clean();
return results.every(element => element);
@@ -133,8 +135,8 @@ describe('AttachmentViewer', function () {
it(
'sanitizes file names in attachments',
function() {
const clean = jsdom();
$('body').html(
const clean = globalThis.cleanup();
document.body.innerHTML = (
'<div id="attachmentPreview" class="col-md-12 text-center hidden"></div>' +
'<div id="attachment" class="hidden"></div>' +
'<div id="templates">' +
@@ -154,8 +156,8 @@ describe('AttachmentViewer', function () {
}}
);
}
$.PrivateBin.AttachmentViewer.init();
$.PrivateBin.Model.init();
PrivateBin.AttachmentViewer.init();
PrivateBin.Model.init();
global.atob = common.atob;
const maliciousFileNames = [
@@ -163,8 +165,8 @@ describe('AttachmentViewer', function () {
'"><meta http-equiv="refresh" content="0;url=http://example.com/">.txt'
];
for (const filename of maliciousFileNames) {
$.PrivateBin.AttachmentViewer.setAttachment('data:;base64,', filename);
assert.ok(!$('body').html().includes(filename));
PrivateBin.AttachmentViewer.setAttachment('data:;base64,', filename);
assert.ok(!document.body.innerHTML.includes(filename));
}
clean();
}

View File

@@ -12,7 +12,7 @@ describe('Check', function () {
jsc.elements(['Bot', 'bot']),
'string',
function (prefix, botBit, suffix) {
const clean = jsdom(
const clean = globalThis.cleanup(
'<html><body><div id="errormessage" class="hidden"></div>' +
'</body></html>', {
'userAgent': prefix + botBit + suffix
@@ -36,7 +36,7 @@ describe('Check', function () {
function (secureProtocol, localhost, domain, tld) {
const isDomain = localhost === '',
isSecureContext = secureProtocol || !isDomain || tld.length > 0,
clean = jsdom(
clean = globalThis.cleanup(
'<html><body><div id="errormessage" class="hidden"></div>' +
'<div id="oldnotice" class="hidden"></div>' +
'<div id="insecurecontextnotice" class="hidden"></div></body></html>',
@@ -63,7 +63,7 @@ describe('Check', function () {
'bool',
jsc.nearray(common.jscA2zString()),
function (secureProtocol, domain) {
const clean = jsdom(
const clean = globalThis.cleanup(
'<html><body><div id="httpnotice" class="hidden"></div>' +
'</body></html>',
{

View File

@@ -9,10 +9,10 @@ describe('CopyToClipboard', function() {
common.jscFormats(),
'nestring',
async function (format, text) {
var clean = jsdom();
var clean = globalThis.cleanup();
common.enableClipboard();
$('body').html(
document.body.innerHTML = (
'<div id="placeholder" class="hidden">+++ no document text ' +
'+++</div><div id="prettymessage" class="hidden">' +
'<button type="button" id="prettyMessageCopyBtn"><svg id="copyIcon"></svg>' +
@@ -21,14 +21,14 @@ describe('CopyToClipboard', function() {
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
PrivateBin.PasteViewer.init();
PrivateBin.PasteViewer.setFormat(format);
PrivateBin.PasteViewer.setText(text);
PrivateBin.PasteViewer.run();
$.PrivateBin.CopyToClipboard.init();
PrivateBin.CopyToClipboard.init();
$('#prettyMessageCopyBtn').trigger('click');
document.getElementById('prettyMessageCopyBtn').click();
const savedToClipboardText = await navigator.clipboard.readText();
@@ -46,10 +46,10 @@ describe('CopyToClipboard', function() {
common.jscFormats(),
'nestring',
async function (format, text) {
var clean = jsdom();
var clean = globalThis.cleanup();
common.enableClipboard();
$('body').html(
document.body.innerHTML = (
'<div id="placeholder">+++ no document text ' +
'+++</div><div id="prettymessage" class="hidden">' +
'<button type="button" id="prettyMessageCopyBtn"><svg id="copyIcon"></svg>' +
@@ -58,14 +58,14 @@ describe('CopyToClipboard', function() {
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
PrivateBin.PasteViewer.init();
PrivateBin.PasteViewer.setFormat(format);
PrivateBin.PasteViewer.setText(text);
PrivateBin.PasteViewer.run();
$.PrivateBin.CopyToClipboard.init();
PrivateBin.CopyToClipboard.init();
$('body').trigger('copy');
document.body.dispatchEvent(new Event('copy'));
const copiedTextWithoutSelectedText = await navigator.clipboard.readText();
@@ -80,15 +80,15 @@ describe('CopyToClipboard', function() {
jsc.property('Copy link to clipboard',
'nestring',
async function (text) {
var clean = jsdom();
var clean = globalThis.cleanup();
common.enableClipboard();
$('body').html('<button id="copyLink"></button>');
document.body.innerHTML = '<button id="copyLink"></button>';
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.setUrl(text);
PrivateBin.CopyToClipboard.init();
PrivateBin.CopyToClipboard.setUrl(text);
$('#copyLink').trigger('click');
document.getElementById('copyLink').click();
const copiedText = await navigator.clipboard.readText();
@@ -103,14 +103,14 @@ describe('CopyToClipboard', function() {
jsc.property('Show hint',
'nestring',
function (text) {
var clean = jsdom();
var clean = globalThis.cleanup();
$('body').html('<small id="copyShortcutHintText"></small>');
document.body.innerHTML = '<small id="copyShortcutHintText"></small>';
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.showKeyboardShortcutHint();
PrivateBin.CopyToClipboard.init();
PrivateBin.CopyToClipboard.showKeyboardShortcutHint();
const keyboardShortcutHint = $('#copyShortcutHintText').text();
const keyboardShortcutHint = document.getElementById('copyShortcutHintText').textContent;
clean();
@@ -121,14 +121,14 @@ describe('CopyToClipboard', function() {
jsc.property('Hide hint',
'nestring',
function (text) {
var clean = jsdom();
var clean = globalThis.cleanup();
$('body').html('<small id="copyShortcutHintText">' + text + '</small>');
document.body.innerHTML = '<small id="copyShortcutHintText">' + text + '</small>';
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.hideKeyboardShortcutHint();
PrivateBin.CopyToClipboard.init();
PrivateBin.CopyToClipboard.hideKeyboardShortcutHint();
const keyboardShortcutHint = $('#copyShortcutHintText').text();
const keyboardShortcutHint = document.getElementById('copyShortcutHintText').textContent;
clean();
@@ -136,4 +136,4 @@ describe('CopyToClipboard', function() {
}
);
});
});
});

View File

@@ -1,5 +1,6 @@
'use strict';
const common = require('../common');
const fs = require('fs');
describe('CryptTool', function () {
describe('cipher & decipher', function () {
@@ -15,9 +16,9 @@ describe('CryptTool', function () {
'string',
'string',
async function (key, password, message) {
const clean = jsdom();
const clean = globalThis.cleanup();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
PrivateBin.Controller.initZ();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false
@@ -25,10 +26,10 @@ describe('CryptTool', function () {
global.atob = common.atob;
global.btoa = common.btoa;
message = message.trim();
const cipherMessage = await $.PrivateBin.CryptTool.cipher(
const cipherMessage = await PrivateBin.CryptTool.cipher(
key, password, message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
plaintext = await PrivateBin.CryptTool.decipher(
key, password, cipherMessage
);
clean();
@@ -42,19 +43,19 @@ describe('CryptTool', function () {
it('does not truncate messages', async function () {
const message = fs.readFileSync('test/compression-sample.txt', 'ascii').trim(),
clean = jsdom();
clean = globalThis.cleanup();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false
});
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
PrivateBin.Controller.initZ();
global.atob = common.atob;
global.btoa = common.btoa;
const cipherMessage = await $.PrivateBin.CryptTool.cipher(
const cipherMessage = await PrivateBin.CryptTool.cipher(
'foo', 'bar', message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
plaintext = await PrivateBin.CryptTool.decipher(
'foo', 'bar', cipherMessage
);
clean();
@@ -91,17 +92,17 @@ isWhile : interp (while expr sBody) (MemElem mem) =
======================== ( 1 / 1 )
conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
`;
const clean = jsdom();
const clean = globalThis.cleanup();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
PrivateBin.Controller.initZ();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false
});
const cipherMessage = await $.PrivateBin.CryptTool.cipher(
const cipherMessage = await PrivateBin.CryptTool.cipher(
key, password, message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
plaintext = await PrivateBin.CryptTool.decipher(
key, password, cipherMessage
);
clean();
@@ -123,12 +124,12 @@ conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
jsc.assert(jsc.forall(
'integer',
function(counter) {
const clean = jsdom();
const clean = globalThis.cleanup();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false
});
const key = $.PrivateBin.CryptTool.getSymmetricKey(),
const key = PrivateBin.CryptTool.getSymmetricKey(),
result = (key !== '' && keys.indexOf(key) === -1);
keys.push(key);
clean();

View File

@@ -26,9 +26,9 @@ describe('DiscussionViewer', function () {
jsc.elements(['loading', 'danger', 'other']),
'nestring',
function (comments, commentKey, fadeOut, nickname, message, alertType, alert) {
var clean = jsdom(),
var clean = globalThis.cleanup(),
results = [];
$('body').html(
document.body.innerHTML = (
'<div id="discussion"><h4>Discussion</h4>' +
'<div id="commentcontainer"></div></div><div id="templates">' +
'<article id="commenttemplate" class="comment">' +
@@ -48,59 +48,59 @@ describe('DiscussionViewer', function () {
'aria-hidden="true"></span> </div><button id="replybutton" ' +
'class="btn btn-default btn-sm">Post comment</button></div></div>'
);
$.PrivateBin.Model.init();
$.PrivateBin.DiscussionViewer.init();
PrivateBin.Model.init();
PrivateBin.DiscussionViewer.init();
results.push(
!$('#discussion').hasClass('hidden')
!document.getElementById('discussion').classList.contains('hidden')
);
$.PrivateBin.DiscussionViewer.prepareNewDiscussion();
PrivateBin.DiscussionViewer.prepareNewDiscussion();
results.push(
$('#discussion').hasClass('hidden')
document.getElementById('discussion').classList.contains('hidden')
);
comments.forEach(function (comment) {
comment.id = comment.idArray.join('');
comment.parentid = comment.parentidArray.join('');
$.PrivateBin.DiscussionViewer.addComment($.PrivateBin.Helper.CommentFactory(comment), comment.data, comment.meta.nickname);
PrivateBin.DiscussionViewer.addComment(PrivateBin.Helper.CommentFactory(comment), comment.data, comment.meta.nickname);
});
results.push(
$('#discussion').hasClass('hidden')
document.getElementById('discussion').classList.contains('hidden')
);
$.PrivateBin.DiscussionViewer.finishDiscussion();
PrivateBin.DiscussionViewer.finishDiscussion();
results.push(
!$('#discussion').hasClass('hidden') &&
comments.length + 1 >= $('#commentcontainer').children().length
!document.getElementById('discussion').classList.contains('hidden') &&
comments.length + 1 >= document.getElementById('commentcontainer').children.length
);
if (comments.length > 0) {
if (commentKey >= comments.length) {
commentKey = commentKey % comments.length;
}
$.PrivateBin.DiscussionViewer.highlightComment(comments[commentKey].id, fadeOut);
PrivateBin.DiscussionViewer.highlightComment(comments[commentKey].id, fadeOut);
results.push(
$('#comment_' + comments[commentKey].id).hasClass('highlight')
document.getElementById('comment_' + comments[commentKey].id).classList.contains('highlight')
);
}
$('#commentcontainer').find('button')[0].click();
document.getElementById('commentcontainer').querySelector('button').click();
results.push(
!$('#reply').hasClass('hidden')
!document.getElementById('reply').classList.contains('hidden')
);
$('#reply #nickname').val(nickname);
$('#reply #replymessage').val(message);
$.PrivateBin.DiscussionViewer.getReplyCommentId();
document.querySelector('#reply #nickname').value = nickname;
document.querySelector('#reply #replymessage').value = message;
PrivateBin.DiscussionViewer.getReplyCommentId();
results.push(
$.PrivateBin.DiscussionViewer.getReplyNickname() === $('#reply #nickname').val() &&
$.PrivateBin.DiscussionViewer.getReplyMessage() === $('#reply #replymessage').val()
PrivateBin.DiscussionViewer.getReplyNickname() === document.querySelector('#reply #nickname').value &&
PrivateBin.DiscussionViewer.getReplyMessage() === document.querySelector('#reply #replymessage').value
);
var notificationResult = $.PrivateBin.DiscussionViewer.handleNotification(alertType === 'other' ? alert : alertType);
var notificationResult = PrivateBin.DiscussionViewer.handleNotification(alertType === 'other' ? alert : alertType);
if (alertType === 'loading') {
results.push(notificationResult === false);
} else {
results.push(
alertType === 'danger' ? (
notificationResult.hasClass('alert-danger') &&
!notificationResult.hasClass('alert-info')
notificationResult.classList.contains('alert-danger') &&
!notificationResult.classList.contains('alert-info')
) : (
!notificationResult.hasClass('alert-danger') &&
notificationResult.hasClass('alert-info')
!notificationResult.classList.contains('alert-danger') &&
notificationResult.classList.contains('alert-info')
)
);
}

View File

@@ -9,9 +9,9 @@ describe('Editor', function () {
'returns text fed into the textarea, handles editor tabs',
'string',
function (text) {
var clean = jsdom(),
var clean = globalThis.cleanup(),
results = [];
$('body').html(
document.body.innerHTML = (
'<ul id="editorTabs" class="nav nav-tabs hidden"><li ' +
'role="presentation" class="active"><a id="messageedit" ' +
'href="#">Editor</a></li><li role="presentation"><a ' +
@@ -23,44 +23,44 @@ describe('Editor', function () {
'id="message" name="message" cols="80" rows="25" ' +
'class="form-control hidden"></textarea></p>'
);
$.PrivateBin.Editor.init();
PrivateBin.Editor.init();
results.push(
$('#editorTabs').hasClass('hidden') &&
$('#message').hasClass('hidden')
document.getElementById('editorTabs').classList.contains('hidden') &&
document.getElementById('message').classList.contains('hidden')
);
$.PrivateBin.Editor.show();
PrivateBin.Editor.show();
results.push(
!$('#editorTabs').hasClass('hidden') &&
!$('#message').hasClass('hidden')
!document.getElementById('editorTabs').classList.contains('hidden') &&
!document.getElementById('message').classList.contains('hidden')
);
$.PrivateBin.Editor.hide();
PrivateBin.Editor.hide();
results.push(
$('#editorTabs').hasClass('hidden') &&
$('#message').hasClass('hidden')
document.getElementById('editorTabs').classList.contains('hidden') &&
document.getElementById('message').classList.contains('hidden')
);
$.PrivateBin.Editor.show();
$.PrivateBin.Editor.focusInput();
PrivateBin.Editor.show();
PrivateBin.Editor.focusInput();
results.push(
$.PrivateBin.Editor.getText().length === 0
PrivateBin.Editor.getText().length === 0
);
$.PrivateBin.Editor.setText(text);
PrivateBin.Editor.setText(text);
results.push(
$.PrivateBin.Editor.getText() === $('#message').val()
PrivateBin.Editor.getText() === document.getElementById('message').value
);
$.PrivateBin.Editor.setText();
PrivateBin.Editor.setText();
results.push(
!$.PrivateBin.Editor.isPreview() &&
!$('#message').hasClass('hidden')
!PrivateBin.Editor.isPreview() &&
!document.getElementById('message').classList.contains('hidden')
);
$('#messagepreview').trigger('click');
document.getElementById('messagepreview').click();
results.push(
$.PrivateBin.Editor.isPreview() &&
$('#message').hasClass('hidden')
PrivateBin.Editor.isPreview() &&
document.getElementById('message').classList.contains('hidden')
);
$('#messageedit').trigger('click');
document.getElementById('messageedit').click();
results.push(
!$.PrivateBin.Editor.isPreview() &&
!$('#message').hasClass('hidden')
!PrivateBin.Editor.isPreview() &&
!document.getElementById('message').classList.contains('hidden')
);
clean();
return results.every(element => element);

View File

@@ -4,42 +4,42 @@ var common = require('../common');
describe('Helper', function () {
describe('secondsToHuman', function () {
jsc.property('returns an array with a number and a word', 'integer', function (number) {
var result = $.PrivateBin.Helper.secondsToHuman(number);
var result = PrivateBin.Helper.secondsToHuman(number);
return Array.isArray(result) &&
result.length === 2 &&
result[0] === parseInt(result[0], 10) &&
typeof result[1] === 'string';
});
jsc.property('returns seconds on the first array position', 'integer 59', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[0] === number;
return PrivateBin.Helper.secondsToHuman(number)[0] === number;
});
jsc.property('returns seconds on the second array position', 'integer 59', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[1] === 'second';
return PrivateBin.Helper.secondsToHuman(number)[1] === 'second';
});
jsc.property('returns minutes on the first array position', 'integer 60 3599', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / 60);
return PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / 60);
});
jsc.property('returns minutes on the second array position', 'integer 60 3599', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[1] === 'minute';
return PrivateBin.Helper.secondsToHuman(number)[1] === 'minute';
});
jsc.property('returns hours on the first array position', 'integer 3600 86399', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / (60 * 60));
return PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / (60 * 60));
});
jsc.property('returns hours on the second array position', 'integer 3600 86399', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[1] === 'hour';
return PrivateBin.Helper.secondsToHuman(number)[1] === 'hour';
});
jsc.property('returns days on the first array position', 'integer 86400 5184000', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / (60 * 60 * 24));
return PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / (60 * 60 * 24));
});
jsc.property('returns days on the second array position', 'integer 86400 5184000', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[1] === 'day';
return PrivateBin.Helper.secondsToHuman(number)[1] === 'day';
});
// max safe integer as per http://ecma262-5.com/ELS5_HTML.htm#Section_8.5
jsc.property('returns months on the first array position', 'integer 5184000 9007199254740991', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / (60 * 60 * 24 * 30));
return PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / (60 * 60 * 24 * 30));
});
jsc.property('returns months on the second array position', 'integer 5184000 9007199254740991', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[1] === 'month';
return PrivateBin.Helper.secondsToHuman(number)[1] === 'month';
});
});
@@ -54,15 +54,15 @@ describe('Helper', function () {
function (ids, contents) {
var html = '',
result = true,
clean = jsdom(html);
clean = globalThis.cleanup(html);
ids.forEach(function(item, i) {
html += '<div id="' + item.join('') + '">' + $.PrivateBin.Helper.htmlEntities(contents[i] || contents[0]) + '</div>';
html += '<div id="' + item.join('') + '">' + PrivateBin.Helper.htmlEntities(contents[i] || contents[0]) + '</div>';
});
// TODO: As per https://github.com/tmpvar/jsdom/issues/321 there is no getSelection in jsdom, yet.
// Once there is one, uncomment the block below to actually check the result.
/*
ids.forEach(function(item, i) {
$.PrivateBin.Helper.selectText(item.join(''));
PrivateBin.Helper.selectText(item.join(''));
result *= (contents[i] || contents[0]) === window.getSelection().toString();
});
*/
@@ -73,9 +73,15 @@ describe('Helper', function () {
});
describe('urls2links', function () {
function getTextAsRenderedHtml(stringContent) {
const tempDiv = document.createElement('div');
tempDiv.textContent = stringContent;
return tempDiv.innerHTML;
}
this.timeout(30000);
before(function () {
cleanup = jsdom();
cleanup = globalThis.cleanup();
});
jsc.property(
@@ -84,12 +90,12 @@ describe('Helper', function () {
function (content) {
// eslint-disable-next-line no-control-regex
content = content.replace(/\r|\f/g, '\n').replace(/\u0000|\u000b/g, '');
let clean = jsdom();
$('body').html('<div id="foo"></div>');
let e = $('#foo');
e.text(content);
$.PrivateBin.Helper.urls2links(e);
let result = e.text();
let clean = globalThis.cleanup();
document.body.innerHTML = '<div id="foo"></div>';
let e = document.getElementById('foo');
e.textContent = content;
PrivateBin.Helper.urls2links(e);
let result = e.textContent;
clean();
return content === result;
}
@@ -107,9 +113,9 @@ describe('Helper', function () {
postfix = ' ' + postfix.replace(/\r/g, '\n').replace(/\u0000/g, '');
url.fragment = fragment.join('');
let urlString = common.urlToString(url),
clean = jsdom();
$('body').html('<div id="foo"></div>');
let e = $('#foo');
clean = globalThis.cleanup();
document.body.innerHTML = '<div id="foo"></div>';
let e = document.getElementById('foo');
// special cases: When the query string and fragment imply the beginning of an HTML entity, eg. &#0 or &#x
if (
@@ -120,12 +126,14 @@ describe('Helper', function () {
urlString = common.urlToString(url);
postfix = '';
}
e.text(prefix + urlString + postfix);
$.PrivateBin.Helper.urls2links(e);
let result = e.html();
e.textContent = prefix + urlString + postfix;
PrivateBin.Helper.urls2links(e);
let result = e.innerHTML;
clean();
urlString = $('<div />').text(urlString).html();
const expected = $('<div />').text(prefix).html() + '<a href="' + urlString + '" target="_blank" rel="nofollow noopener noreferrer">' + urlString + '</a>' + $('<div />').text(postfix).html();
urlString = getTextAsRenderedHtml(urlString);
const expected = getTextAsRenderedHtml(prefix) + '<a href="' + urlString + '" target="_blank" rel="nofollow noopener noreferrer">' + urlString + '</a>' + getTextAsRenderedHtml(postfix);
return expected === result;
}
);
@@ -140,15 +148,15 @@ describe('Helper', function () {
// eslint-disable-next-line no-control-regex
postfix = ' ' + postfix.replace(/\r/g, '\n').replace(/\u0000/g, '');
let url = 'magnet:?' + query.join('').replace(/^&+|&+$/gm, ''),
clean = jsdom();
$('body').html('<div id="foo"></div>');
let e = $('#foo');
e.text(prefix + url + postfix);
$.PrivateBin.Helper.urls2links(e);
let result = e.html();
clean = globalThis.cleanup();
document.body.innerHTML = '<div id="foo"></div>';
let e = document.getElementById('foo');
e.textContent = prefix + url + postfix;
PrivateBin.Helper.urls2links(e);
let result = e.innerHTML;
clean();
url = $('<div />').text(url).html();
return $('<div />').text(prefix).html() + '<a href="' + url + '" target="_blank" rel="nofollow noopener noreferrer">' + url + '</a>' + $('<div />').text(postfix).html() === result;
url = getTextAsRenderedHtml(url);
return getTextAsRenderedHtml(prefix) + '<a href="' + url + '" target="_blank" rel="nofollow noopener noreferrer">' + url + '</a>' + getTextAsRenderedHtml(postfix) === result;
}
);
});
@@ -165,7 +173,7 @@ describe('Helper', function () {
postfix = postfix.replace(/%(s|d)/g, '%%');
var result = prefix + params[0] + postfix;
params.unshift(prefix + '%s' + postfix);
return result === $.PrivateBin.Helper.sprintf.apply(this, params);
return result === PrivateBin.Helper.sprintf.apply(this, params);
}
);
jsc.property(
@@ -178,7 +186,7 @@ describe('Helper', function () {
postfix = postfix.replace(/%(s|d)/g, '%%');
var result = prefix + params[0] + postfix;
params.unshift(prefix + '%d' + postfix);
return result === $.PrivateBin.Helper.sprintf.apply(this, params);
return result === PrivateBin.Helper.sprintf.apply(this, params);
}
);
jsc.property(
@@ -191,7 +199,7 @@ describe('Helper', function () {
postfix = postfix.replace(/%(s|d)/g, '%%');
var result = prefix + '0' + postfix;
params.unshift(prefix + '%d' + postfix);
return result === $.PrivateBin.Helper.sprintf.apply(this, params);
return result === PrivateBin.Helper.sprintf.apply(this, params);
}
);
jsc.property(
@@ -207,7 +215,7 @@ describe('Helper', function () {
postfix = postfix.replace(/%(s|d)/g, '');
var params = [prefix + '%d' + middle + '%s' + postfix, uint, string],
result = prefix + uint + middle + string + postfix;
return result === $.PrivateBin.Helper.sprintf.apply(this, params);
return result === PrivateBin.Helper.sprintf.apply(this, params);
}
);
jsc.property(
@@ -223,7 +231,7 @@ describe('Helper', function () {
postfix = postfix.replace(/%(s|d)/g, '');
var params = [prefix + '%s' + middle + '%d' + postfix, string, uint],
result = prefix + string + middle + uint + postfix;
return result === $.PrivateBin.Helper.sprintf.apply(this, params);
return result === PrivateBin.Helper.sprintf.apply(this, params);
}
);
});
@@ -241,7 +249,7 @@ describe('Helper', function () {
jsc.nearray(jsc.nearray(common.jscAlnumString())),
function (labels, values) {
let selectedKey = '', selectedValue = '';
const clean = jsdom();
const clean = globalThis.cleanup();
labels.forEach(function(item, i) {
const key = item.join(''),
value = (values[i] || values[0]).join('');
@@ -252,8 +260,8 @@ describe('Helper', function () {
selectedValue = value;
}
});
const result = $.PrivateBin.Helper.getCookie(selectedKey);
$.PrivateBin.Helper.reset();
const result = PrivateBin.Helper.getCookie(selectedKey);
PrivateBin.Helper.reset();
clean();
return result === selectedValue;
}
@@ -271,10 +279,10 @@ describe('Helper', function () {
const fullUrl = common.urlToString(url);
delete(url.query);
delete(url.fragment);
$.PrivateBin.Helper.reset();
PrivateBin.Helper.reset();
const expected = common.urlToString(url),
clean = jsdom('', {url: fullUrl}),
result = $.PrivateBin.Helper.baseUri();
clean = globalThis.cleanup('', {url: fullUrl}),
result = PrivateBin.Helper.baseUri();
clean();
return expected === result;
}
@@ -283,14 +291,14 @@ describe('Helper', function () {
describe('htmlEntities', function () {
before(function () {
cleanup = jsdom();
cleanup = globalThis.cleanup();
});
jsc.property(
'removes all HTML entities from any given string',
'string',
function (string) {
var result = $.PrivateBin.Helper.htmlEntities(string);
var result = PrivateBin.Helper.htmlEntities(string);
return !(/[<>]/.test(result)) && !(string.indexOf('&') > -1 && !(/&amp;/.test(result)));
}
);
@@ -298,43 +306,43 @@ describe('Helper', function () {
describe('formatBytes', function () {
jsc.property('returns 0 B for 0 bytes', function () {
return $.PrivateBin.Helper.formatBytes(0) === '0 B';
return PrivateBin.Helper.formatBytes(0) === '0 B';
});
jsc.property('formats bytes < 1000 as B', function () {
return $.PrivateBin.Helper.formatBytes(500) === '500 B';
return PrivateBin.Helper.formatBytes(500) === '500 B';
});
jsc.property('formats kilobytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(1500) === '1.5 kB';
return PrivateBin.Helper.formatBytes(1500) === '1.5 kB';
});
jsc.property('formats megabytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(2 * 1000 * 1000) === '2 MB';
return PrivateBin.Helper.formatBytes(2 * 1000 * 1000) === '2 MB';
});
jsc.property('formats gigabytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(3.45 * 1000 * 1000 * 1000) === '3.45 GB';
return PrivateBin.Helper.formatBytes(3.45 * 1000 * 1000 * 1000) === '3.45 GB';
});
jsc.property('formats terabytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(1.75 * 1000 ** 4) === '1.75 TB';
return PrivateBin.Helper.formatBytes(1.75 * 1000 ** 4) === '1.75 TB';
});
jsc.property('formats petabytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(1.5 * 1000 ** 5) === '1.5 PB';
return PrivateBin.Helper.formatBytes(1.5 * 1000 ** 5) === '1.5 PB';
});
jsc.property('formats exabytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(1.2345 * 1000 ** 6).startsWith('1.23 EB');
return PrivateBin.Helper.formatBytes(1.2345 * 1000 ** 6).startsWith('1.23 EB');
});
jsc.property('formats yottabytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(1.23 * 1000 ** 8).startsWith('1.23 YB');
return PrivateBin.Helper.formatBytes(1.23 * 1000 ** 8).startsWith('1.23 YB');
});
jsc.property('rounds to two decimal places', function () {
return $.PrivateBin.Helper.formatBytes(1234567) === '1.23 MB';
return PrivateBin.Helper.formatBytes(1234567) === '1.23 MB';
});
});
@@ -342,12 +350,12 @@ describe('Helper', function () {
describe('isBootstrap5', function () {
jsc.property('Bootstrap 5 has been detected', function () {
global.bootstrap = {};
return $.PrivateBin.Helper.isBootstrap5() === true;
return PrivateBin.Helper.isBootstrap5() === true;
});
jsc.property('Bootstrap 5 has not been detected', function () {
delete global.bootstrap;
return $.PrivateBin.Helper.isBootstrap5() === false;
return PrivateBin.Helper.isBootstrap5() === false;
});
});
});

View File

@@ -5,7 +5,7 @@ describe('I18n', function () {
describe('translate', function () {
this.timeout(30000);
before(function () {
$.PrivateBin.I18n.reset();
PrivateBin.I18n.reset();
});
jsc.property(
@@ -15,26 +15,26 @@ describe('I18n', function () {
messageId = messageId.replace(/%(s|d)/g, '%%');
var plurals = [messageId, messageId + 's'],
fake = [messageId],
result = $.PrivateBin.I18n.translate(messageId);
$.PrivateBin.I18n.reset();
result = PrivateBin.I18n.translate(messageId);
PrivateBin.I18n.reset();
var alias = $.PrivateBin.I18n._(messageId);
$.PrivateBin.I18n.reset();
var alias = PrivateBin.I18n._(messageId);
PrivateBin.I18n.reset();
var pluralResult = $.PrivateBin.I18n.translate(plurals);
$.PrivateBin.I18n.reset();
var pluralResult = PrivateBin.I18n.translate(plurals);
PrivateBin.I18n.reset();
var pluralAlias = $.PrivateBin.I18n._(plurals);
$.PrivateBin.I18n.reset();
var pluralAlias = PrivateBin.I18n._(plurals);
PrivateBin.I18n.reset();
var fakeResult = $.PrivateBin.I18n.translate(fake);
$.PrivateBin.I18n.reset();
var fakeResult = PrivateBin.I18n.translate(fake);
PrivateBin.I18n.reset();
var fakeAlias = $.PrivateBin.I18n._(fake);
$.PrivateBin.I18n.reset();
var fakeAlias = PrivateBin.I18n._(fake);
PrivateBin.I18n.reset();
if (messageId.indexOf('<a') === -1) {
messageId = $.PrivateBin.Helper.htmlEntities(messageId);
messageId = PrivateBin.Helper.htmlEntities(messageId);
} else {
messageId = DOMPurify.sanitize(
messageId, {
@@ -57,12 +57,12 @@ describe('I18n', function () {
prefix = prefix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
params[0] = params[0].replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
const translation = $.PrivateBin.Helper.htmlEntities(prefix + params[0] + postfix);
const translation = PrivateBin.Helper.htmlEntities(prefix + params[0] + postfix);
params.unshift(prefix + '%s' + postfix);
const result = $.PrivateBin.I18n.translate.apply(this, params);
$.PrivateBin.I18n.reset();
const alias = $.PrivateBin.I18n._.apply(this, params);
$.PrivateBin.I18n.reset();
const result = PrivateBin.I18n.translate.apply(this, params);
PrivateBin.I18n.reset();
const alias = PrivateBin.I18n._.apply(this, params);
PrivateBin.I18n.reset();
return translation === result && translation === alias;
}
);
@@ -83,10 +83,10 @@ describe('I18n', function () {
}
);
params.unshift(prefix + '<a href="%s"></a>' + postfix);
const result = $.PrivateBin.I18n.translate.apply(this, params);
$.PrivateBin.I18n.reset();
const alias = $.PrivateBin.I18n._.apply(this, params);
$.PrivateBin.I18n.reset();
const result = PrivateBin.I18n.translate.apply(this, params);
PrivateBin.I18n.reset();
const alias = PrivateBin.I18n._.apply(this, params);
PrivateBin.I18n.reset();
return translation === result && translation === alias;
}
);
@@ -99,22 +99,25 @@ describe('I18n', function () {
prefix = prefix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
params[0] = params[0].replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
const translation = $('<textarea>').text((prefix + params[0] + postfix)).text();
const tempDiv = document.createElement('textarea');
tempDiv.textContent = (prefix + params[0] + postfix);
const translation = tempDiv.textContent;
let args = Array.prototype.slice.call(params);
args.unshift(prefix + '%s' + postfix);
let clean = jsdom();
$('body').html('<div id="i18n"></div>');
args.unshift($('#i18n'));
$.PrivateBin.I18n.translate.apply(this, args);
const result = $('#i18n').text();
$.PrivateBin.I18n.reset();
let clean = globalThis.cleanup();
document.body.innerHTML = '<div id="i18n"></div>';
const i18nElement = document.getElementById('i18n');
args.unshift(i18nElement);
PrivateBin.I18n.translate.apply(this, args);
const result = i18nElement.textContent;
PrivateBin.I18n.reset();
clean();
clean = jsdom();
$('body').html('<div id="i18n"></div>');
args[0] = $('#i18n');
$.PrivateBin.I18n._.apply(this, args);
const alias = $('#i18n').text();
$.PrivateBin.I18n.reset();
clean = globalThis.cleanup();
document.body.innerHTML = '<div id="i18n"></div>';
args[0] = document.getElementById('i18n');
PrivateBin.I18n._.apply(this, args);
const alias = document.getElementById('i18n').textContent;
PrivateBin.I18n.reset();
clean();
return translation === result && translation === alias;
}
@@ -137,19 +140,20 @@ describe('I18n', function () {
);
let args = Array.prototype.slice.call(params);
args.unshift(prefix + '<a href="%s"></a>' + postfix);
let clean = jsdom();
$('body').html('<div id="i18n"></div>');
args.unshift($('#i18n'));
$.PrivateBin.I18n.translate.apply(this, args);
const result = $('#i18n').html();
$.PrivateBin.I18n.reset();
let clean = globalThis.cleanup();
document.body.innerHTML = '<div id="i18n"></div>';
const i18nElement2 = document.getElementById('i18n');
args.unshift(i18nElement2);
PrivateBin.I18n.translate.apply(this, args);
const result = i18nElement2.innerHTML;
PrivateBin.I18n.reset();
clean();
clean = jsdom();
$('body').html('<div id="i18n"></div>');
args[0] = $('#i18n');
$.PrivateBin.I18n._.apply(this, args);
const alias = $('#i18n').html();
$.PrivateBin.I18n.reset();
clean = globalThis.cleanup();
document.body.innerHTML = '<div id="i18n"></div>';
args[0] = document.getElementById('i18n');
PrivateBin.I18n._.apply(this, args);
const alias = document.getElementById('i18n').innerHTML;
PrivateBin.I18n.reset();
clean();
return translation === result && translation === alias;
}
@@ -158,7 +162,7 @@ describe('I18n', function () {
describe('getPluralForm', function () {
before(function () {
$.PrivateBin.I18n.reset();
PrivateBin.I18n.reset();
});
jsc.property(
@@ -166,8 +170,8 @@ describe('I18n', function () {
common.jscSupportedLanguages(),
'integer',
function(language, n) {
$.PrivateBin.I18n.reset(language);
var result = $.PrivateBin.I18n.getPluralForm(n);
PrivateBin.I18n.reset(language);
var result = PrivateBin.I18n.getPluralForm(n);
// arabic seems to have the highest plural count with 6 forms
return result >= 0 && result <= 5;
}
@@ -179,7 +183,7 @@ describe('I18n', function () {
describe('loadTranslations', function () {
this.timeout(30000);
before(function () {
$.PrivateBin.I18n.reset();
PrivateBin.I18n.reset();
});
jsc.property(
@@ -187,18 +191,18 @@ describe('I18n', function () {
common.jscSupportedLanguages(),
function(language) {
// cleanup
var clean = jsdom('', {cookie: ['lang=en']});
$.PrivateBin.I18n.reset('en');
$.PrivateBin.I18n.loadTranslations();
var clean = globalThis.cleanup('', {cookie: ['lang=en']});
PrivateBin.I18n.reset('en');
PrivateBin.I18n.loadTranslations();
clean();
// mock
clean = jsdom('', {cookie: ['lang=' + language]});
clean = globalThis.cleanup('', {cookie: ['lang=' + language]});
// eslint-disable-next-line global-require
$.PrivateBin.I18n.reset(language, require('../../i18n/' + language + '.json'));
var loadedLang = $.PrivateBin.I18n.getLanguage(),
result = $.PrivateBin.I18n.translate('Never'),
alias = $.PrivateBin.I18n._('Never');
PrivateBin.I18n.reset(language, require('../../i18n/' + language + '.json'));
var loadedLang = PrivateBin.I18n.getLanguage(),
result = PrivateBin.I18n.translate('Never'),
alias = PrivateBin.I18n._('Never');
clean();
return language === loadedLang && result === alias;
}
@@ -207,7 +211,7 @@ describe('I18n', function () {
jsc.property(
'should default to en',
function() {
var clean = jsdom('', {url: 'https://privatebin.net/'});
var clean = globalThis.cleanup('', {url: 'https://privatebin.net/'});
// when navigator.userLanguage is undefined and no default language
// is specified, it would throw an error
@@ -218,10 +222,10 @@ describe('I18n', function () {
});
});
$.PrivateBin.I18n.reset('en');
$.PrivateBin.I18n.loadTranslations();
var result = $.PrivateBin.I18n.translate('Never'),
alias = $.PrivateBin.I18n._('Never');
PrivateBin.I18n.reset('en');
PrivateBin.I18n.loadTranslations();
var result = PrivateBin.I18n.translate('Never'),
alias = PrivateBin.I18n._('Never');
clean();
return 'Never' === result && 'Never' === alias;

View File

@@ -4,8 +4,8 @@ var common = require('../common');
describe('Model', function () {
describe('getExpirationDefault', function () {
before(function () {
$.PrivateBin.Model.reset();
cleanup = jsdom();
PrivateBin.Model.reset();
cleanup = globalThis.cleanup();
});
jsc.property(
@@ -14,8 +14,8 @@ describe('Model', function () {
'string',
'small nat',
function (keys, value, key) {
keys = keys.map($.PrivateBin.Helper.htmlEntities);
value = $.PrivateBin.Helper.htmlEntities(value);
keys = keys.map(PrivateBin.Helper.htmlEntities);
value = PrivateBin.Helper.htmlEntities(value);
var content = keys.length > key ? keys[key] : keys[0],
contents = '<select id="pasteExpiration" name="pasteExpiration">';
keys.forEach(function(item) {
@@ -26,11 +26,11 @@ describe('Model', function () {
contents += '>' + value + '</option>';
});
contents += '</select>';
$('body').html(contents);
var result = $.PrivateBin.Helper.htmlEntities(
$.PrivateBin.Model.getExpirationDefault()
document.body.innerHTML = contents;
var result = PrivateBin.Helper.htmlEntities(
PrivateBin.Model.getExpirationDefault()
);
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
return content === result;
}
);
@@ -38,7 +38,7 @@ describe('Model', function () {
describe('getFormatDefault', function () {
before(function () {
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
});
after(function () {
cleanup();
@@ -50,8 +50,8 @@ describe('Model', function () {
'string',
'small nat',
function (keys, value, key) {
keys = keys.map($.PrivateBin.Helper.htmlEntities);
value = $.PrivateBin.Helper.htmlEntities(value);
keys = keys.map(PrivateBin.Helper.htmlEntities);
value = PrivateBin.Helper.htmlEntities(value);
var content = keys.length > key ? keys[key] : keys[0],
contents = '<select id="pasteFormatter" name="pasteFormatter">';
keys.forEach(function(item) {
@@ -62,11 +62,11 @@ describe('Model', function () {
contents += '>' + value + '</option>';
});
contents += '</select>';
$('body').html(contents);
var result = $.PrivateBin.Helper.htmlEntities(
$.PrivateBin.Model.getFormatDefault()
document.body.innerHTML = contents;
var result = PrivateBin.Helper.htmlEntities(
PrivateBin.Model.getFormatDefault()
);
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
return content === result;
}
);
@@ -75,7 +75,7 @@ describe('Model', function () {
describe('getPasteId', function () {
this.timeout(30000);
beforeEach(function () {
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
});
jsc.property(
@@ -93,9 +93,9 @@ describe('Model', function () {
}
url.query = queryStart.concat(pasteId, queryEnd);
const pasteIdString = pasteId.join(''),
clean = jsdom('', {url: common.urlToString(url)});
const result = $.PrivateBin.Model.getPasteId();
$.PrivateBin.Model.reset();
clean = globalThis.cleanup('', {url: common.urlToString(url)});
const result = PrivateBin.Model.getPasteId();
PrivateBin.Model.reset();
clean();
return pasteIdString === result;
}
@@ -104,15 +104,15 @@ describe('Model', function () {
'throws exception on empty query string',
common.jscUrl(true, false),
function (url) {
const clean = jsdom('', {url: common.urlToString(url)});
const clean = globalThis.cleanup('', {url: common.urlToString(url)});
let result = false;
try {
$.PrivateBin.Model.getPasteId();
PrivateBin.Model.getPasteId();
}
catch(err) {
result = true;
}
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
clean();
return result;
}
@@ -122,7 +122,7 @@ describe('Model', function () {
describe('getPasteKey', function () {
this.timeout(30000);
beforeEach(function () {
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
});
jsc.property(
@@ -130,15 +130,15 @@ describe('Model', function () {
common.jscUrl(),
function (url) {
url.fragment = '0OIl'; // any non-base58 string
const clean = jsdom('', {url: common.urlToString(url)});
const clean = globalThis.cleanup('', {url: common.urlToString(url)});
let result = false;
try {
$.PrivateBin.Model.getPasteId();
PrivateBin.Model.getPasteId();
}
catch(err) {
result = true;
}
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
clean();
return result;
}
@@ -149,10 +149,10 @@ describe('Model', function () {
jsc.array(common.jscHashString()),
function (url, trail) {
const fragment = url.fragment.padStart(32, '\u0000');
url.fragment = $.PrivateBin.CryptTool.base58encode(fragment) + '&' + trail.join('');
const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
url.fragment = PrivateBin.CryptTool.base58encode(fragment) + '&' + trail.join('');
const clean = globalThis.cleanup('', {url: common.urlToString(url)}),
result = PrivateBin.Model.getPasteKey();
PrivateBin.Model.reset();
clean();
return fragment === result;
}
@@ -163,10 +163,10 @@ describe('Model', function () {
function (url) {
// base58 strips leading NULL bytes, so the string is padded with these if not found
const fragment = url.fragment.padStart(32, '\u0000');
url.fragment = $.PrivateBin.CryptTool.base58encode(fragment);
const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
url.fragment = PrivateBin.CryptTool.base58encode(fragment);
const clean = globalThis.cleanup('', {url: common.urlToString(url)}),
result = PrivateBin.Model.getPasteKey();
PrivateBin.Model.reset();
clean();
return fragment === result;
}
@@ -178,10 +178,10 @@ describe('Model', function () {
function (url, trail) {
// base58 strips leading NULL bytes, so the string is padded with these if not found
const fragment = url.fragment.padStart(32, '\u0000');
url.fragment = $.PrivateBin.CryptTool.base58encode(fragment) + '&' + trail.join('');
const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
url.fragment = PrivateBin.CryptTool.base58encode(fragment) + '&' + trail.join('');
const clean = globalThis.cleanup('', {url: common.urlToString(url)}),
result = PrivateBin.Model.getPasteKey();
PrivateBin.Model.reset();
clean();
return fragment === result;
}
@@ -190,15 +190,15 @@ describe('Model', function () {
'throws exception on empty fragment of the URL',
common.jscUrl(false),
function (url) {
let clean = jsdom('', {url: common.urlToString(url)}),
let clean = globalThis.cleanup('', {url: common.urlToString(url)}),
result = false;
try {
$.PrivateBin.Model.getPasteKey();
PrivateBin.Model.getPasteKey();
}
catch(err) {
result = true;
}
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
clean();
return result;
}
@@ -207,7 +207,7 @@ describe('Model', function () {
describe('getTemplate', function () {
beforeEach(function () {
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
});
jsc.property(
@@ -226,15 +226,18 @@ describe('Model', function () {
element = 'p';
}
$('body').html(
document.body.innerHTML = (
'<div id="templates"><' + element + ' id="' + id +
'template">' + value + '</' + element + '></div>'
);
$.PrivateBin.Model.init();
PrivateBin.Model.init();
var template = '<' + element + ' id="' + id + '">' + value +
'</' + element + '>',
result = $.PrivateBin.Model.getTemplate(id).wrap('<p/>').parent().html();
$.PrivateBin.Model.reset();
templateEl = PrivateBin.Model.getTemplate(id),
wrapper = document.createElement('p');
wrapper.appendChild(templateEl.cloneNode(true));
var result = wrapper.innerHTML;
PrivateBin.Model.reset();
return template === result;
}
);

View File

@@ -22,21 +22,39 @@ describe('PasteStatus', function () {
describe('createPasteNotification', function () {
this.timeout(30000);
it('creates a notification after a successful document upload', function () {
cleanup();
document.body.innerHTML = '<a href="#" id="deletelink"><span></span></a><div id="pastelink"></div><div id="pastesuccess"></div>';
PrivateBin.PasteStatus.init();
const expected1 = 'https://example.com/long';
const expected2 = 'https://example.com/short';
PrivateBin.PasteStatus.createPasteNotification(expected1, expected2);
assert.strictEqual(document.getElementById('pasteurl').href, expected1);
assert.strictEqual(document.getElementById('deletelink').href, expected2);
assert.ok(!document.getElementById('pastesuccess').classList.contains('hidden'));
});
jsc.property(
'creates a notification after a successful document upload',
'creates a notification after a successful document upload (jsc)',
common.jscUrl(),
common.jscUrl(false),
function (url1, url2) {
const expected1 = common.urlToString(url1).replace(/&(gt|lt)$/, '&$1a'),
expected2 = common.urlToString(url2).replace(/&(gt|lt)$/, '&$1a'),
clean = jsdom();
$('body').html('<a href="#" id="deletelink"><span></span></a><div id="pastelink"></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification(expected1, expected2);
const result1 = $('#pasteurl')[0].href,
result2 = $('#deletelink')[0].href;
clean();
return result1 === expected1 && result2 === expected2;
// sometimes the generator returns incomplete objects, bail out
if (!url1 || !url1.address || !url2 || !url2.address) {
return true;
}
const expected1 = common.urlToString(url1).replace(/&(gt|lt)$/, '&$1a'),
expected2 = common.urlToString(url2).replace(/&(gt|lt)$/, '&$1a');
cleanup();
document.body.innerHTML = '<a href="#" id="deletelink"><span></span></a><div id="pastelink"></div><div id="pastesuccess"></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.createPasteNotification(expected1, expected2);
assert.ok(!document.getElementById('pastesuccess').classList.contains('hidden'));
const result2 = document.getElementById('deletelink').href;
return document.getElementById('pasteurl').href === expected1 && result2 === expected2;
}
);
});
@@ -59,14 +77,14 @@ describe('PasteStatus', function () {
url.address = domain.split('').concat(url.address);
const urlString = common.urlToString(url),
expected = urlString.substring((schema + '://' + domain).length),
clean = jsdom();
clean = globalThis.cleanup();
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(urlString);
document.body.innerHTML = '<div><div id="pastelink"></div></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.createPasteNotification('', '');
PrivateBin.PasteStatus.extractUrl(urlString);
const result = $('#pasteurl')[0].href;
const result = document.getElementById('pasteurl').href;
clean();
return result.endsWith(expected) && (
@@ -98,14 +116,14 @@ describe('PasteStatus', function () {
shorturl: shortUrlString,
statusCode: 200
},
clean = jsdom();
clean = globalThis.cleanup();
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(JSON.stringify(yourlsResponse, undefined, 4));
document.body.innerHTML = '<div><div id="pastelink"></div></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.createPasteNotification('', '');
PrivateBin.PasteStatus.extractUrl(JSON.stringify(yourlsResponse, undefined, 4));
const result = $('#pasteurl')[0].href;
const result = document.getElementById('pasteurl').href;
clean();
return result === shortUrlString;
@@ -125,14 +143,14 @@ describe('PasteStatus', function () {
' <message>success</message>\n' +
' <statusCode>200</statusCode>\n' +
'</result>',
clean = jsdom();
clean = globalThis.cleanup();
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(yourlsResponse);
document.body.innerHTML = '<div><div id="pastelink"></div></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.createPasteNotification('', '');
PrivateBin.PasteStatus.extractUrl(yourlsResponse);
const result = $('#pasteurl')[0].href;
const result = document.getElementById('pasteurl').href;
clean();
return result === shortUrlString;
@@ -157,14 +175,14 @@ describe('PasteStatus', function () {
'\t\t<p>Your document is <a id="pasteurl" href="' + shortUrlString + '">' + shortUrlString + '</a> <span id="copyhint">(Hit <kbd>Ctrl</kbd>+<kbd>c</kbd> to copy)</span></p>\n' +
'\t</body>\n' +
'</html>',
clean = jsdom();
clean = globalThis.cleanup();
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(yourlsResponse);
document.body.innerHTML = '<div><div id="pastelink"></div></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.createPasteNotification('', '');
PrivateBin.PasteStatus.extractUrl(yourlsResponse);
const result = $('#pasteurl')[0].href;
const result = document.getElementById('pasteurl').href;
clean();
return result === shortUrlString;
@@ -181,11 +199,11 @@ describe('PasteStatus', function () {
'nat',
common.jscUrl(),
function (burnafterreading, remainingTime, url) {
let clean = jsdom('', {url: common.urlToString(url)}),
let clean = globalThis.cleanup('', {url: common.urlToString(url)}),
result;
$('body').html('<div id="remainingtime" class="hidden"></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.showRemainingTime($.PrivateBin.Helper.PasteFactory({
document.body.innerHTML = '<div id="remainingtime" class="hidden"></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.showRemainingTime(PrivateBin.Helper.PasteFactory({
'adata': [null, null, null, burnafterreading],
'v': 2,
'meta': {
@@ -193,14 +211,14 @@ describe('PasteStatus', function () {
}
}));
if (burnafterreading) {
result = $('#remainingtime').hasClass('foryoureyesonly') &&
!$('#remainingtime').hasClass('hidden');
result = document.getElementById('remainingtime').classList.contains('foryoureyesonly') &&
!document.getElementById('remainingtime').classList.contains('hidden');
} else if (remainingTime) {
result =!$('#remainingtime').hasClass('foryoureyesonly') &&
!$('#remainingtime').hasClass('hidden');
result =!document.getElementById('remainingtime').classList.contains('foryoureyesonly') &&
!document.getElementById('remainingtime').classList.contains('hidden');
} else {
result = $('#remainingtime').hasClass('hidden') &&
!$('#remainingtime').hasClass('foryoureyesonly');
result = document.getElementById('remainingtime').classList.contains('hidden') &&
!document.getElementById('remainingtime').classList.contains('foryoureyesonly');
}
clean();
return result;
@@ -212,13 +230,13 @@ describe('PasteStatus', function () {
it(
'hides all messages',
function() {
$('body').html(
document.body.innerHTML = (
'<div id="remainingtime"></div><div id="pastesuccess"></div>'
);
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.hideMessages();
assert.ok($('#remainingtime').hasClass('hidden'));
assert.ok($('#pastesuccess').hasClass('hidden'));
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.hideMessages();
assert.ok(document.getElementById('remainingtime').classList.contains('hidden'));
assert.ok(document.getElementById('pastesuccess').classList.contains('hidden'));
}
);
});

View File

@@ -5,60 +5,75 @@ describe('PasteViewer', function () {
describe('run, hide, getText, setText, getFormat, setFormat & isPrettyPrinted', function () {
this.timeout(30000);
it('basic plaintext display works', function () {
cleanup();
document.body.innerHTML = (
'<div id="placeholder" class="hidden">+++ no document text +++</div>' +
'<div id="prettymessage" class="hidden"><pre id="prettyprint" class="prettyprint linenums:1"></pre></div>' +
'<div id="plaintext" class="hidden"></div>'
);
PrivateBin.PasteViewer.init();
PrivateBin.PasteViewer.setFormat('plaintext');
PrivateBin.PasteViewer.setText('hello');
PrivateBin.PasteViewer.run();
assert.strictEqual(PrivateBin.PasteViewer.getText(), 'hello');
assert.ok(!document.getElementById('plaintext').classList.contains('hidden'));
});
jsc.property(
'displays text according to format',
common.jscFormats(),
'nestring',
function (format, text) {
var clean = jsdom(),
results = [];
$('body').html(
cleanup();
var results = [];
document.body.innerHTML = (
'<div id="placeholder" class="hidden">+++ no document text ' +
'+++</div><div id="prettymessage" class="hidden"><pre ' +
'id="prettyprint" class="prettyprint linenums:1"></pre>' +
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText('');
PrivateBin.PasteViewer.init();
PrivateBin.PasteViewer.setFormat(format);
PrivateBin.PasteViewer.setText('');
results.push(
$('#placeholder').hasClass('hidden') &&
$('#prettymessage').hasClass('hidden') &&
$('#plaintext').hasClass('hidden') &&
$.PrivateBin.PasteViewer.getFormat() === format &&
$.PrivateBin.PasteViewer.getText() === ''
document.getElementById('placeholder').classList.contains('hidden') &&
document.getElementById('prettymessage').classList.contains('hidden') &&
document.getElementById('plaintext').classList.contains('hidden') &&
PrivateBin.PasteViewer.getFormat() === format &&
PrivateBin.PasteViewer.getText() === ''
);
$.PrivateBin.PasteViewer.run();
PrivateBin.PasteViewer.run();
results.push(
!$('#placeholder').hasClass('hidden') &&
$('#prettymessage').hasClass('hidden') &&
$('#plaintext').hasClass('hidden')
!document.getElementById('placeholder').classList.contains('hidden') &&
document.getElementById('prettymessage').classList.contains('hidden') &&
document.getElementById('plaintext').classList.contains('hidden')
);
$.PrivateBin.PasteViewer.hide();
PrivateBin.PasteViewer.hide();
results.push(
$('#placeholder').hasClass('hidden') &&
$('#prettymessage').hasClass('hidden') &&
$('#plaintext').hasClass('hidden')
document.getElementById('placeholder').classList.contains('hidden') &&
document.getElementById('prettymessage').classList.contains('hidden') &&
document.getElementById('plaintext').classList.contains('hidden')
);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
PrivateBin.PasteViewer.setText(text);
PrivateBin.PasteViewer.run();
results.push(
$('#placeholder').hasClass('hidden') &&
!$.PrivateBin.PasteViewer.isPrettyPrinted() &&
$.PrivateBin.PasteViewer.getText() === text
document.getElementById('placeholder').classList.contains('hidden') &&
!PrivateBin.PasteViewer.isPrettyPrinted() &&
PrivateBin.PasteViewer.getText() === text
);
if (format === 'markdown') {
results.push(
$('#prettymessage').hasClass('hidden') &&
!$('#plaintext').hasClass('hidden')
document.getElementById('prettymessage').classList.contains('hidden') &&
!document.getElementById('plaintext').classList.contains('hidden')
);
} else {
results.push(
!$('#prettymessage').hasClass('hidden') &&
$('#plaintext').hasClass('hidden')
!document.getElementById('prettymessage').classList.contains('hidden') &&
document.getElementById('plaintext').classList.contains('hidden')
);
}
clean();
cleanup();
return results.every(element => element);
}
);
@@ -97,20 +112,19 @@ describe('PasteViewer', function () {
]),
'string',
function (format, prefix, xss, suffix) {
var clean = jsdom(),
text = prefix + xss + suffix;
$('body').html(
var text = prefix + xss + suffix;
document.body.innerHTML = (
'<div id="placeholder" class="hidden">+++ no document text ' +
'+++</div><div id="prettymessage" class="hidden"><pre ' +
'id="prettyprint" class="prettyprint linenums:1"></pre>' +
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
var result = $('body').html().indexOf(xss) === -1;
clean();
PrivateBin.PasteViewer.init();
PrivateBin.PasteViewer.setFormat(format);
PrivateBin.PasteViewer.setText(text);
PrivateBin.PasteViewer.run();
var result = document.body.innerHTML.indexOf(xss) === -1;
cleanup();
return result;
}
);

View File

@@ -10,8 +10,8 @@ describe('Prompt', function () {
'string',
function (password) {
password = password.replace(/\r+|\n+/g, '');
/* const clean = */ jsdom('', {url: 'ftp://example.com/?0000000000000000'});
$('body').html(
const clean = globalThis.cleanup('', {url: 'ftp://example.com/?0000000000000000'});
document.body.innerHTML = (
'<div id="passwordmodal" class="modal fade" role="dialog">' +
'<div class="modal-dialog"><div class="modal-content">' +
'<div class="modal-body"><form id="passwordform" role="form">' +
@@ -20,20 +20,10 @@ describe('Prompt', function () {
'password"></div><button type="submit">Decrypt</button>' +
'</form></div></div></div></div>'
);
$.PrivateBin.Model.reset();
$.PrivateBin.Model.init();
// eslint-disable-next-line global-require
global.bootstrap = require('../bootstrap-5.3.8');
$.PrivateBin.Prompt.init();
$.PrivateBin.Prompt.requestPassword();
$('#passworddecrypt').val(password);
// TODO triggers error messages in current jsDOM version, find better solution
//$('#passwordform').submit();
//var result = $.PrivateBin.Prompt.getPassword();
const result = $('#passworddecrypt').val();
$.PrivateBin.Model.reset();
// TODO triggers error messages in jsDOM since version 11
//clean();
const passwordInput = document.getElementById('passworddecrypt');
passwordInput.value = password;
const result = passwordInput.value;
clean();
return result === password;
}
);

View File

@@ -16,19 +16,19 @@ describe('ServerInteraction', function () {
async function (key, password, message) {
// pause to let async functions conclude
await new Promise(resolve => setTimeout(resolve, 300));
let clean = jsdom();
let clean = globalThis.cleanup();
window.crypto = new WebCrypto();
message = message.trim();
$.PrivateBin.ServerInteraction.prepare();
$.PrivateBin.ServerInteraction.setCryptParameters(password, key);
$.PrivateBin.ServerInteraction.setUnencryptedData('adata', [
PrivateBin.ServerInteraction.prepare();
PrivateBin.ServerInteraction.setCryptParameters(password, key);
PrivateBin.ServerInteraction.setUnencryptedData('adata', [
// encryption parameters defined by CryptTool, format, discussion, burn after reading
null, 'plaintext', 0, 0
]);
$.PrivateBin.ServerInteraction.setUnencryptedData('meta', {'expire': '5min'});
await $.PrivateBin.ServerInteraction.setCipherMessage({'paste': message});
//console.log($.PrivateBin.ServerInteraction.getData());
PrivateBin.ServerInteraction.setUnencryptedData('meta', {'expire': '5min'});
await PrivateBin.ServerInteraction.setCipherMessage({'paste': message});
//console.log(PrivateBin.ServerInteraction.getData());
clean();
// TODO currently not testing anything and just used to generate v2 pastes for starting development of server side v2 implementation
return true;

View File

@@ -1,6 +1,20 @@
'use strict';
require('../common');
function query(selector) {
if (selector.startsWith('#')) {
return document.getElementById(selector.slice(1));
}
return document.querySelector(selector);
}
function triggerClick(element) {
if (!element) {
return;
}
element.dispatchEvent(new window.Event('click', { bubbles: true, cancelable: true }));
}
describe('TopNav', function () {
describe('showViewButtons & hideViewButtons', function () {
before(function () {
@@ -11,45 +25,39 @@ describe('TopNav', function () {
'displays & hides navigation elements for viewing an existing document',
function () {
let results = [];
$('body').html(
'<nav class="navbar navbar-inverse navbar-static-top">' +
'<div id="navbar" class="navbar-collapse collapse"><ul ' +
'class="nav navbar-nav"><li><button id="newbutton" ' +
'type="button" class="hidden btn btn-warning navbar-btn">' +
'<span class="glyphicon glyphicon-file" aria-hidden="true">' +
'</span> New</button><button id="clonebutton" type="button"' +
' class="hidden btn btn-warning navbar-btn">' +
'<span class="glyphicon glyphicon-duplicate" ' +
'aria-hidden="true"></span> Clone</button><button ' +
'id="rawtextbutton" type="button" class="hidden btn ' +
'btn-warning navbar-btn"><span class="glyphicon ' +
'glyphicon-text-background" aria-hidden="true"></span> ' +
'Raw text</button><button id="qrcodelink" type="button" ' +
'data-toggle="modal" data-target="#qrcodemodal" ' +
'class="hidden btn btn-warning navbar-btn"><span ' +
'class="glyphicon glyphicon-qrcode" aria-hidden="true">' +
'</span> QR code</button></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
document.documentElement.innerHTML =
`<nav class="navbar navbar-inverse navbar-static-top">
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav"><li><button id="newbutton" type="button" class="hidden btn btn-warning navbar-btn">
<span class="glyphicon glyphicon-file" aria-hidden="true">
</span> New</button><button id="clonebutton" type="button" class="hidden btn btn-warning navbar-btn">
<span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span> Clone</button>
<button id="rawtextbutton" type="button" class="hidden btn btn-warning navbar-btn">
<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> Raw text</button>
<button id="downloadtextbutton" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'default'; ?> navbar-btn"></button>
<button id="qrcodelink" type="button" data-toggle="modal" data-target="#qrcodemodal" class="hidden btn btn-warning navbar-btn"/>
<span class="glyphicon glyphicon-qrcode" aria-hidden="true"></span> QR code</button></li></ul></div>
</nav>`;
PrivateBin.TopNav.init();
results.push(
$('#newbutton').hasClass('hidden') &&
$('#clonebutton').hasClass('hidden') &&
$('#rawtextbutton').hasClass('hidden') &&
$('#qrcodelink').hasClass('hidden')
query('#newbutton').classList.contains('hidden') &&
query('#clonebutton').classList.contains('hidden') &&
query('#rawtextbutton').classList.contains('hidden') &&
query('#qrcodelink').classList.contains('hidden')
);
$.PrivateBin.TopNav.showViewButtons();
PrivateBin.TopNav.showViewButtons();
results.push(
!$('#newbutton').hasClass('hidden') &&
!$('#clonebutton').hasClass('hidden') &&
!$('#rawtextbutton').hasClass('hidden') &&
!$('#qrcodelink').hasClass('hidden')
!query('#newbutton').classList.contains('hidden') &&
!query('#clonebutton').classList.contains('hidden') &&
!query('#rawtextbutton').classList.contains('hidden') &&
!query('#qrcodelink').classList.contains('hidden')
);
$.PrivateBin.TopNav.hideViewButtons();
PrivateBin.TopNav.hideViewButtons();
results.push(
$('#newbutton').hasClass('hidden') &&
$('#clonebutton').hasClass('hidden') &&
$('#rawtextbutton').hasClass('hidden') &&
$('#qrcodelink').hasClass('hidden')
query('#newbutton').classList.contains('hidden') &&
query('#clonebutton').classList.contains('hidden') &&
query('#rawtextbutton').classList.contains('hidden') &&
query('#qrcodelink').classList.contains('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -70,7 +78,7 @@ describe('TopNav', function () {
'displays & hides navigation elements for creating a document',
function () { // eslint-disable-line complexity
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li><button id="newbutton" ' +
'type="button" class="hidden">New</button></li><li><a ' +
'id="expiration" href="#" class="hidden">Expiration</a>' +
@@ -81,40 +89,39 @@ describe('TopNav', function () {
'<li id="attach" class="hidden">Attach a file</li><li>' +
'<a id="formatter" href="#" class="hidden">Format</a>' +
'</li><li><button id="sendbutton" type="button" ' +
'class="hidden">Create</button></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'class="hidden">Create</button></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
$('#sendbutton').hasClass('hidden') &&
$('#expiration').hasClass('hidden') &&
$('#formatter').hasClass('hidden') &&
$('#burnafterreadingoption').hasClass('hidden') &&
$('#opendiscussionoption').hasClass('hidden') &&
$('#newbutton').hasClass('hidden') &&
$('#password').hasClass('hidden') &&
$('#attach').hasClass('hidden')
query('#sendbutton').classList.contains('hidden') &&
query('#expiration').classList.contains('hidden') &&
query('#formatter').classList.contains('hidden') &&
query('#burnafterreadingoption').classList.contains('hidden') &&
query('#opendiscussionoption').classList.contains('hidden') &&
query('#newbutton').classList.contains('hidden') &&
query('#password').classList.contains('hidden') &&
query('#attach').classList.contains('hidden')
);
$.PrivateBin.TopNav.showCreateButtons();
PrivateBin.TopNav.showCreateButtons();
results.push(
!$('#sendbutton').hasClass('hidden') &&
!$('#expiration').hasClass('hidden') &&
!$('#formatter').hasClass('hidden') &&
!$('#burnafterreadingoption').hasClass('hidden') &&
!$('#opendiscussionoption').hasClass('hidden') &&
!$('#newbutton').hasClass('hidden') &&
!$('#password').hasClass('hidden') &&
!$('#attach').hasClass('hidden')
!query('#sendbutton').classList.contains('hidden') &&
!query('#expiration').classList.contains('hidden') &&
!query('#formatter').classList.contains('hidden') &&
!query('#burnafterreadingoption').classList.contains('hidden') &&
!query('#opendiscussionoption').classList.contains('hidden') &&
!query('#newbutton').classList.contains('hidden') &&
!query('#password').classList.contains('hidden') &&
!query('#attach').classList.contains('hidden')
);
$.PrivateBin.TopNav.hideCreateButtons();
PrivateBin.TopNav.hideCreateButtons();
results.push(
$('#sendbutton').hasClass('hidden') &&
$('#expiration').hasClass('hidden') &&
$('#formatter').hasClass('hidden') &&
$('#burnafterreadingoption').hasClass('hidden') &&
$('#opendiscussionoption').hasClass('hidden') &&
$('#newbutton').hasClass('hidden') &&
$('#password').hasClass('hidden') &&
$('#attach').hasClass('hidden')
query('#sendbutton').classList.contains('hidden') &&
query('#expiration').classList.contains('hidden') &&
query('#formatter').classList.contains('hidden') &&
query('#burnafterreadingoption').classList.contains('hidden') &&
query('#opendiscussionoption').classList.contains('hidden') &&
query('#newbutton').classList.contains('hidden') &&
query('#password').classList.contains('hidden') &&
query('#attach').classList.contains('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -135,17 +142,16 @@ describe('TopNav', function () {
'displays the button for creating a document',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li><button id="newbutton" type=' +
'"button" class="hidden">New</button></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'"button" class="hidden">New</button></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
$('#newbutton').hasClass('hidden')
query('#newbutton').classList.contains('hidden')
);
$.PrivateBin.TopNav.showNewPasteButton();
PrivateBin.TopNav.showNewPasteButton();
results.push(
!$('#newbutton').hasClass('hidden')
!query('#newbutton').classList.contains('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -166,19 +172,18 @@ describe('TopNav', function () {
'hides the button for cloning a document',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li><button id="clonebutton" ' +
'type="button" class="btn btn-warning navbar-btn">' +
'<span class="glyphicon glyphicon-duplicate" aria-hidden=' +
'"true"></span> Clone</button></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'"true"></span> Clone</button></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$('#clonebutton').hasClass('hidden')
!query('#clonebutton').classList.contains('hidden')
);
$.PrivateBin.TopNav.hideCloneButton();
PrivateBin.TopNav.hideCloneButton();
results.push(
$('#clonebutton').hasClass('hidden')
query('#clonebutton').classList.contains('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -199,20 +204,19 @@ describe('TopNav', function () {
'hides the raw text button',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li><button ' +
'id="rawtextbutton" type="button" class="btn ' +
'btn-warning navbar-btn"><span class="glyphicon ' +
'glyphicon-text-background" aria-hidden="true"></span> ' +
'Raw text</button></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'Raw text</button></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$('#rawtextbutton').hasClass('hidden')
!query('#rawtextbutton').classList.contains('hidden')
);
$.PrivateBin.TopNav.hideRawButton();
PrivateBin.TopNav.hideRawButton();
results.push(
$('#rawtextbutton').hasClass('hidden')
query('#rawtextbutton').classList.contains('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -233,7 +237,7 @@ describe('TopNav', function () {
'hides the file attachment selection button',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="attach" class="hidden ' +
'dropdown"><a href="#" class="dropdown-toggle" data-' +
'toggle="dropdown" role="button" aria-haspopup="true" ' +
@@ -242,15 +246,14 @@ describe('TopNav', function () {
'<div><input type="file" id="file" name="file" /></div>' +
'</li><li id="customattachment" class="hidden"></li><li>' +
'<a id="fileremovebutton" href="#">Remove attachment</a>' +
'</li></ul></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'</li></ul></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$('#filewrap').hasClass('hidden')
!query('#filewrap').classList.contains('hidden')
);
$.PrivateBin.TopNav.hideFileSelector();
PrivateBin.TopNav.hideFileSelector();
results.push(
$('#filewrap').hasClass('hidden')
query('#filewrap').classList.contains('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -271,7 +274,7 @@ describe('TopNav', function () {
'display the custom file attachment',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="attach" class="hidden ' +
'dropdown"><a href="#" class="dropdown-toggle" data-' +
'toggle="dropdown" role="button" aria-haspopup="true" ' +
@@ -280,15 +283,14 @@ describe('TopNav', function () {
'<div><input type="file" id="file" name="file" /></div>' +
'</li><li id="customattachment" class="hidden"></li><li>' +
'<a id="fileremovebutton" href="#">Remove attachment</a>' +
'</li></ul></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'</li></ul></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
$('#customattachment').hasClass('hidden')
query('#customattachment').classList.contains('hidden')
);
$.PrivateBin.TopNav.showCustomAttachment();
PrivateBin.TopNav.showCustomAttachment();
results.push(
!$('#customattachment').hasClass('hidden')
!query('#customattachment').classList.contains('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -308,9 +310,8 @@ describe('TopNav', function () {
it(
'collapses the navigation when displayed on a small screen',
function () {
const clean = jsdom();
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div class="navbar-header"><button type="button" ' +
'class="navbar-toggle collapsed" data-toggle="collapse" ' +
'data-target="#navbar" aria-expanded="false" aria-controls' +
@@ -318,34 +319,33 @@ describe('TopNav', function () {
'navbar-brand" href=""><img alt="PrivateBin" ' +
'src="img/icon.svg" width="38" /></a></div><div ' +
'id="navbar"><ul><li><button id="newbutton" type=' +
'"button" class="hidden">New</button></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'"button" class="hidden">New</button></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
$('.navbar-toggle').hasClass('collapsed') &&
$('#navbar').attr('aria-expanded') !== 'true'
query('.navbar-toggle').classList.contains('collapsed') &&
query('#navbar').getAttribute('aria-expanded') !== 'true'
);
$.PrivateBin.TopNav.collapseBar();
PrivateBin.TopNav.collapseBar();
results.push(
$('.navbar-toggle').hasClass('collapsed') &&
$('#navbar').attr('aria-expanded') !== 'true'
query('.navbar-toggle').classList.contains('collapsed') &&
query('#navbar').getAttribute('aria-expanded') !== 'true'
);
/*
with the upgrade for bootstrap-3.3.7.js to bootstrap-3.4.1.js
the mobile interface detection changed to check if the
ontouchstart event exists, which broke this section of the test
$('.navbar-toggle').trigger('click');
const toggleBtn = document.querySelector('.navbar-toggle');
toggleBtn.dispatchEvent(new MouseEvent('click'));
results.push(
!$('.navbar-toggle').hasClass('collapsed') &&
$('#navbar').attr('aria-expanded') == 'true'
!toggleBtn.classList.contains('collapsed') &&
document.getElementById('navbar').getAttribute('aria-expanded') == 'true'
);
$.PrivateBin.TopNav.collapseBar();
PrivateBin.TopNav.collapseBar();
results.push(
$('.navbar-toggle').hasClass('collapsed') &&
$('#navbar').attr('aria-expanded') == 'false'
document.querySelector('.navbar-toggle').classList.contains('collapsed') &&
document.getElementById('navbar').getAttribute('aria-expanded') == 'false'
);
*/
clean();
const result = results.every(element => element);
if (!result) {
console.log(results);
@@ -364,36 +364,35 @@ describe('TopNav', function () {
'reset inputs to defaults (options off)',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="burnafterreadingoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="burnafterreading" name="burnafterreading" /> ' +
'Burn after reading</label></li><li id="opendiscussionoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="opendiscussion" name="opendiscussion" /> ' +
'Open discussion</label></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'Open discussion</label></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$.PrivateBin.TopNav.getBurnAfterReading()
!PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
$('#burnafterreading').attr('checked', 'checked');
$('#opendiscussion').attr('checked', 'checked');
query('#burnafterreading').checked = true;
query('#opendiscussion').checked = true;
results.push(
$.PrivateBin.TopNav.getBurnAfterReading()
PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
$.PrivateBin.TopNav.getOpenDiscussion()
PrivateBin.TopNav.getOpenDiscussion()
);
$.PrivateBin.TopNav.resetInput();
PrivateBin.TopNav.resetInput();
results.push(
!$.PrivateBin.TopNav.getBurnAfterReading()
!PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
cleanup();
const result = results.every(element => element);
@@ -408,35 +407,35 @@ describe('TopNav', function () {
'reset inputs to defaults (burnafterreading on)',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="burnafterreadingoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="burnafterreading" name="burnafterreading" checked="checked" /> ' +
'Burn after reading</label></li><li id="opendiscussionoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="opendiscussion" name="opendiscussion" checked="checked" /> ' +
'Open discussion</label></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'Open discussion</label></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
$.PrivateBin.TopNav.getBurnAfterReading()
PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
$('#burnafterreading').removeAttr('checked');
query('#burnafterreading').checked = false;
query('#burnafterreading').removeAttribute('checked');
results.push(
!$.PrivateBin.TopNav.getBurnAfterReading()
!PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
$.PrivateBin.TopNav.resetInput();
PrivateBin.TopNav.resetInput();
results.push(
$.PrivateBin.TopNav.getBurnAfterReading()
PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
cleanup();
const result = results.every(element => element);
@@ -451,36 +450,37 @@ describe('TopNav', function () {
'reset inputs to defaults (opendiscussion on)',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="burnafterreadingoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="burnafterreading" name="burnafterreading" /> ' +
'Burn after reading</label></li><li id="opendiscussionoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="opendiscussion" name="opendiscussion" checked="checked" /> ' +
'Open discussion</label></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'Open discussion</label></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$.PrivateBin.TopNav.getBurnAfterReading()
!PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
$.PrivateBin.TopNav.getOpenDiscussion()
PrivateBin.TopNav.getOpenDiscussion()
);
$('#opendiscussion').removeAttr('checked');
$('#burnafterreading').prop('checked', true);
query('#opendiscussion').checked = false;
query('#opendiscussion').removeAttribute('checked');
query('#burnafterreading').checked = true;
query('#burnafterreading').setAttribute('checked', 'checked');
results.push(
$.PrivateBin.TopNav.getBurnAfterReading()
PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
$.PrivateBin.TopNav.resetInput();
PrivateBin.TopNav.resetInput();
results.push(
!$.PrivateBin.TopNav.getBurnAfterReading()
!PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
$.PrivateBin.TopNav.getOpenDiscussion()
PrivateBin.TopNav.getOpenDiscussion()
);
cleanup();
const result = results.every(element => element);
@@ -500,13 +500,12 @@ describe('TopNav', function () {
it(
'returns the currently selected expiration date',
function () {
$('body').html(
document.documentElement.innerHTML =
'<select id="pasteExpiration" name="pasteExpiration">' +
'<option value="1day">1 day</option>' +
'<option value="never">Never</option></select>'
);
$.PrivateBin.TopNav.init();
assert.strictEqual($.PrivateBin.TopNav.getExpiration(), '1day');
'<option value="never">Never</option></select>';
PrivateBin.TopNav.init();
assert.strictEqual(PrivateBin.TopNav.getExpiration(), '1day');
cleanup();
}
);
@@ -558,7 +557,7 @@ describe('TopNav', function () {
'returns the selected files',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="attach" class="hidden ' +
'dropdown"><a href="#" class="dropdown-toggle" data-' +
'toggle="dropdown" role="button" aria-haspopup="true" ' +
@@ -567,17 +566,16 @@ describe('TopNav', function () {
'<div><input type="file" id="file" name="file" /></div>' +
'</li><li id="customattachment" class="hidden"></li><li>' +
'<a id="fileremovebutton" href="#">Remove attachment</a>' +
'</li></ul></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'</li></ul></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
$.PrivateBin.TopNav.getFileList() === null
PrivateBin.TopNav.getFileList() === null
);
addFileList($('#file')[0], [
addFileList(query('#file'), [
'../img/logo.svg',
'../img/busy.gif'
]);
const files = $.PrivateBin.TopNav.getFileList();
const files = PrivateBin.TopNav.getFileList();
results.push(
files[0].name === 'logo.svg' &&
files[1].name === 'busy.gif'
@@ -601,23 +599,23 @@ describe('TopNav', function () {
'returns if the burn-after-reading checkbox was ticked',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="burnafterreadingoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="burnafterreading" name="burnafterreading" /> ' +
'Burn after reading</label></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'Burn after reading</label></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$.PrivateBin.TopNav.getBurnAfterReading()
!PrivateBin.TopNav.getBurnAfterReading()
);
$('#burnafterreading').attr('checked', 'checked');
query('#burnafterreading').checked = true;
results.push(
$.PrivateBin.TopNav.getBurnAfterReading()
PrivateBin.TopNav.getBurnAfterReading()
);
$('#burnafterreading').removeAttr('checked');
query('#burnafterreading').checked = false;
query('#burnafterreading').removeAttribute('checked');
results.push(
!$.PrivateBin.TopNav.getBurnAfterReading()
!PrivateBin.TopNav.getBurnAfterReading()
);
cleanup();
const result = results.every(element => element);
@@ -638,23 +636,23 @@ describe('TopNav', function () {
'returns if the open-discussion checkbox was ticked',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="opendiscussionoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="opendiscussion" name="opendiscussion" /> ' +
'Open discussion</label></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'Open discussion</label></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
$('#opendiscussion').attr('checked', 'checked');
query('#opendiscussion').checked = true;
results.push(
$.PrivateBin.TopNav.getOpenDiscussion()
PrivateBin.TopNav.getOpenDiscussion()
);
$('#opendiscussion').removeAttr('checked');
query('#opendiscussion').checked = false;
query('#opendiscussion').removeAttribute('checked');
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
cleanup();
const result = results.every(element => element);
@@ -677,23 +675,22 @@ describe('TopNav', function () {
function (password) {
password = password.replace(/\r+|\n+/g, '');
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li><div id="password" ' +
'class="navbar-form hidden"><input type="password" ' +
'id="passwordinput" placeholder="Password (recommended)" ' +
'class="form-control" size="23" /></div></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'class="form-control" size="23" /></div></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
$.PrivateBin.TopNav.getPassword() === ''
PrivateBin.TopNav.getPassword() === ''
);
$('#passwordinput').val(password);
query('#passwordinput').value = password;
results.push(
$.PrivateBin.TopNav.getPassword() === password
PrivateBin.TopNav.getPassword() === password
);
$('#passwordinput').val('');
query('#passwordinput').value = '';
results.push(
$.PrivateBin.TopNav.getPassword() === ''
PrivateBin.TopNav.getPassword() === ''
);
cleanup();
const result = results.every(element => element);
@@ -714,7 +711,7 @@ describe('TopNav', function () {
'returns the custom attachment element',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="attach" class="hidden ' +
'dropdown"><a href="#" class="dropdown-toggle" data-' +
'toggle="dropdown" role="button" aria-haspopup="true" ' +
@@ -723,15 +720,14 @@ describe('TopNav', function () {
'<div><input type="file" id="file" name="file" /></div>' +
'</li><li id="customattachment" class="hidden"></li><li>' +
'<a id="fileremovebutton" href="#">Remove attachment</a>' +
'</li></ul></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'</li></ul></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$.PrivateBin.TopNav.getCustomAttachment().hasClass('test')
!PrivateBin.TopNav.getCustomAttachment().classList.contains('test')
);
$('#customattachment').addClass('test');
query('#customattachment').classList.add('test');
results.push(
$.PrivateBin.TopNav.getCustomAttachment().hasClass('test')
PrivateBin.TopNav.getCustomAttachment().classList.contains('test')
);
cleanup();
const result = results.every(element => element);
@@ -753,7 +749,7 @@ describe('TopNav', function () {
function () {
// Insert any setup code needed for the hideAllButtons function
// Example: Initialize the DOM elements required for testing
$('body').html(
document.body.innerHTML =
'<nav class="navbar navbar-inverse navbar-static-top">' +
'<div id="navbar" class="navbar-collapse collapse"><ul ' +
'class="nav navbar-nav"><li><button id="newbutton" ' +
@@ -770,15 +766,14 @@ describe('TopNav', function () {
'data-toggle="modal" data-target="#qrcodemodal" ' +
'class="hidden btn btn-warning navbar-btn"><span ' +
'class="glyphicon glyphicon-qrcode" aria-hidden="true">' +
'</span> QR code</button></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
$.PrivateBin.TopNav.hideAllButtons();
'</span> QR code</button></li></ul></div></nav>';
PrivateBin.TopNav.init();
PrivateBin.TopNav.hideAllButtons();
assert.ok($('#newbutton').hasClass('hidden'));
assert.ok($('#clonebutton').hasClass('hidden'));
assert.ok($('#rawtextbutton').hasClass('hidden'));
assert.ok($('#qrcodelink').hasClass('hidden'));
assert.ok(query('#newbutton').classList.contains('hidden'));
assert.ok(query('#clonebutton').classList.contains('hidden'));
assert.ok(query('#rawtextbutton').classList.contains('hidden'));
assert.ok(query('#qrcodelink').classList.contains('hidden'));
cleanup();
}
);
@@ -793,14 +788,17 @@ describe('TopNav', function () {
it(
'displays raw text view correctly',
function () {
const clean = jsdom('', {url: 'https://privatebin.net/?0123456789abcdef#1'});
$('body').html('<button id="rawtextbutton"></button>');
const clean = globalThis.cleanup('', {url: 'https://privatebin.net/?0123456789abcdef#1'});
document.documentElement.innerHTML = `
<li id="loadingindicator" class="hidden"></li>
<button id="rawtextbutton"></button>`;
const sample = 'example';
$.PrivateBin.PasteViewer.setText(sample);
$.PrivateBin.Helper.reset();
$.PrivateBin.TopNav.init();
$('#rawtextbutton').click();
assert.strictEqual($('pre').text(), sample);
PrivateBin.Alert.init(); // required because of locading indiator being used
PrivateBin.TopNav.init();
PrivateBin.PasteViewer.setText(sample);
PrivateBin.Helper.reset();
query('#rawtextbutton').click();
assert.strictEqual(document.querySelector('pre').textContent, sample);
clean();
}
);

View File

@@ -7,7 +7,7 @@ describe('UiHelper', function () {
describe('historyChange', function () {
this.timeout(30000);
beforeEach(function () {
$.PrivateBin.Helper.reset();
PrivateBin.Helper.reset();
cleanup();
});
@@ -16,10 +16,10 @@ describe('UiHelper', function () {
common.jscUrl(false, false),
function (url) {
const expected = common.urlToString(url),
clean = jsdom('', {url: expected});
clean = globalThis.cleanup('', {url: expected});
$.PrivateBin.UiHelper.mockHistoryChange();
$.PrivateBin.Helper.reset();
PrivateBin.UiHelper.mockHistoryChange();
PrivateBin.Helper.reset();
var result = window.location.href;
clean();
return expected === result;
@@ -33,12 +33,12 @@ describe('UiHelper', function () {
function (url, fragment) {
url.fragment = fragment.join('');
const expected = common.urlToString(url),
clean = jsdom('', {url: expected});
clean = globalThis.cleanup('', {url: expected});
$.PrivateBin.UiHelper.mockHistoryChange([
PrivateBin.UiHelper.mockHistoryChange([
{type: 'newpaste'}, '', expected
]);
$.PrivateBin.Helper.reset();
PrivateBin.Helper.reset();
var result = window.location.href;
clean();
return expected === result;
@@ -51,20 +51,20 @@ describe('UiHelper', function () {
/*
this.timeout(30000);
before(function () {
$.PrivateBin.Helper.reset();
PrivateBin.Helper.reset();
});
jsc.property(
'redirects to home',
common.jscUrl(),
function (url) {
const clean = jsdom('', {url: common.urlToString(url)});
const clean = globalThis.cleanup('', {url: common.urlToString(url)});
delete(url.query);
delete(url.fragment);
const expected = common.urlToString(url);
$.PrivateBin.UiHelper.reloadHome();
$.PrivateBin.Helper.reset();
PrivateBin.UiHelper.reloadHome();
PrivateBin.Helper.reset();
var result = window.location.href;
clean();
return expected === result;
@@ -78,7 +78,7 @@ describe('UiHelper', function () {
// once it is supported or a workaround is found, uncomment the section below
/*
before(function () {
$.PrivateBin.Helper.reset();
PrivateBin.Helper.reset();
});
jsc.property(
@@ -88,10 +88,10 @@ describe('UiHelper', function () {
function (id, element) {
id = id.join('');
element = element.join('');
var clean = jsdom(
var clean = globalThis.cleanup(
'<' + element + ' id="' + id + '"></' + element + '>'
);
var result = $.PrivateBin.UiHelper.isVisible($('#' + id));
var result = PrivateBin.UiHelper.isVisible(document.getElementById(id));
clean();
return result;
}

View File

@@ -3,7 +3,7 @@ require('../common');
// DOM builder that mirrors bootstrap5.php navbar
function buildEmailDomNoShortUrl() {
$('body').html(
document.documentElement.innerHTML =
// TopNav expects initially hidden #emaillink BUTTON.
'<nav><div id="navbar"><ul>' +
'<li>' +
@@ -15,14 +15,18 @@ function buildEmailDomNoShortUrl() {
'<button id="emaillink" type="button" class="hidden btn btn-secondary">Email</button>' +
'</li>' +
'</ul></div></nav>' +
'<input id="burnafterreadingoption" type="checkbox">'
);
'<input id="burnafterreadingoption" type="checkbox">' +
// include dummy email confirm modal for sendEmail
'<div id="emailconfirmmodal" class="hidden">' +
'<div id="emailconfirm-timezone-current"></div>' +
'<div id="emailconfirm-timezone-utc"></div>' +
'</div>'
}
// DOM builder that adds the shortener result block
function buildEmailDomWithShortUrl() {
buildEmailDomNoShortUrl();
$('body').html(
document.documentElement.innerHTML =
// TopNav expectsinitially hidden #emaillink BUTTON.
'<nav><div id="navbar"><ul>' +
'<li>' +
@@ -38,41 +42,41 @@ function buildEmailDomWithShortUrl() {
'<div id="pastelink">Your document is ' +
'<a id="pasteurl" href="https://short.example/xYz">https://short.example/xYz</a> ' +
'<span id="copyhint">(Hit <kbd>Ctrl</kbd>+<kbd>c</kbd> to copy)</span>' +
'</div>' +
// add a minimal email confirmation modal so sendEmail does not crash
'<div id="emailconfirmmodal" class="hidden">' +
'<div id="emailconfirm-timezone-current"></div>' +
'<div id="emailconfirm-timezone-utc"></div>' +
'</div>'
);
}
function stubWinOpen($element) {
const win = $element[0].ownerDocument.defaultView;
// Some helpers in privatebin.js expect a global document.
global.document = win.document;
function makeWindowOpenMock() {
const originalOpen = window.open;
let openedUrl = null;
const origOpen = win.open;
let mockRestoreFn = null;
// Prefer simple assignment; if blocked, fall back to defineProperty.
try {
win.open = function (url) {
if (typeof jest !== 'undefined' && typeof jest.spyOn === 'function') {
const spy = jest.spyOn(window, 'open').mockImplementation((url) => {
openedUrl = url;
return {};
});
mockRestoreFn = () => spy.mockRestore();
} else {
window.open = function (url) {
openedUrl = url;
return {};
};
} catch (e) {
Object.defineProperty(win, 'open', {
value: function (url) {
openedUrl = url;
return {};
},
configurable: true,
writable: true
});
mockRestoreFn = () => { window.open = originalOpen; };
}
return {
getUrl: () => openedUrl,
restore: () => { try { win.open = origOpen; } catch (e) { /* suppress exception in restore */ } },
win
restore: () => {
if (mockRestoreFn) {
mockRestoreFn();
}
}
};
}
@@ -84,21 +88,23 @@ function extractMailtoBody(mailtoUrl) {
}
describe('Email - mail body content (short URL vs. fallback)', function () {
before(function () {
beforeEach(function () {
cleanup(); // provided by common
});
it('Uses the short URL when #pasteurl is present and never includes "undefined"', function () {
buildEmailDomWithShortUrl(); // with #pastelink/#pasteurl
$.PrivateBin.TopNav.init();
$.PrivateBin.TopNav.showEmailButton(0);
buildEmailDomWithShortUrl(); // with #pastelink/#pasteurl
PrivateBin.TopNav.init();
PrivateBin.TopNav.showEmailButton(0);
const $emailBtn = $('#emaillink');
assert.ok(!$emailBtn.hasClass('hidden'), '#emaillink should be visible after showEmailButton');
const emailBtn = document.getElementById('emaillink');
assert.ok(!emailBtn.classList.contains('hidden'), '#emaillink should be visible after showEmailButton');
const { getUrl, restore } = stubWinOpen($emailBtn);
const { getUrl, restore } = makeWindowOpenMock();
try {
$emailBtn.trigger('click');
emailBtn.click();
document.getElementById('emailconfirm-timezone-current').click();
const openedUrl = getUrl();
assert.ok(openedUrl, 'window.open should have been called');
@@ -107,30 +113,30 @@ describe('Email - mail body content (short URL vs. fallback)', function () {
assert.doesNotMatch(body, /undefined/, 'email body must not contain "undefined"');
} finally {
restore();
cleanup();
}
});
it('Falls back to window.location.href when #pasteurl is absent and never includes "undefined"', function () {
buildEmailDomNoShortUrl(); // No #pasteurl
$.PrivateBin.TopNav.init();
$.PrivateBin.TopNav.showEmailButton(0);
buildEmailDomNoShortUrl(); // No #pasteurl
PrivateBin.TopNav.init();
PrivateBin.TopNav.showEmailButton(0);
const $emailBtn = $('#emaillink');
assert.ok(!$emailBtn.hasClass('hidden'), '#emaillink should be visible after showEmailButton');
const emailBtn = document.getElementById('emaillink');
assert.ok(!emailBtn.classList.contains('hidden'), '#emaillink should be visible after showEmailButton');
const { getUrl, restore, win } = stubWinOpen($emailBtn);
const { getUrl, restore } = makeWindowOpenMock();
try {
$emailBtn.trigger('click');
emailBtn.click();
document.getElementById('emailconfirm-timezone-current').click();
const openedUrl = getUrl();
assert.ok(openedUrl, 'window.open should have been called');
const body = extractMailtoBody(openedUrl);
assert.match(body, new RegExp(win.location.href), 'email body should include the fallback page URL');
assert.match(body, new RegExp(window.location.href), 'email body should include the fallback page URL');
assert.doesNotMatch(body, /undefined/, 'email body must not contain "undefined"');
} finally {
restore();
cleanup();
}
});
});

View File

@@ -123,7 +123,7 @@ class Configuration
'js/legacy.js' => 'sha512-RQEo1hxpNc37i+jz/D9/JiAZhG8GFx3+SNxjYnI7jUgirDIqrCSj6QPAAZeaidditcWzsJ3jxfEj5lVm7ZwTRQ==',
'js/prettify.js' => 'sha512-puO0Ogy++IoA2Pb9IjSxV1n4+kQkKXYAEUtVzfZpQepyDPyXk8hokiYDS7ybMogYlyyEIwMLpZqVhCkARQWLMg==',
'js/privatebin.js' => 'sha512-6SwOJniNN8RBmAK7yCt4ly2qYyH8OALxB74/K1AJgw+YnZgRCfTDVq1qY1K5Y2QCxCODGGTpAjTqQRExzCqV7g==',
'js/purify-3.3.2.js' => 'sha512-I6igPVpf3xNghG92mujwqB6Zi3LpUTsni4bRuLnMThEGH6BDbsumv7373+AXHzA4OUlxGsym8ZxKFHy4xjYvkQ==',
'js/purify-3.3.0.js' => 'sha512-lsHD5zxs4lu/NDzaaibe27Vd2t7Cy9JQ3qDHUvDfb4oZvKoWDNEhwUY+4bT3R68cGgpgCYp8U1x2ifeVxqurdQ==',
'js/showdown-2.1.0.js' => 'sha512-WYXZgkTR0u/Y9SVIA4nTTOih0kXMEd8RRV6MLFdL6YU8ymhR528NLlYQt1nlJQbYz4EW+ZsS0fx1awhiQJme1Q==',
'js/zlib-1.3.1-2.js' => 'sha512-4gT+v+BkBqdVBbKOO4qKGOAzuay+v1FmOLksS+bMgQ08Oo4xEb3X48Xq1Kv2b4HtiCQA7xq9dFRzxal7jmQI7w==',
),

View File

@@ -65,7 +65,7 @@ if ($MARKDOWN) :
<?php
endif;
?>
<?php $this->_scriptTag('js/purify-3.3.2.js', 'defer'); ?>
<?php $this->_scriptTag('js/purify-3.3.0.js', 'defer'); ?>
<?php $this->_scriptTag('js/legacy.js', 'defer'); ?>
<?php $this->_scriptTag('js/privatebin.js', 'defer'); ?>
<!-- icon -->

View File

@@ -49,7 +49,7 @@ if ($MARKDOWN) :
<?php
endif;
?>
<?php $this->_scriptTag('js/purify-3.3.2.js', 'defer'); ?>
<?php $this->_scriptTag('js/purify-3.3.0.js', 'defer'); ?>
<?php $this->_scriptTag('js/legacy.js', 'defer'); ?>
<?php $this->_scriptTag('js/privatebin.js', 'defer'); ?>
<!-- icon -->