migrate therinaldos.com data
Build & Deploy to DigitalOcean Space / build (push) Failing after 2m38s

This commit is contained in:
2024-05-05 15:50:45 -04:00
commit ef1ff240d4
23182 changed files with 3801898 additions and 0 deletions
@@ -0,0 +1,101 @@
<?php
/**
* @copyright Copyright (c) 2016 Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Joas Schilling <coding@schilljs.com>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Vincent Petry <vincent@nextcloud.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 OCA\Provisioning_API\AppInfo;
use OC\Group\Manager as GroupManager;
use OCA\Provisioning_API\Capabilities;
use OCA\Provisioning_API\Listener\UserDeletedListener;
use OCA\Provisioning_API\Middleware\ProvisioningApiMiddleware;
use OCA\Settings\Mailer\NewUserMailHelper;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\AppFramework\Utility\IControllerMethodReflector;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Defaults;
use OCP\IConfig;
use OCP\IGroupManager;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
use OCP\L10N\IFactory;
use OCP\Mail\IMailer;
use OCP\Security\ICrypto;
use OCP\Security\ISecureRandom;
use OCP\User\Events\UserDeletedEvent;
use OCP\Util;
use Psr\Container\ContainerInterface;
class Application extends App implements IBootstrap {
public function __construct(array $urlParams = []) {
parent::__construct('provisioning_api', $urlParams);
}
public function register(IRegistrationContext $context): void {
$context->registerEventListener(UserDeletedEvent::class, UserDeletedListener::class);
$context->registerService(NewUserMailHelper::class, function (ContainerInterface $c) {
return new NewUserMailHelper(
$c->get(Defaults::class),
$c->get(IURLGenerator::class),
$c->get(IFactory::class),
$c->get(IMailer::class),
$c->get(ISecureRandom::class),
$c->get(ITimeFactory::class),
$c->get(IConfig::class),
$c->get(ICrypto::class),
Util::getDefaultEmailAddress('no-reply')
);
});
$context->registerService(ProvisioningApiMiddleware::class, function (ContainerInterface $c) {
$user = $c->get(IUserManager::class)->get($c->get('UserId'));
$isAdmin = false;
$isSubAdmin = false;
if ($user instanceof IUser) {
$groupManager = $c->get(IGroupManager::class);
assert($groupManager instanceof GroupManager);
$isAdmin = $groupManager->isAdmin($user->getUID());
$isSubAdmin = $groupManager->getSubAdmin()->isSubAdmin($user);
}
return new ProvisioningApiMiddleware(
$c->get(IControllerMethodReflector::class),
$isAdmin,
$isSubAdmin
);
});
$context->registerMiddleware(ProvisioningApiMiddleware::class);
$context->registerCapability(Capabilities::class);
}
public function boot(IBootContext $context): void {
}
}
@@ -0,0 +1,72 @@
<?php
/**
* @copyright Copyright (c) 2021 Vincent Petry <vincent@nextcloud.com>
*
* @author Vincent Petry <vincent@nextcloud.com>
* @author Kate Döen <kate.doeen@nextcloud.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 OCA\Provisioning_API;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCP\App\IAppManager;
use OCP\Capabilities\ICapability;
class Capabilities implements ICapability {
/** @var IAppManager */
private $appManager;
public function __construct(IAppManager $appManager) {
$this->appManager = $appManager;
}
/**
* Function an app uses to return the capabilities
*
* @return array{
* provisioning_api: array{
* version: string,
* AccountPropertyScopesVersion: int,
* AccountPropertyScopesFederatedEnabled: bool,
* AccountPropertyScopesPublishedEnabled: bool,
* },
* }
*/
public function getCapabilities() {
$federatedScopeEnabled = $this->appManager->isEnabledForUser('federation');
$publishedScopeEnabled = false;
$federatedFileSharingEnabled = $this->appManager->isEnabledForUser('federatedfilesharing');
if ($federatedFileSharingEnabled) {
/** @var FederatedShareProvider $shareProvider */
$shareProvider = \OC::$server->query(FederatedShareProvider::class);
$publishedScopeEnabled = $shareProvider->isLookupServerUploadEnabled();
}
return [
'provisioning_api' => [
'version' => $this->appManager->getAppVersion('provisioning_api'),
'AccountPropertyScopesVersion' => 2,
'AccountPropertyScopesFederatedEnabled' => $federatedScopeEnabled,
'AccountPropertyScopesPublishedEnabled' => $publishedScopeEnabled,
]
];
}
}
@@ -0,0 +1,299 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2018 John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Georg Ehrke <oc.list@georgehrke.com>
* @author Joas Schilling <coding@schilljs.com>
* @author John Molakvoæ <skjnldsv@protonmail.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Vincent Petry <vincent@nextcloud.com>
* @author Kate Döen <kate.doeen@nextcloud.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 OCA\Provisioning_API\Controller;
use OC\Group\Manager;
use OC\User\Backend;
use OC\User\NoUserException;
use OC_Helper;
use OCA\Provisioning_API\ResponseDefinitions;
use OCP\Accounts\IAccountManager;
use OCP\Accounts\PropertyDoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\OCS\OCSException;
use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\AppFramework\OCSController;
use OCP\Files\NotFoundException;
use OCP\IConfig;
use OCP\IGroupManager;
use OCP\IRequest;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\L10N\IFactory;
use OCP\User\Backend\ISetDisplayNameBackend;
use OCP\User\Backend\ISetPasswordBackend;
/**
* @psalm-import-type Provisioning_APIUserDetails from ResponseDefinitions
* @psalm-import-type Provisioning_APIUserDetailsQuota from ResponseDefinitions
*/
abstract class AUserData extends OCSController {
public const SCOPE_SUFFIX = 'Scope';
public const USER_FIELD_DISPLAYNAME = 'display';
public const USER_FIELD_LANGUAGE = 'language';
public const USER_FIELD_LOCALE = 'locale';
public const USER_FIELD_PASSWORD = 'password';
public const USER_FIELD_QUOTA = 'quota';
public const USER_FIELD_MANAGER = 'manager';
public const USER_FIELD_NOTIFICATION_EMAIL = 'notify_email';
/** @var IUserManager */
protected $userManager;
/** @var IConfig */
protected $config;
/** @var Manager */
protected $groupManager;
/** @var IUserSession */
protected $userSession;
/** @var IAccountManager */
protected $accountManager;
/** @var IFactory */
protected $l10nFactory;
public function __construct(string $appName,
IRequest $request,
IUserManager $userManager,
IConfig $config,
IGroupManager $groupManager,
IUserSession $userSession,
IAccountManager $accountManager,
IFactory $l10nFactory) {
parent::__construct($appName, $request);
$this->userManager = $userManager;
$this->config = $config;
$this->groupManager = $groupManager;
$this->userSession = $userSession;
$this->accountManager = $accountManager;
$this->l10nFactory = $l10nFactory;
}
/**
* creates a array with all user data
*
* @param string $userId
* @param bool $includeScopes
* @return Provisioning_APIUserDetails|null
* @throws NotFoundException
* @throws OCSException
* @throws OCSNotFoundException
*/
protected function getUserData(string $userId, bool $includeScopes = false): ?array {
$currentLoggedInUser = $this->userSession->getUser();
assert($currentLoggedInUser !== null, 'No user logged in');
$data = [];
// Check if the target user exists
$targetUserObject = $this->userManager->get($userId);
if ($targetUserObject === null) {
throw new OCSNotFoundException('User does not exist');
}
$isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
if ($isAdmin
|| $this->groupManager->getSubAdmin()->isUserAccessible($currentLoggedInUser, $targetUserObject)) {
$data['enabled'] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'enabled', 'true') === 'true';
} else {
// Check they are looking up themselves
if ($currentLoggedInUser->getUID() !== $targetUserObject->getUID()) {
return null;
}
}
// Get groups data
$userAccount = $this->accountManager->getAccount($targetUserObject);
$groups = $this->groupManager->getUserGroups($targetUserObject);
$gids = [];
foreach ($groups as $group) {
$gids[] = $group->getGID();
}
if ($isAdmin) {
try {
# might be thrown by LDAP due to handling of users disappears
# from the external source (reasons unknown to us)
# cf. https://github.com/nextcloud/server/issues/12991
$data['storageLocation'] = $targetUserObject->getHome();
} catch (NoUserException $e) {
throw new OCSNotFoundException($e->getMessage(), $e);
}
}
// Find the data
$data['id'] = $targetUserObject->getUID();
$data['lastLogin'] = $targetUserObject->getLastLogin() * 1000;
$data['backend'] = $targetUserObject->getBackendClassName();
$data['subadmin'] = $this->getUserSubAdminGroupsData($targetUserObject->getUID());
$data[self::USER_FIELD_QUOTA] = $this->fillStorageInfo($targetUserObject->getUID());
$managerUids = $targetUserObject->getManagerUids();
$data[self::USER_FIELD_MANAGER] = empty($managerUids) ? '' : $managerUids[0];
try {
if ($includeScopes) {
$data[IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_AVATAR)->getScope();
}
$data[IAccountManager::PROPERTY_EMAIL] = $targetUserObject->getSystemEMailAddress();
if ($includeScopes) {
$data[IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getScope();
}
$additionalEmails = $additionalEmailScopes = [];
$emailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
foreach ($emailCollection->getProperties() as $property) {
$additionalEmails[] = $property->getValue();
if ($includeScopes) {
$additionalEmailScopes[] = $property->getScope();
}
}
$data[IAccountManager::COLLECTION_EMAIL] = $additionalEmails;
if ($includeScopes) {
$data[IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX] = $additionalEmailScopes;
}
$data[IAccountManager::PROPERTY_DISPLAYNAME] = $targetUserObject->getDisplayName();
$data[IAccountManager::PROPERTY_DISPLAYNAME_LEGACY] = $data[IAccountManager::PROPERTY_DISPLAYNAME];
if ($includeScopes) {
$data[IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME)->getScope();
}
foreach ([
IAccountManager::PROPERTY_PHONE,
IAccountManager::PROPERTY_ADDRESS,
IAccountManager::PROPERTY_WEBSITE,
IAccountManager::PROPERTY_TWITTER,
IAccountManager::PROPERTY_FEDIVERSE,
IAccountManager::PROPERTY_ORGANISATION,
IAccountManager::PROPERTY_ROLE,
IAccountManager::PROPERTY_HEADLINE,
IAccountManager::PROPERTY_BIOGRAPHY,
IAccountManager::PROPERTY_PROFILE_ENABLED,
] as $propertyName) {
$property = $userAccount->getProperty($propertyName);
$data[$propertyName] = $property->getValue();
if ($includeScopes) {
$data[$propertyName . self::SCOPE_SUFFIX] = $property->getScope();
}
}
} catch (PropertyDoesNotExistException $e) {
// hard coded properties should exist
throw new OCSException($e->getMessage(), Http::STATUS_INTERNAL_SERVER_ERROR, $e);
}
$data['groups'] = $gids;
$data[self::USER_FIELD_LANGUAGE] = $this->l10nFactory->getUserLanguage($targetUserObject);
$data[self::USER_FIELD_LOCALE] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'locale');
$data[self::USER_FIELD_NOTIFICATION_EMAIL] = $targetUserObject->getPrimaryEMailAddress();
$backend = $targetUserObject->getBackend();
$data['backendCapabilities'] = [
'setDisplayName' => $backend instanceof ISetDisplayNameBackend || $backend->implementsActions(Backend::SET_DISPLAYNAME),
'setPassword' => $backend instanceof ISetPasswordBackend || $backend->implementsActions(Backend::SET_PASSWORD),
];
return $data;
}
/**
* Get the groups a user is a subadmin of
*
* @param string $userId
* @return string[]
* @throws OCSException
*/
protected function getUserSubAdminGroupsData(string $userId): array {
$user = $this->userManager->get($userId);
// Check if the user exists
if ($user === null) {
throw new OCSNotFoundException('User does not exist');
}
// Get the subadmin groups
$subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
$groups = [];
foreach ($subAdminGroups as $key => $group) {
$groups[] = $group->getGID();
}
return $groups;
}
/**
* @param string $userId
* @return Provisioning_APIUserDetailsQuota
* @throws OCSException
*/
protected function fillStorageInfo(string $userId): array {
try {
\OC_Util::tearDownFS();
\OC_Util::setupFS($userId);
$storage = OC_Helper::getStorageInfo('/', null, true, false);
$data = [
'free' => $storage['free'],
'used' => $storage['used'],
'total' => $storage['total'],
'relative' => $storage['relative'],
self::USER_FIELD_QUOTA => $storage['quota'],
];
} catch (NotFoundException $ex) {
// User fs is not setup yet
$user = $this->userManager->get($userId);
if ($user === null) {
throw new OCSException('User does not exist', 101);
}
$quota = $user->getQuota();
if ($quota !== 'none') {
$quota = OC_Helper::computerFileSize($quota);
}
$data = [
self::USER_FIELD_QUOTA => $quota !== false ? $quota : 'none',
'used' => 0
];
} catch (\Exception $e) {
\OC::$server->get(\Psr\Log\LoggerInterface::class)->error(
"Could not load storage info for {user}",
[
'app' => 'provisioning_api',
'user' => $userId,
'exception' => $e,
]
);
/* In case the Exception left things in a bad state */
\OC_Util::tearDownFS();
return [];
}
return $data;
}
}
@@ -0,0 +1,264 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com>
*
* @author Joas Schilling <coding@schilljs.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Kate Döen <kate.doeen@nextcloud.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 OCA\Provisioning_API\Controller;
use OC\AppFramework\Middleware\Security\Exceptions\NotAdminException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\IAppConfig;
use OCP\IConfig;
use OCP\IGroupManager;
use OCP\IL10N;
use OCP\IRequest;
use OCP\IUser;
use OCP\IUserSession;
use OCP\Settings\IDelegatedSettings;
use OCP\Settings\IManager;
class AppConfigController extends OCSController {
/** @var IConfig */
protected $config;
/** @var IAppConfig */
protected $appConfig;
/** @var IUserSession */
private $userSession;
/** @var IL10N */
private $l10n;
/** @var IGroupManager */
private $groupManager;
/** @var IManager */
private $settingManager;
/**
* @param string $appName
* @param IRequest $request
* @param IConfig $config
* @param IAppConfig $appConfig
*/
public function __construct(string $appName,
IRequest $request,
IConfig $config,
IAppConfig $appConfig,
IUserSession $userSession,
IL10N $l10n,
IGroupManager $groupManager,
IManager $settingManager) {
parent::__construct($appName, $request);
$this->config = $config;
$this->appConfig = $appConfig;
$this->userSession = $userSession;
$this->l10n = $l10n;
$this->groupManager = $groupManager;
$this->settingManager = $settingManager;
}
/**
* Get a list of apps
*
* @return DataResponse<Http::STATUS_OK, array{data: string[]}, array{}>
*
* 200: Apps returned
*/
public function getApps(): DataResponse {
return new DataResponse([
'data' => $this->appConfig->getApps(),
]);
}
/**
* Get the config keys of an app
*
* @param string $app ID of the app
* @return DataResponse<Http::STATUS_OK, array{data: string[]}, array{}>|DataResponse<Http::STATUS_FORBIDDEN, array{data: array{message: string}}, array{}>
*
* 200: Keys returned
* 403: App is not allowed
*/
public function getKeys(string $app): DataResponse {
try {
$this->verifyAppId($app);
} catch (\InvalidArgumentException $e) {
return new DataResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_FORBIDDEN);
}
return new DataResponse([
'data' => $this->config->getAppKeys($app),
]);
}
/**
* Get a the config value of an app
*
* @param string $app ID of the app
* @param string $key Key
* @param string $defaultValue Default returned value if the value is empty
* @return DataResponse<Http::STATUS_OK, array{data: string}, array{}>|DataResponse<Http::STATUS_FORBIDDEN, array{data: array{message: string}}, array{}>
*
* 200: Value returned
* 403: App is not allowed
*/
public function getValue(string $app, string $key, string $defaultValue = ''): DataResponse {
try {
$this->verifyAppId($app);
} catch (\InvalidArgumentException $e) {
return new DataResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_FORBIDDEN);
}
return new DataResponse([
'data' => $this->config->getAppValue($app, $key, $defaultValue),
]);
}
/**
* @PasswordConfirmationRequired
* @NoSubAdminRequired
* @NoAdminRequired
*
* Update the config value of an app
*
* @param string $app ID of the app
* @param string $key Key to update
* @param string $value New value for the key
* @return DataResponse<Http::STATUS_OK, array<empty>, array{}>|DataResponse<Http::STATUS_FORBIDDEN, array{data: array{message: string}}, array{}>
*
* 200: Value updated successfully
* 403: App or key is not allowed
*/
public function setValue(string $app, string $key, string $value): DataResponse {
$user = $this->userSession->getUser();
if ($user === null) {
throw new \Exception("User is not logged in."); // Should not happen, since method is guarded by middleware
}
if (!$this->isAllowedToChangedKey($user, $app, $key)) {
throw new NotAdminException($this->l10n->t('Logged in user must be an administrator or have authorization to edit this setting.'));
}
try {
$this->verifyAppId($app);
$this->verifyConfigKey($app, $key, $value);
} catch (\InvalidArgumentException $e) {
return new DataResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_FORBIDDEN);
}
$this->config->setAppValue($app, $key, $value);
return new DataResponse();
}
/**
* @PasswordConfirmationRequired
*
* Delete a config key of an app
*
* @param string $app ID of the app
* @param string $key Key to delete
* @return DataResponse<Http::STATUS_OK, array<empty>, array{}>|DataResponse<Http::STATUS_FORBIDDEN, array{data: array{message: string}}, array{}>
*
* 200: Key deleted successfully
* 403: App or key is not allowed
*/
public function deleteKey(string $app, string $key): DataResponse {
try {
$this->verifyAppId($app);
$this->verifyConfigKey($app, $key, '');
} catch (\InvalidArgumentException $e) {
return new DataResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_FORBIDDEN);
}
$this->config->deleteAppValue($app, $key);
return new DataResponse();
}
/**
* @param string $app
* @throws \InvalidArgumentException
*/
protected function verifyAppId(string $app) {
if (\OC_App::cleanAppId($app) !== $app) {
throw new \InvalidArgumentException('Invalid app id given');
}
}
/**
* @param string $app
* @param string $key
* @param string $value
* @throws \InvalidArgumentException
*/
protected function verifyConfigKey(string $app, string $key, string $value) {
if (in_array($key, ['installed_version', 'enabled', 'types'])) {
throw new \InvalidArgumentException('The given key can not be set');
}
if ($app === 'core' && $key === 'encryption_enabled' && $value !== 'yes') {
throw new \InvalidArgumentException('The given key can not be set');
}
if ($app === 'core' && (strpos($key, 'public_') === 0 || strpos($key, 'remote_') === 0)) {
throw new \InvalidArgumentException('The given key can not be set');
}
if ($app === 'files'
&& $key === 'default_quota'
&& $value === 'none'
&& $this->config->getAppValue('files', 'allow_unlimited_quota', '1') === '0') {
throw new \InvalidArgumentException('The given key can not be set, unlimited quota is forbidden on this instance');
}
}
private function isAllowedToChangedKey(IUser $user, string $app, string $key): bool {
// Admin right verification
$isAdmin = $this->groupManager->isAdmin($user->getUID());
if ($isAdmin) {
return true;
}
$settings = $this->settingManager->getAllAllowedAdminSettings($user);
foreach ($settings as $setting) {
if (!($setting instanceof IDelegatedSettings)) {
continue;
}
$allowedKeys = $setting->getAuthorizedAppConfig();
if (!array_key_exists($app, $allowedKeys)) {
continue;
}
foreach ($allowedKeys[$app] as $regex) {
if ($regex === $key
|| (str_starts_with($regex, '/') && preg_match($regex, $key) === 1)) {
return true;
}
}
}
return false;
}
}
@@ -0,0 +1,145 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Tom Needham <tom@owncloud.com>
* @author Kate Döen <kate.doeen@nextcloud.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\Provisioning_API\Controller;
use OC_App;
use OCA\Provisioning_API\ResponseDefinitions;
use OCP\App\AppPathNotFoundException;
use OCP\App\IAppManager;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSException;
use OCP\AppFramework\OCSController;
use OCP\IRequest;
/**
* @psalm-import-type Provisioning_APIAppInfo from ResponseDefinitions
*/
class AppsController extends OCSController {
/** @var IAppManager */
private $appManager;
public function __construct(
string $appName,
IRequest $request,
IAppManager $appManager
) {
parent::__construct($appName, $request);
$this->appManager = $appManager;
}
/**
* Get a list of installed apps
*
* @param ?string $filter Filter for enabled or disabled apps
* @return DataResponse<Http::STATUS_OK, array{apps: string[]}, array{}>
* @throws OCSException
*
* 200: Installed apps returned
*/
public function getApps(?string $filter = null): DataResponse {
$apps = (new OC_App())->listAllApps();
$list = [];
foreach ($apps as $app) {
$list[] = $app['id'];
}
/** @var string[] $list */
if ($filter) {
switch ($filter) {
case 'enabled':
return new DataResponse(['apps' => \OC_App::getEnabledApps()]);
break;
case 'disabled':
$enabled = OC_App::getEnabledApps();
return new DataResponse(['apps' => array_diff($list, $enabled)]);
break;
default:
// Invalid filter variable
throw new OCSException('', 101);
}
} else {
return new DataResponse(['apps' => $list]);
}
}
/**
* Get the app info for an app
*
* @param string $app ID of the app
* @return DataResponse<Http::STATUS_OK, Provisioning_APIAppInfo, array{}>
* @throws OCSException
*
* 200: App info returned
*/
public function getAppInfo(string $app): DataResponse {
$info = $this->appManager->getAppInfo($app);
if (!is_null($info)) {
return new DataResponse($info);
}
throw new OCSException('The request app was not found', OCSController::RESPOND_NOT_FOUND);
}
/**
* @PasswordConfirmationRequired
*
* Enable an app
*
* @param string $app ID of the app
* @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
* @throws OCSException
*
* 200: App enabled successfully
*/
public function enable(string $app): DataResponse {
try {
$this->appManager->enableApp($app);
} catch (AppPathNotFoundException $e) {
throw new OCSException('The request app was not found', OCSController::RESPOND_NOT_FOUND);
}
return new DataResponse();
}
/**
* @PasswordConfirmationRequired
*
* Disable an app
*
* @param string $app ID of the app
* @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
*
* 200: App disabled successfully
*/
public function disable(string $app): DataResponse {
$this->appManager->disableApp($app);
return new DataResponse();
}
}
@@ -0,0 +1,368 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
* @author John Molakvoæ <skjnldsv@protonmail.com>
* @author Julius Härtl <jus@bitgrid.net>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Tom Needham <tom@owncloud.com>
* @author Kate Döen <kate.doeen@nextcloud.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\Provisioning_API\Controller;
use OCA\Provisioning_API\ResponseDefinitions;
use OCP\Accounts\IAccountManager;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSException;
use OCP\AppFramework\OCS\OCSForbiddenException;
use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\AppFramework\OCSController;
use OCP\IConfig;
use OCP\IGroup;
use OCP\IGroupManager;
use OCP\IRequest;
use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\L10N\IFactory;
use Psr\Log\LoggerInterface;
/**
* @psalm-import-type Provisioning_APIGroupDetails from ResponseDefinitions
* @psalm-import-type Provisioning_APIUserDetails from ResponseDefinitions
*/
class GroupsController extends AUserData {
/** @var LoggerInterface */
private $logger;
public function __construct(string $appName,
IRequest $request,
IUserManager $userManager,
IConfig $config,
IGroupManager $groupManager,
IUserSession $userSession,
IAccountManager $accountManager,
IFactory $l10nFactory,
LoggerInterface $logger) {
parent::__construct($appName,
$request,
$userManager,
$config,
$groupManager,
$userSession,
$accountManager,
$l10nFactory
);
$this->logger = $logger;
}
/**
* @NoAdminRequired
*
* Get a list of groups
*
* @param string $search Text to search for
* @param ?int $limit Limit the amount of groups returned
* @param int $offset Offset for searching for groups
* @return DataResponse<Http::STATUS_OK, array{groups: string[]}, array{}>
*
* 200: Groups returned
*/
public function getGroups(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
$groups = $this->groupManager->search($search, $limit, $offset);
$groups = array_map(function ($group) {
/** @var IGroup $group */
return $group->getGID();
}, $groups);
return new DataResponse(['groups' => $groups]);
}
/**
* @NoAdminRequired
* @AuthorizedAdminSetting(settings=OCA\Settings\Settings\Admin\Sharing)
*
* Get a list of groups details
*
* @param string $search Text to search for
* @param ?int $limit Limit the amount of groups returned
* @param int $offset Offset for searching for groups
* @return DataResponse<Http::STATUS_OK, array{groups: Provisioning_APIGroupDetails[]}, array{}>
*
* 200: Groups details returned
*/
public function getGroupsDetails(string $search = '', int $limit = null, int $offset = 0): DataResponse {
$groups = $this->groupManager->search($search, $limit, $offset);
$groups = array_map(function ($group) {
/** @var IGroup $group */
return [
'id' => $group->getGID(),
'displayname' => $group->getDisplayName(),
'usercount' => $group->count(),
'disabled' => $group->countDisabled(),
'canAdd' => $group->canAddUser(),
'canRemove' => $group->canRemoveUser(),
];
}, $groups);
return new DataResponse(['groups' => $groups]);
}
/**
* @NoAdminRequired
*
* Get a list of users in the specified group
*
* @param string $groupId ID of the group
* @return DataResponse<Http::STATUS_OK, array{users: string[]}, array{}>
* @throws OCSException
*
* @deprecated 14 Use getGroupUsers
*
* 200: Group users returned
*/
public function getGroup(string $groupId): DataResponse {
return $this->getGroupUsers($groupId);
}
/**
* @NoAdminRequired
*
* Get a list of users in the specified group
*
* @param string $groupId ID of the group
* @return DataResponse<Http::STATUS_OK, array{users: string[]}, array{}>
* @throws OCSException
* @throws OCSNotFoundException Group not found
* @throws OCSForbiddenException Missing permissions to get users in the group
*
* 200: User IDs returned
*/
public function getGroupUsers(string $groupId): DataResponse {
$groupId = urldecode($groupId);
$user = $this->userSession->getUser();
$isSubadminOfGroup = false;
// Check the group exists
$group = $this->groupManager->get($groupId);
if ($group !== null) {
$isSubadminOfGroup = $this->groupManager->getSubAdmin()->isSubAdminOfGroup($user, $group);
} else {
throw new OCSNotFoundException('The requested group could not be found');
}
// Check subadmin has access to this group
if ($this->groupManager->isAdmin($user->getUID())
|| $isSubadminOfGroup) {
$users = $this->groupManager->get($groupId)->getUsers();
$users = array_map(function ($user) {
/** @var IUser $user */
return $user->getUID();
}, $users);
/** @var string[] $users */
$users = array_values($users);
return new DataResponse(['users' => $users]);
}
throw new OCSForbiddenException();
}
/**
* @NoAdminRequired
*
* Get a list of users details in the specified group
*
* @param string $groupId ID of the group
* @param string $search Text to search for
* @param int|null $limit Limit the amount of groups returned
* @param int $offset Offset for searching for groups
*
* @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
* @throws OCSException
*
* 200: Group users details returned
*/
public function getGroupUsersDetails(string $groupId, string $search = '', int $limit = null, int $offset = 0): DataResponse {
$groupId = urldecode($groupId);
$currentUser = $this->userSession->getUser();
// Check the group exists
$group = $this->groupManager->get($groupId);
if ($group !== null) {
$isSubadminOfGroup = $this->groupManager->getSubAdmin()->isSubAdminOfGroup($currentUser, $group);
} else {
throw new OCSException('The requested group could not be found', OCSController::RESPOND_NOT_FOUND);
}
// Check subadmin has access to this group
if ($this->groupManager->isAdmin($currentUser->getUID()) || $isSubadminOfGroup) {
$users = $group->searchUsers($search, $limit, $offset);
// Extract required number
$usersDetails = [];
foreach ($users as $user) {
try {
/** @var IUser $user */
$userId = (string)$user->getUID();
$userData = $this->getUserData($userId);
// Do not insert empty entry
if ($userData !== null) {
$usersDetails[$userId] = $userData;
} else {
// Logged user does not have permissions to see this user
// only showing its id
$usersDetails[$userId] = ['id' => $userId];
}
} catch (OCSNotFoundException $e) {
// continue if a users ceased to exist.
}
}
return new DataResponse(['users' => $usersDetails]);
}
throw new OCSException('The requested group could not be found', OCSController::RESPOND_NOT_FOUND);
}
/**
* @PasswordConfirmationRequired
*
* Create a new group
*
* @param string $groupid ID of the group
* @param string $displayname Display name of the group
* @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
* @throws OCSException
*
* 200: Group created successfully
*/
public function addGroup(string $groupid, string $displayname = ''): DataResponse {
// Validate name
if (empty($groupid)) {
$this->logger->error('Group name not supplied', ['app' => 'provisioning_api']);
throw new OCSException('Invalid group name', 101);
}
// Check if it exists
if ($this->groupManager->groupExists($groupid)) {
throw new OCSException('group exists', 102);
}
$group = $this->groupManager->createGroup($groupid);
if ($group === null) {
throw new OCSException('Not supported by backend', 103);
}
if ($displayname !== '') {
$group->setDisplayName($displayname);
}
return new DataResponse();
}
/**
* @PasswordConfirmationRequired
*
* Update a group
*
* @param string $groupId ID of the group
* @param string $key Key to update, only 'displayname'
* @param string $value New value for the key
* @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
* @throws OCSException
*
* 200: Group updated successfully
*/
public function updateGroup(string $groupId, string $key, string $value): DataResponse {
$groupId = urldecode($groupId);
if ($key === 'displayname') {
$group = $this->groupManager->get($groupId);
if ($group === null) {
throw new OCSException('Group does not exist', OCSController::RESPOND_NOT_FOUND);
}
if ($group->setDisplayName($value)) {
return new DataResponse();
}
throw new OCSException('Not supported by backend', 101);
} else {
throw new OCSException('', OCSController::RESPOND_UNKNOWN_ERROR);
}
}
/**
* @PasswordConfirmationRequired
*
* Delete a group
*
* @param string $groupId ID of the group
* @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
* @throws OCSException
*
* 200: Group deleted successfully
*/
public function deleteGroup(string $groupId): DataResponse {
$groupId = urldecode($groupId);
// Check it exists
if (!$this->groupManager->groupExists($groupId)) {
throw new OCSException('', 101);
} elseif ($groupId === 'admin' || !$this->groupManager->get($groupId)->delete()) {
// Cannot delete admin group
throw new OCSException('', 102);
}
return new DataResponse();
}
/**
* Get the list of user IDs that are a subadmin of the group
*
* @param string $groupId ID of the group
* @return DataResponse<Http::STATUS_OK, string[], array{}>
* @throws OCSException
*
* 200: Sub admins returned
*/
public function getSubAdminsOfGroup(string $groupId): DataResponse {
// Check group exists
$targetGroup = $this->groupManager->get($groupId);
if ($targetGroup === null) {
throw new OCSException('Group does not exist', 101);
}
/** @var IUser[] $subadmins */
$subadmins = $this->groupManager->getSubAdmin()->getGroupsSubAdmins($targetGroup);
// New class returns IUser[] so convert back
/** @var string[] $uids */
$uids = [];
foreach ($subadmins as $user) {
$uids[] = $user->getUID();
}
return new DataResponse($uids);
}
}
@@ -0,0 +1,224 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com>
*
* @author Joas Schilling <coding@schilljs.com>
* @author Kate Döen <kate.doeen@nextcloud.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 <https://www.gnu.org/licenses/>.
*
*/
namespace OCA\Provisioning_API\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\Config\BeforePreferenceDeletedEvent;
use OCP\Config\BeforePreferenceSetEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
use OCP\IRequest;
use OCP\IUserSession;
class PreferencesController extends OCSController {
private IConfig $config;
private IUserSession $userSession;
private IEventDispatcher $eventDispatcher;
public function __construct(
string $appName,
IRequest $request,
IConfig $config,
IUserSession $userSession,
IEventDispatcher $eventDispatcher
) {
parent::__construct($appName, $request);
$this->config = $config;
$this->userSession = $userSession;
$this->eventDispatcher = $eventDispatcher;
}
/**
* @NoAdminRequired
* @NoSubAdminRequired
*
* Update multiple preference values of an app
*
* @param string $appId ID of the app
* @param array<string, string> $configs Key-value pairs of the preferences
*
* @return DataResponse<Http::STATUS_OK|Http::STATUS_BAD_REQUEST, array<empty>, array{}>
*
* 200: Preferences updated successfully
* 400: Preference invalid
*/
public function setMultiplePreferences(string $appId, array $configs): DataResponse {
$userId = $this->userSession->getUser()->getUID();
foreach ($configs as $configKey => $configValue) {
$event = new BeforePreferenceSetEvent(
$userId,
$appId,
$configKey,
$configValue
);
$this->eventDispatcher->dispatchTyped($event);
if (!$event->isValid()) {
// No listener validated that the preference can be set (to this value)
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
}
foreach ($configs as $configKey => $configValue) {
$this->config->setUserValue(
$userId,
$appId,
$configKey,
$configValue
);
}
return new DataResponse();
}
/**
* @NoAdminRequired
* @NoSubAdminRequired
*
* Update a preference value of an app
*
* @param string $appId ID of the app
* @param string $configKey Key of the preference
* @param string $configValue New value
* @return DataResponse<Http::STATUS_OK|Http::STATUS_BAD_REQUEST, array<empty>, array{}>
*
* 200: Preference updated successfully
* 400: Preference invalid
*/
public function setPreference(string $appId, string $configKey, string $configValue): DataResponse {
$userId = $this->userSession->getUser()->getUID();
$event = new BeforePreferenceSetEvent(
$userId,
$appId,
$configKey,
$configValue
);
$this->eventDispatcher->dispatchTyped($event);
if (!$event->isValid()) {
// No listener validated that the preference can be set (to this value)
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
$this->config->setUserValue(
$userId,
$appId,
$configKey,
$configValue
);
return new DataResponse();
}
/**
* @NoAdminRequired
* @NoSubAdminRequired
*
* Delete multiple preferences for an app
*
* @param string $appId ID of the app
* @param string[] $configKeys Keys to delete
*
* @return DataResponse<Http::STATUS_OK|Http::STATUS_BAD_REQUEST, array<empty>, array{}>
* 200: Preferences deleted successfully
* 400: Preference invalid
*/
public function deleteMultiplePreference(string $appId, array $configKeys): DataResponse {
$userId = $this->userSession->getUser()->getUID();
foreach ($configKeys as $configKey) {
$event = new BeforePreferenceDeletedEvent(
$userId,
$appId,
$configKey
);
$this->eventDispatcher->dispatchTyped($event);
if (!$event->isValid()) {
// No listener validated that the preference can be deleted
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
}
foreach ($configKeys as $configKey) {
$this->config->deleteUserValue(
$userId,
$appId,
$configKey
);
}
return new DataResponse();
}
/**
* @NoAdminRequired
* @NoSubAdminRequired
*
* Delete a preference for an app
*
* @param string $appId ID of the app
* @param string $configKey Key to delete
* @return DataResponse<Http::STATUS_OK|Http::STATUS_BAD_REQUEST, array<empty>, array{}>
*
* 200: Preference deleted successfully
* 400: Preference invalid
*/
public function deletePreference(string $appId, string $configKey): DataResponse {
$userId = $this->userSession->getUser()->getUID();
$event = new BeforePreferenceDeletedEvent(
$userId,
$appId,
$configKey
);
$this->eventDispatcher->dispatchTyped($event);
if (!$event->isValid()) {
// No listener validated that the preference can be deleted
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
$this->config->deleteUserValue(
$userId,
$appId,
$configKey
);
return new DataResponse();
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,155 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2021 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Kate Döen <kate.doeen@nextcloud.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 <https://www.gnu.org/licenses/>.
*
*/
namespace OCA\Provisioning_API\Controller;
use InvalidArgumentException;
use OC\Security\Crypto;
use OCP\Accounts\IAccountManager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IL10N;
use OCP\IRequest;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Security\VerificationToken\InvalidTokenException;
use OCP\Security\VerificationToken\IVerificationToken;
#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
class VerificationController extends Controller {
/** @var IVerificationToken */
private $verificationToken;
/** @var IUserManager */
private $userManager;
/** @var IL10N */
private $l10n;
/** @var IUserSession */
private $userSession;
/** @var IAccountManager */
private $accountManager;
/** @var Crypto */
private $crypto;
public function __construct(
string $appName,
IRequest $request,
IVerificationToken $verificationToken,
IUserManager $userManager,
IL10N $l10n,
IUserSession $userSession,
IAccountManager $accountManager,
Crypto $crypto
) {
parent::__construct($appName, $request);
$this->verificationToken = $verificationToken;
$this->userManager = $userManager;
$this->l10n = $l10n;
$this->userSession = $userSession;
$this->accountManager = $accountManager;
$this->crypto = $crypto;
}
/**
* @NoCSRFRequired
* @NoAdminRequired
* @NoSubAdminRequired
*/
public function showVerifyMail(string $token, string $userId, string $key): TemplateResponse {
if ($this->userSession->getUser()->getUID() !== $userId) {
// not a public page, hence getUser() must return an IUser
throw new InvalidArgumentException('Logged in user is not mail address owner');
}
$email = $this->crypto->decrypt($key);
return new TemplateResponse(
'core', 'confirmation', [
'title' => $this->l10n->t('Email confirmation'),
'message' => $this->l10n->t('To enable the email address %s please click the button below.', [$email]),
'action' => $this->l10n->t('Confirm'),
], TemplateResponse::RENDER_AS_GUEST);
}
/**
* @NoAdminRequired
* @NoSubAdminRequired
* @BruteForceProtection(action=emailVerification)
*/
public function verifyMail(string $token, string $userId, string $key): TemplateResponse {
$throttle = false;
try {
if ($this->userSession->getUser()->getUID() !== $userId) {
throw new InvalidArgumentException('Logged in user is not mail address owner');
}
$email = $this->crypto->decrypt($key);
$ref = \substr(hash('sha256', $email), 0, 8);
$user = $this->userManager->get($userId);
$this->verificationToken->check($token, $user, 'verifyMail' . $ref, $email);
$userAccount = $this->accountManager->getAccount($user);
$emailProperty = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL)
->getPropertyByValue($email);
if ($emailProperty === null) {
throw new InvalidArgumentException($this->l10n->t('Email was already removed from account and cannot be confirmed anymore.'));
}
$emailProperty->setLocallyVerified(IAccountManager::VERIFIED);
$this->accountManager->updateAccount($userAccount);
$this->verificationToken->delete($token, $user, 'verifyMail' . $ref);
} catch (InvalidTokenException $e) {
if ($e->getCode() === InvalidTokenException::TOKEN_EXPIRED) {
$error = $this->l10n->t('Could not verify mail because the token is expired.');
} else {
$throttle = true;
$error = $this->l10n->t('Could not verify mail because the token is invalid.');
}
} catch (InvalidArgumentException $e) {
$error = $e->getMessage();
} catch (\Exception $e) {
$error = $this->l10n->t('An unexpected error occurred. Please contact your admin.');
}
if (isset($error)) {
$response = new TemplateResponse(
'core', 'error', [
'errors' => [['error' => $error]]
], TemplateResponse::RENDER_AS_GUEST);
if ($throttle) {
$response->throttle();
}
return $response;
}
return new TemplateResponse(
'core', 'success', [
'title' => $this->l10n->t('Email confirmation successful'),
'message' => $this->l10n->t('Email confirmation successful'),
], TemplateResponse::RENDER_AS_GUEST);
}
}
@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
/**
* @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.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 OCA\Provisioning_API;
use OCA\FederatedFileSharing\FederatedShareProvider;
use OCP\IServerContainer;
class FederatedShareProviderFactory {
/** @var IServerContainer */
private $serverContainer;
public function __construct(IServerContainer $serverContainer) {
$this->serverContainer = $serverContainer;
}
public function get(): FederatedShareProvider {
return $this->serverContainer->query(FederatedShareProvider::class);
}
}
@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com>
*
* @author 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 OCA\Provisioning_API\Listener;
use OC\KnownUser\KnownUserService;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\User\Events\UserDeletedEvent;
class UserDeletedListener implements IEventListener {
/** @var KnownUserService */
private $service;
public function __construct(KnownUserService $service) {
$this->service = $service;
}
public function handle(Event $event): void {
if (!($event instanceof UserDeletedEvent)) {
// Unrelated
return;
}
$user = $event->getUser();
// Delete all entries of this user
$this->service->deleteKnownTo($user->getUID());
// Delete all entries that other users know this user
$this->service->deleteByContactUserId($user->getUID());
}
}
@@ -0,0 +1,32 @@
<?php
/**
* @copyright Copyright (c) 2016 Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.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 OCA\Provisioning_API\Middleware\Exceptions;
use OCP\AppFramework\Http;
class NotSubAdminException extends \Exception {
public function __construct() {
parent::__construct('Logged in user must be at least a sub admin', Http::STATUS_FORBIDDEN);
}
}
@@ -0,0 +1,93 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Joas Schilling <coding@schilljs.com>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.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 OCA\Provisioning_API\Middleware;
use OCA\Provisioning_API\Middleware\Exceptions\NotSubAdminException;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Middleware;
use OCP\AppFramework\OCS\OCSException;
use OCP\AppFramework\Utility\IControllerMethodReflector;
class ProvisioningApiMiddleware extends Middleware {
/** @var IControllerMethodReflector */
private $reflector;
/** @var bool */
private $isAdmin;
/** @var bool */
private $isSubAdmin;
/**
* ProvisioningApiMiddleware constructor.
*
* @param IControllerMethodReflector $reflector
* @param bool $isAdmin
* @param bool $isSubAdmin
*/
public function __construct(
IControllerMethodReflector $reflector,
bool $isAdmin,
bool $isSubAdmin) {
$this->reflector = $reflector;
$this->isAdmin = $isAdmin;
$this->isSubAdmin = $isSubAdmin;
}
/**
* @param Controller $controller
* @param string $methodName
*
* @throws NotSubAdminException
*/
public function beforeController($controller, $methodName) {
// If AuthorizedAdminSetting, the check will be done in the SecurityMiddleware
if (!$this->isAdmin && !$this->reflector->hasAnnotation('NoSubAdminRequired') && !$this->isSubAdmin && !$this->reflector->hasAnnotation('AuthorizedAdminSetting')) {
throw new NotSubAdminException();
}
}
/**
* @param Controller $controller
* @param string $methodName
* @param \Exception $exception
* @throws \Exception
* @return Response
*/
public function afterException($controller, $methodName, \Exception $exception) {
if ($exception instanceof NotSubAdminException) {
throw new OCSException($exception->getMessage(), Http::STATUS_FORBIDDEN);
}
throw $exception;
}
}
@@ -0,0 +1,137 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2023 Kate Döen <kate.doeen@nextcloud.com>
*
* @author Kate Döen <kate.doeen@nextcloud.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 OCA\Provisioning_API;
/**
* @psalm-type Provisioning_APIUserDetailsQuota = array{
* free?: float|int,
* quota?: float|int|string,
* relative?: float|int,
* total?: float|int,
* used?: float|int,
* }
*
* @psalm-type Provisioning_APIUserDetails = array{
* additional_mail: string[],
* additional_mailScope?: string[],
* address: string,
* addressScope?: string,
* avatarScope?: string,
* backend: string,
* backendCapabilities: array{
* setDisplayName: bool,
* setPassword: bool
* },
* biography: string,
* biographyScope?: string,
* display-name: string,
* displayname: string,
* displaynameScope?: string,
* email: ?string,
* emailScope?: string,
* enabled?: bool,
* fediverse: string,
* fediverseScope?: string,
* groups: string[],
* headline: string,
* headlineScope?: string,
* id: string,
* language: string,
* lastLogin: int,
* locale: string,
* manager: string,
* notify_email: ?string,
* organisation: string,
* organisationScope?: string,
* phone: string,
* phoneScope?: string,
* profile_enabled: string,
* profile_enabledScope?: string,
* quota: Provisioning_APIUserDetailsQuota,
* role: string,
* roleScope?: string,
* storageLocation?: string,
* subadmin: string[],
* twitter: string,
* twitterScope?: string,
* website: string,
* websiteScope?: string,
* }
*
* @psalm-type Provisioning_APIAppInfo = array{
* active: bool|null,
* activity: ?mixed,
* author: ?mixed,
* background-jobs: ?mixed,
* bugs: ?mixed,
* category: ?mixed,
* collaboration: ?mixed,
* commands: ?mixed,
* default_enable: ?mixed,
* dependencies: ?mixed,
* description: string,
* discussion: ?mixed,
* documentation: ?mixed,
* groups: ?mixed,
* id: string,
* info: ?mixed,
* internal: bool|null,
* level: int|null,
* licence: ?mixed,
* name: string,
* namespace: ?mixed,
* navigations: ?mixed,
* preview: ?mixed,
* previewAsIcon: bool|null,
* public: ?mixed,
* remote: ?mixed,
* removable: bool|null,
* repair-steps: ?mixed,
* repository: ?mixed,
* sabre: ?mixed,
* screenshot: ?mixed,
* settings: ?mixed,
* summary: string,
* trash: ?mixed,
* two-factor-providers: ?mixed,
* types: ?mixed,
* version: string,
* versions: ?mixed,
* website: ?mixed,
* }
*
* @psalm-type Provisioning_APIGroupDetails = array{
* id: string,
* displayname: string,
* usercount: bool|int,
* disabled: bool|int,
* canAdd: bool,
* canRemove: bool,
* }
*/
class ResponseDefinitions {
}