Skip to content
Closed
Next Next commit
tests: Add tests for naughty filenames
Signed-off-by: Robbert Gurdeep Singh <[email protected]>
  • Loading branch information
beardhatcode committed Apr 19, 2021
commit 1f12788a09ecb9b3006340fa2229c1ef980776fc
119 changes: 119 additions & 0 deletions cypress/integration/image-oddname.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/**
* @copyright Copyright (c) 2019 John Molakvoæ <[email protected]>
*
* @author John Molakvoæ <[email protected]>
* @author Robbert Gurdeep Singh <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

import { randHash } from "../utils/";

/**
* Make a name aimed to break the viewer in case of escaping errors
*
* @param {String} realName
* @returns {String} a name for the file to be uploaded as
*/
function naughtyFileName(realName) {
const ext = realName.split(".").pop();
return (
"~⛰️ shot of a ${big} mountain`, " +
"realy #1's " +
'" #_+="%2520 was this called ' +
realName +
"? :p ." +
ext.toUpperCase()
);
}

for (let [file, type] of [
["audio.mp3", "audio/mpeg"],
["audio.ogg", "audio/mpeg"],
["audio.ogg", "audio/ogg"],
["image1.jpg", "image/jpeg"],
["image.gif", "image/gif"],
["image.heic", "image/heic"],
["image.png", "image/png"],
["image-small.png", "image/png"],
["image.svg", "image/svg"],
["image.webp", "image/webp"],
["video1.mp4", "video/mp4"],
["video.mkv", "video/mkv"],
["video.ogv", "video/ogv"],
["video.webm", "video/webm"],
]) {
const placedName = naughtyFileName(file);

// We'll escape all the characters in the name to match it with css
const placedNameCss = placedName.replaceAll(
/./gi,
(x) => "\\" + ("00000" + x.charCodeAt(0).toString(16)).slice(-6)
);
const randUser = randHash();

describe(`Open ${file} in viewer with a naughy name`, function () {
before(function () {
// Init user
cy.nextcloudCreateUser(randUser, "password");
cy.login(randUser, "password");

// Upload test files
cy.uploadFile(file, type, "", placedName);
cy.visit("/apps/files");

// wait a bit for things to be settled
cy.wait(1000);
});
after(function () {
cy.logout();
});

it(`See ${file} as ${placedName} in the list`, function () {
cy.get(`#fileList tr[data-file="${placedNameCss}"]`, {
timeout: 10000,
}).should("contain", placedName);
});

it("Open the viewer on file click", function () {
cy.openFile(placedName);
cy.get("body > .viewer").should("be.visible");
});

it("Does not see a loading animation", function () {
cy.get("body > .viewer", { timeout: 10000 })
.should("be.visible")
.and("have.class", "modal-mask")
.and("not.have.class", "icon-loading");
});

it("See the menu icon and title on the viewer header", function () {
cy.get("body > .viewer .modal-title").should("contain", placedName);
cy.get(
"body > .viewer .modal-header button.action-item__menutoggle"
).should("be.visible");
cy.get("body > .viewer .modal-header button.icon-close").should(
"be.visible"
);
});

it("Does not see navigation arrows", function () {
cy.get("body > .viewer a.prev").should("not.be.visible");
cy.get("body > .viewer a.next").should("not.be.visible");
});
});
}
31 changes: 22 additions & 9 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,24 @@ Cypress.Commands.add('nextcloudCreateUser', (user, password) => {
})
})

Cypress.Commands.add('uploadFile', (fileName, mimeType, path = '') => {
Cypress.Commands.add('uploadFile', (fixtureFileName, mimeType, path = '', uploadedFileName = null) => {
if(uploadedFileName === null){
uploadedFileName = fixtureFileName;
}
// get fixture
return cy.fixture(fileName, 'base64').then(file => {
return cy.fixture(fixtureFileName, 'base64').then(file => {
// convert the logo base64 string to a blob
const blob = Cypress.Blob.base64StringToBlob(file, mimeType)
try {
const file = new File([blob], fileName, { type: mimeType })
const file = new File([blob], uploadedFileName, { type: mimeType })
return cy.window().then(async window => {
await axios.put(`${Cypress.env('baseUrl')}/remote.php/webdav${path}/${fileName}`, file, {
await axios.put(`${Cypress.env('baseUrl')}/remote.php/webdav${path}/${encodeURIComponent(uploadedFileName)}`, file, {
headers: {
requesttoken: window.OC.requestToken,
'Content-Type': mimeType,
}
}).then(response => {
cy.log(`Uploaded ${fileName}`, response)
cy.log(`Uploaded ${fixtureFileName} as ${uploadedFileName}`, response)
})
})
} catch (error) {
Expand All @@ -102,19 +105,29 @@ Cypress.Commands.add('createFolder', dirName => {
cy.log('Created folder', dirName)
})

function cssEscape(v) {
if (v.match(/^[A-Za-z0-9 -]*$/)) {
return v;
} else {
let a = v.replaceAll(/./gi, (x) => "\\" + ("00000" + x.charCodeAt(0).toString(16)).slice(-6))
console.log(a);
return a;
}
}

Cypress.Commands.add('openFile', fileName => {
cy.get(`#fileList tr[data-file="${fileName}"] a.name`).click()
cy.get(`#fileList tr[data-file="${cssEscape(fileName)}"] a.name`).click()
cy.wait(250)
})

Cypress.Commands.add('getFileId', fileName => {
return cy.get(`#fileList tr[data-file="${fileName}"]`)
return cy.get(`#fileList tr[data-file="${cssEscape(fileName)}"]`)
.should('have.attr', 'data-id')
})

Cypress.Commands.add('deleteFile', fileName => {
cy.get(`#fileList tr[data-file="${fileName}"] a.name .action-menu`).click()
cy.get(`#fileList tr[data-file="${fileName}"] a.name + .popovermenu .action-delete`).click()
cy.get(`#fileList tr[data-file="${cssEscape(fileName)}"] a.name .action-menu`).click()
cy.get(`#fileList tr[data-file="${cssEscape(fileName)}"] a.name + .popovermenu .action-delete`).click()
})

/**
Expand Down