Skip to content
24 changes: 5 additions & 19 deletions lib/private/AppFramework/DependencyInjection/DIContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -313,23 +313,11 @@ protected function query(string $name, bool $autoload = true, array $chain = [])
return $this->appName;
}

$isServerClass = str_starts_with($name, 'OCP\\') || str_starts_with($name, 'OC\\');
if ($isServerClass && !$this->has($name)) {
return $this->server->query($name, $autoload, $chain);
}

try {
return $this->queryNoFallback($name, $chain);
} catch (QueryException $firstException) {
try {
return $this->server->query($name, $autoload, $chain);
} catch (QueryException $secondException) {
if ($firstException->getCode() === 1) {
throw $secondException;
}
throw $firstException;
}
$result = $this->queryNoFallback($name, $chain);
if ($result !== null) {
return $result;
}
return $this->server->query($name, $autoload, $chain);
}

/**
Expand All @@ -353,8 +341,6 @@ public function queryNoFallback($name, array $chain) {
/* AppFramework services are scoped to the application */
return parent::query($name, chain: $chain);
}

throw new QueryException('Could not resolve ' . $name . '!'
. ' Class can not be instantiated', 1);
return null;
}
}
29 changes: 19 additions & 10 deletions lib/private/AppFramework/Utility/SimpleContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@

protected Container $container;

/** @var array<string,string> */
private array $aliases = [];

public function __construct() {
$this->container = new Container();
}
Expand All @@ -43,13 +46,13 @@
*/
#[\Override]
public function get(string $id): mixed {
return $this->query($this->sanitizeName($id));
return $this->query($this->resolveAlias($this->sanitizeName($id)));
}

#[\Override]
public function has(string $id): bool {
// If a service is no registered but is an existing class, we can probably load it
return isset($this->container[$id]) || class_exists($id);
return isset($this->aliases[$id]) || isset($this->container[$id]) || class_exists($id);
}

/**
Expand Down Expand Up @@ -93,7 +96,7 @@
try {
$builtIn = $parameterType !== null && ($parameterType instanceof ReflectionNamedType)
&& $parameterType->isBuiltin();
return $this->query($resolveName, !$builtIn, $chain);
return $this->query($this->resolveAlias($resolveName), !$builtIn, $chain);
} catch (ContainerExceptionInterface $e) {
// Service not found, use the default value when available
if ($parameter->isDefaultValueAvailable()) {
Expand All @@ -103,7 +106,7 @@
if ($parameterType !== null && ($parameterType instanceof ReflectionNamedType) && !$parameterType->isBuiltin()) {
$resolveName = $parameter->getName();
try {
return $this->query($resolveName, chain: $chain);
return $this->query($this->resolveAlias($resolveName), chain: $chain);
} catch (ContainerExceptionInterface $e2) {
// Pass null if typed and nullable
if ($parameter->allowsNull() && ($parameterType instanceof ReflectionNamedType)) {
Expand Down Expand Up @@ -134,7 +137,7 @@
public function resolve(string $name, array $chain = []): mixed {
$baseMsg = 'Could not resolve ' . $name . '!';
try {
$class = new ReflectionClass($name);

Check failure on line 140 in lib/private/AppFramework/Utility/SimpleContainer.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-security

TaintedCallable

lib/private/AppFramework/Utility/SimpleContainer.php:140:33: TaintedCallable: Detected tainted text (see https://psalm.dev/243)
if ($class->isInstantiable()) {
return $this->buildClass($class, $chain);
} else {
Expand All @@ -148,7 +151,7 @@
}

/**
* @param string $name Already sanitized name
* @param string $name Already sanitized name and alias resolved
* @param list<class-string> $chain
*/
protected function query(string $name, bool $autoload = true, array $chain = []): mixed {
Expand Down Expand Up @@ -195,6 +198,9 @@
if (isset($this->container[$name])) {
unset($this->container[$name]);
}
if (isset($this->aliases[$name])) {
unset($this->aliases[$name]);
}
if ($shared) {
$this->container[$name] = $wrapped;
} else {
Expand All @@ -210,11 +216,14 @@
* @param string $target the target that should be resolved instead
*/
public function registerAlias(string $alias, string $target): void {
$this->registerService(
$alias,
static fn (ContainerInterface $container): mixed => $container->get($target),
false,
);
$this->aliases[$alias] = $target;
}

protected function resolveAlias(string $name) : string {
if (isset($this->aliases[$name])) {
return $this->resolveAlias($this->aliases[$name]);
}
return $name;
}

protected function registerDeprecatedAlias(string $alias, string $target): void {
Expand Down
21 changes: 7 additions & 14 deletions lib/private/ServerContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
$applicationClassName = $sensitiveNamespace . '\\AppInfo\\Application';
if (class_exists($applicationClassName)) {
/* The application constructor will register the container, see App::__construct */
$app = new $applicationClassName();

Check failure on line 90 in lib/private/ServerContainer.php

View workflow job for this annotation

GitHub Actions / static-code-analysis-security

TaintedCallable

lib/private/ServerContainer.php:90:17: TaintedCallable: Detected tainted text (see https://psalm.dev/243)
if (isset($this->appContainers[$namespace])) {
$this->appContainers[$namespace]->offsetSet($applicationClassName, $app);
/** @psalm-suppress NoValue false-positive (see comment above) */
Expand Down Expand Up @@ -124,22 +124,15 @@
#[\Override]
protected function query(string $name, bool $autoload = true, array $chain = []): mixed {
if (str_starts_with($name, 'OCA\\')) {
// Skip server container query for app namespace classes
if (isset($this->container[$name])) {
return $this->container[$name];
}
// Continue with general autoloading
// In case the service starts with OCA\ we try to find the service in
// the apps container first.
// In case the service starts with OCA\ we try to find the service in the apps container.
if (($appContainer = $this->getAppContainerForService($name)) !== null) {
try {
return $appContainer->queryNoFallback($name, $chain);
} catch (QueryException $e) {
// Didn't find the service or the respective app container
// In this case the service won't be part of the core container,
// so we can throw directly
throw $e;
return $appContainer->queryNoFallback($name, $chain);
$result = $appContainer->queryNoFallback($name, $chain);
if ($result !== null) {
return $result;
}
throw new QueryException('Could not resolve ' . $name . '!'
. ' Class can not be instantiated', 1);
}
}

Expand Down
Loading