Compare commits

..

17 Commits

Author SHA1 Message Date
El RIDO
df5f4b1440 Merge pull request #1814 from PrivateBin/dependabot/npm_and_yarn/js/flatted-3.4.2
chore(deps-dev): bump flatted from 3.3.3 to 3.4.2 in /js
2026-03-21 15:49:19 +01:00
dependabot[bot]
7eaa70ae31 chore(deps-dev): bump flatted from 3.3.3 to 3.4.2 in /js
Bumps [flatted](https://github.com/WebReflection/flatted) from 3.3.3 to 3.4.2.
- [Commits](https://github.com/WebReflection/flatted/compare/v3.3.3...v3.4.2)

---
updated-dependencies:
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-21 10:28:50 +00:00
El RIDO
a0bdb2b3c8 Merge pull request #1811 from PrivateBin/dependabot/github_actions/dawidd6/action-download-artifact-19
chore(deps): bump dawidd6/action-download-artifact from 18 to 19
2026-03-18 19:58:33 +01:00
dependabot[bot]
f5543d4317 chore(deps): bump dawidd6/action-download-artifact from 18 to 19
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 18 to 19.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](1f8785ff7a...8a338493df)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-version: '19'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-18 11:52:44 +00:00
El RIDO
4ba870f48a Merge pull request #1809 from PrivateBin/dependabot/github_actions/dawidd6/action-download-artifact-18
chore(deps): bump dawidd6/action-download-artifact from 17 to 18
2026-03-16 22:04:15 +01:00
dependabot[bot]
907c4d75f6 chore(deps): bump dawidd6/action-download-artifact from 17 to 18
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 17 to 18.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](09b07ec687...1f8785ff7a)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-version: '18'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-16 11:56:20 +00:00
rugk
47d5485a33 Merge pull request #1804 from PrivateBin/docs/contrib-guide
Strengthen AI guidlines & enforce screenshots for visual changes
2026-03-15 15:22:13 +01:00
El RIDO
07eb15eb36 Merge pull request #1808 from PrivateBin/dependabot/github_actions/dawidd6/action-download-artifact-17
chore(deps): bump dawidd6/action-download-artifact from 16 to 17
2026-03-12 14:05:12 +01:00
dependabot[bot]
69ac3ad079 chore(deps): bump dawidd6/action-download-artifact from 16 to 17
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 16 to 17.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](2536c51d3d...09b07ec687)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-version: '17'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-12 11:52:43 +00:00
El RIDO
ab8e2ea2dc Merge pull request #1807 from PrivateBin/purify-3.3.2
update DOMpurify library from 3.3.0 to 3.3.2
2026-03-10 18:41:19 +01:00
El RIDO
604e61beaa update DOMpurify library from 3.3.0 to 3.3.2 2026-03-07 09:00:06 +01:00
El RIDO
6d3c9c9206 Merge pull request #1806 from PrivateBin/crowdin-translation
New Crowdin updates
2026-03-07 08:43:23 +01:00
PrivateBin Translator Bot
1bf20398e3 New translations en.json (Slovenian) 2026-03-05 17:51:08 +01:00
PrivateBin Translator Bot
09f65bf06b New translations en.json (Slovenian) 2026-03-05 14:49:45 +01:00
rugk
d462c201de style: fix typos 2026-03-03 15:21:37 +01:00
rugk
2986c97ea7 docs: also adjust PR template accordingly 2026-03-03 15:19:11 +01:00
rugk
e69570b73e Strengthen AI guidlines & force screenshots for visual users
IMHO after https://github.com/PrivateBin/PrivateBin/pull/1754 we again need to make it a requirement in the guidelines to disclose the fact an LLM is used.

This also adds to attach screenshots for visual changes etc. (which again also ensures users actually _test_ the changes they submit)

I wrote it here and not in the wiki, because:
* this text can be read by an LLM inside the git repo, which I guess is beneficial
* the text may be shown more prominently ere IMHO
* I guess the wiki guidelines rather give a "big introduction" into how to contribute with the code base, and do not define "rules"/guidelines at all
2026-03-03 15:15:22 +01:00
33 changed files with 2008 additions and 2112 deletions

View File

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

1
.gitattributes vendored
View File

@@ -9,7 +9,6 @@ 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,3 +6,10 @@ 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 @@
<!-- This is a template for your Pull Request. This are just some suggestions for you. You do not have to use all of them. -->
<!--Please honor our guidelines as written in the CONTRIBUTING.md file. To emphasize: it is required to disclose the usage of an LLM tool. -->
<!-- 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,11 +6,12 @@ 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 -->
<!-- List all the changes you have done. This section is just an example and may be removed if irrelevant. -->
*
*
## 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@2536c51d3d126276eb39f74d6bc9c72ac6ef30d3
uses: dawidd6/action-download-artifact@8a338493df3d275e4a7a63bcff3b8fe97e51a927
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: ip-lib 1.22.0 & polyfill-php80 1.33.0
* CHANGED: Upgrading libraries to: DOMpurify 3.3.2, 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 server ne ve ničesar o prilepljenih podatkih. Podatki so zakodirani/odkodirani %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 strežnik ne ve ničesar o prilepljenih podatkih. Podatki so šifrirani/dešifrirani %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?)": "Ne morem odkodirati prilepka: V URL-ju manjka ključ (A si uporabil 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?)": "Prilepka ni mogoče odkodirati: v URL-ju manjka ključ. Ali je bil uporabljen 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! Prosimo, 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! Prosim, 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 WebAssemblyja, ki se uporablja za stiskanje zlib. Nestisnjene dokumente lahko ustvarite, stisnjenih pa ne morete brati.",
"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.",
"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.": "Do te povezave lahko dostopate samo enkrat, ne uporabljajte gumba za nazaj ali osvežitev v brskalniku.",
"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«.",
"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 skrajšanja URL, ki ne kaže na naš primerek.",
"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.",
"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 dokumenta zaradi manjkajoče podpore za WebAssembly.",
"Error compressing document, due to missing WebAssembly support.": "Napaka pri stiskanju pripleka 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,46 +4,7 @@
global.assert = require('assert');
global.jsc = require('jsverify');
global.jsdom = require('jsdom-global');
// 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.cleanup = global.jsdom();
global.fs = require('fs');
global.WebCrypto = require('@peculiar/webcrypto').Crypto;
@@ -51,23 +12,14 @@ 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 ? window.PR.prettyPrint : function() {};
global.prettyPrintOne = window.PR ? window.PR.prettyPrintOne : function() {};
global.prettyPrint = window.PR.prettyPrint;
global.prettyPrintOne = window.PR.prettyPrintOne;
global.showdown = require('./showdown-2.1.0');
global.DOMPurify = require('./purify-3.3.0');
global.DOMPurify = require('./purify-3.3.2');
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'],

View File

@@ -1,22 +0,0 @@
{
"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,11 +1853,10 @@
}
},
"node_modules/flatted": {
"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"
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
"dev": true
},
"node_modules/foreground-child": {
"version": "3.3.1",
@@ -5736,9 +5735,9 @@
}
},
"flatted": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
"dev": true
},
"foreground-child": {

View File

@@ -16,7 +16,6 @@
"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,11 +11,12 @@ describe('Alert', function () {
icon = icon.join('');
message = message.join('');
const expected = '<div id="status">' + message + '</div>';
document.body.innerHTML =
'<div id="status"></div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showStatus(message, icon);
const result = document.body.innerHTML;
$('body').html(
'<div id="status"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showStatus(message, icon);
const result = $('body').html();
return expected === result;
}
);
@@ -29,13 +30,14 @@ describe('Alert', function () {
'class="statusmessage alert alert-info"><span ' +
'class="glyphicon glyphicon-info-sign" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
document.body.innerHTML =
$('body').html(
'<div id="status" role="alert" class="statusmessage ' +
'alert alert-info hidden"><span class="glyphicon ' +
'glyphicon-info-sign" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showStatus(message);
const result = document.body.innerHTML;
'glyphicon-info-sign" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showStatus(message);
const result = $('body').html();
return expected === result;
}
);
@@ -51,13 +53,14 @@ describe('Alert', function () {
'class="statusmessage alert alert-info"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
document.body.innerHTML =
$('body').html(
'<div id="status" role="alert" class="statusmessage ' +
'alert alert-info hidden"><span class="glyphicon ' +
'glyphicon-info-sign" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showStatus(message, icon);
const result = document.body.innerHTML;
'glyphicon-info-sign" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showStatus(message, icon);
const result = $('body').html();
return expected === result;
}
);
@@ -72,11 +75,12 @@ describe('Alert', function () {
icon = icon.join('');
message = message.join('');
const expected = '<div id="errormessage">' + message + '</div>';
document.body.innerHTML =
'<div id="errormessage"></div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showWarning(message, icon);
const result = document.body.innerHTML;
$('body').html(
'<div id="errormessage"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showWarning(message, icon);
const result = $('body').html();
return expected === result;
}
);
@@ -91,13 +95,14 @@ describe('Alert', function () {
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-warning-sign" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
document.body.innerHTML =
$('body').html(
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showWarning(message);
const result = document.body.innerHTML;
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showWarning(message);
const result = $('body').html();
return expected === result;
}
);
@@ -113,13 +118,14 @@ describe('Alert', function () {
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
document.body.innerHTML =
$('body').html(
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showWarning(message, icon);
const result = document.body.innerHTML;
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showWarning(message, icon);
const result = $('body').html();
return expected === result;
}
);
@@ -134,11 +140,12 @@ describe('Alert', function () {
icon = icon.join('');
message = message.join('');
const expected = '<div id="errormessage">' + message + '</div>';
document.body.innerHTML =
'<div id="errormessage"></div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showError(message, icon);
const result = document.body.innerHTML;
$('body').html(
'<div id="errormessage"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showError(message, icon);
const result = $('body').html();
return expected === result;
}
);
@@ -153,13 +160,14 @@ describe('Alert', function () {
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-alert" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
document.body.innerHTML =
$('body').html(
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showError(message);
const result = document.body.innerHTML;
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showError(message);
const result = $('body').html();
return expected === result;
}
);
@@ -175,13 +183,14 @@ describe('Alert', function () {
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
document.body.innerHTML =
$('body').html(
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showError(message, icon);
const result = document.body.innerHTML;
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showError(message, icon);
const result = $('body').html();
return expected === result;
}
);
@@ -197,11 +206,12 @@ describe('Alert', function () {
message = message.join('');
string = string.join('');
const expected = '<div id="remainingtime" class="">' + string + message + number + '</div>';
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;
$('body').html(
'<div id="remainingtime" class="hidden"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]);
const result = $('body').html();
return expected === result;
}
);
@@ -218,13 +228,14 @@ describe('Alert', function () {
'class="alert alert-info"><span ' +
'class="glyphicon glyphicon-fire" aria-hidden="true">' +
'</span> <span>' + string + message + number + '</span></div>';
document.body.innerHTML =
$('body').html(
'<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 = document.body.innerHTML;
'glyphicon-fire" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]);
const result = $('body').html();
return expected === result;
}
);
@@ -243,11 +254,12 @@ describe('Alert', function () {
message = defaultMessage;
}
const expected = '<div id="loadingindicator" class="">' + message + '</div>';
document.body.innerHTML =
'<div id="loadingindicator" class="hidden">' + defaultMessage + '</div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showLoading(message, icon);
const result = document.body.innerHTML;
$('body').html(
'<div id="loadingindicator" class="hidden">' + defaultMessage + '</div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showLoading(message, icon);
const result = $('body').html();
return expected === result;
}
);
@@ -267,14 +279,15 @@ describe('Alert', function () {
'id="loadingindicator" class="navbar-text"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> <span>' + message + '</span></li></ul>';
document.body.innerHTML =
$('body').html(
'<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 = document.body.innerHTML;
defaultMessage + '</li></ul>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showLoading(message, icon);
const result = $('body').html();
return expected === result;
}
);
@@ -284,16 +297,17 @@ describe('Alert', function () {
it(
'hides the loading message',
function() {
document.body.innerHTML =
$('body').html(
'<ul class="nav navbar-nav"><li id="loadingindicator" ' +
'class="navbar-text"><span class="glyphicon ' +
'glyphicon-time" aria-hidden="true"></span> ' +
'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'));
'Loading…</li></ul>'
);
$('body').addClass('loading');
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.hideLoading();
assert.ok(!$('body').hasClass('loading'));
assert.ok($('#loadingindicator').hasClass('hidden'));
}
);
});
@@ -302,17 +316,18 @@ describe('Alert', function () {
it(
'hides all messages',
function() {
document.body.innerHTML =
$('body').html(
'<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(document.getElementById('status').classList.contains('hidden'));
assert.ok(document.getElementById('errormessage').classList.contains('hidden'));
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.hideMessages();
assert.ok($('#status').hasClass('hidden'));
assert.ok($('#errormessage').hasClass('hidden'));
}
);
});
@@ -327,15 +342,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;
}
document.body.innerHTML =
$('body').html(
'<ul class="nav navbar-nav"><li id="loadingindicator" ' +
'class="navbar-text hidden"><span class="glyphicon ' +
'glyphicon-time" aria-hidden="true"></span> ' +
@@ -348,14 +363,15 @@ 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 = globalThis.cleanup(),
let clean = jsdom(),
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, '');
document.body.innerHTML = (
$('body').html(
'<div id="attachmentPreview" class="col-md-12 text-center hidden"></div>' +
'<div id="attachment" class="hidden"></div>' +
'<div id="templates">' +
@@ -51,62 +51,60 @@ describe('AttachmentViewer', function () {
}}
);
}
PrivateBin.AttachmentViewer.init();
PrivateBin.Model.init();
$.PrivateBin.AttachmentViewer.init();
$.PrivateBin.Model.init();
results.push(
!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')
!$.PrivateBin.AttachmentViewer.hasAttachment() &&
$('#attachment').hasClass('hidden') &&
$('#attachment').children().length === 0 &&
$('#attachmenttemplate').hasClass('hidden') &&
$('#attachmentPreview').hasClass('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() &&
document.getElementById('attachment').classList.contains('hidden') &&
document.getElementById('attachment').children.length > 0 &&
document.getElementById('attachmentPreview').classList.contains('hidden') &&
$.PrivateBin.AttachmentViewer.hasAttachment() &&
$('#attachment').hasClass('hidden') &&
$('#attachment').children().length > 0 &&
$('#attachmentPreview').hasClass('hidden') &&
attachment[0][0] === data &&
attachment[0][1] === filename
);
PrivateBin.AttachmentViewer.showAttachment();
$.PrivateBin.AttachmentViewer.showAttachment();
results.push(
!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'))
!$('#attachment').hasClass('hidden') &&
$('#attachment').children().length > 0 &&
(previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden'))
);
PrivateBin.AttachmentViewer.hideAttachment();
$.PrivateBin.AttachmentViewer.hideAttachment();
results.push(
document.getElementById('attachment').classList.contains('hidden') &&
(previewSupported ? !document.getElementById('attachmentPreview').classList.contains('hidden') : document.getElementById('attachmentPreview').classList.contains('hidden'))
$('#attachment').hasClass('hidden') &&
(previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden'))
);
if (previewSupported) {
PrivateBin.AttachmentViewer.hideAttachmentPreview();
results.push(document.getElementById('attachmentPreview').classList.contains('hidden'));
$.PrivateBin.AttachmentViewer.hideAttachmentPreview();
results.push($('#attachmentPreview').hasClass('hidden'));
}
PrivateBin.AttachmentViewer.showAttachment();
$.PrivateBin.AttachmentViewer.showAttachment();
results.push(
!document.getElementById('attachment').classList.contains('hidden') &&
(previewSupported ? !document.getElementById('attachmentPreview').classList.contains('hidden') : document.getElementById('attachmentPreview').classList.contains('hidden'))
!$('#attachment').hasClass('hidden') &&
(previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden'))
);
let element = document.createElement('div');
PrivateBin.AttachmentViewer.moveAttachmentTo(element, attachment[0], prefix + '%s' + postfix);
let element = $('<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) {
const tempTA = document.createElement('textarea');
tempTA.textContent = (prefix + filename + postfix);
result = tempTA.textContent;
result = $('<textarea>').text((prefix + filename + postfix)).text();
} 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']
}
@@ -114,18 +112,18 @@ describe('AttachmentViewer', function () {
}
if (filename.length) {
results.push(
element.querySelector('a').href === data &&
element.querySelector('a').getAttribute('download') === filename &&
element.querySelector('a').textContent === result
element.find('a')[0].href === data &&
element.find('a')[0].getAttribute('download') === filename &&
element.find('a')[0].text === result
);
} else {
results.push(element.querySelector('a').href === data);
results.push(element.find('a')[0].href === data);
}
PrivateBin.AttachmentViewer.removeAttachment();
$.PrivateBin.AttachmentViewer.removeAttachment();
results.push(
document.getElementById('attachment').classList.contains('hidden') &&
document.getElementById('attachment').children.length === 0 &&
document.getElementById('attachmentPreview').classList.contains('hidden')
$('#attachment').hasClass('hidden') &&
$('#attachment').children().length === 0 &&
$('#attachmentPreview').hasClass('hidden')
);
clean();
return results.every(element => element);
@@ -135,8 +133,8 @@ describe('AttachmentViewer', function () {
it(
'sanitizes file names in attachments',
function() {
const clean = globalThis.cleanup();
document.body.innerHTML = (
const clean = jsdom();
$('body').html(
'<div id="attachmentPreview" class="col-md-12 text-center hidden"></div>' +
'<div id="attachment" class="hidden"></div>' +
'<div id="templates">' +
@@ -156,8 +154,8 @@ describe('AttachmentViewer', function () {
}}
);
}
PrivateBin.AttachmentViewer.init();
PrivateBin.Model.init();
$.PrivateBin.AttachmentViewer.init();
$.PrivateBin.Model.init();
global.atob = common.atob;
const maliciousFileNames = [
@@ -165,8 +163,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(!document.body.innerHTML.includes(filename));
$.PrivateBin.AttachmentViewer.setAttachment('data:;base64,', filename);
assert.ok(!$('body').html().includes(filename));
}
clean();
}

View File

@@ -12,7 +12,7 @@ describe('Check', function () {
jsc.elements(['Bot', 'bot']),
'string',
function (prefix, botBit, suffix) {
const clean = globalThis.cleanup(
const clean = jsdom(
'<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 = globalThis.cleanup(
clean = jsdom(
'<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 = globalThis.cleanup(
const clean = jsdom(
'<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 = globalThis.cleanup();
var clean = jsdom();
common.enableClipboard();
document.body.innerHTML = (
$('body').html(
'<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();
document.getElementById('prettyMessageCopyBtn').click();
$('#prettyMessageCopyBtn').trigger('click');
const savedToClipboardText = await navigator.clipboard.readText();
@@ -46,10 +46,10 @@ describe('CopyToClipboard', function() {
common.jscFormats(),
'nestring',
async function (format, text) {
var clean = globalThis.cleanup();
var clean = jsdom();
common.enableClipboard();
document.body.innerHTML = (
$('body').html(
'<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();
document.body.dispatchEvent(new Event('copy'));
$('body').trigger('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 = globalThis.cleanup();
var clean = jsdom();
common.enableClipboard();
document.body.innerHTML = '<button id="copyLink"></button>';
$('body').html('<button id="copyLink"></button>');
PrivateBin.CopyToClipboard.init();
PrivateBin.CopyToClipboard.setUrl(text);
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.setUrl(text);
document.getElementById('copyLink').click();
$('#copyLink').trigger('click');
const copiedText = await navigator.clipboard.readText();
@@ -103,14 +103,14 @@ describe('CopyToClipboard', function() {
jsc.property('Show hint',
'nestring',
function (text) {
var clean = globalThis.cleanup();
var clean = jsdom();
document.body.innerHTML = '<small id="copyShortcutHintText"></small>';
$('body').html('<small id="copyShortcutHintText"></small>');
PrivateBin.CopyToClipboard.init();
PrivateBin.CopyToClipboard.showKeyboardShortcutHint();
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.showKeyboardShortcutHint();
const keyboardShortcutHint = document.getElementById('copyShortcutHintText').textContent;
const keyboardShortcutHint = $('#copyShortcutHintText').text();
clean();
@@ -121,14 +121,14 @@ describe('CopyToClipboard', function() {
jsc.property('Hide hint',
'nestring',
function (text) {
var clean = globalThis.cleanup();
var clean = jsdom();
document.body.innerHTML = '<small id="copyShortcutHintText">' + text + '</small>';
$('body').html('<small id="copyShortcutHintText">' + text + '</small>');
PrivateBin.CopyToClipboard.init();
PrivateBin.CopyToClipboard.hideKeyboardShortcutHint();
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.hideKeyboardShortcutHint();
const keyboardShortcutHint = document.getElementById('copyShortcutHintText').textContent;
const keyboardShortcutHint = $('#copyShortcutHintText').text();
clean();
@@ -136,4 +136,4 @@ describe('CopyToClipboard', function() {
}
);
});
});
});

View File

@@ -1,6 +1,5 @@
'use strict';
const common = require('../common');
const fs = require('fs');
describe('CryptTool', function () {
describe('cipher & decipher', function () {
@@ -16,9 +15,9 @@ describe('CryptTool', function () {
'string',
'string',
async function (key, password, message) {
const clean = globalThis.cleanup();
const clean = jsdom();
// ensure zlib is getting loaded
PrivateBin.Controller.initZ();
$.PrivateBin.Controller.initZ();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false
@@ -26,10 +25,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();
@@ -43,19 +42,19 @@ describe('CryptTool', function () {
it('does not truncate messages', async function () {
const message = fs.readFileSync('test/compression-sample.txt', 'ascii').trim(),
clean = globalThis.cleanup();
clean = jsdom();
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();
@@ -92,17 +91,17 @@ isWhile : interp (while expr sBody) (MemElem mem) =
======================== ( 1 / 1 )
conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
`;
const clean = globalThis.cleanup();
const clean = jsdom();
// 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();
@@ -124,12 +123,12 @@ conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
jsc.assert(jsc.forall(
'integer',
function(counter) {
const clean = globalThis.cleanup();
const clean = jsdom();
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 = globalThis.cleanup(),
var clean = jsdom(),
results = [];
document.body.innerHTML = (
$('body').html(
'<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(
!document.getElementById('discussion').classList.contains('hidden')
!$('#discussion').hasClass('hidden')
);
PrivateBin.DiscussionViewer.prepareNewDiscussion();
$.PrivateBin.DiscussionViewer.prepareNewDiscussion();
results.push(
document.getElementById('discussion').classList.contains('hidden')
$('#discussion').hasClass('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(
document.getElementById('discussion').classList.contains('hidden')
$('#discussion').hasClass('hidden')
);
PrivateBin.DiscussionViewer.finishDiscussion();
$.PrivateBin.DiscussionViewer.finishDiscussion();
results.push(
!document.getElementById('discussion').classList.contains('hidden') &&
comments.length + 1 >= document.getElementById('commentcontainer').children.length
!$('#discussion').hasClass('hidden') &&
comments.length + 1 >= $('#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(
document.getElementById('comment_' + comments[commentKey].id).classList.contains('highlight')
$('#comment_' + comments[commentKey].id).hasClass('highlight')
);
}
document.getElementById('commentcontainer').querySelector('button').click();
$('#commentcontainer').find('button')[0].click();
results.push(
!document.getElementById('reply').classList.contains('hidden')
!$('#reply').hasClass('hidden')
);
document.querySelector('#reply #nickname').value = nickname;
document.querySelector('#reply #replymessage').value = message;
PrivateBin.DiscussionViewer.getReplyCommentId();
$('#reply #nickname').val(nickname);
$('#reply #replymessage').val(message);
$.PrivateBin.DiscussionViewer.getReplyCommentId();
results.push(
PrivateBin.DiscussionViewer.getReplyNickname() === document.querySelector('#reply #nickname').value &&
PrivateBin.DiscussionViewer.getReplyMessage() === document.querySelector('#reply #replymessage').value
$.PrivateBin.DiscussionViewer.getReplyNickname() === $('#reply #nickname').val() &&
$.PrivateBin.DiscussionViewer.getReplyMessage() === $('#reply #replymessage').val()
);
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.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')
!notificationResult.hasClass('alert-danger') &&
notificationResult.hasClass('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 = globalThis.cleanup(),
var clean = jsdom(),
results = [];
document.body.innerHTML = (
$('body').html(
'<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(
document.getElementById('editorTabs').classList.contains('hidden') &&
document.getElementById('message').classList.contains('hidden')
$('#editorTabs').hasClass('hidden') &&
$('#message').hasClass('hidden')
);
PrivateBin.Editor.show();
$.PrivateBin.Editor.show();
results.push(
!document.getElementById('editorTabs').classList.contains('hidden') &&
!document.getElementById('message').classList.contains('hidden')
!$('#editorTabs').hasClass('hidden') &&
!$('#message').hasClass('hidden')
);
PrivateBin.Editor.hide();
$.PrivateBin.Editor.hide();
results.push(
document.getElementById('editorTabs').classList.contains('hidden') &&
document.getElementById('message').classList.contains('hidden')
$('#editorTabs').hasClass('hidden') &&
$('#message').hasClass('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() === document.getElementById('message').value
$.PrivateBin.Editor.getText() === $('#message').val()
);
PrivateBin.Editor.setText();
$.PrivateBin.Editor.setText();
results.push(
!PrivateBin.Editor.isPreview() &&
!document.getElementById('message').classList.contains('hidden')
!$.PrivateBin.Editor.isPreview() &&
!$('#message').hasClass('hidden')
);
document.getElementById('messagepreview').click();
$('#messagepreview').trigger('click');
results.push(
PrivateBin.Editor.isPreview() &&
document.getElementById('message').classList.contains('hidden')
$.PrivateBin.Editor.isPreview() &&
$('#message').hasClass('hidden')
);
document.getElementById('messageedit').click();
$('#messageedit').trigger('click');
results.push(
!PrivateBin.Editor.isPreview() &&
!document.getElementById('message').classList.contains('hidden')
!$.PrivateBin.Editor.isPreview() &&
!$('#message').hasClass('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 = globalThis.cleanup(html);
clean = jsdom(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,15 +73,9 @@ 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 = globalThis.cleanup();
cleanup = jsdom();
});
jsc.property(
@@ -90,12 +84,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 = 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;
let clean = jsdom();
$('body').html('<div id="foo"></div>');
let e = $('#foo');
e.text(content);
$.PrivateBin.Helper.urls2links(e);
let result = e.text();
clean();
return content === result;
}
@@ -113,9 +107,9 @@ describe('Helper', function () {
postfix = ' ' + postfix.replace(/\r/g, '\n').replace(/\u0000/g, '');
url.fragment = fragment.join('');
let urlString = common.urlToString(url),
clean = globalThis.cleanup();
document.body.innerHTML = '<div id="foo"></div>';
let e = document.getElementById('foo');
clean = jsdom();
$('body').html('<div id="foo"></div>');
let e = $('#foo');
// special cases: When the query string and fragment imply the beginning of an HTML entity, eg. &#0 or &#x
if (
@@ -126,14 +120,12 @@ describe('Helper', function () {
urlString = common.urlToString(url);
postfix = '';
}
e.textContent = prefix + urlString + postfix;
PrivateBin.Helper.urls2links(e);
let result = e.innerHTML;
e.text(prefix + urlString + postfix);
$.PrivateBin.Helper.urls2links(e);
let result = e.html();
clean();
urlString = getTextAsRenderedHtml(urlString);
const expected = getTextAsRenderedHtml(prefix) + '<a href="' + urlString + '" target="_blank" rel="nofollow noopener noreferrer">' + urlString + '</a>' + getTextAsRenderedHtml(postfix);
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();
return expected === result;
}
);
@@ -148,15 +140,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 = 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 = jsdom();
$('body').html('<div id="foo"></div>');
let e = $('#foo');
e.text(prefix + url + postfix);
$.PrivateBin.Helper.urls2links(e);
let result = e.html();
clean();
url = getTextAsRenderedHtml(url);
return getTextAsRenderedHtml(prefix) + '<a href="' + url + '" target="_blank" rel="nofollow noopener noreferrer">' + url + '</a>' + getTextAsRenderedHtml(postfix) === result;
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;
}
);
});
@@ -173,7 +165,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(
@@ -186,7 +178,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(
@@ -199,7 +191,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(
@@ -215,7 +207,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(
@@ -231,7 +223,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);
}
);
});
@@ -249,7 +241,7 @@ describe('Helper', function () {
jsc.nearray(jsc.nearray(common.jscAlnumString())),
function (labels, values) {
let selectedKey = '', selectedValue = '';
const clean = globalThis.cleanup();
const clean = jsdom();
labels.forEach(function(item, i) {
const key = item.join(''),
value = (values[i] || values[0]).join('');
@@ -260,8 +252,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;
}
@@ -279,10 +271,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 = globalThis.cleanup('', {url: fullUrl}),
result = PrivateBin.Helper.baseUri();
clean = jsdom('', {url: fullUrl}),
result = $.PrivateBin.Helper.baseUri();
clean();
return expected === result;
}
@@ -291,14 +283,14 @@ describe('Helper', function () {
describe('htmlEntities', function () {
before(function () {
cleanup = globalThis.cleanup();
cleanup = jsdom();
});
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)));
}
);
@@ -306,43 +298,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';
});
});
@@ -350,12 +342,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,25 +99,22 @@ 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 tempDiv = document.createElement('textarea');
tempDiv.textContent = (prefix + params[0] + postfix);
const translation = tempDiv.textContent;
const translation = $('<textarea>').text((prefix + params[0] + postfix)).text();
let args = Array.prototype.slice.call(params);
args.unshift(prefix + '%s' + postfix);
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();
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();
clean();
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 = jsdom();
$('body').html('<div id="i18n"></div>');
args[0] = $('#i18n');
$.PrivateBin.I18n._.apply(this, args);
const alias = $('#i18n').text();
$.PrivateBin.I18n.reset();
clean();
return translation === result && translation === alias;
}
@@ -140,20 +137,19 @@ describe('I18n', function () {
);
let args = Array.prototype.slice.call(params);
args.unshift(prefix + '<a href="%s"></a>' + postfix);
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();
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();
clean();
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 = jsdom();
$('body').html('<div id="i18n"></div>');
args[0] = $('#i18n');
$.PrivateBin.I18n._.apply(this, args);
const alias = $('#i18n').html();
$.PrivateBin.I18n.reset();
clean();
return translation === result && translation === alias;
}
@@ -162,7 +158,7 @@ describe('I18n', function () {
describe('getPluralForm', function () {
before(function () {
PrivateBin.I18n.reset();
$.PrivateBin.I18n.reset();
});
jsc.property(
@@ -170,8 +166,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;
}
@@ -183,7 +179,7 @@ describe('I18n', function () {
describe('loadTranslations', function () {
this.timeout(30000);
before(function () {
PrivateBin.I18n.reset();
$.PrivateBin.I18n.reset();
});
jsc.property(
@@ -191,18 +187,18 @@ describe('I18n', function () {
common.jscSupportedLanguages(),
function(language) {
// cleanup
var clean = globalThis.cleanup('', {cookie: ['lang=en']});
PrivateBin.I18n.reset('en');
PrivateBin.I18n.loadTranslations();
var clean = jsdom('', {cookie: ['lang=en']});
$.PrivateBin.I18n.reset('en');
$.PrivateBin.I18n.loadTranslations();
clean();
// mock
clean = globalThis.cleanup('', {cookie: ['lang=' + language]});
clean = jsdom('', {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;
}
@@ -211,7 +207,7 @@ describe('I18n', function () {
jsc.property(
'should default to en',
function() {
var clean = globalThis.cleanup('', {url: 'https://privatebin.net/'});
var clean = jsdom('', {url: 'https://privatebin.net/'});
// when navigator.userLanguage is undefined and no default language
// is specified, it would throw an error
@@ -222,10 +218,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 = globalThis.cleanup();
$.PrivateBin.Model.reset();
cleanup = jsdom();
});
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>';
document.body.innerHTML = contents;
var result = PrivateBin.Helper.htmlEntities(
PrivateBin.Model.getExpirationDefault()
$('body').html(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>';
document.body.innerHTML = contents;
var result = PrivateBin.Helper.htmlEntities(
PrivateBin.Model.getFormatDefault()
$('body').html(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 = globalThis.cleanup('', {url: common.urlToString(url)});
const result = PrivateBin.Model.getPasteId();
PrivateBin.Model.reset();
clean = jsdom('', {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 = globalThis.cleanup('', {url: common.urlToString(url)});
const clean = jsdom('', {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 = globalThis.cleanup('', {url: common.urlToString(url)});
const clean = jsdom('', {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 = globalThis.cleanup('', {url: common.urlToString(url)}),
result = PrivateBin.Model.getPasteKey();
PrivateBin.Model.reset();
url.fragment = $.PrivateBin.CryptTool.base58encode(fragment) + '&' + trail.join('');
const clean = jsdom('', {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 = globalThis.cleanup('', {url: common.urlToString(url)}),
result = PrivateBin.Model.getPasteKey();
PrivateBin.Model.reset();
url.fragment = $.PrivateBin.CryptTool.base58encode(fragment);
const clean = jsdom('', {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 = globalThis.cleanup('', {url: common.urlToString(url)}),
result = PrivateBin.Model.getPasteKey();
PrivateBin.Model.reset();
url.fragment = $.PrivateBin.CryptTool.base58encode(fragment) + '&' + trail.join('');
const clean = jsdom('', {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 = globalThis.cleanup('', {url: common.urlToString(url)}),
let clean = jsdom('', {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,18 +226,15 @@ describe('Model', function () {
element = 'p';
}
document.body.innerHTML = (
$('body').html(
'<div id="templates"><' + element + ' id="' + id +
'template">' + value + '</' + element + '></div>'
);
PrivateBin.Model.init();
$.PrivateBin.Model.init();
var template = '<' + element + ' id="' + id + '">' + value +
'</' + element + '>',
templateEl = PrivateBin.Model.getTemplate(id),
wrapper = document.createElement('p');
wrapper.appendChild(templateEl.cloneNode(true));
var result = wrapper.innerHTML;
PrivateBin.Model.reset();
result = $.PrivateBin.Model.getTemplate(id).wrap('<p/>').parent().html();
$.PrivateBin.Model.reset();
return template === result;
}
);

View File

@@ -22,39 +22,21 @@ 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 (jsc)',
'creates a notification after a successful document upload',
common.jscUrl(),
common.jscUrl(false),
function (url1, url2) {
// 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;
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;
}
);
});
@@ -77,14 +59,14 @@ describe('PasteStatus', function () {
url.address = domain.split('').concat(url.address);
const urlString = common.urlToString(url),
expected = urlString.substring((schema + '://' + domain).length),
clean = globalThis.cleanup();
clean = jsdom();
document.body.innerHTML = '<div><div id="pastelink"></div></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.createPasteNotification('', '');
PrivateBin.PasteStatus.extractUrl(urlString);
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(urlString);
const result = document.getElementById('pasteurl').href;
const result = $('#pasteurl')[0].href;
clean();
return result.endsWith(expected) && (
@@ -116,14 +98,14 @@ describe('PasteStatus', function () {
shorturl: shortUrlString,
statusCode: 200
},
clean = globalThis.cleanup();
clean = jsdom();
document.body.innerHTML = '<div><div id="pastelink"></div></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.createPasteNotification('', '');
PrivateBin.PasteStatus.extractUrl(JSON.stringify(yourlsResponse, undefined, 4));
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(JSON.stringify(yourlsResponse, undefined, 4));
const result = document.getElementById('pasteurl').href;
const result = $('#pasteurl')[0].href;
clean();
return result === shortUrlString;
@@ -143,14 +125,14 @@ describe('PasteStatus', function () {
' <message>success</message>\n' +
' <statusCode>200</statusCode>\n' +
'</result>',
clean = globalThis.cleanup();
clean = jsdom();
document.body.innerHTML = '<div><div id="pastelink"></div></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.createPasteNotification('', '');
PrivateBin.PasteStatus.extractUrl(yourlsResponse);
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(yourlsResponse);
const result = document.getElementById('pasteurl').href;
const result = $('#pasteurl')[0].href;
clean();
return result === shortUrlString;
@@ -175,14 +157,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 = globalThis.cleanup();
clean = jsdom();
document.body.innerHTML = '<div><div id="pastelink"></div></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.createPasteNotification('', '');
PrivateBin.PasteStatus.extractUrl(yourlsResponse);
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(yourlsResponse);
const result = document.getElementById('pasteurl').href;
const result = $('#pasteurl')[0].href;
clean();
return result === shortUrlString;
@@ -199,11 +181,11 @@ describe('PasteStatus', function () {
'nat',
common.jscUrl(),
function (burnafterreading, remainingTime, url) {
let clean = globalThis.cleanup('', {url: common.urlToString(url)}),
let clean = jsdom('', {url: common.urlToString(url)}),
result;
document.body.innerHTML = '<div id="remainingtime" class="hidden"></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.showRemainingTime(PrivateBin.Helper.PasteFactory({
$('body').html('<div id="remainingtime" class="hidden"></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.showRemainingTime($.PrivateBin.Helper.PasteFactory({
'adata': [null, null, null, burnafterreading],
'v': 2,
'meta': {
@@ -211,14 +193,14 @@ describe('PasteStatus', function () {
}
}));
if (burnafterreading) {
result = document.getElementById('remainingtime').classList.contains('foryoureyesonly') &&
!document.getElementById('remainingtime').classList.contains('hidden');
result = $('#remainingtime').hasClass('foryoureyesonly') &&
!$('#remainingtime').hasClass('hidden');
} else if (remainingTime) {
result =!document.getElementById('remainingtime').classList.contains('foryoureyesonly') &&
!document.getElementById('remainingtime').classList.contains('hidden');
result =!$('#remainingtime').hasClass('foryoureyesonly') &&
!$('#remainingtime').hasClass('hidden');
} else {
result = document.getElementById('remainingtime').classList.contains('hidden') &&
!document.getElementById('remainingtime').classList.contains('foryoureyesonly');
result = $('#remainingtime').hasClass('hidden') &&
!$('#remainingtime').hasClass('foryoureyesonly');
}
clean();
return result;
@@ -230,13 +212,13 @@ describe('PasteStatus', function () {
it(
'hides all messages',
function() {
document.body.innerHTML = (
$('body').html(
'<div id="remainingtime"></div><div id="pastesuccess"></div>'
);
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.hideMessages();
assert.ok(document.getElementById('remainingtime').classList.contains('hidden'));
assert.ok(document.getElementById('pastesuccess').classList.contains('hidden'));
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.hideMessages();
assert.ok($('#remainingtime').hasClass('hidden'));
assert.ok($('#pastesuccess').hasClass('hidden'));
}
);
});

View File

@@ -5,75 +5,60 @@ 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) {
cleanup();
var results = [];
document.body.innerHTML = (
var clean = jsdom(),
results = [];
$('body').html(
'<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(
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() === ''
$('#placeholder').hasClass('hidden') &&
$('#prettymessage').hasClass('hidden') &&
$('#plaintext').hasClass('hidden') &&
$.PrivateBin.PasteViewer.getFormat() === format &&
$.PrivateBin.PasteViewer.getText() === ''
);
PrivateBin.PasteViewer.run();
$.PrivateBin.PasteViewer.run();
results.push(
!document.getElementById('placeholder').classList.contains('hidden') &&
document.getElementById('prettymessage').classList.contains('hidden') &&
document.getElementById('plaintext').classList.contains('hidden')
!$('#placeholder').hasClass('hidden') &&
$('#prettymessage').hasClass('hidden') &&
$('#plaintext').hasClass('hidden')
);
PrivateBin.PasteViewer.hide();
$.PrivateBin.PasteViewer.hide();
results.push(
document.getElementById('placeholder').classList.contains('hidden') &&
document.getElementById('prettymessage').classList.contains('hidden') &&
document.getElementById('plaintext').classList.contains('hidden')
$('#placeholder').hasClass('hidden') &&
$('#prettymessage').hasClass('hidden') &&
$('#plaintext').hasClass('hidden')
);
PrivateBin.PasteViewer.setText(text);
PrivateBin.PasteViewer.run();
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
results.push(
document.getElementById('placeholder').classList.contains('hidden') &&
!PrivateBin.PasteViewer.isPrettyPrinted() &&
PrivateBin.PasteViewer.getText() === text
$('#placeholder').hasClass('hidden') &&
!$.PrivateBin.PasteViewer.isPrettyPrinted() &&
$.PrivateBin.PasteViewer.getText() === text
);
if (format === 'markdown') {
results.push(
document.getElementById('prettymessage').classList.contains('hidden') &&
!document.getElementById('plaintext').classList.contains('hidden')
$('#prettymessage').hasClass('hidden') &&
!$('#plaintext').hasClass('hidden')
);
} else {
results.push(
!document.getElementById('prettymessage').classList.contains('hidden') &&
document.getElementById('plaintext').classList.contains('hidden')
!$('#prettymessage').hasClass('hidden') &&
$('#plaintext').hasClass('hidden')
);
}
cleanup();
clean();
return results.every(element => element);
}
);
@@ -112,19 +97,20 @@ describe('PasteViewer', function () {
]),
'string',
function (format, prefix, xss, suffix) {
var text = prefix + xss + suffix;
document.body.innerHTML = (
var clean = jsdom(),
text = prefix + xss + suffix;
$('body').html(
'<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 = document.body.innerHTML.indexOf(xss) === -1;
cleanup();
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
var result = $('body').html().indexOf(xss) === -1;
clean();
return result;
}
);

View File

@@ -10,8 +10,8 @@ describe('Prompt', function () {
'string',
function (password) {
password = password.replace(/\r+|\n+/g, '');
const clean = globalThis.cleanup('', {url: 'ftp://example.com/?0000000000000000'});
document.body.innerHTML = (
/* const clean = */ jsdom('', {url: 'ftp://example.com/?0000000000000000'});
$('body').html(
'<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,10 +20,20 @@ describe('Prompt', function () {
'password"></div><button type="submit">Decrypt</button>' +
'</form></div></div></div></div>'
);
const passwordInput = document.getElementById('passworddecrypt');
passwordInput.value = password;
const result = passwordInput.value;
clean();
$.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();
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 = globalThis.cleanup();
let clean = jsdom();
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,20 +1,6 @@
'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 () {
@@ -25,39 +11,45 @@ describe('TopNav', function () {
'displays & hides navigation elements for viewing an existing document',
function () {
let results = [];
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(
query('#newbutton').classList.contains('hidden') &&
query('#clonebutton').classList.contains('hidden') &&
query('#rawtextbutton').classList.contains('hidden') &&
query('#qrcodelink').classList.contains('hidden')
$('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.showViewButtons();
$.PrivateBin.TopNav.init();
results.push(
!query('#newbutton').classList.contains('hidden') &&
!query('#clonebutton').classList.contains('hidden') &&
!query('#rawtextbutton').classList.contains('hidden') &&
!query('#qrcodelink').classList.contains('hidden')
$('#newbutton').hasClass('hidden') &&
$('#clonebutton').hasClass('hidden') &&
$('#rawtextbutton').hasClass('hidden') &&
$('#qrcodelink').hasClass('hidden')
);
PrivateBin.TopNav.hideViewButtons();
$.PrivateBin.TopNav.showViewButtons();
results.push(
query('#newbutton').classList.contains('hidden') &&
query('#clonebutton').classList.contains('hidden') &&
query('#rawtextbutton').classList.contains('hidden') &&
query('#qrcodelink').classList.contains('hidden')
!$('#newbutton').hasClass('hidden') &&
!$('#clonebutton').hasClass('hidden') &&
!$('#rawtextbutton').hasClass('hidden') &&
!$('#qrcodelink').hasClass('hidden')
);
$.PrivateBin.TopNav.hideViewButtons();
results.push(
$('#newbutton').hasClass('hidden') &&
$('#clonebutton').hasClass('hidden') &&
$('#rawtextbutton').hasClass('hidden') &&
$('#qrcodelink').hasClass('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -78,7 +70,7 @@ describe('TopNav', function () {
'displays & hides navigation elements for creating a document',
function () { // eslint-disable-line complexity
let results = [];
document.documentElement.innerHTML =
$('body').html(
'<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>' +
@@ -89,39 +81,40 @@ 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();
results.push(
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')
'class="hidden">Create</button></li></ul></div></nav>'
);
PrivateBin.TopNav.showCreateButtons();
$.PrivateBin.TopNav.init();
results.push(
!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')
$('#sendbutton').hasClass('hidden') &&
$('#expiration').hasClass('hidden') &&
$('#formatter').hasClass('hidden') &&
$('#burnafterreadingoption').hasClass('hidden') &&
$('#opendiscussionoption').hasClass('hidden') &&
$('#newbutton').hasClass('hidden') &&
$('#password').hasClass('hidden') &&
$('#attach').hasClass('hidden')
);
PrivateBin.TopNav.hideCreateButtons();
$.PrivateBin.TopNav.showCreateButtons();
results.push(
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')
!$('#sendbutton').hasClass('hidden') &&
!$('#expiration').hasClass('hidden') &&
!$('#formatter').hasClass('hidden') &&
!$('#burnafterreadingoption').hasClass('hidden') &&
!$('#opendiscussionoption').hasClass('hidden') &&
!$('#newbutton').hasClass('hidden') &&
!$('#password').hasClass('hidden') &&
!$('#attach').hasClass('hidden')
);
$.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')
);
cleanup();
const result = results.every(element => element);
@@ -142,16 +135,17 @@ describe('TopNav', function () {
'displays the button for creating a document',
function () {
let results = [];
document.documentElement.innerHTML =
$('body').html(
'<nav><div id="navbar"><ul><li><button id="newbutton" type=' +
'"button" class="hidden">New</button></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
query('#newbutton').classList.contains('hidden')
'"button" class="hidden">New</button></li></ul></div></nav>'
);
PrivateBin.TopNav.showNewPasteButton();
$.PrivateBin.TopNav.init();
results.push(
!query('#newbutton').classList.contains('hidden')
$('#newbutton').hasClass('hidden')
);
$.PrivateBin.TopNav.showNewPasteButton();
results.push(
!$('#newbutton').hasClass('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -172,18 +166,19 @@ describe('TopNav', function () {
'hides the button for cloning a document',
function () {
let results = [];
document.documentElement.innerHTML =
$('body').html(
'<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();
results.push(
!query('#clonebutton').classList.contains('hidden')
'"true"></span> Clone</button></li></ul></div></nav>'
);
PrivateBin.TopNav.hideCloneButton();
$.PrivateBin.TopNav.init();
results.push(
query('#clonebutton').classList.contains('hidden')
!$('#clonebutton').hasClass('hidden')
);
$.PrivateBin.TopNav.hideCloneButton();
results.push(
$('#clonebutton').hasClass('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -204,19 +199,20 @@ describe('TopNav', function () {
'hides the raw text button',
function () {
let results = [];
document.documentElement.innerHTML =
$('body').html(
'<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();
results.push(
!query('#rawtextbutton').classList.contains('hidden')
'Raw text</button></li></ul></div></nav>'
);
PrivateBin.TopNav.hideRawButton();
$.PrivateBin.TopNav.init();
results.push(
query('#rawtextbutton').classList.contains('hidden')
!$('#rawtextbutton').hasClass('hidden')
);
$.PrivateBin.TopNav.hideRawButton();
results.push(
$('#rawtextbutton').hasClass('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -237,7 +233,7 @@ describe('TopNav', function () {
'hides the file attachment selection button',
function () {
let results = [];
document.documentElement.innerHTML =
$('body').html(
'<nav><div id="navbar"><ul><li id="attach" class="hidden ' +
'dropdown"><a href="#" class="dropdown-toggle" data-' +
'toggle="dropdown" role="button" aria-haspopup="true" ' +
@@ -246,14 +242,15 @@ 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();
results.push(
!query('#filewrap').classList.contains('hidden')
'</li></ul></li></ul></div></nav>'
);
PrivateBin.TopNav.hideFileSelector();
$.PrivateBin.TopNav.init();
results.push(
query('#filewrap').classList.contains('hidden')
!$('#filewrap').hasClass('hidden')
);
$.PrivateBin.TopNav.hideFileSelector();
results.push(
$('#filewrap').hasClass('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -274,7 +271,7 @@ describe('TopNav', function () {
'display the custom file attachment',
function () {
let results = [];
document.documentElement.innerHTML =
$('body').html(
'<nav><div id="navbar"><ul><li id="attach" class="hidden ' +
'dropdown"><a href="#" class="dropdown-toggle" data-' +
'toggle="dropdown" role="button" aria-haspopup="true" ' +
@@ -283,14 +280,15 @@ 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();
results.push(
query('#customattachment').classList.contains('hidden')
'</li></ul></li></ul></div></nav>'
);
PrivateBin.TopNav.showCustomAttachment();
$.PrivateBin.TopNav.init();
results.push(
!query('#customattachment').classList.contains('hidden')
$('#customattachment').hasClass('hidden')
);
$.PrivateBin.TopNav.showCustomAttachment();
results.push(
!$('#customattachment').hasClass('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -310,8 +308,9 @@ describe('TopNav', function () {
it(
'collapses the navigation when displayed on a small screen',
function () {
const clean = jsdom();
let results = [];
document.documentElement.innerHTML =
$('body').html(
'<nav><div class="navbar-header"><button type="button" ' +
'class="navbar-toggle collapsed" data-toggle="collapse" ' +
'data-target="#navbar" aria-expanded="false" aria-controls' +
@@ -319,33 +318,34 @@ 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();
results.push(
query('.navbar-toggle').classList.contains('collapsed') &&
query('#navbar').getAttribute('aria-expanded') !== 'true'
'"button" class="hidden">New</button></li></ul></div></nav>'
);
PrivateBin.TopNav.collapseBar();
$.PrivateBin.TopNav.init();
results.push(
query('.navbar-toggle').classList.contains('collapsed') &&
query('#navbar').getAttribute('aria-expanded') !== 'true'
$('.navbar-toggle').hasClass('collapsed') &&
$('#navbar').attr('aria-expanded') !== 'true'
);
$.PrivateBin.TopNav.collapseBar();
results.push(
$('.navbar-toggle').hasClass('collapsed') &&
$('#navbar').attr('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
const toggleBtn = document.querySelector('.navbar-toggle');
toggleBtn.dispatchEvent(new MouseEvent('click'));
$('.navbar-toggle').trigger('click');
results.push(
!toggleBtn.classList.contains('collapsed') &&
document.getElementById('navbar').getAttribute('aria-expanded') == 'true'
!$('.navbar-toggle').hasClass('collapsed') &&
$('#navbar').attr('aria-expanded') == 'true'
);
PrivateBin.TopNav.collapseBar();
$.PrivateBin.TopNav.collapseBar();
results.push(
document.querySelector('.navbar-toggle').classList.contains('collapsed') &&
document.getElementById('navbar').getAttribute('aria-expanded') == 'false'
$('.navbar-toggle').hasClass('collapsed') &&
$('#navbar').attr('aria-expanded') == 'false'
);
*/
clean();
const result = results.every(element => element);
if (!result) {
console.log(results);
@@ -364,35 +364,36 @@ describe('TopNav', function () {
'reset inputs to defaults (options off)',
function () {
let results = [];
document.documentElement.innerHTML =
$('body').html(
'<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()
);
query('#burnafterreading').checked = true;
query('#opendiscussion').checked = true;
$('#burnafterreading').attr('checked', 'checked');
$('#opendiscussion').attr('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);
@@ -407,35 +408,35 @@ describe('TopNav', function () {
'reset inputs to defaults (burnafterreading on)',
function () {
let results = [];
document.documentElement.innerHTML =
$('body').html(
'<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()
);
query('#burnafterreading').checked = false;
query('#burnafterreading').removeAttribute('checked');
$('#burnafterreading').removeAttr('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);
@@ -450,37 +451,36 @@ describe('TopNav', function () {
'reset inputs to defaults (opendiscussion on)',
function () {
let results = [];
document.documentElement.innerHTML =
$('body').html(
'<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()
);
query('#opendiscussion').checked = false;
query('#opendiscussion').removeAttribute('checked');
query('#burnafterreading').checked = true;
query('#burnafterreading').setAttribute('checked', 'checked');
$('#opendiscussion').removeAttr('checked');
$('#burnafterreading').prop('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);
@@ -500,12 +500,13 @@ describe('TopNav', function () {
it(
'returns the currently selected expiration date',
function () {
document.documentElement.innerHTML =
$('body').html(
'<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();
}
);
@@ -557,7 +558,7 @@ describe('TopNav', function () {
'returns the selected files',
function () {
let results = [];
document.documentElement.innerHTML =
$('body').html(
'<nav><div id="navbar"><ul><li id="attach" class="hidden ' +
'dropdown"><a href="#" class="dropdown-toggle" data-' +
'toggle="dropdown" role="button" aria-haspopup="true" ' +
@@ -566,16 +567,17 @@ 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();
results.push(
PrivateBin.TopNav.getFileList() === null
'</li></ul></li></ul></div></nav>'
);
addFileList(query('#file'), [
$.PrivateBin.TopNav.init();
results.push(
$.PrivateBin.TopNav.getFileList() === null
);
addFileList($('#file')[0], [
'../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'
@@ -599,23 +601,23 @@ describe('TopNav', function () {
'returns if the burn-after-reading checkbox was ticked',
function () {
let results = [];
document.documentElement.innerHTML =
$('body').html(
'<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();
results.push(
!PrivateBin.TopNav.getBurnAfterReading()
'Burn after reading</label></li></ul></div></nav>'
);
query('#burnafterreading').checked = true;
$.PrivateBin.TopNav.init();
results.push(
PrivateBin.TopNav.getBurnAfterReading()
!$.PrivateBin.TopNav.getBurnAfterReading()
);
query('#burnafterreading').checked = false;
query('#burnafterreading').removeAttribute('checked');
$('#burnafterreading').attr('checked', 'checked');
results.push(
!PrivateBin.TopNav.getBurnAfterReading()
$.PrivateBin.TopNav.getBurnAfterReading()
);
$('#burnafterreading').removeAttr('checked');
results.push(
!$.PrivateBin.TopNav.getBurnAfterReading()
);
cleanup();
const result = results.every(element => element);
@@ -636,23 +638,23 @@ describe('TopNav', function () {
'returns if the open-discussion checkbox was ticked',
function () {
let results = [];
document.documentElement.innerHTML =
$('body').html(
'<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();
results.push(
!PrivateBin.TopNav.getOpenDiscussion()
'Open discussion</label></li></ul></div></nav>'
);
query('#opendiscussion').checked = true;
$.PrivateBin.TopNav.init();
results.push(
PrivateBin.TopNav.getOpenDiscussion()
!$.PrivateBin.TopNav.getOpenDiscussion()
);
query('#opendiscussion').checked = false;
query('#opendiscussion').removeAttribute('checked');
$('#opendiscussion').attr('checked', 'checked');
results.push(
!PrivateBin.TopNav.getOpenDiscussion()
$.PrivateBin.TopNav.getOpenDiscussion()
);
$('#opendiscussion').removeAttr('checked');
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
);
cleanup();
const result = results.every(element => element);
@@ -675,22 +677,23 @@ describe('TopNav', function () {
function (password) {
password = password.replace(/\r+|\n+/g, '');
let results = [];
document.documentElement.innerHTML =
$('body').html(
'<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();
results.push(
PrivateBin.TopNav.getPassword() === ''
'class="form-control" size="23" /></div></li></ul></div></nav>'
);
query('#passwordinput').value = password;
$.PrivateBin.TopNav.init();
results.push(
PrivateBin.TopNav.getPassword() === password
$.PrivateBin.TopNav.getPassword() === ''
);
query('#passwordinput').value = '';
$('#passwordinput').val(password);
results.push(
PrivateBin.TopNav.getPassword() === ''
$.PrivateBin.TopNav.getPassword() === password
);
$('#passwordinput').val('');
results.push(
$.PrivateBin.TopNav.getPassword() === ''
);
cleanup();
const result = results.every(element => element);
@@ -711,7 +714,7 @@ describe('TopNav', function () {
'returns the custom attachment element',
function () {
let results = [];
document.documentElement.innerHTML =
$('body').html(
'<nav><div id="navbar"><ul><li id="attach" class="hidden ' +
'dropdown"><a href="#" class="dropdown-toggle" data-' +
'toggle="dropdown" role="button" aria-haspopup="true" ' +
@@ -720,14 +723,15 @@ 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();
results.push(
!PrivateBin.TopNav.getCustomAttachment().classList.contains('test')
'</li></ul></li></ul></div></nav>'
);
query('#customattachment').classList.add('test');
$.PrivateBin.TopNav.init();
results.push(
PrivateBin.TopNav.getCustomAttachment().classList.contains('test')
!$.PrivateBin.TopNav.getCustomAttachment().hasClass('test')
);
$('#customattachment').addClass('test');
results.push(
$.PrivateBin.TopNav.getCustomAttachment().hasClass('test')
);
cleanup();
const result = results.every(element => element);
@@ -749,7 +753,7 @@ describe('TopNav', function () {
function () {
// Insert any setup code needed for the hideAllButtons function
// Example: Initialize the DOM elements required for testing
document.body.innerHTML =
$('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" ' +
@@ -766,14 +770,15 @@ 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(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'));
assert.ok($('#newbutton').hasClass('hidden'));
assert.ok($('#clonebutton').hasClass('hidden'));
assert.ok($('#rawtextbutton').hasClass('hidden'));
assert.ok($('#qrcodelink').hasClass('hidden'));
cleanup();
}
);
@@ -788,17 +793,14 @@ describe('TopNav', function () {
it(
'displays raw text view correctly',
function () {
const clean = globalThis.cleanup('', {url: 'https://privatebin.net/?0123456789abcdef#1'});
document.documentElement.innerHTML = `
<li id="loadingindicator" class="hidden"></li>
<button id="rawtextbutton"></button>`;
const clean = jsdom('', {url: 'https://privatebin.net/?0123456789abcdef#1'});
$('body').html('<button id="rawtextbutton"></button>');
const sample = 'example';
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);
$.PrivateBin.PasteViewer.setText(sample);
$.PrivateBin.Helper.reset();
$.PrivateBin.TopNav.init();
$('#rawtextbutton').click();
assert.strictEqual($('pre').text(), 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 = globalThis.cleanup('', {url: expected});
clean = jsdom('', {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 = globalThis.cleanup('', {url: expected});
clean = jsdom('', {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 = globalThis.cleanup('', {url: common.urlToString(url)});
const clean = jsdom('', {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 = globalThis.cleanup(
var clean = jsdom(
'<' + element + ' id="' + id + '"></' + element + '>'
);
var result = PrivateBin.UiHelper.isVisible(document.getElementById(id));
var result = $.PrivateBin.UiHelper.isVisible($('#' + id));
clean();
return result;
}

View File

@@ -3,7 +3,7 @@ require('../common');
// DOM builder that mirrors bootstrap5.php navbar
function buildEmailDomNoShortUrl() {
document.documentElement.innerHTML =
$('body').html(
// TopNav expects initially hidden #emaillink BUTTON.
'<nav><div id="navbar"><ul>' +
'<li>' +
@@ -15,18 +15,14 @@ function buildEmailDomNoShortUrl() {
'<button id="emaillink" type="button" class="hidden btn btn-secondary">Email</button>' +
'</li>' +
'</ul></div></nav>' +
'<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>'
'<input id="burnafterreadingoption" type="checkbox">'
);
}
// DOM builder that adds the shortener result block
function buildEmailDomWithShortUrl() {
buildEmailDomNoShortUrl();
document.documentElement.innerHTML =
$('body').html(
// TopNav expectsinitially hidden #emaillink BUTTON.
'<nav><div id="navbar"><ul>' +
'<li>' +
@@ -42,41 +38,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 makeWindowOpenMock() {
const originalOpen = window.open;
let openedUrl = null;
let mockRestoreFn = null;
function stubWinOpen($element) {
const win = $element[0].ownerDocument.defaultView;
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) {
// Some helpers in privatebin.js expect a global document.
global.document = win.document;
let openedUrl = null;
const origOpen = win.open;
// Prefer simple assignment; if blocked, fall back to defineProperty.
try {
win.open = function (url) {
openedUrl = url;
return {};
};
mockRestoreFn = () => { window.open = originalOpen; };
} catch (e) {
Object.defineProperty(win, 'open', {
value: function (url) {
openedUrl = url;
return {};
},
configurable: true,
writable: true
});
}
return {
getUrl: () => openedUrl,
restore: () => {
if (mockRestoreFn) {
mockRestoreFn();
}
}
restore: () => { try { win.open = origOpen; } catch (e) { /* suppress exception in restore */ } },
win
};
}
@@ -88,23 +84,21 @@ function extractMailtoBody(mailtoUrl) {
}
describe('Email - mail body content (short URL vs. fallback)', function () {
beforeEach(function () {
before(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 = document.getElementById('emaillink');
assert.ok(!emailBtn.classList.contains('hidden'), '#emaillink should be visible after showEmailButton');
const $emailBtn = $('#emaillink');
assert.ok(!$emailBtn.hasClass('hidden'), '#emaillink should be visible after showEmailButton');
const { getUrl, restore } = makeWindowOpenMock();
const { getUrl, restore } = stubWinOpen($emailBtn);
try {
emailBtn.click();
document.getElementById('emailconfirm-timezone-current').click();
$emailBtn.trigger('click');
const openedUrl = getUrl();
assert.ok(openedUrl, 'window.open should have been called');
@@ -113,30 +107,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 = document.getElementById('emaillink');
assert.ok(!emailBtn.classList.contains('hidden'), '#emaillink should be visible after showEmailButton');
const $emailBtn = $('#emaillink');
assert.ok(!$emailBtn.hasClass('hidden'), '#emaillink should be visible after showEmailButton');
const { getUrl, restore } = makeWindowOpenMock();
const { getUrl, restore, win } = stubWinOpen($emailBtn);
try {
emailBtn.click();
document.getElementById('emailconfirm-timezone-current').click();
$emailBtn.trigger('click');
const openedUrl = getUrl();
assert.ok(openedUrl, 'window.open should have been called');
const body = extractMailtoBody(openedUrl);
assert.match(body, new RegExp(window.location.href), 'email body should include the fallback page URL');
assert.match(body, new RegExp(win.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.0.js' => 'sha512-lsHD5zxs4lu/NDzaaibe27Vd2t7Cy9JQ3qDHUvDfb4oZvKoWDNEhwUY+4bT3R68cGgpgCYp8U1x2ifeVxqurdQ==',
'js/purify-3.3.2.js' => 'sha512-I6igPVpf3xNghG92mujwqB6Zi3LpUTsni4bRuLnMThEGH6BDbsumv7373+AXHzA4OUlxGsym8ZxKFHy4xjYvkQ==',
'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.0.js', 'defer'); ?>
<?php $this->_scriptTag('js/purify-3.3.2.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.0.js', 'defer'); ?>
<?php $this->_scriptTag('js/purify-3.3.2.js', 'defer'); ?>
<?php $this->_scriptTag('js/legacy.js', 'defer'); ?>
<?php $this->_scriptTag('js/privatebin.js', 'defer'); ?>
<!-- icon -->