Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/workflows/cypress-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,25 @@ jobs:
git submodule sync --recursive
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1

- name: Register main git reference
run: |
main_app_ref="$(if [ "${{ matrix.server-versions }}" = "master" ]; then echo -n "main"; else echo -n "${{ matrix.server-versions }}"; fi)"
echo "main_app_ref=$main_app_ref" >> $GITHUB_ENV

- name: Checkout viewer
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
repository: nextcloud/viewer
ref: ${{ matrix.server-versions }}
path: apps/viewer

- name: Checkout spreed
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
repository: nextcloud/spreed
ref: ${{ env.main_app_ref }}
path: apps/spreed

- name: Checkout files_pdfviewer
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
Expand Down Expand Up @@ -106,6 +118,13 @@ jobs:
run: |
composer install

- name: Build talk
working-directory: apps/spreed
run: |
composer install --no-dev
npm ci
npm run dev

- name: Set up Nextcloud
env:
DB_PORT: 4444
Expand All @@ -125,6 +144,7 @@ jobs:
php occ app:enable --force viewer
php occ app:enable --force files_pdfviewer
php occ app:enable --force richdocuments
php occ app:enable --force spreed
php occ app:list
php occ config:system:set trusted_domains 1 --value="172.17.0.1"

Expand Down
1 change: 1 addition & 0 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ You can also edit your documents off-line with the Collabora Office app from the
<licence>agpl</licence>
<author>Collabora Productivity based on work of Frank Karlitschek, Victor Dubiniuk</author>
<types>
<filesystem />
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We dropped this with #1728 in the past due to performance impact, but this is no longer a problem since the whole Application.php is now only using lazy registration methods

<prevent_group_restriction/>
</types>
<documentation>
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/integration.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,4 @@ describe('Nextcloud integration', function() {
})
})
})
})
})
110 changes: 110 additions & 0 deletions cypress/e2e/talk.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* SPDX-FileCopyrightText: 2023 Julius Härtl <jus@bitgrid.net>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

describe('Talk integraiton integration', function() {
let randUser

const resetConfig = () => {
cy.nextcloudTestingAppConfigSet('files', 'watermark_enabled', 'no')
cy.nextcloudTestingAppConfigSet('files', 'watermark_text', '{userId}')
cy.nextcloudTestingAppConfigSet('files', 'watermark_shareTalkPublic', 'no')
cy.nextcloudTestingAppConfigSet('richdocuments', 'uiDefaults-UIMode', 'notebookbar')
}

before(function() {
resetConfig()
cy.createRandomUser().then(user => {
randUser = user
cy.login(user)
cy.uploadFile(user, 'document.odt', 'application/vnd.oasis.opendocument.text', '/document.odt')
})
})

afterEach(() => {
resetConfig()
})

const filename = 'document.odt'

beforeEach(function() {
cy.login(randUser)
})

it('Can share a file to a talk room and open it', function() {
cy.createTalkRoom(randUser, {
roomName: 'Test room',
}).then(room => {
cy.log(`Created talk room "${room.name}"`, room)
cy.shareFileToTalkRoom(randUser, filename, room.token)
cy.visit(`/call/${room.token}`)
cy.get('.file-preview')
.should('be.visible')
.should('contain.text', filename)
.click()

cy.waitForViewer()
cy.waitForCollabora()
})
})

it('See that the file is shared without download', function() {
cy.nextcloudTestingAppConfigSet('files', 'watermark_enabled', 'yes')
cy.nextcloudTestingAppConfigSet('files', 'watermark_shareTalkPublic', 'yes')
cy.nextcloudTestingAppConfigSet('files', 'watermark_text', 'TestingWatermark')

cy.createTalkRoom(randUser, {
roomName: 'Secure room',
}).then(room => {
cy.log(`Created talk room "${room.name}"`, room)
cy.shareFileToTalkRoom(randUser, filename, room.token, { permission: 1 })
cy.makeTalkRoomPublic(randUser, room.token)

cy.logout()
cy.clearAllLocalStorage()
cy.visit(`/call/${room.token}`)
cy.get('.username-form__input input[type="text"]')
.should('be.visible')
.type('Test user{enter}')

// Assert that the download button is hidden in talk
cy.get('.messages:contains("document.odt")')
.trigger('mouseover')

cy.get('.file-preview')
.closest('.message')
.find('button[aria-label="Actions"]')
.should('be.visible')
.click()

cy.get('.action:contains("Download")')
.should('not.exist')

// Assert the file is still opening
cy.get('.file-preview')
.should('be.visible')
.should('contain.text', filename)
// We need to get the href to work around how cypress works with windows
.invoke('attr', 'href')
.then((href) => {
cy.visit(href)

cy.get('[data-cy="guestNameModal"]').should('be.visible')
cy.inputCollaboraGuestName('A guest')

cy.waitForCollabora()

cy.url().then(url => {
const baseUrl = url.split('?')[0]
cy.request({
url: baseUrl + '/download',
failOnStatusCode: false,
}).then((response) => {
expect(response.status).to.eq(403)
})
})
})
})
})
})
65 changes: 58 additions & 7 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Cypress.Commands.add('uploadFile', (user, fixture, mimeType, target = `/${fixtur
})

Cypress.Commands.add('ocsRequest', (user, options) => {
const auth = { user: user.userId, password: user.password }
const auth = user ? { user: user.userId, password: user.password } : null
return cy.request({
form: true,
auth,
Expand All @@ -109,6 +109,22 @@ Cypress.Commands.add('shareFileToUser', (user, path, targetUser, shareData = {})
})
})

Cypress.Commands.add('shareFileToTalkRoom', (user, path, roomId, shareData = {}) => {
cy.login(user)
cy.ocsRequest(user, {
method: 'POST',
url: `${url}/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json`,
body: {
path,
shareType: 10,
shareWith: roomId,
...shareData,
},
}).then(response => {
cy.log(`${user.userId} shared ${path} with talk room ${roomId}`, response.status)
})
})

Cypress.Commands.add('shareFileToRemoteUser', (user, path, targetUser, shareData = {}) => {
cy.login(user)
const federatedId = `${targetUser.userId}@${url}`
Expand Down Expand Up @@ -396,10 +412,45 @@ Cypress.Commands.add('verifyTemplateFields', (fields, fileId) => {
})

Cypress.Commands.add('pickFile', (filename) => {
cy.get('.office-target-picker')
.find(`tr[data-filename="${filename}"]`)
.click()
cy.get('.office-target-picker')
.find('button[aria-label="Select file"]')
.click()
cy.get('.office-target-picker')
.find(`tr[data-filename="${filename}"]`)
.click()
cy.get('.office-target-picker')
.find('button[aria-label="Select file"]')
.click()
})

Cypress.Commands.add('createTalkRoom', (user, options = {}) => {
cy.login(user)
return cy.ocsRequest(user, {
method: 'POST',
url: `${url}/ocs/v2.php/apps/spreed/api/v4/room?format=json`,
body: {
roomType: options.roomType || 3, // Default to group conversation
roomName: options.roomName,
invite: options.invite || '',
source: options.source || '',
objectType: options.objectType || '',
objectId: options.objectId || '',
password: options.password || '',
}
}).then(response => {
cy.log(`Created talk room "${options.roomName}"`, response.status)
return cy.wrap(response.body.ocs.data)
})
})

Cypress.Commands.add('makeTalkRoomPublic', (user, token, password = '') => {
cy.login(user)
return cy.ocsRequest(user, {
method: 'POST',
url: `${url}/ocs/v2.php/apps/spreed/api/v4/room/${token}/public?format=json`,
body: {
password: password,
}
}).then(response => {
cy.log(`Made talk room public`, response.status)
return cy.wrap(response.body.ocs.data)
})
})

7 changes: 7 additions & 0 deletions lib/AppConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,13 @@ public function useSecureViewAdditionalMimes(): bool {
return $this->config->getAppValue(Application::APPNAME, self::USE_SECURE_VIEW_ADDITIONAL_MIMES, 'no') === 'yes';
}

public function getMimeTypes(): array {
return array_merge(
Capabilities::MIMETYPES,
Capabilities::MIMETYPES_MSOFFICE,
);
}

public function getDomainList(): array {
$urls = array_merge(
[ $this->domainOnly($this->getCollaboraUrlPublic()) ],
Expand Down
38 changes: 38 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
namespace OCA\Richdocuments\AppInfo;

use OCA\Files_Sharing\Event\ShareLinkAccessedEvent;
use OCA\Richdocuments\AppConfig;
use OCA\Richdocuments\Capabilities;
use OCA\Richdocuments\Conversion\ConversionProvider;
use OCA\Richdocuments\Db\WopiMapper;
Expand All @@ -20,6 +21,7 @@
use OCA\Richdocuments\Listener\FileCreatedFromTemplateListener;
use OCA\Richdocuments\Listener\LoadAdditionalListener;
use OCA\Richdocuments\Listener\LoadViewerListener;
use OCA\Richdocuments\Listener\OverwritePublicSharePropertiesListener;
use OCA\Richdocuments\Listener\ReferenceListener;
use OCA\Richdocuments\Listener\RegisterTemplateFileCreatorListener;
use OCA\Richdocuments\Listener\ShareLinkListener;
Expand All @@ -32,13 +34,15 @@
use OCA\Richdocuments\Preview\OpenDocument;
use OCA\Richdocuments\Preview\Pdf;
use OCA\Richdocuments\Reference\OfficeTargetReferenceProvider;
use OCA\Richdocuments\Storage\SecureViewWrapper;
use OCA\Richdocuments\TaskProcessing\SlideDeckGenerationProvider;
use OCA\Richdocuments\TaskProcessing\SlideDeckGenerationTaskType;
use OCA\Richdocuments\TaskProcessing\TextToDocumentProvider;
use OCA\Richdocuments\TaskProcessing\TextToDocumentTaskType;
use OCA\Richdocuments\TaskProcessing\TextToSpreadsheetProvider;
use OCA\Richdocuments\TaskProcessing\TextToSpreadsheetTaskType;
use OCA\Richdocuments\Template\CollaboraTemplateProvider;
use OCA\Talk\Events\OverwritePublicSharePropertiesEvent;
use OCA\Viewer\Event\LoadViewer;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
Expand All @@ -47,12 +51,15 @@
use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
use OCP\Collaboration\Reference\RenderReferenceEvent;
use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent;
use OCP\Files\Storage\IStorage;
use OCP\Files\Template\BeforeGetTemplatesEvent;
use OCP\Files\Template\FileCreatedFromTemplateEvent;
use OCP\Files\Template\RegisterTemplateCreatorEvent;
use OCP\IAppConfig;
use OCP\Preview\BeforePreviewFetchedEvent;
use OCP\Security\CSP\AddContentSecurityPolicyEvent;
use OCP\Security\FeaturePolicy\AddFeaturePolicyEvent;
use OCP\Server;

class Application extends App implements IBootstrap {
public const APPNAME = 'richdocuments';
Expand All @@ -62,6 +69,8 @@ public function __construct(array $urlParams = []) {
}

public function register(IRegistrationContext $context): void {
\OCP\Util::connectHook('OC_Filesystem', 'preSetup', $this, 'addStorageWrapper');

$context->registerTemplateProvider(CollaboraTemplateProvider::class);
$context->registerCapability(Capabilities::class);
$context->registerMiddleWare(WOPIMiddleware::class);
Expand All @@ -76,6 +85,7 @@ public function register(IRegistrationContext $context): void {
$context->registerEventListener(RenderReferenceEvent::class, ReferenceListener::class);
$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);
$context->registerEventListener(BeforeGetTemplatesEvent::class, BeforeGetTemplatesListener::class);
$context->registerEventListener(OverwritePublicSharePropertiesEvent::class, OverwritePublicSharePropertiesListener::class);
$context->registerReferenceProvider(OfficeTargetReferenceProvider::class);
$context->registerSensitiveMethods(WopiMapper::class, [
'getPathForToken',
Expand All @@ -101,4 +111,32 @@ public function register(IRegistrationContext $context): void {

public function boot(IBootContext $context): void {
}

/**
* @internal
*/
public function addStorageWrapper(): void {
if (Server::get(IAppConfig::class)->getValueString(AppConfig::WATERMARK_APP_NAMESPACE, 'watermark_enabled', 'no') === 'no') {
return;
}

\OC\Files\Filesystem::addStorageWrapper('richdocuments', [$this, 'addStorageWrapperCallback'], -10);
}

/**
* @param $mountPoint
* @param IStorage $storage
* @return SecureViewWrapper|IStorage
*@internal
*/
public function addStorageWrapperCallback($mountPoint, IStorage $storage) {
if (!\OC::$CLI && $mountPoint !== '/') {
return new SecureViewWrapper([
'storage' => $storage,
'mountPoint' => $mountPoint,
]);
}

return $storage;
}
}
1 change: 1 addition & 0 deletions lib/Controller/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ public function updateWatermarkSettings($settings = []): JSONResponse {
'watermark_shareAll',
'watermark_shareRead',
'watermark_shareDisabledDownload',
'watermark_shareTalkPublic',
'watermark_linkSecure',
'watermark_linkRead',
'watermark_linkAll',
Expand Down
Loading
Loading