feat: Add new forbidden filename options to Capabilities

Allow clients to access the new filename validation options
and make frontend name validation possible.

Co-authored-by: Ferdinand Thiessen <opensource@fthiessen.de>
Co-authored-by: Kate <26026535+provokateurin@users.noreply.github.com>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
pull/46414/head
Ferdinand Thiessen 2024-07-10 16:59:26 +07:00
parent b09347ae53
commit a229723b8c
No known key found for this signature in database
GPG Key ID: 45FAE7268762B400
7 changed files with 50 additions and 14 deletions

@ -7,28 +7,31 @@
*/ */
namespace OCA\Files; namespace OCA\Files;
use OC\Files\FilenameValidator;
use OCP\Capabilities\ICapability; use OCP\Capabilities\ICapability;
use OCP\IConfig;
class Capabilities implements ICapability { class Capabilities implements ICapability {
protected IConfig $config; public function __construct(
protected FilenameValidator $filenameValidator,
public function __construct(IConfig $config) { ) {
$this->config = $config;
} }
/** /**
* Return this classes capabilities * Return this classes capabilities
* *
* @return array{files: array{bigfilechunking: bool, blacklisted_files: array<mixed>, forbidden_filename_characters: array<string>}} * @return array{files: array{'$comment': ?string, bigfilechunking: bool, blacklisted_files: array<mixed>, forbidden_filenames: list<string>, forbidden_filename_characters: list<string>, forbidden_filename_extensions: list<string>}}
*/ */
public function getCapabilities() { public function getCapabilities(): array {
return [ return [
'files' => [ 'files' => [
'$comment' => '"blacklisted_files" is deprecated as of Nextcloud 30, use "forbidden_filenames" instead',
'blacklisted_files' => $this->filenameValidator->getForbiddenFilenames(),
'forbidden_filenames' => $this->filenameValidator->getForbiddenFilenames(),
'forbidden_filename_characters' => $this->filenameValidator->getForbiddenCharacters(),
'forbidden_filename_extensions' => $this->filenameValidator->getForbiddenExtensions(),
'bigfilechunking' => true, 'bigfilechunking' => true,
'blacklisted_files' => (array)$this->config->getSystemValue('blacklisted_files', ['.htaccess']),
'forbidden_filename_characters' => \OCP\Util::getForbiddenFileNameChars(),
], ],
]; ];
} }

@ -29,12 +29,19 @@
"files": { "files": {
"type": "object", "type": "object",
"required": [ "required": [
"$comment",
"bigfilechunking", "bigfilechunking",
"blacklisted_files", "blacklisted_files",
"forbidden_filenames",
"forbidden_filename_characters", "forbidden_filename_characters",
"forbidden_filename_extensions",
"directEditing" "directEditing"
], ],
"properties": { "properties": {
"$comment": {
"type": "string",
"nullable": true
},
"bigfilechunking": { "bigfilechunking": {
"type": "boolean" "type": "boolean"
}, },
@ -44,12 +51,24 @@
"type": "object" "type": "object"
} }
}, },
"forbidden_filenames": {
"type": "array",
"items": {
"type": "string"
}
},
"forbidden_filename_characters": { "forbidden_filename_characters": {
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
} }
}, },
"forbidden_filename_extensions": {
"type": "array",
"items": {
"type": "string"
}
},
"directEditing": { "directEditing": {
"type": "object", "type": "object",
"required": [ "required": [

@ -22,7 +22,9 @@ class CapabilitiesContext implements Context, SnippetAcceptingContext {
* @param \Behat\Gherkin\Node\TableNode|null $formData * @param \Behat\Gherkin\Node\TableNode|null $formData
*/ */
public function checkCapabilitiesResponse(\Behat\Gherkin\Node\TableNode $formData) { public function checkCapabilitiesResponse(\Behat\Gherkin\Node\TableNode $formData) {
$capabilitiesXML = simplexml_load_string($this->response->getBody())->data->capabilities; $capabilitiesXML = simplexml_load_string($this->response->getBody());
Assert::assertNotFalse($capabilitiesXML, 'Failed to fetch capabilities');
$capabilitiesXML = $capabilitiesXML->data->capabilities;
foreach ($formData->getHash() as $row) { foreach ($formData->getHash() as $row) {
$path_to_element = explode('@@@', $row['path_to_element']); $path_to_element = explode('@@@', $row['path_to_element']);

@ -8,6 +8,7 @@ namespace OC\Core\Controller;
use bantu\IniGetWrapper\IniGetWrapper; use bantu\IniGetWrapper\IniGetWrapper;
use OC\Authentication\Token\IProvider; use OC\Authentication\Token\IProvider;
use OC\CapabilitiesManager; use OC\CapabilitiesManager;
use OC\Files\FilenameValidator;
use OC\Template\JSConfigHelper; use OC\Template\JSConfigHelper;
use OCP\App\IAppManager; use OCP\App\IAppManager;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
@ -44,6 +45,7 @@ class OCJSController extends Controller {
CapabilitiesManager $capabilitiesManager, CapabilitiesManager $capabilitiesManager,
IInitialStateService $initialStateService, IInitialStateService $initialStateService,
IProvider $tokenProvider, IProvider $tokenProvider,
FilenameValidator $filenameValidator,
) { ) {
parent::__construct($appName, $request); parent::__construct($appName, $request);
@ -59,7 +61,8 @@ class OCJSController extends Controller {
$urlGenerator, $urlGenerator,
$capabilitiesManager, $capabilitiesManager,
$initialStateService, $initialStateService,
$tokenProvider $tokenProvider,
$filenameValidator,
); );
} }

@ -133,7 +133,9 @@ abstract class BaseResponse extends Response {
$v = []; $v = [];
} }
if (\is_array($v)) { if ($k === '$comment') {
$writer->writeComment($v);
} elseif (\is_array($v)) {
$writer->startElement($k); $writer->startElement($k);
$this->toXML($v, $writer); $this->toXML($v, $writer);
$writer->endElement(); $writer->endElement();

@ -10,6 +10,7 @@ namespace OC\Template;
use bantu\IniGetWrapper\IniGetWrapper; use bantu\IniGetWrapper\IniGetWrapper;
use OC\Authentication\Token\IProvider; use OC\Authentication\Token\IProvider;
use OC\CapabilitiesManager; use OC\CapabilitiesManager;
use OC\Files\FilenameValidator;
use OC\Share\Share; use OC\Share\Share;
use OCP\App\AppPathNotFoundException; use OCP\App\AppPathNotFoundException;
use OCP\App\IAppManager; use OCP\App\IAppManager;
@ -51,6 +52,7 @@ class JSConfigHelper {
protected CapabilitiesManager $capabilitiesManager, protected CapabilitiesManager $capabilitiesManager,
protected IInitialStateService $initialStateService, protected IInitialStateService $initialStateService,
protected IProvider $tokenProvider, protected IProvider $tokenProvider,
protected FilenameValidator $filenameValidator,
) { ) {
} }
@ -132,9 +134,12 @@ class JSConfigHelper {
$capabilities = $this->capabilitiesManager->getCapabilities(false, true); $capabilities = $this->capabilitiesManager->getCapabilities(false, true);
$config = [ $config = [
'auto_logout' => $this->config->getSystemValue('auto_logout', false), /** @deprecated 30.0.0 - use files capabilities instead */
'blacklist_files_regex' => FileInfo::BLACKLIST_FILES_REGEX, 'blacklist_files_regex' => FileInfo::BLACKLIST_FILES_REGEX,
'forbidden_filename_characters' => Util::getForbiddenFileNameChars(), /** @deprecated 30.0.0 - use files capabilities instead */
'forbidden_filename_characters' => $this->filenameValidator->getForbiddenCharacters(),
'auto_logout' => $this->config->getSystemValue('auto_logout', false),
'loglevel' => $this->config->getSystemValue('loglevel_frontend', 'loglevel' => $this->config->getSystemValue('loglevel_frontend',
$this->config->getSystemValue('loglevel', ILogger::WARN) $this->config->getSystemValue('loglevel', ILogger::WARN)
), ),

@ -9,6 +9,7 @@ namespace OC;
use bantu\IniGetWrapper\IniGetWrapper; use bantu\IniGetWrapper\IniGetWrapper;
use OC\Authentication\Token\IProvider; use OC\Authentication\Token\IProvider;
use OC\Files\FilenameValidator;
use OC\Search\SearchQuery; use OC\Search\SearchQuery;
use OC\Template\CSSResourceLocator; use OC\Template\CSSResourceLocator;
use OC\Template\JSConfigHelper; use OC\Template\JSConfigHelper;
@ -228,6 +229,7 @@ class TemplateLayout extends \OC_Template {
\OC::$server->get(CapabilitiesManager::class), \OC::$server->get(CapabilitiesManager::class),
\OCP\Server::get(IInitialStateService::class), \OCP\Server::get(IInitialStateService::class),
\OCP\Server::get(IProvider::class), \OCP\Server::get(IProvider::class),
\OCP\Server::get(FilenameValidator::class),
); );
$config = $jsConfigHelper->getConfig(); $config = $jsConfigHelper->getConfig();
if (\OC::$server->getContentSecurityPolicyNonceManager()->browserSupportsCspV3()) { if (\OC::$server->getContentSecurityPolicyNonceManager()->browserSupportsCspV3()) {