File manager - Edit - /home/jardides/www/Jardi-design/images/administrator/Command.tar
Back
Status.php 0000604 00000003005 15247207135 0006540 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Bart Visscher <bartv@thisnet.nl> * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class Status extends Base { protected function configure() { parent::configure(); $this ->setName('status') ->setDescription('show some status information') ; } protected function execute(InputInterface $input, OutputInterface $output) { $values = array( 'installed' => (bool) \OC::$server->getConfig()->getSystemValue('installed', false), 'version' => implode('.', \OCP\Util::getVersion()), 'versionstring' => \OC_Util::getVersionString(), 'edition' => '', ); $this->writeArrayInOutputFormat($input, $output, $values); } } Config/ListConfigs.php 0000604 00000007703 15247207135 0010717 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Config; use OC\Core\Command\Base; use OC\SystemConfig; use OCP\IAppConfig; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class ListConfigs extends Base { protected $defaultOutputFormat = self::OUTPUT_FORMAT_JSON_PRETTY; /** * @var SystemConfig */ protected $systemConfig; /** @var IAppConfig */ protected $appConfig; /** * @param SystemConfig $systemConfig * @param IAppConfig $appConfig */ public function __construct(SystemConfig $systemConfig, IAppConfig $appConfig) { parent::__construct(); $this->systemConfig = $systemConfig; $this->appConfig = $appConfig; } protected function configure() { parent::configure(); $this ->setName('config:list') ->setDescription('List all configs') ->addArgument( 'app', InputArgument::OPTIONAL, 'Name of the app ("system" to get the config.php values, "all" for all apps and system)', 'all' ) ->addOption( 'private', null, InputOption::VALUE_NONE, 'Use this option when you want to include sensitive configs like passwords, salts, ...' ) ; } protected function execute(InputInterface $input, OutputInterface $output) { $app = $input->getArgument('app'); $noSensitiveValues = !$input->getOption('private'); switch ($app) { case 'system': $configs = [ 'system' => $this->getSystemConfigs($noSensitiveValues), ]; break; case 'all': $apps = $this->appConfig->getApps(); $configs = [ 'system' => $this->getSystemConfigs($noSensitiveValues), 'apps' => [], ]; foreach ($apps as $appName) { $configs['apps'][$appName] = $this->getAppConfigs($appName, $noSensitiveValues); } break; default: $configs = [ 'apps' => [ $app => $this->getAppConfigs($app, $noSensitiveValues), ], ]; } $this->writeArrayInOutputFormat($input, $output, $configs); } /** * Get the system configs * * @param bool $noSensitiveValues * @return array */ protected function getSystemConfigs($noSensitiveValues) { $keys = $this->systemConfig->getKeys(); $configs = []; foreach ($keys as $key) { if ($noSensitiveValues) { $value = $this->systemConfig->getFilteredValue($key, serialize(null)); } else { $value = $this->systemConfig->getValue($key, serialize(null)); } if ($value !== 'N;') { $configs[$key] = $value; } } return $configs; } /** * Get the app configs * * @param string $app * @param bool $noSensitiveValues * @return array */ protected function getAppConfigs($app, $noSensitiveValues) { if ($noSensitiveValues) { return $this->appConfig->getFilteredValues($app, false); } else { return $this->appConfig->getValues($app, false); } } /** * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'app') { return array_merge(['all', 'system'], \OC_App::getAllApps()); } return []; } } Config/System/GetConfig.php 0000604 00000005633 15247207135 0011624 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Config\System; use OC\SystemConfig; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class GetConfig extends Base { /** * @var SystemConfig */ protected $systemConfig; /** * @param SystemConfig $systemConfig */ public function __construct(SystemConfig $systemConfig) { parent::__construct(); $this->systemConfig = $systemConfig; } protected function configure() { parent::configure(); $this ->setName('config:system:get') ->setDescription('Get a system config value') ->addArgument( 'name', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'Name of the config to get, specify multiple for array parameter' ) ->addOption( 'default-value', null, InputOption::VALUE_OPTIONAL, 'If no default value is set and the config does not exist, the command will exit with 1' ) ; } /** * Executes the current command. * * @param InputInterface $input An InputInterface instance * @param OutputInterface $output An OutputInterface instance * @return null|int null or 0 if everything went fine, or an error code */ protected function execute(InputInterface $input, OutputInterface $output) { $configNames = $input->getArgument('name'); $configName = array_shift($configNames); $defaultValue = $input->getOption('default-value'); if (!in_array($configName, $this->systemConfig->getKeys()) && !$input->hasParameterOption('--default-value')) { return 1; } if (!in_array($configName, $this->systemConfig->getKeys())) { $configValue = $defaultValue; } else { $configValue = $this->systemConfig->getValue($configName); if (!empty($configNames)) { foreach ($configNames as $configName) { if (isset($configValue[$configName])) { $configValue = $configValue[$configName]; } else if (!$input->hasParameterOption('--default-value')) { return 1; } else { $configValue = $defaultValue; break; } } } } $this->writeMixedInOutputFormat($input, $output, $configValue); return 0; } } Config/System/Base.php 0000604 00000004415 15247207135 0010626 0 ustar 00 <?php /** * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\Core\Command\Config\System; use OC\SystemConfig; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; abstract class Base extends \OC\Core\Command\Base { /** @var SystemConfig */ protected $systemConfig; /** * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'name') { $words = $this->getPreviousNames($context, $context->getWordIndex()); if (empty($words)) { $completions = $this->systemConfig->getKeys(); } else { $key = array_shift($words); $value = $this->systemConfig->getValue($key); $completions = array_keys($value); while (!empty($words) && is_array($value)) { $key = array_shift($words); if (!isset($value[$key]) || !is_array($value[$key])) { break; } $value = $value[$key]; $completions = array_keys($value); } } return $completions; } return parent::completeArgumentValues($argumentName, $context); } /** * @param CompletionContext $context * @param int $currentIndex * @return string[] */ protected function getPreviousNames(CompletionContext $context, $currentIndex) { $word = $context->getWordAtIndex($currentIndex - 1); if ($word === $this->getName() || $currentIndex <= 0) { return []; } $words = $this->getPreviousNames($context, $currentIndex - 1); $words[] = $word; return $words; } } Config/System/SetConfig.php 0000604 00000013277 15247207135 0011643 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * @author Robin McCorkell <robin@mccorkell.me.uk> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Config\System; use OC\SystemConfig; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class SetConfig extends Base { /** * @var SystemConfig */ protected $systemConfig; /** * @param SystemConfig $systemConfig */ public function __construct(SystemConfig $systemConfig) { parent::__construct(); $this->systemConfig = $systemConfig; } protected function configure() { parent::configure(); $this ->setName('config:system:set') ->setDescription('Set a system config value') ->addArgument( 'name', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'Name of the config parameter, specify multiple for array parameter' ) ->addOption( 'type', null, InputOption::VALUE_REQUIRED, 'Value type [string, integer, double, boolean]', 'string' ) ->addOption( 'value', null, InputOption::VALUE_REQUIRED, 'The new value of the config' ) ->addOption( 'update-only', null, InputOption::VALUE_NONE, 'Only updates the value, if it is not set before, it is not being added' ) ; } protected function execute(InputInterface $input, OutputInterface $output) { $configNames = $input->getArgument('name'); $configName = $configNames[0]; $configValue = $this->castValue($input->getOption('value'), $input->getOption('type')); $updateOnly = $input->getOption('update-only'); if (sizeof($configNames) > 1) { $existingValue = $this->systemConfig->getValue($configName); $newValue = $this->mergeArrayValue( array_slice($configNames, 1), $existingValue, $configValue['value'], $updateOnly ); $this->systemConfig->setValue($configName, $newValue); } else { if ($updateOnly && !in_array($configName, $this->systemConfig->getKeys(), true)) { throw new \UnexpectedValueException('Config parameter does not exist'); } $this->systemConfig->setValue($configName, $configValue['value']); } $output->writeln('<info>System config value ' . implode(' => ', $configNames) . ' set to ' . $configValue['readable-value'] . '</info>'); return 0; } /** * @param string $value * @param string $type * @return mixed * @throws \InvalidArgumentException */ protected function castValue($value, $type) { switch ($type) { case 'integer': case 'int': if (!is_numeric($value)) { throw new \InvalidArgumentException('Non-numeric value specified'); } return [ 'value' => (int) $value, 'readable-value' => 'integer ' . (int) $value, ]; case 'double': case 'float': if (!is_numeric($value)) { throw new \InvalidArgumentException('Non-numeric value specified'); } return [ 'value' => (double) $value, 'readable-value' => 'double ' . (double) $value, ]; case 'boolean': case 'bool': $value = strtolower($value); switch ($value) { case 'true': return [ 'value' => true, 'readable-value' => 'boolean ' . $value, ]; case 'false': return [ 'value' => false, 'readable-value' => 'boolean ' . $value, ]; default: throw new \InvalidArgumentException('Unable to parse value as boolean'); } case 'null': return [ 'value' => null, 'readable-value' => 'null', ]; case 'string': $value = (string) $value; return [ 'value' => $value, 'readable-value' => ($value === '') ? 'empty string' : 'string ' . $value, ]; default: throw new \InvalidArgumentException('Invalid type'); } } /** * @param array $configNames * @param mixed $existingValues * @param mixed $value * @param bool $updateOnly * @return array merged value * @throws \UnexpectedValueException */ protected function mergeArrayValue(array $configNames, $existingValues, $value, $updateOnly) { $configName = array_shift($configNames); if (!is_array($existingValues)) { $existingValues = []; } if (!empty($configNames)) { if (isset($existingValues[$configName])) { $existingValue = $existingValues[$configName]; } else { $existingValue = []; } $existingValues[$configName] = $this->mergeArrayValue($configNames, $existingValue, $value, $updateOnly); } else { if (!isset($existingValues[$configName]) && $updateOnly) { throw new \UnexpectedValueException('Config parameter does not exist'); } $existingValues[$configName] = $value; } return $existingValues; } /** * @param string $optionName * @param CompletionContext $context * @return string[] */ public function completeOptionValues($optionName, CompletionContext $context) { if ($optionName === 'type') { return ['string', 'integer', 'double', 'boolean']; } return parent::completeOptionValues($optionName, $context); } } Config/System/DeleteConfig.php 0000604 00000007371 15247207135 0012310 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Config\System; use OC\SystemConfig; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class DeleteConfig extends Base { /** * @var SystemConfig */ protected $systemConfig; /** * @param SystemConfig $systemConfig */ public function __construct(SystemConfig $systemConfig) { parent::__construct(); $this->systemConfig = $systemConfig; } protected function configure() { parent::configure(); $this ->setName('config:system:delete') ->setDescription('Delete a system config value') ->addArgument( 'name', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'Name of the config to delete, specify multiple for array parameter' ) ->addOption( 'error-if-not-exists', null, InputOption::VALUE_NONE, 'Checks whether the config exists before deleting it' ) ; } protected function execute(InputInterface $input, OutputInterface $output) { $configNames = $input->getArgument('name'); $configName = $configNames[0]; if (sizeof($configNames) > 1) { if ($input->hasParameterOption('--error-if-not-exists') && !in_array($configName, $this->systemConfig->getKeys())) { $output->writeln('<error>System config ' . implode(' => ', $configNames) . ' could not be deleted because it did not exist</error>'); return 1; } $value = $this->systemConfig->getValue($configName); try { $value = $this->removeSubValue(array_slice($configNames, 1), $value, $input->hasParameterOption('--error-if-not-exists')); } catch (\UnexpectedValueException $e) { $output->writeln('<error>System config ' . implode(' => ', $configNames) . ' could not be deleted because it did not exist</error>'); return 1; } $this->systemConfig->setValue($configName, $value); $output->writeln('<info>System config value ' . implode(' => ', $configNames) . ' deleted</info>'); return 0; } else { if ($input->hasParameterOption('--error-if-not-exists') && !in_array($configName, $this->systemConfig->getKeys())) { $output->writeln('<error>System config ' . $configName . ' could not be deleted because it did not exist</error>'); return 1; } $this->systemConfig->deleteValue($configName); $output->writeln('<info>System config value ' . $configName . ' deleted</info>'); return 0; } } protected function removeSubValue($keys, $currentValue, $throwError) { $nextKey = array_shift($keys); if (is_array($currentValue)) { if (isset($currentValue[$nextKey])) { if (empty($keys)) { unset($currentValue[$nextKey]); } else { $currentValue[$nextKey] = $this->removeSubValue($keys, $currentValue[$nextKey], $throwError); } } else if ($throwError) { throw new \UnexpectedValueException('Config parameter does not exist'); } } else if ($throwError) { throw new \UnexpectedValueException('Config parameter does not exist'); } return $currentValue; } } Config/App/SetConfig.php 0000604 00000004743 15247207135 0011075 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Config\App; use OCP\IConfig; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class SetConfig extends Base { /** * @var IConfig */ protected $config; /** * @param IConfig $config */ public function __construct(IConfig $config) { parent::__construct(); $this->config = $config; } protected function configure() { parent::configure(); $this ->setName('config:app:set') ->setDescription('Set an app config value') ->addArgument( 'app', InputArgument::REQUIRED, 'Name of the app' ) ->addArgument( 'name', InputArgument::REQUIRED, 'Name of the config to set' ) ->addOption( 'value', null, InputOption::VALUE_REQUIRED, 'The new value of the config' ) ->addOption( 'update-only', null, InputOption::VALUE_NONE, 'Only updates the value, if it is not set before, it is not being added' ) ; } protected function execute(InputInterface $input, OutputInterface $output) { $appName = $input->getArgument('app'); $configName = $input->getArgument('name'); if (!in_array($configName, $this->config->getAppKeys($appName)) && $input->hasParameterOption('--update-only')) { $output->writeln('<comment>Config value ' . $configName . ' for app ' . $appName . ' not updated, as it has not been set before.</comment>'); return 1; } $configValue = $input->getOption('value'); $this->config->setAppValue($appName, $configName, $configValue); $output->writeln('<info>Config value ' . $configName . ' for app ' . $appName . ' set to ' . $configValue . '</info>'); return 0; } } Config/App/DeleteConfig.php 0000604 00000004446 15247207135 0011544 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Config\App; use OCP\IConfig; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class DeleteConfig extends Base { /** * @var IConfig */ protected $config; /** * @param IConfig $config */ public function __construct(IConfig $config) { parent::__construct(); $this->config = $config; } protected function configure() { parent::configure(); $this ->setName('config:app:delete') ->setDescription('Delete an app config value') ->addArgument( 'app', InputArgument::REQUIRED, 'Name of the app' ) ->addArgument( 'name', InputArgument::REQUIRED, 'Name of the config to delete' ) ->addOption( 'error-if-not-exists', null, InputOption::VALUE_NONE, 'Checks whether the config exists before deleting it' ) ; } protected function execute(InputInterface $input, OutputInterface $output) { $appName = $input->getArgument('app'); $configName = $input->getArgument('name'); if ($input->hasParameterOption('--error-if-not-exists') && !in_array($configName, $this->config->getAppKeys($appName))) { $output->writeln('<error>Config ' . $configName . ' of app ' . $appName . ' could not be deleted because it did not exist</error>'); return 1; } $this->config->deleteAppValue($appName, $configName); $output->writeln('<info>Config value ' . $configName . ' of app ' . $appName . ' deleted</info>'); return 0; } } Config/App/Base.php 0000604 00000002675 15247207135 0010070 0 ustar 00 <?php /** * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\Core\Command\Config\App; use OCP\IConfig; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; abstract class Base extends \OC\Core\Command\Base { /** * @var IConfig */ protected $config; /** * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'app') { return \OC_App::getAllApps(); } if ($argumentName === 'name') { $appName = $context->getWordAtIndex($context->getWordIndex() - 1); return $this->config->getAppKeys($appName); } return []; } } Config/App/GetConfig.php 0000604 00000005072 15247207135 0011055 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Config\App; use OCP\IConfig; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class GetConfig extends Base { /** * @var IConfig */ protected $config; /** * @param IConfig $config */ public function __construct(IConfig $config) { parent::__construct(); $this->config = $config; } protected function configure() { parent::configure(); $this ->setName('config:app:get') ->setDescription('Get an app config value') ->addArgument( 'app', InputArgument::REQUIRED, 'Name of the app' ) ->addArgument( 'name', InputArgument::REQUIRED, 'Name of the config to get' ) ->addOption( 'default-value', null, InputOption::VALUE_OPTIONAL, 'If no default value is set and the config does not exist, the command will exit with 1' ) ; } /** * Executes the current command. * * @param InputInterface $input An InputInterface instance * @param OutputInterface $output An OutputInterface instance * @return null|int null or 0 if everything went fine, or an error code */ protected function execute(InputInterface $input, OutputInterface $output) { $appName = $input->getArgument('app'); $configName = $input->getArgument('name'); $defaultValue = $input->getOption('default-value'); if (!in_array($configName, $this->config->getAppKeys($appName)) && !$input->hasParameterOption('--default-value')) { return 1; } if (!in_array($configName, $this->config->getAppKeys($appName))) { $configValue = $defaultValue; } else { $configValue = $this->config->getAppValue($appName, $configName); } $this->writeMixedInOutputFormat($input, $output, $configValue); return 0; } } Config/Import.php 0000604 00000014762 15247207135 0007750 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Config; use OCP\IConfig; use Stecman\Component\Symfony\Console\BashCompletion\Completion; use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface; use Stecman\Component\Symfony\Console\BashCompletion\Completion\ShellPathCompletion; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class Import extends Command implements CompletionAwareInterface { protected $validRootKeys = ['system', 'apps']; /** @var IConfig */ protected $config; /** * @param IConfig $config */ public function __construct(IConfig $config) { parent::__construct(); $this->config = $config; } protected function configure() { $this ->setName('config:import') ->setDescription('Import a list of configs') ->addArgument( 'file', InputArgument::OPTIONAL, 'File with the json array to import' ) ; } protected function execute(InputInterface $input, OutputInterface $output) { $importFile = $input->getArgument('file'); if ($importFile !== null) { $content = $this->getArrayFromFile($importFile); } else { $content = $this->getArrayFromStdin(); } try { $configs = $this->validateFileContent($content); } catch (\UnexpectedValueException $e) { $output->writeln('<error>' . $e->getMessage(). '</error>'); return; } if (!empty($configs['system'])) { $this->config->setSystemValues($configs['system']); } if (!empty($configs['apps'])) { foreach ($configs['apps'] as $app => $appConfigs) { foreach ($appConfigs as $key => $value) { if ($value === null) { $this->config->deleteAppValue($app, $key); } else { $this->config->setAppValue($app, $key, $value); } } } } $output->writeln('<info>Config successfully imported from: ' . $importFile . '</info>'); } /** * Get the content from stdin ("config:import < file.json") * * @return string */ protected function getArrayFromStdin() { // Read from stdin. stream_set_blocking is used to prevent blocking // when nothing is passed via stdin. stream_set_blocking(STDIN, 0); $content = file_get_contents('php://stdin'); stream_set_blocking(STDIN, 1); return $content; } /** * Get the content of the specified file ("config:import file.json") * * @param string $importFile * @return string */ protected function getArrayFromFile($importFile) { $content = file_get_contents($importFile); return $content; } /** * @param string $content * @return array * @throws \UnexpectedValueException when the array is invalid */ protected function validateFileContent($content) { $decodedContent = json_decode($content, true); if (!is_array($decodedContent) || empty($decodedContent)) { throw new \UnexpectedValueException('The file must contain a valid json array'); } $this->validateArray($decodedContent); return $decodedContent; } /** * Validates that the array only contains `system` and `apps` * * @param array $array */ protected function validateArray($array) { $arrayKeys = array_keys($array); $additionalKeys = array_diff($arrayKeys, $this->validRootKeys); $commonKeys = array_intersect($arrayKeys, $this->validRootKeys); if (!empty($additionalKeys)) { throw new \UnexpectedValueException('Found invalid entries in root: ' . implode(', ', $additionalKeys)); } if (empty($commonKeys)) { throw new \UnexpectedValueException('At least one key of the following is expected: ' . implode(', ', $this->validRootKeys)); } if (isset($array['system'])) { if (is_array($array['system'])) { foreach ($array['system'] as $name => $value) { $this->checkTypeRecursively($value, $name); } } else { throw new \UnexpectedValueException('The system config array is not an array'); } } if (isset($array['apps'])) { if (is_array($array['apps'])) { $this->validateAppsArray($array['apps']); } else { throw new \UnexpectedValueException('The apps config array is not an array'); } } } /** * @param mixed $configValue * @param string $configName */ protected function checkTypeRecursively($configValue, $configName) { if (!is_array($configValue) && !is_bool($configValue) && !is_int($configValue) && !is_string($configValue) && !is_null($configValue)) { throw new \UnexpectedValueException('Invalid system config value for "' . $configName . '". Only arrays, bools, integers, strings and null (delete) are allowed.'); } if (is_array($configValue)) { foreach ($configValue as $key => $value) { $this->checkTypeRecursively($value, $configName); } } } /** * Validates that app configs are only integers and strings * * @param array $array */ protected function validateAppsArray($array) { foreach ($array as $app => $configs) { foreach ($configs as $name => $value) { if (!is_int($value) && !is_string($value) && !is_null($value)) { throw new \UnexpectedValueException('Invalid app config value for "' . $app . '":"' . $name . '". Only integers, strings and null (delete) are allowed.'); } } } } /** * @param string $optionName * @param CompletionContext $context * @return string[] */ public function completeOptionValues($optionName, CompletionContext $context) { return []; } /** * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'file') { $helper = new ShellPathCompletion( $this->getName(), 'file', Completion::TYPE_ARGUMENT ); return $helper->run(); } return []; } } User/ListCommand.php 0000604 00000004750 15247207135 0010415 0 ustar 00 <?php /** * @copyright Copyright (c) 2016 Robin Appelman <robin@icewind.nl> * * @author Robin Appelman <robin@icewind.nl> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\Core\Command\User; use OC\Core\Command\Base; use OCP\IUser; use OCP\IUserManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class ListCommand extends Base { /** @var IUserManager */ protected $userManager; /** * @param IUserManager $userManager */ public function __construct(IUserManager $userManager) { $this->userManager = $userManager; parent::__construct(); } protected function configure() { $this ->setName('user:list') ->setDescription('list configured users') ->addOption( 'limit', 'l', InputOption::VALUE_OPTIONAL, 'Number of users to retrieve', 500 )->addOption( 'offset', 'o', InputOption::VALUE_OPTIONAL, 'Offset for retrieving users', 0 )->addOption( 'output', null, InputOption::VALUE_OPTIONAL, 'Output format (plain, json or json_pretty, default is plain)', $this->defaultOutputFormat ); } protected function execute(InputInterface $input, OutputInterface $output) { $users = $this->userManager->search('', (int)$input->getOption('limit'), (int)$input->getOption('offset')); $this->writeArrayInOutputFormat($input, $output, $this->formatUsers($users)); } /** * @param IUser[] $users * @return array */ private function formatUsers(array $users) { $keys = array_map(function (IUser $user) { return $user->getUID(); }, $users); $values = array_map(function (IUser $user) { return $user->getDisplayName(); }, $users); return array_combine($keys, $values); } } User/Delete.php 0000604 00000004064 15247207135 0007403 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Arthur Schiwon <blizzz@arthur-schiwon.de> * @author Jens-Christian Fischer <jens-christian.fischer@switch.ch> * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\User; use OCP\IUserManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; class Delete extends Command { /** @var IUserManager */ protected $userManager; /** * @param IUserManager $userManager */ public function __construct(IUserManager $userManager) { $this->userManager = $userManager; parent::__construct(); } protected function configure() { $this ->setName('user:delete') ->setDescription('deletes the specified user') ->addArgument( 'uid', InputArgument::REQUIRED, 'the username' ); } protected function execute(InputInterface $input, OutputInterface $output) { $user = $this->userManager->get($input->getArgument('uid')); if (is_null($user)) { $output->writeln('<error>User does not exist</error>'); return; } if ($user->delete()) { $output->writeln('<info>The specified user was deleted</info>'); return; } $output->writeln('<error>The specified user could not be deleted. Please check the logs.</error>'); } } User/Enable.php 0000604 00000003451 15247207135 0007366 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\User; use OCP\IUser; use OCP\IUserManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; class Enable extends Command { /** @var IUserManager */ protected $userManager; /** * @param IUserManager $userManager */ public function __construct(IUserManager $userManager) { $this->userManager = $userManager; parent::__construct(); } protected function configure() { $this ->setName('user:enable') ->setDescription('enables the specified user') ->addArgument( 'uid', InputArgument::REQUIRED, 'the username' ); } protected function execute(InputInterface $input, OutputInterface $output) { $user = $this->userManager->get($input->getArgument('uid')); if (is_null($user)) { $output->writeln('<error>User does not exist</error>'); return; } $user->setEnabled(true); $output->writeln('<info>The specified user is enabled</info>'); } } User/Add.php 0000604 00000011314 15247207135 0006665 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * @author Laurens Post <lkpost@scept.re> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\User; use OC\Files\Filesystem; use OCP\IGroupManager; use OCP\IUser; use OCP\IUserManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Question\Question; class Add extends Command { /** @var \OCP\IUserManager */ protected $userManager; /** @var \OCP\IGroupManager */ protected $groupManager; /** * @param IUserManager $userManager * @param IGroupManager $groupManager */ public function __construct(IUserManager $userManager, IGroupManager $groupManager) { parent::__construct(); $this->userManager = $userManager; $this->groupManager = $groupManager; } protected function configure() { $this ->setName('user:add') ->setDescription('adds a user') ->addArgument( 'uid', InputArgument::REQUIRED, 'User ID used to login (must only contain a-z, A-Z, 0-9, -, _ and @)' ) ->addOption( 'password-from-env', null, InputOption::VALUE_NONE, 'read password from environment variable OC_PASS' ) ->addOption( 'display-name', null, InputOption::VALUE_OPTIONAL, 'User name used in the web UI (can contain any characters)' ) ->addOption( 'group', 'g', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'groups the user should be added to (The group will be created if it does not exist)' ); } protected function execute(InputInterface $input, OutputInterface $output) { $uid = $input->getArgument('uid'); if ($this->userManager->userExists($uid)) { $output->writeln('<error>The user "' . $uid . '" already exists.</error>'); return 1; } if ($input->getOption('password-from-env')) { $password = getenv('OC_PASS'); if (!$password) { $output->writeln('<error>--password-from-env given, but OC_PASS is empty!</error>'); return 1; } } elseif ($input->isInteractive()) { /** @var QuestionHelper $helper */ $helper = $this->getHelper('question'); $question = new Question('Enter password: '); $question->setHidden(true); $password = $helper->ask($input, $output, $question); $question = new Question('Confirm password: '); $question->setHidden(true); $confirm = $helper->ask($input, $output,$question); if ($password !== $confirm) { $output->writeln("<error>Passwords did not match!</error>"); return 1; } } else { $output->writeln("<error>Interactive input or --password-from-env is needed for entering a password!</error>"); return 1; } try { $user = $this->userManager->createUser( $input->getArgument('uid'), $password ); } catch (\Exception $e) { $output->writeln('<error>' . $e->getMessage() . '</error>'); return 1; } if ($user instanceof IUser) { $output->writeln('<info>The user "' . $user->getUID() . '" was created successfully</info>'); } else { $output->writeln('<error>An error occurred while creating the user</error>'); return 1; } if ($input->getOption('display-name')) { $user->setDisplayName($input->getOption('display-name')); $output->writeln('Display name set to "' . $user->getDisplayName() . '"'); } $groups = $input->getOption('group'); if (!empty($groups)) { // Make sure we init the Filesystem for the user, in case we need to // init some group shares. Filesystem::init($user->getUID(), ''); } foreach ($groups as $groupName) { $group = $this->groupManager->get($groupName); if (!$group) { $this->groupManager->createGroup($groupName); $group = $this->groupManager->get($groupName); $output->writeln('Created group "' . $group->getGID() . '"'); } $group->addUser($user); $output->writeln('User "' . $user->getUID() . '" added to group "' . $group->getGID() . '"'); } } } User/LastSeen.php 0000604 00000004227 15247207135 0007720 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Arthur Schiwon <blizzz@arthur-schiwon.de> * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Pierre Ozoux <pierre@ozoux.net> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\User; use OCP\IUserManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; class LastSeen extends Command { /** @var IUserManager */ protected $userManager; /** * @param IUserManager $userManager */ public function __construct(IUserManager $userManager) { $this->userManager = $userManager; parent::__construct(); } protected function configure() { $this ->setName('user:lastseen') ->setDescription('shows when the user was logged in last time') ->addArgument( 'uid', InputArgument::REQUIRED, 'the username' ); } protected function execute(InputInterface $input, OutputInterface $output) { $user = $this->userManager->get($input->getArgument('uid')); if(is_null($user)) { $output->writeln('<error>User does not exist</error>'); return; } $lastLogin = $user->getLastLogin(); if($lastLogin === 0) { $output->writeln('User ' . $user->getUID() . ' has never logged in, yet.'); } else { $date = new \DateTime(); $date->setTimestamp($lastLogin); $output->writeln($user->getUID() . '`s last login: ' . $date->format('d.m.Y H:i')); } } } User/Disable.php 0000604 00000003456 15247207135 0007550 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\User; use OCP\IUser; use OCP\IUserManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; class Disable extends Command { /** @var IUserManager */ protected $userManager; /** * @param IUserManager $userManager */ public function __construct(IUserManager $userManager) { $this->userManager = $userManager; parent::__construct(); } protected function configure() { $this ->setName('user:disable') ->setDescription('disables the specified user') ->addArgument( 'uid', InputArgument::REQUIRED, 'the username' ); } protected function execute(InputInterface $input, OutputInterface $output) { $user = $this->userManager->get($input->getArgument('uid')); if (is_null($user)) { $output->writeln('<error>User does not exist</error>'); return; } $user->setEnabled(false); $output->writeln('<info>The specified user is disabled</info>'); } } User/Report.php 0000604 00000005002 15247207135 0007445 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Arthur Schiwon <blizzz@arthur-schiwon.de> * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\User; use OCP\IUserManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class Report extends Command { /** @var IUserManager */ protected $userManager; /** * @param IUserManager $userManager */ public function __construct(IUserManager $userManager) { $this->userManager = $userManager; parent::__construct(); } protected function configure() { $this ->setName('user:report') ->setDescription('shows how many users have access'); } protected function execute(InputInterface $input, OutputInterface $output) { $table = new Table($output); $table->setHeaders(array('User Report', '')); $userCountArray = $this->countUsers(); if(!empty($userCountArray)) { $total = 0; $rows = array(); foreach($userCountArray as $classname => $users) { $total += $users; $rows[] = array($classname, $users); } $rows[] = array(' '); $rows[] = array('total users', $total); } else { $rows[] = array('No backend enabled that supports user counting', ''); } $userDirectoryCount = $this->countUserDirectories(); $rows[] = array(' '); $rows[] = array('user directories', $userDirectoryCount); $table->setRows($rows); $table->render(); } private function countUsers() { return $this->userManager->countUsers(); } private function countUserDirectories() { $dataview = new \OC\Files\View('/'); $userDirectories = $dataview->getDirectoryContent('/', 'httpd/unix-directory'); return count($userDirectories); } } User/Info.php 0000604 00000005414 15247207135 0007074 0 ustar 00 <?php /** * @copyright Copyright (c) 2016 Robin Appelman <robin@icewind.nl> * * @author Robin Appelman <robin@icewind.nl> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\Core\Command\User; use OC\Core\Command\Base; use OCP\IGroupManager; use OCP\IUser; use OCP\IUserManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Info extends Base { /** @var IUserManager */ protected $userManager; /** @var IGroupManager */ protected $groupManager; /** * @param IUserManager $userManager * @param IGroupManager $groupManager */ public function __construct(IUserManager $userManager, IGroupManager $groupManager) { $this->userManager = $userManager; $this->groupManager = $groupManager; parent::__construct(); } protected function configure() { $this ->setName('user:info') ->setDescription('show user info') ->addArgument( 'user', InputArgument::REQUIRED, 'user to show' )->addOption( 'output', null, InputOption::VALUE_OPTIONAL, 'Output format (plain, json or json_pretty, default is plain)', $this->defaultOutputFormat ); } protected function execute(InputInterface $input, OutputInterface $output) { $user = $this->userManager->get($input->getArgument('user')); if (is_null($user)) { $output->writeln('<error>user not found</error>'); return 1; } $groups = $this->groupManager->getUserGroupIds($user); $data = [ 'user_id' => $user->getUID(), 'display_name' => $user->getDisplayName(), 'email' => ($user->getEMailAddress()) ? $user->getEMailAddress() : '', 'cloud_id' => $user->getCloudId(), 'enabled' => $user->isEnabled(), 'groups' => $groups, 'quota' => $user->getQuota(), 'last_seen' => date(\DateTime::ATOM, $user->getLastLogin()), // ISO-8601 'user_directory' => $user->getHome(), 'backend' => $user->getBackendClassName() ]; $this->writeArrayInOutputFormat($input, $output, $data); } } User/Setting.php 0000604 00000016370 15247207135 0007621 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\User; use OC\Core\Command\Base; use OCP\IConfig; use OCP\IDBConnection; use OCP\IUser; use OCP\IUserManager; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; class Setting extends Base { /** @var IUserManager */ protected $userManager; /** @var IConfig */ protected $config; /** @var IDBConnection */ protected $connection; /** * @param IUserManager $userManager * @param IConfig $config * @param IDBConnection $connection */ public function __construct(IUserManager $userManager, IConfig $config, IDBConnection $connection) { parent::__construct(); $this->userManager = $userManager; $this->config = $config; $this->connection = $connection; } protected function configure() { parent::configure(); $this ->setName('user:setting') ->setDescription('Read and modify user settings') ->addArgument( 'uid', InputArgument::REQUIRED, 'User ID used to login' ) ->addArgument( 'app', InputArgument::OPTIONAL, 'Restrict the settings to a given app', '' ) ->addArgument( 'key', InputArgument::OPTIONAL, 'Setting key to set, get or delete', '' ) ->addOption( 'ignore-missing-user', null, InputOption::VALUE_NONE, 'Use this option to ignore errors when the user does not exist' ) // Get ->addOption( 'default-value', null, InputOption::VALUE_REQUIRED, '(Only applicable on get) If no default value is set and the config does not exist, the command will exit with 1' ) // Set ->addArgument( 'value', InputArgument::OPTIONAL, 'The new value of the setting', null ) ->addOption( 'update-only', null, InputOption::VALUE_NONE, 'Only updates the value, if it is not set before, it is not being added' ) // Delete ->addOption( 'delete', null, InputOption::VALUE_NONE, 'Specify this option to delete the config' ) ->addOption( 'error-if-not-exists', null, InputOption::VALUE_NONE, 'Checks whether the setting exists before deleting it' ) ; } protected function checkInput(InputInterface $input) { $uid = $input->getArgument('uid'); if (!$input->getOption('ignore-missing-user') && !$this->userManager->userExists($uid)) { throw new \InvalidArgumentException('The user "' . $uid . '" does not exists.'); } if ($input->getArgument('key') === '' && $input->hasParameterOption('--default-value')) { throw new \InvalidArgumentException('The "default-value" option can only be used when specifying a key.'); } if ($input->getArgument('key') === '' && $input->getArgument('value') !== null) { throw new \InvalidArgumentException('The value argument can only be used when specifying a key.'); } if ($input->getArgument('value') !== null && $input->hasParameterOption('--default-value')) { throw new \InvalidArgumentException('The value argument can not be used together with "default-value".'); } if ($input->getOption('update-only') && $input->getArgument('value') === null) { throw new \InvalidArgumentException('The "update-only" option can only be used together with "value".'); } if ($input->getArgument('key') === '' && $input->getOption('delete')) { throw new \InvalidArgumentException('The "delete" option can only be used when specifying a key.'); } if ($input->getOption('delete') && $input->hasParameterOption('--default-value')) { throw new \InvalidArgumentException('The "delete" option can not be used together with "default-value".'); } if ($input->getOption('delete') && $input->getArgument('value') !== null) { throw new \InvalidArgumentException('The "delete" option can not be used together with "value".'); } if ($input->getOption('error-if-not-exists') && !$input->getOption('delete')) { throw new \InvalidArgumentException('The "error-if-not-exists" option can only be used together with "delete".'); } } protected function execute(InputInterface $input, OutputInterface $output) { try { $this->checkInput($input); } catch (\InvalidArgumentException $e) { $output->writeln('<error>' . $e->getMessage() . '</error>'); return 1; } $uid = $input->getArgument('uid'); $app = $input->getArgument('app'); $key = $input->getArgument('key'); if ($key !== '') { $value = $this->config->getUserValue($uid, $app, $key, null); if ($input->getArgument('value') !== null) { if ($input->hasParameterOption('--update-only') && $value === null) { $output->writeln('<error>The setting does not exist for user "' . $uid . '".</error>'); return 1; } if ($app === 'settings' && $key === 'email') { $user = $this->userManager->get($uid); if ($user instanceof IUser) { $user->setEMailAddress($input->getArgument('value')); return 0; } } $this->config->setUserValue($uid, $app, $key, $input->getArgument('value')); return 0; } else if ($input->hasParameterOption('--delete')) { if ($input->hasParameterOption('--error-if-not-exists') && $value === null) { $output->writeln('<error>The setting does not exist for user "' . $uid . '".</error>'); return 1; } if ($app === 'settings' && $key === 'email') { $user = $this->userManager->get($uid); if ($user instanceof IUser) { $user->setEMailAddress(''); return 0; } } $this->config->deleteUserValue($uid, $app, $key); return 0; } else if ($value !== null) { $output->writeln($value); return 0; } else { if ($input->hasParameterOption('--default-value')) { $output->writeln($input->getOption('default-value')); return 0; } else { $output->writeln('<error>The setting does not exist for user "' . $uid . '".</error>'); return 1; } } } else { $settings = $this->getUserSettings($uid, $app); $this->writeArrayInOutputFormat($input, $output, $settings); return 0; } } protected function getUserSettings($uid, $app) { $query = $this->connection->getQueryBuilder(); $query->select('*') ->from('preferences') ->where($query->expr()->eq('userid', $query->createNamedParameter($uid))); if ($app !== '') { $query->andWhere($query->expr()->eq('appid', $query->createNamedParameter($app))); } $result = $query->execute(); $settings = []; while ($row = $result->fetch()) { $settings[$row['appid']][$row['configkey']] = $row['configvalue']; } $result->closeCursor(); return $settings; } } User/ResetPassword.php 0000604 00000007740 15247207135 0011012 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Andreas Fischer <bantu@owncloud.com> * @author Christopher Schäpers <kondou@ts.unde.re> * @author Clark Tomlinson <fallen013@gmail.com> * @author Joas Schilling <coding@schilljs.com> * @author Laurens Post <lkpost@scept.re> * @author Morris Jobke <hey@morrisjobke.de> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\User; use OCP\IUserManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\Question; class ResetPassword extends Command { /** @var IUserManager */ protected $userManager; public function __construct(IUserManager $userManager) { $this->userManager = $userManager; parent::__construct(); } protected function configure() { $this ->setName('user:resetpassword') ->setDescription('Resets the password of the named user') ->addArgument( 'user', InputArgument::REQUIRED, 'Username to reset password' ) ->addOption( 'password-from-env', null, InputOption::VALUE_NONE, 'read password from environment variable OC_PASS' ) ; } protected function execute(InputInterface $input, OutputInterface $output) { $username = $input->getArgument('user'); /** @var $user \OCP\IUser */ $user = $this->userManager->get($username); if (is_null($user)) { $output->writeln('<error>User does not exist</error>'); return 1; } if ($input->getOption('password-from-env')) { $password = getenv('OC_PASS'); if (!$password) { $output->writeln('<error>--password-from-env given, but OC_PASS is empty!</error>'); return 1; } } elseif ($input->isInteractive()) { /** @var QuestionHelper $helper */ $helper = $this->getHelper('question'); if (\OCP\App::isEnabled('encryption')) { $output->writeln( '<error>Warning: Resetting the password when using encryption will result in data loss!</error>' ); $question = new ConfirmationQuestion('Do you want to continue?'); if (!$helper->ask($input, $output, $question)) { return 1; } } $question = new Question('Enter a new password: '); $question->setHidden(true); $password = $helper->ask($input, $output, $question); if ($password === null) { $output->writeln("<error>Password cannot be empty!</error>"); return 1; } $question = new Question('Confirm the new password: '); $question->setHidden(true); $confirm = $helper->ask($input, $output, $question); if ($password !== $confirm) { $output->writeln("<error>Passwords did not match!</error>"); return 1; } } else { $output->writeln("<error>Interactive input or --password-from-env is needed for entering a new password!</error>"); return 1; } try { $success = $user->setPassword($password); } catch (\Exception $e) { $output->writeln('<error>' . $e->getMessage() . '</error>'); return 1; } if ($success) { $output->writeln("<info>Successfully reset password for " . $username . "</info>"); } else { $output->writeln("<error>Error while resetting password!</error>"); return 1; } } } Db/ConvertType.php 0000604 00000031625 15247207135 0010075 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Andreas Fischer <bantu@owncloud.com> * @author Bart Visscher <bartv@thisnet.nl> * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * @author tbelau666 <thomas.belau@gmx.de> * @author Thomas Müller <thomas.mueller@tmit.eu> * @author unclejamal3000 <andreas.pramhaas@posteo.de> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Db; use OCP\DB\QueryBuilder\IQueryBuilder; use \OCP\IConfig; use OC\DB\Connection; use OC\DB\ConnectionFactory; use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\Question; class ConvertType extends Command implements CompletionAwareInterface { /** * @var \OCP\IConfig */ protected $config; /** * @var \OC\DB\ConnectionFactory */ protected $connectionFactory; /** @var array */ protected $columnTypes; /** * @param \OCP\IConfig $config * @param \OC\DB\ConnectionFactory $connectionFactory */ public function __construct(IConfig $config, ConnectionFactory $connectionFactory) { $this->config = $config; $this->connectionFactory = $connectionFactory; parent::__construct(); } protected function configure() { $this ->setName('db:convert-type') ->setDescription('Convert the Nextcloud database to the newly configured one') ->addArgument( 'type', InputArgument::REQUIRED, 'the type of the database to convert to' ) ->addArgument( 'username', InputArgument::REQUIRED, 'the username of the database to convert to' ) ->addArgument( 'hostname', InputArgument::REQUIRED, 'the hostname of the database to convert to' ) ->addArgument( 'database', InputArgument::REQUIRED, 'the name of the database to convert to' ) ->addOption( 'port', null, InputOption::VALUE_REQUIRED, 'the port of the database to convert to' ) ->addOption( 'password', null, InputOption::VALUE_REQUIRED, 'the password of the database to convert to. Will be asked when not specified. Can also be passed via stdin.' ) ->addOption( 'clear-schema', null, InputOption::VALUE_NONE, 'remove all tables from the destination database' ) ->addOption( 'all-apps', null, InputOption::VALUE_NONE, 'whether to create schema for all apps instead of only installed apps' ) ->addOption( 'chunk-size', null, InputOption::VALUE_REQUIRED, 'the maximum number of database rows to handle in a single query, bigger tables will be handled in chunks of this size. Lower this if the process runs out of memory during conversion.', 1000 ) ; } protected function validateInput(InputInterface $input, OutputInterface $output) { $type = $this->connectionFactory->normalizeType($input->getArgument('type')); if ($type === 'sqlite3') { throw new \InvalidArgumentException( 'Converting to SQLite (sqlite3) is currently not supported.' ); } if ($type === $this->config->getSystemValue('dbtype', '')) { throw new \InvalidArgumentException(sprintf( 'Can not convert from %1$s to %1$s.', $type )); } if ($type === 'oci' && $input->getOption('clear-schema')) { // Doctrine unconditionally tries (at least in version 2.3) // to drop sequence triggers when dropping a table, even though // such triggers may not exist. This results in errors like // "ORA-04080: trigger 'OC_STORAGES_AI_PK' does not exist". throw new \InvalidArgumentException( 'The --clear-schema option is not supported when converting to Oracle (oci).' ); } } protected function readPassword(InputInterface $input, OutputInterface $output) { // Explicitly specified password if ($input->getOption('password')) { return; } // Read from stdin. stream_set_blocking is used to prevent blocking // when nothing is passed via stdin. stream_set_blocking(STDIN, 0); $password = file_get_contents('php://stdin'); stream_set_blocking(STDIN, 1); if (trim($password) !== '') { $input->setOption('password', $password); return; } // Read password by interacting if ($input->isInteractive()) { /** @var QuestionHelper $helper */ $helper = $this->getHelper('question'); $question = new Question('What is the database password?'); $question->setHidden(true); $question->setHiddenFallback(false); $password = $helper->ask($input, $output, $question); $input->setOption('password', $password); return; } } protected function execute(InputInterface $input, OutputInterface $output) { $this->validateInput($input, $output); $this->readPassword($input, $output); $fromDB = \OC::$server->getDatabaseConnection(); $toDB = $this->getToDBConnection($input, $output); if ($input->getOption('clear-schema')) { $this->clearSchema($toDB, $input, $output); } $this->createSchema($toDB, $input, $output); $toTables = $this->getTables($toDB); $fromTables = $this->getTables($fromDB); // warn/fail if there are more tables in 'from' database $extraFromTables = array_diff($fromTables, $toTables); if (!empty($extraFromTables)) { $output->writeln('<comment>The following tables will not be converted:</comment>'); $output->writeln($extraFromTables); if (!$input->getOption('all-apps')) { $output->writeln('<comment>Please note that tables belonging to available but currently not installed apps</comment>'); $output->writeln('<comment>can be included by specifying the --all-apps option.</comment>'); } /** @var QuestionHelper $helper */ $helper = $this->getHelper('question'); $question = new ConfirmationQuestion('Continue with the conversion (y/n)? [n] ', false); if (!$helper->ask($input, $output, $question)) { return; } } $intersectingTables = array_intersect($toTables, $fromTables); $this->convertDB($fromDB, $toDB, $intersectingTables, $input, $output); } protected function createSchema(Connection $toDB, InputInterface $input, OutputInterface $output) { $output->writeln('<info>Creating schema in new database</info>'); $schemaManager = new \OC\DB\MDB2SchemaManager($toDB); $schemaManager->createDbFromStructure(\OC::$SERVERROOT.'/db_structure.xml'); $apps = $input->getOption('all-apps') ? \OC_App::getAllApps() : \OC_App::getEnabledApps(); foreach($apps as $app) { if (file_exists(\OC_App::getAppPath($app).'/appinfo/database.xml')) { $schemaManager->createDbFromStructure(\OC_App::getAppPath($app).'/appinfo/database.xml'); } } } protected function getToDBConnection(InputInterface $input, OutputInterface $output) { $type = $input->getArgument('type'); $connectionParams = array( 'host' => $input->getArgument('hostname'), 'user' => $input->getArgument('username'), 'password' => $input->getOption('password'), 'dbname' => $input->getArgument('database'), 'tablePrefix' => $this->config->getSystemValue('dbtableprefix', 'oc_'), ); if ($input->getOption('port')) { $connectionParams['port'] = $input->getOption('port'); } return $this->connectionFactory->getConnection($type, $connectionParams); } protected function clearSchema(Connection $db, InputInterface $input, OutputInterface $output) { $toTables = $this->getTables($db); if (!empty($toTables)) { $output->writeln('<info>Clearing schema in new database</info>'); } foreach($toTables as $table) { $db->getSchemaManager()->dropTable($table); } } protected function getTables(Connection $db) { $filterExpression = '/^' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/'; $db->getConfiguration()-> setFilterSchemaAssetsExpression($filterExpression); return $db->getSchemaManager()->listTableNames(); } protected function copyTable(Connection $fromDB, Connection $toDB, $table, InputInterface $input, OutputInterface $output) { $chunkSize = $input->getOption('chunk-size'); $query = $fromDB->getQueryBuilder(); $query->automaticTablePrefix(false); $query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries') ->from($table); $result = $query->execute(); $count = $result->fetchColumn(); $result->closeCursor(); $numChunks = ceil($count/$chunkSize); if ($numChunks > 1) { $output->writeln('chunked query, ' . $numChunks . ' chunks'); } $progress = new ProgressBar($output, $count); $progress->start(); $redraw = $count > $chunkSize ? 100 : ($count > 100 ? 5 : 1); $progress->setRedrawFrequency($redraw); $query = $fromDB->getQueryBuilder(); $query->automaticTablePrefix(false); $query->select('*') ->from($table) ->setMaxResults($chunkSize); $insertQuery = $toDB->getQueryBuilder(); $insertQuery->automaticTablePrefix(false); $insertQuery->insert($table); $parametersCreated = false; for ($chunk = 0; $chunk < $numChunks; $chunk++) { $query->setFirstResult($chunk * $chunkSize); $result = $query->execute(); while ($row = $result->fetch()) { $progress->advance(); if (!$parametersCreated) { foreach ($row as $key => $value) { $insertQuery->setValue($key, $insertQuery->createParameter($key)); } $parametersCreated = true; } foreach ($row as $key => $value) { $type = $this->getColumnType($table, $key); if ($type !== false) { $insertQuery->setParameter($key, $value, $type); } else { $insertQuery->setParameter($key, $value); } } $insertQuery->execute(); } $result->closeCursor(); } $progress->finish(); } protected function getColumnType($table, $column) { if (isset($this->columnTypes[$table][$column])) { return $this->columnTypes[$table][$column]; } $prefix = $this->config->getSystemValue('dbtableprefix', 'oc_'); $this->columnTypes[$table][$column] = false; if ($table === $prefix . 'cards' && $column === 'carddata') { $this->columnTypes[$table][$column] = IQueryBuilder::PARAM_LOB; } else if ($column === 'calendardata') { if ($table === $prefix . 'calendarobjects' || $table === $prefix . 'schedulingobjects') { $this->columnTypes[$table][$column] = IQueryBuilder::PARAM_LOB; } } return $this->columnTypes[$table][$column]; } protected function convertDB(Connection $fromDB, Connection $toDB, array $tables, InputInterface $input, OutputInterface $output) { $this->config->setSystemValue('maintenance', true); try { // copy table rows foreach($tables as $table) { $output->writeln($table); $this->copyTable($fromDB, $toDB, $table, $input, $output); } if ($input->getArgument('type') === 'pgsql') { $tools = new \OC\DB\PgSqlTools($this->config); $tools->resynchronizeDatabaseSequences($toDB); } // save new database config $this->saveDBInfo($input); } catch(\Exception $e) { $this->config->setSystemValue('maintenance', false); throw $e; } $this->config->setSystemValue('maintenance', false); } protected function saveDBInfo(InputInterface $input) { $type = $input->getArgument('type'); $username = $input->getArgument('username'); $dbHost = $input->getArgument('hostname'); $dbName = $input->getArgument('database'); $password = $input->getOption('password'); if ($input->getOption('port')) { $dbHost .= ':'.$input->getOption('port'); } $this->config->setSystemValues([ 'dbtype' => $type, 'dbname' => $dbName, 'dbhost' => $dbHost, 'dbuser' => $username, 'dbpassword' => $password, ]); } /** * Return possible values for the named option * * @param string $optionName * @param CompletionContext $context * @return string[] */ public function completeOptionValues($optionName, CompletionContext $context) { return []; } /** * Return possible values for the named argument * * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'type') { return ['mysql', 'oci', 'pgsql']; } return []; } } Db/GenerateChangeScript.php 0000604 00000005355 15247207135 0011641 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Morris Jobke <hey@morrisjobke.de> * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Db; use Stecman\Component\Symfony\Console\BashCompletion\Completion; use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface; use Stecman\Component\Symfony\Console\BashCompletion\Completion\ShellPathCompletion; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class GenerateChangeScript extends Command implements CompletionAwareInterface { protected function configure() { $this ->setName('db:generate-change-script') ->setDescription('generates the change script from the current connected db to db_structure.xml') ->addArgument( 'schema-xml', InputArgument::OPTIONAL, 'the schema xml to be used as target schema', \OC::$SERVERROOT . '/db_structure.xml' ) ; } protected function execute(InputInterface $input, OutputInterface $output) { $file = $input->getArgument('schema-xml'); $schemaManager = new \OC\DB\MDB2SchemaManager(\OC::$server->getDatabaseConnection()); try { $result = $schemaManager->updateDbFromStructure($file, true); $output->writeln($result); } catch (\Exception $e) { $output->writeln('Failed to update database structure ('.$e.')'); } } /** * @param string $optionName * @param CompletionContext $context * @return string[] */ public function completeOptionValues($optionName, CompletionContext $context) { return []; } /** * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'schema-xml') { $helper = new ShellPathCompletion( $this->getName(), 'schema-xml', Completion::TYPE_ARGUMENT ); return $helper->run(); } return []; } } Db/ConvertMysqlToMB4.php 0000604 00000005326 15247207135 0011066 0 ustar 00 <?php /** * @author Thomas Müller <thomas.mueller@tmit.eu> * * @copyright Copyright (c) 2017, ownCloud GmbH * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Db; use Doctrine\DBAL\Platforms\MySqlPlatform; use OC\DB\MySqlTools; use OC\Migration\ConsoleOutput; use OC\Repair\Collation; use OCP\IConfig; use OCP\IDBConnection; use OCP\ILogger; use OCP\IURLGenerator; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class ConvertMysqlToMB4 extends Command { /** @var IConfig */ private $config; /** @var IDBConnection */ private $connection; /** @var IURLGenerator */ private $urlGenerator; /** @var ILogger */ private $logger; /** * @param IConfig $config * @param IDBConnection $connection * @param IURLGenerator $urlGenerator * @param ILogger $logger */ public function __construct(IConfig $config, IDBConnection $connection, IURLGenerator $urlGenerator, ILogger $logger) { $this->config = $config; $this->connection = $connection; $this->urlGenerator = $urlGenerator; $this->logger = $logger; parent::__construct(); } protected function configure() { $this ->setName('db:convert-mysql-charset') ->setDescription('Convert charset of MySQL/MariaDB to use utf8mb4'); } protected function execute(InputInterface $input, OutputInterface $output) { if (!$this->connection->getDatabasePlatform() instanceof MySqlPlatform) { $output->writeln("This command is only valid for MySQL/MariaDB databases."); return 1; } $tools = new MySqlTools(); if (!$tools->supports4ByteCharset($this->connection)) { $url = $this->urlGenerator->linkToDocs('admin-mysql-utf8mb4'); $output->writeln("The database is not properly setup to use the charset utf8mb4."); $output->writeln("For more information please read the documentation at $url"); return 1; } // enable charset $this->config->setSystemValue('mysql.utf8mb4', true); // run conversion $coll = new Collation($this->config, $this->logger, $this->connection, false); $coll->run(new ConsoleOutput($output)); return 0; } } L10n/CreateJs.php 0000604 00000011577 15247207135 0007504 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Morris Jobke <hey@morrisjobke.de> * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\L10n; use DirectoryIterator; use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use UnexpectedValueException; class CreateJs extends Command implements CompletionAwareInterface { protected function configure() { $this ->setName('l10n:createjs') ->setDescription('Create javascript translation files for a given app') ->addArgument( 'app', InputOption::VALUE_REQUIRED, 'name of the app' ) ->addArgument( 'lang', InputOption::VALUE_OPTIONAL, 'name of the language' ); } protected function execute(InputInterface $input, OutputInterface $output) { $app = $input->getArgument('app'); $lang = $input->getArgument('lang'); $path = \OC_App::getAppPath($app); if ($path === false) { $output->writeln("The app <$app> is unknown."); return; } $languages = $lang; if (empty($lang)) { $languages= $this->getAllLanguages($path); } foreach($languages as $lang) { $this->writeFiles($app, $path, $lang, $output); } } private function getAllLanguages($path) { $result = array(); foreach (new DirectoryIterator("$path/l10n") as $fileInfo) { if($fileInfo->isDot()) { continue; } if($fileInfo->isDir()) { continue; } if($fileInfo->getExtension() !== 'php') { continue; } $result[]= substr($fileInfo->getBasename(), 0, -4); } return $result; } private function writeFiles($app, $path, $lang, OutputInterface $output) { list($translations, $plurals) = $this->loadTranslations($path, $lang); $this->writeJsFile($app, $path, $lang, $output, $translations, $plurals); $this->writeJsonFile($path, $lang, $output, $translations, $plurals); } private function writeJsFile($app, $path, $lang, OutputInterface $output, $translations, $plurals) { $jsFile = "$path/l10n/$lang.js"; if (file_exists($jsFile)) { $output->writeln("File already exists: $jsFile"); return; } $content = "OC.L10N.register(\n \"$app\",\n {\n "; $jsTrans = array(); foreach ($translations as $id => $val) { if (is_array($val)) { $val = '[ ' . join(',', $val) . ']'; } $jsTrans[] = "\"$id\" : \"$val\""; } $content .= join(",\n ", $jsTrans); $content .= "\n},\n\"$plurals\");\n"; file_put_contents($jsFile, $content); $output->writeln("Javascript translation file generated: $jsFile"); } private function writeJsonFile($path, $lang, OutputInterface $output, $translations, $plurals) { $jsFile = "$path/l10n/$lang.json"; if (file_exists($jsFile)) { $output->writeln("File already exists: $jsFile"); return; } $content = array('translations' => $translations, 'pluralForm' => $plurals); file_put_contents($jsFile, json_encode($content)); $output->writeln("Json translation file generated: $jsFile"); } private function loadTranslations($path, $lang) { $phpFile = "$path/l10n/$lang.php"; $TRANSLATIONS = array(); $PLURAL_FORMS = ''; if (!file_exists($phpFile)) { throw new UnexpectedValueException("PHP translation file <$phpFile> does not exist."); } require $phpFile; return array($TRANSLATIONS, $PLURAL_FORMS); } /** * Return possible values for the named option * * @param string $optionName * @param CompletionContext $context * @return string[] */ public function completeOptionValues($optionName, CompletionContext $context) { return []; } /** * Return possible values for the named argument * * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'app') { return \OC_App::getAllApps(); } else if ($argumentName === 'lang') { $appName = $context->getWordAtIndex($context->getWordIndex() - 1); return $this->getAllLanguages(\OC_App::getAppPath($appName)); } return []; } } Encryption/DecryptAll.php 0000604 00000013236 15247207135 0011461 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Björn Schießle <bjoern@schiessle.org> * @author davitol <dtoledo@solidgear.es> * @author Joas Schilling <coding@schilljs.com> * @author Sergio Bertolín <sbertolin@solidgear.es> * @author Vincent Petry <pvince81@owncloud.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Encryption; use OCP\App\IAppManager; use OCP\Encryption\IManager; use OCP\IConfig; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ConfirmationQuestion; class DecryptAll extends Command { /** @var IManager */ protected $encryptionManager; /** @var IAppManager */ protected $appManager; /** @var IConfig */ protected $config; /** @var QuestionHelper */ protected $questionHelper; /** @var bool */ protected $wasTrashbinEnabled; /** @var bool */ protected $wasMaintenanceModeEnabled; /** @var \OC\Encryption\DecryptAll */ protected $decryptAll; /** * @param IManager $encryptionManager * @param IAppManager $appManager * @param IConfig $config * @param \OC\Encryption\DecryptAll $decryptAll * @param QuestionHelper $questionHelper */ public function __construct( IManager $encryptionManager, IAppManager $appManager, IConfig $config, \OC\Encryption\DecryptAll $decryptAll, QuestionHelper $questionHelper ) { parent::__construct(); $this->appManager = $appManager; $this->encryptionManager = $encryptionManager; $this->config = $config; $this->decryptAll = $decryptAll; $this->questionHelper = $questionHelper; } /** * Set maintenance mode and disable the trashbin app */ protected function forceMaintenanceAndTrashbin() { $this->wasTrashbinEnabled = $this->appManager->isEnabledForUser('files_trashbin'); $this->wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false); $this->config->setSystemValue('maintenance', true); $this->appManager->disableApp('files_trashbin'); } /** * Reset the maintenance mode and re-enable the trashbin app */ protected function resetMaintenanceAndTrashbin() { $this->config->setSystemValue('maintenance', $this->wasMaintenanceModeEnabled); if ($this->wasTrashbinEnabled) { $this->appManager->enableApp('files_trashbin'); } } protected function configure() { parent::configure(); $this->setName('encryption:decrypt-all'); $this->setDescription('Disable server-side encryption and decrypt all files'); $this->setHelp( 'This will disable server-side encryption and decrypt all files for ' . 'all users if it is supported by your encryption module. ' . 'Please make sure that no user access his files during this process!' ); $this->addArgument( 'user', InputArgument::OPTIONAL, 'user for which you want to decrypt all files (optional)', '' ); } protected function execute(InputInterface $input, OutputInterface $output) { try { if ($this->encryptionManager->isEnabled() === true) { $output->write('Disable server side encryption... '); $this->config->setAppValue('core', 'encryption_enabled', 'no'); $output->writeln('done.'); } else { $output->writeln('Server side encryption not enabled. Nothing to do.'); return; } $uid = $input->getArgument('user'); if ($uid === '') { $message = 'your Nextcloud'; } else { $message = "$uid's account"; } $output->writeln("\n"); $output->writeln("You are about to start to decrypt all files stored in $message."); $output->writeln('It will depend on the encryption module and your setup if this is possible.'); $output->writeln('Depending on the number and size of your files this can take some time'); $output->writeln('Please make sure that no user access his files during this process!'); $output->writeln(''); $question = new ConfirmationQuestion('Do you really want to continue? (y/n) ', false); if ($this->questionHelper->ask($input, $output, $question)) { $this->forceMaintenanceAndTrashbin(); $user = $input->getArgument('user'); $result = $this->decryptAll->decryptAll($input, $output, $user); if ($result === false) { $output->writeln(' aborted.'); $output->writeln('Server side encryption remains enabled'); $this->config->setAppValue('core', 'encryption_enabled', 'yes'); } else if ($uid !== '') { $output->writeln('Server side encryption remains enabled'); $this->config->setAppValue('core', 'encryption_enabled', 'yes'); } $this->resetMaintenanceAndTrashbin(); } else { $output->write('Enable server side encryption... '); $this->config->setAppValue('core', 'encryption_enabled', 'yes'); $output->writeln('done.'); $output->writeln('aborted'); } } catch (\Exception $e) { // enable server side encryption again if something went wrong $this->config->setAppValue('core', 'encryption_enabled', 'yes'); $this->resetMaintenanceAndTrashbin(); throw $e; } } } Encryption/Enable.php 0000604 00000004664 15247207135 0010611 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Encryption; use OCP\Encryption\IManager; use OCP\IConfig; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class Enable extends Command { /** @var IConfig */ protected $config; /** @var IManager */ protected $encryptionManager; /** * @param IConfig $config * @param IManager $encryptionManager */ public function __construct(IConfig $config, IManager $encryptionManager) { parent::__construct(); $this->encryptionManager = $encryptionManager; $this->config = $config; } protected function configure() { $this ->setName('encryption:enable') ->setDescription('Enable encryption') ; } protected function execute(InputInterface $input, OutputInterface $output) { if ($this->config->getAppValue('core', 'encryption_enabled', 'no') === 'yes') { $output->writeln('Encryption is already enabled'); } else { $this->config->setAppValue('core', 'encryption_enabled', 'yes'); $output->writeln('<info>Encryption enabled</info>'); } $output->writeln(''); $modules = $this->encryptionManager->getEncryptionModules(); if (empty($modules)) { $output->writeln('<error>No encryption module is loaded</error>'); } else { $defaultModule = $this->config->getAppValue('core', 'default_encryption_module', null); if ($defaultModule === null) { $output->writeln('<error>No default module is set</error>'); } else if (!isset($modules[$defaultModule])) { $output->writeln('<error>The current default module does not exist: ' . $defaultModule . '</error>'); } else { $output->writeln('Default module: ' . $defaultModule); } } } } Encryption/ShowKeyStorageRoot.php 0000604 00000003204 15247207135 0013172 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Björn Schießle <bjoern@schiessle.org> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Encryption; use OC\Encryption\Util; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class ShowKeyStorageRoot extends Command{ /** @var Util */ protected $util; /** * @param Util $util */ public function __construct(Util $util) { parent::__construct(); $this->util = $util; } protected function configure() { parent::configure(); $this ->setName('encryption:show-key-storage-root') ->setDescription('Show current key storage root'); } protected function execute(InputInterface $input, OutputInterface $output) { $currentRoot = $this->util->getKeyStorageRoot(); $rootDescription = $currentRoot !== '' ? $currentRoot : 'default storage location (data/)'; $output->writeln("Current key storage root: <info>$rootDescription</info>"); } } Encryption/Status.php 0000604 00000003211 15247207135 0010671 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Encryption; use OC\Core\Command\Base; use OCP\Encryption\IManager; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class Status extends Base { /** @var IManager */ protected $encryptionManager; /** * @param IManager $encryptionManager */ public function __construct(IManager $encryptionManager) { parent::__construct(); $this->encryptionManager = $encryptionManager; } protected function configure() { parent::configure(); $this ->setName('encryption:status') ->setDescription('Lists the current status of encryption') ; } protected function execute(InputInterface $input, OutputInterface $output) { $this->writeArrayInOutputFormat($input, $output, [ 'enabled' => $this->encryptionManager->isEnabled(), 'defaultModule' => $this->encryptionManager->getDefaultEncryptionModuleId(), ]); } } Encryption/ListModules.php 0000604 00000004627 15247207135 0011666 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Encryption; use OC\Core\Command\Base; use OCP\Encryption\IManager; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class ListModules extends Base { /** @var IManager */ protected $encryptionManager; /** * @param IManager $encryptionManager */ public function __construct(IManager $encryptionManager) { parent::__construct(); $this->encryptionManager = $encryptionManager; } protected function configure() { parent::configure(); $this ->setName('encryption:list-modules') ->setDescription('List all available encryption modules') ; } protected function execute(InputInterface $input, OutputInterface $output) { $encryptionModules = $this->encryptionManager->getEncryptionModules(); $defaultEncryptionModuleId = $this->encryptionManager->getDefaultEncryptionModuleId(); $encModules = array(); foreach ($encryptionModules as $module) { $encModules[$module['id']]['displayName'] = $module['displayName']; $encModules[$module['id']]['default'] = $module['id'] === $defaultEncryptionModuleId; } $this->writeModuleList($input, $output, $encModules); } /** * @param InputInterface $input * @param OutputInterface $output * @param array $items */ protected function writeModuleList(InputInterface $input, OutputInterface $output, $items) { if ($input->getOption('output') === self::OUTPUT_FORMAT_PLAIN) { array_walk($items, function(&$item) { if (!$item['default']) { $item = $item['displayName']; } else { $item = $item['displayName'] . ' [default*]'; } }); } $this->writeArrayInOutputFormat($input, $output, $items); } } Encryption/EncryptAll.php 0000604 00000010142 15247207135 0011464 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Björn Schießle <bjoern@schiessle.org> * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Encryption; use OCP\App\IAppManager; use OCP\Encryption\IManager; use OCP\IConfig; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ConfirmationQuestion; class EncryptAll extends Command { /** @var IManager */ protected $encryptionManager; /** @var IAppManager */ protected $appManager; /** @var IConfig */ protected $config; /** @var QuestionHelper */ protected $questionHelper; /** @var bool */ protected $wasTrashbinEnabled; /** @var bool */ protected $wasMaintenanceModeEnabled; /** * @param IManager $encryptionManager * @param IAppManager $appManager * @param IConfig $config * @param QuestionHelper $questionHelper */ public function __construct( IManager $encryptionManager, IAppManager $appManager, IConfig $config, QuestionHelper $questionHelper ) { parent::__construct(); $this->appManager = $appManager; $this->encryptionManager = $encryptionManager; $this->config = $config; $this->questionHelper = $questionHelper; } /** * Set maintenance mode and disable the trashbin app */ protected function forceMaintenanceAndTrashbin() { $this->wasTrashbinEnabled = $this->appManager->isEnabledForUser('files_trashbin'); $this->wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false); $this->config->setSystemValue('maintenance', true); $this->appManager->disableApp('files_trashbin'); } /** * Reset the maintenance mode and re-enable the trashbin app */ protected function resetMaintenanceAndTrashbin() { $this->config->setSystemValue('maintenance', $this->wasMaintenanceModeEnabled); if ($this->wasTrashbinEnabled) { $this->appManager->enableApp('files_trashbin'); } } protected function configure() { parent::configure(); $this->setName('encryption:encrypt-all'); $this->setDescription('Encrypt all files for all users'); $this->setHelp( 'This will encrypt all files for all users. ' . 'Please make sure that no user access his files during this process!' ); } protected function execute(InputInterface $input, OutputInterface $output) { if ($this->encryptionManager->isEnabled() === false) { throw new \Exception('Server side encryption is not enabled'); } $output->writeln("\n"); $output->writeln('You are about to encrypt all files stored in your Nextcloud installation.'); $output->writeln('Depending on the number of available files, and their size, this may take quite some time.'); $output->writeln('Please ensure that no user accesses their files during this time!'); $output->writeln('Note: The encryption module you use determines which files get encrypted.'); $output->writeln(''); $question = new ConfirmationQuestion('Do you really want to continue? (y/n) ', false); if ($this->questionHelper->ask($input, $output, $question)) { $this->forceMaintenanceAndTrashbin(); try { $defaultModule = $this->encryptionManager->getEncryptionModule(); $defaultModule->encryptAll($input, $output); } catch (\Exception $ex) { $this->resetMaintenanceAndTrashbin(); throw $ex; } $this->resetMaintenanceAndTrashbin(); } else { $output->writeln('aborted'); } } } Encryption/Disable.php 0000604 00000003203 15247207135 0010752 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Encryption; use OCP\IConfig; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class Disable extends Command { /** @var IConfig */ protected $config; /** * @param IConfig $config */ public function __construct(IConfig $config) { parent::__construct(); $this->config = $config; } protected function configure() { $this ->setName('encryption:disable') ->setDescription('Disable encryption') ; } protected function execute(InputInterface $input, OutputInterface $output) { if ($this->config->getAppValue('core', 'encryption_enabled', 'no') !== 'yes') { $output->writeln('Encryption is already disabled'); } else { $this->config->setAppValue('core', 'encryption_enabled', 'no'); $output->writeln('<info>Encryption disabled</info>'); } } } Encryption/ChangeKeyStorageRoot.php 0000604 00000016264 15247207135 0013451 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Björn Schießle <bjoern@schiessle.org> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Encryption; use OC\Encryption\Keys\Storage; use OC\Encryption\Util; use OC\Files\Filesystem; use OC\Files\View; use OCP\IConfig; use OCP\IUserManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ConfirmationQuestion; class ChangeKeyStorageRoot extends Command { /** @var View */ protected $rootView; /** @var IUserManager */ protected $userManager; /** @var IConfig */ protected $config; /** @var Util */ protected $util; /** @var QuestionHelper */ protected $questionHelper; /** * @param View $view * @param IUserManager $userManager * @param IConfig $config * @param Util $util * @param QuestionHelper $questionHelper */ public function __construct(View $view, IUserManager $userManager, IConfig $config, Util $util, QuestionHelper $questionHelper) { parent::__construct(); $this->rootView = $view; $this->userManager = $userManager; $this->config = $config; $this->util = $util; $this->questionHelper = $questionHelper; } protected function configure() { parent::configure(); $this ->setName('encryption:change-key-storage-root') ->setDescription('Change key storage root') ->addArgument( 'newRoot', InputArgument::OPTIONAL, 'new root of the key storage relative to the data folder' ); } protected function execute(InputInterface $input, OutputInterface $output) { $oldRoot = $this->util->getKeyStorageRoot(); $newRoot = $input->getArgument('newRoot'); if ($newRoot === null) { $question = new ConfirmationQuestion('No storage root given, do you want to reset the key storage root to the default location? (y/n) ', false); if (!$this->questionHelper->ask($input, $output, $question)) { return; } $newRoot = ''; } $oldRootDescription = $oldRoot !== '' ? $oldRoot : 'default storage location'; $newRootDescription = $newRoot !== '' ? $newRoot : 'default storage location'; $output->writeln("Change key storage root from <info>$oldRootDescription</info> to <info>$newRootDescription</info>"); $success = $this->moveAllKeys($oldRoot, $newRoot, $output); if ($success) { $this->util->setKeyStorageRoot($newRoot); $output->writeln(''); $output->writeln("Key storage root successfully changed to <info>$newRootDescription</info>"); } } /** * move keys to new key storage root * * @param string $oldRoot * @param string $newRoot * @param OutputInterface $output * @return bool * @throws \Exception */ protected function moveAllKeys($oldRoot, $newRoot, OutputInterface $output) { $output->writeln("Start to move keys:"); if ($this->rootView->is_dir(($oldRoot)) === false) { $output->writeln("No old keys found: Nothing needs to be moved"); return false; } $this->prepareNewRoot($newRoot); $this->moveSystemKeys($oldRoot, $newRoot); $this->moveUserKeys($oldRoot, $newRoot, $output); return true; } /** * prepare new key storage * * @param string $newRoot * @throws \Exception */ protected function prepareNewRoot($newRoot) { if ($this->rootView->is_dir($newRoot) === false) { throw new \Exception("New root folder doesn't exist. Please create the folder or check the permissions and try again."); } $result = $this->rootView->file_put_contents( $newRoot . '/' . Storage::KEY_STORAGE_MARKER, 'ownCloud will detect this folder as key storage root only if this file exists' ); if ($result === false) { throw new \Exception("Can't write to new root folder. Please check the permissions and try again"); } } /** * move system key folder * * @param string $oldRoot * @param string $newRoot */ protected function moveSystemKeys($oldRoot, $newRoot) { if ( $this->rootView->is_dir($oldRoot . '/files_encryption') && $this->targetExists($newRoot . '/files_encryption') === false ) { $this->rootView->rename($oldRoot . '/files_encryption', $newRoot . '/files_encryption'); } } /** * setup file system for the given user * * @param string $uid */ protected function setupUserFS($uid) { \OC_Util::tearDownFS(); \OC_Util::setupFS($uid); } /** * iterate over each user and move the keys to the new storage * * @param string $oldRoot * @param string $newRoot * @param OutputInterface $output */ protected function moveUserKeys($oldRoot, $newRoot, OutputInterface $output) { $progress = new ProgressBar($output); $progress->start(); foreach($this->userManager->getBackends() as $backend) { $limit = 500; $offset = 0; do { $users = $backend->getUsers('', $limit, $offset); foreach ($users as $user) { $progress->advance(); $this->setupUserFS($user); $this->moveUserEncryptionFolder($user, $oldRoot, $newRoot); } $offset += $limit; } while(count($users) >= $limit); } $progress->finish(); } /** * move user encryption folder to new root folder * * @param string $user * @param string $oldRoot * @param string $newRoot * @throws \Exception */ protected function moveUserEncryptionFolder($user, $oldRoot, $newRoot) { if ($this->userManager->userExists($user)) { $source = $oldRoot . '/' . $user . '/files_encryption'; $target = $newRoot . '/' . $user . '/files_encryption'; if ( $this->rootView->is_dir($source) && $this->targetExists($target) === false ) { $this->prepareParentFolder($newRoot . '/' . $user); $this->rootView->rename($source, $target); } } } /** * Make preparations to filesystem for saving a key file * * @param string $path relative to data/ */ protected function prepareParentFolder($path) { $path = Filesystem::normalizePath($path); // If the file resides within a subdirectory, create it if ($this->rootView->file_exists($path) === false) { $sub_dirs = explode('/', ltrim($path, '/')); $dir = ''; foreach ($sub_dirs as $sub_dir) { $dir .= '/' . $sub_dir; if ($this->rootView->file_exists($dir) === false) { $this->rootView->mkdir($dir); } } } } /** * check if target already exists * * @param $path * @return bool * @throws \Exception */ protected function targetExists($path) { if ($this->rootView->file_exists($path)) { throw new \Exception("new folder '$path' already exists"); } return false; } } Encryption/SetDefaultModule.php 0000604 00000004162 15247207135 0012622 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Encryption; use OCP\Encryption\IManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class SetDefaultModule extends Command { /** @var IManager */ protected $encryptionManager; /** * @param IManager $encryptionManager */ public function __construct(IManager $encryptionManager) { parent::__construct(); $this->encryptionManager = $encryptionManager; } protected function configure() { parent::configure(); $this ->setName('encryption:set-default-module') ->setDescription('Set the encryption default module') ->addArgument( 'module', InputArgument::REQUIRED, 'ID of the encryption module that should be used' ) ; } protected function execute(InputInterface $input, OutputInterface $output) { $moduleId = $input->getArgument('module'); if ($moduleId === $this->encryptionManager->getDefaultEncryptionModuleId()) { $output->writeln('"' . $moduleId . '"" is already the default module'); } else if ($this->encryptionManager->setDefaultEncryptionModule($moduleId)) { $output->writeln('<info>Set default module to "' . $moduleId . '"</info>'); } else { $output->writeln('<error>The specified module "' . $moduleId . '" does not exist</error>'); } } } Background/Ajax.php 0000604 00000002376 15247207135 0010231 0 ustar 00 <?php /** * The MIT License (MIT) * * Copyright (c) 2015 Christian Kampka <christian@kampka.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ namespace OC\Core\Command\Background; class Ajax extends Base { protected function getMode() { return 'ajax'; } } Background/Cron.php 0000604 00000002376 15247207135 0010247 0 ustar 00 <?php /** * The MIT License (MIT) * * Copyright (c) 2015 Christian Kampka <christian@kampka.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ namespace OC\Core\Command\Background; class Cron extends Base { protected function getMode() { return 'cron'; } } Background/WebCron.php 0000604 00000002404 15247207135 0010675 0 ustar 00 <?php /** * The MIT License (MIT) * * Copyright (c) 2015 Christian Kampka <christian@kampka.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ namespace OC\Core\Command\Background; class WebCron extends Base { protected function getMode() { return 'webcron'; } } Background/Base.php 0000604 00000004701 15247207135 0010212 0 ustar 00 <?php /** * The MIT License (MIT) * * Copyright (c) 2015 Christian Kampka <christian@kampka.net> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ namespace OC\Core\Command\Background; use \OCP\IConfig; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * An abstract base class for configuring the background job mode * from the command line interface. * Subclasses will override the getMode() function to specify the mode to configure. */ abstract class Base extends Command { abstract protected function getMode(); /** * @var \OCP\IConfig */ protected $config; /** * @param \OCP\IConfig $config */ public function __construct(IConfig $config) { $this->config = $config; parent::__construct(); } protected function configure() { $mode = $this->getMode(); $this ->setName("background:$mode") ->setDescription("Use $mode to run background jobs"); } /** * Executing this command will set the background job mode for owncloud. * The mode to set is specified by the concrete sub class by implementing the * getMode() function. * * @param InputInterface $input * @param OutputInterface $output */ protected function execute(InputInterface $input, OutputInterface $output) { $mode = $this->getMode(); $this->config->setAppValue( 'core', 'backgroundjobs_mode', $mode ); $output->writeln("Set mode for background jobs to '$mode'"); } } Log/File.php 0000604 00000010503 15247207135 0006656 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Robin McCorkell <robin@mccorkell.me.uk> * @author Thomas Pulzer <t.pulzer@kniel.de> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Log; use \OCP\IConfig; use Stecman\Component\Symfony\Console\BashCompletion\Completion; use Stecman\Component\Symfony\Console\BashCompletion\Completion\ShellPathCompletion; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class File extends Command implements Completion\CompletionAwareInterface { /** @var IConfig */ protected $config; public function __construct(IConfig $config) { $this->config = $config; parent::__construct(); } protected function configure() { $this ->setName('log:file') ->setDescription('manipulate logging backend') ->addOption( 'enable', null, InputOption::VALUE_NONE, 'enable this logging backend' ) ->addOption( 'file', null, InputOption::VALUE_REQUIRED, 'set the log file path' ) ->addOption( 'rotate-size', null, InputOption::VALUE_REQUIRED, 'set the file size for log rotation, 0 = disabled' ) ; } protected function execute(InputInterface $input, OutputInterface $output) { $toBeSet = []; if ($input->getOption('enable')) { $toBeSet['log_type'] = 'file'; } if ($file = $input->getOption('file')) { $toBeSet['logfile'] = $file; } if (($rotateSize = $input->getOption('rotate-size')) !== null) { $rotateSize = \OCP\Util::computerFileSize($rotateSize); $this->validateRotateSize($rotateSize); $toBeSet['log_rotate_size'] = $rotateSize; } // set config foreach ($toBeSet as $option => $value) { $this->config->setSystemValue($option, $value); } // display config // TODO: Drop backwards compatibility for config in the future $logType = $this->config->getSystemValue('log_type', 'file'); if ($logType === 'file' || $logType === 'owncloud') { $enabledText = 'enabled'; } else { $enabledText = 'disabled'; } $output->writeln('Log backend file: '.$enabledText); $dataDir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data'); $defaultLogFile = rtrim($dataDir, '/').'/nextcloud.log'; $output->writeln('Log file: '.$this->config->getSystemValue('logfile', $defaultLogFile)); $rotateSize = $this->config->getSystemValue('log_rotate_size', 0); if ($rotateSize) { $rotateString = \OCP\Util::humanFileSize($rotateSize); } else { $rotateString = 'disabled'; } $output->writeln('Rotate at: '.$rotateString); } /** * @param mixed $rotateSize * @throws \InvalidArgumentException */ protected function validateRotateSize(&$rotateSize) { if ($rotateSize === false) { throw new \InvalidArgumentException('Error parsing log rotation file size'); } $rotateSize = (int) $rotateSize; if ($rotateSize < 0) { throw new \InvalidArgumentException('Log rotation file size must be non-negative'); } } /** * @param string $optionName * @param CompletionContext $context * @return string[] */ public function completeOptionValues($optionName, CompletionContext $context) { if ($optionName === 'file') { $helper = new ShellPathCompletion( $this->getName(), 'file', Completion::TYPE_OPTION ); return $helper->run(); } else if ($optionName === 'rotate-size') { return [0]; } return []; } /** * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { return []; } } Log/Manage.php 0000604 00000012163 15247207135 0007173 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * @author Robin McCorkell <robin@mccorkell.me.uk> * @author Roeland Jago Douma <roeland@famdouma.nl> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Log; use OCP\IConfig; use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Manage extends Command implements CompletionAwareInterface { const DEFAULT_BACKEND = 'file'; const DEFAULT_LOG_LEVEL = 2; const DEFAULT_TIMEZONE = 'UTC'; /** @var IConfig */ protected $config; public function __construct(IConfig $config) { $this->config = $config; parent::__construct(); } protected function configure() { $this ->setName('log:manage') ->setDescription('manage logging configuration') ->addOption( 'backend', null, InputOption::VALUE_REQUIRED, 'set the logging backend [file, syslog, errorlog]' ) ->addOption( 'level', null, InputOption::VALUE_REQUIRED, 'set the log level [debug, info, warning, error]' ) ->addOption( 'timezone', null, InputOption::VALUE_REQUIRED, 'set the logging timezone' ) ; } protected function execute(InputInterface $input, OutputInterface $output) { // collate config setting to the end, to avoid partial configuration $toBeSet = []; if ($backend = $input->getOption('backend')) { $this->validateBackend($backend); $toBeSet['log_type'] = $backend; } $level = $input->getOption('level'); if ($level !== null) { if (is_numeric($level)) { $levelNum = $level; // sanity check $this->convertLevelNumber($levelNum); } else { $levelNum = $this->convertLevelString($level); } $toBeSet['loglevel'] = $levelNum; } if ($timezone = $input->getOption('timezone')) { $this->validateTimezone($timezone); $toBeSet['logtimezone'] = $timezone; } // set config foreach ($toBeSet as $option => $value) { $this->config->setSystemValue($option, $value); } // display configuration $backend = $this->config->getSystemValue('log_type', self::DEFAULT_BACKEND); $output->writeln('Enabled logging backend: '.$backend); $levelNum = $this->config->getSystemValue('loglevel', self::DEFAULT_LOG_LEVEL); $level = $this->convertLevelNumber($levelNum); $output->writeln('Log level: '.$level.' ('.$levelNum.')'); $timezone = $this->config->getSystemValue('logtimezone', self::DEFAULT_TIMEZONE); $output->writeln('Log timezone: '.$timezone); } /** * @param string $backend * @throws \InvalidArgumentException */ protected function validateBackend($backend) { if (!class_exists('OC\\Log\\'.ucfirst($backend))) { throw new \InvalidArgumentException('Invalid backend'); } } /** * @param string $timezone * @throws \Exception */ protected function validateTimezone($timezone) { new \DateTimeZone($timezone); } /** * @param string $level * @return int * @throws \InvalidArgumentException */ protected function convertLevelString($level) { $level = strtolower($level); switch ($level) { case 'debug': return 0; case 'info': return 1; case 'warning': case 'warn': return 2; case 'error': case 'err': return 3; } throw new \InvalidArgumentException('Invalid log level string'); } /** * @param int $levelNum * @return string * @throws \InvalidArgumentException */ protected function convertLevelNumber($levelNum) { switch ($levelNum) { case 0: return 'Debug'; case 1: return 'Info'; case 2: return 'Warning'; case 3: return 'Error'; } throw new \InvalidArgumentException('Invalid log level number'); } /** * @param string $optionName * @param CompletionContext $context * @return string[] */ public function completeOptionValues($optionName, CompletionContext $context) { if ($optionName === 'backend') { return ['file', 'syslog', 'errorlog']; } else if ($optionName === 'level') { return ['debug', 'info', 'warning', 'error']; } else if ($optionName === 'timezone') { return \DateTimeZone::listIdentifiers(); } return []; } /** * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { return []; } } Maintenance/Repair.php 0000604 00000011352 15247207135 0010725 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin Appelman <robin@icewind.nl> * @author Thomas Müller <thomas.mueller@tmit.eu> * @author Vincent Petry <pvince81@owncloud.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Maintenance; use Exception; use OCP\IConfig; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\GenericEvent; class Repair extends Command { /** @var \OC\Repair $repair */ protected $repair; /** @var IConfig */ protected $config; /** @var EventDispatcherInterface */ private $dispatcher; /** @var ProgressBar */ private $progress; /** @var OutputInterface */ private $output; /** * @param \OC\Repair $repair * @param IConfig $config */ public function __construct(\OC\Repair $repair, IConfig $config, EventDispatcherInterface $dispatcher) { $this->repair = $repair; $this->config = $config; $this->dispatcher = $dispatcher; parent::__construct(); } protected function configure() { $this ->setName('maintenance:repair') ->setDescription('repair this installation') ->addOption( 'include-expensive', null, InputOption::VALUE_NONE, 'Use this option when you want to include resource and load expensive tasks'); } protected function execute(InputInterface $input, OutputInterface $output) { $includeExpensive = $input->getOption('include-expensive'); if ($includeExpensive) { foreach ($this->repair->getExpensiveRepairSteps() as $step) { $this->repair->addStep($step); } } $apps = \OC::$server->getAppManager()->getInstalledApps(); foreach ($apps as $app) { if (!\OC_App::isEnabled($app)) { continue; } $info = \OC_App::getAppInfo($app); if (!is_array($info)) { continue; } $steps = $info['repair-steps']['post-migration']; foreach ($steps as $step) { try { $this->repair->addStep($step); } catch (Exception $ex) { $output->writeln("<error>Failed to load repair step for $app: {$ex->getMessage()}</error>"); } } } $maintenanceMode = $this->config->getSystemValue('maintenance', false); $this->config->setSystemValue('maintenance', true); $this->progress = new ProgressBar($output); $this->output = $output; $this->dispatcher->addListener('\OC\Repair::startProgress', [$this, 'handleRepairFeedBack']); $this->dispatcher->addListener('\OC\Repair::advance', [$this, 'handleRepairFeedBack']); $this->dispatcher->addListener('\OC\Repair::finishProgress', [$this, 'handleRepairFeedBack']); $this->dispatcher->addListener('\OC\Repair::step', [$this, 'handleRepairFeedBack']); $this->dispatcher->addListener('\OC\Repair::info', [$this, 'handleRepairFeedBack']); $this->dispatcher->addListener('\OC\Repair::warning', [$this, 'handleRepairFeedBack']); $this->dispatcher->addListener('\OC\Repair::error', [$this, 'handleRepairFeedBack']); $this->repair->run(); $this->config->setSystemValue('maintenance', $maintenanceMode); } public function handleRepairFeedBack($event) { if (!$event instanceof GenericEvent) { return; } switch ($event->getSubject()) { case '\OC\Repair::startProgress': $this->progress->start($event->getArgument(0)); break; case '\OC\Repair::advance': $this->progress->advance($event->getArgument(0)); break; case '\OC\Repair::finishProgress': $this->progress->finish(); $this->output->writeln(''); break; case '\OC\Repair::step': $this->output->writeln(' - ' . $event->getArgument(0)); break; case '\OC\Repair::info': $this->output->writeln(' - ' . $event->getArgument(0)); break; case '\OC\Repair::warning': $this->output->writeln(' - WARNING: ' . $event->getArgument(0)); break; case '\OC\Repair::error': $this->output->writeln(' - ERROR: ' . $event->getArgument(0)); break; } } } Maintenance/UpdateHtaccess.php 0000604 00000003011 15247207135 0012374 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Lukas Reschke <lukas@statuscode.ch> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Maintenance; use InvalidArgumentException; use OC\Setup; use OCP\IConfig; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class UpdateHtaccess extends Command { protected function configure() { $this ->setName('maintenance:update:htaccess') ->setDescription('Updates the .htaccess file'); } protected function execute(InputInterface $input, OutputInterface $output) { if (\OC\Setup::updateHtaccess()) { $output->writeln('.htaccess has been updated'); return 0; } else { $output->writeln('<error>Error updating .htaccess file, not enough permissions?</error>'); return 1; } } } Maintenance/Install.php 0000604 00000015724 15247207135 0011120 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Bernhard Posselt <dev@bernhard-posselt.com> * @author Christian Kampka <christian@kampka.net> * @author Joas Schilling <coding@schilljs.com> * @author Jörn Friedrich Dreyer <jfd@butonic.de> * @author Morris Jobke <hey@morrisjobke.de> * @author Thomas Müller <thomas.mueller@tmit.eu> * @author Thomas Pulzer <t.pulzer@kniel.de> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Maintenance; use InvalidArgumentException; use OC\Setup; use OC\SystemConfig; use OCP\Defaults; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\Question; class Install extends Command { /** * @var SystemConfig */ private $config; public function __construct(SystemConfig $config) { parent::__construct(); $this->config = $config; } protected function configure() { $this ->setName('maintenance:install') ->setDescription('install Nextcloud') ->addOption('database', null, InputOption::VALUE_REQUIRED, 'Supported database type', 'sqlite') ->addOption('database-name', null, InputOption::VALUE_REQUIRED, 'Name of the database') ->addOption('database-host', null, InputOption::VALUE_REQUIRED, 'Hostname of the database', 'localhost') ->addOption('database-port', null, InputOption::VALUE_REQUIRED, 'Port the database is listening on') ->addOption('database-user', null, InputOption::VALUE_REQUIRED, 'User name to connect to the database') ->addOption('database-pass', null, InputOption::VALUE_OPTIONAL, 'Password of the database user', null) ->addOption('database-table-prefix', null, InputOption::VALUE_OPTIONAL, 'Prefix for all tables (default: oc_)', null) ->addOption('database-table-space', null, InputOption::VALUE_OPTIONAL, 'Table space of the database (oci only)', null) ->addOption('admin-user', null, InputOption::VALUE_REQUIRED, 'User name of the admin account', 'admin') ->addOption('admin-pass', null, InputOption::VALUE_REQUIRED, 'Password of the admin account') ->addOption('data-dir', null, InputOption::VALUE_REQUIRED, 'Path to data directory', \OC::$SERVERROOT."/data"); } protected function execute(InputInterface $input, OutputInterface $output) { // validate the environment $server = \OC::$server; $setupHelper = new Setup($this->config, $server->getIniWrapper(), $server->getL10N('lib'), $server->query(Defaults::class), $server->getLogger(), $server->getSecureRandom()); $sysInfo = $setupHelper->getSystemInfo(true); $errors = $sysInfo['errors']; if (count($errors) > 0) { $this->printErrors($output, $errors); // ignore the OS X setup warning if(count($errors) !== 1 || (string)($errors[0]['error']) !== 'Mac OS X is not supported and Nextcloud will not work properly on this platform. Use it at your own risk! ') { return 1; } } // validate user input $options = $this->validateInput($input, $output, array_keys($sysInfo['databases'])); // perform installation $errors = $setupHelper->install($options); if (count($errors) > 0) { $this->printErrors($output, $errors); return 1; } $output->writeln("Nextcloud was successfully installed"); return 0; } /** * @param InputInterface $input * @param OutputInterface $output * @param string[] $supportedDatabases * @return array */ protected function validateInput(InputInterface $input, OutputInterface $output, $supportedDatabases) { $db = strtolower($input->getOption('database')); if (!in_array($db, $supportedDatabases)) { throw new InvalidArgumentException("Database <$db> is not supported."); } $dbUser = $input->getOption('database-user'); $dbPass = $input->getOption('database-pass'); $dbName = $input->getOption('database-name'); $dbPort = $input->getOption('database-port'); if ($db === 'oci') { // an empty hostname needs to be read from the raw parameters $dbHost = $input->getParameterOption('--database-host', ''); } else { $dbHost = $input->getOption('database-host'); } $dbTablePrefix = 'oc_'; if ($input->hasParameterOption('--database-table-prefix')) { $dbTablePrefix = (string) $input->getOption('database-table-prefix'); $dbTablePrefix = trim($dbTablePrefix); } if ($input->hasParameterOption('--database-pass')) { $dbPass = (string) $input->getOption('database-pass'); } $adminLogin = $input->getOption('admin-user'); $adminPassword = $input->getOption('admin-pass'); $dataDir = $input->getOption('data-dir'); if ($db !== 'sqlite') { if (is_null($dbUser)) { throw new InvalidArgumentException("Database user not provided."); } if (is_null($dbName)) { throw new InvalidArgumentException("Database name not provided."); } if (is_null($dbPass)) { /** @var QuestionHelper $helper */ $helper = $this->getHelper('question'); $question = new Question('What is the password to access the database with user <'.$dbUser.'>?'); $question->setHidden(true); $question->setHiddenFallback(false); $dbPass = $helper->ask($input, $output, $question); } } if (is_null($adminPassword)) { /** @var QuestionHelper $helper */ $helper = $this->getHelper('question'); $question = new Question('What is the password you like to use for the admin account <'.$adminLogin.'>?'); $question->setHidden(true); $question->setHiddenFallback(false); $adminPassword = $helper->ask($input, $output, $question); } $options = [ 'dbtype' => $db, 'dbuser' => $dbUser, 'dbpass' => $dbPass, 'dbname' => $dbName, 'dbhost' => $dbHost, 'dbport' => $dbPort, 'dbtableprefix' => $dbTablePrefix, 'adminlogin' => $adminLogin, 'adminpass' => $adminPassword, 'directory' => $dataDir ]; if ($db === 'oci') { $options['dbtablespace'] = $input->getParameterOption('--database-table-space', ''); } return $options; } /** * @param OutputInterface $output * @param $errors */ protected function printErrors(OutputInterface $output, $errors) { foreach ($errors as $error) { if (is_array($error)) { $output->writeln('<error>' . (string)$error['error'] . '</error>'); $output->writeln('<info> -> ' . (string)$error['hint'] . '</info>'); } else { $output->writeln('<error>' . (string)$error . '</error>'); } } } } Maintenance/Mode.php 0000604 00000004143 15247207135 0010367 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Morris Jobke <hey@morrisjobke.de> * @author scolebrook <scolebrook@mac.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Maintenance; use \OCP\IConfig; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Mode extends Command { /** @var IConfig */ protected $config; public function __construct(IConfig $config) { $this->config = $config; parent::__construct(); } protected function configure() { $this ->setName('maintenance:mode') ->setDescription('set maintenance mode') ->addOption( 'on', null, InputOption::VALUE_NONE, 'enable maintenance mode' ) ->addOption( 'off', null, InputOption::VALUE_NONE, 'disable maintenance mode' ); } protected function execute(InputInterface $input, OutputInterface $output) { if ($input->getOption('on')) { $this->config->setSystemValue('maintenance', true); $output->writeln('Maintenance mode enabled'); } elseif ($input->getOption('off')) { $this->config->setSystemValue('maintenance', false); $output->writeln('Maintenance mode disabled'); } else { if ($this->config->getSystemValue('maintenance', false)) { $output->writeln('Maintenance mode is currently enabled'); } else { $output->writeln('Maintenance mode is currently disabled'); } } } } Maintenance/DataFingerprint.php 0000604 00000003212 15247207135 0012560 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Roeland Jago Douma <roeland@famdouma.nl> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Maintenance; use OCP\AppFramework\Utility\ITimeFactory; use OCP\IConfig; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class DataFingerprint extends Command { /** @var IConfig */ protected $config; /** @var ITimeFactory */ protected $timeFactory; public function __construct(IConfig $config, ITimeFactory $timeFactory) { $this->config = $config; $this->timeFactory = $timeFactory; parent::__construct(); } protected function configure() { $this ->setName('maintenance:data-fingerprint') ->setDescription('update the systems data-fingerprint after a backup is restored'); } protected function execute(InputInterface $input, OutputInterface $output) { $this->config->setSystemValue('data-fingerprint', md5($this->timeFactory->getTime())); } } Maintenance/Mimetype/UpdateJS.php 0000604 00000007126 15247207135 0012757 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * @author Robin McCorkell <robin@mccorkell.me.uk> * @author Roeland Jago Douma <roeland@famdouma.nl> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Maintenance\Mimetype; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use OCP\Files\IMimeTypeDetector; class UpdateJS extends Command { /** @var IMimeTypeDetector */ protected $mimetypeDetector; public function __construct( IMimeTypeDetector $mimetypeDetector ) { parent::__construct(); $this->mimetypeDetector = $mimetypeDetector; } protected function configure() { $this ->setName('maintenance:mimetype:update-js') ->setDescription('Update mimetypelist.js'); } protected function execute(InputInterface $input, OutputInterface $output) { // Fetch all the aliases $aliases = $this->mimetypeDetector->getAllAliases(); // Remove comments $keys = array_filter(array_keys($aliases), function($k) { return $k[0] === '_'; }); foreach($keys as $key) { unset($aliases[$key]); } // Fetch all files $dir = new \DirectoryIterator(\OC::$SERVERROOT.'/core/img/filetypes'); $files = []; foreach($dir as $fileInfo) { if ($fileInfo->isFile()) { $file = preg_replace('/.[^.]*$/', '', $fileInfo->getFilename()); $files[] = $file; } } //Remove duplicates $files = array_values(array_unique($files)); sort($files); // Fetch all themes! $themes = []; $dirs = new \DirectoryIterator(\OC::$SERVERROOT.'/themes/'); foreach($dirs as $dir) { //Valid theme dir if ($dir->isFile() || $dir->isDot()) { continue; } $theme = $dir->getFilename(); $themeDir = $dir->getPath() . '/' . $theme . '/core/img/filetypes/'; // Check if this theme has its own filetype icons if (!file_exists($themeDir)) { continue; } $themes[$theme] = []; // Fetch all the theme icons! $themeIt = new \DirectoryIterator($themeDir); foreach ($themeIt as $fileInfo) { if ($fileInfo->isFile()) { $file = preg_replace('/.[^.]*$/', '', $fileInfo->getFilename()); $themes[$theme][] = $file; } } //Remove Duplicates $themes[$theme] = array_values(array_unique($themes[$theme])); sort($themes[$theme]); } //Generate the JS $js = '/** * This file is automatically generated * DO NOT EDIT MANUALLY! * * You can update the list of MimeType Aliases in config/mimetypealiases.json * The list of files is fetched from core/img/filetypes * To regenerate this file run ./occ maintenance:mimetypesjs */ OC.MimeTypeList={ aliases: ' . json_encode($aliases, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . ', files: ' . json_encode($files, JSON_PRETTY_PRINT) . ', themes: ' . json_encode($themes, JSON_PRETTY_PRINT) . ' }; '; //Output the JS file_put_contents(\OC::$SERVERROOT.'/core/js/mimetypelist.js', $js); $output->writeln('<info>mimetypelist.js is updated'); } } Maintenance/Mimetype/UpdateDB.php 0000604 00000005600 15247207135 0012723 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Robin McCorkell <robin@mccorkell.me.uk> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Maintenance\Mimetype; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputOption; use OCP\Files\IMimeTypeDetector; use OCP\Files\IMimeTypeLoader; class UpdateDB extends Command { const DEFAULT_MIMETYPE = 'application/octet-stream'; /** @var IMimeTypeDetector */ protected $mimetypeDetector; /** @var IMimeTypeLoader */ protected $mimetypeLoader; public function __construct( IMimeTypeDetector $mimetypeDetector, IMimeTypeLoader $mimetypeLoader ) { parent::__construct(); $this->mimetypeDetector = $mimetypeDetector; $this->mimetypeLoader = $mimetypeLoader; } protected function configure() { $this ->setName('maintenance:mimetype:update-db') ->setDescription('Update database mimetypes and update filecache') ->addOption( 'repair-filecache', null, InputOption::VALUE_NONE, 'Repair filecache for all mimetypes, not just new ones' ) ; } protected function execute(InputInterface $input, OutputInterface $output) { $mappings = $this->mimetypeDetector->getAllMappings(); $totalFilecacheUpdates = 0; $totalNewMimetypes = 0; foreach ($mappings as $ext => $mimetypes) { if ($ext[0] === '_') { // comment continue; } $mimetype = $mimetypes[0]; $existing = $this->mimetypeLoader->exists($mimetype); // this will add the mimetype if it didn't exist $mimetypeId = $this->mimetypeLoader->getId($mimetype); if (!$existing) { $output->writeln('Added mimetype "'.$mimetype.'" to database'); $totalNewMimetypes++; } if (!$existing || $input->getOption('repair-filecache')) { $touchedFilecacheRows = $this->mimetypeLoader->updateFilecache($ext, $mimetypeId); if ($touchedFilecacheRows > 0) { $output->writeln('Updated '.$touchedFilecacheRows.' filecache rows for mimetype "'.$mimetype.'"'); } $totalFilecacheUpdates += $touchedFilecacheRows; } } $output->writeln('Added '.$totalNewMimetypes.' new mimetypes'); $output->writeln('Updated '.$totalFilecacheUpdates.' filecache rows'); } } InterruptedException.php 0000604 00000001560 15247207135 0011445 0 ustar 00 <?php /** * @author Vincent Petry <pvince81@owncloud.com> * * @copyright Copyright (c) 2017, ownCloud, Inc. * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command; /** * Exception for when the user hit ctrl-c */ class InterruptedException extends \Exception {} App/Enable.php 0000604 00000006332 15247207135 0007171 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin Appelman <robin@icewind.nl> * @author Vincent Petry <pvince81@owncloud.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\App; use OCP\App\IAppManager; use OCP\IGroup; use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Enable extends Command implements CompletionAwareInterface { /** @var IAppManager */ protected $manager; /** * @param IAppManager $manager */ public function __construct(IAppManager $manager) { parent::__construct(); $this->manager = $manager; } protected function configure() { $this ->setName('app:enable') ->setDescription('enable an app') ->addArgument( 'app-id', InputArgument::REQUIRED, 'enable the specified app' ) ->addOption( 'groups', 'g', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'enable the app only for a list of groups' ) ; } protected function execute(InputInterface $input, OutputInterface $output) { $appId = $input->getArgument('app-id'); if (!\OC_App::getAppPath($appId)) { $output->writeln($appId . ' not found'); return 1; } $groups = $input->getOption('groups'); $appClass = new \OC_App(); if (empty($groups)) { $appClass->enable($appId); $output->writeln($appId . ' enabled'); } else { $appClass->enable($appId, $groups); $output->writeln($appId . ' enabled for groups: ' . implode(', ', $groups)); } return 0; } /** * @param string $optionName * @param CompletionContext $context * @return string[] */ public function completeOptionValues($optionName, CompletionContext $context) { if ($optionName === 'groups') { return array_map(function(IGroup $group) { return $group->getGID(); }, \OC::$server->getGroupManager()->search($context->getCurrentWord())); } return []; } /** * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'app-id') { $allApps = \OC_App::getAllApps(); return array_diff($allApps, \OC_App::getEnabledApps(true, true)); } return []; } } App/CheckCode.php 0000604 00000021213 15247207135 0007606 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin McCorkell <robin@mccorkell.me.uk> * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\App; use OC\App\CodeChecker\CodeChecker; use OC\App\CodeChecker\DatabaseSchemaChecker; use OC\App\CodeChecker\EmptyCheck; use OC\App\CodeChecker\InfoChecker; use OC\App\CodeChecker\LanguageParseChecker; use OC\App\InfoParser; use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class CheckCode extends Command implements CompletionAwareInterface { /** @var InfoParser */ private $infoParser; protected $checkers = [ 'private' => '\OC\App\CodeChecker\PrivateCheck', 'deprecation' => '\OC\App\CodeChecker\DeprecationCheck', 'strong-comparison' => '\OC\App\CodeChecker\StrongComparisonCheck', ]; public function __construct(InfoParser $infoParser) { parent::__construct(); $this->infoParser = $infoParser; } protected function configure() { $this ->setName('app:check-code') ->setDescription('check code to be compliant') ->addArgument( 'app-id', InputArgument::REQUIRED, 'check the specified app' ) ->addOption( 'checker', 'c', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'enable the specified checker(s)', [ 'private', 'deprecation', 'strong-comparison' ] ) ->addOption( '--skip-checkers', null, InputOption::VALUE_NONE, 'skips the the code checkers to only check info.xml, language and database schema' ) ->addOption( '--skip-validate-info', null, InputOption::VALUE_NONE, 'skips the info.xml/version check' ); } protected function execute(InputInterface $input, OutputInterface $output) { $appId = $input->getArgument('app-id'); $checkList = new EmptyCheck(); foreach ($input->getOption('checker') as $checker) { if (!isset($this->checkers[$checker])) { throw new \InvalidArgumentException('Invalid checker: '.$checker); } $checkerClass = $this->checkers[$checker]; $checkList = new $checkerClass($checkList); } $codeChecker = new CodeChecker($checkList); $codeChecker->listen('CodeChecker', 'analyseFileBegin', function($params) use ($output) { if(OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $output->writeln("<info>Analysing {$params}</info>"); } }); $codeChecker->listen('CodeChecker', 'analyseFileFinished', function($filename, $errors) use ($output) { $count = count($errors); // show filename if the verbosity is low, but there are errors in a file if($count > 0 && OutputInterface::VERBOSITY_VERBOSE > $output->getVerbosity()) { $output->writeln("<info>Analysing {$filename}</info>"); } // show error count if there are errors present or the verbosity is high if($count > 0 || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $output->writeln(" {$count} errors"); } usort($errors, function($a, $b) { return $a['line'] >$b['line']; }); foreach($errors as $p) { $line = sprintf("%' 4d", $p['line']); $output->writeln(" <error>line $line: {$p['disallowedToken']} - {$p['reason']}</error>"); } }); $errors = []; if(!$input->getOption('skip-checkers')) { $errors = $codeChecker->analyse($appId); } if(!$input->getOption('skip-validate-info')) { $infoChecker = new InfoChecker($this->infoParser); $infoChecker->listen('InfoChecker', 'mandatoryFieldMissing', function($key) use ($output) { $output->writeln("<error>Mandatory field missing: $key</error>"); }); $infoChecker->listen('InfoChecker', 'deprecatedFieldFound', function($key, $value) use ($output) { if($value === [] || is_null($value) || $value === '') { $output->writeln("<info>Deprecated field available: $key</info>"); } else { $output->writeln("<info>Deprecated field available: $key => $value</info>"); } }); $infoChecker->listen('InfoChecker', 'missingRequirement', function($minMax) use ($output) { $output->writeln("<comment>Nextcloud $minMax version requirement missing (will be an error in Nextcloud 12 and later)</comment>"); }); $infoChecker->listen('InfoChecker', 'duplicateRequirement', function($minMax) use ($output) { $output->writeln("<error>Duplicate $minMax ownCloud version requirement found</error>"); }); $infoChecker->listen('InfoChecker', 'differentVersions', function($versionFile, $infoXML) use ($output) { $output->writeln("<error>Different versions provided (appinfo/version: $versionFile - appinfo/info.xml: $infoXML)</error>"); }); $infoChecker->listen('InfoChecker', 'sameVersions', function($path) use ($output) { $output->writeln("<info>Version file isn't needed anymore and can be safely removed ($path)</info>"); }); $infoChecker->listen('InfoChecker', 'migrateVersion', function($version) use ($output) { $output->writeln("<info>Migrate the app version to appinfo/info.xml (add <version>$version</version> to appinfo/info.xml and remove appinfo/version)</info>"); }); if(OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $infoChecker->listen('InfoChecker', 'mandatoryFieldFound', function($key, $value) use ($output) { $output->writeln("<info>Mandatory field available: $key => $value</info>"); }); $infoChecker->listen('InfoChecker', 'optionalFieldFound', function($key, $value) use ($output) { $output->writeln("<info>Optional field available: $key => $value</info>"); }); $infoChecker->listen('InfoChecker', 'unusedFieldFound', function($key, $value) use ($output) { $output->writeln("<info>Unused field available: $key => $value</info>"); }); } $infoErrors = $infoChecker->analyse($appId); $errors = array_merge($errors, $infoErrors); $languageParser = new LanguageParseChecker(); $languageErrors = $languageParser->analyse($appId); foreach ($languageErrors as $languageError) { $output->writeln("<error>$languageError</error>"); } $errors = array_merge($errors, $languageErrors); $databaseSchema = new DatabaseSchemaChecker(); $schemaErrors = $databaseSchema->analyse($appId); foreach ($schemaErrors['errors'] as $schemaError) { $output->writeln("<error>$schemaError</error>"); } foreach ($schemaErrors['warnings'] as $schemaWarning) { $output->writeln("<comment>$schemaWarning</comment>"); } $errors = array_merge($errors, $schemaErrors['errors']); } $this->analyseUpdateFile($appId, $output); if (empty($errors)) { $output->writeln('<info>App is compliant - awesome job!</info>'); return 0; } else { $output->writeln('<error>App is not compliant</error>'); return 101; } } /** * @param string $appId * @param $output */ private function analyseUpdateFile($appId, OutputInterface $output) { $appPath = \OC_App::getAppPath($appId); if ($appPath === false) { throw new \RuntimeException("No app with given id <$appId> known."); } $updatePhp = $appPath . '/appinfo/update.php'; if (file_exists($updatePhp)) { $output->writeln("<info>Deprecated file found: $updatePhp - please use repair steps</info>"); } } /** * @param string $optionName * @param CompletionContext $context * @return string[] */ public function completeOptionValues($optionName, CompletionContext $context) { if ($optionName === 'checker') { return ['private', 'deprecation', 'strong-comparison']; } return []; } /** * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'app-id') { return \OC_App::getAllApps(); } return []; } } App/Disable.php 0000604 00000005306 15247207135 0007346 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin Appelman <robin@icewind.nl> * @author Vincent Petry <pvince81@owncloud.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\App; use OCP\App\IAppManager; use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class Disable extends Command implements CompletionAwareInterface { /** @var IAppManager */ protected $manager; /** * @param IAppManager $manager */ public function __construct(IAppManager $manager) { parent::__construct(); $this->manager = $manager; } protected function configure() { $this ->setName('app:disable') ->setDescription('disable an app') ->addArgument( 'app-id', InputArgument::REQUIRED, 'disable the specified app' ); } protected function execute(InputInterface $input, OutputInterface $output) { $appId = $input->getArgument('app-id'); if ($this->manager->isInstalled($appId)) { try { $this->manager->disableApp($appId); $output->writeln($appId . ' disabled'); } catch(\Exception $e) { $output->writeln($e->getMessage()); return 2; } } else { $output->writeln('No such app enabled: ' . $appId); } } /** * @param string $optionName * @param CompletionContext $context * @return string[] */ public function completeOptionValues($optionName, CompletionContext $context) { return []; } /** * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'app-id') { return array_diff(\OC_App::getEnabledApps(true, true), $this->manager->getAlwaysEnabledApps()); } return []; } } App/GetPath.php 0000604 00000004126 15247207135 0007336 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Victor Dubiniuk <dubiniuk@owncloud.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\App; use OC\Core\Command\Base; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class GetPath extends Base { protected function configure() { parent::configure(); $this ->setName('app:getpath') ->setDescription('Get an absolute path to the app directory') ->addArgument( 'app', InputArgument::REQUIRED, 'Name of the app' ) ; } /** * Executes the current command. * * @param InputInterface $input An InputInterface instance * @param OutputInterface $output An OutputInterface instance * @return null|int null or 0 if everything went fine, or an error code */ protected function execute(InputInterface $input, OutputInterface $output) { $appName = $input->getArgument('app'); $path = \OC_App::getAppPath($appName); if ($path !== false) { $output->writeln($path); return 0; } // App not found, exit with non-zero return 1; } /** * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'app') { return \OC_App::getAllApps(); } return []; } } App/ListApps.php 0000604 00000007376 15247207135 0007553 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin Appelman <robin@icewind.nl> * @author Victor Dubiniuk <dubiniuk@owncloud.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\App; use OC\Core\Command\Base; use OCP\App\IAppManager; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class ListApps extends Base { /** @var IAppManager */ protected $manager; /** * @param IAppManager $manager */ public function __construct(IAppManager $manager) { parent::__construct(); $this->manager = $manager; } protected function configure() { parent::configure(); $this ->setName('app:list') ->setDescription('List all available apps') ->addOption( 'shipped', null, InputOption::VALUE_REQUIRED, 'true - limit to shipped apps only, false - limit to non-shipped apps only' ) ; } protected function execute(InputInterface $input, OutputInterface $output) { if ($input->getOption('shipped') === 'true' || $input->getOption('shipped') === 'false'){ $shippedFilter = $input->getOption('shipped') === 'true'; } else { $shippedFilter = null; } $apps = \OC_App::getAllApps(); $enabledApps = $disabledApps = []; $versions = \OC_App::getAppVersions(); //sort enabled apps above disabled apps foreach ($apps as $app) { if ($shippedFilter !== null && \OC_App::isShipped($app) !== $shippedFilter){ continue; } if ($this->manager->isInstalled($app)) { $enabledApps[] = $app; } else { $disabledApps[] = $app; } } $apps = ['enabled' => [], 'disabled' => []]; sort($enabledApps); foreach ($enabledApps as $app) { $apps['enabled'][$app] = (isset($versions[$app])) ? $versions[$app] : true; } sort($disabledApps); foreach ($disabledApps as $app) { $apps['disabled'][$app] = null; } $this->writeAppList($input, $output, $apps); } /** * @param InputInterface $input * @param OutputInterface $output * @param array $items */ protected function writeAppList(InputInterface $input, OutputInterface $output, $items) { switch ($input->getOption('output')) { case self::OUTPUT_FORMAT_PLAIN: $output->writeln('Enabled:'); parent::writeArrayInOutputFormat($input, $output, $items['enabled']); $output->writeln('Disabled:'); parent::writeArrayInOutputFormat($input, $output, $items['disabled']); break; default: parent::writeArrayInOutputFormat($input, $output, $items); break; } } /** * @param string $optionName * @param CompletionContext $completionContext * @return array */ public function completeOptionValues($optionName, CompletionContext $completionContext) { if ($optionName === 'shipped') { return ['true', 'false']; } return []; } /** * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { return []; } } TwoFactorAuth/Disable.php 0000604 00000003645 15247207135 0011364 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Christoph Wurst <christoph@owncloud.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\TwoFactorAuth; use OC\Authentication\TwoFactorAuth\Manager; use OCP\IUserManager; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class Disable extends Base { /** @var Manager */ private $manager; /** @var IUserManager */ protected $userManager; public function __construct(Manager $manager, IUserManager $userManager) { parent::__construct('twofactorauth:disable'); $this->manager = $manager; $this->userManager = $userManager; } protected function configure() { parent::configure(); $this->setName('twofactorauth:disable'); $this->setDescription('Disable two-factor authentication for a user'); $this->addArgument('uid', InputArgument::REQUIRED); } protected function execute(InputInterface $input, OutputInterface $output) { $uid = $input->getArgument('uid'); $user = $this->userManager->get($uid); if (is_null($user)) { $output->writeln("<error>Invalid UID</error>"); return; } $this->manager->disableTwoFactorAuthentication($user); $output->writeln("Two-factor authentication disabled for user $uid"); } } TwoFactorAuth/Enable.php 0000604 00000003637 15247207135 0011210 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Christoph Wurst <christoph@owncloud.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\TwoFactorAuth; use OC\Authentication\TwoFactorAuth\Manager; use OCP\IUserManager; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class Enable extends Base { /** @var Manager */ private $manager; /** @var IUserManager */ protected $userManager; public function __construct(Manager $manager, IUserManager $userManager) { parent::__construct('twofactorauth:enable'); $this->manager = $manager; $this->userManager = $userManager; } protected function configure() { parent::configure(); $this->setName('twofactorauth:enable'); $this->setDescription('Enable two-factor authentication for a user'); $this->addArgument('uid', InputArgument::REQUIRED); } protected function execute(InputInterface $input, OutputInterface $output) { $uid = $input->getArgument('uid'); $user = $this->userManager->get($uid); if (is_null($user)) { $output->writeln("<error>Invalid UID</error>"); return; } $this->manager->enableTwoFactorAuthentication($user); $output->writeln("Two-factor authentication enabled for user $uid"); } } TwoFactorAuth/Base.php 0000604 00000003517 15247207135 0010671 0 ustar 00 <?php /** * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\Core\Command\TwoFactorAuth; use OCP\IUserManager; use OCP\IUser; use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; class Base extends \OC\Core\Command\Base implements CompletionAwareInterface { /** @var IUserManager */ protected $userManager; /** * Return possible values for the named option * * @param string $optionName * @param CompletionContext $context * @return string[] */ public function completeOptionValues($optionName, CompletionContext $context) { return []; } /** * Return possible values for the named argument * * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { if ($argumentName === 'uid') { return array_map(function(IUser $user) { return $user->getUID(); }, $this->userManager->search($context->getCurrentWord(), 100)); } return []; } } Upgrade.php 0000604 00000026560 15247207135 0006657 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Andreas Fischer <bantu@owncloud.com> * @author Björn Schießle <bjoern@schiessle.org> * @author Joas Schilling <coding@schilljs.com> * @author Lukas Reschke <lukas@statuscode.ch> * @author Morris Jobke <hey@morrisjobke.de> * @author Owen Winkler <a_github@midnightcircus.com> * @author Steffen Lindner <mail@steffen-lindner.de> * @author Thomas Müller <thomas.mueller@tmit.eu> * @author Thomas Pulzer <t.pulzer@kniel.de> * @author Vincent Petry <pvince81@owncloud.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command; use OC\Console\TimestampFormatter; use OC\Updater; use OCP\IConfig; use OCP\ILogger; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\EventDispatcher\GenericEvent; class Upgrade extends Command { const ERROR_SUCCESS = 0; const ERROR_NOT_INSTALLED = 1; const ERROR_MAINTENANCE_MODE = 2; const ERROR_UP_TO_DATE = 0; const ERROR_INVALID_ARGUMENTS = 4; const ERROR_FAILURE = 5; /** @var IConfig */ private $config; /** @var ILogger */ private $logger; /** * @param IConfig $config * @param ILogger $logger */ public function __construct(IConfig $config, ILogger $logger) { parent::__construct(); $this->config = $config; $this->logger = $logger; } protected function configure() { $this ->setName('upgrade') ->setDescription('run upgrade routines after installation of a new release. The release has to be installed before.') ->addOption( '--no-app-disable', null, InputOption::VALUE_NONE, 'skips the disable of third party apps' ); } /** * Execute the upgrade command * * @param InputInterface $input input interface * @param OutputInterface $output output interface */ protected function execute(InputInterface $input, OutputInterface $output) { if(\OC::checkUpgrade(false)) { if (OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) { // Prepend each line with a little timestamp $timestampFormatter = new TimestampFormatter($this->config, $output->getFormatter()); $output->setFormatter($timestampFormatter); } $self = $this; $updater = new Updater( $this->config, \OC::$server->getIntegrityCodeChecker(), $this->logger ); if ($input->getOption('no-app-disable')) { $updater->setSkip3rdPartyAppsDisable(true); } $dispatcher = \OC::$server->getEventDispatcher(); $progress = new ProgressBar($output); $progress->setFormat(" %message%\n %current%/%max% [%bar%] %percent:3s%%"); $listener = function($event) use ($progress, $output) { if ($event instanceof GenericEvent) { $message = $event->getSubject(); if (OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) { $output->writeln(' Checking table ' . $message); } else { if (strlen($message) > 60) { $message = substr($message, 0, 57) . '...'; } $progress->setMessage($message); if ($event[0] === 1) { $output->writeln(''); $progress->start($event[1]); } $progress->setProgress($event[0]); if ($event[0] === $event[1]) { $progress->setMessage('Done'); $progress->finish(); $output->writeln(''); } } } }; $repairListener = function($event) use ($progress, $output) { if (!$event instanceof GenericEvent) { return; } switch ($event->getSubject()) { case '\OC\Repair::startProgress': $progress->setMessage('Starting ...'); $output->writeln($event->getArgument(1)); $output->writeln(''); $progress->start($event->getArgument(0)); break; case '\OC\Repair::advance': $desc = $event->getArgument(1); if (!empty($desc)) { $progress->setMessage($desc); } $progress->advance($event->getArgument(0)); break; case '\OC\Repair::finishProgress': $progress->setMessage('Done'); $progress->finish(); $output->writeln(''); break; case '\OC\Repair::step': if(OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) { $output->writeln('<info>Repair step: ' . $event->getArgument(0) . '</info>'); } break; case '\OC\Repair::info': if(OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) { $output->writeln('<info>Repair info: ' . $event->getArgument(0) . '</info>'); } break; case '\OC\Repair::warning': $output->writeln('<error>Repair warning: ' . $event->getArgument(0) . '</error>'); break; case '\OC\Repair::error': $output->writeln('<error>Repair error: ' . $event->getArgument(0) . '</error>'); break; } }; $dispatcher->addListener('\OC\DB\Migrator::executeSql', $listener); $dispatcher->addListener('\OC\DB\Migrator::checkTable', $listener); $dispatcher->addListener('\OC\Repair::startProgress', $repairListener); $dispatcher->addListener('\OC\Repair::advance', $repairListener); $dispatcher->addListener('\OC\Repair::finishProgress', $repairListener); $dispatcher->addListener('\OC\Repair::step', $repairListener); $dispatcher->addListener('\OC\Repair::info', $repairListener); $dispatcher->addListener('\OC\Repair::warning', $repairListener); $dispatcher->addListener('\OC\Repair::error', $repairListener); $updater->listen('\OC\Updater', 'maintenanceEnabled', function () use($output) { $output->writeln('<info>Turned on maintenance mode</info>'); }); $updater->listen('\OC\Updater', 'maintenanceDisabled', function () use($output) { $output->writeln('<info>Turned off maintenance mode</info>'); }); $updater->listen('\OC\Updater', 'maintenanceActive', function () use($output) { $output->writeln('<info>Maintenance mode is kept active</info>'); }); $updater->listen('\OC\Updater', 'updateEnd', function ($success) use($output, $self) { if ($success) { $message = "<info>Update successful</info>"; } else { $message = "<error>Update failed</error>"; } $output->writeln($message); }); $updater->listen('\OC\Updater', 'dbUpgradeBefore', function () use($output) { $output->writeln('<info>Updating database schema</info>'); }); $updater->listen('\OC\Updater', 'dbUpgrade', function () use($output) { $output->writeln('<info>Updated database</info>'); }); $updater->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($output) { $output->writeln('<info>Checking whether the database schema can be updated (this can take a long time depending on the database size)</info>'); }); $updater->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($output) { $output->writeln('<info>Checked database schema update</info>'); }); $updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($output) { $output->writeln('<comment>Disabled incompatible app: ' . $app . '</comment>'); }); $updater->listen('\OC\Updater', 'thirdPartyAppDisabled', function ($app) use ($output) { $output->writeln('<comment>Disabled 3rd-party app: ' . $app . '</comment>'); }); $updater->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use($output) { $output->writeln('<info>Checking for update of app ' . $app . ' in appstore</info>'); }); $updater->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($output) { $output->writeln('<info>Update app ' . $app . ' from appstore</info>'); }); $updater->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use($output) { $output->writeln('<info>Checked for update of app "' . $app . '" in appstore </info>'); }); $updater->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($output) { $output->writeln('<info>Checking updates of apps</info>'); }); $updater->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($output) { $output->writeln("<info>Checking whether the database schema for <$app> can be updated (this can take a long time depending on the database size)</info>"); }); $updater->listen('\OC\Updater', 'appUpgradeCheck', function () use ($output) { $output->writeln('<info>Checked database schema update for apps</info>'); }); $updater->listen('\OC\Updater', 'appUpgradeStarted', function ($app, $version) use ($output) { $output->writeln("<info>Updating <$app> ...</info>"); }); $updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($output) { $output->writeln("<info>Updated <$app> to $version</info>"); }); $updater->listen('\OC\Updater', 'failure', function ($message) use($output, $self) { $output->writeln("<error>$message</error>"); }); $updater->listen('\OC\Updater', 'setDebugLogLevel', function ($logLevel, $logLevelName) use($output) { $output->writeln("<info>Set log level to debug</info>"); }); $updater->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($output) { $output->writeln("<info>Reset log level</info>"); }); $updater->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($output) { $output->writeln("<info>Starting code integrity check...</info>"); }); $updater->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($output) { $output->writeln("<info>Finished code integrity check</info>"); }); $success = $updater->upgrade(); $this->postUpgradeCheck($input, $output); if(!$success) { return self::ERROR_FAILURE; } return self::ERROR_SUCCESS; } else if($this->config->getSystemValue('maintenance', false)) { //Possible scenario: Nextcloud core is updated but an app failed $output->writeln('<warning>Nextcloud is in maintenance mode</warning>'); $output->write('<comment>Maybe an upgrade is already in process. Please check the ' . 'logfile (data/nextcloud.log). If you want to re-run the ' . 'upgrade procedure, remove the "maintenance mode" from ' . 'config.php and call this script again.</comment>' , true); return self::ERROR_MAINTENANCE_MODE; } else { $output->writeln('<info>Nextcloud is already latest version</info>'); return self::ERROR_UP_TO_DATE; } } /** * Perform a post upgrade check (specific to the command line tool) * * @param InputInterface $input input interface * @param OutputInterface $output output interface */ protected function postUpgradeCheck(InputInterface $input, OutputInterface $output) { $trustedDomains = $this->config->getSystemValue('trusted_domains', array()); if (empty($trustedDomains)) { $output->write( '<warning>The setting "trusted_domains" could not be ' . 'set automatically by the upgrade script, ' . 'please set it manually</warning>' ); } } } Integrity/CheckCore.php 0000604 00000003306 15247207135 0011065 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Carla Schroder <carla@owncloud.com> * @author Victor Dubiniuk <dubiniuk@owncloud.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Integrity; use OC\IntegrityCheck\Checker; use OC\Core\Command\Base; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * Class CheckCore * * @package OC\Core\Command\Integrity */ class CheckCore extends Base { /** * @var Checker */ private $checker; public function __construct(Checker $checker) { parent::__construct(); $this->checker = $checker; } /** * {@inheritdoc } */ protected function configure() { parent::configure(); $this ->setName('integrity:check-core') ->setDescription('Check integrity of core code using a signature.'); } /** * {@inheritdoc } */ protected function execute(InputInterface $input, OutputInterface $output) { $result = $this->checker->verifyCoreSignature(); $this->writeArrayInOutputFormat($input, $output, $result); if (count($result)>0){ return 1; } } } Integrity/SignCore.php 0000604 00000006265 15247207135 0010757 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Lukas Reschke <lukas@statuscode.ch> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Integrity; use OC\IntegrityCheck\Checker; use OC\IntegrityCheck\Helpers\FileAccessHelper; use phpseclib\Crypt\RSA; use phpseclib\File\X509; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** * Class SignCore * * @package OC\Core\Command\Integrity */ class SignCore extends Command { /** @var Checker */ private $checker; /** @var FileAccessHelper */ private $fileAccessHelper; /** * @param Checker $checker * @param FileAccessHelper $fileAccessHelper */ public function __construct(Checker $checker, FileAccessHelper $fileAccessHelper) { parent::__construct(null); $this->checker = $checker; $this->fileAccessHelper = $fileAccessHelper; } protected function configure() { $this ->setName('integrity:sign-core') ->setDescription('Sign core using a private key.') ->addOption('privateKey', null, InputOption::VALUE_REQUIRED, 'Path to private key to use for signing') ->addOption('certificate', null, InputOption::VALUE_REQUIRED, 'Path to certificate to use for signing') ->addOption('path', null, InputOption::VALUE_REQUIRED, 'Path of core to sign'); } /** * {@inheritdoc } */ protected function execute(InputInterface $input, OutputInterface $output) { $privateKeyPath = $input->getOption('privateKey'); $keyBundlePath = $input->getOption('certificate'); $path = $input->getOption('path'); if(is_null($privateKeyPath) || is_null($keyBundlePath) || is_null($path)) { $output->writeln('--privateKey, --certificate and --path are required.'); return null; } $privateKey = $this->fileAccessHelper->file_get_contents($privateKeyPath); $keyBundle = $this->fileAccessHelper->file_get_contents($keyBundlePath); if($privateKey === false) { $output->writeln(sprintf('Private key "%s" does not exists.', $privateKeyPath)); return null; } if($keyBundle === false) { $output->writeln(sprintf('Certificate "%s" does not exists.', $keyBundlePath)); return null; } $rsa = new RSA(); $rsa->loadKey($privateKey); $x509 = new X509(); $x509->loadX509($keyBundle); $x509->setPrivateKey($rsa); try { $this->checker->writeCoreSignature($x509, $rsa, $path); $output->writeln('Successfully signed "core"'); } catch (\Exception $e){ $output->writeln('Error: ' . $e->getMessage()); return 1; } return 0; } } Integrity/SignApp.php 0000604 00000007415 15247207135 0010605 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Lukas Reschke <lukas@statuscode.ch> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Integrity; use OC\IntegrityCheck\Checker; use OC\IntegrityCheck\Helpers\FileAccessHelper; use OCP\IURLGenerator; use phpseclib\Crypt\RSA; use phpseclib\File\X509; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** * Class SignApp * * @package OC\Core\Command\Integrity */ class SignApp extends Command { /** @var Checker */ private $checker; /** @var FileAccessHelper */ private $fileAccessHelper; /** @var IURLGenerator */ private $urlGenerator; /** * @param Checker $checker * @param FileAccessHelper $fileAccessHelper * @param IURLGenerator $urlGenerator */ public function __construct(Checker $checker, FileAccessHelper $fileAccessHelper, IURLGenerator $urlGenerator) { parent::__construct(null); $this->checker = $checker; $this->fileAccessHelper = $fileAccessHelper; $this->urlGenerator = $urlGenerator; } protected function configure() { $this ->setName('integrity:sign-app') ->setDescription('Signs an app using a private key.') ->addOption('path', null, InputOption::VALUE_REQUIRED, 'Application to sign') ->addOption('privateKey', null, InputOption::VALUE_REQUIRED, 'Path to private key to use for signing') ->addOption('certificate', null, InputOption::VALUE_REQUIRED, 'Path to certificate to use for signing'); } /** * {@inheritdoc } */ protected function execute(InputInterface $input, OutputInterface $output) { $path = $input->getOption('path'); $privateKeyPath = $input->getOption('privateKey'); $keyBundlePath = $input->getOption('certificate'); if(is_null($path) || is_null($privateKeyPath) || is_null($keyBundlePath)) { $documentationUrl = $this->urlGenerator->linkToDocs('developer-code-integrity'); $output->writeln('This command requires the --path, --privateKey and --certificate.'); $output->writeln('Example: ./occ integrity:sign-app --path="/Users/lukasreschke/Programming/myapp/" --privateKey="/Users/lukasreschke/private/myapp.key" --certificate="/Users/lukasreschke/public/mycert.crt"'); $output->writeln('For more information please consult the documentation: '. $documentationUrl); return null; } $privateKey = $this->fileAccessHelper->file_get_contents($privateKeyPath); $keyBundle = $this->fileAccessHelper->file_get_contents($keyBundlePath); if($privateKey === false) { $output->writeln(sprintf('Private key "%s" does not exists.', $privateKeyPath)); return null; } if($keyBundle === false) { $output->writeln(sprintf('Certificate "%s" does not exists.', $keyBundlePath)); return null; } $rsa = new RSA(); $rsa->loadKey($privateKey); $x509 = new X509(); $x509->loadX509($keyBundle); $x509->setPrivateKey($rsa); try { $this->checker->writeAppSignature($path, $x509, $rsa); $output->writeln('Successfully signed "'.$path.'"'); } catch (\Exception $e){ $output->writeln('Error: ' . $e->getMessage()); return 1; } return 0; } } Integrity/CheckApp.php 0000604 00000004120 15247207135 0010710 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Carla Schroder <carla@owncloud.com> * @author Victor Dubiniuk <dubiniuk@owncloud.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Integrity; use OC\IntegrityCheck\Checker; use OC\Core\Command\Base; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** * Class CheckApp * * @package OC\Core\Command\Integrity */ class CheckApp extends Base { /** * @var Checker */ private $checker; public function __construct(Checker $checker) { parent::__construct(); $this->checker = $checker; } /** * {@inheritdoc } */ protected function configure() { parent::configure(); $this ->setName('integrity:check-app') ->setDescription('Check integrity of an app using a signature.') ->addArgument('appid', null, InputArgument::REQUIRED, 'Application to check') ->addOption('path', null, InputOption::VALUE_OPTIONAL, 'Path to application. If none is given it will be guessed.'); } /** * {@inheritdoc } */ protected function execute(InputInterface $input, OutputInterface $output) { $appid = $input->getArgument('appid'); $path = strval($input->getOption('path')); $result = $this->checker->verifyAppSignature($appid, $path); $this->writeArrayInOutputFormat($input, $output, $result); if (count($result)>0){ return 1; } } } Check.php 0000604 00000003245 15247207135 0006300 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command; use OC\SystemConfig; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class Check extends Base { /** * @var SystemConfig */ private $config; public function __construct(SystemConfig $config) { parent::__construct(); $this->config = $config; } protected function configure() { parent::configure(); $this ->setName('check') ->setDescription('check dependencies of the server environment') ; } protected function execute(InputInterface $input, OutputInterface $output) { $errors = \OC_Util::checkServer($this->config); if (!empty($errors)) { $errors = array_map(function($item) { return (string) $item['error']; }, $errors); $this->writeArrayInOutputFormat($input, $output, $errors); return 1; } return 0; } } Security/RemoveCertificate.php 0000604 00000003531 15247207135 0012470 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Carla Schroder <carla@owncloud.com> * @author Robin Appelman <robin@icewind.nl> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Security; use OC\Core\Command\Base; use OCP\ICertificateManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class RemoveCertificate extends Base { /** @var ICertificateManager */ protected $certificateManager; public function __construct(ICertificateManager $certificateManager) { $this->certificateManager = $certificateManager; parent::__construct(); } protected function configure() { $this ->setName('security:certificates:remove') ->setDescription('remove trusted certificate') ->addArgument( 'name', InputArgument::REQUIRED, 'the file name of the certificate to remove' ); } protected function execute(InputInterface $input, OutputInterface $output) { $name = $input->getArgument('name'); $this->certificateManager->removeCertificate($name); } } Security/ListCertificates.php 0000604 00000006120 15247207135 0012326 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Robin Appelman <robin@icewind.nl> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Security; use OC\Core\Command\Base; use OCP\ICertificate; use OCP\ICertificateManager; use OCP\IL10N; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class ListCertificates extends Base { /** @var ICertificateManager */ protected $certificateManager; /** @var IL10N */ protected $l; public function __construct(ICertificateManager $certificateManager, IL10N $l) { $this->certificateManager = $certificateManager; $this->l = $l; parent::__construct(); } protected function configure() { $this ->setName('security:certificates') ->setDescription('list trusted certificates'); parent::configure(); } protected function execute(InputInterface $input, OutputInterface $output) { $outputType = $input->getOption('output'); if ($outputType === self::OUTPUT_FORMAT_JSON || $outputType === self::OUTPUT_FORMAT_JSON_PRETTY) { $certificates = array_map(function (ICertificate $certificate) { return [ 'name' => $certificate->getName(), 'common_name' => $certificate->getCommonName(), 'organization' => $certificate->getOrganization(), 'expire' => $certificate->getExpireDate()->format(\DateTime::ATOM), 'issuer' => $certificate->getIssuerName(), 'issuer_organization' => $certificate->getIssuerOrganization(), 'issue_date' => $certificate->getIssueDate()->format(\DateTime::ATOM) ]; }, $this->certificateManager->listCertificates()); if ($outputType === self::OUTPUT_FORMAT_JSON) { $output->writeln(json_encode(array_values($certificates))); } else { $output->writeln(json_encode(array_values($certificates), JSON_PRETTY_PRINT)); } } else { $table = new Table($output); $table->setHeaders([ 'File Name', 'Common Name', 'Organization', 'Valid Until', 'Issued By' ]); $rows = array_map(function (ICertificate $certificate) { return [ $certificate->getName(), $certificate->getCommonName(), $certificate->getOrganization(), $this->l->l('date', $certificate->getExpireDate()), $certificate->getIssuerName() ]; }, $this->certificateManager->listCertificates()); $table->setRows($rows); $table->render(); } } } Security/ImportCertificate.php 0000604 00000003727 15247207135 0012514 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Robin Appelman <robin@icewind.nl> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command\Security; use OC\Core\Command\Base; use OCP\ICertificateManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class ImportCertificate extends Base { /** @var ICertificateManager */ protected $certificateManager; public function __construct(ICertificateManager $certificateManager) { $this->certificateManager = $certificateManager; parent::__construct(); } protected function configure() { $this ->setName('security:certificates:import') ->setDescription('import trusted certificate') ->addArgument( 'path', InputArgument::REQUIRED, 'path to the certificate to import' ); } protected function execute(InputInterface $input, OutputInterface $output) { $path = $input->getArgument('path'); if (!file_exists($path)) { $output->writeln('<error>certificate not found</error>'); return; } $certData = file_get_contents($path); $name = basename($path); $this->certificateManager->addCertificate($certData, $name); } } Group/AddUser.php 0000604 00000004502 15247207135 0007703 0 ustar 00 <?php /** * @copyright Copyright (c) 2016 Robin Appelman <robin@icewind.nl> * * @author Robin Appelman <robin@icewind.nl> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\Core\Command\Group; use OC\Core\Command\Base; use OCP\IGroupManager; use OCP\IUserManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class AddUser extends Base { /** @var IUserManager */ protected $userManager; /** @var IGroupManager */ protected $groupManager; /** * @param IUserManager $userManager * @param IGroupManager $groupManager */ public function __construct(IUserManager $userManager, IGroupManager $groupManager) { $this->userManager = $userManager; $this->groupManager = $groupManager; parent::__construct(); } protected function configure() { $this ->setName('group:adduser') ->setDescription('add a user to a group') ->addArgument( 'group', InputArgument::REQUIRED, 'group to add the user to' )->addArgument( 'user', InputArgument::REQUIRED, 'user to add to the group' ); } protected function execute(InputInterface $input, OutputInterface $output) { $group = $this->groupManager->get($input->getArgument('group')); if (is_null($group)) { $output->writeln('<error>group not found</error>'); return 1; } $user = $this->userManager->get($input->getArgument('user')); if (is_null($user)) { $output->writeln('<error>user not found</error>'); return 1; } $group->addUser($user); } } Group/RemoveUser.php 0000604 00000004532 15247207135 0010453 0 ustar 00 <?php /** * @copyright Copyright (c) 2016 Robin Appelman <robin@icewind.nl> * * @author Robin Appelman <robin@icewind.nl> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\Core\Command\Group; use OC\Core\Command\Base; use OCP\IGroupManager; use OCP\IUserManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class RemoveUser extends Base { /** @var IUserManager */ protected $userManager; /** @var IGroupManager */ protected $groupManager; /** * @param IUserManager $userManager * @param IGroupManager $groupManager */ public function __construct(IUserManager $userManager, IGroupManager $groupManager) { $this->userManager = $userManager; $this->groupManager = $groupManager; parent::__construct(); } protected function configure() { $this ->setName('group:removeuser') ->setDescription('remove a user from a group') ->addArgument( 'group', InputArgument::REQUIRED, 'group to remove the user from' )->addArgument( 'user', InputArgument::REQUIRED, 'user to remove from the group' ); } protected function execute(InputInterface $input, OutputInterface $output) { $group = $this->groupManager->get($input->getArgument('group')); if (is_null($group)) { $output->writeln('<error>group not found</error>'); return 1; } $user = $this->userManager->get($input->getArgument('user')); if (is_null($user)) { $output->writeln('<error>user not found</error>'); return 1; } $group->removeUser($user); } } Group/ListCommand.php 0000604 00000005062 15247207135 0010570 0 ustar 00 <?php /** * @copyright Copyright (c) 2016 Robin Appelman <robin@icewind.nl> * * @author Robin Appelman <robin@icewind.nl> * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ namespace OC\Core\Command\Group; use OC\Core\Command\Base; use OCP\IGroup; use OCP\IGroupManager; use OCP\IUser; use OCP\IUserManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class ListCommand extends Base { /** @var IGroupManager */ protected $groupManager; /** * @param IGroupManager $groupManager */ public function __construct(IGroupManager $groupManager) { $this->groupManager = $groupManager; parent::__construct(); } protected function configure() { $this ->setName('group:list') ->setDescription('list configured groups') ->addOption( 'limit', 'l', InputOption::VALUE_OPTIONAL, 'Number of groups to retrieve', 500 )->addOption( 'offset', 'o', InputOption::VALUE_OPTIONAL, 'Offset for retrieving groups', 0 )->addOption( 'output', null, InputOption::VALUE_OPTIONAL, 'Output format (plain, json or json_pretty, default is plain)', $this->defaultOutputFormat ); } protected function execute(InputInterface $input, OutputInterface $output) { $groups = $this->groupManager->search('', (int)$input->getOption('limit'), (int)$input->getOption('offset')); $this->writeArrayInOutputFormat($input, $output, $this->formatGroups($groups)); } /** * @param IGroup[] $groups * @return array */ private function formatGroups(array $groups) { $keys = array_map(function (IGroup $group) { return $group->getGID(); }, $groups); $values = array_map(function (IGroup $group) { return array_keys($group->getUsers()); }, $groups); return array_combine($keys, $values); } } Base.php 0000604 00000012066 15247207135 0006136 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OC\Core\Command; use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface; use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Base extends Command implements CompletionAwareInterface { const OUTPUT_FORMAT_PLAIN = 'plain'; const OUTPUT_FORMAT_JSON = 'json'; const OUTPUT_FORMAT_JSON_PRETTY = 'json_pretty'; protected $defaultOutputFormat = self::OUTPUT_FORMAT_PLAIN; /** @var boolean */ private $php_pcntl_signal = false; /** @var boolean */ private $interrupted = false; protected function configure() { $this ->addOption( 'output', null, InputOption::VALUE_OPTIONAL, 'Output format (plain, json or json_pretty, default is plain)', $this->defaultOutputFormat ) ; } /** * @param InputInterface $input * @param OutputInterface $output * @param array $items * @param string $prefix */ protected function writeArrayInOutputFormat(InputInterface $input, OutputInterface $output, $items, $prefix = ' - ') { switch ($input->getOption('output')) { case self::OUTPUT_FORMAT_JSON: $output->writeln(json_encode($items)); break; case self::OUTPUT_FORMAT_JSON_PRETTY: $output->writeln(json_encode($items, JSON_PRETTY_PRINT)); break; default: foreach ($items as $key => $item) { if (is_array($item)) { $output->writeln($prefix . $key . ':'); $this->writeArrayInOutputFormat($input, $output, $item, ' ' . $prefix); continue; } if (!is_int($key)) { $value = $this->valueToString($item); if (!is_null($value)) { $output->writeln($prefix . $key . ': ' . $value); } else { $output->writeln($prefix . $key); } } else { $output->writeln($prefix . $this->valueToString($item)); } } break; } } /** * @param InputInterface $input * @param OutputInterface $output * @param mixed $item */ protected function writeMixedInOutputFormat(InputInterface $input, OutputInterface $output, $item) { if (is_array($item)) { $this->writeArrayInOutputFormat($input, $output, $item, ''); return; } switch ($input->getOption('output')) { case self::OUTPUT_FORMAT_JSON: $output->writeln(json_encode($item)); break; case self::OUTPUT_FORMAT_JSON_PRETTY: $output->writeln(json_encode($item, JSON_PRETTY_PRINT)); break; default: $output->writeln($this->valueToString($item, false)); break; } } protected function valueToString($value, $returnNull = true) { if ($value === false) { return 'false'; } else if ($value === true) { return 'true'; } else if ($value === null) { return ($returnNull) ? null : 'null'; } else { return $value; } } /** * @return bool */ protected function hasBeenInterrupted() { // return always false if pcntl_signal functions are not accessible if ($this->php_pcntl_signal) { pcntl_signal_dispatch(); return $this->interrupted; } else { return false; } } /** * Changes the status of the command to "interrupted" if ctrl-c has been pressed * * Gives a chance to the command to properly terminate what it's doing */ protected function cancelOperation() { $this->interrupted = true; } public function run(InputInterface $input, OutputInterface $output) { // check if the php pcntl_signal functions are accessible $this->php_pcntl_signal = function_exists('pcntl_signal'); if ($this->php_pcntl_signal) { // Collect interrupts and notify the running command pcntl_signal(SIGTERM, [$this, 'cancelOperation']); pcntl_signal(SIGINT, [$this, 'cancelOperation']); } return parent::run($input, $output); } /** * @param string $optionName * @param CompletionContext $context * @return string[] */ public function completeOptionValues($optionName, CompletionContext $context) { if ($optionName === 'output') { return ['plain', 'json', 'json_pretty']; } return []; } /** * @param string $argumentName * @param CompletionContext $context * @return string[] */ public function completeArgumentValues($argumentName, CompletionContext $context) { return []; } } DeleteOrphanedFiles.php 0000604 00000004646 15247216174 0011142 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Joas Schilling <coding@schilljs.com> * @author Morris Jobke <hey@morrisjobke.de> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OCA\Files\Command; use OCP\IDBConnection; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; /** * Delete all file entries that have no matching entries in the storage table. */ class DeleteOrphanedFiles extends Command { const CHUNK_SIZE = 200; /** * @var IDBConnection */ protected $connection; public function __construct(IDBConnection $connection) { $this->connection = $connection; parent::__construct(); } protected function configure() { $this ->setName('files:cleanup') ->setDescription('cleanup filecache'); } public function execute(InputInterface $input, OutputInterface $output) { $deletedEntries = 0; $query = $this->connection->getQueryBuilder(); $query->select('fc.fileid') ->from('filecache', 'fc') ->where($query->expr()->isNull('s.numeric_id')) ->leftJoin('fc', 'storages', 's', $query->expr()->eq('fc.storage', 's.numeric_id')) ->setMaxResults(self::CHUNK_SIZE); $deleteQuery = $this->connection->getQueryBuilder(); $deleteQuery->delete('filecache') ->where($deleteQuery->expr()->eq('fileid', $deleteQuery->createParameter('objectid'))); $deletedInLastChunk = self::CHUNK_SIZE; while ($deletedInLastChunk === self::CHUNK_SIZE) { $deletedInLastChunk = 0; $result = $query->execute(); while ($row = $result->fetch()) { $deletedInLastChunk++; $deletedEntries += $deleteQuery->setParameter('objectid', (int) $row['fileid']) ->execute(); } $result->closeCursor(); } $output->writeln("$deletedEntries orphaned file cache entries deleted"); } } ScanAppData.php 0000604 00000017671 15247216174 0007415 0 ustar 00 <?php namespace OCA\Files\Command; use Doctrine\DBAL\Connection; use OC\Core\Command\Base; use OC\Core\Command\InterruptedException; use OC\ForbiddenException; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\Files\StorageNotAvailableException; use OCP\IConfig; use OCP\IDBConnection; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Helper\Table; class ScanAppData extends Base { /** @var IRootFolder */ protected $root; /** @var IConfig */ protected $config; /** @var float */ protected $execTime = 0; /** @var int */ protected $foldersCounter = 0; /** @var int */ protected $filesCounter = 0; public function __construct(IRootFolder $rootFolder, IConfig $config) { parent::__construct(); $this->root = $rootFolder; $this->config = $config; } protected function configure() { parent::configure(); $this ->setName('files:scan-app-data') ->setDescription('rescan the AppData folder') ->addOption( 'quiet', 'q', InputOption::VALUE_NONE, 'suppress any output' ) ->addOption( 'verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'verbose the output' ); } public function checkScanWarning($fullPath, OutputInterface $output) { $normalizedPath = basename(\OC\Files\Filesystem::normalizePath($fullPath)); $path = basename($fullPath); if ($normalizedPath !== $path) { $output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>'); } } protected function scanFiles($verbose, OutputInterface $output) { try { $appData = $this->getAppDataFolder(); } catch (NotFoundException $e) { $output->writeln('NoAppData folder found'); return; } $connection = $this->reconnectToDatabase($output); $scanner = new \OC\Files\Utils\Scanner(null, $connection, \OC::$server->getLogger()); # check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception # printout and count if ($verbose) { $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) { $output->writeln("\tFile <info>$path</info>"); $this->filesCounter += 1; if ($this->hasBeenInterrupted()) { throw new InterruptedException(); } }); $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) { $output->writeln("\tFolder <info>$path</info>"); $this->foldersCounter += 1; if ($this->hasBeenInterrupted()) { throw new InterruptedException(); } }); $scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) { $output->writeln("Error while scanning, storage not available (" . $e->getMessage() . ")"); }); # count only } else { $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function () use ($output) { $this->filesCounter += 1; if ($this->hasBeenInterrupted()) { throw new InterruptedException(); } }); $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function () use ($output) { $this->foldersCounter += 1; if ($this->hasBeenInterrupted()) { throw new InterruptedException(); } }); } $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function($path) use ($output) { $this->checkScanWarning($path, $output); }); $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function($path) use ($output) { $this->checkScanWarning($path, $output); }); try { $scanner->scan($appData->getPath()); } catch (ForbiddenException $e) { $output->writeln("<error>Storage not writable</error>"); $output->writeln("Make sure you're running the scan command only as the user the web server runs as"); } catch (InterruptedException $e) { # exit the function if ctrl-c has been pressed $output->writeln('Interrupted by user'); } catch (NotFoundException $e) { $output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>'); } catch (\Exception $e) { $output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>'); $output->writeln('<error>' . $e->getTraceAsString() . '</error>'); } } protected function execute(InputInterface $input, OutputInterface $output) { # no messaging level option means: no full printout but statistics # $quiet means no print at all # $verbose means full printout including statistics # -q -v full stat # 0 0 no yes # 0 1 yes yes # 1 -- no no (quiet overrules verbose) $verbose = $input->getOption('verbose'); $quiet = $input->getOption('quiet'); # restrict the verbosity level to VERBOSITY_VERBOSE if ($output->getVerbosity() > OutputInterface::VERBOSITY_VERBOSE) { $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); } if ($quiet) { $verbose = false; } $output->writeln("\nScanning AppData for files"); $this->initTools(); $this->scanFiles($verbose, $output); # stat: printout statistics if $quiet was not set if (!$quiet) { $this->presentStats($output); } } /** * Initialises some useful tools for the Command */ protected function initTools() { // Start the timer $this->execTime = -microtime(true); // Convert PHP errors to exceptions set_error_handler([$this, 'exceptionErrorHandler'], E_ALL); } /** * Processes PHP errors as exceptions in order to be able to keep track of problems * * @see https://secure.php.net/manual/en/function.set-error-handler.php * * @param int $severity the level of the error raised * @param string $message * @param string $file the filename that the error was raised in * @param int $line the line number the error was raised * * @throws \ErrorException */ public function exceptionErrorHandler($severity, $message, $file, $line) { if (!(error_reporting() & $severity)) { // This error code is not included in error_reporting return; } throw new \ErrorException($message, 0, $severity, $file, $line); } /** * @param OutputInterface $output */ protected function presentStats(OutputInterface $output) { // Stop the timer $this->execTime += microtime(true); $output->writeln(""); $headers = [ 'Folders', 'Files', 'Elapsed time' ]; $this->showSummary($headers, null, $output); } /** * Shows a summary of operations * * @param string[] $headers * @param string[] $rows * @param OutputInterface $output */ protected function showSummary($headers, $rows, OutputInterface $output) { $niceDate = $this->formatExecTime(); if (!$rows) { $rows = [ $this->foldersCounter, $this->filesCounter, $niceDate, ]; } $table = new Table($output); $table ->setHeaders($headers) ->setRows([$rows]); $table->render(); } /** * Formats microtime into a human readable format * * @return string */ protected function formatExecTime() { list($secs, $tens) = explode('.', sprintf("%.1f", ($this->execTime))); # if you want to have microseconds add this: . '.' . $tens; return date('H:i:s', $secs); } /** * @return \OCP\IDBConnection */ protected function reconnectToDatabase(OutputInterface $output) { /** @var Connection | IDBConnection $connection*/ $connection = \OC::$server->getDatabaseConnection(); try { $connection->close(); } catch (\Exception $ex) { $output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>"); } while (!$connection->isConnected()) { try { $connection->connect(); } catch (\Exception $ex) { $output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>"); sleep(60); } } return $connection; } /** * @return \OCP\Files\Folder * @throws NotFoundException */ private function getAppDataFolder() { $instanceId = $this->config->getSystemValue('instanceid', null); if ($instanceId === null) { throw new NotFoundException(); } return $this->root->get('appdata_'.$instanceId); } } Scan.php 0000604 00000025130 15247216174 0006147 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Bart Visscher <bartv@thisnet.nl> * @author Jörn Friedrich Dreyer <jfd@butonic.de> * @author martin.mattel@diemattels.at <martin.mattel@diemattels.at> * @author Morris Jobke <hey@morrisjobke.de> * @author Robin Appelman <robin@icewind.nl> * @author Thomas Müller <thomas.mueller@tmit.eu> * @author Vincent Petry <pvince81@owncloud.com> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OCA\Files\Command; use Doctrine\DBAL\Connection; use OC\Core\Command\Base; use OC\Core\Command\InterruptedException; use OC\ForbiddenException; use OCP\Files\NotFoundException; use OCP\Files\StorageNotAvailableException; use OCP\IDBConnection; use OCP\IUserManager; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Helper\Table; class Scan extends Base { /** @var IUserManager $userManager */ private $userManager; /** @var float */ protected $execTime = 0; /** @var int */ protected $foldersCounter = 0; /** @var int */ protected $filesCounter = 0; public function __construct(IUserManager $userManager) { $this->userManager = $userManager; parent::__construct(); } protected function configure() { parent::configure(); $this ->setName('files:scan') ->setDescription('rescan filesystem') ->addArgument( 'user_id', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'will rescan all files of the given user(s)' ) ->addOption( 'path', 'p', InputArgument::OPTIONAL, 'limit rescan to this path, eg. --path="/alice/files/Music", the user_id is determined by the path and the user_id parameter and --all are ignored' ) ->addOption( 'quiet', 'q', InputOption::VALUE_NONE, 'suppress any output' ) ->addOption( 'verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'verbose the output' ) ->addOption( 'all', null, InputOption::VALUE_NONE, 'will rescan all files of all known users' )->addOption( 'unscanned', null, InputOption::VALUE_NONE, 'only scan files which are marked as not fully scanned' ); } public function checkScanWarning($fullPath, OutputInterface $output) { $normalizedPath = basename(\OC\Files\Filesystem::normalizePath($fullPath)); $path = basename($fullPath); if ($normalizedPath !== $path) { $output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>'); } } protected function scanFiles($user, $path, $verbose, OutputInterface $output, $backgroundScan = false) { $connection = $this->reconnectToDatabase($output); $scanner = new \OC\Files\Utils\Scanner($user, $connection, \OC::$server->getLogger()); # check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception # printout and count if ($verbose) { $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) { $output->writeln("\tFile <info>$path</info>"); $this->filesCounter += 1; if ($this->hasBeenInterrupted()) { throw new InterruptedException(); } }); $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) { $output->writeln("\tFolder <info>$path</info>"); $this->foldersCounter += 1; if ($this->hasBeenInterrupted()) { throw new InterruptedException(); } }); $scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) { $output->writeln("Error while scanning, storage not available (" . $e->getMessage() . ")"); }); # count only } else { $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function () use ($output) { $this->filesCounter += 1; if ($this->hasBeenInterrupted()) { throw new InterruptedException(); } }); $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function () use ($output) { $this->foldersCounter += 1; if ($this->hasBeenInterrupted()) { throw new InterruptedException(); } }); } $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) { $this->checkScanWarning($path, $output); }); $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) { $this->checkScanWarning($path, $output); }); try { if ($backgroundScan) { $scanner->backgroundScan($path); } else { $scanner->scan($path); } } catch (ForbiddenException $e) { $output->writeln("<error>Home storage for user $user not writable</error>"); $output->writeln("Make sure you're running the scan command only as the user the web server runs as"); } catch (InterruptedException $e) { # exit the function if ctrl-c has been pressed $output->writeln('Interrupted by user'); } catch (NotFoundException $e) { $output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>'); } catch (\Exception $e) { $output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>'); $output->writeln('<error>' . $e->getTraceAsString() . '</error>'); } } protected function execute(InputInterface $input, OutputInterface $output) { $inputPath = $input->getOption('path'); if ($inputPath) { $inputPath = '/' . trim($inputPath, '/'); list (, $user,) = explode('/', $inputPath, 3); $users = array($user); } else if ($input->getOption('all')) { $users = $this->userManager->search(''); } else { $users = $input->getArgument('user_id'); } # no messaging level option means: no full printout but statistics # $quiet means no print at all # $verbose means full printout including statistics # -q -v full stat # 0 0 no yes # 0 1 yes yes # 1 -- no no (quiet overrules verbose) $verbose = $input->getOption('verbose'); $quiet = $input->getOption('quiet'); # restrict the verbosity level to VERBOSITY_VERBOSE if ($output->getVerbosity() > OutputInterface::VERBOSITY_VERBOSE) { $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); } if ($quiet) { $verbose = false; } # check quantity of users to be process and show it on the command line $users_total = count($users); if ($users_total === 0) { $output->writeln("<error>Please specify the user id to scan, \"--all\" to scan for all users or \"--path=...\"</error>"); return; } else { if ($users_total > 1) { $output->writeln("\nScanning files for $users_total users"); } } $this->initTools(); $user_count = 0; foreach ($users as $user) { if (is_object($user)) { $user = $user->getUID(); } $path = $inputPath ? $inputPath : '/' . $user; $user_count += 1; if ($this->userManager->userExists($user)) { # add an extra line when verbose is set to optical separate users if ($verbose) { $output->writeln(""); } $output->writeln("Starting scan for user $user_count out of $users_total ($user)"); # full: printout data if $verbose was set $this->scanFiles($user, $path, $verbose, $output, $input->getOption('unscanned')); } else { $output->writeln("<error>Unknown user $user_count $user</error>"); } # check on each user if there was a user interrupt (ctrl-c) and exit foreach if ($this->hasBeenInterrupted()) { break; } } # stat: printout statistics if $quiet was not set if (!$quiet) { $this->presentStats($output); } } /** * Initialises some useful tools for the Command */ protected function initTools() { // Start the timer $this->execTime = -microtime(true); // Convert PHP errors to exceptions set_error_handler([$this, 'exceptionErrorHandler'], E_ALL); } /** * Processes PHP errors as exceptions in order to be able to keep track of problems * * @see https://secure.php.net/manual/en/function.set-error-handler.php * * @param int $severity the level of the error raised * @param string $message * @param string $file the filename that the error was raised in * @param int $line the line number the error was raised * * @throws \ErrorException */ public function exceptionErrorHandler($severity, $message, $file, $line) { if (!(error_reporting() & $severity)) { // This error code is not included in error_reporting return; } throw new \ErrorException($message, 0, $severity, $file, $line); } /** * @param OutputInterface $output */ protected function presentStats(OutputInterface $output) { // Stop the timer $this->execTime += microtime(true); $output->writeln(""); $headers = [ 'Folders', 'Files', 'Elapsed time' ]; $this->showSummary($headers, null, $output); } /** * Shows a summary of operations * * @param string[] $headers * @param string[] $rows * @param OutputInterface $output */ protected function showSummary($headers, $rows, OutputInterface $output) { $niceDate = $this->formatExecTime(); if (!$rows) { $rows = [ $this->foldersCounter, $this->filesCounter, $niceDate, ]; } $table = new Table($output); $table ->setHeaders($headers) ->setRows([$rows]); $table->render(); } /** * Formats microtime into a human readable format * * @return string */ protected function formatExecTime() { list($secs, $tens) = explode('.', sprintf("%.1f", ($this->execTime))); # if you want to have microseconds add this: . '.' . $tens; return date('H:i:s', $secs); } /** * @return \OCP\IDBConnection */ protected function reconnectToDatabase(OutputInterface $output) { /** @var Connection | IDBConnection $connection */ $connection = \OC::$server->getDatabaseConnection(); try { $connection->close(); } catch (\Exception $ex) { $output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>"); } while (!$connection->isConnected()) { try { $connection->connect(); } catch (\Exception $ex) { $output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>"); sleep(60); } } return $connection; } } TransferOwnership.php 0000604 00000021447 15247216174 0010755 0 ustar 00 <?php /** * @copyright Copyright (c) 2016, ownCloud, Inc. * * @author Carla Schroder <carla@owncloud.com> * @author Joas Schilling <coding@schilljs.com> * @author Thomas Müller <thomas.mueller@tmit.eu> * * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see <http://www.gnu.org/licenses/> * */ namespace OCA\Files\Command; use OC\Files\Filesystem; use OC\Files\View; use OCP\Files\FileInfo; use OCP\Files\IHomeStorage; use OCP\Files\Mount\IMountManager; use OCP\IUser; use OCP\IUserManager; use OCP\Share\IManager; use OCP\Share\IShare; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class TransferOwnership extends Command { /** @var IUserManager $userManager */ private $userManager; /** @var IManager */ private $shareManager; /** @var IMountManager */ private $mountManager; /** @var FileInfo[] */ private $allFiles = []; /** @var FileInfo[] */ private $encryptedFiles = []; /** @var IShare[] */ private $shares = []; /** @var string */ private $sourceUser; /** @var string */ private $destinationUser; /** @var string */ private $sourcePath; /** @var string */ private $finalTarget; public function __construct(IUserManager $userManager, IManager $shareManager, IMountManager $mountManager) { $this->userManager = $userManager; $this->shareManager = $shareManager; $this->mountManager = $mountManager; parent::__construct(); } protected function configure() { $this ->setName('files:transfer-ownership') ->setDescription('All files and folders are moved to another user - shares are moved as well.') ->addArgument( 'source-user', InputArgument::REQUIRED, 'owner of files which shall be moved' ) ->addArgument( 'destination-user', InputArgument::REQUIRED, 'user who will be the new owner of the files' ) ->addOption( 'path', null, InputOption::VALUE_REQUIRED, 'selectively provide the path to transfer. For example --path="folder_name"', '' ); } protected function execute(InputInterface $input, OutputInterface $output) { $sourceUserObject = $this->userManager->get($input->getArgument('source-user')); $destinationUserObject = $this->userManager->get($input->getArgument('destination-user')); if (!$sourceUserObject instanceof IUser) { $output->writeln("<error>Unknown source user $this->sourceUser</error>"); return 1; } if (!$destinationUserObject instanceof IUser) { $output->writeln("<error>Unknown destination user $this->destinationUser</error>"); return 1; } $this->sourceUser = $sourceUserObject->getUID(); $this->destinationUser = $destinationUserObject->getUID(); $sourcePathOption = ltrim($input->getOption('path'), '/'); $this->sourcePath = rtrim($this->sourceUser . '/files/' . $sourcePathOption, '/'); // target user has to be ready if (!\OC::$server->getEncryptionManager()->isReadyForUser($this->destinationUser)) { $output->writeln("<error>The target user is not ready to accept files. The user has at least to be logged in once.</error>"); return 2; } $date = date('Y-m-d H-i-s'); $this->finalTarget = "$this->destinationUser/files/transferred from $this->sourceUser on $date"; // setup filesystem Filesystem::initMountPoints($this->sourceUser); Filesystem::initMountPoints($this->destinationUser); $view = new View(); if (!$view->is_dir($this->sourcePath)) { $output->writeln("<error>Unknown path provided: $sourcePathOption</error>"); return 1; } // analyse source folder $this->analyse($output); // collect all the shares $this->collectUsersShares($output); // transfer the files $this->transfer($output); // restore the shares $this->restoreShares($output); } private function walkFiles(View $view, $path, \Closure $callBack) { foreach ($view->getDirectoryContent($path) as $fileInfo) { if (!$callBack($fileInfo)) { return; } if ($fileInfo->getType() === FileInfo::TYPE_FOLDER) { $this->walkFiles($view, $fileInfo->getPath(), $callBack); } } } /** * @param OutputInterface $output * @throws \Exception */ protected function analyse(OutputInterface $output) { $view = new View(); $output->writeln("Analysing files of $this->sourceUser ..."); $progress = new ProgressBar($output); $progress->start(); $self = $this; $this->walkFiles($view, $this->sourcePath, function (FileInfo $fileInfo) use ($progress, $self) { if ($fileInfo->getType() === FileInfo::TYPE_FOLDER) { // only analyze into folders from main storage, if (!$fileInfo->getStorage()->instanceOfStorage(IHomeStorage::class)) { return false; } return true; } $progress->advance(); $this->allFiles[] = $fileInfo; if ($fileInfo->isEncrypted()) { $this->encryptedFiles[] = $fileInfo; } return true; }); $progress->finish(); $output->writeln(''); // no file is allowed to be encrypted if (!empty($this->encryptedFiles)) { $output->writeln("<error>Some files are encrypted - please decrypt them first</error>"); foreach($this->encryptedFiles as $encryptedFile) { /** @var FileInfo $encryptedFile */ $output->writeln(" " . $encryptedFile->getPath()); } throw new \Exception('Execution terminated.'); } } /** * @param OutputInterface $output */ private function collectUsersShares(OutputInterface $output) { $output->writeln("Collecting all share information for files and folder of $this->sourceUser ..."); $progress = new ProgressBar($output, count($this->shares)); foreach([\OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE] as $shareType) { $offset = 0; while (true) { $sharePage = $this->shareManager->getSharesBy($this->sourceUser, $shareType, null, true, 50, $offset); $progress->advance(count($sharePage)); if (empty($sharePage)) { break; } $this->shares = array_merge($this->shares, $sharePage); $offset += 50; } } $progress->finish(); $output->writeln(''); } /** * @param OutputInterface $output */ protected function transfer(OutputInterface $output) { $view = new View(); $output->writeln("Transferring files to $this->finalTarget ..."); // This change will help user to transfer the folder specified using --path option. // Else only the content inside folder is transferred which is not correct. if($this->sourcePath !== "$this->sourceUser/files") { $view->mkdir($this->finalTarget); $this->finalTarget = $this->finalTarget . '/' . basename($this->sourcePath); } $view->rename($this->sourcePath, $this->finalTarget); if (!is_dir("$this->sourceUser/files")) { // because the files folder is moved away we need to recreate it $view->mkdir("$this->sourceUser/files"); } } /** * @param OutputInterface $output */ private function restoreShares(OutputInterface $output) { $output->writeln("Restoring shares ..."); $progress = new ProgressBar($output, count($this->shares)); foreach($this->shares as $share) { try { if ($share->getSharedWith() === $this->destinationUser) { // Unmount the shares before deleting, so we don't try to get the storage later on. $shareMountPoint = $this->mountManager->find('/' . $this->destinationUser . '/files' . $share->getTarget()); if ($shareMountPoint) { $this->mountManager->removeMount($shareMountPoint->getMountPoint()); } $this->shareManager->deleteShare($share); } else { if ($share->getShareOwner() === $this->sourceUser) { $share->setShareOwner($this->destinationUser); } if ($share->getSharedBy() === $this->sourceUser) { $share->setSharedBy($this->destinationUser); } $this->shareManager->updateShare($share); } } catch (\OCP\Files\NotFoundException $e) { $output->writeln('<error>Share with id ' . $share->getId() . ' points at deleted file, skipping</error>'); } catch (\Exception $e) { $output->writeln('<error>Could not restore share with id ' . $share->getId() . ':' . $e->getTraceAsString() . '</error>'); } $progress->advance(); } $progress->finish(); $output->writeln(''); } }
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Generation time: 0 |
proxy
|
phpinfo
|
Settings