import Docker from 'dockerode'; import 'wait-on'; import { PassThrough } from 'stream'; import { basename } from 'path'; import 'fs'; import 'fast-xml-parser'; /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; /** * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ class User { constructor(user, password = user, language = 'en') { Object.defineProperty(this, "userId", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "password", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "language", { enumerable: true, configurable: true, writable: true, value: void 0 }); this.userId = user; this.password = password; this.language = language; } static createRandom() { const uid = (Math.random() + 1).toString(36).substring(7); return new User(uid); } } /* eslint-disable no-console */ /** * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ const docker = new Docker(); // Store the container name, different names are used to prevent conflicts when testing multiple apps locally let _containerName = null; /** * Get the container name that is currently created and/or used by dockerode */ const getContainerName = function () { if (_containerName === null) { const app = basename(process.cwd()).replace(' ', ''); _containerName = `nextcloud-e2e-test-server_${app}`; } return _containerName; }; /** * Get the current container used * Throws if not found */ const getContainer = function () { return docker.getContainer(getContainerName()); }; /** * Execute a command in the container */ const runExec = function (command_1) { return __awaiter(this, arguments, void 0, function* (command, { container, user = 'www-data', verbose = false, env = [] } = {}) { container = container || getContainer(); const exec = yield container.exec({ Cmd: typeof command === 'string' ? [command] : command, AttachStdout: true, AttachStderr: true, User: user, Env: env, }); return new Promise((resolve, reject) => { const dataStream = new PassThrough(); exec.start({}, (err, stream) => { if (stream) { // Pass stdout and stderr to dataStream exec.modem.demuxStream(stream, dataStream, dataStream); stream.on('end', () => dataStream.end()); } else { reject(err); } }); const data = []; dataStream.on('data', (chunk) => { var _a; data.push(chunk.toString('utf8')); const printable = (_a = data.at(-1)) === null || _a === void 0 ? void 0 : _a.trim(); if (verbose && printable) { console.log(`ā”œā”€ ${printable.replace(/\n/gi, '\nā”œā”€ ')}`); } }); dataStream.on('error', (err) => reject(err)); dataStream.on('end', () => resolve(data.join(''))); }); }); }; /** * Execute an occ command in the container */ const runOcc = function (command, { container, env = [], verbose = false } = {}) { const cmdArray = typeof command === 'string' ? [command] : command; return runExec(['php', 'occ', ...cmdArray], { container, verbose, env }); }; /** * Add a user to the Nextcloud in the container. */ const addUser = function (user, { container, env = [], verbose = false } = {}) { return runOcc(['user:add', user.userId, '--password-from-env'], { container, verbose, env: ['OC_PASS=' + user.password, ...env] }); }; /** * SPDX-FileCopyrightText: 2024 Ferdinand Thiessen * SPDX-License-Identifier: AGPL-3.0-or-later */ /** * Create a new random user * @return The new user */ function createRandomUser() { return __awaiter(this, void 0, void 0, function* () { const user = User.createRandom(); yield addUser(user); return user; }); } /** * Helper to login on the Nextcloud instance * @param request API request object * @param user The user to login */ function login(request, user) { return __awaiter(this, void 0, void 0, function* () { const tokenResponse = yield request.get('./csrftoken', { failOnStatusCode: true, }); const requesttoken = (yield tokenResponse.json()).token; yield request.post('./login', { form: { user: user.userId, password: user.password, requesttoken, }, headers: { Origin: tokenResponse.url().replace(/index.php.*/, ''), }, failOnStatusCode: true, }); yield request.get('apps/files', { failOnStatusCode: true, }); }); } export { createRandomUser, login };