Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stable29] Fix encryption wrapper not seen by groupfolder cache #3133

Merged
merged 3 commits into from
Aug 28, 2024
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
169 changes: 169 additions & 0 deletions cypress/e2e/encryption.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import {
addUserToGroup,
createGroup,
createGroupFolder,
deleteGroupFolder,
disableEncryption,
disableEncryptionModule,
disableGroupfoldersEncryption,
disableHomeStorageEncryption,
enableEncryption,
enableEncryptionModule,
enableGroupfoldersEncryption,
enableHomeStorageEncryption,
enterFolder,
fileOrFolderExists,
PERMISSION_DELETE,
PERMISSION_READ,
PERMISSION_WRITE,
} from './groupfoldersUtils'

import {
assertFileContent,
moveFile,
} from './files/filesUtils'

import { randHash } from '../utils'

import type { User } from '@nextcloud/cypress'

describe('Groupfolders encryption behavior', () => {
let user1: User
let groupFolderId: string
let groupName: string
let groupFolderName: string

before(() => {
enableEncryptionModule()
enableEncryption()
})

beforeEach(() => {
if (groupFolderId) {
deleteGroupFolder(groupFolderId)
}
groupName = `test_group_${randHash()}`
groupFolderName = `test_group_folder_${randHash()}`

cy.createRandomUser()
.then(_user => {
user1 = _user
})
createGroup(groupName)
.then(() => {
addUserToGroup(groupName, user1.userId)
createGroupFolder(groupFolderName, groupName, [PERMISSION_READ, PERMISSION_WRITE, PERMISSION_DELETE])
})
})

after(() => {
// Restore default values
disableGroupfoldersEncryption()
enableHomeStorageEncryption()
disableEncryption()
disableEncryptionModule()
})

it('Move file from encrypted storage to encrypted groupfolder', () => {
enableHomeStorageEncryption()
enableGroupfoldersEncryption()

cy.uploadContent(user1, new Blob(['Content of the file']), 'text/plain', '/file1.txt')

cy.login(user1)
cy.visit('/apps/files')

moveFile('file1.txt', groupFolderName)

enterFolder(groupFolderName)
fileOrFolderExists('file1.txt')
assertFileContent('file1.txt', 'Content of the file')
})

it('Move file from encrypted storage to non encrypted groupfolder', () => {
enableHomeStorageEncryption()
disableGroupfoldersEncryption()

cy.uploadContent(user1, new Blob(['Content of the file']), 'text/plain', '/file1.txt')

cy.login(user1)
cy.visit('/apps/files')

moveFile('file1.txt', groupFolderName)

enterFolder(groupFolderName)
fileOrFolderExists('file1.txt')
assertFileContent('file1.txt', 'Content of the file')
})

it('Move file from non encrypted storage to encrypted groupfolder', () => {
disableHomeStorageEncryption()
enableGroupfoldersEncryption()

cy.uploadContent(user1, new Blob(['Content of the file']), 'text/plain', '/file1.txt')

cy.login(user1)
cy.visit('/apps/files')

moveFile('file1.txt', groupFolderName)

enterFolder(groupFolderName)
fileOrFolderExists('file1.txt')
assertFileContent('file1.txt', 'Content of the file')
})

it('Move file from encrypted groupfolder to encrypted storage', () => {
enableHomeStorageEncryption()
enableGroupfoldersEncryption()

cy.uploadContent(user1, new Blob(['Content of the file']), 'text/plain', `/${groupFolderName}/file1.txt`)

cy.login(user1)
cy.visit('/apps/files')

enterFolder(groupFolderName)
moveFile('file1.txt', '/')

cy.visit('/apps/files')
fileOrFolderExists('file1.txt')
assertFileContent('file1.txt', 'Content of the file')
})

it('Move file from encrypted groupfolder to non encrypted storage', () => {
disableHomeStorageEncryption()
enableGroupfoldersEncryption()

cy.uploadContent(user1, new Blob(['Content of the file']), 'text/plain', `/${groupFolderName}/file1.txt`)

cy.login(user1)
cy.visit('/apps/files')

enterFolder(groupFolderName)
moveFile('file1.txt', '/')

cy.visit('/apps/files')
fileOrFolderExists('file1.txt')
assertFileContent('file1.txt', 'Content of the file')
})

it('Move file from non encrypted groupfolder to encrypted storage', () => {
enableHomeStorageEncryption()
disableGroupfoldersEncryption()

cy.uploadContent(user1, new Blob(['Content of the file']), 'text/plain', `/${groupFolderName}/file1.txt`)

cy.login(user1)
cy.visit('/apps/files')

enterFolder(groupFolderName)
moveFile('file1.txt', '/')

cy.visit('/apps/files')
fileOrFolderExists('file1.txt')
assertFileContent('file1.txt', 'Content of the file')
})
})
8 changes: 8 additions & 0 deletions cypress/e2e/files/filesUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,11 @@ export const clickOnBreadcumbs = (label: string) => {
cy.get('[data-cy-files-content-breadcrumbs]').contains(label).click()
cy.wait('@propfind')
}

export const assertFileContent = (fileName: string, expectedContent: string) => {
cy.intercept({ method: 'GET', times: 1, url: 'remote.php/**' }).as('downloadFile')
getRowForFile(fileName).should('be.visible')
triggerActionForFile(fileName, 'download')
cy.wait('@downloadFile')
.then(({ response }) => expect(response?.body).to.equal(expectedContent))
}
33 changes: 33 additions & 0 deletions cypress/e2e/groupfoldersUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,39 @@ export function deleteGroupFolder(groupFolderId: string) {
return cy.runOccCommand(`groupfolders:delete ${groupFolderId}`)
}

export function enableEncryptionModule() {
return cy.runOccCommand('app:enable encryption')
}

export function disableEncryptionModule() {
return cy.runOccCommand('app:disable encryption')
}

export function enableEncryption() {
return cy.runOccCommand('config:app:set --value=yes core encryption_enabled')
}

export function disableEncryption() {
return cy.runOccCommand('config:app:delete core encryption_enabled')
}

export function enableHomeStorageEncryption() {
// Default value is enabled
return cy.runOccCommand('config:app:delete encryption encryptHomeStorage')
}

export function disableHomeStorageEncryption() {
return cy.runOccCommand('config:app:set --value=0 encryption encryptHomeStorage')
}

export function enableGroupfoldersEncryption() {
return cy.runOccCommand('config:app:set --value=true groupfolders enable_encryption')
}

export function disableGroupfoldersEncryption() {
return cy.runOccCommand('config:app:delete groupfolders enable_encryption')
}

export function fileOrFolderExists(name: string) {
// Make sure file list is loaded first
cy.get('[data-cy-files-list-tfoot],[data-cy-files-content-empty]').should('be.visible')
Expand Down
29 changes: 29 additions & 0 deletions lib/Mount/GroupFolderEncryptionJail.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\GroupFolders\Mount;

use OC\Files\Cache\Wrapper\CacheJail;
use OC\Files\Storage\Wrapper\Jail;

/**
* Jail with overridden behaviors specific to group folders when encryption is
* enabled.
*/
class GroupFolderEncryptionJail extends Jail {
public function getCache($path = '', $storage = null) {
if (!$storage) {
$storage = $this->getWrapperStorage();
}
// By default the Jail reuses the inner cache, but when encryption is
// enabled the storage needs to be passed to the cache so it takes into
// account the outer Encryption wrapper.
$sourceCache = $this->getWrapperStorage()->getCache($this->getUnjailedPath($path), $storage);
return new CacheJail($sourceCache, $this->rootPath);
}
}
12 changes: 8 additions & 4 deletions lib/Mount/MountProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,11 @@ public function getMount(
$cacheEntry['permissions'] &= $aclRootPermissions;
}

$baseStorage = new Jail([
'storage' => $storage,
'root' => $rootPath
]);
if ($this->enableEncryption) {
$baseStorage = new GroupFolderEncryptionJail([
'storage' => $storage,
'root' => $rootPath
]);
$quotaStorage = new GroupFolderStorage([
'storage' => $baseStorage,
'quota' => $quota,
Expand All @@ -244,6 +244,10 @@ public function getMount(
'mountOwner' => $user,
]);
} else {
$baseStorage = new Jail([
'storage' => $storage,
'root' => $rootPath
]);
$quotaStorage = new GroupFolderNoEncryptionStorage([
'storage' => $baseStorage,
'quota' => $quota,
Expand Down
7 changes: 7 additions & 0 deletions tests/stub.phpstub
Original file line number Diff line number Diff line change
Expand Up @@ -671,9 +671,15 @@ namespace OC\Files\Cache {

namespace OC\Files\Cache\Wrapper {
use OC\Files\Cache\Cache;
use OCP\Files\Cache\ICache;

class CacheWrapper extends Cache {
public function getCache(): Cache {}
}

class CacheJail extends CacheWrapper {
public function __construct(?ICache $cache, string $root, ?CacheDependencies $dependencies = null) {}
}
}

namespace OC\Files {
Expand Down Expand Up @@ -1553,6 +1559,7 @@ namespace OC\Files\Storage\Wrapper{


class Jail extends Wrapper {
protected $rootPath;
public function getUnjailedPath(string $path): string {}
public function getUnjailedStorage(): IStorage {}
}
Expand Down
Loading