Skip to content
Open
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
22 changes: 20 additions & 2 deletions apps/provisioning_api/lib/Controller/AppConfigController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\Config\BeforeAppConfigDeletedEvent;
use OCP\Config\BeforeAppConfigSetEvent;
use OCP\Config\ValueType;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Exceptions\AppConfigUnknownKeyException;
use OCP\IAppConfig;
use OCP\IGroupManager;
Expand All @@ -42,6 +45,7 @@ public function __construct(
private IManager $settingManager,
private IAppManager $appManager,
private readonly ConfigManager $configManager,
private readonly IEventDispatcher $eventDispatcher,
) {
parent::__construct($appName, $request);
}
Expand Down Expand Up @@ -108,9 +112,10 @@ public function getValue(string $app, string $key, string $defaultValue = ''): D
* @param string $app ID of the app
* @param string $key Key to update
* @param string $value New value for the key
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>|DataResponse<Http::STATUS_FORBIDDEN, array{data: array{message: string}}, array{}>
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN, array{data: array{message: string}}, array{}>
*
* 200: Value updated successfully
* 400: Value rejected
* 403: App or key is not allowed
*/
#[PasswordConfirmationRequired]
Expand All @@ -133,6 +138,12 @@ public function setValue(string $app, string $key, string $value): DataResponse
return new DataResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_FORBIDDEN);
}

$event = new BeforeAppConfigSetEvent($app, $key, $value);
$this->eventDispatcher->dispatchTyped($event);
if ($event->isRejected()) {
return new DataResponse(['data' => ['message' => $this->l10n->t('The given value was rejected')]], Http::STATUS_BAD_REQUEST);
}

$type = null;

// checking expected type from lexicon
Expand Down Expand Up @@ -166,9 +177,10 @@ public function setValue(string $app, string $key, string $value): DataResponse
*
* @param string $app ID of the app
* @param string $key Key to delete
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>|DataResponse<Http::STATUS_FORBIDDEN, array{data: array{message: string}}, array{}>
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN, array{data: array{message: string}}, array{}>
*
* 200: Key deleted successfully
* 400: Deletion rejected
* 403: App or key is not allowed
*/
#[PasswordConfirmationRequired]
Expand All @@ -180,6 +192,12 @@ public function deleteKey(string $app, string $key): DataResponse {
return new DataResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_FORBIDDEN);
}

$event = new BeforeAppConfigDeletedEvent($app, $key);
$this->eventDispatcher->dispatchTyped($event);
if ($event->isRejected()) {
return new DataResponse(['data' => ['message' => $this->l10n->t('Deleting the given key was rejected')]], Http::STATUS_BAD_REQUEST);
}

$this->appConfig->deleteKey($app, $key);
return new DataResponse();
}
Expand Down
46 changes: 46 additions & 0 deletions apps/provisioning_api/openapi-administration.json
Original file line number Diff line number Diff line change
Expand Up @@ -2605,6 +2605,52 @@
}
}
},
"400": {
"description": "Deletion rejected",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"type": "object",
"required": [
"data"
],
"properties": {
"data": {
"type": "object",
"required": [
"message"
],
"properties": {
"message": {
"type": "string"
}
}
}
}
}
}
}
}
}
}
}
},
"403": {
"description": "App or key is not allowed",
"content": {
Expand Down
92 changes: 92 additions & 0 deletions apps/provisioning_api/openapi-full.json
Original file line number Diff line number Diff line change
Expand Up @@ -2911,6 +2911,52 @@
}
}
},
"400": {
"description": "Deletion rejected",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"type": "object",
"required": [
"data"
],
"properties": {
"data": {
"type": "object",
"required": [
"message"
],
"properties": {
"message": {
"type": "string"
}
}
}
}
}
}
}
}
}
}
}
},
"403": {
"description": "App or key is not allowed",
"content": {
Expand Down Expand Up @@ -3105,6 +3151,52 @@
}
}
},
"400": {
"description": "Value rejected",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"type": "object",
"required": [
"data"
],
"properties": {
"data": {
"type": "object",
"required": [
"message"
],
"properties": {
"message": {
"type": "string"
}
}
}
}
}
}
}
}
}
}
}
},
"403": {
"description": "App or key is not allowed",
"content": {
Expand Down
46 changes: 46 additions & 0 deletions apps/provisioning_api/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -4010,6 +4010,52 @@
}
}
},
"400": {
"description": "Value rejected",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {
"type": "object",
"required": [
"data"
],
"properties": {
"data": {
"type": "object",
"required": [
"message"
],
"properties": {
"message": {
"type": "string"
}
}
}
}
}
}
}
}
}
}
}
},
"403": {
"description": "App or key is not allowed",
"content": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
use OCP\App\IAppManager;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\Config\BeforeAppConfigDeletedEvent;
use OCP\Config\BeforeAppConfigSetEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Exceptions\AppConfigUnknownKeyException;
use OCP\IAppConfig;
use OCP\IGroupManager;
Expand Down Expand Up @@ -41,6 +44,7 @@ class AppConfigControllerTest extends TestCase {
private IGroupManager&MockObject $groupManager;
private IAppManager $appManager;
private ConfigManager $configManager;
private IEventDispatcher&MockObject $eventDispatcher;

protected function setUp(): void {
parent::setUp();
Expand All @@ -52,6 +56,7 @@ protected function setUp(): void {
$this->groupManager = $this->createMock(IGroupManager::class);
$this->appManager = Server::get(IAppManager::class);
$this->configManager = Server::get(ConfigManager::class);
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
}

/**
Expand All @@ -72,6 +77,7 @@ protected function getInstance(array $methods = []) {
$this->settingManager,
$this->appManager,
$this->configManager,
$this->eventDispatcher,
);
} else {
return $this->getMockBuilder(AppConfigController::class)
Expand All @@ -85,6 +91,7 @@ protected function getInstance(array $methods = []) {
$this->settingManager,
$this->appManager,
$this->configManager,
$this->eventDispatcher,
])
->onlyMethods($methods)
->getMock();
Expand Down Expand Up @@ -339,6 +346,45 @@ public function testDeleteValue(string $app, string $key, ?\Throwable $appThrows
}
}

public function testSetValueRejected(): void {
$adminUser = $this->createMock(IUser::class);
$adminUser->method('getUid')
->willReturn('admin');
$this->userSession->method('getUser')
->willReturn($adminUser);
$this->groupManager->method('isAdmin')
->with('admin')
->willReturn(true);
$this->eventDispatcher->expects($this->once())
->method('dispatchTyped')
->willReturnCallback(function (BeforeAppConfigSetEvent $event): void {
$this->assertSame('app1', $event->getAppId());
$this->assertSame('key', $event->getConfigKey());
$this->assertSame('value', $event->getConfigValue());
$event->setValid(false);
});
$this->appConfig->expects($this->never())
->method('setValueMixed');

$result = $this->getInstance(['verifyAppId', 'verifyConfigKey'])->setValue('app1', 'key', 'value');
$this->assertSame(Http::STATUS_BAD_REQUEST, $result->getStatus());
}

public function testDeleteValueRejected(): void {
$this->eventDispatcher->expects($this->once())
->method('dispatchTyped')
->willReturnCallback(function (BeforeAppConfigDeletedEvent $event): void {
$this->assertSame('app1', $event->getAppId());
$this->assertSame('key', $event->getConfigKey());
$event->setValid(false);
});
$this->appConfig->expects($this->never())
->method('deleteKey');

$result = $this->getInstance(['verifyAppId', 'verifyConfigKey'])->deleteKey('app1', 'key');
$this->assertSame(Http::STATUS_BAD_REQUEST, $result->getStatus());
}

public function testVerifyAppId(): void {
$api = $this->getInstance();
$this->invokePrivate($api, 'verifyAppId', ['activity']);
Expand Down
2 changes: 2 additions & 0 deletions core/Command/Config/App/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
namespace OC\Core\Command\Config\App;

use OC\Config\ConfigManager;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IAppConfig;
use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;

abstract class Base extends \OC\Core\Command\Base {
public function __construct(
protected IAppConfig $appConfig,
protected readonly ConfigManager $configManager,
protected readonly IEventDispatcher $eventDispatcher,
) {
parent::__construct();
}
Expand Down
Loading
Loading