Compare commits

..

299 Commits

Author SHA1 Message Date
C Montero-Luque 35746e68ce 7.0.14 RC2 2016-05-02 04:20:40 -04:00
C Montero-Luque fe03f46a39 7.0.14 RC1 2016-04-26 21:28:52 -04:00
Thomas Müller 6518d6d0e8 Merge pull request #24167 from owncloud/stable7-certificate
[stable7] Ignore certificate file if it starts with file://
2016-04-22 09:34:44 +02:00
Lukas Reschke 9d5005c795 [stable7] Ignore certificate file if it starts with file:// 2016-04-21 18:47:17 +02:00
C Montero-Luque 84b831b0fe 7.0.13 2016-03-08 09:05:31 -05:00
C Montero-Luque 392696998b 7.0.13 RC2 2016-03-04 18:17:59 -05:00
C Montero-Luque a1fecc1d09 7.0.13 RC1 2016-03-01 21:27:10 -05:00
C. Montero Luque 40f3404d71 Merge pull request #22763 from owncloud/stable7-phpmailer
[stable7] Backport PHPMailer validation
2016-03-01 15:26:58 -05:00
Lukas Reschke 9ae57d55f0 [stable7] Backport PHPMailer validation
For https://github.com/owncloud/3rdparty/pull/252
2016-03-01 21:25:00 +01:00
C Montero-Luque 5557f6835d 7.0.12 2015-12-21 07:25:49 -05:00
C Montero-Luque a76d0cdc3d 7.0.12 RC2 2015-12-18 17:35:20 -05:00
C Montero-Luque f0032bd7b5 7.0.12 RC1 2015-12-15 16:13:05 -05:00
Lukas Reschke 5436575564 Merge pull request #21191 from owncloud/preview-non-existing-7
[7.0] Handle non existing files in version previews
2015-12-14 16:34:14 +01:00
Robin Appelman f746100e13 Handle non existing files in version previews 2015-12-14 15:59:36 +01:00
Lukas Reschke 85e068a723 Use XMLWriter to generate response
Gets rid of manual XML generation.
2015-12-14 09:37:16 +01:00
C Montero-Luque 119cd08c93 7.0.11 2015-10-30 12:47:18 -04:00
C Montero-Luque 912e346229 7.0.11 RC2 2015-10-28 10:39:53 -04:00
Thomas Müller 65ba58d2a4 Merge pull request #20062 from owncloud/stable7-add-warning-for-php7
[stable7] Stop processing if PHP 7 is used
2015-10-26 22:03:45 +01:00
Lukas Reschke 48a2e343e0 Stop processing if PHP 7 is used
PHP 7 is only compatible with ownCloud 8.2.0
2015-10-26 17:40:26 +01:00
C Montero-Luque df9b8cdd7f 7.0.11 RC1 2015-10-21 17:43:21 -04:00
Morris Jobke cdcb6c3dc7 Merge pull request #18858 from owncloud/memcached-fix-stable7
[stable7] Fallback to complete Memcached flush if getAllKeys fails
2015-10-09 13:18:54 +02:00
Thomas Müller 89b0a6796d Merge pull request #19626 from owncloud/stable7-backport-13771
[stable7] generate valid human readable text for 0 - fixed #9342
2015-10-08 17:23:02 +02:00
Thomas Müller 75d4dac8ed generate valid human readable text for 0 - fixed #9342 2015-10-07 15:51:30 +02:00
Morris Jobke 7b6602e0db Merge pull request #19448 from owncloud/stable7-backport-19441
[stable7][upgrade] switch to debug logging on upgrade
2015-10-02 12:39:26 +02:00
Thomas Müller fd8ddf6d27 Merge pull request #19493 from owncloud/stable7-fix-php5.3
PHP 5.3 compliance
2015-10-01 11:56:41 +02:00
Thomas Müller 754d4f68a7 Fix #19492 2015-10-01 10:51:44 +02:00
Morris Jobke f4c7b3051d [upgrade] switch to debug logging on upgrade
* resets afterwards
* adds output about the previous log level
2015-09-29 16:36:55 +02:00
Morris Jobke 9d270bcc46 Merge pull request #17954 from owncloud/backport-17464-stable7
fix uncaught exception on not permitted file types when setting avata…
2015-09-28 11:52:23 +02:00
Morris Jobke 0f2ea52861 Merge pull request #18705 from owncloud/stable7-dav-copy-fix
[stable7] Check for file existence before doing a DAV copy
2015-09-28 11:51:06 +02:00
C Montero-Luque 4b6474edf1 7.0.10 2015-09-10 10:23:53 -04:00
Morris Jobke a2658515b3 Merge pull request #18898 from owncloud/revert-18385-stable7-fix-repair-emit
Revert "[stable7] forward repair events to updater"
2015-09-08 14:28:37 +02:00
Lukas Reschke bc5368f9be Revert "[stable7] forward repair events to updater" 2015-09-08 14:20:32 +02:00
Morris Jobke cde3efb63c Merge pull request #18845 from owncloud/app-upgrade-routenotfound-stable7
[stable7] Always add to $loadedApps
2015-09-07 00:24:32 +02:00
Robin McCorkell 3bc4c92d76 Fallback to complete Memcached flush if getAllKeys fails
Newer Memcached's do not support the underlying protocol commands that
getAllKeys() is implemented with. We should fallback to clearing
everything in that case, as causing (temporary) performance problems for
other applications on the server is better than having stale cached data.
2015-09-06 20:42:23 +01:00
Robin McCorkell 0f4c90acbc Always add to $loadedApps 2015-09-05 11:45:33 +01:00
Thomas Müller 7438c463d4 Merge pull request #18793 from owncloud/LukasReschke-patch-1
[stable7] Use PHP 5.3 syntax
2015-09-03 09:13:57 +02:00
Lukas Reschke c50a378c3b [stable7] Use PHP 5.3 syntax 2015-09-03 08:49:23 +02:00
C Montero-Luque 30303822e3 7.0.9 2015-09-02 10:52:28 +02:00
Vincent Petry 5849a2de8c Check for file existence before doing a DAV copy
Partial backport of f39fcbc250 from 8.1
2015-08-31 15:18:14 +02:00
Morris Jobke 0f89d4f9ef Merge pull request #18602 from owncloud/stable7-backport-17083
[stable7] take share target into account when updating recipient etags
2015-08-29 12:48:54 +02:00
Vincent Petry f7e0370f32 Unit test for etag update on custom share folder 2015-08-27 14:50:26 +02:00
Robin Appelman 9c60922311 take share target into account when updating recipient etags 2015-08-27 14:50:18 +02:00
C Montero-Luque c67435189e 7.0.9 RC1 2015-08-27 11:35:00 +02:00
Morris Jobke 6bcffdc889 Merge pull request #18561 from owncloud/ext-objectstore-stable7
[stable7] Prevent objectstore being set from client side
2015-08-25 18:33:42 +02:00
Robin McCorkell b05e178bbf Prevent objectstore being set from client side 2015-08-25 16:29:12 +01:00
Thomas Müller 3b3ce91d46 Merge pull request #18385 from owncloud/stable7-fix-repair-emit
[stable7] forward repair events to updater
2015-08-19 09:31:19 +02:00
Morris Jobke 2ce22eeefb forward repair events to updater
* fixes #17313
* already in stable8+: 22bc37cb82 - #13513
2015-08-18 13:15:27 +02:00
Morris Jobke b1f8c5cfac Merge pull request #18180 from owncloud/backport-18159-stable7
Backport 18159 stable7
2015-08-16 14:40:41 +02:00
michag86 164865e813 Update installer.php 2015-08-10 18:43:28 +02:00
michag86 f0e62145d3 Check if archive contains a directory named like appid 2015-08-10 18:43:24 +02:00
Frank Karlitschek ebe5c05764 7.0.8 2015-08-07 20:18:58 -04:00
C Montero-Luque 1287036801 7.0.8 RC1 2015-08-03 08:55:49 -04:00
Arthur Schiwon d44a6563a7 fix uncaught exception on not permitted file types when setting avatar, fixes #17232 2015-07-29 13:15:53 +02:00
C Montero-Luque e8cc365310 7.0.8 beta 1 2015-07-22 22:28:57 -04:00
Morris Jobke 3feccc9562 Merge pull request #17765 from owncloud/backport-17723-stable7
Backport of #17723 to stable7
2015-07-21 00:05:22 +02:00
Morris Jobke 6dfb2afa29 Merge pull request #17368 from owncloud/fix_16740_7.0
[stable7] owner is stored as 'uid_owner', not as 'owner' in the oc_share table
2015-07-20 23:14:46 +02:00
Arthur Schiwon a1815cf275 Backport of #17723 to stable7
fix runtime caching in ldap's user manager, fixes #17631
2015-07-20 23:09:47 +02:00
Joas Schilling 5c4e6b1c3e Merge pull request #17406 from owncloud/stable7-backport-17095
[stable7] Proper error handling
2015-07-16 11:56:10 +02:00
Thomas Müller 374dd3cbcb Merge pull request #17630 from owncloud/stable7-rescanversionsonlyonce
[stable7] Only rescan versions once in trashbin
2015-07-14 14:04:26 +02:00
Vincent Petry 895285ab59 Only rescan versions once in trashbin
Whenever versions need to be rescanned, only do it once per PHP request.
Happens whenever multiple files need to be expired.
2015-07-14 06:39:06 +02:00
Morris Jobke f4aa78c75f Merge pull request #17416 from owncloud/issue-17260-NaN-when-creating-new-user-and-group
Return correct user count when the group has none
2015-07-09 22:47:47 +02:00
Joas Schilling 0dfc47c02d Return correct user count when the group has none 2015-07-06 13:32:11 +02:00
Morris Jobke fba6ac5050 [updater] mark failure in red 2015-07-06 10:58:22 +02:00
Morris Jobke 917002f3ec [updater] propagate error case properly
* add $success to the updateEnd hook
* add new return code for a update failure
* add exception class to failure hook message
2015-07-06 10:58:12 +02:00
Morris Jobke 8df392738c Added error message on initMountpoints exception 2015-07-06 10:53:25 +02:00
C Montero-Luque 4df15bf573 7.0.7 2015-07-03 06:17:54 -04:00
Bjoern Schiessle 5fadc7e3c6 owner is stored as 'uid_owner', not as 'owner' in the oc_share table 2015-07-03 10:43:16 +02:00
C. Montero Luque 84b1253def Merge pull request #17208 from owncloud/stable7-fix-16812
[Stable7] Oracle workaround for adding a column with not-null default value
2015-07-02 15:26:00 -04:00
Morris Jobke 065bcf4790 Merge pull request #17319 from owncloud/stable7-clean-ocsid
[stable7] Delete OCS ID from DB if none is specified
2015-07-02 14:39:43 +02:00
Morris Jobke d8f88aa413 Merge pull request #17314 from owncloud/stable7-remove-ocs-ids
[stable7] Remove OCS IDs
2015-07-02 14:39:35 +02:00
Lukas Reschke a1da45a172 Bump versions 2015-07-02 09:27:36 +02:00
Lukas Reschke 6170aa5cc3 Delete OCS ID from DB if none is specified
If no OCS ID is specified in appinfo.xml and an app update is triggered and a OCS ID is stored in the DB we should clean the value.

Ref https://github.com/owncloud/activity/issues/320#issuecomment-117937748
2015-07-02 09:26:37 +02:00
Lukas Reschke 552bcf1dcf [stable7] Remove OCS IDs
While making the AppStore ready for 8.1 I also deleted some dummy entries which means that these IDs do not resolve anymore. We should remove them to prevent errors such as https://github.com/owncloud/core/issues/17307

Ref https://github.com/owncloud/activity/issues/320#issuecomment-117691867
2015-07-02 08:54:57 +02:00
C Montero-Luque f29af9c23b 7.0.7RC1 2015-06-30 18:49:26 -04:00
Morris Jobke 4448c06f14 Merge pull request #17234 from owncloud/oc-version-to-app-store-stable7
Add oc version to app store requests in stable7
2015-06-29 16:35:24 +02:00
Joas Schilling f5f92447e5 Add oc version to app store requests in stable7 2015-06-29 16:01:57 +02:00
Victor Dubiniuk ed1565e18c Oracle-specific workaround for adding a column with not-null default value 2015-06-27 00:03:27 +03:00
Frank Karlitschek c1bed643a0 Merge pull request #17180 from owncloud/stable7-backport-17026
[stable7] [config.sample.php] set correct default value for skeletondirectory
2015-06-25 14:56:25 -04:00
Morris Jobke 3c02cbe5dd [config.sample.php] set correct default value for skeletondirectory 2015-06-25 17:08:55 +02:00
Morris Jobke e2a9c7a911 Merge pull request #17116 from owncloud/stable7-17115
[stable7] [sharing] handle shares of users that aren't available anymore
2015-06-24 17:38:47 +02:00
Morris Jobke 81ceb00632 [sharing] handle shares of users that aren't available anymore
* properly handle the case where an abandoned share is left and
  simply skip it
2015-06-23 18:18:26 +02:00
C Montero-Luque e5237a2cfe version 7.0.7 beta 2015-06-23 11:56:31 -04:00
Morris Jobke e2b486eab6 Merge pull request #17034 from owncloud/backport-16890-stable7
Backport of #16890 to stable7
2015-06-23 16:32:21 +02:00
Joas Schilling b1fc1b2e4c Merge pull request #17096 from owncloud/stable7-fix-deleted-users
[Stable7] fix deleted users during upgrade migration
2015-06-23 14:51:31 +02:00
Lukas Reschke 063b8ea31d Merge pull request #16581 from owncloud/stable7-cors-no-cookie-auth
Disallow cookie auth for cors requests stable7
2015-06-23 13:37:50 +02:00
Thomas Müller 6fdd1d094f Merge pull request #17020 from owncloud/stable7-proper-repair-step-info
Proper repair step info during upgrade on cli
2015-06-23 13:37:38 +02:00
Morris Jobke e6bf1ca7b3 skip users that are not available anymore during sharing upgrade 2015-06-23 11:34:30 +02:00
Morris Jobke 6ee4fe56db Merge pull request #17073 from owncloud/appframework-type-cast-stable7
[stable7] Allow multiple whitespace in type hints in AppFramework
2015-06-22 15:46:51 +02:00
Robin McCorkell 28ea652e19 AppFramework annotation whitespace unit test 2015-06-22 12:18:03 +01:00
Robin McCorkell 8592c0efb7 Allow multiple whitespace in type hints in AppFramework
Type hints such as `@param bool     $doSomething` will now correctly get
parsed, allowing for alignment of docblock parameters if the app developer so
wishes.
2015-06-22 12:18:02 +01:00
Thomas Müller 1e0febe467 Merge pull request #17021 from owncloud/stable7-verify-path
[stable7] Verify if path exists
2015-06-19 15:47:12 +02:00
Arthur Schiwon 0766a679b4 Backport of #16890 to stable7
the user is gone, userExists will not bring him back. But the user's folder needs to be deleted anyway

delete user test to take getHome into account to ensure it is also deleted subsequently

Conflicts:
	apps/user_ldap/tests/user_ldap.php
2015-06-18 22:14:59 +02:00
Lukas Reschke ff2de8439a Verify if path exists
We need to check if the path exists and throw an error instead of handling this situation ungraciously.
2015-06-18 17:28:09 +02:00
Morris Jobke d48ab2b051 Proper repair step info during upgrade on cli 2015-06-18 16:49:20 +02:00
Morris Jobke f2b7eb85c8 Merge pull request #16991 from owncloud/stable7-verify-if-path-exists
[stable7] Verify if path exists
2015-06-17 16:59:24 +02:00
Lukas Reschke 1fc8afef1e Throw nicer error message instead 500 2015-06-17 15:41:21 +02:00
Lukas Reschke f4bc29a1e7 Verify if path exists
We need to verify if the specified path exists to gracefully prevent errors.
2015-06-17 15:08:39 +02:00
Morris Jobke 448ee4e7a9 Merge pull request #16969 from owncloud/stable7-backport-15549
[Stable7] don't update identical values
2015-06-17 10:22:44 +02:00
Jens-Christian Fischer 07ef143fde clarify the duplication of the $params array 2015-06-16 16:30:24 +02:00
Jens-Christian Fischer 4eb90cf3dc don't update identical values
The UPDATE oc_filecache statement blindly overwrites identical data.
Databases like Postgres that create a new row on an update
and mark the old one as dead will suffer from the previous
behaviour, as millions of "new" rows are created in the database.

This patch changes the WHERE clause to test for identical
values and not updating if the values in the DB are identical
to the ones being passed.
2015-06-16 16:30:19 +02:00
Thomas Müller 99d03daf65 Merge pull request #16864 from owncloud/backport-concatenation-7
[stable7] Don't use command concatenation
2015-06-11 09:42:49 +02:00
Morris Jobke 532a919a0c Merge pull request #16863 from owncloud/stable7-backport-16840
[stable7] Disable video preview if previews are disabled
2015-06-10 15:53:18 +02:00
Lukas Reschke b0314907c0 Don't use command concatenation
Possibly fixes https://github.com/owncloud/core/issues/16853
2015-06-10 15:19:18 +02:00
Morris Jobke 7ca01a65dd Disable video preview if previews are disabled 2015-06-10 15:00:30 +02:00
Morris Jobke 429fb87386 Merge pull request #16759 from owncloud/backport-16748-stable7
Backport stable7: port detection needs to take care of now thrown exceptions when LDAP …
2015-06-10 09:14:17 +02:00
Morris Jobke e5ff9f0b6b Merge pull request #16682 from owncloud/stable7-check-for-arry
Check if array
2015-06-10 07:36:31 +02:00
Morris Jobke fe92dd7381 Merge pull request #16707 from owncloud/stable7-fix-ie8-ie9
[stable7] Add min-height to login page for IE8 and IE9
2015-06-10 07:35:47 +02:00
blizzz 02bffbe670 Merge pull request #16773 from owncloud/fix-16582
return name instead of false, as it is on oc8 and master, so groups a…
2015-06-09 23:52:25 +02:00
Arthur Schiwon fda8d66697 return name instead of false, as it is on oc8 and master, so groups are displayed in files_external 2015-06-05 22:06:50 +02:00
Arthur Schiwon ef16f4ba57 port detection needs to take care of now thrown exceptions when LDAP server is not available 2015-06-05 13:20:46 +02:00
Frank Karlitschek 59b3c2fde3 7.0.6 2015-06-03 20:41:01 -04:00
Morris Jobke c72de30ccb Add min-height to login page for IE8 and IE9 2015-06-03 10:48:15 +02:00
Lukas Reschke a88df5c6ec Check if array
The great library that we use apparently uses mixed types for everything because 🙈

Fixes https://github.com/owncloud/core/issues/16679
2015-06-02 12:39:01 +02:00
Frank Karlitschek 54642984b1 7.0.6RC2 2015-06-01 18:54:41 -04:00
Thomas Müller 1c19fd15e0 Merge pull request #16666 from owncloud/fix-code
Fix compatibility with 5.3 again
2015-06-01 17:50:07 +02:00
Lukas Reschke 9b05d22b0c Fix compatibility with 5.4 again
Fixes https://github.com/owncloud/core/issues/16665
2015-06-01 17:24:58 +02:00
Lukas Reschke 200e9d9497 Disallow semicolons in passed commands 2015-06-01 17:06:21 +02:00
Lukas Reschke 5fa749cd96 Ensure that passed argument is always a string
Some code paths called the `normalizePath` functionality with types other than a string which resulted in unexpected behaviour.

Thus the function is now manually casting the type to a string and I corrected the usage in list.php as well.
2015-06-01 17:06:16 +02:00
Lukas Reschke a15710afad Clean application identifier before processing 2015-06-01 17:06:10 +02:00
Lukas Reschke 7071cf15c2 Revert custom patch that can cause problems 2015-06-01 17:06:05 +02:00
Morris Jobke 97dbd04e0a Merge pull request #16635 from owncloud/stable7-fix-themes-readme
[stable7] Fix themes README
2015-05-30 13:05:51 +02:00
Morris Jobke ba93c3d18b Fix themes README
Fixes #16617
2015-05-30 12:12:02 +02:00
Frank Karlitschek 927cae7efc 7.0.6 RC1 2015-05-29 13:58:39 -04:00
Vincent Petry b04d510053 Merge pull request #16608 from owncloud/fix_14588
[stable7] make sure to get the right list of users with access to the file when deleting a shared file
2015-05-28 16:53:55 +02:00
Bjoern Schiessle b4741cfa96 make sure to get the right list of users with access to the file, including the owner 2015-05-28 16:13:05 +02:00
Bernhard Posselt 6b4f1706b9 backport #16532 to stable7 2015-05-27 14:32:37 +02:00
Thomas Müller 55a122a9fe Merge pull request #13742 from owncloud/fix-12190-2-stable7
[backport #13740] backport #13740 to stable7
2015-05-26 16:06:21 +02:00
Morris Jobke 5014d2c60c Merge pull request #15402 from owncloud/response-setContentLengthHeader-stable7
[stable7] Add OC_Response::setContentLengthHeader() for Apache PHP SAPI workaround.
2015-05-20 10:15:58 +02:00
Morris Jobke 8a39256092 Merge pull request #15077 from owncloud/fix-smb-oc-admin-stable7
[stable7] Support constructing an SMB_OC without saved session credentials
2015-05-20 10:03:18 +02:00
Arthur Schiwon ae850d76ea add primary group users to resultset before caching 2015-05-14 01:09:57 +02:00
Morris Jobke 765526ec4c Merge pull request #15271 from owncloud/stable7-fix-ext-owncloud
[stable7] Fix bugs in ownCloud external storage
2015-05-13 09:40:20 +02:00
Thomas Müller 87052be76f Merge pull request #16291 from RealRancor/asset_pipe_note
Add note for asset pipeline and third-party apps on stable7
2015-05-13 00:52:20 +02:00
RealRancor 02ef384064 Add note for asset pipeline and third-party apps on stable7 2015-05-12 18:59:57 +02:00
Morris Jobke cf05d50654 Merge pull request #15863 from owncloud/public-reshare-webdav-stable7
[stable7] Fix webdav access for public reshare
2015-05-08 13:56:07 +02:00
Lukas Reschke f5a597b259 Merge pull request #16114 from owncloud/stable7-backport-15510-and-15465
[stable7] block cron.php and OCS API when in single user mode or maintenance mode
2015-05-08 12:13:24 +02:00
Thomas Müller 2c656b0e4c Fix singe user mode on public.php - take two 2015-05-06 12:14:34 +02:00
Thomas Müller 9c44e7bfb8 Fix single user check in case no user is logged in 2015-05-06 12:12:40 +02:00
Robin Appelman 0418b330d5 block ocs in single user mode 2015-05-06 12:10:02 +02:00
Robin Appelman 780530ec83 block webdav in single user mode 2015-05-06 12:08:58 +02:00
Robin Appelman 67c862c286 block cron when in single user mode 2015-05-06 11:51:14 +02:00
Joas Schilling 88006222a9 Disable OCS api when in maintenance mode 2015-05-06 11:50:08 +02:00
Lukas Reschke d01bfe3587 Merge pull request #15833 from owncloud/backport-files-external-fixes
Backport files external fixes
2015-05-05 12:22:35 +02:00
Robin Appelman 38644cffd4 fix subfolder reshares over webdav 2015-04-24 14:19:52 +02:00
Robin Appelman 2c10e31c8f resolve reshares in public webdav 2015-04-24 14:19:52 +02:00
Jörn Friedrich Dreyer e37f9c8351 use displayname lookup route in files_external settings 2015-04-23 14:23:17 +02:00
Jörn Friedrich Dreyer 79187fcb10 add lookup route for displaynames 2015-04-23 14:23:03 +02:00
Morris Jobke e72cd711ad Merge pull request #15332 from owncloud/dont_hide_exceptions
do not hide exception when ldap server has a hiccup
2015-04-22 22:48:29 +02:00
Arthur Schiwon 598f798c04 throw exception when LDAP Connection was lost 2015-04-22 15:22:11 +02:00
Jörn Friedrich Dreyer 919241cdda fix filesystem and encryption tests 2015-04-22 11:34:17 +02:00
Jörn Friedrich Dreyer f7db588e62 throw exception when backends don't provide a user instead of creating legacy local storages 2015-04-22 11:34:17 +02:00
Morris Jobke a2cc658f37 throw exception if setup is incomplete 2015-04-22 11:34:14 +02:00
Morris Jobke f830150acc more robust share dialog 2015-04-22 11:33:05 +02:00
Jörn Friedrich Dreyer 77a601c3fe fix_tests 2015-04-22 11:33:05 +02:00
Jörn Friedrich Dreyer 24037218dd do not disclose information, show generic error on login page 2015-04-22 11:33:05 +02:00
Jörn Friedrich Dreyer caae0e6f47 do not hide exception when ldap server has a hiccup 2015-04-22 11:32:58 +02:00
Arthur Schiwon 07988cf77c Fixes returns of group memberships and counting if all members have the specific groups as primary set. 2015-04-14 14:56:36 +02:00
Arthur Schiwon f3bd266787 Backport of #13740
inlcude AD primary group in user filter, if a group is selected. fixes #12190

fix counting of users in primary group

💄

adept to OC 7

and escape the search term

Conflicts:
	apps/user_ldap/lib/connection.php
2015-04-14 14:56:01 +02:00
Morris Jobke 03c9657607 Merge pull request #15559 from owncloud/backport-15541-stable7
[stable7] Add "Reply-To" support for sharing notifications
2015-04-13 08:50:22 +02:00
Lukas Reschke e6c2382a19 Add "Reply-To" support for sharing notifications
Very hacky backport of https://github.com/owncloud/core/pull/15541 - I changed the code path to use OC_Mail instead the OCP pendant since I didn't want to modify the public API. (OCP\Util::sendMail() is anyways deprecated with 8.1)
2015-04-12 23:03:32 +02:00
Morris Jobke 43b2f3c2dc Merge pull request #15435 from owncloud/dont_return_empty_groups
don't return null for not existing group id's
2015-04-10 14:23:38 +02:00
Jörn Friedrich Dreyer 1ae73f0e99 don't return null for not existing group id's 2015-04-07 13:47:10 +02:00
Andreas Fischer 3f23ae4a16 Add OC_Response::setContentLengthHeader() for Apache PHP SAPI workaround.
Do not send Content-Length headers with a value larger than PHP_INT_MAX
(2147483647) on Apache PHP SAPI 32-bit. PHP will eat them and send 2147483647
instead.

When X-Sendfile is enabled, Apache will send a correct Content-Length header,
even for files larger than 2147483647 bytes. When X-Sendfile is not enabled,
ownCloud will not send a Content-Length header. This prevents progress bars
from working, but allows the actual transfer to work properly.
2015-04-04 11:53:32 +02:00
Thomas Müller a4c0f259a5 Merge pull request #15370 from owncloud/stable7-backport-15353
Cron has to be executed with the correct user - fixes 13912 and others
2015-04-02 09:22:01 +02:00
Thomas Müller 6ebe04f8d4 Cron has to be executed with the correct user - fixes 13912 and others 2015-04-01 18:30:20 +02:00
Robin McCorkell 1c5a86a115 Fix bugs in ownCloud external storage 2015-03-27 12:31:20 +00:00
Morris Jobke 57d6c49a62 Merge pull request #15251 from owncloud/use_default_share_folder_oc7
always fall back to default share folder
2015-03-27 09:56:46 +01:00
Lukas Reschke 423311c7e8 Merge pull request #14498 from owncloud/kill-substr-mssql-stable7
[stable7] Remove hacky Substring support for MSSQL
2015-03-26 23:00:33 +01:00
Bjoern Schiessle 0cdeeec82b always fall back to default share folder 2015-03-26 22:46:43 +01:00
Morris Jobke 32bd2d15e3 Merge pull request #15072 from owncloud/fix_group_share
also call generateTarget for group shares
2015-03-26 22:24:42 +01:00
Morris Jobke ef1ddfc5db Merge pull request #14861 from owncloud/stable7-fix-sizepropagationwithshare
[stable7] Fix size propagation over shared storage boundary
2015-03-26 20:14:00 +01:00
Thomas Müller 529d45c5b2 Merge pull request #15161 from owncloud/stable7-fixcronconfig
[stable7] Fix config API usage in cron.php
2015-03-24 20:22:30 +01:00
Morris Jobke 0c72c99f04 Merge pull request #14889 from owncloud/backport-14849-stable7
[stable7] support paged results against 389ds.
2015-03-24 20:11:34 +01:00
Vincent Petry 2bb6a920e3 Fix config API usage in cron.php 2015-03-24 18:19:43 +01:00
Morris Jobke 1325649b4b Merge pull request #15141 from owncloud/backport-15123-stable7
[backport] [stable7] offset needs to be considered in computed limit
2015-03-24 11:12:16 +01:00
Arthur Schiwon bf7e2c756f offset needs to be considered in computed limit 2015-03-24 10:22:49 +01:00
Robin McCorkell 467da3c519 Support constructing an SMB_OC without saved session credentials
Conflicts:
	apps/files_external/lib/smb_oc.php
2015-03-20 16:07:19 +00:00
Bjoern Schiessle df2f85ee01 also call generateTarget for group share to add the correct prefix if share_folder is defined in config.php 2015-03-20 15:51:25 +01:00
Thomas Müller 9e52b174b1 Merge pull request #14902 from owncloud/tempmanager-fix-backport
Check directory handle before we use it
2015-03-16 09:44:52 +01:00
Robin McCorkell 03ca380815 Check directory handle before we use it 2015-03-15 18:28:01 +00:00
Arthur Schiwon db763760f1 support paged results against 389ds. 2015-03-13 23:03:47 +01:00
Robin Appelman 0ca1500330 also clear statcache in mapped local 2015-03-13 11:53:50 +01:00
Robin Appelman 92cbeefa34 Clear statcache before getting the mtime from local storage backends 2015-03-13 11:53:21 +01:00
Vincent Petry b62d20f2ee Uglify unit test to make them work on stable7 2015-03-13 11:36:31 +01:00
Vincent Petry 4f9c750a0a Add unit test for size propagation across share boundaries 2015-03-13 11:09:41 +01:00
Vincent Petry a529b2bf86 Fix size propagation over shared storage boundary 2015-03-13 11:09:36 +01:00
Thomas Müller 27ec925132 Merge pull request #14846 from owncloud/fix-14843-stable7
cron shall not operate in case we are in maintenance mode - fixes #14843
2015-03-13 09:25:18 +01:00
Thomas Müller c716776a90 cron shall not operate in case we are in maintenance mode - fixes #14843 2015-03-12 21:08:00 +01:00
Morris Jobke b588692ef4 Merge pull request #14637 from owncloud/backport-13341
[Stable7] Read version and product name from update template
2015-03-11 20:16:01 +01:00
Morris Jobke 5544509283 Merge pull request #14182 from RealRancor/update_office_preview
[stable7] Fix libre/openoffice preview on multi-user instances
2015-03-11 17:55:00 +01:00
Morris Jobke 39492eb020 Merge pull request #14707 from owncloud/ldap-reset-paged-search-on-null-limit-stable7
LDAP: reset paged search on null limit [stable7]
2015-03-09 08:15:18 +01:00
Arthur Schiwon 24eb2bcab5 set up paged search when limit is 0 2015-03-05 13:22:52 +01:00
Frank Karlitschek 8b83580af7 bump release 2015-03-02 22:45:17 +01:00
Frank Karlitschek 02757ad08e Merge pull request #14688 from owncloud/stable7-trashbin-selected-delete
[stable7] Fix deleting selected files in the trashbin
2015-03-04 08:54:56 -05:00
Robin Appelman 3bf505b566 Fix deleting selected files in the trashbin 2015-03-04 12:48:52 +01:00
Morris Jobke 1dea188fea Merge pull request #14642 from owncloud/issue/13751-only-variables-passed-by-reference
[Stable7] Fix "Only variables should be passed by reference" in stable7 template
2015-03-02 16:10:49 +01:00
Joas Schilling 86e4177914 Fix "Only variables should be passed by reference" in stable7 template 2015-03-02 14:31:38 +01:00
Vincent Petry ec71e0b4e6 Read version and product name from update template
During upgrade, the config settings aren't always available due to
base.php changes. This fix makes the update info page read the product
name and version from the update template, which already had them.
2015-03-02 11:39:23 +01:00
Lukas Reschke 51017e43a0 Remove hacky Substring support for MSSQL
Substring() is not required for the core functionality and this allows us to get rid of a huge hack...
2015-02-25 14:08:44 +01:00
Thomas Müller eb778eb2b0 Merge pull request #14425 from owncloud/backport-12313
[stable7] The class name is Movie NOT Movies
2015-02-23 15:12:57 +01:00
Olivier Paroz 45ad072c62 The class name is Movie NOT Movies
Conflicts:
	config/config.sample.php
	lib/private/preview.php
2015-02-23 11:02:46 +01:00
Frank Karlitschek 3ac33c865b 7.0.5 2015-02-16 04:56:33 +01:00
Lukas Reschke 431638742c Merge pull request #14040 from owncloud/stable7-app-upgrade-order
[Stable7] app upgrade order fix
2015-02-17 14:48:09 +01:00
Thomas Müller 7b432cbbf7 Merge pull request #12327 from owncloud/stable7l10nbport
backport some strings to stable7
2015-02-17 14:08:45 +01:00
Thomas Müller 01cede4511 Merge pull request #14254 from owncloud/console-execution-time-stable7
[backport-14243-stable7] console commands shall not be limited with respect to execution time
2015-02-16 19:44:07 +01:00
Thomas Müller 73954c44c6 console commands shall not be limited with respect to execution time - fixes #14156 2015-02-16 16:22:16 +01:00
Lukas Reschke e345ae7b53 Merge pull request #13988 from owncloud/group-share-collition-wrong-type-in-post-hook-stable7
[stable7] Do not overwrite the shareType so the post hook is still correct
2015-02-16 14:41:52 +01:00
RealRancor 9fd53ef84f Removed anchor in config.sample.php 2015-02-13 15:28:35 +01:00
RealRancor 6a46ede8b7 Fix libre/openoffice preview on multi-user instances 2015-02-12 23:20:54 +01:00
Jörn Friedrich Dreyer 3e5a1ad76b Merge pull request #14147 from owncloud/no-whitespace-from-themes-stable7
catch any whitespaces which might get written to the output buffer while...
2015-02-12 17:07:34 +01:00
Thomas Müller a45c606b96 catch any whitespaces which might get written to the output buffer while loading a theme 2015-02-12 11:28:59 +01:00
Thomas Müller fcad7252bd Merge pull request #14078 from owncloud/stable7-preview-hint
Add hint for troubleshooting MS Word previews
2015-02-11 21:17:59 +01:00
RealRancor c11edb9138 Add hint for troubleshooting MS Word previews 2015-02-11 01:14:58 +01:00
Vincent Petry 61852536fe Fix "other" app update stack 2015-02-10 11:58:25 +01:00
Arthur Schiwon d9d7774cc1 on ownCloud upgrade: upgrade all apps in order, load important ones 2015-02-10 11:58:23 +01:00
Joas Schilling 63e5282c41 Add a test for the post_shared hook shareType
Conflicts:
	tests/lib/share/share.php
2015-02-09 16:27:44 +01:00
Joas Schilling 0c3204c7a6 Do not overwrite the shareType so the post hook is still correct
Conflicts:
	lib/private/share/share.php
2015-02-09 16:26:29 +01:00
RealRancor c2a72ce6b0 external user app: Add note to enable it first 2015-02-07 20:12:15 +01:00
Lukas Reschke cbf8dd439c Normalize before processing 2015-02-06 15:09:31 +01:00
Frank Karlitschek c658ec658a 7.0.5 RC1 2015-02-06 02:46:00 +01:00
Morris Jobke 9db5323a92 Merge pull request #13927 from owncloud/fix_ghost_directories
fix creation of ghost directories
2015-02-06 00:07:43 +01:00
Bjoern Schiessle c58501ee87 for password protected link shares the password is stored in shareWith, so we need to set this manually to null for the hooks 2015-02-05 17:11:27 +01:00
Thomas Müller 3e9d8cce10 Merge pull request #13759 from owncloud/fix-12035
fix LDAP update routine to OC 7
2015-02-05 17:05:32 +01:00
Morris Jobke 6897be7a93 Merge pull request #13888 from owncloud/upload_to_root_of_mountpoint_stable7
detect root of mountpoint also if the trailing slash is missed
2015-02-04 16:21:34 +01:00
Björn Schießle f0b0e462ea Merge pull request #13796 from owncloud/issue/13490-stable7-backport
[stable7] use uid provided by setupfs hook to mount server2server shares
2015-02-04 14:59:44 +01:00
Bjoern Schiessle 2b83afdd7e detect root of mountpoint also if the trailing slash is missed 2015-02-04 14:53:17 +01:00
Morris Jobke a81b4c54d8 Merge pull request #13880 from owncloud/backport-10398-stable7
[backport #10398] Give a better error message for external shares with self-signed ssl cer...
2015-02-04 14:09:25 +01:00
Robin Appelman 7975b74816 Give a better error message for external shares with self-signed ssl certificates 2015-02-04 12:19:08 +01:00
Thomas Müller 361b70e4d7 Merge pull request #13803 from owncloud/revert-close-cursor-stable7
Revert "Close cursor early in calculateFolderSize" for now
2015-01-30 23:23:44 +01:00
Morris Jobke 8305ae6b09 Merge pull request #13798 from owncloud/update-sabre-dav-stable7
Update sabre dav to 1.8.12 on stable7
2015-01-30 16:10:34 +01:00
Joas Schilling 91fc933432 Revert "Close cursor early in calculateFolderSize"
This reverts commit 234f33e01e.
2015-01-30 15:35:54 +01:00
Joas Schilling ed60bdeac9 Update sabre dav to 1.8.12 on stable7 2015-01-30 14:43:41 +01:00
Joas Schilling bd14af5806 use uid provided by setupfs hook to mount server2server shares
otherwise mount will fail for public link shares

backport of 66f0db30b2
2015-01-30 12:57:03 +01:00
Vincent Petry 234f33e01e Close cursor early in calculateFolderSize
This method triggers additional queries in $this->update() so to avoid
potential database locks or delays, we close the cursor as soon as it is not needed any more
2015-01-29 14:53:44 +01:00
Arthur Schiwon 441f807bce fix update routine 2015-01-29 12:51:12 +01:00
Morris Jobke 80560e70b7 Merge pull request #13470 from owncloud/stable7-share-fixfindshareforuserwithmultiplegroups
[stable7] Fix getItemSharedWithUser for groups
2015-01-23 12:59:39 +01:00
Georg Ehrke 56c51d481c add config-option for an image's maximum filesize when generating previews 2015-01-22 23:23:36 +01:00
Georg Ehrke 2d2e024cfa remove insane debug-log from OC_Image 2015-01-22 23:21:40 +01:00
Morris Jobke 491c714f54 Fix undefined offset 1 for wrong user mail address
* fixes Undefined offset: 1 at lib/private/mail.php#143
2015-01-22 17:26:13 +01:00
Robin Appelman 8459b9f6fb Add unit test 2015-01-22 16:18:36 +01:00
Robin Appelman 153ff1b766 Remove duplicated slashes from the requested url 2015-01-22 16:18:32 +01:00
Morris Jobke 11efe732f9 Merge pull request #13555 from owncloud/issue/13482-stable7
Stable7 Backport Set the debugoutput channel to error_log instead of echoing it
2015-01-21 16:31:04 +01:00
Joas Schilling f03a1868ab Set the debugoutput channel to error_log instead of echoing it 2015-01-21 15:34:58 +01:00
Arthur Schiwon 1c000b799b this must be larger then (>), since buggy behaviour occurs when the parameter is a small number 2015-01-21 14:38:47 +01:00
Vincent Petry 18d46dfdeb Fix getItemSharedWithUser for groups
Fixed SQL query for whenever a user has more than one group.
Added missing $owner where clause for group lookup.
Added unit tests for the group cases.

Backport of 40931a8b0d from master
2015-01-20 22:07:21 +01:00
Thomas Müller 9d761fcaee Merge pull request #13422 from owncloud/user-mgnt-init-fix
Increase initial user count to 50
2015-01-19 15:08:16 +01:00
Carla Schroder 5f70ed188b Note in config.sample.php that certain previews are not available in ms windows 2015-01-17 09:27:27 +01:00
Morris Jobke 616fd4b54a Increase initial user count to 50
* fix initial user count if you have a big screen (or a portrait screen)
2015-01-16 18:04:29 +01:00
Thomas Müller 6d87922cea Merge pull request #13384 from owncloud/stable7-fix-13317-backport
Fix backport of #13317
2015-01-15 17:27:09 +01:00
Robin Appelman 0753514e5b Fix test 2015-01-15 14:24:54 +01:00
Robin Appelman 7ef006e1c9 php <5.4 style array 2015-01-15 14:02:36 +01:00
Robin Appelman 5a58d142e5 Proper constant for stable7 2015-01-15 14:02:11 +01:00
Robin Appelman db51d9aacb Add View::getMount() for stable7 2015-01-15 14:01:52 +01:00
Vincent Petry d534f262aa Use source storage permissions when scanning shared storage 2015-01-15 11:15:39 +01:00
Robin Appelman 0f04bfc319 Return valid fileinfo objects for part files 2015-01-15 00:22:38 +01:00
Morris Jobke 4d42485bf5 drop useless "!!! No reuse of etag" - fixes #13187
Backport of 9b49b52fc6 from master
2015-01-13 13:47:09 +01:00
Arthur Schiwon 713f2b3a52 fix retrieval of user groups
Conflicts:
	apps/user_ldap/lib/connection.php
2015-01-13 10:19:50 +01:00
Morris Jobke 0d39a63b05 Merge pull request #13186 from owncloud/no-session-for-formfactor-stable7
no need to store the form factor in the session - it's computation is ra...
2015-01-09 18:19:26 +01:00
Jan-Christoph Borchardt bd1bf9e9ac replace outdated 'shared' people icon with regular share icon as fallback 2015-01-09 17:58:45 +01:00
Thomas Müller 6552fec113 no need to store the form factor in the session - it's computation is rather cheep
Conflicts:
	lib/private/template.php
2015-01-09 10:19:28 +01:00
Morris Jobke d5190b5481 Merge pull request #12735 from owncloud/temp-handling-stable7
[stable7] Cleanup handling of temporary files
2015-01-08 18:35:00 +01:00
Robin Appelman 06bc987bd9 Use the TempManager to handle temporary files
Conflicts:
	lib/private/helper.php
2015-01-08 16:22:14 +01:00
Robin Appelman 344606b2c8 Add \OC\TempManager to handle creating and cleaning temporary files
Conflicts:
	lib/private/server.php
	lib/public/iservercontainer.php
2015-01-08 16:22:14 +01:00
Vincent Petry a5574e885c Fix source path when share is a mount point
Whenever an external storage mount point is shared directly, its path is
empty which causes a leading slash to appear in the source path.

This fix removes the bogus leading slash in such situation.

Backport of 01c83158bb from master
2015-01-08 16:07:44 +01:00
Robin Appelman bf1f9df590 Prevent leaking db connection info in the stacktrace 2015-01-07 09:48:25 +01:00
Morris Jobke 2fd2b182e7 Check for version before mounting a public link
* ownCloud 7.0.0 is needed - version of merge of server <-> server
  sharing - https://github.com/owncloud/core/pull/8399
* adjust error message
2015-01-05 13:23:53 +01:00
Byron Marohn 8778af681c Added error check to lib/private/image.php
This checks that imagecreatetruecolor actually creates an image, rather than returning FALSE.
Without this check, subsequent loop might create billions of ERROR-level log messages.

Signed-off-by: Byron Marohn <combustible@live.com>
2015-01-02 08:48:59 +01:00
blizzz fb63e75743 Merge pull request #12643 from owncloud/ldap-user-cleanup-stable7
LDAP User Cleanup - stable7
2014-12-19 19:04:50 +01:00
Morris Jobke 4c0af1b2a2 Merge pull request #12332 from owncloud/langbport2
more strings to backport
2014-12-19 14:14:03 +01:00
Morris Jobke 9c38baac9e show spinner on file upload in IE8, 9 2014-12-19 02:04:35 +01:00
Arthur Schiwon dd18f963d4 and don't forget to adjust tests 2014-12-18 12:22:34 +01:00
Arthur Schiwon 5d46dfd2b4 PHPdoc fixes, no code change 2014-12-17 16:08:01 +01:00
Arthur Schiwon 1d54735d5d forgotten file 2014-12-17 13:52:09 +01:00
Arthur Schiwon cb5f9d2164 add ldap:check-user to check user existance on the fly 2014-12-17 13:37:53 +01:00
Jan-Christoph Borchardt a26ddb33a2 Merge pull request #12798 from cyberb/stable7
fixes #12434 (stable7)
2014-12-16 14:35:11 +01:00
Arthur Schiwon dd8ba68e07 LDAP User Cleanup
background job for user clean up

adjust user backend for clean up

register background job

remove dead code

dependency injection

make Helper non-static for proper testing

check whether it is OK to run clean up job. Do not forget to pass arguments.

use correct method to get the config from server

methods can be private, proper indirect testing is given

no automatic user deletion

make limit readable for test purposes

make method less complex

add first tests

let preferences accept limit and offset for getUsersForValue

DI via constructor does not work for background jobs

after detecting, now we have retrieving deleted users and their details

we need this method to be public for now

finalize export method, add missing getter

clean up namespaces and get rid of unnecessary files

helper is not static anymore

cleanup according to scrutinizer

add cli tool to show deleted users

uses are necessary after recent namespace change

also remove user from mappings table on deletion

add occ command to delete users

fix use statement

improve output

big fixes / improvements

PHP doc

return true in userExists early for cleaning up deleted users

bump version

control state and interval with one config.php setting, now ldapUserCleanupInterval. 0 will disable it. enabled by default.

improve doc

rename cli method to be consistent with  others

introduce ldapUserCleanupInterval in sample config

don't show last login as unix epoche start when no  login happend

less log output

consistent namespace for OfflineUser

rename GarbageCollector to DeletedUsersIndex and move it to user subdir

fix unit tests

add tests for deleteUser

more test adjustements
2014-12-15 12:56:16 +01:00
Morris Jobke bfe4ee6e47 Merge pull request #12825 from d1saster/stable7-fixpcre
make regex in controllermethodreflector.php compatible with PCRE 6.x
2014-12-14 10:51:56 +01:00
Morris Jobke a429fa74d9 Merge pull request #12655 from owncloud/fix-appstore-link
fix broken link on app management page for apps without ocsid
2014-12-13 11:54:30 +01:00
Morris Jobke f0a0e44d2e fix broken link on app management page for apps without ocsid - fix #9574, fix #10461 2014-12-13 08:39:38 +01:00
Philipp Knechtges 533e8e14b6 make regex in controllermethodreflector.php compatible with PCRE 6.x
The syntax ?<...> seems to be only supported from PCRE 7.0 on. For
backwards-compability ?P<...> is used.
2014-12-13 02:16:37 +01:00
Vincent Petry 60099b91c4 Merge pull request #12624 from nazar-pc/stable7
Backport of #11524 into stable7
2014-12-12 11:34:40 +01:00
Georg Ehrke 5fd1d54607 remove ugly hack and don't use OC\Preview\Image for tiffs and svgs 2014-12-12 08:30:17 +01:00
Vincent Petry 0eb3496ab6 Return real mime type on PROPFIND
Return the real (insecure) mime type on PROPFIND
2014-12-12 08:29:44 +01:00
Robin Appelman bd06b4cf42 Ensure user mountpoints are setup when using getUserFolder 2014-12-12 08:29:15 +01:00
Vincent Petry 72c0cc2267 Do not remove dir entry if it has the same name as the parent
This fixes an issue when a subdir has the same name as its parent, it
would get exluded from the list.
2014-12-11 23:57:17 +01:00
Boris Rybalkin 43b6676d0e fixes #12434 2014-12-11 18:44:50 +00:00
Morris Jobke 36e7d3b7da Merge pull request #12663 from zinks-/l10n-fr-backport
Patched french translation (backported from master)
2014-12-10 08:59:11 +01:00
Morris Jobke 7a60651037 Merge pull request #12656 from owncloud/stable7-fix-12164
Wipe cache if there is no response from feed
2014-12-10 08:26:02 +01:00
Robin Appelman 50705cfaf8 Add js unit test 2014-12-10 08:24:35 +01:00
Robin Appelman 3720ba9318 Dont show the delete button for selected files if one of the selected files is not deletable 2014-12-10 08:24:31 +01:00
Robin Appelman a05fc9dc73 Check if files are deletable before trying to delete them 2014-12-10 08:24:27 +01:00
Morris Jobke cf0a12f999 fix placeholder fake in IE8 & 9 that brokes group listing in user management - fixes #12525 2014-12-10 08:23:26 +01:00
Volkan Gezer 5fcc3401e2 translated saved message in files external 2014-12-10 08:23:03 +01:00
Victor Dubiniuk 60b2dd6ab4 Skip headers that can not be split 2014-12-10 08:22:06 +01:00
Morris Jobke ed96f8c628 remove duplicate loaded personal.js - fixes #12674 2014-12-10 08:21:40 +01:00
Victor Dubiniuk 21f467dd36 Wipe cache if there is no response from feed 2014-12-06 15:19:34 +03:00
Thomas Imbreckx 26e504e096 Patched french translation (backported from master) 2014-12-05 19:14:08 +01:00
Vincent Petry 913ad8634f Merge pull request #11524 from nazar-pc/patch-1
Page size calculation based on real page height
2014-12-04 17:07:41 +01:00
Volkan Gezer 11ca5588ea more strings to backport 2014-11-20 16:51:10 +01:00
Volkan Gezer c494887d98 backport some strings to stable7 2014-11-20 15:13:37 +01:00
254 changed files with 4085 additions and 1165 deletions
+3 -1
View File
@@ -27,7 +27,9 @@ $success = true;
//Now delete
foreach ($files as $file) {
if (\OC\Files\Filesystem::file_exists($dir . '/' . $file) &&
!\OC\Files\Filesystem::unlink($dir . '/' . $file)) {
!(\OC\Files\Filesystem::isDeletable($dir . '/' . $file) &&
\OC\Files\Filesystem::unlink($dir . '/' . $file))
) {
$filesWithError .= $file . "\n";
$success = false;
}
+1 -1
View File
@@ -5,7 +5,7 @@ OCP\JSON::checkLoggedIn();
$l = OC_L10N::get('files');
// Load the files
$dir = isset($_GET['dir']) ? $_GET['dir'] : '';
$dir = isset($_GET['dir']) ? (string)$_GET['dir'] : '';
$dir = \OC\Files\Filesystem::normalizePath($dir);
try {
+3
View File
@@ -119,6 +119,9 @@ if($source) {
$freeSpace = $storageStats['freeSpace'];
foreach($meta['wrapper_data'] as $header) {
if (strpos($header, ':') === false){
continue;
}
list($name, $value) = explode(':', $header);
if ('content-length' === strtolower(trim($name))) {
$length = (int) trim($value);
+4
View File
@@ -49,6 +49,10 @@ if (empty($_POST['dirToken'])) {
// The token defines the target directory (security reasons)
$path = \OC\Files\Filesystem::getPath($linkItem['file_source']);
if($path === null) {
OCP\JSON::error(array('data' => array_merge(array('message' => $l->t('Unable to set upload directory.')))));
die();
}
$dir = sprintf(
"/%s/%s",
$path,
+1 -1
View File
@@ -39,7 +39,7 @@ $ftype=\OC_Helper::getSecureMimeType(\OC\Files\Filesystem::getMimeType( $filenam
header('Content-Type:'.$ftype);
OCP\Response::setContentDispositionHeader(basename($filename), 'attachment');
OCP\Response::disableCaching();
header('Content-Length: '.\OC\Files\Filesystem::filesize($filename));
OCP\Response::setContentLengthHeader(\OC\Files\Filesystem::filesize($filename));
OC_Util::obEnd();
\OC\Files\Filesystem::readfile( $filename );
+15
View File
@@ -490,6 +490,21 @@ OC.Upload = {
}
});
} else {
// for all browsers that don't support the progress bar
// IE 8 & 9
// show a spinner
fileupload.on('fileuploadstart', function() {
$('#upload').addClass('icon-loading');
$('#upload .icon-upload').hide();
});
// hide a spinner
fileupload.on('fileuploadstop fileuploadfail', function() {
$('#upload').removeClass('icon-loading');
$('#upload .icon-upload').show();
});
}
}
+18 -6
View File
@@ -49,8 +49,10 @@
fileSummary: null,
initialized: false,
// number of files per page
pageSize: 20,
// number of files per page, calculated dynamically
pageSize: function() {
return Math.ceil(this.$container.height() / 50);
},
/**
* Array of files in the current folder.
@@ -479,7 +481,8 @@
mimetype: $el.attr('data-mime'),
type: $el.attr('data-type'),
size: parseInt($el.attr('data-size'), 10),
etag: $el.attr('data-etag')
etag: $el.attr('data-etag'),
permissions: parseInt($el.attr('data-permissions'), 10)
};
},
@@ -490,7 +493,7 @@
*/
_nextPage: function(animate) {
var index = this.$fileList.children().length,
count = this.pageSize,
count = this.pageSize(),
tr,
fileData,
newTrs = [],
@@ -1167,7 +1170,7 @@
// if there are less elements visible than one page
// but there are still pending elements in the array,
// then directly append the next page
if (lastIndex < this.files.length && lastIndex < this.pageSize) {
if (lastIndex < this.files.length && lastIndex < this.pageSize()) {
this._nextPage(true);
}
@@ -1562,7 +1565,7 @@
this.$el.find('.selectedActions').addClass('hidden');
}
else {
canDelete = (this.getDirectoryPermissions() & OC.PERMISSION_DELETE);
canDelete = (this.getDirectoryPermissions() & OC.PERMISSION_DELETE) && this.isSelectedDeletable();
this.$el.find('.selectedActions').removeClass('hidden');
this.$el.find('#headerSize a>span:first').text(OC.Util.humanFileSize(summary.totalSize));
var selection = '';
@@ -1582,6 +1585,15 @@
}
},
/**
* Check whether all selected files are deletable
*/
isSelectedDeletable: function() {
return _.reduce(this.getSelectedFiles(), function(deletable, file) {
return deletable && (file.permissions & OC.PERMISSION_DELETE);
}, true);
},
/**
* Returns whether all files are selected
* @return true if all files are selected, false otherwise
+1 -1
View File
@@ -350,7 +350,7 @@ var createDragShadow = function(event) {
}
// do not show drag shadow for too many files
var selectedFiles = _.first(FileList.getSelectedFiles(), FileList.pageSize);
var selectedFiles = _.first(FileList.getSelectedFiles(), FileList.pageSize());
selectedFiles = _.sortBy(selectedFiles, FileList._fileInfoCompare);
if (!isDragSelected && selectedFiles.length === 1) {
+4 -4
View File
@@ -17,7 +17,7 @@ $TRANSLATIONS = array(
"Invalid Token" => "Jeton non valide",
"No file was uploaded. Unknown error" => "Aucun fichier n'a été envoyé. Erreur inconnue",
"There is no error, the file uploaded with success" => "Aucune erreur, le fichier a été envoyé avec succès.",
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Le fichier envoyé dépasse l'instruction upload_max_filesize située dans le fichier php.ini:",
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Le fichier envoyé dépasse l'instruction upload_max_filesize située dans le fichier php.ini :",
"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Le fichier envoyé dépasse l'instruction MAX_FILE_SIZE qui est spécifiée dans le formulaire HTML.",
"The uploaded file was only partially uploaded" => "Le fichier n'a été que partiellement envoyé.",
"No file was uploaded" => "Pas de fichier envoyé.",
@@ -62,7 +62,7 @@ $TRANSLATIONS = array(
"Your storage is almost full ({usedSpacePercent}%)" => "Votre espace de stockage est presque plein ({usedSpacePercent}%)",
"Encryption App is enabled but your keys are not initialized, please log-out and log-in again" => "L'application de chiffrement est activée mais vos clés ne sont pas initialisées, veuillez vous déconnecter et ensuite vous reconnecter.",
"Invalid private key for Encryption App. Please update your private key password in your personal settings to recover access to your encrypted files." => "Votre clef privée pour l'application de chiffrement est invalide ! Veuillez mettre à jour le mot de passe de votre clef privée dans vos paramètres personnels pour récupérer l'accès à vos fichiers chiffrés.",
"Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Le chiffrement était désactivé mais vos fichiers sont toujours chiffrés. Veuillez vous rendre sur vos Paramètres personnels pour déchiffrer vos fichiers.",
"Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files." => "Le chiffrement a été désactivé mais vos fichiers sont toujours chiffrés. Veuillez vous rendre sur vos paramètres personnels pour déchiffrer vos fichiers.",
"{dirs} and {files}" => "{dirs} et {files}",
"%s could not be renamed" => "%s ne peut être renommé",
"Upload (max. %s)" => "Envoi (max. %s)",
@@ -77,13 +77,13 @@ $TRANSLATIONS = array(
"Text file" => "Fichier texte",
"New folder" => "Nouveau dossier",
"Folder" => "Dossier",
"From link" => "Depuis le lien",
"From link" => "Depuis un lien",
"You dont have permission to upload or create files here" => "Vous n'avez pas la permission de téléverser ou de créer des fichiers ici",
"Nothing in here. Upload something!" => "Il n'y a rien ici ! Envoyez donc quelque chose :)",
"Download" => "Télécharger",
"Upload too large" => "Téléversement trop volumineux",
"The files you are trying to upload exceed the maximum size for file uploads on this server." => "Les fichiers que vous essayez d'envoyer dépassent la taille maximale permise par ce serveur.",
"Files are being scanned, please wait." => "Les fichiers sont en cours d'analyse, veuillez patienter.",
"Currently scanning" => "Analyse en cours de traitement"
"Currently scanning" => "Analyse en cours",
);
$PLURAL_FORMS = "nplurals=2; plural=(n > 1);";
+31 -10
View File
@@ -20,7 +20,7 @@
*/
describe('OCA.Files.FileList tests', function() {
var testFiles, alertStub, notificationStub, fileList;
var testFiles, alertStub, notificationStub, fileList, pageSizeStub;
var bcResizeStub;
/**
@@ -97,7 +97,8 @@ describe('OCA.Files.FileList tests', function() {
name: 'One.txt',
mimetype: 'text/plain',
size: 12,
etag: 'abc'
etag: 'abc',
permissions: OC.PERMISSION_ALL
}, {
id: 2,
type: 'file',
@@ -105,6 +106,7 @@ describe('OCA.Files.FileList tests', function() {
mimetype: 'image/jpeg',
size: 12049,
etag: 'def',
permissions: OC.PERMISSION_ALL
}, {
id: 3,
type: 'file',
@@ -112,15 +114,17 @@ describe('OCA.Files.FileList tests', function() {
mimetype: 'application/pdf',
size: 58009,
etag: '123',
permissions: OC.PERMISSION_ALL
}, {
id: 4,
type: 'dir',
name: 'somedir',
mimetype: 'httpd/unix-directory',
size: 250,
etag: '456'
etag: '456',
permissions: OC.PERMISSION_ALL
}];
pageSizeStub = sinon.stub(OCA.Files.FileList.prototype, 'pageSize').returns(20);
fileList = new OCA.Files.FileList($('#app-content-files'));
});
afterEach(function() {
@@ -130,6 +134,7 @@ describe('OCA.Files.FileList tests', function() {
notificationStub.restore();
alertStub.restore();
bcResizeStub.restore();
pageSizeStub.restore();
});
describe('Getters', function() {
it('Returns the current directory', function() {
@@ -814,7 +819,7 @@ describe('OCA.Files.FileList tests', function() {
fileList.$fileList.on('fileActionsReady', handler);
fileList._nextPage();
expect(handler.calledOnce).toEqual(true);
expect(handler.getCall(0).args[0].$files.length).toEqual(fileList.pageSize);
expect(handler.getCall(0).args[0].$files.length).toEqual(fileList.pageSize());
});
it('does not trigger "fileActionsReady" event after single add with silent argument', function() {
var handler = sinon.stub();
@@ -1478,6 +1483,17 @@ describe('OCA.Files.FileList tests', function() {
$('.select-all').click();
expect(fileList.$el.find('.delete-selected').hasClass('hidden')).toEqual(true);
});
it('show doesnt show the delete action if one or more files are not deletable', function () {
fileList.setFiles(testFiles);
$('#permissions').val(OC.PERMISSION_READ | OC.PERMISSION_DELETE);
$('.select-all').click();
expect(fileList.$el.find('.delete-selected').hasClass('hidden')).toEqual(false);
testFiles[0].permissions = OC.PERMISSION_READ;
$('.select-all').click();
fileList.setFiles(testFiles);
$('.select-all').click();
expect(fileList.$el.find('.delete-selected').hasClass('hidden')).toEqual(true);
});
});
describe('Actions', function() {
beforeEach(function() {
@@ -1494,7 +1510,8 @@ describe('OCA.Files.FileList tests', function() {
mimetype: 'text/plain',
type: 'file',
size: 12,
etag: 'abc'
etag: 'abc',
permissions: OC.PERMISSION_ALL
});
expect(files[1]).toEqual({
id: 3,
@@ -1502,7 +1519,8 @@ describe('OCA.Files.FileList tests', function() {
name: 'Three.pdf',
mimetype: 'application/pdf',
size: 58009,
etag: '123'
etag: '123',
permissions: OC.PERMISSION_ALL
});
expect(files[2]).toEqual({
id: 4,
@@ -1510,7 +1528,8 @@ describe('OCA.Files.FileList tests', function() {
name: 'somedir',
mimetype: 'httpd/unix-directory',
size: 250,
etag: '456'
etag: '456',
permissions: OC.PERMISSION_ALL
});
});
it('Removing a file removes it from the selection', function() {
@@ -1523,7 +1542,8 @@ describe('OCA.Files.FileList tests', function() {
mimetype: 'text/plain',
type: 'file',
size: 12,
etag: 'abc'
etag: 'abc',
permissions: OC.PERMISSION_ALL
});
expect(files[1]).toEqual({
id: 4,
@@ -1531,7 +1551,8 @@ describe('OCA.Files.FileList tests', function() {
name: 'somedir',
mimetype: 'httpd/unix-directory',
size: 250,
etag: '456'
etag: '456',
permissions: OC.PERMISSION_ALL
});
});
describe('Download', function() {
-1
View File
@@ -19,5 +19,4 @@ Note that this app encrypts all files that are touched by ownCloud, so external
<types>
<filesystem/>
</types>
<ocsid>166047</ocsid>
</info>
+1 -1
View File
@@ -1 +1 @@
0.6.1
0.6.2
+4 -4
View File
@@ -4,8 +4,8 @@ $TRANSLATIONS = array(
"Could not enable recovery key. Please check your recovery key password!" => "Impossible d'activer la clé de récupération. Veuillez vérifier votre mot de passe de clé de récupération !",
"Recovery key successfully disabled" => "Clé de récupération désactivée avec succès",
"Could not disable recovery key. Please check your recovery key password!" => "Impossible de désactiver la clé de récupération. Veuillez vérifier votre mot de passe de clé de récupération !",
"Password successfully changed." => "Mot de passe changé avec succès ",
"Could not change the password. Maybe the old password was not correct." => "Ne peut pas changer le mot de passe. L'ancien mot de passe est peut-être incorrect.",
"Password successfully changed." => "Mot de passe changé avec succès.",
"Could not change the password. Maybe the old password was not correct." => "Erreur lors du changement de mot de passe. L'ancien mot de passe est peut-être incorrect.",
"Private key password successfully updated." => "Mot de passe de la clé privé mis à jour avec succès.",
"Could not update the private key password. Maybe the old password was not correct." => "Impossible de mettre à jour le mot de passe de la clé privé. Peut-être que l'ancien mot de passe n'était pas correcte.",
"Encryption app not initialized! Maybe the encryption app was re-enabled during your session. Please try to log out and log back in to initialize the encryption app." => "L'application de chiffrement n'est pas initialisée ! Peut-être que cette application a été réactivée pendant votre session. Veuillez essayer de vous déconnecter et ensuite de vous reconnecter pour initialiser l'application de chiffrement.",
@@ -22,8 +22,8 @@ $TRANSLATIONS = array(
"Enable recovery key (allow to recover users files in case of password loss):" => "Activer la clef de récupération (permet de récupérer les fichiers des utilisateurs en cas de perte de mot de passe).",
"Recovery key password" => "Mot de passe de la clef de récupération",
"Repeat Recovery key password" => "Répétez le mot de passe de la clé de récupération",
"Enabled" => "Activer",
"Disabled" => "Désactiver",
"Enabled" => "Activé",
"Disabled" => "Désactivé",
"Change recovery key password:" => "Modifier le mot de passe de la clef de récupération :",
"Old Recovery key password" => "Ancien mot de passe de la clef de récupération",
"New Recovery key password" => "Nouveau mot de passe de la clef de récupération",
+9 -2
View File
@@ -23,6 +23,7 @@
*/
namespace OCA\Encryption;
use OC\User\NoUserException;
/**
* Class for utilities relating to encrypted file storage system
@@ -903,8 +904,14 @@ class Util {
) {
return true;
}
$util = new Util($this->view, $user);
return $util->ready();
try {
$util = new Util($this->view, $user);
return $util->ready();
} catch (NoUserException $e) {
\OCP\Util::writeLog('Encryption library',
'No User object for '.$user, \OCP\Util::DEBUG);
return false;
}
}
/**
@@ -28,7 +28,6 @@ $result = false;
if ($recoveryAdminEnabled || !$privateKeySet) {
\OCP\Util::addscript('files_encryption', 'settings-personal');
\OCP\Util::addScript('settings', 'personal');
$tmpl->assign('recoveryEnabled', $recoveryAdminEnabled);
$tmpl->assign('recoveryEnabledForUser', $recoveryEnabledForUser);
+15 -9
View File
@@ -37,6 +37,7 @@ class Test_Encryption_Hooks extends \OCA\Files_Encryption\Tests\TestCase {
const TEST_ENCRYPTION_HOOKS_USER1 = "test-encryption-hooks-user1.dot";
const TEST_ENCRYPTION_HOOKS_USER2 = "test-encryption-hooks-user2.dot";
const TEST_ENCRYPTION_HOOKS_USER3 = "test-encryption-hooks-user3.dot";
/** @var \OC\Files\View */
public $user1View; // view on /data/user1/files
@@ -120,6 +121,7 @@ class Test_Encryption_Hooks extends \OCA\Files_Encryption\Tests\TestCase {
// cleanup test user
\OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
\OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
\OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER3);
\OC_Hook::clear();
\OC_FileProxy::clearProxies();
@@ -444,31 +446,35 @@ class Test_Encryption_Hooks extends \OCA\Files_Encryption\Tests\TestCase {
$view = new \OC\Files\View();
// set user password for the first time
\OCA\Encryption\Hooks::postCreateUser(array('uid' => 'newUser', 'password' => 'newUserPassword'));
\OC_User::createUser(self::TEST_ENCRYPTION_HOOKS_USER3, 'newUserPassword');
\OCA\Encryption\Hooks::postCreateUser(array(
'uid' => self::TEST_ENCRYPTION_HOOKS_USER3,
'password' => 'newUserPassword')
);
$this->assertTrue($view->file_exists('public-keys/newUser.public.key'));
$this->assertTrue($view->file_exists('newUser/files_encryption/newUser.private.key'));
$this->assertTrue($view->file_exists('public-keys/'.self::TEST_ENCRYPTION_HOOKS_USER3.'.public.key'));
$this->assertTrue($view->file_exists(self::TEST_ENCRYPTION_HOOKS_USER3.'/files_encryption/'.self::TEST_ENCRYPTION_HOOKS_USER3.'.private.key'));
// check if we are able to decrypt the private key
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, 'newUser');
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, self::TEST_ENCRYPTION_HOOKS_USER3);
$privateKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, 'newUserPassword');
$this->assertTrue(is_string($privateKey));
// change the password before the user logged-in for the first time,
// we can replace the encryption keys
\OCA\Encryption\Hooks::setPassphrase(array('uid' => 'newUser', 'password' => 'passwordChanged'));
\OCA\Encryption\Hooks::setPassphrase(array('uid' => self::TEST_ENCRYPTION_HOOKS_USER3, 'password' => 'passwordChanged'));
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, 'newUser');
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, self::TEST_ENCRYPTION_HOOKS_USER3);
$privateKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, 'passwordChanged');
$this->assertTrue(is_string($privateKey));
// now create a files folder to simulate a already used account
$view->mkdir('/newUser/files');
$view->mkdir('/'.self::TEST_ENCRYPTION_HOOKS_USER3.'/files');
// change the password after the user logged in, now the password should not change
\OCA\Encryption\Hooks::setPassphrase(array('uid' => 'newUser', 'password' => 'passwordChanged2'));
\OCA\Encryption\Hooks::setPassphrase(array('uid' => self::TEST_ENCRYPTION_HOOKS_USER3, 'password' => 'passwordChanged2'));
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, 'newUser');
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, self::TEST_ENCRYPTION_HOOKS_USER3);
$privateKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, 'passwordChanged2');
$this->assertFalse($privateKey);
+72
View File
@@ -38,6 +38,7 @@ use OCA\Encryption;
class Test_Encryption_Trashbin extends \OCA\Files_Encryption\Tests\TestCase {
const TEST_ENCRYPTION_TRASHBIN_USER1 = "test-trashbin-user1";
const TEST_ENCRYPTION_TRASHBIN_USER2 = "test-trashbin-user2";
public $userId;
public $pass;
@@ -60,6 +61,7 @@ class Test_Encryption_Trashbin extends \OCA\Files_Encryption\Tests\TestCase {
\OC_Hook::clear('OC_Filesystem');
\OC_Hook::clear('OC_User');
\OC_Hook::clear('OCP\\Share');
// trashbin hooks
\OCA\Files_Trashbin\Trashbin::registerHooks();
@@ -67,11 +69,24 @@ class Test_Encryption_Trashbin extends \OCA\Files_Encryption\Tests\TestCase {
// Filesystem related hooks
\OCA\Encryption\Helper::registerFilesystemHooks();
// register share hooks
\OC::registerShareHooks();
\OCA\Files_Sharing\Helper::registerHooks();
// Sharing related hooks
\OCA\Encryption\Helper::registerShareHooks();
// Filesystem related hooks
\OCA\Encryption\Helper::registerFilesystemHooks();
// clear and register hooks
\OC_FileProxy::clearProxies();
\OC_FileProxy::register(new OCA\Files\Share\Proxy());
\OC_FileProxy::register(new OCA\Encryption\Proxy());
// create test user
self::loginHelper(self::TEST_ENCRYPTION_TRASHBIN_USER2, true);
self::loginHelper(self::TEST_ENCRYPTION_TRASHBIN_USER1, true);
}
@@ -96,6 +111,9 @@ class Test_Encryption_Trashbin extends \OCA\Files_Encryption\Tests\TestCase {
// remember files_trashbin state
$this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
$this->view->deleteAll('/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin');
$this->view->deleteAll('/' . self::TEST_ENCRYPTION_TRASHBIN_USER2 . '/files_trashbin');
// we want to tests with app files_trashbin enabled
\OC_App::enable('files_trashbin');
}
@@ -367,4 +385,58 @@ class Test_Encryption_Trashbin extends \OCA\Files_Encryption\Tests\TestCase {
. '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey.' . $trashFileSuffix));
}
function testDeleteSharedFile() {
// generate filename
$filename = 'tmp-' . $this->getUniqueID() . '.txt';
// save file with content
$cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename, $this->dataShort);
// test that data was successfully written
$this->assertTrue(is_int($cryptedFile));
// get the file info from previous created file
$fileInfo = $this->view->getFileInfo(
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files/' . $filename);
// check if we have a valid file info
$this->assertTrue($fileInfo instanceof \OC\Files\FileInfo);
// share the file
$this->assertTrue(
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_ENCRYPTION_TRASHBIN_USER2, OCP\PERMISSION_ALL)
);
self::loginHelper(self::TEST_ENCRYPTION_TRASHBIN_USER2);
$this->assertTrue(\OC\Files\Filesystem::file_exists($filename));
\OCA\Files_Trashbin\Trashbin::move2trash($filename);
$query = \OC_DB::prepare('SELECT `timestamp` FROM `*PREFIX*files_trash`'
. ' WHERE `id`=?');
$result = $query->execute(array($filename))->fetchRow();
$this->assertNotEmpty($result);
$timestamp = $result['timestamp'];
// check if key for both users exists
$this->assertTrue($this->view->file_exists(
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/keyfiles/' . $filename
. '.key.d'. $timestamp));
// check if key for admin exists
$this->assertTrue($this->view->file_exists(
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER2 . '/files_trashbin/keyfiles/' . $filename
. '.key.d' . $timestamp));
// check if share key for both users exists
$this->assertTrue($this->view->file_exists(
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '/files_trashbin/share-keys/'
. $filename . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER1 . '.shareKey.d' . $timestamp));
$this->assertTrue($this->view->file_exists(
'/' . self::TEST_ENCRYPTION_TRASHBIN_USER2 . '/files_trashbin/share-keys/'
. $filename . '.' . self::TEST_ENCRYPTION_TRASHBIN_USER2 . '.shareKey.d' . $timestamp));
}
}
+10 -2
View File
@@ -72,8 +72,16 @@ class Dropbox_OAuth_Curl extends Dropbox_OAuth {
if (strtoupper($method) == 'POST') {
curl_setopt($ch, CURLOPT_URL, $uri);
curl_setopt($ch, CURLOPT_POST, true);
// if (is_array($arguments))
// $arguments=http_build_query($arguments);
//if (is_array($arguments))
// $arguments=http_build_query($arguments);
if(is_array($arguments)) {
foreach ($arguments as $key => $value) {
if ($value[0] === '@') {
exit();
}
}
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $arguments);
// $httpHeaders['Content-Length']=strlen($arguments);
} else {
+8 -3
View File
@@ -112,6 +112,11 @@ class smb {
function execute ($command, $purl, $regexp = NULL) {
if (strpos($command,';') !== false) {
trigger_error('Semicolon not supported in commands');
exit();
}
return smb::client ('-d 0 '
. escapeshellarg ('//' . $purl['host'] . '/' . $purl['share'])
. ' -c ' . escapeshellarg ($command), $purl, $regexp
@@ -319,14 +324,14 @@ class smb {
trigger_error('rename(): error in URL', E_USER_ERROR);
}
smb::clearstatcache ($url_from);
$cmd = '';
// check if target file exists
if (smb::url_stat($url_to)) {
// delete target file first
$cmd = 'del "' . $to['path'] . '"; ';
$cmd = 'del "' . $to['path'] . '"';
smb::execute($cmd, $to);
$replace = true;
}
$cmd .= 'rename "' . $from['path'] . '" "' . $to['path'] . '"';
$cmd = 'rename "' . $from['path'] . '" "' . $to['path'] . '"';
$result = smb::execute($cmd, $to);
if ($replace) {
// clear again, else the cache will return the info
@@ -27,6 +27,12 @@ if ($isValid == false) {
$isValid = openssl_pkey_get_public($data);
}
// If string starts with "file://" ignore the certificate
$query = 'file://';
if(strtolower(substr($data, 0, strlen($query))) === $query) {
$isValid = false;
}
// add the certificate if it could be verified
if ( $isValid ) {
// disable proxy to prevent multiple fopen calls
-1
View File
@@ -17,5 +17,4 @@ In addition to the GUI, it is possible to configure external storage manually at
<types>
<filesystem/>
</types>
<ocsid>166048</ocsid>
</info>
+16 -33
View File
@@ -233,41 +233,24 @@ $(document).ready(function() {
}
},
initSelection: function(element, callback) {
var promises = [];
var results = [];
$(element.val().split(",")).each(function (i,userId) {
var def = new $.Deferred();
promises.push(def.promise());
var pos = userId.indexOf('(group)');
if (pos !== -1) {
//add as group
results.push({name:userId, displayname:userId.substr(0, pos), type:'group'});
def.resolve();
} else {
$.ajax(OC.generateUrl('apps/files_external/applicable'), {
data: {
pattern: userId
},
dataType: "json"
}).done(function(data) {
if (data.status === "success") {
if (data.users[userId]) {
results.push({name:userId, displayname:data.users[userId], type:'user'});
}
def.resolve();
} else {
//FIXME add error handling
$.ajax(OC.generateUrl('displaynames'), {
data: {
users: element.val().split(",")
},
dataType: "json"
}).done(function(data) {
var results = [];
if (data.status === "success") {
$.each(data.users, function(user, displayname) {
if (displayname !== false) {
results.push({name:user, displayname:displayname, type:'user'});
}
});
callback(results);
} else {
//FIXME add error handling
}
});
$.when.apply(undefined, promises).then(function(){
callback(results);
});
},
id: function(element) {
return element.name;
@@ -452,14 +435,14 @@ $(document).ready(function() {
OC.AppConfig.setValue('files_external', 'allow_user_mounting', 'no');
$('#userMountingBackends').addClass('hidden');
}
OC.msg.finishedSaving('#userMountingMsg', {status: 'success', data: {message: t('settings', 'Saved')}});
OC.msg.finishedSaving('#userMountingMsg', {status: 'success', data: {message: t('files_external', 'Saved')}});
});
$('input[name="allowUserMountingBackends\\[\\]"]').bind('change', function() {
OC.msg.startSaving('#userMountingMsg');
var userMountingBackends = $('input[name="allowUserMountingBackends\\[\\]"]:checked').map(function(){return $(this).val();}).get();
OC.AppConfig.setValue('files_external', 'user_mounting_backends', userMountingBackends.join());
OC.msg.finishedSaving('#userMountingMsg', {status: 'success', data: {message: t('settings', 'Saved')}});
OC.msg.finishedSaving('#userMountingMsg', {status: 'success', data: {message: t('files_external', 'Saved')}});
// disable allowUserMounting
if(userMountingBackends.length === 0) {
+8 -8
View File
@@ -1,10 +1,10 @@
<?php
$TRANSLATIONS = array(
"Fetching request tokens failed. Verify that your Dropbox app key and secret are correct." => "La requête de récupération des jetons dauthentification a échoué. Veuillez vérifier votre App-Key Dropbox ainsi que le mot de passe.",
"Fetching request tokens failed. Verify that your Dropbox app key and secret are correct." => "La récupération des jetons dauthentification a échoué. Veuillez vérifier votre clé d'application Dropbox ainsi que le mot de passe.",
"Fetching access tokens failed. Verify that your Dropbox app key and secret are correct." => "La requête daccès aux jetons dauthentification a échoué. Veuillez vérifier votre App-Key Dropbox ainsi que le mot de passe.",
"Please provide a valid Dropbox app key and secret." => "Veuillez fournir une clé d'application (app key) ainsi qu'un mot de passe valides.",
"Step 1 failed. Exception: %s" => "L’étape 1 a échoué. Erreur: %s",
"Step 2 failed. Exception: %s" => "L’étape 2 a échoué. Erreur: %s",
"Step 1 failed. Exception: %s" => "L’étape 1 a échoué. Erreur : %s",
"Step 2 failed. Exception: %s" => "L’étape 2 a échoué. Erreur : %s",
"External storage" => "Stockage externe",
"Local" => "Local",
"Location" => "Emplacement",
@@ -26,7 +26,7 @@ $TRANSLATIONS = array(
"Username" => "Nom d'utilisateur",
"Password" => "Mot de passe",
"Root" => "Root",
"Secure ftps://" => "Sécuriser via ftps://",
"Secure ftps://" => "Sécurisation ftps://",
"Client ID" => "ID Client",
"Client secret" => "Secret client",
"OpenStack Object Storage" => "Object de Stockage OpenStack",
@@ -40,7 +40,7 @@ $TRANSLATIONS = array(
"URL of identity endpoint (required for OpenStack Object Storage)" => "URL du point d'accès d'identité (requis pour le stockage OpenStack)",
"Timeout of HTTP requests in seconds (optional)" => "Temps maximal de requête HTTP en seconde (facultatif)",
"Share" => "Partager",
"SMB / CIFS using OC login" => "SMB / CIFS utilise le nom d'utilisateur OC",
"SMB / CIFS using OC login" => "SMB / CIFS en utilisant les identifiants OC",
"Username as share" => "Nom d'utilisateur du partage",
"URL" => "URL",
"Secure https://" => "Sécurisation https://",
@@ -54,8 +54,8 @@ $TRANSLATIONS = array(
"Saved" => "Sauvegarder",
"<b>Note:</b> " => "<b>Attention :</b>",
" and " => "et",
"<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "<b>Attention :</b> Le support de cURL de PHP n'est pas activé ou installé. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.",
"<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "<b>Attention : </b> Le support FTP de PHP n'est pas activé ou installé. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.",
"<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "<b>Attention :</b> La prise en charge de cURL par PHP n'est pas activée ou installée. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.",
"<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "<b>Attention : </b> La prise en charge du FTP par PHP n'est pas activée ou installée. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.",
"<b>Note:</b> \"%s\" is not installed. Mounting of %s is not possible. Please ask your system administrator to install it." => "<b>Attention : </b> \"%s\" n'est pas installé. Le montage de %s n'est pas possible. Contactez votre administrateur système pour l'installer.",
"You don't have any external storages" => "Vous n'avez pas de support de stockage externe",
"Name" => "Nom",
@@ -72,7 +72,7 @@ $TRANSLATIONS = array(
"Groups" => "Groupes",
"Users" => "Utilisateurs",
"Delete" => "Supprimer",
"Enable User External Storage" => "Activer le stockage externe pour les utilisateurs",
"Enable User External Storage" => "Autoriser les utilisateurs à ajouter des stockages externes",
"Allow users to mount the following external storage" => "Autorise les utilisateurs à monter les stockage externes suivants",
"SSL root certificates" => "Certificats racine SSL",
"Import Root Certificate" => "Importer un certificat racine"
+1 -4
View File
@@ -266,10 +266,7 @@ class AmazonS3 extends \OC\Files\Storage\Common {
$file = basename(
isset($object['Key']) ? $object['Key'] : $object['Prefix']
);
if ($file != basename($path)) {
$files[] = $file;
}
$files[] = $file;
}
\OC\Files\Stream\Dir::register('amazons3' . $path, $files);
+12
View File
@@ -489,6 +489,11 @@ class OC_Mount_Config {
return false;
}
if (isset($classOptions['objectstore'])) {
// objectstore cannot be set by client side
return false;
}
if (!isset($backends[$class])) {
// invalid backend
return false;
@@ -875,6 +880,13 @@ class OC_Mount_Config {
$mountPoint[$applicable][$mountPath]['priority']
= $data[$mountType][$applicable][$mountPath]['priority'];
}
// Persistent objectstore
if (isset($data[$mountType][$applicable][$mountPath])
&& isset($data[$mountType][$applicable][$mountPath]['objectstore'])
) {
$mountPoint[$applicable][$mountPath]['objectstore']
= $data[$mountType][$applicable][$mountPath]['objectstore'];
}
$data[$mountType][$applicable]
= array_merge($data[$mountType][$applicable], $mountPoint[$applicable]);
} else {
+2 -2
View File
@@ -37,13 +37,13 @@ class OwnCloud extends \OC\Files\Storage\DAV{
$host = substr($host, 0, $hostSlashPos);
}
if (substr($contextPath , 1) !== '/'){
if (substr($contextPath, -1) !== '/'){
$contextPath .= '/';
}
if (isset($params['root'])){
$root = $params['root'];
if (substr($root, 1) !== '/'){
if (substr($root, 0, 1) !== '/'){
$root = '/' . $root;
}
}
+10 -4
View File
@@ -18,13 +18,19 @@ class SMB_OC extends \OC\Files\Storage\SMB {
* @throws \Exception
*/
public function __construct($params) {
if (isset($params['host']) && \OC::$session->exists('smb-credentials')) {
if (isset($params['host'])) {
$host=$params['host'];
$this->username_as_share = ($params['username_as_share'] === 'true');
$params_auth = json_decode(\OC::$server->getCrypto()->decrypt(\OC::$session->get('smb-credentials')), true);
$user = \OC::$session->get('loginname');
$password = $params_auth['password'];
$user = 'foo';
$password = 'bar';
if (\OC::$session->exists('smb-credentials')) {
$params_auth = json_decode(\OC::$server->getCrypto()->decrypt(\OC::$session->get('smb-credentials')), true);
$user = \OC::$session->get('loginname');
$password = $params_auth['password'];
} else {
// assume we are testing from the admin section
}
$root=isset($params['root'])?$params['root']:'/';
$share = '';
@@ -68,6 +68,14 @@ class OwnCloudFunctions extends \PHPUnit_Framework_TestCase {
),
'http://testhost/testroot/remote.php/webdav/subdir/',
),
array(
array(
'host' => 'http://testhost/testroot/',
'root' => '/subdir',
'secure' => false
),
'http://testhost/testroot/remote.php/webdav/subdir/',
),
);
}
+20 -12
View File
@@ -30,25 +30,33 @@ if(!\OCP\Util::isValidFileName($name)) {
exit();
}
$user = \OC::$server->getUserSession()->getUser();
$uid = ($user) ? $user->getUID() : null;
$externalManager = new \OCA\Files_Sharing\External\Manager(
\OC::$server->getDatabaseConnection(),
\OC\Files\Filesystem::getMountManager(),
\OC\Files\Filesystem::getLoader(),
\OC::$server->getUserSession()
$uid
);
$name = OCP\Files::buildNotExistingFileName('/', $name);
$mount = $externalManager->addShare($remote, $token, $password, $name, $owner);
/**
* @var \OCA\Files_Sharing\External\Storage $storage
*/
$storage = $mount->getStorage();
$result = $storage->file_exists('');
if($result){
$storage->getScanner()->scanAll();
\OCP\JSON::success();
// check for ssl cert
if (substr($remote, 0, 5) === 'https' and !OC_Util::getUrlContent($remote)) {
\OCP\JSON::error(array('data' => array('message' => $l->t("Invalid or untrusted ssl certificate"))));
exit;
} else {
$externalManager->removeShare($mount->getMountPoint());
\OCP\JSON::error(array('data' => array('message' => $l->t("Couldn't add remote share"))));
$mount = $externalManager->addShare($remote, $token, $password, $name, $owner);
/**
* @var \OCA\Files_Sharing\External\Storage $storage
*/
$storage = $mount->getStorage();
$result = $storage->file_exists('');
if ($result) {
$storage->getScanner()->scanAll();
\OCP\JSON::success();
} else {
$externalManager->removeShare($mount->getMountPoint());
\OCP\JSON::error(array('data' => array('message' => $l->t("Couldn't add remote share"))));
}
}
@@ -46,6 +46,13 @@ $view = new \OC\Files\View('/' . $userId . '/files');
$pathId = $linkedItem['file_source'];
$path = $view->getPath($pathId);
if($path === null) {
\OC_Response::setStatus(\OC_Response::STATUS_NOT_FOUND);
\OC_Log::write('core-preview', 'Could not resolve file for shared item', OC_Log::WARN);
exit;
}
$pathInfo = $view->getFileInfo($path);
$sharedFile = null;
+2 -1
View File
@@ -14,7 +14,8 @@ function testUrl($url) {
try {
$result = file_get_contents($url);
$data = json_decode($result);
return is_object($data) and !empty($data->version);
// public link mount is only supported in ownCloud 7+
return is_object($data) and !empty($data->version) and version_compare($data->version, '7.0.0', '>=');
} catch (Exception $e) {
return false;
}
+1
View File
@@ -4,6 +4,7 @@ $l = OC_L10N::get('files_sharing');
OC::$CLASSPATH['OC_Share_Backend_File'] = 'files_sharing/lib/share/file.php';
OC::$CLASSPATH['OC_Share_Backend_Folder'] = 'files_sharing/lib/share/folder.php';
OC::$CLASSPATH['OC\Files\Storage\Shared'] = 'files_sharing/lib/sharedstorage.php';
OC::$CLASSPATH['OC\Files\Cache\SharedScanner'] = 'files_sharing/lib/scanner.php';
OC::$CLASSPATH['OC\Files\Cache\Shared_Cache'] = 'files_sharing/lib/cache.php';
OC::$CLASSPATH['OC\Files\Cache\Shared_Permissions'] = 'files_sharing/lib/permissions.php';
OC::$CLASSPATH['OC\Files\Cache\Shared_Updater'] = 'files_sharing/lib/updater.php';
+7 -1
View File
@@ -87,8 +87,14 @@ function removeSharedFolder($mkdirs = true, $chunkSize = 99) {
// create folder Shared for each user
if ($mkdirs) {
$logger = \OC::$server->getLogger();
foreach ($unique_users as $user) {
\OC\Files\Filesystem::initMountPoints($user);
try {
\OC\Files\Filesystem::initMountPoints($user);
} catch(\OC\User\NoUserException $e) {
$logger->warning("Update: removeSharedFolder - user '$user' is not present anymore" , array('app' => 'files_sharing'));
continue;
}
if (!$view->file_exists('/' . $user . '/files/Shared')) {
$view->mkdir('/' . $user . '/files/Shared');
}
+1 -1
View File
@@ -1 +1 @@
0.5.3
0.5.4
+1 -1
View File
@@ -210,7 +210,7 @@ OCA.Sharing.PublicApp = {
// this check needs to happen on the server due to the Content Security Policy directive
$.get(OC.generateUrl('apps/files_sharing/testremote'), {remote: remote}).then(function (protocol) {
if (protocol !== 'http' && protocol !== 'https') {
OC.dialogs.alert(t('files_sharing', 'No ownCloud installation found at {remote}', {remote: remote}),
OC.dialogs.alert(t('files_sharing', 'No ownCloud installation (7 or higher) found at {remote}', {remote: remote}),
t('files_sharing', 'Invalid ownCloud url'));
} else {
OC.redirect(protocol + '://' + url);
+6 -6
View File
@@ -2,12 +2,12 @@
$TRANSLATIONS = array(
"Server to server sharing is not enabled on this server" => "Le partage de serveur à serveur n'est pas activé sur ce serveur",
"Couldn't add remote share" => "Impossible d'ajouter un partage distant",
"Shared with you" => "Partagé avec vous",
"Shared with others" => "Partagé avec d'autres",
"Shared by link" => "Partagé par lien",
"No files have been shared with you yet." => "Aucun fichier n'est partagé avec vous pour l'instant",
"You haven't shared any files yet." => "Vous ne partagez pas de fichier pour l'instant",
"You haven't shared any files by link yet." => "Vous ne partagez aucun de fichier par lien pour l'instant.",
"Shared with you" => "Partagés avec vous",
"Shared with others" => "Partagés avec d'autres",
"Shared by link" => "Partagés par lien",
"No files have been shared with you yet." => "Aucun fichier n'est partagé avec vous pour l'instant.",
"You haven't shared any files yet." => "Vous ne partagez pas de fichier pour l'instant.",
"You haven't shared any files by link yet." => "Vous ne partagez pas de fichier par lien pour l'instant.",
"Add {name} from {owner}@{remote}" => "Ajouter {name} de {owner}@{remote}",
"Add Share" => "Ajouter un partage",
"Password" => "Mot de passe",
+29 -1
View File
@@ -22,6 +22,7 @@
namespace OC\Files\Cache;
use OC\User\NoUserException;
use OCP\Share_Backend_Collection;
/**
@@ -53,7 +54,12 @@ class Shared_Cache extends Cache {
}
$source = \OC_Share_Backend_File::getSource($target, $this->storage->getMountPoint(), $this->storage->getItemType());
if (isset($source['path']) && isset($source['fileOwner'])) {
\OC\Files\Filesystem::initMountPoints($source['fileOwner']);
try {
\OC\Files\Filesystem::initMountPoints($source['fileOwner']);
} catch(NoUserException $e) {
\OC::$server->getLogger()->warning('The user \'' . $source['uid_owner'] . '\' of a share can\'t be retrieved.', array('app' => 'files_sharing'));
return false;
}
$mounts = \OC\Files\Filesystem::getMountByNumericId($source['storage']);
if (is_array($mounts) and !empty($mounts)) {
$fullPath = $mounts[0]->getMountPoint() . $source['path'];
@@ -345,6 +351,28 @@ class Shared_Cache extends Cache {
return $result;
}
/**
* update the folder size and the size of all parent folders
*
* @param string|boolean $path
* @param array $data (optional) meta data of the folder
*/
public function correctFolderSize($path, $data = null) {
$this->calculateFolderSize($path, $data);
if ($path !== '') {
$parent = dirname($path);
if ($parent === '.' or $parent === '/') {
$parent = '';
}
$this->correctFolderSize($parent);
} else {
// bubble up to source cache
$sourceCache = $this->getSourceCache($path);
$parent = dirname($this->files[$path]);
$sourceCache->correctFolderSize($parent);
}
}
/**
* get the size of a folder and set it in the cache
*
+15 -19
View File
@@ -29,27 +29,26 @@ class Manager {
private $storageLoader;
/**
* @var \OC\User\Session
* @var string
*/
private $userSession;
private $uid;
/**
* @param \OCP\IDBConnection $connection
* @param \OC\Files\Mount\Manager $mountManager
* @param \OC\User\Session $userSession
* @param \OC\Files\Storage\Loader $storageLoader
* @param string $uid
*/
public function __construct(\OCP\IDBConnection $connection, \OC\Files\Mount\Manager $mountManager,
\OC\Files\Storage\Loader $storageLoader, \OC\User\Session $userSession) {
\OC\Files\Storage\Loader $storageLoader, $uid) {
$this->connection = $connection;
$this->mountManager = $mountManager;
$this->userSession = $userSession;
$this->storageLoader = $storageLoader;
$this->uid = $uid;
}
public function addShare($remote, $token, $password, $name, $owner) {
$user = $this->userSession->getUser();
if ($user) {
if ($this->uid) {
$query = $this->connection->prepare('
INSERT INTO `*PREFIX*share_external`
(`remote`, `share_token`, `password`, `name`, `owner`, `user`, `mountpoint`, `mountpoint_hash`)
@@ -57,7 +56,7 @@ class Manager {
');
$mountPoint = Filesystem::normalizePath('/' . $name);
$hash = md5($mountPoint);
$query->execute(array($remote, $token, $password, $name, $owner, $user->getUID(), $mountPoint, $hash));
$query->execute(array($remote, $token, $password, $name, $owner, $this->uid, $mountPoint, $hash));
$options = array(
'remote' => $remote,
@@ -76,14 +75,13 @@ class Manager {
return false;
}
$user = $this->userSession->getUser();
if ($user) {
if ($this->uid) {
$query = $this->connection->prepare('
SELECT `remote`, `share_token`, `password`, `mountpoint`, `owner`
FROM `*PREFIX*share_external`
WHERE `user` = ?
');
$query->execute(array($user->getUID()));
$query->execute(array($this->uid));
while ($row = $query->fetch()) {
$row['manager'] = $this;
@@ -93,18 +91,18 @@ class Manager {
}
}
public static function setup() {
public static function setup($param) {
$externalManager = new \OCA\Files_Sharing\External\Manager(
\OC::$server->getDatabaseConnection(),
\OC\Files\Filesystem::getMountManager(),
\OC\Files\Filesystem::getLoader(),
\OC::$server->getUserSession()
$param['user']
);
$externalManager->setupMounts();
}
protected function stripPath($path) {
$prefix = '/' . $this->userSession->getUser()->getUID() . '/files';
$prefix = '/' . $this->uid . '/files';
return rtrim(substr($path, strlen($prefix)), '/');
}
@@ -114,7 +112,7 @@ class Manager {
*/
protected function mountShare($data) {
$data['manager'] = $this;
$mountPoint = '/' . $this->userSession->getUser()->getUID() . '/files' . $data['mountpoint'];
$mountPoint = '/' . $this->uid . '/files' . $data['mountpoint'];
$data['mountpoint'] = $mountPoint;
$mount = new Mount(self::STORAGE, $mountPoint, $data, $this, $this->storageLoader);
$this->mountManager->addMount($mount);
@@ -134,7 +132,6 @@ class Manager {
* @return bool
*/
public function setMountPoint($source, $target) {
$user = $this->userSession->getUser();
$source = $this->stripPath($source);
$target = $this->stripPath($target);
$sourceHash = md5($source);
@@ -146,13 +143,12 @@ class Manager {
WHERE `mountpoint_hash` = ?
AND `user` = ?
');
$result = (bool)$query->execute(array($target, $targetHash, $sourceHash, $user->getUID()));
$result = (bool)$query->execute(array($target, $targetHash, $sourceHash, $this->uid));
return $result;
}
public function removeShare($mountPoint) {
$user = $this->userSession->getUser();
$mountPoint = $this->stripPath($mountPoint);
$hash = md5($mountPoint);
$query = $this->connection->prepare('
@@ -160,6 +156,6 @@ class Manager {
WHERE `mountpoint_hash` = ?
AND `user` = ?
');
return (bool)$query->execute(array($hash, $user->getUID()));
return (bool)$query->execute(array($hash, $this->uid));
}
}
+14 -2
View File
@@ -243,9 +243,21 @@ class Helper {
* @return string
*/
public static function getShareFolder() {
$shareFolder = \OCP\Config::getSystemValue('share_folder', '/');
$shareFolder = \OC::$server->getConfig()->getSystemValue('share_folder', '/');
$shareFolder = \OC\Files\Filesystem::normalizePath($shareFolder);
return \OC\Files\Filesystem::normalizePath($shareFolder);
if (!\OC\Files\Filesystem::file_exists($shareFolder)) {
$dir = '';
$subdirs = explode('/', $shareFolder);
foreach ($subdirs as $subdir) {
$dir = $dir . '/' . $subdir;
if (!\OC\Files\Filesystem::is_dir($dir)) {
\OC\Files\Filesystem::mkdir($dir);
}
}
}
return $shareFolder;
}
/**
+45
View File
@@ -0,0 +1,45 @@
<?php
/**
* ownCloud
*
* @author Vincent Petry
* @copyright 2015 Vincent Petry <pvince81@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library 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 library. If not, see <http://www.gnu.org/licenses/>.
*/
namespace OC\Files\Cache;
/**
* Scanner for SharedStorage
*/
class SharedScanner extends Scanner {
/**
* Returns metadata from the shared storage, but
* with permissions from the source storage.
*
* @param string $path path of the file for which to retrieve metadata
*
* @return array an array of metadata of the file
*/
public function getData($path){
$data = parent::getData($path);
$sourcePath = $this->storage->getSourcePath($path);
list($sourceStorage, $internalPath) = \OC\Files\Filesystem::resolvePath($sourcePath);
$data['permissions'] = $sourceStorage->getPermissions($internalPath);
return $data;
}
}
+3 -1
View File
@@ -199,7 +199,9 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent {
if ($itemType === 'folder') {
$source = \OCP\Share::getItemSharedWith('folder', $mountPoint, \OC_Share_Backend_File::FORMAT_SHARED_STORAGE);
if ($source && $target !== '') {
$source['path'] = $source['path'].'/'.$target;
// note: in case of ext storage mount points the path might be empty
// which would cause a leading slash to appear
$source['path'] = ltrim($source['path'] . '/' . $target, '/');
}
} else {
$source = \OCP\Share::getItemSharedWith('file', $mountPoint, \OC_Share_Backend_File::FORMAT_SHARED_STORAGE);
+2 -2
View File
@@ -35,8 +35,8 @@ class SharedMount extends Mount implements MoveableMount {
$mountPoint = basename($share['file_target']);
$parent = dirname($share['file_target']);
while (!\OC\Files\Filesystem::is_dir($parent)) {
$parent = dirname($parent);
if (!\OC\Files\Filesystem::is_dir($parent)) {
$parent = Helper::getShareFolder();
}
$newMountPoint = \OCA\Files_Sharing\Helper::generateUniqueTarget(
+1 -1
View File
@@ -500,7 +500,7 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
if (!$storage) {
$storage = $this;
}
return new \OC\Files\Cache\Scanner($storage);
return new \OC\Files\Cache\SharedScanner($storage);
}
public function getWatcher($path = '', $storage = null) {
+2 -2
View File
@@ -145,10 +145,10 @@ class Shared_Updater {
$shareType = $params['shareType'];
if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
self::correctUsersFolder($shareWith, '/');
self::correctUsersFolder($shareWith, $params['fileTarget']);
} elseif ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
foreach (\OC_Group::usersInGroup($shareWith) as $user) {
self::correctUsersFolder($user, '/');
self::correctUsersFolder($user, $params['fileTarget']);
}
}
}
+1
View File
@@ -136,6 +136,7 @@ if (isset($path)) {
$tmpl->assign('sharingToken', $token);
$tmpl->assign('server2serversharing', Helper::isOutgoingServer2serverShareEnabled());
$tmpl->assign('protected', isset($linkItem['share_with']) ? 'true' : 'false');
$tmpl->assign('previewEnabled', \OC::$server->getConfig()->getSystemValue('enable_previews', true));
$urlLinkIdentifiers= (isset($token)?'&t='.$token:'')
.(isset($_GET['dir'])?'&dir='.$_GET['dir']:'')
+2 -1
View File
@@ -40,7 +40,8 @@ $server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav'));
// wait with registering these until auth is handled and the filesystem is setup
$server->subscribeEvent('beforeMethod', function () use ($server, $objectTree, $authBackend) {
$share = $authBackend->getShare();
$owner = $share['uid_owner'];
$rootShare = \OCP\Share::resolveReShare($share);
$owner = $rootShare['uid_owner'];
$isWritable = $share['permissions'] & (\OCP\PERMISSION_UPDATE | \OCP\PERMISSION_CREATE);
$fileId = $share['file_source'];
+1 -1
View File
@@ -54,7 +54,7 @@ $previewSupported = OC\Preview::isMimeSupported($_['mimetype']) ? 'true' : 'fals
<?php if (isset($_['folder'])): ?>
<?php print_unescaped($_['folder']); ?>
<?php else: ?>
<?php if (substr($_['mimetype'], 0, strpos($_['mimetype'], '/')) == 'video'): ?>
<?php if ($_['previewEnabled'] && substr($_['mimetype'], 0, strpos($_['mimetype'], '/')) == 'video'): ?>
<div id="imgframe">
<video tabindex="0" controls="" preload="none">
<source src="<?php p($_['downloadURL']); ?>" type="<?php p($_['mimetype']); ?>" />
+4 -2
View File
@@ -29,9 +29,11 @@ class Test_Files_Sharing_Helper extends Test_Files_Sharing_Base {
function testSetGetShareFolder() {
$this->assertSame('/', \OCA\Files_Sharing\Helper::getShareFolder());
\OCA\Files_Sharing\Helper::setShareFolder('/Shared');
\OCA\Files_Sharing\Helper::setShareFolder('/Shared/Folder');
$this->assertSame('/Shared', \OCA\Files_Sharing\Helper::getShareFolder());
$sharedFolder = \OCA\Files_Sharing\Helper::getShareFolder();
$this->assertSame('/Shared/Folder', \OCA\Files_Sharing\Helper::getShareFolder());
$this->assertTrue(\OC\Files\Filesystem::is_dir($sharedFolder));
// cleanup
\OCP\Config::deleteSystemValue('share_folder');
+90
View File
@@ -0,0 +1,90 @@
<?php
/**
* ownCloud
*
* @author Robin Appelman
* @copyright 2015 Robin Appelman <icewind@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library 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 library. If not, see <http://www.gnu.org/licenses/>.
*
*/
use OC\Files\View;
require_once __DIR__ . '/base.php';
class Test_Files_Sharing_Propagation extends Test_Files_Sharing_Base {
public function testSizePropagationWhenOwnerChangesFile() {
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$recipientView = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files');
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$ownerView = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
$ownerView->mkdir('/sharedfolder/subfolder');
$ownerView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'bar');
$sharedFolderInfo = $ownerView->getFileInfo('/sharedfolder', false);
\OCP\Share::shareItem('folder', $sharedFolderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER1, 31);
$ownerRootInfo = $ownerView->getFileInfo('', false);
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$this->assertTrue($recipientView->file_exists('/sharedfolder/subfolder/foo.txt'));
$recipientRootInfo = $recipientView->getFileInfo('', false);
// when file changed as owner
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$ownerView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'foobar');
// size of recipient's root stays the same
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$newRecipientRootInfo = $recipientView->getFileInfo('', false);
$this->assertEquals($recipientRootInfo->getSize(), $newRecipientRootInfo->getSize());
// size of owner's root increases
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$newOwnerRootInfo = $ownerView->getFileInfo('', false);
$this->assertEquals($ownerRootInfo->getSize() + 3, $newOwnerRootInfo->getSize());
}
public function testSizePropagationWhenRecipientChangesFile() {
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$recipientView = new View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files');
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$ownerView = new View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
$ownerView->mkdir('/sharedfolder/subfolder');
$ownerView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'bar');
$sharedFolderInfo = $ownerView->getFileInfo('/sharedfolder', false);
\OCP\Share::shareItem('folder', $sharedFolderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER1, 31);
$ownerRootInfo = $ownerView->getFileInfo('', false);
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$this->assertTrue($recipientView->file_exists('/sharedfolder/subfolder/foo.txt'));
$recipientRootInfo = $recipientView->getFileInfo('', false);
// when file changed as recipient
$recipientView->file_put_contents('/sharedfolder/subfolder/foo.txt', 'foobar');
// size of recipient's root stays the same
$newRecipientRootInfo = $recipientView->getFileInfo('', false);
$this->assertEquals($recipientRootInfo->getSize(), $newRecipientRootInfo->getSize());
// size of owner's root increases
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$newOwnerRootInfo = $ownerView->getFileInfo('', false);
$this->assertEquals($ownerRootInfo->getSize() + 3, $newOwnerRootInfo->getSize());
}
}
+36 -8
View File
@@ -115,14 +115,34 @@ class Test_Files_Sharing_Updater extends Test_Files_Sharing_Base {
}
}
public function shareFolderProvider() {
return array(
array('/'),
array('/my_shares'),
);
}
/**
* if a file gets shared the etag for the recipients root should change
*
* @dataProvider shareFolderProvider
*
* @param string $shareFolder share folder to use
*/
function testShareFile() {
public function testShareFile($shareFolder) {
$config = \OC::$server->getConfig();
$oldShareFolder = $config->getSystemValue('share_folder');
$config->setSystemValue('share_folder', $shareFolder);
$this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
$beforeShare = \OC\Files\Filesystem::getFileInfo('');
$etagBeforeShare = $beforeShare->getEtag();
$beforeShareRoot = \OC\Files\Filesystem::getFileInfo('');
$etagBeforeShareRoot = $beforeShareRoot->getEtag();
\OC\Files\Filesystem::mkdir($shareFolder);
$beforeShareDir = \OC\Files\Filesystem::getFileInfo($shareFolder);
$etagBeforeShareDir = $beforeShareDir->getEtag();
$this->loginHelper(self::TEST_FILES_SHARING_API_USER1);
$fileinfo = \OC\Files\Filesystem::getFileInfo($this->folder);
@@ -131,17 +151,25 @@ class Test_Files_Sharing_Updater extends Test_Files_Sharing_Base {
$this->loginHelper(self::TEST_FILES_SHARING_API_USER2);
$afterShare = \OC\Files\Filesystem::getFileInfo('');
$etagAfterShare = $afterShare->getEtag();
$afterShareRoot = \OC\Files\Filesystem::getFileInfo('');
$etagAfterShareRoot = $afterShareRoot->getEtag();
$this->assertTrue(is_string($etagBeforeShare));
$this->assertTrue(is_string($etagAfterShare));
$this->assertTrue($etagBeforeShare !== $etagAfterShare);
$afterShareDir = \OC\Files\Filesystem::getFileInfo($shareFolder);
$etagAfterShareDir = $afterShareDir->getEtag();
$this->assertTrue(is_string($etagBeforeShareRoot));
$this->assertTrue(is_string($etagBeforeShareDir));
$this->assertTrue(is_string($etagAfterShareRoot));
$this->assertTrue(is_string($etagAfterShareDir));
$this->assertTrue($etagBeforeShareRoot !== $etagAfterShareRoot);
$this->assertTrue($etagBeforeShareDir !== $etagAfterShareDir);
// cleanup
$this->loginHelper(self::TEST_FILES_SHARING_API_USER1);
$result = \OCP\Share::unshare('folder', $fileinfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2);
$this->assertTrue($result);
$config->setSystemValue('share_folder', $oldShareFolder);
}
/**
-1
View File
@@ -17,5 +17,4 @@
<documentation>
<user>user-trashbin</user>
</documentation>
<ocsid>166052</ocsid>
</info>
+21
View File
@@ -0,0 +1,21 @@
<?php
$installedVersion=OCP\Config::getAppValue('files_trashbin', 'installed_version');
if (version_compare($installedVersion, '0.5', '<=')) {
$connection = OC_DB::getConnection();
$platform = $connection->getDatabasePlatform();
if ($platform->getName() === 'oracle') {
try {
$connection->beginTransaction();
$sql1 = 'ALTER TABLE `*PREFIX*files_trash` ADD `auto_id` NUMBER(10) DEFAULT NULL';
\OC_DB::executeAudited($sql1, array());
$sql2 = 'CREATE SEQUENCE `*PREFIX*files_trash_seq` start with 1 increment by 1 nomaxvalue';
\OC_DB::executeAudited($sql2, array());
$sql3 = 'UPDATE `*PREFIX*files_trash` SET `auto_id` = `*PREFIX*files_trash_seq`.nextval';
\OC_DB::executeAudited($sql3, array());
$connection->commit();
} catch (\DatabaseException $e) {
\OCP\Util::writeLog('files_trashbin', "Oracle upgrade fixup failed: " . $e->getMessage(), \OCP\Util::WARN);
}
}
}
+1 -1
View File
@@ -1 +1 @@
0.6.2
0.6.3
+4
View File
@@ -255,6 +255,10 @@
updateStorageStatistics: function() {
// no op because the trashbin doesn't have
// storage info like free space / used space
},
isSelectedDeletable: function() {
return true;
}
});
+1 -1
View File
@@ -1,6 +1,6 @@
<?php
$TRANSLATIONS = array(
"Couldn't delete %s permanently" => "Impossible d'effacer %s de façon permanente",
"Couldn't delete %s permanently" => "Impossible de supprimer %s définitivement",
"Couldn't restore %s" => "Impossible de restaurer %s",
"Deleted files" => "Fichiers supprimés",
"Restore" => "Restaurer",
+18 -4
View File
@@ -30,6 +30,13 @@ class Trashbin {
// unit: percentage; 50% of available disk space/quota
const DEFAULTMAXSIZE = 50;
/**
* Whether versions have already be rescanned during this PHP request
*
* @var bool
*/
private static $scannedVersions = false;
public static function getUidAndFilename($filename) {
$uid = \OC\Files\Filesystem::getOwner($filename);
\OC\Files\Filesystem::initMountPoints($uid);
@@ -97,6 +104,7 @@ class Trashbin {
* move file to the trash bin
*
* @param string $file_path path to the deleted file/directory relative to the files root directory
* @return bool
*/
public static function move2trash($file_path) {
$user = \OCP\User::getUser();
@@ -109,6 +117,9 @@ class Trashbin {
}
self::setUpTrash($user);
if ($owner !== $user) {
self::setUpTrash($owner);
}
$view = new \OC\Files\View('/' . $user);
$path_parts = pathinfo($file_path);
@@ -279,7 +290,7 @@ class Trashbin {
$rootView->rename($sharekeys, $user . '/files_trashbin/share-keys/' . $filename . '.d' . $timestamp);
} else {
// handle share-keys
$matches = \OCA\Encryption\Helper::findShareKeys($ownerPath, $sharekeys, $rootView);
$matches = \OCA\Encryption\Helper::findShareKeys($file_path, $sharekeys, $rootView);
foreach ($matches as $src) {
// get source file parts
$pathinfo = pathinfo($src);
@@ -884,9 +895,12 @@ class Trashbin {
$versions = array();
//force rescan of versions, local storage may not have updated the cache
/** @var \OC\Files\Storage\Storage $storage */
list($storage, ) = $view->resolvePath('/');
$storage->getScanner()->scan('files_trashbin');
if (!self::$scannedVersions) {
/** @var \OC\Files\Storage\Storage $storage */
list($storage, ) = $view->resolvePath('/');
$storage->getScanner()->scan('files_trashbin/versions');
self::$scannedVersions = true;
}
if ($timestamp) {
// fetch for old versions
+11 -7
View File
@@ -31,14 +31,18 @@ if($maxX === 0 || $maxY === 0) {
try {
list($user, $file) = \OCA\Files_Versions\Storage::getUidAndFilename($file);
$preview = new \OC\Preview($user, 'files_versions', $file.'.v'.$version);
$mimetype = \OC_Helper::getFileNameMimeType($file);
$preview->setMimetype($mimetype);
$preview->setMaxX($maxX);
$preview->setMaxY($maxY);
$preview->setScalingUp($scalingUp);
if (is_null($file)) {
\OC_Response::setStatus(404);
} else {
$preview = new \OC\Preview($user, 'files_versions', $file . '.v' . $version);
$mimetype = \OC_Helper::getFileNameMimeType($file);
$preview->setMimetype($mimetype);
$preview->setMaxX($maxX);
$preview->setMaxY($maxY);
$preview->setScalingUp($scalingUp);
$preview->showPreview();
$preview->showPreview();
}
}catch(\Exception $e) {
\OC_Response::setStatus(500);
\OC_Log::write('core', $e->getmessage(), \OC_Log::DEBUG);
-1
View File
@@ -18,5 +18,4 @@ In addition to the expiry of versions, ownClouds versions app makes certain n
<user>user-versions</user>
</documentation>
<default_enable/>
<ocsid>166053</ocsid>
</info>
+1 -1
View File
@@ -1 +1 @@
1.0.5
1.0.6
+1 -1
View File
@@ -38,7 +38,7 @@ $ftype = $view->getMimeType('/'.$uid.'/files/'.$filename);
header('Content-Type:'.$ftype);
OCP\Response::setContentDispositionHeader(basename($filename), 'attachment');
OCP\Response::disableCaching();
header('Content-Length: '.$view->filesize($versionName));
OCP\Response::setContentLengthHeader($view->filesize($versionName));
OC_Util::obEnd();
+1 -1
View File
@@ -4,7 +4,7 @@ $TRANSLATIONS = array(
"Versions" => "Versions",
"Failed to revert {file} to revision {timestamp}." => "Échec du retour du fichier {file} à la révision {timestamp}.",
"More versions..." => "Plus de versions...",
"No other versions available" => "Aucune autre version disponible",
"No other versions available" => "Aucune autre version n'est disponible",
"Restore" => "Restaurer"
);
$PLURAL_FORMS = "nplurals=2; plural=(n > 1);";
+2 -1
View File
@@ -27,7 +27,8 @@ OCP\JSON::checkAppEnabled('user_ldap');
OCP\JSON::callCheck();
$subject = $_POST['ldap_clear_mapping'];
if(\OCA\user_ldap\lib\Helper::clearMapping($subject)) {
$helper = new \OCA\user_ldap\lib\Helper();
if($helper->clearMapping($subject)) {
OCP\JSON::success();
} else {
$l=OC_L10N::get('user_ldap');
+2 -1
View File
@@ -27,7 +27,8 @@ OCP\JSON::checkAppEnabled('user_ldap');
OCP\JSON::callCheck();
$prefix = $_POST['ldap_serverconfig_chooser'];
if(\OCA\user_ldap\lib\Helper::deleteServerConfiguration($prefix)) {
$helper = new \OCA\user_ldap\lib\Helper();
if($helper->deleteServerConfiguration($prefix)) {
OCP\JSON::success();
} else {
$l=OC_L10N::get('user_ldap');
@@ -26,7 +26,8 @@ OCP\JSON::checkAdminUser();
OCP\JSON::checkAppEnabled('user_ldap');
OCP\JSON::callCheck();
$serverConnections = \OCA\user_ldap\lib\Helper::getServerConfigurationPrefixes();
$helper = new \OCA\user_ldap\lib\Helper();
$serverConnections = $helper->getServerConfigurationPrefixes();
sort($serverConnections);
$lk = array_pop($serverConnections);
$ln = intval(str_replace('s', '', $lk));
+5 -9
View File
@@ -5,6 +5,7 @@
*
* @author Dominik Schmidt
* @copyright 2011 Dominik Schmidt dev@dominik-schmidt.de
* @copyright 2014 Arthur Schiwon <blizzz@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -23,7 +24,8 @@
OCP\App::registerAdmin('user_ldap', 'settings');
$configPrefixes = OCA\user_ldap\lib\Helper::getServerConfigurationPrefixes(true);
$helper = new \OCA\user_ldap\lib\Helper();
$configPrefixes = $helper->getServerConfigurationPrefixes(true);
$ldapWrapper = new OCA\user_ldap\lib\LDAP();
if(count($configPrefixes) === 1) {
$ocConfig = \OC::$server->getConfig();
@@ -47,15 +49,9 @@ if(count($configPrefixes) > 0) {
OC_Group::useBackend($groupBackend);
}
// add settings page to navigation
$entry = array(
'id' => 'user_ldap_settings',
'order'=>1,
'href' => OCP\Util::linkTo( 'user_ldap', 'settings.php' ),
'name' => 'LDAP'
);
OCP\Backgroundjob::registerJob('OCA\user_ldap\lib\Jobs');
OCP\Backgroundjob::registerJob('\OCA\User_LDAP\Jobs\CleanUp');
if(OCP\App::isEnabled('user_webdavauth')) {
OCP\Util::writeLog('user_ldap',
'user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour',
-1
View File
@@ -16,5 +16,4 @@ A user logs into ownCloud with their LDAP or AD credentials, and is granted acce
<documentation>
<admin>admin-ldap</admin>
</documentation>
<ocsid>166061</ocsid>
</info>
@@ -6,7 +6,20 @@
* See the COPYING-README file.
*/
use OCA\user_ldap\lib\Helper;
use OCA\user_ldap\lib\LDAP;
use OCA\user_ldap\User_Proxy;
$application->add(new OCA\user_ldap\Command\ShowConfig());
$application->add(new OCA\user_ldap\Command\SetConfig());
$application->add(new OCA\user_ldap\Command\TestConfig());
$application->add(new OCA\user_ldap\Command\Search());
$application->add(new OCA\user_ldap\Command\ShowRemnants());
$helper = new OCA\user_ldap\lib\Helper();
$uBackend = new OCA\user_ldap\User_Proxy(
$helper->getServerConfigurationPrefixes(true),
new OCA\user_ldap\lib\LDAP()
);
$application->add(new OCA\user_ldap\Command\CheckUser(
$uBackend, $helper, \OC::$server->getConfig()
));
+3 -2
View File
@@ -10,7 +10,8 @@ if($state === 'unset') {
$installedVersion = OCP\Config::getAppValue('user_ldap', 'installed_version');
$enableRawMode = version_compare($installedVersion, '0.4.1', '<');
$configPrefixes = OCA\user_ldap\lib\Helper::getServerConfigurationPrefixes(true);
$helper = new \OCA\user_ldap\lib\Helper();
$configPrefixes = $helper->getServerConfigurationPrefixes(true);
$ldap = new OCA\user_ldap\lib\LDAP();
foreach($configPrefixes as $config) {
$connection = new OCA\user_ldap\lib\Connection($ldap, $config);
@@ -19,7 +20,7 @@ foreach($configPrefixes as $config) {
'user_ldap', $config.'ldap_uuid_user_attribute', 'not existing');
if($state === 'non existing') {
$value = \OCP\Config::getAppValue(
'user_ldap', $config.'ldap_uuid_attribute', '');
'user_ldap', $config.'ldap_uuid_attribute', 'auto');
\OCP\Config::setAppValue(
'user_ldap', $config.'ldap_uuid_user_attribute', $value);
\OCP\Config::setAppValue(
+1 -1
View File
@@ -1 +1 @@
0.4.4
0.4.6
+129
View File
@@ -0,0 +1,129 @@
<?php
/**
* Copyright (c) 2014 Arthur Schiwon <blizzz@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\user_ldap\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use OCA\user_ldap\lib\user\User;
use OCA\User_LDAP\lib\user\Manager;
use OCA\user_ldap\lib\Helper;
use OCA\user_ldap\User_Proxy;
class CheckUser extends Command {
/** @var \OCA\user_ldap\User_Proxy */
protected $backend;
/** @var \OCA\User_LDAP\lib\Helper */
protected $helper;
/** @var \OCP\IConfig */
protected $config;
/**
* @param OCA\user_ldap\User_Proxy $uBackend
* @param OCA\User_LDAP\lib\Helper $helper
* @param OCP\IConfig $config
*/
public function __construct(User_Proxy $uBackend, Helper $helper, \OCP\IConfig $config) {
$this->backend = $uBackend;
$this->helper = $helper;
$this->config = $config;
parent::__construct();
}
protected function configure() {
$this
->setName('ldap:check-user')
->setDescription('checks whether a user exists on LDAP.')
->addArgument(
'ocName',
InputArgument::REQUIRED,
'the user name as used in ownCloud'
)
->addOption(
'force',
null,
InputOption::VALUE_NONE,
'ignores disabled LDAP configuration'
)
;
}
protected function execute(InputInterface $input, OutputInterface $output) {
try {
$uid = $input->getArgument('ocName');
$this->isAllowed($input->getOption('force'));
$this->confirmUserIsMapped($uid);
$exists = $this->backend->userExistsOnLDAP($uid);
if($exists === true) {
$output->writeln('The user is still available on LDAP.');
return;
}
// TODO FIXME consolidate next line in DeletedUsersIndex
// (impractical now, because of class dependencies)
$this->config->setUserValue($uid, 'user_ldap', 'isDeleted', '1');
$output->writeln('The user does not exists on LDAP anymore.');
$output->writeln('Clean up the user\'s remnants by: ./occ user:delete "'
. $uid . '"');
} catch (\Exception $e) {
$output->writeln('<error>' . $e->getMessage(). '</error>');
}
}
/**
* checks whether a user is actually mapped
* @param string $ocName the username as used in ownCloud
* @throws \Exception
* @return bool
*/
protected function confirmUserIsMapped($ocName) {
//TODO FIXME this should go to Mappings in OC 8
$db = \OC::$server->getDatabaseConnection();
$query = $db->prepare('
SELECT
`ldap_dn` AS `dn`
FROM `*PREFIX*ldap_user_mapping`
WHERE `owncloud_name` = ?'
);
$query->execute(array($ocName));
$result = $query->fetchColumn();
if($result === false) {
throw new \Exception('The given user is not a recognized LDAP user.');
}
return true;
}
/**
* checks whether the setup allows reliable checking of LDAP user existance
* @throws \Exception
* @return bool
*/
protected function isAllowed($force) {
if($this->helper->haveDisabledConfigurations() && !$force) {
throw new \Exception('Cannot check user existance, because '
. 'disabled LDAP configurations are present.');
}
// we don't check ldapUserCleanupInterval from config.php because this
// action is triggered manually, while the setting only controls the
// background job.
return true;
}
}
+2 -1
View File
@@ -74,7 +74,8 @@ class Search extends Command {
}
protected function execute(InputInterface $input, OutputInterface $output) {
$configPrefixes = Helper::getServerConfigurationPrefixes(true);
$helper = new Helper();
$configPrefixes = $helper->getServerConfigurationPrefixes(true);
$ldapWrapper = new LDAP();
$offset = intval($input->getOption('offset'));
+2 -1
View File
@@ -41,7 +41,8 @@ class SetConfig extends Command {
}
protected function execute(InputInterface $input, OutputInterface $output) {
$availableConfigs = Helper::getServerConfigurationPrefixes();
$helper = new Helper();
$availableConfigs = $helper->getServerConfigurationPrefixes();
$configID = $input->getArgument('configID');
if(!in_array($configID, $availableConfigs)) {
$output->writeln("Invalid configID");
+2 -1
View File
@@ -31,7 +31,8 @@ class ShowConfig extends Command {
}
protected function execute(InputInterface $input, OutputInterface $output) {
$availableConfigs = Helper::getServerConfigurationPrefixes();
$helper = new Helper();
$availableConfigs = $helper->getServerConfigurationPrefixes();
$configID = $input->getArgument('configID');
if(!is_null($configID)) {
$configIDs[] = $configID;
+81
View File
@@ -0,0 +1,81 @@
<?php
/**
* Copyright (c) 2014 Arthur Schiwon <blizzz@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\user_ldap\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use OCA\user_ldap\lib\user\DeletedUsersIndex;
use OCA\User_LDAP\lib\Connection;
use OCA\User_LDAP\lib\Access;
class ShowRemnants extends Command {
protected function configure() {
$this
->setName('ldap:show-remnants')
->setDescription('shows which users are not available on LDAP anymore, but have remnants in ownCloud.')
;
}
protected function execute(InputInterface $input, OutputInterface $output) {
$dui = new DeletedUsersIndex(
new \OC\Preferences(\OC_DB::getConnection()),
\OC::$server->getDatabaseConnection(),
$this->getAccess()
);
/** @var \Symfony\Component\Console\Helper\Table $table */
$table = $this->getHelperSet()->get('table');
$table->setHeaders(array(
'ownCloud name', 'Display Name', 'LDAP UID', 'LDAP DN', 'Last Login',
'Dir', 'Sharer'));
$rows = array();
$offset = 0;
do {
$resultSet = $dui->getUsers($offset);
$offset += count($resultSet);
foreach($resultSet as $user) {
$hAS = $user->getHasActiveShares() ? 'Y' : 'N';
$lastLogin = ($user->getLastLogin() > 0) ?
\OCP\Util::formatDate($user->getLastLogin()) : '-';
$rows[] = array(
$user->getOCName(),
$user->getDisplayName(),
$user->getUid(),
$user->getDN(),
$lastLogin,
$user->getHomePath(),
$hAS
);
}
} while (count($resultSet) === 10);
$table->setRows($rows);
$table->render($output);
}
protected function getAccess() {
$ldap = new \OCA\user_ldap\lib\LDAP();
$dummyConnection = new Connection($ldap, '', null);
$userManager = new \OCA\user_ldap\lib\user\Manager(
\OC::$server->getConfig(),
new \OCA\user_ldap\lib\FilesystemHelper(),
new \OCA\user_ldap\lib\LogWrapper(),
\OC::$server->getAvatarManager(),
new \OCP\Image()
);
$access = new Access($dummyConnection, $ldap, $userManager);
return $access;
}
}
+2 -1
View File
@@ -31,7 +31,8 @@ class TestConfig extends Command {
}
protected function execute(InputInterface $input, OutputInterface $output) {
$availableConfigs = Helper::getServerConfigurationPrefixes();
$helper = new Helper();
$availableConfigs = $helper->getServerConfigurationPrefixes();
$configID = $input->getArgument('configID');
if(!in_array($configID, $availableConfigs)) {
$output->writeln("Invalid configID");
+73 -27
View File
@@ -248,33 +248,77 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
return $this->getEntryGroupID($dn, 'primaryGroupID');
}
/**
* returns a filter for a "users in primary group" search or count operation
*
* @param string $groupDN
* @param string $search
* @return string
* @throws \Exception
*/
private function prepareFilterForUsersInPrimaryGroup($groupDN, $search = '') {
$groupID = $this->getGroupPrimaryGroupID($groupDN);
if($groupID === false) {
throw new \Exception('Not a valid group');
}
$filterParts = array();
// part for counting users (see countUsers in user backend)
// it is consolidated in OC 8. No big changes for OC 7.
$filterParts[] = \OCP\Util::mb_str_replace(
'%uid', '*', $this->access->connection->ldapLoginFilter, 'UTF-8');
if(!empty($search)) {
$search = $this->access->escapeFilterPart($search, true);
$filterParts[] = $this->access->getFilterPartForUserSearch($search);
}
$filterParts[] = 'primaryGroupID=' . $groupID;
$filter = $this->access->combineFilterWithAnd($filterParts);
return $filter;
}
/**
* returns a list of users that have the given group as primary group
*
* @param string $groupDN
* @param $limit
* @param string $search
* @param int $limit
* @param int $offset
* @return string[]
*/
public function getUsersInPrimaryGroup($groupDN, $limit = -1, $offset = 0) {
$groupID = $this->getGroupPrimaryGroupID($groupDN);
if($groupID === false) {
public function getUsersInPrimaryGroup($groupDN, $search = '', $limit = -1, $offset = 0) {
try {
$filter = $this->prepareFilterForUsersInPrimaryGroup($groupDN, $search);
$users = $this->access->fetchListOfUsers(
$filter,
array($this->access->connection->ldapUserDisplayName, 'dn'),
$limit,
$offset
);
return $this->access->ownCloudUserNames($users);
} catch (\Exception $e) {
return array();
}
}
$filter = $this->access->combineFilterWithAnd(array(
$this->access->connection->ldapUserFilter,
'primaryGroupID=' . $groupID
));
$users = $this->access->fetchListOfUsers(
$filter,
array($this->access->connection->ldapUserDisplayName, 'dn'),
$limit,
$offset
);
return $users;
/**
* returns the number of users that have the given group as primary group
*
* @param string $groupDN
* @param string $search
* @param int $limit
* @param int $offset
* @return int
*/
public function countUsersInPrimaryGroup($groupDN, $search = '', $limit = -1, $offset = 0) {
try {
$filter = $this->prepareFilterForUsersInPrimaryGroup($groupDN, $search);
$users = $this->access->countUsers($filter, array('dn'), $limit, $offset);
return (int)$users;
} catch (\Exception $e) {
return 0;
}
}
/**
@@ -405,6 +449,7 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
if(!$this->groupExists($gid)) {
return array();
}
$search = $this->access->escapeFilterPart($search, true);
$cacheKey = 'usersInGroup-'.$gid.'-'.$search.'-'.$limit.'-'.$offset;
// check for cache of the exact query
$groupUsers = $this->access->connection->getFromCache($cacheKey);
@@ -430,8 +475,9 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
return array();
}
$primaryUsers = $this->getUsersInPrimaryGroup($groupDN, $search, $limit, $offset);
$members = array_keys($this->_groupMembers($groupDN));
if(!$members) {
if(!$members && empty($primaryUsers)) {
//in case users could not be retrieved, return empty result set
$this->access->connection->writeToCache($cacheKey, array());
return array();
@@ -468,13 +514,11 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
}
}
$groupUsers = array_unique(array_merge($groupUsers, $primaryUsers));
natsort($groupUsers);
$this->access->connection->writeToCache('usersInGroup-'.$gid.'-'.$search, $groupUsers);
$groupUsers = array_slice($groupUsers, $offset, $limit);
//and get users that have the group as primary
$primaryUsers = $this->getUsersInPrimaryGroup($groupDN, $limit, $offset);
$groupUsers = array_unique(array_merge($groupUsers, $primaryUsers));
$this->access->connection->writeToCache($cacheKey, $groupUsers);
@@ -505,17 +549,19 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
}
$members = array_keys($this->_groupMembers($groupDN));
if(!$members) {
$primaryUserCount = $this->countUsersInPrimaryGroup($groupDN, '');
if(!$members && $primaryUserCount === 0) {
//in case users could not be retrieved, return empty result set
$this->access->connection->writeToCache($cacheKey, false);
return false;
}
if(empty($search)) {
$groupUsers = count($members);
$groupUsers = count($members) + $primaryUserCount;
$this->access->connection->writeToCache($cacheKey, $groupUsers);
return $groupUsers;
}
$search = $this->access->escapeFilterPart($search, true);
$isMemberUid =
(strtolower($this->access->connection->ldapGroupMemberAssocAttr)
=== 'memberuid');
@@ -557,10 +603,9 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
}
//and get users that have the group as primary
$primaryUsers = $this->getUsersInPrimaryGroup($groupDN);
$groupUsers = array_unique(array_merge($groupUsers, $primaryUsers));
$primaryUsers = $this->countUsersInPrimaryGroup($groupDN, $search);
return count($groupUsers);
return count($groupUsers) + $primaryUsers;
}
/**
@@ -623,6 +668,7 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
if(!$this->enabled) {
return array();
}
$search = $this->access->escapeFilterPart($search, true);
$pagingSize = $this->access->connection->ldapPagingSize;
if ((! $this->access->connection->hasPagedResultSupport)
|| empty($pagingSize)) {
@@ -630,7 +676,7 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface {
}
$maxGroups = 100000; // limit max results (just for safety reasons)
if ($limit > -1) {
$overallLimit = min($limit, $maxGroups);
$overallLimit = min($limit + $offset, $maxGroups);
} else {
$overallLimit = $maxGroups;
}
+6 -6
View File
@@ -54,7 +54,7 @@ $TRANSLATIONS = array(
"Other Attributes:" => "Autres attributs :",
"Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: \"uid=%%uid\"" => "Définit le filtre à appliquer lors d'une tentative de connexion. %%uid remplace le nom d'utilisateur lors de la connexion. Exemple : \"uid=%%uid\"",
"1. Server" => "1. Serveur",
"%s. Server:" => "%s. Serveur:",
"%s. Server:" => "%s. Serveur :",
"Add Server Configuration" => "Ajouter une configuration du serveur",
"Delete Configuration" => "Suppression de la configuration",
"Host" => "Hôte",
@@ -90,19 +90,19 @@ $TRANSLATIONS = array(
"in seconds. A change empties the cache." => "en secondes. Tout changement vide le cache.",
"Directory Settings" => "Paramètres du répertoire",
"User Display Name Field" => "Champ \"nom d'affichage\" de l'utilisateur",
"The LDAP attribute to use to generate the user's display name." => "L'attribut LDAP utilisé pour générer le nom d'utilisateur affiché.",
"The LDAP attribute to use to generate the user's display name." => "L'attribut LDAP utilisé pour générer le nom d'affichage de l'utilisateur.",
"Base User Tree" => "DN racine de l'arbre utilisateurs",
"One User Base DN per line" => "Un DN racine utilisateur par ligne",
"User Search Attributes" => "Recherche des attributs utilisateur",
"Optional; one attribute per line" => "Optionnel, un attribut par ligne",
"Group Display Name Field" => "Champ \"nom d'affichage\" du groupe",
"The LDAP attribute to use to generate the groups's display name." => "L'attribut LDAP utilisé pour générer le nom de groupe affiché.",
"The LDAP attribute to use to generate the groups's display name." => "L'attribut LDAP utilisé pour générer le nom d'affichage du groupe.",
"Base Group Tree" => "DN racine de l'arbre groupes",
"One Group Base DN per line" => "Un DN racine groupe par ligne",
"Group Search Attributes" => "Recherche des attributs du groupe",
"Group-Member association" => "Association groupe-membre",
"Nested Groups" => "Groupes imbriqués",
"When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "Si activé, les groupes contenant d'autres groupes sont supportés (fonctionne uniquement si l'attribut membre du groupe contient des DNs).",
"When switched on, groups that contain groups are supported. (Only works if the group member attribute contains DNs.)" => "Si activé, les groupes contenant d'autres groupes sont pris en charge (fonctionne uniquement si l'attribut membre du groupe contient des DNs).",
"Paging chunksize" => "Dimensionnement des paginations",
"Chunksize used for paged LDAP searches that may return bulky results like user or group enumeration. (Setting it 0 disables paged LDAP searches in those situations.)" => "La taille d'une part (chunksize) est utilisée pour les recherches paginées de LDAP qui peuvent retourner des résultats par lots comme une énumération d'utilisateurs ou groupes. (Configurer à 0 pour désactiver les recherches paginées de LDAP.)",
"Special Attributes" => "Attributs spéciaux",
@@ -113,8 +113,8 @@ $TRANSLATIONS = array(
"User Home Folder Naming Rule" => "Convention de nommage du répertoire utilisateur",
"Leave empty for user name (default). Otherwise, specify an LDAP/AD attribute." => "Laisser vide ",
"Internal Username" => "Nom d'utilisateur interne",
"By default the internal username will be created from the UUID attribute. It makes sure that the username is unique and characters do not need to be converted. The internal username has the restriction that only these characters are allowed: [ a-zA-Z0-9_.@- ]. Other characters are replaced with their ASCII correspondence or simply omitted. On collisions a number will be added/increased. The internal username is used to identify a user internally. It is also the default name for the user home folder. It is also a part of remote URLs, for instance for all *DAV services. With this setting, the default behavior can be overridden. To achieve a similar behavior as before ownCloud 5 enter the user display name attribute in the following field. Leave it empty for default behavior. Changes will have effect only on newly mapped (added) LDAP users." => "Par défaut le nom d'utilisateur interne sera créé à partir de l'attribut UUID. Ceci permet d'assurer que le nom d'utilisateur est unique et que les caractères ne nécessitent pas de conversion. Le nom d'utilisateur interne doit contenir uniquement les caractères suivants : [ a-zA-Z0-9_.@- ]. Les autres caractères sont remplacés par leur correspondance ASCII ou simplement omis. En cas de collision, un nombre est incrémenté/crémenté. Le nom d'utilisateur interne est utilisé pour identifier l'utilisateur au sein du système. C'est aussi le nom par défaut du répertoire utilisateur dans ownCloud. C'est aussi le port d'URLs distants, par exemple pour tous les services *DAV. Le comportement par défaut peut être modifié à l'aide de ce paramètre. Pour obtenir un comportement similaire aux versions précédentes à ownCloud 5, saisir le nom d'utilisateur à afficher dans le champ suivant. Laissez à blanc pour le comportement par défaut. Les modifications prendront effet seulement pour les nouveaux (ajoutés) utilisateurs LDAP.",
"Internal Username Attribute:" => "Nom d'utilisateur interne:",
"By default the internal username will be created from the UUID attribute. It makes sure that the username is unique and characters do not need to be converted. The internal username has the restriction that only these characters are allowed: [ a-zA-Z0-9_.@- ]. Other characters are replaced with their ASCII correspondence or simply omitted. On collisions a number will be added/increased. The internal username is used to identify a user internally. It is also the default name for the user home folder. It is also a part of remote URLs, for instance for all *DAV services. With this setting, the default behavior can be overridden. To achieve a similar behavior as before ownCloud 5 enter the user display name attribute in the following field. Leave it empty for default behavior. Changes will have effect only on newly mapped (added) LDAP users." => "Par défaut le nom d'utilisateur interne sera créé à partir de l'attribut UUID. Ceci permet d'assurer que le nom d'utilisateur est unique et que les caractères ne nécessitent pas de conversion. Le nom d'utilisateur interne doit contenir uniquement les caractères suivants : [ a-zA-Z0-9_.@- ]. Les autres caractères sont remplacés par leur correspondance ASCII ou simplement omis. En cas de collision, un nombre est ajouté/incrémenté. Le nom d'utilisateur interne est utilisé pour identifier l'utilisateur au sein du système. C'est aussi le nom par défaut du répertoire utilisateur dans ownCloud. Il fait aussi partie de certains URL de services, par exemple pour tous les services *DAV. Le comportement par défaut peut être modifié à l'aide de ce paramètre. Pour obtenir un comportement similaire aux versions précédentes à ownCloud 5, saisir le nom d'utilisateur à afficher dans le champ suivant. Laissez à blanc pour le comportement par défaut. Les modifications prendront effet seulement pour les nouveaux (ajoutés) utilisateurs LDAP.",
"Internal Username Attribute:" => "Nom d'utilisateur interne :",
"Override UUID detection" => "Surcharger la détection d'UUID",
"By default, the UUID attribute is automatically detected. The UUID attribute is used to doubtlessly identify LDAP users and groups. Also, the internal username will be created based on the UUID, if not specified otherwise above. You can override the setting and pass an attribute of your choice. You must make sure that the attribute of your choice can be fetched for both users and groups and it is unique. Leave it empty for default behavior. Changes will have effect only on newly mapped (added) LDAP users and groups." => "Par défaut, l'attribut UUID est automatiquement détecté. Cet attribut est utilisé pour identifier les utilisateurs et groupes de façon fiable. Un nom d'utilisateur interne basé sur l'UUID sera automatiquement créé, sauf s'il est spécifié autrement ci-dessus. Vous pouvez modifier ce comportement et définir l'attribut de votre choix. Vous devez alors vous assurer que l'attribut de votre choix peut être récupéré pour les utilisateurs ainsi que pour les groupes et qu'il soit unique. Laisser à blanc pour le comportement par défaut. Les modifications seront effectives uniquement pour les nouveaux (ajoutés) utilisateurs et groupes LDAP.",
"UUID Attribute for Users:" => "Attribut UUID pour les utilisateurs :",
+37 -38
View File
@@ -97,7 +97,11 @@ class Access extends LDAPUtility implements user\IUserTools {
$this->abandonPagedSearch();
// openLDAP requires that we init a new Paged Search. Not needed by AD,
// but does not hurt either.
$this->initPagedSearch($filter, array($dn), array($attr), 1, 0);
$pagingSize = intval($this->connection->ldapPagingSize);
// 0 won't result in replies, small numbers may leave out groups
// (cf. #12306), 500 is default for paging and should work everywhere.
$maxResults = $pagingSize > 20 ? $pagingSize : 500;
$this->initPagedSearch($filter, array($dn), array($attr), $maxResults, 0);
$dn = $this->DNasBaseParameter($dn);
$rr = @$this->ldap->read($cr, $dn, $filter, array($attr));
if(!$this->ldap->isResource($rr)) {
@@ -285,7 +289,7 @@ class Access extends LDAPUtility implements user\IUserTools {
* @param boolean $isUser is it a user? otherwise group
* @return string with the LDAP DN on success, otherwise false
*/
private function ocname2dn($name, $isUser) {
public function ocname2dn($name, $isUser) {
$table = $this->getMapTable($isUser);
$query = \OCP\DB::prepare('
@@ -626,38 +630,16 @@ class Access extends LDAPUtility implements user\IUserTools {
}
/**
* retrieves all known groups from the mappings table
* @return array with the results
*
* retrieves all known groups from the mappings table
* removes a user from the mappings table
* @param string $ocName
*/
private function mappedGroups() {
return $this->mappedComponents(false);
}
/**
* retrieves all known users from the mappings table
* @return array with the results
*
* retrieves all known users from the mappings table
*/
private function mappedUsers() {
return $this->mappedComponents(true);
}
/**
* @param boolean $isUsers
* @return array
*/
private function mappedComponents($isUsers) {
$table = $this->getMapTable($isUsers);
$query = \OCP\DB::prepare('
SELECT `ldap_dn`, `owncloud_name`
FROM `'. $table . '`'
);
return $query->execute()->fetchAll();
public function unmapUser($ocName) {
$table = $this->getMapTable(true);
$delete = \OCP\DB::prepare('
DELETE FROM `' . $table . '`
WHERE `owncloud_name` = ?
');
$delete->execute(array($ocName));
}
/**
@@ -705,7 +687,10 @@ class Access extends LDAPUtility implements user\IUserTools {
if($isUser) {
//make sure that email address is retrieved prior to login, so user
//will be notified when something is shared with him
$this->userManager->get($ocName)->update();
$user = $this->userManager->get($ocName);
if($user instanceof user\User) {
$user->update();
}
}
return true;
@@ -1084,7 +1069,7 @@ class Access extends LDAPUtility implements user\IUserTools {
/**
* escapes (user provided) parts for LDAP filter
* @param string $input, the provided value
* @param bool $allowAsterisk wether in * at the beginning should be preserved
* @param bool $allowAsterisk whether in * at the beginning should be preserved
* @return string the escaped string
*/
public function escapeFilterPart($input, $allowAsterisk = false) {
@@ -1485,7 +1470,8 @@ class Access extends LDAPUtility implements user\IUserTools {
* @return void
*/
private function setPagedResultCookie($base, $filter, $limit, $offset, $cookie) {
if(!empty($cookie)) {
// allow '0' for 389ds
if(!empty($cookie) || $cookie === '0') {
$cacheKey = 'lc' . crc32($base) . '-' . crc32($filter) . '-' .intval($limit) . '-' . intval($offset);
$this->cookies[$cacheKey] = $cookie;
$this->lastCookie = $cookie;
@@ -1523,11 +1509,12 @@ class Access extends LDAPUtility implements user\IUserTools {
foreach($bases as $base) {
$cookie = $this->getPagedResultCookie($base, $filter, $limit, $offset);
if(empty($cookie) && ($offset > 0)) {
if(empty($cookie) && $cookie !== "0" && ($offset > 0)) {
// no cookie known, although the offset is not 0. Maybe cache run out. We need
// to start all over *sigh* (btw, Dear Reader, did you know LDAP paged
// searching was designed by MSFT?)
// Lukas: No, but thanks to reading that source I finally know!
// '0' is valid, because 389ds
$reOffset = ($offset - $limit) < 0 ? 0 : $offset - $limit;
//a bit recursive, $offset of 0 is the exit
\OCP\Util::writeLog('user_ldap', 'Looking for cookie L/O '.$limit.'/'.$reOffset, \OCP\Util::INFO);
@@ -1535,7 +1522,8 @@ class Access extends LDAPUtility implements user\IUserTools {
$cookie = $this->getPagedResultCookie($base, $filter, $limit, $offset);
//still no cookie? obviously, the server does not like us. Let's skip paging efforts.
//TODO: remember this, probably does not change in the next request...
if(empty($cookie)) {
if(empty($cookie) && $cookie !== '0') {
// '0' is valid, because 389ds
$cookie = null;
}
}
@@ -1556,6 +1544,17 @@ class Access extends LDAPUtility implements user\IUserTools {
}
}
} else if($this->connection->hasPagedResultSupport && intval($limit) === 0) {
// a search without limit was requested. However, if we do use
// Paged Search once, we always must do it. This requires us to
// initialize it with the configured page size.
$this->abandonPagedSearch();
// in case someone set it to 0 … use 500, otherwise no results will
// be returned.
$pageSize = intval($this->connection->ldapPagingSize) > 0 ? intval($this->connection->ldapPagingSize) : 500;
$pagedSearchOK = $this->ldap->controlPagedResult(
$this->connection->getConnectionResource(), $pageSize, false, ''
);
}
return $pagedSearchOK;
+13 -4
View File
@@ -24,12 +24,19 @@
namespace OCA\user_ldap\lib;
//magic properties (incomplete)
use OC\ServerNotAvailableException;
/**
* responsible for LDAP connections in context with the provided configuration
*
* @property string ldapUserFilter
* @property string ldapUserDisplayName
* @property boolean hasPagedResultSupport
*/
* @property string[] ldapBaseUsers
* @property int|string ldapPagingSize holds an integer
* @property string ldapLoginFilter
* @property string ldapGroupMemberAssocAttr
*/
class Connection extends LDAPUtility {
private $ldapConnectionRes = null;
private $configPrefix;
@@ -43,7 +50,7 @@ class Connection extends LDAPUtility {
//cache handler
protected $cache;
//settings handler
/** @var Configuration settings handler **/
protected $configuration;
protected $doNotValidate = false;
@@ -70,8 +77,9 @@ class Connection extends LDAPUtility {
}
$this->hasPagedResultSupport =
$this->ldap->hasPagedResultSupport();
$helper = new Helper();
$this->doNotValidate = !in_array($this->configPrefix,
Helper::getServerConfigurationPrefixes());
$helper->getServerConfigurationPrefixes());
}
public function __destruct() {
@@ -155,7 +163,8 @@ class Connection extends LDAPUtility {
$this->establishConnection();
}
if(is_null($this->ldapConnectionRes)) {
\OCP\Util::writeLog('user_ldap', 'Connection could not be established', \OCP\Util::ERROR);
\OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, \OCP\Util::ERROR);
throw new ServerNotAvailableException('Connection to LDAP server could not be established');
}
return $this->ldapConnectionRes;
}
+21 -5
View File
@@ -45,7 +45,7 @@ class Helper {
* except the default (first) server shall be connected to.
*
*/
static public function getServerConfigurationPrefixes($activeConfigurations = false) {
public function getServerConfigurationPrefixes($activeConfigurations = false) {
$referenceConfigkey = 'ldap_configuration_active';
$sql = '
@@ -83,7 +83,7 @@ class Helper {
* @return array an array with configprefix as keys
*
*/
static public function getServerConfigurationHosts() {
public function getServerConfigurationHosts() {
$referenceConfigkey = 'ldap_host';
$query = '
@@ -110,7 +110,7 @@ class Helper {
* @param string $prefix the configuration prefix of the config to delete
* @return bool true on success, false otherwise
*/
static public function deleteServerConfiguration($prefix) {
public function deleteServerConfiguration($prefix) {
//just to be on the safe side
\OCP\User::checkAdminUser();
@@ -144,13 +144,29 @@ class Helper {
return true;
}
/**
* checks whether there is one or more disabled LDAP configurations
* @throws \Exception
* @return bool
*/
public function haveDisabledConfigurations() {
$all = $this->getServerConfigurationPrefixes(false);
$active = $this->getServerConfigurationPrefixes(true);
if(!is_array($all) || !is_array($active)) {
throw new \Exception('Unexpected Return Value');
}
return count($all) !== count($active) || count($all) === 0;
}
/**
* Truncate's the given mapping table
*
* @param string $mapping either 'user' or 'group'
* @return bool true on success, false otherwise
*/
static public function clearMapping($mapping) {
public function clearMapping($mapping) {
if($mapping === 'user') {
$table = '`*PREFIX*ldap_user_mapping`';
} else if ($mapping === 'group') {
@@ -176,7 +192,7 @@ class Helper {
* @param string $url the URL
* @return string|false domain as string on success, false otherwise
*/
static public function getDomainFromURL($url) {
public function getDomainFromURL($url) {
$uinfo = parse_url($url);
if(!is_array($uinfo)) {
return false;
+2 -1
View File
@@ -156,7 +156,8 @@ class Jobs extends \OC\BackgroundJob\TimedJob {
if(!is_null(self::$groupBE)) {
return self::$groupBE;
}
$configPrefixes = Helper::getServerConfigurationPrefixes(true);
$helper = new Helper();
$configPrefixes = $helper->getServerConfigurationPrefixes(true);
$ldapWrapper = new LDAP();
if(count($configPrefixes) === 1) {
//avoid the proxy when there is only one LDAP server configured
+227
View File
@@ -0,0 +1,227 @@
<?php
/**
* Copyright (c) 2014 Arthur Schiwon <blizzz@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\User_LDAP\Jobs;
use \OCA\user_ldap\User_Proxy;
use \OCA\user_ldap\lib\Helper;
use \OCA\user_ldap\lib\LDAP;
/**
* Class CleanUp
*
* a Background job to clean up deleted users
*
* @package OCA\user_ldap\lib;
*/
class CleanUp extends \OC\BackgroundJob\TimedJob {
/**
* @var int $limit amount of users that should be checked per run
*/
protected $limit = 50;
/**
* @var \OCP\UserInterface $userBackend
*/
protected $userBackend;
/**
* @var \OCP\IConfig $ocConfig
*/
protected $ocConfig;
/**
* @var \OCP\IDBConnection $db
*/
protected $db;
/**
* @var Helper $ldapHelper
*/
protected $ldapHelper;
/**
* @var int $defaultIntervalMin default interval in minutes
*/
protected $defaultIntervalMin = 51;
public function __construct() {
$minutes = \OC::$server->getConfig()->getSystemValue(
'ldapUserCleanupInterval', strval($this->defaultIntervalMin));
$this->setInterval(intval($minutes) * 60);
}
/**
* assigns the instances passed to run() to the class properties
* @param array $arguments
*/
public function setArguments($arguments) {
//Dependency Injection is not possible, because the constructor will
//only get values that are serialized to JSON. I.e. whatever we would
//pass in app.php we do add here, except something else is passed e.g.
//in tests.
if(isset($arguments['helper'])) {
$this->ldapHelper = $arguments['helper'];
} else {
$this->ldapHelper = new Helper();
}
if(isset($arguments['userBackend'])) {
$this->userBackend = $arguments['userBackend'];
} else {
$this->userBackend = new User_Proxy(
$this->ldapHelper->getServerConfigurationPrefixes(true),
new LDAP()
);
}
if(isset($arguments['ocConfig'])) {
$this->ocConfig = $arguments['ocConfig'];
} else {
$this->ocConfig = \OC::$server->getConfig();
}
if(isset($arguments['db'])) {
$this->db = $arguments['db'];
} else {
$this->db = \OC::$server->getDatabaseConnection();
}
}
/**
* makes the background job do its work
* @param array $argument
*/
public function run($argument) {
$this->setArguments($argument);
if(!$this->isCleanUpAllowed()) {
return;
}
$users = $this->getMappedUsers($this->limit, $this->getOffset());
if(!is_array($users)) {
//something wrong? Let's start from the beginning next time and
//abort
$this->setOffset(true);
return;
}
$resetOffset = $this->isOffsetResetNecessary(count($users));
$this->checkUsers($users);
$this->setOffset($resetOffset);
}
/**
* checks whether next run should start at 0 again
* @param int $resultCount
* @return bool
*/
public function isOffsetResetNecessary($resultCount) {
return ($resultCount < $this->limit) ? true : false;
}
/**
* checks whether cleaning up LDAP users is allowed
* @return bool
*/
public function isCleanUpAllowed() {
try {
if($this->ldapHelper->haveDisabledConfigurations()) {
return false;
}
} catch (\Exception $e) {
return false;
}
$enabled = $this->isCleanUpEnabled();
return $enabled;
}
/**
* checks whether clean up is enabled by configuration
* @return bool
*/
private function isCleanUpEnabled() {
return (bool)$this->ocConfig->getSystemValue(
'ldapUserCleanupInterval', strval($this->defaultIntervalMin));
}
/**
* checks users whether they are still existing
* @param array $users result from getMappedUsers()
*/
private function checkUsers($users) {
foreach($users as $user) {
$this->checkUser($user);
}
}
/**
* checks whether a user is still existing in LDAP
* @param string[] $user
*/
private function checkUser($user) {
if($this->userBackend->userExistsOnLDAP($user['name'])) {
//still available, all good
return;
}
// TODO FIXME consolidate next line in DeletedUsersIndex
// (impractical now, because of class dependencies)
$this->ocConfig->setUserValue($user['name'], 'user_ldap', 'isDeleted', '1');
}
/**
* returns a batch of users from the mappings table
* @param int $limit
* @param int $offset
* @return array
*/
public function getMappedUsers($limit, $offset) {
$query = $this->db->prepare('
SELECT
`ldap_dn` AS `dn`,
`owncloud_name` AS `name`,
`directory_uuid` AS `uuid`
FROM `*PREFIX*ldap_user_mapping`',
$limit,
$offset
);
$query->execute();
return $query->fetchAll();
}
/**
* gets the offset to fetch users from the mappings table
* @return int
*/
private function getOffset() {
return $this->ocConfig->getAppValue('user_ldap', 'cleanUpJobOffset', 0);
}
/**
* sets the new offset for the next run
* @param bool $reset whether the offset should be set to 0
*/
public function setOffset($reset = false) {
$newOffset = $reset ? 0 :
$this->getOffset() + $this->limit;
$this->ocConfig->setAppValue('user_ldap', 'cleanUpJobOffset', $newOffset);
}
/**
* returns the chunk size (limit in DB speak)
* @return int
*/
public function getChunkSize() {
return $this->limit;
}
}
+4
View File
@@ -23,6 +23,8 @@
namespace OCA\user_ldap\lib;
use OC\ServerNotAvailableException;
class LDAP implements ILDAPWrapper {
protected $curFunc = '';
protected $curArgs = array();
@@ -280,6 +282,8 @@ class LDAP implements ILDAPWrapper {
//for now
} else if ($errorCode === 10) {
//referrals, we switch them off, but then there is AD :)
} else if ($errorCode === -1) {
throw new ServerNotAvailableException('Lost connection to LDAP server.');
} else {
\OCP\Util::writeLog('user_ldap',
'LDAP error '.$errorMsg.' (' .
@@ -0,0 +1,125 @@
<?php
/**
* ownCloud LDAP Helper
*
* @author Arthur Schiwon
* @copyright 2014 Arthur Schiwon <blizzz@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library 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 library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\user_ldap\lib\user;
use OCA\user_ldap\lib\user\OfflineUser;
use OCA\user_ldap\lib\Access;
/**
* Class DeletedUsersIndex
* @package OCA\User_LDAP
*/
class DeletedUsersIndex {
/**
* @var \OC\Preferences $preferences
*/
protected $preferences;
/**
* @var \OCP\IDBConnection $db
*/
protected $db;
/**
* @var \OCA\user_ldap\lib\Access $access
*/
protected $access;
/**
* @var int $limit
*/
protected $limit = 10;
/**
* @var array $deletedUsers
*/
protected $deletedUsers = false;
public function __construct(\OC\Preferences $preferences, \OCP\IDBConnection $db, Access $access) {
$this->preferences = $preferences;
$this->db = $db;
$this->access = $access;
}
/**
* returns key to be used against $this->deletedUsers
* @param int $limit
* @param int $offset
* @return string
*/
private function getDeletedUsersCacheKey($limit, $offset) {
return strval($limit) . '.' . strval($offset);
}
/**
* reads LDAP users marked as deleted from the database
* @param int $offset
* @return OCA\user_ldap\lib\user\OfflineUser[]
*/
private function fetchDeletedUsers($offset) {
$deletedUsers = $this->preferences->getUsersForValue(
'user_ldap', 'isDeleted', '1', $this->limit, $offset);
$key = $this->getDeletedUsersCacheKey($this->limit, $offset);
$userObjects = array();
foreach($deletedUsers as $user) {
$userObjects[] = new OfflineUser($user, $this->preferences, $this->db, $this->access);
}
$this->deletedUsers[$key] = $userObjects;
if(count($userObjects) > 0) {
$this->hasUsers();
}
return $this->deletedUsers[$key];
}
/**
* returns all LDAP users that are marked as deleted
* @param int|null $offset
* @return OCA\user_ldap\lib\user\OfflineUser[]
*/
public function getUsers($offset = null) {
$key = $this->getDeletedUsersCacheKey($this->limit, $offset);
if(is_array($this->deletedUsers) && isset($this->deletedUsers[$key])) {
return $this->deletedUsers[$key];
}
return $this->fetchDeletedUsers($offset);
}
/**
* whether at least one user was detected as deleted
* @return bool
*/
public function hasUsers() {
if($this->deletedUsers === false) {
$this->fetchDeletedUsers(0);
}
foreach($this->deletedUsers as $batch) {
if(count($batch) > 0) {
return true;
}
}
return false;
}
}
+3
View File
@@ -39,4 +39,7 @@ interface IUserTools {
public function username2dn($name);
//temporary hack for LDAP user cleanup, will be removed in OC 8.
public function ocname2dn($name, $isUser);
}
+53 -19
View File
@@ -27,6 +27,7 @@ use OCA\user_ldap\lib\user\IUserTools;
use OCA\user_ldap\lib\user\User;
use OCA\user_ldap\lib\LogWrapper;
use OCA\user_ldap\lib\FilesystemHelper;
use OCA\user_ldap\lib\user\OfflineUser;
/**
* Manager
@@ -60,7 +61,9 @@ class Manager {
*/
protected $avatarManager;
/**
* @var string[][]
* array['byDN'] \OCA\user_ldap\lib\User[]
* ['byUid'] \OCA\user_ldap\lib\User[]
* @var array $users
*/
protected $users = array(
'byDN' => array(),
@@ -114,8 +117,8 @@ class Manager {
$user = new User($uid, $dn, $this->access, $this->ocConfig,
$this->ocFilesystem, clone $this->image, $this->ocLog,
$this->avatarManager);
$users['byDN'][$dn] = $user;
$users['byUid'][$uid] = $user;
$this->users['byDN'][$dn] = $user;
$this->users['byUid'][$uid] = $user;
return $user;
}
@@ -131,9 +134,51 @@ class Manager {
}
/**
* @brief returns a User object by it's DN or ownCloud username
* Checks whether the specified user is marked as deleted
* @param string $id the ownCloud user name
* @return bool
*/
public function isDeletedUser($id) {
$isDeleted = $this->ocConfig->getUserValue(
$id, 'user_ldap', 'isDeleted', 0);
return intval($isDeleted) === 1;
}
/**
* creates and returns an instance of OfflineUser for the specified user
* @param string $id
* @return \OCA\user_ldap\lib\user\OfflineUser
*/
public function getDeletedUser($id) {
return new OfflineUser(
$id,
new \OC\Preferences(\OC_DB::getConnection()),
\OC::$server->getDatabaseConnection(),
$this->access);
}
/**
* @brief returns a User object by it's ownCloud username
* @param string the DN or username of the user
* @return \OCA\user_ldap\lib\User | null
* @return \OCA\user_ldap\lib\user\User|\OCA\user_ldap\lib\user\OfflineUser|null
*/
protected function createInstancyByUserName($id) {
//most likely a uid. Check whether it is a deleted user
if($this->isDeletedUser($id)) {
return $this->getDeletedUser($id);
}
$dn = $this->access->username2dn($id);
if($dn !== false) {
return $this->createAndCache($dn, $id);
}
return null;
}
/**
* @brief returns a User object by it's DN or ownCloud username
* @param string the username of the user
* @return \OCA\user_ldap\lib\user\User|\OCA\user_ldap\lib\user\OfflineUser|null
* @throws \Exception when connection could not be established
*/
public function get($id) {
$this->checkAccess();
@@ -143,25 +188,14 @@ class Manager {
return $this->users['byUid'][$id];
}
if(!$this->access->stringResemblesDN($id) ) {
//most likely a uid
$dn = $this->access->username2dn($id);
if($dn !== false) {
return $this->createAndCache($dn, $id);
}
} else {
//so it's a DN
if($this->access->stringResemblesDN($id) ) {
$uid = $this->access->dn2username($id);
if($uid !== false) {
return $this->createAndCache($id, $uid);
}
}
//either funny uid or invalid. Assume funny to be on the safe side.
$dn = $this->access->username2dn($id);
if($dn !== false) {
return $this->createAndCache($dn, $id);
}
return null;
return $this->createInstancyByUserName($id);
}
}
+217
View File
@@ -0,0 +1,217 @@
<?php
/**
* ownCloud LDAP User
*
* @author Arthur Schiwon
* @copyright 2014 Arthur Schiwon blizzz@owncloud.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library 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 library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\user_ldap\lib\user;
use OCA\user_ldap\lib\Access;
class OfflineUser {
/**
* @var string $ocName
*/
protected $ocName;
/**
* @var string $dn
*/
protected $dn;
/**
* @var string $uid the UID as provided by LDAP
*/
protected $uid;
/**
* @var string $displayName
*/
protected $displayName;
/**
* @var string $homePath
*/
protected $homePath;
/**
* @var string $lastLogin the timestamp of the last login
*/
protected $lastLogin;
/**
* @var string $email
*/
protected $email;
/**
* @var bool $hasActiveShares
*/
protected $hasActiveShares;
/**
* @var \OC\Preferences $preferences
*/
protected $preferences;
/**
* @var \OCP\IDBConnection $db
*/
protected $db;
/**
* @var \OCA\user_ldap\lib\Access
*/
protected $access;
public function __construct($ocName, \OC\Preferences $preferences, \OCP\IDBConnection $db, Access $access) {
$this->ocName = $ocName;
$this->preferences = $preferences;
$this->db = $db;
$this->access = $access;
$this->fetchDetails();
}
/**
* exports the user details in an assoc array
* @return array
*/
public function export() {
$data = array();
$data['ocName'] = $this->getOCName();
$data['dn'] = $this->getDN();
$data['uid'] = $this->getUID();
$data['displayName'] = $this->getDisplayName();
$data['homePath'] = $this->getHomePath();
$data['lastLogin'] = $this->getLastLogin();
$data['email'] = $this->getEmail();
$data['hasActiveShares'] = $this->getHasActiveShares();
return $data;
}
/**
* getter for ownCloud internal name
* @return string
*/
public function getOCName() {
return $this->ocName;
}
/**
* getter for LDAP uid
* @return string
*/
public function getUID() {
return $this->uid;
}
/**
* getter for LDAP DN
* @return string
*/
public function getDN() {
return $this->dn;
}
/**
* getter for display name
* @return string
*/
public function getDisplayName() {
return $this->displayName;
}
/**
* getter for email
* @return string
*/
public function getEmail() {
return $this->email;
}
/**
* getter for home directory path
* @return string
*/
public function getHomePath() {
return $this->homePath;
}
/**
* getter for the last login timestamp
* @return int
*/
public function getLastLogin() {
return intval($this->lastLogin);
}
/**
* getter for having active shares
* @return bool
*/
public function getHasActiveShares() {
return $this->hasActiveShares;
}
/**
* reads the user details
*/
protected function fetchDetails() {
$properties = array (
'displayName' => 'user_ldap',
'uid' => 'user_ldap',
'homePath' => 'user_ldap',
'email' => 'settings',
'lastLogin' => 'login'
);
foreach($properties as $property => $app) {
$this->$property = $this->preferences->getValue($this->ocName, $app, $property, '');
}
$dn = $this->access->ocname2dn($this->ocName, true);
$this->dn = ($dn !== false) ? $dn : '';
$this->determineShares();
}
/**
* finds out whether the user has active shares. The result is stored in
* $this->hasActiveShares
*/
protected function determineShares() {
$query = $this->db->prepare('
SELECT COUNT(`uid_owner`)
FROM `*PREFIX*share`
WHERE `uid_owner` = ?
', 1);
$query->execute(array($this->ocName));
$sResult = $query->fetchColumn(0);
if(intval($sResult) === 1) {
$this->hasActiveShares = true;
return;
}
$query = $this->db->prepare('
SELECT COUNT(`owner`)
FROM `*PREFIX*share_external`
WHERE `owner` = ?
', 1);
$query->execute(array($this->ocName));
$sResult = $query->fetchColumn(0);
if(intval($sResult) === 1) {
$this->hasActiveShares = true;
return;
}
$this->hasActiveShares = false;
}
}
+32 -1
View File
@@ -212,6 +212,31 @@ class User {
return true;
}
/**
* Stores a key-value pair in relation to this user
* @param string $key
* @param string $value
*/
private function store($key, $value) {
$this->config->setUserValue($this->uid, 'user_ldap', $key, $value);
}
/**
* Stores the display name in the databae
* @param string $displayName
*/
public function storeDisplayName($displayName) {
$this->store('displayName', $displayName);
}
/**
* Stores the LDAP Username in the Database
* @param string $userName
*/
public function storeLDAPUserName($userName) {
$this->store('uid', $userName);
}
/**
* @brief checks whether an update method specified by feature was run
* already. If not, it will marked like this, because it is expected that
@@ -318,7 +343,13 @@ class User {
}
$avatar = $this->avatarManager->getAvatar($this->uid);
$avatar->set($this->image);
try {
$avatar->set($this->image);
} catch (\Exception $e) {
\OC::$server->getLogger()->notice(
'Could not set avatar for ' . $this->dn . ', because: ' . $e->getMessage(),
array('app' => 'user_ldap'));
}
}
}
+36 -17
View File
@@ -23,6 +23,8 @@
namespace OCA\user_ldap\lib;
use OC\ServerNotAvailableException;
class Wizard extends LDAPUtility {
static protected $l;
protected $access;
@@ -614,7 +616,8 @@ class Wizard extends LDAPUtility {
//this did not help :(
//Let's see whether we can parse the Host URL and convert the domain to
//a base DN
$domain = Helper::getDomainFromURL($this->configuration->ldapHost);
$helper = new Helper();
$domain = $helper->getDomainFromURL($this->configuration->ldapHost);
if(!$domain) {
return false;
}
@@ -803,13 +806,23 @@ class Wizard extends LDAPUtility {
}
$base = $this->configuration->ldapBase[0];
foreach($cns as $cn) {
$rr = $this->ldap->search($cr, $base, 'cn=' . $cn, array('dn'));
$rr = $this->ldap->search($cr, $base, 'cn=' . $cn, array('dn', 'primaryGroupToken'));
if(!$this->ldap->isResource($rr)) {
continue;
}
$er = $this->ldap->firstEntry($cr, $rr);
$attrs = $this->ldap->getAttributes($cr, $er);
$dn = $this->ldap->getDN($cr, $er);
$filter .= '(memberof=' . $dn . ')';
if(empty($dn)) {
continue;
}
$filterPart = '(memberof=' . $dn . ')';
if(isset($attrs['primaryGroupToken'])) {
$pgt = $attrs['primaryGroupToken'][0];
$primaryFilterPart = '(primaryGroupID=' . $pgt .')';
$filterPart = '(|' . $filterPart . $primaryFilterPart . ')';
}
$filter .= $filterPart;
}
$filter .= ')';
}
@@ -954,18 +967,27 @@ class Wizard extends LDAPUtility {
$this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
$this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0);
$this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT);
if($tls) {
$isTlsWorking = @$this->ldap->startTls($cr);
if(!$isTlsWorking) {
return false;
}
}
\OCP\Util::writeLog('user_ldap', 'Wiz: Attemping to Bind ', \OCP\Util::DEBUG);
//interesting part: do the bind!
$login = $this->ldap->bind($cr,
$this->configuration->ldapAgentName,
$this->configuration->ldapAgentPassword);
try {
if($tls) {
$isTlsWorking = @$this->ldap->startTls($cr);
if(!$isTlsWorking) {
return false;
}
}
\OCP\Util::writeLog('user_ldap', 'Wiz: Attemping to Bind ', \OCP\Util::DEBUG);
//interesting part: do the bind!
$login = $this->ldap->bind($cr,
$this->configuration->ldapAgentName,
$this->configuration->ldapAgentPassword
);
$errNo = $this->ldap->errno($cr);
$error = ldap_error($cr);
$this->ldap->unbind($cr);
} catch(ServerNotAvailableException $e) {
return false;
}
if($login === true) {
$this->ldap->unbind($cr);
@@ -976,9 +998,6 @@ class Wizard extends LDAPUtility {
return true;
}
$errNo = $this->ldap->errno($cr);
$error = ldap_error($cr);
$this->ldap->unbind($cr);
if($errNo === -1 || ($errNo === 2 && $ncc)) {
//host, port or TLS wrong
return false;
+3 -2
View File
@@ -36,8 +36,9 @@ OCP\Util::addStyle('core', 'jquery-ui-1.10.0.custom');
// fill template
$tmpl = new OCP\Template('user_ldap', 'settings');
$prefixes = \OCA\user_ldap\lib\Helper::getServerConfigurationPrefixes();
$hosts = \OCA\user_ldap\lib\Helper::getServerConfigurationHosts();
$helper = new \OCA\user_ldap\lib\Helper();
$prefixes = $helper->getServerConfigurationPrefixes();
$hosts = $helper->getServerConfigurationHosts();
$wizardHtml = '';
$toc = array();
+90 -1
View File
@@ -77,10 +77,15 @@ class Test_Group_Ldap extends \PHPUnit_Framework_TestCase {
->method('readAttribute')
->will($this->returnValue(array('u11', 'u22', 'u33', 'u34')));
// for primary groups
$access->expects($this->once())
->method('countUsers')
->will($this->returnValue(2));
$groupBackend = new GroupLDAP($access);
$users = $groupBackend->countUsersInGroup('group');
$this->assertSame(4, $users);
$this->assertSame(6, $users);
}
public function testCountWithSearchString() {
@@ -294,4 +299,88 @@ class Test_Group_Ldap extends \PHPUnit_Framework_TestCase {
$groupBackend->inGroup($uid, $gid);
}
public function testGetGroupsWithOffset() {
$access = $this->getAccessMock();
$this->enableGroups($access);
$access->expects($this->once())
->method('ownCloudGroupNames')
->will($this->returnValue(array('group1', 'group2')));
$groupBackend = new GroupLDAP($access);
$groups = $groupBackend->getGroups('', 2, 2);
$this->assertSame(2, count($groups));
}
/**
* tests that a user listing is complete, if all it's members have the group
* as their primary.
*/
public function testUsersInGroupPrimaryMembersOnly() {
$access = $this->getAccessMock();
$this->enableGroups($access);
$access->connection->expects($this->any())
->method('getFromCache')
->will($this->returnValue(null));
$access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn, $attr) {
if($attr === 'primaryGroupToken') {
return array(1337);
}
return array();
}));
$access->expects($this->any())
->method('groupname2dn')
->will($this->returnValue('cn=foobar,dc=foo,dc=bar'));
$access->expects($this->once())
->method('ownCloudUserNames')
->will($this->returnValue(array('lisa', 'bart', 'kira', 'brad')));
$groupBackend = new GroupLDAP($access);
$users = $groupBackend->usersInGroup('foobar');
$this->assertSame(4, count($users));
}
/**
* tests that a user counting is complete, if all it's members have the group
* as their primary.
*/
public function testCountUsersInGroupPrimaryMembersOnly() {
$access = $this->getAccessMock();
$this->enableGroups($access);
$access->connection->expects($this->any())
->method('getFromCache')
->will($this->returnValue(null));
$access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn, $attr) {
if($attr === 'primaryGroupToken') {
return array(1337);
}
return array();
}));
$access->expects($this->any())
->method('groupname2dn')
->will($this->returnValue('cn=foobar,dc=foo,dc=bar'));
$access->expects($this->once())
->method('countUsers')
->will($this->returnValue(4));
$groupBackend = new GroupLDAP($access);
$users = $groupBackend->countUsersInGroup('foobar');
$this->assertSame(4, $users);
}
}
+2 -1
View File
@@ -23,7 +23,8 @@ class Test_Helper extends \PHPUnit_Framework_TestCase {
$result = $statement->execute();
$this->assertEquals(2, $result->fetchOne());
Helper::clearMapping('user');
$helper = new Helper();
$helper->clearMapping('user');
$result = $statement->execute();
$this->assertEquals(0, $result->fetchOne());
+155
View File
@@ -0,0 +1,155 @@
<?php
/**
* Copyright (c) 2014 Arthur Schiwon <blizzz@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\user_ldap\tests;
class Test_CleanUp extends \PHPUnit_Framework_TestCase {
public function getMocks() {
$mocks = array();
$mocks['userBackend'] =
$this->getMockBuilder('\OCA\user_ldap\User_Proxy')
->disableOriginalConstructor()
->getMock();
$mocks['ocConfig'] = $this->getMock('\OCP\IConfig');
$mocks['db'] = $this->getMock('\OCP\IDBConnection');
$mocks['helper'] = $this->getMock('\OCA\user_ldap\lib\Helper');
return $mocks;
}
/**
* clean up job must not run when there are disabled configurations
*/
public function test_runNotAllowedByDisabledConfigurations() {
$args = $this->getMocks();
$args['helper']->expects($this->once())
->method('haveDisabledConfigurations')
->will($this->returnValue(true) );
$args['ocConfig']->expects($this->never())
->method('getSystemValue');
$bgJob = new \OCA\User_LDAP\Jobs\CleanUp();
$bgJob->setArguments($args);
$result = $bgJob->isCleanUpAllowed();
$this->assertSame(false, $result);
}
/**
* clean up job must not run when LDAP Helper is broken i.e.
* returning unexpected results
*/
public function test_runNotAllowedByBrokenHelper() {
$args = $this->getMocks();
$args['helper']->expects($this->once())
->method('haveDisabledConfigurations')
->will($this->throwException(new \Exception()));
$args['ocConfig']->expects($this->never())
->method('getSystemValue');
$bgJob = new \OCA\User_LDAP\Jobs\CleanUp();
$bgJob->setArguments($args);
$result = $bgJob->isCleanUpAllowed();
$this->assertSame(false, $result);
}
/**
* clean up job must not run when it is not enabled
*/
public function test_runNotAllowedBySysConfig() {
$args = $this->getMocks();
$args['helper']->expects($this->once())
->method('haveDisabledConfigurations')
->will($this->returnValue(false));
$args['ocConfig']->expects($this->once())
->method('getSystemValue')
->will($this->returnValue(false));
$bgJob = new \OCA\User_LDAP\Jobs\CleanUp();
$bgJob->setArguments($args);
$result = $bgJob->isCleanUpAllowed();
$this->assertSame(false, $result);
}
/**
* clean up job is allowed to run
*/
public function test_runIsAllowed() {
$args = $this->getMocks();
$args['helper']->expects($this->once())
->method('haveDisabledConfigurations')
->will($this->returnValue(false));
$args['ocConfig']->expects($this->once())
->method('getSystemValue')
->will($this->returnValue(true));
$bgJob = new \OCA\User_LDAP\Jobs\CleanUp();
$bgJob->setArguments($args);
$result = $bgJob->isCleanUpAllowed();
$this->assertSame(true, $result);
}
/**
* test whether sql is OK
*/
public function test_getMappedUsers() {
$args = $this->getMocks();
$bgJob = new \OCA\User_LDAP\Jobs\CleanUp();
$bgJob->setArguments($args);
if(version_compare(\PHPUnit_Runner_Version::id(), '3.8', '<')) {
//otherwise we run into
//https://github.com/sebastianbergmann/phpunit-mock-objects/issues/103
$this->markTestIncomplete();
}
$stmt = $this->getMock('\Doctrine\DBAL\Driver\Statement');
$args['db']->expects($this->once())
->method('prepare')
->will($this->returnValue($stmt));
$bgJob->getMappedUsers(0, $bgJob->getChunkSize());
}
/**
* check whether offset will be reset when it needs to
*/
public function test_OffsetResetIsNecessary() {
$args = $this->getMocks();
$bgJob = new \OCA\User_LDAP\Jobs\CleanUp();
$bgJob->setArguments($args);
$result = $bgJob->isOffsetResetNecessary($bgJob->getChunkSize() - 1);
$this->assertSame(true, $result);
}
/**
* make sure offset is not reset when it is not due
*/
public function test_OffsetResetIsNotNecessary() {
$args = $this->getMocks();
$bgJob = new \OCA\User_LDAP\Jobs\CleanUp();
$bgJob->setArguments($args);
$result = $bgJob->isOffsetResetNecessary($bgJob->getChunkSize());
$this->assertSame(false, $result);
}
}
+157 -153
View File
@@ -1,24 +1,24 @@
<?php
/**
* ownCloud
*
* @author Arthur Schiwon
* @copyright 2014 Arthur Schiwon blizzz@owncloud.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library 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 library. If not, see <http://www.gnu.org/licenses/>.
*
*/
* ownCloud
*
* @author Arthur Schiwon
* @copyright 2014 Arthur Schiwon blizzz@owncloud.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library 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 library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\user_ldap\tests;
@@ -26,173 +26,177 @@ use OCA\user_ldap\lib\user\Manager;
class Test_User_Manager extends \PHPUnit_Framework_TestCase {
private function getTestInstances() {
$access = $this->getMock('\OCA\user_ldap\lib\user\IUserTools');
$config = $this->getMock('\OCP\IConfig');
$filesys = $this->getMock('\OCA\user_ldap\lib\FilesystemHelper');
$log = $this->getMock('\OCA\user_ldap\lib\LogWrapper');
$avaMgr = $this->getMock('\OCP\IAvatarManager');
$image = $this->getMock('\OCP\Image');
private function getTestInstances() {
$access = $this->getMock('\OCA\user_ldap\lib\user\IUserTools');
$config = $this->getMock('\OCP\IConfig');
$filesys = $this->getMock('\OCA\user_ldap\lib\FilesystemHelper');
$log = $this->getMock('\OCA\user_ldap\lib\LogWrapper');
$avaMgr = $this->getMock('\OCP\IAvatarManager');
$image = $this->getMock('\OCP\Image');
return array($access, $config, $filesys, $image, $log, $avaMgr);
}
return array($access, $config, $filesys, $image, $log, $avaMgr);
}
public function testGetByDNExisting() {
list($access, $config, $filesys, $image, $log, $avaMgr) =
$this->getTestInstances();
public function testGetByDNExisting() {
list($access, $config, $filesys, $image, $log, $avaMgr) =
$this->getTestInstances();
$inputDN = 'cn=foo,dc=foobar,dc=bar';
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
$inputDN = 'cn=foo,dc=foobar,dc=bar';
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
$access->expects($this->once())
->method('stringResemblesDN')
->with($this->equalTo($inputDN))
->will($this->returnValue(true));
$access->expects($this->once())
->method('dn2username')
->with($this->equalTo($inputDN))
->will($this->returnValue($uid));
$access->expects($this->never())
->method('username2dn');
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
}
public function testGetByEDirectoryDN() {
list($access, $config, $filesys, $image, $log, $avaMgr) =
$this->getTestInstances();
$inputDN = 'uid=foo,o=foobar,c=bar';
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
->method('stringResemblesDN')
->with($this->equalTo($inputDN))
->will($this->returnValue(true));
$access->expects($this->once())
->method('stringResemblesDN')
->with($this->equalTo($inputDN))
->will($this->returnValue(true));
->method('dn2username')
->with($this->equalTo($inputDN))
->will($this->returnValue($uid));
$access->expects($this->once())
->method('dn2username')
->with($this->equalTo($inputDN))
->will($this->returnValue($uid));
$access->expects($this->never())
->method('username2dn');
$access->expects($this->never())
->method('username2dn');
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
// Now we fetch the user again. If this leads to a failing test,
// runtime caching the manager is broken.
$user = $manager->get($inputDN);
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
}
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
}
public function testGetByExoticDN() {
list($access, $config, $filesys, $image, $log, $avaMgr) =
$this->getTestInstances();
public function testGetByEDirectoryDN() {
list($access, $config, $filesys, $image, $log, $avaMgr) =
$this->getTestInstances();
$inputDN = 'ab=cde,f=ghei,mno=pq';
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
$inputDN = 'uid=foo,o=foobar,c=bar';
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
$access->expects($this->once())
->method('stringResemblesDN')
->with($this->equalTo($inputDN))
->will($this->returnValue(true));
$access->expects($this->once())
->method('dn2username')
->with($this->equalTo($inputDN))
->will($this->returnValue($uid));
$access->expects($this->never())
->method('username2dn');
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
}
public function testGetByDNNotExisting() {
list($access, $config, $filesys, $image, $log, $avaMgr) =
$this->getTestInstances();
$inputDN = 'cn=gone,dc=foobar,dc=bar';
->method('stringResemblesDN')
->with($this->equalTo($inputDN))
->will($this->returnValue(true));
$access->expects($this->once())
->method('stringResemblesDN')
->with($this->equalTo($inputDN))
->will($this->returnValue(true));
->method('dn2username')
->with($this->equalTo($inputDN))
->will($this->returnValue($uid));
$access->expects($this->once())
->method('dn2username')
->with($this->equalTo($inputDN))
->will($this->returnValue(false));
$access->expects($this->never())
->method('username2dn');
$access->expects($this->once())
->method('username2dn')
->with($this->equalTo($inputDN))
->will($this->returnValue(false));
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
}
$this->assertNull($user);
}
public function testGetByExoticDN() {
list($access, $config, $filesys, $image, $log, $avaMgr) =
$this->getTestInstances();
public function testGetByUidExisting() {
list($access, $config, $filesys, $image, $log, $avaMgr) =
$this->getTestInstances();
$inputDN = 'ab=cde,f=ghei,mno=pq';
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
$dn = 'cn=foo,dc=foobar,dc=bar';
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
$access->expects($this->once())
->method('stringResemblesDN')
->with($this->equalTo($inputDN))
->will($this->returnValue(true));
$access->expects($this->never())
->method('dn2username');
$access->expects($this->once())
->method('dn2username')
->with($this->equalTo($inputDN))
->will($this->returnValue($uid));
$access->expects($this->once())
->method('username2dn')
->with($this->equalTo($uid))
->will($this->returnValue($dn));
$access->expects($this->never())
->method('username2dn');
$access->expects($this->once())
->method('stringResemblesDN')
->with($this->equalTo($uid))
->will($this->returnValue(false));
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
$manager->setLdapAccess($access);
$user = $manager->get($uid);
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
}
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
}
public function testGetByDNNotExisting() {
list($access, $config, $filesys, $image, $log, $avaMgr) =
$this->getTestInstances();
public function testGetByUidNotExisting() {
list($access, $config, $filesys, $image, $log, $avaMgr) =
$this->getTestInstances();
$inputDN = 'cn=gone,dc=foobar,dc=bar';
$dn = 'cn=foo,dc=foobar,dc=bar';
$uid = 'gone';
$access->expects($this->once())
->method('stringResemblesDN')
->with($this->equalTo($inputDN))
->will($this->returnValue(true));
$access->expects($this->never())
->method('dn2username');
$access->expects($this->once())
->method('dn2username')
->with($this->equalTo($inputDN))
->will($this->returnValue(false));
$access->expects($this->exactly(2))
->method('username2dn')
->with($this->equalTo($uid))
->will($this->returnValue(false));
$access->expects($this->once())
->method('username2dn')
->with($this->equalTo($inputDN))
->will($this->returnValue(false));
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
$manager->setLdapAccess($access);
$user = $manager->get($uid);
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
$manager->setLdapAccess($access);
$user = $manager->get($inputDN);
}
$this->assertNull($user);
}
public function testGetByUidExisting() {
list($access, $config, $filesys, $image, $log, $avaMgr) =
$this->getTestInstances();
$dn = 'cn=foo,dc=foobar,dc=bar';
$uid = '563418fc-423b-1033-8d1c-ad5f418ee02e';
$access->expects($this->never())
->method('dn2username');
$access->expects($this->once())
->method('username2dn')
->with($this->equalTo($uid))
->will($this->returnValue($dn));
$access->expects($this->once())
->method('stringResemblesDN')
->with($this->equalTo($uid))
->will($this->returnValue(false));
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
$manager->setLdapAccess($access);
$user = $manager->get($uid);
// Now we fetch the user again. If this leads to a failing test,
// runtime caching the manager is broken.
$user = $manager->get($uid);
$this->assertInstanceOf('\OCA\user_ldap\lib\user\User', $user);
}
public function testGetByUidNotExisting() {
list($access, $config, $filesys, $image, $log, $avaMgr) =
$this->getTestInstances();
$dn = 'cn=foo,dc=foobar,dc=bar';
$uid = 'gone';
$access->expects($this->never())
->method('dn2username');
$access->expects($this->exactly(1))
->method('username2dn')
->with($this->equalTo($uid))
->will($this->returnValue(false));
$manager = new Manager($config, $filesys, $log, $avaMgr, $image);
$manager->setLdapAccess($access);
$user = $manager->get($uid);
}
}
+216 -45
View File
@@ -121,7 +121,7 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
->method('fetchListOfUsers')
->will($this->returnCallback(function($filter) {
if($filter === 'roland') {
return array('dnOfRoland,dc=test');
return array(array('dn' => 'dnOfRoland,dc=test'));
}
return array();
}));
@@ -228,6 +228,28 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
$this->assertFalse($result);
}
public function testDeleteUserCancel() {
$access = $this->getAccessMock();
$backend = new UserLDAP($access);
$result = $backend->deleteUser('notme');
$this->assertFalse($result);
}
public function testDeleteUserSuccess() {
$access = $this->getAccessMock();
$backend = new UserLDAP($access);
$pref = \OC::$server->getConfig();
$pref->setUserValue('jeremy', 'user_ldap', 'isDeleted', 1);
$pref->setUserValue('jeremy', 'user_ldap', 'homePath', '/var/vhome/jdings/');
$result = $backend->deleteUser('jeremy');
$this->assertTrue($result);
$home = $backend->getHome('jeremy');
$this->assertSame($home, '/var/vhome/jdings/');
}
/**
* Prepares the Access mock for getUsers tests
* @param \OCA\user_ldap\lib\Access $access mock
@@ -378,21 +400,53 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
$this->prepareMockForUserExists($access);
$access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn) {
if($dn === 'dnOfRoland,dc=test') {
return array();
}
return false;
}));
->method('readAttribute')
->will($this->returnCallback(function($dn) {
if($dn === 'dnOfRoland,dc=test') {
return array();
}
return false;
}));
//test for existing user
$result = $backend->userExists('gunslinger');
$this->assertTrue($result);
}
/**
* @expectedException \Exception
*/
public function testUserExistsForDeleted() {
$access = $this->getAccessMock();
$backend = new UserLDAP($access);
$this->prepareMockForUserExists($access);
$access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn) {
if($dn === 'dnOfRoland,dc=test') {
return array();
}
return false;
}));
//test for deleted user
$result = $backend->userExists('formerUser');
$this->assertFalse($result);
}
public function testUserExistsForNeverExisting() {
$access = $this->getAccessMock();
$backend = new UserLDAP($access);
$this->prepareMockForUserExists($access);
$access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn) {
if($dn === 'dnOfRoland,dc=test') {
return array();
}
return false;
}));
//test for never-existing user
$result = $backend->userExists('mallory');
@@ -406,21 +460,55 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
\OC_User::useBackend($backend);
$access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn) {
if($dn === 'dnOfRoland,dc=test') {
return array();
}
return false;
}));
->method('readAttribute')
->will($this->returnCallback(function($dn) {
if($dn === 'dnOfRoland,dc=test') {
return array();
}
return false;
}));
//test for existing user
$result = \OCP\User::userExists('gunslinger');
$this->assertTrue($result);
}
/**
* @expectedException \Exception
*/
public function testUserExistsPublicAPIForDeleted() {
$access = $this->getAccessMock();
$backend = new UserLDAP($access);
$this->prepareMockForUserExists($access);
\OC_User::useBackend($backend);
$access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn) {
if($dn === 'dnOfRoland,dc=test') {
return array();
}
return false;
}));
//test for deleted user
$result = \OCP\User::userExists('formerUser');
$this->assertFalse($result);
}
public function testUserExistsPublicAPIForNeverExisting() {
$access = $this->getAccessMock();
$backend = new UserLDAP($access);
$this->prepareMockForUserExists($access);
\OC_User::useBackend($backend);
$access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn) {
if($dn === 'dnOfRoland,dc=test') {
return array();
}
return false;
}));
//test for never-existing user
$result = \OCP\User::userExists('mallory');
@@ -436,50 +524,100 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
$this->assertFalse($result);
}
public function testGetHome() {
public function testGetHomeAbsolutePath() {
$access = $this->getAccessMock();
$backend = new UserLDAP($access);
$this->prepareMockForUserExists($access);
$access->connection->expects($this->any())
->method('__get')
->will($this->returnCallback(function($name) {
if($name === 'homeFolderNamingRule') {
return 'attr:testAttribute';
}
return null;
}));
->method('__get')
->will($this->returnCallback(function($name) {
if($name === 'homeFolderNamingRule') {
return 'attr:testAttribute';
}
return null;
}));
$access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn, $attr) {
switch ($dn) {
case 'dnOfRoland,dc=test':
if($attr === 'testAttribute') {
return array('/tmp/rolandshome/');
}
return array();
break;
case 'dnOfLadyOfShadows,dc=test':
if($attr === 'testAttribute') {
return array('susannah/');
}
return array();
break;
default:
return false;
}
}));
->method('readAttribute')
->will($this->returnCallback(function($dn, $attr) {
switch ($dn) {
case 'dnOfRoland,dc=test':
if($attr === 'testAttribute') {
return array('/tmp/rolandshome/');
}
return array();
break;
default:
return false;
}
}));
//absolut path
$result = $backend->getHome('gunslinger');
$this->assertEquals('/tmp/rolandshome/', $result);
}
public function testGetHomeDatadirRelative() {
$access = $this->getAccessMock();
$backend = new UserLDAP($access);
$this->prepareMockForUserExists($access);
$access->connection->expects($this->any())
->method('__get')
->will($this->returnCallback(function($name) {
if($name === 'homeFolderNamingRule') {
return 'attr:testAttribute';
}
return null;
}));
$access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn, $attr) {
switch ($dn) {
case 'dnOfLadyOfShadows,dc=test':
if($attr === 'testAttribute') {
return array('susannah/');
}
return array();
break;
default:
return false;
}
}));
//datadir-relativ path
$result = $backend->getHome('ladyofshadows');
$datadir = \OCP\Config::getSystemValue('datadirectory',
\OC::$SERVERROOT.'/data');
\OC::$SERVERROOT.'/data');
$this->assertEquals($datadir.'/susannah/', $result);
}
/**
* @expectedException \Exception
*/
public function testGetHomeNoPath() {
$access = $this->getAccessMock();
$backend = new UserLDAP($access);
$this->prepareMockForUserExists($access);
$access->connection->expects($this->any())
->method('__get')
->will($this->returnCallback(function($name) {
if($name === 'homeFolderNamingRule') {
return 'attr:testAttribute';
}
return null;
}));
$access->expects($this->any())
->method('readAttribute')
->will($this->returnCallback(function($dn, $attr) {
switch ($dn) {
default:
return false;
}
}));
//no path at all triggers OC default behaviour
$result = $backend->getHome('newyorker');
@@ -519,6 +657,12 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
$backend = new UserLDAP($access);
$this->prepareMockForUserExists($access);
$access->connection->expects($this->any())
->method('getConnectionResource')
->will($this->returnCallback(function() {
return true;
}));
//with displayName
$result = $backend->getDisplayName('gunslinger');
$this->assertEquals('Roland Deschain', $result);
@@ -530,9 +674,36 @@ class Test_User_Ldap_Direct extends \PHPUnit_Framework_TestCase {
public function testGetDisplayNamePublicAPI() {
$access = $this->getAccessMock();
$access->expects($this->any())
->method('username2dn')
->will($this->returnCallback(function($uid) {
switch ($uid) {
case 'gunslinger':
return 'dnOfRoland,dc=test';
break;
case 'formerUser':
return 'dnOfFormerUser,dc=test';
break;
case 'newyorker':
return 'dnOfNewYorker,dc=test';
break;
case 'ladyofshadows':
return 'dnOfLadyOfShadows,dc=test';
break;
default:
return false;
}
}));
$this->prepareAccessForGetDisplayName($access);
$backend = new UserLDAP($access);
$this->prepareMockForUserExists($access);
$access->connection->expects($this->any())
->method('getConnectionResource')
->will($this->returnCallback(function() {
return true;
}));
\OC_User::useBackend($backend);
//with displayName
+94 -21
View File
@@ -26,8 +26,15 @@
namespace OCA\user_ldap;
use OCA\user_ldap\lib\BackendUtility;
use OCA\user_ldap\lib\user\OfflineUser;
use OCA\User_LDAP\lib\User\User;
class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
/**
* @var string[] $homesToKill
*/
protected $homesToKill = array();
/**
* checks whether the user is allowed to change his avatar in ownCloud
* @param string $uid the ownCloud user name
@@ -35,7 +42,7 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
*/
public function canChangeAvatar($uid) {
$user = $this->access->userManager->get($uid);
if(is_null($user)) {
if(!$user instanceof User) {
return false;
}
if($user->getAvatarImage() === false) {
@@ -57,15 +64,17 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
$uid = $this->access->escapeFilterPart($uid);
//find out dn of the user name
$attrs = array($this->access->connection->ldapUserDisplayName, 'dn',
'uid', 'samaccountname');
$filter = \OCP\Util::mb_str_replace(
'%uid', $uid, $this->access->connection->ldapLoginFilter, 'UTF-8');
$ldap_users = $this->access->fetchListOfUsers($filter, 'dn');
if(count($ldap_users) < 1) {
$users = $this->access->fetchListOfUsers($filter, $attrs);
if(count($users) < 1) {
return false;
}
$dn = $ldap_users[0];
$dn = $users[0]['dn'];
$user = $this->access->userManager->get($dn);
if(is_null($user)) {
if(!$user instanceof User) {
\OCP\Util::writeLog('user_ldap',
'LDAP Login: Could not get user object for DN ' . $dn .
'. Maybe the LDAP entry has no set display name attribute?',
@@ -79,6 +88,15 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
}
$user->markLogin();
if(isset($users[0][$this->access->connection->ldapUserDisplayName])) {
$dpn = $users[0][$this->access->connection->ldapUserDisplayName];
$user->storeDisplayName($dpn);
}
if(isset($users[0]['uid'])) {
$user->storeLDAPUserName($users[0]['uid']);
} else if(isset($users[0]['samaccountname'])) {
$user->storeLDAPUserName($users[0]['samaccountname']);
}
return $user->getUsername();
}
@@ -127,10 +145,38 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
return $ldap_users;
}
/**
* checks whether a user is still available on LDAP
* @param string|\OCA\User_LDAP\lib\user\User $user either the ownCloud user
* name or an instance of that user
* @return bool
*/
public function userExistsOnLDAP($user) {
if(is_string($user)) {
$user = $this->access->userManager->get($user);
}
if(!$user instanceof User) {
return false;
}
$dn = $user->getDN();
//check if user really still exists by reading its entry
if(!is_array($this->access->readAttribute($dn, ''))) {
$lcr = $this->access->connection->getConnectionResource();
if(is_null($lcr)) {
throw new \Exception('No LDAP Connection to server ' . $this->access->connection->ldapHost);
}
return false;
}
return true;
}
/**
* check if a user exists
* @param string $uid the username
* @return boolean
* @throws \Exception when connection could not be established
*/
public function userExists($uid) {
if($this->access->connection->isCached('userExists'.$uid)) {
@@ -138,43 +184,64 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
}
//getting dn, if false the user does not exist. If dn, he may be mapped only, requires more checking.
$user = $this->access->userManager->get($uid);
if(is_null($user)) {
\OCP\Util::writeLog('user_ldap', 'No DN found for '.$uid.' on '.
$this->access->connection->ldapHost, \OCP\Util::DEBUG);
$this->access->connection->writeToCache('userExists'.$uid, false);
return false;
}
$dn = $user->getDN();
//check if user really still exists by reading its entry
if(!is_array($this->access->readAttribute($dn, ''))) {
\OCP\Util::writeLog('user_ldap', 'LDAP says no user '.$dn.' on '.
$this->access->connection->ldapHost, \OCP\Util::DEBUG);
$this->access->connection->writeToCache('userExists'.$uid, false);
return false;
} else if($user instanceof OfflineUser) {
//express check for users marked as deleted. Returning true is
//necessary for cleanup
return true;
}
$this->access->connection->writeToCache('userExists'.$uid, true);
$user->update();
return true;
$result = $this->userExistsOnLDAP($user);
$this->access->connection->writeToCache('userExists'.$uid, $result);
if($result === true) {
$user->update();
}
return $result;
}
/**
* delete a user
* returns whether a user was deleted in LDAP
*
* @param string $uid The username of the user to delete
* @return bool
*
* Deletes a user
*/
public function deleteUser($uid) {
return false;
$pref = \OC::$server->getConfig();
$marked = $pref->getUserValue($uid, 'user_ldap', 'isDeleted', 0);
if(intval($marked) === 0) {
\OC::$server->getLogger()->notice(
'User '.$uid . ' is not marked as deleted, not cleaning up.',
array('app' => 'user_ldap'));
return false;
}
\OC::$server->getLogger()->info('Cleaning up after user ' . $uid,
array('app' => 'user_ldap'));
//Get Home Directory out of user preferences so we can return it later,
//necessary for removing directories as done by OC_User.
$home = $pref->getUserValue($uid, 'user_ldap', 'homePath', '');
$this->homesToKill[$uid] = $home;
$this->access->unmapUser($uid);
return true;
}
/**
* get the user's home directory
* @param string $uid the username
* @return boolean
* @return string|bool
*/
public function getHome($uid) {
if(isset($this->homesToKill[$uid]) && !empty($this->homesToKill[$uid])) {
//a deleted user who needs some clean up
return $this->homesToKill[$uid];
}
// user Exists check required as it is not done in user proxy!
if(!$this->userExists($uid)) {
return false;
@@ -184,6 +251,7 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
if($this->access->connection->isCached($cacheKey)) {
return $this->access->connection->getFromCache($cacheKey);
}
$pref = \OC::$server->getConfig();
if(strpos($this->access->connection->homeFolderNamingRule, 'attr:') === 0) {
$attr = substr($this->access->connection->homeFolderNamingRule, strlen('attr:'));
$homedir = $this->access->readAttribute(
@@ -203,12 +271,17 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface {
\OC::$SERVERROOT.'/data' ) . '/' . $homedir[0];
}
$this->access->connection->writeToCache($cacheKey, $homedir);
//we need it to store it in the DB as well in case a user gets
//deleted so we can clean up afterwards
$pref->setUserValue($uid, 'user_ldap', 'homePath', $homedir);
//TODO: if home directory changes, the old one needs to be removed.
return $homedir;
}
}
//false will apply default behaviour as defined and done by OC_User
$this->access->connection->writeToCache($cacheKey, false);
$pref->setUserValue($uid, 'user_ldap', 'homePath', '');
return false;
}
+13 -1
View File
@@ -24,6 +24,7 @@
namespace OCA\user_ldap;
use OCA\user_ldap\lib\ILDAPWrapper;
use OCA\User_LDAP\lib\User\User;
class User_Proxy extends lib\Proxy implements \OCP\UserInterface {
private $backends = array();
@@ -144,6 +145,17 @@ class User_Proxy extends lib\Proxy implements \OCP\UserInterface {
return $this->handleRequest($uid, 'userExists', array($uid));
}
/**
* check if a user exists on LDAP
* @param string|OCA\User_LDAP\lib\User\User $user either the ownCloud user
* name or an instance of that user
* @return boolean
*/
public function userExistsOnLDAP($user) {
$id = ($user instanceof User) ? $user->getUsername() : $user;
return $this->handleRequest($id, 'userExistsOnLDAP', array($user));
}
/**
* Check if the password is correct
* @param string $uid The username
@@ -209,7 +221,7 @@ class User_Proxy extends lib\Proxy implements \OCP\UserInterface {
* Deletes a user
*/
public function deleteUser($uid) {
return false;
return $this->handleRequest($uid, 'deleteUser', array($uid));
}
/**
-1
View File
@@ -12,5 +12,4 @@
<types>
<authentication/>
</types>
<ocsid>166062</ocsid>
</info>
+1 -1
View File
@@ -1 +1 @@
1.1.0.1
1.1.0.2

Some files were not shown because too many files have changed in this diff Show More