update jsdom dependency, fix tests

This commit is contained in:
El RIDO 2025-02-27 08:16:30 +01:00
parent 64b0e33574
commit 4e518b3fce
No known key found for this signature in database
GPG Key ID: 0F5C940A6BD81F92
8 changed files with 678 additions and 888 deletions

View File

@ -5,7 +5,6 @@ global.assert = require('assert');
global.jsc = require('jsverify');
global.jsdom = require('jsdom-global');
global.cleanup = global.jsdom();
global.URL = require('jsdom-url').URL;
global.fs = require('fs');
global.WebCrypto = require('@peculiar/webcrypto').Crypto;
@ -79,8 +78,16 @@ function parseMime(line) {
}
// common testing helper functions
exports.atob = atob;
exports.btoa = btoa;
// as of jsDOM 22 the base64 functions provided in the DOM are more restrictive
// than browser implementation and throw when being passed invalid unicode
// codepoints - as we use these in the encryption with binary data, we need
// these to be character encoding agnostic
exports.atob = function(encoded) {
return Buffer.from(encoded, 'base64').toString('binary');
}
exports.btoa = function(text) {
return Buffer.from(text, 'binary').toString('base64');
}
// provides random lowercase characters from a to z
exports.jscA2zString = function() {

1059
js/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,9 +8,8 @@
},
"devDependencies": {
"@peculiar/webcrypto": "^1.5.0",
"jsdom": "^20.0.3",
"jsdom": "^26.0.0",
"jsdom-global": "^3.0.2",
"jsdom-url": "^3.0.1",
"jsverify": "^0.8.3"
},
"scripts": {

View File

@ -1,5 +1,5 @@
'use strict';
var common = require('../common');
const common = require('../common');
describe('AttachmentViewer', function () {
describe('setAttachment, showAttachment, removeAttachment, hideAttachment, hideAttachmentPreview, hasAttachment, getAttachment & moveAttachmentTo', function () {
@ -14,11 +14,12 @@ describe('AttachmentViewer', function () {
'string',
function (mimeType, rawdata, filename, prefix, postfix) {
let clean = jsdom(),
data = 'data:' + mimeType + ';base64,' + btoa(rawdata),
data = 'data:' + mimeType + ';base64,' + common.btoa(rawdata),
mimePrefix = mimeType.substring(0, 6),
previewSupported = (
mimeType.substring(0, 6) === 'image/' ||
mimeType.substring(0, 6) === 'audio/' ||
mimeType.substring(0, 6) === 'video/' ||
mimePrefix === 'image/' ||
mimePrefix === 'audio/' ||
mimePrefix === 'video/' ||
mimeType.match(/\/pdf/i)
),
results = [],
@ -48,6 +49,7 @@ describe('AttachmentViewer', function () {
$('#attachment').hasClass('hidden') &&
$('#attachmentPreview').hasClass('hidden')
);
global.atob = common.atob;
if (filename.length) {
$.PrivateBin.AttachmentViewer.setAttachment(data, filename);
} else {

View File

@ -4,8 +4,11 @@ const common = require('../common');
describe('CopyToClipboard', function() {
this.timeout(30000);
describe ('Copy paste co clipboard', function () {
jsc.property('Copy with button click', common.jscFormats(), 'nestring', async function (format, text) {
describe ('Copy paste to clipboard', function () {
jsc.property('Copy with button click',
common.jscFormats(),
'nestring',
async function (format, text) {
var clean = jsdom();
common.enableClipboard();
@ -32,13 +35,17 @@ describe('CopyToClipboard', function() {
clean();
return text === savedToClipboardText;
});
}
);
/**
* Unfortunately in JSVerify impossible to check if copy with shortcut when user selected some text on the page
* (the copy paste to clipboard should not work in this case) due to lucking window.getSelection() in jsdom.
* (the copy paste to clipboard should not work in this case) due to lacking window.getSelection() in jsdom.
*/
jsc.property('Copy with keyboard shortcut', common.jscFormats(), 'nestring', async function (format, text) {
jsc.property('Copy with keyboard shortcut',
common.jscFormats(),
'nestring',
async function (format, text) {
var clean = jsdom();
common.enableClipboard();
@ -65,11 +72,14 @@ describe('CopyToClipboard', function() {
clean();
return copiedTextWithoutSelectedText === text;
});
}
);
});
jsc.property('Copy link to clipboard', 'nestring', async function (text) {
jsc.property('Copy link to clipboard',
'nestring',
async function (text) {
var clean = jsdom();
common.enableClipboard();
@ -85,11 +95,14 @@ describe('CopyToClipboard', function() {
clean();
return text === copiedText;
});
}
);
describe('Keyboard shortcut hint', function () {
jsc.property('Show hint', 'nestring', function (text) {
jsc.property('Show hint',
'nestring',
function (text) {
var clean = jsdom();
$('body').html('<small id="copyShortcutHintText"></small>');
@ -102,9 +115,12 @@ describe('CopyToClipboard', function() {
clean();
return keyboardShortcutHint.length > 0;
});
}
);
jsc.property('Hide hint', 'nestring', function (text) {
jsc.property('Hide hint',
'nestring',
function (text) {
var clean = jsdom();
$('body').html('<small id="copyShortcutHintText">' + text + '</small>');
@ -117,7 +133,7 @@ describe('CopyToClipboard', function() {
clean();
return keyboardShortcutHint.length === 0;
}
);
});
});
});

View File

@ -1,5 +1,5 @@
'use strict';
require('../common');
const common = require('../common');
describe('CryptTool', function () {
describe('cipher & decipher', function () {
@ -15,24 +15,26 @@ describe('CryptTool', function () {
'string',
'string',
async function (key, password, message) {
// pause to let async functions conclude
await new Promise(resolve => setTimeout(resolve, 300));
let clean = jsdom();
const clean = jsdom();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
global.atob = common.atob;
global.btoa = common.btoa;
message = message.trim();
let cipherMessage = await $.PrivateBin.CryptTool.cipher(
const cipherMessage = await $.PrivateBin.CryptTool.cipher(
key, password, message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
key, password, cipherMessage
);
clean();
return message === plaintext;
const result = (message === plaintext);
if (!result) console.log(plaintext, cipherMessage);
return result;
}
),
{tests: 3});
@ -41,18 +43,19 @@ describe('CryptTool', function () {
// The below static unit tests are included to ensure deciphering of "classic"
// SJCL based pastes still works
it(
'supports PrivateBin v1 ciphertext (SJCL & browser atob)',
function () {
'supports PrivateBin v1 ciphertext 1 (SJCL & browser atob)',
async function () {
delete global.Base64;
let clean = jsdom();
const clean = jsdom();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
global.atob = common.atob;
// Of course you can easily decipher the following texts, if you like.
// Bonus points for finding their sources and hidden meanings.
return $.PrivateBin.CryptTool.decipher(
const paste = await $.PrivateBin.CryptTool.decipher(
'6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=',
// -- "That's amazing. I've got the same combination on my luggage."
Array.apply(0, Array(6)).map((_,b) => b + 1).join(''),
@ -83,8 +86,30 @@ describe('CryptTool', function () {
'QUxMXI5htsn2rf0HxCFu7Po8DNYLxTS+67hYjDIYWYaEIc8LXWMLyDm9' +
'C5fARPJ4F2BIWgzgzkNj+dVjusft2XnziamWdbS5u3kuRlVuz5LQj+R5' +
'imnqQAincdZTkTT1nYx+DatlOLllCYIHffpI="}'
).then(function (paste1) {
$.PrivateBin.CryptTool.decipher(
);
clean();
const result = typeof paste === 'string' && paste.includes('securely packed in iron');
if (!result) console.log(paste);
assert.ok(result);
}
);
it(
'supports PrivateBin v1 ciphertext 2 (SJCL & browser atob)',
async function () {
delete global.Base64;
const clean = jsdom();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
global.atob = common.atob;
// Of course you can easily decipher the following texts, if you like.
// Bonus points for finding their sources and hidden meanings.
const paste = await $.PrivateBin.CryptTool.decipher(
's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
'', // no password
'{"iv":"WA42mdxIVXUwBqZu7JYNiw==","v":1,"iter":10000,"ks"' +
@ -109,30 +134,28 @@ describe('CryptTool', function () {
'XhHvixZLcSjX2KQuHmEoWzmJcr3DavdoXZmAurGWLKjzEdJc5dSD/eNr' +
'99gjHX7wphJ6umKMM+fn6PcbYJkhDh2GlJL5COXjXfm/5aj/vuyaRRWZ' +
'MZtmnYpGAtAPg7AUG"}'
).then(function (paste2) {
clean();
assert.ok(
paste1.includes('securely packed in iron') &&
paste2.includes('Sol is right')
);
});
});
clean();
const result = typeof paste === 'string' && paste.includes('Sol is right');
if (!result) console.log(paste);
assert.ok(result);
}
);
it(
'supports ZeroBin ciphertext (SJCL & Base64 1.7)',
function () {
'supports ZeroBin ciphertext 1 (SJCL & Base64 1.7)',
async function () {
global.Base64 = require('../base64-1.7').Base64;
var clean = jsdom();
const clean = jsdom();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
global.atob = common.atob;
// Of course you can easily decipher the following texts, if you like.
// Bonus points for finding their sources and hidden meanings.
return $.PrivateBin.CryptTool.decipher(
const paste = await $.PrivateBin.CryptTool.decipher(
'6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=',
// -- "That's amazing. I've got the same combination on my luggage."
Array.apply(0, Array(6)).map((_,b) => b + 1).join(''),
@ -155,8 +178,27 @@ describe('CryptTool', function () {
'7mNNo7xba/YT9KoPDaniqnYqb+q2pX1WNWE7dLS2wfroMAS3kh8P22DA' +
'V37AeiNoD2PcI6ZcHbRdPa+XRrRcJhSPPW7UQ0z4OvBfjdu/w390QxAx' +
'SxvZewoh49fKKB6hTsRnZb4tpHkjlww=="}'
).then(function (paste1) {
$.PrivateBin.CryptTool.decipher(
);
clean();
delete global.Base64;
const result = typeof paste === 'string' && paste.includes('securely packed in iron');
if (!result) console.log(paste);
assert.ok(result);
}
);
it(
'supports ZeroBin ciphertext 2 (SJCL & Base64 1.7)',
async function () {
global.Base64 = require('../base64-1.7').Base64;
const clean = jsdom();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
global.atob = common.atob;
const paste = await $.PrivateBin.CryptTool.decipher(
's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
'', // no password
'{"iv":"Z7lAZQbkrqGMvruxoSm6Pw==","v":1,"iter":10000,"ks"' +
@ -174,20 +216,17 @@ describe('CryptTool', function () {
'7tmfcF73w9dufDFI3LNca2KxzBnWNPYvIZKBwWbq8ncxkb191dP6mjEi' +
'7NnhqVk5A6vIBbu4AC5PZf76l6yep4xsoy/QtdDxCMocCXeAML9MQ9uP' +
'QbuspOKrBvMfN5igA1kBqasnxI472KBNXsdZnaDddSVUuvhTcETM="}'
).then(function (paste2) {
);
clean();
delete global.Base64;
assert.ok(
paste1.includes('securely packed in iron') &&
paste2.includes('Sol is right')
);
});
});
const result = typeof paste === 'string' && paste.includes('Sol is right');
if (!result) console.log(paste);
assert.ok(result);
}
);
it('does not truncate messages', async function () {
let message = fs.readFileSync('test/compression-sample.txt', 'utf8'),
const message = fs.readFileSync('test/compression-sample.txt', 'ascii').trim(),
clean = jsdom();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
@ -195,17 +234,18 @@ describe('CryptTool', function () {
});
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
let cipherMessage = await $.PrivateBin.CryptTool.cipher(
global.atob = common.atob;
global.btoa = common.btoa;
const cipherMessage = await $.PrivateBin.CryptTool.cipher(
'foo', 'bar', message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
'foo', 'bar', cipherMessage
);
clean();
assert.strictEqual(
message,
plaintext
);
const result = (message === plaintext);
if (!result) console.log(plaintext, cipherMessage);
assert.ok(result);
});
it('can en- and decrypt a particular message (#260)', function () {
@ -213,8 +253,6 @@ describe('CryptTool', function () {
'string',
'string',
async function (key, password) {
// pause to let async functions conclude
await new Promise(resolve => setTimeout(resolve, 300));
const message = `
1 subgoal
@ -237,21 +275,23 @@ isWhile : interp (while expr sBody) (MemElem mem) =
======================== ( 1 / 1 )
conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
`;
let clean = jsdom();
const clean = jsdom();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
let cipherMessage = await $.PrivateBin.CryptTool.cipher(
const cipherMessage = await $.PrivateBin.CryptTool.cipher(
key, password, message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
key, password, cipherMessage
);
clean();
return message === plaintext;
const result = (message === plaintext);
if (!result) console.log(plaintext, cipherMessage);
return result;
}
),
{tests: 3});
@ -259,25 +299,27 @@ conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
});
describe('getSymmetricKey', function () {
this.timeout(30000);
var keys = [];
this.timeout(10000);
let keys = [];
// the parameter is used to ensure the test is run more then one time
jsc.property(
'returns random, non-empty keys',
it('returns random, non-empty keys', function () {
jsc.assert(jsc.forall(
'integer',
function(counter) {
var clean = jsdom();
const clean = jsdom();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
var key = $.PrivateBin.CryptTool.getSymmetricKey(),
const key = $.PrivateBin.CryptTool.getSymmetricKey(),
result = (key !== '' && keys.indexOf(key) === -1);
keys.push(key);
clean();
return result;
}
);
),
{tests: 10});
});
});
});

View File

@ -94,7 +94,6 @@ describe('Model', function () {
url.query = queryStart.concat(pasteId, queryEnd);
const pasteIdString = pasteId.join(''),
clean = jsdom('', {url: common.urlToString(url)});
global.URL = require('jsdom-url').URL;
const result = $.PrivateBin.Model.getPasteId();
$.PrivateBin.Model.reset();
clean();
@ -107,7 +106,6 @@ describe('Model', function () {
function (url) {
let clean = jsdom('', {url: common.urlToString(url)}),
result = false;
global.URL = require('jsdom-url').URL;
try {
$.PrivateBin.Model.getPasteId();
}
@ -131,7 +129,7 @@ describe('Model', function () {
'returns the fragment of a v1 URL',
common.jscUrl(),
function (url) {
url.fragment = common.btoa(url.fragment.padStart(32, '\u0000'));
url.fragment = '0OIl'; // any non-base58 string
const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
@ -140,17 +138,17 @@ describe('Model', function () {
}
);
jsc.property(
'returns the v1 fragment stripped of trailing query parts',
'returns the fragment stripped of trailing query parts',
common.jscUrl(),
jsc.array(common.jscHashString()),
function (url, trail) {
const fragmentString = common.btoa(url.fragment.padStart(32, '\u0000'));
url.fragment = fragmentString + '&' + trail.join('');
const fragment = url.fragment.padStart(32, '\u0000');
url.fragment = $.PrivateBin.CryptTool.base58encode(fragment) + '&' + trail.join('');
const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
clean();
return fragmentString === result;
return fragment === result;
}
);
jsc.property(

View File

@ -732,7 +732,6 @@ describe('TopNav', function () {
'displays raw text view correctly',
function () {
const clean = jsdom('', {url: 'https://privatebin.net/?0123456789abcdef#0'});
//global.URL = require('jsdom-url').URL;
$('body').html('<button id="rawtextbutton"></button>');
const sample = 'example';
$.PrivateBin.PasteViewer.setText(sample);