Skip to content
Draft
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
28 changes: 28 additions & 0 deletions config/config.sample.php
Original file line number Diff line number Diff line change
Expand Up @@ -1824,6 +1824,34 @@
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET wait_timeout = 28800'
],

/**
* Allows defining custom DB types and options as well as the ability to override
* the default connection parameters as defined by
* OC\DB\ConnectionFactory::defaultConnectionParams.
*/
'dbconnectionparams' => [
'dbtype' => [
'adapter' => AdapterMySQL::class,
'charset' => 'UTF8',
'driver' => 'pdo_dbtype',
'wrapperClass' => Doctrine\DBAL\Connection::class,
],
],

/**
* Allows additional configuration options to be provided for the database
* connection as defined by Doctrine\DBAL\Configuration::class. This is useful
* for specifying a custom logger, middlewares, etc.
*/
'dbconfigurationparams' => [
"sqllogger" => 'Doctrine\DBAL\Logging\SQLLogger',
"resultcache" => 'Psr\Cache\CacheItemPoolInterface',
"schemaassetsfilter" => 'callable',
"autocommit" => true,
"middlewares" => array(
'Doctrine\DBAL\Driver\Middleware',
),
],
/**
* sqlite3 journal mode can be specified using this configuration parameter -
* can be 'WAL' or 'DELETE' see for more details https://www.sqlite.org/wal.html
Expand Down
51 changes: 47 additions & 4 deletions lib/private/AppFramework/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,15 @@
use OC\AppFramework\DependencyInjection\DIContainer;
use OC\AppFramework\Http\Dispatcher;
use OC\AppFramework\Http\Request;
use OCP\App\IAppManager;
use OCP\Profiler\IProfiler;
use OC\Profiler\RoutingDataCollector;
use OCP\AppFramework\QueryException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\ICallbackResponse;
use OCP\AppFramework\Http\IOutput;
use OCP\AppFramework\QueryException;
use OCP\Diagnostics\IEventLogger;
use OCP\HintException;
use OCP\IRequest;
use OCP\Profiler\IProfiler;

/**
* Entry point for every request in your app. You can consider this as your
Expand All @@ -69,7 +68,7 @@ public static function buildAppNamespace(string $appId, string $topNamespace = '
return $topNamespace . self::$nameSpaceCache[$appId];
}

$appInfo = \OCP\Server::get(IAppManager::class)->getAppInfo($appId);
$appInfo = self::getAppInfo($appId);
if (isset($appInfo['namespace'])) {
self::$nameSpaceCache[$appId] = trim($appInfo['namespace']);
} else {
Expand All @@ -91,11 +90,42 @@ public static function buildAppNamespace(string $appId, string $topNamespace = '
return $topNamespace . self::$nameSpaceCache[$appId];
}

public static function getAppInfo(string $appId, bool $path = false, $lang = null) {
if ($path) {
$file = $appId;
} else {
$dir = \OC_App::findAppInDirectories($appId);

if ($dir === false) {
return null;
}

$appPath = $dir['path'] . '/' . $appId;
$file = $appPath . '/appinfo/info.xml';
}

$parser = new \OC\App\InfoParser();
$data = $parser->parse($file);

if (is_array($data)) {
$data = \OC_App::parseAppInfo($data, $lang);
}

return $data;
}

public static function getAppIdForClass(string $className, string $topNamespace = 'OCA\\'): ?string {
if (!str_starts_with($className, $topNamespace)) {
return null;
}

if (str_starts_with($className, $topNamespace)) {
$classNoTopNamespace = substr($className, strlen($topNamespace));
$appNameParts = explode('\\', $classNoTopNamespace, 2);
$appName = reset($appNameParts);
return strtolower($appName);
}

foreach (self::$nameSpaceCache as $appId => $namespace) {
if (str_starts_with($className, $topNamespace . $namespace . '\\')) {
return $appId;
Expand All @@ -105,6 +135,19 @@ public static function getAppIdForClass(string $className, string $topNamespace
return null;
}

public static function registerAppClass(string $className): void {
$classParts = explode('\\', $className, 2);
$topNamespace = reset($classParts) . '\\';
$appId = self::getAppIdForClass($className, $topNamespace);
$dir = \OC_App::findAppInDirectories($appId);

if ($dir === false) {
throw new \OCP\App\AppPathNotFoundException('App not found in any app directory');
}

$appPath = $dir['path'] . '/' . $appId;
\OC_App::registerAutoloading($appId, $appPath);
}

/**
* Shortcut for calling a controller method and printing the result
Expand Down
49 changes: 48 additions & 1 deletion lib/private/DB/ConnectionFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Event\Listeners\OracleSessionInit;
use Doctrine\DBAL\Event\Listeners\SQLSessionInit;
use OC\AppFramework\App;
use OC\SystemConfig;

/**
Expand Down Expand Up @@ -93,6 +94,21 @@ public function __construct(SystemConfig $systemConfig) {
if ($collationOverride) {
$this->defaultConnectionParams['mysql']['collation'] = $collationOverride;
}

$connectionParams = $this->config->getValue('dbconnectionparams', array()) ?: array();

foreach ($connectionParams as $type) {
foreach ($type as $key => $param) {
switch ($key) {
case 'adapter':
case 'wrapperClass':
\OC::$server->get(App::class)::registerAppClass($param);
break;
}
}
}

$this->defaultConnectionParams = array_replace_recursive($this->defaultConnectionParams, $connectionParams);
}

/**
Expand Down Expand Up @@ -158,9 +174,40 @@ public function getConnection($type, $additionalConnectionParams) {
break;
}
/** @var Connection $connection */
$configuration = new Configuration();

foreach ($this->config->getValue('dbconfigurationparams', array()) as $param => $value) {
switch ($param) {
case "sqllogger":
\OC::$server->get(App::class)::registerAppClass($value);
$configuration->setSQLLogger(new $value());

Check failure

Code scanning / Psalm

TaintedCallable

Detected tainted text

Check failure

Code scanning / Psalm

TaintedCallable

Detected tainted text
break;
case "resultcache":
\OC::$server->get(App::class)::registerAppClass($value);
$configuration->setResultCache(new $value());

Check failure

Code scanning / Psalm

TaintedCallable

Detected tainted text

Check failure

Code scanning / Psalm

TaintedCallable

Detected tainted text
break;
case "schemaassetsfilter":
$configuration->setSchemaAssetsFilter($value);
break;
case "autocommit":
$configuration->setAutoCommit($value);
break;
case "middlewares":
$middlewares = array();

foreach ($value as $middleware) {
\OC::$server->get(App::class)::registerAppClass($middleware);
array_push($middlewares, new $middleware());

Check failure

Code scanning / Psalm

TaintedCallable

Detected tainted text
}

$configuration->setMiddlewares($value);
break;
}
}

$connection = DriverManager::getConnection(
array_merge($this->getDefaultConnectionParams($type), $additionalConnectionParams),
new Configuration(),
$configuration,
$eventManager
);
return $connection;
Expand Down
2 changes: 1 addition & 1 deletion lib/private/legacy/OC_App.php
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ public static function getInstallPath() {
*
* @param string $appId
* @param bool $ignoreCache ignore cache and rebuild it
* @return false|string
* @return false|array
*/
public static function findAppInDirectories(string $appId, bool $ignoreCache = false) {
$sanitizedAppId = self::cleanAppId($appId);
Expand Down