aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorCôme Chilliet <come.chilliet@nextcloud.com>2025-02-17 18:06:45 +0100
committerCôme Chilliet <come.chilliet@nextcloud.com>2025-02-17 18:08:23 +0100
commite757b649b7b6415ae5f77e59b5160052896b2c21 (patch)
tree21f63c87b66d8f316c5c2166e58dfb547db79b65 /apps
parent9edabfa21fa7e587c0ad95d2d230d215b060ade0 (diff)
downloadnextcloud-server-e757b649b7b6415ae5f77e59b5160052896b2c21.tar.gz
nextcloud-server-e757b649b7b6415ae5f77e59b5160052896b2c21.zip
fix: Fix psalm taint false-positives by small refactoringsfix/fix-psalm-taint-errors-2
Mostly make it clear that we trust admin input or that we correctly escape strings. Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
Diffstat (limited to 'apps')
-rw-r--r--apps/files_external/lib/Config/ConfigAdapter.php18
-rw-r--r--apps/provisioning_api/lib/Controller/AppsController.php27
-rw-r--r--apps/theming/lib/Util.php7
3 files changed, 45 insertions, 7 deletions
diff --git a/apps/files_external/lib/Config/ConfigAdapter.php b/apps/files_external/lib/Config/ConfigAdapter.php
index c84fbb19102..db53c8cf6c9 100644
--- a/apps/files_external/lib/Config/ConfigAdapter.php
+++ b/apps/files_external/lib/Config/ConfigAdapter.php
@@ -40,6 +40,19 @@ class ConfigAdapter implements IMountProvider {
}
/**
+ * @param class-string $class
+ * @return class-string<IObjectStore>
+ * @throws \InvalidArgumentException
+ * @psalm-taint-escape callable
+ */
+ private function validateObjectStoreClassString(string $class): string {
+ if (!\is_subclass_of($class, IObjectStore::class)) {
+ throw new \InvalidArgumentException('Invalid object store');
+ }
+ return $class;
+ }
+
+ /**
* Process storage ready for mounting
*
* @throws QueryException
@@ -51,10 +64,7 @@ class ConfigAdapter implements IMountProvider {
$objectStore = $storage->getBackendOption('objectstore');
if ($objectStore) {
- $objectClass = $objectStore['class'];
- if (!is_subclass_of($objectClass, IObjectStore::class)) {
- throw new \InvalidArgumentException('Invalid object store');
- }
+ $objectClass = $this->validateObjectStoreClassString($objectStore['class']);
$storage->setBackendOption('objectstore', new $objectClass($objectStore));
}
diff --git a/apps/provisioning_api/lib/Controller/AppsController.php b/apps/provisioning_api/lib/Controller/AppsController.php
index 04dfd8f29b1..4d32584591b 100644
--- a/apps/provisioning_api/lib/Controller/AppsController.php
+++ b/apps/provisioning_api/lib/Controller/AppsController.php
@@ -28,6 +28,17 @@ class AppsController extends OCSController {
}
/**
+ * @throws \InvalidArgumentException
+ */
+ protected function verifyAppId(string $app): string {
+ $cleanId = $this->appManager->cleanAppId($app);
+ if ($cleanId !== $app) {
+ throw new \InvalidArgumentException('Invalid app id given');
+ }
+ return $cleanId;
+ }
+
+ /**
* Get a list of installed apps
*
* @param ?string $filter Filter for enabled or disabled apps
@@ -71,6 +82,11 @@ class AppsController extends OCSController {
* 200: App info returned
*/
public function getAppInfo(string $app): DataResponse {
+ try {
+ $app = $this->verifyAppId($app);
+ } catch (\InvalidArgumentException $e) {
+ throw new OCSException($e->getMessage(), OCSController::RESPOND_UNAUTHORISED);
+ }
$info = $this->appManager->getAppInfo($app);
if (!is_null($info)) {
return new DataResponse($info);
@@ -91,7 +107,10 @@ class AppsController extends OCSController {
#[PasswordConfirmationRequired]
public function enable(string $app): DataResponse {
try {
+ $app = $this->verifyAppId($app);
$this->appManager->enableApp($app);
+ } catch (\InvalidArgumentException $e) {
+ throw new OCSException($e->getMessage(), OCSController::RESPOND_UNAUTHORISED);
} catch (AppPathNotFoundException $e) {
throw new OCSException('The request app was not found', OCSController::RESPOND_NOT_FOUND);
}
@@ -103,12 +122,18 @@ class AppsController extends OCSController {
*
* @param string $app ID of the app
* @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
+ * @throws OCSException
*
* 200: App disabled successfully
*/
#[PasswordConfirmationRequired]
public function disable(string $app): DataResponse {
- $this->appManager->disableApp($app);
+ try {
+ $app = $this->verifyAppId($app);
+ $this->appManager->disableApp($app);
+ } catch (\InvalidArgumentException $e) {
+ throw new OCSException($e->getMessage(), OCSController::RESPOND_UNAUTHORISED);
+ }
return new DataResponse();
}
}
diff --git a/apps/theming/lib/Util.php b/apps/theming/lib/Util.php
index c4e1c6b2107..b7022dae8b9 100644
--- a/apps/theming/lib/Util.php
+++ b/apps/theming/lib/Util.php
@@ -197,7 +197,7 @@ class Util {
* @return string|ISimpleFile path to app icon / file of logo
*/
public function getAppIcon($app) {
- $app = str_replace(['\0', '/', '\\', '..'], '', $app);
+ $app = $this->appManager->cleanAppId($app);
try {
$appPath = $this->appManager->getAppPath($app);
$icon = $appPath . '/img/' . $app . '.svg';
@@ -228,7 +228,10 @@ class Util {
* @return string|false absolute path to image
*/
public function getAppImage($app, $image) {
- $app = str_replace(['\0', '/', '\\', '..'], '', $app);
+ $app = $this->appManager->cleanAppId($app);
+ /**
+ * @psalm-taint-escape file
+ */
$image = str_replace(['\0', '\\', '..'], '', $image);
if ($app === 'core') {
$icon = \OC::$SERVERROOT . '/core/img/' . $image;