summaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private')
-rw-r--r--lib/private/Accounts/AccountManager.php155
-rw-r--r--lib/private/Accounts/Hooks.php27
-rw-r--r--lib/private/Activity/ActivitySettingsAdapter.php18
-rw-r--r--lib/private/Activity/Event.php1
-rw-r--r--lib/private/Activity/Manager.php18
-rw-r--r--lib/private/AllConfig.php19
-rw-r--r--lib/private/App/AppManager.php2
-rw-r--r--lib/private/App/AppStore/Bundles/HubBundle.php13
-rw-r--r--lib/private/App/AppStore/Fetcher/AppFetcher.php40
-rw-r--r--lib/private/App/AppStore/Fetcher/Fetcher.php34
-rw-r--r--lib/private/App/CodeChecker/CodeChecker.php8
-rw-r--r--lib/private/App/CodeChecker/NodeVisitor.php13
-rw-r--r--lib/private/App/DependencyAnalyzer.php28
-rw-r--r--lib/private/App/Platform.php5
-rw-r--r--lib/private/AppConfig.php51
-rw-r--r--lib/private/AppFramework/App.php16
-rw-r--r--lib/private/AppFramework/Bootstrap/BootContext.php6
-rw-r--r--lib/private/AppFramework/Bootstrap/Coordinator.php38
-rw-r--r--lib/private/AppFramework/Bootstrap/FunctionInjector.php5
-rw-r--r--lib/private/AppFramework/Bootstrap/RegistrationContext.php77
-rw-r--r--lib/private/AppFramework/DependencyInjection/DIContainer.php7
-rw-r--r--lib/private/AppFramework/Http.php2
-rw-r--r--lib/private/AppFramework/Http/Dispatcher.php54
-rw-r--r--lib/private/AppFramework/Http/Output.php22
-rw-r--r--lib/private/AppFramework/Http/Request.php11
-rw-r--r--lib/private/AppFramework/Logger.php1
-rw-r--r--lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php3
-rw-r--r--lib/private/AppFramework/Middleware/CompressionMiddleware.php4
-rw-r--r--lib/private/AppFramework/Middleware/MiddlewareDispatcher.php6
-rw-r--r--lib/private/AppFramework/Middleware/NotModifiedMiddleware.php3
-rw-r--r--lib/private/AppFramework/Middleware/Security/BruteForceMiddleware.php31
-rw-r--r--lib/private/AppFramework/Middleware/Security/CORSMiddleware.php2
-rw-r--r--lib/private/AppFramework/Middleware/Security/SameSiteCookieMiddleware.php2
-rw-r--r--lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php1
-rw-r--r--lib/private/AppFramework/OCS/V1Response.php3
-rw-r--r--lib/private/AppFramework/OCS/V2Response.php2
-rw-r--r--lib/private/AppFramework/Routing/RouteConfig.php8
-rw-r--r--lib/private/AppFramework/Routing/RouteParser.php263
-rw-r--r--lib/private/AppFramework/ScopedPsrLogger.php7
-rw-r--r--lib/private/AppFramework/Services/AppConfig.php4
-rw-r--r--lib/private/AppFramework/Services/InitialState.php3
-rw-r--r--lib/private/AppFramework/Utility/ControllerMethodReflector.php1
-rw-r--r--lib/private/AppFramework/Utility/SimpleContainer.php13
-rw-r--r--lib/private/Archive/Archive.php2
-rw-r--r--lib/private/Archive/TAR.php11
-rw-r--r--lib/private/Archive/ZIP.php52
-rw-r--r--lib/private/Authentication/Listeners/LoginFailedListener.php3
-rw-r--r--lib/private/Authentication/Listeners/RemoteWipeActivityListener.php15
-rw-r--r--lib/private/Authentication/Listeners/RemoteWipeEmailListener.php20
-rw-r--r--lib/private/Authentication/Listeners/RemoteWipeNotificationsListener.php3
-rw-r--r--lib/private/Authentication/Listeners/UserDeletedStoreCleanupListener.php3
-rw-r--r--lib/private/Authentication/Listeners/UserDeletedTokenCleanupListener.php20
-rw-r--r--lib/private/Authentication/Listeners/UserLoggedInListener.php59
-rw-r--r--lib/private/Authentication/Login/LoggedInCheckCommand.php11
-rw-r--r--lib/private/Authentication/Login/UserDisabledCheckCommand.php7
-rw-r--r--lib/private/Authentication/LoginCredentials/Store.php23
-rw-r--r--lib/private/Authentication/Token/DefaultToken.php2
-rw-r--r--lib/private/Authentication/Token/DefaultTokenMapper.php3
-rw-r--r--lib/private/Authentication/Token/DefaultTokenProvider.php6
-rw-r--r--lib/private/Authentication/Token/IProvider.php4
-rw-r--r--lib/private/Authentication/Token/PublicKeyToken.php2
-rw-r--r--lib/private/Authentication/Token/PublicKeyTokenMapper.php4
-rw-r--r--lib/private/Authentication/Token/PublicKeyTokenProvider.php28
-rw-r--r--lib/private/Authentication/Token/RemoteWipe.php6
-rw-r--r--lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php35
-rw-r--r--lib/private/Authentication/TwoFactorAuth/Manager.php22
-rw-r--r--lib/private/Authentication/TwoFactorAuth/Registry.php9
-rw-r--r--lib/private/Authentication/WebAuthn/Db/PublicKeyCredentialMapper.php4
-rw-r--r--lib/private/Authentication/WebAuthn/Manager.php7
-rw-r--r--lib/private/BackgroundJob/Job.php1
-rw-r--r--lib/private/BackgroundJob/JobList.php15
-rw-r--r--lib/private/BackgroundJob/TimedJob.php1
-rw-r--r--lib/private/Cache/File.php2
-rw-r--r--lib/private/Calendar/Manager.php6
-rw-r--r--lib/private/Collaboration/AutoComplete/Manager.php2
-rw-r--r--lib/private/Collaboration/Collaborators/GroupPlugin.php3
-rw-r--r--lib/private/Collaboration/Collaborators/LookupPlugin.php1
-rw-r--r--lib/private/Collaboration/Collaborators/MailPlugin.php3
-rw-r--r--lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php1
-rw-r--r--lib/private/Collaboration/Collaborators/RemotePlugin.php3
-rw-r--r--lib/private/Collaboration/Collaborators/Search.php11
-rw-r--r--lib/private/Collaboration/Collaborators/UserPlugin.php79
-rw-r--r--lib/private/Command/ClosureJob.php5
-rw-r--r--lib/private/Command/CommandJob.php3
-rw-r--r--lib/private/Command/CronBus.php7
-rw-r--r--lib/private/Comments/Comment.php32
-rw-r--r--lib/private/Comments/Manager.php238
-rw-r--r--lib/private/Comments/ManagerFactory.php9
-rw-r--r--lib/private/Config.php11
-rw-r--r--lib/private/Contacts/ContactsMenu/ContactsStore.php25
-rw-r--r--lib/private/Contacts/ContactsMenu/Manager.php6
-rw-r--r--lib/private/ContactsManager.php16
-rw-r--r--lib/private/DB/Adapter.php5
-rw-r--r--lib/private/DB/AdapterPgSql.php3
-rw-r--r--lib/private/DB/AdapterSqlite.php2
-rw-r--r--lib/private/DB/Connection.php92
-rw-r--r--lib/private/DB/MDB2SchemaManager.php3
-rw-r--r--lib/private/DB/MDB2SchemaReader.php2
-rw-r--r--lib/private/DB/MigrationService.php63
-rw-r--r--lib/private/DB/Migrator.php7
-rw-r--r--lib/private/DB/MissingPrimaryKeyInformation.php41
-rw-r--r--lib/private/DB/OracleConnection.php29
-rw-r--r--lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php14
-rw-r--r--lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php8
-rw-r--r--lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php25
-rw-r--r--lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php46
-rw-r--r--lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php3
-rw-r--r--lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php7
-rw-r--r--lib/private/DB/QueryBuilder/QueryBuilder.php74
-rw-r--r--lib/private/DB/SchemaWrapper.php1
-rw-r--r--lib/private/Dashboard/Manager.php54
-rw-r--r--lib/private/DirectEditing/Manager.php37
-rw-r--r--lib/private/Encryption/DecryptAll.php2
-rw-r--r--lib/private/Encryption/File.php3
-rw-r--r--lib/private/Encryption/Keys/Storage.php150
-rw-r--r--lib/private/Encryption/Util.php4
-rw-r--r--lib/private/EventDispatcher/EventDispatcher.php6
-rw-r--r--lib/private/EventDispatcher/GenericEventWrapper.php4
-rw-r--r--lib/private/EventDispatcher/ServiceEventListener.php12
-rw-r--r--lib/private/EventDispatcher/SymfonyAdapter.php1
-rw-r--r--lib/private/Federation/CloudFederationProviderManager.php3
-rw-r--r--lib/private/Federation/CloudFederationShare.php1
-rw-r--r--lib/private/Federation/CloudId.php11
-rw-r--r--lib/private/Federation/CloudIdManager.php57
-rw-r--r--lib/private/Files/Cache/AbstractCacheEvent.php12
-rw-r--r--lib/private/Files/Cache/Cache.php155
-rw-r--r--lib/private/Files/Cache/CacheEntry.php5
-rw-r--r--lib/private/Files/Cache/CacheQueryBuilder.php13
-rw-r--r--lib/private/Files/Cache/HomeCache.php23
-rw-r--r--lib/private/Files/Cache/LocalRootScanner.php5
-rw-r--r--lib/private/Files/Cache/NullWatcher.php56
-rw-r--r--lib/private/Files/Cache/Propagator.php11
-rw-r--r--lib/private/Files/Cache/Scanner.php2
-rw-r--r--lib/private/Files/Cache/Storage.php36
-rw-r--r--lib/private/Files/Cache/StorageGlobal.php7
-rw-r--r--lib/private/Files/Cache/Updater.php2
-rw-r--r--lib/private/Files/Cache/Watcher.php2
-rw-r--r--lib/private/Files/Cache/Wrapper/CacheJail.php5
-rw-r--r--lib/private/Files/Cache/Wrapper/CacheWrapper.php2
-rw-r--r--lib/private/Files/Config/MountProviderCollection.php25
-rw-r--r--lib/private/Files/Config/UserMountCache.php26
-rw-r--r--lib/private/Files/FileInfo.php4
-rw-r--r--lib/private/Files/Filesystem.php9
-rw-r--r--lib/private/Files/Mount/MountPoint.php4
-rw-r--r--lib/private/Files/Mount/ObjectStorePreviewCacheMountProvider.php151
-rw-r--r--lib/private/Files/Node/File.php2
-rw-r--r--lib/private/Files/Node/Folder.php68
-rw-r--r--lib/private/Files/Node/LazyFolder.php5
-rw-r--r--lib/private/Files/Node/LazyRoot.php1
-rw-r--r--lib/private/Files/Node/Node.php2
-rw-r--r--lib/private/Files/Node/NonExistingFolder.php2
-rw-r--r--lib/private/Files/Node/Root.php2
-rw-r--r--lib/private/Files/ObjectStore/AppdataPreviewObjectStoreStorage.php45
-rw-r--r--lib/private/Files/ObjectStore/Azure.php4
-rw-r--r--lib/private/Files/ObjectStore/NoopScanner.php2
-rw-r--r--lib/private/Files/ObjectStore/ObjectStoreStorage.php117
-rw-r--r--lib/private/Files/ObjectStore/S3ConnectionTrait.php49
-rw-r--r--lib/private/Files/ObjectStore/S3ObjectTrait.php5
-rw-r--r--lib/private/Files/ObjectStore/S3Signature.php3
-rw-r--r--lib/private/Files/ObjectStore/StorageObjectStore.php4
-rw-r--r--lib/private/Files/ObjectStore/Swift.php13
-rw-r--r--lib/private/Files/ObjectStore/SwiftFactory.php1
-rw-r--r--lib/private/Files/Storage/Common.php3
-rw-r--r--lib/private/Files/Storage/CommonTest.php4
-rw-r--r--lib/private/Files/Storage/DAV.php10
-rw-r--r--lib/private/Files/Storage/FailedStorage.php2
-rw-r--r--lib/private/Files/Storage/Flysystem.php6
-rw-r--r--lib/private/Files/Storage/Home.php2
-rw-r--r--lib/private/Files/Storage/Local.php19
-rw-r--r--lib/private/Files/Storage/LocalRootStorage.php5
-rw-r--r--lib/private/Files/Storage/StorageFactory.php2
-rw-r--r--lib/private/Files/Storage/Temporary.php2
-rw-r--r--lib/private/Files/Storage/Wrapper/Encoding.php6
-rw-r--r--lib/private/Files/Storage/Wrapper/Encryption.php9
-rw-r--r--lib/private/Files/Storage/Wrapper/Jail.php10
-rw-r--r--lib/private/Files/Storage/Wrapper/Quota.php23
-rw-r--r--lib/private/Files/Storage/Wrapper/Wrapper.php6
-rw-r--r--lib/private/Files/Stream/Encryption.php14
-rw-r--r--lib/private/Files/Stream/Quota.php2
-rw-r--r--lib/private/Files/Type/Detection.php13
-rw-r--r--lib/private/Files/Type/Loader.php10
-rw-r--r--lib/private/Files/Utils/Scanner.php2
-rw-r--r--lib/private/Files/View.php40
-rw-r--r--lib/private/ForbiddenException.php2
-rw-r--r--lib/private/FullTextSearch/Model/SearchRequestSimpleQuery.php5
-rw-r--r--lib/private/Group/Backend.php2
-rw-r--r--lib/private/Group/Database.php24
-rw-r--r--lib/private/Group/Group.php2
-rw-r--r--lib/private/Group/Manager.php6
-rw-r--r--lib/private/Group/MetaData.php5
-rw-r--r--lib/private/Hooks/Emitter.php2
-rw-r--r--lib/private/Hooks/EmitterTrait.php6
-rw-r--r--lib/private/Hooks/ForwardingEmitter.php66
-rw-r--r--lib/private/Hooks/LegacyEmitter.php40
-rw-r--r--lib/private/Hooks/PublicEmitter.php1
-rw-r--r--lib/private/Http/Client/Client.php10
-rw-r--r--lib/private/Http/WellKnown/RequestManager.php124
-rw-r--r--lib/private/InitialStateService.php62
-rw-r--r--lib/private/Installer.php52
-rw-r--r--lib/private/IntegrityCheck/Checker.php2
-rw-r--r--lib/private/L10N/Factory.php18
-rwxr-xr-xlib/private/LargeFileHelper.php7
-rw-r--r--lib/private/Lock/DBLockingProvider.php5
-rw-r--r--lib/private/Lock/MemcacheLockingProvider.php3
-rw-r--r--lib/private/Lock/NoopLockingProvider.php2
-rw-r--r--lib/private/Log.php3
-rw-r--r--lib/private/Log/ErrorHandler.php9
-rw-r--r--lib/private/Log/ExceptionSerializer.php4
-rw-r--r--lib/private/Log/File.php5
-rw-r--r--lib/private/Mail/EMailTemplate.php52
-rw-r--r--lib/private/Mail/Mailer.php7
-rw-r--r--lib/private/Memcache/APCu.php7
-rw-r--r--lib/private/Memcache/Factory.php2
-rw-r--r--lib/private/Memcache/Memcached.php14
-rw-r--r--lib/private/Memcache/NullCache.php2
-rw-r--r--lib/private/Memcache/Redis.php8
-rw-r--r--lib/private/Migration/BackgroundRepair.php3
-rw-r--r--lib/private/NaturalSort.php2
-rw-r--r--lib/private/NavigationManager.php22
-rw-r--r--lib/private/OCS/DiscoveryService.php2
-rw-r--r--lib/private/Preview/Generator.php17
-rw-r--r--lib/private/Preview/Storage/Root.php25
-rw-r--r--lib/private/Preview/TXT.php2
-rw-r--r--lib/private/PreviewManager.php17
-rw-r--r--lib/private/Repair.php44
-rw-r--r--lib/private/Repair/AddBruteForceCleanupJob.php50
-rw-r--r--lib/private/Repair/CleanTags.php2
-rw-r--r--lib/private/Repair/ClearFrontendCaches.php6
-rw-r--r--lib/private/Repair/ClearGeneratedAvatarCache.php3
-rw-r--r--lib/private/Repair/NC20/EncryptionLegacyCipher.php69
-rw-r--r--lib/private/Repair/NC20/EncryptionMigration.php69
-rw-r--r--lib/private/Repair/NC20/ShippedDashboardEnable.php53
-rw-r--r--lib/private/Repair/NC21/AddCheckForUserCertificatesJob.php61
-rw-r--r--lib/private/Repair/NC21/ValidatePhoneNumber.php90
-rw-r--r--lib/private/Repair/OldGroupMembershipShares.php2
-rw-r--r--lib/private/Repair/Owncloud/CleanPreviews.php73
-rw-r--r--lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php132
-rw-r--r--lib/private/Repair/Owncloud/InstallCoreBundle.php80
-rw-r--r--lib/private/Repair/Owncloud/MoveAvatars.php72
-rw-r--r--lib/private/Repair/Owncloud/MoveAvatarsBackgroundJob.php114
-rw-r--r--lib/private/Repair/Owncloud/SaveAccountsTableData.php10
-rw-r--r--lib/private/Repair/Owncloud/UpdateLanguageCodes.php89
-rw-r--r--lib/private/Repair/RepairInvalidShares.php3
-rw-r--r--lib/private/Repair/RepairMimeTypes.php127
-rw-r--r--lib/private/Repair/SqliteAutoincrement.php2
-rw-r--r--lib/private/RepairException.php2
-rw-r--r--lib/private/Route/Route.php2
-rw-r--r--lib/private/Route/Router.php66
-rw-r--r--lib/private/Search.php2
-rw-r--r--lib/private/Search/Provider/File.php4
-rw-r--r--lib/private/Search/Result/File.php28
-rw-r--r--lib/private/Search/SearchComposer.php36
-rw-r--r--lib/private/Search/SearchQuery.php37
-rw-r--r--lib/private/Security/Bruteforce/Capabilities.php5
-rw-r--r--lib/private/Security/Bruteforce/CleanupJob.php56
-rw-r--r--lib/private/Security/Bruteforce/Throttler.php107
-rw-r--r--lib/private/Security/CSP/ContentSecurityPolicyManager.php3
-rw-r--r--lib/private/Security/CertificateManager.php92
-rw-r--r--lib/private/Security/CredentialsManager.php30
-rw-r--r--lib/private/Security/Crypto.php22
-rw-r--r--lib/private/Security/FeaturePolicy/FeaturePolicyManager.php3
-rw-r--r--lib/private/Security/Hasher.php1
-rw-r--r--lib/private/Security/Normalizer/IpAddress.php3
-rw-r--r--lib/private/Server.php1211
-rw-r--r--lib/private/ServerContainer.php6
-rw-r--r--lib/private/Session/CryptoSessionData.php1
-rw-r--r--lib/private/Session/CryptoWrapper.php28
-rw-r--r--lib/private/Session/Internal.php10
-rw-r--r--lib/private/Settings/Manager.php26
-rw-r--r--lib/private/Setup.php7
-rw-r--r--lib/private/Setup/AbstractDatabase.php8
-rw-r--r--lib/private/Setup/MySQL.php9
-rw-r--r--lib/private/Setup/PostgreSQL.php1
-rw-r--r--lib/private/Share/Constants.php6
-rw-r--r--lib/private/Share/Helper.php145
-rw-r--r--lib/private/Share/Share.php291
-rw-r--r--lib/private/Share20/DefaultShareProvider.php14
-rw-r--r--lib/private/Share20/Hooks.php4
-rw-r--r--lib/private/Share20/LegacyHooks.php1
-rw-r--r--lib/private/Share20/Manager.php39
-rw-r--r--lib/private/Share20/ProviderFactory.php42
-rw-r--r--lib/private/Share20/UserRemovedListener.php5
-rw-r--r--lib/private/Streamer.php6
-rw-r--r--lib/private/SubAdmin.php24
-rw-r--r--lib/private/Support/Subscription/Registry.php107
-rw-r--r--lib/private/SystemTag/ManagerFactory.php2
-rw-r--r--lib/private/SystemTag/SystemTag.php2
-rw-r--r--lib/private/SystemTag/SystemTagManager.php11
-rw-r--r--lib/private/SystemTag/SystemTagObjectMapper.php2
-rw-r--r--lib/private/TagManager.php59
-rw-r--r--lib/private/Tagging/TagMapper.php2
-rw-r--r--lib/private/Tags.php21
-rw-r--r--lib/private/TempManager.php17
-rw-r--r--lib/private/Template/Base.php4
-rw-r--r--lib/private/Template/CSSResourceLocator.php6
-rw-r--r--lib/private/Template/IconsCacher.php6
-rw-r--r--lib/private/Template/JSCombiner.php2
-rw-r--r--lib/private/Template/JSConfigHelper.php8
-rw-r--r--lib/private/Template/JSResourceLocator.php2
-rw-r--r--lib/private/Template/SCSSCacher.php88
-rw-r--r--lib/private/TemplateLayout.php78
-rw-r--r--lib/private/URLGenerator.php106
-rw-r--r--lib/private/Updater.php52
-rw-r--r--lib/private/User/Backend.php16
-rw-r--r--lib/private/User/Database.php10
-rw-r--r--lib/private/User/Manager.php15
-rw-r--r--lib/private/User/Session.php27
-rw-r--r--lib/private/User/User.php47
-rw-r--r--lib/private/UserStatus/Manager.php106
-rw-r--r--lib/private/legacy/OC_API.php4
-rw-r--r--lib/private/legacy/OC_App.php38
-rw-r--r--lib/private/legacy/OC_DB.php22
-rw-r--r--lib/private/legacy/OC_DB_StatementWrapper.php13
-rw-r--r--lib/private/legacy/OC_FileChunking.php6
-rw-r--r--lib/private/legacy/OC_Files.php23
-rw-r--r--lib/private/legacy/OC_Helper.php23
-rw-r--r--lib/private/legacy/OC_Hook.php10
-rw-r--r--lib/private/legacy/OC_Image.php21
-rw-r--r--lib/private/legacy/OC_JSON.php4
-rw-r--r--lib/private/legacy/OC_Response.php2
-rw-r--r--lib/private/legacy/OC_Template.php17
-rw-r--r--lib/private/legacy/OC_User.php2
-rw-r--r--lib/private/legacy/OC_Util.php50
-rw-r--r--lib/private/legacy/template/functions.php26
324 files changed, 6276 insertions, 2672 deletions
diff --git a/lib/private/Accounts/AccountManager.php b/lib/private/Accounts/AccountManager.php
index 7b99fb0a410..05feaf87b8f 100644
--- a/lib/private/Accounts/AccountManager.php
+++ b/lib/private/Accounts/AccountManager.php
@@ -30,13 +30,19 @@
namespace OC\Accounts;
+use libphonenumber\NumberParseException;
+use libphonenumber\PhoneNumber;
+use libphonenumber\PhoneNumberFormat;
+use libphonenumber\PhoneNumberUtil;
use OCA\Settings\BackgroundJobs\VerifyUserData;
use OCP\Accounts\IAccount;
use OCP\Accounts\IAccountManager;
use OCP\BackgroundJob\IJobList;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IConfig;
use OCP\IDBConnection;
-use OCP\ILogger;
use OCP\IUser;
+use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
use function json_decode;
@@ -55,44 +61,89 @@ class AccountManager implements IAccountManager {
/** @var IDBConnection database connection */
private $connection;
+ /** @var IConfig */
+ private $config;
+
/** @var string table name */
private $table = 'accounts';
+ /** @var string table name */
+ private $dataTable = 'accounts_data';
+
/** @var EventDispatcherInterface */
private $eventDispatcher;
/** @var IJobList */
private $jobList;
- /** @var ILogger */
+ /** @var LoggerInterface */
private $logger;
- /**
- * AccountManager constructor.
- *
- * @param IDBConnection $connection
- * @param EventDispatcherInterface $eventDispatcher
- * @param IJobList $jobList
- */
public function __construct(IDBConnection $connection,
+ IConfig $config,
EventDispatcherInterface $eventDispatcher,
IJobList $jobList,
- ILogger $logger) {
+ LoggerInterface $logger) {
$this->connection = $connection;
+ $this->config = $config;
$this->eventDispatcher = $eventDispatcher;
$this->jobList = $jobList;
$this->logger = $logger;
}
/**
+ * @param string $input
+ * @return string Provided phone number in E.164 format when it was a valid number
+ * @throws \InvalidArgumentException When the phone number was invalid or no default region is set and the number doesn't start with a country code
+ */
+ protected function parsePhoneNumber(string $input): string {
+ $defaultRegion = $this->config->getSystemValueString('default_phone_region', '');
+
+ if ($defaultRegion === '') {
+ // When no default region is set, only +49… numbers are valid
+ if (strpos($input, '+') !== 0) {
+ throw new \InvalidArgumentException(self::PROPERTY_PHONE);
+ }
+
+ $defaultRegion = 'EN';
+ }
+
+ $phoneUtil = PhoneNumberUtil::getInstance();
+ try {
+ $phoneNumber = $phoneUtil->parse($input, $defaultRegion);
+ if ($phoneNumber instanceof PhoneNumber && $phoneUtil->isValidNumber($phoneNumber)) {
+ return $phoneUtil->format($phoneNumber, PhoneNumberFormat::E164);
+ }
+ } catch (NumberParseException $e) {
+ }
+
+ throw new \InvalidArgumentException(self::PROPERTY_PHONE);
+ }
+
+ /**
* update user record
*
* @param IUser $user
- * @param $data
+ * @param array $data
+ * @param bool $throwOnData Set to true if you can inform the user about invalid data
+ * @return array The potentially modified data (e.g. phone numbers are converted to E.164 format)
+ * @throws \InvalidArgumentException Message is the property that was invalid
*/
- public function updateUser(IUser $user, $data) {
+ public function updateUser(IUser $user, array $data, bool $throwOnData = false): array {
$userData = $this->getUser($user);
$updated = true;
+
+ if (isset($data[self::PROPERTY_PHONE]) && $data[self::PROPERTY_PHONE]['value'] !== '') {
+ try {
+ $data[self::PROPERTY_PHONE]['value'] = $this->parsePhoneNumber($data[self::PROPERTY_PHONE]['value']);
+ } catch (\InvalidArgumentException $e) {
+ if ($throwOnData) {
+ throw $e;
+ }
+ $data[self::PROPERTY_PHONE]['value'] = '';
+ }
+ }
+
if (empty($userData)) {
$this->insertNewUser($user, $data);
} elseif ($userData !== $data) {
@@ -110,6 +161,8 @@ class AccountManager implements IAccountManager {
new GenericEvent($user, $data)
);
}
+
+ return $data;
}
/**
@@ -123,6 +176,21 @@ class AccountManager implements IAccountManager {
$query->delete($this->table)
->where($query->expr()->eq('uid', $query->createNamedParameter($uid)))
->execute();
+
+ $this->deleteUserData($user);
+ }
+
+ /**
+ * delete user from accounts table
+ *
+ * @param IUser $user
+ */
+ public function deleteUserData(IUser $user): void {
+ $uid = $user->getUID();
+ $query = $this->connection->getQueryBuilder();
+ $query->delete($this->dataTable)
+ ->where($query->expr()->eq('uid', $query->createNamedParameter($uid)))
+ ->execute();
}
/**
@@ -134,19 +202,21 @@ class AccountManager implements IAccountManager {
public function getUser(IUser $user) {
$uid = $user->getUID();
$query = $this->connection->getQueryBuilder();
- $query->select('data')->from($this->table)
+ $query->select('data')
+ ->from($this->table)
->where($query->expr()->eq('uid', $query->createParameter('uid')))
->setParameter('uid', $uid);
- $query->execute();
- $result = $query->execute()->fetchAll();
+ $result = $query->execute();
+ $accountData = $result->fetchAll();
+ $result->closeCursor();
- if (empty($result)) {
+ if (empty($accountData)) {
$userData = $this->buildDefaultUserRecord($user);
$this->insertNewUser($user, $userData);
return $userData;
}
- $userDataArray = json_decode($result[0]['data'], true);
+ $userDataArray = json_decode($accountData[0]['data'], true);
$jsonError = json_last_error();
if ($userDataArray === null || $userDataArray === [] || $jsonError !== JSON_ERROR_NONE) {
$this->logger->critical("User data of $uid contained invalid JSON (error $jsonError), hence falling back to a default user record");
@@ -158,6 +228,24 @@ class AccountManager implements IAccountManager {
return $userDataArray;
}
+ public function searchUsers(string $property, array $values): array {
+ $query = $this->connection->getQueryBuilder();
+ $query->select('*')
+ ->from($this->dataTable)
+ ->where($query->expr()->eq('name', $query->createNamedParameter($property)))
+ ->andWhere($query->expr()->in('value', $query->createNamedParameter($values, IQueryBuilder::PARAM_STR_ARRAY)));
+
+ $result = $query->execute();
+ $matches = [];
+
+ while ($row = $result->fetch()) {
+ $matches[$row['value']] = $row['uid'];
+ }
+ $result->closeCursor();
+
+ return $matches;
+ }
+
/**
* check if we need to ask the server for email verification, if yes we create a cronjob
*
@@ -178,7 +266,7 @@ class AccountManager implements IAccountManager {
'lastRun' => time()
]
);
- $newData[AccountManager::PROPERTY_EMAIL]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
+ $newData[self::PROPERTY_EMAIL]['verified'] = self::VERIFICATION_IN_PROGRESS;
}
return $newData;
@@ -261,7 +349,7 @@ class AccountManager implements IAccountManager {
* @param IUser $user
* @param array $data
*/
- protected function insertNewUser(IUser $user, $data) {
+ protected function insertNewUser(IUser $user, array $data): void {
$uid = $user->getUID();
$jsonEncodedData = json_encode($data);
$query = $this->connection->getQueryBuilder();
@@ -273,6 +361,9 @@ class AccountManager implements IAccountManager {
]
)
->execute();
+
+ $this->deleteUserData($user);
+ $this->writeUserData($user, $data);
}
/**
@@ -281,7 +372,7 @@ class AccountManager implements IAccountManager {
* @param IUser $user
* @param array $data
*/
- protected function updateExistingUser(IUser $user, $data) {
+ protected function updateExistingUser(IUser $user, array $data): void {
$uid = $user->getUID();
$jsonEncodedData = json_encode($data);
$query = $this->connection->getQueryBuilder();
@@ -289,6 +380,30 @@ class AccountManager implements IAccountManager {
->set('data', $query->createNamedParameter($jsonEncodedData))
->where($query->expr()->eq('uid', $query->createNamedParameter($uid)))
->execute();
+
+ $this->deleteUserData($user);
+ $this->writeUserData($user, $data);
+ }
+
+ protected function writeUserData(IUser $user, array $data): void {
+ $query = $this->connection->getQueryBuilder();
+ $query->insert($this->dataTable)
+ ->values(
+ [
+ 'uid' => $query->createNamedParameter($user->getUID()),
+ 'name' => $query->createParameter('name'),
+ 'value' => $query->createParameter('value'),
+ ]
+ );
+ foreach ($data as $propertyName => $property) {
+ if ($propertyName === self::PROPERTY_AVATAR) {
+ continue;
+ }
+
+ $query->setParameter('name', $propertyName)
+ ->setParameter('value', $property['value']);
+ $query->execute();
+ }
}
/**
diff --git a/lib/private/Accounts/Hooks.php b/lib/private/Accounts/Hooks.php
index 2288b884c5c..d4e9637dfee 100644
--- a/lib/private/Accounts/Hooks.php
+++ b/lib/private/Accounts/Hooks.php
@@ -4,6 +4,7 @@
*
* @author Bjoern Schiessle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -24,23 +25,19 @@
namespace OC\Accounts;
-use OCP\ILogger;
+use OCP\Accounts\IAccountManager;
use OCP\IUser;
+use Psr\Log\LoggerInterface;
class Hooks {
- /** @var AccountManager */
- private $accountManager = null;
+ /** @var AccountManager|null */
+ private $accountManager;
- /** @var ILogger */
+ /** @var LoggerInterface */
private $logger;
- /**
- * Hooks constructor.
- *
- * @param ILogger $logger
- */
- public function __construct(ILogger $logger) {
+ public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
}
@@ -66,14 +63,14 @@ class Hooks {
switch ($feature) {
case 'eMailAddress':
- if ($accountData[AccountManager::PROPERTY_EMAIL]['value'] !== $newValue) {
- $accountData[AccountManager::PROPERTY_EMAIL]['value'] = $newValue;
+ if ($accountData[IAccountManager::PROPERTY_EMAIL]['value'] !== $newValue) {
+ $accountData[IAccountManager::PROPERTY_EMAIL]['value'] = $newValue;
$accountManager->updateUser($user, $accountData);
}
break;
case 'displayName':
- if ($accountData[AccountManager::PROPERTY_DISPLAYNAME]['value'] !== $newValue) {
- $accountData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $newValue;
+ if ($accountData[IAccountManager::PROPERTY_DISPLAYNAME]['value'] !== $newValue) {
+ $accountData[IAccountManager::PROPERTY_DISPLAYNAME]['value'] = $newValue;
$accountManager->updateUser($user, $accountData);
}
break;
@@ -85,7 +82,7 @@ class Hooks {
*
* @return AccountManager
*/
- protected function getAccountManager() {
+ protected function getAccountManager(): AccountManager {
if ($this->accountManager === null) {
$this->accountManager = \OC::$server->query(AccountManager::class);
}
diff --git a/lib/private/Activity/ActivitySettingsAdapter.php b/lib/private/Activity/ActivitySettingsAdapter.php
index c49231bee2c..2dd852f0fd4 100644
--- a/lib/private/Activity/ActivitySettingsAdapter.php
+++ b/lib/private/Activity/ActivitySettingsAdapter.php
@@ -1,9 +1,12 @@
<?php
declare(strict_types=1);
+
/**
* @copyright Copyright (c) 2020 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
@@ -17,7 +20,7 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
@@ -25,6 +28,7 @@ namespace OC\Activity;
use OCP\Activity\ActivitySettings;
use OCP\Activity\ISetting;
+use OCP\IL10N;
/**
* Adapt the old interface based settings into the new abstract
@@ -32,9 +36,11 @@ use OCP\Activity\ISetting;
*/
class ActivitySettingsAdapter extends ActivitySettings {
private $oldSettings;
+ private $l10n;
- public function __construct(ISetting $oldSettings) {
+ public function __construct(ISetting $oldSettings, IL10N $l10n) {
$this->oldSettings = $oldSettings;
+ $this->l10n = $l10n;
}
public function getIdentifier() {
@@ -45,6 +51,14 @@ class ActivitySettingsAdapter extends ActivitySettings {
return $this->oldSettings->getName();
}
+ public function getGroupIdentifier() {
+ return 'other';
+ }
+
+ public function getGroupName() {
+ return $this->l10n->t('Other activities');
+ }
+
public function getPriority() {
return $this->oldSettings->getPriority();
}
diff --git a/lib/private/Activity/Event.php b/lib/private/Activity/Event.php
index 5f82b37c91a..8535561cbbe 100644
--- a/lib/private/Activity/Event.php
+++ b/lib/private/Activity/Event.php
@@ -9,6 +9,7 @@ declare(strict_types=1);
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
* @author Phil Davis <phil.davis@inf.org>
+ * @author Robin Appelman <robin@icewind.nl>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Activity/Manager.php b/lib/private/Activity/Manager.php
index 81fd91c778a..25b666e6a0e 100644
--- a/lib/private/Activity/Manager.php
+++ b/lib/private/Activity/Manager.php
@@ -7,6 +7,7 @@
* @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Joas Schilling <coding@schilljs.com>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
@@ -36,6 +37,7 @@ use OCP\Activity\IManager;
use OCP\Activity\IProvider;
use OCP\Activity\ISetting;
use OCP\IConfig;
+use OCP\IL10N;
use OCP\IRequest;
use OCP\IUser;
use OCP\IUserSession;
@@ -66,14 +68,20 @@ class Manager implements IManager {
/** @var string */
protected $currentUserId;
- public function __construct(IRequest $request,
- IUserSession $session,
- IConfig $config,
- IValidator $validator) {
+ protected $l10n;
+
+ public function __construct(
+ IRequest $request,
+ IUserSession $session,
+ IConfig $config,
+ IValidator $validator,
+ IL10N $l10n
+ ) {
$this->request = $request;
$this->session = $session;
$this->config = $config;
$this->validator = $validator;
+ $this->l10n = $l10n;
}
/** @var \Closure[] */
@@ -273,7 +281,7 @@ class Manager implements IManager {
if ($setting instanceof ISetting) {
if (!$setting instanceof ActivitySettings) {
- $setting = new ActivitySettingsAdapter($setting);
+ $setting = new ActivitySettingsAdapter($setting, $this->l10n);
}
} else {
throw new \InvalidArgumentException('Invalid activity filter registered');
diff --git a/lib/private/AllConfig.php b/lib/private/AllConfig.php
index 5218d969b47..36f5f2cd40a 100644
--- a/lib/private/AllConfig.php
+++ b/lib/private/AllConfig.php
@@ -8,6 +8,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Loki3000 <github@labcms.ru>
* @author Lukas Reschke <lukas@statuscode.ch>
+ * @author MichaIng <micha@dietpi.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
@@ -316,7 +317,7 @@ class AllConfig implements \OCP\IConfig {
*/
public function getUserValue($userId, $appName, $key, $default = '') {
$data = $this->getUserValues($userId);
- if (isset($data[$appName]) and isset($data[$appName][$key])) {
+ if (isset($data[$appName][$key])) {
return $data[$appName][$key];
} else {
return $default;
@@ -350,11 +351,11 @@ class AllConfig implements \OCP\IConfig {
// TODO - FIXME
$this->fixDIInit();
- $sql = 'DELETE FROM `*PREFIX*preferences` '.
+ $sql = 'DELETE FROM `*PREFIX*preferences` '.
'WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?';
$this->connection->executeUpdate($sql, [$userId, $appName, $key]);
- if (isset($this->userCache[$userId]) and isset($this->userCache[$userId][$appName])) {
+ if (isset($this->userCache[$userId][$appName])) {
unset($this->userCache[$userId][$appName][$key]);
}
}
@@ -368,7 +369,7 @@ class AllConfig implements \OCP\IConfig {
// TODO - FIXME
$this->fixDIInit();
- $sql = 'DELETE FROM `*PREFIX*preferences` '.
+ $sql = 'DELETE FROM `*PREFIX*preferences` '.
'WHERE `userid` = ?';
$this->connection->executeUpdate($sql, [$userId]);
@@ -384,7 +385,7 @@ class AllConfig implements \OCP\IConfig {
// TODO - FIXME
$this->fixDIInit();
- $sql = 'DELETE FROM `*PREFIX*preferences` '.
+ $sql = 'DELETE FROM `*PREFIX*preferences` '.
'WHERE `appid` = ?';
$this->connection->executeUpdate($sql, [$appName]);
@@ -407,7 +408,7 @@ class AllConfig implements \OCP\IConfig {
return $this->userCache[$userId];
}
if ($userId === null || $userId === '') {
- $this->userCache[$userId]=[];
+ $this->userCache[$userId] = [];
return $this->userCache[$userId];
}
@@ -456,7 +457,7 @@ class AllConfig implements \OCP\IConfig {
$placeholders = (count($chunk) === 50) ? $placeholders50 : implode(',', array_fill(0, count($chunk), '?'));
- $query = 'SELECT `userid`, `configvalue` ' .
+ $query = 'SELECT `userid`, `configvalue` ' .
'FROM `*PREFIX*preferences` ' .
'WHERE `appid` = ? AND `configkey` = ? ' .
'AND `userid` IN (' . $placeholders . ')';
@@ -482,7 +483,7 @@ class AllConfig implements \OCP\IConfig {
// TODO - FIXME
$this->fixDIInit();
- $sql = 'SELECT `userid` FROM `*PREFIX*preferences` ' .
+ $sql = 'SELECT `userid` FROM `*PREFIX*preferences` ' .
'WHERE `appid` = ? AND `configkey` = ? ';
if ($this->getSystemValue('dbtype', 'sqlite') === 'oci') {
@@ -514,7 +515,7 @@ class AllConfig implements \OCP\IConfig {
// TODO - FIXME
$this->fixDIInit();
- $sql = 'SELECT `userid` FROM `*PREFIX*preferences` ' .
+ $sql = 'SELECT `userid` FROM `*PREFIX*preferences` ' .
'WHERE `appid` = ? AND `configkey` = ? ';
if ($this->getSystemValue('dbtype', 'sqlite') === 'oci') {
diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php
index f756664e457..7063878429a 100644
--- a/lib/private/App/AppManager.php
+++ b/lib/private/App/AppManager.php
@@ -18,7 +18,7 @@
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tobia De Koninck <tobia@ledfan.be>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/App/AppStore/Bundles/HubBundle.php b/lib/private/App/AppStore/Bundles/HubBundle.php
index 59b52389ef8..301be810c5d 100644
--- a/lib/private/App/AppStore/Bundles/HubBundle.php
+++ b/lib/private/App/AppStore/Bundles/HubBundle.php
@@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright Copyright (c) 2020 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
+ * @author Julius Härtl <jus@bitgrid.net>
*
* @license GNU AGPL version 3 or any later version
*
@@ -32,13 +33,19 @@ class HubBundle extends Bundle {
}
public function getAppIdentifiers() {
- return [
+ $hubApps = [
'spreed',
'contacts',
'calendar',
'mail',
- 'richdocumentscode',
- 'richdocuments',
];
+
+ $architecture = php_uname('m');
+ if (PHP_OS_FAMILY === 'Linux' && in_array($architecture, ['x86_64', 'aarch64'])) {
+ $hubApps[] = 'richdocuments';
+ $hubApps[] = 'richdocumentscode' . ($architecture === 'aarch64' ? '_arm64' : '');
+ }
+
+ return $hubApps;
}
}
diff --git a/lib/private/App/AppStore/Fetcher/AppFetcher.php b/lib/private/App/AppStore/Fetcher/AppFetcher.php
index e4c2ba4e85e..4dc517879e8 100644
--- a/lib/private/App/AppStore/Fetcher/AppFetcher.php
+++ b/lib/private/App/AppStore/Fetcher/AppFetcher.php
@@ -6,6 +6,7 @@
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Georg Ehrke <oc.list@georgehrke.com>
* @author Joas Schilling <coding@schilljs.com>
+ * @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -78,15 +79,16 @@ class AppFetcher extends Fetcher {
*
* @param string $ETag
* @param string $content
+ * @param bool [$allowUnstable] Allow unstable releases
*
* @return array
*/
- protected function fetch($ETag, $content) {
+ protected function fetch($ETag, $content, $allowUnstable = false) {
/** @var mixed[] $response */
$response = parent::fetch($ETag, $content);
- $allowPreReleases = $this->getChannel() === 'beta' || $this->getChannel() === 'daily';
- $allowNightly = $this->getChannel() === 'daily';
+ $allowPreReleases = $allowUnstable || $this->getChannel() === 'beta' || $this->getChannel() === 'daily';
+ $allowNightly = $allowUnstable || $this->getChannel() === 'daily';
foreach ($response['data'] as $dataKey => $app) {
$releases = [];
@@ -99,14 +101,32 @@ class AppFetcher extends Fetcher {
// Exclude all versions not compatible with the current version
try {
$versionParser = new VersionParser();
- $version = $versionParser->getVersion($release['rawPlatformVersionSpec']);
+ $serverVersion = $versionParser->getVersion($release['rawPlatformVersionSpec']);
$ncVersion = $this->getVersion();
- $min = $version->getMinimumVersion();
- $max = $version->getMaximumVersion();
- $minFulfilled = $this->compareVersion->isCompatible($ncVersion, $min, '>=');
- $maxFulfilled = $max !== '' &&
- $this->compareVersion->isCompatible($ncVersion, $max, '<=');
- if ($minFulfilled && ($this->ignoreMaxVersion || $maxFulfilled)) {
+ $minServerVersion = $serverVersion->getMinimumVersion();
+ $maxServerVersion = $serverVersion->getMaximumVersion();
+ $minFulfilled = $this->compareVersion->isCompatible($ncVersion, $minServerVersion, '>=');
+ $maxFulfilled = $maxServerVersion !== '' &&
+ $this->compareVersion->isCompatible($ncVersion, $maxServerVersion, '<=');
+ $isPhpCompatible = true;
+ if (($release['rawPhpVersionSpec'] ?? '*') !== '*') {
+ $phpVersion = $versionParser->getVersion($release['rawPhpVersionSpec']);
+ $minPhpVersion = $phpVersion->getMinimumVersion();
+ $maxPhpVersion = $phpVersion->getMaximumVersion();
+ $minPhpFulfilled = $minPhpVersion === '' || $this->compareVersion->isCompatible(
+ PHP_VERSION,
+ $minPhpVersion,
+ '>='
+ );
+ $maxPhpFulfilled = $maxPhpVersion === '' || $this->compareVersion->isCompatible(
+ PHP_VERSION,
+ $maxPhpVersion,
+ '<='
+ );
+
+ $isPhpCompatible = $minPhpFulfilled && $maxPhpFulfilled;
+ }
+ if ($minFulfilled && ($this->ignoreMaxVersion || $maxFulfilled) && $isPhpCompatible) {
$releases[] = $release;
}
} catch (\InvalidArgumentException $e) {
diff --git a/lib/private/App/AppStore/Fetcher/Fetcher.php b/lib/private/App/AppStore/Fetcher/Fetcher.php
index 500a0568c99..c5d83fcb1df 100644
--- a/lib/private/App/AppStore/Fetcher/Fetcher.php
+++ b/lib/private/App/AppStore/Fetcher/Fetcher.php
@@ -2,10 +2,11 @@
/**
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
*
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Georg Ehrke <oc.list@georgehrke.com>
* @author Joas Schilling <coding@schilljs.com>
+ * @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
+ * @author Julius Härtl <jus@bitgrid.net>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -42,6 +43,7 @@ use OCP\ILogger;
abstract class Fetcher {
public const INVALIDATE_AFTER_SECONDS = 3600;
+ public const RETRY_AFTER_FAILURE_SECONDS = 300;
/** @var IAppData */
protected $appData;
@@ -91,6 +93,9 @@ abstract class Fetcher {
*/
protected function fetch($ETag, $content) {
$appstoreenabled = $this->config->getSystemValue('appstoreenabled', true);
+ if ((int)$this->config->getAppValue('settings', 'appstore-fetcher-lastFailure', '0') > time() - self::RETRY_AFTER_FAILURE_SECONDS) {
+ return [];
+ }
if (!$appstoreenabled) {
return [];
@@ -107,7 +112,12 @@ abstract class Fetcher {
}
$client = $this->clientService->newClient();
- $response = $client->get($this->getEndpoint(), $options);
+ try {
+ $response = $client->get($this->getEndpoint(), $options);
+ } catch (ConnectException $e) {
+ $this->config->setAppValue('settings', 'appstore-fetcher-lastFailure', (string)time());
+ throw $e;
+ }
$responseJson = [];
if ($response->getStatusCode() === Http::STATUS_NOT_MODIFIED) {
@@ -116,6 +126,7 @@ abstract class Fetcher {
$responseJson['data'] = json_decode($response->getBody(), true);
$ETag = $response->getHeader('ETag');
}
+ $this->config->deleteAppValue('settings', 'appstore-fetcher-lastFailure');
$responseJson['timestamp'] = $this->timeFactory->getTime();
$responseJson['ncversion'] = $this->getVersion();
@@ -129,9 +140,10 @@ abstract class Fetcher {
/**
* Returns the array with the categories on the appstore server
*
+ * @param bool [$allowUnstable] Allow unstable releases
* @return array
*/
- public function get() {
+ public function get($allowUnstable = false) {
$appstoreenabled = $this->config->getSystemValue('appstoreenabled', true);
$internetavailable = $this->config->getSystemValue('has_internet_connection', true);
@@ -148,7 +160,9 @@ abstract class Fetcher {
// File does already exists
$file = $rootFolder->getFile($this->fileName);
$jsonBlob = json_decode($file->getContent(), true);
- if (is_array($jsonBlob)) {
+
+ // Always get latests apps info if $allowUnstable
+ if (!$allowUnstable && is_array($jsonBlob)) {
// No caching when the version has been updated
if (isset($jsonBlob['ncversion']) && $jsonBlob['ncversion'] === $this->getVersion()) {
@@ -171,7 +185,17 @@ abstract class Fetcher {
// Refresh the file content
try {
- $responseJson = $this->fetch($ETag, $content);
+ $responseJson = $this->fetch($ETag, $content, $allowUnstable);
+
+ if (empty($responseJson)) {
+ return [];
+ }
+
+ // Don't store the apps request file
+ if ($allowUnstable) {
+ return $responseJson['data'];
+ }
+
$file->putContent(json_encode($responseJson));
return json_decode($file->getContent(), true)['data'];
} catch (ConnectException $e) {
diff --git a/lib/private/App/CodeChecker/CodeChecker.php b/lib/private/App/CodeChecker/CodeChecker.php
index 13d6ff887f3..9dec9c9f4d7 100644
--- a/lib/private/App/CodeChecker/CodeChecker.php
+++ b/lib/private/App/CodeChecker/CodeChecker.php
@@ -40,10 +40,10 @@ class CodeChecker extends BasicEmitter {
public const CLASS_IMPLEMENTS_NOT_ALLOWED = 1001;
public const STATIC_CALL_NOT_ALLOWED = 1002;
public const CLASS_CONST_FETCH_NOT_ALLOWED = 1003;
- public const CLASS_NEW_NOT_ALLOWED = 1004;
- public const OP_OPERATOR_USAGE_DISCOURAGED = 1005;
- public const CLASS_USE_NOT_ALLOWED = 1006;
- public const CLASS_METHOD_CALL_NOT_ALLOWED = 1007;
+ public const CLASS_NEW_NOT_ALLOWED = 1004;
+ public const OP_OPERATOR_USAGE_DISCOURAGED = 1005;
+ public const CLASS_USE_NOT_ALLOWED = 1006;
+ public const CLASS_METHOD_CALL_NOT_ALLOWED = 1007;
/** @var Parser */
private $parser;
diff --git a/lib/private/App/CodeChecker/NodeVisitor.php b/lib/private/App/CodeChecker/NodeVisitor.php
index 635f1357ffd..001a0ee6883 100644
--- a/lib/private/App/CodeChecker/NodeVisitor.php
+++ b/lib/private/App/CodeChecker/NodeVisitor.php
@@ -2,6 +2,7 @@
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Joas Schilling <coding@schilljs.com>
* @author Morris Jobke <hey@morrisjobke.de>
@@ -103,7 +104,7 @@ class NodeVisitor extends NodeVisitorAbstract {
public function enterNode(Node $node) {
if ($this->checkEqualOperatorUsage && $node instanceof Node\Expr\BinaryOp\Equal) {
- $this->errors[]= [
+ $this->errors[] = [
'disallowedToken' => '==',
'errorCode' => CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED,
'line' => $node->getLine(),
@@ -111,7 +112,7 @@ class NodeVisitor extends NodeVisitorAbstract {
];
}
if ($this->checkEqualOperatorUsage && $node instanceof Node\Expr\BinaryOp\NotEqual) {
- $this->errors[]= [
+ $this->errors[] = [
'disallowedToken' => '!=',
'errorCode' => CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED,
'line' => $node->getLine(),
@@ -247,7 +248,7 @@ class NodeVisitor extends NodeVisitorAbstract {
$lowerName = strtolower($name);
if (isset($this->blackListedClassNames[$lowerName])) {
- $this->errors[]= [
+ $this->errors[] = [
'disallowedToken' => $name,
'errorCode' => $errorCode,
'line' => $node->getLine(),
@@ -261,7 +262,7 @@ class NodeVisitor extends NodeVisitorAbstract {
$lowerName = strtolower($name);
if (isset($this->blackListedConstants[$lowerName])) {
- $this->errors[]= [
+ $this->errors[] = [
'disallowedToken' => $name,
'errorCode' => CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED,
'line' => $node->getLine(),
@@ -275,7 +276,7 @@ class NodeVisitor extends NodeVisitorAbstract {
$lowerName = strtolower($name);
if (isset($this->blackListedFunctions[$lowerName])) {
- $this->errors[]= [
+ $this->errors[] = [
'disallowedToken' => $name,
'errorCode' => CodeChecker::STATIC_CALL_NOT_ALLOWED,
'line' => $node->getLine(),
@@ -289,7 +290,7 @@ class NodeVisitor extends NodeVisitorAbstract {
$lowerName = strtolower($name);
if (isset($this->blackListedMethods[$lowerName])) {
- $this->errors[]= [
+ $this->errors[] = [
'disallowedToken' => $name,
'errorCode' => CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED,
'line' => $node->getLine(),
diff --git a/lib/private/App/DependencyAnalyzer.php b/lib/private/App/DependencyAnalyzer.php
index 63d84cd5a43..eb114adbb48 100644
--- a/lib/private/App/DependencyAnalyzer.php
+++ b/lib/private/App/DependencyAnalyzer.php
@@ -6,11 +6,13 @@
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
+ * @author Julius Härtl <jus@bitgrid.net>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Stefan Weil <sw@weilnetz.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Valdnet <47037905+Valdnet@users.noreply.github.com>
*
* @license AGPL-3.0
*
@@ -63,6 +65,7 @@ class DependencyAnalyzer {
}
return array_merge(
+ $this->analyzeArchitecture($dependencies),
$this->analyzePhpVersion($dependencies),
$this->analyzeDatabases($dependencies),
$this->analyzeCommands($dependencies),
@@ -166,13 +169,36 @@ class DependencyAnalyzer {
}
if (isset($dependencies['php']['@attributes']['min-int-size'])) {
$intSize = $dependencies['php']['@attributes']['min-int-size'];
- if ($intSize > $this->platform->getIntSize()*8) {
+ if ($intSize > $this->platform->getIntSize() * 8) {
$missing[] = (string)$this->l->t('%sbit or higher PHP required.', [$intSize]);
}
}
return $missing;
}
+ private function analyzeArchitecture(array $dependencies) {
+ $missing = [];
+ if (!isset($dependencies['architecture'])) {
+ return $missing;
+ }
+
+ $supportedArchitectures = $dependencies['architecture'];
+ if (empty($supportedArchitectures)) {
+ return $missing;
+ }
+ if (!is_array($supportedArchitectures)) {
+ $supportedArchitectures = [$supportedArchitectures];
+ }
+ $supportedArchitectures = array_map(function ($architecture) {
+ return $this->getValue($architecture);
+ }, $supportedArchitectures);
+ $currentArchitecture = $this->platform->getArchitecture();
+ if (!in_array($currentArchitecture, $supportedArchitectures, true)) {
+ $missing[] = (string)$this->l->t('The following architectures are supported: %s', [implode(', ', $supportedArchitectures)]);
+ }
+ return $missing;
+ }
+
/**
* @param array $dependencies
* @return array
diff --git a/lib/private/App/Platform.php b/lib/private/App/Platform.php
index 4a64177232f..f83e7cf8272 100644
--- a/lib/private/App/Platform.php
+++ b/lib/private/App/Platform.php
@@ -4,6 +4,7 @@
*
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Julius Härtl <jus@bitgrid.net>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
@@ -97,4 +98,8 @@ class Platform {
$repo = new PlatformRepository();
return $repo->findLibrary($name);
}
+
+ public function getArchitecture(): string {
+ return php_uname('m');
+ }
}
diff --git a/lib/private/AppConfig.php b/lib/private/AppConfig.php
index 97338c1895b..84305e60a12 100644
--- a/lib/private/AppConfig.php
+++ b/lib/private/AppConfig.php
@@ -13,6 +13,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license AGPL-3.0
*
@@ -49,11 +50,12 @@ class AppConfig implements IAppConfig {
'/^sites$/',
],
'spreed' => [
+ '/^bridge_bot_password/',
+ '/^signaling_servers$/',
'/^signaling_ticket_secret$/',
- '/^turn_server_secret$/',
'/^stun_servers$/',
'/^turn_servers$/',
- '/^signaling_servers$/',
+ '/^turn_server_secret$/',
],
'theming' => [
'/^imprintUrl$/',
@@ -201,12 +203,9 @@ class AppConfig implements IAppConfig {
$sql = $this->conn->getQueryBuilder();
$sql->update('appconfig')
- ->set('configvalue', $sql->createParameter('configvalue'))
- ->where($sql->expr()->eq('appid', $sql->createParameter('app')))
- ->andWhere($sql->expr()->eq('configkey', $sql->createParameter('configkey')))
- ->setParameter('configvalue', $value)
- ->setParameter('app', $app)
- ->setParameter('configkey', $key);
+ ->set('configvalue', $sql->createNamedParameter($value))
+ ->where($sql->expr()->eq('appid', $sql->createNamedParameter($app)))
+ ->andWhere($sql->expr()->eq('configkey', $sql->createNamedParameter($key)));
/*
* Only limit to the existing value for non-Oracle DBs:
@@ -214,9 +213,25 @@ class AppConfig implements IAppConfig {
* > Large objects (LOBs) are not supported in comparison conditions.
*/
if (!($this->conn instanceof OracleConnection)) {
- // Only update the value when it is not the same
- $sql->andWhere($sql->expr()->neq('configvalue', $sql->createParameter('configvalue')))
- ->setParameter('configvalue', $value);
+
+ /*
+ * Only update the value when it is not the same
+ * Note that NULL requires some special handling. Since comparing
+ * against null can have special results.
+ */
+
+ if ($value === null) {
+ $sql->andWhere(
+ $sql->expr()->isNotNull('configvalue')
+ );
+ } else {
+ $sql->andWhere(
+ $sql->expr()->orX(
+ $sql->expr()->isNull('configvalue'),
+ $sql->expr()->neq('configvalue', $sql->createNamedParameter($value))
+ )
+ );
+ }
}
$changedRow = (bool) $sql->execute();
@@ -334,13 +349,23 @@ class AppConfig implements IAppConfig {
$rows = $result->fetchAll();
foreach ($rows as $row) {
if (!isset($this->cache[$row['appid']])) {
- $this->cache[$row['appid']] = [];
+ $this->cache[(string)$row['appid']] = [];
}
- $this->cache[$row['appid']][$row['configkey']] = $row['configvalue'];
+ $this->cache[(string)$row['appid']][(string)$row['configkey']] = (string)$row['configvalue'];
}
$result->closeCursor();
$this->configLoaded = true;
}
+
+ /**
+ * Clear all the cached app config values
+ *
+ * WARNING: do not use this - this is only for usage with the SCSSCacher to
+ * clear the memory cache of the app config
+ */
+ public function clearCachedConfig() {
+ $this->configLoaded = false;
+ }
}
diff --git a/lib/private/AppFramework/App.php b/lib/private/AppFramework/App.php
index 75876055d80..d6bf7bc81c3 100644
--- a/lib/private/AppFramework/App.php
+++ b/lib/private/AppFramework/App.php
@@ -10,6 +10,7 @@ declare(strict_types=1);
* @author Joas Schilling <coding@schilljs.com>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
@@ -33,6 +34,7 @@ namespace OC\AppFramework;
use OC\AppFramework\DependencyInjection\DIContainer;
use OC\AppFramework\Http\Dispatcher;
+use OC\AppFramework\Http\Request;
use OC\HintException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\ICallbackResponse;
@@ -59,7 +61,7 @@ class App {
* the transformed app id, defaults to OCA\
* @return string the starting namespace for the app
*/
- public static function buildAppNamespace(string $appId, string $topNamespace='OCA\\'): string {
+ public static function buildAppNamespace(string $appId, string $topNamespace = 'OCA\\'): string {
// Hit the cache!
if (isset(self::$nameSpaceCache[$appId])) {
return $topNamespace . self::$nameSpaceCache[$appId];
@@ -87,7 +89,7 @@ class App {
return $topNamespace . self::$nameSpaceCache[$appId];
}
- public static function getAppIdForClass(string $className, string $topNamespace='OCA\\'): ?string {
+ public static function getAppIdForClass(string $className, string $topNamespace = 'OCA\\'): ?string {
if (strpos($className, $topNamespace) !== 0) {
return null;
}
@@ -113,9 +115,13 @@ class App {
*/
public static function main(string $controllerName, string $methodName, DIContainer $container, array $urlParams = null) {
if (!is_null($urlParams)) {
- $container->query(IRequest::class)->setUrlParameters($urlParams);
+ /** @var Request $request */
+ $request = $container->query(IRequest::class);
+ $request->setUrlParameters($urlParams);
} elseif (isset($container['urlParams']) && !is_null($container['urlParams'])) {
- $container->query(IRequest::class)->setUrlParameters($container['urlParams']);
+ /** @var Request $request */
+ $request = $container->query(IRequest::class);
+ $request->setUrlParameters($container['urlParams']);
}
$appName = $container['AppName'];
@@ -222,7 +228,7 @@ class App {
$dispatcher = $container['Dispatcher'];
- list(, , $output) = $dispatcher->dispatch($controller, $methodName);
+ list(, , $output) = $dispatcher->dispatch($controller, $methodName);
return $output;
}
}
diff --git a/lib/private/AppFramework/Bootstrap/BootContext.php b/lib/private/AppFramework/Bootstrap/BootContext.php
index 45aaf167e75..0acfaad7ab6 100644
--- a/lib/private/AppFramework/Bootstrap/BootContext.php
+++ b/lib/private/AppFramework/Bootstrap/BootContext.php
@@ -5,7 +5,8 @@ declare(strict_types=1);
/**
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
*
- * @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Morris Jobke <hey@morrisjobke.de>
*
* @license GNU AGPL version 3 or any later version
*
@@ -20,7 +21,8 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
namespace OC\AppFramework\Bootstrap;
diff --git a/lib/private/AppFramework/Bootstrap/Coordinator.php b/lib/private/AppFramework/Bootstrap/Coordinator.php
index 358e71d7854..06a17e5242b 100644
--- a/lib/private/AppFramework/Bootstrap/Coordinator.php
+++ b/lib/private/AppFramework/Bootstrap/Coordinator.php
@@ -5,7 +5,10 @@ declare(strict_types=1);
/**
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
*
- * @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Julius Härtl <jus@bitgrid.net>
+ * @author Morris Jobke <hey@morrisjobke.de>
+ * @author Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
@@ -20,7 +23,8 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
namespace OC\AppFramework\Bootstrap;
@@ -34,7 +38,6 @@ use OCP\Dashboard\IManager;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\ILogger;
use OCP\IServerContainer;
-use RuntimeException;
use Throwable;
use function class_exists;
use function class_implements;
@@ -60,6 +63,9 @@ class Coordinator {
/** @var RegistrationContext|null */
private $registrationContext;
+ /** @var string[] */
+ private $bootedApps = [];
+
public function __construct(IServerContainer $container,
Registry $registry,
IManager $dashboardManager,
@@ -72,14 +78,23 @@ class Coordinator {
$this->logger = $logger;
}
- public function runRegistration(): void {
- if ($this->registrationContext !== null) {
- throw new RuntimeException('Registration has already been run');
- }
+ public function runInitialRegistration(): void {
+ $this->registerApps(OC_App::getEnabledApps());
+ }
+
+ public function runLazyRegistration(string $appId): void {
+ $this->registerApps([$appId]);
+ }
- $this->registrationContext = new RegistrationContext($this->logger);
+ /**
+ * @param string[] $appIds
+ */
+ private function registerApps(array $appIds): void {
+ if ($this->registrationContext === null) {
+ $this->registrationContext = new RegistrationContext($this->logger);
+ }
$apps = [];
- foreach (OC_App::getEnabledApps() as $appId) {
+ foreach ($appIds as $appId) {
/*
* First, we have to enable the app's autoloader
*
@@ -134,6 +149,11 @@ class Coordinator {
}
public function bootApp(string $appId): void {
+ if (isset($this->bootedApps[$appId])) {
+ return;
+ }
+ $this->bootedApps[$appId] = true;
+
$appNameSpace = App::buildAppNamespace($appId);
$applicationClassName = $appNameSpace . '\\AppInfo\\Application';
if (!class_exists($applicationClassName)) {
diff --git a/lib/private/AppFramework/Bootstrap/FunctionInjector.php b/lib/private/AppFramework/Bootstrap/FunctionInjector.php
index 25c1fbc0be6..3c20701618b 100644
--- a/lib/private/AppFramework/Bootstrap/FunctionInjector.php
+++ b/lib/private/AppFramework/Bootstrap/FunctionInjector.php
@@ -5,7 +5,7 @@ declare(strict_types=1);
/**
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
*
- * @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @license GNU AGPL version 3 or any later version
*
@@ -20,7 +20,8 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
namespace OC\AppFramework\Bootstrap;
diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php
index efcf9175b97..d6271f5ce45 100644
--- a/lib/private/AppFramework/Bootstrap/RegistrationContext.php
+++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php
@@ -5,7 +5,11 @@ declare(strict_types=1);
/**
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
*
- * @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
+ * @author Julius Härtl <jus@bitgrid.net>
+ * @author Robin Windey <ro.windey@gmail.com>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
*
@@ -20,7 +24,8 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
namespace OC\AppFramework\Bootstrap;
@@ -66,6 +71,12 @@ class RegistrationContext {
/** @var array[] */
private $alternativeLogins = [];
+ /** @var array[] */
+ private $initialStates = [];
+
+ /** @var array[] */
+ private $wellKnownHandlers = [];
+
/** @var ILogger */
private $logger;
@@ -100,10 +111,10 @@ class RegistrationContext {
);
}
- public function registerDashboardPanel(string $panelClass): void {
+ public function registerDashboardWidget(string $widgetClass): void {
$this->context->registerDashboardPanel(
$this->appId,
- $panelClass
+ $widgetClass
);
}
@@ -161,6 +172,20 @@ class RegistrationContext {
$class
);
}
+
+ public function registerInitialStateProvider(string $class): void {
+ $this->context->registerInitialState(
+ $this->appId,
+ $class
+ );
+ }
+
+ public function registerWellKnownHandler(string $class): void {
+ $this->context->registerWellKnown(
+ $this->appId,
+ $class
+ );
+ }
};
}
@@ -190,7 +215,7 @@ class RegistrationContext {
"appId" => $appId,
"name" => $name,
"factory" => $factory,
- "sharred" => $shared,
+ "shared" => $shared,
];
}
@@ -240,11 +265,25 @@ class RegistrationContext {
];
}
+ public function registerInitialState(string $appId, string $class): void {
+ $this->initialStates[] = [
+ 'appId' => $appId,
+ 'class' => $class,
+ ];
+ }
+
+ public function registerWellKnown(string $appId, string $class): void {
+ $this->wellKnownHandlers[] = [
+ 'appId' => $appId,
+ 'class' => $class,
+ ];
+ }
+
/**
* @param App[] $apps
*/
public function delegateCapabilityRegistrations(array $apps): void {
- foreach ($this->capabilities as $registration) {
+ while (($registration = array_shift($this->capabilities)) !== null) {
try {
$apps[$registration['appId']]
->getContainer()
@@ -263,7 +302,7 @@ class RegistrationContext {
* @param App[] $apps
*/
public function delegateCrashReporterRegistrations(array $apps, Registry $registry): void {
- foreach ($this->crashReporters as $registration) {
+ while (($registration = array_shift($this->crashReporters)) !== null) {
try {
$registry->registerLazy($registration['class']);
} catch (Throwable $e) {
@@ -280,9 +319,9 @@ class RegistrationContext {
* @param App[] $apps
*/
public function delegateDashboardPanelRegistrations(array $apps, IManager $dashboardManager): void {
- foreach ($this->dashboardPanels as $panel) {
+ while (($panel = array_shift($this->dashboardPanels)) !== null) {
try {
- $dashboardManager->lazyRegisterPanel($panel['class']);
+ $dashboardManager->lazyRegisterWidget($panel['class']);
} catch (Throwable $e) {
$appId = $panel['appId'];
$this->logger->logException($e, [
@@ -294,7 +333,7 @@ class RegistrationContext {
}
public function delegateEventListenerRegistrations(IEventDispatcher $eventDispatcher): void {
- foreach ($this->eventListeners as $registration) {
+ while (($registration = array_shift($this->eventListeners)) !== null) {
try {
if (isset($registration['priority'])) {
$eventDispatcher->addServiceListener(
@@ -322,7 +361,7 @@ class RegistrationContext {
* @param App[] $apps
*/
public function delegateContainerRegistrations(array $apps): void {
- foreach ($this->services as $registration) {
+ while (($registration = array_shift($this->services)) !== null) {
try {
/**
* Register the service and convert the callable into a \Closure if necessary
@@ -382,7 +421,7 @@ class RegistrationContext {
* @param App[] $apps
*/
public function delegateMiddlewareRegistrations(array $apps): void {
- foreach ($this->middlewares as $middleware) {
+ while (($middleware = array_shift($this->middlewares)) !== null) {
try {
$apps[$middleware['appId']]
->getContainer()
@@ -410,4 +449,18 @@ class RegistrationContext {
public function getAlternativeLogins(): array {
return $this->alternativeLogins;
}
+
+ /**
+ * @erturn array[]
+ */
+ public function getInitialStates(): array {
+ return $this->initialStates;
+ }
+
+ /**
+ * @return array[]
+ */
+ public function getWellKnownHandlers(): array {
+ return $this->wellKnownHandlers;
+ }
}
diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php
index cd426d64699..3ef816f503e 100644
--- a/lib/private/AppFramework/DependencyInjection/DIContainer.php
+++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php
@@ -6,7 +6,6 @@
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Bjoern Schiessle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Joas Schilling <coding@schilljs.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@statuscode.ch>
@@ -62,6 +61,7 @@ use OCP\Files\Folder;
use OCP\Files\IAppData;
use OCP\Group\ISubAdmin;
use OCP\IConfig;
+use OCP\IDBConnection;
use OCP\IInitialStateService;
use OCP\IL10N;
use OCP\ILogger;
@@ -181,7 +181,10 @@ class DIContainer extends SimpleContainer implements IAppContainer {
$c->get('Protocol'),
$c->get(MiddlewareDispatcher::class),
$c->get(IControllerMethodReflector::class),
- $c->get(IRequest::class)
+ $c->get(IRequest::class),
+ $c->get(IConfig::class),
+ $c->get(IDBConnection::class),
+ $c->get(LoggerInterface::class)
);
});
diff --git a/lib/private/AppFramework/Http.php b/lib/private/AppFramework/Http.php
index 88e49816eb9..828efe390e7 100644
--- a/lib/private/AppFramework/Http.php
+++ b/lib/private/AppFramework/Http.php
@@ -41,7 +41,7 @@ class Http extends BaseHttp {
* @param array $server $_SERVER
* @param string $protocolVersion the http version to use defaults to HTTP/1.1
*/
- public function __construct($server, $protocolVersion='HTTP/1.1') {
+ public function __construct($server, $protocolVersion = 'HTTP/1.1') {
$this->server = $server;
$this->protocolVersion = $protocolVersion;
diff --git a/lib/private/AppFramework/Http/Dispatcher.php b/lib/private/AppFramework/Http/Dispatcher.php
index 3892bb667f0..47e6650c999 100644
--- a/lib/private/AppFramework/Http/Dispatcher.php
+++ b/lib/private/AppFramework/Http/Dispatcher.php
@@ -7,6 +7,7 @@ declare(strict_types=1);
*
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Julius Härtl <jus@bitgrid.net>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
@@ -35,11 +36,14 @@ namespace OC\AppFramework\Http;
use OC\AppFramework\Http;
use OC\AppFramework\Middleware\MiddlewareDispatcher;
use OC\AppFramework\Utility\ControllerMethodReflector;
-
+use OC\DB\Connection;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\Response;
+use OCP\IConfig;
+use OCP\IDBConnection;
use OCP\IRequest;
+use Psr\Log\LoggerInterface;
/**
* Class to dispatch the request to the middleware dispatcher
@@ -58,6 +62,15 @@ class Dispatcher {
/** @var IRequest */
private $request;
+ /** @var IConfig */
+ private $config;
+
+ /** @var IDBConnection|Connection */
+ private $connection;
+
+ /** @var LoggerInterface */
+ private $logger;
+
/**
* @param Http $protocol the http protocol with contains all status headers
* @param MiddlewareDispatcher $middlewareDispatcher the dispatcher which
@@ -65,15 +78,24 @@ class Dispatcher {
* @param ControllerMethodReflector $reflector the reflector that is used to inject
* the arguments for the controller
* @param IRequest $request the incoming request
+ * @param IConfig $config
+ * @param IDBConnection $connection
+ * @param LoggerInterface $logger
*/
public function __construct(Http $protocol,
MiddlewareDispatcher $middlewareDispatcher,
ControllerMethodReflector $reflector,
- IRequest $request) {
+ IRequest $request,
+ IConfig $config,
+ IDBConnection $connection,
+ LoggerInterface $logger) {
$this->protocol = $protocol;
$this->middlewareDispatcher = $middlewareDispatcher;
$this->reflector = $reflector;
$this->request = $request;
+ $this->config = $config;
+ $this->connection = $connection;
+ $this->logger = $logger;
}
@@ -97,8 +119,36 @@ class Dispatcher {
$this->middlewareDispatcher->beforeController($controller,
$methodName);
+
+ $databaseStatsBefore = [];
+ if ($this->config->getSystemValueBool('debug', false)) {
+ $databaseStatsBefore = $this->connection->getStats();
+ }
+
$response = $this->executeController($controller, $methodName);
+ if (!empty($databaseStatsBefore)) {
+ $databaseStatsAfter = $this->connection->getStats();
+ $numBuilt = $databaseStatsAfter['built'] - $databaseStatsBefore['built'];
+ $numExecuted = $databaseStatsAfter['executed'] - $databaseStatsBefore['executed'];
+
+ if ($numBuilt > 50) {
+ $this->logger->debug('Controller {class}::{method} created {count} QueryBuilder objects, please check if they are created inside a loop by accident.' , [
+ 'class' => (string) get_class($controller),
+ 'method' => $methodName,
+ 'count' => $numBuilt,
+ ]);
+ }
+
+ if ($numExecuted > 100) {
+ $this->logger->warning('Controller {class}::{method} executed {count} queries.' , [
+ 'class' => (string) get_class($controller),
+ 'method' => $methodName,
+ 'count' => $numExecuted,
+ ]);
+ }
+ }
+
// if an exception appears, the middleware checks if it can handle the
// exception and creates a response. If no response is created, it is
// assumed that theres no middleware who can handle it and the error is
diff --git a/lib/private/AppFramework/Http/Output.php b/lib/private/AppFramework/Http/Output.php
index 8777c1970a6..d2e8cd338ba 100644
--- a/lib/private/AppFramework/Http/Output.php
+++ b/lib/private/AppFramework/Http/Output.php
@@ -3,8 +3,10 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Robin Appelman <robin@icewind.nl>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Stefan Weil <sw@weilnetz.de>
*
* @license AGPL-3.0
@@ -95,17 +97,13 @@ class Output implements IOutput {
public function setCookie($name, $value, $expire, $path, $domain, $secure, $httpOnly, $sameSite = 'Lax') {
$path = $this->webRoot ? : '/';
- if (PHP_VERSION_ID < 70300) {
- setcookie($name, $value, $expire, $path, $domain, $secure, $httpOnly);
- } else {
- setcookie($name, $value, [
- 'expires' => $expire,
- 'path' => $path,
- 'domain' => $domain,
- 'secure' => $secure,
- 'httponly' => $httpOnly,
- 'samesite' => $sameSite
- ]);
- }
+ setcookie($name, $value, [
+ 'expires' => $expire,
+ 'path' => $path,
+ 'domain' => $domain,
+ 'secure' => $secure,
+ 'httponly' => $httpOnly,
+ 'samesite' => $sameSite
+ ]);
}
}
diff --git a/lib/private/AppFramework/Http/Request.php b/lib/private/AppFramework/Http/Request.php
index d0ecdbea6c7..deabbe5206a 100644
--- a/lib/private/AppFramework/Http/Request.php
+++ b/lib/private/AppFramework/Http/Request.php
@@ -10,6 +10,7 @@ declare(strict_types=1);
* @author Bernhard Posselt <dev@bernhard-posselt.com>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Kesselberg <mail@danielkesselberg.de>
+ * @author Georg Ehrke <oc.list@georgehrke.com>
* @author Joas Schilling <coding@schilljs.com>
* @author Juan Pablo Villafáñez <jvillafanez@solidgear.es>
* @author Julius Härtl <jus@bitgrid.net>
@@ -22,7 +23,7 @@ declare(strict_types=1);
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -74,7 +75,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
// Android Chrome user agent: https://developers.google.com/chrome/mobile/docs/user-agent
public const USER_AGENT_ANDROID_MOBILE_CHROME = '#Android.*Chrome/[.0-9]*#';
public const USER_AGENT_FREEBOX = '#^Mozilla/5\.0$#';
- public const REGEX_LOCALHOST = '/^(127\.0\.0\.1|localhost|::1)$/';
+ public const REGEX_LOCALHOST = '/^(127\.0\.0\.1|localhost|\[::1\])$/';
/**
* @deprecated use \OCP\IRequest::USER_AGENT_CLIENT_IOS instead
@@ -135,8 +136,8 @@ class Request implements \ArrayAccess, \Countable, IRequest {
* @param string $stream
* @see http://www.php.net/manual/en/reserved.variables.php
*/
- public function __construct(array $vars= [],
- ISecureRandom $secureRandom = null,
+ public function __construct(array $vars,
+ ISecureRandom $secureRandom,
IConfig $config,
CsrfTokenManager $csrfTokenManager = null,
string $stream = 'php://input') {
@@ -826,7 +827,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
*/
public function getScriptName(): string {
$name = $this->server['SCRIPT_NAME'];
- $overwriteWebRoot = $this->config->getSystemValue('overwritewebroot');
+ $overwriteWebRoot = $this->config->getSystemValue('overwritewebroot');
if ($overwriteWebRoot !== '' && $this->isOverwriteCondition()) {
// FIXME: This code is untestable due to __DIR__, also that hardcoded path is really dangerous
$serverRoot = str_replace('\\', '/', substr(__DIR__, 0, -\strlen('lib/private/appframework/http/')));
diff --git a/lib/private/AppFramework/Logger.php b/lib/private/AppFramework/Logger.php
index 062a705efc4..16f4dd36e78 100644
--- a/lib/private/AppFramework/Logger.php
+++ b/lib/private/AppFramework/Logger.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
/**
* @copyright Copyright (c) 2018, Roeland Jago Douma <roeland@famdouma.nl>
*
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
diff --git a/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php b/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php
index 9eafd5b740c..28f322f42b7 100644
--- a/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php
+++ b/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
/**
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
*
+ * @author Julius Härtl <jus@bitgrid.net>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
@@ -70,7 +71,7 @@ class AdditionalScriptsMiddleware extends Middleware {
$isLoggedIn = false;
}
- $this->dispatcher->dispatchTyped(new BeforeTemplateRenderedEvent($isLoggedIn));
+ $this->dispatcher->dispatchTyped(new BeforeTemplateRenderedEvent($isLoggedIn, $response));
}
return $response;
diff --git a/lib/private/AppFramework/Middleware/CompressionMiddleware.php b/lib/private/AppFramework/Middleware/CompressionMiddleware.php
index 6956be76693..f6d3839891e 100644
--- a/lib/private/AppFramework/Middleware/CompressionMiddleware.php
+++ b/lib/private/AppFramework/Middleware/CompressionMiddleware.php
@@ -1,9 +1,11 @@
<?php
declare(strict_types=1);
+
/**
* @copyright Copyright (c) 2020, 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
@@ -19,7 +21,7 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff --git a/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php b/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php
index 270058dc554..577931b8222 100644
--- a/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php
+++ b/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php
@@ -116,7 +116,7 @@ class MiddlewareDispatcher {
* @throws \Exception the passed in exception if it can't handle it
*/
public function afterException(Controller $controller, string $methodName, \Exception $exception): Response {
- for ($i=$this->middlewareCounter-1; $i>=0; $i--) {
+ for ($i = $this->middlewareCounter - 1; $i >= 0; $i--) {
$middleware = $this->middlewares[$i];
try {
return $middleware->afterException($controller, $methodName, $exception);
@@ -139,7 +139,7 @@ class MiddlewareDispatcher {
* @return Response a Response object
*/
public function afterController(Controller $controller, string $methodName, Response $response): Response {
- for ($i= \count($this->middlewares)-1; $i>=0; $i--) {
+ for ($i = \count($this->middlewares) - 1; $i >= 0; $i--) {
$middleware = $this->middlewares[$i];
$response = $middleware->afterController($controller, $methodName, $response);
}
@@ -158,7 +158,7 @@ class MiddlewareDispatcher {
* @return string the output that should be printed
*/
public function beforeOutput(Controller $controller, string $methodName, string $output): string {
- for ($i= \count($this->middlewares)-1; $i>=0; $i--) {
+ for ($i = \count($this->middlewares) - 1; $i >= 0; $i--) {
$middleware = $this->middlewares[$i];
$output = $middleware->beforeOutput($controller, $methodName, $output);
}
diff --git a/lib/private/AppFramework/Middleware/NotModifiedMiddleware.php b/lib/private/AppFramework/Middleware/NotModifiedMiddleware.php
index e34310b4116..083761dcf02 100644
--- a/lib/private/AppFramework/Middleware/NotModifiedMiddleware.php
+++ b/lib/private/AppFramework/Middleware/NotModifiedMiddleware.php
@@ -1,6 +1,7 @@
<?php
declare(strict_types=1);
+
/**
* @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
*
@@ -19,7 +20,7 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff --git a/lib/private/AppFramework/Middleware/Security/BruteForceMiddleware.php b/lib/private/AppFramework/Middleware/Security/BruteForceMiddleware.php
index 398c2f3f3a4..31a4791845e 100644
--- a/lib/private/AppFramework/Middleware/Security/BruteForceMiddleware.php
+++ b/lib/private/AppFramework/Middleware/Security/BruteForceMiddleware.php
@@ -1,8 +1,12 @@
<?php
+
+declare(strict_types=1);
+
/**
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Lukas Reschke <lukas@statuscode.ch>
*
* @license GNU AGPL version 3 or any later version
@@ -26,9 +30,15 @@ namespace OC\AppFramework\Middleware\Security;
use OC\AppFramework\Utility\ControllerMethodReflector;
use OC\Security\Bruteforce\Throttler;
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Response;
+use OCP\AppFramework\Http\TooManyRequestsResponse;
use OCP\AppFramework\Middleware;
+use OCP\AppFramework\OCS\OCSException;
+use OCP\AppFramework\OCSController;
use OCP\IRequest;
+use OCP\Security\Bruteforce\MaxDelayReached;
/**
* Class BruteForceMiddleware performs the bruteforce protection for controllers
@@ -66,7 +76,7 @@ class BruteForceMiddleware extends Middleware {
if ($this->reflector->hasAnnotation('BruteForceProtection')) {
$action = $this->reflector->getAnnotationParameter('BruteForceProtection', 'action');
- $this->throttler->sleepDelay($this->request->getRemoteAddress(), $action);
+ $this->throttler->sleepDelayOrThrowOnMax($this->request->getRemoteAddress(), $action);
}
}
@@ -83,4 +93,23 @@ class BruteForceMiddleware extends Middleware {
return parent::afterController($controller, $methodName, $response);
}
+
+ /**
+ * @param Controller $controller
+ * @param string $methodName
+ * @param \Exception $exception
+ * @throws \Exception
+ * @return Response
+ */
+ public function afterException($controller, $methodName, \Exception $exception): Response {
+ if ($exception instanceof MaxDelayReached) {
+ if ($controller instanceof OCSController) {
+ throw new OCSException($exception->getMessage(), Http::STATUS_TOO_MANY_REQUESTS);
+ }
+
+ return new TooManyRequestsResponse();
+ }
+
+ throw $exception;
+ }
}
diff --git a/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php b/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php
index af6d3de6570..765311858de 100644
--- a/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php
+++ b/lib/private/AppFramework/Middleware/Security/CORSMiddleware.php
@@ -145,7 +145,7 @@ class CORSMiddleware extends Middleware {
*/
public function afterException($controller, $methodName, \Exception $exception) {
if ($exception instanceof SecurityException) {
- $response = new JSONResponse(['message' => $exception->getMessage()]);
+ $response = new JSONResponse(['message' => $exception->getMessage()]);
if ($exception->getCode() !== 0) {
$response->setStatus($exception->getCode());
} else {
diff --git a/lib/private/AppFramework/Middleware/Security/SameSiteCookieMiddleware.php b/lib/private/AppFramework/Middleware/Security/SameSiteCookieMiddleware.php
index 7a358f6ebf2..48d386e749e 100644
--- a/lib/private/AppFramework/Middleware/Security/SameSiteCookieMiddleware.php
+++ b/lib/private/AppFramework/Middleware/Security/SameSiteCookieMiddleware.php
@@ -48,7 +48,7 @@ class SameSiteCookieMiddleware extends Middleware {
public function beforeController($controller, $methodName) {
$requestUri = $this->request->getScriptName();
$processingScript = explode('/', $requestUri);
- $processingScript = $processingScript[count($processingScript)-1];
+ $processingScript = $processingScript[count($processingScript) - 1];
if ($processingScript !== 'index.php') {
return;
diff --git a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php
index 089f3589454..76665f8998f 100644
--- a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php
+++ b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php
@@ -10,6 +10,7 @@ declare(strict_types=1);
* @author Bjoern Schiessle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Kesselberg <mail@danielkesselberg.de>
+ * @author Holger Hees <holger.hees@gmail.com>
* @author Joas Schilling <coding@schilljs.com>
* @author Julien Veyssier <eneiluj@posteo.net>
* @author Lukas Reschke <lukas@statuscode.ch>
diff --git a/lib/private/AppFramework/OCS/V1Response.php b/lib/private/AppFramework/OCS/V1Response.php
index 5a3e4090425..97a3acce681 100644
--- a/lib/private/AppFramework/OCS/V1Response.php
+++ b/lib/private/AppFramework/OCS/V1Response.php
@@ -2,6 +2,7 @@
/**
* @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl>
*
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
@@ -35,7 +36,7 @@ class V1Response extends BaseResponse {
* @return int
*/
public function getStatus() {
- $status = parent::getStatus();
+ $status = parent::getStatus();
if ($status === Http::STATUS_FORBIDDEN || $status === API::RESPOND_UNAUTHORISED) {
return Http::STATUS_UNAUTHORIZED;
}
diff --git a/lib/private/AppFramework/OCS/V2Response.php b/lib/private/AppFramework/OCS/V2Response.php
index b6863262d81..3d1868857ce 100644
--- a/lib/private/AppFramework/OCS/V2Response.php
+++ b/lib/private/AppFramework/OCS/V2Response.php
@@ -36,7 +36,7 @@ class V2Response extends BaseResponse {
* @return int
*/
public function getStatus() {
- $status = parent::getStatus();
+ $status = parent::getStatus();
if ($status === API::RESPOND_UNAUTHORISED) {
return Http::STATUS_UNAUTHORIZED;
} elseif ($status === API::RESPOND_NOT_FOUND) {
diff --git a/lib/private/AppFramework/Routing/RouteConfig.php b/lib/private/AppFramework/Routing/RouteConfig.php
index 1921ce65128..b382e7eb4b0 100644
--- a/lib/private/AppFramework/Routing/RouteConfig.php
+++ b/lib/private/AppFramework/Routing/RouteConfig.php
@@ -32,7 +32,7 @@ declare(strict_types=1);
namespace OC\AppFramework\Routing;
use OC\AppFramework\DependencyInjection\DIContainer;
-use OCP\Route\IRouter;
+use OC\Route\Router;
/**
* Class RouteConfig
@@ -42,7 +42,7 @@ class RouteConfig {
/** @var DIContainer */
private $container;
- /** @var IRouter */
+ /** @var Router */
private $router;
/** @var array */
@@ -65,11 +65,11 @@ class RouteConfig {
/**
* @param \OC\AppFramework\DependencyInjection\DIContainer $container
- * @param \OCP\Route\IRouter $router
+ * @param \OC\Route\Router $router
* @param array $routes
* @internal param $appName
*/
- public function __construct(DIContainer $container, IRouter $router, $routes) {
+ public function __construct(DIContainer $container, Router $router, $routes) {
$this->routes = $routes;
$this->container = $container;
$this->router = $router;
diff --git a/lib/private/AppFramework/Routing/RouteParser.php b/lib/private/AppFramework/Routing/RouteParser.php
new file mode 100644
index 00000000000..8511ff9ee39
--- /dev/null
+++ b/lib/private/AppFramework/Routing/RouteParser.php
@@ -0,0 +1,263 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @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\AppFramework\Routing;
+
+use OC\Route\Route;
+use Symfony\Component\Routing\RouteCollection;
+
+class RouteParser {
+ /** @var string[] */
+ private $controllerNameCache = [];
+
+ private const rootUrlApps = [
+ 'cloud_federation_api',
+ 'core',
+ 'files_sharing',
+ 'files',
+ 'settings',
+ 'spreed',
+ ];
+
+ public function parseDefaultRoutes(array $routes, string $appName): RouteCollection {
+ $collection = $this->processIndexRoutes($routes, $appName);
+ $collection->addCollection($this->processIndexResources($routes, $appName));
+
+ return $collection;
+ }
+
+ public function parseOCSRoutes(array $routes, string $appName): RouteCollection {
+ $collection = $this->processOCS($routes, $appName);
+ $collection->addCollection($this->processOCSResources($routes, $appName));
+
+ return $collection;
+ }
+
+ private function processOCS(array $routes, string $appName): RouteCollection {
+ $collection = new RouteCollection();
+ $ocsRoutes = $routes['ocs'] ?? [];
+ foreach ($ocsRoutes as $ocsRoute) {
+ $result = $this->processRoute($ocsRoute, $appName, 'ocs.');
+
+ $collection->add($result[0], $result[1]);
+ }
+
+ return $collection;
+ }
+
+ /**
+ * Creates one route base on the give configuration
+ * @param array $routes
+ * @throws \UnexpectedValueException
+ */
+ private function processIndexRoutes(array $routes, string $appName): RouteCollection {
+ $collection = new RouteCollection();
+ $simpleRoutes = $routes['routes'] ?? [];
+ foreach ($simpleRoutes as $simpleRoute) {
+ $result = $this->processRoute($simpleRoute, $appName);
+
+ $collection->add($result[0], $result[1]);
+ }
+
+ return $collection;
+ }
+
+ private function processRoute(array $route, string $appName, string $routeNamePrefix = ''): array {
+ $name = $route['name'];
+ $postfix = $route['postfix'] ?? '';
+ $root = $this->buildRootPrefix($route, $appName, $routeNamePrefix);
+
+ $url = $root . '/' . ltrim($route['url'], '/');
+ $verb = strtoupper($route['verb'] ?? 'GET');
+
+ $split = explode('#', $name, 2);
+ if (count($split) !== 2) {
+ throw new \UnexpectedValueException('Invalid route name');
+ }
+ list($controller, $action) = $split;
+
+ $controllerName = $this->buildControllerName($controller);
+ $actionName = $this->buildActionName($action);
+
+ $routeName = $routeNamePrefix . $appName . '.' . $controller . '.' . $action . $postfix;
+
+ $routeObject = new Route($url);
+ $routeObject->method($verb);
+
+ // optionally register requirements for route. This is used to
+ // tell the route parser how url parameters should be matched
+ if (array_key_exists('requirements', $route)) {
+ $routeObject->requirements($route['requirements']);
+ }
+
+ // optionally register defaults for route. This is used to
+ // tell the route parser how url parameters should be default valued
+ $defaults = [];
+ if (array_key_exists('defaults', $route)) {
+ $defaults = $route['defaults'];
+ }
+
+ $defaults['caller'] = [$appName, $controllerName, $actionName];
+ $routeObject->defaults($defaults);
+
+ return [$routeName, $routeObject];
+ }
+
+ /**
+ * For a given name and url restful OCS routes are created:
+ * - index
+ * - show
+ * - create
+ * - update
+ * - destroy
+ *
+ * @param array $routes
+ */
+ private function processOCSResources(array $routes, string $appName): RouteCollection {
+ return $this->processResources($routes['ocs-resources'] ?? [], $appName, 'ocs.');
+ }
+
+ /**
+ * For a given name and url restful routes are created:
+ * - index
+ * - show
+ * - create
+ * - update
+ * - destroy
+ *
+ * @param array $routes
+ */
+ private function processIndexResources(array $routes, string $appName): RouteCollection {
+ return $this->processResources($routes['resources'] ?? [], $appName);
+ }
+
+ /**
+ * For a given name and url restful routes are created:
+ * - index
+ * - show
+ * - create
+ * - update
+ * - destroy
+ *
+ * @param array $resources
+ * @param string $routeNamePrefix
+ */
+ private function processResources(array $resources, string $appName, string $routeNamePrefix = ''): RouteCollection {
+ // declaration of all restful actions
+ $actions = [
+ ['name' => 'index', 'verb' => 'GET', 'on-collection' => true],
+ ['name' => 'show', 'verb' => 'GET'],
+ ['name' => 'create', 'verb' => 'POST', 'on-collection' => true],
+ ['name' => 'update', 'verb' => 'PUT'],
+ ['name' => 'destroy', 'verb' => 'DELETE'],
+ ];
+
+ $collection = new RouteCollection();
+ foreach ($resources as $resource => $config) {
+ $root = $this->buildRootPrefix($config, $appName, $routeNamePrefix);
+
+ // the url parameter used as id to the resource
+ foreach ($actions as $action) {
+ $url = $root . '/' . ltrim($config['url'], '/');
+ $method = $action['name'];
+
+ $verb = strtoupper($action['verb'] ?? 'GET');
+ $collectionAction = $action['on-collection'] ?? false;
+ if (!$collectionAction) {
+ $url .= '/{id}';
+ }
+
+ $controller = $resource;
+
+ $controllerName = $this->buildControllerName($controller);
+ $actionName = $this->buildActionName($method);
+
+ $routeName = $routeNamePrefix . $appName . '.' . strtolower($resource) . '.' . $method;
+
+ $route = new Route($url);
+ $route->method($verb);
+
+ $route->defaults(['caller' => [$appName, $controllerName, $actionName]]);
+
+ $collection->add($routeName, $route);
+ }
+ }
+
+ return $collection;
+ }
+
+ private function buildRootPrefix(array $route, string $appName, string $routeNamePrefix): string {
+ $defaultRoot = $appName === 'core' ? '' : '/apps/' . $appName;
+ $root = $route['root'] ?? $defaultRoot;
+
+ if ($routeNamePrefix !== '') {
+ // In OCS all apps are whitelisted
+ return $root;
+ }
+
+ if (!\in_array($appName, self::rootUrlApps, true)) {
+ // Only allow root URLS for some apps
+ return $defaultRoot;
+ }
+
+ return $root;
+ }
+
+ /**
+ * Based on a given route name the controller name is generated
+ * @param string $controller
+ * @return string
+ */
+ private function buildControllerName(string $controller): string {
+ if (!isset($this->controllerNameCache[$controller])) {
+ $this->controllerNameCache[$controller] = $this->underScoreToCamelCase(ucfirst($controller)) . 'Controller';
+ }
+ return $this->controllerNameCache[$controller];
+ }
+
+ /**
+ * Based on the action part of the route name the controller method name is generated
+ * @param string $action
+ * @return string
+ */
+ private function buildActionName(string $action): string {
+ return $this->underScoreToCamelCase($action);
+ }
+
+ /**
+ * Underscored strings are converted to camel case strings
+ * @param string $str
+ * @return string
+ */
+ private function underScoreToCamelCase(string $str): string {
+ $pattern = '/_[a-z]?/';
+ return preg_replace_callback(
+ $pattern,
+ function ($matches) {
+ return strtoupper(ltrim($matches[0], '_'));
+ },
+ $str);
+ }
+}
diff --git a/lib/private/AppFramework/ScopedPsrLogger.php b/lib/private/AppFramework/ScopedPsrLogger.php
index d0ace1790c9..5f4872efd97 100644
--- a/lib/private/AppFramework/ScopedPsrLogger.php
+++ b/lib/private/AppFramework/ScopedPsrLogger.php
@@ -5,7 +5,8 @@ declare(strict_types=1);
/**
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
*
- * @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Maxence Lange <maxence@artificial-owl.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -20,7 +21,8 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
namespace OC\AppFramework;
@@ -140,6 +142,7 @@ class ScopedPsrLogger implements LoggerInterface {
public function log($level, $message, array $context = []) {
$this->inner->log(
+ $level,
$message,
array_merge(
[
diff --git a/lib/private/AppFramework/Services/AppConfig.php b/lib/private/AppFramework/Services/AppConfig.php
index eaca647f438..37e73fb55b1 100644
--- a/lib/private/AppFramework/Services/AppConfig.php
+++ b/lib/private/AppFramework/Services/AppConfig.php
@@ -1,9 +1,11 @@
<?php
declare(strict_types=1);
+
/**
* @copyright Copyright (c) 2020, 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
@@ -19,7 +21,7 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff --git a/lib/private/AppFramework/Services/InitialState.php b/lib/private/AppFramework/Services/InitialState.php
index fd076bbebf1..25c7339f1e7 100644
--- a/lib/private/AppFramework/Services/InitialState.php
+++ b/lib/private/AppFramework/Services/InitialState.php
@@ -1,6 +1,7 @@
<?php
declare(strict_types=1);
+
/**
* @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
*
@@ -19,7 +20,7 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff --git a/lib/private/AppFramework/Utility/ControllerMethodReflector.php b/lib/private/AppFramework/Utility/ControllerMethodReflector.php
index 81ae7407120..77417974d9a 100644
--- a/lib/private/AppFramework/Utility/ControllerMethodReflector.php
+++ b/lib/private/AppFramework/Utility/ControllerMethodReflector.php
@@ -9,6 +9,7 @@ declare(strict_types=1);
* @author Bjoern Schiessle <bjoern@schiessle.org>
* @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 Olivier Paroz <github@oparoz.com>
diff --git a/lib/private/AppFramework/Utility/SimpleContainer.php b/lib/private/AppFramework/Utility/SimpleContainer.php
index c17578183ac..f73e09e645e 100644
--- a/lib/private/AppFramework/Utility/SimpleContainer.php
+++ b/lib/private/AppFramework/Utility/SimpleContainer.php
@@ -7,7 +7,6 @@
* @author Joas Schilling <coding@schilljs.com>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
@@ -74,13 +73,13 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
}
return $class->newInstanceArgs(array_map(function (ReflectionParameter $parameter) {
- $parameterClass = $parameter->getClass();
+ $parameterType = $parameter->getType();
+
+ $resolveName = $parameter->getName();
// try to find out if it is a class or a simple parameter
- if ($parameterClass === null) {
- $resolveName = $parameter->getName();
- } else {
- $resolveName = $parameterClass->name;
+ if ($parameterType !== null && !$parameterType->isBuiltin()) {
+ $resolveName = $parameterType->getName();
}
try {
@@ -92,7 +91,7 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
return $parameter->getDefaultValue();
}
- if ($parameterClass !== null) {
+ if ($parameterType !== null && !$parameterType->isBuiltin()) {
$resolveName = $parameter->getName();
return $this->query($resolveName);
}
diff --git a/lib/private/Archive/Archive.php b/lib/private/Archive/Archive.php
index ee27009ca83..633e5e8ab0e 100644
--- a/lib/private/Archive/Archive.php
+++ b/lib/private/Archive/Archive.php
@@ -47,7 +47,7 @@ abstract class Archive {
* @param string $source either a local file or string data
* @return bool
*/
- abstract public function addFile($path, $source='');
+ abstract public function addFile($path, $source = '');
/**
* rename a file or folder in the archive
* @param string $source
diff --git a/lib/private/Archive/TAR.php b/lib/private/Archive/TAR.php
index 0d4103299ce..a9dd28b389b 100644
--- a/lib/private/Archive/TAR.php
+++ b/lib/private/Archive/TAR.php
@@ -5,6 +5,7 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Joas Schilling <coding@schilljs.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
@@ -381,4 +382,14 @@ class TAR extends Archive {
$types = [null, 'gz', 'bz'];
$this->tar = new \Archive_Tar($this->path, $types[self::getTarType($this->path)]);
}
+
+ /**
+ * Get error object from archive_tar.
+ */
+ public function getError(): ?\PEAR_Error {
+ if ($this->tar instanceof \Archive_Tar && $this->tar->error_object instanceof \PEAR_Error) {
+ return $this->tar->error_object;
+ }
+ return null;
+ }
}
diff --git a/lib/private/Archive/ZIP.php b/lib/private/Archive/ZIP.php
index 31aea420a3d..fd34f4d4cea 100644
--- a/lib/private/Archive/ZIP.php
+++ b/lib/private/Archive/ZIP.php
@@ -39,15 +39,15 @@ class ZIP extends Archive {
/**
* @var \ZipArchive zip
*/
- private $zip=null;
+ private $zip = null;
private $path;
/**
* @param string $source
*/
public function __construct($source) {
- $this->path=$source;
- $this->zip=new \ZipArchive();
+ $this->path = $source;
+ $this->zip = new \ZipArchive();
if ($this->zip->open($source, \ZipArchive::CREATE)) {
} else {
\OCP\Util::writeLog('files_archive', 'Error while opening archive '.$source, ILogger::WARN);
@@ -67,11 +67,11 @@ class ZIP extends Archive {
* @param string $source either a local file or string data
* @return bool
*/
- public function addFile($path, $source='') {
- if ($source and $source[0]=='/' and file_exists($source)) {
- $result=$this->zip->addFile($source, $path);
+ public function addFile($path, $source = '') {
+ if ($source and $source[0] == '/' and file_exists($source)) {
+ $result = $this->zip->addFile($source, $path);
} else {
- $result=$this->zip->addFromString($path, $source);
+ $result = $this->zip->addFromString($path, $source);
}
if ($result) {
$this->zip->close();//close and reopen to save the zip
@@ -86,8 +86,8 @@ class ZIP extends Archive {
* @return boolean|null
*/
public function rename($source, $dest) {
- $source=$this->stripPath($source);
- $dest=$this->stripPath($dest);
+ $source = $this->stripPath($source);
+ $dest = $this->stripPath($dest);
$this->zip->renameName($source, $dest);
}
/**
@@ -96,7 +96,7 @@ class ZIP extends Archive {
* @return int
*/
public function filesize($path) {
- $stat=$this->zip->statName($path);
+ $stat = $this->zip->statName($path);
return $stat['size'];
}
/**
@@ -113,13 +113,13 @@ class ZIP extends Archive {
* @return array
*/
public function getFolder($path) {
- $files=$this->getFiles();
- $folderContent=[];
- $pathLength=strlen($path);
+ $files = $this->getFiles();
+ $folderContent = [];
+ $pathLength = strlen($path);
foreach ($files as $file) {
- if (substr($file, 0, $pathLength)==$path and $file!=$path) {
- if (strrpos(substr($file, 0, -1), '/')<=$pathLength) {
- $folderContent[]=substr($file, $pathLength);
+ if (substr($file, 0, $pathLength) == $path and $file != $path) {
+ if (strrpos(substr($file, 0, -1), '/') <= $pathLength) {
+ $folderContent[] = substr($file, $pathLength);
}
}
}
@@ -130,10 +130,10 @@ class ZIP extends Archive {
* @return array
*/
public function getFiles() {
- $fileCount=$this->zip->numFiles;
- $files=[];
- for ($i=0;$i<$fileCount;$i++) {
- $files[]=$this->zip->getNameIndex($i);
+ $fileCount = $this->zip->numFiles;
+ $files = [];
+ for ($i = 0;$i < $fileCount;$i++) {
+ $files[] = $this->zip->getNameIndex($i);
}
return $files;
}
@@ -169,7 +169,7 @@ class ZIP extends Archive {
* @return bool
*/
public function fileExists($path) {
- return ($this->zip->locateName($path)!==false) or ($this->zip->locateName($path.'/')!==false);
+ return ($this->zip->locateName($path) !== false) or ($this->zip->locateName($path.'/') !== false);
}
/**
* remove a file or folder from the archive
@@ -190,16 +190,16 @@ class ZIP extends Archive {
* @return resource
*/
public function getStream($path, $mode) {
- if ($mode=='r' or $mode=='rb') {
+ if ($mode == 'r' or $mode == 'rb') {
return $this->zip->getStream($path);
} else {
//since we can't directly get a writable stream,
//make a temp copy of the file and put it back
//in the archive when the stream is closed
- if (strrpos($path, '.')!==false) {
- $ext=substr($path, strrpos($path, '.'));
+ if (strrpos($path, '.') !== false) {
+ $ext = substr($path, strrpos($path, '.'));
} else {
- $ext='';
+ $ext = '';
}
$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
if ($this->fileExists($path)) {
@@ -225,7 +225,7 @@ class ZIP extends Archive {
* @return string
*/
private function stripPath($path) {
- if (!$path || $path[0]=='/') {
+ if (!$path || $path[0] == '/') {
return substr($path, 1);
} else {
return $path;
diff --git a/lib/private/Authentication/Listeners/LoginFailedListener.php b/lib/private/Authentication/Listeners/LoginFailedListener.php
index 72800ad509c..19f0b92c3a6 100644
--- a/lib/private/Authentication/Listeners/LoginFailedListener.php
+++ b/lib/private/Authentication/Listeners/LoginFailedListener.php
@@ -35,6 +35,9 @@ use OCP\EventDispatcher\IEventListener;
use OCP\IUserManager;
use OCP\Util;
+/**
+ * @template-implements IEventListener<\OC\Authentication\Events\LoginFailed>
+ */
class LoginFailedListener implements IEventListener {
/** @var IEventDispatcher */
diff --git a/lib/private/Authentication/Listeners/RemoteWipeActivityListener.php b/lib/private/Authentication/Listeners/RemoteWipeActivityListener.php
index 0ab2dcf4837..0bdfa7cb39b 100644
--- a/lib/private/Authentication/Listeners/RemoteWipeActivityListener.php
+++ b/lib/private/Authentication/Listeners/RemoteWipeActivityListener.php
@@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -33,18 +34,21 @@ use OC\Authentication\Token\IToken;
use OCP\Activity\IManager as IActvityManager;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
-use OCP\ILogger;
+use Psr\Log\LoggerInterface;
+/**
+ * @template-implements IEventListener<\OC\Authentication\Events\ARemoteWipeEvent>
+ */
class RemoteWipeActivityListener implements IEventListener {
/** @var IActvityManager */
private $activityManager;
- /** @var ILogger */
+ /** @var LoggerInterface */
private $logger;
public function __construct(IActvityManager $activityManager,
- ILogger $logger) {
+ LoggerInterface $logger) {
$this->activityManager = $activityManager;
$this->logger = $logger;
}
@@ -69,10 +73,9 @@ class RemoteWipeActivityListener implements IEventListener {
try {
$this->activityManager->publish($activity);
} catch (BadMethodCallException $e) {
- $this->logger->logException($e, [
+ $this->logger->warning('could not publish activity', [
'app' => 'core',
- 'level' => ILogger::WARN,
- 'message' => 'could not publish activity',
+ 'exception' => $e,
]);
}
}
diff --git a/lib/private/Authentication/Listeners/RemoteWipeEmailListener.php b/lib/private/Authentication/Listeners/RemoteWipeEmailListener.php
index 799c4ea4cf5..2f330879a2a 100644
--- a/lib/private/Authentication/Listeners/RemoteWipeEmailListener.php
+++ b/lib/private/Authentication/Listeners/RemoteWipeEmailListener.php
@@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -32,14 +33,17 @@ use OC\Authentication\Events\RemoteWipeStarted;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\IL10N;
-use OCP\ILogger;
use OCP\IUser;
use OCP\IUserManager;
use OCP\L10N\IFactory as IL10nFactory;
use OCP\Mail\IMailer;
use OCP\Mail\IMessage;
+use Psr\Log\LoggerInterface;
use function substr;
+/**
+ * @template-implements IEventListener<\OC\Authentication\Events\ARemoteWipeEvent>
+ */
class RemoteWipeEmailListener implements IEventListener {
/** @var IMailer */
@@ -51,13 +55,13 @@ class RemoteWipeEmailListener implements IEventListener {
/** @var IL10N */
private $l10n;
- /** @var ILogger */
+ /** @var LoggerInterface */
private $logger;
public function __construct(IMailer $mailer,
IUserManager $userManager,
IL10nFactory $l10nFactory,
- ILogger $logger) {
+ LoggerInterface $logger) {
$this->mailer = $mailer;
$this->userManager = $userManager;
$this->l10n = $l10nFactory->get('core');
@@ -85,9 +89,8 @@ class RemoteWipeEmailListener implements IEventListener {
$this->getWipingStartedMessage($event, $user)
);
} catch (Exception $e) {
- $this->logger->logException($e, [
- 'message' => "Could not send remote wipe started email to <$uid>",
- 'level' => ILogger::ERROR,
+ $this->logger->error("Could not send remote wipe started email to <$uid>", [
+ 'exception' => $e,
]);
}
} elseif ($event instanceof RemoteWipeFinished) {
@@ -107,9 +110,8 @@ class RemoteWipeEmailListener implements IEventListener {
$this->getWipingFinishedMessage($event, $user)
);
} catch (Exception $e) {
- $this->logger->logException($e, [
- 'message' => "Could not send remote wipe finished email to <$uid>",
- 'level' => ILogger::ERROR,
+ $this->logger->error("Could not send remote wipe finished email to <$uid>", [
+ 'exception' => $e,
]);
}
}
diff --git a/lib/private/Authentication/Listeners/RemoteWipeNotificationsListener.php b/lib/private/Authentication/Listeners/RemoteWipeNotificationsListener.php
index 831107a05cd..965fb291fbf 100644
--- a/lib/private/Authentication/Listeners/RemoteWipeNotificationsListener.php
+++ b/lib/private/Authentication/Listeners/RemoteWipeNotificationsListener.php
@@ -35,6 +35,9 @@ use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Notification\IManager as INotificationManager;
+/**
+ * @template-implements IEventListener<\OC\Authentication\Events\ARemoteWipeEvent>
+ */
class RemoteWipeNotificationsListener implements IEventListener {
/** @var INotificationManager */
diff --git a/lib/private/Authentication/Listeners/UserDeletedStoreCleanupListener.php b/lib/private/Authentication/Listeners/UserDeletedStoreCleanupListener.php
index c8f2da82db6..057568f514e 100644
--- a/lib/private/Authentication/Listeners/UserDeletedStoreCleanupListener.php
+++ b/lib/private/Authentication/Listeners/UserDeletedStoreCleanupListener.php
@@ -31,6 +31,9 @@ use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\User\Events\UserDeletedEvent;
+/**
+ * @template-implements IEventListener<\OCP\User\Events\UserDeletedEvent>
+ */
class UserDeletedStoreCleanupListener implements IEventListener {
/** @var Registry */
diff --git a/lib/private/Authentication/Listeners/UserDeletedTokenCleanupListener.php b/lib/private/Authentication/Listeners/UserDeletedTokenCleanupListener.php
index d6238eb5ac8..2d78bd2d01c 100644
--- a/lib/private/Authentication/Listeners/UserDeletedTokenCleanupListener.php
+++ b/lib/private/Authentication/Listeners/UserDeletedTokenCleanupListener.php
@@ -5,7 +5,8 @@ declare(strict_types=1);
/**
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
*
- * @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -20,7 +21,8 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
namespace OC\Authentication\Listeners;
@@ -28,20 +30,23 @@ namespace OC\Authentication\Listeners;
use OC\Authentication\Token\Manager;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
-use OCP\ILogger;
use OCP\User\Events\UserDeletedEvent;
+use Psr\Log\LoggerInterface;
use Throwable;
+/**
+ * @template-implements IEventListener<\OCP\User\Events\UserDeletedEvent>
+ */
class UserDeletedTokenCleanupListener implements IEventListener {
/** @var Manager */
private $manager;
- /** @var ILogger */
+ /** @var LoggerInterface */
private $logger;
public function __construct(Manager $manager,
- ILogger $logger) {
+ LoggerInterface $logger) {
$this->manager = $manager;
$this->logger = $logger;
}
@@ -63,9 +68,8 @@ class UserDeletedTokenCleanupListener implements IEventListener {
$this->manager->invalidateTokenById($uid, $token->getId());
}
} catch (Throwable $e) {
- $this->logger->logException($e, [
- 'message' => 'Could not clean up auth tokens after user deletion: ' . $e->getMessage(),
- 'error' => ILogger::ERROR,
+ $this->logger->error('Could not clean up auth tokens after user deletion: ' . $e->getMessage(), [
+ 'exception' => $e,
]);
}
}
diff --git a/lib/private/Authentication/Listeners/UserLoggedInListener.php b/lib/private/Authentication/Listeners/UserLoggedInListener.php
new file mode 100644
index 00000000000..711a759fad4
--- /dev/null
+++ b/lib/private/Authentication/Listeners/UserLoggedInListener.php
@@ -0,0 +1,59 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @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 OC\Authentication\Listeners;
+
+use OC\Authentication\Token\Manager;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\User\Events\PostLoginEvent;
+
+/**
+ * @template-implements IEventListener<\OCP\User\Events\PostLoginEvent>
+ */
+class UserLoggedInListener implements IEventListener {
+
+ /** @var Manager */
+ private $manager;
+
+ public function __construct(Manager $manager) {
+ $this->manager = $manager;
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof PostLoginEvent)) {
+ return;
+ }
+
+ // If this is already a token login there is nothing to do
+ if ($event->isTokenLogin()) {
+ return;
+ }
+
+ $this->manager->updatePasswords($event->getUser()->getUID(), $event->getPassword());
+ }
+}
diff --git a/lib/private/Authentication/Login/LoggedInCheckCommand.php b/lib/private/Authentication/Login/LoggedInCheckCommand.php
index d2546a62d16..3c71c844d72 100644
--- a/lib/private/Authentication/Login/LoggedInCheckCommand.php
+++ b/lib/private/Authentication/Login/LoggedInCheckCommand.php
@@ -3,6 +3,7 @@
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
@@ -29,19 +30,17 @@ namespace OC\Authentication\Login;
use OC\Authentication\Events\LoginFailed;
use OC\Core\Controller\LoginController;
use OCP\EventDispatcher\IEventDispatcher;
-use OCP\ILogger;
-use OCP\IUserManager;
+use Psr\Log\LoggerInterface;
class LoggedInCheckCommand extends ALoginCommand {
- /** @var ILogger */
+ /** @var LoggerInterface */
private $logger;
/** @var IEventDispatcher */
private $dispatcher;
- /** @var IUserManager */
- private $userManager;
- public function __construct(ILogger $logger, IEventDispatcher $dispatcher) {
+ public function __construct(LoggerInterface $logger,
+ IEventDispatcher $dispatcher) {
$this->logger = $logger;
$this->dispatcher = $dispatcher;
}
diff --git a/lib/private/Authentication/Login/UserDisabledCheckCommand.php b/lib/private/Authentication/Login/UserDisabledCheckCommand.php
index e33853ef5bd..0889fc99b20 100644
--- a/lib/private/Authentication/Login/UserDisabledCheckCommand.php
+++ b/lib/private/Authentication/Login/UserDisabledCheckCommand.php
@@ -3,6 +3,7 @@
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -26,19 +27,19 @@ declare(strict_types=1);
namespace OC\Authentication\Login;
use OC\Core\Controller\LoginController;
-use OCP\ILogger;
use OCP\IUserManager;
+use Psr\Log\LoggerInterface;
class UserDisabledCheckCommand extends ALoginCommand {
/** @var IUserManager */
private $userManager;
- /** @var ILogger */
+ /** @var LoggerInterface */
private $logger;
public function __construct(IUserManager $userManager,
- ILogger $logger) {
+ LoggerInterface $logger) {
$this->userManager = $userManager;
$this->logger = $logger;
}
diff --git a/lib/private/Authentication/LoginCredentials/Store.php b/lib/private/Authentication/LoginCredentials/Store.php
index f4bedd88a18..1810732ac3a 100644
--- a/lib/private/Authentication/LoginCredentials/Store.php
+++ b/lib/private/Authentication/LoginCredentials/Store.php
@@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright 2016 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -32,28 +33,25 @@ use OC\Authentication\Token\IProvider;
use OCP\Authentication\Exceptions\CredentialsUnavailableException;
use OCP\Authentication\LoginCredentials\ICredentials;
use OCP\Authentication\LoginCredentials\IStore;
-use OCP\ILogger;
use OCP\ISession;
use OCP\Session\Exceptions\SessionNotAvailableException;
use OCP\Util;
+use Psr\Log\LoggerInterface;
class Store implements IStore {
/** @var ISession */
private $session;
- /** @var ILogger */
+ /** @var LoggerInterface */
private $logger;
/** @var IProvider|null */
private $tokenProvider;
- /**
- * @param ISession $session
- * @param ILogger $logger
- * @param IProvider $tokenProvider
- */
- public function __construct(ISession $session, ILogger $logger, IProvider $tokenProvider = null) {
+ public function __construct(ISession $session,
+ LoggerInterface $logger,
+ IProvider $tokenProvider = null) {
$this->session = $session;
$this->logger = $logger;
$this->tokenProvider = $tokenProvider;
@@ -111,8 +109,13 @@ class Store implements IStore {
}
if ($trySession && $this->session->exists('login_credentials')) {
- $creds = json_decode($this->session->get('login_credentials'));
- return new Credentials($creds->uid, $creds->uid, $creds->password);
+ /** @var array $creds */
+ $creds = json_decode($this->session->get('login_credentials'), true);
+ return new Credentials(
+ $creds['uid'],
+ $creds['loginName'] ?? $this->session->get('loginname') ?? $creds['uid'], // Pre 20 didn't have a loginName property, hence fall back to the session value and then to the UID
+ $creds['password']
+ );
}
// If we reach this line, an exception was thrown.
diff --git a/lib/private/Authentication/Token/DefaultToken.php b/lib/private/Authentication/Token/DefaultToken.php
index 9df907dfb4a..d91866ae66f 100644
--- a/lib/private/Authentication/Token/DefaultToken.php
+++ b/lib/private/Authentication/Token/DefaultToken.php
@@ -163,7 +163,7 @@ class DefaultToken extends Entity implements INamedToken {
$scope = json_decode($this->getScope(), true);
if (!$scope) {
return [
- 'filesystem'=> true
+ 'filesystem' => true
];
}
return $scope;
diff --git a/lib/private/Authentication/Token/DefaultTokenMapper.php b/lib/private/Authentication/Token/DefaultTokenMapper.php
index e51033ed1df..40d503772b0 100644
--- a/lib/private/Authentication/Token/DefaultTokenMapper.php
+++ b/lib/private/Authentication/Token/DefaultTokenMapper.php
@@ -35,6 +35,9 @@ use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
+/**
+ * @template-extends QBMapper<DefaultToken>
+ */
class DefaultTokenMapper extends QBMapper {
public function __construct(IDBConnection $db) {
parent::__construct($db, 'authtoken');
diff --git a/lib/private/Authentication/Token/DefaultTokenProvider.php b/lib/private/Authentication/Token/DefaultTokenProvider.php
index ee8a28d3cb0..a6a1af5a97a 100644
--- a/lib/private/Authentication/Token/DefaultTokenProvider.php
+++ b/lib/private/Authentication/Token/DefaultTokenProvider.php
@@ -39,8 +39,8 @@ use OC\Authentication\Exceptions\PasswordlessTokenException;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IConfig;
-use OCP\ILogger;
use OCP\Security\ICrypto;
+use Psr\Log\LoggerInterface;
class DefaultTokenProvider implements IProvider {
@@ -53,7 +53,7 @@ class DefaultTokenProvider implements IProvider {
/** @var IConfig */
private $config;
- /** @var ILogger */
+ /** @var LoggerInterface */
private $logger;
/** @var ITimeFactory */
@@ -62,7 +62,7 @@ class DefaultTokenProvider implements IProvider {
public function __construct(DefaultTokenMapper $mapper,
ICrypto $crypto,
IConfig $config,
- ILogger $logger,
+ LoggerInterface $logger,
ITimeFactory $time) {
$this->mapper = $mapper;
$this->crypto = $crypto;
diff --git a/lib/private/Authentication/Token/IProvider.php b/lib/private/Authentication/Token/IProvider.php
index 384828c207e..2b6223fded9 100644
--- a/lib/private/Authentication/Token/IProvider.php
+++ b/lib/private/Authentication/Token/IProvider.php
@@ -140,13 +140,13 @@ interface IProvider {
/**
* Get the (unencrypted) password of the given token
*
- * @param IToken $token
+ * @param IToken $savedToken
* @param string $tokenId
* @throws InvalidTokenException
* @throws PasswordlessTokenException
* @return string
*/
- public function getPassword(IToken $token, string $tokenId): string;
+ public function getPassword(IToken $savedToken, string $tokenId): string;
/**
* Encrypt and set the password of the given token
diff --git a/lib/private/Authentication/Token/PublicKeyToken.php b/lib/private/Authentication/Token/PublicKeyToken.php
index 320373436f1..d2336c81efd 100644
--- a/lib/private/Authentication/Token/PublicKeyToken.php
+++ b/lib/private/Authentication/Token/PublicKeyToken.php
@@ -180,7 +180,7 @@ class PublicKeyToken extends Entity implements INamedToken, IWipeableToken {
$scope = json_decode($this->getScope(), true);
if (!$scope) {
return [
- 'filesystem'=> true
+ 'filesystem' => true
];
}
return $scope;
diff --git a/lib/private/Authentication/Token/PublicKeyTokenMapper.php b/lib/private/Authentication/Token/PublicKeyTokenMapper.php
index e05325fec30..d44ff3c50dd 100644
--- a/lib/private/Authentication/Token/PublicKeyTokenMapper.php
+++ b/lib/private/Authentication/Token/PublicKeyTokenMapper.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
/**
* @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl>
*
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
@@ -32,6 +33,9 @@ use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
+/**
+ * @template-extends QBMapper<PublicKeyToken>
+ */
class PublicKeyTokenMapper extends QBMapper {
public function __construct(IDBConnection $db) {
parent::__construct($db, 'authtoken');
diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php
index 091f47d7da3..38551e63b87 100644
--- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php
+++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
/**
* @copyright Copyright 2018, 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 Morris Jobke <hey@morrisjobke.de>
@@ -38,8 +39,8 @@ use OC\Cache\CappedMemoryCache;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IConfig;
-use OCP\ILogger;
use OCP\Security\ICrypto;
+use Psr\Log\LoggerInterface;
class PublicKeyTokenProvider implements IProvider {
/** @var PublicKeyTokenMapper */
@@ -51,10 +52,10 @@ class PublicKeyTokenProvider implements IProvider {
/** @var IConfig */
private $config;
- /** @var ILogger $logger */
+ /** @var LoggerInterface */
private $logger;
- /** @var ITimeFactory $time */
+ /** @var ITimeFactory */
private $time;
/** @var CappedMemoryCache */
@@ -63,7 +64,7 @@ class PublicKeyTokenProvider implements IProvider {
public function __construct(PublicKeyTokenMapper $mapper,
ICrypto $crypto,
IConfig $config,
- ILogger $logger,
+ LoggerInterface $logger,
ITimeFactory $time) {
$this->mapper = $mapper;
$this->crypto = $crypto;
@@ -214,9 +215,13 @@ class PublicKeyTokenProvider implements IProvider {
if (!($token instanceof PublicKeyToken)) {
throw new InvalidTokenException("Invalid token type");
}
- /** @var DefaultToken $token */
+
+ $activityInterval = $this->config->getSystemValueInt('token_auth_activity_update', 60);
+ $activityInterval = min(max($activityInterval, 0), 300);
+
+ /** @var PublicKeyToken $token */
$now = $this->time->getTime();
- if ($token->getLastActivity() < ($now - 60)) {
+ if ($token->getLastActivity() < ($now - $activityInterval)) {
// Update token only once per minute
$token->setLastActivity($now);
$this->mapper->update($token);
@@ -227,20 +232,20 @@ class PublicKeyTokenProvider implements IProvider {
return $this->mapper->getTokenByUser($uid);
}
- public function getPassword(IToken $token, string $tokenId): string {
- if (!($token instanceof PublicKeyToken)) {
+ public function getPassword(IToken $savedToken, string $tokenId): string {
+ if (!($savedToken instanceof PublicKeyToken)) {
throw new InvalidTokenException("Invalid token type");
}
- if ($token->getPassword() === null) {
+ if ($savedToken->getPassword() === null) {
throw new PasswordlessTokenException();
}
// Decrypt private key with tokenId
- $privateKey = $this->decrypt($token->getPrivateKey(), $tokenId);
+ $privateKey = $this->decrypt($savedToken->getPrivateKey(), $tokenId);
// Decrypt password with private key
- return $this->decryptPassword($token->getPassword(), $privateKey);
+ return $this->decryptPassword($savedToken->getPassword(), $privateKey);
}
public function setPassword(IToken $token, string $tokenId, string $password) {
@@ -419,6 +424,7 @@ class PublicKeyTokenProvider implements IProvider {
foreach ($tokens as $t) {
$publicKey = $t->getPublicKey();
$t->setPassword($this->encryptPassword($password, $publicKey));
+ $t->setPasswordInvalid(false);
$this->updateToken($t);
}
}
diff --git a/lib/private/Authentication/Token/RemoteWipe.php b/lib/private/Authentication/Token/RemoteWipe.php
index cab68357a01..b762073a8bc 100644
--- a/lib/private/Authentication/Token/RemoteWipe.php
+++ b/lib/private/Authentication/Token/RemoteWipe.php
@@ -28,13 +28,13 @@ declare(strict_types=1);
namespace OC\Authentication\Token;
+use Psr\Log\LoggerInterface;
use function array_filter;
use OC\Authentication\Events\RemoteWipeFinished;
use OC\Authentication\Events\RemoteWipeStarted;
use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Authentication\Exceptions\WipeTokenException;
use OCP\EventDispatcher\IEventDispatcher;
-use OCP\ILogger;
use OCP\IUser;
class RemoteWipe {
@@ -45,12 +45,12 @@ class RemoteWipe {
/** @var IEventDispatcher */
private $eventDispatcher;
- /** @var ILogger */
+ /** @var LoggerInterface */
private $logger;
public function __construct(IProvider $tokenProvider,
IEventDispatcher $eventDispatcher,
- ILogger $logger) {
+ LoggerInterface $logger) {
$this->tokenProvider = $tokenProvider;
$this->eventDispatcher = $eventDispatcher;
$this->logger = $logger;
diff --git a/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php b/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php
index 02e6863d1c4..bd8ff0353ee 100644
--- a/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php
+++ b/lib/private/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDao.php
@@ -29,6 +29,7 @@ namespace OC\Authentication\TwoFactorAuth\Db;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
+use function array_map;
/**
* Data access object to query and assign (provider_id, uid, enabled) tuples of
@@ -91,13 +92,35 @@ class ProviderUserAssignmentDao {
}
}
- public function deleteByUser(string $uid) {
- $qb = $this->conn->getQueryBuilder();
-
- $deleteQuery = $qb->delete(self::TABLE_NAME)
- ->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid)));
-
+ /**
+ * Delete all provider states of a user and return the provider IDs
+ *
+ * @param string $uid
+ *
+ * @return int[]
+ */
+ public function deleteByUser(string $uid): array {
+ $qb1 = $this->conn->getQueryBuilder();
+ $selectQuery = $qb1->select('*')
+ ->from(self::TABLE_NAME)
+ ->where($qb1->expr()->eq('uid', $qb1->createNamedParameter($uid)));
+ $selectResult = $selectQuery->execute();
+ $rows = $selectResult->fetchAll();
+ $selectResult->closeCursor();
+
+ $qb2 = $this->conn->getQueryBuilder();
+ $deleteQuery = $qb2
+ ->delete(self::TABLE_NAME)
+ ->where($qb2->expr()->eq('uid', $qb2->createNamedParameter($uid)));
$deleteQuery->execute();
+
+ return array_map(function (array $row) {
+ return [
+ 'provider_id' => $row['provider_id'],
+ 'uid' => $row['uid'],
+ 'enabled' => 1 === (int) $row['enabled'],
+ ];
+ }, $rows);
}
public function deleteAll(string $providerId) {
diff --git a/lib/private/Authentication/TwoFactorAuth/Manager.php b/lib/private/Authentication/TwoFactorAuth/Manager.php
index 07e61175361..0a60606ad65 100644
--- a/lib/private/Authentication/TwoFactorAuth/Manager.php
+++ b/lib/private/Authentication/TwoFactorAuth/Manager.php
@@ -6,6 +6,7 @@ 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>
*
@@ -27,8 +28,6 @@ declare(strict_types=1);
namespace OC\Authentication\TwoFactorAuth;
-use function array_diff;
-use function array_filter;
use BadMethodCallException;
use Exception;
use OC\Authentication\Exceptions\InvalidTokenException;
@@ -39,11 +38,13 @@ use OCP\Authentication\TwoFactorAuth\IActivatableAtLogin;
use OCP\Authentication\TwoFactorAuth\IProvider;
use OCP\Authentication\TwoFactorAuth\IRegistry;
use OCP\IConfig;
-use OCP\ILogger;
use OCP\ISession;
use OCP\IUser;
+use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
+use function array_diff;
+use function array_filter;
class Manager {
public const SESSION_UID_KEY = 'two_factor_auth_uid';
@@ -69,7 +70,7 @@ class Manager {
/** @var IManager */
private $activityManager;
- /** @var ILogger */
+ /** @var LoggerInterface */
private $logger;
/** @var TokenProvider */
@@ -84,9 +85,13 @@ class Manager {
public function __construct(ProviderLoader $providerLoader,
IRegistry $providerRegistry,
MandatoryTwoFactor $mandatoryTwoFactor,
- ISession $session, IConfig $config,
- IManager $activityManager, ILogger $logger, TokenProvider $tokenProvider,
- ITimeFactory $timeFactory, EventDispatcherInterface $eventDispatcher) {
+ ISession $session,
+ IConfig $config,
+ IManager $activityManager,
+ LoggerInterface $logger,
+ TokenProvider $tokenProvider,
+ ITimeFactory $timeFactory,
+ EventDispatcherInterface $eventDispatcher) {
$this->providerLoader = $providerLoader;
$this->providerRegistry = $providerRegistry;
$this->mandatoryTwoFactor = $mandatoryTwoFactor;
@@ -295,8 +300,7 @@ class Manager {
try {
$this->activityManager->publish($activity);
} catch (BadMethodCallException $e) {
- $this->logger->warning('could not publish activity', ['app' => 'core']);
- $this->logger->logException($e, ['app' => 'core']);
+ $this->logger->warning('could not publish activity', ['app' => 'core', 'exception' => $e]);
}
}
diff --git a/lib/private/Authentication/TwoFactorAuth/Registry.php b/lib/private/Authentication/TwoFactorAuth/Registry.php
index 97df2bd5311..2af8566d3e5 100644
--- a/lib/private/Authentication/TwoFactorAuth/Registry.php
+++ b/lib/private/Authentication/TwoFactorAuth/Registry.php
@@ -31,6 +31,7 @@ use OC\Authentication\TwoFactorAuth\Db\ProviderUserAssignmentDao;
use OCP\Authentication\TwoFactorAuth\IProvider;
use OCP\Authentication\TwoFactorAuth\IRegistry;
use OCP\Authentication\TwoFactorAuth\RegistryEvent;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderDisabled;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IUser;
@@ -66,11 +67,11 @@ class Registry implements IRegistry {
$this->dispatcher->dispatch(self::EVENT_PROVIDER_DISABLED, $event);
}
- /**
- * @todo evaluate if we should emit RegistryEvents for each of the deleted rows -> needs documentation
- */
public function deleteUserData(IUser $user): void {
- $this->assignmentDao->deleteByUser($user->getUID());
+ foreach ($this->assignmentDao->deleteByUser($user->getUID()) as $provider) {
+ $event = new TwoFactorProviderDisabled($provider['provider_id']);
+ $this->dispatcher->dispatchTyped($event);
+ }
}
public function cleanUp(string $providerId) {
diff --git a/lib/private/Authentication/WebAuthn/Db/PublicKeyCredentialMapper.php b/lib/private/Authentication/WebAuthn/Db/PublicKeyCredentialMapper.php
index 9c436b38b5d..d08cb71d72f 100644
--- a/lib/private/Authentication/WebAuthn/Db/PublicKeyCredentialMapper.php
+++ b/lib/private/Authentication/WebAuthn/Db/PublicKeyCredentialMapper.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
/**
* @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
*
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
@@ -30,6 +31,9 @@ use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\QBMapper;
use OCP\IDBConnection;
+/**
+ * @template-extends QBMapper<PublicKeyCredentialEntity>
+ */
class PublicKeyCredentialMapper extends QBMapper {
public function __construct(IDBConnection $db) {
parent::__construct($db, 'webauthn', PublicKeyCredentialEntity::class);
diff --git a/lib/private/Authentication/WebAuthn/Manager.php b/lib/private/Authentication/WebAuthn/Manager.php
index 4415badc9b0..9ef3a0718ca 100644
--- a/lib/private/Authentication/WebAuthn/Manager.php
+++ b/lib/private/Authentication/WebAuthn/Manager.php
@@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
@@ -35,8 +36,8 @@ use OC\Authentication\WebAuthn\Db\PublicKeyCredentialEntity;
use OC\Authentication\WebAuthn\Db\PublicKeyCredentialMapper;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\IConfig;
-use OCP\ILogger;
use OCP\IUser;
+use Psr\Log\LoggerInterface;
use Webauthn\AttestationStatement\AttestationObjectLoader;
use Webauthn\AttestationStatement\AttestationStatementSupportManager;
use Webauthn\AttestationStatement\NoneAttestationStatementSupport;
@@ -63,7 +64,7 @@ class Manager {
/** @var PublicKeyCredentialMapper */
private $credentialMapper;
- /** @var ILogger */
+ /** @var LoggerInterface */
private $logger;
/** @var IConfig */
@@ -72,7 +73,7 @@ class Manager {
public function __construct(
CredentialRepository $repository,
PublicKeyCredentialMapper $credentialMapper,
- ILogger $logger,
+ LoggerInterface $logger,
IConfig $config
) {
$this->repository = $repository;
diff --git a/lib/private/BackgroundJob/Job.php b/lib/private/BackgroundJob/Job.php
index a464ea2ba1f..312ec628e0b 100644
--- a/lib/private/BackgroundJob/Job.php
+++ b/lib/private/BackgroundJob/Job.php
@@ -3,7 +3,6 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Daniel Kesselberg <mail@danielkesselberg.de>
- * @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Noveen Sachdeva <noveen.sachdeva@research.iiit.ac.in>
* @author Robin Appelman <robin@icewind.nl>
diff --git a/lib/private/BackgroundJob/JobList.php b/lib/private/BackgroundJob/JobList.php
index 1adecb5b32d..5a89dcdeba6 100644
--- a/lib/private/BackgroundJob/JobList.php
+++ b/lib/private/BackgroundJob/JobList.php
@@ -6,7 +6,6 @@
* @author Georg Ehrke <oc.list@georgehrke.com>
* @author Joas Schilling <coding@schilljs.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
- * @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Noveen Sachdeva <noveen.sachdeva@research.iiit.ac.in>
* @author Robin Appelman <robin@icewind.nl>
@@ -180,7 +179,6 @@ class JobList implements IJobList {
* get the next job in the list
*
* @return IJob|null
- * @suppress SqlInjectionChecker
*/
public function getNext() {
$query = $this->connection->getQueryBuilder();
@@ -300,7 +298,6 @@ class JobList implements IJobList {
* Remove the reservation for a job
*
* @param IJob $job
- * @suppress SqlInjectionChecker
*/
public function unlockJob(IJob $job) {
$query = $this->connection->getQueryBuilder();
@@ -311,18 +308,6 @@ class JobList implements IJobList {
}
/**
- * get the id of the last ran job
- *
- * @return int
- * @deprecated 9.1.0 - The functionality behind the value is deprecated, it
- * only tells you which job finished last, but since we now allow multiple
- * executors to run in parallel, it's not used to calculate the next job.
- */
- public function getLastJob() {
- return (int) $this->config->getAppValue('backgroundjob', 'lastjob', 0);
- }
-
- /**
* set the lastRun of $job to now
*
* @param IJob $job
diff --git a/lib/private/BackgroundJob/TimedJob.php b/lib/private/BackgroundJob/TimedJob.php
index d33cdd90b37..c0ce130c6cf 100644
--- a/lib/private/BackgroundJob/TimedJob.php
+++ b/lib/private/BackgroundJob/TimedJob.php
@@ -3,6 +3,7 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
diff --git a/lib/private/Cache/File.php b/lib/private/Cache/File.php
index be6540ff2d2..04ec33f7615 100644
--- a/lib/private/Cache/File.php
+++ b/lib/private/Cache/File.php
@@ -10,7 +10,7 @@
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Sebastian Wessalowski <sebastian@wessalowski.org>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Calendar/Manager.php b/lib/private/Calendar/Manager.php
index ab8af870221..f8401259eb4 100644
--- a/lib/private/Calendar/Manager.php
+++ b/lib/private/Calendar/Manager.php
@@ -31,12 +31,12 @@ class Manager implements \OCP\Calendar\IManager {
/**
* @var ICalendar[] holds all registered calendars
*/
- private $calendars=[];
+ private $calendars = [];
/**
* @var \Closure[] to call to load/register calendar providers
*/
- private $calendarLoaders=[];
+ private $calendarLoaders = [];
/**
* This function is used to search and find objects within the user's calendars.
@@ -51,7 +51,7 @@ class Manager implements \OCP\Calendar\IManager {
* @return array an array of events/journals/todos which are arrays of arrays of key-value-pairs
* @since 13.0.0
*/
- public function search($pattern, array $searchProperties=[], array $options=[], $limit=null, $offset=null) {
+ public function search($pattern, array $searchProperties = [], array $options = [], $limit = null, $offset = null) {
$this->loadCalendars();
$result = [];
foreach ($this->calendars as $calendar) {
diff --git a/lib/private/Collaboration/AutoComplete/Manager.php b/lib/private/Collaboration/AutoComplete/Manager.php
index dc3b76f1f4d..d03de3a9fd3 100644
--- a/lib/private/Collaboration/AutoComplete/Manager.php
+++ b/lib/private/Collaboration/AutoComplete/Manager.php
@@ -30,7 +30,7 @@ use OCP\IServerContainer;
class Manager implements IManager {
/** @var string[] */
- protected $sorters =[];
+ protected $sorters = [];
/** @var ISorter[] */
protected $sorterInstances = [];
diff --git a/lib/private/Collaboration/Collaborators/GroupPlugin.php b/lib/private/Collaboration/Collaborators/GroupPlugin.php
index d4051cab36f..18a6631ed80 100644
--- a/lib/private/Collaboration/Collaborators/GroupPlugin.php
+++ b/lib/private/Collaboration/Collaborators/GroupPlugin.php
@@ -4,6 +4,7 @@
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Julius Härtl <jus@bitgrid.net>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
@@ -70,7 +71,7 @@ class GroupPlugin implements ISearchPlugin {
$hasMoreResults = true;
}
- $userGroups = [];
+ $userGroups = [];
if (!empty($groups) && ($this->shareWithGroupOnly || $this->shareeEnumerationInGroupOnly)) {
// Intersect all the groups that match with the groups this user is a member of
$userGroups = $this->groupManager->getUserGroups($this->userSession->getUser());
diff --git a/lib/private/Collaboration/Collaborators/LookupPlugin.php b/lib/private/Collaboration/Collaborators/LookupPlugin.php
index ab36d712d2a..974254e9a3f 100644
--- a/lib/private/Collaboration/Collaborators/LookupPlugin.php
+++ b/lib/private/Collaboration/Collaborators/LookupPlugin.php
@@ -5,6 +5,7 @@
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Bjoern Schiessle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
diff --git a/lib/private/Collaboration/Collaborators/MailPlugin.php b/lib/private/Collaboration/Collaborators/MailPlugin.php
index 90dc5919176..7bdd29afc4e 100644
--- a/lib/private/Collaboration/Collaborators/MailPlugin.php
+++ b/lib/private/Collaboration/Collaborators/MailPlugin.php
@@ -136,6 +136,8 @@ class MailPlugin implements ISearchPlugin {
'shareType' => IShare::TYPE_USER,
'shareWith' => $cloud->getUser(),
],
+ 'shareWithDisplayNameUnique' => !empty($emailAddress) ? $emailAddress : $cloud->getUser()
+
]];
$searchResult->addResultSet($userType, [], $singleResult);
$searchResult->markExactIdMatch($emailType);
@@ -170,6 +172,7 @@ class MailPlugin implements ISearchPlugin {
'shareType' => IShare::TYPE_USER,
'shareWith' => $cloud->getUser(),
],
+ 'shareWithDisplayNameUnique' => !empty($emailAddress) ? $emailAddress : $cloud->getUser()
];
continue;
}
diff --git a/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php b/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php
index 17e7793a685..62e0a43b41e 100644
--- a/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php
+++ b/lib/private/Collaboration/Collaborators/RemoteGroupPlugin.php
@@ -3,6 +3,7 @@
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Bjoern Schiessle <bjoern@schiessle.org>
+ * @author Joas Schilling <coding@schilljs.com>
* @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
diff --git a/lib/private/Collaboration/Collaborators/RemotePlugin.php b/lib/private/Collaboration/Collaborators/RemotePlugin.php
index af94027fbe9..3d9b1f9847a 100644
--- a/lib/private/Collaboration/Collaborators/RemotePlugin.php
+++ b/lib/private/Collaboration/Collaborators/RemotePlugin.php
@@ -103,7 +103,8 @@ class RemotePlugin implements ISearchPlugin {
'value' => [
'shareType' => IShare::TYPE_USER,
'shareWith' => $remoteUser
- ]
+ ],
+ 'shareWithDisplayNameUnique' => $contact['EMAIL'] !== null && $contact['EMAIL'] !== '' ? $contact['EMAIL'] : $contact['UID'],
];
}
diff --git a/lib/private/Collaboration/Collaborators/Search.php b/lib/private/Collaboration/Collaborators/Search.php
index 8594e87e4a9..7b5789640a0 100644
--- a/lib/private/Collaboration/Collaborators/Search.php
+++ b/lib/private/Collaboration/Collaborators/Search.php
@@ -4,6 +4,8 @@
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
+ * @author onehappycat <one.happy.cat@gmx.com>
* @author Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
@@ -67,14 +69,14 @@ class Search implements ISearch {
foreach ($this->pluginList[$type] as $plugin) {
/** @var ISearchPlugin $searchPlugin */
$searchPlugin = $this->c->resolve($plugin);
- $hasMoreResults |= $searchPlugin->search($search, $limit, $offset, $searchResult);
+ $hasMoreResults = $searchPlugin->search($search, $limit, $offset, $searchResult) || $hasMoreResults;
}
}
// Get from lookup server, not a separate share type
if ($lookup) {
$searchPlugin = $this->c->resolve(LookupPlugin::class);
- $hasMoreResults |= $searchPlugin->search($search, $limit, $offset, $searchResult);
+ $hasMoreResults = $searchPlugin->search($search, $limit, $offset, $searchResult) || $hasMoreResults;
}
// sanitizing, could go into the plugins as well
@@ -90,9 +92,10 @@ class Search implements ISearch {
$searchResult->unsetResult($emailType);
}
- // if we have an exact local user match, there is no need to show the remote and email matches
+ // if we have an exact local user match with an email-a-like query,
+ // there is no need to show the remote and email matches.
$userType = new SearchResultType('users');
- if ($searchResult->hasExactIdMatch($userType)) {
+ if (strpos($search, '@') !== false && $searchResult->hasExactIdMatch($userType)) {
$searchResult->unsetResult($remoteType);
$searchResult->unsetResult($emailType);
}
diff --git a/lib/private/Collaboration/Collaborators/UserPlugin.php b/lib/private/Collaboration/Collaborators/UserPlugin.php
index d1f29350734..d832a42000c 100644
--- a/lib/private/Collaboration/Collaborators/UserPlugin.php
+++ b/lib/private/Collaboration/Collaborators/UserPlugin.php
@@ -4,10 +4,13 @@
*
* @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) <skjnldsv@protonmail.com>
* @author Julius Härtl <jus@bitgrid.net>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Citharel <nextcloud@tcit.fr>
*
* @license GNU AGPL version 3 or any later version
@@ -38,6 +41,7 @@ use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Share\IShare;
+use OCP\UserStatus\IManager as IUserStatusManager;
class UserPlugin implements ISearchPlugin {
/* @var bool */
@@ -53,13 +57,29 @@ class UserPlugin implements ISearchPlugin {
private $userSession;
/** @var IUserManager */
private $userManager;
+ /** @var IUserStatusManager */
+ private $userStatusManager;
- public function __construct(IConfig $config, IUserManager $userManager, IGroupManager $groupManager, IUserSession $userSession) {
+ /**
+ * UserPlugin constructor.
+ *
+ * @param IConfig $config
+ * @param IUserManager $userManager
+ * @param IGroupManager $groupManager
+ * @param IUserSession $userSession
+ * @param IUserStatusManager $userStatusManager
+ */
+ public function __construct(IConfig $config,
+ IUserManager $userManager,
+ IGroupManager $groupManager,
+ IUserSession $userSession,
+ IUserStatusManager $userStatusManager) {
$this->config = $config;
$this->groupManager = $groupManager;
$this->userSession = $userSession;
$this->userManager = $userManager;
+ $this->userStatusManager = $userStatusManager;
$this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
@@ -78,7 +98,15 @@ class UserPlugin implements ISearchPlugin {
$usersInGroup = $this->groupManager->displayNamesInGroup($userGroupId, $search, $limit, $offset);
foreach ($usersInGroup as $userId => $displayName) {
$userId = (string) $userId;
- $users[$userId] = $this->userManager->get($userId);
+ $user = $this->userManager->get($userId);
+ if (!$user->isEnabled()) {
+ // Ignore disabled users
+ continue;
+ }
+ $users[$userId] = $user;
+ }
+ if (count($usersInGroup) >= $limit) {
+ $hasMoreResults = true;
}
}
} else {
@@ -99,24 +127,44 @@ class UserPlugin implements ISearchPlugin {
$foundUserById = false;
$lowerSearch = strtolower($search);
+ $userStatuses = $this->userStatusManager->getUserStatuses(array_keys($users));
foreach ($users as $uid => $user) {
$userDisplayName = $user->getDisplayName();
$userEmail = $user->getEMailAddress();
$uid = (string) $uid;
+
+ $status = [];
+ if (array_key_exists($uid, $userStatuses)) {
+ $userStatus = $userStatuses[$uid];
+ $status = [
+ 'status' => $userStatus->getStatus(),
+ 'message' => $userStatus->getMessage(),
+ 'icon' => $userStatus->getIcon(),
+ 'clearAt' => $userStatus->getClearAt()
+ ? (int)$userStatus->getClearAt()->format('U')
+ : null,
+ ];
+ }
+
+
if (
- strtolower($uid) === $lowerSearch ||
+ $lowerSearch !== '' && (strtolower($uid) === $lowerSearch ||
strtolower($userDisplayName) === $lowerSearch ||
- strtolower($userEmail) === $lowerSearch
+ strtolower($userEmail) === $lowerSearch)
) {
if (strtolower($uid) === $lowerSearch) {
$foundUserById = true;
}
$result['exact'][] = [
'label' => $userDisplayName,
+ 'subline' => $status['message'] ?? '',
+ 'icon' => 'icon-user',
'value' => [
'shareType' => IShare::TYPE_USER,
'shareWith' => $uid,
],
+ 'shareWithDisplayNameUnique' => !empty($userEmail) ? $userEmail : $uid,
+ 'status' => $status,
];
} else {
$addToWideResults = false;
@@ -134,10 +182,14 @@ class UserPlugin implements ISearchPlugin {
if ($addToWideResults) {
$result['wide'][] = [
'label' => $userDisplayName,
+ 'subline' => $status['message'] ?? '',
+ 'icon' => 'icon-user',
'value' => [
'shareType' => IShare::TYPE_USER,
'shareWith' => $uid,
],
+ 'shareWithDisplayNameUnique' => !empty($userEmail) ? $userEmail : $uid,
+ 'status' => $status,
];
}
}
@@ -157,12 +209,31 @@ class UserPlugin implements ISearchPlugin {
}
if ($addUser) {
+ $status = [];
+ $uid = $user->getUID();
+ $userEmail = $user->getEMailAddress();
+ if (array_key_exists($user->getUID(), $userStatuses)) {
+ $userStatus = $userStatuses[$user->getUID()];
+ $status = [
+ 'status' => $userStatus->getStatus(),
+ 'message' => $userStatus->getMessage(),
+ 'icon' => $userStatus->getIcon(),
+ 'clearAt' => $userStatus->getClearAt()
+ ? (int)$userStatus->getClearAt()->format('U')
+ : null,
+ ];
+ }
+
$result['exact'][] = [
'label' => $user->getDisplayName(),
+ 'icon' => 'icon-user',
+ 'subline' => $status['message'] ?? '',
'value' => [
'shareType' => IShare::TYPE_USER,
'shareWith' => $user->getUID(),
],
+ 'shareWithDisplayNameUnique' => $userEmail !== null && $userEmail !== '' ? $userEmail : $uid,
+ 'status' => $status,
];
}
}
diff --git a/lib/private/Command/ClosureJob.php b/lib/private/Command/ClosureJob.php
index d67dad348a3..c92fd304f91 100644
--- a/lib/private/Command/ClosureJob.php
+++ b/lib/private/Command/ClosureJob.php
@@ -3,6 +3,7 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Robin Appelman <robin@icewind.nl>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license AGPL-3.0
*
@@ -23,12 +24,10 @@
namespace OC\Command;
use OC\BackgroundJob\QueuedJob;
-use SuperClosure\Serializer;
class ClosureJob extends QueuedJob {
protected function run($serializedCallable) {
- $serializer = new Serializer();
- $callable = $serializer->unserialize($serializedCallable);
+ $callable = \Opis\Closure\unserialize($serializedCallable);
if (is_callable($callable)) {
$callable();
} else {
diff --git a/lib/private/Command/CommandJob.php b/lib/private/Command/CommandJob.php
index 7b2ae60beab..ed251b841ed 100644
--- a/lib/private/Command/CommandJob.php
+++ b/lib/private/Command/CommandJob.php
@@ -3,6 +3,7 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Robin Appelman <robin@icewind.nl>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license AGPL-3.0
*
@@ -30,7 +31,7 @@ use OCP\Command\ICommand;
*/
class CommandJob extends QueuedJob {
protected function run($serializedCommand) {
- $command = unserialize($serializedCommand);
+ $command = \Opis\Closure\unserialize($serializedCommand);
if ($command instanceof ICommand) {
$command->handle();
} else {
diff --git a/lib/private/Command/CronBus.php b/lib/private/Command/CronBus.php
index 5bb8e4b0045..86aa239bdde 100644
--- a/lib/private/Command/CronBus.php
+++ b/lib/private/Command/CronBus.php
@@ -5,6 +5,7 @@
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
*
@@ -26,7 +27,6 @@
namespace OC\Command;
use OCP\Command\ICommand;
-use SuperClosure\Serializer;
class CronBus extends AsyncBus {
/**
@@ -68,10 +68,9 @@ class CronBus extends AsyncBus {
*/
private function serializeCommand($command) {
if ($command instanceof \Closure) {
- $serializer = new Serializer();
- return $serializer->serialize($command);
+ return \Opis\Closure\serialize($command);
} elseif (is_callable($command) or $command instanceof ICommand) {
- return serialize($command);
+ return \Opis\Closure\serialize($command);
} else {
throw new \InvalidArgumentException('Invalid command');
}
diff --git a/lib/private/Comments/Comment.php b/lib/private/Comments/Comment.php
index 7c553c25a1c..7368425174a 100644
--- a/lib/private/Comments/Comment.php
+++ b/lib/private/Comments/Comment.php
@@ -32,19 +32,19 @@ use OCP\Comments\MessageTooLongException;
class Comment implements IComment {
protected $data = [
- 'id' => '',
- 'parentId' => '0',
+ 'id' => '',
+ 'parentId' => '0',
'topmostParentId' => '0',
- 'childrenCount' => '0',
- 'message' => '',
- 'verb' => '',
- 'actorType' => '',
- 'actorId' => '',
- 'objectType' => '',
- 'objectId' => '',
- 'referenceId' => null,
- 'creationDT' => null,
- 'latestChildDT' => null,
+ 'childrenCount' => '0',
+ 'message' => '',
+ 'verb' => '',
+ 'actorType' => '',
+ 'actorId' => '',
+ 'objectType' => '',
+ 'objectId' => '',
+ 'referenceId' => null,
+ 'creationDT' => null,
+ 'latestChildDT' => null,
];
/**
@@ -301,12 +301,12 @@ class Comment implements IComment {
public function setActor($actorType, $actorId) {
if (
!is_string($actorType) || !trim($actorType)
- || !is_string($actorId) || $actorId === ''
+ || !is_string($actorId) || $actorId === ''
) {
throw new \InvalidArgumentException('String expected.');
}
$this->data['actorType'] = trim($actorType);
- $this->data['actorId'] = $actorId;
+ $this->data['actorId'] = $actorId;
return $this;
}
@@ -387,12 +387,12 @@ class Comment implements IComment {
public function setObject($objectType, $objectId) {
if (
!is_string($objectType) || !trim($objectType)
- || !is_string($objectId) || trim($objectId) === ''
+ || !is_string($objectId) || trim($objectId) === ''
) {
throw new \InvalidArgumentException('String expected.');
}
$this->data['objectType'] = trim($objectType);
- $this->data['objectId'] = trim($objectId);
+ $this->data['objectId'] = trim($objectId);
return $this;
}
diff --git a/lib/private/Comments/Manager.php b/lib/private/Comments/Manager.php
index a0a670817f4..1cc82b5c2ce 100644
--- a/lib/private/Comments/Manager.php
+++ b/lib/private/Comments/Manager.php
@@ -4,7 +4,7 @@
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
+ * @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -30,6 +30,8 @@ namespace OC\Comments;
use Doctrine\DBAL\Exception\DriverException;
use Doctrine\DBAL\Exception\InvalidFieldNameException;
+use OCA\Comments\AppInfo\Application;
+use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Comments\CommentsEvent;
use OCP\Comments\IComment;
use OCP\Comments\ICommentsEventHandler;
@@ -38,20 +40,28 @@ use OCP\Comments\NotFoundException;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IConfig;
use OCP\IDBConnection;
-use OCP\ILogger;
use OCP\IUser;
+use OCP\IInitialStateService;
+use OCP\Util;
+use Psr\Log\LoggerInterface;
class Manager implements ICommentsManager {
/** @var IDBConnection */
protected $dbConn;
- /** @var ILogger */
+ /** @var LoggerInterface */
protected $logger;
/** @var IConfig */
protected $config;
+ /** @var ITimeFactory */
+ protected $timeFactory;
+
+ /** @var IInitialStateService */
+ protected $initialStateService;
+
/** @var IComment[] */
protected $commentsCache = [];
@@ -64,21 +74,16 @@ class Manager implements ICommentsManager {
/** @var \Closure[] */
protected $displayNameResolvers = [];
- /**
- * Manager constructor.
- *
- * @param IDBConnection $dbConn
- * @param ILogger $logger
- * @param IConfig $config
- */
- public function __construct(
- IDBConnection $dbConn,
- ILogger $logger,
- IConfig $config
- ) {
+ public function __construct(IDBConnection $dbConn,
+ LoggerInterface $logger,
+ IConfig $config,
+ ITimeFactory $timeFactory,
+ IInitialStateService $initialStateService) {
$this->dbConn = $dbConn;
$this->logger = $logger;
$this->config = $config;
+ $this->timeFactory = $timeFactory;
+ $this->initialStateService = $initialStateService;
}
/**
@@ -396,6 +401,7 @@ class Manager implements ICommentsManager {
* @param string $sortDirection direction of the comments (`asc` or `desc`)
* @param int $limit optional, number of maximum comments to be returned. if
* set to 0, all comments are returned.
+ * @param bool $includeLastKnown
* @return IComment[]
* @return array
*/
@@ -404,7 +410,8 @@ class Manager implements ICommentsManager {
string $objectId,
int $lastKnownCommentId,
string $sortDirection = 'asc',
- int $limit = 30
+ int $limit = 30,
+ bool $includeLastKnown = false
): array {
$comments = [];
@@ -428,6 +435,11 @@ class Manager implements ICommentsManager {
if ($lastKnownComment instanceof IComment) {
$lastKnownCommentDateTime = $lastKnownComment->getCreationDateTime();
if ($sortDirection === 'desc') {
+ if ($includeLastKnown) {
+ $idComparison = $query->expr()->lte('id', $query->createNamedParameter($lastKnownCommentId));
+ } else {
+ $idComparison = $query->expr()->lt('id', $query->createNamedParameter($lastKnownCommentId));
+ }
$query->andWhere(
$query->expr()->orX(
$query->expr()->lt(
@@ -441,11 +453,16 @@ class Manager implements ICommentsManager {
$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
IQueryBuilder::PARAM_DATE
),
- $query->expr()->lt('id', $query->createNamedParameter($lastKnownCommentId))
+ $idComparison
)
)
);
} else {
+ if ($includeLastKnown) {
+ $idComparison = $query->expr()->gte('id', $query->createNamedParameter($lastKnownCommentId));
+ } else {
+ $idComparison = $query->expr()->gt('id', $query->createNamedParameter($lastKnownCommentId));
+ }
$query->andWhere(
$query->expr()->orX(
$query->expr()->gt(
@@ -459,7 +476,7 @@ class Manager implements ICommentsManager {
$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
IQueryBuilder::PARAM_DATE
),
- $query->expr()->gt('id', $query->createNamedParameter($lastKnownCommentId))
+ $idComparison
)
)
);
@@ -518,6 +535,25 @@ class Manager implements ICommentsManager {
* @return IComment[]
*/
public function search(string $search, string $objectType, string $objectId, string $verb, int $offset, int $limit = 50): array {
+ $objectIds = [];
+ if ($objectId) {
+ $objectIds[] = $objectIds;
+ }
+ return $this->searchForObjects($search, $objectType, $objectIds, $verb, $offset, $limit);
+ }
+
+ /**
+ * Search for comments on one or more objects with a given content
+ *
+ * @param string $search content to search for
+ * @param string $objectType Limit the search by object type
+ * @param array $objectIds Limit the search by object ids
+ * @param string $verb Limit the verb of the comment
+ * @param int $offset
+ * @param int $limit
+ * @return IComment[]
+ */
+ public function searchForObjects(string $search, string $objectType, array $objectIds, string $verb, int $offset, int $limit = 50): array {
$query = $this->dbConn->getQueryBuilder();
$query->select('*')
@@ -532,8 +568,8 @@ class Manager implements ICommentsManager {
if ($objectType !== '') {
$query->andWhere($query->expr()->eq('object_type', $query->createNamedParameter($objectType)));
}
- if ($objectId !== '') {
- $query->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)));
+ if (!empty($objectIds)) {
+ $query->andWhere($query->expr()->in('object_id', $query->createNamedParameter($objectIds, IQueryBuilder::PARAM_STR_ARRAY)));
}
if ($verb !== '') {
$query->andWhere($query->expr()->eq('verb', $query->createNamedParameter($verb)));
@@ -589,13 +625,145 @@ class Manager implements ICommentsManager {
}
/**
+ * @param string $objectType the object type, e.g. 'files'
+ * @param string[] $objectIds the id of the object
+ * @param IUser $user
+ * @param string $verb Limit the verb of the comment - Added in 14.0.0
+ * @return array Map with object id => # of unread comments
+ * @psalm-return array<string, int>
+ * @since 21.0.0
+ */
+ public function getNumberOfUnreadCommentsForObjects(string $objectType, array $objectIds, IUser $user, $verb = ''): array {
+ $query = $this->dbConn->getQueryBuilder();
+ $query->select('c.object_id', $query->func()->count('c.id', 'num_comments'))
+ ->from('comments', 'c')
+ ->leftJoin('c', 'comments_read_markers', 'm', $query->expr()->andX(
+ $query->expr()->eq('m.user_id', $query->createNamedParameter($user->getUID())),
+ $query->expr()->eq('c.object_type', 'm.object_type'),
+ $query->expr()->eq('c.object_id', 'm.object_id')
+ ))
+ ->where($query->expr()->eq('c.object_type', $query->createNamedParameter($objectType)))
+ ->andWhere($query->expr()->in('c.object_id', $query->createNamedParameter($objectIds, IQueryBuilder::PARAM_STR_ARRAY)))
+ ->andWhere($query->expr()->orX(
+ $query->expr()->gt('c.creation_timestamp', 'm.marker_datetime'),
+ $query->expr()->isNull('m.marker_datetime')
+ ))
+ ->groupBy('c.object_id');
+
+ if ($verb !== '') {
+ $query->andWhere($query->expr()->eq('c.verb', $query->createNamedParameter($verb)));
+ }
+
+ $result = $query->execute();
+ $unreadComments = array_fill_keys($objectIds, 0);
+ while ($row = $result->fetch()) {
+ $unreadComments[$row['object_id']] = (int) $row['num_comments'];
+ }
+ $result->closeCursor();
+
+ return $unreadComments;
+ }
+
+ /**
+ * @param string $objectType
+ * @param string $objectId
+ * @param int $lastRead
+ * @param string $verb
+ * @return int
+ * @since 21.0.0
+ */
+ public function getNumberOfCommentsForObjectSinceComment(string $objectType, string $objectId, int $lastRead, string $verb = ''): int {
+ $query = $this->dbConn->getQueryBuilder();
+ $query->select($query->func()->count('id', 'num_messages'))
+ ->from('comments')
+ ->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
+ ->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
+ ->andWhere($query->expr()->gt('id', $query->createNamedParameter($lastRead)));
+
+ if ($verb !== '') {
+ $query->andWhere($query->expr()->eq('verb', $query->createNamedParameter($verb)));
+ }
+
+ $result = $query->execute();
+ $data = $result->fetch();
+ $result->closeCursor();
+
+ return (int) ($data['num_messages'] ?? 0);
+ }
+
+ /**
+ * @param string $objectType
+ * @param string $objectId
+ * @param \DateTime $beforeDate
+ * @param string $verb
+ * @return int
+ * @since 21.0.0
+ */
+ public function getLastCommentBeforeDate(string $objectType, string $objectId, \DateTime $beforeDate, string $verb = ''): int {
+ $query = $this->dbConn->getQueryBuilder();
+ $query->select('id')
+ ->from('comments')
+ ->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
+ ->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
+ ->andWhere($query->expr()->lt('creation_timestamp', $query->createNamedParameter($beforeDate, IQueryBuilder::PARAM_DATE)))
+ ->orderBy('creation_timestamp', 'desc');
+
+ if ($verb !== '') {
+ $query->andWhere($query->expr()->eq('verb', $query->createNamedParameter($verb)));
+ }
+
+ $result = $query->execute();
+ $data = $result->fetch();
+ $result->closeCursor();
+
+ return (int) ($data['id'] ?? 0);
+ }
+
+ /**
+ * @param string $objectType
+ * @param string $objectId
+ * @param string $verb
+ * @param string $actorType
+ * @param string[] $actors
+ * @return \DateTime[] Map of "string actor" => "\DateTime most recent comment date"
+ * @psalm-return array<string, \DateTime>
+ * @since 21.0.0
+ */
+ public function getLastCommentDateByActor(
+ string $objectType,
+ string $objectId,
+ string $verb,
+ string $actorType,
+ array $actors
+ ): array {
+ $lastComments = [];
+
+ $query = $this->dbConn->getQueryBuilder();
+ $query->select('actor_id')
+ ->selectAlias($query->createFunction('MAX(' . $query->getColumnName('creation_timestamp') . ')'), 'last_comment')
+ ->from('comments')
+ ->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
+ ->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
+ ->andWhere($query->expr()->eq('verb', $query->createNamedParameter($verb)))
+ ->andWhere($query->expr()->eq('actor_type', $query->createNamedParameter($actorType)))
+ ->andWhere($query->expr()->in('actor_id', $query->createNamedParameter($actors, IQueryBuilder::PARAM_STR_ARRAY)))
+ ->groupBy('actor_id');
+
+ $result = $query->execute();
+ while ($row = $result->fetch()) {
+ $lastComments[$row['actor_id']] = $this->timeFactory->getDateTime($row['last_comment']);
+ }
+ $result->closeCursor();
+
+ return $lastComments;
+ }
+
+ /**
* Get the number of unread comments for all files in a folder
*
* @param int $folderId
* @param IUser $user
* @return array [$fileId => $unreadCount]
- *
- * @suppress SqlInjectionChecker
*/
public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user) {
$qb = $this->dbConn->getQueryBuilder();
@@ -695,7 +863,10 @@ class Manager implements ICommentsManager {
$affectedRows = $query->execute();
$this->uncache($id);
} catch (DriverException $e) {
- $this->logger->logException($e, ['app' => 'core_comments']);
+ $this->logger->error($e->getMessage(), [
+ 'exception' => $e,
+ 'app' => 'core_comments',
+ ]);
return false;
}
@@ -920,7 +1091,10 @@ class Manager implements ICommentsManager {
try {
$affectedRows = $query->execute();
} catch (DriverException $e) {
- $this->logger->logException($e, ['app' => 'core_comments']);
+ $this->logger->error($e->getMessage(), [
+ 'exception' => $e,
+ 'app' => 'core_comments',
+ ]);
return false;
}
return ($affectedRows > 0);
@@ -935,7 +1109,6 @@ class Manager implements ICommentsManager {
* @param \DateTime $dateTime
* @param IUser $user
* @since 9.0.0
- * @suppress SqlInjectionChecker
*/
public function setReadMark($objectType, $objectId, \DateTime $dateTime, IUser $user) {
$this->checkRoleParameters('Object', $objectType, $objectId);
@@ -1025,7 +1198,10 @@ class Manager implements ICommentsManager {
try {
$affectedRows = $query->execute();
} catch (DriverException $e) {
- $this->logger->logException($e, ['app' => 'core_comments']);
+ $this->logger->error($e->getMessage(), [
+ 'exception' => $e,
+ 'app' => 'core_comments',
+ ]);
return false;
}
return ($affectedRows > 0);
@@ -1121,4 +1297,14 @@ class Manager implements ICommentsManager {
$entity->handle($event);
}
}
+
+ /**
+ * Load the Comments app into the page
+ *
+ * @since 21.0.0
+ */
+ public function load(): void {
+ $this->initialStateService->provideInitialState(Application::APP_ID, 'max-message-length', IComment::MAX_MESSAGE_LENGTH);
+ Util::addScript(Application::APP_ID, 'comments-app');
+ }
}
diff --git a/lib/private/Comments/ManagerFactory.php b/lib/private/Comments/ManagerFactory.php
index dd69a4f9261..ec2cb1e69a1 100644
--- a/lib/private/Comments/ManagerFactory.php
+++ b/lib/private/Comments/ManagerFactory.php
@@ -3,9 +3,10 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -54,10 +55,6 @@ class ManagerFactory implements ICommentsManagerFactory {
* @since 9.0.0
*/
public function getManager() {
- return new Manager(
- $this->serverContainer->getDatabaseConnection(),
- $this->serverContainer->getLogger(),
- $this->serverContainer->getConfig()
- );
+ return $this->serverContainer->get(Manager::class);
}
}
diff --git a/lib/private/Config.php b/lib/private/Config.php
index cbdbc5b2e64..a6c4acb7d96 100644
--- a/lib/private/Config.php
+++ b/lib/private/Config.php
@@ -19,6 +19,7 @@
* @author Philipp Schaffrath <github@philipp.schaffrath.email>
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license AGPL-3.0
*
@@ -47,6 +48,8 @@ class Config {
/** @var array Associative array ($key => $value) */
protected $cache = [];
+ /** @var array */
+ protected $envCache = [];
/** @var string */
protected $configDir;
/** @var string */
@@ -88,9 +91,9 @@ class Config {
* @return mixed the value or $default
*/
public function getValue($key, $default = null) {
- $envValue = getenv(self::ENV_PREFIX . $key);
- if ($envValue !== false) {
- return $envValue;
+ $envKey = self::ENV_PREFIX . $key;
+ if (isset($this->envCache[$envKey])) {
+ return $this->envCache[$envKey];
}
if (isset($this->cache[$key])) {
@@ -222,6 +225,8 @@ class Config {
flock($filePointer, LOCK_UN);
fclose($filePointer);
}
+
+ $this->envCache = getenv();
}
/**
diff --git a/lib/private/Contacts/ContactsMenu/ContactsStore.php b/lib/private/Contacts/ContactsMenu/ContactsStore.php
index b0bd99b844e..e2bd7edc63d 100644
--- a/lib/private/Contacts/ContactsMenu/ContactsStore.php
+++ b/lib/private/Contacts/ContactsMenu/ContactsStore.php
@@ -3,6 +3,7 @@
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
* @copyright 2017 Lukas Reschke <lukas@statuscode.ch>
*
+ * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Calviño Sánchez <danxuliu@gmail.com>
* @author Georg Ehrke <oc.list@georgehrke.com>
@@ -73,11 +74,23 @@ class ContactsStore implements IContactsStore {
* @param string|null $filter
* @return IEntry[]
*/
- public function getContacts(IUser $user, $filter) {
- $allContacts = $this->contactsManager->search($filter ?: '', [
- 'FN',
- 'EMAIL'
- ]);
+ public function getContacts(IUser $user, $filter, ?int $limit = null, ?int $offset = null) {
+ $options = [];
+ if ($limit !== null) {
+ $options['limit'] = $limit;
+ }
+ if ($offset !== null) {
+ $options['offset'] = $offset;
+ }
+
+ $allContacts = $this->contactsManager->search(
+ $filter ?: '',
+ [
+ 'FN',
+ 'EMAIL'
+ ],
+ $options
+ );
$entries = array_map(function (array $contact) {
return $this->contactArrayToEntry($contact);
@@ -122,7 +135,7 @@ class ContactsStore implements IContactsStore {
if ($excludedGroups) {
$excludedGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
$decodedExcludeGroups = json_decode($excludedGroups, true);
- $excludeGroupsList = ($decodedExcludeGroups !== null) ? $decodedExcludeGroups : [];
+ $excludeGroupsList = ($decodedExcludeGroups !== null) ? $decodedExcludeGroups : [];
if (count(array_intersect($excludeGroupsList, $selfGroups)) !== 0) {
// a group of the current user is excluded -> filter all local users
diff --git a/lib/private/Contacts/ContactsMenu/Manager.php b/lib/private/Contacts/ContactsMenu/Manager.php
index 293f1366b05..d08db5775e5 100644
--- a/lib/private/Contacts/ContactsMenu/Manager.php
+++ b/lib/private/Contacts/ContactsMenu/Manager.php
@@ -2,6 +2,7 @@
/**
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
*
+ * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Georg Ehrke <oc.list@georgehrke.com>
* @author Julius Härtl <jus@bitgrid.net>
@@ -26,6 +27,7 @@
namespace OC\Contacts\ContactsMenu;
use OCP\App\IAppManager;
+use OCP\Constants;
use OCP\Contacts\ContactsMenu\IEntry;
use OCP\IConfig;
use OCP\IUser;
@@ -62,11 +64,11 @@ class Manager {
* @return array
*/
public function getEntries(IUser $user, $filter) {
- $maxAutocompleteResults = $this->config->getSystemValueInt('sharing.maxAutocompleteResults', 25);
+ $maxAutocompleteResults = max(0, $this->config->getSystemValueInt('sharing.maxAutocompleteResults', Constants::SHARING_MAX_AUTOCOMPLETE_RESULTS_DEFAULT));
$minSearchStringLength = $this->config->getSystemValueInt('sharing.minSearchStringLength', 0);
$topEntries = [];
if (strlen($filter) >= $minSearchStringLength) {
- $entries = $this->store->getContacts($user, $filter);
+ $entries = $this->store->getContacts($user, $filter, $maxAutocompleteResults);
$sortedEntries = $this->sortEntries($entries);
$topEntries = array_slice($sortedEntries, 0, $maxAutocompleteResults);
diff --git a/lib/private/ContactsManager.php b/lib/private/ContactsManager.php
index 999b6597978..4cdc3d48fff 100644
--- a/lib/private/ContactsManager.php
+++ b/lib/private/ContactsManager.php
@@ -2,14 +2,10 @@
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
- * @author Arne Hamann <kontakt+github@arne.email>
* @author Bart Visscher <bartv@thisnet.nl>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
* @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
- * @author Julius Härtl <jus@bitgrid.net>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tobia De Koninck <tobia@ledfan.be>
*
@@ -69,11 +65,11 @@ class ContactsManager implements IManager {
* This function can be used to delete the contact identified by the given id
*
* @param object $id the unique identifier to a contact
- * @param string $addressBookKey identifier of the address book in which the contact shall be deleted
+ * @param string $address_book_key identifier of the address book in which the contact shall be deleted
* @return bool successful or not
*/
- public function delete($id, $addressBookKey) {
- $addressBook = $this->getAddressBook($addressBookKey);
+ public function delete($id, $address_book_key) {
+ $addressBook = $this->getAddressBook($address_book_key);
if (!$addressBook) {
return null;
}
@@ -90,11 +86,11 @@ class ContactsManager implements IManager {
* Otherwise the contact will be updated by replacing the entire data set.
*
* @param array $properties this array if key-value-pairs defines a contact
- * @param string $addressBookKey identifier of the address book in which the contact shall be created or updated
+ * @param string $address_book_key identifier of the address book in which the contact shall be created or updated
* @return array representing the contact just created or updated
*/
- public function createOrUpdate($properties, $addressBookKey) {
- $addressBook = $this->getAddressBook($addressBookKey);
+ public function createOrUpdate($properties, $address_book_key) {
+ $addressBook = $this->getAddressBook($address_book_key);
if (!$addressBook) {
return null;
}
diff --git a/lib/private/DB/Adapter.php b/lib/private/DB/Adapter.php
index f27a90dd690..26fd018dec1 100644
--- a/lib/private/DB/Adapter.php
+++ b/lib/private/DB/Adapter.php
@@ -103,7 +103,7 @@ class Adapter {
}
$query = 'INSERT INTO `' .$table . '` (`'
. implode('`,`', array_keys($input)) . '`) SELECT '
- . str_repeat('?,', count($input)-1).'? ' // Is there a prettier alternative?
+ . str_repeat('?,', count($input) - 1).'? ' // Is there a prettier alternative?
. 'FROM `' . $table . '` WHERE ';
$inserts = array_values($input);
@@ -130,9 +130,6 @@ class Adapter {
}
}
- /**
- * @suppress SqlInjectionChecker
- */
public function insertIgnoreConflict(string $table,array $values) : int {
try {
$builder = $this->conn->getQueryBuilder();
diff --git a/lib/private/DB/AdapterPgSql.php b/lib/private/DB/AdapterPgSql.php
index 7f7f5150780..77f0b6b7722 100644
--- a/lib/private/DB/AdapterPgSql.php
+++ b/lib/private/DB/AdapterPgSql.php
@@ -41,9 +41,6 @@ class AdapterPgSql extends Adapter {
return $statement;
}
- /**
- * @suppress SqlInjectionChecker
- */
public function insertIgnoreConflict(string $table,array $values) : int {
if ($this->isPre9_5CompatMode() === true) {
return parent::insertIgnoreConflict($table, $values);
diff --git a/lib/private/DB/AdapterSqlite.php b/lib/private/DB/AdapterSqlite.php
index 43ec4a90c62..5731ee1721a 100644
--- a/lib/private/DB/AdapterSqlite.php
+++ b/lib/private/DB/AdapterSqlite.php
@@ -71,7 +71,7 @@ class AdapterSqlite extends Adapter {
}
$fieldList = '`' . implode('`,`', array_keys($input)) . '`';
$query = "INSERT INTO `$table` ($fieldList) SELECT "
- . str_repeat('?,', count($input)-1).'? '
+ . str_repeat('?,', count($input) - 1).'? '
. " WHERE NOT EXISTS (SELECT 1 FROM `$table` WHERE ";
$inserts = array_values($input);
diff --git a/lib/private/DB/Connection.php b/lib/private/DB/Connection.php
index 3b24703d434..b024989ac04 100644
--- a/lib/private/DB/Connection.php
+++ b/lib/private/DB/Connection.php
@@ -5,7 +5,7 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
+ * @author Julius Härtl <jus@bitgrid.net>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Ole Ostergaard <ole.c.ostergaard@gmail.com>
* @author Ole Ostergaard <ole.ostergaard@knime.com>
@@ -39,26 +39,37 @@ use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Exception\ConstraintViolationException;
+use Doctrine\DBAL\Exception\NotNullConstraintViolationException;
use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\DBAL\Schema\Schema;
use OC\DB\QueryBuilder\QueryBuilder;
+use OC\SystemConfig;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
+use OCP\ILogger;
use OCP\PreConditionNotMetException;
class Connection extends ReconnectWrapper implements IDBConnection {
- /**
- * @var string $tablePrefix
- */
+ /** @var string */
protected $tablePrefix;
- /**
- * @var \OC\DB\Adapter $adapter
- */
+ /** @var \OC\DB\Adapter $adapter */
protected $adapter;
+ /** @var SystemConfig */
+ private $systemConfig;
+
+ /** @var ILogger */
+ private $logger;
+
protected $lockedTable = null;
+ /** @var int */
+ protected $queriesBuilt = 0;
+
+ /** @var int */
+ protected $queriesExecuted = 0;
+
public function connect() {
try {
return parent::connect();
@@ -68,16 +79,24 @@ class Connection extends ReconnectWrapper implements IDBConnection {
}
}
+ public function getStats(): array {
+ return [
+ 'built' => $this->queriesBuilt,
+ 'executed' => $this->queriesExecuted,
+ ];
+ }
+
/**
* Returns a QueryBuilder for the connection.
*
* @return \OCP\DB\QueryBuilder\IQueryBuilder
*/
public function getQueryBuilder() {
+ $this->queriesBuilt++;
return new QueryBuilder(
$this,
- \OC::$server->getSystemConfig(),
- \OC::$server->getLogger()
+ $this->systemConfig,
+ $this->logger
);
}
@@ -90,6 +109,7 @@ class Connection extends ReconnectWrapper implements IDBConnection {
public function createQueryBuilder() {
$backtrace = $this->getCallerBacktrace();
\OC::$server->getLogger()->debug('Doctrine QueryBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
+ $this->queriesBuilt++;
return parent::createQueryBuilder();
}
@@ -102,6 +122,7 @@ class Connection extends ReconnectWrapper implements IDBConnection {
public function getExpressionBuilder() {
$backtrace = $this->getCallerBacktrace();
\OC::$server->getLogger()->debug('Doctrine ExpressionBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
+ $this->queriesBuilt++;
return parent::getExpressionBuilder();
}
@@ -149,6 +170,9 @@ class Connection extends ReconnectWrapper implements IDBConnection {
parent::__construct($params, $driver, $config, $eventManager);
$this->adapter = new $params['adapter']($this);
$this->tablePrefix = $params['tablePrefix'];
+
+ $this->systemConfig = \OC::$server->getSystemConfig();
+ $this->logger = \OC::$server->getLogger();
}
/**
@@ -159,7 +183,7 @@ class Connection extends ReconnectWrapper implements IDBConnection {
* @param int $offset
* @return \Doctrine\DBAL\Driver\Statement The prepared statement.
*/
- public function prepare($statement, $limit=null, $offset=null) {
+ public function prepare($statement, $limit = null, $offset = null) {
if ($limit === -1) {
$limit = null;
}
@@ -179,7 +203,7 @@ class Connection extends ReconnectWrapper implements IDBConnection {
* If the query is parametrized, a prepared statement is used.
* If an SQLLogger is configured, the execution is logged.
*
- * @param string $query The SQL query to execute.
+ * @param string $sql The SQL query to execute.
* @param array $params The parameters to bind to the query, if any.
* @param array $types The types the previous parameters are in.
* @param \Doctrine\DBAL\Cache\QueryCacheProfile|null $qcp The query cache profile, optional.
@@ -188,10 +212,18 @@ class Connection extends ReconnectWrapper implements IDBConnection {
*
* @throws \Doctrine\DBAL\DBALException
*/
- public function executeQuery($query, array $params = [], $types = [], QueryCacheProfile $qcp = null) {
- $query = $this->replaceTablePrefix($query);
- $query = $this->adapter->fixupStatement($query);
- return parent::executeQuery($query, $params, $types, $qcp);
+ public function executeQuery($sql, array $params = [], $types = [], QueryCacheProfile $qcp = null) {
+ $sql = $this->replaceTablePrefix($sql);
+ $sql = $this->adapter->fixupStatement($sql);
+ $this->queriesExecuted++;
+ return parent::executeQuery($sql, $params, $types, $qcp);
+ }
+
+ public function executeUpdate($sql, array $params = [], array $types = []) {
+ $sql = $this->replaceTablePrefix($sql);
+ $sql = $this->adapter->fixupStatement($sql);
+ $this->queriesExecuted++;
+ return parent::executeUpdate($sql, $params, $types);
}
/**
@@ -200,7 +232,7 @@ class Connection extends ReconnectWrapper implements IDBConnection {
*
* This method supports PDO binding types as well as DBAL mapping types.
*
- * @param string $query The SQL query.
+ * @param string $sql The SQL query.
* @param array $params The query parameters.
* @param array $types The parameter types.
*
@@ -208,10 +240,11 @@ class Connection extends ReconnectWrapper implements IDBConnection {
*
* @throws \Doctrine\DBAL\DBALException
*/
- public function executeUpdate($query, array $params = [], array $types = []) {
- $query = $this->replaceTablePrefix($query);
- $query = $this->adapter->fixupStatement($query);
- return parent::executeUpdate($query, $params, $types);
+ public function executeStatement($sql, array $params = [], array $types = []) {
+ $sql = $this->replaceTablePrefix($sql);
+ $sql = $this->adapter->fixupStatement($sql);
+ $this->queriesExecuted++;
+ return parent::executeStatement($sql, $params, $types);
}
/**
@@ -279,7 +312,6 @@ class Connection extends ReconnectWrapper implements IDBConnection {
* @return int number of new rows
* @throws \Doctrine\DBAL\DBALException
* @throws PreConditionNotMetException
- * @suppress SqlInjectionChecker
*/
public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []) {
try {
@@ -291,6 +323,8 @@ class Connection extends ReconnectWrapper implements IDBConnection {
}, array_merge($keys, $values))
);
return $insertQb->execute();
+ } catch (NotNullConstraintViolationException $e) {
+ throw $e;
} catch (ConstraintViolationException $e) {
// value already exists, try update
$updateQb = $this->getQueryBuilder();
@@ -301,11 +335,17 @@ class Connection extends ReconnectWrapper implements IDBConnection {
$where = $updateQb->expr()->andX();
$whereValues = array_merge($keys, $updatePreconditionValues);
foreach ($whereValues as $name => $value) {
- $where->add($updateQb->expr()->eq(
- $name,
- $updateQb->createNamedParameter($value, $this->getType($value)),
- $this->getType($value)
- ));
+ if ($value === '') {
+ $where->add($updateQb->expr()->emptyString(
+ $name
+ ));
+ } else {
+ $where->add($updateQb->expr()->eq(
+ $name,
+ $updateQb->createNamedParameter($value, $this->getType($value)),
+ $this->getType($value)
+ ));
+ }
}
$updateQb->where($where);
$affected = $updateQb->execute();
diff --git a/lib/private/DB/MDB2SchemaManager.php b/lib/private/DB/MDB2SchemaManager.php
index 145272619b4..44ea3986214 100644
--- a/lib/private/DB/MDB2SchemaManager.php
+++ b/lib/private/DB/MDB2SchemaManager.php
@@ -11,7 +11,7 @@
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -145,7 +145,6 @@ class MDB2SchemaManager {
$toSchema = new Schema([], [], $this->conn->getSchemaManager()->createSchemaConfig());
$fromSchema = $schemaReader->loadSchemaFromFile($file, $toSchema);
$toSchema = clone $fromSchema;
- /** @var $table \Doctrine\DBAL\Schema\Table */
foreach ($toSchema->getTables() as $table) {
$toSchema->dropTable($table->getName());
}
diff --git a/lib/private/DB/MDB2SchemaReader.php b/lib/private/DB/MDB2SchemaReader.php
index b371e1a16b2..abf58ffa053 100644
--- a/lib/private/DB/MDB2SchemaReader.php
+++ b/lib/private/DB/MDB2SchemaReader.php
@@ -10,7 +10,7 @@
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/DB/MigrationService.php b/lib/private/DB/MigrationService.php
index 62f1d731f55..6a1cb4be016 100644
--- a/lib/private/DB/MigrationService.php
+++ b/lib/private/DB/MigrationService.php
@@ -4,10 +4,11 @@
* @copyright Copyright (c) 2017, ownCloud GmbH
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Joas Schilling <coding@schilljs.com>
+ * @author Julius Härtl <jus@bitgrid.net>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license AGPL-3.0
*
@@ -27,6 +28,7 @@
namespace OC\DB;
+use Doctrine\DBAL\Exception\DriverException;
use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
use Doctrine\DBAL\Schema\Index;
@@ -124,6 +126,11 @@ class MigrationService {
return false;
}
+ if ($this->connection->tableExists('migrations') && \OC::$server->getConfig()->getAppValue('core', 'vendor', '') !== 'owncloud') {
+ $this->migrationTableCreated = true;
+ return false;
+ }
+
$schema = new SchemaWrapper($this->connection);
/**
@@ -408,10 +415,57 @@ class MigrationService {
* @throws \InvalidArgumentException
*/
public function migrate($to = 'latest', $schemaOnly = false) {
+ if ($schemaOnly) {
+ $this->migrateSchemaOnly($to);
+ return;
+ }
+
+ // read known migrations
+ $toBeExecuted = $this->getMigrationsToExecute($to);
+ foreach ($toBeExecuted as $version) {
+ try {
+ $this->executeStep($version, $schemaOnly);
+ } catch (DriverException $e) {
+ // The exception itself does not contain the name of the migration,
+ // so we wrap it here, to make debugging easier.
+ throw new \Exception('Database error when running migration ' . $to . ' for app ' . $this->getApp(), 0, $e);
+ }
+ }
+ }
+
+ /**
+ * Applies all not yet applied versions up to $to
+ *
+ * @param string $to
+ * @throws \InvalidArgumentException
+ */
+ public function migrateSchemaOnly($to = 'latest') {
// read known migrations
$toBeExecuted = $this->getMigrationsToExecute($to);
+
+ if (empty($toBeExecuted)) {
+ return;
+ }
+
+ $toSchema = null;
foreach ($toBeExecuted as $version) {
- $this->executeStep($version, $schemaOnly);
+ $instance = $this->createInstance($version);
+
+ $toSchema = $instance->changeSchema($this->output, function () use ($toSchema) {
+ return $toSchema ?: new SchemaWrapper($this->connection);
+ }, ['tablePrefix' => $this->connection->getPrefix()]) ?: $toSchema;
+
+ $this->markAsExecuted($version);
+ }
+
+ if ($toSchema instanceof SchemaWrapper) {
+ $targetSchema = $toSchema->getWrappedSchema();
+ if ($this->checkOracle) {
+ $beforeSchema = $this->connection->createSchema();
+ $this->ensureOracleIdentifierLengthLimit($beforeSchema, $targetSchema, strlen($this->connection->getPrefix()));
+ }
+ $this->connection->migrateToSchema($targetSchema);
+ $toSchema->performDropTableCalls();
}
}
@@ -513,6 +567,11 @@ class MigrationService {
if ((!$sourceTable instanceof Table || !$sourceTable->hasColumn($thing->getName())) && \strlen($thing->getName()) > 30) {
throw new \InvalidArgumentException('Column name "' . $table->getName() . '"."' . $thing->getName() . '" is too long.');
}
+
+ if ($thing->getNotnull() && $thing->getDefault() === ''
+ && $sourceTable instanceof Table && !$sourceTable->hasColumn($thing->getName())) {
+ throw new \InvalidArgumentException('Column name "' . $table->getName() . '"."' . $thing->getName() . '" is NotNull, but has empty string or null as default.');
+ }
}
foreach ($table->getIndexes() as $thing) {
diff --git a/lib/private/DB/Migrator.php b/lib/private/DB/Migrator.php
index 2ea365ab294..569b1a6c282 100644
--- a/lib/private/DB/Migrator.php
+++ b/lib/private/DB/Migrator.php
@@ -11,7 +11,7 @@
* @author tbelau666 <thomas.belau@gmx.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -226,7 +226,6 @@ class Migrator {
$sourceSchema = $connection->getSchemaManager()->createSchema();
// remove tables we don't know about
- /** @var $table \Doctrine\DBAL\Schema\Table */
foreach ($sourceSchema->getTables() as $table) {
if (!$targetSchema->hasTable($table->getName())) {
$sourceSchema->dropTable($table->getName());
@@ -305,13 +304,13 @@ class Migrator {
if (is_null($this->dispatcher)) {
return;
}
- $this->dispatcher->dispatch('\OC\DB\Migrator::executeSql', new GenericEvent($sql, [$step+1, $max]));
+ $this->dispatcher->dispatch('\OC\DB\Migrator::executeSql', new GenericEvent($sql, [$step + 1, $max]));
}
private function emitCheckStep($tableName, $step, $max) {
if (is_null($this->dispatcher)) {
return;
}
- $this->dispatcher->dispatch('\OC\DB\Migrator::checkTable', new GenericEvent($tableName, [$step+1, $max]));
+ $this->dispatcher->dispatch('\OC\DB\Migrator::checkTable', new GenericEvent($tableName, [$step + 1, $max]));
}
}
diff --git a/lib/private/DB/MissingPrimaryKeyInformation.php b/lib/private/DB/MissingPrimaryKeyInformation.php
new file mode 100644
index 00000000000..62b5dd2c631
--- /dev/null
+++ b/lib/private/DB/MissingPrimaryKeyInformation.php
@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2018 Morris Jobke <hey@morrisjobke.de>
+ *
+ * @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 OC\DB;
+
+class MissingPrimaryKeyInformation {
+ private $listOfMissingPrimaryKeys = [];
+
+ public function addHintForMissingSubject(string $tableName) {
+ $this->listOfMissingPrimaryKeys[] = [
+ 'tableName' => $tableName,
+ ];
+ }
+
+ public function getListOfMissingPrimaryKeys(): array {
+ return $this->listOfMissingPrimaryKeys;
+ }
+}
diff --git a/lib/private/DB/OracleConnection.php b/lib/private/DB/OracleConnection.php
index b53ee850149..8198f3bd5e5 100644
--- a/lib/private/DB/OracleConnection.php
+++ b/lib/private/DB/OracleConnection.php
@@ -8,6 +8,7 @@
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license AGPL-3.0
*
@@ -47,35 +48,35 @@ class OracleConnection extends Connection {
/**
* {@inheritDoc}
*/
- public function insert($tableName, array $data, array $types = []) {
- if ($tableName[0] !== $this->getDatabasePlatform()->getIdentifierQuoteCharacter()) {
- $tableName = $this->quoteIdentifier($tableName);
+ public function insert($table, array $data, array $types = []) {
+ if ($table[0] !== $this->getDatabasePlatform()->getIdentifierQuoteCharacter()) {
+ $table = $this->quoteIdentifier($table);
}
$data = $this->quoteKeys($data);
- return parent::insert($tableName, $data, $types);
+ return parent::insert($table, $data, $types);
}
/**
* {@inheritDoc}
*/
- public function update($tableName, array $data, array $identifier, array $types = []) {
- if ($tableName[0] !== $this->getDatabasePlatform()->getIdentifierQuoteCharacter()) {
- $tableName = $this->quoteIdentifier($tableName);
+ public function update($table, array $data, array $criteria, array $types = []) {
+ if ($table[0] !== $this->getDatabasePlatform()->getIdentifierQuoteCharacter()) {
+ $table = $this->quoteIdentifier($table);
}
$data = $this->quoteKeys($data);
- $identifier = $this->quoteKeys($identifier);
- return parent::update($tableName, $data, $identifier, $types);
+ $criteria = $this->quoteKeys($criteria);
+ return parent::update($table, $data, $criteria, $types);
}
/**
* {@inheritDoc}
*/
- public function delete($tableExpression, array $identifier, array $types = []) {
- if ($tableExpression[0] !== $this->getDatabasePlatform()->getIdentifierQuoteCharacter()) {
- $tableExpression = $this->quoteIdentifier($tableExpression);
+ public function delete($table, array $criteria, array $types = []) {
+ if ($table[0] !== $this->getDatabasePlatform()->getIdentifierQuoteCharacter()) {
+ $table = $this->quoteIdentifier($table);
}
- $identifier = $this->quoteKeys($identifier);
- return parent::delete($tableExpression, $identifier);
+ $criteria = $this->quoteKeys($criteria);
+ return parent::delete($table, $criteria);
}
/**
diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php
index f4b434466e4..61eea80640e 100644
--- a/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php
+++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php
@@ -2,6 +2,7 @@
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
+ * @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Joas Schilling <coding@schilljs.com>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -33,6 +34,7 @@ use OC\DB\QueryBuilder\QueryFunction;
use OC\DB\QueryBuilder\QuoteHelper;
use OCP\DB\QueryBuilder\IExpressionBuilder;
use OCP\DB\QueryBuilder\ILiteral;
+use OCP\DB\QueryBuilder\IParameter;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\DB\QueryBuilder\IQueryFunction;
use OCP\IDBConnection;
@@ -278,7 +280,7 @@ class ExpressionBuilder implements IExpressionBuilder {
/**
* Creates a LIKE() comparison expression with the given arguments.
*
- * @param string $x Field in string format to be inspected by LIKE() comparison.
+ * @param ILiteral|IParameter|IQueryFunction|string $x Field in string format to be inspected by LIKE() comparison.
* @param mixed $y Argument to be used in LIKE() comparison.
* @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
* required when comparing text fields for oci compatibility
@@ -309,7 +311,7 @@ class ExpressionBuilder implements IExpressionBuilder {
/**
* Creates a NOT LIKE() comparison expression with the given arguments.
*
- * @param string $x Field in string format to be inspected by NOT LIKE() comparison.
+ * @param ILiteral|IParameter|IQueryFunction|string $x Field in string format to be inspected by NOT LIKE() comparison.
* @param mixed $y Argument to be used in NOT LIKE() comparison.
* @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
* required when comparing text fields for oci compatibility
@@ -325,8 +327,8 @@ class ExpressionBuilder implements IExpressionBuilder {
/**
* Creates a IN () comparison expression with the given arguments.
*
- * @param string $x The field in string format to be inspected by IN() comparison.
- * @param string|array $y The placeholder or the array of values to be used by IN() comparison.
+ * @param ILiteral|IParameter|IQueryFunction|string $x The field in string format to be inspected by IN() comparison.
+ * @param ILiteral|IParameter|IQueryFunction|string|array $y The placeholder or the array of values to be used by IN() comparison.
* @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
* required when comparing text fields for oci compatibility
*
@@ -341,8 +343,8 @@ class ExpressionBuilder implements IExpressionBuilder {
/**
* Creates a NOT IN () comparison expression with the given arguments.
*
- * @param string $x The field in string format to be inspected by NOT IN() comparison.
- * @param string|array $y The placeholder or the array of values to be used by NOT IN() comparison.
+ * @param ILiteral|IParameter|IQueryFunction|string $x The field in string format to be inspected by NOT IN() comparison.
+ * @param ILiteral|IParameter|IQueryFunction|string|array $y The placeholder or the array of values to be used by NOT IN() comparison.
* @param mixed|null $type one of the IQueryBuilder::PARAM_* constants
* required when comparing text fields for oci compatibility
*
diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php
index 2aa007dba04..f41242fdc60 100644
--- a/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php
+++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php
@@ -170,6 +170,10 @@ class OCIExpressionBuilder extends ExpressionBuilder {
$column = $this->helper->quoteColumnName($column);
return new QueryFunction('to_char(' . $column . ')');
}
+ if ($type === IQueryBuilder::PARAM_INT) {
+ $column = $this->helper->quoteColumnName($column);
+ return new QueryFunction('to_number(to_char(' . $column . '))');
+ }
return parent::castColumn($column, $type);
}
@@ -185,8 +189,6 @@ class OCIExpressionBuilder extends ExpressionBuilder {
* @inheritdoc
*/
public function iLike($x, $y, $type = null) {
- $x = $this->helper->quoteColumnName($x);
- $y = $this->helper->quoteColumnName($y);
- return new QueryFunction('REGEXP_LIKE(' . $x . ', \'^\' || REPLACE(REPLACE(' . $y . ', \'%\', \'.*\'), \'_\', \'.\') || \'$\', \'i\')');
+ return $this->like($this->functionBuilder->lower($x), $this->functionBuilder->lower($y));
}
}
diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php
index a49edc505f5..b8c54546b78 100644
--- a/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php
+++ b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php
@@ -27,6 +27,7 @@ namespace OC\DB\QueryBuilder\FunctionBuilder;
use OC\DB\QueryBuilder\QueryFunction;
use OC\DB\QueryBuilder\QuoteHelper;
use OCP\DB\QueryBuilder\IFunctionBuilder;
+use OCP\DB\QueryBuilder\IQueryFunction;
class FunctionBuilder implements IFunctionBuilder {
/** @var QuoteHelper */
@@ -41,15 +42,15 @@ class FunctionBuilder implements IFunctionBuilder {
$this->helper = $helper;
}
- public function md5($input) {
+ public function md5($input): IQueryFunction {
return new QueryFunction('MD5(' . $this->helper->quoteColumnName($input) . ')');
}
- public function concat($x, $y) {
+ public function concat($x, $y): IQueryFunction {
return new QueryFunction('CONCAT(' . $this->helper->quoteColumnName($x) . ', ' . $this->helper->quoteColumnName($y) . ')');
}
- public function substring($input, $start, $length = null) {
+ public function substring($input, $start, $length = null): IQueryFunction {
if ($length) {
return new QueryFunction('SUBSTR(' . $this->helper->quoteColumnName($input) . ', ' . $this->helper->quoteColumnName($start) . ', ' . $this->helper->quoteColumnName($length) . ')');
} else {
@@ -57,41 +58,41 @@ class FunctionBuilder implements IFunctionBuilder {
}
}
- public function sum($field) {
+ public function sum($field): IQueryFunction {
return new QueryFunction('SUM(' . $this->helper->quoteColumnName($field) . ')');
}
- public function lower($field) {
+ public function lower($field): IQueryFunction {
return new QueryFunction('LOWER(' . $this->helper->quoteColumnName($field) . ')');
}
- public function add($x, $y) {
+ public function add($x, $y): IQueryFunction {
return new QueryFunction($this->helper->quoteColumnName($x) . ' + ' . $this->helper->quoteColumnName($y));
}
- public function subtract($x, $y) {
+ public function subtract($x, $y): IQueryFunction {
return new QueryFunction($this->helper->quoteColumnName($x) . ' - ' . $this->helper->quoteColumnName($y));
}
- public function count($count = '', $alias = '') {
+ public function count($count = '', $alias = ''): IQueryFunction {
$alias = $alias ? (' AS ' . $this->helper->quoteColumnName($alias)) : '';
$quotedName = $count === '' ? '*' : $this->helper->quoteColumnName($count);
return new QueryFunction('COUNT(' . $quotedName . ')' . $alias);
}
- public function max($field) {
+ public function max($field): IQueryFunction {
return new QueryFunction('MAX(' . $this->helper->quoteColumnName($field) . ')');
}
- public function min($field) {
+ public function min($field): IQueryFunction {
return new QueryFunction('MIN(' . $this->helper->quoteColumnName($field) . ')');
}
- public function greatest($x, $y) {
+ public function greatest($x, $y): IQueryFunction {
return new QueryFunction('GREATEST(' . $this->helper->quoteColumnName($x) . ', ' . $this->helper->quoteColumnName($y) . ')');
}
- public function least($x, $y) {
+ public function least($x, $y): IQueryFunction {
return new QueryFunction('LEAST(' . $this->helper->quoteColumnName($x) . ', ' . $this->helper->quoteColumnName($y) . ')');
}
}
diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php
index f9347210c13..c269fc03c8a 100644
--- a/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php
+++ b/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php
@@ -2,6 +2,7 @@
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
+ * @author Joas Schilling <coding@schilljs.com>
* @author Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
@@ -24,9 +25,52 @@
namespace OC\DB\QueryBuilder\FunctionBuilder;
use OC\DB\QueryBuilder\QueryFunction;
+use OCP\DB\QueryBuilder\ILiteral;
+use OCP\DB\QueryBuilder\IParameter;
+use OCP\DB\QueryBuilder\IQueryFunction;
class OCIFunctionBuilder extends FunctionBuilder {
- public function md5($input) {
+ public function md5($input): IQueryFunction {
return new QueryFunction('LOWER(DBMS_OBFUSCATION_TOOLKIT.md5 (input => UTL_RAW.cast_to_raw(' . $this->helper->quoteColumnName($input) .')))');
}
+
+ /**
+ * As per https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions060.htm
+ * Oracle uses the first value to cast the rest or the values. So when the
+ * first value is a literal, plain value or column, instead of doing the
+ * math, it will cast the expression to int and continue with a "0". So when
+ * the second parameter is a function or column, we have to put that as
+ * first parameter.
+ *
+ * @param string|ILiteral|IParameter|IQueryFunction $x
+ * @param string|ILiteral|IParameter|IQueryFunction $y
+ * @return IQueryFunction
+ */
+ public function greatest($x, $y): IQueryFunction {
+ if (is_string($y) || $y instanceof IQueryFunction) {
+ return parent::greatest($y, $x);
+ }
+
+ return parent::greatest($x, $y);
+ }
+
+ /**
+ * As per https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions060.htm
+ * Oracle uses the first value to cast the rest or the values. So when the
+ * first value is a literal, plain value or column, instead of doing the
+ * math, it will cast the expression to int and continue with a "0". So when
+ * the second parameter is a function or column, we have to put that as
+ * first parameter.
+ *
+ * @param string|ILiteral|IParameter|IQueryFunction $x
+ * @param string|ILiteral|IParameter|IQueryFunction $y
+ * @return IQueryFunction
+ */
+ public function least($x, $y): IQueryFunction {
+ if (is_string($y) || $y instanceof IQueryFunction) {
+ return parent::least($y, $x);
+ }
+
+ return parent::least($x, $y);
+ }
}
diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php
index 8753d26104f..a44b80bbaaf 100644
--- a/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php
+++ b/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php
@@ -25,9 +25,10 @@
namespace OC\DB\QueryBuilder\FunctionBuilder;
use OC\DB\QueryBuilder\QueryFunction;
+use OCP\DB\QueryBuilder\IQueryFunction;
class PgSqlFunctionBuilder extends FunctionBuilder {
- public function concat($x, $y) {
+ public function concat($x, $y): IQueryFunction {
return new QueryFunction('(' . $this->helper->quoteColumnName($x) . ' || ' . $this->helper->quoteColumnName($y) . ')');
}
}
diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php
index 6d8e947c407..8e490c15a3c 100644
--- a/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php
+++ b/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php
@@ -25,17 +25,18 @@
namespace OC\DB\QueryBuilder\FunctionBuilder;
use OC\DB\QueryBuilder\QueryFunction;
+use OCP\DB\QueryBuilder\IQueryFunction;
class SqliteFunctionBuilder extends FunctionBuilder {
- public function concat($x, $y) {
+ public function concat($x, $y): IQueryFunction {
return new QueryFunction('(' . $this->helper->quoteColumnName($x) . ' || ' . $this->helper->quoteColumnName($y) . ')');
}
- public function greatest($x, $y) {
+ public function greatest($x, $y): IQueryFunction {
return new QueryFunction('MAX(' . $this->helper->quoteColumnName($x) . ', ' . $this->helper->quoteColumnName($y) . ')');
}
- public function least($x, $y) {
+ public function least($x, $y): IQueryFunction {
return new QueryFunction('MIN(' . $this->helper->quoteColumnName($x) . ', ' . $this->helper->quoteColumnName($y) . ')');
}
}
diff --git a/lib/private/DB/QueryBuilder/QueryBuilder.php b/lib/private/DB/QueryBuilder/QueryBuilder.php
index a2941950d5c..2f8707326de 100644
--- a/lib/private/DB/QueryBuilder/QueryBuilder.php
+++ b/lib/private/DB/QueryBuilder/QueryBuilder.php
@@ -3,11 +3,13 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @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 Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -30,6 +32,7 @@ namespace OC\DB\QueryBuilder;
use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
+use Doctrine\DBAL\Query\QueryException;
use OC\DB\OracleConnection;
use OC\DB\QueryBuilder\ExpressionBuilder\ExpressionBuilder;
use OC\DB\QueryBuilder\ExpressionBuilder\MySqlExpressionBuilder;
@@ -41,6 +44,7 @@ use OC\DB\QueryBuilder\FunctionBuilder\OCIFunctionBuilder;
use OC\DB\QueryBuilder\FunctionBuilder\PgSqlFunctionBuilder;
use OC\DB\QueryBuilder\FunctionBuilder\SqliteFunctionBuilder;
use OC\SystemConfig;
+use OCP\DB\QueryBuilder\ILiteral;
use OCP\DB\QueryBuilder\IParameter;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\DB\QueryBuilder\IQueryFunction;
@@ -191,23 +195,51 @@ class QueryBuilder implements IQueryBuilder {
*/
public function execute() {
if ($this->systemConfig->getValue('log_query', false)) {
- $params = [];
- foreach ($this->getParameters() as $placeholder => $value) {
- if (is_array($value)) {
- $params[] = $placeholder . ' => (\'' . implode('\', \'', $value) . '\')';
+ try {
+ $params = [];
+ foreach ($this->getParameters() as $placeholder => $value) {
+ if ($value instanceof \DateTime) {
+ $params[] = $placeholder . ' => DateTime:\'' . $value->format('c') . '\'';
+ } elseif (is_array($value)) {
+ $params[] = $placeholder . ' => (\'' . implode('\', \'', $value) . '\')';
+ } else {
+ $params[] = $placeholder . ' => \'' . $value . '\'';
+ }
+ }
+ if (empty($params)) {
+ $this->logger->debug('DB QueryBuilder: \'{query}\'', [
+ 'query' => $this->getSQL(),
+ 'app' => 'core',
+ ]);
} else {
- $params[] = $placeholder . ' => \'' . $value . '\'';
+ $this->logger->debug('DB QueryBuilder: \'{query}\' with parameters: {params}', [
+ 'query' => $this->getSQL(),
+ 'params' => implode(', ', $params),
+ 'app' => 'core',
+ ]);
}
+ } catch (\Error $e) {
+ // likely an error during conversion of $value to string
+ $this->logger->debug('DB QueryBuilder: error trying to log SQL query');
+ $this->logger->logException($e);
}
- if (empty($params)) {
- $this->logger->debug('DB QueryBuilder: \'{query}\'', [
- 'query' => $this->getSQL(),
- 'app' => 'core',
- ]);
- } else {
- $this->logger->debug('DB QueryBuilder: \'{query}\' with parameters: {params}', [
+ }
+
+ if (!empty($this->getQueryPart('select'))) {
+ $select = $this->getQueryPart('select');
+ $hasSelectAll = array_filter($select, static function ($s) {
+ return $s === '*';
+ });
+ $hasSelectSpecific = array_filter($select, static function ($s) {
+ return $s !== '*';
+ });
+
+ if (empty($hasSelectAll) === empty($hasSelectSpecific)) {
+ $exception = new QueryException('Query is selecting * and specific values in the same query. This is not supported in Oracle.');
+ $this->logger->logException($exception, [
+ 'message' => 'Query is selecting * and specific values in the same query. This is not supported in Oracle.',
'query' => $this->getSQL(),
- 'params' => implode(', ', $params),
+ 'level' => ILogger::ERROR,
'app' => 'core',
]);
}
@@ -364,7 +396,7 @@ class QueryBuilder implements IQueryBuilder {
* Gets the maximum number of results the query object was set to retrieve (the "limit").
* Returns NULL if {@link setMaxResults} was not applied to this query builder.
*
- * @return integer The maximum number of results.
+ * @return int|null The maximum number of results.
*/
public function getMaxResults() {
return $this->queryBuilder->getMaxResults();
@@ -434,8 +466,14 @@ class QueryBuilder implements IQueryBuilder {
* @return $this This QueryBuilder instance.
*/
public function selectDistinct($select) {
+ if (!is_array($select)) {
+ $select = [$select];
+ }
+
+ $quotedSelect = $this->helper->quoteColumnNames($select);
+
$this->queryBuilder->addSelect(
- 'DISTINCT ' . $this->helper->quoteColumnName($select)
+ 'DISTINCT ' . implode(', ', $quotedSelect)
);
return $this;
@@ -694,7 +732,7 @@ class QueryBuilder implements IQueryBuilder {
* </code>
*
* @param string $key The column to set.
- * @param string $value The value, expression, placeholder, etc.
+ * @param ILiteral|IParameter|IQueryFunction|string $value The value, expression, placeholder, etc.
*
* @return $this This QueryBuilder instance.
*/
@@ -867,14 +905,14 @@ class QueryBuilder implements IQueryBuilder {
* </code>
*
* @param string $column The column into which the value should be inserted.
- * @param string $value The value that should be inserted into the column.
+ * @param IParameter|string $value The value that should be inserted into the column.
*
* @return $this This QueryBuilder instance.
*/
public function setValue($column, $value) {
$this->queryBuilder->setValue(
$this->helper->quoteColumnName($column),
- $value
+ (string) $value
);
return $this;
diff --git a/lib/private/DB/SchemaWrapper.php b/lib/private/DB/SchemaWrapper.php
index e42535d64ab..440008d35b3 100644
--- a/lib/private/DB/SchemaWrapper.php
+++ b/lib/private/DB/SchemaWrapper.php
@@ -111,6 +111,7 @@ class SchemaWrapper implements ISchemaWrapper {
* @return \Doctrine\DBAL\Schema\Table
*/
public function createTable($tableName) {
+ unset($this->tablesToDelete[$tableName]);
return $this->schema->createTable($this->connection->getPrefix() . $tableName);
}
diff --git a/lib/private/Dashboard/Manager.php b/lib/private/Dashboard/Manager.php
index 0c285a8b53d..9f703bb14ad 100644
--- a/lib/private/Dashboard/Manager.php
+++ b/lib/private/Dashboard/Manager.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
/**
* @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net>
*
+ * @author Joas Schilling <coding@schilljs.com>
* @author Julius Härtl <jus@bitgrid.net>
*
* @license GNU AGPL version 3 or any later version
@@ -16,7 +17,7 @@ declare(strict_types=1);
*
* 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
+ * 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
@@ -29,7 +30,7 @@ namespace OC\Dashboard;
use InvalidArgumentException;
use OCP\AppFramework\QueryException;
use OCP\Dashboard\IManager;
-use OCP\Dashboard\IPanel;
+use OCP\Dashboard\IWidget;
use OCP\ILogger;
use OCP\IServerContainer;
use Throwable;
@@ -37,10 +38,10 @@ use Throwable;
class Manager implements IManager {
/** @var array */
- private $lazyPanels = [];
+ private $lazyWidgets = [];
- /** @var IPanel[] */
- private $panels = [];
+ /** @var IWidget[] */
+ private $widgets = [];
/** @var IServerContainer */
private $serverContainer;
@@ -49,31 +50,31 @@ class Manager implements IManager {
$this->serverContainer = $serverContainer;
}
- private function registerPanel(IPanel $panel): void {
- if (array_key_exists($panel->getId(), $this->panels)) {
- throw new InvalidArgumentException('Dashboard panel with this id has already been registered');
+ private function registerWidget(IWidget $widget): void {
+ if (array_key_exists($widget->getId(), $this->widgets)) {
+ throw new InvalidArgumentException('Dashboard widget with this id has already been registered');
}
- $this->panels[$panel->getId()] = $panel;
+ $this->widgets[$widget->getId()] = $widget;
}
- public function lazyRegisterPanel(string $panelClass): void {
- $this->lazyPanels[] = $panelClass;
+ public function lazyRegisterWidget(string $widgetClass): void {
+ $this->lazyWidgets[] = $widgetClass;
}
public function loadLazyPanels(): void {
- $classes = $this->lazyPanels;
+ $classes = $this->lazyWidgets;
foreach ($classes as $class) {
try {
- /** @var IPanel $panel */
- $panel = $this->serverContainer->query($class);
+ /** @var IWidget $widget */
+ $widget = $this->serverContainer->query($class);
} catch (QueryException $e) {
/*
* There is a circular dependency between the logger and the registry, so
* we can not inject it. Thus the static call.
*/
\OC::$server->getLogger()->logException($e, [
- 'message' => 'Could not load lazy dashbaord panel: ' . $e->getMessage(),
+ 'message' => 'Could not load lazy dashbaord widget: ' . $e->getMessage(),
'level' => ILogger::FATAL,
]);
}
@@ -82,32 +83,41 @@ class Manager implements IManager {
* type, so we might get a TypeError here that we should catch.
*/
try {
- $this->registerPanel($panel);
+ $this->registerWidget($widget);
} catch (Throwable $e) {
/*
* There is a circular dependency between the logger and the registry, so
* we can not inject it. Thus the static call.
*/
\OC::$server->getLogger()->logException($e, [
- 'message' => 'Could not register lazy dashboard panel: ' . $e->getMessage(),
+ 'message' => 'Could not register lazy dashboard widget: ' . $e->getMessage(),
'level' => ILogger::FATAL,
]);
}
try {
- $panel->load();
+ $startTime = microtime(true);
+ $widget->load();
+ $endTime = microtime(true);
+ $duration = $endTime - $startTime;
+ if ($duration > 1) {
+ \OC::$server->getLogger()->error('Dashboard widget {widget} took {duration} seconds to load.', [
+ 'widget' => $widget->getId(),
+ 'duration' => round($duration, 2),
+ ]);
+ }
} catch (Throwable $e) {
\OC::$server->getLogger()->logException($e, [
- 'message' => 'Error during dashboard panel loading: ' . $e->getMessage(),
+ 'message' => 'Error during dashboard widget loading: ' . $e->getMessage(),
'level' => ILogger::FATAL,
]);
}
}
- $this->lazyPanels = [];
+ $this->lazyWidgets = [];
}
- public function getPanels(): array {
+ public function getWidgets(): array {
$this->loadLazyPanels();
- return $this->panels;
+ return $this->widgets;
}
}
diff --git a/lib/private/DirectEditing/Manager.php b/lib/private/DirectEditing/Manager.php
index c3098fb1a97..0e7e988eef2 100644
--- a/lib/private/DirectEditing/Manager.php
+++ b/lib/private/DirectEditing/Manager.php
@@ -35,6 +35,7 @@ use OCP\DirectEditing\ACreateFromTemplate;
use OCP\DirectEditing\IEditor;
use \OCP\DirectEditing\IManager;
use OCP\DirectEditing\IToken;
+use OCP\Encryption\IManager as EncryptionManager;
use OCP\Files\File;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
@@ -45,6 +46,7 @@ use OCP\IUserSession;
use OCP\L10N\IFactory;
use OCP\Security\ISecureRandom;
use OCP\Share\IShare;
+use Throwable;
use function array_key_exists;
use function in_array;
@@ -55,30 +57,33 @@ class Manager implements IManager {
/** @var IEditor[] */
private $editors = [];
-
/** @var IDBConnection */
private $connection;
- /**
- * @var ISecureRandom
- */
+ /** @var ISecureRandom */
private $random;
+ /** @var string|null */
private $userId;
+ /** @var IRootFolder */
private $rootFolder;
/** @var IL10N */
private $l10n;
+ /** @var EncryptionManager */
+ private $encryptionManager;
public function __construct(
ISecureRandom $random,
IDBConnection $connection,
IUserSession $userSession,
IRootFolder $rootFolder,
- IFactory $l10nFactory
+ IFactory $l10nFactory,
+ EncryptionManager $encryptionManager
) {
$this->random = $random;
$this->connection = $connection;
$this->userId = $userSession->getUser() ? $userSession->getUser()->getUID() : null;
$this->rootFolder = $rootFolder;
$this->l10n = $l10nFactory->get('core');
+ $this->encryptionManager = $encryptionManager;
}
public function registerDirectEditor(IEditor $directEditor): void {
@@ -116,7 +121,7 @@ class Manager implements IManager {
}
}
$return = [];
- $return['templates'] = $templates;
+ $return['templates'] = $templates;
return $return;
}
@@ -171,7 +176,7 @@ class Manager implements IManager {
}
$editor = $this->getEditor($tokenObject->getEditor());
$this->accessToken($token);
- } catch (\Throwable $throwable) {
+ } catch (Throwable $throwable) {
$this->invalidateToken($token);
return new NotFoundResponse();
}
@@ -275,4 +280,22 @@ class Manager implements IManager {
}
return $files[0];
}
+
+ public function isEnabled(): bool {
+ if (!$this->encryptionManager->isEnabled()) {
+ return true;
+ }
+
+ try {
+ $moduleId = $this->encryptionManager->getDefaultEncryptionModuleId();
+ $module = $this->encryptionManager->getEncryptionModule($moduleId);
+ /** @var \OCA\Encryption\Util $util */
+ $util = \OC::$server->get(\OCA\Encryption\Util::class);
+ if ($module->isReadyForUser($this->userId) && $util->isMasterKeyEnabled()) {
+ return true;
+ }
+ } catch (Throwable $e) {
+ }
+ return false;
+ }
}
diff --git a/lib/private/Encryption/DecryptAll.php b/lib/private/Encryption/DecryptAll.php
index 19bd2f81378..fa913d3655b 100644
--- a/lib/private/Encryption/DecryptAll.php
+++ b/lib/private/Encryption/DecryptAll.php
@@ -9,7 +9,7 @@
* @author Joas Schilling <coding@schilljs.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author sammo2828 <sammo2828@gmail.com>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Encryption/File.php b/lib/private/Encryption/File.php
index b631e4fc63f..c0a58d1256e 100644
--- a/lib/private/Encryption/File.php
+++ b/lib/private/Encryption/File.php
@@ -5,9 +5,10 @@
* @author Björn Schießle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Encryption/Keys/Storage.php b/lib/private/Encryption/Keys/Storage.php
index cee32691261..a2b27de6b51 100644
--- a/lib/private/Encryption/Keys/Storage.php
+++ b/lib/private/Encryption/Keys/Storage.php
@@ -8,7 +8,7 @@
* @author Joas Schilling <coding@schilljs.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -31,8 +31,11 @@ namespace OC\Encryption\Keys;
use OC\Encryption\Util;
use OC\Files\Filesystem;
use OC\Files\View;
+use OC\ServerNotAvailableException;
use OC\User\NoUserException;
use OCP\Encryption\Keys\IStorage;
+use OCP\IConfig;
+use OCP\Security\ICrypto;
class Storage implements IStorage {
@@ -62,11 +65,17 @@ class Storage implements IStorage {
/** @var array */
private $keyCache = [];
+ /** @var ICrypto */
+ private $crypto;
+
+ /** @var IConfig */
+ private $config;
+
/**
* @param View $view
* @param Util $util
*/
- public function __construct(View $view, Util $util) {
+ public function __construct(View $view, Util $util, ICrypto $crypto, IConfig $config) {
$this->view = $view;
$this->util = $util;
@@ -74,6 +83,8 @@ class Storage implements IStorage {
$this->keys_base_dir = $this->encryption_base_dir .'/keys';
$this->backup_base_dir = $this->encryption_base_dir .'/backup';
$this->root_dir = $this->util->getKeyStorageRoot();
+ $this->crypto = $crypto;
+ $this->config = $config;
}
/**
@@ -81,7 +92,7 @@ class Storage implements IStorage {
*/
public function getUserKey($uid, $keyId, $encryptionModuleId) {
$path = $this->constructUserKeyPath($encryptionModuleId, $keyId, $uid);
- return $this->getKey($path);
+ return base64_decode($this->getKeyWithUid($path, $uid));
}
/**
@@ -90,17 +101,17 @@ class Storage implements IStorage {
public function getFileKey($path, $keyId, $encryptionModuleId) {
$realFile = $this->util->stripPartialFileExtension($path);
$keyDir = $this->getFileKeyDir($encryptionModuleId, $realFile);
- $key = $this->getKey($keyDir . $keyId);
+ $key = $this->getKey($keyDir . $keyId)['key'];
if ($key === '' && $realFile !== $path) {
// Check if the part file has keys and use them, if no normal keys
// exist. This is required to fix copyBetweenStorage() when we
// rename a .part file over storage borders.
$keyDir = $this->getFileKeyDir($encryptionModuleId, $path);
- $key = $this->getKey($keyDir . $keyId);
+ $key = $this->getKey($keyDir . $keyId)['key'];
}
- return $key;
+ return base64_decode($key);
}
/**
@@ -108,7 +119,7 @@ class Storage implements IStorage {
*/
public function getSystemUserKey($keyId, $encryptionModuleId) {
$path = $this->constructUserKeyPath($encryptionModuleId, $keyId, null);
- return $this->getKey($path);
+ return base64_decode($this->getKeyWithUid($path, null));
}
/**
@@ -116,7 +127,10 @@ class Storage implements IStorage {
*/
public function setUserKey($uid, $keyId, $key, $encryptionModuleId) {
$path = $this->constructUserKeyPath($encryptionModuleId, $keyId, $uid);
- return $this->setKey($path, $key);
+ return $this->setKey($path, [
+ 'key' => base64_encode($key),
+ 'uid' => $uid,
+ ]);
}
/**
@@ -124,7 +138,9 @@ class Storage implements IStorage {
*/
public function setFileKey($path, $keyId, $key, $encryptionModuleId) {
$keyDir = $this->getFileKeyDir($encryptionModuleId, $path);
- return $this->setKey($keyDir . $keyId, $key);
+ return $this->setKey($keyDir . $keyId, [
+ 'key' => base64_encode($key),
+ ]);
}
/**
@@ -132,7 +148,10 @@ class Storage implements IStorage {
*/
public function setSystemUserKey($keyId, $key, $encryptionModuleId) {
$path = $this->constructUserKeyPath($encryptionModuleId, $keyId, null);
- return $this->setKey($path, $key);
+ return $this->setKey($path, [
+ 'key' => base64_encode($key),
+ 'uid' => null,
+ ]);
}
/**
@@ -200,19 +219,106 @@ class Storage implements IStorage {
}
/**
+ * @param string $path
+ * @param string|null $uid
+ * @return string
+ * @throws ServerNotAvailableException
+ *
+ * Small helper function to fetch the key and verify the value for user and system keys
+ */
+ private function getKeyWithUid(string $path, ?string $uid): string {
+ $data = $this->getKey($path);
+
+ if (!isset($data['key'])) {
+ throw new ServerNotAvailableException('Key is invalid');
+ }
+
+ if ($data['key'] === '') {
+ return '';
+ }
+
+ if (!array_key_exists('uid', $data) || $data['uid'] !== $uid) {
+ // If the migration is done we error out
+ $versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0.0');
+ if (version_compare($versionFromBeforeUpdate, '20.0.0.1', '<=')) {
+ return $data['key'];
+ }
+
+ if ($this->config->getSystemValueBool('encryption.key_storage_migrated', true)) {
+ throw new ServerNotAvailableException('Key has been modified');
+ } else {
+ //Otherwise we migrate
+ $data['uid'] = $uid;
+ $this->setKey($path, $data);
+ }
+ }
+
+ return $data['key'];
+ }
+
+ /**
* read key from hard disk
*
* @param string $path to key
- * @return string
+ * @return array containing key as base64encoded key, and possible the uid
*/
- private function getKey($path) {
- $key = '';
+ private function getKey($path): array {
+ $key = [
+ 'key' => '',
+ ];
if ($this->view->file_exists($path)) {
if (isset($this->keyCache[$path])) {
- $key = $this->keyCache[$path];
+ $key = $this->keyCache[$path];
} else {
- $key = $this->view->file_get_contents($path);
+ $data = $this->view->file_get_contents($path);
+
+ // Version <20.0.0.1 doesn't have this
+ $versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0.0');
+ if (version_compare($versionFromBeforeUpdate, '20.0.0.1', '<=')) {
+ $key = [
+ 'key' => base64_encode($data),
+ ];
+ } else {
+ if ($this->config->getSystemValueBool('encryption.key_storage_migrated', true)) {
+ try {
+ $clearData = $this->crypto->decrypt($data);
+ } catch (\Exception $e) {
+ throw new ServerNotAvailableException('Could not decrypt key', 0, $e);
+ }
+
+ $dataArray = json_decode($clearData, true);
+ if ($dataArray === null) {
+ throw new ServerNotAvailableException('Invalid encryption key');
+ }
+
+ $key = $dataArray;
+ } else {
+ /*
+ * Even if not all keys are migrated we should still try to decrypt it (in case some have moved).
+ * However it is only a failure now if it is an array and decryption fails
+ */
+ $fallback = false;
+ try {
+ $clearData = $this->crypto->decrypt($data);
+ } catch (\Exception $e) {
+ $fallback = true;
+ }
+
+ if (!$fallback) {
+ $dataArray = json_decode($clearData, true);
+ if ($dataArray === null) {
+ throw new ServerNotAvailableException('Invalid encryption key');
+ }
+ $key = $dataArray;
+ } else {
+ $key = [
+ 'key' => base64_encode($data),
+ ];
+ }
+ }
+ }
+
$this->keyCache[$path] = $key;
}
}
@@ -225,13 +331,23 @@ class Storage implements IStorage {
*
*
* @param string $path path to key directory
- * @param string $key key
+ * @param array $key key
* @return bool
*/
private function setKey($path, $key) {
$this->keySetPreparation(dirname($path));
- $result = $this->view->file_put_contents($path, $key);
+ $versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0.0');
+ if (version_compare($versionFromBeforeUpdate, '20.0.0.1', '<=')) {
+ // Only store old format if this happens during the migration.
+ // TODO: Remove for 21
+ $data = base64_decode($key['key']);
+ } else {
+ // Wrap the data
+ $data = $this->crypto->encrypt(json_encode($key));
+ }
+
+ $result = $this->view->file_put_contents($path, $data);
if (is_int($result) && $result > 0) {
$this->keyCache[$path] = $key;
diff --git a/lib/private/Encryption/Util.php b/lib/private/Encryption/Util.php
index 0bda00a5cbc..f5107d2ec43 100644
--- a/lib/private/Encryption/Util.php
+++ b/lib/private/Encryption/Util.php
@@ -174,7 +174,7 @@ class Util {
if ($c->getType() === 'dir') {
$dirList[] = $c->getPath();
} else {
- $result[] = $c->getPath();
+ $result[] = $c->getPath();
}
}
}
@@ -255,7 +255,7 @@ class Util {
// if path also contains a transaction id, we remove it too
$extension = pathinfo($fPath, PATHINFO_EXTENSION);
if (substr($extension, 0, 12) === 'ocTransferId') { // 12 = strlen("ocTransferId")
- $newLength = strlen($fPath) - strlen($extension) -1;
+ $newLength = strlen($fPath) - strlen($extension) - 1;
$fPath = substr($fPath, 0, $newLength);
}
return $fPath;
diff --git a/lib/private/EventDispatcher/EventDispatcher.php b/lib/private/EventDispatcher/EventDispatcher.php
index f2a87cc4c70..8fe4bcbb942 100644
--- a/lib/private/EventDispatcher/EventDispatcher.php
+++ b/lib/private/EventDispatcher/EventDispatcher.php
@@ -28,6 +28,7 @@ declare(strict_types=1);
namespace OC\EventDispatcher;
+use Psr\Log\LoggerInterface;
use function get_class;
use OC\Broadcast\Events\BroadcastEvent;
use OCP\Broadcast\Events\IBroadcastEvent;
@@ -35,7 +36,6 @@ use OCP\EventDispatcher\ABroadcastedEvent;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IContainer;
-use OCP\ILogger;
use OCP\IServerContainer;
use Symfony\Component\EventDispatcher\EventDispatcher as SymfonyDispatcher;
@@ -47,12 +47,12 @@ class EventDispatcher implements IEventDispatcher {
/** @var IContainer */
private $container;
- /** @var ILogger */
+ /** @var LoggerInterface */
private $logger;
public function __construct(SymfonyDispatcher $dispatcher,
IServerContainer $container,
- ILogger $logger) {
+ LoggerInterface $logger) {
$this->dispatcher = $dispatcher;
$this->container = $container;
$this->logger = $logger;
diff --git a/lib/private/EventDispatcher/GenericEventWrapper.php b/lib/private/EventDispatcher/GenericEventWrapper.php
index dc3e7553f0c..916297f4998 100644
--- a/lib/private/EventDispatcher/GenericEventWrapper.php
+++ b/lib/private/EventDispatcher/GenericEventWrapper.php
@@ -1,9 +1,11 @@
<?php
declare(strict_types=1);
+
/**
* @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
*
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
@@ -19,7 +21,7 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff --git a/lib/private/EventDispatcher/ServiceEventListener.php b/lib/private/EventDispatcher/ServiceEventListener.php
index a648884d6f7..301531f8931 100644
--- a/lib/private/EventDispatcher/ServiceEventListener.php
+++ b/lib/private/EventDispatcher/ServiceEventListener.php
@@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -30,7 +31,7 @@ use OCP\AppFramework\QueryException;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\IContainer;
-use OCP\ILogger;
+use Psr\Log\LoggerInterface;
/**
* Lazy service event listener
@@ -46,7 +47,7 @@ final class ServiceEventListener {
/** @var string */
private $class;
- /** @var ILogger */
+ /** @var LoggerInterface */
private $logger;
/** @var null|IEventListener */
@@ -54,7 +55,7 @@ final class ServiceEventListener {
public function __construct(IContainer $container,
string $class,
- ILogger $logger) {
+ LoggerInterface $logger) {
$this->container = $container;
$this->class = $class;
$this->logger = $logger;
@@ -65,9 +66,8 @@ final class ServiceEventListener {
try {
$this->service = $this->container->query($this->class);
} catch (QueryException $e) {
- $this->logger->logException($e, [
- 'level' => ILogger::ERROR,
- 'message' => "Could not load event listener service " . $this->class,
+ $this->logger->error("Could not load event listener service " . $this->class, [
+ 'exception' => $e,
]);
return;
}
diff --git a/lib/private/EventDispatcher/SymfonyAdapter.php b/lib/private/EventDispatcher/SymfonyAdapter.php
index 454f4ca4b01..9389e725405 100644
--- a/lib/private/EventDispatcher/SymfonyAdapter.php
+++ b/lib/private/EventDispatcher/SymfonyAdapter.php
@@ -7,6 +7,7 @@ declare(strict_types=1);
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
diff --git a/lib/private/Federation/CloudFederationProviderManager.php b/lib/private/Federation/CloudFederationProviderManager.php
index 459d82c5bfb..597227533f9 100644
--- a/lib/private/Federation/CloudFederationProviderManager.php
+++ b/lib/private/Federation/CloudFederationProviderManager.php
@@ -3,6 +3,7 @@
* @copyright Copyright (c) 2018 Bjoern Schiessle <bjoern@schiessle.org>
*
* @author Bjoern Schiessle <bjoern@schiessle.org>
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @license GNU AGPL version 3 or any later version
*
@@ -75,7 +76,7 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
IClientService $httpClientService,
ICloudIdManager $cloudIdManager,
ILogger $logger) {
- $this->cloudFederationProvider= [];
+ $this->cloudFederationProvider = [];
$this->appManager = $appManager;
$this->httpClientService = $httpClientService;
$this->cloudIdManager = $cloudIdManager;
diff --git a/lib/private/Federation/CloudFederationShare.php b/lib/private/Federation/CloudFederationShare.php
index 507a3cd061a..52acee5a24e 100644
--- a/lib/private/Federation/CloudFederationShare.php
+++ b/lib/private/Federation/CloudFederationShare.php
@@ -3,6 +3,7 @@
* @copyright Copyright (c) 2018 Bjoern Schiessle <bjoern@schiessle.org>
*
* @author Bjoern Schiessle <bjoern@schiessle.org>
+ * @author Joas Schilling <coding@schilljs.com>
*
* @license GNU AGPL version 3 or any later version
*
diff --git a/lib/private/Federation/CloudId.php b/lib/private/Federation/CloudId.php
index 80e174589b0..27a222c0583 100644
--- a/lib/private/Federation/CloudId.php
+++ b/lib/private/Federation/CloudId.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
/**
* @copyright Copyright (c) 2017, Robin Appelman <robin@icewind.nl>
*
+ * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
@@ -36,6 +37,8 @@ class CloudId implements ICloudId {
private $user;
/** @var string */
private $remote;
+ /** @var string|null */
+ private $displayName;
/**
* CloudId constructor.
@@ -44,10 +47,11 @@ class CloudId implements ICloudId {
* @param string $user
* @param string $remote
*/
- public function __construct(string $id, string $user, string $remote) {
+ public function __construct(string $id, string $user, string $remote, ?string $displayName = null) {
$this->id = $id;
$this->user = $user;
$this->remote = $remote;
+ $this->displayName = $displayName;
}
/**
@@ -60,6 +64,11 @@ class CloudId implements ICloudId {
}
public function getDisplayId(): string {
+ if ($this->displayName) {
+ $atPos = strrpos($this->getId(), '@');
+ $atHost = substr($this->getId(), $atPos);
+ return $this->displayName . $atHost;
+ }
return str_replace('https://', '', str_replace('http://', '', $this->getId()));
}
diff --git a/lib/private/Federation/CloudIdManager.php b/lib/private/Federation/CloudIdManager.php
index a5ebc98c1fd..0671a0bfa02 100644
--- a/lib/private/Federation/CloudIdManager.php
+++ b/lib/private/Federation/CloudIdManager.php
@@ -5,7 +5,9 @@ declare(strict_types=1);
/**
* @copyright Copyright (c) 2017, Robin Appelman <robin@icewind.nl>
*
+ * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Guillaume Virlet <github@virlet.org>
* @author Joas Schilling <coding@schilljs.com>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -29,10 +31,18 @@ declare(strict_types=1);
namespace OC\Federation;
+use OCP\Contacts\IManager;
use OCP\Federation\ICloudId;
use OCP\Federation\ICloudIdManager;
class CloudIdManager implements ICloudIdManager {
+ /** @var IManager */
+ private $contactsManager;
+
+ public function __construct(IManager $contactsManager) {
+ $this->contactsManager = $contactsManager;
+ }
+
/**
* @param string $cloudId
* @return ICloudId
@@ -60,23 +70,38 @@ class CloudIdManager implements ICloudIdManager {
$invalidPos = min($posSlash, $posColon);
}
- // Find the last @ before $invalidPos
- $pos = $lastAtPos = 0;
- while ($lastAtPos !== false && $lastAtPos <= $invalidPos) {
- $pos = $lastAtPos;
- $lastAtPos = strpos($id, '@', $pos + 1);
- }
+ $lastValidAtPos = strrpos($id, '@', $invalidPos - strlen($id));
- if ($pos !== false) {
- $user = substr($id, 0, $pos);
- $remote = substr($id, $pos + 1);
+ if ($lastValidAtPos !== false) {
+ $user = substr($id, 0, $lastValidAtPos);
+ $remote = substr($id, $lastValidAtPos + 1);
if (!empty($user) && !empty($remote)) {
- return new CloudId($id, $user, $remote);
+ return new CloudId($id, $user, $remote, $this->getDisplayNameFromContact($id));
}
}
throw new \InvalidArgumentException('Invalid cloud id');
}
+ protected function getDisplayNameFromContact(string $cloudId): ?string {
+ $addressBookEntries = $this->contactsManager->search($cloudId, ['CLOUD']);
+ foreach ($addressBookEntries as $entry) {
+ if (isset($entry['CLOUD'])) {
+ foreach ($entry['CLOUD'] as $cloudID) {
+ if ($cloudID === $cloudId) {
+ // Warning, if user decides to make his full name local only,
+ // no FN is found on federated servers
+ if (isset($entry['FN'])) {
+ return $entry['FN'];
+ } else {
+ return $cloudID;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
/**
* @param string $user
* @param string $remote
@@ -84,7 +109,17 @@ class CloudIdManager implements ICloudIdManager {
*/
public function getCloudId(string $user, string $remote): ICloudId {
// TODO check what the correct url is for remote (asking the remote)
- return new CloudId($user. '@' . $remote, $user, $remote);
+ $fixedRemote = $this->fixRemoteURL($remote);
+ if (strpos($fixedRemote, 'http://') === 0) {
+ $host = substr($fixedRemote, strlen('http://'));
+ } elseif (strpos($fixedRemote, 'https://') === 0) {
+ $host = substr($fixedRemote, strlen('https://'));
+ } else {
+ $host = $fixedRemote;
+ }
+ $id = $user . '@' . $remote;
+ $displayName = $this->getDisplayNameFromContact($user . '@' . $host);
+ return new CloudId($id, $user, $fixedRemote, $displayName);
}
/**
diff --git a/lib/private/Files/Cache/AbstractCacheEvent.php b/lib/private/Files/Cache/AbstractCacheEvent.php
index a4029476fa5..bb7ade386e0 100644
--- a/lib/private/Files/Cache/AbstractCacheEvent.php
+++ b/lib/private/Files/Cache/AbstractCacheEvent.php
@@ -36,6 +36,7 @@ class AbstractCacheEvent extends Event implements ICacheEvent {
protected $storage;
protected $path;
protected $fileId;
+ protected $storageId;
/**
* @param IStorage $storage
@@ -43,10 +44,11 @@ class AbstractCacheEvent extends Event implements ICacheEvent {
* @param int $fileId
* @since 16.0.0
*/
- public function __construct(IStorage $storage, string $path, int $fileId) {
+ public function __construct(IStorage $storage, string $path, int $fileId, int $storageId) {
$this->storage = $storage;
$this->path = $path;
$this->fileId = $fileId;
+ $this->storageId = $storageId;
}
/**
@@ -80,4 +82,12 @@ class AbstractCacheEvent extends Event implements ICacheEvent {
public function getFileId(): int {
return $this->fileId;
}
+
+ /**
+ * @return int
+ * @since 21.0.0
+ */
+ public function getStorageId(): int {
+ return $this->storageId;
+ }
}
diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php
index de807421d26..64cd2b25ee5 100644
--- a/lib/private/Files/Cache/Cache.php
+++ b/lib/private/Files/Cache/Cache.php
@@ -18,7 +18,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -41,7 +41,11 @@ namespace OC\Files\Cache;
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Files\Cache\CacheEntryInsertedEvent;
+use OCP\Files\Cache\CacheEntryUpdatedEvent;
use OCP\Files\Cache\CacheInsertEvent;
+use OCP\Files\Cache\CacheEntryRemovedEvent;
use OCP\Files\Cache\CacheUpdateEvent;
use OCP\Files\Cache\ICache;
use OCP\Files\Cache\ICacheEntry;
@@ -91,6 +95,9 @@ class Cache implements ICache {
*/
protected $connection;
+ /**
+ * @var IEventDispatcher
+ */
protected $eventDispatcher;
/** @var QuerySearchHelper */
@@ -109,7 +116,7 @@ class Cache implements ICache {
$this->storageCache = new Storage($storage);
$this->mimetypeLoader = \OC::$server->getMimeTypeLoader();
$this->connection = \OC::$server->getDatabaseConnection();
- $this->eventDispatcher = \OC::$server->getEventDispatcher();
+ $this->eventDispatcher = \OC::$server->get(IEventDispatcher::class);
$this->querySearchHelper = new QuerySearchHelper($this->mimetypeLoader);
}
@@ -151,7 +158,9 @@ class Cache implements ICache {
$query->whereFileId($file);
}
- $data = $query->execute()->fetch();
+ $result = $query->execute();
+ $data = $result->fetch();
+ $result->closeCursor();
//merge partial data
if (!$data and is_string($file) and isset($this->partial[$file])) {
@@ -220,7 +229,10 @@ class Cache implements ICache {
->whereParent($fileId)
->orderBy('name', 'ASC');
- $files = $query->execute()->fetchAll();
+ $result = $query->execute();
+ $files = $result->fetchAll();
+ $result->closeCursor();
+
return array_map(function (array $data) {
return self::cacheEntryFromData($data, $this->mimetypeLoader);
}, $files);
@@ -254,8 +266,6 @@ class Cache implements ICache {
*
* @return int file id
* @throws \RuntimeException
- *
- * @suppress SqlInjectionChecker
*/
public function insert($file, array $data) {
// normalize file
@@ -281,7 +291,8 @@ class Cache implements ICache {
$data['name'] = basename($file);
[$values, $extensionValues] = $this->normalizeData($data);
- $values['storage'] = $this->getNumericStorageId();
+ $storageId = $this->getNumericStorageId();
+ $values['storage'] = $storageId;
try {
$builder = $this->connection->getQueryBuilder();
@@ -305,7 +316,9 @@ class Cache implements ICache {
$query->execute();
}
- $this->eventDispatcher->dispatch(CacheInsertEvent::class, new CacheInsertEvent($this->storage, $file, $fileId));
+ $event = new CacheEntryInsertedEvent($this->storage, $file, $fileId, $storageId);
+ $this->eventDispatcher->dispatch(CacheInsertEvent::class, $event);
+ $this->eventDispatcher->dispatchTyped($event);
return $fileId;
}
} catch (UniqueConstraintViolationException $e) {
@@ -396,7 +409,9 @@ class Cache implements ICache {
$path = $this->getPathById($id);
// path can still be null if the file doesn't exist
if ($path !== null) {
- $this->eventDispatcher->dispatch(CacheUpdateEvent::class, new CacheUpdateEvent($this->storage, $path, $id));
+ $event = new CacheEntryUpdatedEvent($this->storage, $path, $id, $this->getNumericStorageId());
+ $this->eventDispatcher->dispatch(CacheUpdateEvent::class, $event);
+ $this->eventDispatcher->dispatchTyped($event);
}
}
@@ -469,7 +484,10 @@ class Cache implements ICache {
->whereStorageId()
->wherePath($file);
- $id = $query->execute()->fetchColumn();
+ $result = $query->execute();
+ $id = $result->fetchColumn();
+ $result->closeCursor();
+
return $id === false ? -1 : (int)$id;
}
@@ -530,6 +548,8 @@ class Cache implements ICache {
if ($entry->getMimeType() == FileInfo::MIMETYPE_FOLDER) {
$this->removeChildren($entry);
}
+
+ $this->eventDispatcher->dispatchTyped(new CacheEntryRemovedEvent($this->storage, $entry->getPath(), $entry->getId(), $this->getNumericStorageId()));
}
}
@@ -553,25 +573,35 @@ class Cache implements ICache {
* @throws \OC\DatabaseException
*/
private function removeChildren(ICacheEntry $entry) {
- $children = $this->getFolderContentsById($entry->getId());
- $childIds = array_map(function (ICacheEntry $cacheEntry) {
- return $cacheEntry->getId();
- }, $children);
- $childFolders = array_filter($children, function ($child) {
- return $child->getMimeType() == FileInfo::MIMETYPE_FOLDER;
- });
- foreach ($childFolders as $folder) {
- $this->removeChildren($folder);
+ $parentIds = [$entry->getId()];
+ $queue = [$entry->getId()];
+
+ // we walk depth first trough the file tree, removing all filecache_extended attributes while we walk
+ // and collecting all folder ids to later use to delete the filecache entries
+ while ($entryId = array_pop($queue)) {
+ $children = $this->getFolderContentsById($entryId);
+ $childIds = array_map(function (ICacheEntry $cacheEntry) {
+ return $cacheEntry->getId();
+ }, $children);
+
+ $query = $this->getQueryBuilder();
+ $query->delete('filecache_extended')
+ ->where($query->expr()->in('fileid', $query->createNamedParameter($childIds, IQueryBuilder::PARAM_INT_ARRAY)));
+ $query->execute();
+
+ /** @var ICacheEntry[] $childFolders */
+ $childFolders = array_filter($children, function ($child) {
+ return $child->getMimeType() == FileInfo::MIMETYPE_FOLDER;
+ });
+ foreach ($childFolders as $folder) {
+ $parentIds[] = $folder->getId();
+ $queue[] = $folder->getId();
+ }
}
$query = $this->getQueryBuilder();
$query->delete('filecache')
- ->whereParent($entry->getId());
- $query->execute();
-
- $query = $this->getQueryBuilder();
- $query->delete('filecache_extended')
- ->where($query->expr()->in('fileid', $query->createNamedParameter($childIds, IQueryBuilder::PARAM_INT_ARRAY)));
+ ->whereParentIn($parentIds);
$query->execute();
}
@@ -603,7 +633,6 @@ class Cache implements ICache {
* @param string $targetPath
* @throws \OC\DatabaseException
* @throws \Exception if the given storages have an invalid id
- * @suppress SqlInjectionChecker
*/
public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
if ($sourceCache instanceof Cache) {
@@ -662,6 +691,17 @@ class Cache implements ICache {
$query->execute();
$this->connection->commit();
+
+ if ($sourceCache->getNumericStorageId() !== $this->getNumericStorageId()) {
+ $this->eventDispatcher->dispatchTyped(new CacheEntryRemovedEvent($this->storage, $sourcePath, $sourceId, $sourceCache->getNumericStorageId()));
+ $event = new CacheEntryInsertedEvent($this->storage, $targetPath, $sourceId, $this->getNumericStorageId());
+ $this->eventDispatcher->dispatch(CacheInsertEvent::class, $event);
+ $this->eventDispatcher->dispatchTyped($event);
+ } else {
+ $event = new CacheEntryUpdatedEvent($this->storage, $targetPath, $sourceId, $this->getNumericStorageId());
+ $this->eventDispatcher->dispatch(CacheUpdateEvent::class, $event);
+ $this->eventDispatcher->dispatchTyped($event);
+ }
} else {
$this->moveFromCacheFallback($sourceCache, $sourcePath, $targetPath);
}
@@ -703,7 +743,11 @@ class Cache implements ICache {
->from('filecache')
->whereStorageId()
->wherePath($file);
- $size = $query->execute()->fetchColumn();
+
+ $result = $query->execute();
+ $size = $result->fetchColumn();
+ $result->closeCursor();
+
if ($size !== false) {
if ((int)$size === -1) {
return self::SHALLOW;
@@ -738,9 +782,13 @@ class Cache implements ICache {
->whereStorageId()
->andWhere($query->expr()->iLike('name', $query->createNamedParameter($pattern)));
+ $result = $query->execute();
+ $files = $result->fetchAll();
+ $result->closeCursor();
+
return array_map(function (array $data) {
return self::cacheEntryFromData($data, $this->mimetypeLoader);
- }, $query->execute()->fetchAll());
+ }, $files);
}
/**
@@ -775,9 +823,13 @@ class Cache implements ICache {
$query->andWhere($query->expr()->eq('mimepart', $query->createNamedParameter($mimeId, IQueryBuilder::PARAM_INT)));
}
+ $result = $query->execute();
+ $files = $result->fetchAll();
+ $result->closeCursor();
+
return array_map(function (array $data) {
return self::cacheEntryFromData($data, $this->mimetypeLoader);
- }, $query->execute()->fetchAll());
+ }, $files);
}
public function searchQuery(ISearchQuery $searchQuery) {
@@ -858,7 +910,11 @@ class Cache implements ICache {
->whereParent($fileId)
->andWhere($query->expr()->lt('size', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT)));
- return (int)$query->execute()->fetchColumn();
+ $result = $query->execute();
+ $size = (int)$result->fetchColumn();
+ $result->closeCursor();
+
+ return $size;
}
return -1;
}
@@ -885,7 +941,11 @@ class Cache implements ICache {
->whereStorageId()
->whereParent($id);
- if ($row = $query->execute()->fetch()) {
+ $result = $query->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+
+ if ($row) {
[$sum, $min] = array_values($row);
$sum = 0 + $sum;
$min = 0 + $min;
@@ -913,9 +973,13 @@ class Cache implements ICache {
->from('filecache')
->whereStorageId();
+ $result = $query->execute();
+ $files = $result->fetchAll(\PDO::FETCH_COLUMN);
+ $result->closeCursor();
+
return array_map(function ($id) {
return (int)$id;
- }, $query->execute()->fetchAll(\PDO::FETCH_COLUMN));
+ }, $files);
}
/**
@@ -933,9 +997,14 @@ class Cache implements ICache {
->from('filecache')
->whereStorageId()
->andWhere($query->expr()->lt('size', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
- ->orderBy('fileid', 'DESC');
+ ->orderBy('fileid', 'DESC')
+ ->setMaxResults(1);
+
+ $result = $query->execute();
+ $path = $result->fetchColumn();
+ $result->closeCursor();
- return $query->execute()->fetchColumn();
+ return $path;
}
/**
@@ -951,8 +1020,15 @@ class Cache implements ICache {
->whereStorageId()
->whereFileId($id);
- $path = $query->execute()->fetchColumn();
- return $path === false ? null : $path;
+ $result = $query->execute();
+ $path = $result->fetchColumn();
+ $result->closeCursor();
+
+ if ($path === false) {
+ return null;
+ }
+
+ return (string) $path;
}
/**
@@ -969,7 +1045,12 @@ class Cache implements ICache {
$query->select('path', 'storage')
->from('filecache')
->where($query->expr()->eq('fileid', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
- if ($row = $query->execute()->fetch()) {
+
+ $result = $query->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+
+ if ($row) {
$numericId = $row['storage'];
$path = $row['path'];
} else {
diff --git a/lib/private/Files/Cache/CacheEntry.php b/lib/private/Files/Cache/CacheEntry.php
index 744b88b5b51..a9d2a1acbf0 100644
--- a/lib/private/Files/Cache/CacheEntry.php
+++ b/lib/private/Files/Cache/CacheEntry.php
@@ -2,6 +2,7 @@
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Robin Appelman <robin@icewind.nl>
*
* @license AGPL-3.0
@@ -27,7 +28,7 @@ use OCP\Files\Cache\ICacheEntry;
/**
* meta data for a file or folder
*/
-class CacheEntry implements ICacheEntry, \ArrayAccess {
+class CacheEntry implements ICacheEntry {
/**
* @var array
*/
@@ -67,7 +68,7 @@ class CacheEntry implements ICacheEntry, \ArrayAccess {
public function getPath() {
- return $this->data['path'];
+ return (string)$this->data['path'];
}
diff --git a/lib/private/Files/Cache/CacheQueryBuilder.php b/lib/private/Files/Cache/CacheQueryBuilder.php
index 332274eda2a..ac17cfaffb2 100644
--- a/lib/private/Files/Cache/CacheQueryBuilder.php
+++ b/lib/private/Files/Cache/CacheQueryBuilder.php
@@ -94,4 +94,17 @@ class CacheQueryBuilder extends QueryBuilder {
return $this;
}
+
+ public function whereParentIn(array $parents) {
+ $alias = $this->alias;
+ if ($alias) {
+ $alias .= '.';
+ } else {
+ $alias = '';
+ }
+
+ $this->andWhere($this->expr()->in("{$alias}parent", $this->createNamedParameter($parents, IQueryBuilder::PARAM_INT_ARRAY)));
+
+ return $this;
+ }
}
diff --git a/lib/private/Files/Cache/HomeCache.php b/lib/private/Files/Cache/HomeCache.php
index b86a31fe4d1..93906bfc93f 100644
--- a/lib/private/Files/Cache/HomeCache.php
+++ b/lib/private/Files/Cache/HomeCache.php
@@ -5,10 +5,11 @@
* @author Andreas Fischer <bantu@owncloud.com>
* @author Björn Schießle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -52,12 +53,19 @@ class HomeCache extends Cache {
}
if ($entry && $entry['mimetype'] === 'httpd/unix-directory') {
$id = $entry['fileid'];
- $sql = 'SELECT SUM(`size`) AS f1 ' .
- 'FROM `*PREFIX*filecache` ' .
- 'WHERE `parent` = ? AND `storage` = ? AND `size` >= 0';
- $result = \OC_DB::executeAudited($sql, [$id, $this->getNumericStorageId()]);
- if ($row = $result->fetchRow()) {
- $result->closeCursor();
+
+ $query = $this->connection->getQueryBuilder();
+ $query->selectAlias($query->func()->sum('size'), 'f1')
+ ->from('filecache')
+ ->where($query->expr()->eq('parent', $query->createNamedParameter($id)))
+ ->andWhere($query->expr()->eq('storage', $query->createNamedParameter($this->getNumericStorageId())))
+ ->andWhere($query->expr()->gte('size', $query->createNamedParameter(0)));
+
+ $result = $query->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+
+ if ($row) {
list($sum) = array_values($row);
$totalSize = 0 + $sum;
$entry['size'] += 0;
@@ -65,6 +73,7 @@ class HomeCache extends Cache {
$this->update($id, ['size' => $totalSize]);
}
}
+ $result->closeCursor();
}
return $totalSize;
}
diff --git a/lib/private/Files/Cache/LocalRootScanner.php b/lib/private/Files/Cache/LocalRootScanner.php
index 9ecc8c6611d..a10f51150e1 100644
--- a/lib/private/Files/Cache/LocalRootScanner.php
+++ b/lib/private/Files/Cache/LocalRootScanner.php
@@ -1,9 +1,12 @@
<?php
declare(strict_types=1);
+
/**
* @copyright Copyright (c) 2020 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
@@ -17,7 +20,7 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff --git a/lib/private/Files/Cache/NullWatcher.php b/lib/private/Files/Cache/NullWatcher.php
new file mode 100644
index 00000000000..146961d1c51
--- /dev/null
+++ b/lib/private/Files/Cache/NullWatcher.php
@@ -0,0 +1,56 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2020 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\Files\Cache;
+
+class NullWatcher extends Watcher {
+ private $policy;
+
+ public function __construct() {
+ }
+
+ public function setPolicy($policy) {
+ $this->policy = $policy;
+ }
+
+ public function getPolicy() {
+ return $this->policy;
+ }
+
+ public function checkUpdate($path, $cachedEntry = null) {
+ return false;
+ }
+
+ public function update($path, $cachedData) {
+ }
+
+ public function needsUpdate($path, $cachedData) {
+ return false;
+ }
+
+ public function cleanFolder($path) {
+ }
+}
diff --git a/lib/private/Files/Cache/Propagator.php b/lib/private/Files/Cache/Propagator.php
index 92fa6436548..cdbe8b60175 100644
--- a/lib/private/Files/Cache/Propagator.php
+++ b/lib/private/Files/Cache/Propagator.php
@@ -3,7 +3,6 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
@@ -63,7 +62,6 @@ class Propagator implements IPropagator {
* @param string $internalPath
* @param int $time
* @param int $sizeDifference number of bytes the file has grown
- * @suppress SqlInjectionChecker
*/
public function propagateChange($internalPath, $time, $sizeDifference = 0) {
// Do not propogate changes in ignored paths
@@ -105,9 +103,9 @@ class Propagator implements IPropagator {
$builder = $this->connection->getQueryBuilder();
$builder->update('filecache')
->set('size', $builder->func()->greatest(
- $builder->createNamedParameter(-1, IQueryBuilder::PARAM_INT),
- $builder->func()->add('size', $builder->createNamedParameter($sizeDifference)))
- )
+ $builder->func()->add('size', $builder->createNamedParameter($sizeDifference)),
+ $builder->createNamedParameter(-1, IQueryBuilder::PARAM_INT)
+ ))
->where($builder->expr()->eq('storage', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)))
->andWhere($builder->expr()->in('path_hash', $hashParams))
->andWhere($builder->expr()->gt('size', $builder->expr()->literal(-1, IQueryBuilder::PARAM_INT)));
@@ -156,7 +154,6 @@ class Propagator implements IPropagator {
/**
* Commit the active propagation batch
- * @suppress SqlInjectionChecker
*/
public function commitBatch() {
if (!$this->inBatch) {
@@ -170,7 +167,7 @@ class Propagator implements IPropagator {
$storageId = (int)$this->storage->getStorageCache()->getNumericId();
$query->update('filecache')
- ->set('mtime', $query->createFunction('GREATEST(' . $query->getColumnName('mtime') . ', ' . $query->createParameter('time') . ')'))
+ ->set('mtime', $query->func()->greatest('mtime', $query->createParameter('time')))
->set('etag', $query->expr()->literal(uniqid()))
->where($query->expr()->eq('storage', $query->expr()->literal($storageId, IQueryBuilder::PARAM_INT)))
->andWhere($query->expr()->eq('path_hash', $query->createParameter('hash')));
diff --git a/lib/private/Files/Cache/Scanner.php b/lib/private/Files/Cache/Scanner.php
index f895948574b..1b9637ac61e 100644
--- a/lib/private/Files/Cache/Scanner.php
+++ b/lib/private/Files/Cache/Scanner.php
@@ -16,7 +16,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Files/Cache/Storage.php b/lib/private/Files/Cache/Storage.php
index 62228e16290..74f5df2a5b1 100644
--- a/lib/private/Files/Cache/Storage.php
+++ b/lib/private/Files/Cache/Storage.php
@@ -3,14 +3,13 @@
* @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 Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -126,9 +125,14 @@ class Storage {
* @return string|null either the storage id string or null if the numeric id is not known
*/
public static function getStorageId($numericId) {
- $sql = 'SELECT `id` FROM `*PREFIX*storages` WHERE `numeric_id` = ?';
- $result = \OC_DB::executeAudited($sql, [$numericId]);
- if ($row = $result->fetchRow()) {
+ $query = \OC::$server->getDatabaseConnection()->getQueryBuilder();
+ $query->select('id')
+ ->from('storages')
+ ->where($query->expr()->eq('numeric_id', $query->createNamedParameter($numericId)));
+ $result = $query->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+ if ($row) {
return $row['id'];
} else {
return null;
@@ -170,9 +174,14 @@ class Storage {
* @param int $delay amount of seconds to delay reconsidering that storage further
*/
public function setAvailability($isAvailable, int $delay = 0) {
- $sql = 'UPDATE `*PREFIX*storages` SET `available` = ?, `last_checked` = ? WHERE `id` = ?';
$available = $isAvailable ? 1 : 0;
- \OC_DB::executeAudited($sql, [$available, time() + $delay, $this->storageId]);
+
+ $query = \OC::$server->getDatabaseConnection()->getQueryBuilder();
+ $query->update('storages')
+ ->set('available', $query->createNamedParameter($available))
+ ->set('last_checked', $query->createNamedParameter(time() + $delay))
+ ->where($query->expr()->eq('id', $query->createNamedParameter($this->storageId)));
+ $query->execute();
}
/**
@@ -193,12 +202,17 @@ class Storage {
public static function remove($storageId) {
$storageId = self::adjustStorageId($storageId);
$numericId = self::getNumericStorageId($storageId);
- $sql = 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?';
- \OC_DB::executeAudited($sql, [$storageId]);
+
+ $query = \OC::$server->getDatabaseConnection()->getQueryBuilder();
+ $query->delete('storages')
+ ->where($query->expr()->eq('id', $query->createNamedParameter($storageId)));
+ $query->execute();
if (!is_null($numericId)) {
- $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `storage` = ?';
- \OC_DB::executeAudited($sql, [$numericId]);
+ $query = \OC::$server->getDatabaseConnection()->getQueryBuilder();
+ $query->delete('filecache')
+ ->where($query->expr()->eq('storage', $query->createNamedParameter($numericId)));
+ $query->execute();
}
}
}
diff --git a/lib/private/Files/Cache/StorageGlobal.php b/lib/private/Files/Cache/StorageGlobal.php
index 26a7be24634..23d6035084d 100644
--- a/lib/private/Files/Cache/StorageGlobal.php
+++ b/lib/private/Files/Cache/StorageGlobal.php
@@ -2,6 +2,7 @@
/**
* @copyright Robin Appelman <robin@icewind.nl>
*
+ * @author Joas Schilling <coding@schilljs.com>
* @author Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
@@ -61,6 +62,7 @@ class StorageGlobal {
while ($row = $result->fetch()) {
$this->cache[$row['id']] = $row;
}
+ $result->closeCursor();
}
/**
@@ -74,7 +76,10 @@ class StorageGlobal {
->from('storages')
->where($builder->expr()->eq('id', $builder->createNamedParameter($storageId)));
- $row = $query->execute()->fetch();
+ $result = $query->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+
if ($row) {
$this->cache[$storageId] = $row;
}
diff --git a/lib/private/Files/Cache/Updater.php b/lib/private/Files/Cache/Updater.php
index 79501d910e5..04179ba0aaf 100644
--- a/lib/private/Files/Cache/Updater.php
+++ b/lib/private/Files/Cache/Updater.php
@@ -8,7 +8,7 @@
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Files/Cache/Watcher.php b/lib/private/Files/Cache/Watcher.php
index d6291ca71e9..19e17e60959 100644
--- a/lib/private/Files/Cache/Watcher.php
+++ b/lib/private/Files/Cache/Watcher.php
@@ -7,7 +7,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Files/Cache/Wrapper/CacheJail.php b/lib/private/Files/Cache/Wrapper/CacheJail.php
index 8d4f412868e..6c1c17be028 100644
--- a/lib/private/Files/Cache/Wrapper/CacheJail.php
+++ b/lib/private/Files/Cache/Wrapper/CacheJail.php
@@ -2,7 +2,6 @@
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
- * @author Ari Selseng <ari@selseng.net>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Jagszent <daniel@jagszent.de>
* @author Morris Jobke <hey@morrisjobke.de>
@@ -254,9 +253,9 @@ class CacheJail extends CacheWrapper {
* @param string|boolean $path
* @param array $data (optional) meta data of the folder
*/
- public function correctFolderSize($path, $data = null, $isBackgroundSize = false) {
+ public function correctFolderSize($path, $data = null, $isBackgroundScan = false) {
if ($this->getCache() instanceof Cache) {
- $this->getCache()->correctFolderSize($this->getSourcePath($path), $data, $isBackgroundSize);
+ $this->getCache()->correctFolderSize($this->getSourcePath($path), $data, $isBackgroundScan);
}
}
diff --git a/lib/private/Files/Cache/Wrapper/CacheWrapper.php b/lib/private/Files/Cache/Wrapper/CacheWrapper.php
index 4901a530799..cac6cfed87e 100644
--- a/lib/private/Files/Cache/Wrapper/CacheWrapper.php
+++ b/lib/private/Files/Cache/Wrapper/CacheWrapper.php
@@ -10,7 +10,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Files/Config/MountProviderCollection.php b/lib/private/Files/Config/MountProviderCollection.php
index 34db652290f..3900e9870bd 100644
--- a/lib/private/Files/Config/MountProviderCollection.php
+++ b/lib/private/Files/Config/MountProviderCollection.php
@@ -30,6 +30,7 @@ use OC\Hooks\EmitterTrait;
use OCP\Files\Config\IHomeMountProvider;
use OCP\Files\Config\IMountProvider;
use OCP\Files\Config\IMountProviderCollection;
+use OCP\Files\Config\IRootMountProvider;
use OCP\Files\Config\IUserMountCache;
use OCP\Files\Mount\IMountManager;
use OCP\Files\Mount\IMountPoint;
@@ -49,6 +50,9 @@ class MountProviderCollection implements IMountProviderCollection, Emitter {
*/
private $providers = [];
+ /** @var \OCP\Files\Config\IRootMountProvider[] */
+ private $rootProviders = [];
+
/**
* @var \OCP\Files\Storage\IStorageFactory
*/
@@ -198,4 +202,25 @@ class MountProviderCollection implements IMountProviderCollection, Emitter {
public function getMountCache() {
return $this->mountCache;
}
+
+ public function registerRootProvider(IRootMountProvider $provider) {
+ $this->rootProviders[] = $provider;
+ }
+
+ /**
+ * Get all root mountpoints
+ *
+ * @return \OCP\Files\Mount\IMountPoint[]
+ * @since 20.0.0
+ */
+ public function getRootMounts(): array {
+ $loader = $this->loader;
+ $mounts = array_map(function (IRootMountProvider $provider) use ($loader) {
+ return $provider->getRootMounts($loader);
+ }, $this->rootProviders);
+ $mounts = array_reduce($mounts, function (array $mounts, array $providerMounts) {
+ return array_merge($mounts, $providerMounts);
+ }, []);
+ return $mounts;
+ }
}
diff --git a/lib/private/Files/Config/UserMountCache.php b/lib/private/Files/Config/UserMountCache.php
index 9cf3b43a431..46ea1394252 100644
--- a/lib/private/Files/Config/UserMountCache.php
+++ b/lib/private/Files/Config/UserMountCache.php
@@ -4,11 +4,12 @@
*
* @author Dariusz Olszewski <starypatyk@users.noreply.github.com>
* @author Joas Schilling <coding@schilljs.com>
+ * @author Julius Härtl <jus@bitgrid.net>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -234,7 +235,9 @@ class UserMountCache implements IUserMountCache {
->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID())));
- $rows = $query->execute()->fetchAll();
+ $result = $query->execute();
+ $rows = $result->fetchAll();
+ $result->closeCursor();
$this->mountsForUsers[$user->getUID()] = array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
}
@@ -257,7 +260,9 @@ class UserMountCache implements IUserMountCache {
$query->andWhere($builder->expr()->eq('user_id', $builder->createPositionalParameter($user)));
}
- $rows = $query->execute()->fetchAll();
+ $result = $query->execute();
+ $rows = $result->fetchAll();
+ $result->closeCursor();
return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
}
@@ -273,7 +278,9 @@ class UserMountCache implements IUserMountCache {
->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT)));
- $rows = $query->execute()->fetchAll();
+ $result = $query->execute();
+ $rows = $result->fetchAll();
+ $result->closeCursor();
return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
}
@@ -290,7 +297,10 @@ class UserMountCache implements IUserMountCache {
->from('filecache')
->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
- $row = $query->execute()->fetch();
+ $result = $query->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+
if (is_array($row)) {
$this->cacheInfoCache[$fileId] = [
(int)$row['storage'],
@@ -374,7 +384,6 @@ class UserMountCache implements IUserMountCache {
/**
* @param array $users
* @return array
- * @suppress SqlInjectionChecker
*/
public function getUsedSpaceForUsers(array $users) {
$builder = $this->connection->getQueryBuilder();
@@ -409,4 +418,9 @@ class UserMountCache implements IUserMountCache {
$result->closeCursor();
return $results;
}
+
+ public function clear(): void {
+ $this->cacheInfoCache = new CappedMemoryCache();
+ $this->mountsForUsers = new CappedMemoryCache();
+ }
}
diff --git a/lib/private/Files/FileInfo.php b/lib/private/Files/FileInfo.php
index 3c6bdd3b5a0..35e69ae270f 100644
--- a/lib/private/Files/FileInfo.php
+++ b/lib/private/Files/FileInfo.php
@@ -13,7 +13,7 @@
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author tbartenstein <tbartenstein@users.noreply.github.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -95,7 +95,7 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
* @param \OCP\Files\Mount\IMountPoint $mount
* @param \OCP\IUser|null $owner
*/
- public function __construct($path, $storage, $internalPath, $data, $mount, $owner= null) {
+ public function __construct($path, $storage, $internalPath, $data, $mount, $owner = null) {
$this->path = $path;
$this->storage = $storage;
$this->internalPath = $internalPath;
diff --git a/lib/private/Files/Filesystem.php b/lib/private/Files/Filesystem.php
index 9d534815cdc..bf94be273f2 100644
--- a/lib/private/Files/Filesystem.php
+++ b/lib/private/Files/Filesystem.php
@@ -9,6 +9,7 @@
* @author Florin Peter <github@florin-peter.de>
* @author Joas Schilling <coding@schilljs.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author korelstar <korelstar@users.noreply.github.com>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
@@ -17,7 +18,7 @@
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Sam Tuke <mail@samtuke.com>
* @author Stephan Peijnik <speijnik@anexia-it.com>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -437,13 +438,13 @@ class Filesystem {
// home mounts are handled seperate since we need to ensure this is mounted before we call the other mount providers
$homeMount = $mountConfigManager->getHomeMountForUser($userObject);
+ self::getMountManager()->addMount($homeMount);
+
if ($homeMount->getStorageRootId() === -1) {
$homeMount->getStorage()->mkdir('');
$homeMount->getStorage()->getScanner()->scan('');
}
- self::getMountManager()->addMount($homeMount);
-
\OC\Files\Filesystem::getStorage($user);
// Chance to mount for other storages
@@ -813,7 +814,7 @@ class Filesystem {
$cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath, $keepUnicode]);
- if (isset(self::$normalizedPathCache[$cacheKey])) {
+ if ($cacheKey && isset(self::$normalizedPathCache[$cacheKey])) {
return self::$normalizedPathCache[$cacheKey];
}
diff --git a/lib/private/Files/Mount/MountPoint.php b/lib/private/Files/Mount/MountPoint.php
index f9cda6fbce8..cbf3785c409 100644
--- a/lib/private/Files/Mount/MountPoint.php
+++ b/lib/private/Files/Mount/MountPoint.php
@@ -11,7 +11,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -102,6 +102,7 @@ class MountPoint implements IMountPoint {
$mountpoint = $this->formatPath($mountpoint);
$this->mountPoint = $mountpoint;
+ $this->mountId = $mountId;
if ($storage instanceof Storage) {
$this->class = get_class($storage);
$this->storage = $this->loader->wrap($this, $storage);
@@ -113,7 +114,6 @@ class MountPoint implements IMountPoint {
$this->class = $storage;
$this->arguments = $arguments;
}
- $this->mountId = $mountId;
}
/**
diff --git a/lib/private/Files/Mount/ObjectStorePreviewCacheMountProvider.php b/lib/private/Files/Mount/ObjectStorePreviewCacheMountProvider.php
new file mode 100644
index 00000000000..4185c9b86a7
--- /dev/null
+++ b/lib/private/Files/Mount/ObjectStorePreviewCacheMountProvider.php
@@ -0,0 +1,151 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2020, Morris Jobke <hey@morrisjobke.de>
+ *
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @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\Files\Mount;
+
+use OC\Files\ObjectStore\AppdataPreviewObjectStoreStorage;
+use OC\Files\ObjectStore\ObjectStoreStorage;
+use OC\Files\Storage\Wrapper\Jail;
+use OCP\Files\Config\IRootMountProvider;
+use OCP\Files\Storage\IStorageFactory;
+use OCP\IConfig;
+use OCP\ILogger;
+
+/**
+ * Mount provider for object store app data folder for previews
+ */
+class ObjectStorePreviewCacheMountProvider implements IRootMountProvider {
+ /** @var ILogger */
+ private $logger;
+ /** @var IConfig */
+ private $config;
+
+ public function __construct(ILogger $logger, IConfig $config) {
+ $this->logger = $logger;
+ $this->config = $config;
+ }
+
+ /**
+ * @return MountPoint[]
+ * @throws \Exception
+ */
+ public function getRootMounts(IStorageFactory $loader): array {
+ if (!is_array($this->config->getSystemValue('objectstore_multibucket'))) {
+ return [];
+ }
+ if ($this->config->getSystemValue('objectstore.multibucket.preview-distribution', false) !== true) {
+ return [];
+ }
+
+ $instanceId = $this->config->getSystemValueString('instanceid', '');
+ $mountPoints = [];
+ $directoryRange = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
+ $i = 0;
+ foreach ($directoryRange as $parent) {
+ foreach ($directoryRange as $child) {
+ $mountPoints[] = new MountPoint(
+ AppdataPreviewObjectStoreStorage::class,
+ '/appdata_' . $instanceId . '/preview/' . $parent . '/' . $child,
+ $this->getMultiBucketObjectStore($i),
+ $loader
+ );
+ $i++;
+ }
+ }
+
+ $rootStorageArguments = $this->getMultiBucketObjectStoreForRoot();
+ $fakeRootStorage = new ObjectStoreStorage($rootStorageArguments);
+ $fakeRootStorageJail = new Jail([
+ 'storage' => $fakeRootStorage,
+ 'root' => '/appdata_' . $instanceId . '/preview',
+ ]);
+
+ // add a fallback location to be able to fetch existing previews from the old bucket
+ $mountPoints[] = new MountPoint(
+ $fakeRootStorageJail,
+ '/appdata_' . $instanceId . '/preview/old-multibucket',
+ null,
+ $loader
+ );
+
+ return $mountPoints;
+ }
+
+ protected function getMultiBucketObjectStore(int $number): array {
+ $config = $this->config->getSystemValue('objectstore_multibucket');
+
+ // sanity checks
+ if (empty($config['class'])) {
+ $this->logger->error('No class given for objectstore', ['app' => 'files']);
+ }
+ if (!isset($config['arguments'])) {
+ $config['arguments'] = [];
+ }
+
+ /*
+ * Use any provided bucket argument as prefix
+ * and add the mapping from parent/child => bucket
+ */
+ if (!isset($config['arguments']['bucket'])) {
+ $config['arguments']['bucket'] = '';
+ }
+
+ $config['arguments']['bucket'] .= "-preview-$number";
+
+ // instantiate object store implementation
+ $config['arguments']['objectstore'] = new $config['class']($config['arguments']);
+
+ $config['arguments']['internal-id'] = $number;
+
+ return $config['arguments'];
+ }
+
+ protected function getMultiBucketObjectStoreForRoot(): array {
+ $config = $this->config->getSystemValue('objectstore_multibucket');
+
+ // sanity checks
+ if (empty($config['class'])) {
+ $this->logger->error('No class given for objectstore', ['app' => 'files']);
+ }
+ if (!isset($config['arguments'])) {
+ $config['arguments'] = [];
+ }
+
+ /*
+ * Use any provided bucket argument as prefix
+ * and add the mapping from parent/child => bucket
+ */
+ if (!isset($config['arguments']['bucket'])) {
+ $config['arguments']['bucket'] = '';
+ }
+ $config['arguments']['bucket'] .= '0';
+
+ // instantiate object store implementation
+ $config['arguments']['objectstore'] = new $config['class']($config['arguments']);
+
+ return $config['arguments'];
+ }
+}
diff --git a/lib/private/Files/Node/File.php b/lib/private/Files/Node/File.php
index 915e336b996..c140c3e977b 100644
--- a/lib/private/Files/Node/File.php
+++ b/lib/private/Files/Node/File.php
@@ -9,7 +9,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php
index d9639e9f1ab..40499949110 100644
--- a/lib/private/Files/Node/Folder.php
+++ b/lib/private/Files/Node/Folder.php
@@ -4,13 +4,14 @@
*
* @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 Julius Härtl <jus@bitgrid.net>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -31,6 +32,7 @@
namespace OC\Files\Node;
use OC\DB\QueryBuilder\Literal;
+use OC\Files\Storage\Wrapper\Jail;
use OCA\Files_Sharing\SharedStorage;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Files\Config\ICachedMountInfo;
@@ -188,7 +190,7 @@ class Folder extends Node implements \OCP\Files\Folder {
} else {
$result = $this->view->touch($fullPath);
}
- if (!$result) {
+ if ($result === false) {
throw new NotPermittedException('Could not create path');
}
$node = new File($this->root, $this->view, $fullPath);
@@ -438,13 +440,33 @@ class Folder extends Node implements \OCP\Files\Folder {
$mountMap = array_combine($storageIds, $mounts);
$folderMimetype = $mimetypeLoader->getId(FileInfo::MIMETYPE_FOLDER);
+ /*
+ * Construct an array of the storage id with their prefix path
+ * This helps us to filter in the final query
+ */
+ $filters = array_map(function (IMountPoint $mount) {
+ $storage = $mount->getStorage();
+
+ $storageId = $storage->getCache()->getNumericStorageId();
+ $prefix = '';
+
+ if ($storage->instanceOfStorage(Jail::class)) {
+ $prefix = $storage->getUnJailedPath('');
+ }
+
+ return [
+ 'storageId' => $storageId,
+ 'pathPrefix' => $prefix,
+ ];
+ }, $mounts);
+
// Search in batches of 500 entries
$searchLimit = 500;
$results = [];
$searchResultCount = 0;
$count = 0;
do {
- $searchResult = $this->recentSearch($searchLimit, $offset, $storageIds, $folderMimetype);
+ $searchResult = $this->recentSearch($searchLimit, $offset, $folderMimetype, $filters);
// Exit condition if there are no more results
if (count($searchResult) === 0) {
@@ -466,13 +488,36 @@ class Folder extends Node implements \OCP\Files\Folder {
return array_slice($results, 0, $limit);
}
- private function recentSearch($limit, $offset, $storageIds, $folderMimetype) {
- $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
+ private function recentSearch($limit, $offset, $folderMimetype, $filters) {
+ $dbconn = \OC::$server->getDatabaseConnection();
+ $builder = $dbconn->getQueryBuilder();
$query = $builder
->select('f.*')
- ->from('filecache', 'f')
- ->andWhere($builder->expr()->in('f.storage', $builder->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)))
- ->andWhere($builder->expr()->orX(
+ ->from('filecache', 'f');
+
+ /*
+ * Here is where we construct the filtering.
+ * Note that this is expensive filtering as it is a lot of like queries.
+ * However the alternative is we do this filtering and parsing later in php with the risk of looping endlessly
+ */
+ $storageFilters = $builder->expr()->orX();
+ foreach ($filters as $filter) {
+ $storageFilter = $builder->expr()->andX(
+ $builder->expr()->eq('f.storage', $builder->createNamedParameter($filter['storageId']))
+ );
+
+ if ($filter['pathPrefix'] !== '') {
+ $storageFilter->add(
+ $builder->expr()->like('f.path', $builder->createNamedParameter($dbconn->escapeLikeParameter($filter['pathPrefix']) . '/%'))
+ );
+ }
+
+ $storageFilters->add($storageFilter);
+ }
+
+ $query->andWhere($storageFilters);
+
+ $query->andWhere($builder->expr()->orX(
// handle non empty folders separate
$builder->expr()->neq('f.mimetype', $builder->createNamedParameter($folderMimetype, IQueryBuilder::PARAM_INT)),
$builder->expr()->eq('f.size', new Literal(0))
@@ -482,7 +527,12 @@ class Folder extends Node implements \OCP\Files\Folder {
->orderBy('f.mtime', 'DESC')
->setMaxResults($limit)
->setFirstResult($offset);
- return $query->execute()->fetchAll();
+
+ $result = $query->execute();
+ $rows = $result->fetchAll();
+ $result->closeCursor();
+
+ return $rows;
}
private function recentParse($result, $mountMap, $mimetypeLoader) {
diff --git a/lib/private/Files/Node/LazyFolder.php b/lib/private/Files/Node/LazyFolder.php
index 50cd0f90110..52dfb3c20a4 100644
--- a/lib/private/Files/Node/LazyFolder.php
+++ b/lib/private/Files/Node/LazyFolder.php
@@ -1,9 +1,12 @@
<?php
declare(strict_types=1);
+
/**
* @copyright Copyright (c) 2020 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
@@ -17,7 +20,7 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff --git a/lib/private/Files/Node/LazyRoot.php b/lib/private/Files/Node/LazyRoot.php
index e17640373fe..899fd130655 100644
--- a/lib/private/Files/Node/LazyRoot.php
+++ b/lib/private/Files/Node/LazyRoot.php
@@ -2,7 +2,6 @@
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
diff --git a/lib/private/Files/Node/Node.php b/lib/private/Files/Node/Node.php
index 70821e685f8..92635a55baa 100644
--- a/lib/private/Files/Node/Node.php
+++ b/lib/private/Files/Node/Node.php
@@ -10,7 +10,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Files/Node/NonExistingFolder.php b/lib/private/Files/Node/NonExistingFolder.php
index 65af837da43..eaf7963eb9b 100644
--- a/lib/private/Files/Node/NonExistingFolder.php
+++ b/lib/private/Files/Node/NonExistingFolder.php
@@ -4,7 +4,7 @@
*
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php
index f24082851e0..fba8a24b40f 100644
--- a/lib/private/Files/Node/Root.php
+++ b/lib/private/Files/Node/Root.php
@@ -12,7 +12,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Stefan Weil <sw@weilnetz.de>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Files/ObjectStore/AppdataPreviewObjectStoreStorage.php b/lib/private/Files/ObjectStore/AppdataPreviewObjectStoreStorage.php
new file mode 100644
index 00000000000..bdc41f9ed95
--- /dev/null
+++ b/lib/private/Files/ObjectStore/AppdataPreviewObjectStoreStorage.php
@@ -0,0 +1,45 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2020, Morris Jobke <hey@morrisjobke.de>
+ *
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @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\Files\ObjectStore;
+
+class AppdataPreviewObjectStoreStorage extends ObjectStoreStorage {
+
+ /** @var string */
+ private $internalId;
+
+ public function __construct($params) {
+ if (!isset($params['internal-id'])) {
+ throw new \Exception('missing id in parameters');
+ }
+ $this->internalId = (string)$params['internal-id'];
+ parent::__construct($params);
+ }
+
+ public function getId() {
+ return 'object::appdata::preview:' . $this->internalId;
+ }
+}
diff --git a/lib/private/Files/ObjectStore/Azure.php b/lib/private/Files/ObjectStore/Azure.php
index 0b65a6b80e5..2ef13d60c56 100644
--- a/lib/private/Files/ObjectStore/Azure.php
+++ b/lib/private/Files/ObjectStore/Azure.php
@@ -130,4 +130,8 @@ class Azure implements IObjectStore {
}
}
}
+
+ public function copyObject($from, $to) {
+ $this->getBlobClient()->copyBlob($this->containerName, $to, $this->containerName, $from);
+ }
}
diff --git a/lib/private/Files/ObjectStore/NoopScanner.php b/lib/private/Files/ObjectStore/NoopScanner.php
index 25b52416efd..9195e7f8d9f 100644
--- a/lib/private/Files/ObjectStore/NoopScanner.php
+++ b/lib/private/Files/ObjectStore/NoopScanner.php
@@ -69,7 +69,7 @@ class NoopScanner extends Scanner {
* @param array $folderData existing cache data for the folder to be scanned
* @return int the size of the scanned folder or -1 if the size is unknown at this stage
*/
- protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $folderData = null, $lock = true) {
+ protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $folderId = null, $lock = true) {
return 0;
}
diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php
index a5112bcbba6..9815fe6a245 100644
--- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php
+++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php
@@ -33,10 +33,15 @@ use Icewind\Streams\CallbackWrapper;
use Icewind\Streams\CountWrapper;
use Icewind\Streams\IteratorDirectory;
use OC\Files\Cache\CacheEntry;
+use OC\Files\Storage\PolyFill\CopyDirectory;
+use OCP\Files\Cache\ICacheEntry;
+use OCP\Files\FileInfo;
use OCP\Files\NotFoundException;
use OCP\Files\ObjectStore\IObjectStore;
class ObjectStoreStorage extends \OC\Files\Storage\Common {
+ use CopyDirectory;
+
/**
* @var \OCP\Files\ObjectStore\IObjectStore $objectStore
*/
@@ -227,6 +232,16 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
}
}
+ public function getPermissions($path) {
+ $stat = $this->stat($path);
+
+ if (is_array($stat) && isset($stat['permissions'])) {
+ return $stat['permissions'];
+ }
+
+ return parent::getPermissions($path);
+ }
+
/**
* Override this method if you need a different unique resource identifier for your object storage implementation.
* The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
@@ -286,6 +301,11 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
case 'rb':
$stat = $this->stat($path);
if (is_array($stat)) {
+ // Reading 0 sized files is a waste of time
+ if (isset($stat['size']) && $stat['size'] === 0) {
+ return fopen('php://memory', $mode);
+ }
+
try {
return $this->objectStore->readObject($this->getURN($stat['fileid']));
} catch (NotFoundException $e) {
@@ -304,7 +324,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
} else {
return false;
}
- // no break
+ // no break
case 'w':
case 'wb':
case 'w+':
@@ -419,9 +439,9 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
public function file_put_contents($path, $data) {
$handle = $this->fopen($path, 'w+');
- fwrite($handle, $data);
+ $result = fwrite($handle, $data);
fclose($handle);
- return true;
+ return $result;
}
public function writeStream(string $path, $stream, int $size = null): int {
@@ -446,14 +466,20 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
$exists = $this->getCache()->inCache($path);
$uploadPath = $exists ? $path : $path . '.part';
- $fileId = $this->getCache()->put($uploadPath, $stat);
+
+ if ($exists) {
+ $fileId = $stat['fileid'];
+ } else {
+ $fileId = $this->getCache()->put($uploadPath, $stat);
+ }
+
$urn = $this->getURN($fileId);
try {
//upload to object storage
if ($size === null) {
$countStream = CountWrapper::wrap($stream, function ($writtenSize) use ($fileId, &$size) {
$this->getCache()->update($fileId, [
- 'size' => $writtenSize
+ 'size' => $writtenSize,
]);
$size = $writtenSize;
});
@@ -461,19 +487,33 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
if (is_resource($countStream)) {
fclose($countStream);
}
+ $stat['size'] = $size;
} else {
$this->objectStore->writeObject($urn, $stream);
}
} catch (\Exception $ex) {
- $this->getCache()->remove($uploadPath);
- $this->logger->logException($ex, [
- 'app' => 'objectstore',
- 'message' => 'Could not create object ' . $urn . ' for ' . $path,
- ]);
+ if (!$exists) {
+ /*
+ * Only remove the entry if we are dealing with a new file.
+ * Else people lose access to existing files
+ */
+ $this->getCache()->remove($uploadPath);
+ $this->logger->logException($ex, [
+ 'app' => 'objectstore',
+ 'message' => 'Could not create object ' . $urn . ' for ' . $path,
+ ]);
+ } else {
+ $this->logger->logException($ex, [
+ 'app' => 'objectstore',
+ 'message' => 'Could not update object ' . $urn . ' for ' . $path,
+ ]);
+ }
throw $ex; // make this bubble up
}
- if (!$exists) {
+ if ($exists) {
+ $this->getCache()->update($fileId, $stat);
+ } else {
if ($this->objectStore->objectExists($urn)) {
$this->getCache()->move($uploadPath, $path);
} else {
@@ -488,4 +528,59 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common {
public function getObjectStore(): IObjectStore {
return $this->objectStore;
}
+
+ public function copy($path1, $path2) {
+ $path1 = $this->normalizePath($path1);
+ $path2 = $this->normalizePath($path2);
+
+ $cache = $this->getCache();
+ $sourceEntry = $cache->get($path1);
+ if (!$sourceEntry) {
+ throw new NotFoundException('Source object not found');
+ }
+
+ $this->copyInner($sourceEntry, $path2);
+
+ return true;
+ }
+
+ private function copyInner(ICacheEntry $sourceEntry, string $to) {
+ $cache = $this->getCache();
+
+ if ($sourceEntry->getMimeType() === FileInfo::MIMETYPE_FOLDER) {
+ if ($cache->inCache($to)) {
+ $cache->remove($to);
+ }
+ $this->mkdir($to);
+
+ foreach ($cache->getFolderContentsById($sourceEntry->getId()) as $child) {
+ $this->copyInner($child, $to . '/' . $child->getName());
+ }
+ } else {
+ $this->copyFile($sourceEntry, $to);
+ }
+ }
+
+ private function copyFile(ICacheEntry $sourceEntry, string $to) {
+ $cache = $this->getCache();
+
+ $sourceUrn = $this->getURN($sourceEntry->getId());
+
+ $cache->copyFromCache($cache, $sourceEntry, $to);
+ $targetEntry = $cache->get($to);
+
+ if (!$targetEntry) {
+ throw new \Exception('Target not in cache after copy');
+ }
+
+ $targetUrn = $this->getURN($targetEntry->getId());
+
+ try {
+ $this->objectStore->copyObject($sourceUrn, $targetUrn);
+ } catch (\Exception $e) {
+ $cache->remove($to);
+
+ throw $e;
+ }
+ }
}
diff --git a/lib/private/Files/ObjectStore/S3ConnectionTrait.php b/lib/private/Files/ObjectStore/S3ConnectionTrait.php
index b96a11833cd..6b469860de5 100644
--- a/lib/private/Files/ObjectStore/S3ConnectionTrait.php
+++ b/lib/private/Files/ObjectStore/S3ConnectionTrait.php
@@ -4,9 +4,12 @@
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Florent <florent@coppint.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
* @author S. Cat <33800996+sparrowjack63@users.noreply.github.com>
+ * @author Stephen Cuppett <steve@cuppett.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -28,8 +31,13 @@
namespace OC\Files\ObjectStore;
use Aws\ClientResolver;
+use Aws\Credentials\CredentialProvider;
+use Aws\Credentials\Credentials;
+use Aws\Exception\CredentialsException;
use Aws\S3\Exception\S3Exception;
use Aws\S3\S3Client;
+use GuzzleHttp\Promise;
+use GuzzleHttp\Promise\RejectedPromise;
use OCP\ILogger;
trait S3ConnectionTrait {
@@ -54,8 +62,8 @@ trait S3ConnectionTrait {
protected $test;
protected function parseParams($params) {
- if (empty($params['key']) || empty($params['secret']) || empty($params['bucket'])) {
- throw new \Exception("Access Key, Secret and Bucket have to be configured.");
+ if (empty($params['bucket'])) {
+ throw new \Exception("Bucket has to be configured.");
}
$this->id = 'amazon::' . $params['bucket'];
@@ -69,6 +77,7 @@ trait S3ConnectionTrait {
if (!isset($params['port']) || $params['port'] === '') {
$params['port'] = (isset($params['use_ssl']) && $params['use_ssl'] === false) ? 80 : 443;
}
+ $params['verify_bucket_exists'] = empty($params['verify_bucket_exists']) ? true : $params['verify_bucket_exists'];
$this->params = $params;
}
@@ -90,12 +99,19 @@ trait S3ConnectionTrait {
$scheme = (isset($this->params['use_ssl']) && $this->params['use_ssl'] === false) ? 'http' : 'https';
$base_url = $scheme . '://' . $this->params['hostname'] . ':' . $this->params['port'] . '/';
+ // Adding explicit credential provider to the beginning chain.
+ // Including environment variables and IAM instance profiles.
+ $provider = CredentialProvider::memoize(
+ CredentialProvider::chain(
+ $this->paramCredentialProvider(),
+ CredentialProvider::env(),
+ CredentialProvider::instanceProfile()
+ )
+ );
+
$options = [
'version' => isset($this->params['version']) ? $this->params['version'] : 'latest',
- 'credentials' => [
- 'key' => $this->params['key'],
- 'secret' => $this->params['secret'],
- ],
+ 'credentials' => $provider,
'endpoint' => $base_url,
'region' => $this->params['region'],
'use_path_style_endpoint' => isset($this->params['use_path_style']) ? $this->params['use_path_style'] : false,
@@ -116,7 +132,7 @@ trait S3ConnectionTrait {
['app' => 'objectstore']);
}
- if (!$this->connection->doesBucketExist($this->bucket)) {
+ if ($this->params['verify_bucket_exists'] && !$this->connection->doesBucketExist($this->bucket)) {
$logger = \OC::$server->getLogger();
try {
$logger->info('Bucket "' . $this->bucket . '" does not exist - creating it.', ['app' => 'objectstore']);
@@ -161,4 +177,23 @@ trait S3ConnectionTrait {
return null;
}
}
+
+ /**
+ * This function creates a credential provider based on user parameter file
+ */
+ protected function paramCredentialProvider() : callable {
+ return function () {
+ $key = empty($this->params['key']) ? null : $this->params['key'];
+ $secret = empty($this->params['secret']) ? null : $this->params['secret'];
+
+ if ($key && $secret) {
+ return Promise\promise_for(
+ new Credentials($key, $secret)
+ );
+ }
+
+ $msg = 'Could not find parameters set for credentials in config file.';
+ return new RejectedPromise(new CredentialsException($msg));
+ };
+ }
}
diff --git a/lib/private/Files/ObjectStore/S3ObjectTrait.php b/lib/private/Files/ObjectStore/S3ObjectTrait.php
index d7c878178d2..80b8a6f132d 100644
--- a/lib/private/Files/ObjectStore/S3ObjectTrait.php
+++ b/lib/private/Files/ObjectStore/S3ObjectTrait.php
@@ -3,6 +3,7 @@
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Florent <florent@coppint.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -123,4 +124,8 @@ trait S3ObjectTrait {
public function objectExists($urn) {
return $this->getConnection()->doesObjectExist($this->bucket, $urn);
}
+
+ public function copyObject($from, $to) {
+ $this->getConnection()->copy($this->getBucket(), $from, $this->getBucket(), $to);
+ }
}
diff --git a/lib/private/Files/ObjectStore/S3Signature.php b/lib/private/Files/ObjectStore/S3Signature.php
index bcd1eef7b2a..ab8854849fa 100644
--- a/lib/private/Files/ObjectStore/S3Signature.php
+++ b/lib/private/Files/ObjectStore/S3Signature.php
@@ -3,6 +3,7 @@
*
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
@@ -128,7 +129,7 @@ class S3Signature implements SignatureInterface {
) {
$modify = [
'remove_headers' => ['X-Amz-Date'],
- 'set_headers' => ['Date' => gmdate(\DateTime::RFC2822)]
+ 'set_headers' => ['Date' => gmdate(\DateTime::RFC2822)]
];
// Add the security token header if one is being used by the credentials
diff --git a/lib/private/Files/ObjectStore/StorageObjectStore.php b/lib/private/Files/ObjectStore/StorageObjectStore.php
index a7551385b34..acf46758956 100644
--- a/lib/private/Files/ObjectStore/StorageObjectStore.php
+++ b/lib/private/Files/ObjectStore/StorageObjectStore.php
@@ -93,4 +93,8 @@ class StorageObjectStore implements IObjectStore {
public function objectExists($urn) {
return $this->storage->file_exists($urn);
}
+
+ public function copyObject($from, $to) {
+ $this->storage->copy($from, $to);
+ }
}
diff --git a/lib/private/Files/ObjectStore/Swift.php b/lib/private/Files/ObjectStore/Swift.php
index 87347c3f71b..1b0888b0700 100644
--- a/lib/private/Files/ObjectStore/Swift.php
+++ b/lib/private/Files/ObjectStore/Swift.php
@@ -2,6 +2,7 @@
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
+ * @author Adrian Brzezinski <adrian.brzezinski@eo.pl>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
@@ -86,13 +87,13 @@ class Swift implements IObjectStore {
if (filesize($tmpFile) < SWIFT_SEGMENT_SIZE) {
$this->getContainer()->createObject([
'name' => $urn,
- 'stream' => stream_for($handle)
+ 'stream' => stream_for($handle),
]);
} else {
$this->getContainer()->createLargeObject([
'name' => $urn,
'stream' => stream_for($handle),
- 'segmentSize' => SWIFT_SEGMENT_SIZE
+ 'segmentSize' => SWIFT_SEGMENT_SIZE,
]);
}
}
@@ -113,7 +114,7 @@ class Swift implements IObjectStore {
'stream' => true,
'headers' => [
'X-Auth-Token' => $tokenId,
- 'Cache-Control' => 'no-cache'
+ 'Cache-Control' => 'no-cache',
],
]
);
@@ -148,4 +149,10 @@ class Swift implements IObjectStore {
public function objectExists($urn) {
return $this->getContainer()->objectExists($urn);
}
+
+ public function copyObject($from, $to) {
+ $this->getContainer()->getObject($from)->copy([
+ 'destination' => $this->getContainer()->name . '/' . $to
+ ]);
+ }
}
diff --git a/lib/private/Files/ObjectStore/SwiftFactory.php b/lib/private/Files/ObjectStore/SwiftFactory.php
index 0354fba638f..54975e8d021 100644
--- a/lib/private/Files/ObjectStore/SwiftFactory.php
+++ b/lib/private/Files/ObjectStore/SwiftFactory.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
/**
* @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
*
+ * @author Adrian Brzezinski <adrian.brzezinski@eo.pl>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Julien Lutran <julien.lutran@corp.ovh.com>
* @author Morris Jobke <hey@morrisjobke.de>
diff --git a/lib/private/Files/Storage/Common.php b/lib/private/Files/Storage/Common.php
index 958d09832c4..6a530877f43 100644
--- a/lib/private/Files/Storage/Common.php
+++ b/lib/private/Files/Storage/Common.php
@@ -4,7 +4,6 @@
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Bart Visscher <bartv@thisnet.nl>
- * @author Björn Schießle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Greta Doci <gretadoci@gmail.com>
* @author hkjolhede <hkjolhede@gmail.com>
@@ -22,7 +21,7 @@
* @author scambra <sergio@entrecables.com>
* @author Stefan Weil <sw@weilnetz.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
* @author Vinicius Cubas Brand <vinicius@eita.org.br>
*
* @license AGPL-3.0
diff --git a/lib/private/Files/Storage/CommonTest.php b/lib/private/Files/Storage/CommonTest.php
index b59090893d4..43a87f8d704 100644
--- a/lib/private/Files/Storage/CommonTest.php
+++ b/lib/private/Files/Storage/CommonTest.php
@@ -41,7 +41,7 @@ class CommonTest extends \OC\Files\Storage\Common {
private $storage;
public function __construct($params) {
- $this->storage=new \OC\Files\Storage\Local($params);
+ $this->storage = new \OC\Files\Storage\Local($params);
}
public function getId() {
@@ -80,7 +80,7 @@ class CommonTest extends \OC\Files\Storage\Common {
public function free_space($path) {
return $this->storage->free_space($path);
}
- public function touch($path, $mtime=null) {
+ public function touch($path, $mtime = null) {
return $this->storage->touch($path, $mtime);
}
}
diff --git a/lib/private/Files/Storage/DAV.php b/lib/private/Files/Storage/DAV.php
index 269cd49b4e1..8f5001c8143 100644
--- a/lib/private/Files/Storage/DAV.php
+++ b/lib/private/Files/Storage/DAV.php
@@ -7,6 +7,7 @@
* @author Björn Schießle <bjoern@schiessle.org>
* @author Carlos Cerrillo <ccerrillo@gmail.com>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Joas Schilling <coding@schilljs.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@statuscode.ch>
@@ -16,7 +17,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -121,9 +122,6 @@ class DAV extends Common {
if ($this->secure === true) {
// inject mock for testing
$this->certManager = \OC::$server->getCertificateManager();
- if (is_null($this->certManager)) { //no user
- $this->certManager = \OC::$server->getCertificateManager(null);
- }
}
$this->root = $params['root'] ?? '/';
$this->root = '/' . ltrim($this->root, '/');
@@ -488,8 +486,8 @@ class DAV extends Common {
/**
* @param string $path
- * @param string $data
- * @return int
+ * @param mixed $data
+ * @return int|false
*/
public function file_put_contents($path, $data) {
$path = $this->cleanPath($path);
diff --git a/lib/private/Files/Storage/FailedStorage.php b/lib/private/Files/Storage/FailedStorage.php
index 50e2f255430..bb97fe73875 100644
--- a/lib/private/Files/Storage/FailedStorage.php
+++ b/lib/private/Files/Storage/FailedStorage.php
@@ -6,7 +6,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Files/Storage/Flysystem.php b/lib/private/Files/Storage/Flysystem.php
index a7747823acc..9b26516bef3 100644
--- a/lib/private/Files/Storage/Flysystem.php
+++ b/lib/private/Files/Storage/Flysystem.php
@@ -73,7 +73,11 @@ abstract class Flysystem extends Common {
* {@inheritdoc}
*/
public function file_put_contents($path, $data) {
- return $this->flysystem->put($this->buildPath($path), $data);
+ $result = $this->flysystem->put($this->buildPath($path), $data);
+ if ($result === true) {
+ return strlen($data);
+ }
+ return $result;
}
/**
diff --git a/lib/private/Files/Storage/Home.php b/lib/private/Files/Storage/Home.php
index c725076893f..5c35c93bfc8 100644
--- a/lib/private/Files/Storage/Home.php
+++ b/lib/private/Files/Storage/Home.php
@@ -6,7 +6,7 @@
* @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>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Files/Storage/Local.php b/lib/private/Files/Storage/Local.php
index 0b636d06bde..5d0ce596b11 100644
--- a/lib/private/Files/Storage/Local.php
+++ b/lib/private/Files/Storage/Local.php
@@ -2,11 +2,13 @@
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
+ * @author aler9 <46489434+aler9@users.noreply.github.com>
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Bart Visscher <bartv@thisnet.nl>
* @author Boris Rybalkin <ribalkin@gmail.com>
* @author Brice Maron <brice@bmaron.net>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author J0WI <J0WI@users.noreply.github.com>
* @author Jakob Sack <mail@jakobsack.de>
* @author Joas Schilling <coding@schilljs.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
@@ -20,7 +22,7 @@
* @author Stefan Weil <sw@weilnetz.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -109,6 +111,7 @@ class Local extends \OC\Files\Storage\Common {
* @var \SplFileInfo $file
*/
$file = $it->current();
+ clearstatcache(true, $this->getSourcePath($file));
if (in_array($file->getBasename(), ['.', '..'])) {
$it->next();
continue;
@@ -119,6 +122,7 @@ class Local extends \OC\Files\Storage\Common {
}
$it->next();
}
+ clearstatcache(true, $this->getSourcePath($path));
return rmdir($this->getSourcePath($path));
} catch (\UnexpectedValueException $e) {
return false;
@@ -141,10 +145,10 @@ class Local extends \OC\Files\Storage\Common {
}
public function stat($path) {
- clearstatcache();
$fullPath = $this->getSourcePath($path);
- $statResult = stat($fullPath);
- if (PHP_INT_SIZE === 4 && !$this->is_dir($path)) {
+ clearstatcache(true, $fullPath);
+ $statResult = @stat($fullPath);
+ if (PHP_INT_SIZE === 4 && $statResult && !$this->is_dir($path)) {
$filesize = $this->filesize($path);
$statResult['size'] = $filesize;
$statResult[7] = $filesize;
@@ -156,9 +160,7 @@ class Local extends \OC\Files\Storage\Common {
* @inheritdoc
*/
public function getMetaData($path) {
- $fullPath = $this->getSourcePath($path);
- clearstatcache();
- $stat = @stat($fullPath);
+ $stat = $this->stat($path);
if (!$stat) {
return null;
}
@@ -177,6 +179,7 @@ class Local extends \OC\Files\Storage\Common {
}
if (!($path === '' || $path === '/')) { // deletable depends on the parents unix permissions
+ $fullPath = $this->getSourcePath($path);
$parent = dirname($fullPath);
if (is_writable($parent)) {
$permissions += Constants::PERMISSION_DELETE;
@@ -554,7 +557,7 @@ class Local extends \OC\Files\Storage\Common {
}
public function writeStream(string $path, $stream, int $size = null): int {
- $result = file_put_contents($this->getSourcePath($path), $stream);
+ $result = $this->file_put_contents($path, $stream);
if ($result === false) {
throw new GenericFileException("Failed write steam to $path");
} else {
diff --git a/lib/private/Files/Storage/LocalRootStorage.php b/lib/private/Files/Storage/LocalRootStorage.php
index 0ad9c18b640..6f954212484 100644
--- a/lib/private/Files/Storage/LocalRootStorage.php
+++ b/lib/private/Files/Storage/LocalRootStorage.php
@@ -1,9 +1,12 @@
<?php
declare(strict_types=1);
+
/**
* @copyright Copyright (c) 2020 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
@@ -17,7 +20,7 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff --git a/lib/private/Files/Storage/StorageFactory.php b/lib/private/Files/Storage/StorageFactory.php
index 52ddbfb2ed5..2e7dd732edd 100644
--- a/lib/private/Files/Storage/StorageFactory.php
+++ b/lib/private/Files/Storage/StorageFactory.php
@@ -5,7 +5,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Files/Storage/Temporary.php b/lib/private/Files/Storage/Temporary.php
index 5e4024286c5..686600e5d21 100644
--- a/lib/private/Files/Storage/Temporary.php
+++ b/lib/private/Files/Storage/Temporary.php
@@ -6,7 +6,7 @@
* @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>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Files/Storage/Wrapper/Encoding.php b/lib/private/Files/Storage/Wrapper/Encoding.php
index a2ef1780d6c..b837f77fbbc 100644
--- a/lib/private/Files/Storage/Wrapper/Encoding.php
+++ b/lib/private/Files/Storage/Wrapper/Encoding.php
@@ -5,7 +5,7 @@
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -309,8 +309,8 @@ class Encoding extends Wrapper {
* see http://php.net/manual/en/function.file_put_contents.php
*
* @param string $path
- * @param string $data
- * @return bool
+ * @param mixed $data
+ * @return int|false
*/
public function file_put_contents($path, $data) {
return $this->storage->file_put_contents($this->findPathToUse($path), $data);
diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php
index 897624ff6ae..8efb1c20980 100644
--- a/lib/private/Files/Storage/Wrapper/Encryption.php
+++ b/lib/private/Files/Storage/Wrapper/Encryption.php
@@ -13,7 +13,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -234,8 +234,8 @@ class Encryption extends Wrapper {
* see http://php.net/manual/en/function.file_put_contents.php
*
* @param string $path
- * @param string $data
- * @return bool
+ * @param mixed $data
+ * @return int|false
*/
public function file_put_contents($path, $data) {
// file put content will always be translated to a stream write
@@ -263,7 +263,7 @@ class Encryption extends Wrapper {
$encryptionModule = $this->getEncryptionModule($path);
if ($encryptionModule) {
- $this->keyStorage->deleteAllFileKeys($this->getFullPath($path));
+ $this->keyStorage->deleteAllFileKeys($fullPath);
}
return $this->storage->unlink($path);
@@ -818,6 +818,7 @@ class Encryption extends Wrapper {
$fileSize = $this->filesize($path);
$stat['size'] = $fileSize;
$stat[7] = $fileSize;
+ $stat['hasHeader'] = $this->getHeaderSize($path) > 0;
return $stat;
}
diff --git a/lib/private/Files/Storage/Wrapper/Jail.php b/lib/private/Files/Storage/Wrapper/Jail.php
index 7350c104ba8..2396c07a0f1 100644
--- a/lib/private/Files/Storage/Wrapper/Jail.php
+++ b/lib/private/Files/Storage/Wrapper/Jail.php
@@ -56,11 +56,7 @@ class Jail extends Wrapper {
}
public function getUnjailedPath($path) {
- if ($path === '') {
- return $this->rootPath;
- } else {
- return Filesystem::normalizePath($this->rootPath . '/' . $path);
- }
+ return trim(Filesystem::normalizePath($this->rootPath . '/' . $path), '/');
}
/**
@@ -263,8 +259,8 @@ class Jail extends Wrapper {
* see http://php.net/manual/en/function.file_put_contents.php
*
* @param string $path
- * @param string $data
- * @return bool
+ * @param mixed $data
+ * @return int|false
*/
public function file_put_contents($path, $data) {
return $this->getWrapperStorage()->file_put_contents($this->getUnjailedPath($path), $data);
diff --git a/lib/private/Files/Storage/Wrapper/Quota.php b/lib/private/Files/Storage/Wrapper/Quota.php
index 62d3335987c..4de1c091a97 100644
--- a/lib/private/Files/Storage/Wrapper/Quota.php
+++ b/lib/private/Files/Storage/Wrapper/Quota.php
@@ -2,6 +2,7 @@
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
+ * @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Julius Härtl <jus@bitgrid.net>
* @author Lukas Reschke <lukas@statuscode.ch>
@@ -9,7 +10,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -71,7 +72,10 @@ class Quota extends Wrapper {
protected function getSize($path, $storage = null) {
if ($this->config->getValue('quota_include_external_storage', false)) {
$rootInfo = Filesystem::getFileInfo('', 'ext');
- return $rootInfo->getSize(true);
+ if ($rootInfo) {
+ return $rootInfo->getSize(true);
+ }
+ return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
} else {
if (is_null($storage)) {
$cache = $this->getCache();
@@ -118,8 +122,8 @@ class Quota extends Wrapper {
* see http://php.net/manual/en/function.file_put_contents.php
*
* @param string $path
- * @param string $data
- * @return bool
+ * @param mixed $data
+ * @return int|false
*/
public function file_put_contents($path, $data) {
$free = $this->free_space($path);
@@ -161,7 +165,7 @@ class Quota extends Wrapper {
$free = $this->free_space($path);
if ($source && $free >= 0 && $mode !== 'r' && $mode !== 'rb') {
// only apply quota for files, not metadata, trash or others
- if (strpos(ltrim($path, '/'), 'files/') === 0) {
+ if ($this->shouldApplyQuota($path)) {
return \OC\Files\Stream\Quota::wrap($source, $free);
}
}
@@ -183,6 +187,13 @@ class Quota extends Wrapper {
}
/**
+ * Only apply quota for files, not metadata, trash or others
+ */
+ private function shouldApplyQuota(string $path): bool {
+ return strpos(ltrim($path, '/'), 'files/') === 0;
+ }
+
+ /**
* @param IStorage $sourceStorage
* @param string $sourceInternalPath
* @param string $targetInternalPath
@@ -214,7 +225,7 @@ class Quota extends Wrapper {
public function mkdir($path) {
$free = $this->free_space($path);
- if ($free === 0.0) {
+ if ($this->shouldApplyQuota($path) && $free === 0.0) {
return false;
}
diff --git a/lib/private/Files/Storage/Wrapper/Wrapper.php b/lib/private/Files/Storage/Wrapper/Wrapper.php
index 4584bebe076..e94f3714c9e 100644
--- a/lib/private/Files/Storage/Wrapper/Wrapper.php
+++ b/lib/private/Files/Storage/Wrapper/Wrapper.php
@@ -9,7 +9,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
* @author Vinicius Cubas Brand <vinicius@eita.org.br>
*
* @license AGPL-3.0
@@ -250,8 +250,8 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
* see http://php.net/manual/en/function.file_put_contents.php
*
* @param string $path
- * @param string $data
- * @return bool
+ * @param mixed $data
+ * @return int|false
*/
public function file_put_contents($path, $data) {
return $this->getWrapperStorage()->file_put_contents($path, $data);
diff --git a/lib/private/Files/Stream/Encryption.php b/lib/private/Files/Stream/Encryption.php
index 1fc14daacbd..577d1554101 100644
--- a/lib/private/Files/Stream/Encryption.php
+++ b/lib/private/Files/Stream/Encryption.php
@@ -12,7 +12,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -416,7 +416,7 @@ class Encryption extends Wrapper {
return $return;
}
- $newFilePosition = floor($newPosition / $this->unencryptedBlockSize)
+ $newFilePosition = (int)floor($newPosition / $this->unencryptedBlockSize)
* $this->util->getBlockSize() + $this->headerSize;
$oldFilePosition = parent::stream_tell();
@@ -432,7 +432,7 @@ class Encryption extends Wrapper {
public function stream_close() {
$this->flush('end');
- $position = (int)floor($this->position/$this->unencryptedBlockSize);
+ $position = (int)floor($this->position / $this->unencryptedBlockSize);
$remainingData = $this->encryptionModule->end($this->fullPath, $position . 'end');
if ($this->readOnly === false) {
if (!empty($remainingData)) {
@@ -465,7 +465,7 @@ class Encryption extends Wrapper {
// automatically attempted when the file is written to disk -
// we are handling that separately here and we don't want to
// get into an infinite loop
- $position = (int)floor($this->position/$this->unencryptedBlockSize);
+ $position = (int)floor($this->position / $this->unencryptedBlockSize);
$encrypted = $this->encryptionModule->encrypt($this->cache, $position . $positionPrefix);
$bytesWritten = parent::stream_write($encrypted);
$this->writeFlag = false;
@@ -473,8 +473,8 @@ class Encryption extends Wrapper {
// If so then update the encrypted filesize
// Note that the unencrypted pointer and filesize are NOT yet updated when flush() is called
// We recalculate the encrypted filesize as we do not know the context of calling flush()
- $completeBlocksInFile=(int)floor($this->unencryptedSize/$this->unencryptedBlockSize);
- if ($completeBlocksInFile === (int)floor($this->position/$this->unencryptedBlockSize)) {
+ $completeBlocksInFile = (int)floor($this->unencryptedSize / $this->unencryptedBlockSize);
+ if ($completeBlocksInFile === (int)floor($this->position / $this->unencryptedBlockSize)) {
$this->size = $this->util->getBlockSize() * $completeBlocksInFile;
$this->size += $bytesWritten;
$this->size += $this->headerSize;
@@ -493,7 +493,7 @@ class Encryption extends Wrapper {
if ($this->cache === '' && !($this->position === $this->unencryptedSize && ($this->position % $this->unencryptedBlockSize) === 0)) {
// Get the data from the file handle
$data = $this->stream_read_block($this->util->getBlockSize());
- $position = (int)floor($this->position/$this->unencryptedBlockSize);
+ $position = (int)floor($this->position / $this->unencryptedBlockSize);
$numberOfChunks = (int)($this->unencryptedSize / $this->unencryptedBlockSize);
if ($numberOfChunks === $position) {
$position .= 'end';
diff --git a/lib/private/Files/Stream/Quota.php b/lib/private/Files/Stream/Quota.php
index 3bf46264b83..db5691187ce 100644
--- a/lib/private/Files/Stream/Quota.php
+++ b/lib/private/Files/Stream/Quota.php
@@ -6,7 +6,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Files/Type/Detection.php b/lib/private/Files/Type/Detection.php
index bfca6dabd2f..247f6005e57 100644
--- a/lib/private/Files/Type/Detection.php
+++ b/lib/private/Files/Type/Detection.php
@@ -6,11 +6,14 @@ declare(strict_types=1);
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Andreas Fischer <bantu@owncloud.com>
+ * @author bladewing <lukas@ifflaender-family.de>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Hendrik Leppelsack <hendrik@leppelsack.de>
* @author Jens-Christian Fischer <jens-christian.fischer@switch.ch>
* @author Joas Schilling <coding@schilljs.com>
+ * @author Julius Härtl <jus@bitgrid.net>
+ * @author lui87kw <lukas.ifflaender@uni-wuerzburg.de>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Magnus Walbeck <mw@mwalbeck.org>
* @author Morris Jobke <hey@morrisjobke.de>
@@ -18,7 +21,7 @@ declare(strict_types=1);
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
* @author Xheni Myrtaj <myrtajxheni@gmail.com>
*
* @license AGPL-3.0
@@ -120,8 +123,14 @@ class Detection implements IMimeTypeDetector {
$this->mimetypes = array_merge($this->mimetypes, $types);
// Update the alternative mimetypes to avoid having to look them up each time.
- foreach ($this->mimetypes as $mimeType) {
+ foreach ($this->mimetypes as $extension => $mimeType) {
+ if (strpos($extension, '_comment') === 0) {
+ continue;
+ }
$this->secureMimeTypes[$mimeType[0]] = $mimeType[1] ?? $mimeType[0];
+ if (isset($mimeType[1])) {
+ $this->secureMimeTypes[$mimeType[1]] = $mimeType[1];
+ }
}
}
diff --git a/lib/private/Files/Type/Loader.php b/lib/private/Files/Type/Loader.php
index d128bc724b6..489ed65c228 100644
--- a/lib/private/Files/Type/Loader.php
+++ b/lib/private/Files/Type/Loader.php
@@ -123,7 +123,10 @@ class Loader implements IMimeTypeLoader {
->where(
$fetch->expr()->eq('mimetype', $fetch->createNamedParameter($mimetype)
));
- $row = $fetch->execute()->fetch();
+
+ $result = $fetch->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
if (!$row) {
throw new \Exception("Failed to get mimetype id for $mimetype after trying to store it");
@@ -141,7 +144,10 @@ class Loader implements IMimeTypeLoader {
$qb = $this->dbConnection->getQueryBuilder();
$qb->select('id', 'mimetype')
->from('mimetypes');
- $results = $qb->execute()->fetchAll();
+
+ $result = $qb->execute();
+ $results = $result->fetchAll();
+ $result->closeCursor();
foreach ($results as $row) {
$this->mimetypes[$row['id']] = $row['mimetype'];
diff --git a/lib/private/Files/Utils/Scanner.php b/lib/private/Files/Utils/Scanner.php
index 996380037b7..5509a49941b 100644
--- a/lib/private/Files/Utils/Scanner.php
+++ b/lib/private/Files/Utils/Scanner.php
@@ -10,7 +10,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php
index ef8656258d1..1bee09e3659 100644
--- a/lib/private/Files/View.php
+++ b/lib/private/Files/View.php
@@ -3,6 +3,7 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
+ * @author Ashod Nakashian <ashod.nakashian@collabora.co.uk>
* @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
@@ -26,7 +27,7 @@
* @author Scott Dutton <exussum12@users.noreply.github.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -239,7 +240,7 @@ class View {
public function getLocalFile($path) {
$parent = substr($path, 0, strrpos($path, '/'));
$path = $this->getAbsolutePath($path);
- list($storage, $internalPath) = Filesystem::resolvePath($path);
+ [$storage, $internalPath] = Filesystem::resolvePath($path);
if (Filesystem::isValidPath($parent) and $storage) {
return $storage->getLocalFile($internalPath);
} else {
@@ -254,7 +255,7 @@ class View {
public function getLocalFolder($path) {
$parent = substr($path, 0, strrpos($path, '/'));
$path = $this->getAbsolutePath($path);
- list($storage, $internalPath) = Filesystem::resolvePath($path);
+ [$storage, $internalPath] = Filesystem::resolvePath($path);
if (Filesystem::isValidPath($parent) and $storage) {
return $storage->getLocalFolder($internalPath);
} else {
@@ -665,13 +666,19 @@ class View {
return false;
}
- $this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
+ try {
+ $this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
+ } catch (\Exception $e) {
+ // Release the shared lock before throwing.
+ $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
+ throw $e;
+ }
/** @var \OC\Files\Storage\Storage $storage */
- list($storage, $internalPath) = $this->resolvePath($path);
+ [$storage, $internalPath] = $this->resolvePath($path);
$target = $storage->fopen($internalPath, 'w');
if ($target) {
- list(, $result) = \OC_Helper::streamCopy($data, $target);
+ [, $result] = \OC_Helper::streamCopy($data, $target);
fclose($target);
fclose($data);
@@ -1089,7 +1096,7 @@ class View {
[Filesystem::signal_param_path => $this->getHookPath($path)]
);
}
- list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
+ [$storage, $internalPath] = Filesystem::resolvePath($absolutePath . $postFix);
if ($storage) {
return $storage->hash($type, $internalPath, $raw);
}
@@ -1143,7 +1150,7 @@ class View {
$run = $this->runHooks($hooks, $path);
/** @var \OC\Files\Storage\Storage $storage */
- list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
+ [$storage, $internalPath] = Filesystem::resolvePath($absolutePath . $postFix);
if ($run and $storage) {
if (in_array('write', $hooks) || in_array('delete', $hooks)) {
try {
@@ -1568,7 +1575,7 @@ class View {
* @var \OC\Files\Storage\Storage $storage
* @var string $internalPath
*/
- list($storage, $internalPath) = Filesystem::resolvePath($path);
+ [$storage, $internalPath] = Filesystem::resolvePath($path);
if ($storage) {
$cache = $storage->getCache($path);
@@ -1705,7 +1712,7 @@ class View {
* @var Storage\Storage $storage
* @var string $internalPath
*/
- list($storage, $internalPath) = $this->resolvePath($path);
+ [$storage, $internalPath] = $this->resolvePath($path);
if ($storage) {
return $storage->getETag($internalPath);
} else {
@@ -1719,10 +1726,11 @@ class View {
* Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file
*
* @param int $id
- * @throws NotFoundException
+ * @param int|null $storageId
* @return string
+ * @throws NotFoundException
*/
- public function getPath($id) {
+ public function getPath($id, int $storageId = null) {
$id = (int)$id;
$manager = Filesystem::getMountManager();
$mounts = $manager->findIn($this->fakeRoot);
@@ -1737,6 +1745,12 @@ class View {
return $a instanceof SharedMount && (!$b instanceof SharedMount) ? 1 : -1;
});
+ if (!is_null($storageId)) {
+ $mounts = array_filter($mounts, function (IMountPoint $mount) use ($storageId) {
+ return $mount->getNumericStorageId() === $storageId;
+ });
+ }
+
foreach ($mounts as $mount) {
/**
* @var \OC\Files\Mount\MountPoint $mount
@@ -1844,7 +1858,7 @@ class View {
public function verifyPath($path, $fileName) {
try {
/** @type \OCP\Files\Storage $storage */
- list($storage, $internalPath) = $this->resolvePath($path);
+ [$storage, $internalPath] = $this->resolvePath($path);
$storage->verifyPath($internalPath, $fileName);
} catch (ReservedWordException $ex) {
$l = \OC::$server->getL10N('lib');
diff --git a/lib/private/ForbiddenException.php b/lib/private/ForbiddenException.php
index 1ba38e39924..8a00b78291a 100644
--- a/lib/private/ForbiddenException.php
+++ b/lib/private/ForbiddenException.php
@@ -3,7 +3,7 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/FullTextSearch/Model/SearchRequestSimpleQuery.php b/lib/private/FullTextSearch/Model/SearchRequestSimpleQuery.php
index c015c4c1579..f6241938f82 100644
--- a/lib/private/FullTextSearch/Model/SearchRequestSimpleQuery.php
+++ b/lib/private/FullTextSearch/Model/SearchRequestSimpleQuery.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
/**
* @copyright 2018
*
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Maxence Lange <maxence@artificial-owl.com>
*
* @license GNU AGPL version 3 or any later version
@@ -173,8 +174,8 @@ final class SearchRequestSimpleQuery implements ISearchRequestSimpleQuery, JsonS
*/
public function jsonSerialize() {
return [
- 'type' => $this->getType(),
- 'field' => $this->getField(),
+ 'type' => $this->getType(),
+ 'field' => $this->getField(),
'values' => $this->getValues()
];
}
diff --git a/lib/private/Group/Backend.php b/lib/private/Group/Backend.php
index ebd8d3620d4..e041254bd5a 100644
--- a/lib/private/Group/Backend.php
+++ b/lib/private/Group/Backend.php
@@ -5,7 +5,7 @@
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Knut Ahlers <knut@ahlers.me>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Group/Database.php b/lib/private/Group/Database.php
index 8e6181a56cd..97094c67728 100644
--- a/lib/private/Group/Database.php
+++ b/lib/private/Group/Database.php
@@ -348,15 +348,27 @@ class Database extends ABackend implements
$this->fixDI();
$query = $this->dbConn->getQueryBuilder();
- $query->select('uid')
- ->from('group_user')
+ $query->select('g.uid')
+ ->from('group_user', 'g')
->where($query->expr()->eq('gid', $query->createNamedParameter($gid)))
- ->orderBy('uid', 'ASC');
+ ->orderBy('g.uid', 'ASC');
if ($search !== '') {
- $query->andWhere($query->expr()->like('uid', $query->createNamedParameter(
- '%' . $this->dbConn->escapeLikeParameter($search) . '%'
- )));
+ $query->leftJoin('g', 'users', 'u', $query->expr()->eq('g.uid', 'u.uid'))
+ ->leftJoin('u', 'preferences', 'p', $query->expr()->andX(
+ $query->expr()->eq('p.userid', 'u.uid'),
+ $query->expr()->eq('p.appid', $query->expr()->literal('settings')),
+ $query->expr()->eq('p.configkey', $query->expr()->literal('email')))
+ )
+ // sqlite doesn't like re-using a single named parameter here
+ ->andWhere(
+ $query->expr()->orX(
+ $query->expr()->ilike('g.uid', $query->createNamedParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')),
+ $query->expr()->ilike('u.displayname', $query->createNamedParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')),
+ $query->expr()->ilike('p.configvalue', $query->createNamedParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%'))
+ )
+ )
+ ->orderBy('u.uid_lower', 'ASC');
}
if ($limit !== -1) {
diff --git a/lib/private/Group/Group.php b/lib/private/Group/Group.php
index 2e16d5f1242..d3f8c603121 100644
--- a/lib/private/Group/Group.php
+++ b/lib/private/Group/Group.php
@@ -12,7 +12,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Group/Manager.php b/lib/private/Group/Manager.php
index 6056bcdb3e3..4c731a9f488 100644
--- a/lib/private/Group/Manager.php
+++ b/lib/private/Group/Manager.php
@@ -18,7 +18,7 @@
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Roman Kreisel <mail@romankreisel.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
* @author Vinicius Cubas Brand <vinicius@eita.org.br>
* @author voxsim "Simon Vocella"
*
@@ -41,6 +41,7 @@
namespace OC\Group;
use OC\Hooks\PublicEmitter;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\GroupInterface;
use OCP\IGroup;
use OCP\IGroupManager;
@@ -416,7 +417,8 @@ class Manager extends PublicEmitter implements IGroupManager {
$this->subAdmin = new \OC\SubAdmin(
$this->userManager,
$this,
- \OC::$server->getDatabaseConnection()
+ \OC::$server->getDatabaseConnection(),
+ \OC::$server->get(IEventDispatcher::class)
);
}
diff --git a/lib/private/Group/MetaData.php b/lib/private/Group/MetaData.php
index 21857b6c8f0..5449cdbe29a 100644
--- a/lib/private/Group/MetaData.php
+++ b/lib/private/Group/MetaData.php
@@ -4,6 +4,7 @@
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Joas Schilling <coding@schilljs.com>
* @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
* @author Lukas Reschke <lukas@statuscode.ch>
@@ -30,6 +31,7 @@
namespace OC\Group;
+use OC\Group\Manager as GroupManager;
use OCP\IGroupManager;
use OCP\IUserSession;
@@ -44,7 +46,7 @@ class MetaData {
protected $isAdmin;
/** @var array */
protected $metaData = [];
- /** @var IGroupManager */
+ /** @var GroupManager */
protected $groupManager;
/** @var bool */
protected $sorting = false;
@@ -55,7 +57,6 @@ class MetaData {
* @param string $user the uid of the current user
* @param bool $isAdmin whether the current users is an admin
* @param IGroupManager $groupManager
- * @param IUserManager $userManager
* @param IUserSession $userSession
*/
public function __construct(
diff --git a/lib/private/Hooks/Emitter.php b/lib/private/Hooks/Emitter.php
index cd4793ef3f9..4240cef520b 100644
--- a/lib/private/Hooks/Emitter.php
+++ b/lib/private/Hooks/Emitter.php
@@ -39,6 +39,7 @@ interface Emitter {
* @param string $method
* @param callable $callback
* @return void
+ * @deprecated 18.0.0 use \OCP\EventDispatcher\IEventDispatcher::addListener
*/
public function listen($scope, $method, callable $callback);
@@ -47,6 +48,7 @@ interface Emitter {
* @param string $method optional
* @param callable $callback optional
* @return void
+ * @deprecated 18.0.0 use \OCP\EventDispatcher\IEventDispatcher::removeListener
*/
public function removeListener($scope = null, $method = null, callable $callback = null);
}
diff --git a/lib/private/Hooks/EmitterTrait.php b/lib/private/Hooks/EmitterTrait.php
index 85efa218f64..1cbfe0f5a06 100644
--- a/lib/private/Hooks/EmitterTrait.php
+++ b/lib/private/Hooks/EmitterTrait.php
@@ -24,6 +24,9 @@
namespace OC\Hooks;
+/**
+ * @deprecated 18.0.0 use events and the \OCP\EventDispatcher\IEventDispatcher service
+ */
trait EmitterTrait {
/**
@@ -35,6 +38,7 @@ trait EmitterTrait {
* @param string $scope
* @param string $method
* @param callable $callback
+ * @deprecated 18.0.0 use \OCP\EventDispatcher\IEventDispatcher::addListener
*/
public function listen($scope, $method, callable $callback) {
$eventName = $scope . '::' . $method;
@@ -50,6 +54,7 @@ trait EmitterTrait {
* @param string $scope optional
* @param string $method optional
* @param callable $callback optional
+ * @deprecated 18.0.0 use \OCP\EventDispatcher\IEventDispatcher::removeListener
*/
public function removeListener($scope = null, $method = null, callable $callback = null) {
$names = [];
@@ -93,6 +98,7 @@ trait EmitterTrait {
* @param string $scope
* @param string $method
* @param array $arguments optional
+ * @deprecated 18.0.0 use \OCP\EventDispatcher\IEventDispatcher::dispatchTyped
*/
protected function emit($scope, $method, array $arguments = []) {
$eventName = $scope . '::' . $method;
diff --git a/lib/private/Hooks/ForwardingEmitter.php b/lib/private/Hooks/ForwardingEmitter.php
deleted file mode 100644
index 3ac6cca096a..00000000000
--- a/lib/private/Hooks/ForwardingEmitter.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @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\Hooks;
-
-/**
- * Class ForwardingEmitter
- *
- * allows forwarding all listen calls to other emitters
- *
- * @package OC\Hooks
- */
-abstract class ForwardingEmitter extends BasicEmitter {
- /**
- * @var \OC\Hooks\Emitter[] array
- */
- private $forwardEmitters = [];
-
- /**
- * @param string $scope
- * @param string $method
- * @param callable $callback
- */
- public function listen($scope, $method, callable $callback) {
- parent::listen($scope, $method, $callback);
- foreach ($this->forwardEmitters as $emitter) {
- $emitter->listen($scope, $method, $callback);
- }
- }
-
- /**
- * @param \OC\Hooks\Emitter $emitter
- */
- protected function forward(Emitter $emitter) {
- $this->forwardEmitters[] = $emitter;
-
- //forward all previously connected hooks
- foreach ($this->listeners as $key => $listeners) {
- list($scope, $method) = explode('::', $key, 2);
- foreach ($listeners as $listener) {
- $emitter->listen($scope, $method, $listener);
- }
- }
- }
-}
diff --git a/lib/private/Hooks/LegacyEmitter.php b/lib/private/Hooks/LegacyEmitter.php
deleted file mode 100644
index 470c5e0b11d..00000000000
--- a/lib/private/Hooks/LegacyEmitter.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @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\Hooks;
-
-abstract class LegacyEmitter extends BasicEmitter {
- /**
- * @param string $scope
- * @param string $method
- * @param array $arguments
- *
- * @suppress PhanAccessMethodProtected
- */
- protected function emit($scope, $method, array $arguments = []) {
- \OC_Hook::emit($scope, $method, $arguments);
- parent::emit($scope, $method, $arguments);
- }
-}
diff --git a/lib/private/Hooks/PublicEmitter.php b/lib/private/Hooks/PublicEmitter.php
index dbccc34f2e9..e698b322180 100644
--- a/lib/private/Hooks/PublicEmitter.php
+++ b/lib/private/Hooks/PublicEmitter.php
@@ -33,6 +33,7 @@ class PublicEmitter extends BasicEmitter {
* @param string $scope
* @param string $method
* @param array $arguments optional
+ * @deprecated 18.0.0 use \OCP\EventDispatcher\IEventDispatcher::dispatchTyped
*
* @suppress PhanAccessMethodProtected
*/
diff --git a/lib/private/Http/Client/Client.php b/lib/private/Http/Client/Client.php
index 4c03d386476..3f616df0b28 100644
--- a/lib/private/Http/Client/Client.php
+++ b/lib/private/Http/Client/Client.php
@@ -5,11 +5,13 @@ declare(strict_types=1);
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
+ * @author Carlos Ferreira <carlos@reendex.com>
* @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 Mohammed Abdellatif <m.latief@gmail.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Scott Shambarger <devel@shambarger.net>
@@ -98,16 +100,12 @@ class Client implements IClient {
private function getCertBundle(): string {
// If the instance is not yet setup we need to use the static path as
- // $this->certificateManager->getAbsoluteBundlePath() tries to instantiiate
+ // $this->certificateManager->getAbsoluteBundlePath() tries to instantiate
// a view
if ($this->config->getSystemValue('installed', false) === false) {
return \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
}
- if ($this->certificateManager->listCertificates() === []) {
- return \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
- }
-
return $this->certificateManager->getAbsoluteBundlePath();
}
@@ -164,7 +162,7 @@ class Client implements IClient {
}
$host = strtolower($host);
- // remove brackets from IPv6 addresses
+ // Remove brackets from IPv6 addresses
if (strpos($host, '[') === 0 && substr($host, -1) === ']') {
$host = substr($host, 1, -1);
}
diff --git a/lib/private/Http/WellKnown/RequestManager.php b/lib/private/Http/WellKnown/RequestManager.php
new file mode 100644
index 00000000000..d17ea5c671b
--- /dev/null
+++ b/lib/private/Http/WellKnown/RequestManager.php
@@ -0,0 +1,124 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @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\Http\WellKnown;
+
+use OC\AppFramework\Bootstrap\Coordinator;
+use OCP\AppFramework\QueryException;
+use OCP\Http\WellKnown\IHandler;
+use OCP\Http\WellKnown\IRequestContext;
+use OCP\Http\WellKnown\IResponse;
+use OCP\Http\WellKnown\JrdResponse;
+use OCP\IRequest;
+use OCP\IServerContainer;
+use Psr\Log\LoggerInterface;
+use RuntimeException;
+use function array_reduce;
+
+class RequestManager {
+
+ /** @var Coordinator */
+ private $coordinator;
+
+ /** @var IServerContainer */
+ private $container;
+
+ /** @var LoggerInterface */
+ private $logger;
+
+ public function __construct(Coordinator $coordinator,
+ IServerContainer $container,
+ LoggerInterface $logger) {
+ $this->coordinator = $coordinator;
+ $this->container = $container;
+ $this->logger = $logger;
+ }
+
+ public function process(string $service, IRequest $request): ?IResponse {
+ $handlers = $this->loadHandlers();
+ $context = new class($request) implements IRequestContext {
+ /** @var IRequest */
+ private $request;
+
+ public function __construct(IRequest $request) {
+ $this->request = $request;
+ }
+
+ public function getHttpRequest(): IRequest {
+ return $this->request;
+ }
+ };
+
+ $subject = $request->getParam('resource');
+ $initialResponse = new JrdResponse($subject ?? '');
+ $finalResponse = array_reduce($handlers, function (?IResponse $previousResponse, IHandler $handler) use ($context, $service) {
+ return $handler->handle($service, $context, $previousResponse);
+ }, $initialResponse);
+
+ if ($finalResponse instanceof JrdResponse && $finalResponse->isEmpty()) {
+ return null;
+ }
+
+ return $finalResponse;
+ }
+
+ /**
+ * @return IHandler[]
+ */
+ private function loadHandlers(): array {
+ $context = $this->coordinator->getRegistrationContext();
+
+ if ($context === null) {
+ throw new RuntimeException("Well known handlers requested before the apps had been fully registered");
+ }
+
+ $registrations = $context->getWellKnownHandlers();
+ $this->logger->debug(count($registrations) . " well known handlers registered");
+
+ return array_filter(
+ array_map(function (array $registration) {
+ $class = $registration['class'];
+
+ try {
+ $handler = $this->container->get($class);
+
+ if (!($handler) instanceof IHandler) {
+ $this->logger->error("Well known handler $class is invalid");
+
+ return null;
+ }
+
+ return $handler;
+ } catch (QueryException $e) {
+ $this->logger->error("Could not load well known handler $class", [
+ 'exception' => $e,
+ ]);
+
+ return null;
+ }
+ }, $registrations)
+ );
+ }
+}
diff --git a/lib/private/InitialStateService.php b/lib/private/InitialStateService.php
index 55ce9c41726..7f9a084ef70 100644
--- a/lib/private/InitialStateService.php
+++ b/lib/private/InitialStateService.php
@@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
@@ -28,8 +29,12 @@ declare(strict_types=1);
namespace OC;
use Closure;
+use OC\AppFramework\Bootstrap\Coordinator;
+use OCP\AppFramework\QueryException;
+use OCP\AppFramework\Services\InitialStateProvider;
use OCP\IInitialStateService;
use OCP\ILogger;
+use OCP\IServerContainer;
class InitialStateService implements IInitialStateService {
@@ -42,8 +47,16 @@ class InitialStateService implements IInitialStateService {
/** @var Closure[][] */
private $lazyStates = [];
- public function __construct(ILogger $logger) {
+ /** @var Coordinator */
+ private $bootstrapCoordinator;
+
+ /** @var IServerContainer */
+ private $container;
+
+ public function __construct(ILogger $logger, Coordinator $bootstrapCoordinator, IServerContainer $container) {
$this->logger = $logger;
+ $this->bootstrapCoordinator = $bootstrapCoordinator;
+ $this->container = $container;
}
public function provideInitialState(string $appName, string $key, $data): void {
@@ -72,14 +85,61 @@ class InitialStateService implements IInitialStateService {
private function invokeLazyStateCallbacks(): void {
foreach ($this->lazyStates as $app => $lazyStates) {
foreach ($lazyStates as $key => $lazyState) {
+ $startTime = microtime(true);
$this->provideInitialState($app, $key, $lazyState());
+ $endTime = microtime(true);
+ $duration = $endTime - $startTime;
+ if ($duration > 1) {
+ $this->logger->warning('Lazy initial state provider for {key} took {duration} seconds.', [
+ 'app' => $app,
+ 'key' => $key,
+ 'duration' => round($duration, 2),
+ ]);
+ }
}
}
$this->lazyStates = [];
}
+ /**
+ * Load the lazy states via the IBootstrap mechanism
+ */
+ private function loadLazyStates(): void {
+ $context = $this->bootstrapCoordinator->getRegistrationContext();
+
+ if ($context === null) {
+ // To early, nothing to do yet
+ return;
+ }
+
+ $initialStates = $context->getInitialStates();
+ foreach ($initialStates as $initialState) {
+ try {
+ $provider = $this->container->query($initialState['class']);
+ } catch (QueryException $e) {
+ // Log an continue. We can be fault tolerant here.
+ $this->logger->logException($e, [
+ 'message' => 'Could not load initial state provider dynamically: ' . $e->getMessage(),
+ 'level' => ILogger::ERROR,
+ 'app' => $initialState['appId'],
+ ]);
+ continue;
+ }
+
+ if (!($provider instanceof InitialStateProvider)) {
+ // Log an continue. We can be fault tolerant here.
+ $this->logger->error('Initial state provider is not an InitialStateProvider instance: ' . $initialState['class'], [
+ 'app' => $initialState['appId'],
+ ]);
+ }
+
+ $this->provideInitialState($initialState['appId'], $provider->getKey(), $provider);
+ }
+ }
+
public function getInitialStates(): array {
$this->invokeLazyStateCallbacks();
+ $this->loadLazyStates();
$appStates = [];
foreach ($this->states as $app => $states) {
diff --git a/lib/private/Installer.php b/lib/private/Installer.php
index d5c9d076eda..0b020aed569 100644
--- a/lib/private/Installer.php
+++ b/lib/private/Installer.php
@@ -6,6 +6,7 @@
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Brice Maron <brice@bmaron.net>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Frank Karlitschek <frank@karlitschek.de>
* @author Georg Ehrke <oc.list@georgehrke.com>
* @author Joas Schilling <coding@schilljs.com>
@@ -42,6 +43,7 @@ namespace OC;
use Doctrine\DBAL\Exception\TableExistsException;
use OC\App\AppStore\Bundles\Bundle;
use OC\App\AppStore\Fetcher\AppFetcher;
+use OC\AppFramework\Bootstrap\Coordinator;
use OC\Archive\TAR;
use OC_App;
use OC_DB;
@@ -138,6 +140,9 @@ class Installer {
// check for required dependencies
\OC_App::checkAppDependencies($this->config, $l, $info, $ignoreMax);
+ /** @var Coordinator $coordinator */
+ $coordinator = \OC::$server->get(Coordinator::class);
+ $coordinator->runLazyRegistration($appId);
\OC_App::registerAutoloading($appId, $basedir);
$previousVersion = $this->config->getAppValue($info['id'], 'installed_version', false);
@@ -154,7 +159,7 @@ class Installer {
}
} else {
$ms = new \OC\DB\MigrationService($info['id'], \OC::$server->getDatabaseConnection());
- $ms->migrate();
+ $ms->migrate('latest', true);
}
if ($previousVersion) {
OC_App::executeRepairSteps($appId, $info['repair-steps']['post-migration']);
@@ -173,10 +178,10 @@ class Installer {
\OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no');
//set remote/public handlers
- foreach ($info['remote'] as $name=>$path) {
+ foreach ($info['remote'] as $name => $path) {
\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path);
}
- foreach ($info['public'] as $name=>$path) {
+ foreach ($info['public'] as $name => $path) {
\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path);
}
@@ -189,12 +194,13 @@ class Installer {
* Updates the specified app from the appstore
*
* @param string $appId
+ * @param bool [$allowUnstable] Allow unstable releases
* @return bool
*/
- public function updateAppstoreApp($appId) {
- if ($this->isUpdateAvailable($appId)) {
+ public function updateAppstoreApp($appId, $allowUnstable = false) {
+ if ($this->isUpdateAvailable($appId, $allowUnstable)) {
try {
- $this->downloadApp($appId);
+ $this->downloadApp($appId, $allowUnstable);
} catch (\Exception $e) {
$this->logger->logException($e, [
'level' => ILogger::ERROR,
@@ -212,13 +218,14 @@ class Installer {
* Downloads an app and puts it into the app directory
*
* @param string $appId
+ * @param bool [$allowUnstable]
*
* @throws \Exception If the installation was not successful
*/
- public function downloadApp($appId) {
+ public function downloadApp($appId, $allowUnstable = false) {
$appId = strtolower($appId);
- $apps = $this->appFetcher->get();
+ $apps = $this->appFetcher->get($allowUnstable);
foreach ($apps as $app) {
if ($app['id'] === $appId) {
// Load the certificate
@@ -292,12 +299,14 @@ class Installer {
if ($archive) {
if (!$archive->extract($extractDir)) {
- throw new \Exception(
- sprintf(
- 'Could not extract app %s',
- $appId
- )
- );
+ $errorMessage = 'Could not extract app ' . $appId;
+
+ $archiveError = $archive->getError();
+ if ($archiveError instanceof \PEAR_Error) {
+ $errorMessage .= ': ' . $archiveError->getMessage();
+ }
+
+ throw new \Exception($errorMessage);
}
$allFiles = scandir($extractDir);
$folders = array_diff($allFiles, ['.', '..']);
@@ -384,9 +393,10 @@ class Installer {
* Check if an update for the app is available
*
* @param string $appId
+ * @param bool $allowUnstable
* @return string|false false or the version number of the update
*/
- public function isUpdateAvailable($appId) {
+ public function isUpdateAvailable($appId, $allowUnstable = false) {
if ($this->isInstanceReadyForUpdates === null) {
$installPath = OC_App::getInstallPath();
if ($installPath === false || $installPath === null) {
@@ -405,7 +415,7 @@ class Installer {
}
if ($this->apps === null) {
- $this->apps = $this->appFetcher->get();
+ $this->apps = $this->appFetcher->get($allowUnstable);
}
foreach ($this->apps as $app) {
@@ -452,7 +462,7 @@ class Installer {
*/
public function isDownloaded($name) {
foreach (\OC::$APPSROOTS as $dir) {
- $dirToTest = $dir['path'];
+ $dirToTest = $dir['path'];
$dirToTest .= '/';
$dirToTest .= $name;
$dirToTest .= '/';
@@ -532,7 +542,7 @@ class Installer {
if ($filename[0] !== '.' and is_dir($app_dir['path']."/$filename")) {
if (file_exists($app_dir['path']."/$filename/appinfo/info.xml")) {
if ($config->getAppValue($filename, "installed_version", null) === null) {
- $info=OC_App::getAppInfo($filename);
+ $info = OC_App::getAppInfo($filename);
$enabled = isset($info['default_enable']);
if (($enabled || in_array($filename, $appManager->getAlwaysEnabledApps()))
&& $config->getAppValue($filename, 'enabled') !== 'no') {
@@ -584,7 +594,7 @@ class Installer {
}
} else {
$ms = new \OC\DB\MigrationService($app, \OC::$server->getDatabaseConnection());
- $ms->migrate();
+ $ms->migrate('latest', true);
}
//run appinfo/install.php
@@ -606,10 +616,10 @@ class Installer {
}
//set remote/public handlers
- foreach ($info['remote'] as $name=>$path) {
+ foreach ($info['remote'] as $name => $path) {
$config->setAppValue('core', 'remote_'.$name, $app.'/'.$path);
}
- foreach ($info['public'] as $name=>$path) {
+ foreach ($info['public'] as $name => $path) {
$config->setAppValue('core', 'public_'.$name, $app.'/'.$path);
}
diff --git a/lib/private/IntegrityCheck/Checker.php b/lib/private/IntegrityCheck/Checker.php
index f5c4d6bb016..504cd391c42 100644
--- a/lib/private/IntegrityCheck/Checker.php
+++ b/lib/private/IntegrityCheck/Checker.php
@@ -11,7 +11,7 @@ declare(strict_types=1);
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
* @author Xheni Myrtaj <myrtajxheni@gmail.com>
*
* @license AGPL-3.0
diff --git a/lib/private/L10N/Factory.php b/lib/private/L10N/Factory.php
index 3ab62de4b97..9c9a3cc951e 100644
--- a/lib/private/L10N/Factory.php
+++ b/lib/private/L10N/Factory.php
@@ -9,6 +9,7 @@
* @author Bjoern Schiessle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Georg Ehrke <oc.list@georgehrke.com>
+ * @author GretaD <gretadoci@gmail.com>
* @author Joas Schilling <coding@schilljs.com>
* @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
* @author Lukas Reschke <lukas@statuscode.ch>
@@ -65,6 +66,11 @@ class Factory implements IFactory {
/**
* @var array
*/
+ protected $localeCache = [];
+
+ /**
+ * @var array
+ */
protected $availableLocales = [];
/**
@@ -390,12 +396,14 @@ class Factory implements IFactory {
return true;
}
- $locales = $this->findAvailableLocales();
- $userLocale = array_filter($locales, function ($value) use ($locale) {
- return $locale === $value['code'];
- });
+ if ($this->localeCache === []) {
+ $locales = $this->findAvailableLocales();
+ foreach ($locales as $l) {
+ $this->localeCache[$l['code']] = true;
+ }
+ }
- return !empty($userLocale);
+ return isset($this->localeCache[$locale]);
}
/**
diff --git a/lib/private/LargeFileHelper.php b/lib/private/LargeFileHelper.php
index 2a6a6714eb3..b07d77a02fa 100755
--- a/lib/private/LargeFileHelper.php
+++ b/lib/private/LargeFileHelper.php
@@ -5,6 +5,7 @@
*
* @author Andreas Fischer <bantu@owncloud.com>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author marco44 <cousinmarc@gmail.com>
* @author Michael Roitzsch <reactorcontrol@icloud.com>
@@ -29,6 +30,8 @@
namespace OC;
+use bantu\IniGetWrapper\IniGetWrapper;
+
/**
* Helper class for large files on 32-bit platforms.
*/
@@ -117,7 +120,7 @@ class LargeFileHelper {
* null on failure.
*/
public function getFileSizeViaCurl($fileName) {
- if (\OC::$server->getIniWrapper()->getString('open_basedir') === '') {
+ if (\OC::$server->get(IniGetWrapper::class)->getString('open_basedir') === '') {
$encodedFileName = rawurlencode($fileName);
$ch = curl_init("file:///$encodedFileName");
curl_setopt($ch, CURLOPT_NOBODY, true);
@@ -190,7 +193,7 @@ class LargeFileHelper {
try {
$result = filemtime($fullPath);
} catch (\Exception $e) {
- $result =- 1;
+ $result = - 1;
}
if ($result < 0) {
if (\OC_Helper::is_function_enabled('exec')) {
diff --git a/lib/private/Lock/DBLockingProvider.php b/lib/private/Lock/DBLockingProvider.php
index f48bf57028f..c6b9cf63780 100644
--- a/lib/private/Lock/DBLockingProvider.php
+++ b/lib/private/Lock/DBLockingProvider.php
@@ -5,7 +5,6 @@
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Individual IT Services <info@individual-it.net>
* @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Ole Ostergaard <ole.c.ostergaard@gmail.com>
* @author Robin Appelman <robin@icewind.nl>
@@ -216,8 +215,6 @@ class DBLockingProvider extends AbstractLockingProvider {
/**
* @param string $path
* @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE
- *
- * @suppress SqlInjectionChecker
*/
public function releaseLock(string $path, int $type) {
$this->markRelease($path, $type);
@@ -288,8 +285,6 @@ class DBLockingProvider extends AbstractLockingProvider {
/**
* release all lock acquired by this instance which were marked using the mark* methods
- *
- * @suppress SqlInjectionChecker
*/
public function releaseAll() {
parent::releaseAll();
diff --git a/lib/private/Lock/MemcacheLockingProvider.php b/lib/private/Lock/MemcacheLockingProvider.php
index b8b4cef275d..439894e901f 100644
--- a/lib/private/Lock/MemcacheLockingProvider.php
+++ b/lib/private/Lock/MemcacheLockingProvider.php
@@ -6,6 +6,7 @@ declare(strict_types=1);
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Jaakko Salo <jaakkos@gmail.com>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
@@ -60,7 +61,7 @@ class MemcacheLockingProvider extends AbstractLockingProvider {
public function isLocked(string $path, int $type): bool {
$lockValue = $this->memcache->get($path);
if ($type === self::LOCK_SHARED) {
- return $lockValue > 0;
+ return is_int($lockValue) && $lockValue > 0;
} elseif ($type === self::LOCK_EXCLUSIVE) {
return $lockValue === 'exclusive';
} else {
diff --git a/lib/private/Lock/NoopLockingProvider.php b/lib/private/Lock/NoopLockingProvider.php
index 4f38d5159b9..728ad26de68 100644
--- a/lib/private/Lock/NoopLockingProvider.php
+++ b/lib/private/Lock/NoopLockingProvider.php
@@ -7,7 +7,7 @@ declare(strict_types=1);
*
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Log.php b/lib/private/Log.php
index 2048d60a53b..83b92ecd1ab 100644
--- a/lib/private/Log.php
+++ b/lib/private/Log.php
@@ -36,10 +36,9 @@ declare(strict_types=1);
namespace OC;
+use Nextcloud\LogNormalizer\Normalizer;
use OCP\Log\IDataLogger;
use function array_merge;
-use InterfaSys\LogNormalizer\Normalizer;
-
use OC\Log\ExceptionSerializer;
use OCP\ILogger;
use OCP\Log\IFileBased;
diff --git a/lib/private/Log/ErrorHandler.php b/lib/private/Log/ErrorHandler.php
index d37af8212a0..3f4c9ee64b1 100644
--- a/lib/private/Log/ErrorHandler.php
+++ b/lib/private/Log/ErrorHandler.php
@@ -5,6 +5,7 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Julius Härtl <jus@bitgrid.net>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
@@ -41,7 +42,7 @@ class ErrorHandler {
return preg_replace('/\/\/(.*):(.*)@/', '//xxx:xxx@', $msg);
}
- public static function register($debug=false) {
+ public static function register($debug = false) {
$handler = new ErrorHandler();
if ($debug) {
@@ -88,12 +89,14 @@ class ErrorHandler {
return;
}
$msg = $message . ' at ' . $file . '#' . $line;
- self::$logger->error(self::removePassword($msg), ['app' => 'PHP']);
+ $e = new \Error(self::removePassword($msg));
+ self::$logger->logException($e, ['app' => 'PHP']);
}
//Recoverable handler which catch all errors, warnings and notices
public static function onAll($number, $message, $file, $line) {
$msg = $message . ' at ' . $file . '#' . $line;
- self::$logger->debug(self::removePassword($msg), ['app' => 'PHP']);
+ $e = new \Error(self::removePassword($msg));
+ self::$logger->logException($e, ['app' => 'PHP', 'level' => 0]);
}
}
diff --git a/lib/private/Log/ExceptionSerializer.php b/lib/private/Log/ExceptionSerializer.php
index a2bc1963003..0cb68f08914 100644
--- a/lib/private/Log/ExceptionSerializer.php
+++ b/lib/private/Log/ExceptionSerializer.php
@@ -8,6 +8,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -86,6 +87,9 @@ class ExceptionSerializer {
// files_external: UserStoragesController
'update',
+
+ // Preview providers, don't log big data strings
+ 'imagecreatefromstring',
];
public const methodsWithSensitiveParametersByClass = [
diff --git a/lib/private/Log/File.php b/lib/private/Log/File.php
index 9e9abb11484..289afed9179 100644
--- a/lib/private/Log/File.php
+++ b/lib/private/Log/File.php
@@ -7,6 +7,7 @@
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author duritong <peter.meier+github@immerda.ch>
* @author Georg Ehrke <oc.list@georgehrke.com>
+ * @author J0WI <J0WI@users.noreply.github.com>
* @author Joas Schilling <coding@schilljs.com>
* @author Julius Härtl <jus@bitgrid.net>
* @author Lukas Reschke <lukas@statuscode.ch>
@@ -106,7 +107,7 @@ class File extends LogDetails implements IWriter, IFileBased {
* @param int $offset
* @return array
*/
- public function getEntries(int $limit=50, int $offset=0):array {
+ public function getEntries(int $limit = 50, int $offset = 0):array {
$minLevel = $this->config->getValue("loglevel", ILogger::WARN);
$entries = [];
$handle = @fopen($this->logFile, 'rb');
@@ -117,7 +118,7 @@ class File extends LogDetails implements IWriter, IFileBased {
$entriesCount = 0;
$lines = 0;
// Loop through each character of the file looking for new lines
- while ($pos >= 0 && ($limit === null ||$entriesCount < $limit)) {
+ while ($pos >= 0 && ($limit === null || $entriesCount < $limit)) {
fseek($handle, $pos);
$ch = fgetc($handle);
if ($ch == "\n" || $pos == 0) {
diff --git a/lib/private/Mail/EMailTemplate.php b/lib/private/Mail/EMailTemplate.php
index 2c8efa7e010..d5bd27007df 100644
--- a/lib/private/Mail/EMailTemplate.php
+++ b/lib/private/Mail/EMailTemplate.php
@@ -8,15 +8,17 @@ declare(strict_types=1);
*
* @author Bjoern Schiessle <bjoern@schiessle.org>
* @author brad2014 <brad2014@users.noreply.github.com>
+ * @author Brad Rubenstein <brad@wbr.tech>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Jan-Christoph Borchardt <hey@jancborchardt.net>
* @author Joas Schilling <coding@schilljs.com>
* @author Julius Härtl <jus@bitgrid.net>
* @author Liam JACK <liamjack@users.noreply.github.com>
* @author Lukas Reschke <lukas@statuscode.ch>
+ * @author medcloud <42641918+medcloud@users.noreply.github.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Tomasz Paluszkiewicz <tomasz.paluszkiewicz@gmail.com>
- * @author Simon Spannagel <simonspa@kth.se>
*
* @license GNU AGPL version 3 or any later version
*
@@ -118,8 +120,8 @@ EOF;
<table class="row collapse" style="border-collapse:collapse;border-spacing:0;display:table;padding:0;position:relative;text-align:left;vertical-align:top;width:100%%">
<tbody>
<tr style="padding:0;text-align:left;vertical-align:top">
- <center data-parsed="" style="background-color:%s;width:150px;height:150px;padding:0px;position:relative;border-radius:200px">
- <img class="logo float-center" src="%s" alt="%s" align="center" style="-ms-interpolation-mode:bicubic;clear:both;display:block;float:none;outline:0;text-align:center;text-decoration:none;position:absolute;max-height:100px;max-width:100px;width:auto;height:auto;position:absolute;top:0;bottom:0;left:0;right:0;margin:auto;">
+ <center data-parsed="" style="background-color:%s;min-width:175px;max-height:175px; padding:35px 0px;border-radius:200px">
+ <img class="logo float-center" src="%s" alt="%s" align="center" style="-ms-interpolation-mode:bicubic;clear:both;display:block;float:none;margin:0 auto;outline:0;text-align:center;text-decoration:none;max-height:105px;max-width:105px;width:auto;height:auto">
</center>
</tr>
</tbody>
@@ -291,7 +293,7 @@ EOF;
<td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,'Helvetica Neue',Arial,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
<table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%%">
<tr style="padding:0;text-align:left;vertical-align:top">
- <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border:0 solid %2\$;border-collapse:collapse!important;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,'Helvetica Neue',Arial,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
+ <td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border:0 solid %2\$s;border-collapse:collapse!important;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,'Helvetica Neue',Arial,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
<a href="%3\$s" style="Margin:0;border:0 solid %4\$s;border-radius:2px;color:%5\$s;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,'Helvetica Neue',Arial,sans-serif;font-size:16px;font-weight:regular;line-height:1.3;margin:0;padding:10px 25px 10px 25px;text-align:left;outline:1px solid %5\$s;text-decoration:none">%7\$s</a>
</td>
</tr>
@@ -447,19 +449,21 @@ EOF;
* @param string $metaInfo Note: When $plainMetaInfo falls back to this, HTML is automatically escaped in the HTML email
* @param string $icon Absolute path, must be 16*16 pixels
* @param string|bool $plainText Text that is used in the plain text email
- * if empty the $text is used, if false none will be used
+ * if empty or true the $text is used, if false none will be used
* @param string|bool $plainMetaInfo Meta info that is used in the plain text email
- * if empty the $metaInfo is used, if false none will be used
+ * if empty or true the $metaInfo is used, if false none will be used
+ * @param integer plainIndent If > 0, Indent plainText by this amount.
* @since 12.0.0
*/
- public function addBodyListItem(string $text, string $metaInfo = '', string $icon = '', $plainText = '', $plainMetaInfo = '') {
+ public function addBodyListItem(string $text, string $metaInfo = '', string $icon = '', $plainText = '', $plainMetaInfo = '', $plainIndent = 0) {
$this->ensureBodyListOpened();
- if ($plainText === '') {
+ if ($plainText === '' || $plainText === true) {
$plainText = $text;
$text = htmlspecialchars($text);
+ $text = str_replace("\n", "<br/>", $text); // convert newlines to HTML breaks
}
- if ($plainMetaInfo === '') {
+ if ($plainMetaInfo === '' || $plainMetaInfo === true) {
$plainMetaInfo = $metaInfo;
$metaInfo = htmlspecialchars($metaInfo);
}
@@ -475,11 +479,29 @@ EOF;
}
$this->htmlBody .= vsprintf($this->listItem, [$icon, $htmlText]);
if ($plainText !== false) {
- $this->plainBody .= ' * ' . $plainText;
- if ($plainMetaInfo !== false) {
- $this->plainBody .= ' (' . $plainMetaInfo . ')';
+ if ($plainIndent === 0) {
+ /*
+ * If plainIndent is not set by caller, this is the old NC17 layout code.
+ */
+ $this->plainBody .= ' * ' . $plainText;
+ if ($plainMetaInfo !== false) {
+ $this->plainBody .= ' (' . $plainMetaInfo . ')';
+ }
+ $this->plainBody .= PHP_EOL;
+ } else {
+ /*
+ * Caller can set plainIndent > 0 to format plainText in tabular fashion.
+ * with plainMetaInfo in column 1, and plainText in column 2.
+ * The plainMetaInfo label is right justified in a field of width
+ * "plainIndent". Multilines after the first are indented plainIndent+1
+ * (to account for space after label). Fixes: #12391
+ */
+ /** @var string $label */
+ $label = ($plainMetaInfo !== false)? $plainMetaInfo : '';
+ $this->plainBody .= sprintf("%${plainIndent}s %s\n",
+ $label,
+ str_replace("\n", "\n" . str_repeat(' ', $plainIndent + 1), $plainText));
}
- $this->plainBody .= PHP_EOL;
}
}
@@ -538,7 +560,7 @@ EOF;
$textColor = $this->themingDefaults->getTextColorPrimary();
$this->htmlBody .= vsprintf($this->buttonGroup, [$color, $color, $urlLeft, $color, $textColor, $textColor, $textLeft, $urlRight, $textRight]);
- $this->plainBody .= $plainTextLeft . ': ' . $urlLeft . PHP_EOL;
+ $this->plainBody .= PHP_EOL . $plainTextLeft . ': ' . $urlLeft . PHP_EOL;
$this->plainBody .= $plainTextRight . ': ' . $urlRight . PHP_EOL . PHP_EOL;
}
@@ -573,7 +595,7 @@ EOF;
$this->plainBody .= $plainText . ': ';
}
- $this->plainBody .= $url . PHP_EOL;
+ $this->plainBody .= $url . PHP_EOL;
}
/**
diff --git a/lib/private/Mail/Mailer.php b/lib/private/Mail/Mailer.php
index fc8de9ccd0b..f8dc739428a 100644
--- a/lib/private/Mail/Mailer.php
+++ b/lib/private/Mail/Mailer.php
@@ -12,6 +12,7 @@ declare(strict_types=1);
* @author Jared Boone <jared.boone@gmail.com>
* @author Joas Schilling <coding@schilljs.com>
* @author Julius Härtl <jus@bitgrid.net>
+ * @author kevin147147 <kevintamool@gmail.com>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -59,9 +60,9 @@ use OCP\Mail\Events\BeforeMessageSent;
* $mailer = \OC::$server->getMailer();
* $message = $mailer->createMessage();
* $message->setSubject('Your Subject');
- * $message->setFrom(array('cloud@domain.org' => 'ownCloud Notifier');
- * $message->setTo(array('recipient@domain.org' => 'Recipient');
- * $message->setBody('The message text');
+ * $message->setFrom(array('cloud@domain.org' => 'ownCloud Notifier'));
+ * $message->setTo(array('recipient@domain.org' => 'Recipient'));
+ * $message->setBody('The message text', 'text/html');
* $mailer->send($message);
*
* This message can then be passed to send() of \OC\Mail\Mailer
diff --git a/lib/private/Memcache/APCu.php b/lib/private/Memcache/APCu.php
index 87d72ec1968..ed3c81b70d7 100644
--- a/lib/private/Memcache/APCu.php
+++ b/lib/private/Memcache/APCu.php
@@ -5,7 +5,7 @@
* @author Andreas Fischer <bantu@owncloud.com>
* @author Bart Visscher <bartv@thisnet.nl>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Clark Tomlinson <fallen013@gmail.com>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
@@ -28,6 +28,7 @@
namespace OC\Memcache;
+use bantu\IniGetWrapper\IniGetWrapper;
use OCP\IMemcache;
class APCu extends Cache implements IMemcache {
@@ -154,9 +155,9 @@ class APCu extends Cache implements IMemcache {
public static function isAvailable() {
if (!extension_loaded('apcu')) {
return false;
- } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enabled')) {
+ } elseif (!\OC::$server->get(IniGetWrapper::class)->getBool('apc.enabled')) {
return false;
- } elseif (!\OC::$server->getIniWrapper()->getBool('apc.enable_cli') && \OC::$CLI) {
+ } elseif (!\OC::$server->get(IniGetWrapper::class)->getBool('apc.enable_cli') && \OC::$CLI) {
return false;
} elseif (
version_compare(phpversion('apc') ?: '0.0.0', '4.0.6') === -1 &&
diff --git a/lib/private/Memcache/Factory.php b/lib/private/Memcache/Factory.php
index 030769b5557..6db9b1007ac 100644
--- a/lib/private/Memcache/Factory.php
+++ b/lib/private/Memcache/Factory.php
@@ -11,7 +11,7 @@
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Stefan Weil <sw@weilnetz.de>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Memcache/Memcached.php b/lib/private/Memcache/Memcached.php
index eff76a41c45..7b852a418e1 100644
--- a/lib/private/Memcache/Memcached.php
+++ b/lib/private/Memcache/Memcached.php
@@ -52,13 +52,13 @@ class Memcached extends Cache implements IMemcache {
$defaultOptions = [
\Memcached::OPT_CONNECT_TIMEOUT => 50,
- \Memcached::OPT_RETRY_TIMEOUT => 50,
- \Memcached::OPT_SEND_TIMEOUT => 50,
- \Memcached::OPT_RECV_TIMEOUT => 50,
- \Memcached::OPT_POLL_TIMEOUT => 50,
+ \Memcached::OPT_RETRY_TIMEOUT => 50,
+ \Memcached::OPT_SEND_TIMEOUT => 50,
+ \Memcached::OPT_RECV_TIMEOUT => 50,
+ \Memcached::OPT_POLL_TIMEOUT => 50,
// Enable compression
- \Memcached::OPT_COMPRESSION => true,
+ \Memcached::OPT_COMPRESSION => true,
// Turn on consistent hashing
\Memcached::OPT_LIBKETAMA_COMPATIBLE => true,
@@ -110,7 +110,7 @@ class Memcached extends Cache implements IMemcache {
public function set($key, $value, $ttl = 0) {
if ($ttl > 0) {
- $result = self::$cache->set($this->getNameSpace() . $key, $value, $ttl);
+ $result = self::$cache->set($this->getNameSpace() . $key, $value, $ttl);
} else {
$result = self::$cache->set($this->getNameSpace() . $key, $value);
}
@@ -126,7 +126,7 @@ class Memcached extends Cache implements IMemcache {
}
public function remove($key) {
- $result= self::$cache->delete($this->getNameSpace() . $key);
+ $result = self::$cache->delete($this->getNameSpace() . $key);
if (self::$cache->getResultCode() !== \Memcached::RES_NOTFOUND) {
$this->verifyReturnCode();
}
diff --git a/lib/private/Memcache/NullCache.php b/lib/private/Memcache/NullCache.php
index bdb6406b24c..5ad3cb22201 100644
--- a/lib/private/Memcache/NullCache.php
+++ b/lib/private/Memcache/NullCache.php
@@ -7,7 +7,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Memcache/Redis.php b/lib/private/Memcache/Redis.php
index dfbdd029565..56470afa0c5 100644
--- a/lib/private/Memcache/Redis.php
+++ b/lib/private/Memcache/Redis.php
@@ -101,7 +101,13 @@ class Redis extends Cache implements IMemcacheTTL {
if (!is_int($value)) {
$value = json_encode($value);
}
- return self::$cache->setnx($this->getPrefix() . $key, $value);
+
+ $args = ['nx'];
+ if ($ttl !== 0 && is_int($ttl)) {
+ $args['ex'] = $ttl;
+ }
+
+ return self::$cache->set($this->getPrefix() . $key, $value, $args);
}
/**
diff --git a/lib/private/Migration/BackgroundRepair.php b/lib/private/Migration/BackgroundRepair.php
index fd616d505e0..5b8c7875ab7 100644
--- a/lib/private/Migration/BackgroundRepair.php
+++ b/lib/private/Migration/BackgroundRepair.php
@@ -2,6 +2,7 @@
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -62,7 +63,7 @@ class BackgroundRepair extends TimedJob {
*/
public function execute($jobList, ILogger $logger = null) {
// add an interval of 15 mins
- $this->setInterval(15*60);
+ $this->setInterval(15 * 60);
$this->jobList = $jobList;
$this->logger = $logger;
diff --git a/lib/private/NaturalSort.php b/lib/private/NaturalSort.php
index 31829a84e6a..d328ad0f359 100644
--- a/lib/private/NaturalSort.php
+++ b/lib/private/NaturalSort.php
@@ -8,7 +8,7 @@
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin McCorkell <robin@mccorkell.me.uk>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/NavigationManager.php b/lib/private/NavigationManager.php
index 81642fac234..e250523b98f 100644
--- a/lib/private/NavigationManager.php
+++ b/lib/private/NavigationManager.php
@@ -6,6 +6,7 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Kesselberg <mail@danielkesselberg.de>
+ * @author Georg Ehrke <oc.list@georgehrke.com>
* @author Joas Schilling <coding@schilljs.com>
* @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
* @author Julius Härtl <jus@bitgrid.net>
@@ -79,12 +80,7 @@ class NavigationManager implements INavigationManager {
}
/**
- * Creates a new navigation entry
- *
- * @param array|\Closure $entry Array containing: id, name, order, icon and href key
- * The use of a closure is preferred, because it will avoid
- * loading the routing of your app, unless required.
- * @return void
+ * @inheritDoc
*/
public function add($entry) {
if ($entry instanceof \Closure) {
@@ -106,10 +102,7 @@ class NavigationManager implements INavigationManager {
}
/**
- * Get a list of navigation entries
- *
- * @param string $type type of the navigation entries
- * @return array
+ * @inheritDoc
*/
public function getAll(string $type = 'link'): array {
$this->init();
@@ -171,19 +164,14 @@ class NavigationManager implements INavigationManager {
}
/**
- * Sets the current navigation entry of the currently running app
- * @param string $id of the app entry to activate (from added $entry)
+ * @inheritDoc
*/
public function setActiveEntry($id) {
$this->activeEntry = $id;
}
/**
- * gets the active Menu entry
- * @return string id or empty string
- *
- * This function returns the id of the active navigation entry (set by
- * setActiveEntry
+ * @inheritDoc
*/
public function getActiveEntry() {
return $this->activeEntry;
diff --git a/lib/private/OCS/DiscoveryService.php b/lib/private/OCS/DiscoveryService.php
index 1c69d1ecc9a..0a28b09fda1 100644
--- a/lib/private/OCS/DiscoveryService.php
+++ b/lib/private/OCS/DiscoveryService.php
@@ -97,7 +97,7 @@ class DiscoveryService implements IDiscoveryService {
}
// Write into cache
- $this->cache->set($remote . '#' . $service, json_encode($discoveredServices), 60*60*24);
+ $this->cache->set($remote . '#' . $service, json_encode($discoveredServices), 60 * 60 * 24);
return $discoveredServices;
}
diff --git a/lib/private/Preview/Generator.php b/lib/private/Preview/Generator.php
index f7aed987d89..2be08d1b2c4 100644
--- a/lib/private/Preview/Generator.php
+++ b/lib/private/Preview/Generator.php
@@ -3,10 +3,12 @@
* @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Elijah Martin-Merrill <elijah@nyp-itsours.com>
* @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Scott Dutton <scott@exussum.co.uk>
*
* @license GNU AGPL version 3 or any later version
*
@@ -126,9 +128,6 @@ class Generator {
if ($mimeType === null) {
$mimeType = $file->getMimeType();
}
- if (!$this->previewManager->isMimeSupported($mimeType)) {
- throw new NotFoundException();
- }
$previewFolder = $this->getPreviewFolder($file);
@@ -155,7 +154,7 @@ class Generator {
$crop = $specification['crop'] ?? false;
$mode = $specification['mode'] ?? IPreview::MODE_FILL;
- // If both width and heigth are -1 we just want the max preview
+ // If both width and height are -1 we just want the max preview
if ($width === -1 && $height === -1) {
$width = $maxWidth;
$height = $maxHeight;
@@ -176,6 +175,10 @@ class Generator {
try {
$preview = $this->getCachedPreview($previewFolder, $width, $height, $crop, $maxPreview->getMimeType(), $previewVersion);
} catch (NotFoundException $e) {
+ if (!$this->previewManager->isMimeSupported($mimeType)) {
+ throw new NotFoundException();
+ }
+
if ($maxPreviewImage === null) {
$maxPreviewImage = $this->helper->getImage($maxPreview);
}
@@ -192,6 +195,12 @@ class Generator {
}
}
+ // Free memory being used by the embedded image resource. Without this the image is kept in memory indefinitely.
+ // Garbage Collection does NOT free this memory. We have to do it ourselves.
+ if ($maxPreviewImage instanceof \OC_Image) {
+ $maxPreviewImage->destroy();
+ }
+
return $preview;
}
diff --git a/lib/private/Preview/Storage/Root.php b/lib/private/Preview/Storage/Root.php
index a9a72026a51..675263fdd50 100644
--- a/lib/private/Preview/Storage/Root.php
+++ b/lib/private/Preview/Storage/Root.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
/**
* @copyright Copyright (c) 2020, 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
@@ -33,13 +34,16 @@ use OCP\Files\NotFoundException;
use OCP\Files\SimpleFS\ISimpleFolder;
class Root extends AppData {
+ private $isMultibucketPreviewDistributionEnabled = false;
public function __construct(IRootFolder $rootFolder, SystemConfig $systemConfig) {
parent::__construct($rootFolder, $systemConfig, 'preview');
+
+ $this->isMultibucketPreviewDistributionEnabled = $systemConfig->getValue('objectstore.multibucket.preview-distribution', false) === true;
}
public function getFolder(string $name): ISimpleFolder {
- $internalFolder = $this->getInternalFolder($name);
+ $internalFolder = self::getInternalFolder($name);
try {
return parent::getFolder($internalFolder);
@@ -50,11 +54,24 @@ class Root extends AppData {
*/
}
- return parent::getFolder($name);
+ try {
+ return parent::getFolder($name);
+ } catch (NotFoundException $e) {
+ /*
+ * The old folder structure is not found.
+ * Lets try the multibucket fallback if available
+ */
+ if ($this->isMultibucketPreviewDistributionEnabled) {
+ return parent::getFolder('old-multibucket/' . $internalFolder);
+ }
+
+ // when there is no further fallback just throw the exception
+ throw $e;
+ }
}
public function newFolder(string $name): ISimpleFolder {
- $internalFolder = $this->getInternalFolder($name);
+ $internalFolder = self::getInternalFolder($name);
return parent::newFolder($internalFolder);
}
@@ -66,7 +83,7 @@ class Root extends AppData {
return [];
}
- private function getInternalFolder(string $name): string {
+ public static function getInternalFolder(string $name): string {
return implode('/', str_split(substr(md5($name), 0, 7))) . '/' . $name;
}
}
diff --git a/lib/private/Preview/TXT.php b/lib/private/Preview/TXT.php
index 4004b0a0647..968a15a5683 100644
--- a/lib/private/Preview/TXT.php
+++ b/lib/private/Preview/TXT.php
@@ -76,7 +76,7 @@ class TXT extends ProviderV2 {
imagecolorallocate($image, 255, 255, 255);
$textColor = imagecolorallocate($image, 0, 0, 0);
- $fontFile = __DIR__;
+ $fontFile = __DIR__;
$fontFile .= '/../../../core';
$fontFile .= '/fonts/NotoSans-Regular.ttf';
diff --git a/lib/private/PreviewManager.php b/lib/private/PreviewManager.php
index 546d495b47d..8fa0fc92da5 100644
--- a/lib/private/PreviewManager.php
+++ b/lib/private/PreviewManager.php
@@ -261,7 +261,6 @@ class PreviewManager implements IPreview {
continue;
}
- /** @var $provider IProvider */
if ($provider->isAvailable($file)) {
return true;
}
@@ -370,14 +369,14 @@ class PreviewManager implements IPreview {
$checkImagick = new \Imagick();
$imagickProviders = [
- 'SVG' => ['mimetype' => '/image\/svg\+xml/', 'class' => Preview\SVG::class],
- 'TIFF' => ['mimetype' => '/image\/tiff/', 'class' => Preview\TIFF::class],
- 'PDF' => ['mimetype' => '/application\/pdf/', 'class' => Preview\PDF::class],
- 'AI' => ['mimetype' => '/application\/illustrator/', 'class' => Preview\Illustrator::class],
- 'PSD' => ['mimetype' => '/application\/x-photoshop/', 'class' => Preview\Photoshop::class],
- 'EPS' => ['mimetype' => '/application\/postscript/', 'class' => Preview\Postscript::class],
- 'TTF' => ['mimetype' => '/application\/(?:font-sfnt|x-font$)/', 'class' => Preview\Font::class],
- 'HEIC' => ['mimetype' => '/image\/hei(f|c)/', 'class' => Preview\HEIC::class],
+ 'SVG' => ['mimetype' => '/image\/svg\+xml/', 'class' => Preview\SVG::class],
+ 'TIFF' => ['mimetype' => '/image\/tiff/', 'class' => Preview\TIFF::class],
+ 'PDF' => ['mimetype' => '/application\/pdf/', 'class' => Preview\PDF::class],
+ 'AI' => ['mimetype' => '/application\/illustrator/', 'class' => Preview\Illustrator::class],
+ 'PSD' => ['mimetype' => '/application\/x-photoshop/', 'class' => Preview\Photoshop::class],
+ 'EPS' => ['mimetype' => '/application\/postscript/', 'class' => Preview\Postscript::class],
+ 'TTF' => ['mimetype' => '/application\/(?:font-sfnt|x-font$)/', 'class' => Preview\Font::class],
+ 'HEIC' => ['mimetype' => '/image\/hei(f|c)/', 'class' => Preview\HEIC::class],
];
foreach ($imagickProviders as $queryFormat => $provider) {
diff --git a/lib/private/Repair.php b/lib/private/Repair.php
index 60609de4170..80a8a8a87c1 100644
--- a/lib/private/Repair.php
+++ b/lib/private/Repair.php
@@ -14,7 +14,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -34,20 +34,31 @@
namespace OC;
+use OC\App\AppStore\Bundles\BundleFetcher;
use OC\Avatar\AvatarManager;
+use OC\Repair\AddBruteForceCleanupJob;
use OC\Repair\AddCleanupUpdaterBackupsJob;
use OC\Repair\CleanTags;
use OC\Repair\ClearFrontendCaches;
use OC\Repair\ClearGeneratedAvatarCache;
use OC\Repair\Collation;
use OC\Repair\MoveUpdaterStepFile;
+use OC\Repair\Owncloud\CleanPreviews;
use OC\Repair\NC11\FixMountStorages;
+use OC\Repair\Owncloud\MoveAvatars;
+use OC\Repair\Owncloud\InstallCoreBundle;
+use OC\Repair\Owncloud\UpdateLanguageCodes;
use OC\Repair\NC13\AddLogRotateJob;
use OC\Repair\NC14\AddPreviewBackgroundCleanupJob;
use OC\Repair\NC16\AddClenupLoginFlowV2BackgroundJob;
use OC\Repair\NC16\CleanupCardDAVPhotoCache;
use OC\Repair\NC16\ClearCollectionsAccessCache;
use OC\Repair\NC18\ResetGeneratedAvatarFlag;
+use OC\Repair\NC20\EncryptionLegacyCipher;
+use OC\Repair\NC20\EncryptionMigration;
+use OC\Repair\NC20\ShippedDashboardEnable;
+use OC\Repair\NC21\AddCheckForUserCertificatesJob;
+use OC\Repair\NC21\ValidatePhoneNumber;
use OC\Repair\OldGroupMembershipShares;
use OC\Repair\Owncloud\DropAccountTermsTable;
use OC\Repair\Owncloud\SaveAccountsTableData;
@@ -84,7 +95,7 @@ class Repair implements IOutput {
*/
public function __construct(array $repairSteps, EventDispatcherInterface $dispatcher) {
$this->repairSteps = $repairSteps;
- $this->dispatcher = $dispatcher;
+ $this->dispatcher = $dispatcher;
}
/**
@@ -141,11 +152,26 @@ class Repair implements IOutput {
public static function getRepairSteps() {
return [
new Collation(\OC::$server->getConfig(), \OC::$server->getLogger(), \OC::$server->getDatabaseConnection(), false),
- new RepairMimeTypes(\OC::$server->getConfig()),
+ new RepairMimeTypes(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()),
new CleanTags(\OC::$server->getDatabaseConnection(), \OC::$server->getUserManager()),
new RepairInvalidShares(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()),
new MoveUpdaterStepFile(\OC::$server->getConfig()),
+ new MoveAvatars(
+ \OC::$server->getJobList(),
+ \OC::$server->getConfig()
+ ),
+ new CleanPreviews(
+ \OC::$server->getJobList(),
+ \OC::$server->getUserManager(),
+ \OC::$server->getConfig()
+ ),
new FixMountStorages(\OC::$server->getDatabaseConnection()),
+ new UpdateLanguageCodes(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig()),
+ new InstallCoreBundle(
+ \OC::$server->query(BundleFetcher::class),
+ \OC::$server->getConfig(),
+ \OC::$server->query(Installer::class)
+ ),
new AddLogRotateJob(\OC::$server->getJobList()),
new ClearFrontendCaches(\OC::$server->getMemCacheFactory(), \OC::$server->query(SCSSCacher::class), \OC::$server->query(JSCombiner::class)),
new ClearGeneratedAvatarCache(\OC::$server->getConfig(), \OC::$server->query(AvatarManager::class)),
@@ -156,6 +182,11 @@ class Repair implements IOutput {
new RemoveLinkShares(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig(), \OC::$server->getGroupManager(), \OC::$server->getNotificationManager(), \OC::$server->query(ITimeFactory::class)),
new ClearCollectionsAccessCache(\OC::$server->getConfig(), \OC::$server->query(IManager::class)),
\OC::$server->query(ResetGeneratedAvatarFlag::class),
+ \OC::$server->query(EncryptionLegacyCipher::class),
+ \OC::$server->query(EncryptionMigration::class),
+ \OC::$server->get(ShippedDashboardEnable::class),
+ \OC::$server->get(AddBruteForceCleanupJob::class),
+ \OC::$server->get(AddCheckForUserCertificatesJob::class),
];
}
@@ -167,7 +198,8 @@ class Repair implements IOutput {
*/
public static function getExpensiveRepairSteps() {
return [
- new OldGroupMembershipShares(\OC::$server->getDatabaseConnection(), \OC::$server->getGroupManager())
+ new OldGroupMembershipShares(\OC::$server->getDatabaseConnection(), \OC::$server->getGroupManager()),
+ \OC::$server->get(ValidatePhoneNumber::class),
];
}
@@ -179,8 +211,8 @@ class Repair implements IOutput {
*/
public static function getBeforeUpgradeRepairSteps() {
$connection = \OC::$server->getDatabaseConnection();
- $config = \OC::$server->getConfig();
- $steps = [
+ $config = \OC::$server->getConfig();
+ $steps = [
new Collation(\OC::$server->getConfig(), \OC::$server->getLogger(), $connection, true),
new SqliteAutoincrement($connection),
new SaveAccountsTableData($connection, $config),
diff --git a/lib/private/Repair/AddBruteForceCleanupJob.php b/lib/private/Repair/AddBruteForceCleanupJob.php
new file mode 100644
index 00000000000..b287b4baa2f
--- /dev/null
+++ b/lib/private/Repair/AddBruteForceCleanupJob.php
@@ -0,0 +1,50 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @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 OC\Repair;
+
+use OC\Security\Bruteforce\CleanupJob;
+use OCP\BackgroundJob\IJobList;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class AddBruteForceCleanupJob implements IRepairStep {
+
+ /** @var IJobList */
+ protected $jobList;
+
+ public function __construct(IJobList $jobList) {
+ $this->jobList = $jobList;
+ }
+
+ public function getName() {
+ return 'Add job to cleanup the bruteforce entries';
+ }
+
+ public function run(IOutput $output) {
+ $this->jobList->add(CleanupJob::class);
+ }
+}
diff --git a/lib/private/Repair/CleanTags.php b/lib/private/Repair/CleanTags.php
index 959eb50e5a7..5b8e44f37b6 100644
--- a/lib/private/Repair/CleanTags.php
+++ b/lib/private/Repair/CleanTags.php
@@ -4,7 +4,6 @@
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -171,7 +170,6 @@ class CleanTags implements IRepairStep {
* @param string $sourceId
* @param string $sourceNullColumn If this column is null in the source table,
* the entry is deleted in the $deleteTable
- * @suppress SqlInjectionChecker
*/
protected function deleteOrphanEntries(IOutput $output, $repairInfo, $deleteTable, $deleteId, $sourceTable, $sourceId, $sourceNullColumn) {
$qb = $this->connection->getQueryBuilder();
diff --git a/lib/private/Repair/ClearFrontendCaches.php b/lib/private/Repair/ClearFrontendCaches.php
index 4f48d9623b1..523a1fc6be5 100644
--- a/lib/private/Repair/ClearFrontendCaches.php
+++ b/lib/private/Repair/ClearFrontendCaches.php
@@ -2,7 +2,7 @@
/**
* @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
*
- * @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Julius Härtl <jus@bitgrid.net>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
@@ -46,8 +46,8 @@ class ClearFrontendCaches implements IRepairStep {
SCSSCacher $SCSSCacher,
JSCombiner $JSCombiner) {
$this->cacheFactory = $cacheFactory;
- $this->scssCacher = $SCSSCacher;
- $this->jsCombiner = $JSCombiner;
+ $this->scssCacher = $SCSSCacher;
+ $this->jsCombiner = $JSCombiner;
}
public function getName() {
diff --git a/lib/private/Repair/ClearGeneratedAvatarCache.php b/lib/private/Repair/ClearGeneratedAvatarCache.php
index 44a390d66a1..26d436451bf 100644
--- a/lib/private/Repair/ClearGeneratedAvatarCache.php
+++ b/lib/private/Repair/ClearGeneratedAvatarCache.php
@@ -2,6 +2,7 @@
/**
* @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
*
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
* @author Michael Weimann <mail@michael-weimann.eu>
*
@@ -38,7 +39,7 @@ class ClearGeneratedAvatarCache implements IRepairStep {
private $config;
public function __construct(IConfig $config, AvatarManager $avatarManager) {
- $this->config = $config;
+ $this->config = $config;
$this->avatarManager = $avatarManager;
}
diff --git a/lib/private/Repair/NC20/EncryptionLegacyCipher.php b/lib/private/Repair/NC20/EncryptionLegacyCipher.php
new file mode 100644
index 00000000000..e60a2435349
--- /dev/null
+++ b/lib/private/Repair/NC20/EncryptionLegacyCipher.php
@@ -0,0 +1,69 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ * @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 OC\Repair\NC20;
+
+use OCP\Encryption\IManager;
+use OCP\IConfig;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class EncryptionLegacyCipher implements IRepairStep {
+
+ /** @var IConfig */
+ private $config;
+ /** @var IManager */
+ private $manager;
+
+ public function __construct(IConfig $config,
+ IManager $manager) {
+ $this->config = $config;
+ $this->manager = $manager;
+ }
+
+ public function getName(): string {
+ return 'Keep legacy encryption enabled';
+ }
+
+ private function shouldRun(): bool {
+ $versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0.0');
+ return version_compare($versionFromBeforeUpdate, '20.0.0.0', '<=');
+ }
+
+ public function run(IOutput $output): void {
+ if (!$this->shouldRun()) {
+ return;
+ }
+
+ $masterKeyId = $this->config->getAppValue('encryption', 'masterKeyId');
+ if ($this->manager->isEnabled() || !empty($masterKeyId)) {
+ if ($this->config->getSystemValue('encryption.legacy_format_support', '') === '') {
+ $this->config->setSystemValue('encryption.legacy_format_support', true);
+ }
+ }
+ }
+}
diff --git a/lib/private/Repair/NC20/EncryptionMigration.php b/lib/private/Repair/NC20/EncryptionMigration.php
new file mode 100644
index 00000000000..45789d2317b
--- /dev/null
+++ b/lib/private/Repair/NC20/EncryptionMigration.php
@@ -0,0 +1,69 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ * @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 OC\Repair\NC20;
+
+use OCP\Encryption\IManager;
+use OCP\IConfig;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class EncryptionMigration implements IRepairStep {
+
+ /** @var IConfig */
+ private $config;
+ /** @var IManager */
+ private $manager;
+
+ public function __construct(IConfig $config,
+ IManager $manager) {
+ $this->config = $config;
+ $this->manager = $manager;
+ }
+
+ public function getName(): string {
+ return 'Check encryption key format';
+ }
+
+ private function shouldRun(): bool {
+ $versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0.0');
+ return version_compare($versionFromBeforeUpdate, '20.0.0.1', '<=');
+ }
+
+ public function run(IOutput $output): void {
+ if (!$this->shouldRun()) {
+ return;
+ }
+
+ $masterKeyId = $this->config->getAppValue('encryption', 'masterKeyId');
+ if ($this->manager->isEnabled() || !empty($masterKeyId)) {
+ if ($this->config->getSystemValue('encryption.key_storage_migrated', '') === '') {
+ $this->config->setSystemValue('encryption.key_storage_migrated', false);
+ }
+ }
+ }
+}
diff --git a/lib/private/Repair/NC20/ShippedDashboardEnable.php b/lib/private/Repair/NC20/ShippedDashboardEnable.php
new file mode 100644
index 00000000000..b8900373b2a
--- /dev/null
+++ b/lib/private/Repair/NC20/ShippedDashboardEnable.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @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/>.
+ *
+ */
+
+declare(strict_types=1);
+
+
+namespace OC\Repair\NC20;
+
+use OCP\IConfig;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class ShippedDashboardEnable implements IRepairStep {
+
+ /** @var IConfig */
+ private $config;
+
+ public function __construct(IConfig $config) {
+ $this->config = $config;
+ }
+
+ public function getName() {
+ return 'Remove old dashboard app config data';
+ }
+
+ public function run(IOutput $output) {
+ $version = $this->config->getAppValue('dashboard', 'version', '7.0.0');
+ if (version_compare($version, '7.0.0', '<')) {
+ $this->config->deleteAppValues('dashboard');
+ $output->info('Removed old dashboard app config');
+ }
+ }
+}
diff --git a/lib/private/Repair/NC21/AddCheckForUserCertificatesJob.php b/lib/private/Repair/NC21/AddCheckForUserCertificatesJob.php
new file mode 100644
index 00000000000..df6637e3948
--- /dev/null
+++ b/lib/private/Repair/NC21/AddCheckForUserCertificatesJob.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * @copyright Copyright (c) 2020 Morris Jobke <hey@morrisjobke.de>
+ *
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @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\Repair\NC21;
+
+use OC\Core\BackgroundJobs\CheckForUserCertificates;
+use OCP\BackgroundJob\IJobList;
+use OCP\IConfig;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class AddCheckForUserCertificatesJob implements IRepairStep {
+
+ /** @var IJobList */
+ protected $jobList;
+ /** @var IConfig */
+ private $config;
+
+ public function __construct(IConfig $config, IJobList $jobList) {
+ $this->jobList = $jobList;
+ $this->config = $config;
+ }
+
+ public function getName() {
+ return 'Queue a one-time job to check for user uploaded certificates';
+ }
+
+ private function shouldRun() {
+ $versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0.0');
+
+ // was added to 21.0.0.2
+ return version_compare($versionFromBeforeUpdate, '21.0.0.2', '<');
+ }
+
+ public function run(IOutput $output) {
+ if ($this->shouldRun()) {
+ $this->config->setAppValue('files_external', 'user_certificate_scan', 'not-run-yet');
+ $this->jobList->add(CheckForUserCertificates::class);
+ }
+ }
+}
diff --git a/lib/private/Repair/NC21/ValidatePhoneNumber.php b/lib/private/Repair/NC21/ValidatePhoneNumber.php
new file mode 100644
index 00000000000..995c38602f3
--- /dev/null
+++ b/lib/private/Repair/NC21/ValidatePhoneNumber.php
@@ -0,0 +1,90 @@
+<?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 OC\Repair\NC21;
+
+use OC\Accounts\AccountManager;
+use OCP\Accounts\IAccountManager;
+use OCP\IConfig;
+use OCP\IUser;
+use OCP\IUserManager;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class ValidatePhoneNumber implements IRepairStep {
+
+ /** @var IConfig */
+ protected $config;
+ /** @var IUserManager */
+ protected $userManager;
+ /** @var AccountManager */
+ private $accountManager;
+
+ public function __construct(IUserManager $userManager,
+ AccountManager $accountManager,
+ IConfig $config) {
+ $this->config = $config;
+ $this->userManager = $userManager;
+ $this->accountManager = $accountManager;
+ }
+
+ public function getName(): string {
+ return 'Validate the phone number and store it in a known format for search';
+ }
+
+ private function shouldRun(): bool {
+ return true;
+ }
+
+ public function run(IOutput $output): void {
+ if ($this->config->getSystemValueString('default_phone_region', '') === '') {
+ throw new \Exception('Can not validate phone numbers without `default_phone_region` being set in the config file');
+ }
+
+ $numUpdated = 0;
+ $numRemoved = 0;
+
+ $this->userManager->callForSeenUsers(function (IUser $user) use (&$numUpdated, &$numRemoved) {
+ $account = $this->accountManager->getUser($user);
+
+ if ($account[IAccountManager::PROPERTY_PHONE]['value'] !== '') {
+ $updated = $this->accountManager->updateUser($user, $account);
+
+ if ($account[IAccountManager::PROPERTY_PHONE]['value'] !== $updated[IAccountManager::PROPERTY_PHONE]['value']) {
+ if ($updated[IAccountManager::PROPERTY_PHONE]['value'] === '') {
+ $numRemoved++;
+ } else {
+ $numUpdated++;
+ }
+ }
+ }
+ });
+
+ if ($numRemoved > 0 || $numUpdated > 0) {
+ $output->info('Updated ' . $numUpdated . ' entries and cleaned ' . $numRemoved . ' invalid phone numbers');
+ }
+ }
+}
diff --git a/lib/private/Repair/OldGroupMembershipShares.php b/lib/private/Repair/OldGroupMembershipShares.php
index 2b2fd9cd470..d991ef82ac9 100644
--- a/lib/private/Repair/OldGroupMembershipShares.php
+++ b/lib/private/Repair/OldGroupMembershipShares.php
@@ -3,7 +3,6 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
* @license AGPL-3.0
@@ -66,7 +65,6 @@ class OldGroupMembershipShares implements IRepairStep {
* Must throw exception on error.
*
* @throws \Exception in case of failure
- * @suppress SqlInjectionChecker
*/
public function run(IOutput $output) {
$deletedEntries = 0;
diff --git a/lib/private/Repair/Owncloud/CleanPreviews.php b/lib/private/Repair/Owncloud/CleanPreviews.php
new file mode 100644
index 00000000000..267a1be7985
--- /dev/null
+++ b/lib/private/Repair/Owncloud/CleanPreviews.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @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\Repair\Owncloud;
+
+use OCP\BackgroundJob\IJobList;
+use OCP\IConfig;
+use OCP\IUser;
+use OCP\IUserManager;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class CleanPreviews implements IRepairStep {
+
+ /** @var IJobList */
+ private $jobList;
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /** @var IConfig */
+ private $config;
+
+ /**
+ * MoveAvatars constructor.
+ *
+ * @param IJobList $jobList
+ * @param IUserManager $userManager
+ * @param IConfig $config
+ */
+ public function __construct(IJobList $jobList,
+ IUserManager $userManager,
+ IConfig $config) {
+ $this->jobList = $jobList;
+ $this->userManager = $userManager;
+ $this->config = $config;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName() {
+ return 'Add preview cleanup background jobs';
+ }
+
+ public function run(IOutput $output) {
+ if (!$this->config->getAppValue('core', 'previewsCleanedUp', false)) {
+ $this->userManager->callForSeenUsers(function (IUser $user) {
+ $this->jobList->add(CleanPreviewsBackgroundJob::class, ['uid' => $user->getUID()]);
+ });
+ $this->config->setAppValue('core', 'previewsCleanedUp', '1');
+ }
+ }
+}
diff --git a/lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php b/lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php
new file mode 100644
index 00000000000..90aa59b2950
--- /dev/null
+++ b/lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php
@@ -0,0 +1,132 @@
+<?php
+/**
+ * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @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\Repair\Owncloud;
+
+use OC\BackgroundJob\QueuedJob;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\BackgroundJob\IJobList;
+use OCP\Files\Folder;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\Files\NotPermittedException;
+use OCP\ILogger;
+use OCP\IUserManager;
+
+class CleanPreviewsBackgroundJob extends QueuedJob {
+ /** @var IRootFolder */
+ private $rootFolder;
+
+ /** @var ILogger */
+ private $logger;
+
+ /** @var IJobList */
+ private $jobList;
+
+ /** @var ITimeFactory */
+ private $timeFactory;
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /**
+ * CleanPreviewsBackgroundJob constructor.
+ *
+ * @param IRootFolder $rootFolder
+ * @param ILogger $logger
+ * @param IJobList $jobList
+ * @param ITimeFactory $timeFactory
+ * @param IUserManager $userManager
+ */
+ public function __construct(IRootFolder $rootFolder,
+ ILogger $logger,
+ IJobList $jobList,
+ ITimeFactory $timeFactory,
+ IUserManager $userManager) {
+ $this->rootFolder = $rootFolder;
+ $this->logger = $logger;
+ $this->jobList = $jobList;
+ $this->timeFactory = $timeFactory;
+ $this->userManager = $userManager;
+ }
+
+ public function run($arguments) {
+ $uid = $arguments['uid'];
+ if (!$this->userManager->userExists($uid)) {
+ $this->logger->info('User no longer exists, skip user ' . $uid);
+ return;
+ }
+ $this->logger->info('Started preview cleanup for ' . $uid);
+ $empty = $this->cleanupPreviews($uid);
+
+ if (!$empty) {
+ $this->jobList->add(self::class, ['uid' => $uid]);
+ $this->logger->info('New preview cleanup scheduled for ' . $uid);
+ } else {
+ $this->logger->info('Preview cleanup done for ' . $uid);
+ }
+ }
+
+ /**
+ * @param $uid
+ * @return bool
+ */
+ private function cleanupPreviews($uid) {
+ try {
+ $userFolder = $this->rootFolder->getUserFolder($uid);
+ } catch (NotFoundException $e) {
+ return true;
+ }
+
+ $userRoot = $userFolder->getParent();
+
+ try {
+ /** @var Folder $thumbnailFolder */
+ $thumbnailFolder = $userRoot->get('thumbnails');
+ } catch (NotFoundException $e) {
+ return true;
+ }
+
+ $thumbnails = $thumbnailFolder->getDirectoryListing();
+
+ $start = $this->timeFactory->getTime();
+ foreach ($thumbnails as $thumbnail) {
+ try {
+ $thumbnail->delete();
+ } catch (NotPermittedException $e) {
+ // Ignore
+ }
+
+ if (($this->timeFactory->getTime() - $start) > 15) {
+ return false;
+ }
+ }
+
+ try {
+ $thumbnailFolder->delete();
+ } catch (NotPermittedException $e) {
+ // Ignore
+ }
+
+ return true;
+ }
+}
diff --git a/lib/private/Repair/Owncloud/InstallCoreBundle.php b/lib/private/Repair/Owncloud/InstallCoreBundle.php
new file mode 100644
index 00000000000..10d5357e5d8
--- /dev/null
+++ b/lib/private/Repair/Owncloud/InstallCoreBundle.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @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\Repair\Owncloud;
+
+use OC\App\AppStore\Bundles\BundleFetcher;
+use OC\Installer;
+use OCP\IConfig;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class InstallCoreBundle implements IRepairStep {
+ /** @var BundleFetcher */
+ private $bundleFetcher;
+ /** @var IConfig */
+ private $config;
+ /** @var Installer */
+ private $installer;
+
+ /**
+ * @param BundleFetcher $bundleFetcher
+ * @param IConfig $config
+ * @param Installer $installer
+ */
+ public function __construct(BundleFetcher $bundleFetcher,
+ IConfig $config,
+ Installer $installer) {
+ $this->bundleFetcher = $bundleFetcher;
+ $this->config = $config;
+ $this->installer = $installer;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName() {
+ return 'Install new core bundle components';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run(IOutput $output) {
+ $versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
+
+ if (version_compare($versionFromBeforeUpdate, '12.0.0.14', '>')) {
+ return;
+ }
+
+ $defaultBundle = $this->bundleFetcher->getDefaultInstallationBundle();
+ foreach ($defaultBundle as $bundle) {
+ try {
+ $this->installer->installAppBundle($bundle);
+ $output->info('Successfully installed core app bundle.');
+ } catch (\Exception $e) {
+ $output->warning('Could not install core app bundle: ' . $e->getMessage());
+ }
+ }
+ }
+}
diff --git a/lib/private/Repair/Owncloud/MoveAvatars.php b/lib/private/Repair/Owncloud/MoveAvatars.php
new file mode 100644
index 00000000000..37c79de22ab
--- /dev/null
+++ b/lib/private/Repair/Owncloud/MoveAvatars.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @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\Repair\Owncloud;
+
+use OCP\BackgroundJob\IJobList;
+use OCP\IConfig;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class MoveAvatars implements IRepairStep {
+
+ /** @var IJobList */
+ private $jobList;
+
+ /** @var IConfig */
+ private $config;
+
+ /**
+ * MoveAvatars constructor.
+ *
+ * @param IJobList $jobList
+ * @param IConfig $config
+ */
+ public function __construct(IJobList $jobList,
+ IConfig $config) {
+ $this->jobList = $jobList;
+ $this->config = $config;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName() {
+ return 'Add move avatar background job';
+ }
+
+ public function run(IOutput $output) {
+ // only run once
+ if ($this->config->getAppValue('core', 'moveavatarsdone') === 'yes') {
+ $output->info('Repair step already executed');
+ return;
+ }
+ if ($this->config->getSystemValue('enable_avatars', true) === false) {
+ $output->info('Avatars are disabled');
+ } else {
+ $output->info('Add background job');
+ $this->jobList->add(MoveAvatarsBackgroundJob::class);
+ // if all were done, no need to redo the repair during next upgrade
+ $this->config->setAppValue('core', 'moveavatarsdone', 'yes');
+ }
+ }
+}
diff --git a/lib/private/Repair/Owncloud/MoveAvatarsBackgroundJob.php b/lib/private/Repair/Owncloud/MoveAvatarsBackgroundJob.php
new file mode 100644
index 00000000000..e69beae7d6e
--- /dev/null
+++ b/lib/private/Repair/Owncloud/MoveAvatarsBackgroundJob.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @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\Repair\Owncloud;
+
+use OC\BackgroundJob\QueuedJob;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\Files\Storage;
+use OCP\IAvatarManager;
+use OCP\IUser;
+use OCP\IUserManager;
+use Psr\Log\LoggerInterface;
+
+class MoveAvatarsBackgroundJob extends QueuedJob {
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /** @var LoggerInterface */
+ private $logger;
+
+ /** @var IAvatarManager */
+ private $avatarManager;
+
+ /** @var Storage */
+ private $owncloudAvatarStorage;
+
+ public function __construct(IUserManager $userManager, LoggerInterface $logger, IAvatarManager $avatarManager, IRootFolder $rootFolder) {
+ $this->userManager = $userManager;
+ $this->logger = $logger;
+ $this->avatarManager = $avatarManager;
+ try {
+ $this->owncloudAvatarStorage = $rootFolder->get('avatars')->getStorage();
+ } catch (\Exception $e) {
+ }
+ }
+
+ public function run($arguments) {
+ $this->logger->info('Started migrating avatars to AppData folder');
+ $this->moveAvatars();
+ $this->logger->info('All avatars migrated to AppData folder');
+ }
+
+ private function moveAvatars(): void {
+ if (!$this->owncloudAvatarStorage) {
+ $this->logger->info('No legacy avatars available, skipping migration');
+ return;
+ }
+
+ $counter = 0;
+ $this->userManager->callForSeenUsers(function (IUser $user) use ($counter) {
+ $uid = $user->getUID();
+
+ $path = 'avatars/' . $this->buildOwnCloudAvatarPath($uid);
+ $avatar = $this->avatarManager->getAvatar($uid);
+ try {
+ $avatarPath = $path . '/avatar.' . $this->getExtension($path);
+ $resource = $this->owncloudAvatarStorage->fopen($avatarPath, 'r');
+ if ($resource) {
+ $avatar->set($resource);
+ fclose($resource);
+ } else {
+ throw new \Exception('Failed to open old avatar file for reading');
+ }
+ } catch (NotFoundException $e) {
+ // In case there is no avatar we can just skip
+ } catch (\Throwable $e) {
+ $this->logger->error('Failed to migrate avatar for user ' . $uid, ['exception' => $e]);
+ }
+
+ $counter++;
+ if ($counter % 100 === 0) {
+ $this->logger->info('{amount} avatars migrated', ['amount' => $counter]);
+ }
+ });
+ }
+
+ /**
+ * @throws NotFoundException
+ */
+ private function getExtension(string $path): string {
+ if ($this->owncloudAvatarStorage->file_exists("{$path}/avatar.jpg")) {
+ return 'jpg';
+ }
+ if ($this->owncloudAvatarStorage->file_exists("{$path}/avatar.png")) {
+ return 'png';
+ }
+ throw new NotFoundException("{$path}/avatar.jpg|png");
+ }
+
+ protected function buildOwnCloudAvatarPath(string $userId): string {
+ return substr_replace(substr_replace(md5($userId), '/', 4, 0), '/', 2, 0);
+ }
+}
diff --git a/lib/private/Repair/Owncloud/SaveAccountsTableData.php b/lib/private/Repair/Owncloud/SaveAccountsTableData.php
index 6ca46934d71..f11397d7ae5 100644
--- a/lib/private/Repair/Owncloud/SaveAccountsTableData.php
+++ b/lib/private/Repair/Owncloud/SaveAccountsTableData.php
@@ -4,6 +4,7 @@
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
+ * @author Julius Härtl <jus@bitgrid.net>
*
* @license GNU AGPL version 3 or any later version
*
@@ -78,6 +79,15 @@ class SaveAccountsTableData implements IRepairStep {
$numUsers = $this->runStep($offset);
}
+ // oc_persistent_locks will be removed later on anyways so we can just drop and ignore any foreign key constraints here
+ $tableName = $this->config->getSystemValue('dbtableprefix', 'oc_') . 'persistent_locks';
+ $schema = $this->db->createSchema();
+ $table = $schema->getTable($tableName);
+ foreach ($table->getForeignKeys() as $foreignKey) {
+ $table->removeForeignKey($foreignKey->getName());
+ }
+ $this->db->migrateToSchema($schema);
+
// Remove the table
if ($this->hasForeignKeyOnPersistentLocks) {
$this->db->dropTable('persistent_locks');
diff --git a/lib/private/Repair/Owncloud/UpdateLanguageCodes.php b/lib/private/Repair/Owncloud/UpdateLanguageCodes.php
new file mode 100644
index 00000000000..cd923b4e802
--- /dev/null
+++ b/lib/private/Repair/Owncloud/UpdateLanguageCodes.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Morris Jobke <hey@morrisjobke.de>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @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\Repair\Owncloud;
+
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IConfig;
+use OCP\IDBConnection;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class UpdateLanguageCodes implements IRepairStep {
+ /** @var IDBConnection */
+ private $connection;
+
+ /** @var IConfig */
+ private $config;
+
+ /**
+ * @param IDBConnection $connection
+ * @param IConfig $config
+ */
+ public function __construct(IDBConnection $connection,
+ IConfig $config) {
+ $this->connection = $connection;
+ $this->config = $config;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName() {
+ return 'Repair language codes';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run(IOutput $output) {
+ $versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
+
+ if (version_compare($versionFromBeforeUpdate, '12.0.0.13', '>')) {
+ return;
+ }
+
+ $languages = [
+ 'bg_BG' => 'bg',
+ 'cs_CZ' => 'cs',
+ 'fi_FI' => 'fi',
+ 'hu_HU' => 'hu',
+ 'nb_NO' => 'nb',
+ 'sk_SK' => 'sk',
+ 'th_TH' => 'th',
+ ];
+
+ foreach ($languages as $oldCode => $newCode) {
+ $qb = $this->connection->getQueryBuilder();
+
+ $affectedRows = $qb->update('preferences')
+ ->set('configvalue', $qb->createNamedParameter($newCode))
+ ->where($qb->expr()->eq('appid', $qb->createNamedParameter('core')))
+ ->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter('lang')))
+ ->andWhere($qb->expr()->eq('configvalue', $qb->createNamedParameter($oldCode), IQueryBuilder::PARAM_STR))
+ ->execute();
+
+ $output->info('Changed ' . $affectedRows . ' setting(s) from "' . $oldCode . '" to "' . $newCode . '" in preferences table.');
+ }
+ }
+}
diff --git a/lib/private/Repair/RepairInvalidShares.php b/lib/private/Repair/RepairInvalidShares.php
index 27defdeda01..bc03374ff98 100644
--- a/lib/private/Repair/RepairInvalidShares.php
+++ b/lib/private/Repair/RepairInvalidShares.php
@@ -6,7 +6,7 @@
* @author Joas Schilling <coding@schilljs.com>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -56,7 +56,6 @@ class RepairInvalidShares implements IRepairStep {
/**
* Adjust file share permissions
- * @suppress SqlInjectionChecker
*/
private function adjustFileSharePermissions(IOutput $out) {
$mask = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_SHARE;
diff --git a/lib/private/Repair/RepairMimeTypes.php b/lib/private/Repair/RepairMimeTypes.php
index b6b6ceed104..3e6fa51b196 100644
--- a/lib/private/Repair/RepairMimeTypes.php
+++ b/lib/private/Repair/RepairMimeTypes.php
@@ -5,15 +5,16 @@
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
+ * @author Julius Härtl <jus@bitgrid.net>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author nik gaffney <nik@fo.am>
* @author Olivier Paroz <github@oparoz.com>
* @author Rello <Rello@users.noreply.github.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Stefan Weil <sw@weilnetz.de>
* @author Thomas Ebert <thomas.ebert@usability.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Victor Dubiniuk <dubiniuk@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -33,84 +34,74 @@
namespace OC\Repair;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IConfig;
+use OCP\IDBConnection;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
class RepairMimeTypes implements IRepairStep {
- /**
- * @var \OCP\IConfig
- */
+ /** @var IConfig */
protected $config;
+ /** @var IDBConnection */
+ protected $connection;
- /**
- * @var int
- */
+ /** @var int */
protected $folderMimeTypeId;
- /**
- * @param \OCP\IConfig $config
- */
- public function __construct($config) {
+ public function __construct(IConfig $config,
+ IDBConnection $connection) {
$this->config = $config;
+ $this->connection = $connection;
}
public function getName() {
return 'Repair mime types';
}
- private static function existsStmt() {
- return \OC_DB::prepare('
- SELECT count(`mimetype`)
- FROM `*PREFIX*mimetypes`
- WHERE `mimetype` = ?
- ');
- }
-
- private static function getIdStmt() {
- return \OC_DB::prepare('
- SELECT `id`
- FROM `*PREFIX*mimetypes`
- WHERE `mimetype` = ?
- ');
- }
-
- private static function insertStmt() {
- return \OC_DB::prepare('
- INSERT INTO `*PREFIX*mimetypes` ( `mimetype` )
- VALUES ( ? )
- ');
- }
-
- private static function updateByNameStmt() {
- return \OC_DB::prepare('
- UPDATE `*PREFIX*filecache`
- SET `mimetype` = ?
- WHERE `mimetype` <> ? AND `mimetype` <> ? AND `name` ILIKE ?
- ');
- }
-
private function updateMimetypes($updatedMimetypes) {
+ $query = $this->connection->getQueryBuilder();
+ $query->select('id')
+ ->from('mimetypes')
+ ->where($query->expr()->eq('mimetype', $query->createParameter('mimetype'), IQueryBuilder::PARAM_INT));
+ $insert = $this->connection->getQueryBuilder();
+ $insert->insert('mimetypes')
+ ->setValue('mimetype', $insert->createParameter('mimetype'));
+
if (empty($this->folderMimeTypeId)) {
- $result = \OC_DB::executeAudited(self::getIdStmt(), ['httpd/unix-directory']);
- $this->folderMimeTypeId = (int)$result->fetchOne();
+ $query->setParameter('mimetype', 'httpd/unix-directory');
+ $result = $query->execute();
+ $this->folderMimeTypeId = (int)$result->fetchColumn();
+ $result->closeCursor();
}
+ $update = $this->connection->getQueryBuilder();
+ $update->update('filecache')
+ ->set('mimetype', $update->createParameter('mimetype'))
+ ->where($update->expr()->neq('mimetype', $update->createParameter('mimetype'), IQueryBuilder::PARAM_INT))
+ ->andWhere($update->expr()->neq('mimetype', $update->createParameter('folder'), IQueryBuilder::PARAM_INT))
+ ->andWhere($update->expr()->iLike('name', $update->createParameter('name')))
+ ->setParameter('folder', $this->folderMimeTypeId);
+
$count = 0;
foreach ($updatedMimetypes as $extension => $mimetype) {
- $result = \OC_DB::executeAudited(self::existsStmt(), [$mimetype]);
- $exists = $result->fetchOne();
+ // get target mimetype id
+ $query->setParameter('mimetype', $mimetype);
+ $result = $query->execute();
+ $mimetypeId = (int)$result->fetchColumn();
+ $result->closeCursor();
- if (!$exists) {
+ if (!$mimetypeId) {
// insert mimetype
- \OC_DB::executeAudited(self::insertStmt(), [$mimetype]);
+ $insert->setParameter('mimetype', $mimetype);
+ $insert->execute();
+ $mimetypeId = $insert->getLastInsertId();
}
- // get target mimetype id
- $result = \OC_DB::executeAudited(self::getIdStmt(), [$mimetype]);
- $mimetypeId = $result->fetchOne();
-
// change mimetype for files with x extension
- $count += \OC_DB::executeAudited(self::updateByNameStmt(), [$mimetypeId, $this->folderMimeTypeId, $mimetypeId, '%.' . $extension]);
+ $update->setParameter('mimetype', $mimetypeId)
+ ->setParameter('name', '%' . $this->connection->escapeLikeParameter('.' . $extension));
+ $count += $update->execute();
}
return $count;
@@ -191,6 +182,26 @@ class RepairMimeTypes implements IRepairStep {
return $this->updateMimetypes($updatedMimetypes);
}
+ private function introduceOpenDocumentTemplates() {
+ $updatedMimetypes = [
+ 'ott' => 'application/vnd.oasis.opendocument.text-template',
+ 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
+ 'otp' => 'application/vnd.oasis.opendocument.presentation-template',
+ 'otg' => 'application/vnd.oasis.opendocument.graphics-template',
+ ];
+
+ return $this->updateMimetypes($updatedMimetypes);
+ }
+
+ private function introduceOrgModeType() {
+ $updatedMimetypes = [
+ 'org' => 'text/org'
+ ];
+
+ return $this->updateMimetypes($updatedMimetypes);
+ }
+
+
/**
* Fix mime types
*/
@@ -227,5 +238,13 @@ class RepairMimeTypes implements IRepairStep {
if (version_compare($ocVersionFromBeforeUpdate, '14.0.0.10', '<') && $this->introduceComicbookTypes()) {
$out->info('Fixed comicbook mime types');
}
+
+ if (version_compare($ocVersionFromBeforeUpdate, '20.0.0.5', '<') && $this->introduceOpenDocumentTemplates()) {
+ $out->info('Fixed OpenDocument template mime types');
+ }
+
+ if (version_compare($ocVersionFromBeforeUpdate, '21.0.0.7', '<') && $this->introduceOrgModeType()) {
+ $out->info('Fixed orgmode mime types');
+ }
}
}
diff --git a/lib/private/Repair/SqliteAutoincrement.php b/lib/private/Repair/SqliteAutoincrement.php
index 4bdd7c729b4..651a3c144f3 100644
--- a/lib/private/Repair/SqliteAutoincrement.php
+++ b/lib/private/Repair/SqliteAutoincrement.php
@@ -4,7 +4,7 @@
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/RepairException.php b/lib/private/RepairException.php
index 002ec36fb94..c06fcc91f6e 100644
--- a/lib/private/RepairException.php
+++ b/lib/private/RepairException.php
@@ -3,7 +3,7 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/Route/Route.php b/lib/private/Route/Route.php
index 705183d24ae..8e419344881 100644
--- a/lib/private/Route/Route.php
+++ b/lib/private/Route/Route.php
@@ -151,7 +151,7 @@ class Route extends SymfonyRoute implements IRoute {
public function actionInclude($file) {
$function = function ($param) use ($file) {
unset($param["_route"]);
- $_GET=array_merge($_GET, $param);
+ $_GET = array_merge($_GET, $param);
unset($param);
require_once "$file";
} ;
diff --git a/lib/private/Route/Router.php b/lib/private/Route/Router.php
index de7c720f271..71bc4a6c4f7 100644
--- a/lib/private/Route/Router.php
+++ b/lib/private/Route/Router.php
@@ -13,7 +13,7 @@
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -33,6 +33,7 @@
namespace OC\Route;
+use OC\AppFramework\Routing\RouteParser;
use OCP\AppFramework\App;
use OCP\ILogger;
use OCP\Route\IRouter;
@@ -73,7 +74,7 @@ class Router implements IRouter {
$this->logger = $logger;
$baseUrl = \OC::$WEBROOT;
if (!(\OC::$server->getConfig()->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true')) {
- $baseUrl = \OC::$server->getURLGenerator()->linkTo('', 'index.php');
+ $baseUrl .= '/index.php';
}
if (!\OC::$CLI && isset($_SERVER['REQUEST_METHOD'])) {
$method = $_SERVER['REQUEST_METHOD'];
@@ -177,14 +178,6 @@ class Router implements IRouter {
}
/**
- * @return string
- * @deprecated
- */
- public function getCacheKey() {
- return '';
- }
-
- /**
* @param string $name
* @return \Symfony\Component\Routing\RouteCollection
*/
@@ -239,9 +232,9 @@ class Router implements IRouter {
*
* @param string $url The url to find
* @throws \Exception
- * @return void
+ * @return array
*/
- public function match($url) {
+ public function findMatchingRoute(string $url): array {
if (substr($url, 0, 6) === '/apps/') {
// empty string / 'apps' / $app / rest of the route
list(, , $app,) = explode('/', $url, 4);
@@ -287,10 +280,24 @@ class Router implements IRouter {
}
}
+ return $parameters;
+ }
+
+ /**
+ * Find and execute the route matching $url
+ *
+ * @param string $url The url to find
+ * @throws \Exception
+ * @return void
+ */
+ public function match($url) {
+ $parameters = $this->findMatchingRoute($url);
+
\OC::$server->getEventLogger()->start('run_route', 'Run route');
if (isset($parameters['caller'])) {
$caller = $parameters['caller'];
unset($parameters['caller']);
+ unset($parameters['action']);
$application = $this->getApplicationClass($caller[0]);
\OC\AppFramework\App::main($caller[1], $caller[2], $application->getContainer(), $parameters);
} elseif (isset($parameters['action'])) {
@@ -299,6 +306,7 @@ class Router implements IRouter {
throw new \Exception('not a callable action');
}
unset($parameters['action']);
+ unset($parameters['caller']);
call_user_func($action, $parameters);
} elseif (isset($parameters['file'])) {
include $parameters['file'];
@@ -333,13 +341,27 @@ class Router implements IRouter {
public function generate($name,
$parameters = [],
$absolute = false) {
+ $referenceType = UrlGenerator::ABSOLUTE_URL;
+ if ($absolute === false) {
+ $referenceType = UrlGenerator::ABSOLUTE_PATH;
+ }
+ $name = $this->fixLegacyRootName($name);
+ if (strpos($name, '.') !== false) {
+ list($appName, $other) = explode('.', $name, 3);
+ // OCS routes are prefixed with "ocs."
+ if ($appName === 'ocs') {
+ $appName = $other;
+ }
+ $this->loadRoutes($appName);
+ try {
+ return $this->getGenerator()->generate($name, $parameters, $referenceType);
+ } catch (RouteNotFoundException $e) {
+ }
+ }
+
+ // Fallback load all routes
$this->loadRoutes();
try {
- $referenceType = UrlGenerator::ABSOLUTE_URL;
- if ($absolute === false) {
- $referenceType = UrlGenerator::ABSOLUTE_PATH;
- }
- $name = $this->fixLegacyRootName($name);
return $this->getGenerator()->generate($name, $parameters, $referenceType);
} catch (RouteNotFoundException $e) {
$this->logger->logException($e, ['level' => ILogger::INFO]);
@@ -399,8 +421,14 @@ class Router implements IRouter {
*/
private function setupRoutes($routes, $appName) {
if (is_array($routes)) {
- $application = $this->getApplicationClass($appName);
- $application->registerRoutes($this, $routes);
+ $routeParser = new RouteParser();
+
+ $defaultRoutes = $routeParser->parseDefaultRoutes($routes, $appName);
+ $ocsRoutes = $routeParser->parseOCSRoutes($routes, $appName);
+
+ $this->root->addCollection($defaultRoutes);
+ $ocsRoutes->addPrefix('/ocsapp');
+ $this->root->addCollection($ocsRoutes);
}
}
diff --git a/lib/private/Search.php b/lib/private/Search.php
index ae22a6d9f19..9ecf34aef54 100644
--- a/lib/private/Search.php
+++ b/lib/private/Search.php
@@ -36,6 +36,7 @@ use OCP\Search\Provider;
* Provide an interface to all search providers
*/
class Search implements ISearch {
+ /** @var Provider[] */
private $providers = [];
private $registeredProviders = [];
@@ -51,7 +52,6 @@ class Search implements ISearch {
$this->initProviders();
$results = [];
foreach ($this->providers as $provider) {
- /** @var $provider Provider */
if (! $provider->providesResultsFor($inApps)) {
continue;
}
diff --git a/lib/private/Search/Provider/File.php b/lib/private/Search/Provider/File.php
index 9a41a46bd35..b4e35d374ca 100644
--- a/lib/private/Search/Provider/File.php
+++ b/lib/private/Search/Provider/File.php
@@ -6,6 +6,7 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Jakob Sack <mail@jakobsack.de>
+ * @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -39,10 +40,11 @@ class File extends \OCP\Search\Provider {
/**
* Search for files and folders matching the given query
* @param string $query
- * @return \OCP\Search\Result
+ * @return \OCP\Search\Result[]
* @deprecated 20.0.0
*/
public function search($query) {
+ \OC_Util::setupFS();
$files = Filesystem::search($query);
$results = [];
// edit results
diff --git a/lib/private/Search/Result/File.php b/lib/private/Search/Result/File.php
index f93b033c07f..33e1e97f471 100644
--- a/lib/private/Search/Result/File.php
+++ b/lib/private/Search/Result/File.php
@@ -4,6 +4,7 @@
*
* @author Andrew Brown <andrew@casabrown.com>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
@@ -28,6 +29,8 @@ namespace OC\Search\Result;
use OCP\Files\FileInfo;
use OCP\Files\Folder;
+use OCP\IPreview;
+use OCP\IUserSession;
/**
* A found file
@@ -79,6 +82,14 @@ class File extends \OCP\Search\Result {
public $permissions;
/**
+ * Has a preview
+ *
+ * @var string
+ * @deprecated 20.0.0
+ */
+ public $has_preview;
+
+ /**
* Create a new file search result
* @param FileInfo $data file data given by provider
* @deprecated 20.0.0
@@ -101,6 +112,7 @@ class File extends \OCP\Search\Result {
$this->size = $data->getSize();
$this->modified = $data->getMtime();
$this->mime_type = $data->getMimetype();
+ $this->has_preview = $this->hasPreview($data);
}
/**
@@ -118,9 +130,21 @@ class File extends \OCP\Search\Result {
*/
protected function getRelativePath($path) {
if (!isset(self::$userFolderCache)) {
- $user = \OC::$server->getUserSession()->getUser()->getUID();
- self::$userFolderCache = \OC::$server->getUserFolder($user);
+ $userSession = \OC::$server->get(IUserSession::class);
+ $userID = $userSession->getUser()->getUID();
+ self::$userFolderCache = \OC::$server->getUserFolder($userID);
}
return self::$userFolderCache->getRelativePath($path);
}
+
+ /**
+ * Is the preview available
+ * @param FileInfo $data
+ * @return bool
+ * @deprecated 20.0.0
+ */
+ protected function hasPreview($data) {
+ $previewManager = \OC::$server->get(IPreview::class);
+ return $previewManager->isAvailable($data);
+ }
}
diff --git a/lib/private/Search/SearchComposer.php b/lib/private/Search/SearchComposer.php
index 61bbbbc969b..5290c2ac3c1 100644
--- a/lib/private/Search/SearchComposer.php
+++ b/lib/private/Search/SearchComposer.php
@@ -5,7 +5,9 @@ declare(strict_types=1);
/**
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
*
- * @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
+ * @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -20,7 +22,8 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
namespace OC\Search;
@@ -106,20 +109,35 @@ class SearchComposer {
}
/**
- * Get a list of all provider IDs for the consecutive calls to `search`
+ * Get a list of all provider IDs & Names for the consecutive calls to `search`
+ * Sort the list by the order property
+ *
+ * @param string $route the route the user is currently at
+ * @param array $routeParameters the parameters of the route the user is currently at
*
- * @return string[]
+ * @return array
*/
- public function getProviders(): array {
+ public function getProviders(string $route, array $routeParameters): array {
$this->loadLazyProviders();
+ $providers = array_values(
+ array_map(function (IProvider $provider) use ($route, $routeParameters) {
+ return [
+ 'id' => $provider->getId(),
+ 'name' => $provider->getName(),
+ 'order' => $provider->getOrder($route, $routeParameters),
+ ];
+ }, $this->providers)
+ );
+
+ usort($providers, function ($provider1, $provider2) {
+ return $provider1['order'] <=> $provider2['order'];
+ });
+
/**
* Return an array with the IDs, but strip the associative keys
*/
- return array_values(
- array_map(function (IProvider $provider) {
- return $provider->getId();
- }, $this->providers));
+ return $providers;
}
/**
diff --git a/lib/private/Search/SearchQuery.php b/lib/private/Search/SearchQuery.php
index 2ed31fed441..728802b6e80 100644
--- a/lib/private/Search/SearchQuery.php
+++ b/lib/private/Search/SearchQuery.php
@@ -5,7 +5,9 @@ declare(strict_types=1);
/**
* @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
*
- * @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
+ * @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
@@ -20,7 +22,8 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
namespace OC\Search;
@@ -28,7 +31,7 @@ namespace OC\Search;
use OCP\Search\ISearchQuery;
class SearchQuery implements ISearchQuery {
- public const LIMIT_DEFAULT = 20;
+ public const LIMIT_DEFAULT = 5;
/** @var string */
private $term;
@@ -42,20 +45,32 @@ class SearchQuery implements ISearchQuery {
/** @var int|string|null */
private $cursor;
+ /** @var string */
+ private $route;
+
+ /** @var array */
+ private $routeParameters;
+
/**
* @param string $term
* @param int $sortOrder
* @param int $limit
* @param int|string|null $cursor
+ * @param string $route
+ * @param array $routeParameters
*/
public function __construct(string $term,
int $sortOrder = ISearchQuery::SORT_DATE_DESC,
int $limit = self::LIMIT_DEFAULT,
- $cursor = null) {
+ $cursor = null,
+ string $route = '',
+ array $routeParameters = []) {
$this->term = $term;
$this->sortOrder = $sortOrder;
$this->limit = $limit;
$this->cursor = $cursor;
+ $this->route = $route;
+ $this->routeParameters = $routeParameters;
}
/**
@@ -85,4 +100,18 @@ class SearchQuery implements ISearchQuery {
public function getCursor() {
return $this->cursor;
}
+
+ /**
+ * @inheritDoc
+ */
+ public function getRoute(): string {
+ return $this->route;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getRouteParameters(): array {
+ return $this->routeParameters;
+ }
}
diff --git a/lib/private/Security/Bruteforce/Capabilities.php b/lib/private/Security/Bruteforce/Capabilities.php
index eab55db1c90..7547348ce34 100644
--- a/lib/private/Security/Bruteforce/Capabilities.php
+++ b/lib/private/Security/Bruteforce/Capabilities.php
@@ -2,6 +2,7 @@
/**
* @copyright Copyright (c) 2017 Roeland Jago Douma <roeland@famdouma.nl>
*
+ * @author Julius Härtl <jus@bitgrid.net>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
@@ -46,6 +47,10 @@ class Capabilities implements IPublicCapability {
}
public function getCapabilities() {
+ if (version_compare(\OC::$server->getConfig()->getSystemValue('version', '0.0.0.0'), '12.0.0.0', '<')) {
+ return [];
+ }
+
return [
'bruteforce' => [
'delay' => $this->throttler->getDelay($this->request->getRemoteAddress())
diff --git a/lib/private/Security/Bruteforce/CleanupJob.php b/lib/private/Security/Bruteforce/CleanupJob.php
new file mode 100644
index 00000000000..edf59cdcdc5
--- /dev/null
+++ b/lib/private/Security/Bruteforce/CleanupJob.php
@@ -0,0 +1,56 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @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 OC\Security\Bruteforce;
+
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\BackgroundJob\TimedJob;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+
+class CleanupJob extends TimedJob {
+
+ /** @var IDBConnection */
+ private $connection;
+
+ public function __construct(ITimeFactory $time, IDBConnection $connection) {
+ parent::__construct($time);
+ $this->connection = $connection;
+
+ // Run once a day
+ $this->setInterval(3600 * 24);
+ }
+
+ protected function run($argument) {
+ // Delete all entries more than 48 hours old
+ $time = $this->time->getTime() - (48 * 3600);
+
+ $qb = $this->connection->getQueryBuilder();
+ $qb->delete('bruteforce_attempts')
+ ->where($qb->expr()->lt('occurred', $qb->createNamedParameter($time), IQueryBuilder::PARAM_INT));
+ $qb->execute();
+ }
+}
diff --git a/lib/private/Security/Bruteforce/Throttler.php b/lib/private/Security/Bruteforce/Throttler.php
index 63c6361b9ce..e1d9127a7bb 100644
--- a/lib/private/Security/Bruteforce/Throttler.php
+++ b/lib/private/Security/Bruteforce/Throttler.php
@@ -1,11 +1,15 @@
<?php
+
+declare(strict_types=1);
+
/**
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
*
* @author Bjoern Schiessle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
+ * @author Johannes Riedel <joeried@users.noreply.github.com>
* @author Lukas Reschke <lukas@statuscode.ch>
- * @author Mark Berezovsky <xpnf@yandex.ru>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -34,6 +38,7 @@ use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\ILogger;
+use OCP\Security\Bruteforce\MaxDelayReached;
/**
* Class Throttler implements the bruteforce protection for security actions in
@@ -50,6 +55,9 @@ use OCP\ILogger;
*/
class Throttler {
public const LOGIN_ACTION = 'login';
+ public const MAX_DELAY = 25;
+ public const MAX_DELAY_MS = 25000; // in milliseconds
+ public const MAX_ATTEMPTS = 10;
/** @var IDBConnection */
private $db;
@@ -82,7 +90,7 @@ class Throttler {
* @param int $expire
* @return \DateInterval
*/
- private function getCutoff($expire) {
+ private function getCutoff(int $expire): \DateInterval {
$d1 = new \DateTime();
$d2 = clone $d1;
$d2->sub(new \DateInterval('PT' . $expire . 'S'));
@@ -92,11 +100,12 @@ class Throttler {
/**
* Calculate the cut off timestamp
*
+ * @param float $maxAgeHours
* @return int
*/
- private function getCutoffTimestamp(): int {
+ private function getCutoffTimestamp(float $maxAgeHours = 12.0): int {
return (new \DateTime())
- ->sub($this->getCutoff(43200))
+ ->sub($this->getCutoff((int) ($maxAgeHours * 3600)))
->getTimestamp();
}
@@ -106,11 +115,10 @@ class Throttler {
* @param string $action
* @param string $ip
* @param array $metadata Optional metadata logged to the database
- * @suppress SqlInjectionChecker
*/
- public function registerAttempt($action,
- $ip,
- array $metadata = []) {
+ public function registerAttempt(string $action,
+ string $ip,
+ array $metadata = []): void {
// No need to log if the bruteforce protection is disabled
if ($this->config->getSystemValue('auth.bruteforce.protection.enabled', true) === false) {
return;
@@ -150,15 +158,14 @@ class Throttler {
* @param string $ip
* @return bool
*/
- private function isIPWhitelisted($ip) {
+ private function isIPWhitelisted(string $ip): bool {
if ($this->config->getSystemValue('auth.bruteforce.protection.enabled', true) === false) {
return true;
}
$keys = $this->config->getAppKeys('bruteForce');
$keys = array_filter($keys, function ($key) {
- $regex = '/^whitelist_/S';
- return preg_match($regex, $key) === 1;
+ return 0 === strpos($key, 'whitelist_');
});
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
@@ -188,8 +195,8 @@ class Throttler {
$valid = true;
for ($i = 0; $i < $mask; $i++) {
- $part = ord($addr[(int)($i/8)]);
- $orig = ord($ip[(int)($i/8)]);
+ $part = ord($addr[(int)($i / 8)]);
+ $orig = ord($ip[(int)($i / 8)]);
$bitmask = 1 << (7 - ($i % 8));
@@ -215,18 +222,28 @@ class Throttler {
*
* @param string $ip
* @param string $action optionally filter by action
+ * @param float $maxAgeHours
* @return int
*/
- public function getDelay($ip, $action = '') {
+ public function getAttempts(string $ip, string $action = '', float $maxAgeHours = 12): int {
+ if ($maxAgeHours > 48) {
+ $this->logger->error('Bruteforce has to use less than 48 hours');
+ $maxAgeHours = 48;
+ }
+
+ if ($ip === '') {
+ return 0;
+ }
+
$ipAddress = new IpAddress($ip);
if ($this->isIPWhitelisted((string)$ipAddress)) {
return 0;
}
- $cutoffTime = $this->getCutoffTimestamp();
+ $cutoffTime = $this->getCutoffTimestamp($maxAgeHours);
$qb = $this->db->getQueryBuilder();
- $qb->select('*')
+ $qb->select($qb->func()->count('*', 'attempts'))
->from('bruteforce_attempts')
->where($qb->expr()->gt('occurred', $qb->createNamedParameter($cutoffTime)))
->andWhere($qb->expr()->eq('subnet', $qb->createNamedParameter($ipAddress->getSubnet())));
@@ -235,24 +252,37 @@ class Throttler {
$qb->andWhere($qb->expr()->eq('action', $qb->createNamedParameter($action)));
}
- $attempts = count($qb->execute()->fetchAll());
+ $result = $qb->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+ return (int) $row['attempts'];
+ }
+
+ /**
+ * Get the throttling delay (in milliseconds)
+ *
+ * @param string $ip
+ * @param string $action optionally filter by action
+ * @return int
+ */
+ public function getDelay(string $ip, string $action = ''): int {
+ $attempts = $this->getAttempts($ip, $action);
if ($attempts === 0) {
return 0;
}
- $maxDelay = 25;
$firstDelay = 0.1;
- if ($attempts > (8 * PHP_INT_SIZE - 1)) {
+ if ($attempts > self::MAX_ATTEMPTS) {
// Don't ever overflow. Just assume the maxDelay time:s
- $firstDelay = $maxDelay;
- } else {
- $firstDelay *= pow(2, $attempts);
- if ($firstDelay > $maxDelay) {
- $firstDelay = $maxDelay;
- }
+ return self::MAX_DELAY_MS;
+ }
+
+ $delay = $firstDelay * 2 ** $attempts;
+ if ($delay > self::MAX_DELAY) {
+ return self::MAX_DELAY_MS;
}
- return (int) \ceil($firstDelay * 1000);
+ return (int) \ceil($delay * 1000);
}
/**
@@ -260,9 +290,9 @@ class Throttler {
*
* @param string $ip
* @param string $action
- * @param string $metadata
+ * @param array $metadata
*/
- public function resetDelay($ip, $action, $metadata) {
+ public function resetDelay(string $ip, string $action, array $metadata): void {
$ipAddress = new IpAddress($ip);
if ($this->isIPWhitelisted((string)$ipAddress)) {
return;
@@ -303,8 +333,27 @@ class Throttler {
* @param string $action optionally filter by action
* @return int the time spent sleeping
*/
- public function sleepDelay($ip, $action = '') {
+ public function sleepDelay(string $ip, string $action = ''): int {
+ $delay = $this->getDelay($ip, $action);
+ usleep($delay * 1000);
+ return $delay;
+ }
+
+ /**
+ * Will sleep for the defined amount of time unless maximum was reached in the last 30 minutes
+ * In this case a "429 Too Many Request" exception is thrown
+ *
+ * @param string $ip
+ * @param string $action optionally filter by action
+ * @return int the time spent sleeping
+ * @throws MaxDelayReached when reached the maximum
+ */
+ public function sleepDelayOrThrowOnMax(string $ip, string $action = ''): int {
$delay = $this->getDelay($ip, $action);
+ if (($delay === self::MAX_DELAY_MS) && $this->getAttempts($ip, $action, 0.5) > self::MAX_ATTEMPTS) {
+ // If the ip made too many attempts within the last 30 mins we don't execute anymore
+ throw new MaxDelayReached('Reached maximum delay');
+ }
usleep($delay * 1000);
return $delay;
}
diff --git a/lib/private/Security/CSP/ContentSecurityPolicyManager.php b/lib/private/Security/CSP/ContentSecurityPolicyManager.php
index e0403e77936..60a176cbd8b 100644
--- a/lib/private/Security/CSP/ContentSecurityPolicyManager.php
+++ b/lib/private/Security/CSP/ContentSecurityPolicyManager.php
@@ -7,6 +7,7 @@ declare(strict_types=1);
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Lukas Reschke <lukas@statuscode.ch>
+ * @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license AGPL-3.0
@@ -57,7 +58,7 @@ class ContentSecurityPolicyManager implements IContentSecurityPolicyManager {
*/
public function getDefaultPolicy(): ContentSecurityPolicy {
$event = new AddContentSecurityPolicyEvent($this);
- $this->dispatcher->dispatch(AddContentSecurityPolicyEvent::class, $event);
+ $this->dispatcher->dispatchTyped($event);
$defaultPolicy = new \OC\Security\CSP\ContentSecurityPolicy();
foreach ($this->policies as $policy) {
diff --git a/lib/private/Security/CertificateManager.php b/lib/private/Security/CertificateManager.php
index e69132ff4df..ef0c6563320 100644
--- a/lib/private/Security/CertificateManager.php
+++ b/lib/private/Security/CertificateManager.php
@@ -40,11 +40,6 @@ use OCP\Security\ISecureRandom;
*/
class CertificateManager implements ICertificateManager {
/**
- * @var string
- */
- protected $uid;
-
- /**
* @var \OC\Files\View
*/
protected $view;
@@ -63,18 +58,15 @@ class CertificateManager implements ICertificateManager {
protected $random;
/**
- * @param string $uid
* @param \OC\Files\View $view relative to data/
* @param IConfig $config
* @param ILogger $logger
* @param ISecureRandom $random
*/
- public function __construct($uid,
- \OC\Files\View $view,
+ public function __construct(\OC\Files\View $view,
IConfig $config,
ILogger $logger,
ISecureRandom $random) {
- $this->uid = $uid;
$this->view = $view;
$this->config = $config;
$this->logger = $logger;
@@ -112,6 +104,29 @@ class CertificateManager implements ICertificateManager {
return $result;
}
+ private function hasCertificates(): bool {
+ if (!$this->config->getSystemValue('installed', false)) {
+ return false;
+ }
+
+ $path = $this->getPathToCertificates() . 'uploads/';
+ if (!$this->view->is_dir($path)) {
+ return false;
+ }
+ $result = [];
+ $handle = $this->view->opendir($path);
+ if (!is_resource($handle)) {
+ return false;
+ }
+ while (false !== ($file = readdir($handle))) {
+ if ($file !== '.' && $file !== '..') {
+ return true;
+ }
+ }
+ closedir($handle);
+ return false;
+ }
+
/**
* create the certificate bundle of all trusted certificated
*/
@@ -148,7 +163,7 @@ class CertificateManager implements ICertificateManager {
fwrite($fhCerts, $defaultCertificates);
// Append the system certificate bundle
- $systemBundle = $this->getCertificateBundle(null);
+ $systemBundle = $this->getCertificateBundle();
if ($systemBundle !== $certPath && $this->view->file_exists($systemBundle)) {
$systemCertificates = $this->view->file_get_contents($systemBundle);
fwrite($fhCerts, $systemCertificates);
@@ -207,73 +222,50 @@ class CertificateManager implements ICertificateManager {
}
/**
- * Get the path to the certificate bundle for this user
+ * Get the path to the certificate bundle
*
- * @param string|null $uid (optional) user to get the certificate bundle for, use `null` to get the system bundle
* @return string
*/
- public function getCertificateBundle($uid = '') {
- if ($uid === '') {
- $uid = $this->uid;
- }
- return $this->getPathToCertificates($uid) . 'rootcerts.crt';
+ public function getCertificateBundle() {
+ return $this->getPathToCertificates() . 'rootcerts.crt';
}
/**
- * Get the full local path to the certificate bundle for this user
+ * Get the full local path to the certificate bundle
*
- * @param string $uid (optional) user to get the certificate bundle for, use `null` to get the system bundle
* @return string
*/
- public function getAbsoluteBundlePath($uid = '') {
- if ($uid === '') {
- $uid = $this->uid;
+ public function getAbsoluteBundlePath() {
+ if (!$this->hasCertificates()) {
+ return \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
}
- if ($this->needsRebundling($uid)) {
- if (is_null($uid)) {
- $manager = new CertificateManager(null, $this->view, $this->config, $this->logger, $this->random);
- $manager->createCertificateBundle();
- } else {
- $this->createCertificateBundle();
- }
+
+ if ($this->needsRebundling()) {
+ $this->createCertificateBundle();
}
- return $this->view->getLocalFile($this->getCertificateBundle($uid));
+
+ return $this->view->getLocalFile($this->getCertificateBundle());
}
/**
- * @param string|null $uid (optional) user to get the certificate path for, use `null` to get the system path
* @return string
*/
- private function getPathToCertificates($uid = '') {
- if ($uid === '') {
- $uid = $this->uid;
- }
- return is_null($uid) ? '/files_external/' : '/' . $uid . '/files_external/';
+ private function getPathToCertificates() {
+ return '/files_external/';
}
/**
* Check if we need to re-bundle the certificates because one of the sources has updated
*
- * @param string $uid (optional) user to get the certificate path for, use `null` to get the system path
* @return bool
*/
- private function needsRebundling($uid = '') {
- if ($uid === '') {
- $uid = $this->uid;
- }
- $sourceMTimes = [$this->getFilemtimeOfCaBundle()];
- $targetBundle = $this->getCertificateBundle($uid);
+ private function needsRebundling() {
+ $targetBundle = $this->getCertificateBundle();
if (!$this->view->file_exists($targetBundle)) {
return true;
}
- if (!is_null($uid)) { // also depend on the system bundle
- $sourceMTimes[] = $this->view->filemtime($this->getCertificateBundle(null));
- }
-
- $sourceMTime = array_reduce($sourceMTimes, function ($max, $mtime) {
- return max($max, $mtime);
- }, 0);
+ $sourceMTime = $this->getFilemtimeOfCaBundle();
return $sourceMTime > $this->view->filemtime($targetBundle);
}
diff --git a/lib/private/Security/CredentialsManager.php b/lib/private/Security/CredentialsManager.php
index ace8e6889ec..7ba8a0020ff 100644
--- a/lib/private/Security/CredentialsManager.php
+++ b/lib/private/Security/CredentialsManager.php
@@ -3,7 +3,7 @@
* @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 Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
@@ -35,7 +35,7 @@ use OCP\Security\ICrypto;
* @package OC\Security
*/
class CredentialsManager implements ICredentialsManager {
- public const DB_TABLE = 'credentials';
+ public const DB_TABLE = 'storages_credentials';
/** @var ICrypto */
protected $crypto;
@@ -81,10 +81,17 @@ class CredentialsManager implements ICredentialsManager {
$qb = $this->dbConnection->getQueryBuilder();
$qb->select('credentials')
->from(self::DB_TABLE)
- ->where($qb->expr()->eq('user', $qb->createNamedParameter((string)$userId)))
- ->andWhere($qb->expr()->eq('identifier', $qb->createNamedParameter($identifier)))
- ;
- $result = $qb->execute()->fetch();
+ ->where($qb->expr()->eq('identifier', $qb->createNamedParameter($identifier)));
+
+ if ($userId === '') {
+ $qb->andWhere($qb->expr()->emptyString('user'));
+ } else {
+ $qb->andWhere($qb->expr()->eq('user', $qb->createNamedParameter((string)$userId)));
+ }
+
+ $qResult = $qb->execute();
+ $result = $qResult->fetch();
+ $qResult->closeCursor();
if (!$result) {
return null;
@@ -104,9 +111,14 @@ class CredentialsManager implements ICredentialsManager {
public function delete($userId, $identifier) {
$qb = $this->dbConnection->getQueryBuilder();
$qb->delete(self::DB_TABLE)
- ->where($qb->expr()->eq('user', $qb->createNamedParameter((string)$userId)))
- ->andWhere($qb->expr()->eq('identifier', $qb->createNamedParameter($identifier)))
- ;
+ ->where($qb->expr()->eq('identifier', $qb->createNamedParameter($identifier)));
+
+ if ($userId === '') {
+ $qb->andWhere($qb->expr()->emptyString('user'));
+ } else {
+ $qb->andWhere($qb->expr()->eq('user', $qb->createNamedParameter((string)$userId)));
+ }
+
return $qb->execute();
}
diff --git a/lib/private/Security/Crypto.php b/lib/private/Security/Crypto.php
index 154448281b9..7b1e1a49b19 100644
--- a/lib/private/Security/Crypto.php
+++ b/lib/private/Security/Crypto.php
@@ -8,6 +8,7 @@ declare(strict_types=1);
* @author Andreas Fischer <bantu@owncloud.com>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Lukas Reschke <lukas@statuscode.ch>
+ * @author lynn-stephenson <lynn.stephenson@protonmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
@@ -90,16 +91,17 @@ class Crypto implements ICrypto {
if ($password === '') {
$password = $this->config->getSystemValue('secret');
}
- $this->cipher->setPassword($password);
+ $keyMaterial = hash_hkdf('sha512', $password);
+ $this->cipher->setPassword(substr($keyMaterial, 0, 32));
$iv = \random_bytes($this->ivLength);
$this->cipher->setIV($iv);
$ciphertext = bin2hex($this->cipher->encrypt($plaintext));
$iv = bin2hex($iv);
- $hmac = bin2hex($this->calculateHMAC($ciphertext.$iv, $password));
+ $hmac = bin2hex($this->calculateHMAC($ciphertext.$iv, substr($keyMaterial, 32)));
- return $ciphertext.'|'.$iv.'|'.$hmac.'|2';
+ return $ciphertext.'|'.$iv.'|'.$hmac.'|3';
}
/**
@@ -114,7 +116,7 @@ class Crypto implements ICrypto {
if ($password === '') {
$password = $this->config->getSystemValue('secret');
}
- $this->cipher->setPassword($password);
+ $hmacKey = $encryptionKey = $password;
$parts = explode('|', $authenticatedCiphertext);
$partCount = \count($parts);
@@ -128,14 +130,20 @@ class Crypto implements ICrypto {
if ($partCount === 4) {
$version = $parts[3];
- if ($version === '2') {
+ if ($version >= '2') {
$iv = hex2bin($iv);
}
- }
+ if ($version === '3') {
+ $keyMaterial = hash_hkdf('sha512', $password);
+ $encryptionKey = substr($keyMaterial, 0, 32);
+ $hmacKey = substr($keyMaterial, 32);
+ }
+ }
+ $this->cipher->setPassword($encryptionKey);
$this->cipher->setIV($iv);
- if (!hash_equals($this->calculateHMAC($parts[0] . $parts[1], $password), $hmac)) {
+ if (!hash_equals($this->calculateHMAC($parts[0] . $parts[1], $hmacKey), $hmac)) {
throw new \Exception('HMAC does not match.');
}
diff --git a/lib/private/Security/FeaturePolicy/FeaturePolicyManager.php b/lib/private/Security/FeaturePolicy/FeaturePolicyManager.php
index 6143a5b95fc..b2959c310c8 100644
--- a/lib/private/Security/FeaturePolicy/FeaturePolicyManager.php
+++ b/lib/private/Security/FeaturePolicy/FeaturePolicyManager.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
/**
* @copyright Copyright (c) 2019, 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
@@ -47,7 +48,7 @@ class FeaturePolicyManager {
public function getDefaultPolicy(): FeaturePolicy {
$event = new AddFeaturePolicyEvent($this);
- $this->dispatcher->dispatch(AddFeaturePolicyEvent::class, $event);
+ $this->dispatcher->dispatchTyped($event);
$defaultPolicy = new FeaturePolicy();
foreach ($this->policies as $policy) {
diff --git a/lib/private/Security/Hasher.php b/lib/private/Security/Hasher.php
index a51508ba8e9..4b068ce0110 100644
--- a/lib/private/Security/Hasher.php
+++ b/lib/private/Security/Hasher.php
@@ -8,6 +8,7 @@ declare(strict_types=1);
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Lukas Reschke <lukas@statuscode.ch>
+ * @author MichaIng <micha@dietpi.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
diff --git a/lib/private/Security/Normalizer/IpAddress.php b/lib/private/Security/Normalizer/IpAddress.php
index b471c499440..a679936e20c 100644
--- a/lib/private/Security/Normalizer/IpAddress.php
+++ b/lib/private/Security/Normalizer/IpAddress.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
/**
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch>
*
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Konrad Bucheli <kb@open.ch>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -78,7 +79,7 @@ class IpAddress {
}
$pos = strpos($ip, '%'); // if there is an explicit interface added to the IP, e.g. fe80::ae2d:d1e7:fe1e:9a8d%enp2s0
if ($pos !== false) {
- $ip = substr($ip, 0, $pos-1);
+ $ip = substr($ip, 0, $pos - 1);
}
$binary = \inet_pton($ip);
for ($i = 128; $i > $maskBits; $i -= 8) {
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 09bb7336785..687eba68e73 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -20,6 +20,7 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Julius Haertl <jus@bitgrid.net>
* @author Julius Härtl <jus@bitgrid.net>
+ * @author Lionel Elie Mamane <lionel@mamane.lu>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Maxence Lange <maxence@artificial-owl.com>
* @author Michael Weimann <mail@michael-weimann.eu>
@@ -29,12 +30,10 @@
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author root <root@localhost.localdomain>
- * @author Sander <brantje@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Tobia De Koninck <tobia@ledfan.be>
- * @author Vincent Petry <pvince81@owncloud.com>
- * @author Xheni Myrtaj <myrtajxheni@gmail.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -61,10 +60,10 @@ use OC\App\AppStore\Bundles\BundleFetcher;
use OC\App\AppStore\Fetcher\AppFetcher;
use OC\App\AppStore\Fetcher\CategoryFetcher;
use OC\AppFramework\Http\Request;
-use OC\AppFramework\Utility\SimpleContainer;
use OC\AppFramework\Utility\TimeFactory;
use OC\Authentication\Events\LoginFailed;
use OC\Authentication\Listeners\LoginFailedListener;
+use OC\Authentication\Listeners\UserLoggedInListener;
use OC\Authentication\LoginCredentials\Store;
use OC\Authentication\Token\IProvider;
use OC\Avatar\AvatarManager;
@@ -80,6 +79,7 @@ use OC\Contacts\ContactsMenu\ContactsStore;
use OC\Dashboard\DashboardManager;
use OC\Diagnostics\EventLogger;
use OC\Diagnostics\QueryLogger;
+use OC\EventDispatcher\SymfonyAdapter;
use OC\Federation\CloudFederationFactory;
use OC\Federation\CloudFederationProviderManager;
use OC\Federation\CloudIdManager;
@@ -88,10 +88,12 @@ use OC\Files\Config\UserMountCacheListener;
use OC\Files\Mount\CacheMountProvider;
use OC\Files\Mount\LocalHomeMountProvider;
use OC\Files\Mount\ObjectHomeMountProvider;
+use OC\Files\Mount\ObjectStorePreviewCacheMountProvider;
use OC\Files\Node\HookConnector;
use OC\Files\Node\LazyRoot;
use OC\Files\Node\Root;
use OC\Files\Storage\StorageFactory;
+use OC\Files\Type\Loader;
use OC\Files\View;
use OC\FullTextSearch\FullTextSearchManager;
use OC\Http\Client\ClientService;
@@ -114,13 +116,13 @@ use OC\Preview\GeneratorHelper;
use OC\Remote\Api\ApiFactory;
use OC\Remote\InstanceFactory;
use OC\RichObjectStrings\Validator;
+use OC\Route\Router;
use OC\Security\Bruteforce\Throttler;
use OC\Security\CertificateManager;
use OC\Security\CredentialsManager;
use OC\Security\Crypto;
use OC\Security\CSP\ContentSecurityPolicyManager;
use OC\Security\CSP\ContentSecurityPolicyNonceManager;
-use OC\Security\CSRF\CsrfTokenGenerator;
use OC\Security\CSRF\CsrfTokenManager;
use OC\Security\CSRF\TokenStorage\SessionStorage;
use OC\Security\Hasher;
@@ -131,9 +133,7 @@ use OC\Share20\ProviderFactory;
use OC\Share20\ShareHelper;
use OC\SystemTag\ManagerFactory as SystemTagManagerFactory;
use OC\Tagging\TagMapper;
-use OC\Template\IconsCacher;
use OC\Template\JSCombiner;
-use OC\Template\SCSSCacher;
use OCA\Theming\ImageManager;
use OCA\Theming\ThemingDefaults;
use OCA\Theming\Util;
@@ -150,6 +150,8 @@ use OCP\Dashboard\IDashboardManager;
use OCP\Defaults;
use OCP\Diagnostics\IEventLogger;
use OCP\Diagnostics\IQueryLogger;
+use OCP\Encryption\IFile;
+use OCP\Encryption\Keys\IStorage;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Federation\ICloudFederationFactory;
use OCP\Federation\ICloudFederationProviderManager;
@@ -178,6 +180,7 @@ use OCP\IAppConfig;
use OCP\IAvatarManager;
use OCP\ICache;
use OCP\ICacheFactory;
+use OCP\ICertificateManager;
use OCP\IDateTimeFormatter;
use OCP\IDateTimeZone;
use OCP\IDBConnection;
@@ -190,6 +193,7 @@ use OCP\IPreview;
use OCP\IRequest;
use OCP\ISearch;
use OCP\IServerContainer;
+use OCP\ISession;
use OCP\ITagManager;
use OCP\ITempManager;
use OCP\IURLGenerator;
@@ -219,8 +223,8 @@ use OCP\User\Events\BeforeUserLoggedInEvent;
use OCP\User\Events\BeforeUserLoggedInWithCookieEvent;
use OCP\User\Events\BeforeUserLoggedOutEvent;
use OCP\User\Events\PasswordUpdatedEvent;
+use OCP\User\Events\PostLoginEvent;
use OCP\User\Events\UserChangedEvent;
-use OCP\User\Events\UserCreatedEvent;
use OCP\User\Events\UserDeletedEvent;
use OCP\User\Events\UserLoggedInEvent;
use OCP\User\Events\UserLoggedInWithCookieEvent;
@@ -257,6 +261,7 @@ class Server extends ServerContainer implements IServerContainer {
// To find out if we are running from CLI or not
$this->registerParameter('isCLI', \OC::$CLI);
+ $this->registerParameter('serverRoot', \OC::$SERVERROOT);
$this->registerService(ContainerInterface::class, function (ContainerInterface $c) {
return $c;
@@ -266,37 +271,51 @@ class Server extends ServerContainer implements IServerContainer {
});
$this->registerAlias(\OCP\Calendar\IManager::class, \OC\Calendar\Manager::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('CalendarManager', \OC\Calendar\Manager::class);
$this->registerAlias(\OCP\Calendar\Resource\IManager::class, \OC\Calendar\Resource\Manager::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('CalendarResourceBackendManager', \OC\Calendar\Resource\Manager::class);
$this->registerAlias(\OCP\Calendar\Room\IManager::class, \OC\Calendar\Room\Manager::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('CalendarRoomBackendManager', \OC\Calendar\Room\Manager::class);
$this->registerAlias(\OCP\Contacts\IManager::class, \OC\ContactsManager::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('ContactsManager', \OCP\Contacts\IManager::class);
$this->registerAlias(\OCP\DirectEditing\IManager::class, \OC\DirectEditing\Manager::class);
$this->registerAlias(IActionFactory::class, ActionFactory::class);
+ $this->registerService(View::class, function (Server $c) {
+ return new View();
+ }, false);
- $this->registerService(IPreview::class, function (Server $c) {
+ $this->registerService(IPreview::class, function (ContainerInterface $c) {
return new PreviewManager(
- $c->getConfig(),
- $c->getRootFolder(),
- new \OC\Preview\Storage\Root($c->getRootFolder(), $c->getSystemConfig(), 'preview'),
- $c->getEventDispatcher(),
- $c->getGeneratorHelper(),
- $c->getSession()->get('user_id')
+ $c->get(\OCP\IConfig::class),
+ $c->get(IRootFolder::class),
+ new \OC\Preview\Storage\Root(
+ $c->get(IRootFolder::class),
+ $c->get(SystemConfig::class)
+ ),
+ $c->get(SymfonyAdapter::class),
+ $c->get(GeneratorHelper::class),
+ $c->get(ISession::class)->get('user_id')
);
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('PreviewManager', IPreview::class);
- $this->registerService(\OC\Preview\Watcher::class, function (Server $c) {
+ $this->registerService(\OC\Preview\Watcher::class, function (ContainerInterface $c) {
return new \OC\Preview\Watcher(
- new \OC\Preview\Storage\Root($c->getRootFolder(), $c->getSystemConfig(), 'preview')
+ new \OC\Preview\Storage\Root(
+ $c->get(IRootFolder::class),
+ $c->get(SystemConfig::class)
+ )
);
});
@@ -304,371 +323,351 @@ class Server extends ServerContainer implements IServerContainer {
$view = new View();
$util = new Encryption\Util(
$view,
- $c->getUserManager(),
- $c->getGroupManager(),
- $c->getConfig()
+ $c->get(IUserManager::class),
+ $c->get(IGroupManager::class),
+ $c->get(\OCP\IConfig::class)
);
return new Encryption\Manager(
- $c->getConfig(),
- $c->getLogger(),
+ $c->get(\OCP\IConfig::class),
+ $c->get(ILogger::class),
$c->getL10N('core'),
new View(),
$util,
new ArrayCache()
);
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('EncryptionManager', \OCP\Encryption\IManager::class);
- $this->registerService('EncryptionFileHelper', function (Server $c) {
+ /** @deprecated 21.0.0 */
+ $this->registerDeprecatedAlias('EncryptionFileHelper', IFile::class);
+ $this->registerService(IFile::class, function (ContainerInterface $c) {
$util = new Encryption\Util(
new View(),
- $c->getUserManager(),
- $c->getGroupManager(),
- $c->getConfig()
+ $c->get(IUserManager::class),
+ $c->get(IGroupManager::class),
+ $c->get(\OCP\IConfig::class)
);
return new Encryption\File(
$util,
- $c->getRootFolder(),
- $c->getShareManager()
+ $c->get(IRootFolder::class),
+ $c->get(\OCP\Share\IManager::class)
);
});
- $this->registerService('EncryptionKeyStorage', function (Server $c) {
+ /** @deprecated 21.0.0 */
+ $this->registerDeprecatedAlias('EncryptionKeyStorage', IStorage::class);
+ $this->registerService(IStorage::class, function (ContainerInterface $c) {
$view = new View();
$util = new Encryption\Util(
$view,
- $c->getUserManager(),
- $c->getGroupManager(),
- $c->getConfig()
+ $c->get(IUserManager::class),
+ $c->get(IGroupManager::class),
+ $c->get(\OCP\IConfig::class)
);
- return new Encryption\Keys\Storage($view, $util);
- });
- $this->registerService('TagMapper', function (Server $c) {
- return new TagMapper($c->getDatabaseConnection());
+ return new Encryption\Keys\Storage(
+ $view,
+ $util,
+ $c->get(ICrypto::class),
+ $c->get(\OCP\IConfig::class)
+ );
});
+ /** @deprecated 20.0.0 */
+ $this->registerDeprecatedAlias('TagMapper', TagMapper::class);
- $this->registerService(\OCP\ITagManager::class, function (Server $c) {
- $tagMapper = $c->query('TagMapper');
- return new TagManager($tagMapper, $c->getUserSession());
- });
+ $this->registerAlias(\OCP\ITagManager::class, TagManager::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('TagManager', \OCP\ITagManager::class);
- $this->registerService('SystemTagManagerFactory', function (Server $c) {
- $config = $c->getConfig();
+ $this->registerService('SystemTagManagerFactory', function (ContainerInterface $c) {
+ /** @var \OCP\IConfig $config */
+ $config = $c->get(\OCP\IConfig::class);
$factoryClass = $config->getSystemValue('systemtags.managerFactory', SystemTagManagerFactory::class);
return new $factoryClass($this);
});
- $this->registerService(ISystemTagManager::class, function (Server $c) {
- return $c->query('SystemTagManagerFactory')->getManager();
+ $this->registerService(ISystemTagManager::class, function (ContainerInterface $c) {
+ return $c->get('SystemTagManagerFactory')->getManager();
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('SystemTagManager', ISystemTagManager::class);
- $this->registerService(ISystemTagObjectMapper::class, function (Server $c) {
- return $c->query('SystemTagManagerFactory')->getObjectMapper();
+ $this->registerService(ISystemTagObjectMapper::class, function (ContainerInterface $c) {
+ return $c->get('SystemTagManagerFactory')->getObjectMapper();
});
- $this->registerService('RootFolder', function (Server $c) {
+ $this->registerService('RootFolder', function (ContainerInterface $c) {
$manager = \OC\Files\Filesystem::getMountManager(null);
$view = new View();
$root = new Root(
$manager,
$view,
null,
- $c->getUserMountCache(),
- $this->getLogger(),
- $this->getUserManager()
+ $c->get(IUserMountCache::class),
+ $this->get(ILogger::class),
+ $this->get(IUserManager::class)
);
- $previewConnector = new \OC\Preview\WatcherConnector($root, $c->getSystemConfig());
+ $previewConnector = new \OC\Preview\WatcherConnector(
+ $root,
+ $c->get(SystemConfig::class)
+ );
$previewConnector->connectWatcher();
return $root;
});
- $this->registerService(HookConnector::class, function (Server $c) {
+ $this->registerService(HookConnector::class, function (ContainerInterface $c) {
return new HookConnector(
- $c->query(IRootFolder::class),
+ $c->get(IRootFolder::class),
new View(),
- $c->query(\OC\EventDispatcher\SymfonyAdapter::class),
- $c->query(IEventDispatcher::class)
+ $c->get(\OC\EventDispatcher\SymfonyAdapter::class),
+ $c->get(IEventDispatcher::class)
);
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('SystemTagObjectMapper', ISystemTagObjectMapper::class);
- $this->registerService(IRootFolder::class, function (Server $c) {
+ $this->registerService(IRootFolder::class, function (ContainerInterface $c) {
return new LazyRoot(function () use ($c) {
- return $c->query('RootFolder');
+ return $c->get('RootFolder');
});
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('LazyRootFolder', IRootFolder::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('UserManager', \OC\User\Manager::class);
$this->registerAlias(\OCP\IUserManager::class, \OC\User\Manager::class);
- $this->registerService(\OCP\IGroupManager::class, function (Server $c) {
- $groupManager = new \OC\Group\Manager($this->getUserManager(), $c->getEventDispatcher(), $this->getLogger());
+ $this->registerService(\OCP\IGroupManager::class, function (ContainerInterface $c) {
+ $groupManager = new \OC\Group\Manager($this->get(IUserManager::class), $c->get(SymfonyAdapter::class), $this->get(ILogger::class));
$groupManager->listen('\OC\Group', 'preCreate', function ($gid) {
- \OC_Hook::emit('OC_Group', 'pre_createGroup', ['run' => true, 'gid' => $gid]);
-
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new BeforeGroupCreatedEvent($gid));
});
$groupManager->listen('\OC\Group', 'postCreate', function (\OC\Group\Group $group) {
- \OC_Hook::emit('OC_User', 'post_createGroup', ['gid' => $group->getGID()]);
-
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new GroupCreatedEvent($group));
});
$groupManager->listen('\OC\Group', 'preDelete', function (\OC\Group\Group $group) {
- \OC_Hook::emit('OC_Group', 'pre_deleteGroup', ['run' => true, 'gid' => $group->getGID()]);
-
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new BeforeGroupDeletedEvent($group));
});
$groupManager->listen('\OC\Group', 'postDelete', function (\OC\Group\Group $group) {
- \OC_Hook::emit('OC_User', 'post_deleteGroup', ['gid' => $group->getGID()]);
-
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new GroupDeletedEvent($group));
});
$groupManager->listen('\OC\Group', 'preAddUser', function (\OC\Group\Group $group, \OC\User\User $user) {
- \OC_Hook::emit('OC_Group', 'pre_addToGroup', ['run' => true, 'uid' => $user->getUID(), 'gid' => $group->getGID()]);
-
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new BeforeUserAddedEvent($group, $user));
});
$groupManager->listen('\OC\Group', 'postAddUser', function (\OC\Group\Group $group, \OC\User\User $user) {
- \OC_Hook::emit('OC_Group', 'post_addToGroup', ['uid' => $user->getUID(), 'gid' => $group->getGID()]);
- //Minimal fix to keep it backward compatible TODO: clean up all the GroupManager hooks
- \OC_Hook::emit('OC_User', 'post_addToGroup', ['uid' => $user->getUID(), 'gid' => $group->getGID()]);
-
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new UserAddedEvent($group, $user));
});
$groupManager->listen('\OC\Group', 'preRemoveUser', function (\OC\Group\Group $group, \OC\User\User $user) {
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new BeforeUserRemovedEvent($group, $user));
});
$groupManager->listen('\OC\Group', 'postRemoveUser', function (\OC\Group\Group $group, \OC\User\User $user) {
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new UserRemovedEvent($group, $user));
});
return $groupManager;
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('GroupManager', \OCP\IGroupManager::class);
- $this->registerService(Store::class, function (Server $c) {
- $session = $c->getSession();
- if (\OC::$server->getSystemConfig()->getValue('installed', false)) {
- $tokenProvider = $c->query(IProvider::class);
+ $this->registerService(Store::class, function (ContainerInterface $c) {
+ $session = $c->get(ISession::class);
+ if (\OC::$server->get(SystemConfig::class)->getValue('installed', false)) {
+ $tokenProvider = $c->get(IProvider::class);
} else {
$tokenProvider = null;
}
- $logger = $c->getLogger();
+ $logger = $c->get(LoggerInterface::class);
return new Store($session, $logger, $tokenProvider);
});
$this->registerAlias(IStore::class, Store::class);
- $this->registerService(Authentication\Token\DefaultTokenMapper::class, function (Server $c) {
- $dbConnection = $c->getDatabaseConnection();
- return new Authentication\Token\DefaultTokenMapper($dbConnection);
- });
$this->registerAlias(IProvider::class, Authentication\Token\Manager::class);
$this->registerService(\OC\User\Session::class, function (Server $c) {
- $manager = $c->getUserManager();
+ $manager = $c->get(IUserManager::class);
$session = new \OC\Session\Memory('');
$timeFactory = new TimeFactory();
// Token providers might require a working database. This code
// might however be called when ownCloud is not yet setup.
- if (\OC::$server->getSystemConfig()->getValue('installed', false)) {
- $defaultTokenProvider = $c->query(IProvider::class);
+ if (\OC::$server->get(SystemConfig::class)->getValue('installed', false)) {
+ $defaultTokenProvider = $c->get(IProvider::class);
} else {
$defaultTokenProvider = null;
}
- $legacyDispatcher = $c->getEventDispatcher();
+ $legacyDispatcher = $c->get(SymfonyAdapter::class);
$userSession = new \OC\User\Session(
$manager,
$session,
$timeFactory,
$defaultTokenProvider,
- $c->getConfig(),
- $c->getSecureRandom(),
+ $c->get(\OCP\IConfig::class),
+ $c->get(ISecureRandom::class),
$c->getLockdownManager(),
- $c->getLogger(),
- $c->query(IEventDispatcher::class)
+ $c->get(ILogger::class),
+ $c->get(IEventDispatcher::class)
);
+ /** @deprecated 21.0.0 use BeforeUserCreatedEvent event with the IEventDispatcher instead */
$userSession->listen('\OC\User', 'preCreateUser', function ($uid, $password) {
\OC_Hook::emit('OC_User', 'pre_createUser', ['run' => true, 'uid' => $uid, 'password' => $password]);
-
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
- $dispatcher->dispatchTyped(new BeforeUserCreatedEvent($uid, $password));
});
+ /** @deprecated 21.0.0 use UserCreatedEvent event with the IEventDispatcher instead */
$userSession->listen('\OC\User', 'postCreateUser', function ($user, $password) {
- /** @var $user \OC\User\User */
+ /** @var \OC\User\User $user */
\OC_Hook::emit('OC_User', 'post_createUser', ['uid' => $user->getUID(), 'password' => $password]);
-
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
- $dispatcher->dispatchTyped(new UserCreatedEvent($user, $password));
});
+ /** @deprecated 21.0.0 use BeforeUserDeletedEvent event with the IEventDispatcher instead */
$userSession->listen('\OC\User', 'preDelete', function ($user) use ($legacyDispatcher) {
- /** @var $user \OC\User\User */
+ /** @var \OC\User\User $user */
\OC_Hook::emit('OC_User', 'pre_deleteUser', ['run' => true, 'uid' => $user->getUID()]);
$legacyDispatcher->dispatch('OCP\IUser::preDelete', new GenericEvent($user));
-
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
- $dispatcher->dispatchTyped(new BeforeUserDeletedEvent($user));
});
+ /** @deprecated 21.0.0 use UserDeletedEvent event with the IEventDispatcher instead */
$userSession->listen('\OC\User', 'postDelete', function ($user) {
- /** @var $user \OC\User\User */
+ /** @var \OC\User\User $user */
\OC_Hook::emit('OC_User', 'post_deleteUser', ['uid' => $user->getUID()]);
-
- /** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
- $dispatcher->dispatchTyped(new UserDeletedEvent($user));
});
$userSession->listen('\OC\User', 'preSetPassword', function ($user, $password, $recoveryPassword) {
- /** @var $user \OC\User\User */
+ /** @var \OC\User\User $user */
\OC_Hook::emit('OC_User', 'pre_setPassword', ['run' => true, 'uid' => $user->getUID(), 'password' => $password, 'recoveryPassword' => $recoveryPassword]);
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new BeforePasswordUpdatedEvent($user, $password, $recoveryPassword));
});
$userSession->listen('\OC\User', 'postSetPassword', function ($user, $password, $recoveryPassword) {
- /** @var $user \OC\User\User */
+ /** @var \OC\User\User $user */
\OC_Hook::emit('OC_User', 'post_setPassword', ['run' => true, 'uid' => $user->getUID(), 'password' => $password, 'recoveryPassword' => $recoveryPassword]);
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new PasswordUpdatedEvent($user, $password, $recoveryPassword));
});
$userSession->listen('\OC\User', 'preLogin', function ($uid, $password) {
\OC_Hook::emit('OC_User', 'pre_login', ['run' => true, 'uid' => $uid, 'password' => $password]);
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new BeforeUserLoggedInEvent($uid, $password));
});
- $userSession->listen('\OC\User', 'postLogin', function ($user, $password, $isTokenLogin) {
- /** @var $user \OC\User\User */
- \OC_Hook::emit('OC_User', 'post_login', ['run' => true, 'uid' => $user->getUID(), 'password' => $password, 'isTokenLogin' => $isTokenLogin]);
+ $userSession->listen('\OC\User', 'postLogin', function ($user, $loginName, $password, $isTokenLogin) {
+ /** @var \OC\User\User $user */
+ \OC_Hook::emit('OC_User', 'post_login', ['run' => true, 'uid' => $user->getUID(), 'loginName' => $loginName, 'password' => $password, 'isTokenLogin' => $isTokenLogin]);
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new UserLoggedInEvent($user, $password, $isTokenLogin));
});
$userSession->listen('\OC\User', 'preRememberedLogin', function ($uid) {
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new BeforeUserLoggedInWithCookieEvent($uid));
});
$userSession->listen('\OC\User', 'postRememberedLogin', function ($user, $password) {
- /** @var $user \OC\User\User */
+ /** @var \OC\User\User $user */
\OC_Hook::emit('OC_User', 'post_login', ['run' => true, 'uid' => $user->getUID(), 'password' => $password]);
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new UserLoggedInWithCookieEvent($user, $password));
});
$userSession->listen('\OC\User', 'logout', function ($user) {
\OC_Hook::emit('OC_User', 'logout', []);
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new BeforeUserLoggedOutEvent($user));
});
$userSession->listen('\OC\User', 'postLogout', function ($user) {
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new UserLoggedOutEvent($user));
});
$userSession->listen('\OC\User', 'changeUser', function ($user, $feature, $value, $oldValue) {
- /** @var $user \OC\User\User */
+ /** @var \OC\User\User $user */
\OC_Hook::emit('OC_User', 'changeUser', ['run' => true, 'user' => $user, 'feature' => $feature, 'value' => $value, 'old_value' => $oldValue]);
/** @var IEventDispatcher $dispatcher */
- $dispatcher = $this->query(IEventDispatcher::class);
+ $dispatcher = $this->get(IEventDispatcher::class);
$dispatcher->dispatchTyped(new UserChangedEvent($user, $feature, $value, $oldValue));
});
return $userSession;
});
$this->registerAlias(\OCP\IUserSession::class, \OC\User\Session::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('UserSession', \OC\User\Session::class);
$this->registerAlias(\OCP\Authentication\TwoFactorAuth\IRegistry::class, \OC\Authentication\TwoFactorAuth\Registry::class);
$this->registerAlias(INavigationManager::class, \OC\NavigationManager::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('NavigationManager', INavigationManager::class);
- $this->registerService(\OC\AllConfig::class, function (Server $c) {
- return new \OC\AllConfig(
- $c->getSystemConfig()
- );
- });
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('AllConfig', \OC\AllConfig::class);
$this->registerAlias(\OCP\IConfig::class, \OC\AllConfig::class);
$this->registerService(\OC\SystemConfig::class, function ($c) use ($config) {
return new \OC\SystemConfig($config);
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('SystemConfig', \OC\SystemConfig::class);
- $this->registerService(\OC\AppConfig::class, function (Server $c) {
- return new \OC\AppConfig($c->getDatabaseConnection());
- });
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('AppConfig', \OC\AppConfig::class);
$this->registerAlias(IAppConfig::class, \OC\AppConfig::class);
$this->registerService(IFactory::class, function (Server $c) {
return new \OC\L10N\Factory(
- $c->getConfig(),
+ $c->get(\OCP\IConfig::class),
$c->getRequest(),
- $c->getUserSession(),
+ $c->get(IUserSession::class),
\OC::$SERVERROOT
);
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('L10NFactory', IFactory::class);
- $this->registerService(IURLGenerator::class, function (Server $c) {
- $config = $c->getConfig();
- $cacheFactory = $c->getMemCacheFactory();
- $request = $c->getRequest();
- return new \OC\URLGenerator(
- $config,
- $cacheFactory,
- $request
- );
- });
+ $this->registerAlias(IURLGenerator::class, URLGenerator::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('URLGenerator', IURLGenerator::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('AppFetcher', AppFetcher::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('CategoryFetcher', CategoryFetcher::class);
$this->registerService(ICache::class, function ($c) {
return new Cache\File();
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('UserCache', ICache::class);
$this->registerService(Factory::class, function (Server $c) {
- $arrayCacheFactory = new \OC\Memcache\Factory('', $c->getLogger(),
+ $arrayCacheFactory = new \OC\Memcache\Factory('', $c->get(ILogger::class),
ArrayCache::class,
ArrayCache::class,
ArrayCache::class
);
- $config = $c->getConfig();
+ /** @var \OCP\IConfig $config */
+ $config = $c->get(\OCP\IConfig::class);
if ($config->getSystemValue('installed', false) && !(defined('PHPUNIT_RUN') && PHPUNIT_RUN)) {
$v = \OC_App::getAppVersions();
@@ -677,7 +676,7 @@ class Server extends ServerContainer implements IServerContainer {
$instanceId = \OC_Util::getInstanceId();
$path = \OC::$SERVERROOT;
$prefix = md5($instanceId . '-' . $version . '-' . $path);
- return new \OC\Memcache\Factory($prefix, $c->getLogger(),
+ return new \OC\Memcache\Factory($prefix, $c->get(ILogger::class),
$config->getSystemValue('memcache.local', null),
$config->getSystemValue('memcache.distributed', null),
$config->getSystemValue('memcache.locking', null)
@@ -685,22 +684,26 @@ class Server extends ServerContainer implements IServerContainer {
}
return $arrayCacheFactory;
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('MemCacheFactory', Factory::class);
$this->registerAlias(ICacheFactory::class, Factory::class);
$this->registerService('RedisFactory', function (Server $c) {
- $systemConfig = $c->getSystemConfig();
+ $systemConfig = $c->get(SystemConfig::class);
return new RedisFactory($systemConfig);
});
$this->registerService(\OCP\Activity\IManager::class, function (Server $c) {
+ $l10n = $this->get(IFactory::class)->get('lib');
return new \OC\Activity\Manager(
$c->getRequest(),
- $c->getUserSession(),
- $c->getConfig(),
- $c->query(IValidator::class)
+ $c->get(IUserSession::class),
+ $c->get(\OCP\IConfig::class),
+ $c->get(IValidator::class),
+ $l10n
);
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('ActivityManager', \OCP\Activity\IManager::class);
$this->registerService(\OCP\Activity\IEventMerger::class, function (Server $c) {
@@ -712,49 +715,45 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerService(AvatarManager::class, function (Server $c) {
return new AvatarManager(
- $c->query(\OC\User\Manager::class),
+ $c->get(\OC\User\Manager::class),
$c->getAppDataDir('avatar'),
$c->getL10N('lib'),
- $c->getLogger(),
- $c->getConfig()
+ $c->get(ILogger::class),
+ $c->get(\OCP\IConfig::class)
);
});
$this->registerAlias(IAvatarManager::class, AvatarManager::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('AvatarManager', AvatarManager::class);
$this->registerAlias(\OCP\Support\CrashReport\IRegistry::class, \OC\Support\CrashReport\Registry::class);
$this->registerAlias(\OCP\Support\Subscription\IRegistry::class, \OC\Support\Subscription\Registry::class);
$this->registerService(\OC\Log::class, function (Server $c) {
- $logType = $c->query(AllConfig::class)->getSystemValue('log_type', 'file');
- $factory = new LogFactory($c, $this->getSystemConfig());
+ $logType = $c->get(AllConfig::class)->getSystemValue('log_type', 'file');
+ $factory = new LogFactory($c, $this->get(SystemConfig::class));
$logger = $factory->get($logType);
- $registry = $c->query(\OCP\Support\CrashReport\IRegistry::class);
+ $registry = $c->get(\OCP\Support\CrashReport\IRegistry::class);
- return new Log($logger, $this->getSystemConfig(), null, $registry);
+ return new Log($logger, $this->get(SystemConfig::class), null, $registry);
});
$this->registerAlias(ILogger::class, \OC\Log::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('Logger', \OC\Log::class);
// PSR-3 logger
$this->registerAlias(LoggerInterface::class, PsrLoggerAdapter::class);
$this->registerService(ILogFactory::class, function (Server $c) {
- return new LogFactory($c, $this->getSystemConfig());
+ return new LogFactory($c, $this->get(SystemConfig::class));
});
- $this->registerService(IJobList::class, function (Server $c) {
- $config = $c->getConfig();
- return new \OC\BackgroundJob\JobList(
- $c->getDatabaseConnection(),
- $config,
- new TimeFactory()
- );
- });
+ $this->registerAlias(IJobList::class, \OC\BackgroundJob\JobList::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('JobList', IJobList::class);
- $this->registerService(IRouter::class, function (Server $c) {
- $cacheFactory = $c->getMemCacheFactory();
- $logger = $c->getLogger();
+ $this->registerService(Router::class, function (Server $c) {
+ $cacheFactory = $c->get(ICacheFactory::class);
+ $logger = $c->get(ILogger::class);
if ($cacheFactory->isLocalCacheAvailable()) {
$router = new \OC\Route\CachingRouter($cacheFactory->createLocal('route'), $logger);
} else {
@@ -762,42 +761,39 @@ class Server extends ServerContainer implements IServerContainer {
}
return $router;
});
+ $this->registerAlias(IRouter::class, Router::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('Router', IRouter::class);
- $this->registerService(ISearch::class, function ($c) {
- return new Search();
- });
+ $this->registerAlias(ISearch::class, Search::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('Search', ISearch::class);
$this->registerService(\OC\Security\RateLimiting\Backend\IBackend::class, function ($c) {
return new \OC\Security\RateLimiting\Backend\MemoryCache(
- $this->getMemCacheFactory(),
+ $this->get(ICacheFactory::class),
new \OC\AppFramework\Utility\TimeFactory()
);
});
- $this->registerService(\OCP\Security\ISecureRandom::class, function ($c) {
- return new SecureRandom();
- });
+ $this->registerAlias(\OCP\Security\ISecureRandom::class, SecureRandom::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('SecureRandom', \OCP\Security\ISecureRandom::class);
- $this->registerService(ICrypto::class, function (Server $c) {
- return new Crypto($c->getConfig(), $c->getSecureRandom());
- });
+ $this->registerAlias(ICrypto::class, Crypto::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('Crypto', ICrypto::class);
- $this->registerService(IHasher::class, function (Server $c) {
- return new Hasher($c->getConfig());
- });
+ $this->registerAlias(IHasher::class, Hasher::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('Hasher', IHasher::class);
- $this->registerService(ICredentialsManager::class, function (Server $c) {
- return new CredentialsManager($c->getCrypto(), $c->getDatabaseConnection());
- });
+ $this->registerAlias(ICredentialsManager::class, CredentialsManager::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('CredentialsManager', ICredentialsManager::class);
$this->registerService(IDBConnection::class, function (Server $c) {
- $systemConfig = $c->getSystemConfig();
+ $systemConfig = $c->get(SystemConfig::class);
$factory = new \OC\DB\ConnectionFactory($systemConfig);
$type = $systemConfig->getValue('dbtype', 'sqlite');
if (!$factory->isValidType($type)) {
@@ -808,147 +804,129 @@ class Server extends ServerContainer implements IServerContainer {
$connection->getConfiguration()->setSQLLogger($c->getQueryLogger());
return $connection;
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('DatabaseConnection', IDBConnection::class);
-
- $this->registerService(IClientService::class, function (Server $c) {
- $user = \OC_User::getUser();
- $uid = $user ? $user : null;
- return new ClientService(
- $c->getConfig(),
- $c->getLogger(),
- new \OC\Security\CertificateManager(
- $uid,
- new View(),
- $c->getConfig(),
- $c->getLogger(),
- $c->getSecureRandom()
- )
- );
- });
+ $this->registerAlias(ICertificateManager::class, CertificateManager::class);
+ $this->registerAlias(IClientService::class, ClientService::class);
$this->registerDeprecatedAlias('HttpClientService', IClientService::class);
- $this->registerService(IEventLogger::class, function (Server $c) {
+ $this->registerService(IEventLogger::class, function (ContainerInterface $c) {
$eventLogger = new EventLogger();
- if ($c->getSystemConfig()->getValue('debug', false)) {
+ if ($c->get(SystemConfig::class)->getValue('debug', false)) {
// In debug mode, module is being activated by default
$eventLogger->activate();
}
return $eventLogger;
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('EventLogger', IEventLogger::class);
- $this->registerService(IQueryLogger::class, function (Server $c) {
+ $this->registerService(IQueryLogger::class, function (ContainerInterface $c) {
$queryLogger = new QueryLogger();
- if ($c->getSystemConfig()->getValue('debug', false)) {
+ if ($c->get(SystemConfig::class)->getValue('debug', false)) {
// In debug mode, module is being activated by default
$queryLogger->activate();
}
return $queryLogger;
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('QueryLogger', IQueryLogger::class);
- $this->registerService(TempManager::class, function (Server $c) {
- return new TempManager(
- $c->getLogger(),
- $c->getConfig()
- );
- });
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('TempManager', TempManager::class);
$this->registerAlias(ITempManager::class, TempManager::class);
- $this->registerService(AppManager::class, function (Server $c) {
+ $this->registerService(AppManager::class, function (ContainerInterface $c) {
+ // TODO: use auto-wiring
return new \OC\App\AppManager(
- $c->getUserSession(),
- $c->getConfig(),
- $c->query(\OC\AppConfig::class),
- $c->getGroupManager(),
- $c->getMemCacheFactory(),
- $c->getEventDispatcher(),
- $c->getLogger()
+ $c->get(IUserSession::class),
+ $c->get(\OCP\IConfig::class),
+ $c->get(\OC\AppConfig::class),
+ $c->get(IGroupManager::class),
+ $c->get(ICacheFactory::class),
+ $c->get(SymfonyAdapter::class),
+ $c->get(ILogger::class)
);
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('AppManager', AppManager::class);
$this->registerAlias(IAppManager::class, AppManager::class);
- $this->registerService(IDateTimeZone::class, function (Server $c) {
- return new DateTimeZone(
- $c->getConfig(),
- $c->getSession()
- );
- });
+ $this->registerAlias(IDateTimeZone::class, DateTimeZone::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('DateTimeZone', IDateTimeZone::class);
$this->registerService(IDateTimeFormatter::class, function (Server $c) {
- $language = $c->getConfig()->getUserValue($c->getSession()->get('user_id'), 'core', 'lang', null);
+ $language = $c->get(\OCP\IConfig::class)->getUserValue($c->get(ISession::class)->get('user_id'), 'core', 'lang', null);
return new DateTimeFormatter(
- $c->getDateTimeZone()->getTimeZone(),
+ $c->get(IDateTimeZone::class)->getTimeZone(),
$c->getL10N('lib', $language)
);
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('DateTimeFormatter', IDateTimeFormatter::class);
- $this->registerService(IUserMountCache::class, function (Server $c) {
- $mountCache = new UserMountCache($c->getDatabaseConnection(), $c->getUserManager(), $c->getLogger());
+ $this->registerService(IUserMountCache::class, function (ContainerInterface $c) {
+ $mountCache = new UserMountCache(
+ $c->get(IDBConnection::class),
+ $c->get(IUserManager::class),
+ $c->get(ILogger::class)
+ );
$listener = new UserMountCacheListener($mountCache);
- $listener->listen($c->getUserManager());
+ $listener->listen($c->get(IUserManager::class));
return $mountCache;
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('UserMountCache', IUserMountCache::class);
- $this->registerService(IMountProviderCollection::class, function (Server $c) {
+ $this->registerService(IMountProviderCollection::class, function (ContainerInterface $c) {
$loader = \OC\Files\Filesystem::getLoader();
- $mountCache = $c->query(IUserMountCache::class);
+ $mountCache = $c->get(IUserMountCache::class);
$manager = new \OC\Files\Config\MountProviderCollection($loader, $mountCache);
// builtin providers
- $config = $c->getConfig();
+ $config = $c->get(\OCP\IConfig::class);
+ $logger = $c->get(ILogger::class);
$manager->registerProvider(new CacheMountProvider($config));
$manager->registerHomeProvider(new LocalHomeMountProvider());
$manager->registerHomeProvider(new ObjectHomeMountProvider($config));
+ $manager->registerRootProvider(new ObjectStorePreviewCacheMountProvider($logger, $config));
return $manager;
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('MountConfigManager', IMountProviderCollection::class);
- $this->registerService('IniWrapper', function ($c) {
- return new IniGetWrapper();
- });
- $this->registerService('AsyncCommandBus', function (Server $c) {
- $busClass = $c->getConfig()->getSystemValue('commandbus');
+ /** @deprecated 20.0.0 */
+ $this->registerDeprecatedAlias('IniWrapper', IniGetWrapper::class);
+ $this->registerService(IBus::class, function (ContainerInterface $c) {
+ $busClass = $c->get(\OCP\IConfig::class)->getSystemValue('commandbus');
if ($busClass) {
[$app, $class] = explode('::', $busClass, 2);
- if ($c->getAppManager()->isInstalled($app)) {
+ if ($c->get(IAppManager::class)->isInstalled($app)) {
\OC_App::loadApp($app);
- return $c->query($class);
+ return $c->get($class);
} else {
throw new ServiceUnavailableException("The app providing the command bus ($app) is not enabled");
}
} else {
- $jobList = $c->getJobList();
+ $jobList = $c->get(IJobList::class);
return new CronBus($jobList);
}
});
- $this->registerAlias(IBus::class, 'AsyncCommandBus');
- $this->registerService('TrustedDomainHelper', function ($c) {
- return new TrustedDomainHelper($this->getConfig());
- });
- $this->registerService(Throttler::class, function (Server $c) {
- return new Throttler(
- $c->getDatabaseConnection(),
- new TimeFactory(),
- $c->getLogger(),
- $c->getConfig()
- );
- });
+ $this->registerDeprecatedAlias('AsyncCommandBus', IBus::class);
+ /** @deprecated 20.0.0 */
+ $this->registerDeprecatedAlias('TrustedDomainHelper', TrustedDomainHelper::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('Throttler', Throttler::class);
- $this->registerService('IntegrityCodeChecker', function (Server $c) {
+ $this->registerService('IntegrityCodeChecker', function (ContainerInterface $c) {
// IConfig and IAppManager requires a working database. This code
// might however be called when ownCloud is not yet setup.
- if (\OC::$server->getSystemConfig()->getValue('installed', false)) {
- $config = $c->getConfig();
- $appManager = $c->getAppManager();
+ if (\OC::$server->get(SystemConfig::class)->getValue('installed', false)) {
+ $config = $c->get(\OCP\IConfig::class);
+ $appManager = $c->get(IAppManager::class);
} else {
$config = null;
$appManager = null;
@@ -959,13 +937,13 @@ class Server extends ServerContainer implements IServerContainer {
new FileAccessHelper(),
new AppLocator(),
$config,
- $c->getMemCacheFactory(),
+ $c->get(ICacheFactory::class),
$appManager,
- $c->getTempManager(),
- $c->getMimeTypeDetector()
+ $c->get(ITempManager::class),
+ $c->get(IMimeTypeDetector::class)
);
});
- $this->registerService(\OCP\IRequest::class, function ($c) {
+ $this->registerService(\OCP\IRequest::class, function (ContainerInterface $c) {
if (isset($this['urlParams'])) {
$urlParams = $this['urlParams'];
} else {
@@ -993,29 +971,31 @@ class Server extends ServerContainer implements IServerContainer {
: '',
'urlParams' => $urlParams,
],
- $this->getSecureRandom(),
- $this->getConfig(),
- $this->getCsrfTokenManager(),
+ $this->get(ISecureRandom::class),
+ $this->get(\OCP\IConfig::class),
+ $this->get(CsrfTokenManager::class),
$stream
);
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('Request', \OCP\IRequest::class);
$this->registerService(IMailer::class, function (Server $c) {
return new Mailer(
- $c->getConfig(),
- $c->getLogger(),
- $c->query(Defaults::class),
- $c->getURLGenerator(),
+ $c->get(\OCP\IConfig::class),
+ $c->get(ILogger::class),
+ $c->get(Defaults::class),
+ $c->get(IURLGenerator::class),
$c->getL10N('lib'),
- $c->query(IEventDispatcher::class),
- $c->getL10NFactory()
+ $c->get(IEventDispatcher::class),
+ $c->get(IFactory::class)
);
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('Mailer', IMailer::class);
- $this->registerService('LDAPProvider', function (Server $c) {
- $config = $c->getConfig();
+ $this->registerService('LDAPProvider', function (ContainerInterface $c) {
+ $config = $c->get(\OCP\IConfig::class);
$factoryClass = $config->getSystemValue('ldapProviderFactory', null);
if (is_null($factoryClass)) {
throw new \Exception('ldapProviderFactory not set');
@@ -1024,20 +1004,20 @@ class Server extends ServerContainer implements IServerContainer {
$factory = new $factoryClass($this);
return $factory->getLDAPProvider();
});
- $this->registerService(ILockingProvider::class, function (Server $c) {
- $ini = $c->getIniWrapper();
- $config = $c->getConfig();
+ $this->registerService(ILockingProvider::class, function (ContainerInterface $c) {
+ $ini = $c->get(IniGetWrapper::class);
+ $config = $c->get(\OCP\IConfig::class);
$ttl = $config->getSystemValue('filelocking.ttl', max(3600, $ini->getNumeric('max_execution_time')));
if ($config->getSystemValue('filelocking.enabled', true) or (defined('PHPUNIT_RUN') && PHPUNIT_RUN)) {
/** @var \OC\Memcache\Factory $memcacheFactory */
- $memcacheFactory = $c->getMemCacheFactory();
+ $memcacheFactory = $c->get(ICacheFactory::class);
$memcache = $memcacheFactory->createLocking('lock');
if (!($memcache instanceof \OC\Memcache\NullCache)) {
return new MemcacheLockingProvider($memcache, $ttl);
}
return new DBLockingProvider(
- $c->getDatabaseConnection(),
- $c->getLogger(),
+ $c->get(IDBConnection::class),
+ $c->get(ILogger::class),
new TimeFactory(),
$ttl,
!\OC::$CLI
@@ -1045,61 +1025,56 @@ class Server extends ServerContainer implements IServerContainer {
}
return new NoopLockingProvider();
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('LockingProvider', ILockingProvider::class);
- $this->registerService(IMountManager::class, function () {
- return new \OC\Files\Mount\Manager();
- });
+ $this->registerAlias(IMountManager::class, \OC\Files\Mount\Manager::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('MountManager', IMountManager::class);
- $this->registerService(IMimeTypeDetector::class, function (Server $c) {
+ $this->registerService(IMimeTypeDetector::class, function (ContainerInterface $c) {
return new \OC\Files\Type\Detection(
- $c->getURLGenerator(),
- $c->getLogger(),
+ $c->get(IURLGenerator::class),
+ $c->get(ILogger::class),
\OC::$configDir,
\OC::$SERVERROOT . '/resources/config/'
);
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('MimeTypeDetector', IMimeTypeDetector::class);
- $this->registerService(IMimeTypeLoader::class, function (Server $c) {
- return new \OC\Files\Type\Loader(
- $c->getDatabaseConnection()
- );
- });
+ $this->registerAlias(IMimeTypeLoader::class, Loader::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('MimeTypeLoader', IMimeTypeLoader::class);
$this->registerService(BundleFetcher::class, function () {
return new BundleFetcher($this->getL10N('lib'));
});
- $this->registerService(\OCP\Notification\IManager::class, function (Server $c) {
- return new Manager(
- $c->query(IValidator::class),
- $c->getLogger()
- );
- });
+ $this->registerAlias(\OCP\Notification\IManager::class, Manager::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('NotificationManager', \OCP\Notification\IManager::class);
- $this->registerService(CapabilitiesManager::class, function (Server $c) {
- $manager = new CapabilitiesManager($c->getLogger());
+ $this->registerService(CapabilitiesManager::class, function (ContainerInterface $c) {
+ $manager = new CapabilitiesManager($c->get(ILogger::class));
$manager->registerCapability(function () use ($c) {
- return new \OC\OCS\CoreCapabilities($c->getConfig());
+ return new \OC\OCS\CoreCapabilities($c->get(\OCP\IConfig::class));
});
$manager->registerCapability(function () use ($c) {
- return $c->query(\OC\Security\Bruteforce\Capabilities::class);
+ return $c->get(\OC\Security\Bruteforce\Capabilities::class);
});
return $manager;
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('CapabilitiesManager', CapabilitiesManager::class);
$this->registerService(ICommentsManager::class, function (Server $c) {
- $config = $c->getConfig();
+ $config = $c->get(\OCP\IConfig::class);
$factoryClass = $config->getSystemValue('comments.managerFactory', CommentsManagerFactory::class);
/** @var \OCP\Comments\ICommentsManagerFactory $factory */
$factory = new $factoryClass($this);
$manager = $factory->getManager();
$manager->registerDisplayNameResolver('user', function ($id) use ($c) {
- $manager = $c->getUserManager();
+ $manager = $c->get(IUserManager::class);
$user = $manager->get($id);
if (is_null($user)) {
$l = $c->getL10N('core');
@@ -1112,8 +1087,10 @@ class Server extends ServerContainer implements IServerContainer {
return $manager;
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('CommentsManager', ICommentsManager::class);
+ $this->registerAlias(\OC_Defaults::class, 'ThemingDefaults');
$this->registerService('ThemingDefaults', function (Server $c) {
/*
* Dark magic for autoloader.
@@ -1128,47 +1105,42 @@ class Server extends ServerContainer implements IServerContainer {
$classExists = false;
}
- if ($classExists && $c->getConfig()->getSystemValue('installed', false) && $c->getAppManager()->isInstalled('theming') && $c->getTrustedDomainHelper()->isTrustedDomain($c->getRequest()->getInsecureServerHost())) {
+ if ($classExists && $c->get(\OCP\IConfig::class)->getSystemValue('installed', false) && $c->get(IAppManager::class)->isInstalled('theming') && $c->getTrustedDomainHelper()->isTrustedDomain($c->getRequest()->getInsecureServerHost())) {
return new ThemingDefaults(
- $c->getConfig(),
+ $c->get(\OCP\IConfig::class),
$c->getL10N('theming'),
- $c->getURLGenerator(),
- $c->getMemCacheFactory(),
- new Util($c->getConfig(), $this->getAppManager(), $c->getAppDataDir('theming')),
- new ImageManager($c->getConfig(), $c->getAppDataDir('theming'), $c->getURLGenerator(), $this->getMemCacheFactory(), $this->getLogger()),
- $c->getAppManager(),
- $c->getNavigationManager()
+ $c->get(IURLGenerator::class),
+ $c->get(ICacheFactory::class),
+ new Util($c->get(\OCP\IConfig::class), $this->get(IAppManager::class), $c->getAppDataDir('theming')),
+ new ImageManager(
+ $c->get(\OCP\IConfig::class),
+ $c->getAppDataDir('theming'),
+ $c->get(IURLGenerator::class),
+ $this->get(ICacheFactory::class),
+ $this->get(ILogger::class),
+ $this->get(ITempManager::class)
+ ),
+ $c->get(IAppManager::class),
+ $c->get(INavigationManager::class)
);
}
return new \OC_Defaults();
});
- $this->registerService(SCSSCacher::class, function (Server $c) {
- return new SCSSCacher(
- $c->getLogger(),
- $c->query(\OC\Files\AppData\Factory::class),
- $c->getURLGenerator(),
- $c->getConfig(),
- $c->getThemingDefaults(),
- \OC::$SERVERROOT,
- $this->getMemCacheFactory(),
- $c->query(IconsCacher::class),
- new TimeFactory()
- );
- });
$this->registerService(JSCombiner::class, function (Server $c) {
return new JSCombiner(
$c->getAppDataDir('js'),
- $c->getURLGenerator(),
- $this->getMemCacheFactory(),
- $c->getSystemConfig(),
- $c->getLogger()
+ $c->get(IURLGenerator::class),
+ $this->get(ICacheFactory::class),
+ $c->get(SystemConfig::class),
+ $c->get(ILogger::class)
);
});
$this->registerAlias(\OCP\EventDispatcher\IEventDispatcher::class, \OC\EventDispatcher\EventDispatcher::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('EventDispatcher', \OC\EventDispatcher\SymfonyAdapter::class);
$this->registerAlias(EventDispatcherInterface::class, \OC\EventDispatcher\SymfonyAdapter::class);
- $this->registerService('CryptoWrapper', function (Server $c) {
+ $this->registerService('CryptoWrapper', function (ContainerInterface $c) {
// FIXME: Instantiiated here due to cyclic dependency
$request = new Request(
[
@@ -1182,66 +1154,54 @@ class Server extends ServerContainer implements IServerContainer {
? $_SERVER['REQUEST_METHOD']
: null,
],
- $c->getSecureRandom(),
- $c->getConfig()
+ $c->get(ISecureRandom::class),
+ $c->get(\OCP\IConfig::class)
);
return new CryptoWrapper(
- $c->getConfig(),
- $c->getCrypto(),
- $c->getSecureRandom(),
+ $c->get(\OCP\IConfig::class),
+ $c->get(ICrypto::class),
+ $c->get(ISecureRandom::class),
$request
);
});
- $this->registerService(CsrfTokenManager::class, function (Server $c) {
- $tokenGenerator = new CsrfTokenGenerator($c->getSecureRandom());
-
- return new CsrfTokenManager(
- $tokenGenerator,
- $c->query(SessionStorage::class)
- );
- });
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('CsrfTokenManager', CsrfTokenManager::class);
- $this->registerService(SessionStorage::class, function (Server $c) {
- return new SessionStorage($c->getSession());
+ $this->registerService(SessionStorage::class, function (ContainerInterface $c) {
+ return new SessionStorage($c->get(ISession::class));
});
$this->registerAlias(\OCP\Security\IContentSecurityPolicyManager::class, ContentSecurityPolicyManager::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('ContentSecurityPolicyManager', ContentSecurityPolicyManager::class);
- $this->registerService('ContentSecurityPolicyNonceManager', function (Server $c) {
- return new ContentSecurityPolicyNonceManager(
- $c->getCsrfTokenManager(),
- $c->getRequest()
- );
- });
-
- $this->registerService(\OCP\Share\IManager::class, function (Server $c) {
- $config = $c->getConfig();
+ $this->registerService(\OCP\Share\IManager::class, function (IServerContainer $c) {
+ $config = $c->get(\OCP\IConfig::class);
$factoryClass = $config->getSystemValue('sharing.managerFactory', ProviderFactory::class);
/** @var \OCP\Share\IProviderFactory $factory */
$factory = new $factoryClass($this);
$manager = new \OC\Share20\Manager(
- $c->getLogger(),
- $c->getConfig(),
- $c->getSecureRandom(),
- $c->getHasher(),
- $c->getMountManager(),
- $c->getGroupManager(),
+ $c->get(ILogger::class),
+ $c->get(\OCP\IConfig::class),
+ $c->get(ISecureRandom::class),
+ $c->get(IHasher::class),
+ $c->get(IMountManager::class),
+ $c->get(IGroupManager::class),
$c->getL10N('lib'),
- $c->getL10NFactory(),
+ $c->get(IFactory::class),
$factory,
- $c->getUserManager(),
- $c->getLazyRootFolder(),
- $c->getEventDispatcher(),
- $c->getMailer(),
- $c->getURLGenerator(),
- $c->getThemingDefaults(),
- $c->query(IEventDispatcher::class)
+ $c->get(IUserManager::class),
+ $c->get(IRootFolder::class),
+ $c->get(SymfonyAdapter::class),
+ $c->get(IMailer::class),
+ $c->get(IURLGenerator::class),
+ $c->get('ThemingDefaults'),
+ $c->get(IEventDispatcher::class)
);
return $manager;
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('ShareManager', \OCP\Share\IManager::class);
$this->registerService(\OCP\Collaboration\Collaborators\ISearch::class, function (Server $c) {
@@ -1256,6 +1216,7 @@ class Server extends ServerContainer implements IServerContainer {
return $instance;
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('CollaboratorSearch', \OCP\Collaboration\Collaborators\ISearch::class);
$this->registerAlias(\OCP\Collaboration\Collaborators\ISearchResult::class, \OC\Collaboration\Collaborators\SearchResult::class);
@@ -1264,40 +1225,41 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerAlias(\OCP\Collaboration\Resources\IProviderManager::class, \OC\Collaboration\Resources\ProviderManager::class);
$this->registerAlias(\OCP\Collaboration\Resources\IManager::class, \OC\Collaboration\Resources\Manager::class);
- $this->registerService('SettingsManager', function (Server $c) {
- $manager = new \OC\Settings\Manager(
- $c->getLogger(),
- $c->getL10NFactory(),
- $c->getURLGenerator(),
- $c
- );
- return $manager;
- });
- $this->registerService(\OC\Files\AppData\Factory::class, function (Server $c) {
+ $this->registerDeprecatedAlias('SettingsManager', \OC\Settings\Manager::class);
+ $this->registerAlias(\OCP\Settings\IManager::class, \OC\Settings\Manager::class);
+ $this->registerService(\OC\Files\AppData\Factory::class, function (ContainerInterface $c) {
return new \OC\Files\AppData\Factory(
- $c->getRootFolder(),
- $c->getSystemConfig()
+ $c->get(IRootFolder::class),
+ $c->get(SystemConfig::class)
);
});
- $this->registerService('LockdownManager', function (Server $c) {
+ $this->registerService('LockdownManager', function (ContainerInterface $c) {
return new LockdownManager(function () use ($c) {
- return $c->getSession();
+ return $c->get(ISession::class);
});
});
- $this->registerService(\OCP\OCS\IDiscoveryService::class, function (Server $c) {
- return new DiscoveryService($c->getMemCacheFactory(), $c->getHTTPClientService());
+ $this->registerService(\OCP\OCS\IDiscoveryService::class, function (ContainerInterface $c) {
+ return new DiscoveryService(
+ $c->get(ICacheFactory::class),
+ $c->get(IClientService::class)
+ );
});
- $this->registerService(ICloudIdManager::class, function (Server $c) {
- return new CloudIdManager();
+ $this->registerService(ICloudIdManager::class, function (ContainerInterface $c) {
+ return new CloudIdManager($c->get(\OCP\Contacts\IManager::class));
});
$this->registerAlias(\OCP\GlobalScale\IConfig::class, \OC\GlobalScale\Config::class);
- $this->registerService(ICloudFederationProviderManager::class, function (Server $c) {
- return new CloudFederationProviderManager($c->getAppManager(), $c->getHTTPClientService(), $c->getCloudIdManager(), $c->getLogger());
+ $this->registerService(ICloudFederationProviderManager::class, function (ContainerInterface $c) {
+ return new CloudFederationProviderManager(
+ $c->get(IAppManager::class),
+ $c->get(IClientService::class),
+ $c->get(ICloudIdManager::class),
+ $c->get(ILogger::class)
+ );
});
$this->registerService(ICloudFederationFactory::class, function (Server $c) {
@@ -1305,9 +1267,11 @@ class Server extends ServerContainer implements IServerContainer {
});
$this->registerAlias(\OCP\AppFramework\Utility\IControllerMethodReflector::class, \OC\AppFramework\Utility\ControllerMethodReflector::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('ControllerMethodReflector', \OCP\AppFramework\Utility\IControllerMethodReflector::class);
$this->registerAlias(\OCP\AppFramework\Utility\ITimeFactory::class, \OC\AppFramework\Utility\TimeFactory::class);
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('TimeFactory', \OCP\AppFramework\Utility\ITimeFactory::class);
$this->registerService(Defaults::class, function (Server $c) {
@@ -1315,52 +1279,43 @@ class Server extends ServerContainer implements IServerContainer {
$c->getThemingDefaults()
);
});
+ /** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('Defaults', \OCP\Defaults::class);
- $this->registerService(\OCP\ISession::class, function (SimpleContainer $c) {
- return $c->query(\OCP\IUserSession::class)->getSession();
- });
+ $this->registerService(\OCP\ISession::class, function (ContainerInterface $c) {
+ return $c->get(\OCP\IUserSession::class)->getSession();
+ }, false);
- $this->registerService(IShareHelper::class, function (Server $c) {
+ $this->registerService(IShareHelper::class, function (ContainerInterface $c) {
return new ShareHelper(
- $c->query(\OCP\Share\IManager::class)
+ $c->get(\OCP\Share\IManager::class)
);
});
- $this->registerService(Installer::class, function (Server $c) {
+ $this->registerService(Installer::class, function (ContainerInterface $c) {
return new Installer(
- $c->getAppFetcher(),
- $c->getHTTPClientService(),
- $c->getTempManager(),
- $c->getLogger(),
- $c->getConfig(),
+ $c->get(AppFetcher::class),
+ $c->get(IClientService::class),
+ $c->get(ITempManager::class),
+ $c->get(ILogger::class),
+ $c->get(\OCP\IConfig::class),
\OC::$CLI
);
});
- $this->registerService(IApiFactory::class, function (Server $c) {
- return new ApiFactory($c->getHTTPClientService());
+ $this->registerService(IApiFactory::class, function (ContainerInterface $c) {
+ return new ApiFactory($c->get(IClientService::class));
});
- $this->registerService(IInstanceFactory::class, function (Server $c) {
- $memcacheFactory = $c->getMemCacheFactory();
- return new InstanceFactory($memcacheFactory->createLocal('remoteinstance.'), $c->getHTTPClientService());
+ $this->registerService(IInstanceFactory::class, function (ContainerInterface $c) {
+ $memcacheFactory = $c->get(ICacheFactory::class);
+ return new InstanceFactory($memcacheFactory->createLocal('remoteinstance.'), $c->get(IClientService::class));
});
- $this->registerService(IContactsStore::class, function (Server $c) {
- return new ContactsStore(
- $c->getContactsManager(),
- $c->getConfig(),
- $c->getUserManager(),
- $c->getGroupManager()
- );
- });
$this->registerAlias(IContactsStore::class, ContactsStore::class);
$this->registerAlias(IAccountManager::class, AccountManager::class);
- $this->registerService(IStorageFactory::class, function () {
- return new StorageFactory();
- });
+ $this->registerAlias(IStorageFactory::class, StorageFactory::class);
$this->registerAlias(IDashboardManager::class, DashboardManager::class);
$this->registerAlias(\OCP\Dashboard\IManager::class, \OC\Dashboard\Manager::class);
@@ -1370,45 +1325,47 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerAlias(IInitialStateService::class, InitialStateService::class);
+ $this->registerAlias(\OCP\UserStatus\IManager::class, \OC\UserStatus\Manager::class);
+
$this->connectDispatcher();
}
public function boot() {
/** @var HookConnector $hookConnector */
- $hookConnector = $this->query(HookConnector::class);
+ $hookConnector = $this->get(HookConnector::class);
$hookConnector->viewToNode();
}
/**
* @return \OCP\Calendar\IManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getCalendarManager() {
- return $this->query(\OC\Calendar\Manager::class);
+ return $this->get(\OC\Calendar\Manager::class);
}
/**
* @return \OCP\Calendar\Resource\IManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getCalendarResourceBackendManager() {
- return $this->query(\OC\Calendar\Resource\Manager::class);
+ return $this->get(\OC\Calendar\Resource\Manager::class);
}
/**
* @return \OCP\Calendar\Room\IManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getCalendarRoomBackendManager() {
- return $this->query(\OC\Calendar\Room\Manager::class);
+ return $this->get(\OC\Calendar\Room\Manager::class);
}
private function connectDispatcher() {
- $dispatcher = $this->getEventDispatcher();
+ $dispatcher = $this->get(SymfonyAdapter::class);
// Delete avatar on user deletion
$dispatcher->addListener('OCP\IUser::preDelete', function (GenericEvent $e) {
- $logger = $this->getLogger();
+ $logger = $this->get(ILogger::class);
$manager = $this->getAvatarManager();
/** @var IUser $user */
$user = $e->getSubject();
@@ -1446,40 +1403,41 @@ class Server extends ServerContainer implements IServerContainer {
});
/** @var IEventDispatcher $eventDispatched */
- $eventDispatched = $this->query(IEventDispatcher::class);
+ $eventDispatched = $this->get(IEventDispatcher::class);
$eventDispatched->addServiceListener(LoginFailed::class, LoginFailedListener::class);
+ $eventDispatched->addServiceListener(PostLoginEvent::class, UserLoggedInListener::class);
}
/**
* @return \OCP\Contacts\IManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getContactsManager() {
- return $this->query(\OCP\Contacts\IManager::class);
+ return $this->get(\OCP\Contacts\IManager::class);
}
/**
* @return \OC\Encryption\Manager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getEncryptionManager() {
- return $this->query(\OCP\Encryption\IManager::class);
+ return $this->get(\OCP\Encryption\IManager::class);
}
/**
* @return \OC\Encryption\File
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getEncryptionFilesHelper() {
- return $this->query('EncryptionFileHelper');
+ return $this->get(IFile::class);
}
/**
* @return \OCP\Encryption\Keys\IStorage
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getEncryptionKeyStorage() {
- return $this->query('EncryptionKeyStorage');
+ return $this->get(IStorage::class);
}
/**
@@ -1488,20 +1446,20 @@ class Server extends ServerContainer implements IServerContainer {
* In case the current execution was not initiated by a web request null is returned
*
* @return \OCP\IRequest
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getRequest() {
- return $this->query(IRequest::class);
+ return $this->get(IRequest::class);
}
/**
* Returns the preview manager which can create preview images for a given file
*
* @return IPreview
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getPreviewManager() {
- return $this->query(IPreview::class);
+ return $this->get(IPreview::class);
}
/**
@@ -1509,10 +1467,10 @@ class Server extends ServerContainer implements IServerContainer {
*
* @see \OCP\ITagManager::load()
* @return ITagManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getTagManager() {
- return $this->query(ITagManager::class);
+ return $this->get(ITagManager::class);
}
/**
@@ -1521,10 +1479,10 @@ class Server extends ServerContainer implements IServerContainer {
* @return ISystemTagManager
*
* @since 9.0.0
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getSystemTagManager() {
- return $this->query(ISystemTagManager::class);
+ return $this->get(ISystemTagManager::class);
}
/**
@@ -1533,30 +1491,30 @@ class Server extends ServerContainer implements IServerContainer {
* @return ISystemTagObjectMapper
*
* @since 9.0.0
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getSystemTagObjectMapper() {
- return $this->query(ISystemTagObjectMapper::class);
+ return $this->get(ISystemTagObjectMapper::class);
}
/**
* Returns the avatar manager, used for avatar functionality
*
* @return IAvatarManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getAvatarManager() {
- return $this->query(IAvatarManager::class);
+ return $this->get(IAvatarManager::class);
}
/**
* Returns the root folder of ownCloud's data directory
*
* @return IRootFolder
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getRootFolder() {
- return $this->query(IRootFolder::class);
+ return $this->get(IRootFolder::class);
}
/**
@@ -1565,9 +1523,10 @@ class Server extends ServerContainer implements IServerContainer {
* is actually used.
*
* @return IRootFolder
+ * @deprecated 20.0.0
*/
public function getLazyRootFolder() {
- return $this->query(IRootFolder::class);
+ return $this->get(IRootFolder::class);
}
/**
@@ -1575,109 +1534,109 @@ class Server extends ServerContainer implements IServerContainer {
*
* @param string $userId user ID
* @return \OCP\Files\Folder|null
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getUserFolder($userId = null) {
if ($userId === null) {
- $user = $this->getUserSession()->getUser();
+ $user = $this->get(IUserSession::class)->getUser();
if (!$user) {
return null;
}
$userId = $user->getUID();
}
- $root = $this->getRootFolder();
+ $root = $this->get(IRootFolder::class);
return $root->getUserFolder($userId);
}
/**
* @return \OC\User\Manager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getUserManager() {
- return $this->query(IUserManager::class);
+ return $this->get(IUserManager::class);
}
/**
* @return \OC\Group\Manager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getGroupManager() {
- return $this->query(IGroupManager::class);
+ return $this->get(IGroupManager::class);
}
/**
* @return \OC\User\Session
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getUserSession() {
- return $this->query(IUserSession::class);
+ return $this->get(IUserSession::class);
}
/**
* @return \OCP\ISession
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getSession() {
- return $this->getUserSession()->getSession();
+ return $this->get(IUserSession::class)->getSession();
}
/**
* @param \OCP\ISession $session
*/
public function setSession(\OCP\ISession $session) {
- $this->query(SessionStorage::class)->setSession($session);
- $this->getUserSession()->setSession($session);
- $this->query(Store::class)->setSession($session);
+ $this->get(SessionStorage::class)->setSession($session);
+ $this->get(IUserSession::class)->setSession($session);
+ $this->get(Store::class)->setSession($session);
}
/**
* @return \OC\Authentication\TwoFactorAuth\Manager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getTwoFactorAuthManager() {
- return $this->query(\OC\Authentication\TwoFactorAuth\Manager::class);
+ return $this->get(\OC\Authentication\TwoFactorAuth\Manager::class);
}
/**
* @return \OC\NavigationManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getNavigationManager() {
- return $this->query(INavigationManager::class);
+ return $this->get(INavigationManager::class);
}
/**
* @return \OCP\IConfig
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getConfig() {
- return $this->query(AllConfig::class);
+ return $this->get(AllConfig::class);
}
/**
* @return \OC\SystemConfig
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getSystemConfig() {
- return $this->query(SystemConfig::class);
+ return $this->get(SystemConfig::class);
}
/**
* Returns the app config manager
*
* @return IAppConfig
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getAppConfig() {
- return $this->query(IAppConfig::class);
+ return $this->get(IAppConfig::class);
}
/**
* @return IFactory
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getL10NFactory() {
- return $this->query(IFactory::class);
+ return $this->get(IFactory::class);
}
/**
@@ -1686,26 +1645,26 @@ class Server extends ServerContainer implements IServerContainer {
* @param string $app appid
* @param string $lang
* @return IL10N
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getL10N($app, $lang = null) {
- return $this->getL10NFactory()->get($app, $lang);
+ return $this->get(IFactory::class)->get($app, $lang);
}
/**
* @return IURLGenerator
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getURLGenerator() {
- return $this->query(IURLGenerator::class);
+ return $this->get(IURLGenerator::class);
}
/**
* @return AppFetcher
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getAppFetcher() {
- return $this->query(AppFetcher::class);
+ return $this->get(AppFetcher::class);
}
/**
@@ -1716,27 +1675,27 @@ class Server extends ServerContainer implements IServerContainer {
* @deprecated 8.1.0 use getMemCacheFactory to obtain a proper cache
*/
public function getCache() {
- return $this->query(ICache::class);
+ return $this->get(ICache::class);
}
/**
* Returns an \OCP\CacheFactory instance
*
* @return \OCP\ICacheFactory
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getMemCacheFactory() {
- return $this->query(Factory::class);
+ return $this->get(ICacheFactory::class);
}
/**
* Returns an \OC\RedisFactory instance
*
* @return \OC\RedisFactory
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getGetRedisFactory() {
- return $this->query('RedisFactory');
+ return $this->get('RedisFactory');
}
@@ -1744,151 +1703,135 @@ class Server extends ServerContainer implements IServerContainer {
* Returns the current session
*
* @return \OCP\IDBConnection
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getDatabaseConnection() {
- return $this->query(IDBConnection::class);
+ return $this->get(IDBConnection::class);
}
/**
* Returns the activity manager
*
* @return \OCP\Activity\IManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getActivityManager() {
- return $this->query(\OCP\Activity\IManager::class);
+ return $this->get(\OCP\Activity\IManager::class);
}
/**
* Returns an job list for controlling background jobs
*
* @return IJobList
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getJobList() {
- return $this->query(IJobList::class);
+ return $this->get(IJobList::class);
}
/**
* Returns a logger instance
*
* @return ILogger
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getLogger() {
- return $this->query(ILogger::class);
+ return $this->get(ILogger::class);
}
/**
* @return ILogFactory
* @throws \OCP\AppFramework\QueryException
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getLogFactory() {
- return $this->query(ILogFactory::class);
+ return $this->get(ILogFactory::class);
}
/**
* Returns a router for generating and matching urls
*
* @return IRouter
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getRouter() {
- return $this->query(IRouter::class);
+ return $this->get(IRouter::class);
}
/**
* Returns a search instance
*
* @return ISearch
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getSearch() {
- return $this->query(ISearch::class);
+ return $this->get(ISearch::class);
}
/**
* Returns a SecureRandom instance
*
* @return \OCP\Security\ISecureRandom
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getSecureRandom() {
- return $this->query(ISecureRandom::class);
+ return $this->get(ISecureRandom::class);
}
/**
* Returns a Crypto instance
*
* @return ICrypto
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getCrypto() {
- return $this->query(ICrypto::class);
+ return $this->get(ICrypto::class);
}
/**
* Returns a Hasher instance
*
* @return IHasher
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getHasher() {
- return $this->query(IHasher::class);
+ return $this->get(IHasher::class);
}
/**
* Returns a CredentialsManager instance
*
* @return ICredentialsManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getCredentialsManager() {
- return $this->query(ICredentialsManager::class);
+ return $this->get(ICredentialsManager::class);
}
/**
- * Get the certificate manager for the user
+ * Get the certificate manager
*
- * @param string $userId (optional) if not specified the current loggedin user is used, use null to get the system certificate manager
- * @return \OCP\ICertificateManager | null if $uid is null and no user is logged in
- * @deprecated
- */
- public function getCertificateManager($userId = '') {
- if ($userId === '') {
- $userSession = $this->getUserSession();
- $user = $userSession->getUser();
- if (is_null($user)) {
- return null;
- }
- $userId = $user->getUID();
- }
- return new CertificateManager(
- $userId,
- new View(),
- $this->getConfig(),
- $this->getLogger(),
- $this->getSecureRandom()
- );
+ * @return \OCP\ICertificateManager
+ */
+ public function getCertificateManager() {
+ return $this->get(ICertificateManager::class);
}
/**
* Returns an instance of the HTTP client service
*
* @return IClientService
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getHTTPClientService() {
- return $this->query(IClientService::class);
+ return $this->get(IClientService::class);
}
/**
* Create a new event source
*
* @return \OCP\IEventSource
- * @deprecated
+ * @deprecated 20.0.0
*/
public function createEventSource() {
return new \OC_EventSource();
@@ -1900,10 +1843,10 @@ class Server extends ServerContainer implements IServerContainer {
* The returned logger only logs data when debug mode is enabled
*
* @return IEventLogger
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getEventLogger() {
- return $this->query(IEventLogger::class);
+ return $this->get(IEventLogger::class);
}
/**
@@ -1912,47 +1855,47 @@ class Server extends ServerContainer implements IServerContainer {
* The returned logger only logs data when debug mode is enabled
*
* @return IQueryLogger
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getQueryLogger() {
- return $this->query(IQueryLogger::class);
+ return $this->get(IQueryLogger::class);
}
/**
* Get the manager for temporary files and folders
*
* @return \OCP\ITempManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getTempManager() {
- return $this->query(ITempManager::class);
+ return $this->get(ITempManager::class);
}
/**
* Get the app manager
*
* @return \OCP\App\IAppManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getAppManager() {
- return $this->query(IAppManager::class);
+ return $this->get(IAppManager::class);
}
/**
* Creates a new mailer
*
* @return IMailer
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getMailer() {
- return $this->query(IMailer::class);
+ return $this->get(IMailer::class);
}
/**
* Get the webroot
*
* @return string
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getWebRoot() {
return $this->webRoot;
@@ -1960,62 +1903,62 @@ class Server extends ServerContainer implements IServerContainer {
/**
* @return \OC\OCSClient
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getOcsClient() {
- return $this->query('OcsClient');
+ return $this->get('OcsClient');
}
/**
* @return IDateTimeZone
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getDateTimeZone() {
- return $this->query(IDateTimeZone::class);
+ return $this->get(IDateTimeZone::class);
}
/**
* @return IDateTimeFormatter
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getDateTimeFormatter() {
- return $this->query(IDateTimeFormatter::class);
+ return $this->get(IDateTimeFormatter::class);
}
/**
* @return IMountProviderCollection
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getMountProviderCollection() {
- return $this->query(IMountProviderCollection::class);
+ return $this->get(IMountProviderCollection::class);
}
/**
* Get the IniWrapper
*
* @return IniGetWrapper
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getIniWrapper() {
- return $this->query('IniWrapper');
+ return $this->get(IniGetWrapper::class);
}
/**
* @return \OCP\Command\IBus
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getCommandBus() {
- return $this->query('AsyncCommandBus');
+ return $this->get(IBus::class);
}
/**
* Get the trusted domain helper
*
* @return TrustedDomainHelper
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getTrustedDomainHelper() {
- return $this->query('TrustedDomainHelper');
+ return $this->get(TrustedDomainHelper::class);
}
/**
@@ -2023,56 +1966,56 @@ class Server extends ServerContainer implements IServerContainer {
*
* @return ILockingProvider
* @since 8.1.0
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getLockingProvider() {
- return $this->query(ILockingProvider::class);
+ return $this->get(ILockingProvider::class);
}
/**
* @return IMountManager
- * @deprecated
+ * @deprecated 20.0.0
**/
public function getMountManager() {
- return $this->query(IMountManager::class);
+ return $this->get(IMountManager::class);
}
/**
* @return IUserMountCache
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getUserMountCache() {
- return $this->query(IUserMountCache::class);
+ return $this->get(IUserMountCache::class);
}
/**
* Get the MimeTypeDetector
*
* @return IMimeTypeDetector
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getMimeTypeDetector() {
- return $this->query(IMimeTypeDetector::class);
+ return $this->get(IMimeTypeDetector::class);
}
/**
* Get the MimeTypeLoader
*
* @return IMimeTypeLoader
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getMimeTypeLoader() {
- return $this->query(IMimeTypeLoader::class);
+ return $this->get(IMimeTypeLoader::class);
}
/**
* Get the manager of all the capabilities
*
* @return CapabilitiesManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getCapabilitiesManager() {
- return $this->query(CapabilitiesManager::class);
+ return $this->get(CapabilitiesManager::class);
}
/**
@@ -2083,7 +2026,7 @@ class Server extends ServerContainer implements IServerContainer {
* @deprecated 18.0.0 use \OCP\EventDispatcher\IEventDispatcher
*/
public function getEventDispatcher() {
- return $this->query(\OC\EventDispatcher\SymfonyAdapter::class);
+ return $this->get(\OC\EventDispatcher\SymfonyAdapter::class);
}
/**
@@ -2091,230 +2034,230 @@ class Server extends ServerContainer implements IServerContainer {
*
* @return \OCP\Notification\IManager
* @since 8.2.0
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getNotificationManager() {
- return $this->query(\OCP\Notification\IManager::class);
+ return $this->get(\OCP\Notification\IManager::class);
}
/**
* @return ICommentsManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getCommentsManager() {
- return $this->query(ICommentsManager::class);
+ return $this->get(ICommentsManager::class);
}
/**
* @return \OCA\Theming\ThemingDefaults
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getThemingDefaults() {
- return $this->query('ThemingDefaults');
+ return $this->get('ThemingDefaults');
}
/**
* @return \OC\IntegrityCheck\Checker
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getIntegrityCodeChecker() {
- return $this->query('IntegrityCodeChecker');
+ return $this->get('IntegrityCodeChecker');
}
/**
* @return \OC\Session\CryptoWrapper
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getSessionCryptoWrapper() {
- return $this->query('CryptoWrapper');
+ return $this->get('CryptoWrapper');
}
/**
* @return CsrfTokenManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getCsrfTokenManager() {
- return $this->query(CsrfTokenManager::class);
+ return $this->get(CsrfTokenManager::class);
}
/**
* @return Throttler
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getBruteForceThrottler() {
- return $this->query(Throttler::class);
+ return $this->get(Throttler::class);
}
/**
* @return IContentSecurityPolicyManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getContentSecurityPolicyManager() {
- return $this->query(ContentSecurityPolicyManager::class);
+ return $this->get(ContentSecurityPolicyManager::class);
}
/**
* @return ContentSecurityPolicyNonceManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getContentSecurityPolicyNonceManager() {
- return $this->query('ContentSecurityPolicyNonceManager');
+ return $this->get(ContentSecurityPolicyNonceManager::class);
}
/**
* Not a public API as of 8.2, wait for 9.0
*
* @return \OCA\Files_External\Service\BackendService
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getStoragesBackendService() {
- return $this->query(BackendService::class);
+ return $this->get(BackendService::class);
}
/**
* Not a public API as of 8.2, wait for 9.0
*
* @return \OCA\Files_External\Service\GlobalStoragesService
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getGlobalStoragesService() {
- return $this->query(GlobalStoragesService::class);
+ return $this->get(GlobalStoragesService::class);
}
/**
* Not a public API as of 8.2, wait for 9.0
*
* @return \OCA\Files_External\Service\UserGlobalStoragesService
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getUserGlobalStoragesService() {
- return $this->query(UserGlobalStoragesService::class);
+ return $this->get(UserGlobalStoragesService::class);
}
/**
* Not a public API as of 8.2, wait for 9.0
*
* @return \OCA\Files_External\Service\UserStoragesService
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getUserStoragesService() {
- return $this->query(UserStoragesService::class);
+ return $this->get(UserStoragesService::class);
}
/**
* @return \OCP\Share\IManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getShareManager() {
- return $this->query(\OCP\Share\IManager::class);
+ return $this->get(\OCP\Share\IManager::class);
}
/**
* @return \OCP\Collaboration\Collaborators\ISearch
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getCollaboratorSearch() {
- return $this->query(\OCP\Collaboration\Collaborators\ISearch::class);
+ return $this->get(\OCP\Collaboration\Collaborators\ISearch::class);
}
/**
* @return \OCP\Collaboration\AutoComplete\IManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getAutoCompleteManager() {
- return $this->query(IManager::class);
+ return $this->get(IManager::class);
}
/**
* Returns the LDAP Provider
*
* @return \OCP\LDAP\ILDAPProvider
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getLDAPProvider() {
- return $this->query('LDAPProvider');
+ return $this->get('LDAPProvider');
}
/**
* @return \OCP\Settings\IManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getSettingsManager() {
- return $this->query('SettingsManager');
+ return $this->get(\OC\Settings\Manager::class);
}
/**
* @return \OCP\Files\IAppData
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getAppDataDir($app) {
/** @var \OC\Files\AppData\Factory $factory */
- $factory = $this->query(\OC\Files\AppData\Factory::class);
+ $factory = $this->get(\OC\Files\AppData\Factory::class);
return $factory->get($app);
}
/**
* @return \OCP\Lockdown\ILockdownManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getLockdownManager() {
- return $this->query('LockdownManager');
+ return $this->get('LockdownManager');
}
/**
* @return \OCP\Federation\ICloudIdManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getCloudIdManager() {
- return $this->query(ICloudIdManager::class);
+ return $this->get(ICloudIdManager::class);
}
/**
* @return \OCP\GlobalScale\IConfig
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getGlobalScaleConfig() {
- return $this->query(IConfig::class);
+ return $this->get(IConfig::class);
}
/**
* @return \OCP\Federation\ICloudFederationProviderManager
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getCloudFederationProviderManager() {
- return $this->query(ICloudFederationProviderManager::class);
+ return $this->get(ICloudFederationProviderManager::class);
}
/**
* @return \OCP\Remote\Api\IApiFactory
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getRemoteApiFactory() {
- return $this->query(IApiFactory::class);
+ return $this->get(IApiFactory::class);
}
/**
* @return \OCP\Federation\ICloudFederationFactory
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getCloudFederationFactory() {
- return $this->query(ICloudFederationFactory::class);
+ return $this->get(ICloudFederationFactory::class);
}
/**
* @return \OCP\Remote\IInstanceFactory
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getRemoteInstanceFactory() {
- return $this->query(IInstanceFactory::class);
+ return $this->get(IInstanceFactory::class);
}
/**
* @return IStorageFactory
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getStorageFactory() {
- return $this->query(IStorageFactory::class);
+ return $this->get(IStorageFactory::class);
}
/**
@@ -2322,10 +2265,10 @@ class Server extends ServerContainer implements IServerContainer {
*
* @return GeneratorHelper
* @since 17.0.0
- * @deprecated
+ * @deprecated 20.0.0
*/
public function getGeneratorHelper() {
- return $this->query(\OC\Preview\GeneratorHelper::class);
+ return $this->get(\OC\Preview\GeneratorHelper::class);
}
private function registerDeprecatedAlias(string $alias, string $target) {
@@ -2333,7 +2276,7 @@ class Server extends ServerContainer implements IServerContainer {
try {
/** @var ILogger $logger */
$logger = $container->get(ILogger::class);
- $logger->debug('The requested alias "' . $alias . '" is depreacted. Please request "' . $target . '" directly. This alias will be removed in a future Nextcloud version.', ['app' => 'serverDI']);
+ $logger->debug('The requested alias "' . $alias . '" is deprecated. Please request "' . $target . '" directly. This alias will be removed in a future Nextcloud version.', ['app' => 'serverDI']);
} catch (ContainerExceptionInterface $e) {
// Could not get logger. Continue
}
diff --git a/lib/private/ServerContainer.php b/lib/private/ServerContainer.php
index 72275ac1205..50592f36ada 100644
--- a/lib/private/ServerContainer.php
+++ b/lib/private/ServerContainer.php
@@ -133,6 +133,12 @@ class ServerContainer extends SimpleContainer {
public function query(string $name, bool $autoload = true) {
$name = $this->sanitizeName($name);
+ try {
+ return parent::query($name, false);
+ } catch (QueryException $e) {
+ // Continue with general autoloading then
+ }
+
// In case the service starts with OCA\ we try to find the service in
// the apps container first.
if (($appContainer = $this->getAppContainerForService($name)) !== null) {
diff --git a/lib/private/Session/CryptoSessionData.php b/lib/private/Session/CryptoSessionData.php
index fc7693b71b2..2b5b5c7b5e7 100644
--- a/lib/private/Session/CryptoSessionData.php
+++ b/lib/private/Session/CryptoSessionData.php
@@ -87,6 +87,7 @@ class CryptoSessionData implements \ArrayAccess, ISession {
);
} catch (\Exception $e) {
$this->sessionValues = [];
+ $this->regenerateId(true, false);
}
}
diff --git a/lib/private/Session/CryptoWrapper.php b/lib/private/Session/CryptoWrapper.php
index f7f26bb10d2..0f791a865d8 100644
--- a/lib/private/Session/CryptoWrapper.php
+++ b/lib/private/Session/CryptoWrapper.php
@@ -88,22 +88,18 @@ class CryptoWrapper {
$webRoot = '/';
}
- if (PHP_VERSION_ID < 70300) {
- setcookie(self::COOKIE_NAME, $this->passphrase, 0, $webRoot, '', $secureCookie, true);
- } else {
- setcookie(
- self::COOKIE_NAME,
- $this->passphrase,
- [
- 'expires' => 0,
- 'path' => $webRoot,
- 'domain' => '',
- 'secure' => $secureCookie,
- 'httponly' => true,
- 'samesite' => 'Lax',
- ]
- );
- }
+ setcookie(
+ self::COOKIE_NAME,
+ $this->passphrase,
+ [
+ 'expires' => 0,
+ 'path' => $webRoot,
+ 'domain' => '',
+ 'secure' => $secureCookie,
+ 'httponly' => true,
+ 'samesite' => 'Lax',
+ ]
+ );
}
}
}
diff --git a/lib/private/Session/Internal.php b/lib/private/Session/Internal.php
index ffe16537874..b7e1c7b7bf8 100644
--- a/lib/private/Session/Internal.php
+++ b/lib/private/Session/Internal.php
@@ -104,7 +104,7 @@ class Internal extends Session {
public function clear() {
$this->invoke('session_unset');
$this->regenerateId();
- $this->startSession();
+ $this->startSession(true);
$_SESSION = [];
}
@@ -213,11 +213,7 @@ class Internal extends Session {
}
}
- private function startSession() {
- if (PHP_VERSION_ID < 70300) {
- $this->invoke('session_start');
- } else {
- $this->invoke('session_start', [['cookie_samesite' => 'Lax']]);
- }
+ private function startSession(bool $silence = false) {
+ $this->invoke('session_start', [['cookie_samesite' => 'Lax']], $silence);
}
}
diff --git a/lib/private/Settings/Manager.php b/lib/private/Settings/Manager.php
index ac4f8f9342c..37a87a40725 100644
--- a/lib/private/Settings/Manager.php
+++ b/lib/private/Settings/Manager.php
@@ -38,8 +38,8 @@ use OCP\ILogger;
use OCP\IServerContainer;
use OCP\IURLGenerator;
use OCP\L10N\IFactory;
+use OCP\Settings\IIconSection;
use OCP\Settings\IManager;
-use OCP\Settings\ISection;
use OCP\Settings\ISettings;
use OCP\Settings\ISubAdminSettings;
@@ -80,7 +80,7 @@ class Manager implements IManager {
/**
* @param string $type 'admin' or 'personal'
- * @param string $section Class must implement OCP\Settings\ISection
+ * @param string $section Class must implement OCP\Settings\IIconSection
*
* @return void
*/
@@ -95,7 +95,7 @@ class Manager implements IManager {
/**
* @param string $type 'admin' or 'personal'
*
- * @return ISection[]
+ * @return IIconSection[]
*/
protected function getSections(string $type): array {
if (!isset($this->sections[$type])) {
@@ -106,24 +106,19 @@ class Manager implements IManager {
return $this->sections[$type];
}
- foreach ($this->sectionClasses[$type] as $index => $class) {
+ foreach (array_unique($this->sectionClasses[$type]) as $index => $class) {
try {
- /** @var ISection $section */
+ /** @var IIconSection $section */
$section = \OC::$server->query($class);
} catch (QueryException $e) {
$this->log->logException($e, ['level' => ILogger::INFO]);
continue;
}
- if (!$section instanceof ISection) {
- $this->log->logException(new \InvalidArgumentException('Invalid settings section registered'), ['level' => ILogger::INFO]);
- continue;
- }
-
$sectionID = $section->getID();
- if (isset($this->sections[$type][$sectionID])) {
- $this->log->logException(new \InvalidArgumentException('Section with the same ID already registered'), ['level' => ILogger::INFO]);
+ if ($sectionID !== 'connected-accounts' && isset($this->sections[$type][$sectionID])) {
+ $this->log->logException(new \InvalidArgumentException('Section with the same ID already registered: ' . $sectionID . ', class: ' . $class), ['level' => ILogger::INFO]);
continue;
}
@@ -212,7 +207,7 @@ class Manager implements IManager {
$appSections = $this->getSections('admin');
foreach ($appSections as $section) {
- /** @var ISection $section */
+ /** @var IIconSection $section */
if (!isset($sections[$section->getPriority()])) {
$sections[$section->getPriority()] = [];
}
@@ -261,14 +256,15 @@ class Manager implements IManager {
$sections = [];
$legacyForms = \OC_App::getForms('personal');
- if (!empty($legacyForms) && $this->hasLegacyPersonalSettingsToRender($legacyForms)) {
+ if ((!empty($legacyForms) && $this->hasLegacyPersonalSettingsToRender($legacyForms))
+ || count($this->getPersonalSettings('additional')) > 1) {
$sections[98] = [new Section('additional', $this->l->t('Additional settings'), 0, $this->url->imagePath('core', 'actions/settings-dark.svg'))];
}
$appSections = $this->getSections('personal');
foreach ($appSections as $section) {
- /** @var ISection $section */
+ /** @var IIconSection $section */
if (!isset($sections[$section->getPriority()])) {
$sections[$section->getPriority()] = [];
}
diff --git a/lib/private/Setup.php b/lib/private/Setup.php
index 775c2d0a952..873e82e55de 100644
--- a/lib/private/Setup.php
+++ b/lib/private/Setup.php
@@ -17,6 +17,7 @@
* @author Joas Schilling <coding@schilljs.com>
* @author Julius Härtl <jus@bitgrid.net>
* @author KB7777 <k.burkowski@gmail.com>
+ * @author Kevin Lanni <therealklanni@gmail.com>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author MichaIng <28480705+MichaIng@users.noreply.github.com>
* @author MichaIng <micha@dietpi.com>
@@ -27,7 +28,7 @@
* @author Serge Martin <edb@sigluy.net>
* @author Simounet <contact@simounet.net>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -503,7 +504,7 @@ class Setup {
$setupHelper = new \OC\Setup(
$config,
- \OC::$server->getIniWrapper(),
+ \OC::$server->get(IniGetWrapper::class),
\OC::$server->getL10N('lib'),
\OC::$server->query(Defaults::class),
\OC::$server->getLogger(),
@@ -543,7 +544,7 @@ class Setup {
$content .= "\n RewriteCond %{REQUEST_FILENAME} !/ocs-provider/";
$content .= "\n RewriteCond %{REQUEST_FILENAME} !/ocm-provider/";
$content .= "\n RewriteCond %{REQUEST_URI} !^/\\.well-known/(acme-challenge|pki-validation)/.*";
- $content .= "\n RewriteCond %{REQUEST_FILENAME} !/richdocumentscode/proxy.php$";
+ $content .= "\n RewriteCond %{REQUEST_FILENAME} !/richdocumentscode(_arm64)?/proxy.php$";
$content .= "\n RewriteRule . index.php [PT,E=PATH_INFO:$1]";
$content .= "\n RewriteBase " . $rewriteBase;
$content .= "\n <IfModule mod_env.c>";
diff --git a/lib/private/Setup/AbstractDatabase.php b/lib/private/Setup/AbstractDatabase.php
index b2c290eb874..8a9aed09f1b 100644
--- a/lib/private/Setup/AbstractDatabase.php
+++ b/lib/private/Setup/AbstractDatabase.php
@@ -90,10 +90,10 @@ abstract class AbstractDatabase {
$dbTablePrefix = isset($config['dbtableprefix']) ? $config['dbtableprefix'] : 'oc_';
$this->config->setValues([
- 'dbname' => $dbName,
- 'dbhost' => $dbHost,
+ 'dbname' => $dbName,
+ 'dbhost' => $dbHost,
'dbport' => $dbPort,
- 'dbtableprefix' => $dbTablePrefix,
+ 'dbtableprefix' => $dbTablePrefix,
]);
$this->dbUser = $dbUser;
@@ -150,6 +150,6 @@ abstract class AbstractDatabase {
return;
}
$ms = new MigrationService('core', \OC::$server->getDatabaseConnection());
- $ms->migrate();
+ $ms->migrate('latest', true);
}
}
diff --git a/lib/private/Setup/MySQL.php b/lib/private/Setup/MySQL.php
index 6a5513eab43..54542de72bf 100644
--- a/lib/private/Setup/MySQL.php
+++ b/lib/private/Setup/MySQL.php
@@ -9,10 +9,9 @@
* @author Joas Schilling <coding@schilljs.com>
* @author Michael Göhler <somebody.here@gmx.de>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Oliver Salzburg <oliver.salzburg@gmail.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -57,7 +56,7 @@ class MySQL extends AbstractDatabase {
$this->createDatabase($connection);
//fill the database if needed
- $query='select count(*) from information_schema.tables where table_schema=? AND table_name = ?';
+ $query = 'select count(*) from information_schema.tables where table_schema=? AND table_name = ?';
$connection->executeQuery($query, [$this->dbName, $this->tablePrefix.'users']);
$connection->close();
@@ -93,7 +92,7 @@ class MySQL extends AbstractDatabase {
try {
//this query will fail if there aren't the right permissions, ignore the error
- $query="GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `$name` . * TO '$user'";
+ $query = "GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON `$name` . * TO '$user'";
$connection->executeUpdate($query);
} catch (\Exception $ex) {
$this->logger->logException($ex, [
@@ -165,7 +164,7 @@ class MySQL extends AbstractDatabase {
$this->dbUser = $adminUser;
//create a random password so we don't need to store the admin password in the config file
- $this->dbPassword = $this->random->generate(30);
+ $this->dbPassword = $this->random->generate(30);
$this->createDBUser($connection);
diff --git a/lib/private/Setup/PostgreSQL.php b/lib/private/Setup/PostgreSQL.php
index 17ae991a1de..3d7a0b2a4b1 100644
--- a/lib/private/Setup/PostgreSQL.php
+++ b/lib/private/Setup/PostgreSQL.php
@@ -39,7 +39,6 @@ class PostgreSQL extends AbstractDatabase {
/**
* @param string $username
* @throws \OC\DatabaseSetupException
- * @suppress SqlInjectionChecker
*/
public function setupDatabase($username) {
try {
diff --git a/lib/private/Share/Constants.php b/lib/private/Share/Constants.php
index 2310859c5be..0a705366283 100644
--- a/lib/private/Share/Constants.php
+++ b/lib/private/Share/Constants.php
@@ -7,6 +7,7 @@
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Calviño Sánchez <danxuliu@gmail.com>
* @author Joas Schilling <coding@schilljs.com>
+ * @author Julius Härtl <jus@bitgrid.net>
* @author Morris Jobke <hey@morrisjobke.de>
*
* @license AGPL-3.0
@@ -70,6 +71,11 @@ class Constants {
*/
public const SHARE_TYPE_ROOM = 10;
// const SHARE_TYPE_USERROOM = 11; // Internal type used by RoomShareProvider
+ /**
+ * @deprecated 21.0.0 - use IShare::TYPE_DECK instead
+ */
+ public const SHARE_TYPE_DECK = 12;
+ // const SHARE_TYPE_DECK_USER = 13; // Internal type used by DeckShareProvider
public const FORMAT_NONE = -1;
public const FORMAT_STATUSES = -2;
diff --git a/lib/private/Share/Helper.php b/lib/private/Share/Helper.php
index 90dc3e957e9..6c92661fa76 100644
--- a/lib/private/Share/Helper.php
+++ b/lib/private/Share/Helper.php
@@ -7,10 +7,6 @@
* @author Joas Schilling <coding@schilljs.com>
* @author Miguel Prokop <miguel.prokop@vtu.com>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Robin McCorkell <robin@mccorkell.me.uk>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
*
* @license AGPL-3.0
*
@@ -30,132 +26,9 @@
namespace OC\Share;
-use OC\HintException;
-use OCP\Share\IShare;
-
class Helper extends \OC\Share\Constants {
/**
- * Generate a unique target for the item
- * @param string $itemType
- * @param string $itemSource
- * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
- * @param string $shareWith User or group the item is being shared with
- * @param string $uidOwner User that is the owner of shared item
- * @param string $suggestedTarget The suggested target originating from a reshare (optional)
- * @param int $groupParent The id of the parent group share (optional)
- * @throws \Exception
- * @return string Item target
- */
- public static function generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $suggestedTarget = null, $groupParent = null) {
- // FIXME: $uidOwner and $groupParent seems to be unused
- $backend = \OC\Share\Share::getBackend($itemType);
- if ($shareType === IShare::TYPE_LINK || $shareType === IShare::TYPE_REMOTE) {
- if (isset($suggestedTarget)) {
- return $suggestedTarget;
- }
- return $backend->generateTarget($itemSource, false);
- } else {
- if ($shareType == IShare::TYPE_USER) {
- // Share with is a user, so set share type to user and groups
- $shareType = self::$shareTypeUserAndGroups;
- }
-
- // Check if suggested target exists first
- if (!isset($suggestedTarget)) {
- $suggestedTarget = $itemSource;
- }
- if ($shareType == IShare::TYPE_GROUP) {
- $target = $backend->generateTarget($suggestedTarget, false);
- } else {
- $target = $backend->generateTarget($suggestedTarget, $shareWith);
- }
-
- return $target;
- }
- }
-
- /**
- * Delete all reshares and group share children of an item
- * @param int $parent Id of item to delete
- * @param bool $excludeParent If true, exclude the parent from the delete (optional)
- * @param string $uidOwner The user that the parent was shared with (optional)
- * @param int $newParent new parent for the childrens
- * @param bool $excludeGroupChildren exclude group children elements
- */
- public static function delete($parent, $excludeParent = false, $uidOwner = null, $newParent = null, $excludeGroupChildren = false) {
- $ids = [$parent];
- $deletedItems = [];
- $changeParent = [];
- $parents = [$parent];
- while (!empty($parents)) {
- $parents = "'".implode("','", $parents)."'";
- // Check the owner on the first search of reshares, useful for
- // finding and deleting the reshares by a single user of a group share
- $params = [];
- if (count($ids) == 1 && isset($uidOwner)) {
- // FIXME: don't concat $parents, use Docrine's PARAM_INT_ARRAY approach
- $queryString = 'SELECT `id`, `share_with`, `item_type`, `share_type`, ' .
- '`item_target`, `file_target`, `parent` ' .
- 'FROM `*PREFIX*share` ' .
- 'WHERE `parent` IN ('.$parents.') AND `uid_owner` = ? ';
- $params[] = $uidOwner;
- } else {
- $queryString = 'SELECT `id`, `share_with`, `item_type`, `share_type`, ' .
- '`item_target`, `file_target`, `parent`, `uid_owner` ' .
- 'FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.') ';
- }
- if ($excludeGroupChildren) {
- $queryString .= ' AND `share_type` != ?';
- $params[] = self::$shareTypeGroupUserUnique;
- }
- $query = \OC_DB::prepare($queryString);
- $result = $query->execute($params);
- // Reset parents array, only go through loop again if items are found
- $parents = [];
- while ($item = $result->fetchRow()) {
- $tmpItem = [
- 'id' => $item['id'],
- 'shareWith' => $item['share_with'],
- 'itemTarget' => $item['item_target'],
- 'itemType' => $item['item_type'],
- 'shareType' => (int)$item['share_type'],
- ];
- if (isset($item['file_target'])) {
- $tmpItem['fileTarget'] = $item['file_target'];
- }
- // if we have a new parent for the child we remember the child
- // to update the parent, if not we add it to the list of items
- // which should be deleted
- if ($newParent !== null) {
- $changeParent[] = $item['id'];
- } else {
- $deletedItems[] = $tmpItem;
- $ids[] = $item['id'];
- $parents[] = $item['id'];
- }
- }
- }
- if ($excludeParent) {
- unset($ids[0]);
- }
-
- if (!empty($changeParent)) {
- $idList = "'".implode("','", $changeParent)."'";
- $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `parent` = ? WHERE `id` IN ('.$idList.')');
- $query->execute([$newParent]);
- }
-
- if (!empty($ids)) {
- $idList = "'".implode("','", $ids)."'";
- $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `id` IN ('.$idList.')');
- $query->execute();
- }
-
- return $deletedItems;
- }
-
- /**
* get default expire settings defined by the admin
* @return array contains 'defaultExpireDateSet', 'enforceExpireDate', 'expireAfterDays'
*/
@@ -241,24 +114,6 @@ class Helper extends \OC\Share\Constants {
}
/**
- * split user and remote from federated cloud id
- *
- * @param string $id
- * @return string[]
- * @throws HintException
- */
- public static function splitUserRemote($id) {
- try {
- $cloudId = \OC::$server->getCloudIdManager()->resolveCloudId($id);
- return [$cloudId->getUser(), $cloudId->getRemote()];
- } catch (\InvalidArgumentException $e) {
- $l = \OC::$server->getL10N('core');
- $hint = $l->t('Invalid Federated Cloud ID');
- throw new HintException('Invalid Federated Cloud ID', $hint, 0, $e);
- }
- }
-
- /**
* check if two federated cloud IDs refer to the same user
*
* @param string $user1
diff --git a/lib/private/Share/Share.php b/lib/private/Share/Share.php
index aed233692ed..2d0d4f1cf87 100644
--- a/lib/private/Share/Share.php
+++ b/lib/private/Share/Share.php
@@ -5,18 +5,16 @@
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Bart Visscher <bartv@thisnet.nl>
* @author Bernhard Reiter <ockham@raz.or.at>
- * @author Bjoern Schiessle <bjoern@schiessle.org>
* @author Björn Schießle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Sebastian Döll <sebastian.doell@libasys.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
* @author Volkan Gezer <volkangezer@gmail.com>
*
* @license AGPL-3.0
@@ -104,8 +102,7 @@ class Share extends Constants {
* \OC\Share\Share::getItemsSharedWith('folder'); (apps/files_sharing/tests/UpdaterTest.php)
*/
public static function getItemsSharedWith() {
- return self::getItems('folder', null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, self::FORMAT_NONE,
- null, -1, false);
+ return self::getItems('folder', null, self::$shareTypeUserAndGroups, \OC_User::getUser());
}
/**
@@ -117,11 +114,12 @@ class Share extends Constants {
* @param int $limit Number of items to return (optional) Returns all by default
* @param boolean $includeCollections (optional)
* @return mixed Return depends on format
+ * @deprecated TESTS ONLY - this methods is only used by tests
+ * called like this:
+ * \OC\Share\Share::getItemsSharedWithUser('test', $shareWith); (tests/lib/Share/Backend.php)
*/
- public static function getItemsSharedWithUser($itemType, $user, $format = self::FORMAT_NONE,
- $parameters = null, $limit = -1, $includeCollections = false) {
- return self::getItems($itemType, null, self::$shareTypeUserAndGroups, $user, null, $format,
- $parameters, $limit, $includeCollections);
+ public static function getItemsSharedWithUser($itemType, $user) {
+ return self::getItems('test', null, self::$shareTypeUserAndGroups, $user);
}
/**
@@ -194,6 +192,7 @@ class Share extends Constants {
}
$shares[] = $row;
}
+ $result->closeCursor();
//if didn't found a result than let's look for a group share.
if (empty($shares) && $user !== null) {
@@ -233,23 +232,6 @@ class Share extends Constants {
}
/**
- * Get the item of item type shared with the current user by source
- * @param string $itemType
- * @param string $itemSource
- * @param int $format (optional) Format type must be defined by the backend
- * @param mixed $parameters
- * @param boolean $includeCollections
- * @param string $shareWith (optional) define against which user should be checked, default: current user
- * @return array
- */
- public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE,
- $parameters = null, $includeCollections = false, $shareWith = null) {
- $shareWith = ($shareWith === null) ? \OC_User::getUser() : $shareWith;
- return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, $format,
- $parameters, 1, $includeCollections, true);
- }
-
- /**
* Get the shared item of item type owned by the current user
* @param string $itemType
* @param string $itemSource
@@ -257,126 +239,14 @@ class Share extends Constants {
* @param mixed $parameters
* @param boolean $includeCollections
* @return mixed Return depends on format
+ *
+ * Refactoring notes:
+ * * defacto $parameters and $format is always the default and therefore is removed in the subsequent call
*/
public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE,
$parameters = null, $includeCollections = false) {
- return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format,
- $parameters, -1, $includeCollections);
- }
-
- /**
- * Unshare an item from a user, group, or delete a private link
- * @param string $itemType
- * @param string $itemSource
- * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK
- * @param string $shareWith User or group the item is being shared with
- * @param string $owner owner of the share, if null the current user is used
- * @return boolean true on success or false on failure
- */
- public static function unshare($itemType, $itemSource, $shareType, $shareWith, $owner = null) {
-
- // check if it is a valid itemType
- self::getBackend($itemType);
-
- $items = self::getItemSharedWithUser($itemType, $itemSource, $shareWith, $owner, $shareType);
-
- $toDelete = [];
- $newParent = null;
- $currentUser = $owner ? $owner : \OC_User::getUser();
- foreach ($items as $item) {
- // delete the item with the expected share_type and owner
- if ((int)$item['share_type'] === (int)$shareType && $item['uid_owner'] === $currentUser) {
- $toDelete = $item;
- // if there is more then one result we don't have to delete the children
- // but update their parent. For group shares the new parent should always be
- // the original group share and not the db entry with the unique name
- } elseif ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
- $newParent = $item['parent'];
- } else {
- $newParent = $item['id'];
- }
- }
-
- if (!empty($toDelete)) {
- self::unshareItem($toDelete, $newParent);
- return true;
- }
- return false;
- }
-
- /**
- * Checks whether a share has expired, calls unshareItem() if yes.
- * @param array $item Share data (usually database row)
- * @return boolean True if item was expired, false otherwise.
- */
- protected static function expireItem(array $item) {
- $result = false;
-
- // only use default expiration date for link shares
- if ((int) $item['share_type'] === IShare::TYPE_LINK) {
-
- // calculate expiration date
- if (!empty($item['expiration'])) {
- $userDefinedExpire = new \DateTime($item['expiration']);
- $expires = $userDefinedExpire->getTimestamp();
- } else {
- $expires = null;
- }
-
-
- // get default expiration settings
- $defaultSettings = Helper::getDefaultExpireSetting();
- $expires = Helper::calculateExpireDate($defaultSettings, $item['stime'], $expires);
-
-
- if (is_int($expires)) {
- $now = time();
- if ($now > $expires) {
- self::unshareItem($item);
- $result = true;
- }
- }
- }
- return $result;
- }
-
- /**
- * Unshares a share given a share data array
- * @param array $item Share data (usually database row)
- * @param int $newParent parent ID
- * @return null
- */
- protected static function unshareItem(array $item, $newParent = null) {
- $shareType = (int)$item['share_type'];
- $shareWith = null;
- if ($shareType !== IShare::TYPE_LINK) {
- $shareWith = $item['share_with'];
- }
-
- // Pass all the vars we have for now, they may be useful
- $hookParams = [
- 'id' => $item['id'],
- 'itemType' => $item['item_type'],
- 'itemSource' => $item['item_source'],
- 'shareType' => $shareType,
- 'shareWith' => $shareWith,
- 'itemParent' => $item['parent'],
- 'uidOwner' => $item['uid_owner'],
- ];
- if ($item['item_type'] === 'file' || $item['item_type'] === 'folder') {
- $hookParams['fileSource'] = $item['file_source'];
- $hookParams['fileTarget'] = $item['file_target'];
- }
-
- \OC_Hook::emit(\OCP\Share::class, 'pre_unshare', $hookParams);
- $deletedShares = Helper::delete($item['id'], false, null, $newParent);
- $deletedShares[] = $hookParams;
- $hookParams['deletedShares'] = $deletedShares;
- \OC_Hook::emit(\OCP\Share::class, 'post_unshare', $hookParams);
- if ((int)$item['share_type'] === IShare::TYPE_REMOTE && \OC::$server->getUserSession()->getUser()) {
- list(, $remote) = Helper::splitUserRemote($item['share_with']);
- self::sendRemoteUnshare($remote, $item['id'], $item['token']);
- }
+ return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), self::FORMAT_NONE,
+ null, -1, $includeCollections);
}
/**
@@ -471,10 +341,12 @@ class Share extends Constants {
*
* See public functions getItem(s)... for parameter usage
*
+ * Refactoring notes:
+ * * defacto $limit, $itemsShareWithBySource, $checkExpireDate, $parameters and $format is always the default and therefore is removed in the subsequent call
*/
public static function getItems($itemType, $item = null, $shareType = null, $shareWith = null,
$uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1,
- $includeCollections = false, $itemShareWithBySource = false, $checkExpireDate = true) {
+ $includeCollections = false, $itemShareWithBySource = false, $checkExpireDate = true) {
if (\OC::$server->getConfig()->getAppValue('core', 'shareapi_enabled', 'yes') != 'yes') {
return [];
}
@@ -578,7 +450,7 @@ class Share extends Constants {
$where .= ' AND';
}
// If looking for own shared items, check item_source else check item_target
- if (isset($uidOwner) || $itemShareWithBySource) {
+ if (isset($uidOwner)) {
// If item type is a file, file source needs to be checked in case the item was converted
if ($fileDependent) {
$where .= ' `file_source` = ?';
@@ -603,26 +475,10 @@ class Share extends Constants {
}
}
- if ($shareType == self::$shareTypeUserAndGroups && $limit === 1) {
- // Make sure the unique user target is returned if it exists,
- // unique targets should follow the group share in the database
- // If the limit is not 1, the filtering can be done later
- $where .= ' ORDER BY `*PREFIX*share`.`id` DESC';
- } else {
- $where .= ' ORDER BY `*PREFIX*share`.`id` ASC';
- }
+ $where .= ' ORDER BY `*PREFIX*share`.`id` ASC';
- if ($limit != -1 && !$includeCollections) {
- // The limit must be at least 3, because filtering needs to be done
- if ($limit < 3) {
- $queryLimit = 3;
- } else {
- $queryLimit = $limit;
- }
- } else {
- $queryLimit = null;
- }
- $select = self::createSelectStatement($format, $fileDependent, $uidOwner);
+ $queryLimit = null;
+ $select = self::createSelectStatement(self::FORMAT_NONE, $fileDependent, $uidOwner);
$root = strlen($root);
$query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit);
$result = $query->execute($queryArgs);
@@ -687,14 +543,20 @@ class Share extends Constants {
// Remove root from file source paths if retrieving own shared items
if (isset($uidOwner) && isset($row['path'])) {
if (isset($row['parent'])) {
- $query = \OC_DB::prepare('SELECT `file_target` FROM `*PREFIX*share` WHERE `id` = ?');
- $parentResult = $query->execute([$row['parent']]);
- if ($result === false) {
+ $query = \OC::$server->getDatabaseConnection()->getQueryBuilder();
+ $query->select('file_target')
+ ->from('share')
+ ->where($query->expr()->eq('id', $query->createNamedParameter($row['parent'])));
+
+ $parentResult = $query->execute();
+ $parentRow = $parentResult->fetch();
+ $parentResult->closeCursor();
+
+ if ($parentRow === false) {
\OCP\Util::writeLog('OCP\Share', 'Can\'t select parent: ' .
\OC_DB::getErrorMessage() . ', select=' . $select . ' where=' . $where,
ILogger::ERROR);
} else {
- $parentRow = $parentResult->fetchRow();
$tmpPath = $parentRow['file_target'];
// find the right position where the row path continues from the target path
$pos = strrpos($row['path'], $parentRow['file_target']);
@@ -720,11 +582,6 @@ class Share extends Constants {
}
}
- if ($checkExpireDate) {
- if (self::expireItem($row)) {
- continue;
- }
- }
// Check if resharing is allowed, if not remove share permission
if (isset($row['permissions']) && (!self::isResharingAllowed() | \OCP\Util::isSharingDisabledForUser())) {
$row['permissions'] &= ~\OCP\Constants::PERMISSION_SHARE;
@@ -764,14 +621,6 @@ class Share extends Constants {
if (!empty($items)) {
$collectionItems = [];
foreach ($items as &$row) {
- // Return only the item instead of a 2-dimensional array
- if ($limit == 1 && $row[$column] == $item && ($row['item_type'] == $itemType || $itemType == 'file')) {
- if ($format == self::FORMAT_NONE) {
- return $row;
- } else {
- break;
- }
- }
// Check if this is a collection of the requested item type
if ($includeCollections && $collectionTypes && $row['item_type'] !== 'folder' && in_array($row['item_type'], $collectionTypes)) {
if (($collectionBackend = self::getBackend($row['item_type']))
@@ -807,19 +656,7 @@ class Share extends Constants {
}
if (isset($item)) {
if ($childItem[$column] == $item) {
- // Return only the item instead of a 2-dimensional array
- if ($limit == 1) {
- if ($format == self::FORMAT_NONE) {
- return $childItem;
- } else {
- // Unset the items array and break out of both loops
- $items = [];
- $items[] = $childItem;
- break 2;
- }
- } else {
- $collectionItems[] = $childItem;
- }
+ $collectionItems[] = $childItem;
}
} else {
$collectionItems[] = $childItem;
@@ -855,7 +692,7 @@ class Share extends Constants {
return $item['share_type'] !== self::$shareTypeGroupUserUnique;
});
- return self::formatResult($items, $column, $backend, $format, $parameters);
+ return self::formatResult($items, $column, $backend);
} elseif ($includeCollections && $collectionTypes && in_array('folder', $collectionTypes)) {
// FIXME: Thats a dirty hack to improve file sharing performance,
// see github issue #10588 for more details
@@ -866,10 +703,7 @@ class Share extends Constants {
foreach ($sharedParents as $parent) {
$collectionItems[] = $parent;
}
- if ($limit === 1) {
- return reset($collectionItems);
- }
- return self::formatResult($collectionItems, $column, $backend, $format, $parameters);
+ return self::formatResult($collectionItems, $column, $backend);
}
return [];
@@ -1049,65 +883,6 @@ class Share extends Constants {
return $url;
}
- /**
- * try http post first with https and then with http as a fallback
- *
- * @param string $remoteDomain
- * @param string $urlSuffix
- * @param array $fields post parameters
- * @return array
- */
- private static function tryHttpPostToShareEndpoint($remoteDomain, $urlSuffix, array $fields) {
- $protocol = 'https://';
- $result = [
- 'success' => false,
- 'result' => '',
- ];
- $try = 0;
- $discoveryService = \OC::$server->query(\OCP\OCS\IDiscoveryService::class);
- while ($result['success'] === false && $try < 2) {
- $federationEndpoints = $discoveryService->discover($protocol . $remoteDomain, 'FEDERATED_SHARING');
- $endpoint = isset($federationEndpoints['share']) ? $federationEndpoints['share'] : '/ocs/v2.php/cloud/shares';
- $client = \OC::$server->getHTTPClientService()->newClient();
-
- try {
- $response = $client->post(
- $protocol . $remoteDomain . $endpoint . $urlSuffix . '?format=' . self::RESPONSE_FORMAT,
- [
- 'body' => $fields,
- 'connect_timeout' => 10,
- ]
- );
-
- $result = ['success' => true, 'result' => $response->getBody()];
- } catch (\Exception $e) {
- $result = ['success' => false, 'result' => $e->getMessage()];
- }
-
- $try++;
- $protocol = 'http://';
- }
-
- return $result;
- }
-
- /**
- * send server-to-server unshare to remote server
- *
- * @param string $remote url
- * @param int $id share id
- * @param string $token
- * @return bool
- */
- private static function sendRemoteUnshare($remote, $id, $token) {
- $url = rtrim($remote, '/');
- $fields = ['token' => $token, 'format' => 'json'];
- $url = self::removeProtocolFromUrl($url);
- $result = self::tryHttpPostToShareEndpoint($url, '/'.$id.'/unshare', $fields);
- $status = json_decode($result['result'], true);
-
- return ($result['success'] && ($status['ocs']['meta']['statuscode'] === 100 || $status['ocs']['meta']['statuscode'] === 200));
- }
/**
* @return int
diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php
index ecfe282dfbf..cf05e9bfbc3 100644
--- a/lib/private/Share20/DefaultShareProvider.php
+++ b/lib/private/Share20/DefaultShareProvider.php
@@ -2,6 +2,7 @@
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
+ * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Bjoern Schiessle <bjoern@schiessle.org>
* @author Björn Schießle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
@@ -14,7 +15,7 @@
* @author phisch <git@philippschaffrath.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -824,7 +825,7 @@ class DefaultShareProvider implements IShareProvider {
$pathSections = explode('/', $data['path'], 2);
// FIXME: would not detect rare md5'd home storage case properly
if ($pathSections[0] !== 'files'
- && in_array(explode(':', $data['storage_string_id'], 2)[0], ['home', 'object'])) {
+ && (strpos($data['storage_string_id'], 'home::') === 0 || strpos($data['storage_string_id'], 'object::user') === 0)) {
return false;
}
return true;
@@ -874,6 +875,11 @@ class DefaultShareProvider implements IShareProvider {
$cursor = $qb->execute();
while ($data = $cursor->fetch()) {
+ if ($data['fileid'] && $data['path'] === null) {
+ $data['path'] = (string) $data['path'];
+ $data['name'] = (string) $data['name'];
+ $data['checksum'] = (string) $data['checksum'];
+ }
if ($this->isAccessibleResult($data)) {
$shares[] = $this->createShare($data);
}
@@ -881,7 +887,7 @@ class DefaultShareProvider implements IShareProvider {
$cursor->closeCursor();
} elseif ($shareType === IShare::TYPE_GROUP) {
$user = $this->userManager->get($userId);
- $allGroups = $this->groupManager->getUserGroupIds($user);
+ $allGroups = ($user instanceof IUser) ? $this->groupManager->getUserGroupIds($user) : [];
/** @var Share[] $shares2 */
$shares2 = [];
@@ -1004,7 +1010,7 @@ class DefaultShareProvider implements IShareProvider {
->setShareType((int)$data['share_type'])
->setPermissions((int)$data['permissions'])
->setTarget($data['file_target'])
- ->setNote($data['note'])
+ ->setNote((string)$data['note'])
->setMailSend((bool)$data['mail_send'])
->setStatus((int)$data['accepted'])
->setLabel($data['label']);
diff --git a/lib/private/Share20/Hooks.php b/lib/private/Share20/Hooks.php
index 0e41e20a2cd..b596123bbe0 100644
--- a/lib/private/Share20/Hooks.php
+++ b/lib/private/Share20/Hooks.php
@@ -30,8 +30,4 @@ class Hooks {
public static function post_deleteGroup($arguments) {
\OC::$server->getShareManager()->groupDeleted($arguments['gid']);
}
-
- public static function post_removeFromGroupLDAP($arguments) {
- \OC::$server->getShareManager()->userDeletedFromGroup($arguments['uid'], $arguments['gid']);
- }
}
diff --git a/lib/private/Share20/LegacyHooks.php b/lib/private/Share20/LegacyHooks.php
index 285b45be809..f657b832b5a 100644
--- a/lib/private/Share20/LegacyHooks.php
+++ b/lib/private/Share20/LegacyHooks.php
@@ -3,6 +3,7 @@
* @copyright 2017, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Pauli Järvinen <pauli.jarvinen@gmail.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php
index 3b022f5951c..0787f6d32aa 100644
--- a/lib/private/Share20/Manager.php
+++ b/lib/private/Share20/Manager.php
@@ -7,6 +7,7 @@
* @author Björn Schießle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Calviño Sánchez <danxuliu@gmail.com>
+ * @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Jan-Christoph Borchardt <hey@jancborchardt.net>
* @author Joas Schilling <coding@schilljs.com>
* @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
@@ -18,8 +19,7 @@
* @author Pauli Järvinen <pauli.jarvinen@gmail.com>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thibault Coupin <thibault.coupin@gmail.com>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -43,6 +43,7 @@ use OC\Cache\CappedMemoryCache;
use OC\Files\Mount\MoveableMount;
use OC\HintException;
use OC\Share20\Exception\ProviderException;
+use OCA\Files_Sharing\ISharedStorage;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\File;
use OCP\Files\Folder;
@@ -247,6 +248,7 @@ class Manager implements IManager {
throw new \InvalidArgumentException('SharedWith is not a valid circle');
}
} elseif ($share->getShareType() === IShare::TYPE_ROOM) {
+ } elseif ($share->getShareType() === IShare::TYPE_DECK) {
} else {
// We can't handle other types yet
throw new \InvalidArgumentException('unknown share type');
@@ -286,8 +288,7 @@ class Manager implements IManager {
// Check if we actually have share permissions
if (!$share->getNode()->isShareable()) {
- $path = $userFolder->getRelativePath($share->getNode()->getPath());
- $message_t = $this->l->t('You are not allowed to share %s', [$path]);
+ $message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getName()]);
throw new GenericShareException($message_t, $message_t, 404);
}
@@ -299,10 +300,17 @@ class Manager implements IManager {
$isFederatedShare = $share->getNode()->getStorage()->instanceOfStorage('\OCA\Files_Sharing\External\Storage');
$permissions = 0;
- $userMounts = $userFolder->getById($share->getNode()->getId());
- $userMount = array_shift($userMounts);
- $mount = $userMount->getMountPoint();
if (!$isFederatedShare && $share->getNode()->getOwner() && $share->getNode()->getOwner()->getUID() !== $share->getSharedBy()) {
+ $userMounts = array_filter($userFolder->getById($share->getNode()->getId()), function ($mount) {
+ // We need to filter since there might be other mountpoints that contain the file
+ // e.g. if the user has access to the same external storage that the file is originating from
+ return $mount->getStorage()->instanceOfStorage(ISharedStorage::class);
+ });
+ $userMount = array_shift($userMounts);
+ if ($userMount === null) {
+ throw new GenericShareException('Could not get proper share mount for ' . $share->getNode()->getId() . '. Failing since else the next calls are called with null');
+ }
+ $mount = $userMount->getMountPoint();
// When it's a reshare use the parent share permissions as maximum
$userMountPointId = $mount->getStorageRootId();
$userMountPoints = $userFolder->getById($userMountPointId);
@@ -331,7 +339,7 @@ class Manager implements IManager {
* while we 'most likely' do have that on the storage.
*/
$permissions = $share->getNode()->getPermissions();
- if (!($mount instanceof MoveableMount)) {
+ if (!($share->getNode()->getMountPoint() instanceof MoveableMount)) {
$permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
}
}
@@ -401,9 +409,9 @@ class Manager implements IManager {
$expirationDate = new \DateTime();
$expirationDate->setTime(0,0,0);
- $days = (int)$this->config->getAppValue('core', 'internal_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
- if ($days > $this->shareApiLinkDefaultExpireDays()) {
- $days = $this->shareApiLinkDefaultExpireDays();
+ $days = (int)$this->config->getAppValue('core', 'internal_defaultExpDays', (string)$this->shareApiInternalDefaultExpireDays());
+ if ($days > $this->shareApiInternalDefaultExpireDays()) {
+ $days = $this->shareApiInternalDefaultExpireDays();
}
$expirationDate->add(new \DateInterval('P'.$days.'D'));
}
@@ -805,7 +813,8 @@ class Manager implements IManager {
$this->dispatcher->dispatchTyped(new Share\Events\ShareCreatedEvent($share));
- if ($share->getShareType() === IShare::TYPE_USER) {
+ if ($this->config->getSystemValueBool('sharing.enable_share_mail', true)
+ && $share->getShareType() === IShare::TYPE_USER) {
$mailSend = $share->getMailSend();
if ($mailSend === true) {
$user = $this->userManager->get($share->getSharedWith());
@@ -1386,7 +1395,7 @@ class Manager implements IManager {
*
* @return Share[]
*/
- public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
+ public function getSharesByPath(\OCP\Files\Node $path, $page = 0, $perPage = 50) {
return [];
}
@@ -1879,6 +1888,10 @@ class Manager implements IManager {
return true;
}
+ public function registerShareProvider(string $shareProviderClass): void {
+ $this->factory->registerProvider($shareProviderClass);
+ }
+
public function getAllShares(): iterable {
$providers = $this->factory->getAllProviders();
diff --git a/lib/private/Share20/ProviderFactory.php b/lib/private/Share20/ProviderFactory.php
index 0606fe9c849..643a4fac4c5 100644
--- a/lib/private/Share20/ProviderFactory.php
+++ b/lib/private/Share20/ProviderFactory.php
@@ -6,9 +6,12 @@
* @author Björn Schießle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Daniel Calviño Sánchez <danxuliu@gmail.com>
+ * @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Joas Schilling <coding@schilljs.com>
+ * @author Julius Härtl <jus@bitgrid.net>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Maxence Lange <maxence@nextcloud.com>
+ * @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
@@ -30,7 +33,6 @@
namespace OC\Share20;
-use OC\CapabilitiesManager;
use OC\Share20\Exception\ProviderException;
use OCA\FederatedFileSharing\AddressHandler;
use OCA\FederatedFileSharing\FederatedShareProvider;
@@ -43,6 +45,7 @@ use OCP\EventDispatcher\IEventDispatcher;
use OCP\IServerContainer;
use OCP\Share\IProviderFactory;
use OCP\Share\IShare;
+use OCP\Share\IShareProvider;
/**
* Class ProviderFactory
@@ -66,6 +69,10 @@ class ProviderFactory implements IProviderFactory {
/** @var \OCA\Talk\Share\RoomShareProvider */
private $roomShareProvider = null;
+ private $registeredShareProviders = [];
+
+ private $shareProviders = [];
+
/**
* IProviderFactory constructor.
*
@@ -75,6 +82,10 @@ class ProviderFactory implements IProviderFactory {
$this->serverContainer = $serverContainer;
}
+ public function registerProvider(string $shareProviderClass): void {
+ $this->registeredShareProviders[] = $shareProviderClass;
+ }
+
/**
* Create the default share provider.
*
@@ -184,7 +195,7 @@ class ProviderFactory implements IProviderFactory {
$settingsManager,
$this->serverContainer->query(Defaults::class),
$this->serverContainer->getHasher(),
- $this->serverContainer->query(CapabilitiesManager::class)
+ $this->serverContainer->get(IEventDispatcher::class)
);
}
@@ -256,6 +267,10 @@ class ProviderFactory implements IProviderFactory {
*/
public function getProvider($id) {
$provider = null;
+ if (isset($this->shareProviders[$id])) {
+ return $this->shareProviders[$id];
+ }
+
if ($id === 'ocinternal') {
$provider = $this->defaultShareProvider();
} elseif ($id === 'ocFederatedSharing') {
@@ -268,6 +283,16 @@ class ProviderFactory implements IProviderFactory {
$provider = $this->getRoomShareProvider();
}
+ foreach ($this->registeredShareProviders as $shareProvider) {
+ /** @var IShareProvider $instance */
+ $instance = $this->serverContainer->get($shareProvider);
+ $this->shareProviders[$instance->identifier()] = $instance;
+ }
+
+ if (isset($this->shareProviders[$id])) {
+ $provider = $this->shareProviders[$id];
+ }
+
if ($provider === null) {
throw new ProviderException('No provider with id .' . $id . ' found.');
}
@@ -294,6 +319,8 @@ class ProviderFactory implements IProviderFactory {
$provider = $this->getShareByCircleProvider();
} elseif ($shareType === IShare::TYPE_ROOM) {
$provider = $this->getRoomShareProvider();
+ } elseif ($shareType === IShare::TYPE_DECK) {
+ $provider = $this->getProvider('deck');
}
@@ -319,6 +346,17 @@ class ProviderFactory implements IProviderFactory {
$shares[] = $roomShare;
}
+ foreach ($this->registeredShareProviders as $shareProvider) {
+ /** @var IShareProvider $instance */
+ $instance = $this->serverContainer->get($shareProvider);
+ if (!isset($this->shareProviders[$instance->identifier()])) {
+ $this->shareProviders[$instance->identifier()] = $instance;
+ }
+ $shares[] = $this->shareProviders[$instance->identifier()];
+ }
+
+
+
return $shares;
}
}
diff --git a/lib/private/Share20/UserRemovedListener.php b/lib/private/Share20/UserRemovedListener.php
index 06ac52c05d4..0a81d049494 100644
--- a/lib/private/Share20/UserRemovedListener.php
+++ b/lib/private/Share20/UserRemovedListener.php
@@ -1,9 +1,12 @@
<?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
@@ -17,7 +20,7 @@ declare(strict_types=1);
* 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/>.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
diff --git a/lib/private/Streamer.php b/lib/private/Streamer.php
index a05f77f3cbd..0e3018f77b7 100644
--- a/lib/private/Streamer.php
+++ b/lib/private/Streamer.php
@@ -76,8 +76,12 @@ class Streamer {
* would still be possible to create an invalid zip32 file (for example,
* a zip file from files smaller than 4GB with a central directory
* larger than 4GiB), but it should not happen in the real world.
+ *
+ * We also have to check for a size above 0. As negative sizes could be
+ * from not fully scanned external storages. And then things fall apart
+ * if somebody tries to package to much.
*/
- if ($size < 4 * 1000 * 1000 * 1000 && $numberOfFiles < 65536) {
+ if ($size > 0 && $size < 4 * 1000 * 1000 * 1000 && $numberOfFiles < 65536) {
$this->streamerInstance = new ZipStreamer(['zip64' => false]);
} elseif ($request->isUserAgent($this->preferTarFor)) {
$this->streamerInstance = new TarStreamer();
diff --git a/lib/private/SubAdmin.php b/lib/private/SubAdmin.php
index 890bcf67b3b..a8769f28023 100644
--- a/lib/private/SubAdmin.php
+++ b/lib/private/SubAdmin.php
@@ -6,8 +6,10 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Georg Ehrke <oc.list@georgehrke.com>
+ * @author Joas Schilling <coding@schilljs.com>
* @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
* @author Lukas Reschke <lukas@statuscode.ch>
+ * @author Mikael Hammarin <mikael@try2.se>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
@@ -30,6 +32,9 @@
namespace OC;
use OC\Hooks\PublicEmitter;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Group\Events\SubAdminAddedEvent;
+use OCP\Group\Events\SubAdminRemovedEvent;
use OCP\Group\ISubAdmin;
use OCP\IDBConnection;
use OCP\IGroup;
@@ -48,6 +53,9 @@ class SubAdmin extends PublicEmitter implements ISubAdmin {
/** @var IDBConnection */
private $dbConn;
+ /** @var IEventDispatcher */
+ private $eventDispatcher;
+
/**
* @param IUserManager $userManager
* @param IGroupManager $groupManager
@@ -55,10 +63,12 @@ class SubAdmin extends PublicEmitter implements ISubAdmin {
*/
public function __construct(IUserManager $userManager,
IGroupManager $groupManager,
- IDBConnection $dbConn) {
+ IDBConnection $dbConn,
+ IEventDispatcher $eventDispatcher) {
$this->userManager = $userManager;
$this->groupManager = $groupManager;
$this->dbConn = $dbConn;
+ $this->eventDispatcher = $eventDispatcher;
$this->userManager->listen('\OC\User', 'postDelete', function ($user) {
$this->post_deleteUser($user);
@@ -83,8 +93,10 @@ class SubAdmin extends PublicEmitter implements ISubAdmin {
])
->execute();
+ /** @deprecated 21.0.0 - use type SubAdminAddedEvent instead */
$this->emit('\OC\SubAdmin', 'postCreateSubAdmin', [$user, $group]);
- \OC_Hook::emit("OC_SubAdmin", "post_createSubAdmin", ["gid" => $group->getGID()]);
+ $event = new SubAdminAddedEvent($group, $user);
+ $this->eventDispatcher->dispatchTyped($event);
}
/**
@@ -100,8 +112,10 @@ class SubAdmin extends PublicEmitter implements ISubAdmin {
->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
->execute();
+ /** @deprecated 21.0.0 - use type SubAdminRemovedEvent instead */
$this->emit('\OC\SubAdmin', 'postDeleteSubAdmin', [$user, $group]);
- \OC_Hook::emit("OC_SubAdmin", "post_deleteSubAdmin", ["gid" => $group->getGID()]);
+ $event = new SubAdminRemovedEvent($group, $user);
+ $this->eventDispatcher->dispatchTyped($event);
}
/**
@@ -198,7 +212,7 @@ class SubAdmin extends PublicEmitter implements ISubAdmin {
$group = $this->groupManager->get($row['gid']);
if (!is_null($user) && !is_null($group)) {
$subadmins[] = [
- 'user' => $user,
+ 'user' => $user,
'group' => $group
];
}
@@ -226,7 +240,7 @@ class SubAdmin extends PublicEmitter implements ISubAdmin {
->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
->execute();
- $fetch = $result->fetch();
+ $fetch = $result->fetch();
$result->closeCursor();
$result = !empty($fetch) ? true : false;
diff --git a/lib/private/Support/Subscription/Registry.php b/lib/private/Support/Subscription/Registry.php
index 9f5d78bebb2..72bae2adc8e 100644
--- a/lib/private/Support/Subscription/Registry.php
+++ b/lib/private/Support/Subscription/Registry.php
@@ -7,6 +7,7 @@ declare(strict_types=1);
*
* @author Julius Härtl <jus@bitgrid.net>
* @author Morris Jobke <hey@morrisjobke.de>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
*
@@ -27,13 +28,18 @@ declare(strict_types=1);
namespace OC\Support\Subscription;
+use OC\User\Backend;
use OCP\AppFramework\QueryException;
use OCP\IConfig;
+use OCP\IGroupManager;
use OCP\IServerContainer;
+use OCP\IUserManager;
+use OCP\Notification\IManager;
use OCP\Support\Subscription\Exception\AlreadyRegisteredException;
use OCP\Support\Subscription\IRegistry;
use OCP\Support\Subscription\ISubscription;
use OCP\Support\Subscription\ISupportedApps;
+use Psr\Log\LoggerInterface;
class Registry implements IRegistry {
@@ -48,10 +54,27 @@ class Registry implements IRegistry {
/** @var IServerContainer */
private $container;
-
- public function __construct(IConfig $config, IServerContainer $container) {
+ /** @var IUserManager */
+ private $userManager;
+ /** @var IGroupManager */
+ private $groupManager;
+ /** @var LoggerInterface */
+ private $logger;
+ /** @var IManager */
+ private $notificationManager;
+
+ public function __construct(IConfig $config,
+ IServerContainer $container,
+ IUserManager $userManager,
+ IGroupManager $groupManager,
+ LoggerInterface $logger,
+ IManager $notificationManager) {
$this->config = $config;
$this->container = $container;
+ $this->userManager = $userManager;
+ $this->groupManager = $groupManager;
+ $this->logger = $logger;
+ $this->notificationManager = $notificationManager;
}
private function getSubscription(): ?ISubscription {
@@ -126,9 +149,87 @@ class Registry implements IRegistry {
* @since 17.0.0
*/
public function delegateHasExtendedSupport(): bool {
- if ($this->getSubscription() instanceof ISubscription && method_exists($this->subscription, 'hasExtendedSupport')) {
+ if ($this->getSubscription() instanceof ISubscription) {
return $this->getSubscription()->hasExtendedSupport();
}
return false;
}
+
+
+ /**
+ * Indicates if a hard user limit is reached and no new users should be created
+ *
+ * @since 21.0.0
+ */
+ public function delegateIsHardUserLimitReached(): bool {
+ $subscription = $this->getSubscription();
+ if ($subscription instanceof ISubscription &&
+ $subscription->hasValidSubscription()) {
+ $userLimitReached = $subscription->isHardUserLimitReached();
+ if ($userLimitReached) {
+ $this->notifyAboutReachedUserLimit();
+ }
+ return $userLimitReached;
+ }
+
+ $isOneClickInstance = $this->config->getSystemValueBool('one-click-instance', false);
+
+ if (!$isOneClickInstance) {
+ return false;
+ }
+
+ $userCount = $this->getUserCount();
+ $hardUserLimit = $this->config->getSystemValue('one-click-instance.user-limit', 50);
+
+ $userLimitReached = $userCount >= $hardUserLimit;
+ if ($userLimitReached) {
+ $this->notifyAboutReachedUserLimit();
+ }
+ return $userLimitReached;
+ }
+
+ private function getUserCount(): int {
+ $userCount = 0;
+ $backends = $this->userManager->getBackends();
+ foreach ($backends as $backend) {
+ if ($backend->implementsActions(Backend::COUNT_USERS)) {
+ $backendUsers = $backend->countUsers();
+ if ($backendUsers !== false) {
+ $userCount += $backendUsers;
+ } else {
+ // TODO what if the user count can't be determined?
+ $this->logger->warning('Can not determine user count for ' . get_class($backend), ['app' => 'lib']);
+ }
+ }
+ }
+
+ $disabledUsers = $this->config->getUsersForUserValue('core', 'enabled', 'false');
+ $disabledUsersCount = count($disabledUsers);
+ $userCount = $userCount - $disabledUsersCount;
+
+ if ($userCount < 0) {
+ $userCount = 0;
+
+ // this should never happen
+ $this->logger->warning("Total user count was negative (users: $userCount, disabled: $disabledUsersCount)", ['app' => 'lib']);
+ }
+
+ return $userCount;
+ }
+
+ private function notifyAboutReachedUserLimit() {
+ $admins = $this->groupManager->get('admin')->getUsers();
+ foreach ($admins as $admin) {
+ $notification = $this->notificationManager->createNotification();
+
+ $notification->setApp('core')
+ ->setUser($admin->getUID())
+ ->setDateTime(new \DateTime())
+ ->setObject('user_limit_reached', '1')
+ ->setSubject('user_limit_reached');
+ $this->notificationManager->notify($notification);
+ }
+
+ $this->logger->warning('The user limit was reached and the new user was not created', ['app' => 'lib']);
+ }
}
diff --git a/lib/private/SystemTag/ManagerFactory.php b/lib/private/SystemTag/ManagerFactory.php
index a75a090304e..f894a8fe3ed 100644
--- a/lib/private/SystemTag/ManagerFactory.php
+++ b/lib/private/SystemTag/ManagerFactory.php
@@ -7,7 +7,7 @@ declare(strict_types=1);
*
* @author Joas Schilling <coding@schilljs.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/SystemTag/SystemTag.php b/lib/private/SystemTag/SystemTag.php
index 14ccaffdd4e..8a48e048d39 100644
--- a/lib/private/SystemTag/SystemTag.php
+++ b/lib/private/SystemTag/SystemTag.php
@@ -7,7 +7,7 @@ declare(strict_types=1);
*
* @author Joas Schilling <coding@schilljs.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/SystemTag/SystemTagManager.php b/lib/private/SystemTag/SystemTagManager.php
index 5941400883b..0f700a83490 100644
--- a/lib/private/SystemTag/SystemTagManager.php
+++ b/lib/private/SystemTag/SystemTagManager.php
@@ -8,8 +8,9 @@ declare(strict_types=1);
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -230,7 +231,7 @@ class SystemTagManager implements ISystemTagManager {
/**
* {@inheritdoc}
*/
- public function updateTag(string $tagId, string $tagName, bool $userVisible, bool $userAssignable) {
+ public function updateTag(string $tagId, string $newName, bool $userVisible, bool $userAssignable) {
try {
$tags = $this->getTagsByIds($tagId);
} catch (TagNotFoundException $e) {
@@ -242,7 +243,7 @@ class SystemTagManager implements ISystemTagManager {
$beforeUpdate = array_shift($tags);
$afterUpdate = new SystemTag(
$tagId,
- $tagName,
+ $newName,
$userVisible,
$userAssignable
);
@@ -253,7 +254,7 @@ class SystemTagManager implements ISystemTagManager {
->set('visibility', $query->createParameter('visibility'))
->set('editable', $query->createParameter('editable'))
->where($query->expr()->eq('id', $query->createParameter('tagid')))
- ->setParameter('name', $tagName)
+ ->setParameter('name', $newName)
->setParameter('visibility', $userVisible ? 1 : 0)
->setParameter('editable', $userAssignable ? 1 : 0)
->setParameter('tagid', $tagId);
@@ -266,7 +267,7 @@ class SystemTagManager implements ISystemTagManager {
}
} catch (UniqueConstraintViolationException $e) {
throw new TagAlreadyExistsException(
- 'Tag ("' . $tagName . '", '. $userVisible . ', ' . $userAssignable . ') already exists',
+ 'Tag ("' . $newName . '", '. $userVisible . ', ' . $userAssignable . ') already exists',
0,
$e
);
diff --git a/lib/private/SystemTag/SystemTagObjectMapper.php b/lib/private/SystemTag/SystemTagObjectMapper.php
index 5403321e582..a13afa8c79b 100644
--- a/lib/private/SystemTag/SystemTagObjectMapper.php
+++ b/lib/private/SystemTag/SystemTagObjectMapper.php
@@ -8,7 +8,7 @@ declare(strict_types=1);
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/TagManager.php b/lib/private/TagManager.php
index 96786c58a1a..f283a5d5ada 100644
--- a/lib/private/TagManager.php
+++ b/lib/private/TagManager.php
@@ -4,9 +4,10 @@
*
* @author Bernhard Reiter <ockham@raz.or.at>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -38,32 +39,27 @@
namespace OC;
use OC\Tagging\TagMapper;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+use OCP\ITagManager;
+use OCP\ITags;
+use OCP\IUserSession;
-class TagManager implements \OCP\ITagManager {
+class TagManager implements ITagManager {
- /**
- * User session
- *
- * @var \OCP\IUserSession
- */
+ /** @var TagMapper */
+ private $mapper;
+
+ /** @var IUserSession */
private $userSession;
- /**
- * TagMapper
- *
- * @var TagMapper
- */
- private $mapper;
+ /** @var IDBConnection */
+ private $connection;
- /**
- * Constructor.
- *
- * @param TagMapper $mapper Instance of the TagMapper abstraction layer.
- * @param \OCP\IUserSession $userSession the user session
- */
- public function __construct(TagMapper $mapper, \OCP\IUserSession $userSession) {
+ public function __construct(TagMapper $mapper, IUserSession $userSession, IDBConnection $connection) {
$this->mapper = $mapper;
$this->userSession = $userSession;
+ $this->connection = $connection;
}
/**
@@ -90,4 +86,27 @@ class TagManager implements \OCP\ITagManager {
}
return new Tags($this->mapper, $userId, $type, $defaultTags);
}
+
+ /**
+ * Get all users who favorited an object
+ *
+ * @param string $objectType
+ * @param int $objectId
+ * @return array
+ */
+ public function getUsersFavoritingObject(string $objectType, int $objectId): array {
+ $query = $this->connection->getQueryBuilder();
+ $query->select('uid')
+ ->from('vcategory_to_object', 'o')
+ ->innerJoin('o', 'vcategory', 'c', $query->expr()->eq('o.categoryid', 'c.id'))
+ ->where($query->expr()->eq('objid', $query->createNamedParameter($objectId, IQueryBuilder::PARAM_INT)))
+ ->andWhere($query->expr()->eq('c.type', $query->createNamedParameter($objectType)))
+ ->andWhere($query->expr()->eq('c.category', $query->createNamedParameter(ITags::TAG_FAVORITE)));
+
+ $result = $query->execute();
+ $users = $result->fetchAll(\PDO::FETCH_COLUMN);
+ $result->closeCursor();
+
+ return $users;
+ }
}
diff --git a/lib/private/Tagging/TagMapper.php b/lib/private/Tagging/TagMapper.php
index d9c8a7fb470..cf1d93e3d26 100644
--- a/lib/private/Tagging/TagMapper.php
+++ b/lib/private/Tagging/TagMapper.php
@@ -57,7 +57,7 @@ class TagMapper extends Mapper {
}
$sql = 'SELECT `id`, `uid`, `type`, `category` FROM `' . $this->getTableName() . '` '
- . 'WHERE `uid` IN (' . str_repeat('?,', count($owners)-1) . '?) AND `type` = ? ORDER BY `category`';
+ . 'WHERE `uid` IN (' . str_repeat('?,', count($owners) - 1) . '?) AND `type` = ? ORDER BY `category`';
return $this->findEntities($sql, array_merge($owners, [$type]));
}
diff --git a/lib/private/Tags.php b/lib/private/Tags.php
index 3fc66c69d6c..720e9dd5d7d 100644
--- a/lib/private/Tags.php
+++ b/lib/private/Tags.php
@@ -12,7 +12,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -285,6 +285,7 @@ class Tags implements ITags {
$stmt = \OC_DB::prepare($sql);
$result = $stmt->execute([$tagId]);
if ($result === null) {
+ $stmt->closeCursor();
\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
return false;
}
@@ -301,6 +302,7 @@ class Tags implements ITags {
while ($row = $result->fetchRow()) {
$ids[] = (int)$row['objid'];
}
+ $result->closeCursor();
}
return $ids;
@@ -417,7 +419,7 @@ class Tags implements ITags {
* @param int|null $id int Optional object id to add to this|these tag(s)
* @return bool Returns false on error.
*/
- public function addMultiple($names, $sync=false, $id = null) {
+ public function addMultiple($names, $sync = false, $id = null) {
if (!is_array($names)) {
$names = [$names];
}
@@ -538,6 +540,7 @@ class Tags implements ITags {
]);
}
}
+ $result->closeCursor();
} catch (\Exception $e) {
\OC::$server->getLogger()->logException($e, [
'message' => __METHOD__,
@@ -576,7 +579,7 @@ class Tags implements ITags {
$updates = $ids;
try {
$query = 'DELETE FROM `' . self::RELATION_TABLE . '` ';
- $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) ';
+ $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids) - 1) . '?) ';
$query .= 'AND `type`= ?';
$updates[] = $this->type;
$stmt = \OC_DB::prepare($query);
@@ -658,7 +661,7 @@ class Tags implements ITags {
if (!$this->hasTag($tag)) {
$this->add($tag);
}
- $tagId = $this->getTagId($tag);
+ $tagId = $this->getTagId($tag);
} else {
$tagId = $tag;
}
@@ -694,7 +697,7 @@ class Tags implements ITags {
\OCP\Util::writeLog('core', __METHOD__.', Tag name is empty', ILogger::DEBUG);
return false;
}
- $tagId = $this->getTagId($tag);
+ $tagId = $this->getTagId($tag);
} else {
$tagId = $tag;
}
@@ -774,7 +777,7 @@ class Tags implements ITags {
}
// case-insensitive array_search
- protected function array_searchi($needle, $haystack, $mem='getName') {
+ protected function array_searchi($needle, $haystack, $mem = 'getName') {
if (!is_array($haystack)) {
return false;
}
@@ -830,10 +833,10 @@ class Tags implements ITags {
*/
private function tagMap(Tag $tag) {
return [
- 'id' => $tag->getId(),
- 'name' => $tag->getName(),
+ 'id' => $tag->getId(),
+ 'name' => $tag->getName(),
'owner' => $tag->getOwner(),
- 'type' => $tag->getType()
+ 'type' => $tag->getType()
];
}
}
diff --git a/lib/private/TempManager.php b/lib/private/TempManager.php
index 49d4ee94cf6..e49955622c8 100644
--- a/lib/private/TempManager.php
+++ b/lib/private/TempManager.php
@@ -3,6 +3,7 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Lars <winnetou+github@catolic.de>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Martin Mattel <martin.mattel@diemattels.at>
@@ -31,30 +32,30 @@
namespace OC;
+use bantu\IniGetWrapper\IniGetWrapper;
use OCP\IConfig;
-use OCP\ILogger;
use OCP\ITempManager;
+use Psr\Log\LoggerInterface;
class TempManager implements ITempManager {
/** @var string[] Current temporary files and folders, used for cleanup */
protected $current = [];
/** @var string i.e. /tmp on linux systems */
protected $tmpBaseDir;
- /** @var ILogger */
+ /** @var LoggerInterface */
protected $log;
/** @var IConfig */
protected $config;
+ /** @var IniGetWrapper */
+ protected $iniGetWrapper;
/** Prefix */
public const TMP_PREFIX = 'oc_tmp_';
- /**
- * @param \OCP\ILogger $logger
- * @param \OCP\IConfig $config
- */
- public function __construct(ILogger $logger, IConfig $config) {
+ public function __construct(LoggerInterface $logger, IConfig $config, IniGetWrapper $iniGetWrapper) {
$this->log = $logger;
$this->config = $config;
+ $this->iniGetWrapper = $iniGetWrapper;
$this->tmpBaseDir = $this->getTempBaseDir();
}
@@ -218,7 +219,7 @@ class TempManager implements ITempManager {
if ($temp = $this->config->getSystemValue('tempdirectory', null)) {
$directories[] = $temp;
}
- if ($temp = \OC::$server->getIniWrapper()->get('upload_tmp_dir')) {
+ if ($temp = $this->iniGetWrapper->get('upload_tmp_dir')) {
$directories[] = $temp;
}
if ($temp = getenv('TMP')) {
diff --git a/lib/private/Template/Base.php b/lib/private/Template/Base.php
index 04d03b6e6f5..c95958ceea1 100644
--- a/lib/private/Template/Base.php
+++ b/lib/private/Template/Base.php
@@ -4,7 +4,6 @@
*
* @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <bjoern@schiessle.org>
- * @author Christopher Schäpers <kondou@ts.unde.re>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Julius Härtl <jus@bitgrid.net>
@@ -31,6 +30,7 @@
namespace OC\Template;
use OCP\Defaults;
+use Throwable;
class Base {
private $template; // The template
@@ -92,7 +92,7 @@ class Base {
/**
* Assign variables
* @param string $key key
- * @param array|bool|integer|string $value value
+ * @param array|bool|integer|string|Throwable $value value
* @return bool
*
* This function assigns a variable. It can be accessed via $_[$key] in
diff --git a/lib/private/Template/CSSResourceLocator.php b/lib/private/Template/CSSResourceLocator.php
index 750d33fd726..7b33e181f76 100644
--- a/lib/private/Template/CSSResourceLocator.php
+++ b/lib/private/Template/CSSResourceLocator.php
@@ -66,7 +66,7 @@ class CSSResourceLocator extends ResourceLocator {
) {
return;
}
- $style = substr($style, strpos($style, '/')+1);
+ $style = substr($style, strpos($style, '/') + 1);
$app_path = \OC_App::getAppPath($app);
$app_url = \OC_App::getAppWebPath($app);
@@ -109,7 +109,7 @@ class CSSResourceLocator extends ResourceLocator {
if (is_file($root.'/'.$file)) {
if ($this->scssCacher !== null) {
if ($this->scssCacher->process($root, $file, $app)) {
- $this->append($root, $this->scssCacher->getCachedSCSS($app, $file), \OC::$WEBROOT, true, true);
+ $this->append($this->serverroot, $this->scssCacher->getCachedSCSS($app, $file), \OC::$WEBROOT, true, true);
return true;
} else {
$this->logger->warning('Failed to compile and/or save '.$root.'/'.$file, ['app' => 'core']);
@@ -145,7 +145,7 @@ class CSSResourceLocator extends ResourceLocator {
}
}
- $this->resources[] = [$webRoot? : \OC::$WEBROOT, $webRoot, $file];
+ $this->resources[] = [$webRoot ?: \OC::$WEBROOT, $webRoot, $file];
}
}
}
diff --git a/lib/private/Template/IconsCacher.php b/lib/private/Template/IconsCacher.php
index f9497c9a144..9b80711dd29 100644
--- a/lib/private/Template/IconsCacher.php
+++ b/lib/private/Template/IconsCacher.php
@@ -79,10 +79,10 @@ class IconsCacher {
Factory $appDataFactory,
IURLGenerator $urlGenerator,
ITimeFactory $timeFactory) {
- $this->logger = $logger;
- $this->appData = $appDataFactory->get('css');
+ $this->logger = $logger;
+ $this->appData = $appDataFactory->get('css');
$this->urlGenerator = $urlGenerator;
- $this->timeFactory = $timeFactory;
+ $this->timeFactory = $timeFactory;
try {
$this->folder = $this->appData->getFolder('icons');
diff --git a/lib/private/Template/JSCombiner.php b/lib/private/Template/JSCombiner.php
index 48f6dadfd6a..e9e4333c380 100644
--- a/lib/private/Template/JSCombiner.php
+++ b/lib/private/Template/JSCombiner.php
@@ -138,7 +138,7 @@ class JSCombiner {
return false;
}
- foreach ($deps as $file=>$mtime) {
+ foreach ($deps as $file => $mtime) {
if (!file_exists($file) || filemtime($file) > $mtime) {
return false;
}
diff --git a/lib/private/Template/JSConfigHelper.php b/lib/private/Template/JSConfigHelper.php
index e18081f3a8d..69624825ae4 100644
--- a/lib/private/Template/JSConfigHelper.php
+++ b/lib/private/Template/JSConfigHelper.php
@@ -3,6 +3,7 @@
* @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Abijeet <abijeetpatro@gmail.com>
+ * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Bjoern Schiessle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
@@ -33,6 +34,7 @@ namespace OC\Template;
use bantu\IniGetWrapper\IniGetWrapper;
use OC\CapabilitiesManager;
use OCP\App\IAppManager;
+use OCP\Constants;
use OCP\Defaults;
use OCP\IConfig;
use OCP\IGroupManager;
@@ -160,7 +162,7 @@ class JSConfigHelper {
$defaultInternalExpireDate = $defaultInternalExpireDateEnforced = null;
if ($defaultInternalExpireDateEnabled) {
$defaultInternalExpireDate = (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
- $defaultInternalExpireDateEnforced = $this->config->getAppValue('core', 'shareapi_internal_enforce_expire_date', 'no') === 'yes';
+ $defaultInternalExpireDateEnforced = $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
}
$countOfDataLocation = 0;
@@ -189,8 +191,8 @@ class JSConfigHelper {
'enable_avatars' => true, // here for legacy reasons - to not crash existing code that relies on this value
'lost_password_link' => $this->config->getSystemValue('lost_password_link', null),
'modRewriteWorking' => $this->config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true',
- 'sharing.maxAutocompleteResults' => (int)$this->config->getSystemValue('sharing.maxAutocompleteResults', 0),
- 'sharing.minSearchStringLength' => (int)$this->config->getSystemValue('sharing.minSearchStringLength', 0),
+ 'sharing.maxAutocompleteResults' => max(0, $this->config->getSystemValueInt('sharing.maxAutocompleteResults', Constants::SHARING_MAX_AUTOCOMPLETE_RESULTS_DEFAULT)),
+ 'sharing.minSearchStringLength' => $this->config->getSystemValueInt('sharing.minSearchStringLength', 0),
'blacklist_files_regex' => \OCP\Files\FileInfo::BLACKLIST_FILES_REGEX,
];
diff --git a/lib/private/Template/JSResourceLocator.php b/lib/private/Template/JSResourceLocator.php
index 50af5fd34cc..2f0fe16f491 100644
--- a/lib/private/Template/JSResourceLocator.php
+++ b/lib/private/Template/JSResourceLocator.php
@@ -75,7 +75,7 @@ class JSResourceLocator extends ResourceLocator {
}
$app = substr($script, 0, strpos($script, '/'));
- $script = substr($script, strpos($script, '/')+1);
+ $script = substr($script, strpos($script, '/') + 1);
$app_path = \OC_App::getAppPath($app);
$app_url = \OC_App::getAppWebPath($app);
diff --git a/lib/private/Template/SCSSCacher.php b/lib/private/Template/SCSSCacher.php
index 120ed585e16..1c6ca661839 100644
--- a/lib/private/Template/SCSSCacher.php
+++ b/lib/private/Template/SCSSCacher.php
@@ -30,6 +30,7 @@
namespace OC\Template;
+use OC\AppConfig;
use OC\Files\AppData\Factory;
use OC\Memcache\NullCache;
use OCP\AppFramework\Utility\ITimeFactory;
@@ -89,6 +90,8 @@ class SCSSCacher {
/** @var IMemcache */
private $lockingCache;
+ /** @var AppConfig */
+ private $appConfig;
/**
* @param ILogger $logger
@@ -109,15 +112,16 @@ class SCSSCacher {
$serverRoot,
ICacheFactory $cacheFactory,
IconsCacher $iconsCacher,
- ITimeFactory $timeFactory) {
- $this->logger = $logger;
- $this->appData = $appDataFactory->get('css');
+ ITimeFactory $timeFactory,
+ AppConfig $appConfig) {
+ $this->logger = $logger;
+ $this->appData = $appDataFactory->get('css');
$this->urlGenerator = $urlGenerator;
- $this->config = $config;
- $this->defaults = $defaults;
- $this->serverRoot = $serverRoot;
+ $this->config = $config;
+ $this->defaults = $defaults;
+ $this->serverRoot = $serverRoot;
$this->cacheFactory = $cacheFactory;
- $this->depsCache = $cacheFactory->createDistributed('SCSS-deps-' . md5($this->urlGenerator->getBaseUrl()));
+ $this->depsCache = $cacheFactory->createDistributed('SCSS-deps-' . md5($this->urlGenerator->getBaseUrl()));
$this->isCachedCache = $cacheFactory->createDistributed('SCSS-cached-' . md5($this->urlGenerator->getBaseUrl()));
$lockingCache = $cacheFactory->createDistributed('SCSS-locks-' . md5($this->urlGenerator->getBaseUrl()));
if (!($lockingCache instanceof IMemcache)) {
@@ -126,6 +130,7 @@ class SCSSCacher {
$this->lockingCache = $lockingCache;
$this->iconsCacher = $iconsCacher;
$this->timeFactory = $timeFactory;
+ $this->appConfig = $appConfig;
}
/**
@@ -141,11 +146,12 @@ class SCSSCacher {
$path = explode('/', $root . '/' . $file);
$fileNameSCSS = array_pop($path);
- $fileNameCSS = $this->prependVersionPrefix($this->prependBaseurlPrefix(str_replace('.scss', '.css', $fileNameSCSS)), $app);
+ $fileNameCSS = $this->prependVersionPrefix($this->prependBaseurlPrefix(str_replace('.scss', '.css', $fileNameSCSS)), $app);
- $path = implode('/', $path);
+ $path = implode('/', $path);
$webDir = $this->getWebDir($path, $app, $this->serverRoot, \OC::$WEBROOT);
+ $this->logger->debug('SCSSCacher::process ordinary check follows', ['app' => 'scss_cacher']);
if (!$this->variablesChanged() && $this->isCached($fileNameCSS, $app)) {
// Inject icons vars css if any
return $this->injectCssVariablesIfAny();
@@ -161,23 +167,25 @@ class SCSSCacher {
$lockKey = $webDir . '/' . $fileNameSCSS;
if (!$this->lockingCache->add($lockKey, 'locked!', 120)) {
+ $this->logger->debug('SCSSCacher::process could not get lock for ' . $lockKey . ' and will wait 10 seconds for cached file to be available', ['app' => 'scss_cacher']);
$retry = 0;
sleep(1);
while ($retry < 10) {
+ $this->appConfig->clearCachedConfig();
+ $this->logger->debug('SCSSCacher::process check in while loop follows', ['app' => 'scss_cacher']);
if (!$this->variablesChanged() && $this->isCached($fileNameCSS, $app)) {
// Inject icons vars css if any
- $this->lockingCache->remove($lockKey);
- $this->logger->debug('SCSSCacher: ' .$lockKey.' is now available after '.$retry.'s. Moving on...', ['app' => 'core']);
+ $this->logger->debug("SCSSCacher::process cached file for app '$app' and file '$fileNameCSS' is now available after $retry s. Moving on...", ['app' => 'scss_cacher']);
return $this->injectCssVariablesIfAny();
}
- $this->logger->debug('SCSSCacher: scss cache file locked for '.$lockKey, ['app' => 'core']);
sleep(1);
$retry++;
}
- $this->logger->debug('SCSSCacher: Giving up scss caching for '.$lockKey, ['app' => 'core']);
+ $this->logger->debug('SCSSCacher::process Giving up scss caching for ' . $lockKey, ['app' => 'scss_cacher']);
return false;
}
+ $this->logger->debug('SCSSCacher::process Lock acquired for ' . $lockKey, ['app' => 'scss_cacher']);
try {
$cached = $this->cache($path, $fileNameCSS, $fileNameSCSS, $folder, $webDir);
} catch (\Exception $e) {
@@ -187,6 +195,7 @@ class SCSSCacher {
// Cleaning lock
$this->lockingCache->remove($lockKey);
+ $this->logger->debug('SCSSCacher::process Lock removed for ' . $lockKey, ['app' => 'scss_cacher']);
// Inject icons vars css if any
if ($this->iconsCacher->getCachedCSS() && $this->iconsCacher->getCachedCSS()->getSize() > 0) {
@@ -202,7 +211,7 @@ class SCSSCacher {
* @return ISimpleFile
*/
public function getCachedCSS(string $appName, string $fileName): ISimpleFile {
- $folder = $this->appData->getFolder($appName);
+ $folder = $this->appData->getFolder($appName);
$cachedFileName = $this->prependVersionPrefix($this->prependBaseurlPrefix($fileName), $appName);
return $folder->getFile($cachedFileName);
@@ -224,11 +233,13 @@ class SCSSCacher {
return true;
}
}
+ $this->logger->debug("SCSSCacher::isCached $fileNameCSS isCachedCache is expired or unset", ['app' => 'scss_cacher']);
// Creating file cache if none for further checks
try {
$folder = $this->appData->getFolder($app);
} catch (NotFoundException $e) {
+ $this->logger->debug("SCSSCacher::isCached app data folder for $app could not be fetched", ['app' => 'scss_cacher']);
return false;
}
@@ -238,10 +249,10 @@ class SCSSCacher {
$cachedFile = $folder->getFile($fileNameCSS);
if ($cachedFile->getSize() > 0) {
$depFileName = $fileNameCSS . '.deps';
- $deps = $this->depsCache->get($folder->getName() . '-' . $depFileName);
+ $deps = $this->depsCache->get($folder->getName() . '-' . $depFileName);
if ($deps === null) {
$depFile = $folder->getFile($depFileName);
- $deps = $depFile->getContent();
+ $deps = $depFile->getContent();
// Set to memcache for next run
$this->depsCache->set($folder->getName() . '-' . $depFileName, $deps);
}
@@ -249,16 +260,20 @@ class SCSSCacher {
foreach ((array) $deps as $file => $mtime) {
if (!file_exists($file) || filemtime($file) > $mtime) {
+ $this->logger->debug("SCSSCacher::isCached $fileNameCSS is not considered as cached due to deps file $file", ['app' => 'scss_cacher']);
return false;
}
}
+ $this->logger->debug("SCSSCacher::isCached $fileNameCSS dependencies successfully cached for 5 minutes", ['app' => 'scss_cacher']);
+ // It would probably make sense to adjust this timeout to something higher and see if that has some effect then
$this->isCachedCache->set($key, $this->timeFactory->getTime() + 5 * 60);
return true;
}
-
+ $this->logger->debug("SCSSCacher::isCached $fileNameCSS is not considered as cached cacheValue: $cacheValue", ['app' => 'scss_cacher']);
return false;
} catch (NotFoundException $e) {
+ $this->logger->debug("SCSSCacher::isCached NotFoundException " . $e->getMessage(), ['app' => 'scss_cacher']);
return false;
}
}
@@ -268,8 +283,10 @@ class SCSSCacher {
* @return bool
*/
private function variablesChanged(): bool {
- $injectedVariables = $this->getInjectedVariables();
- if ($this->config->getAppValue('core', 'theming.variables') !== md5($injectedVariables)) {
+ $cachedVariables = $this->config->getAppValue('core', 'theming.variables', '');
+ $injectedVariables = $this->getInjectedVariables($cachedVariables);
+ if ($cachedVariables !== md5($injectedVariables)) {
+ $this->logger->debug('SCSSCacher::variablesChanged storedVariables: ' . json_encode($this->config->getAppValue('core', 'theming.variables')) . ' currentInjectedVariables: ' . json_encode($injectedVariables), ['app' => 'scss_cacher']);
$this->config->setAppValue('core', 'theming.variables', md5($injectedVariables));
$this->resetCache();
return true;
@@ -328,7 +345,7 @@ class SCSSCacher {
'@import "functions.scss";' .
'@import "' . $fileNameSCSS . '";');
} catch (ParserException $e) {
- $this->logger->logException($e, ['app' => 'core']);
+ $this->logger->logException($e, ['app' => 'scss_cacher']);
return false;
}
@@ -350,11 +367,11 @@ class SCSSCacher {
$depFile->putContent($deps);
$this->depsCache->set($folder->getName() . '-' . $depFileName, $deps);
$gzipFile->putContent(gzencode($data, 9));
- $this->logger->debug('SCSSCacher: ' . $webDir . '/' . $fileNameSCSS . ' compiled and successfully cached', ['app' => 'core']);
+ $this->logger->debug('SCSSCacher::cache ' . $webDir . '/' . $fileNameSCSS . ' compiled and successfully cached', ['app' => 'scss_cacher']);
return true;
} catch (NotPermittedException $e) {
- $this->logger->error('SCSSCacher: unable to cache: ' . $fileNameSCSS);
+ $this->logger->error('SCSSCacher::cache unable to cache: ' . $fileNameSCSS, ['app' => 'scss_cacher']);
return false;
}
@@ -365,9 +382,12 @@ class SCSSCacher {
* We need to regenerate all files when variables change
*/
public function resetCache() {
+ $this->logger->debug('SCSSCacher::resetCache', ['app' => 'scss_cacher']);
if (!$this->lockingCache->add('resetCache', 'locked!', 120)) {
+ $this->logger->debug('SCSSCacher::resetCache Locked', ['app' => 'scss_cacher']);
return;
}
+ $this->logger->debug('SCSSCacher::resetCache Lock acquired', ['app' => 'scss_cacher']);
$this->injectedVariables = null;
// do not clear locks
@@ -380,18 +400,19 @@ class SCSSCacher {
try {
$file->delete();
} catch (NotPermittedException $e) {
- $this->logger->logException($e, ['message' => 'SCSSCacher: unable to delete file: ' . $file->getName()]);
+ $this->logger->logException($e, ['message' => 'SCSSCacher::resetCache unable to delete file: ' . $file->getName(), 'app' => 'scss_cacher']);
}
}
}
- $this->logger->debug('SCSSCacher: css cache cleared!');
+ $this->logger->debug('SCSSCacher::resetCache css cache cleared!', ['app' => 'scss_cacher']);
$this->lockingCache->remove('resetCache');
+ $this->logger->debug('SCSSCacher::resetCache Locking removed', ['app' => 'scss_cacher']);
}
/**
* @return string SCSS code for variables from OC_Defaults
*/
- private function getInjectedVariables(): string {
+ private function getInjectedVariables(string $cache = ''): string {
if ($this->injectedVariables !== null) {
return $this->injectedVariables;
}
@@ -400,13 +421,22 @@ class SCSSCacher {
$variables .= '$' . $key . ': ' . $value . ' !default;';
}
+ /*
+ * If we are trying to return the same variables as that are cached
+ * Then there is no need to do the compile step
+ */
+ if ($cache === md5($variables)) {
+ $this->injectedVariables = $variables;
+ return $variables;
+ }
+
// check for valid variables / otherwise fall back to defaults
try {
$scss = new Compiler();
$scss->compile($variables);
$this->injectedVariables = $variables;
} catch (ParserException $e) {
- $this->logger->logException($e, ['app' => 'core']);
+ $this->logger->logException($e, ['app' => 'scss_cacher']);
}
return $variables;
@@ -419,7 +449,7 @@ class SCSSCacher {
* @return string
*/
private function rebaseUrls(string $css, string $webDir): string {
- $re = '/url\([\'"]([^\/][\.\w?=\/-]*)[\'"]\)/x';
+ $re = '/url\([\'"]([^\/][\.\w?=\/-]*)[\'"]\)/x';
$subst = 'url(\'' . $webDir . '/$1\')';
return preg_replace($re, $subst, $css);
@@ -433,8 +463,8 @@ class SCSSCacher {
*/
public function getCachedSCSS(string $appName, string $fileName): string {
$tmpfileLoc = explode('/', $fileName);
- $fileName = array_pop($tmpfileLoc);
- $fileName = $this->prependVersionPrefix($this->prependBaseurlPrefix(str_replace('.scss', '.css', $fileName)), $appName);
+ $fileName = array_pop($tmpfileLoc);
+ $fileName = $this->prependVersionPrefix($this->prependBaseurlPrefix(str_replace('.scss', '.css', $fileName)), $appName);
return substr($this->urlGenerator->linkToRoute('core.Css.getCss', [
'fileName' => $fileName,
diff --git a/lib/private/TemplateLayout.php b/lib/private/TemplateLayout.php
index 69eb26ab8b2..f8f6536cee5 100644
--- a/lib/private/TemplateLayout.php
+++ b/lib/private/TemplateLayout.php
@@ -3,7 +3,6 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Bart Visscher <bartv@thisnet.nl>
- * @author Bjoern Schiessle <bjoern@schiessle.org>
* @author Christopher Schäpers <kondou@ts.unde.re>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Clark Tomlinson <fallen013@gmail.com>
@@ -44,38 +43,52 @@
namespace OC;
-use OC\AppFramework\Http\Request;
+use bantu\IniGetWrapper\IniGetWrapper;
+use OC\Search\SearchQuery;
use OC\Template\JSCombiner;
use OC\Template\JSConfigHelper;
use OC\Template\SCSSCacher;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\Defaults;
+use OCP\IConfig;
use OCP\IInitialStateService;
+use OCP\INavigationManager;
use OCP\Support\Subscription\IRegistry;
+use OCP\Util;
class TemplateLayout extends \OC_Template {
private static $versionHash = '';
- /**
- * @var \OCP\IConfig
- */
+ /** @var IConfig */
private $config;
+ /** @var IInitialStateService */
+ private $initialState;
+
+ /** @var INavigationManager */
+ private $navigationManager;
+
/**
* @param string $renderAs
* @param string $appId application id
*/
public function __construct($renderAs, $appId = '') {
- // yes - should be injected ....
- $this->config = \OC::$server->getConfig();
+ /** @var IConfig */
+ $this->config = \OC::$server->get(IConfig::class);
+
+ /** @var IInitialStateService */
+ $this->initialState = \OC::$server->get(IInitialStateService::class);
- if (\OCP\Util::isIE()) {
- \OC_Util::addStyle('ie');
+ if (Util::isIE()) {
+ Util::addStyle('ie');
}
// Decide which page we show
if ($renderAs === TemplateResponse::RENDER_AS_USER) {
+ /** @var INavigationManager */
+ $this->navigationManager = \OC::$server->get(INavigationManager::class);
+
parent::__construct('core', 'layout.user');
if (in_array(\OC_App::getCurrentApp(), ['settings','admin', 'help']) !== false) {
$this->assign('bodyid', 'body-settings');
@@ -83,13 +96,19 @@ class TemplateLayout extends \OC_Template {
$this->assign('bodyid', 'body-user');
}
+ $this->initialState->provideInitialState('core', 'active-app', $this->navigationManager->getActiveEntry());
+ $this->initialState->provideInitialState('unified-search', 'limit-default', SearchQuery::LIMIT_DEFAULT);
+ Util::addScript('dist/unified-search', null, true);
+
// Add navigation entry
$this->assign('application', '');
$this->assign('appid', $appId);
- $navigation = \OC::$server->getNavigationManager()->getAll();
+
+ $navigation = $this->navigationManager->getAll();
$this->assign('navigation', $navigation);
- $settingsNavigation = \OC::$server->getNavigationManager()->getAll('settings');
+ $settingsNavigation = $this->navigationManager->getAll('settings');
$this->assign('settingsnavigation', $settingsNavigation);
+
foreach ($navigation as $entry) {
if ($entry['active']) {
$this->assign('application', $entry['name']);
@@ -110,7 +129,7 @@ class TemplateLayout extends \OC_Template {
if (\OC_User::getUser() === false) {
$this->assign('userAvatarSet', false);
} else {
- $this->assign('userAvatarSet', \OC::$server->getAvatarManager()->getAvatar(\OC_User::getUser())->exists());
+ $this->assign('userAvatarSet', true);
$this->assign('userAvatarVersion', $this->config->getUserValue(\OC_User::getUser(), 'avatar', 'version', 0));
}
@@ -174,21 +193,24 @@ class TemplateLayout extends \OC_Template {
$jsFiles = self::findJavascriptFiles(\OC_Util::$scripts);
$this->assign('jsfiles', []);
if ($this->config->getSystemValue('installed', false) && $renderAs != TemplateResponse::RENDER_AS_ERROR) {
+ // this is on purpose outside of the if statement below so that the initial state is prefilled (done in the getConfig() call)
+ // see https://github.com/nextcloud/server/pull/22636 for details
+ $jsConfigHelper = new JSConfigHelper(
+ \OC::$server->getL10N('lib'),
+ \OC::$server->query(Defaults::class),
+ \OC::$server->getAppManager(),
+ \OC::$server->getSession(),
+ \OC::$server->getUserSession()->getUser(),
+ $this->config,
+ \OC::$server->getGroupManager(),
+ \OC::$server->get(IniGetWrapper::class),
+ \OC::$server->getURLGenerator(),
+ \OC::$server->getCapabilitiesManager(),
+ \OC::$server->query(IInitialStateService::class)
+ );
+ $config = $jsConfigHelper->getConfig();
if (\OC::$server->getContentSecurityPolicyNonceManager()->browserSupportsCspV3()) {
- $jsConfigHelper = new JSConfigHelper(
- \OC::$server->getL10N('lib'),
- \OC::$server->query(Defaults::class),
- \OC::$server->getAppManager(),
- \OC::$server->getSession(),
- \OC::$server->getUserSession()->getUser(),
- $this->config,
- \OC::$server->getGroupManager(),
- \OC::$server->getIniWrapper(),
- \OC::$server->getURLGenerator(),
- \OC::$server->getCapabilitiesManager(),
- \OC::$server->query(IInitialStateService::class)
- );
- $this->assign('inline_ocjs', $jsConfigHelper->getConfig());
+ $this->assign('inline_ocjs', $config);
} else {
$this->append('jsfiles', \OC::$server->getURLGenerator()->linkToRoute('core.OCJS.getConfig', ['v' => self::$versionHash]));
}
@@ -241,9 +263,7 @@ class TemplateLayout extends \OC_Template {
}
}
- /** @var InitialStateService $initialState */
- $initialState = \OC::$server->query(InitialStateService::class);
- $this->assign('initialStates', $initialState->getInitialStates());
+ $this->assign('initialStates', $this->initialState->getInitialStates());
}
/**
diff --git a/lib/private/URLGenerator.php b/lib/private/URLGenerator.php
index b432b0b69ca..f0de31568f4 100644
--- a/lib/private/URLGenerator.php
+++ b/lib/private/URLGenerator.php
@@ -39,6 +39,7 @@ declare(strict_types=1);
namespace OC;
+use OC\Route\Router;
use OCA\Theming\ThemingDefaults;
use OCP\ICacheFactory;
use OCP\IConfig;
@@ -56,31 +57,30 @@ class URLGenerator implements IURLGenerator {
private $cacheFactory;
/** @var IRequest */
private $request;
+ /** @var Router */
+ private $router;
- /**
- * @param IConfig $config
- * @param ICacheFactory $cacheFactory
- * @param IRequest $request
- */
public function __construct(IConfig $config,
ICacheFactory $cacheFactory,
- IRequest $request) {
+ IRequest $request,
+ Router $router) {
$this->config = $config;
$this->cacheFactory = $cacheFactory;
$this->request = $request;
+ $this->router = $router;
}
/**
* Creates an url using a defined route
- * @param string $route
- * @param array $parameters args with param=>value, will be appended to the returned url
+ *
+ * @param string $routeName
+ * @param array $arguments args with param=>value, will be appended to the returned url
* @return string the url
*
* Returns a url to the given route.
*/
- public function linkToRoute(string $route, array $parameters = []): string {
- // TODO: mock router
- return \OC::$server->getRouter()->generate($route, $parameters);
+ public function linkToRoute(string $routeName, array $arguments = []): string {
+ return $this->router->generate($routeName, $arguments);
}
/**
@@ -96,7 +96,7 @@ class URLGenerator implements IURLGenerator {
}
public function linkToOCSRouteAbsolute(string $routeName, array $arguments = []): string {
- $route = \OC::$server->getRouter()->generate('ocs.'.$routeName, $arguments, false);
+ $route = $this->router->generate('ocs.'.$routeName, $arguments, false);
$indexPhpPos = strpos($route, '/index.php/');
if ($indexPhpPos !== false) {
@@ -111,7 +111,8 @@ class URLGenerator implements IURLGenerator {
/**
* Creates an url
- * @param string $app app
+ *
+ * @param string $appName app
* @param string $file file
* @param array $args array with param=>value, will be appended to the returned url
* The value of $args will be urlencoded
@@ -119,24 +120,24 @@ class URLGenerator implements IURLGenerator {
*
* Returns a url to the given app and file.
*/
- public function linkTo(string $app, string $file, array $args = []): string {
+ public function linkTo(string $appName, string $file, array $args = []): string {
$frontControllerActive = ($this->config->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true');
- if ($app !== '') {
- $app_path = \OC_App::getAppPath($app);
+ if ($appName !== '') {
+ $app_path = \OC_App::getAppPath($appName);
// Check if the app is in the app folder
if ($app_path && file_exists($app_path . '/' . $file)) {
if (substr($file, -3) === 'php') {
- $urlLinkTo = \OC::$WEBROOT . '/index.php/apps/' . $app;
+ $urlLinkTo = \OC::$WEBROOT . '/index.php/apps/' . $appName;
if ($frontControllerActive) {
- $urlLinkTo = \OC::$WEBROOT . '/apps/' . $app;
+ $urlLinkTo = \OC::$WEBROOT . '/apps/' . $appName;
}
$urlLinkTo .= ($file !== 'index.php') ? '/' . $file : '';
} else {
- $urlLinkTo = \OC_App::getAppWebPath($app) . '/' . $file;
+ $urlLinkTo = \OC_App::getAppWebPath($appName) . '/' . $file;
}
} else {
- $urlLinkTo = \OC::$WEBROOT . '/' . $app . '/' . $file;
+ $urlLinkTo = \OC::$WEBROOT . '/' . $appName . '/' . $file;
}
} else {
if (file_exists(\OC::$SERVERROOT . '/core/' . $file)) {
@@ -159,16 +160,17 @@ class URLGenerator implements IURLGenerator {
/**
* Creates path to an image
- * @param string $app app
- * @param string $image image name
+ *
+ * @param string $appName app
+ * @param string $file image name
* @throws \RuntimeException If the image does not exist
* @return string the url
*
* Returns the path to the image.
*/
- public function imagePath(string $app, string $image): string {
+ public function imagePath(string $appName, string $file): string {
$cache = $this->cacheFactory->createDistributed('imagePath-'.md5($this->getBaseUrl()).'-');
- $cacheKey = $app.'-'.$image;
+ $cacheKey = $appName.'-'.$file;
if ($key = $cache->get($cacheKey)) {
return $key;
}
@@ -177,9 +179,9 @@ class URLGenerator implements IURLGenerator {
$theme = \OC_Util::getTheme();
//if a theme has a png but not an svg always use the png
- $basename = substr(basename($image),0,-4);
+ $basename = substr(basename($file),0,-4);
- $appPath = \OC_App::getAppPath($app);
+ $appPath = \OC_App::getAppPath($appName);
// Check if the app is in the app folder
$path = '';
@@ -188,42 +190,42 @@ class URLGenerator implements IURLGenerator {
if ($themingEnabled) {
$themingDefaults = \OC::$server->getThemingDefaults();
if ($themingDefaults instanceof ThemingDefaults) {
- $themingImagePath = $themingDefaults->replaceImagePath($app, $image);
+ $themingImagePath = $themingDefaults->replaceImagePath($appName, $file);
}
}
- if (file_exists(\OC::$SERVERROOT . "/themes/$theme/apps/$app/img/$image")) {
- $path = \OC::$WEBROOT . "/themes/$theme/apps/$app/img/$image";
- } elseif (!file_exists(\OC::$SERVERROOT . "/themes/$theme/apps/$app/img/$basename.svg")
- && file_exists(\OC::$SERVERROOT . "/themes/$theme/apps/$app/img/$basename.png")) {
- $path = \OC::$WEBROOT . "/themes/$theme/apps/$app/img/$basename.png";
- } elseif (!empty($app) and file_exists(\OC::$SERVERROOT . "/themes/$theme/$app/img/$image")) {
- $path = \OC::$WEBROOT . "/themes/$theme/$app/img/$image";
- } elseif (!empty($app) and (!file_exists(\OC::$SERVERROOT . "/themes/$theme/$app/img/$basename.svg")
- && file_exists(\OC::$SERVERROOT . "/themes/$theme/$app/img/$basename.png"))) {
- $path = \OC::$WEBROOT . "/themes/$theme/$app/img/$basename.png";
- } elseif (file_exists(\OC::$SERVERROOT . "/themes/$theme/core/img/$image")) {
- $path = \OC::$WEBROOT . "/themes/$theme/core/img/$image";
+ if (file_exists(\OC::$SERVERROOT . "/themes/$theme/apps/$appName/img/$file")) {
+ $path = \OC::$WEBROOT . "/themes/$theme/apps/$appName/img/$file";
+ } elseif (!file_exists(\OC::$SERVERROOT . "/themes/$theme/apps/$appName/img/$basename.svg")
+ && file_exists(\OC::$SERVERROOT . "/themes/$theme/apps/$appName/img/$basename.png")) {
+ $path = \OC::$WEBROOT . "/themes/$theme/apps/$appName/img/$basename.png";
+ } elseif (!empty($appName) and file_exists(\OC::$SERVERROOT . "/themes/$theme/$appName/img/$file")) {
+ $path = \OC::$WEBROOT . "/themes/$theme/$appName/img/$file";
+ } elseif (!empty($appName) and (!file_exists(\OC::$SERVERROOT . "/themes/$theme/$appName/img/$basename.svg")
+ && file_exists(\OC::$SERVERROOT . "/themes/$theme/$appName/img/$basename.png"))) {
+ $path = \OC::$WEBROOT . "/themes/$theme/$appName/img/$basename.png";
+ } elseif (file_exists(\OC::$SERVERROOT . "/themes/$theme/core/img/$file")) {
+ $path = \OC::$WEBROOT . "/themes/$theme/core/img/$file";
} elseif (!file_exists(\OC::$SERVERROOT . "/themes/$theme/core/img/$basename.svg")
&& file_exists(\OC::$SERVERROOT . "/themes/$theme/core/img/$basename.png")) {
- $path = \OC::$WEBROOT . "/themes/$theme/core/img/$basename.png";
+ $path = \OC::$WEBROOT . "/themes/$theme/core/img/$basename.png";
} elseif ($themingEnabled && $themingImagePath) {
$path = $themingImagePath;
- } elseif ($appPath && file_exists($appPath . "/img/$image")) {
- $path = \OC_App::getAppWebPath($app) . "/img/$image";
+ } elseif ($appPath && file_exists($appPath . "/img/$file")) {
+ $path = \OC_App::getAppWebPath($appName) . "/img/$file";
} elseif ($appPath && !file_exists($appPath . "/img/$basename.svg")
&& file_exists($appPath . "/img/$basename.png")) {
- $path = \OC_App::getAppWebPath($app) . "/img/$basename.png";
- } elseif (!empty($app) and file_exists(\OC::$SERVERROOT . "/$app/img/$image")) {
- $path = \OC::$WEBROOT . "/$app/img/$image";
- } elseif (!empty($app) and (!file_exists(\OC::$SERVERROOT . "/$app/img/$basename.svg")
- && file_exists(\OC::$SERVERROOT . "/$app/img/$basename.png"))) {
- $path = \OC::$WEBROOT . "/$app/img/$basename.png";
- } elseif (file_exists(\OC::$SERVERROOT . "/core/img/$image")) {
- $path = \OC::$WEBROOT . "/core/img/$image";
+ $path = \OC_App::getAppWebPath($appName) . "/img/$basename.png";
+ } elseif (!empty($appName) and file_exists(\OC::$SERVERROOT . "/$appName/img/$file")) {
+ $path = \OC::$WEBROOT . "/$appName/img/$file";
+ } elseif (!empty($appName) and (!file_exists(\OC::$SERVERROOT . "/$appName/img/$basename.svg")
+ && file_exists(\OC::$SERVERROOT . "/$appName/img/$basename.png"))) {
+ $path = \OC::$WEBROOT . "/$appName/img/$basename.png";
+ } elseif (file_exists(\OC::$SERVERROOT . "/core/img/$file")) {
+ $path = \OC::$WEBROOT . "/core/img/$file";
} elseif (!file_exists(\OC::$SERVERROOT . "/core/img/$basename.svg")
&& file_exists(\OC::$SERVERROOT . "/core/img/$basename.png")) {
- $path = \OC::$WEBROOT . "/themes/$theme/core/img/$basename.png";
+ $path = \OC::$WEBROOT . "/themes/$theme/core/img/$basename.png";
}
if ($path !== '') {
@@ -231,7 +233,7 @@ class URLGenerator implements IURLGenerator {
return $path;
}
- throw new RuntimeException('image not found: image:' . $image . ' webroot:' . \OC::$WEBROOT . ' serverroot:' . \OC::$SERVERROOT);
+ throw new RuntimeException('image not found: image:' . $file . ' webroot:' . \OC::$WEBROOT . ' serverroot:' . \OC::$SERVERROOT);
}
diff --git a/lib/private/Updater.php b/lib/private/Updater.php
index 4b5d02aeb64..ec0a50cc6ca 100644
--- a/lib/private/Updater.php
+++ b/lib/private/Updater.php
@@ -9,6 +9,7 @@
* @author Frank Karlitschek <frank@karlitschek.de>
* @author Georg Ehrke <oc.list@georgehrke.com>
* @author Joas Schilling <coding@schilljs.com>
+ * @author Julius Härtl <jus@bitgrid.net>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
@@ -16,7 +17,7 @@
* @author Steffen Lindner <mail@steffen-lindner.de>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -192,8 +193,12 @@ class Updater extends BasicEmitter {
$currentVendor = $this->config->getAppValue('core', 'vendor', '');
// Vendor was not set correctly on install, so we have to white-list known versions
- if ($currentVendor === '' && isset($allowedPreviousVersions['owncloud'][$oldVersion])) {
+ if ($currentVendor === '' && (
+ isset($allowedPreviousVersions['owncloud'][$oldVersion]) ||
+ isset($allowedPreviousVersions['owncloud'][$majorMinor])
+ )) {
$currentVendor = 'owncloud';
+ $this->config->setAppValue('core', 'vendor', $currentVendor);
}
if ($currentVendor === 'nextcloud') {
@@ -300,47 +305,6 @@ class Updater extends BasicEmitter {
}
/**
- * @param string $version the oc version to check app compatibility with
- */
- protected function checkAppUpgrade($version) {
- $apps = \OC_App::getEnabledApps();
- $this->emit('\OC\Updater', 'appUpgradeCheckBefore');
-
- $appManager = \OC::$server->getAppManager();
- foreach ($apps as $appId) {
- $info = \OC_App::getAppInfo($appId);
- $compatible = \OC_App::isAppCompatible($version, $info);
- $isShipped = $appManager->isShipped($appId);
-
- if ($compatible && $isShipped && \OC_App::shouldUpgrade($appId)) {
- /**
- * FIXME: The preupdate check is performed before the database migration, otherwise database changes
- * are not possible anymore within it. - Consider this when touching the code.
- * @link https://github.com/owncloud/core/issues/10980
- * @see \OC_App::updateApp
- */
- if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) {
- $this->includePreUpdate($appId);
- }
- if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) {
- $this->emit('\OC\Updater', 'appSimulateUpdate', [$appId]);
- \OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml');
- }
- }
- }
-
- $this->emit('\OC\Updater', 'appUpgradeCheck');
- }
-
- /**
- * Includes the pre-update file. Done here to prevent namespace mixups.
- * @param string $appId
- */
- private function includePreUpdate($appId) {
- include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
- }
-
- /**
* upgrades all apps within a major ownCloud upgrade. Also loads "priority"
* (types authentication, filesystem, logging, in that order) afterwards.
*
@@ -401,7 +365,7 @@ class Updater extends BasicEmitter {
$disabledApps = [];
$appManager = \OC::$server->getAppManager();
foreach ($apps as $app) {
- // check if the app is compatible with this version of ownCloud
+ // check if the app is compatible with this version of Nextcloud
$info = OC_App::getAppInfo($app);
if ($info === null || !OC_App::isAppCompatible($version, $info)) {
if ($appManager->isShipped($app)) {
diff --git a/lib/private/User/Backend.php b/lib/private/User/Backend.php
index 477448279a5..c87dc5d2d50 100644
--- a/lib/private/User/Backend.php
+++ b/lib/private/User/Backend.php
@@ -39,14 +39,14 @@ abstract class Backend implements UserInterface {
/**
* actions that user backends can define
*/
- public const CREATE_USER = 1; // 1 << 0
- public const SET_PASSWORD = 16; // 1 << 4
- public const CHECK_PASSWORD = 256; // 1 << 8
- public const GET_HOME = 4096; // 1 << 12
- public const GET_DISPLAYNAME = 65536; // 1 << 16
- public const SET_DISPLAYNAME = 1048576; // 1 << 20
- public const PROVIDE_AVATAR = 16777216; // 1 << 24
- public const COUNT_USERS = 268435456; // 1 << 28
+ public const CREATE_USER = 1; // 1 << 0
+ public const SET_PASSWORD = 16; // 1 << 4
+ public const CHECK_PASSWORD = 256; // 1 << 8
+ public const GET_HOME = 4096; // 1 << 12
+ public const GET_DISPLAYNAME = 65536; // 1 << 16
+ public const SET_DISPLAYNAME = 1048576; // 1 << 20
+ public const PROVIDE_AVATAR = 16777216; // 1 << 24
+ public const COUNT_USERS = 268435456; // 1 << 28
protected $possibleActions = [
self::CREATE_USER => 'createUser',
diff --git a/lib/private/User/Database.php b/lib/private/User/Database.php
index e88549c8d81..7c936acd0bd 100644
--- a/lib/private/User/Database.php
+++ b/lib/private/User/Database.php
@@ -26,7 +26,7 @@ declare(strict_types=1);
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -293,14 +293,14 @@ class Database extends ABackend implements
/**
* Check if the password is correct
*
- * @param string $uid The username
+ * @param string $loginName The loginname
* @param string $password The password
* @return string
*
* Check if the password is correct without logging in the user
* returns the user id or false
*/
- public function checkPassword(string $uid, string $password) {
+ public function checkPassword(string $loginName, string $password) {
$this->fixDI();
$qb = $this->dbConn->getQueryBuilder();
@@ -308,7 +308,7 @@ class Database extends ABackend implements
->from($this->table)
->where(
$qb->expr()->eq(
- 'uid_lower', $qb->createNamedParameter(mb_strtolower($uid))
+ 'uid_lower', $qb->createNamedParameter(mb_strtolower($loginName))
)
);
$result = $qb->execute();
@@ -320,7 +320,7 @@ class Database extends ABackend implements
$newHash = '';
if (\OC::$server->getHasher()->verify($password, $storedHash, $newHash)) {
if (!empty($newHash)) {
- $this->updatePassword($uid, $newHash);
+ $this->updatePassword($loginName, $newHash);
}
return (string)$row['uid'];
}
diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php
index 303050a7716..1d58c68268c 100644
--- a/lib/private/User/Manager.php
+++ b/lib/private/User/Manager.php
@@ -34,6 +34,7 @@
namespace OC\User;
+use OC\HintException;
use OC\Hooks\PublicEmitter;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\EventDispatcher\IEventDispatcher;
@@ -42,8 +43,9 @@ use OCP\IGroup;
use OCP\IUser;
use OCP\IUserBackend;
use OCP\IUserManager;
+use OCP\Support\Subscription\IRegistry;
use OCP\User\Backend\IGetRealUIDBackend;
-use OCP\User\Events\CreateUserEvent;
+use OCP\User\Events\BeforeUserCreatedEvent;
use OCP\User\Events\UserCreatedEvent;
use OCP\UserInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -297,6 +299,12 @@ class Manager extends PublicEmitter implements IUserManager {
* @return bool|IUser the created user or false
*/
public function createUser($uid, $password) {
+ // DI injection is not used here as IRegistry needs the user manager itself for user count and thus it would create a cyclic dependency
+ if (\OC::$server->get(IRegistry::class)->delegateIsHardUserLimitReached()) {
+ $l = \OC::$server->getL10N('lib');
+ throw new HintException($l->t('The user limit has been reached and the user was not created.'));
+ }
+
$localBackends = [];
foreach ($this->backends as $backend) {
if ($backend instanceof Database) {
@@ -365,14 +373,16 @@ class Manager extends PublicEmitter implements IUserManager {
throw new \InvalidArgumentException($l->t('The username is already being used'));
}
+ /** @deprecated 21.0.0 use BeforeUserCreatedEvent event with the IEventDispatcher instead */
$this->emit('\OC\User', 'preCreateUser', [$uid, $password]);
- $this->eventDispatcher->dispatchTyped(new CreateUserEvent($uid, $password));
+ $this->eventDispatcher->dispatchTyped(new BeforeUserCreatedEvent($uid, $password));
$state = $backend->createUser($uid, $password);
if ($state === false) {
throw new \InvalidArgumentException($l->t('Could not create user'));
}
$user = $this->getUserObject($uid, $backend);
if ($user instanceof IUser) {
+ /** @deprecated 21.0.0 use UserCreatedEvent event with the IEventDispatcher instead */
$this->emit('\OC\User', 'postCreateUser', [$user, $password]);
$this->eventDispatcher->dispatchTyped(new UserCreatedEvent($user, $password));
}
@@ -547,6 +557,7 @@ class Manager extends PublicEmitter implements IUserManager {
/**
* @param \Closure $callback
+ * @psalm-param \Closure(\OCP\IUser):?bool $callback
* @since 11.0.0
*/
public function callForSeenUsers(\Closure $callback) {
diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php
index 3996869c692..70c7f11c45f 100644
--- a/lib/private/User/Session.php
+++ b/lib/private/User/Session.php
@@ -11,6 +11,7 @@
* @author Greta Doci <gretadoci@gmail.com>
* @author Joas Schilling <coding@schilljs.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Lionel Elie Mamane <lionel@mamane.lu>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
@@ -18,7 +19,7 @@
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Sandro Lutz <sandro.lutz@temparus.ch>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -80,7 +81,7 @@ use Symfony\Component\EventDispatcher\GenericEvent;
* - preUnassignedUserId(string $uid)
* - postUnassignedUserId(string $uid)
* - preLogin(string $user, string $password)
- * - postLogin(\OC\User\User $user, string $password)
+ * - postLogin(\OC\User\User $user, string $loginName, string $password, boolean $isTokenLogin)
* - preRememberedLogin(string $uid)
* - postRememberedLogin(\OC\User\User $user)
* - logout()
@@ -400,11 +401,13 @@ class Session implements IUserSession, Emitter {
$this->dispatcher->dispatchTyped(new PostLoginEvent(
$user,
+ $loginDetails['loginName'],
$loginDetails['password'],
$isToken
));
$this->manager->emit('\OC\User', 'postLogin', [
$user,
+ $loginDetails['loginName'],
$loginDetails['password'],
$isToken,
]);
@@ -811,15 +814,15 @@ class Session implements IUserSession, Emitter {
*/
public function tryTokenLogin(IRequest $request) {
$authHeader = $request->getHeader('Authorization');
- if (strpos($authHeader, 'Bearer ') === false) {
+ if (strpos($authHeader, 'Bearer ') === 0) {
+ $token = substr($authHeader, 7);
+ } else {
// No auth header, let's try session id
try {
$token = $this->session->getId();
} catch (SessionNotAvailableException $ex) {
return false;
}
- } else {
- $token = substr($authHeader, 7);
}
if (!$this->loginWithToken($token)) {
@@ -829,8 +832,18 @@ class Session implements IUserSession, Emitter {
return false;
}
- // Set the session variable so we know this is an app password
- $this->session->set('app_password', $token);
+ try {
+ $dbToken = $this->tokenProvider->getToken($token);
+ } catch (InvalidTokenException $e) {
+ // Can't really happen but better save than sorry
+ return true;
+ }
+
+ // Remember me tokens are not app_passwords
+ if ($dbToken->getRemember() === IToken::DO_NOT_REMEMBER) {
+ // Set the session variable so we know this is an app password
+ $this->session->set('app_password', $token);
+ }
return true;
}
diff --git a/lib/private/User/User.php b/lib/private/User/User.php
index 08bbce4701b..24082926b0d 100644
--- a/lib/private/User/User.php
+++ b/lib/private/User/User.php
@@ -16,7 +16,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -41,12 +41,18 @@ use OC\Avatar\AvatarManager;
use OC\Files\Cache\Storage;
use OC\Hooks\Emitter;
use OC_Helper;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Group\Events\BeforeUserRemovedEvent;
+use OCP\Group\Events\UserRemovedEvent;
use OCP\IAvatarManager;
use OCP\IConfig;
use OCP\IImage;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserBackend;
+use OCP\User\Events\BeforeUserDeletedEvent;
+use OCP\User\Events\UserDeletedEvent;
+use OCP\User\GetQuotaEvent;
use OCP\UserInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
@@ -61,6 +67,9 @@ class User implements IUser {
/** @var UserInterface|null */
private $backend;
/** @var EventDispatcherInterface */
+ private $legacyDispatcher;
+
+ /** @var IEventDispatcher */
private $dispatcher;
/** @var bool */
@@ -87,7 +96,7 @@ class User implements IUser {
public function __construct(string $uid, ?UserInterface $backend, EventDispatcherInterface $dispatcher, $emitter = null, IConfig $config = null, $urlGenerator = null) {
$this->uid = $uid;
$this->backend = $backend;
- $this->dispatcher = $dispatcher;
+ $this->legacyDispatcher = $dispatcher;
$this->emitter = $emitter;
if (is_null($config)) {
$config = \OC::$server->getConfig();
@@ -100,6 +109,8 @@ class User implements IUser {
if (is_null($this->urlGenerator)) {
$this->urlGenerator = \OC::$server->getURLGenerator();
}
+ // TODO: inject
+ $this->dispatcher = \OC::$server->query(IEventDispatcher::class);
}
/**
@@ -203,10 +214,13 @@ class User implements IUser {
* @return bool
*/
public function delete() {
- $this->dispatcher->dispatch(IUser::class . '::preDelete', new GenericEvent($this));
+ /** @deprecated 21.0.0 use BeforeUserDeletedEvent event with the IEventDispatcher instead */
+ $this->legacyDispatcher->dispatch(IUser::class . '::preDelete', new GenericEvent($this));
if ($this->emitter) {
+ /** @deprecated 21.0.0 use BeforeUserDeletedEvent event with the IEventDispatcher instead */
$this->emitter->emit('\OC\User', 'preDelete', [$this]);
}
+ $this->dispatcher->dispatchTyped(new BeforeUserDeletedEvent($this));
// get the home now because it won't return it after user deletion
$homePath = $this->getHome();
$result = $this->backend->deleteUser($this->uid);
@@ -219,9 +233,9 @@ class User implements IUser {
foreach ($groupManager->getUserGroupIds($this) as $groupId) {
$group = $groupManager->get($groupId);
if ($group) {
- \OC_Hook::emit("OC_Group", "pre_removeFromGroup", ["run" => true, "uid" => $this->uid, "gid" => $groupId]);
+ $this->dispatcher->dispatchTyped(new BeforeUserRemovedEvent($group, $this));
$group->removeUser($this);
- \OC_Hook::emit("OC_User", "post_removeFromGroup", ["uid" => $this->uid, "gid" => $groupId]);
+ $this->dispatcher->dispatchTyped(new UserRemovedEvent($group, $this));
}
}
// Delete the user's keys in preferences
@@ -252,10 +266,13 @@ class User implements IUser {
$accountManager = \OC::$server->query(AccountManager::class);
$accountManager->deleteUser($this);
- $this->dispatcher->dispatch(IUser::class . '::postDelete', new GenericEvent($this));
+ /** @deprecated 21.0.0 use UserDeletedEvent event with the IEventDispatcher instead */
+ $this->legacyDispatcher->dispatch(IUser::class . '::postDelete', new GenericEvent($this));
if ($this->emitter) {
+ /** @deprecated 21.0.0 use UserDeletedEvent event with the IEventDispatcher instead */
$this->emitter->emit('\OC\User', 'postDelete', [$this]);
}
+ $this->dispatcher->dispatchTyped(new UserDeletedEvent($this));
}
return !($result === false);
}
@@ -268,7 +285,7 @@ class User implements IUser {
* @return bool
*/
public function setPassword($password, $recoveryPassword = null) {
- $this->dispatcher->dispatch(IUser::class . '::preSetPassword', new GenericEvent($this, [
+ $this->legacyDispatcher->dispatch(IUser::class . '::preSetPassword', new GenericEvent($this, [
'password' => $password,
'recoveryPassword' => $recoveryPassword,
]));
@@ -277,7 +294,7 @@ class User implements IUser {
}
if ($this->backend->implementsActions(Backend::SET_PASSWORD)) {
$result = $this->backend->setPassword($this->uid, $password);
- $this->dispatcher->dispatch(IUser::class . '::postSetPassword', new GenericEvent($this, [
+ $this->legacyDispatcher->dispatch(IUser::class . '::postSetPassword', new GenericEvent($this, [
'password' => $password,
'recoveryPassword' => $recoveryPassword,
]));
@@ -398,7 +415,15 @@ class User implements IUser {
* @since 9.0.0
*/
public function getQuota() {
- $quota = $this->config->getUserValue($this->uid, 'files', 'quota', 'default');
+ // allow apps to modify the user quota by hooking into the event
+ $event = new GetQuotaEvent($this);
+ $this->dispatcher->dispatchTyped($event);
+ $overwriteQuota = $event->getQuota();
+ if ($overwriteQuota) {
+ $quota = $overwriteQuota;
+ } else {
+ $quota = $this->config->getUserValue($this->uid, 'files', 'quota', 'default');
+ }
if ($quota === 'default') {
$quota = $this->config->getAppValue('files', 'default_quota', 'none');
}
@@ -455,7 +480,7 @@ class User implements IUser {
public function getCloudId() {
$uid = $this->getUID();
$server = $this->urlGenerator->getAbsoluteURL('/');
- $server = rtrim($this->removeProtocolFromUrl($server), '/');
+ $server = rtrim($this->removeProtocolFromUrl($server), '/');
return \OC::$server->getCloudIdManager()->getCloudId($uid, $server)->getId();
}
@@ -474,7 +499,7 @@ class User implements IUser {
}
public function triggerChange($feature, $value = null, $oldValue = null) {
- $this->dispatcher->dispatch(IUser::class . '::changeUser', new GenericEvent($this, [
+ $this->legacyDispatcher->dispatch(IUser::class . '::changeUser', new GenericEvent($this, [
'feature' => $feature,
'value' => $value,
'oldValue' => $oldValue,
diff --git a/lib/private/UserStatus/Manager.php b/lib/private/UserStatus/Manager.php
new file mode 100644
index 00000000000..aeef8df27f9
--- /dev/null
+++ b/lib/private/UserStatus/Manager.php
@@ -0,0 +1,106 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2020, Georg Ehrke
+ *
+ * @author Georg Ehrke <oc.list@georgehrke.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\UserStatus;
+
+use OCP\ILogger;
+use OCP\IServerContainer;
+use OCP\UserStatus\IManager;
+use OCP\UserStatus\IProvider;
+use Psr\Container\ContainerExceptionInterface;
+
+class Manager implements IManager {
+
+ /** @var IServerContainer */
+ private $container;
+
+ /** @var ILogger */
+ private $logger;
+
+ /** @var null */
+ private $providerClass;
+
+ /** @var IProvider */
+ private $provider;
+
+ /**
+ * Manager constructor.
+ *
+ * @param IServerContainer $container
+ * @param ILogger $logger
+ */
+ public function __construct(IServerContainer $container,
+ ILogger $logger) {
+ $this->container = $container;
+ $this->logger = $logger;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getUserStatuses(array $userIds): array {
+ $this->setupProvider();
+ if (!$this->provider) {
+ return [];
+ }
+
+ return $this->provider->getUserStatuses($userIds);
+ }
+
+ /**
+ * @param string $class
+ * @since 20.0.0
+ * @internal
+ */
+ public function registerProvider(string $class): void {
+ $this->providerClass = $class;
+ $this->provider = null;
+ }
+
+ /**
+ * Lazily set up provider
+ */
+ private function setupProvider(): void {
+ if ($this->provider !== null) {
+ return;
+ }
+ if ($this->providerClass === null) {
+ return;
+ }
+
+ try {
+ $provider = $this->container->get($this->providerClass);
+ } catch (ContainerExceptionInterface $e) {
+ $this->logger->logException($e, [
+ 'message' => 'Could not load user-status provider dynamically: ' . $e->getMessage(),
+ 'level' => ILogger::ERROR,
+ ]);
+ return;
+ }
+
+ $this->provider = $provider;
+ }
+}
diff --git a/lib/private/legacy/OC_API.php b/lib/private/legacy/OC_API.php
index 37a496a38fe..16a144269b3 100644
--- a/lib/private/legacy/OC_API.php
+++ b/lib/private/legacy/OC_API.php
@@ -12,7 +12,6 @@
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Tom Needham <tom@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
*
* @license AGPL-3.0
*
@@ -43,8 +42,9 @@ class OC_API {
* respond to a call
* @param \OC\OCS\Result $result
* @param string $format the format xml|json
+ * @psalm-taint-escape html
*/
- public static function respond($result, $format='xml') {
+ public static function respond($result, $format = 'xml') {
$request = \OC::$server->getRequest();
// Send 401 headers if unauthorised
diff --git a/lib/private/legacy/OC_App.php b/lib/private/legacy/OC_App.php
index 5851fc01379..32d2569d0a0 100644
--- a/lib/private/legacy/OC_App.php
+++ b/lib/private/legacy/OC_App.php
@@ -33,7 +33,7 @@ declare(strict_types=1);
* @author Sebastian Wessalowski <sebastian@wessalowski.org>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -80,6 +80,9 @@ class OC_App {
/**
* clean the appId
*
+ * @psalm-taint-escape file
+ * @psalm-taint-escape include
+ *
* @param string $app AppId that needs to be cleaned
* @return string
*/
@@ -94,7 +97,7 @@ class OC_App {
* @return bool
*/
public static function isAppLoaded(string $app): bool {
- return in_array($app, self::$loadedApps, true);
+ return isset(self::$loadedApps[$app]);
}
/**
@@ -118,16 +121,19 @@ class OC_App {
// Add each apps' folder as allowed class path
foreach ($apps as $app) {
- $path = self::getAppPath($app);
- if ($path !== false) {
- self::registerAutoloading($app, $path);
+ // If the app is already loaded then autoloading it makes no sense
+ if (!isset(self::$loadedApps[$app])) {
+ $path = self::getAppPath($app);
+ if ($path !== false) {
+ self::registerAutoloading($app, $path);
+ }
}
}
// prevent app.php from printing output
ob_start();
foreach ($apps as $app) {
- if (($types === [] or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
+ if (!isset(self::$loadedApps[$app]) && ($types === [] || self::isType($app, $types))) {
self::loadApp($app);
}
}
@@ -143,7 +149,7 @@ class OC_App {
* @throws Exception
*/
public static function loadApp(string $app) {
- self::$loadedApps[] = $app;
+ self::$loadedApps[$app] = true;
$appPath = self::getAppPath($app);
if ($appPath === false) {
return;
@@ -512,6 +518,8 @@ class OC_App {
* Get the directory for the given app.
* If the app is defined in multiple directories, the first one is taken. (false if not found)
*
+ * @psalm-taint-specialize
+ *
* @param string $appId
* @return string|false
* @deprecated 11.0.0 use \OC::$server->getAppManager()->getAppPath()
@@ -966,6 +974,15 @@ class OC_App {
\OC::$server->getAppManager()->clearAppsCache();
$appData = self::getAppInfo($appId);
+ $ignoreMaxApps = \OC::$server->getConfig()->getSystemValue('app_install_overwrite', []);
+ $ignoreMax = in_array($appId, $ignoreMaxApps, true);
+ \OC_App::checkAppDependencies(
+ \OC::$server->getConfig(),
+ \OC::$server->getL10N('core'),
+ $appData,
+ $ignoreMax
+ );
+
self::registerAutoloading($appId, $appPath, true);
self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
@@ -982,11 +999,6 @@ class OC_App {
\OC::$server->getAppManager()->clearAppsCache();
\OC::$server->getAppManager()->getAppVersion($appId, false);
- // run upgrade code
- if (file_exists($appPath . '/appinfo/update.php')) {
- self::loadApp($appId);
- include $appPath . '/appinfo/update.php';
- }
self::setupBackgroundJobs($appData['background-jobs']);
//set remote/public handlers
@@ -1118,7 +1130,7 @@ class OC_App {
$similarLangFallback = $option['@value'];
} elseif (strpos($attributeLang, $similarLang . '_') === 0) {
if ($similarLangFallback === false) {
- $similarLangFallback = $option['@value'];
+ $similarLangFallback = $option['@value'];
}
}
} else {
diff --git a/lib/private/legacy/OC_DB.php b/lib/private/legacy/OC_DB.php
index 1d2e9bd1429..11cd1f4cae0 100644
--- a/lib/private/legacy/OC_DB.php
+++ b/lib/private/legacy/OC_DB.php
@@ -12,7 +12,7 @@
* @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>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -55,6 +55,7 @@ class OC_DB {
* @param bool|null $isManipulation
* @throws \OC\DatabaseException
* @return OC_DB_StatementWrapper prepared SQL query
+ * @deprecated 21.0.0 Please use \OCP\IDBConnection::getQueryBuilder() instead
*
* SQL query via Doctrine prepare(), needs to be execute()'d!
*/
@@ -68,13 +69,12 @@ class OC_DB {
// return the result
try {
- $result =$connection->prepare($query, $limit, $offset);
+ $result = $connection->prepare($query, $limit, $offset);
} catch (\Doctrine\DBAL\DBALException $e) {
throw new \OC\DatabaseException($e->getMessage());
}
// differentiate between query and manipulation
- $result = new OC_DB_StatementWrapper($result, $isManipulation);
- return $result;
+ return new OC_DB_StatementWrapper($result, $isManipulation);
}
/**
@@ -85,22 +85,27 @@ class OC_DB {
* @return bool
*/
public static function isManipulation($sql) {
+ $sql = trim($sql);
$selectOccurrence = stripos($sql, 'SELECT');
- if ($selectOccurrence !== false && $selectOccurrence < 10) {
+ if ($selectOccurrence === 0) {
return false;
}
$insertOccurrence = stripos($sql, 'INSERT');
- if ($insertOccurrence !== false && $insertOccurrence < 10) {
+ if ($insertOccurrence === 0) {
return true;
}
$updateOccurrence = stripos($sql, 'UPDATE');
- if ($updateOccurrence !== false && $updateOccurrence < 10) {
+ if ($updateOccurrence === 0) {
return true;
}
$deleteOccurrence = stripos($sql, 'DELETE');
- if ($deleteOccurrence !== false && $deleteOccurrence < 10) {
+ if ($deleteOccurrence === 0) {
return true;
}
+
+ // This is triggered with "SHOW VERSION" and some more, so until we made a list, we keep this out.
+ // \OC::$server->getLogger()->logException(new \Exception('Can not detect if query is manipulating: ' . $sql));
+
return false;
}
@@ -112,6 +117,7 @@ class OC_DB {
* @param array $parameters
* @return OC_DB_StatementWrapper
* @throws \OC\DatabaseException
+ * @deprecated 21.0.0 Please use \OCP\IDBConnection::getQueryBuilder() instead
*/
public static function executeAudited($stmt, array $parameters = []) {
if (is_string($stmt)) {
diff --git a/lib/private/legacy/OC_DB_StatementWrapper.php b/lib/private/legacy/OC_DB_StatementWrapper.php
index d4072caf28e..667c2de9678 100644
--- a/lib/private/legacy/OC_DB_StatementWrapper.php
+++ b/lib/private/legacy/OC_DB_StatementWrapper.php
@@ -5,10 +5,10 @@
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Bart Visscher <bartv@thisnet.nl>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Morris Jobke <hey@morrisjobke.de>
- * @author Piotr Mrówczyński <mrow4a@yahoo.com>
* @author Robin Appelman <robin@icewind.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
*
@@ -66,7 +66,7 @@ class OC_DB_StatementWrapper {
* @param array $input
* @return \OC_DB_StatementWrapper|int|bool
*/
- public function execute($input= []) {
+ public function execute($input = []) {
$this->lastArguments = $input;
if (count($input) > 0) {
$result = $this->statement->execute($input);
@@ -105,6 +105,15 @@ class OC_DB_StatementWrapper {
}
/**
+ * Closes the cursor, enabling the statement to be executed again.
+ *
+ * @deprecated Use Result::free() instead.
+ */
+ public function closeCursor(): void {
+ $this->statement->closeCursor();
+ }
+
+ /**
* Binds a PHP variable to a corresponding named or question mark placeholder in the
* SQL statement that was use to prepare the statement.
*
diff --git a/lib/private/legacy/OC_FileChunking.php b/lib/private/legacy/OC_FileChunking.php
index 8aef29541fe..1c24f0d8067 100644
--- a/lib/private/legacy/OC_FileChunking.php
+++ b/lib/private/legacy/OC_FileChunking.php
@@ -11,7 +11,7 @@
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -88,7 +88,7 @@ class OC_FileChunking {
$cache = $this->getCache();
$chunkcount = (int)$this->info['chunkcount'];
- for ($i=($chunkcount-1); $i >= 0; $i--) {
+ for ($i = ($chunkcount - 1); $i >= 0; $i--) {
if (!$cache->hasKey($prefix.$i)) {
return false;
}
@@ -144,7 +144,7 @@ class OC_FileChunking {
public function cleanup() {
$cache = $this->getCache();
$prefix = $this->getPrefix();
- for ($i=0; $i < $this->info['chunkcount']; $i++) {
+ for ($i = 0; $i < $this->info['chunkcount']; $i++) {
$cache->remove($prefix.$i);
}
}
diff --git a/lib/private/legacy/OC_Files.php b/lib/private/legacy/OC_Files.php
index ddb824cd6cd..addee2358dd 100644
--- a/lib/private/legacy/OC_Files.php
+++ b/lib/private/legacy/OC_Files.php
@@ -12,7 +12,6 @@
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Julius Härtl <jus@bitgrid.net>
* @author Ko- <k.stoffelen@cs.ru.nl>
- * @author Lukas Reschke <lukas@statuscode.ch>
* @author Michael Gapczynski <GapczynskiM@gmail.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Nicolai Ehemann <en@enlightened.de>
@@ -23,7 +22,7 @@
* @author Thibaut GRIDEL <tgridel@free.fr>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -41,6 +40,7 @@
*
*/
+use bantu\IniGetWrapper\IniGetWrapper;
use OC\Files\View;
use OC\Streamer;
use OCP\Lock\ILockingProvider;
@@ -108,6 +108,7 @@ class OC_Files {
* @param array $params ; 'head' boolean to only send header of the request ; 'range' http range header
*/
public static function get($dir, $files, $params = null) {
+ OC_Util::setupFS();
$view = \OC\Files\Filesystem::getView();
$getType = self::FILE;
$filename = $dir;
@@ -164,7 +165,7 @@ class OC_Files {
OC_Util::obEnd();
$streamer->sendHeaders($name);
- $executionTime = (int)OC::$server->getIniWrapper()->getNumeric('max_execution_time');
+ $executionTime = (int)OC::$server->get(IniGetWrapper::class)->getNumeric('max_execution_time');
if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
@set_time_limit(0);
}
@@ -208,18 +209,18 @@ class OC_Files {
} catch (\OCP\Lock\LockedException $ex) {
self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
OC::$server->getLogger()->logException($ex);
- $l = \OC::$server->getL10N('core');
+ $l = \OC::$server->getL10N('lib');
$hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
\OC_Template::printErrorPage($l->t('File is currently busy, please try again later'), $hint, 200);
} catch (\OCP\Files\ForbiddenException $ex) {
self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
OC::$server->getLogger()->logException($ex);
- $l = \OC::$server->getL10N('core');
+ $l = \OC::$server->getL10N('lib');
\OC_Template::printErrorPage($l->t('Can\'t read file'), $ex->getMessage(), 200);
} catch (\Exception $ex) {
self::unlockAllTheFiles($dir, $files, $getType, $view, $filename);
OC::$server->getLogger()->logException($ex);
- $l = \OC::$server->getL10N('core');
+ $l = \OC::$server->getL10N('lib');
$hint = method_exists($ex, 'getHint') ? $ex->getHint() : '';
\OC_Template::printErrorPage($l->t('Can\'t read file'), $hint, 200);
}
@@ -231,7 +232,7 @@ class OC_Files {
* @return array $rangeArray ('from'=>int,'to'=>int), ...
*/
private static function parseHttpRangeHeader($rangeHeaderPos, $fileSize) {
- $rArray=explode(',', $rangeHeaderPos);
+ $rArray = explode(',', $rangeHeaderPos);
$minOffset = 0;
$ind = 0;
@@ -243,7 +244,7 @@ class OC_Files {
if ($ranges[0] < $minOffset) { // case: bytes=500-700,601-999
$ranges[0] = $minOffset;
}
- if ($ind > 0 && $rangeArray[$ind-1]['to']+1 == $ranges[0]) { // case: bytes=500-600,601-999
+ if ($ind > 0 && $rangeArray[$ind - 1]['to'] + 1 == $ranges[0]) { // case: bytes=500-600,601-999
$ind--;
$ranges[0] = $rangeArray[$ind]['from'];
}
@@ -252,7 +253,7 @@ class OC_Files {
if (is_numeric($ranges[0]) && is_numeric($ranges[1]) && $ranges[0] < $fileSize && $ranges[0] <= $ranges[1]) {
// case: x-x
if ($ranges[1] >= $fileSize) {
- $ranges[1] = $fileSize-1;
+ $ranges[1] = $fileSize - 1;
}
$rangeArray[$ind++] = [ 'from' => $ranges[0], 'to' => $ranges[1], 'size' => $fileSize ];
$minOffset = $ranges[1] + 1;
@@ -261,14 +262,14 @@ class OC_Files {
}
} elseif (is_numeric($ranges[0]) && $ranges[0] < $fileSize) {
// case: x-
- $rangeArray[$ind++] = [ 'from' => $ranges[0], 'to' => $fileSize-1, 'size' => $fileSize ];
+ $rangeArray[$ind++] = [ 'from' => $ranges[0], 'to' => $fileSize - 1, 'size' => $fileSize ];
break;
} elseif (is_numeric($ranges[1])) {
// case: -x
if ($ranges[1] > $fileSize) {
$ranges[1] = $fileSize;
}
- $rangeArray[$ind++] = [ 'from' => $fileSize-$ranges[1], 'to' => $fileSize-1, 'size' => $fileSize ];
+ $rangeArray[$ind++] = [ 'from' => $fileSize - $ranges[1], 'to' => $fileSize - 1, 'size' => $fileSize ];
break;
}
}
diff --git a/lib/private/legacy/OC_Helper.php b/lib/private/legacy/OC_Helper.php
index 8cd492de117..ccb99a6ebb8 100644
--- a/lib/private/legacy/OC_Helper.php
+++ b/lib/private/legacy/OC_Helper.php
@@ -7,7 +7,6 @@
* @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <bjoern@schiessle.org>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Clark Tomlinson <fallen013@gmail.com>
* @author Daniel Kesselberg <mail@danielkesselberg.de>
* @author Felix Moeller <mail@felixmoeller.de>
* @author Jakob Sack <mail@jakobsack.de>
@@ -26,7 +25,7 @@
* @author Simon Könnecke <simonkoennecke@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -44,6 +43,7 @@
*
*/
+use bantu\IniGetWrapper\IniGetWrapper;
use Symfony\Component\Process\ExecutableFinder;
/**
@@ -220,7 +220,7 @@ class OC_Helper {
// Default check will be done with $path directories :
$dirs = explode(PATH_SEPARATOR, $path);
// WARNING : We have to check if open_basedir is enabled :
- $obd = OC::$server->getIniWrapper()->getString('open_basedir');
+ $obd = OC::$server->get(IniGetWrapper::class)->getString('open_basedir');
if ($obd != "none") {
$obd_values = explode(PATH_SEPARATOR, $obd);
if (count($obd_values) > 0 and $obd_values[0]) {
@@ -414,7 +414,7 @@ class OC_Helper {
* @return int PHP upload file size limit
*/
public static function uploadLimit() {
- $ini = \OC::$server->getIniWrapper();
+ $ini = \OC::$server->get(IniGetWrapper::class);
$upload_max_filesize = OCP\Util::computerFileSize($ini->get('upload_max_filesize'));
$post_max_size = OCP\Util::computerFileSize($ini->get('post_max_size'));
if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) {
@@ -436,7 +436,7 @@ class OC_Helper {
if (!function_exists($function_name)) {
return false;
}
- $ini = \OC::$server->getIniWrapper();
+ $ini = \OC::$server->get(IniGetWrapper::class);
$disabled = explode(',', $ini->get('disable_functions') ?: '');
$disabled = array_map('trim', $disabled);
if (in_array($function_name, $disabled)) {
@@ -475,6 +475,9 @@ class OC_Helper {
/**
* Calculate the disc space for the given path
*
+ * BEWARE: this requires that Util::setupFS() was called
+ * already !
+ *
* @param string $path
* @param \OCP\Files\FileInfo $rootInfo (optional)
* @return array
@@ -495,7 +498,8 @@ class OC_Helper {
$used = 0;
}
$quota = \OCP\Files\FileInfo::SPACE_UNLIMITED;
- $storage = $rootInfo->getStorage();
+ $mount = $rootInfo->getMountPoint();
+ $storage = $mount->getStorage();
$sourceStorage = $storage;
if ($storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
$includeExtStorage = false;
@@ -544,6 +548,11 @@ class OC_Helper {
if ($owner) {
$ownerDisplayName = $owner->getDisplayName();
}
+ if (substr_count($mount->getMountPoint(), '/') < 3) {
+ $mountPoint = '';
+ } else {
+ [,,,$mountPoint] = explode('/', $mount->getMountPoint(), 4);
+ }
return [
'free' => $free,
@@ -553,6 +562,8 @@ class OC_Helper {
'relative' => $relative,
'owner' => $ownerId,
'ownerDisplayName' => $ownerDisplayName,
+ 'mountType' => $mount->getMountType(),
+ 'mountPoint' => trim($mountPoint, '/'),
];
}
diff --git a/lib/private/legacy/OC_Hook.php b/lib/private/legacy/OC_Hook.php
index 1da03df3a1f..cf0e9881e4c 100644
--- a/lib/private/legacy/OC_Hook.php
+++ b/lib/private/legacy/OC_Hook.php
@@ -11,7 +11,7 @@
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Sam Tuke <mail@samtuke.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -128,15 +128,15 @@ class OC_Hook {
* @param string $signalClass
* @param string $signalName
*/
- public static function clear($signalClass='', $signalName='') {
+ public static function clear($signalClass = '', $signalName = '') {
if ($signalClass) {
if ($signalName) {
- self::$registered[$signalClass][$signalName]=[];
+ self::$registered[$signalClass][$signalName] = [];
} else {
- self::$registered[$signalClass]=[];
+ self::$registered[$signalClass] = [];
}
} else {
- self::$registered=[];
+ self::$registered = [];
}
}
diff --git a/lib/private/legacy/OC_Image.php b/lib/private/legacy/OC_Image.php
index 4fdbfb3909f..523468701c7 100644
--- a/lib/private/legacy/OC_Image.php
+++ b/lib/private/legacy/OC_Image.php
@@ -98,7 +98,14 @@ class OC_Image implements \OCP\IImage {
* @return bool
*/
public function valid() { // apparently you can't name a method 'empty'...
- return is_resource($this->resource);
+ if (is_resource($this->resource)) {
+ return true;
+ }
+ if (is_object($this->resource) && get_class($this->resource) === 'GdImage') {
+ return true;
+ }
+
+ return false;
}
/**
@@ -305,7 +312,13 @@ class OC_Image implements \OCP\IImage {
* @throws \InvalidArgumentException in case the supplied resource does not have the type "gd"
*/
public function setResource($resource) {
- if (get_resource_type($resource) === 'gd') {
+ // For PHP<8
+ if (is_resource($resource) && get_resource_type($resource) === 'gd') {
+ $this->resource = $resource;
+ return;
+ }
+ // PHP 8 has real objects for GD stuff
+ if (is_object($resource) && get_class($resource) === 'GdImage') {
$this->resource = $resource;
return;
}
@@ -1175,7 +1188,7 @@ if (!function_exists('imagebmp')) {
} elseif ($bit == 32) {
$bit = 24;
}
- $bits = pow(2, $bit);
+ $bits = (int)pow(2, $bit);
imagetruecolortopalette($im, true, $bits);
$width = imagesx($im);
$height = imagesy($im);
@@ -1211,7 +1224,7 @@ if (!function_exists('imagebmp')) {
} // RLE8
elseif ($compression == 1 && $bit == 8) {
for ($j = $height - 1; $j >= 0; $j--) {
- $lastIndex = "\0";
+ $lastIndex = null;
$sameNum = 0;
for ($i = 0; $i <= $width; $i++) {
$index = imagecolorat($im, $i, $j);
diff --git a/lib/private/legacy/OC_JSON.php b/lib/private/legacy/OC_JSON.php
index a0b9868a023..3094879af38 100644
--- a/lib/private/legacy/OC_JSON.php
+++ b/lib/private/legacy/OC_JSON.php
@@ -10,7 +10,7 @@
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -99,6 +99,7 @@ class OC_JSON {
* Send json error msg
* @deprecated Use a AppFramework JSONResponse instead
* @suppress PhanDeprecatedFunction
+ * @psalm-taint-escape html
*/
public static function error($data = []) {
$data['status'] = 'error';
@@ -110,6 +111,7 @@ class OC_JSON {
* Send json success msg
* @deprecated Use a AppFramework JSONResponse instead
* @suppress PhanDeprecatedFunction
+ * @psalm-taint-escape html
*/
public static function success($data = []) {
$data['status'] = 'success';
diff --git a/lib/private/legacy/OC_Response.php b/lib/private/legacy/OC_Response.php
index 491c6913463..f4c2356aecd 100644
--- a/lib/private/legacy/OC_Response.php
+++ b/lib/private/legacy/OC_Response.php
@@ -10,7 +10,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/legacy/OC_Template.php b/lib/private/legacy/OC_Template.php
index 32d185d25fd..baf2356b549 100644
--- a/lib/private/legacy/OC_Template.php
+++ b/lib/private/legacy/OC_Template.php
@@ -20,7 +20,7 @@
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -114,10 +114,7 @@ class OC_Template extends \OC\Template\Base {
OC_Util::addStyle('server', null, true);
OC_Util::addTranslations('core', null, true);
- if (\OC::$server->getSystemConfig()->getValue('installed', false)) {
- OC_Util::addStyle('search', 'results');
- OC_Util::addScript('search', 'search', true);
- OC_Util::addScript('search', 'searchprovider');
+ if (\OC::$server->getSystemConfig()->getValue('installed', false) && !\OCP\Util::needUpgrade()) {
OC_Util::addScript('merged-template-prepend', null, true);
OC_Util::addScript('dist/files_client', null, true);
OC_Util::addScript('dist/files_fileinfo', null, true);
@@ -164,8 +161,8 @@ class OC_Template extends \OC\Template\Base {
* @param string $text the text content for the element. If $text is null then the
* element will be written as empty element. So use "" to get a closing tag.
*/
- public function addHeader($tag, $attributes, $text=null) {
- $this->headers[]= [
+ public function addHeader($tag, $attributes, $text = null) {
+ $this->headers[] = [
'tag' => $tag,
'attributes' => $attributes,
'text' => $text
@@ -174,7 +171,7 @@ class OC_Template extends \OC\Template\Base {
/**
* Process the template
- * @return boolean|string
+ * @return string
*
* This function process the template. If $this->renderAs is set, it
* will produce a full page.
@@ -198,7 +195,7 @@ class OC_Template extends \OC\Template\Base {
if (strcasecmp($header['tag'], 'script') === 0 && in_array('src', array_map('strtolower', array_keys($header['attributes'])))) {
$headers .= ' defer';
}
- foreach ($header['attributes'] as $name=>$value) {
+ foreach ($header['attributes'] as $name => $value) {
$headers .= ' '.\OCP\Util::sanitizeHTML($name).'="'.\OCP\Util::sanitizeHTML($value).'"';
}
if ($header['text'] !== null) {
@@ -328,7 +325,7 @@ class OC_Template extends \OC\Template\Base {
$content->assign('errorCode', $exception->getCode());
$content->assign('file', $exception->getFile());
$content->assign('line', $exception->getLine());
- $content->assign('trace', $exception->getTraceAsString());
+ $content->assign('exception', $exception);
$content->assign('debugMode', \OC::$server->getSystemConfig()->getValue('debug', false));
$content->assign('remoteAddr', $request->getRemoteAddress());
$content->assign('requestID', $request->getId());
diff --git a/lib/private/legacy/OC_User.php b/lib/private/legacy/OC_User.php
index 29c78da6efb..c8d9b51eaba 100644
--- a/lib/private/legacy/OC_User.php
+++ b/lib/private/legacy/OC_User.php
@@ -18,7 +18,7 @@
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author shkdee <louis.traynard@m4x.org>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php
index 82b7abf6c8f..826d0a31129 100644
--- a/lib/private/legacy/OC_Util.php
+++ b/lib/private/legacy/OC_Util.php
@@ -25,6 +25,7 @@
* @author Joas Schilling <coding@schilljs.com>
* @author John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
+ * @author Julius Härtl <jus@bitgrid.net>
* @author Kawohl <john@owncloud.com>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Markus Goetz <markus@woboq.com>
@@ -43,7 +44,7 @@
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
* @author Victor Dubiniuk <dubiniuk@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
* @author Volkan Gezer <volkangezer@gmail.com>
*
* @license AGPL-3.0
@@ -62,12 +63,14 @@
*
*/
+use bantu\IniGetWrapper\IniGetWrapper;
use OC\AppFramework\Http\Request;
use OC\Files\Storage\LocalRootStorage;
use OCP\IConfig;
use OCP\IGroupManager;
use OCP\ILogger;
use OCP\IUser;
+use OCP\IUserSession;
class OC_Util {
public static $scripts = [];
@@ -296,6 +299,16 @@ class OC_Util {
self::initLocalStorageRootFS();
}
+ /** @var \OCP\Files\Config\IMountProviderCollection $mountProviderCollection */
+ $mountProviderCollection = \OC::$server->query(\OCP\Files\Config\IMountProviderCollection::class);
+ $rootMountProviders = $mountProviderCollection->getRootMounts();
+
+ /** @var \OC\Files\Mount\Manager $mountManager */
+ $mountManager = \OC\Files\Filesystem::getMountManager();
+ foreach ($rootMountProviders as $rootMountProvider) {
+ $mountManager->addMount($rootMountProvider);
+ }
+
if ($user != '' && !\OC::$server->getUserManager()->userExists($user)) {
\OC::$server->getEventLogger()->end('setup_fs');
return false;
@@ -543,16 +556,16 @@ class OC_Util {
$timestamp = filemtime(OC::$SERVERROOT . '/version.php');
require OC::$SERVERROOT . '/version.php';
- /** @var $timestamp int */
+ /** @var int $timestamp */
self::$versionCache['OC_Version_Timestamp'] = $timestamp;
- /** @var $OC_Version string */
+ /** @var string $OC_Version */
self::$versionCache['OC_Version'] = $OC_Version;
- /** @var $OC_VersionString string */
+ /** @var string $OC_VersionString */
self::$versionCache['OC_VersionString'] = $OC_VersionString;
- /** @var $OC_Build string */
+ /** @var string $OC_Build */
self::$versionCache['OC_Build'] = $OC_Build;
- /** @var $OC_Channel string */
+ /** @var string $OC_Channel */
self::$versionCache['OC_Channel'] = $OC_Channel;
}
@@ -727,7 +740,7 @@ class OC_Util {
$webServerRestart = false;
$setup = new \OC\Setup(
$config,
- \OC::$server->getIniWrapper(),
+ \OC::$server->get(IniGetWrapper::class),
\OC::$server->getL10N('lib'),
\OC::$server->query(\OCP\Defaults::class),
\OC::$server->getLogger(),
@@ -852,7 +865,7 @@ class OC_Util {
$missingDependencies = [];
$invalidIniSettings = [];
- $iniWrapper = \OC::$server->getIniWrapper();
+ $iniWrapper = \OC::$server->get(IniGetWrapper::class);
foreach ($dependencies['classes'] as $class => $module) {
if (!class_exists($class)) {
$missingDependencies[] = $module;
@@ -899,7 +912,7 @@ class OC_Util {
}
$errors[] = [
'error' => $l->t('PHP setting "%s" is not set to "%s".', [$setting[0], var_export($setting[1], true)]),
- 'hint' => $l->t('Adjusting this setting in php.ini will make Nextcloud run again')
+ 'hint' => $l->t('Adjusting this setting in php.ini will make Nextcloud run again')
];
$webServerRestart = true;
}
@@ -923,9 +936,9 @@ class OC_Util {
if (function_exists('xml_parser_create') &&
LIBXML_LOADED_VERSION < 20700) {
$version = LIBXML_LOADED_VERSION;
- $major = floor($version/10000);
+ $major = floor($version / 10000);
$version -= ($major * 10000);
- $minor = floor($version/100);
+ $minor = floor($version / 100);
$version -= ($minor * 100);
$patch = $version;
$errors[] = [
@@ -970,6 +983,7 @@ class OC_Util {
try {
$result = \OC_DB::executeAudited('SHOW SERVER_VERSION');
$data = $result->fetchRow();
+ $result->closeCursor();
if (isset($data['server_version'])) {
$version = $data['server_version'];
if (version_compare($version, '9.0.0', '<')) {
@@ -1088,6 +1102,8 @@ class OC_Util {
* @suppress PhanDeprecatedFunction
*/
public static function getDefaultPageUrl() {
+ /** @var IConfig $config */
+ $config = \OC::$server->get(IConfig::class);
$urlGenerator = \OC::$server->getURLGenerator();
// Deny the redirect if the URL contains a @
// This prevents unvalidated redirects like ?redirect_url=:user@domain.com
@@ -1099,8 +1115,16 @@ class OC_Util {
$location = $urlGenerator->getAbsoluteURL($defaultPage);
} else {
$appId = 'files';
- $config = \OC::$server->getConfig();
- $defaultApps = explode(',', $config->getSystemValue('defaultapp', 'files'));
+ $defaultApps = explode(',', $config->getSystemValue('defaultapp', 'dashboard,files'));
+
+ /** @var IUserSession $userSession */
+ $userSession = \OC::$server->get(IUserSession::class);
+ $user = $userSession->getUser();
+ if ($user) {
+ $userDefaultApps = explode(',', $config->getUserValue($user->getUID(), 'core', 'defaultapp'));
+ $defaultApps = array_filter(array_merge($userDefaultApps, $defaultApps));
+ }
+
// find the first app that is enabled for the current user
foreach ($defaultApps as $defaultApp) {
$defaultApp = OC_App::cleanAppId(strip_tags($defaultApp));
diff --git a/lib/private/legacy/template/functions.php b/lib/private/legacy/template/functions.php
index e2a1c476433..4613e36f9f2 100644
--- a/lib/private/legacy/template/functions.php
+++ b/lib/private/legacy/template/functions.php
@@ -14,7 +14,7 @@
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
+ * @author Vincent Petry <vincent@nextcloud.com>
*
* @license AGPL-3.0
*
@@ -47,12 +47,12 @@ function p($string) {
* @param string $opts, additional optional options
*/
function emit_css_tag($href, $opts = '') {
- $s='<link rel="stylesheet"';
+ $s = '<link rel="stylesheet"';
if (!empty($href)) {
- $s.=' href="' . $href .'"';
+ $s .= ' href="' . $href .'"';
}
if (!empty($opts)) {
- $s.=' '.$opts;
+ $s .= ' '.$opts;
}
print_unescaped($s.">\n");
}
@@ -75,20 +75,20 @@ function emit_css_loading_tags($obj) {
* @param string $src the source URL, ignored when empty
* @param string $script_content the inline script content, ignored when empty
*/
-function emit_script_tag($src, $script_content='') {
- $defer_str=' defer';
- $s='<script nonce="' . \OC::$server->getContentSecurityPolicyNonceManager()->getNonce() . '"';
+function emit_script_tag($src, $script_content = '') {
+ $defer_str = ' defer';
+ $s = '<script nonce="' . \OC::$server->getContentSecurityPolicyNonceManager()->getNonce() . '"';
if (!empty($src)) {
// emit script tag for deferred loading from $src
- $s.=$defer_str.' src="' . $src .'">';
+ $s .= $defer_str.' src="' . $src .'">';
} elseif (!empty($script_content)) {
// emit script tag for inline script from $script_content without defer (see MDN)
- $s.=">\n".$script_content."\n";
+ $s .= ">\n".$script_content."\n";
} else {
// no $src nor $src_content, really useless empty tag
- $s.='>';
+ $s .= '>';
}
- $s.='</script>';
+ $s .= '</script>';
print_unescaped($s."\n");
}
@@ -306,9 +306,9 @@ function relative_modified_date($timestamp, $fromTime = null, $dateOnly = false)
return $formatter->formatTimeSpan($timestamp, $fromTime);
}
-function html_select_options($options, $selected, $params=[]) {
+function html_select_options($options, $selected, $params = []) {
if (!is_array($selected)) {
- $selected=[$selected];
+ $selected = [$selected];
}
if (isset($params['combine']) && $params['combine']) {
$options = array_combine($options, $options);