Compare commits

...

352 Commits

Author SHA1 Message Date
C Montero-Luque
aca9fce93f 8.1.4 2015-10-30 12:45:25 -04:00
C Montero-Luque
f7f34dbeb4 8.1.4 RC2 2015-10-28 10:22:39 -04:00
Thomas Müller
8e0cddbe01 Merge pull request #19512 from owncloud/backport-19419-stable8.1
[backport] [stable8.1] memberOf resembles a DN as well and is actively used
2015-10-28 11:09:01 +01:00
Thomas Müller
3bad2ac1e5 fixing typo 2015-10-28 09:24:19 +01:00
Arthur Schiwon
9f3ea9116e memberOf resembles a DN as well and is actively used
Conflicts:
	apps/user_ldap/tests/access.php
2015-10-28 09:21:54 +01:00
Morris Jobke
3387d05ca9 Merge pull request #19972 from owncloud/stable8.1-backport-19635
[stable8.1] allow an attribute to return more than one value
2015-10-27 14:08:26 +01:00
Thomas Müller
74871b1676 Merge pull request #20064 from owncloud/stable8.1-add-warning-for-php7
[stable8.1] Stop processing if PHP 7 is used
2015-10-26 22:04:14 +01:00
Lukas Reschke
352d695c95 Stop processing if PHP 7 is used
PHP 7 is only compatible with ownCloud 8.2.0
2015-10-26 17:39:35 +01:00
Lukas Reschke
cc9d5e44b1 Adjust unit tests 2015-10-26 16:46:34 +01:00
Lukas Reschke
643cba065a Fix style 2015-10-26 16:46:22 +01:00
Frédéric Fortier
c5b28e0795 Revert "adjust to nested group fix
This reverts commit 845485cfe, which fixes #19816 regression.
2015-10-26 16:46:09 +01:00
Thomas Müller
5062007000 Merge pull request #19998 from owncloud/backport-fix-deleted-ldap-user-sharing-stable8.1
[8.1] handle NoUserException in sharing code
2015-10-23 15:26:54 +02:00
Thomas Müller
9daf3e7410 Merge pull request #20007 from owncloud/stable8.1-backport-19957
[8.1] Expose syslog tag in the configuration
2015-10-23 15:26:10 +02:00
Thomas Müller
8f6774fc4c Merge pull request #20002 from owncloud/backport-19970-8.1
[8.1] Fix "Call to a member function getUID() on boolean" in Crypt
2015-10-23 15:25:54 +02:00
Steffen Lindner
371f4bf472 Add syslog_tag docu to sample config 2015-10-23 14:17:04 +02:00
Volker Fröhlich
49879b868b Expose syslog tag in the configuration 2015-10-23 14:16:49 +02:00
Joas Schilling
1cf61baa41 Fix "Call to a member function getUID() on boolean" in Crypt 2015-10-23 13:45:09 +02:00
Morris Jobke
e3642f2f3d handle NoUserException in sharing code
* setup LDAP users
* share from an LDAP user
* delete that LDAP user
* log in as share recipient
* before: unhandled NoUserException
* after: NoUserEception is logged and share is not shown anymore
2015-10-23 12:21:52 +02:00
Arthur Schiwon
bb973c2d76 adjust fetchList with a single requested attribute accordingly 2015-10-22 12:08:25 +02:00
Arthur Schiwon
cde21db620 adjust tests 2015-10-22 12:08:17 +02:00
Arthur Schiwon
f9be35c931 fix primary group retrieval 2015-10-22 12:08:09 +02:00
Arthur Schiwon
ba13cecb76 treat dn as any other attribute when building the search() return array 2015-10-22 12:07:52 +02:00
Arthur Schiwon
5412899665 adjust handling changed return array structure from search() and fetchList() 2015-10-22 12:03:07 +02:00
Arthur Schiwon
6ccc5a6cd3 allow an attribute to return more than one value 2015-10-22 12:02:48 +02:00
Arthur Schiwon
7ccd52db25 lowercase configured displayname attribute so isset works - all attribute names coming from ldap are lowercased for easy comparison 2015-10-22 12:01:26 +02:00
Arthur Schiwon
a05ead505d fix update quota with known value 2015-10-22 12:01:25 +02:00
Arthur Schiwon
0a9904963d stable8.1 related adjustments to #18469 backport 2015-10-22 12:01:25 +02:00
Arthur Schiwon
c1953f9676 Backport #18469 (read all relevant user attributes on login and user search, in one query)
read all relevant user attributes on login and user search, in one query. saves us some.

Conflicts:
	apps/user_ldap/user_ldap.php

adjust to nested group fix

do not throw exception when no attribute is specified
2015-10-22 12:01:25 +02:00
C Montero-Luque
5e8f0a893d 8.1.4 RC1 2015-10-21 17:09:42 -04:00
Thomas Müller
c16a847163 Merge pull request #19832 from owncloud/stable8.1-public-recognizeauthsession
[stable8.1] Allow public auth to recognize sesssion
2015-10-20 14:25:59 +02:00
Thomas Müller
c2ded337e6 Merge pull request #19830 from owncloud/fix-expiration-format-stable8.1
Use proper format when setting the expiration date
2015-10-16 15:43:38 +02:00
Vincent Petry
df4348674b Allow public auth to recognize sesssion
When a public link password has been input, its auth is stored in the
session.
This fix makes it possible to recognize the session when using public
webdav from the files UI.
2015-10-16 13:50:39 +02:00
Thomas Müller
f3392f9e59 Use proper format when setting the expiration date 2015-10-16 13:47:36 +02:00
Thomas Müller
923e6ca1bf Merge pull request #19809 from owncloud/show-serverside-share-link-expiration-stable8.1
Update expiration date on link sharing
2015-10-16 13:08:14 +02:00
Roeland Douma
64fb704c4e Merge pull request #19638 from owncloud/stable8.1_backport_sharingcheckmiddleware_fixes
Stable8.1 backport sharingcheckmiddleware fixes
2015-10-16 08:51:37 +02:00
Thomas Müller
4ba4fb5ffb Merge pull request #19784 from owncloud/stable8.1_backport_19727
[Stable8.1] Return path instead of itemsource
2015-10-15 19:58:42 +02:00
Thomas Müller
e1d2ab83cc Set expiration date on password change 2015-10-15 17:16:18 +02:00
Thomas Müller
6fd2f18b85 Only show expiration date in the web ui if it has been set 2015-10-15 16:58:51 +02:00
Thomas Müller
a2810f6207 Update expiration date on link sharing 2015-10-15 15:23:50 +02:00
Lukas Reschke
4d92aa551d Merge pull request #19786 from owncloud/backport-stable8.1-setup-transport
[stable8.1] Setup sendmail transport
2015-10-15 14:00:24 +02:00
Lukas Reschke
5ed1744a6f Setup sendmail transport
Replaces https://github.com/owncloud/core/pull/19047 and fixes https://github.com/owncloud/enterprise/issues/854  and https://github.com/owncloud/core/issues/19110
2015-10-14 16:29:55 +02:00
Roeland Jago Douma
371061ac6d Return path instead of itemsource
Fixes #19678

Errors should contain paths and not internal ids
2015-10-14 15:56:03 +02:00
Morris Jobke
85c8af596d Merge pull request #19740 from owncloud/stable8.1-do-not-leak-exception-data
[stable8.1] Do not print exception message
2015-10-13 18:19:18 +02:00
Morris Jobke
2f2d94f801 Merge pull request #19287 from RealRancor/restruct_config_sample
Restructure config.sample.php of stable8.1
2015-10-13 16:23:42 +02:00
Lukas Reschke
9ece45ca28 Do not print exception message
In case of an error the error message often contains sensitive data such as the full path which potentially leads to a full path disclosure.

Thus the error message should not directly get displayed to the user and instead be logged.
2015-10-13 14:31:47 +02:00
Morris Jobke
e9a17fbee5 Merge pull request #19715 from owncloud/stable8.1-repair-donotrepairfoldermimetypes
[stable8.1] Do not update mime types for folders with extension
2015-10-13 09:54:00 +02:00
Vincent Petry
37747016f2 Do not update mime types for folders with extension
Some folders might have an extension like "test.conf".
This fix prevents to overwrite the folder's mime type with another mime
type while running the mimetype repair step.
2015-10-12 17:28:32 +02:00
Thomas Müller
07f903a1e3 Merge pull request #19466 from owncloud/tarstreamer-stable8.1
[stable8.1] backport Tarstreamer
2015-10-12 11:58:03 +02:00
Morris Jobke
4c13a648bb Merge pull request #18855 from owncloud/memcached-fix-stable8.1
[stable8.1] Fallback to complete Memcached flush if getAllKeys fails
2015-10-09 13:19:35 +02:00
Morris Jobke
c3ec3b0fe0 Merge pull request #19658 from owncloud/stable8.1-backport-19546
Stable8.1 backport 19546
2015-10-09 13:16:33 +02:00
Thomas Müller
045c491be8 Updating 3rdparty dependency 2015-10-09 13:03:09 +02:00
Robin Appelman
56fcef3d56 fix internal path when searching in storage root
(cherry picked from commit c2d76d2)
2015-10-09 08:52:42 +02:00
Robin Appelman
db909277f1 Add unit test for searching in storage root
(cherry picked from commit e28a2ff)
2015-10-09 08:52:42 +02:00
Olivier Paroz
30c149deeb The minimum size for internalRootLength is 1
(cherry picked from commit 3173ed2)
2015-10-09 08:52:42 +02:00
Thomas Müller
87f27d0ba1 Merge pull request #19652 from owncloud/backport-disable-appstore-for-ee
[stable8.1] Disable app store for EE by default
2015-10-09 08:48:43 +02:00
Thomas Müller
48ec118af6 Merge pull request #19604 from owncloud/stable8.1-backport-19574
[stable8.1] Clear the shares after the test like storages and files
2015-10-09 08:48:27 +02:00
Lukas Reschke
b21912aa41 Disable app store for EE by default
This disables the app store for EE versions by default to address some problems caused by the wrong assumption that "Official" means supported by ownCloud Inc.

Administrators can still enable the app store by setting `appstoreenabled` to true in the config file.
2015-10-08 15:12:41 +02:00
Joas Schilling
f83f80ac71 Only use zip64 when we have 64 bit php 2015-10-08 10:32:24 +02:00
Roeland Jago Douma
c7d9936d67 sharingcheckmiddleware now handles externalshares as well
Added new annotations for the externalsharescontroller class
* @NoOutgoingFederatedSharingRequired
* @NoIncomingFederatedSharingRequired

By default both are required for all functions in the
externalSharesController.

A proper exception is thrown and then a 405 is returned instead of the
default error page. Since it is only an API endpoint this makes more
sense.

Unit tests added and updated
2015-10-08 08:20:08 +02:00
Roeland Jago Douma
ffb8819125 Split files_sharing middelware
Since for external shares there is no need for link shares to be enabled
we should check which controller is actually being called.

This makes sure that in all cases we verify that the files_sharing app
is enabled. But only for the share controller (public shares) we check
if the API is enabled and if links are enabled.

TODO: add checks for federated sharing as well
2015-10-08 08:11:15 +02:00
Lukas Reschke
b5f8f94341 Only intercept exceptions of type "NotFoundException" instead of any Exception
The sharing backend may throw another exception for example when the activity app encounters a problem. Previously this just triggered a 404 error page and the exception got not logged at all. With this change such exceptions get not intercepted and regularly handled as exceptions so that we have meaningful log data. Also the user will be shown a window informing him that an error happened.

Helps to debug cases such as https://github.com/owncloud/core/issues/19465
2015-10-08 08:11:06 +02:00
Roeland Jago Douma
a77f679779 Respect disabled sharing API settings
If the sharing API setting is disabled that sharing check middle ware
should block the request. Thus making link shares unavailable.
Fixes #18970

* Unit test added
* Unit tests updated
2015-10-08 08:09:55 +02:00
Morris Jobke
c2ca7fc91d Clear the shares after the test like storages and files
* adjusted to stable8.1 backport of #19574
2015-10-06 14:12:15 +02:00
Thomas Müller
29a4d1b512 Merge pull request #19598 from owncloud/stable8.1_backport_19553
[stable8.1] Backport of #19553: show MM-DD-YYYY as expiration date consistently
2015-10-06 14:07:04 +02:00
Roeland Jago Douma
c589244b40 Backport of #19553
Show expiration date always as MM-DD-YYYY
2015-10-06 07:50:36 +02:00
Thomas Müller
4a1246fa29 Merge pull request #19485 from owncloud/stable8.1-backport-19460
[8.1] backport 19460 | Fix postScanFile event and make it available to utils scanner
2015-10-01 12:01:49 +02:00
Olivier Paroz
dc128295c6 Make postScanFile and postScanFolder available to OC\Files\Utils\Scanner
(cherry picked from commit cc64c09)
2015-09-30 18:19:44 +02:00
Olivier Paroz
788831f139 Always send a postScanFile event when done scanning a file
postScanFile is important when scanning external storage as it indicates when the file is ready to be used
(cherry picked from commit 9ea05c8)
2015-09-30 18:19:11 +02:00
Thomas Müller
9a81eca7ba Merge pull request #19450 from owncloud/stable8.1-backport-19440-19426
Stable8.1 backport 19440 19426
2015-09-30 16:11:06 +02:00
Thomas Müller
b9e0e6a573 Merge pull request #19475 from owncloud/thumbnail-temp-clean-81
[8.1] Clean temp files used for thumbnail generation
2015-09-30 16:10:27 +02:00
Robin Appelman
32c6fdf098 Clean temp files used for thumbnail generation 2015-09-30 15:15:08 +02:00
Thomas Müller
643b6c11c3 Adding TarStreamer and updating ZipStreamer 2015-09-30 10:32:57 +02:00
Victor Dubiniuk
9e5f538897 Uniform behavour for tar and zip 2015-09-30 10:25:33 +02:00
Victor Dubiniuk
ab68469e61 More corrections 2015-09-30 10:25:33 +02:00
Victor Dubiniuk
b70e7f4d0a Add namespace. Fix broken zip 2015-09-30 10:25:33 +02:00
Victor Dubiniuk
623ce418ce Add PHpdoc 2015-09-30 10:25:33 +02:00
Victor Dubiniuk
6c2f95ff9f Introduce streamer 2015-09-30 10:25:29 +02:00
Morris Jobke
2764aa1b99 Merge pull request #18572 from owncloud/stable8.1-backport-18553
[stable8.1] Save detected l10n of browser on login
2015-09-29 18:23:24 +02:00
Lukas Reschke
1a167dd5ac Add blob: scheme to default CSP policy
Fixes https://github.com/owncloud/core/issues/19438
(cherry picked from commit e735a99)
2015-09-29 17:11:39 +02:00
Olivier Paroz
f934a6fae6 Fix CSP for images for legacy apps
Fixes #19425
(cherry picked from commit c4bac16)
2015-09-29 17:00:54 +02:00
Morris Jobke
50a8ba6062 Merge pull request #19446 from owncloud/stable8.1-backport-19441
[stable8.1][upgrade] switch to debug logging on upgrade
2015-09-29 16:48:09 +02:00
Morris Jobke
427f7d5a5c Merge pull request #19439 from owncloud/stable8.1-share-disablepluginwhennocoreshare
[stable8.1] Do not register JS share plugin if core sharing API is disabled
2015-09-29 16:30:59 +02:00
Morris Jobke
655eb4ce40 [upgrade] switch to debug logging on upgrade
* resets afterwards
* adds output about the previous log level
2015-09-29 16:14:45 +02:00
Vincent Petry
9bd37d2acd Do not register JS share plugin if core sharing API is disabled 2015-09-29 14:24:19 +02:00
Morris Jobke
1d2803ec9a Save detected l10n of browser on login
* fixes owncloud/activity#373
2015-09-28 14:00:33 +02:00
Thomas Müller
d6994b2da6 Merge pull request #19216 from owncloud/stable8.1-discardexpirationdatefornonlinkshares
[stable8.1] Discard expiration date from result for non-link shares
2015-09-24 21:07:15 +02:00
Thomas Müller
c4667d5213 Merge pull request #18957 from owncloud/stable8.1-backport-17791
[stable8.1] Add custom CSP for Win 10 compatibility
2015-09-24 21:06:49 +02:00
RealRancor
310762a118 Restructure config.sample.php of stable8.1 2015-09-23 09:57:34 +02:00
Vincent Petry
7b5218ed30 Merge pull request #19149 from owncloud/issue-19147-backport-update-break
Issue 19147 backport update break
2015-09-22 12:34:55 +02:00
Björn Schießle
00447f32f6 Merge pull request #18747 from owncloud/fix_password_reset_8.1
[stable8.1] use login name for password reset
2015-09-22 09:52:17 +02:00
Thomas Müller
876266f0ce Merge pull request #19051 from owncloud/backport-shibboleth-fix-stable8.1-2
Repeated calls to loginWithApache() should not not try to set user in…
2015-09-21 16:09:47 +02:00
blizzz
dc1755ab52 Merge pull request #18123 from GreenArchon/backport-17759-stable8.1
[stable8.1]Properly nest groups when using memberOf to detect group membership, fixes #17759
2015-09-21 15:51:06 +02:00
Vincent Petry
c48a61a975 Discard expiration date from result for non-link shares 2015-09-21 11:42:46 +02:00
Björn Schießle
42c454e8d0 Merge pull request #19011 from owncloud/fix_18926_8.1
[stable8.1]  check for the right user if we can change his password
2015-09-21 10:05:49 +02:00
Vincent Petry
aaa1249075 Improved update version detection logic 2015-09-18 09:07:18 +02:00
Vincent Petry
380971c76d Simplify comparison algo 2015-09-18 09:07:18 +02:00
Vincent Petry
1efcbca9dc Throw exception on downgrade attempt 2015-09-18 09:07:18 +02:00
Vincent Petry
1f7b231b9a Restrict upgrades to explicit allowed version
version.php now contains the previous ownCloud version from which
upgrades are allowed. Any other upgrades will show a message that the
upgrade/downgrade is not supported.

Conflicts:
	version.php
2015-09-18 09:07:16 +02:00
Thomas Müller
0b279f9a13 Merge pull request #19075 from owncloud/check-maintenance-before-everything-else
Check for maintenance mode first so we send the 503 instead of login …
2015-09-16 10:24:22 +02:00
Joas Schilling
aa12a9983a Check for maintenance mode first so we send the 503 instead of login verification 2015-09-16 09:27:38 +02:00
Thomas Müller
bf149b1529 Repeated calls to loginWithApache() should not not try to set user information in the session again 2015-09-15 16:40:12 +02:00
Joas Schilling
c736f5dcc4 Merge pull request #18816 from owncloud/move-background-job-registration-to-install-update-8.1
Move background job registration to install update 8.1
2015-09-15 10:36:11 +02:00
Morris Jobke
63e07b0525 Merge pull request #18703 from owncloud/request-fix-stable8.1
[stable8.1] Decode request content only on getContent
2015-09-15 09:17:13 +02:00
Individual IT Services
690a4597e3 Merge pull request #19013 from owncloud/stable8.1-backport-19006
[stable8.1] allow ".." in folder names
2015-09-14 16:22:11 +05:45
Individual IT Services
709f289beb allow ".." in folder names
backport of #19006
fix for #18987
2015-09-14 16:04:56 +05:45
Bjoern Schiessle
fd259db588 check for the right user if we can change his password 2015-09-14 11:50:46 +02:00
Joas Schilling
5500cb9b4e Move registration of LDAP background jobs to the install and update 2015-09-14 11:14:54 +02:00
Joas Schilling
15a054f127 Move registration of background job to install/update 2015-09-14 11:08:40 +02:00
C Montero-Luque
015323c1cb 8.1.3 2015-09-10 10:28:00 -04:00
Lukas Reschke
4d1b898bc5 Add custom CSP for Win 10 compatibility
The default content-security-policy of ownCloud forbids inline
JavaScript for security reasons. IE starting on Windows 10 will
however also obey the CSP which will break the event source fallback.
As a workaround thus we set a custom policy which allows the execution
of inline JavaScript.

This fixes https://github.com/owncloud/core/issues/14286
2015-09-10 15:01:38 +02:00
Morris Jobke
8d800e9635 Merge pull request #18928 from owncloud/stable8.1-backport-18832
[stable8.1] Avoid re-propagation of shares during one propagation run
2015-09-09 23:21:08 +02:00
Morris Jobke
bef8dd4171 Merge pull request #18904 from owncloud/missing-context-on-update-file-target_8.1
[stable8.1] Use context function call instead of static
2015-09-09 15:15:56 +02:00
Morris Jobke
2f851201db Merge pull request #18903 from owncloud/fix_sharing_add_to_group_8.1
[stable8.1] fix addToGroup hook
2015-09-09 15:15:48 +02:00
Morris Jobke
cbcbbd9423 Avoid re-propagation of shares during one propagation run
* fix was proposed by @nickvergessen
2015-09-09 15:10:54 +02:00
Morris Jobke
5d433da1ae Merge pull request #18814 from owncloud/shared-mount-delay-setup-8.1
[8.1] Delay setting up the filesystem for a share owner untill the share is used
2015-09-09 15:07:52 +02:00
Joas Schilling
349c650535 Use context function call instead of static 2015-09-08 17:13:39 +02:00
Bjoern Schiessle
3ceee5408a intproduce pre_addToGroup hook. we need to calculate the possible unique
targets before the user was added to the group otherwise we will always detect
a name collision
2015-09-08 17:08:52 +02:00
Bjoern Schiessle
3b30dd4394 use the correct user if we update the share table 2015-09-08 17:08:39 +02:00
Lukas Reschke
f3b8b90191 Merge pull request #18844 from owncloud/app-upgrade-routenotfound-stable8.1
[stable8.1] Always add to $loadedApps
2015-09-08 13:40:54 +02:00
Robin McCorkell
76399dc6b0 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 18:16:15 +01:00
Robin McCorkell
a2d456c195 Always add to $loadedApps 2015-09-05 11:43:00 +01:00
Robin Appelman
9c289b71c6 setup owner when getting users for share 2015-09-03 15:12:46 +02:00
Robin Appelman
4676f39855 Delay setting up the filesystem for a share owner untill the share is used 2015-09-03 15:12:38 +02:00
C Montero-Luque
7b510f2510 8.1.2 2015-09-02 10:54:56 +02:00
Bjoern Schiessle
b823bbbc28 use login name for password reset 2015-09-01 18:01:59 +02:00
Robin McCorkell
0dfa839582 Decode request content only on getContent 2015-08-31 14:05:51 +01:00
C Montero-Luque
01fc0b53f6 8.1.2 RC1 2015-08-30 10:36:12 +02:00
Morris Jobke
04bed337ee Merge pull request #18612 from owncloud/stable8.1-newer-certs-2
[stable8.1] Use certificates that expire in 10 years
2015-08-28 18:44:10 +02:00
Lukas Reschke
0e4bdfbef3 Use certificates that expire in 10 years
🙊 🙊 🙊
2015-08-27 22:25:40 +02:00
Morris Jobke
3233b9c4ee Merge pull request #18583 from owncloud/backport-of-18582
[stable8.1] Remove last occurence of `forcessl`
2015-08-26 22:08:49 +02:00
Lukas Reschke
1850476916 Remove last occurence of forcessl
This shoudl have been adjusted as well, now it's consistent with `setMagicInCookie`. While it does not have a security impact directly some automated scanners reported this all the time.
2015-08-26 15:09:00 +02:00
Morris Jobke
bcc79b0e40 Merge pull request #18579 from owncloud/backport-18279-stable8.1
[backport] also don't count group members when more than 1 ldap configs are active
2015-08-26 14:29:29 +02:00
Arthur Schiwon
1d8b5ac909 also don't count group members when more than 1 ldap configs are active 2015-08-26 11:58:36 +02:00
Joas Schilling
540ad35f3b Merge pull request #18544 from owncloud/stable8.1-backport-18439
[stable8.1] [app management] fix dependency check on install
2015-08-26 11:00:39 +02:00
Morris Jobke
d2c81fd3c5 Merge pull request #18555 from owncloud/fix-gs-share-stable8.1
[stable8.1] Simply hide sharing buttons for IE8 - fixes #18011
2015-08-25 21:59:32 +02:00
Lukas Reschke
c3468c7b29 Merge pull request #18559 from owncloud/ext-objectstore-stable8.1
[stable8.1] Prevent objectstore being set from client side
2015-08-25 20:56:38 +02:00
Robin McCorkell
a1706f61aa Prevent objectstore being set from client side 2015-08-25 16:21:09 +01:00
Thomas Müller
7d436579cb don't load gs-share 2015-08-25 16:50:17 +02:00
Thomas Müller
b2adf17433 Simply hide sharing buttons for IE8 - fixes #18011 2015-08-25 16:09:28 +02:00
Morris Jobke
76306dd5a1 [app management] fix dependency check on install 2015-08-25 14:19:54 +02:00
Morris Jobke
727cb3b2a3 Merge pull request #18446 from owncloud/ext-setuservars-string-stable8.1
[stable8.1] setUserVars() should only attempt substitution with strings
2015-08-25 09:00:22 +02:00
Morris Jobke
227e338542 Merge pull request #18487 from owncloud/add-cors-header-to-allow-client-based-check
[stable8.1] Add CORS header to status.php to allow client-based check…
2015-08-24 09:30:02 +02:00
Lukas Reschke
6dffa0fc95 [stable8.1] Add CORS header to status.php to allow client-based check in the future 2015-08-22 14:48:28 +02:00
Robin McCorkell
bf1096602b Retain compatibility with updated storage configurations
String booleans are still accepted
2015-08-20 12:28:59 +01:00
Robin McCorkell
d6bc77599e setUserVars() should only attempt substitution with strings 2015-08-20 02:21:45 +01:00
Morris Jobke
21c9dd284b Merge pull request #18431 from owncloud/add-warning-ca-bundle-stable8.1
[stable8.1] Add warning for not existing CA bundle when updating
2015-08-19 19:53:44 +02:00
Morris Jobke
174c4e3113 Merge pull request #18353 from owncloud/backport-block-autocomplete
[stable8.1] Add option to disable autocomplete in share dialog
2015-08-19 16:16:11 +02:00
Lukas Reschke
373d1b67b2 Add warning for not existing CA bundle when updating
For newer releases we shall use an integrity check. But that's a good alternative for now.
2015-08-19 15:13:24 +02:00
Thomas Müller
31eb4f06f7 Merge pull request #18397 from owncloud/smb-1.0.4-81
[8.1] Update Icewind/SMB to 1.0.4
2015-08-19 09:16:06 +02:00
Robin Appelman
b9e5809869 update icewind/smb to 1.0.4 2015-08-18 17:36:55 +02:00
Robin Appelman
8c145541f6 update icewind/smb to 1.0.3 2015-08-18 17:36:51 +02:00
Robin McCorkell
880ba38e2c Merge pull request #18367 from owncloud/config-php-tyops-8-1
typo fixes
2015-08-17 23:42:06 +01:00
Carla Schroder
47ec44da3b typo fixes 2015-08-17 10:49:28 -07:00
Morris Jobke
60cd118371 Add option to disable autocomplete in share dialog 2015-08-17 15:45:06 +02:00
Morris Jobke
2c81ac1cf7 Merge pull request #18182 from owncloud/backport-18159-stable8.1
Backport 18159 stable8.1
2015-08-16 14:39:25 +02:00
Thomas Müller
3ea3fc7b62 Merge pull request #18274 from owncloud/issue-18261-sharing-capabilities-use-wrong-default-8.1
[8.1] Issue 18261 sharing capabilities use wrong default 8.1
2015-08-14 12:24:51 +02:00
Morris Jobke
dc012be598 Merge pull request #18277 from owncloud/stable8.1-17852
[stable8.1] add test for factories
2015-08-14 00:36:56 +02:00
Jan-Christoph Borchardt
94f2b2ba8c Merge pull request #18284 from owncloud/stable8.1-backport-17785
[stable8.1] fix mobile scrolling, lower sidebar sensitivity, fix #11193
2015-08-13 23:38:46 +02:00
Jan-Christoph Borchardt
116ec56e8c Merge pull request #18288 from owncloud/stable8.1-backport-18231
[stable8.1] Show strage full warning for shared storages temporary
2015-08-13 23:38:20 +02:00
Morris Jobke
444d5d27de Show strage full warning for shared storages temporary
* removed the setDefault call because then it will always be
  reshown
  * was added with ba475d4862
* fixes #18208
2015-08-13 17:12:41 +02:00
Jan-Christoph Borchardt
dcda1e1e61 fix mobile scrolling, lower sidebar sensitivity, fix #11193 2015-08-13 15:43:49 +02:00
Morris Jobke
6bcf2b9e77 Merge pull request #18257 from owncloud/stable8.1-backport-17680
[stable8.1] handle rmdir on files for ftp storages
2015-08-13 15:31:51 +02:00
Thomas Müller
dbc03b68ae Merge pull request #18237 from owncloud/backport-scanfilesignature
[stable8.1] Backport scanfilesignature
2015-08-13 14:54:25 +02:00
Jan-Christoph Borchardt
94eb5f645a Merge pull request #18266 from owncloud/stable8.1-filelist-emptycontentduringmask
[stable8.1] Make sure to hide empty content message when mask is shown
2015-08-13 14:48:37 +02:00
Bernhard Posselt
c31e2464c8 add test for factories
use ref for factory test

Ensure we construct SimpleContainer

Use single instance of DIContainer in routing tests
2015-08-13 13:27:32 +01:00
Joas Schilling
9e42d3ed43 Fix config map provider for tests 2015-08-13 13:09:08 +02:00
Joas Schilling
d3266f5459 Fix default values of sharing capabilities
The problem is the UI used a different default than the capabilities.
So when you never touched the config, the setting in admins said "disabled"
while the capabilities said "enabled".
2015-08-13 13:01:32 +02:00
Vincent Petry
dcd9154f04 Make sure to hide empty content message when mask is shown 2015-08-13 11:55:15 +02:00
Joas Schilling
c8e1359c9d Add a basic unit test which notifies us about incompatible extending 2015-08-13 11:41:13 +02:00
Robin Appelman
6c8689072c handle rmdir on files for ftp storages 2015-08-13 10:54:41 +02:00
Joas Schilling
e272ec0c3e Fix duplicated line in doc block 2015-08-12 15:51:29 +02:00
Vincent Petry
327f96f29b Fix scanFile signature to avoid boring warning 2015-08-12 15:40:45 +02:00
Vincent Petry
1add97feae Merge pull request #17753 from oparoz/fix-previews-for-public-uploads
[stable8.1] Fix preview of old file on public upload conflicts
2015-08-12 10:58:40 +02:00
Thomas Müller
e9a1a8cf75 Merge pull request #18172 from owncloud/fix-language-of-files-activities-in-emails-8.1
[8.1] Correctly make use of the languageCode argument in the files activity extension
2015-08-12 10:23:49 +02:00
Thomas Müller
69970f83f9 Merge pull request #18139 from owncloud/stable8.1-share-permwrongvar
[stable8.1] Fix removal of share permissions when share disabled for user
2015-08-12 10:23:35 +02:00
Thomas Müller
82bffa0df2 Merge pull request #18108 from owncloud/dav-upload-updater-81
[8.1] go trough the updater when uploading over webdav
2015-08-12 10:21:09 +02:00
Thomas Müller
7c58985ca1 Merge pull request #18104 from owncloud/share-group-conflict-81
[8.1] Re-use the share entry we have for the shared storage instead of searching for it every time
2015-08-12 10:20:44 +02:00
Thomas Müller
18ec257ab2 Merge pull request #18064 from owncloud/import_root_certificates_8.1
[stable8.1] disable "ssl root certificate" settings if user can't mount external storages
2015-08-12 10:20:27 +02:00
Thomas Müller
04b409fb09 Merge pull request #17991 from owncloud/backport-correct-regex
[stable8.1] Correct regex
2015-08-12 10:20:01 +02:00
Thomas Müller
571b7f0c2c Merge pull request #17972 from owncloud/stable81-17969
[stable8.1] [admin settings] only retrieve log file size if file exists
2015-08-12 10:19:52 +02:00
Thomas Müller
e94d8bbf24 Merge pull request #17957 from owncloud/stable8.1-backport-17489
[stable8.1] Fix parsing of sharetime as string
2015-08-12 10:19:31 +02:00
Thomas Müller
ac04692eac Merge pull request #17951 from owncloud/backport-17464-stable8.1
[stable8.1] Backport of #17464, fix uncaught exception on not permitted file type…
2015-08-12 10:19:16 +02:00
Thomas Müller
f7cb36a706 Merge pull request #17947 from owncloud/fix_move_files_8.1
[stable8.1] make sure that hooks are emitted properly on file move operation
2015-08-12 10:19:01 +02:00
michag86
c9132190ab Update installer.php 2015-08-10 18:38:22 +02:00
michag86
677bb62edf Check if archive contains a directory named like appid 2015-08-10 18:38:11 +02:00
Joas Schilling
087acc550c Correctly make use of the languageCode argument in the files activity extension 2015-08-10 14:59:51 +02:00
Frank Karlitschek
ca66a705ec 8.1.1 2015-08-07 20:17:23 -04:00
Vincent Petry
89ccdcf134 Fix removal of share permissions when share disabled for user 2015-08-07 19:05:55 +02:00
Frédéric Fortier
1436baaff7 fix more review comments for #18042 / #17759 2015-08-07 09:14:55 -04:00
Frédéric Fortier
30b3b075ba Take review comments into consideration for pr #18042 / issue #17759 2015-08-07 09:14:40 -04:00
Frédéric Fortier
6e1e70439b Properly nest groups when using memberOf to detect group membership, fixes #17759 2015-08-07 09:14:28 -04:00
Robin Appelman
e0a330315d go trough the updater when uploading over webdav 2015-08-06 16:58:09 +02:00
Robin Appelman
b91f002baf just pass the share instead of searching for it 2015-08-06 14:30:36 +02:00
Robin Appelman
cb791c7fe2 add unit tests for share target conflict with group shares 2015-08-06 14:30:25 +02:00
Thomas Müller
1a1e19f929 Merge pull request #18054 from owncloud/shared-propagate-check-recipient-stable81
[8.1] fix infinite loops with propagating etags on reshares
2015-08-05 12:01:36 +02:00
Bjoern Schiessle
6534202573 also block certificate management in the back-end if external storages are disabled for the user 2015-08-05 10:40:49 +02:00
Bjoern Schiessle
a430e75425 only add the possibility to import ssl root certificates to the personal
setting if the user can mount external storages
2015-08-05 10:40:40 +02:00
Robin Appelman
78a46dcac1 fix infinite loops with propagating etags on reshares 2015-08-04 14:05:41 +02:00
C Montero-Luque
8c9b8f4fe9 8.1.1 RC1 2015-08-03 07:16:38 -04:00
Thomas Müller
a0ab86bb91 Merge pull request #18013 from owncloud/enc_always_update_file_cache_8.1
[stable8.1] let the encryption storage wrapper always update the file cache
2015-08-03 12:54:01 +02:00
Björn Schießle
ab16bea5c7 Merge pull request #17990 from owncloud/enc_only_update_file_cache_once_8.1
[stable8.1] only update database on the first run
2015-08-03 11:34:24 +02:00
Bjoern Schiessle
2e8f47dfb6 always update file cache, the cache can handle partial data correctly if the file doesn't already exists in the file cache 2015-07-31 17:34:01 +02:00
Bjoern Schiessle
a79a15e6c5 only update database on the first run (first run = we have a version number from the old encryption app) 2015-07-31 10:50:56 +02:00
Roeland Douma
cf4f43363c Merge pull request #18003 from owncloud/backport-17805-stable8.1
[stable8.1][avatar] add error handlers for avatar setup
2015-07-31 10:46:18 +02:00
Morris Jobke
ef2eeae852 [avatar] add error handlers for avatar setup
add colon to translated string

use placeholder in t()

Adding a size limitation for avatar upload

Unit test for file size

Fix typo & display server side error message
2015-07-31 07:35:01 +02:00
Lukas Reschke
f7360795f8 Add more unit tests 2015-07-30 16:10:28 +02:00
Lukas Reschke
c61b23561b Correct regular expressions
Previously the regex was only matching on single characters. Meaning that file names such as "👍.txt" where possible while "👍" alone never was. This check apparently never worked as expected.
2015-07-30 16:10:21 +02:00
Morris Jobke
4409aed581 [admin settings] only retrieve log file size if file exists
* fixes #17467
2015-07-29 22:00:21 +01:00
Morris Jobke
a9524e250a Merge pull request #17949 from owncloud/stable8.1-settings-users-apprenderedforsearchbox
[stable8.1] Trigger "apprendered" event in users page
2015-07-29 15:03:58 +02:00
Morris Jobke
42ca905d62 tests for _parseTime with hex and empty strings 2015-07-29 14:55:30 +02:00
Morris Jobke
4d6dcec751 Fix parsing of sharetime as string
In some cases the ajax/share.php will return the share time as string.
If this is the case it would get parsed completely wrong and cause the
share dropdown to not work anymore. This change will properly cast the
string to an interger and also fallback if this is not possible.
2015-07-29 14:55:21 +02:00
Arthur Schiwon
9bfbed5e0d Backport of #17464, fix uncaught exception on not permitted file types when setting avatar
refactor integration tests to make it easier to add new ones

add integration tests for avatar update

fix uncaught exception on not permitted file types when setting avatar, fixes #17232

fix test after rebasing
2015-07-29 12:45:02 +02:00
Vincent Petry
c411dcd30a Trigger "apprendered" event in users page
This will properly update the controls bar width and display the search
box initially.
2015-07-29 11:35:23 +02:00
Bjoern Schiessle
2c83115a3d make sure that we emit the hooks if a file gets moved from a subfolder to the root folder with the nodes API 2015-07-29 11:07:47 +02:00
Thomas Müller
73da1ca71d Merge pull request #17935 from owncloud/detect-old-openssl-versions-stable81
[stable8.1] Detect old NSS and OpenSSL versions
2015-07-29 09:22:23 +02:00
Thomas Müller
7f5f7711ad Merge pull request #17929 from owncloud/stable8.1-smb-storageiddoubleslash
[stable8.1] Double slash for SMB storage id for compatibility
2015-07-28 23:50:31 +02:00
Vincent Petry
891a4d2ccd Merge pull request #17928 from owncloud/fix_17925_8.1
[stable8.1] set logger in constructor
2015-07-28 18:30:14 +02:00
Lukas Reschke
e0b5bea50f Add unit tests 2015-07-28 16:35:55 +02:00
Lukas Reschke
3133949418 Detect old NSS and OpenSSL versions
This will detect old NSS and OpenSSL versions and show appropriate errors in the admin interface.

Fixes https://github.com/owncloud/core/issues/17901
2015-07-28 16:02:06 +02:00
Vincent Petry
dcd5666601 Double slash for SMB storage id for compatibility 2015-07-28 14:30:56 +02:00
Bjoern Schiessle
fc467da7d3 set logger in constructor 2015-07-28 14:21:38 +02:00
Vincent Petry
a949f6c576 Merge pull request #17911 from owncloud/fix-enc-wrapper-without-encryption-stable8.1
[stable8.1] Fix enc wrapper without encryption stable8.1
2015-07-27 19:29:52 +02:00
Thomas Müller
e8cbfd16a2 Merge pull request #17903 from owncloud/fix_17898_8.1
[backport 8.1] get header size before we open the file to avoid locking exception
2015-07-27 17:12:12 +02:00
Bjoern Schiessle
e25a116aa6 adujust version to the stable8.1 branch 2015-07-27 16:48:58 +02:00
Bjoern Schiessle
036ba93ded add condition to update query 2015-07-27 16:09:57 +02:00
Joas Schilling
b8561bda9c Add an update script to reset the value
In case encryption was not enabled, we accidently set encrypted = 1 for
files inside mount points, since 8.1.0. This breaks opening the files in
8.1.1 because we fixed the code that checks if a file is encrypted.
In order to fix the file, we need to reset the flag of the file. However,
the flag might be set because the file is in fact encrypted because it was
uploaded at a time where encryption was enabled.

So we can only do this when:
- Current version of ownCloud before the update is 8.1.0 or 8.2.0.(0-2)
- Encryption is disabled
- files_encryption is not known in the app config

If the first two are not the case, we are save. However, if files_encryption
values exist in the config, we might have a false negative here.
Now if there is no file with unencrypted size greater 0, that means there are
no files that are still encrypted with "files_encryption" encryption. So we
can also safely reset the flag here.

If this is not the case, we go with "better save then sorry" and don't change
the flag but write a message to the ownCloud log file.
2015-07-27 16:09:45 +02:00
Joas Schilling
c4ddf08b79 Add a unit test for the disabled encryption case 2015-07-27 16:08:19 +02:00
Joas Schilling
ef65e519ae Only set is encrypted when encryption is enabled 2015-07-27 16:08:11 +02:00
Bjoern Schiessle
4b41021fc3 get header size before we open the file to avoid locking exception 2015-07-27 14:31:06 +02:00
Thomas Müller
0ef06afc75 Merge pull request #17896 from owncloud/backport-scan-check-path
[stable8.1] check if the user is trying to scan a valid path
2015-07-27 13:40:11 +02:00
Thomas Müller
6dedef7967 Merge pull request #17883 from owncloud/backport-17882
[stable8.1] Allow classes in <h2> tags
2015-07-27 11:56:32 +02:00
Thomas Müller
1c7d737124 Merge pull request #17842 from rullzer/backport_17818
[Stable8.1] assign error message to correct object (backport #17818)
2015-07-27 11:28:15 +02:00
Lukas Reschke
4ee61f3c7a Add unit tests 2015-07-27 11:22:28 +02:00
Robin Appelman
c910ac1f47 check if the user is trying to scan a valid path 2015-07-27 11:19:27 +02:00
Morris Jobke
95e44bfc4e Merge pull request #17843 from owncloud/dont-set-share-password-twice-stable8.1
Adding error handling in case setting the password fails
2015-07-27 08:56:47 +02:00
Lukas Reschke
ee18718099 Allow classes in <h2> tags
Previously something like `<h2 class="inlineblock"><?php p($l->t('Some title')) ?></h2>` was shown as `<h2 class="inlineblock">Some title` within the sidebar instead as `Some Title` due to the fact that the regex was catching these classes but was not properly running the string replace function.
2015-07-26 23:02:22 +02:00
Thomas Müller
6782c6d22e Merge pull request #17853 from owncloud/sharing-password-policy-stable8.1
Sharing password policy stable8.1
2015-07-24 21:25:41 +02:00
Thomas Müller
cef2680c0d Fix PHPDoc on setPassword 2015-07-24 16:49:34 +02:00
Thomas Müller
e29158c892 Use a hook to integrate sharing password verification 2015-07-24 16:49:19 +02:00
Thomas Müller
a53b7e3240 Adding error handling in case setting the password fails 2015-07-23 16:35:10 +02:00
michag86
74e0b6f1e5 assign error message to correct object
fix for  #17817
2015-07-23 16:17:39 +02:00
Jan-Christoph Borchardt
b8e8e3fdaf Merge pull request #17832 from owncloud/improve_apps_template_8.1
[8.1 backport] make sure that there is a space between user- and admin-documentation
2015-07-23 12:29:09 +02:00
Bjoern Schiessle
965fd990fc make sure that there is a space between user- and admin-documentation 2015-07-23 11:00:10 +02:00
C Montero-Luque
3fdd5d9012 8.1.1 beta1 again 2015-07-22 17:05:14 -04:00
C Montero-Luque
b4bef0214e 8.1.1 beta1 2015-07-22 16:49:28 -04:00
Thomas Müller
ee85d1fd37 Merge pull request #17802 from owncloud/update-sabre-dav-2.1.6
Update SabreDAV to 2.1.6
2015-07-22 21:19:35 +02:00
Björn Schießle
77a37e076f Merge pull request #17816 from owncloud/enc_improved_app_description_8.1
[8.1 backport] improved description for the default encryption module
2015-07-22 21:01:20 +02:00
Bjoern Schiessle
a07675e513 improved app description and adjust it to the way the new encryption module works 2015-07-22 16:18:10 +02:00
Joas Schilling
2b63903942 Update SabreDAV to 2.1.6 2015-07-22 12:00:29 +02:00
Joas Schilling
2bc2e974b2 Merge pull request #17752 from owncloud/enc_migration_fix_mountpoint_detection_8.1
[8.1 backport] fix system wide mount point detection on migration
2015-07-21 11:06:09 +02:00
Morris Jobke
2ecba9e5a5 Merge pull request #17762 from owncloud/backport-17723-stable8.1
Backport of #17723 to stable8.1
2015-07-21 00:30:37 +02:00
Morris Jobke
dd5b347672 Merge pull request #17704 from owncloud/backport-stable8.1-17255-17526
Backport stable8.1 #17255 #17526
2015-07-21 00:01:36 +02:00
Arthur Schiwon
8be59bf7e0 Backport of #17723 to stable8.1
fix runtime caching in ldap's user manager, fixes #17631

fix indentation. no code changes, whitespace only.
2015-07-20 22:50:10 +02:00
Thomas Müller
e92d427dde Merge pull request #17707 from owncloud/backport-fix-closest-stable8.1
fix browser compatibility issue for element.closest
2015-07-20 21:36:22 +02:00
Olivier Paroz
897e99ac58 Fix preview of old file on public upload conflicts 2015-07-20 16:51:28 +02:00
Bjoern Schiessle
dc6cc57e11 fix mount point detection 2015-07-20 16:26:07 +02:00
Morris Jobke
f1df6cd4ff Merge pull request #17736 from owncloud/backport-allow-update-of-disabled-apps
[stable8.1] Allow upgrade of not enabled apps
2015-07-20 14:24:22 +02:00
Morris Jobke
ff8e63c991 Merge pull request #17711 from owncloud/fix_repeated_migration_oc8.1
[8.1 backport] Don't mix up directories if the migration runs multiple times
2015-07-20 13:58:20 +02:00
Thomas Müller
d4cc4019fd Allow upgrade of not enabled apps 2015-07-19 12:16:15 +02:00
Björn Schießle
6383bd3744 Merge pull request #17702 from owncloud/enc_detect_legacy_files2_8.1
[8.1 backport] make sure that we always detect legacy files correctlly
2015-07-17 21:39:45 +02:00
Morris Jobke
738e116c00 Merge pull request #17710 from owncloud/stable8.1-s2s-catchremotelockexceptions
[Stable 8.1] s2s catchremotelockexceptions
2015-07-17 18:35:10 +02:00
Bjoern Schiessle
777964ff2b unit tests 2015-07-17 15:30:55 +02:00
Bjoern Schiessle
00a044f885 don't move keys if the key where already moved in a previous migration run 2015-07-17 15:30:43 +02:00
Vincent Petry
335372064e Throw lock exceptions if remote share returned 423 status code 2015-07-17 15:26:40 +02:00
Hendrik Leppelsack
17d7a2893e fix browser compatibility issue for element.closest 2015-07-17 15:08:45 +02:00
Morris Jobke
1b8eb668de Merge pull request #17697 from owncloud/fix-undefined-REMOTE_ADDR-stable8.1
Fixing 'Undefined index: REMOTE_ADDR' - fixes #17460
2015-07-17 14:20:57 +02:00
Arthur Schiwon
a3172008c6 LDAP: when checking group for matching filter, also take base DN into consideration. Fixes #17516 2015-07-17 13:42:33 +02:00
Arthur Schiwon
b2db982768 Backport of 17255 to stable8.1
ensure groups match filter when using memberOf to read users group, refs #17119

integration test

adjust unit test

tests solidity
2015-07-17 13:41:58 +02:00
Bjoern Schiessle
001dd400a1 set targetIsEncrypted to true if file cache indicates that we try to read a encrypted file 2015-07-17 13:28:58 +02:00
Bjoern Schiessle
5bfbfca266 make sure that we always detect legacy files correctly 2015-07-17 13:28:58 +02:00
Thomas Müller
fc6420c290 Fixing 'Undefined index: REMOTE_ADDR' - fixes #17460 2015-07-17 12:35:00 +02:00
Thomas Müller
015d4e3ba3 Merge pull request #17690 from owncloud/stable8.1-repair-ocs-ids
[stable8.1] Add repair step for outdated OCS IDs
2015-07-17 12:02:45 +02:00
Thomas Müller
deeacacfae Merge pull request #17678 from owncloud/backport-encryption_migration_improvements-stable8.1
Backport encryption migration improvements stable8.1
2015-07-17 11:58:06 +02:00
Thomas Müller
d199fb4e8d Merge pull request #17679 from owncloud/backport-fix_trashbin-stable8.1
only move real files to the trash bin
2015-07-17 11:57:41 +02:00
Lukas Reschke
289fd99333 Prefer OCS Id from database
To be consistent with other logic the app id from the database needs to be prefered. Especially when it comes to be able to replace an outdated OCS id.
2015-07-17 08:33:51 +02:00
Lukas Reschke
579bee03bd Add repair step for outdated OCS IDs
There is the case where OCs IDs might become outdated such as it has been with the calendar and contacts app which refer to the old dummy entry. This means that users with the old OCS id can't update updates as well will receive invalid state flags. (e.g. "experimental" instead of "approved")

To allow instances to properly update the applications in the future we need to migrate the OCS IDs for now manually.
2015-07-16 18:52:27 +02:00
Morris Jobke
816910baf1 Merge pull request #17676 from owncloud/backport-files-scan-user-path-stable8.1
Lock scanner to the given user
2015-07-16 16:00:43 +02:00
Bjoern Schiessle
fb452486d7 only move real files to the trash bin 2015-07-16 15:11:12 +02:00
Bjoern Schiessle
ae1332e9c9 only create new key pair if both keys are missing 2015-07-16 14:07:26 +02:00
Bjoern Schiessle
9d9ab82a17 only cleanUp the remaining keys if the migration really finished succesfully 2015-07-16 14:07:17 +02:00
Morris Jobke
edb15bd493 Merge pull request #17653 from owncloud/backport-17330-share-group-path-exception
[stable8.1] Fix the path for users which have an exception for a group share
2015-07-16 13:19:19 +02:00
Robin Appelman
4c6b26d056 Lock scanner to the given user 2015-07-16 12:14:23 +02:00
Vincent Petry
8e1fca7402 Merge pull request #17658 from owncloud/share-lock-owner-parent-stable81
[8.1] lock parent folders for the owner when locking a shared file as recipient
2015-07-16 11:59:48 +02:00
Vincent Petry
db5a574faf Merge pull request #17556 from owncloud/enc_fix_migration_stable8.1
[stable8.1 backport] more secure way to update the database
2015-07-16 11:57:00 +02:00
Morris Jobke
8e0294d0fd Merge pull request #17294 from owncloud/stable8.1-s2s-catchmoreexceptiontypes
[stable8.1] Catch more error codes thrown by federated shares
2015-07-16 11:50:00 +02:00
Morris Jobke
256c57c01e Merge pull request #17337 from owncloud/stable8.1-backport-17077
[stable8.1] fix getting mount points when passing a path to the files:scan command
2015-07-15 14:51:57 +02:00
Robin Appelman
db21b0964c only lock the parent folders 2015-07-15 13:43:34 +02:00
Robin Appelman
cc45b49de7 lock parent folders for the owner when locking a shared file as recipient 2015-07-15 13:42:59 +02:00
Morris Jobke
90104fc5d8 Merge pull request #17643 from owncloud/stable8.1-s2s-hasupdated-catch405
[stable8.1] Throw StorageNotAvailable if propfind on root failed
2015-07-15 11:11:28 +02:00
Joas Schilling
8f2ce01553 Make sure the owner always has the right path 2015-07-15 10:12:50 +02:00
Vincent Petry
3ade5f5111 Add test case when owner renames shared folder 2015-07-15 10:12:41 +02:00
Vincent Petry
60939ebd2c Add unit test for getUsersSharingFile
This is to test if the user list and paths are correct, even when a
recipient renamed the received shared folder
2015-07-15 10:12:29 +02:00
Joas Schilling
c73f938ff4 Fix the path for users which have an exception for a group share 2015-07-15 10:12:16 +02:00
Björn Schießle
06d7480fa2 Merge pull request #17642 from owncloud/stable8.1-backport-17565
[stable8.1] allow remote shares for users with email as usernames
2015-07-14 18:20:45 +02:00
Vincent Petry
48b2a4e034 Throw StorageNotAvailable if propfind on root failed
If PROPFIND fails with 404 or 405 on the remote share root, it means the
storage is not available. Throw StorageNotAvailable is such case.
2015-07-14 17:41:58 +02:00
Felix Böhm
824df7e22d allow remote shares for users with email as usernames 2015-07-14 15:33:12 +02:00
Vincent Petry
ab308d246a Merge pull request #17632 from owncloud/stable8.1-backport-17606
[stable8.1] Handle returned null value in app level code
2015-07-14 11:44:06 +02:00
Morris Jobke
dc9454ea3c Handle returned null value in app level code
* getApplication on OCSClient can also return null
  this is now handled properly
* fixes #17587
2015-07-14 08:58:28 +02:00
Vincent Petry
f920923dd6 Throw storage not available on guzzle error
If the remote server is in maintenance mode, we must throw storage not
available exception instead of not found which might auto-remove the
share.
2015-07-13 18:55:24 +02:00
Thomas Müller
698e2ebc90 Merge pull request #17607 from owncloud/stable8.1-backport-17426
[stable8.1] [config sample] Update info about appstore
2015-07-13 17:40:54 +02:00
Morris Jobke
1548d69762 [config sample] Update info about appstore 2015-07-13 14:52:38 +02:00
Bjoern Schiessle
8466d9d235 more secure way to update the database 2015-07-10 11:49:51 +02:00
Morris Jobke
48b1e9e2a6 Merge pull request #17288 from owncloud/stable8.1-chunk-cleanupgracefulonlock
Stable8.1 chunk cleanupgracefulonlock
2015-07-09 22:31:40 +02:00
Morris Jobke
f21eb35431 Merge pull request #17518 from owncloud/stable8.1-backport-config-sample
[stable8.1] backport config sample
2015-07-09 14:30:05 +02:00
Morris Jobke
509725fad9 [config sample] improve RST markup and wording 2015-07-09 10:09:11 +02:00
Morris Jobke
447c60c4e4 refine sample config text 2015-07-09 10:06:06 +02:00
Morris Jobke
eb055b0d78 [config sample] merge Miscellaneous & All other options 2015-07-09 10:06:01 +02:00
Morris Jobke
d48d59661a Merge pull request #17289 from owncloud/stable8.1-files-cleanuppartfileonlyonce
Stable8.1 files cleanuppartfileonlyonce
2015-07-08 10:34:55 +02:00
Morris Jobke
312d82fe71 Merge pull request #17332 from owncloud/fix-temporary-mountpoint-name-in-activities
Fix the mount point name before creating the activities
2015-07-08 10:33:15 +02:00
Morris Jobke
96b97d1567 Merge pull request #17338 from owncloud/stable8.1-backport-17252
[stable8.1] Only do the description kung-fu on strings - fixes #17028
2015-07-08 10:32:53 +02:00
Morris Jobke
97e49e422f Merge pull request #17366 from owncloud/fix_16740_8.1
[oc8.1] owner is stored as 'uid_owner', not as 'owner' in the oc_share table
2015-07-08 10:32:30 +02:00
Morris Jobke
5d3d44eeb9 Merge pull request #17370 from owncloud/stable8.1-share-onlyshowstaticownerifavailable
[stable8.1] Do not show static share owner if not available
2015-07-08 10:31:33 +02:00
Morris Jobke
51978aa296 Merge pull request #17417 from owncloud/stable8.1-backport-17159
[stable8.1] remove duplicate ID in HTML template for public shares
2015-07-08 10:31:11 +02:00
Morris Jobke
3823713c7c Merge pull request #17429 from owncloud/stable8.1-backport-17088
[stable8.1] [upgrade] add verbosity check and show repair info & steps
2015-07-08 10:29:16 +02:00
Thomas Müller
3854dead08 Merge pull request #17431 from owncloud/stable8.1-update-readme
[stable8.1] Update readme versions
2015-07-07 10:33:36 +02:00
Vincent Petry
ce0f391ecd Update README version and bower 2015-07-07 10:22:36 +02:00
Morris Jobke
388409290a [Repair] add repair info for changed collation 2015-07-07 10:16:54 +02:00
Morris Jobke
fb85fc619d [upgrade] add verbosity check and show repair info & steps 2015-07-07 10:16:49 +02:00
Morris Jobke
d5e90e7239 remove duplicate ID in HTML template for public shares 2015-07-06 13:34:11 +02:00
Vincent Petry
c04beb0bad Do not show static share owner if not available
In some corner cases, an outgoing share exists but sharing is not
allowed for the current user. This would cause the file list to break
because the static text could not be rendered as the owner was
undefined.
2015-07-03 11:54:50 +02:00
Bjoern Schiessle
9def2fcf71 call post_addToGroup als for class OC_User because sharing and LDAP are using this class. Minimal approach to fix #16740 2015-07-03 10:36:09 +02:00
Bjoern Schiessle
1427a79643 owner is stored as 'uid_owner', not as 'owner' in the oc_share table 2015-07-03 10:36:01 +02:00
C Montero-Luque
06ec916b11 8.1.0 2015-07-02 18:20:11 -04:00
Lukas Reschke
7d94d963e9 Merge pull request #17356 from owncloud/stable8.1-apps-keepgloballist
[stable8.1] Fix global app list state
2015-07-02 21:37:41 +02:00
Vincent Petry
c051c180ab Fix global app list state 2015-07-02 17:31:22 +02:00
Lukas Reschke
9cba7c1793 Merge pull request #17317 from owncloud/stable81-clean-ocsid
[stable8.1] Delete OCS ID from DB if none is specified
2015-07-02 14:15:27 +02:00
Lukas Reschke
16514762bf Merge pull request #17311 from owncloud/stable81-remove-ocs-ids
[stable8.1] Remove OCS IDs
2015-07-02 14:15:19 +02:00
Thomas Müller
2727d9797d Only do the description kung-fu on strings - fixes #17028 2015-07-02 13:16:47 +02:00
Robin Appelman
a95b5c3b3e handle invalid results from mount providers 2015-07-02 13:03:09 +02:00
Robin Appelman
1902101923 handle error during setup 2015-07-02 13:03:06 +02:00
Robin Appelman
8a3f54c225 add unit test 2015-07-02 13:03:03 +02:00
Robin Appelman
478fe752e7 fix getting mount points when passing a path to the files:scan command 2015-07-02 13:02:59 +02:00
Joas Schilling
ea731c5c66 Use the item name when refering to the unaccepted remote share 2015-07-02 12:35:30 +02:00
Björn Schießle
caa3210a59 Merge pull request #17308 from owncloud/stable8.1-backport-17293
Stable8.1 backport 17293
2015-07-02 12:17:56 +02:00
Lukas Reschke
8fe5d4b268 Bump versions 2015-07-02 09:20:25 +02:00
Lukas Reschke
85fc84e3d3 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:20:21 +02:00
Lukas Reschke
6008bf975d [stable81] 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:47:31 +02:00
Jan-Christoph Borchardt
4abec8b5b9 Revert "fix z-index of share-autocomplete"
This reverts commit 4edf388a38.
2015-07-02 08:24:04 +02:00
Jan-Christoph Borchardt
d6cbf8be71 Revert "explicitly set z-index on app-content, fix overlap from navigation"
This reverts commit 71e5bc1803.
2015-07-02 08:23:58 +02:00
Vincent Petry
2d92b5a64e Catch more error codes thrown by federated shares
Most of the time it doesn't make sense to forward Guzzle's
RequestException, so we convert it to StorageNotAvailable instead.

This prevents unpredictable error codes to block access to unrelated
folders needlessly.
2015-07-01 16:23:57 +02:00
Thomas Müller
d6b24c7bbc Merge pull request #17266 from owncloud/stable8.1-backport-17224
Stable8.1 backport 17224
2015-07-01 16:12:55 +02:00
Vincent Petry
4aa2eff94c Only delete part file on error if it is really a part file 2015-07-01 15:25:17 +02:00
Vincent Petry
4fff832fa6 Clean up part file only once, not twice on error 2015-07-01 15:25:09 +02:00
Vincent Petry
39e391fd1a Catch cache garbage collection exception on postLogin
Just log the exception instead of preventing access to OC.
2015-07-01 15:19:46 +02:00
Vincent Petry
e48afaf334 Test for chunk cache garbage collection 2015-07-01 15:19:43 +02:00
Vincent Petry
18e4fe7add Do not try clearing locked files in cache folder 2015-07-01 15:19:38 +02:00
Morris Jobke
c7bc669e00 Merge pull request #17267 from owncloud/stable8.1-backport-17264
Use UTF-8 mode for preg_split and preg_replace
2015-07-01 09:13:48 +02:00
Lukas Reschke
09038697cd Use UTF-8 mode for preg_split and preg_replace
Otherwise a single application with a description containing a non compliant character can break the whole ownCloud appstore. This is for example https://apps.owncloud.com/content/show.php?content=149553

Fixes https://github.com/owncloud/core/issues/17101#issuecomment-117365224
2015-07-01 07:52:40 +02:00
Thomas Müller
eb2e8d99cc Avoid namespace clash 2015-07-01 07:48:35 +02:00
Thomas Müller
82493e9789 Fixing content type detection and handle all local printErrorPage calls 2015-07-01 07:48:31 +02:00
Thomas Müller
526a45be18 Adding request specific exception handling - now with WebDAV responses - refs #17192 2015-07-01 07:48:27 +02:00
Thomas Müller
283f8e7e69 Adding exception handling for ServerNotAvailableException - refs #17192 2015-07-01 07:48:23 +02:00
234 changed files with 6254 additions and 2263 deletions

View File

@@ -1,4 +1,4 @@
# Version: 8.1.0
# Version: 8.1.4
<IfModule mod_headers.c>
<IfModule mod_fcgid.c>
<IfModule mod_setenvif.c>

View File

@@ -17,7 +17,7 @@ Depencencies:
[![Dependency Status](https://www.versioneye.com/user/projects/54d1f76f3ca0840b190000c0/badge.svg?style=flat)](https://www.versioneye.com/user/projects/54d1f76f3ca0840b190000c0)
### Installation instructions
https://doc.owncloud.org/server/8.0/developer_manual/app/index.html
https://doc.owncloud.org/server/8.1/developer_manual/app/index.html
### Contribution Guidelines
https://owncloud.org/contribute/
@@ -35,4 +35,4 @@ https://www.transifex.com/projects/p/owncloud/
[![Transifex](https://www.transifex.com/projects/p/owncloud/resource/core/chart/image_png)](https://www.transifex.com/projects/p/owncloud/)
For more detailed information about translations:
http://doc.owncloud.org/server/8.0/developer_manual/core/translation.html
http://doc.owncloud.org/server/8.1/developer_manual/core/translation.html

View File

@@ -81,6 +81,7 @@ class Application extends \OCP\AppFramework\App {
$hookManager->registerHook([
new UserHooks($container->query('KeyManager'),
$server->getUserManager(),
$server->getLogger(),
$container->query('UserSetup'),
$server->getUserSession(),
@@ -195,7 +196,8 @@ class Application extends \OCP\AppFramework\App {
$server->getUserSession(),
$c->query('KeyManager'),
$c->query('Crypt'),
$c->query('Session')
$c->query('Session'),
$server->getSession()
);
});

View File

@@ -2,19 +2,14 @@
<info>
<id>encryption</id>
<description>
This application encrypts all files accessed by ownCloud at rest,
wherever they are stored. As an example, with this application
enabled, external cloud based Amazon S3 storage will be encrypted,
protecting this data on storage outside of the control of the Admin.
When this application is enabled for the first time, all files are
encrypted as users log in and are prompted for their password. The
recommended recovery key option enables recovery of files in case
the key is lost.
Note that this app encrypts all files that are touched by ownCloud,
so external storage providers and applications such as SharePoint
will see new files encrypted when they are accessed. Encryption is
based on AES 128 or 256 bit keys. More information is available in
the Encryption documentation
In order to use this encryption module you need to enable server-side
encryption in the admin settings. Once enabled this module will encrypt
all your files transparently. The encryption is based on AES 256 keys.
The module won't touch existing files, only new files will be encrypted
after server-side encryption was enabled. It is also not possible to
disable the encryption again and switch back to a unencrypted system.
Please read the documentation to know all implications before you decide
to enable server-side encryption.
</description>
<name>Default encryption module</name>
<license>AGPL</license>

View File

@@ -26,4 +26,5 @@ $userManager = OC::$server->getUserManager();
$view = new \OC\Files\View();
$config = \OC::$server->getConfig();
$connection = \OC::$server->getDatabaseConnection();
$application->add(new MigrateKeys($userManager, $view, $connection, $config));
$logger = \OC::$server->getLogger();
$application->add(new MigrateKeys($userManager, $view, $connection, $config, $logger));

View File

@@ -27,6 +27,7 @@ use OC\Files\View;
use OC\User\Manager;
use OCA\Encryption\Migration;
use OCP\IConfig;
use OCP\ILogger;
use OCP\IUserBackend;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
@@ -44,22 +45,27 @@ class MigrateKeys extends Command {
private $connection;
/** @var IConfig */
private $config;
/** @var ILogger */
private $logger;
/**
* @param Manager $userManager
* @param View $view
* @param Connection $connection
* @param IConfig $config
* @param ILogger $logger
*/
public function __construct(Manager $userManager,
View $view,
Connection $connection,
IConfig $config) {
IConfig $config,
ILogger $logger) {
$this->userManager = $userManager;
$this->view = $view;
$this->connection = $connection;
$this->config = $config;
$this->logger = $logger;
parent::__construct();
}
@@ -77,7 +83,7 @@ class MigrateKeys extends Command {
protected function execute(InputInterface $input, OutputInterface $output) {
// perform system reorganization
$migration = new Migration($this->config, $this->view, $this->connection);
$migration = new Migration($this->config, $this->view, $this->connection, $this->logger);
$users = $input->getArgument('user_id');
if (!empty($users)) {
@@ -115,5 +121,7 @@ class MigrateKeys extends Command {
}
}
$migration->finalCleanUp();
}
}

View File

@@ -31,6 +31,7 @@ use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\IL10N;
use OCP\IRequest;
use OCP\ISession;
use OCP\IUserManager;
use OCP\IUserSession;
@@ -54,6 +55,9 @@ class SettingsController extends Controller {
/** @var Session */
private $session;
/** @var ISession */
private $ocSession;
/**
* @param string $AppName
* @param IRequest $request
@@ -63,6 +67,7 @@ class SettingsController extends Controller {
* @param KeyManager $keyManager
* @param Crypt $crypt
* @param Session $session
* @param ISession $ocSession
*/
public function __construct($AppName,
IRequest $request,
@@ -71,7 +76,8 @@ class SettingsController extends Controller {
IUserSession $userSession,
KeyManager $keyManager,
Crypt $crypt,
Session $session) {
Session $session,
ISession $ocSession) {
parent::__construct($AppName, $request);
$this->l = $l10n;
$this->userSession = $userSession;
@@ -79,6 +85,7 @@ class SettingsController extends Controller {
$this->keyManager = $keyManager;
$this->crypt = $crypt;
$this->session = $session;
$this->ocSession = $ocSession;
}
@@ -97,6 +104,13 @@ class SettingsController extends Controller {
//check if password is correct
$passwordCorrect = $this->userManager->checkPassword($uid, $newPassword);
if ($passwordCorrect === false) {
// if check with uid fails we need to check the password with the login name
// e.g. in the ldap case. For local user we need to check the password with
// the uid because in this case the login name is case insensitive
$loginName = $this->ocSession->get('loginname');
$passwordCorrect = $this->userManager->checkPassword($loginName, $newPassword);
}
if ($passwordCorrect !== false) {
$encryptedKey = $this->keyManager->getPrivateKey($uid);

View File

@@ -24,6 +24,7 @@
namespace OCA\Encryption\Hooks;
use OCP\IUserManager;
use OCP\Util as OCUtil;
use OCA\Encryption\Hooks\Contracts\IHook;
use OCA\Encryption\KeyManager;
@@ -41,6 +42,10 @@ class UserHooks implements IHook {
* @var KeyManager
*/
private $keyManager;
/**
* @var IUserManager
*/
private $userManager;
/**
* @var ILogger
*/
@@ -74,6 +79,7 @@ class UserHooks implements IHook {
* UserHooks constructor.
*
* @param KeyManager $keyManager
* @param IUserManager $userManager
* @param ILogger $logger
* @param Setup $userSetup
* @param IUserSession $user
@@ -83,6 +89,7 @@ class UserHooks implements IHook {
* @param Recovery $recovery
*/
public function __construct(KeyManager $keyManager,
IUserManager $userManager,
ILogger $logger,
Setup $userSetup,
IUserSession $user,
@@ -92,6 +99,7 @@ class UserHooks implements IHook {
Recovery $recovery) {
$this->keyManager = $keyManager;
$this->userManager = $userManager;
$this->logger = $logger;
$this->userSetup = $userSetup;
$this->user = $user;
@@ -196,7 +204,7 @@ class UserHooks implements IHook {
public function preSetPassphrase($params) {
if (App::isEnabled('encryption')) {
$user = $this->user->getUser();
$user = $this->userManager->get($params['uid']);
if ($user && !$user->canChangePassword()) {
$this->setPassphrase($params);

View File

@@ -49,7 +49,7 @@ class Crypt {
*/
private $logger;
/**
* @var IUser
* @var string
*/
private $user;
/**
@@ -64,7 +64,7 @@ class Crypt {
*/
public function __construct(ILogger $logger, IUserSession $userSession, IConfig $config) {
$this->logger = $logger;
$this->user = $userSession && $userSession->isLoggedIn() ? $userSession->getUser() : false;
$this->user = $userSession && $userSession->isLoggedIn() ? $userSession->getUser()->getUID() : '"no user given"';
$this->config = $config;
}
@@ -79,7 +79,7 @@ class Crypt {
$res = $this->getOpenSSLPKey();
if (!$res) {
$log->error("Encryption Library couldn't generate users key-pair for {$this->user->getUID()}",
$log->error("Encryption Library couldn't generate users key-pair for {$this->user}",
['app' => 'encryption']);
if (openssl_error_string()) {
@@ -98,7 +98,7 @@ class Crypt {
'privateKey' => $privateKey
];
}
$log->error('Encryption library couldn\'t export users private key, please check your servers OpenSSL configuration.' . $this->user->getUID(),
$log->error('Encryption library couldn\'t export users private key, please check your servers OpenSSL configuration.' . $this->user,
['app' => 'encryption']);
if (openssl_error_string()) {
$log->error('Encryption Library:' . openssl_error_string(),

View File

@@ -406,19 +406,36 @@ class KeyManager {
}
/**
* @param $userId
* check if user has a private and a public key
*
* @param string $userId
* @return bool
* @throws PrivateKeyMissingException
* @throws PublicKeyMissingException
*/
public function userHasKeys($userId) {
$privateKey = $publicKey = true;
try {
$this->getPrivateKey($userId);
$this->getPublicKey($userId);
} catch (PrivateKeyMissingException $e) {
return false;
} catch (PublicKeyMissingException $e) {
return false;
$privateKey = false;
$exception = $e;
}
try {
$this->getPublicKey($userId);
} catch (PublicKeyMissingException $e) {
$publicKey = false;
$exception = $e;
}
if ($privateKey && $publicKey) {
return true;
} elseif (!$privateKey && !$publicKey) {
return false;
} else {
throw $exception;
}
return true;
}
/**

View File

@@ -26,6 +26,7 @@ namespace OCA\Encryption;
use OC\DB\Connection;
use OC\Files\View;
use OCP\IConfig;
use OCP\ILogger;
class Migration {
@@ -36,21 +37,28 @@ class Migration {
private $connection;
/** @var IConfig */
private $config;
/** @var ILogger */
private $logger;
/** @var string*/
protected $installedVersion;
/**
* @param IConfig $config
* @param View $view
* @param Connection $connection
* @param ILogger $logger
*/
public function __construct(IConfig $config, View $view, Connection $connection) {
public function __construct(IConfig $config, View $view, Connection $connection, ILogger $logger) {
$this->view = $view;
$this->view->getUpdater()->disable();
$this->connection = $connection;
$this->moduleId = \OCA\Encryption\Crypto\Encryption::ID;
$this->config = $config;
$this->logger = $logger;
$this->installedVersion = $this->config->getAppValue('files_encryption', 'installed_version', '-1');
}
public function __destruct() {
public function finalCleanUp() {
$this->view->deleteAll('files_encryption/public_keys');
$this->updateFileCache();
$this->config->deleteAppValue('files_encryption', 'installed_version');
@@ -60,12 +68,16 @@ class Migration {
* update file cache, copy unencrypted_size to the 'size' column
*/
private function updateFileCache() {
$query = $this->connection->createQueryBuilder();
$query->update('`*PREFIX*filecache`')
->set('`size`', '`unencrypted_size`')
->where($query->expr()->eq('`encrypted`', ':encrypted'))
->setParameter('encrypted', 1);
$query->execute();
// make sure that we don't update the file cache multiple times
// only update during the first run
if ($this->installedVersion !== '-1') {
$query = $this->connection->createQueryBuilder();
$query->update('`*PREFIX*filecache`')
->set('`size`', '`unencrypted_size`')
->where($query->expr()->eq('`encrypted`', ':encrypted'))
->setParameter('encrypted', 1);
$query->execute();
}
}
/**
@@ -138,27 +150,43 @@ class Migration {
*/
public function updateDB() {
// make sure that we don't update the file cache multiple times
// only update during the first run
if ($this->installedVersion === '-1') {
return;
}
// delete left-over from old encryption which is no longer needed
$this->config->deleteAppValue('files_encryption', 'ocsid');
$this->config->deleteAppValue('files_encryption', 'types');
$this->config->deleteAppValue('files_encryption', 'enabled');
$oldAppValues = $this->connection->createQueryBuilder();
$oldAppValues->select('*')
->from('`*PREFIX*appconfig`')
->where($oldAppValues->expr()->eq('`appid`', ':appid'))
->setParameter('appid', 'files_encryption');
$appSettings = $oldAppValues->execute();
$query = $this->connection->createQueryBuilder();
$query->update('`*PREFIX*appconfig`')
->set('`appid`', ':newappid')
->where($query->expr()->eq('`appid`', ':oldappid'))
->setParameter('oldappid', 'files_encryption')
->setParameter('newappid', 'encryption');
$query->execute();
while ($row = $appSettings->fetch()) {
// 'installed_version' gets deleted at the end of the migration process
if ($row['configkey'] !== 'installed_version' ) {
$this->config->setAppValue('encryption', $row['configkey'], $row['configvalue']);
$this->config->deleteAppValue('files_encryption', $row['configkey']);
}
}
$query = $this->connection->createQueryBuilder();
$query->update('`*PREFIX*preferences`')
->set('`appid`', ':newappid')
->where($query->expr()->eq('`appid`', ':oldappid'))
->setParameter('oldappid', 'files_encryption')
->setParameter('newappid', 'encryption');
$query->execute();
$oldPreferences = $this->connection->createQueryBuilder();
$oldPreferences->select('*')
->from('`*PREFIX*preferences`')
->where($oldPreferences->expr()->eq('`appid`', ':appid'))
->setParameter('appid', 'files_encryption');
$preferenceSettings = $oldPreferences->execute();
while ($row = $preferenceSettings->fetch()) {
$this->config->setUserValue($row['userid'], 'encryption', $row['configkey'], $row['configvalue']);
$this->config->deleteUserValue($row['userid'], 'files_encryption', $row['configkey']);
}
}
/**
@@ -224,9 +252,10 @@ class Migration {
private function renameUsersPrivateKey($user) {
$oldPrivateKey = $user . '/files_encryption/' . $user . '.privateKey';
$newPrivateKey = $user . '/files_encryption/' . $this->moduleId . '/' . $user . '.privateKey';
$this->createPathForKeys(dirname($newPrivateKey));
$this->view->rename($oldPrivateKey, $newPrivateKey);
if ($this->view->file_exists($oldPrivateKey)) {
$this->createPathForKeys(dirname($newPrivateKey));
$this->view->rename($oldPrivateKey, $newPrivateKey);
}
}
/**
@@ -237,9 +266,10 @@ class Migration {
private function renameUsersPublicKey($user) {
$oldPublicKey = '/files_encryption/public_keys/' . $user . '.publicKey';
$newPublicKey = $user . '/files_encryption/' . $this->moduleId . '/' . $user . '.publicKey';
$this->createPathForKeys(dirname($newPublicKey));
$this->view->rename($oldPublicKey, $newPublicKey);
if ($this->view->file_exists($oldPublicKey)) {
$this->createPathForKeys(dirname($newPublicKey));
$this->view->rename($oldPublicKey, $newPublicKey);
}
}
/**
@@ -251,6 +281,11 @@ class Migration {
*/
private function renameFileKeys($user, $path, $trash = false) {
if ($this->view->is_dir($user . '/' . $path) === false) {
$this->logger->info('Skip dir /' . $user . '/' . $path . ': does not exist');
return;
}
$dh = $this->view->opendir($user . '/' . $path);
if (is_resource($dh)) {
@@ -260,8 +295,15 @@ class Migration {
$this->renameFileKeys($user, $path . '/' . $file, $trash);
} else {
$target = $this->getTargetDir($user, $path, $file, $trash);
$this->createPathForKeys(dirname($target));
$this->view->rename($user . '/' . $path . '/' . $file, $target);
if ($target !== false) {
$this->createPathForKeys(dirname($target));
$this->view->rename($user . '/' . $path . '/' . $file, $target);
} else {
$this->logger->warning(
'did not move key "' . $file
. '" could not find the corresponding file in /data/' . $user . '/files.'
. 'Most likely the key was already moved in a previous migration run and is already on the right place.');
}
}
}
}
@@ -269,23 +311,51 @@ class Migration {
}
}
/**
* get system mount points
* wrap static method so that it can be mocked for testing
*
* @internal
* @return array
*/
protected function getSystemMountPoints() {
return \OC_Mount_Config::getSystemMountPoints();
}
/**
* generate target directory
*
* @param string $user
* @param string $filePath
* @param string $keyPath
* @param string $filename
* @param bool $trash
* @return string
*/
private function getTargetDir($user, $filePath, $filename, $trash) {
private function getTargetDir($user, $keyPath, $filename, $trash) {
if ($trash) {
$targetDir = $user . '/files_encryption/keys/files_trashbin/' . substr($filePath, strlen('/files_trashbin/keys/')) . '/' . $this->moduleId . '/' . $filename;
$filePath = substr($keyPath, strlen('/files_trashbin/keys/'));
$targetDir = $user . '/files_encryption/keys/files_trashbin/' . $filePath . '/' . $this->moduleId . '/' . $filename;
} else {
$targetDir = $user . '/files_encryption/keys/files/' . substr($filePath, strlen('/files_encryption/keys/')) . '/' . $this->moduleId . '/' . $filename;
$filePath = substr($keyPath, strlen('/files_encryption/keys/'));
$targetDir = $user . '/files_encryption/keys/files/' . $filePath . '/' . $this->moduleId . '/' . $filename;
}
return $targetDir;
if ($user === '') {
// for system wide mounts we need to check if the mount point really exists
$normalized = \OC\Files\Filesystem::normalizePath($filePath);
$systemMountPoints = $this->getSystemMountPoints();
foreach ($systemMountPoints as $mountPoint) {
$normalizedMountPoint = \OC\Files\Filesystem::normalizePath($mountPoint['mountpoint']) . '/';
if (strpos($normalized, $normalizedMountPoint) === 0)
return $targetDir;
}
} else if ($trash === false && $this->view->file_exists('/' . $user. '/files/' . $filePath)) {
return $targetDir;
} else if ($trash === true && $this->view->file_exists('/' . $user. '/files_trashbin/' . $filePath)) {
return $targetDir;
}
return false;
}
/**

View File

@@ -54,6 +54,9 @@ class SettingsControllerTest extends TestCase {
/** @var \PHPUnit_Framework_MockObject_MockObject */
private $sessionMock;
/** @var \PHPUnit_Framework_MockObject_MockObject */
private $ocSessionMock;
protected function setUp() {
parent::setUp();
@@ -91,9 +94,11 @@ class SettingsControllerTest extends TestCase {
])
->getMock();
$this->ocSessionMock = $this->getMockBuilder('\OCP\ISession')->disableOriginalConstructor()->getMock();
$this->userSessionMock->expects($this->any())
->method('getUID')
->willReturn('testUser');
->willReturn('testUserUid');
$this->userSessionMock->expects($this->any())
->method($this->anything())
@@ -110,7 +115,8 @@ class SettingsControllerTest extends TestCase {
$this->userSessionMock,
$this->keyManagerMock,
$this->cryptMock,
$this->sessionMock
$this->sessionMock,
$this->ocSessionMock
);
}
@@ -122,8 +128,10 @@ class SettingsControllerTest extends TestCase {
$oldPassword = 'old';
$newPassword = 'new';
$this->userSessionMock->expects($this->once())->method('getUID')->willReturn('uid');
$this->userManagerMock
->expects($this->once())
->expects($this->exactly(2))
->method('checkPassword')
->willReturn(false);
@@ -171,16 +179,22 @@ class SettingsControllerTest extends TestCase {
$oldPassword = 'old';
$newPassword = 'new';
$this->userSessionMock
->expects($this->once())
->method('getUID')
->willReturn('testUser');
$this->ocSessionMock->expects($this->once())
->method('get')->with('loginname')->willReturn('testUser');
$this->userManagerMock
->expects($this->once())
->expects($this->at(0))
->method('checkPassword')
->with('testUserUid', 'new')
->willReturn(false);
$this->userManagerMock
->expects($this->at(1))
->method('checkPassword')
->with('testUser', 'new')
->willReturn(true);
$this->cryptMock
->expects($this->once())
->method('decryptPrivateKey')
@@ -200,7 +214,7 @@ class SettingsControllerTest extends TestCase {
$this->keyManagerMock
->expects($this->once())
->method('setPrivateKey')
->with($this->equalTo('testUser'), $this->equalTo('header.encryptedKey'));
->with($this->equalTo('testUserUid'), $this->equalTo('header.encryptedKey'));
$this->sessionMock
->expects($this->once())

View File

@@ -47,6 +47,11 @@ class UserHooksTest extends TestCase {
* @var \PHPUnit_Framework_MockObject_MockObject
*/
private $keyManagerMock;
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
private $userManagerMock;
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
@@ -101,11 +106,58 @@ class UserHooksTest extends TestCase {
$this->assertNull($this->instance->postDeleteUser($this->params));
}
public function testPreSetPassphrase() {
$this->userSessionMock->expects($this->once())
->method('canChangePassword');
/**
* @dataProvider dataTestPreSetPassphrase
*/
public function testPreSetPassphrase($canChange) {
$this->assertNull($this->instance->preSetPassphrase($this->params));
/** @var UserHooks | \PHPUnit_Framework_MockObject_MockObject $instance */
$instance = $this->getMockBuilder('OCA\Encryption\Hooks\UserHooks')
->setConstructorArgs(
[
$this->keyManagerMock,
$this->userManagerMock,
$this->loggerMock,
$this->userSetupMock,
$this->userSessionMock,
$this->utilMock,
$this->sessionMock,
$this->cryptMock,
$this->recoveryMock
]
)
->setMethods(['setPassphrase'])
->getMock();
$userMock = $this->getMock('OCP\IUser');
$this->userManagerMock->expects($this->once())
->method('get')
->with($this->params['uid'])
->willReturn($userMock);
$userMock->expects($this->once())
->method('canChangePassword')
->willReturn($canChange);
if ($canChange) {
// in this case the password will be changed in the post hook
$instance->expects($this->never())->method('setPassphrase');
} else {
// if user can't change the password we update the encryption
// key password already in the pre hook
$instance->expects($this->once())
->method('setPassphrase')
->with($this->params);
}
$instance->preSetPassphrase($this->params);
}
public function dataTestPreSetPassphrase() {
return [
[true],
[false]
];
}
public function testSetPassphrase() {
@@ -186,6 +238,7 @@ class UserHooksTest extends TestCase {
->willReturn(false);
$userHooks = new UserHooks($this->keyManagerMock,
$this->userManagerMock,
$this->loggerMock,
$this->userSetupMock,
$userSessionMock,
@@ -216,6 +269,9 @@ class UserHooksTest extends TestCase {
$this->keyManagerMock = $this->getMockBuilder('OCA\Encryption\KeyManager')
->disableOriginalConstructor()
->getMock();
$this->userManagerMock = $this->getMockBuilder('OCP\IUserManager')
->disableOriginalConstructor()
->getMock();
$this->userSetupMock = $this->getMockBuilder('OCA\Encryption\Users\Setup')
->disableOriginalConstructor()
->getMock();
@@ -258,6 +314,7 @@ class UserHooksTest extends TestCase {
$this->recoveryMock = $recoveryMock;
$this->utilMock = $utilMock;
$this->instance = new UserHooks($this->keyManagerMock,
$this->userManagerMock,
$this->loggerMock,
$this->userSetupMock,
$this->userSessionMock,

View File

@@ -182,18 +182,62 @@ class KeyManagerTest extends TestCase {
);
}
public function testUserHasKeys() {
/**
* @dataProvider dataTestUserHasKeys
*/
public function testUserHasKeys($key, $expected) {
$this->keyStorageMock->expects($this->exactly(2))
->method('getUserKey')
->with($this->equalTo($this->userId), $this->anything())
->willReturn('key');
->willReturn($key);
$this->assertTrue(
$this->assertSame($expected,
$this->instance->userHasKeys($this->userId)
);
}
public function dataTestUserHasKeys() {
return [
['key', true],
['', false]
];
}
/**
* @expectedException \OCA\Encryption\Exceptions\PrivateKeyMissingException
*/
public function testUserHasKeysMissingPrivateKey() {
$this->keyStorageMock->expects($this->exactly(2))
->method('getUserKey')
->willReturnCallback(function ($uid, $keyID, $encryptionModuleId) {
if ($keyID=== 'privateKey') {
return '';
}
return 'key';
});
$this->instance->userHasKeys($this->userId);
}
/**
* @expectedException \OCA\Encryption\Exceptions\PublicKeyMissingException
*/
public function testUserHasKeysMissingPublicKey() {
$this->keyStorageMock->expects($this->exactly(2))
->method('getUserKey')
->willReturnCallback(function ($uid, $keyID, $encryptionModuleId){
if ($keyID === 'publicKey') {
return '';
}
return 'key';
});
$this->instance->userHasKeys($this->userId);
}
public function testInit() {
$this->keyStorageMock->expects($this->any())
->method('getUserKey')

View File

@@ -24,6 +24,7 @@
namespace OCA\Encryption\Tests;
use OCA\Encryption\Migration;
use OCP\ILogger;
class MigrationTest extends \Test\TestCase {
@@ -37,6 +38,9 @@ class MigrationTest extends \Test\TestCase {
private $recovery_key_id = 'recovery_key_id';
private $moduleId;
/** @var PHPUnit_Framework_MockObject_MockObject | ILogger */
private $logger;
public static function setUpBeforeClass() {
parent::setUpBeforeClass();
\OC_User::createUser(self::TEST_ENCRYPTION_MIGRATION_USER1, 'foo');
@@ -53,6 +57,7 @@ class MigrationTest extends \Test\TestCase {
public function setUp() {
$this->logger = $this->getMockBuilder('\OCP\ILogger')->disableOriginalConstructor()->getMock();
$this->view = new \OC\Files\View();
$this->moduleId = \OCA\Encryption\Crypto\Encryption::ID;
}
@@ -100,6 +105,17 @@ class MigrationTest extends \Test\TestCase {
$this->view->file_put_contents($uid . '/files_encryption/keys/folder2/file.2.1/fileKey' , 'data');
}
protected function createDummyFiles($uid) {
$this->view->mkdir($uid . '/files/folder1/folder2/folder3/file3');
$this->view->mkdir($uid . '/files/folder1/folder2/file2');
$this->view->mkdir($uid . '/files/folder1/file.1');
$this->view->mkdir($uid . '/files/folder2/file.2.1');
$this->view->file_put_contents($uid . '/files/folder1/folder2/folder3/file3/fileKey' , 'data');
$this->view->file_put_contents($uid . '/files/folder1/folder2/file2/fileKey' , 'data');
$this->view->file_put_contents($uid . '/files/folder1/file.1/fileKey' , 'data');
$this->view->file_put_contents($uid . '/files/folder2/file.2.1/fileKey' , 'data');
}
protected function createDummyFilesInTrash($uid) {
$this->view->mkdir($uid . '/files_trashbin/keys/file1.d5457864');
$this->view->mkdir($uid . '/files_trashbin/keys/folder1.d7437648723/file2');
@@ -109,6 +125,11 @@ class MigrationTest extends \Test\TestCase {
$this->view->file_put_contents($uid . '/files_trashbin/keys/file1.d5457864/fileKey' , 'data');
$this->view->file_put_contents($uid . '/files_trashbin/keys/folder1.d7437648723/file2/fileKey' , 'data');
// create the files itself
$this->view->mkdir($uid . '/files_trashbin/folder1.d7437648723');
$this->view->file_put_contents($uid . '/files_trashbin/file1.d5457864' , 'data');
$this->view->file_put_contents($uid . '/files_trashbin/folder1.d7437648723/file2' , 'data');
}
protected function createDummySystemWideKeys() {
@@ -118,7 +139,6 @@ class MigrationTest extends \Test\TestCase {
$this->view->file_put_contents('files_encryption/systemwide_2.privateKey', 'data');
$this->view->file_put_contents('files_encryption/public_keys/systemwide_1.publicKey', 'data');
$this->view->file_put_contents('files_encryption/public_keys/systemwide_2.publicKey', 'data');
}
public function testMigrateToNewFolderStructure() {
@@ -134,6 +154,10 @@ class MigrationTest extends \Test\TestCase {
$this->createDummyFileKeys(self::TEST_ENCRYPTION_MIGRATION_USER2);
$this->createDummyFileKeys(self::TEST_ENCRYPTION_MIGRATION_USER3);
$this->createDummyFiles(self::TEST_ENCRYPTION_MIGRATION_USER1);
$this->createDummyFiles(self::TEST_ENCRYPTION_MIGRATION_USER2);
$this->createDummyFiles(self::TEST_ENCRYPTION_MIGRATION_USER3);
$this->createDummyFilesInTrash(self::TEST_ENCRYPTION_MIGRATION_USER2);
// no user for system wide mount points
@@ -142,7 +166,21 @@ class MigrationTest extends \Test\TestCase {
$this->createDummySystemWideKeys();
$m = new Migration(\OC::$server->getConfig(), new \OC\Files\View(), \OC::$server->getDatabaseConnection());
$m = $this->getMockBuilder('OCA\Encryption\Migration')
->setConstructorArgs(
[
\OC::$server->getConfig(),
new \OC\Files\View(),
\OC::$server->getDatabaseConnection(),
$this->logger
]
)->setMethods(['getSystemMountPoints'])->getMock();
$m->expects($this->any())->method('getSystemMountPoints')
->willReturn([['mountpoint' => 'folder1'], ['mountpoint' => 'folder2']]);
$m->reorganizeFolderStructure();
// even if it runs twice folder should always move only once
$m->reorganizeFolderStructure();
$this->assertTrue(
@@ -242,6 +280,12 @@ class MigrationTest extends \Test\TestCase {
$config->setAppValue('files_encryption', 'recoveryAdminEnabled', '1');
$config->setUserValue(self::TEST_ENCRYPTION_MIGRATION_USER1, 'files_encryption', 'recoverKeyEnabled', '1');
//$this->invokePrivate($config, 'cache', [[]]);
$cache = $this->invokePrivate(\OC::$server->getAppConfig(), 'cache');
unset($cache['encryption']);
unset($cache['files_encryption']);
$this->invokePrivate(\OC::$server->getAppConfig(), 'cache', [$cache]);
// delete default values set by the encryption app during initialization
/** @var \OC\DB\Connection $connection */
@@ -261,7 +305,8 @@ class MigrationTest extends \Test\TestCase {
public function testUpdateDB() {
$this->prepareDB();
$m = new Migration(\OC::$server->getConfig(), new \OC\Files\View(), \OC::$server->getDatabaseConnection());
$m = new Migration(\OC::$server->getConfig(), new \OC\Files\View(), \OC::$server->getDatabaseConnection(), $this->logger);
$this->invokePrivate($m, 'installedVersion', ['0.7']);
$m->updateDB();
$this->verifyDB('`*PREFIX*appconfig`', 'files_encryption', 0);
@@ -271,6 +316,59 @@ class MigrationTest extends \Test\TestCase {
}
/**
* test update db if the db already contain some existing new values
*/
public function testUpdateDBExistingNewConfig() {
$this->prepareDB();
$config = \OC::$server->getConfig();
$config->setAppValue('encryption', 'publicShareKeyId', 'wrong_share_id');
$config->setUserValue(self::TEST_ENCRYPTION_MIGRATION_USER1, 'encryption', 'recoverKeyEnabled', '9');
$m = new Migration(\OC::$server->getConfig(), new \OC\Files\View(), \OC::$server->getDatabaseConnection(), $this->logger);
$this->invokePrivate($m, 'installedVersion', ['0.7']);
$m->updateDB();
$this->verifyDB('`*PREFIX*appconfig`', 'files_encryption', 0);
$this->verifyDB('`*PREFIX*preferences`', 'files_encryption', 0);
$this->verifyDB('`*PREFIX*appconfig`', 'encryption', 3);
$this->verifyDB('`*PREFIX*preferences`', 'encryption', 1);
// check if the existing values where overwritten correctly
/** @var \OC\DB\Connection $connection */
$connection = \OC::$server->getDatabaseConnection();
$query = $connection->createQueryBuilder();
$query->select('`configvalue`')
->from('`*PREFIX*appconfig`')
->where($query->expr()->andX(
$query->expr()->eq('`appid`', ':appid'),
$query->expr()->eq('`configkey`', ':configkey')
))
->setParameter('appid', 'encryption')
->setParameter('configkey', 'publicShareKeyId');
$result = $query->execute();
$value = $result->fetch();
$this->assertTrue(isset($value['configvalue']));
$this->assertSame('share_id', $value['configvalue']);
$query = $connection->createQueryBuilder();
$query->select('`configvalue`')
->from('`*PREFIX*preferences`')
->where($query->expr()->andX(
$query->expr()->eq('`appid`', ':appid'),
$query->expr()->eq('`configkey`', ':configkey'),
$query->expr()->eq('`userid`', ':userid')
))
->setParameter('appid', 'encryption')
->setParameter('configkey', 'recoverKeyEnabled')
->setParameter('userid', self::TEST_ENCRYPTION_MIGRATION_USER1);
$result = $query->execute();
$value = $result->fetch();
$this->assertTrue(isset($value['configvalue']));
$this->assertSame('1', $value['configvalue']);
}
public function verifyDB($table, $appid, $expected) {
/** @var \OC\DB\Connection $connection */
$connection = \OC::$server->getDatabaseConnection();
@@ -291,7 +389,8 @@ class MigrationTest extends \Test\TestCase {
*/
public function testUpdateFileCache() {
$this->prepareFileCache();
$m = new Migration(\OC::$server->getConfig(), new \OC\Files\View(), \OC::$server->getDatabaseConnection());
$m = new Migration(\OC::$server->getConfig(), new \OC\Files\View(), \OC::$server->getDatabaseConnection(), $this->logger);
$this->invokePrivate($m, 'installedVersion', ['0.7']);
self::invokePrivate($m, 'updateFileCache');
// check results
@@ -353,4 +452,80 @@ class MigrationTest extends \Test\TestCase {
$this->assertSame(19, count($result));
}
/**
* @dataProvider dataTestGetTargetDir
*/
public function testGetTargetDir($user, $keyPath, $filename, $trash, $systemMounts, $expected) {
$updater = $this->getMockBuilder('\OC\Files\Cache\Updater')
->disableOriginalConstructor()->getMock();
$view = $this->getMockBuilder('\OC\Files\View')
->disableOriginalConstructor()->getMock();
$view->expects($this->any())->method('file_exists')->willReturn(true);
$view->expects($this->any())->method('getUpdater')->willReturn($updater);
$m = $this->getMockBuilder('OCA\Encryption\Migration')
->setConstructorArgs(
[
\OC::$server->getConfig(),
$view,
\OC::$server->getDatabaseConnection(),
$this->logger
]
)->setMethods(['getSystemMountPoints'])->getMock();
$m->expects($this->any())->method('getSystemMountPoints')
->willReturn($systemMounts);
$this->assertSame($expected,
$this->invokePrivate($m, 'getTargetDir', [$user, $keyPath, $filename, $trash])
);
}
public function dataTestGetTargetDir() {
return [
[
'user1',
'/files_encryption/keys/foo/bar.txt',
'user1.shareKey',
false,
[],
'user1/files_encryption/keys/files/foo/bar.txt/OC_DEFAULT_MODULE/user1.shareKey'
],
[
'user1',
'/files_trashbin/keys/foo/bar.txt',
'user1.shareKey',
true,
[],
'user1/files_encryption/keys/files_trashbin/foo/bar.txt/OC_DEFAULT_MODULE/user1.shareKey'
],
[
'',
'/files_encryption/keys/foo/bar.txt',
'user1.shareKey',
false,
[['mountpoint' => 'foo']],
'/files_encryption/keys/files/foo/bar.txt/OC_DEFAULT_MODULE/user1.shareKey'
],
[
'',
'/files_encryption/keys/foo/bar.txt',
'user1.shareKey',
false,
[['mountpoint' => 'foobar']],
false
],
[
'',
'/files_encryption/keys/foobar/bar.txt',
'user1.shareKey',
false,
[['mountpoint' => 'foo']],
false
]
];
}
}

View File

@@ -148,7 +148,7 @@ if ($maxUploadFileSize >= 0 and $totalSize > $maxUploadFileSize) {
}
$result = array();
if (strpos($dir, '..') === false) {
if (\OC\Files\Filesystem::isValidPath($dir) === true) {
$fileCount = count($files['name']);
for ($i = 0; $i < $fileCount; $i++) {

View File

@@ -45,12 +45,12 @@ $server->setBaseUri($baseuri);
// Load plugins
$defaults = new OC_Defaults();
$server->addPlugin(new \OC\Connector\Sabre\MaintenancePlugin(\OC::$server->getConfig()));
$server->addPlugin(new \OC\Connector\Sabre\BlockLegacyClientPlugin(\OC::$server->getConfig()));
$server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend, $defaults->getName()));
// FIXME: The following line is a workaround for legacy components relying on being able to send a GET to /
$server->addPlugin(new \OC\Connector\Sabre\DummyGetResponsePlugin());
$server->addPlugin(new \OC\Connector\Sabre\FilesPlugin($objectTree));
$server->addPlugin(new \OC\Connector\Sabre\MaintenancePlugin(\OC::$server->getConfig()));
$server->addPlugin(new \OC\Connector\Sabre\ExceptionLoggerPlugin('webdav', \OC::$server->getLogger()));
// wait with registering these until auth is handled and the filesystem is setup

View File

@@ -0,0 +1,96 @@
<?php
/**
* @author Björn Schießle <schiessle@owncloud.com>
* @author Joas Schilling <nickvergessen@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
$installedVersion = \OC::$server->getConfig()->getAppValue('files', 'installed_version');
$ocVersion = explode('.', \OC::$server->getSystemConfig()->getValue('version'));
/**
* In case encryption was not enabled, we accidently set encrypted = 1 for
* files inside mount points, since 8.1.0. This breaks opening the files in
* 8.1.1 because we fixed the code that checks if a file is encrypted.
* In order to fix the file, we need to reset the flag of the file. However,
* the flag might be set because the file is in fact encrypted because it was
* uploaded at a time where encryption was enabled.
*
* So we can only do this when:
* - Current version of ownCloud before the update is 8.1.0 or 8.2.0.(0-2)
* - Encryption is disabled
* - files_encryption is not known in the app config
*
* If the first two are not the case, we are save. However, if files_encryption
* values exist in the config, we might have a false negative here.
* Now if there is no file with unencrypted size greater 0, that means there are
* no files that are still encrypted with "files_encryption" encryption. So we
* can also safely reset the flag here.
*
* If this is not the case, we go with "better save then sorry" and don't change
* the flag but write a message to the ownCloud log file.
*/
/**
* @param \OCP\IDBConnection $conn
*/
function owncloud_reset_encrypted_flag(\OCP\IDBConnection $conn) {
$conn->executeUpdate('UPDATE `*PREFIX*filecache` SET `encrypted` = 0 WHERE `encrypted` = 1');
}
// Current version of ownCloud before the update is 8.1.0 or 8.2.0.(0-2)
if ($installedVersion === '1.1.9' && (
// 8.1.0.x
(((int) $ocVersion[0]) === 8 && ((int) $ocVersion[1]) === 1 && ((int) $ocVersion[2]) === 0)
||
// < 8.1.1.1
(((int) $ocVersion[0]) === 8 && ((int) $ocVersion[1]) === 1 && ((int) $ocVersion[2]) === 1 && ((int) $ocVersion[3]) < 1)
)) {
// Encryption is not enabled
if (!\OC::$server->getEncryptionManager()->isEnabled()) {
$conn = \OC::$server->getDatabaseConnection();
// Old encryption is not known in app config
$oldEncryption = \OC::$server->getConfig()->getAppKeys('files_encryption');
if (empty($oldEncryption)) {
owncloud_reset_encrypted_flag($conn);
} else {
$query = $conn->prepare('SELECT * FROM `*PREFIX*filecache` WHERE `encrypted` = 1 AND `unencrypted_size` > 0', 1);
$query->execute();
$empty = $query->fetch();
if (empty($empty)) {
owncloud_reset_encrypted_flag($conn);
} else {
/**
* Sorry in case you are a false positive, but we are not 100% that
* you don't have any encrypted files anymore, so we can not reset
* the value safely
*/
\OC::$server->getLogger()->warning(
'If you have a problem with files not being accessible and '
. 'you are not using encryption, please have a look at the following'
. 'issue: {issue}',
[
'issue' => 'https://github.com/owncloud/core/issues/17846',
]
);
}
}
}
}

View File

@@ -1 +1 @@
1.1.9
1.1.10

View File

@@ -92,10 +92,10 @@ class Scan extends Command {
}
protected function execute(InputInterface $input, OutputInterface $output) {
$path = $input->getOption('path');
if ($path) {
$path = '/'.trim($path, '/');
list (, $user, ) = explode('/', $path, 3);
$inputPath = $input->getOption('path');
if ($inputPath) {
$inputPath = '/' . trim($inputPath, '/');
list (, $user,) = explode('/', $inputPath, 3);
$users = array($user);
} else if ($input->getOption('all')) {
$users = $this->userManager->search('');
@@ -114,6 +114,7 @@ class Scan extends Command {
if (is_object($user)) {
$user = $user->getUID();
}
$path = $inputPath ? $inputPath : '/' . $user;
if ($this->userManager->userExists($user)) {
$this->scanFiles($user, $path, $quiet, $output);
} else {

View File

@@ -1659,6 +1659,7 @@
}
this.$table.addClass('hidden');
this.$el.find('#emptycontent').addClass('hidden');
$mask = $('<div class="mask transparent"></div>');

View File

@@ -116,7 +116,7 @@
ownerDisplayName = $('#ownerDisplayName').val();
if (usedSpacePercent > 98) {
if (owner !== oc_current_user) {
OC.Notification.show(t('files', 'Storage of {owner} is full, files can not be updated or synced anymore!',
OC.Notification.showTemporary(t('files', 'Storage of {owner} is full, files can not be updated or synced anymore!',
{ owner: ownerDisplayName }));
return;
}
@@ -125,7 +125,7 @@
}
if (usedSpacePercent > 90) {
if (owner !== oc_current_user) {
OC.Notification.show(t('files', 'Storage of {owner} is almost full ({usedSpacePercent}%)',
OC.Notification.showTemporary(t('files', 'Storage of {owner} is almost full ({usedSpacePercent}%)',
{ usedSpacePercent: usedSpacePercent, owner: ownerDisplayName }));
return;
}
@@ -239,7 +239,6 @@
// display storage warnings
setTimeout(Files.displayStorageWarnings, 100);
OC.Notification.setDefault(Files.displayStorageWarnings);
// only possible at the moment if user is logged in or the files app is loaded
if (OC.currentUser && OCA.Files.App) {

View File

@@ -136,25 +136,26 @@ class Activity implements IExtension {
return false;
}
$l = $this->getL10N($languageCode);
switch ($text) {
case 'created_self':
return (string) $this->l->t('You created %1$s', $params);
return (string) $l->t('You created %1$s', $params);
case 'created_by':
return (string) $this->l->t('%2$s created %1$s', $params);
return (string) $l->t('%2$s created %1$s', $params);
case 'created_public':
return (string) $this->l->t('%1$s was created in a public folder', $params);
return (string) $l->t('%1$s was created in a public folder', $params);
case 'changed_self':
return (string) $this->l->t('You changed %1$s', $params);
return (string) $l->t('You changed %1$s', $params);
case 'changed_by':
return (string) $this->l->t('%2$s changed %1$s', $params);
return (string) $l->t('%2$s changed %1$s', $params);
case 'deleted_self':
return (string) $this->l->t('You deleted %1$s', $params);
return (string) $l->t('You deleted %1$s', $params);
case 'deleted_by':
return (string) $this->l->t('%2$s deleted %1$s', $params);
return (string) $l->t('%2$s deleted %1$s', $params);
case 'restored_self':
return (string) $this->l->t('You restored %1$s', $params);
return (string) $l->t('You restored %1$s', $params);
case 'restored_by':
return (string) $this->l->t('%2$s restored %1$s', $params);
return (string) $l->t('%2$s restored %1$s', $params);
default:
return false;

View File

@@ -42,6 +42,9 @@ class ActivityTest extends TestCase {
/** @var \PHPUnit_Framework_MockObject_MockObject */
protected $activityHelper;
/** @var \PHPUnit_Framework_MockObject_MockObject */
protected $l10nFactory;
/** @var \OCA\Files\Activity */
protected $activityExtension;
@@ -67,8 +70,28 @@ class ActivityTest extends TestCase {
$this->config
);
$this->l10nFactory = $this->getMockBuilder('OC\L10N\Factory')
->disableOriginalConstructor()
->getMock();
$deL10n = $this->getMockBuilder('OC_L10N')
->disableOriginalConstructor()
->getMock();
$deL10n->expects($this->any())
->method('t')
->willReturnCallback(function ($argument) {
return 'translate(' . $argument . ')';
});
$this->l10nFactory->expects($this->any())
->method('get')
->willReturnMap([
['files', null, new \OC_L10N('files', 'en')],
['files', 'en', new \OC_L10N('files', 'en')],
['files', 'de', $deL10n],
]);
$this->activityExtension = $activityExtension = new Activity(
new \OC\L10N\Factory(),
$this->l10nFactory,
$this->getMockBuilder('OCP\IURLGenerator')->disableOriginalConstructor()->getMock(),
$this->activityManager,
$this->activityHelper,
@@ -111,6 +134,26 @@ class ActivityTest extends TestCase {
$this->activityExtension->translate('files_sharing', '', [], false, false, 'en'),
'Asserting that no translations are set for files_sharing'
);
// Test english
$this->assertNotFalse(
$this->activityExtension->translate('files', 'deleted_self', ['file'], false, false, 'en'),
'Asserting that translations are set for files.deleted_self'
);
$this->assertStringStartsWith(
'You deleted ',
$this->activityExtension->translate('files', 'deleted_self', ['file'], false, false, 'en')
);
// Test translation
$this->assertNotFalse(
$this->activityExtension->translate('files', 'deleted_self', ['file'], false, false, 'de'),
'Asserting that translations are set for files.deleted_self'
);
$this->assertStringStartsWith(
'translate(You deleted ',
$this->activityExtension->translate('files', 'deleted_self', ['file'], false, false, 'de')
);
}
public function testGetSpecialParameterList() {

View File

@@ -1 +1,4 @@
example.php
icewind/smb/tests
icewind/smb/install_libsmbclient.sh
icewind/smb/.travis.yml

View File

@@ -6,7 +6,7 @@
"vendor-dir": "."
},
"require": {
"icewind/smb": "1.0.1",
"icewind/smb": "1.0.4",
"icewind/streams": "0.2"
}
}

View File

@@ -1,23 +1,23 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "7b46d64e33feb600c5f0ec830b211e6f",
"hash": "5c612406bc1235075305b09a5d6996a9",
"packages": [
{
"name": "icewind/smb",
"version": "v1.0.1",
"version": "v1.0.4",
"source": {
"type": "git",
"url": "https://github.com/icewind1991/SMB.git",
"reference": "8041bc1960bf2da94e60b88b34e5c78300eac476"
"reference": "9277bd20262a01b38a33cc7356e98055f2262d32"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/8041bc1960bf2da94e60b88b34e5c78300eac476",
"reference": "8041bc1960bf2da94e60b88b34e5c78300eac476",
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/9277bd20262a01b38a33cc7356e98055f2262d32",
"reference": "9277bd20262a01b38a33cc7356e98055f2262d32",
"shasum": ""
},
"require": {
@@ -45,7 +45,7 @@
}
],
"description": "php wrapper for smbclient and libsmbclient-php",
"time": "2015-04-20 11:16:24"
"time": "2015-08-17 14:20:38"
},
{
"name": "icewind/streams",

View File

@@ -43,17 +43,17 @@
},
{
"name": "icewind/smb",
"version": "v1.0.1",
"version_normalized": "1.0.1.0",
"version": "v1.0.4",
"version_normalized": "1.0.4.0",
"source": {
"type": "git",
"url": "https://github.com/icewind1991/SMB.git",
"reference": "8041bc1960bf2da94e60b88b34e5c78300eac476"
"reference": "9277bd20262a01b38a33cc7356e98055f2262d32"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/8041bc1960bf2da94e60b88b34e5c78300eac476",
"reference": "8041bc1960bf2da94e60b88b34e5c78300eac476",
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/9277bd20262a01b38a33cc7356e98055f2262d32",
"reference": "9277bd20262a01b38a33cc7356e98055f2262d32",
"shasum": ""
},
"require": {
@@ -63,7 +63,7 @@
"require-dev": {
"satooshi/php-coveralls": "dev-master"
},
"time": "2015-04-20 11:16:24",
"time": "2015-08-17 14:20:38",
"type": "library",
"installation-source": "source",
"autoload": {

View File

@@ -1,50 +0,0 @@
language: php
php:
- 5.3
- 5.4
- 5.5
env:
global:
- CURRENT_DIR=`pwd`
before_install:
- pass=$(perl -e 'print crypt("test", "password")')
- sudo useradd -m -p $pass test
- sudo apt-get update -qq
- sudo apt-get install samba smbclient libsmbclient-dev libsmbclient
- wget -O /tmp/libsmbclient-php.zip https://github.com/eduardok/libsmbclient-php/archive/master.zip
- unzip /tmp/libsmbclient-php.zip -d /tmp
- cd /tmp/libsmbclient-php-master
- phpize && ./configure && make && sudo make install
- echo 'extension="libsmbclient.so"' >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- cd $CURRENT_DIR
- chmod go+w $HOME
- printf "%s\n%s\n" test test|sudo smbpasswd -s test
- sudo mkdir /home/test/test
- sudo chown test /home/test/test
- |
echo "[test]
comment = test
path = /home/test
guest ok = yes
writeable = yes
map archive = yes
map system = yes
map hidden = yes
create mask = 0777
inherit permissions = yes" | sudo tee -a /etc/samba/smb.conf
- sudo service smbd restart
- testparm -s
install:
- composer install --dev --no-interaction
script:
- mkdir -p build/logs
- cd tests
- phpunit --coverage-clover ../build/logs/clover.xml --configuration phpunit.xml
after_script:
- cd $CURRENT_DIR
- php vendor/bin/coveralls -v

View File

@@ -0,0 +1,26 @@
<?php
/**
* Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Licensed under the MIT license:
* http://opensource.org/licenses/MIT
*/
namespace Icewind\SMB;
use Icewind\SMB\Exception\InvalidPathException;
abstract class AbstractShare implements IShare {
private $forbiddenCharacters;
public function __construct() {
$this->forbiddenCharacters = array('?', '<', '>', ':', '*', '|', '"', chr(0), "\n", "\r");
}
protected function verifyPath($path) {
foreach ($this->forbiddenCharacters as $char) {
if (strpos($path, $char) !== false) {
throw new InvalidPathException('Invalid path, "' . $char . '" is not allowed');
}
}
}
}

View File

@@ -8,8 +8,10 @@
namespace Icewind\SMB;
use Icewind\SMB\Exception\AuthenticationException;
use Icewind\SMB\Exception\ConnectException;
use Icewind\SMB\Exception\ConnectionException;
use Icewind\SMB\Exception\InvalidHostException;
use Icewind\SMB\Exception\NoLoginServerException;
class Connection extends RawConnection {
const DELIMITER = 'smb:';
@@ -26,18 +28,25 @@ class Connection extends RawConnection {
/**
* get all unprocessed output from smbclient until the next prompt
*
* @throws ConnectionException
* @return string
* @throws AuthenticationException
* @throws ConnectException
* @throws ConnectionException
* @throws InvalidHostException
* @throws NoLoginServerException
*/
public function read() {
if (!$this->isValid()) {
throw new ConnectionException();
throw new ConnectionException('Connection not valid');
}
$line = $this->readLine(); //first line is prompt
$this->checkConnectionError($line);
$output = array();
$line = $this->readLine();
if ($line === false) {
throw new ConnectException('Unknown error');
}
$length = mb_strlen(self::DELIMITER);
while (mb_substr($line, 0, $length) !== self::DELIMITER) { //next prompt functions as delimiter
$output[] .= $line;
@@ -52,20 +61,24 @@ class Connection extends RawConnection {
* @param $line
* @throws AuthenticationException
* @throws InvalidHostException
* @throws NoLoginServerException
*/
private function checkConnectionError($line) {
$line = rtrim($line, ')');
if (substr($line, -23) === ErrorCodes::LogonFailure) {
throw new AuthenticationException();
throw new AuthenticationException('Invalid login');
}
if (substr($line, -26) === ErrorCodes::BadHostName) {
throw new InvalidHostException();
throw new InvalidHostException('Invalid hostname');
}
if (substr($line, -22) === ErrorCodes::Unsuccessful) {
throw new InvalidHostException();
throw new InvalidHostException('Connection unsuccessful');
}
if (substr($line, -28) === ErrorCodes::ConnectionRefused) {
throw new InvalidHostException();
throw new InvalidHostException('Connection refused');
}
if (substr($line, -26) === ErrorCodes::NoLogonServers) {
throw new NoLoginServerException('No login server');
}
}

View File

@@ -15,6 +15,7 @@ class ErrorCodes {
const BadHostName = 'NT_STATUS_BAD_NETWORK_NAME';
const Unsuccessful = 'NT_STATUS_UNSUCCESSFUL';
const ConnectionRefused = 'NT_STATUS_CONNECTION_REFUSED';
const NoLogonServers = 'NT_STATUS_NO_LOGON_SERVERS';
const PathNotFound = 'NT_STATUS_OBJECT_PATH_NOT_FOUND';
const NoSuchFile = 'NT_STATUS_NO_SUCH_FILE';

View File

@@ -0,0 +1,10 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Licensed under the MIT license:
* http://opensource.org/licenses/MIT
*/
namespace Icewind\SMB\Exception;
class InvalidPathException extends InvalidRequestException {}

View File

@@ -5,5 +5,6 @@
* http://opensource.org/licenses/MIT
*/
date_default_timezone_set('UTC');
require_once __DIR__.'/../vendor/autoload.php';
namespace Icewind\SMB\Exception;
class NoLoginServerException extends ConnectException {}

View File

@@ -24,12 +24,7 @@ class NativeServer extends Server {
}
protected function connect() {
$user = $this->getUser();
$workgroup = null;
if (strpos($user, '/')) {
list($workgroup, $user) = explode($user, '/');
}
$this->state->init($workgroup, $user, $this->getPassword());
$this->state->init($this->getWorkgroup(), $this->getUser(), $this->getPassword());
}
/**

View File

@@ -7,7 +7,7 @@
namespace Icewind\SMB;
class NativeShare implements IShare {
class NativeShare extends AbstractShare {
/**
* @var Server $server
*/
@@ -28,6 +28,7 @@ class NativeShare implements IShare {
* @param string $name
*/
public function __construct($server, $name) {
parent::__construct();
$this->server = $server;
$this->name = $name;
$this->state = new NativeState();
@@ -43,15 +44,7 @@ class NativeShare implements IShare {
return;
}
$user = $this->server->getUser();
if (strpos($user, '/')) {
list($workgroup, $user) = explode('/', $user);
} elseif (strpos($user, '\\')) {
list($workgroup, $user) = explode('\\', $user);
} else {
$workgroup = null;
}
$this->state->init($workgroup, $user, $this->server->getPassword());
$this->state->init($this->server->getWorkgroup(), $this->server->getUser(), $this->server->getPassword());
}
/**
@@ -64,6 +57,7 @@ class NativeShare implements IShare {
}
private function buildUrl($path) {
$this->verifyPath($path);
$url = sprintf('smb://%s/%s', $this->server->getHost(), $this->name);
if ($path) {
$path = trim($path, '/');
@@ -149,6 +143,7 @@ class NativeShare implements IShare {
* @throws \Icewind\SMB\Exception\InvalidTypeException
*/
public function del($path) {
$this->connect();
return $this->state->unlink($this->buildUrl($path));
}

View File

@@ -29,6 +29,11 @@ class Server {
*/
protected $password;
/**
* @var string $workgroup
*/
protected $workgroup;
/**
* Check if the smbclient php extension is available
*
@@ -45,10 +50,28 @@ class Server {
*/
public function __construct($host, $user, $password) {
$this->host = $host;
list($workgroup, $user) = $this->splitUser($user);
$this->user = $user;
$this->workgroup = $workgroup;
$this->password = $password;
}
/**
* Split workgroup from username
*
* @param $user
* @return string[] [$workgroup, $user]
*/
public function splitUser($user) {
if (strpos($user, '/')) {
return explode('/', $user, 2);
} elseif (strpos($user, '\\')) {
return explode('\\', $user);
} else {
return array(null, $user);
}
}
/**
* @return string
*/
@@ -77,6 +100,13 @@ class Server {
return $this->host;
}
/**
* @return string
*/
public function getWorkgroup() {
return $this->workgroup;
}
/**
* @return \Icewind\SMB\IShare[]
*
@@ -84,7 +114,8 @@ class Server {
* @throws \Icewind\SMB\Exception\InvalidHostException
*/
public function listShares() {
$command = Server::CLIENT . ' --authentication-file=/proc/self/fd/3' .
$workgroupArgument = ($this->workgroup) ? ' -W ' . escapeshellarg($this->workgroup) : '';
$command = Server::CLIENT . $workgroupArgument . ' --authentication-file=/proc/self/fd/3' .
' -gL ' . escapeshellarg($this->getHost());
$connection = new RawConnection($command);
$connection->writeAuthentication($this->getUser(), $this->getPassword());

View File

@@ -7,17 +7,13 @@
namespace Icewind\SMB;
use Icewind\SMB\Exception\AccessDeniedException;
use Icewind\SMB\Exception\AlreadyExistsException;
use Icewind\SMB\Exception\ConnectionException;
use Icewind\SMB\Exception\Exception;
use Icewind\SMB\Exception\FileInUseException;
use Icewind\SMB\Exception\InvalidTypeException;
use Icewind\SMB\Exception\NotEmptyException;
use Icewind\SMB\Exception\NotFoundException;
use Icewind\Streams\CallbackWrapper;
class Share implements IShare {
class Share extends AbstractShare {
/**
* @var Server $server
*/
@@ -43,6 +39,7 @@ class Share implements IShare {
* @param string $name
*/
public function __construct($server, $name) {
parent::__construct();
$this->server = $server;
$this->name = $name;
$this->parser = new Parser(new TimeZoneProvider($this->server->getHost()));
@@ -57,10 +54,11 @@ class Share implements IShare {
if ($this->connection and $this->connection->isValid()) {
return;
}
$command = sprintf('%s --authentication-file=/proc/self/fd/3 //%s/%s',
$workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : '';
$command = sprintf('%s %s --authentication-file=/proc/self/fd/3 %s',
Server::CLIENT,
$this->server->getHost(),
$this->name
$workgroupArgument,
escapeshellarg('//' . $this->server->getHost() . '/' . $this->name)
);
$this->connection = new Connection($command);
$this->connection->writeAuthentication($this->server->getUser(), $this->server->getPassword());
@@ -256,18 +254,18 @@ class Share implements IShare {
*/
public function read($source) {
$source = $this->escapePath($source);
// close the single quote, open a double quote where we put the single quote...
$source = str_replace('\'', '\'"\'"\'', $source);
// since returned stream is closed by the caller we need to create a new instance
// since we can't re-use the same file descriptor over multiple calls
$command = sprintf('%s --authentication-file=/proc/self/fd/3 //%s/%s -c \'get %s /proc/self/fd/5\'',
$workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : '';
$command = sprintf('%s %s --authentication-file=/proc/self/fd/3 %s',
Server::CLIENT,
$this->server->getHost(),
$this->name,
$source
$workgroupArgument,
escapeshellarg('//' . $this->server->getHost() . '/' . $this->name)
);
$connection = new Connection($command);
$connection->writeAuthentication($this->server->getUser(), $this->server->getPassword());
$connection->write('get ' . $source . ' /proc/self/fd/5');
$connection->write('exit');
$fh = $connection->getFileOutputStream();
stream_context_set_option($fh, 'file', 'connection', $connection);
return $fh;
@@ -284,23 +282,24 @@ class Share implements IShare {
*/
public function write($target) {
$target = $this->escapePath($target);
// close the single quote, open a double quote where we put the single quote...
$target = str_replace('\'', '\'"\'"\'', $target);
// since returned stream is closed by the caller we need to create a new instance
// since we can't re-use the same file descriptor over multiple calls
$command = sprintf('%s --authentication-file=/proc/self/fd/3 //%s/%s -c \'put /proc/self/fd/4 %s\'',
$workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : '';
$command = sprintf('%s %s --authentication-file=/proc/self/fd/3 %s',
Server::CLIENT,
$this->server->getHost(),
$this->name,
$target
$workgroupArgument,
escapeshellarg('//' . $this->server->getHost() . '/' . $this->name)
);
$connection = new RawConnection($command);
$connection = new Connection($command);
$connection->writeAuthentication($this->server->getUser(), $this->server->getPassword());
$fh = $connection->getFileInputStream();
$connection->write('put /proc/self/fd/4 ' . $target);
$connection->write('exit');
// use a close callback to ensure the upload is finished before continuing
// this also serves as a way to keep the connection in scope
return CallbackWrapper::wrap($fh, null, null, function () use ($connection) {
return CallbackWrapper::wrap($fh, null, null, function () use ($connection, $target) {
$connection->close(false); // dont terminate, give the upload some time
});
}
@@ -378,6 +377,7 @@ class Share implements IShare {
* @return string
*/
protected function escapePath($path) {
$this->verifyPath($path);
if ($path === '/') {
$path = '';
}

View File

@@ -1,539 +0,0 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Licensed under the MIT license:
* http://opensource.org/licenses/MIT
*/
namespace Icewind\SMB\Test;
use Icewind\SMB\FileInfo;
abstract class AbstractShare extends \PHPUnit_Framework_TestCase {
/**
* @var \Icewind\SMB\Server $server
*/
protected $server;
/**
* @var \Icewind\SMB\IShare $share
*/
protected $share;
/**
* @var string $root
*/
protected $root;
protected $config;
public function tearDown() {
try {
if ($this->share) {
$this->cleanDir($this->root);
}
unset($this->share);
} catch (\Exception $e) {
unset($this->share);
throw $e;
}
}
public function nameProvider() {
// / ? < > \ : * | " are illegal characters in path on windows
return array(
array('simple'),
array('with spaces_and-underscores'),
array("single'quote'"),
array('日本語'),
array('url %2F +encode'),
array('a somewhat longer filename than the other with more charaters as the all the other filenames'),
array('$as#d€££Ö€ßœĚęĘĞĜΣΥΦΩΫ')
);
}
public function fileDataProvider() {
return array(
array('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua'),
array('Mixed language, 日本語 が わからか and Various _/* characters \\|” €')
);
}
public function nameAndDataProvider() {
$names = $this->nameProvider();
$data = $this->fileDataProvider();
$result = array();
foreach ($names as $name) {
foreach ($data as $text) {
$result[] = array($name[0], $text[0]);
}
}
return $result;
}
public function cleanDir($dir) {
$content = $this->share->dir($dir);
foreach ($content as $metadata) {
if ($metadata->isDirectory()) {
$this->cleanDir($metadata->getPath());
} else {
$this->share->del($metadata->getPath());
}
}
$this->share->rmdir($dir);
}
private function getTextFile($text = '') {
if (!$text) {
$text = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua';
}
$file = tempnam('/tmp', 'smb_test_');
file_put_contents($file, $text);
return $file;
}
public function testListShares() {
$shares = $this->server->listShares();
foreach ($shares as $share) {
if ($share->getName() === $this->config->share) {
return;
}
}
$this->fail('Share "' . $this->config->share . '" not found');
}
public function testRootStartsEmpty() {
$this->assertEquals(array(), $this->share->dir($this->root));
}
/**
* @dataProvider nameProvider
*/
public function testMkdir($name) {
$this->share->mkdir($this->root . '/' . $name);
$dirs = $this->share->dir($this->root);
$this->assertCount(1, $dirs);
$this->assertEquals($name, $dirs[0]->getName());
$this->assertTrue($dirs[0]->isDirectory());
}
/**
* @dataProvider nameProvider
*/
public function testRenameDirectory($name) {
$this->share->mkdir($this->root . '/' . $name);
$this->share->rename($this->root . '/' . $name, $this->root . '/' . $name . '_rename');
$dirs = $this->share->dir($this->root);
$this->assertEquals(1, count($dirs));
$this->assertEquals($name . '_rename', $dirs[0]->getName());
}
/**
* @dataProvider nameProvider
*/
public function testRmdir($name) {
$this->share->mkdir($this->root . '/' . $name);
$this->share->rmdir($this->root . '/' . $name);
$this->assertCount(0, $this->share->dir($this->root));
}
/**
* @dataProvider nameAndDataProvider
*/
public function testPut($name, $text) {
$tmpFile = $this->getTextFile($text);
$size = filesize($tmpFile);
$this->share->put($tmpFile, $this->root . '/' . $name);
unlink($tmpFile);
$files = $this->share->dir($this->root);
$this->assertCount(1, $files);
$this->assertEquals($name, $files[0]->getName());
$this->assertEquals($size, $files[0]->getSize());
$this->assertFalse($files[0]->isDirectory());
}
/**
* @dataProvider nameProvider
*/
public function testRenameFile($name) {
$tmpFile = $this->getTextFile();
$this->share->put($tmpFile, $this->root . '/' . $name);
unlink($tmpFile);
$this->share->rename($this->root . '/' . $name, $this->root . '/' . $name . '_renamed');
$files = $this->share->dir($this->root);
$this->assertEquals(1, count($files));
$this->assertEquals($name . '_renamed', $files[0]->getName());
}
/**
* @dataProvider nameAndDataProvider
*/
public function testGet($name, $text) {
$tmpFile = $this->getTextFile($text);
$this->share->put($tmpFile, $this->root . '/' . $name);
unlink($tmpFile);
$targetFile = tempnam('/tmp', 'smb_test_');
$this->share->get($this->root . '/' . $name, $targetFile);
$this->assertEquals($text, file_get_contents($targetFile));
unlink($targetFile);
}
/**
* @dataProvider nameProvider
*/
public function testDel($name) {
$tmpFile = $this->getTextFile();
$this->share->put($tmpFile, $this->root . '/' . $name);
unlink($tmpFile);
$this->share->del($this->root . '/' . $name);
$this->assertCount(0, $this->share->dir($this->root));
}
/**
* @expectedException \Icewind\SMB\Exception\NotFoundException
*/
public function testCreateFolderInNonExistingFolder() {
$this->share->mkdir($this->root . '/foo/bar');
}
/**
* @expectedException \Icewind\SMB\Exception\NotFoundException
*/
public function testRemoveFolderInNonExistingFolder() {
$this->share->rmdir($this->root . '/foo/bar');
}
/**
* @expectedException \Icewind\SMB\Exception\NotFoundException
*/
public function testRemoveNonExistingFolder() {
$this->share->rmdir($this->root . '/foo');
}
/**
* @expectedException \Icewind\SMB\Exception\AlreadyExistsException
*/
public function testCreateExistingFolder() {
$this->share->mkdir($this->root . '/bar');
$this->share->mkdir($this->root . '/bar');
$this->share->rmdir($this->root . '/bar');
}
/**
* @expectedException \Icewind\SMB\Exception\InvalidTypeException
*/
public function testCreateFileExistingFolder() {
$this->share->mkdir($this->root . '/bar');
$this->share->put($this->getTextFile(), $this->root . '/bar');
$this->share->rmdir($this->root . '/bar');
}
/**
* @expectedException \Icewind\SMB\Exception\NotFoundException
*/
public function testCreateFileInNonExistingFolder() {
$this->share->put($this->getTextFile(), $this->root . '/foo/bar');
}
/**
* @expectedException \Icewind\SMB\Exception\NotFoundException
*/
public function testTestRemoveNonExistingFile() {
$this->share->del($this->root . '/foo');
}
/**
* @expectedException \Icewind\SMB\Exception\NotFoundException
*/
public function testDownloadNonExistingFile() {
$this->share->get($this->root . '/foo', '/dev/null');
}
/**
* @expectedException \Icewind\SMB\Exception\InvalidTypeException
*/
public function testDownloadFolder() {
$this->share->mkdir($this->root . '/foobar');
$this->share->get($this->root . '/foobar', '/dev/null');
$this->share->rmdir($this->root . '/foobar');
}
/**
* @expectedException \Icewind\SMB\Exception\InvalidTypeException
*/
public function testDelFolder() {
$this->share->mkdir($this->root . '/foobar');
$this->share->del($this->root . '/foobar');
$this->share->rmdir($this->root . '/foobar');
}
/**
* @expectedException \Icewind\SMB\Exception\InvalidTypeException
*/
public function testRmdirFile() {
$this->share->put($this->getTextFile(), $this->root . '/foobar');
$this->share->rmdir($this->root . '/foobar');
$this->share->del($this->root . '/foobar');
}
/**
* @expectedException \Icewind\SMB\Exception\NotEmptyException
*/
public function testRmdirNotEmpty() {
$this->share->mkdir($this->root . '/foobar');
$this->share->put($this->getTextFile(), $this->root . '/foobar/asd');
$this->share->rmdir($this->root . '/foobar');
}
/**
* @expectedException \Icewind\SMB\Exception\NotFoundException
*/
public function testDirNonExisting() {
$this->share->dir('/foobar/asd');
}
/**
* @expectedException \Icewind\SMB\Exception\NotFoundException
*/
public function testRmDirNonExisting() {
$this->share->rmdir('/foobar/asd');
}
/**
* @expectedException \Icewind\SMB\Exception\NotFoundException
*/
public function testRenameNonExisting() {
$this->share->rename('/foobar/asd', '/foobar/bar');
}
/**
* @expectedException \Icewind\SMB\Exception\NotFoundException
*/
public function testRenameTargetNonExisting() {
$txt = $this->getTextFile();
$this->share->put($txt, $this->root . '/foo.txt');
unlink($txt);
$this->share->rename($this->root . '/foo.txt', $this->root . '/bar/foo.txt');
}
public function testModifiedDate() {
$now = time();
$this->share->put($this->getTextFile(), $this->root . '/foo.txt');
$dir = $this->share->dir($this->root);
$mtime = $dir[0]->getMTime();
$this->assertTrue(abs($now - $mtime) <= 2, 'Modified time differs by ' . abs($now - $mtime) . ' seconds');
$this->share->del($this->root . '/foo.txt');
}
/**
* @dataProvider nameAndDataProvider
*/
public function testReadStream($name, $text) {
$sourceFile = $this->getTextFile($text);
$this->share->put($sourceFile, $this->root . '/' . $name);
$fh = $this->share->read($this->root . '/' . $name);
$content = stream_get_contents($fh);
fclose($fh);
$this->share->del($this->root . '/' . $name);
$this->assertEquals(file_get_contents($sourceFile), $content);
}
/**
* @dataProvider nameAndDataProvider
*/
public function testWriteStream($name, $text) {
$fh = $this->share->write($this->root . '/' . $name);
fwrite($fh, $text);
fclose($fh);
$tmpFile1 = tempnam('/tmp', 'smb_test_');
$this->share->get($this->root . '/' . $name, $tmpFile1);
$this->assertEquals($text, file_get_contents($tmpFile1));
$this->share->del($this->root . '/' . $name);
unlink($tmpFile1);
}
public function testDir() {
$txtFile = $this->getTextFile();
$this->share->mkdir($this->root . '/dir');
$this->share->put($txtFile, $this->root . '/file.txt');
unlink($txtFile);
$dir = $this->share->dir($this->root);
if ($dir[0]->getName() === 'dir') {
$dirEntry = $dir[0];
} else {
$dirEntry = $dir[1];
}
$this->assertTrue($dirEntry->isDirectory());
$this->assertFalse($dirEntry->isReadOnly());
$this->assertFalse($dirEntry->isReadOnly());
if ($dir[0]->getName() === 'file.txt') {
$fileEntry = $dir[0];
} else {
$fileEntry = $dir[1];
}
$this->assertFalse($fileEntry->isDirectory());
$this->assertFalse($fileEntry->isReadOnly());
$this->assertFalse($fileEntry->isReadOnly());
}
/**
* @dataProvider nameProvider
*/
public function testStat($name) {
$txtFile = $this->getTextFile();
$size = filesize($txtFile);
$this->share->put($txtFile, $this->root . '/' . $name);
unlink($txtFile);
$info = $this->share->stat($this->root . '/' . $name);
$this->assertEquals($size, $info->getSize());
}
/**
* @expectedException \Icewind\SMB\Exception\NotFoundException
*/
public function testStatNonExisting() {
$this->share->stat($this->root . '/fo.txt');
}
/**
* note setting archive and system bit is not supported
*
* @dataProvider nameProvider
*/
public function testSetMode($name) {
$txtFile = $this->getTextFile();
$this->share->put($txtFile, $this->root . '/' . $name);
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_NORMAL);
$info = $this->share->stat($this->root . '/' . $name);
$this->assertFalse($info->isReadOnly());
$this->assertFalse($info->isArchived());
$this->assertFalse($info->isSystem());
$this->assertFalse($info->isHidden());
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_READONLY);
$info = $this->share->stat($this->root . '/' . $name);
$this->assertTrue($info->isReadOnly());
$this->assertFalse($info->isArchived());
$this->assertFalse($info->isSystem());
$this->assertFalse($info->isHidden());
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_ARCHIVE);
$info = $this->share->stat($this->root . '/' . $name);
$this->assertFalse($info->isReadOnly());
$this->assertTrue($info->isArchived());
$this->assertFalse($info->isSystem());
$this->assertFalse($info->isHidden());
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_READONLY | FileInfo::MODE_ARCHIVE);
$info = $this->share->stat($this->root . '/' . $name);
$this->assertTrue($info->isReadOnly());
$this->assertTrue($info->isArchived());
$this->assertFalse($info->isSystem());
$this->assertFalse($info->isHidden());
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_HIDDEN);
$info = $this->share->stat($this->root . '/' . $name);
$this->assertFalse($info->isReadOnly());
$this->assertFalse($info->isArchived());
$this->assertFalse($info->isSystem());
$this->assertTrue($info->isHidden());
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_SYSTEM);
$info = $this->share->stat($this->root . '/' . $name);
$this->assertFalse($info->isReadOnly());
$this->assertFalse($info->isArchived());
$this->assertTrue($info->isSystem());
$this->assertFalse($info->isHidden());
$this->share->setMode($this->root . '/' . $name, FileInfo::MODE_NORMAL);
$info = $this->share->stat($this->root . '/' . $name);
$this->assertFalse($info->isReadOnly());
$this->assertFalse($info->isArchived());
$this->assertFalse($info->isSystem());
$this->assertFalse($info->isHidden());
}
public function pathProvider() {
// / ? < > \ : * | " are illegal characters in path on windows
return array(
array('dir/sub/foo.txt'),
array('bar.txt'),
array("single'quote'/sub/foo.txt"),
array('日本語/url %2F +encode/asd.txt'),
array(
'a somewhat longer folder than the other with more charaters as the all the other filenames/' .
'followed by a somewhat long file name after that.txt'
)
);
}
/**
* @dataProvider pathProvider
*/
public function testSubDirs($path) {
$dirs = explode('/', $path);
$name = array_pop($dirs);
$fullPath = '';
foreach ($dirs as $dir) {
$fullPath .= '/' . $dir;
$this->share->mkdir($this->root . $fullPath);
}
$txtFile = $this->getTextFile();
$size = filesize($txtFile);
$this->share->put($txtFile, $this->root . $fullPath . '/' . $name);
unlink($txtFile);
$info = $this->share->stat($this->root . $fullPath . '/' . $name);
$this->assertEquals($size, $info->getSize());
$this->assertFalse($info->isHidden());
}
public function testDelAfterStat() {
$name = 'foo.txt';
$txtFile = $this->getTextFile();
$this->share->put($txtFile, $this->root . '/' . $name);
unlink($txtFile);
$this->share->stat($this->root . '/' . $name);
$this->share->del($this->root . '/foo.txt');
}
/**
* @param $name
* @dataProvider nameProvider
*/
public function testDirPaths($name) {
$txtFile = $this->getTextFile();
$this->share->mkdir($this->root . '/' . $name);
$this->share->put($txtFile, $this->root . '/' . $name . '/' . $name);
unlink($txtFile);
$content = $this->share->dir($this->root . '/' . $name);
$this->assertCount(1, $content);
$this->assertEquals($name, $content[0]->getName());
}
public function testStatRoot() {
$info = $this->share->stat('/');
$this->assertInstanceOf('\Icewind\SMB\IFileInfo', $info);
}
}

View File

@@ -1,27 +0,0 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Licensed under the MIT license:
* http://opensource.org/licenses/MIT
*/
namespace Icewind\SMB\Test;
use Icewind\SMB\NativeServer;
class NativeShare extends AbstractShare {
public function setUp() {
if (!function_exists('smbclient_state_new')) {
$this->markTestSkipped('libsmbclient php extension not installed');
}
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
$this->server = new NativeServer($this->config->host, $this->config->user, $this->config->password);
$this->share = $this->server->getShare($this->config->share);
if ($this->config->root) {
$this->root = '/' . $this->config->root . '/' . uniqid();
} else {
$this->root = '/' . uniqid();
}
$this->share->mkdir($this->root);
}
}

View File

@@ -1,143 +0,0 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Licensed under the MIT license:
* http://opensource.org/licenses/MIT
*/
namespace Icewind\SMB\Test;
use Icewind\SMB\NativeServer;
class NativeStream extends \PHPUnit_Framework_TestCase {
/**
* @var \Icewind\SMB\Server $server
*/
protected $server;
/**
* @var \Icewind\SMB\NativeShare $share
*/
protected $share;
/**
* @var string $root
*/
protected $root;
protected $config;
public function setUp() {
if (!function_exists('smbclient_state_new')) {
$this->markTestSkipped('libsmbclient php extension not installed');
}
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
$this->server = new NativeServer($this->config->host, $this->config->user, $this->config->password);
$this->share = $this->server->getShare($this->config->share);
if ($this->config->root) {
$this->root = '/' . $this->config->root . '/' . uniqid();
} else {
$this->root = '/' . uniqid();
}
$this->share->mkdir($this->root);
}
private function getTextFile() {
$text = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua';
$file = tempnam('/tmp', 'smb_test_');
file_put_contents($file, $text);
return $file;
}
public function testSeekTell() {
$sourceFile = $this->getTextFile();
$this->share->put($sourceFile, $this->root . '/foobar');
$fh = $this->share->read($this->root . '/foobar');
$content = fread($fh, 3);
$this->assertEquals('Lor', $content);
fseek($fh, -2, SEEK_CUR);
$content = fread($fh, 3);
$this->assertEquals('ore', $content);
fseek($fh, 3, SEEK_SET);
$content = fread($fh, 3);
$this->assertEquals('em ', $content);
fseek($fh, -3, SEEK_END);
$content = fread($fh, 3);
$this->assertEquals('qua', $content);
fseek($fh, -3, SEEK_END);
$this->assertEquals(120, ftell($fh));
}
public function testStat() {
$sourceFile = $this->getTextFile();
$this->share->put($sourceFile, $this->root . '/foobar');
$fh = $this->share->read($this->root . '/foobar');
$stat = fstat($fh);
$this->assertEquals(filesize($sourceFile), $stat['size']);
unlink($sourceFile);
}
public function testTruncate() {
if (version_compare(phpversion(), '5.4.0', '<')) {
$this->markTestSkipped('php <5.4 doesn\'t support truncate for stream wrappers');
}
$fh = $this->share->write($this->root . '/foobar');
fwrite($fh, 'foobar');
ftruncate($fh, 3);
fclose($fh);
$fh = $this->share->read($this->root . '/foobar');
$this->assertEquals('foo', stream_get_contents($fh));
}
public function testEOF() {
if (version_compare(phpversion(), '5.4.0', '<')) {
$this->markTestSkipped('php <5.4 doesn\'t support truncate for stream wrappers');
}
$fh = $this->share->write($this->root . '/foobar');
fwrite($fh, 'foobar');
fclose($fh);
$fh = $this->share->read($this->root . '/foobar');
fread($fh, 3);
$this->assertFalse(feof($fh));
fread($fh, 5);
$this->assertTrue(feof($fh));
}
public function testLockUnsupported() {
$fh = $this->share->write($this->root . '/foobar');
$this->assertFalse(flock($fh, LOCK_SH));
}
public function testSetOptionUnsupported() {
$fh = $this->share->write($this->root . '/foobar');
$this->assertFalse(stream_set_blocking($fh, false));
}
public function tearDown() {
if ($this->share) {
$this->cleanDir($this->root);
}
unset($this->share);
}
public function cleanDir($dir) {
$content = $this->share->dir($dir);
foreach ($content as $metadata) {
if ($metadata->isDirectory()) {
$this->cleanDir($metadata->getPath());
} else {
$this->share->del($metadata->getPath());
}
}
$this->share->rmdir($dir);
}
}

View File

@@ -1,103 +0,0 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Licensed under the MIT license:
* http://opensource.org/licenses/MIT
*/
namespace Icewind\SMB\Test;
use Icewind\SMB\FileInfo;
class Parser extends \PHPUnit_Framework_TestCase {
public function modeProvider() {
return array(
array('D', FileInfo::MODE_DIRECTORY),
array('A', FileInfo::MODE_ARCHIVE),
array('S', FileInfo::MODE_SYSTEM),
array('H', FileInfo::MODE_HIDDEN),
array('R', FileInfo::MODE_READONLY),
array('N', FileInfo::MODE_NORMAL),
array('RA', FileInfo::MODE_READONLY | FileInfo::MODE_ARCHIVE),
array('RAH', FileInfo::MODE_READONLY | FileInfo::MODE_ARCHIVE | FileInfo::MODE_HIDDEN)
);
}
/**
* @param string $timeZone
* @return \Icewind\SMB\TimeZoneProvider
*/
private function getTimeZoneProvider($timeZone) {
$mock = $this->getMockBuilder('\Icewind\SMB\TimeZoneProvider')
->disableOriginalConstructor()
->getMock();
$mock->expects($this->any())
->method('get')
->will($this->returnValue($timeZone));
return $mock;
}
/**
* @dataProvider modeProvider
*/
public function testParseMode($string, $mode) {
$parser = new \Icewind\SMB\Parser($this->getTimeZoneProvider('UTC'));
$this->assertEquals($mode, $parser->parseMode($string), 'Failed parsing ' . $string);
}
public function statProvider() {
return array(
array(
array(
'altname: test.txt',
'create_time: Sat Oct 12 07:05:58 PM 2013 CEST',
'access_time: Tue Oct 15 02:58:48 PM 2013 CEST',
'write_time: Sat Oct 12 07:05:58 PM 2013 CEST',
'change_time: Sat Oct 12 07:05:58 PM 2013 CEST',
'attributes: (80)',
'stream: [::$DATA], 29634 bytes'
),
array(
'mtime' => strtotime('12 Oct 2013 19:05:58 CEST'),
'mode' => FileInfo::MODE_NORMAL,
'size' => 29634
)
)
);
}
/**
* @dataProvider statProvider
*/
public function testStat($output, $stat) {
$parser = new \Icewind\SMB\Parser($this->getTimeZoneProvider('UTC'));
$this->assertEquals($stat, $parser->parseStat($output));
}
public function dirProvider() {
return array(
array(
array(
' . D 0 Tue Aug 26 19:11:56 2014',
' .. DR 0 Sun Oct 28 15:24:02 2012',
' c.pdf N 29634 Sat Oct 12 19:05:58 2013',
'',
' 62536 blocks of size 8388608. 57113 blocks available'
),
array(
new FileInfo('/c.pdf', 'c.pdf', 29634, strtotime('12 Oct 2013 19:05:58 CEST'),
FileInfo::MODE_NORMAL)
)
)
);
}
/**
* @dataProvider dirProvider
*/
public function testDir($output, $dir) {
$parser = new \Icewind\SMB\Parser($this->getTimeZoneProvider('CEST'));
$this->assertEquals($dir, $parser->parseDir($output, ''));
}
}

View File

@@ -1,57 +0,0 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Licensed under the MIT license:
* http://opensource.org/licenses/MIT
*/
namespace Icewind\SMB\Test;
class Server extends \PHPUnit_Framework_TestCase {
/**
* @var \Icewind\SMB\Server $server
*/
private $server;
private $config;
public function setUp() {
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
$this->server = new \Icewind\SMB\Server($this->config->host, $this->config->user, $this->config->password);
}
public function testListShares() {
$shares = $this->server->listShares();
foreach ($shares as $share) {
if ($share->getName() === $this->config->share) {
return;
}
}
$this->fail('Share "' . $this->config->share . '" not found');
}
/**
* @expectedException \Icewind\SMB\Exception\AuthenticationException
*/
public function testWrongUserName() {
$this->markTestSkipped('This fails for no reason on travis');
$server = new \Icewind\SMB\Server($this->config->host, uniqid(), uniqid());
$server->listShares();
}
/**
* @expectedException \Icewind\SMB\Exception\AuthenticationException
*/
public function testWrongPassword() {
$server = new \Icewind\SMB\Server($this->config->host, $this->config->user, uniqid());
$server->listShares();
}
/**
* @expectedException \Icewind\SMB\Exception\InvalidHostException
*/
public function testWrongHost() {
$server = new \Icewind\SMB\Server(uniqid(), $this->config->user, $this->config->password);
$server->listShares();
}
}

View File

@@ -1,24 +0,0 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Licensed under the MIT license:
* http://opensource.org/licenses/MIT
*/
namespace Icewind\SMB\Test;
use Icewind\SMB\Server as NormalServer;
class Share extends AbstractShare {
public function setUp() {
$this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
$this->server = new NormalServer($this->config->host, $this->config->user, $this->config->password);
$this->share = $this->server->getShare($this->config->share);
if ($this->config->root) {
$this->root = '/' . $this->config->root . '/' . uniqid();
} else {
$this->root = '/' . uniqid();
}
$this->share->mkdir($this->root);
}
}

View File

@@ -1,7 +0,0 @@
{
"host": "localhost",
"user": "test",
"password": "test",
"share": "test",
"root": "test"
}

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<phpunit bootstrap="bootstrap.php">
<testsuite name='SMB'>
<directory suffix='.php'>./</directory>
</testsuite>
</phpunit>

View File

@@ -90,6 +90,15 @@ abstract class StoragesController extends Controller {
}
// TODO: validate that other attrs are set
if ($storage->getBackendOption('objectstore')) {
// objectstore must not be sent from client side
return new DataResponse(
array(
'message' => (string)$this->l10n->t('Objectstore forbidden')
),
Http::STATUS_UNPROCESSABLE_ENTITY
);
}
$backends = \OC_Mount_Config::getBackends();
if (!isset($backends[$storage->getBackendClass()])) {

View File

@@ -121,7 +121,7 @@ class AmazonS3 extends \OC\Files\Storage\Common {
$params['region'] = empty($params['region']) ? 'eu-west-1' : $params['region'];
$params['hostname'] = empty($params['hostname']) ? 's3.amazonaws.com' : $params['hostname'];
if (!isset($params['port']) || $params['port'] === '') {
$params['port'] = ($params['use_ssl'] === 'false') ? 80 : 443;
$params['port'] = ($params['use_ssl'] === false || $params['use_ssl'] === 'false') ? 80 : 443;
}
$this->params = $params;
}
@@ -586,7 +586,7 @@ class AmazonS3 extends \OC\Files\Storage\Common {
return $this->connection;
}
$scheme = ($this->params['use_ssl'] === 'false') ? 'http' : 'https';
$scheme = ($this->params['use_ssl'] === false || $this->params['use_ssl'] === 'false') ? 'http' : 'https';
$base_url = $scheme . '://' . $this->params['hostname'] . ':' . $this->params['port'] . '/';
$this->connection = S3Client::factory(array(

View File

@@ -297,7 +297,9 @@ class OC_Mount_Config {
}
}
} else {
$input = str_replace('$user', $user, $input);
if (is_string($input)) {
$input = str_replace('$user', $user, $input);
}
}
return $input;
}

View File

@@ -78,7 +78,10 @@ class SMB extends Common {
* @return string
*/
public function getId() {
return 'smb::' . $this->server->getUser() . '@' . $this->server->getHost() . '/' . $this->share->getName() . '/' . $this->root;
// FIXME: double slash to keep compatible with the old storage ids,
// failure to do so will lead to creation of a new storage id and
// loss of shares from the storage
return 'smb::' . $this->server->getUser() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
}
/**

View File

@@ -39,7 +39,7 @@ class SMB_OC extends SMB {
public function __construct($params) {
if (isset($params['host'])) {
$host = $params['host'];
$this->username_as_share = ($params['username_as_share'] === 'true');
$this->username_as_share = ($params['username_as_share'] === true);
// dummy credentials, unused, to satisfy constructor
$user = 'foo';

View File

@@ -173,6 +173,25 @@ class StorageConfig implements \JsonSerializable {
$this->backendOptions = $backendOptions;
}
/**
* @param string $option
* @return mixed
*/
public function getBackendOption($key) {
if (isset($this->backendOptions[$key])) {
return $this->backendOptions[$key];
}
return null;
}
/**
* @param string $option
* @param mixed $value
*/
public function setBackendOption($key, $value) {
$this->backendOptions[$key] = $value;
}
/**
* Returns the mount priority
*

View File

@@ -40,8 +40,11 @@ abstract class StreamWrapper extends Common {
}
public function rmdir($path) {
if ($this->file_exists($path) && $this->isDeletable($path)) {
if ($this->is_dir($path) && $this->isDeletable($path)) {
$dh = $this->opendir($path);
if (!is_resource($dh)) {
return false;
}
while (($file = readdir($dh)) !== false) {
if ($this->is_dir($path . '/' . $file)) {
$this->rmdir($path . '/' . $file);

View File

@@ -352,10 +352,14 @@ abstract class StoragesService {
if (!isset($allStorages[$id])) {
throw new NotFoundException('Storage with id "' . $id . '" not found');
}
$oldStorage = $allStorages[$id];
$allStorages[$id] = $updatedStorage;
// ensure objectstore is persistent
if ($objectstore = $oldStorage->getBackendOption('objectstore')) {
$updatedStorage->setBackendOption('objectstore', $objectstore);
}
$allStorages[$id] = $updatedStorage;
$this->writeConfig($allStorages);
$this->triggerChangeHooks($oldStorage, $updatedStorage);

View File

@@ -60,7 +60,7 @@
<?php elseif (strpos($placeholder, '!') === 0): ?>
<label><input type="checkbox"
data-parameter="<?php p($parameter); ?>"
<?php if ($value == 'true'): ?> checked="checked"<?php endif; ?>
<?php if ($value === true || $value === 'true'): ?> checked="checked"<?php endif; ?>
/><?php p(substr($placeholder, 1)); ?></label>
<?php elseif (strpos($placeholder, '#') === 0): ?>
<input type="hidden"

View File

@@ -61,4 +61,16 @@ class SMB extends Storage {
$this->assertTrue($result);
$this->assertTrue($this->instance->is_dir('foo bar'));
}
public function testStorageId() {
$this->instance = new \OC\Files\Storage\SMB([
'host' => 'testhost',
'user' => 'testuser',
'password' => 'somepass',
'share' => 'someshare',
'root' => 'someroot',
]);
$this->assertEquals('smb::testuser@testhost//someshare//someroot/', $this->instance->getId());
$this->instance = null;
}
}

View File

@@ -170,8 +170,14 @@ class Server2Server {
$query = \OCP\DB::prepare('DELETE FROM `*PREFIX*share_external` WHERE `remote_id` = ? AND `share_token` = ?');
$query->execute(array($id, $token));
if ($share['accepted']) {
$path = trim($mountpoint, '/');
} else {
$path = trim($share['name'], '/');
}
\OC::$server->getActivityManager()->publishActivity(
'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_UNSHARED, array($owner, $mountpoint), '', array(),
'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_UNSHARED, array($owner, $path), '', array(),
'', '', $user, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_MEDIUM);
}

View File

@@ -39,9 +39,6 @@ $l = \OC::$server->getL10N('files_sharing');
\OC::$CLASSPATH['OCA\Files\Share\Maintainer'] = 'files_sharing/lib/maintainer.php';
\OC::$CLASSPATH['OCA\Files\Share\Proxy'] = 'files_sharing/lib/proxy.php';
// Exceptions
\OC::$CLASSPATH['OCA\Files_Sharing\Exceptions\BrokenPath'] = 'files_sharing/lib/exceptions.php';
$application = new Application();
$application->registerMountProviders();
$application->setupPropagation();
@@ -57,10 +54,6 @@ $application->setupPropagation();
\OCP\Util::addScript('files_sharing', 'share');
\OCP\Util::addScript('files_sharing', 'external');
// FIXME: registering a job here will cause additional useless SQL queries
// when the route is not cron.php, needs a better way
\OC::$server->getJobList()->add('OCA\Files_sharing\Lib\DeleteOrphanedSharesJob');
\OC::$server->getActivityManager()->registerExtension(function() {
return new \OCA\Files_Sharing\Activity(
\OC::$server->query('L10NFactory'),

View File

@@ -59,7 +59,6 @@ class Application extends App {
return new ExternalSharesController(
$c->query('AppName'),
$c->query('Request'),
$c->query('IsIncomingShareEnabled'),
$c->query('ExternalManager')
);
});
@@ -76,9 +75,6 @@ class Application extends App {
$container->registerService('UserManager', function (SimpleContainer $c) use ($server) {
return $server->getUserManager();
});
$container->registerService('IsIncomingShareEnabled', function (SimpleContainer $c) {
return Helper::isIncomingServer2serverShareEnabled();
});
$container->registerService('ExternalManager', function (SimpleContainer $c) use ($server) {
$user = $server->getUserSession()->getUser();
$uid = $user ? $user->getUID() : null;
@@ -98,7 +94,8 @@ class Application extends App {
return new SharingCheckMiddleware(
$c->query('AppName'),
$server->getConfig(),
$server->getAppManager()
$server->getAppManager(),
$c['ControllerMethodReflector']
);
});

View File

@@ -19,5 +19,4 @@ Turning the feature off removes shared files and folders on the server for all s
<files>public.php</files>
<webdav>publicwebdav.php</webdav>
</public>
<ocsid>166050</ocsid>
</info>

View File

@@ -0,0 +1,22 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
\OC::$server->getJobList()->add('OCA\Files_sharing\Lib\DeleteOrphanedSharesJob');

View File

@@ -28,3 +28,4 @@ if (version_compare($installedVersion, '0.6.0', '<')) {
$m->addAcceptRow();
}
\OC::$server->getJobList()->add('OCA\Files_sharing\Lib\DeleteOrphanedSharesJob');

View File

@@ -1 +1 @@
0.6.1
0.6.3

View File

@@ -72,7 +72,7 @@ thead {
}
/* keep long file names in one line to not overflow download button on mobile */
.directDownload #download {
.directDownload #downloadFile {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;

View File

@@ -158,9 +158,18 @@ OCA.Sharing.PublicApp = {
};
this.fileList.generatePreviewUrl = function (urlSpec) {
urlSpec = urlSpec || {};
if (!urlSpec.x) {
urlSpec.x = 36;
}
if (!urlSpec.y) {
urlSpec.y = 36;
}
urlSpec.x *= window.devicePixelRatio;
urlSpec.y *= window.devicePixelRatio;
urlSpec.x = Math.floor(urlSpec.x);
urlSpec.y = Math.floor(urlSpec.y);
urlSpec.t = $('#dirToken').val();
urlSpec.y = Math.floor(36 * window.devicePixelRatio);
urlSpec.x = Math.floor(36 * window.devicePixelRatio);
return OC.generateUrl('/apps/files_sharing/ajax/publicpreview.php?') + $.param(urlSpec);
};
@@ -292,15 +301,8 @@ $(document).ready(function () {
if (window.Files) {
// HACK: for oc-dialogs previews that depends on Files:
Files.lazyLoadPreview = function (path, mime, ready, width, height, etag) {
return App.fileList.lazyLoadPreview({
path: path,
mime: mime,
callback: ready,
width: width,
height: height,
etag: etag
});
Files.generatePreviewUrl = function (urlSpec) {
return App.fileList.generatePreviewUrl(urlSpec);
};
}
});

View File

@@ -25,6 +25,10 @@
* @param {OCA.Files.FileList} fileList file list to be extended
*/
attach: function(fileList) {
// core sharing is disabled/not loaded
if (!OC.Share) {
return;
}
if (fileList.id === 'trashbin' || fileList.id === 'files.public') {
return;
}
@@ -151,7 +155,7 @@
var permissions = $tr.data('permissions');
var hasLink = !!(shareStatus && shareStatus.link);
OC.Share.markFileAsShared($tr, true, hasLink);
if ((permissions & OC.PERMISSION_SHARE) === 0) {
if ((permissions & OC.PERMISSION_SHARE) === 0 && $tr.attr('data-share-owner')) {
// if no share action exists because the admin disabled sharing for this user
// we create a share notification action to inform the user about files
// shared with him otherwise we just update the existing share action.

View File

@@ -190,12 +190,12 @@ class Activity implements IExtension {
if ($app === self::FILES_SHARING_APP) {
switch ($text) {
case self::SUBJECT_REMOTE_SHARE_RECEIVED:
case self::SUBJECT_REMOTE_SHARE_UNSHARED:
return array(
0 => '',// We can not use 'username' since the user is in a different ownCloud
);
case self::SUBJECT_REMOTE_SHARE_ACCEPTED:
case self::SUBJECT_REMOTE_SHARE_DECLINED:
case self::SUBJECT_REMOTE_SHARE_UNSHARED:
return array(
0 => '',// We can not use 'username' since the user is in a different ownCloud
1 => 'file',

View File

@@ -31,6 +31,7 @@
namespace OC\Files\Cache;
use OC\User\NoUserException;
use OCP\Share_Backend_Collection;
/**
@@ -60,9 +61,14 @@ class Shared_Cache extends Cache {
if ($target === false || $target === $this->storage->getMountPoint()) {
$target = '';
}
$source = \OC_Share_Backend_File::getSource($target, $this->storage->getMountPoint(), $this->storage->getItemType());
$source = \OC_Share_Backend_File::getSource($target, $this->storage->getShare());
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()->logException($e, ['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'];
@@ -242,7 +248,7 @@ class Shared_Cache extends Cache {
*/
protected function getMoveInfo($path) {
$cache = $this->getSourceCache($path);
$file = \OC_Share_Backend_File::getSource($path, $this->storage->getMountPoint(), $this->storage->getItemType());
$file = \OC_Share_Backend_File::getSource($path, $this->storage->getShare());
return [$cache->getNumericStorageId(), $file['path']];
}

View File

@@ -59,20 +59,20 @@ class Capabilities {
$public['enabled'] = $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
if ($public['enabled']) {
$public['password'] = [];
$public['password']['enforced'] = ($this->config->getAppValue('core', 'shareapi_enforce_links_password', 'yes') === 'yes');
$public['password']['enforced'] = ($this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes');
$public['expire_date'] = [];
$public['expire_date']['enabled'] = $this->config->getAppValue('core', 'shareapi_default_expire_date', 'yes') === 'yes';
$public['expire_date']['enabled'] = $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
if ($public['expire_date']['enabled']) {
$public['expire_date']['days'] = $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
$public['expire_date']['enforced'] = $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'yes') === 'yes';
$public['expire_date']['enforced'] = $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
}
$public['send_mail'] = $this->config->getAppValue('core', 'shareapi_allow_public_notification', 'yes') === 'yes';
$public['send_mail'] = $this->config->getAppValue('core', 'shareapi_allow_public_notification', 'no') === 'yes';
}
$res["public"] = $public;
$res['user']['send_mail'] = $this->config->getAppValue('core', 'shareapi_allow_mail_notification', 'yes') === 'yes';
$res['user']['send_mail'] = $this->config->getAppValue('core', 'shareapi_allow_mail_notification', 'no') === 'yes';
$res['resharing'] = $this->config->getAppValue('core', 'shareapi_allow_resharing', 'yes') === 'yes';

View File

@@ -82,10 +82,13 @@ class PublicAuth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
}
return true;
} else if (\OC::$server->getSession()->exists('public_link_authenticated')
&& \OC::$server->getSession()->get('public_link_authenticated') === $linkItem['id']) {
return true;
} else {
return false;
}
} elseif ($linkItem['share_type'] == \OCP\Share::SHARE_TYPE_REMOTE) {
} else if ($linkItem['share_type'] == \OCP\Share::SHARE_TYPE_REMOTE) {
return true;
} else {
return false;

View File

@@ -36,8 +36,6 @@ use OCP\AppFramework\Http\JSONResponse;
*/
class ExternalSharesController extends Controller {
/** @var bool */
private $incomingShareEnabled;
/** @var \OCA\Files_Sharing\External\Manager */
private $externalManager;
@@ -49,52 +47,42 @@ class ExternalSharesController extends Controller {
*/
public function __construct($appName,
IRequest $request,
$incomingShareEnabled,
\OCA\Files_Sharing\External\Manager $externalManager) {
parent::__construct($appName, $request);
$this->incomingShareEnabled = $incomingShareEnabled;
$this->externalManager = $externalManager;
}
/**
* @NoAdminRequired
* @NoOutgoingFederatedSharingRequired
*
* @return JSONResponse
*/
public function index() {
$shares = [];
if ($this->incomingShareEnabled) {
$shares = $this->externalManager->getOpenShares();
}
return new JSONResponse($shares);
return new JSONResponse($this->externalManager->getOpenShares());
}
/**
* @NoAdminRequired
* @NoOutgoingFederatedSharingRequired
*
* @param int $id
* @return JSONResponse
*/
public function create($id) {
if ($this->incomingShareEnabled) {
$this->externalManager->acceptShare($id);
}
$this->externalManager->acceptShare($id);
return new JSONResponse();
}
/**
* @NoAdminRequired
* @NoOutgoingFederatedSharingRequired
*
* @param $id
* @return JSONResponse
*/
public function destroy($id) {
if ($this->incomingShareEnabled) {
$this->externalManager->declineShare($id);
}
$this->externalManager->declineShare($id);
return new JSONResponse();
}
}

View File

@@ -46,6 +46,7 @@ use OCA\Files_Sharing\Helper;
use OCP\User;
use OCP\Util;
use OCA\Files_Sharing\Activity;
use \OCP\Files\NotFoundException;
/**
* Class ShareController
@@ -148,6 +149,7 @@ class ShareController extends Controller {
* @param string $token
* @param string $path
* @return TemplateResponse|RedirectResponse
* @throws NotFoundException
*/
public function showShare($token, $path = '') {
\OC_User::setIncognitoMode(true);
@@ -171,7 +173,7 @@ class ShareController extends Controller {
$getPath = Filesystem::normalizePath($path);
$originalSharePath .= $path;
} else {
throw new OCP\Files\NotFoundException();
throw new NotFoundException();
}
$file = basename($originalSharePath);
@@ -303,7 +305,7 @@ class ShareController extends Controller {
/**
* @param string $token
* @return string Resolved file path of the token
* @throws \Exception In case share could not get properly resolved
* @throws NotFoundException In case share could not get properly resolved
*/
private function getPath($token) {
$linkItem = Share::getShareByToken($token, false);
@@ -312,7 +314,7 @@ class ShareController extends Controller {
$rootLinkItem = Share::resolveReShare($linkItem);
if (isset($rootLinkItem['uid_owner'])) {
if(!$this->userManager->userExists($rootLinkItem['uid_owner'])) {
throw new \Exception('Owner of the share does not exist anymore');
throw new NotFoundException('Owner of the share does not exist anymore');
}
OC_Util::tearDownFS();
OC_Util::setupFS($rootLinkItem['uid_owner']);
@@ -324,6 +326,6 @@ class ShareController extends Controller {
}
}
throw new \Exception('No file found belonging to file.');
throw new NotFoundException('No file found belonging to file.');
}
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_Sharing\Exceptions;
/**
* S2S sharing not allowed
*/
class S2SException extends \Exception {
}

View File

@@ -48,9 +48,10 @@ class Scanner extends \OC\Files\Cache\Scanner {
* @param int $reuseExisting
* @param int $parentId
* @param array | null $cacheData existing data in the cache for the file to be scanned
* @param bool $lock set to false to disable getting an additional read lock during scanning
* @return array an array of metadata of the scanned file
*/
public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null) {
public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true) {
try {
return parent::scanFile($file, $reuseExisting);
} catch (ForbiddenException $e) {

View File

@@ -191,7 +191,7 @@ class Storage extends DAV implements ISharedStorage {
throw new StorageInvalidException();
} else {
// ownCloud instance is gone, likely to be a temporary server configuration error
throw $e;
throw new StorageNotAvailableException();
}
} catch (ForbiddenException $e) {
// auth error, remove share for now (provide a dialog in the future)
@@ -201,10 +201,7 @@ class Storage extends DAV implements ISharedStorage {
} catch (\GuzzleHttp\Exception\ConnectException $e) {
throw new StorageNotAvailableException();
} catch (\GuzzleHttp\Exception\RequestException $e) {
if ($e->getCode() === 503) {
throw new StorageNotAvailableException();
}
throw $e;
throw new StorageNotAvailableException();
} catch (\Exception $e) {
throw $e;
}
@@ -250,16 +247,13 @@ class Storage extends DAV implements ISharedStorage {
try {
$response = $client->post($url, ['body' => ['password' => $password]]);
} catch (\GuzzleHttp\Exception\RequestException $e) {
switch ($e->getCode()) {
case 401:
case 403:
if ($e->getCode() === 401 || $e->getCode() === 403) {
throw new ForbiddenException();
case 404:
throw new NotFoundException();
case 500:
throw new \Exception();
}
throw $e;
// throw this to be on the safe side: the share will still be visible
// in the UI in case the failure is intermittent, and the user will
// be able to decide whether to remove it if it's really gone
throw new StorageNotAvailableException();
}
return json_decode($response->getBody(), true);

View File

@@ -27,7 +27,11 @@ use OCP\App\IAppManager;
use OCP\AppFramework\Http\NotFoundResponse;
use OCP\AppFramework\Middleware;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\Files\NotFoundException;
use OCP\IConfig;
use OCP\AppFramework\Utility\IControllerMethodReflector;
use OCA\Files_Sharing\Exceptions\S2SException;
use OCP\AppFramework\Http\JSONResponse;
/**
* Checks whether the "sharing check" is enabled
@@ -42,6 +46,8 @@ class SharingCheckMiddleware extends Middleware {
protected $config;
/** @var IAppManager */
protected $appManager;
/** @var IControllerMethodReflector */
protected $reflector;
/***
* @param string $appName
@@ -50,30 +56,74 @@ class SharingCheckMiddleware extends Middleware {
*/
public function __construct($appName,
IConfig $config,
IAppManager $appManager) {
IAppManager $appManager,
IControllerMethodReflector $reflector
) {
$this->appName = $appName;
$this->config = $config;
$this->appManager = $appManager;
$this->reflector = $reflector;
}
/**
* Check if sharing is enabled before the controllers is executed
*
* @param \OCP\AppFramework\Controller $controller
* @param string $methodName
* @throws NotFoundException
*/
public function beforeController($controller, $methodName) {
if(!$this->isSharingEnabled()) {
throw new \Exception('Sharing is disabled.');
throw new NotFoundException('Sharing is disabled.');
}
if ($controller instanceof \OCA\Files_Sharing\Controllers\ExternalSharesController &&
!$this->externalSharesChecks()) {
throw new S2SException('Federated sharing not allowed');
} else if ($controller instanceof \OCA\Files_Sharing\Controllers\ShareController &&
!$this->isLinkSharingEnabled()) {
throw new NotFoundException('Link sharing is disabled');
}
}
/**
* Return 404 page in case of an exception
* Return 404 page in case of a not found exception
*
* @param \OCP\AppFramework\Controller $controller
* @param string $methodName
* @param \Exception $exception
* @return TemplateResponse
* @return NotFoundResponse
* @throws \Exception
*/
public function afterException($controller, $methodName, \Exception $exception){
return new NotFoundResponse();
public function afterException($controller, $methodName, \Exception $exception) {
if(is_a($exception, '\OCP\Files\NotFoundException')) {
return new NotFoundResponse();
}
if (is_a($exception, '\OCA\Files_Sharing\Exceptions\S2SException')) {
return new JSONResponse($exception->getMessage(), 405);
}
throw $exception;
}
/**
* Checks for externalshares controller
* @return bool
*/
private function externalSharesChecks() {
if (!$this->reflector->hasAnnotation('NoIncomingFederatedSharingRequired') &&
$this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes') !== 'yes') {
return false;
}
if (!$this->reflector->hasAnnotation('NoOutgoingFederatedSharingRequired') &&
$this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') !== 'yes') {
return false;
}
return true;
}
/**
@@ -87,6 +137,19 @@ class SharingCheckMiddleware extends Middleware {
return false;
}
return true;
}
/**
* Check if link sharing is allowed
* @return bool
*/
private function isLinkSharingEnabled() {
// Check if the shareAPI is enabled
if ($this->config->getAppValue('core', 'shareapi_enabled', 'yes') !== 'yes') {
return false;
}
// Check whether public sharing is enabled
if($this->config->getAppValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
return false;

View File

@@ -66,12 +66,6 @@ class MountProvider implements IMountProvider {
return $share['permissions'] > 0;
});
$shares = array_map(function ($share) use ($user, $storageFactory) {
try {
Filesystem::initMountPoints($share['uid_owner']);
} catch(NoUserException $e) {
\OC::$server->getLogger()->warning('The user \'' . $share['uid_owner'] . '\' of share with ID \'' . $share['id'] . '\' can\'t be retrieved.', array('app' => 'files_sharing'));
return null;
}
// for updating etags for the share owner when we make changes to this share.
$ownerPropagator = $this->propagationManager->getChangePropagator($share['uid_owner']);

View File

@@ -126,20 +126,28 @@ class RecipientPropagator {
});
}
protected $propagatingIds = [];
public function propagateById($id) {
if (isset($this->propagatingIds[$id])) {
return;
}
$this->propagatingIds[$id] = true;
$shares = Share::getAllSharesForFileId($id);
foreach ($shares as $share) {
// propagate down the share tree
$this->markDirty($share, microtime(true));
// propagate up the share tree
$user = $share['uid_owner'];
if($user !== $this->userId) {
if ($share['share_with'] === $this->userId) {
$user = $share['uid_owner'];
$view = new View('/' . $user . '/files');
$path = $view->getPath($share['file_source']);
$watcher = new ChangeWatcher($view, $this->manager->getSharePropagator($user));
$watcher->writeHook(['path' => $path]);
}
}
unset($this->propagatingIds[$id]);
}
}

View File

@@ -206,27 +206,15 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent {
/**
* @param string $target
* @param string $mountPoint
* @param string $itemType
* @param array $share
* @return array|false source item
*/
public static function getSource($target, $mountPoint, $itemType) {
if ($itemType === 'folder') {
$source = \OCP\Share::getItemSharedWith('folder', $mountPoint, \OC_Share_Backend_File::FORMAT_SHARED_STORAGE);
if ($source && $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);
public static function getSource($target, $share) {
if ($share['item_type'] === 'folder' && $target !== '') {
// note: in case of ext storage mount points the path might be empty
// which would cause a leading slash to appear
$share['path'] = ltrim($share['path'] . '/' . $target, '/');
}
if ($source) {
return self::resolveReshares($source);
}
\OCP\Util::writeLog('files_sharing', 'File source not found for: '.$target, \OCP\Util::DEBUG);
return false;
return self::resolveReshares($share);
}
}

View File

@@ -41,35 +41,47 @@ class SharedMount extends MountPoint implements MoveableMount {
*/
protected $ownerPropagator;
/**
* @var \OC\Files\View
*/
private $recipientView;
/**
* @var string
*/
private $user;
public function __construct($storage, $mountpoint, $arguments = null, $loader = null) {
// first update the mount point before creating the parent
$this->ownerPropagator = $arguments['propagator'];
$newMountPoint = $this->verifyMountPoint($arguments['share'], $arguments['user']);
$absMountPoint = '/' . $arguments['user'] . '/files' . $newMountPoint;
$this->user = $arguments['user'];
$this->recipientView = new View('/' . $this->user . '/files');
$newMountPoint = $this->verifyMountPoint($arguments['share']);
$absMountPoint = '/' . $this->user . '/files' . $newMountPoint;
$arguments['ownerView'] = new View('/' . $arguments['share']['uid_owner'] . '/files');
parent::__construct($storage, $absMountPoint, $arguments, $loader);
}
/**
* check if the parent folder exists otherwise move the mount point up
*/
private function verifyMountPoint(&$share, $user) {
private function verifyMountPoint(&$share) {
$mountPoint = basename($share['file_target']);
$parent = dirname($share['file_target']);
$view = new View('/' . $user . '/files');
if (!$view->is_dir($parent)) {
if (!$this->recipientView->is_dir($parent)) {
$parent = Helper::getShareFolder();
}
$newMountPoint = \OCA\Files_Sharing\Helper::generateUniqueTarget(
\OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
array(),
new \OC\Files\View('/' . $user . '/files')
);
\OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
[],
$this->recipientView
);
if($newMountPoint !== $share['file_target']) {
self::updateFileTarget($newMountPoint, $share);
if ($newMountPoint !== $share['file_target']) {
$this->updateFileTarget($newMountPoint, $share);
$share['file_target'] = $newMountPoint;
$share['unique_name'] = true;
}
@@ -79,11 +91,12 @@ class SharedMount extends MountPoint implements MoveableMount {
/**
* update fileTarget in the database if the mount point changed
*
* @param string $newPath
* @param array $share reference to the share which should be modified
* @return bool
*/
private static function updateFileTarget($newPath, &$share) {
private function updateFileTarget($newPath, &$share) {
// if the user renames a mount point from a group share we need to create a new db entry
// for the unique name
if ($share['share_type'] === \OCP\Share::SHARE_TYPE_GROUP && empty($share['unique_name'])) {
@@ -91,7 +104,7 @@ class SharedMount extends MountPoint implements MoveableMount {
.' `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`,'
.' `file_target`, `token`, `parent`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)');
$arguments = array($share['item_type'], $share['item_source'], $share['item_target'],
2, \OCP\User::getUser(), $share['uid_owner'], $share['permissions'], $share['stime'], $share['file_source'],
2, $this->user, $share['uid_owner'], $share['permissions'], $share['stime'], $share['file_source'],
$newPath, $share['token'], $share['id']);
} else {
// rename mount point
@@ -99,7 +112,7 @@ class SharedMount extends MountPoint implements MoveableMount {
'Update `*PREFIX*share`
SET `file_target` = ?
WHERE `id` = ?'
);
);
$arguments = array($newPath, $share['id']);
}

View File

@@ -45,8 +45,18 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
private $files = array();
private static $isInitialized = array();
/**
* @var \OC\Files\View
*/
private $ownerView;
public function __construct($arguments) {
$this->share = $arguments['share'];
$this->ownerView = $arguments['ownerView'];
}
private function init() {
Filesystem::initMountPoints($this->share['uid_owner']);
}
/**
@@ -74,17 +84,18 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
* @return array Returns array with the keys path, permissions, and owner or false if not found
*/
public function getFile($target) {
$this->init();
if (!isset($this->files[$target])) {
// Check for partial files
if (pathinfo($target, PATHINFO_EXTENSION) === 'part') {
$source = \OC_Share_Backend_File::getSource(substr($target, 0, -5), $this->getMountPoint(), $this->getItemType());
$source = \OC_Share_Backend_File::getSource(substr($target, 0, -5), $this->getShare());
if ($source) {
$source['path'] .= '.part';
// All partial files have delete permission
$source['permissions'] |= \OCP\Constants::PERMISSION_DELETE;
}
} else {
$source = \OC_Share_Backend_File::getSource($target, $this->getMountPoint(), $this->getItemType());
$source = \OC_Share_Backend_File::getSource($target, $this->getShare());
}
$this->files[$target] = $source;
}
@@ -313,7 +324,7 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
}
public function rename($path1, $path2) {
$this->init();
// we need the paths relative to data/user/files
$relPath1 = $this->getMountPoint() . '/' . $path1;
$relPath2 = $this->getMountPoint() . '/' . $path2;
@@ -623,6 +634,11 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
/** @var \OCP\Files\Storage $targetStorage */
list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
$targetStorage->acquireLock($targetInternalPath, $type, $provider);
// lock the parent folders of the owner when locking the share as recipient
if ($path === '') {
$sourcePath = $this->ownerView->getPath($this->share['file_source']);
$this->ownerView->lockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
}
}
/**
@@ -634,6 +650,11 @@ class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
/** @var \OCP\Files\Storage $targetStorage */
list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
$targetStorage->releaseLock($targetInternalPath, $type, $provider);
// unlock the parent folders of the owner when unlocking the share as recipient
if ($path === '') {
$sourcePath = $this->ownerView->getPath($this->share['file_source']);
$this->ownerView->unlockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
}
}
/**

View File

@@ -25,6 +25,12 @@
$l = \OC::$server->getL10N('files_sharing');
$isIE8 = false;
preg_match('/MSIE (.*?);/', $_SERVER['HTTP_USER_AGENT'], $matches);
if (count($matches) > 0 && $matches[1] <= 9) {
$isIE8 = true;
}
$uid = \OC::$server->getUserSession()->getUser()->getUID();
$server = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
$cloudID = $uid . '@' . rtrim(\OCA\Files_Sharing\Helper::removeProtocolFromUrl($server), '/');
@@ -38,5 +44,6 @@ $tmpl->assign('message_without_URL', $l->t('Share with me through my #ownCloud F
$tmpl->assign('owncloud_logo_path', $ownCloudLogoPath);
$tmpl->assign('reference', $url);
$tmpl->assign('cloudId', $cloudID);
$tmpl->assign('showShareIT', !$isIE8);
return $tmpl->fetchPage();

View File

@@ -100,7 +100,7 @@ $thumbSize = 1024;
<div id="imgframe"></div>
<?php endif; ?>
<div class="directDownload">
<a href="<?php p($_['downloadURL']); ?>" id="download" class="button">
<a href="<?php p($_['downloadURL']); ?>" id="downloadFile" class="button">
<img class="svg" alt="" src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>"/>
<?php p($l->t('Download %s', array($_['filename'])))?> (<?php p($_['fileSize']) ?>)
</a>

View File

@@ -3,8 +3,10 @@
/** @var array $_ */
script('files_sharing', 'settings-personal');
style('files_sharing', 'settings-personal');
script('files_sharing', '3rdparty/gs-share/gs-share');
style('files_sharing', '3rdparty/gs-share/style');
if ($_['showShareIT']) {
script('files_sharing', '3rdparty/gs-share/gs-share');
style('files_sharing', '3rdparty/gs-share/style');
}
?>
<?php if ($_['outgoingServer2serverShareEnabled']): ?>
@@ -18,6 +20,7 @@ style('files_sharing', '3rdparty/gs-share/style');
<br>
<?php if ($_['showShareIT']) {?>
<p>
<?php p($l->t('Share it:')); ?>
<div class="gs-share">
@@ -68,6 +71,7 @@ style('files_sharing', '3rdparty/gs-share/style');
</a></xmp>
</p>
<?php } ?>
</div>
<?php endif; ?>

View File

@@ -78,7 +78,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkPassword() {
$map = [
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_enforce_links_password', 'yes', 'yes'],
['core', 'shareapi_enforce_links_password', 'no', 'yes'],
];
$result = $this->getResults($map);
$this->assertArrayHasKey('password', $result['public']);
@@ -89,7 +89,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkNoPassword() {
$map = [
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_enforce_links_password', 'yes', 'no'],
['core', 'shareapi_enforce_links_password', 'no', 'no'],
];
$result = $this->getResults($map);
$this->assertArrayHasKey('password', $result['public']);
@@ -100,7 +100,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkNoExpireDate() {
$map = [
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_default_expire_date', 'yes', 'no'],
['core', 'shareapi_default_expire_date', 'no', 'no'],
];
$result = $this->getResults($map);
$this->assertArrayHasKey('expire_date', $result['public']);
@@ -111,9 +111,9 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkExpireDate() {
$map = [
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_default_expire_date', 'yes', 'yes'],
['core', 'shareapi_default_expire_date', 'no', 'yes'],
['core', 'shareapi_expire_after_n_days', '7', '7'],
['core', 'shareapi_enforce_expire_date', 'yes', 'no'],
['core', 'shareapi_enforce_expire_date', 'no', 'no'],
];
$result = $this->getResults($map);
$this->assertArrayHasKey('expire_date', $result['public']);
@@ -126,8 +126,8 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkExpireDateEnforced() {
$map = [
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_default_expire_date', 'yes', 'yes'],
['core', 'shareapi_enforce_expire_date', 'yes', 'yes'],
['core', 'shareapi_default_expire_date', 'no', 'yes'],
['core', 'shareapi_enforce_expire_date', 'no', 'yes'],
];
$result = $this->getResults($map);
$this->assertArrayHasKey('expire_date', $result['public']);
@@ -138,7 +138,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkSendMail() {
$map = [
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_allow_public_notification', 'yes', 'yes'],
['core', 'shareapi_allow_public_notification', 'no', 'yes'],
];
$result = $this->getResults($map);
$this->assertTrue($result['public']['send_mail']);
@@ -147,7 +147,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testLinkNoSendMail() {
$map = [
['core', 'shareapi_allow_links', 'yes', 'yes'],
['core', 'shareapi_allow_public_notification', 'yes', 'no'],
['core', 'shareapi_allow_public_notification', 'no', 'no'],
];
$result = $this->getResults($map);
$this->assertFalse($result['public']['send_mail']);
@@ -155,7 +155,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testUserSendMail() {
$map = [
['core', 'shareapi_allow_mail_notification', 'yes', 'yes'],
['core', 'shareapi_allow_mail_notification', 'no', 'yes'],
];
$result = $this->getResults($map);
$this->assertTrue($result['user']['send_mail']);
@@ -163,7 +163,7 @@ class FilesSharingCapabilitiesTest extends \Test\TestCase {
public function testUserNoSendMail() {
$map = [
['core', 'shareapi_allow_mail_notification', 'yes', 'no'],
['core', 'shareapi_allow_mail_notification', 'no', 'no'],
];
$result = $this->getResults($map);
$this->assertFalse($result['user']['send_mail']);

View File

@@ -0,0 +1,89 @@
<?php
/**
* @author Lukas Reschke <lukas@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_Sharing\Controllers;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\Http\Client\IClientService;
use OCP\IRequest;
/**
* Class ExternalShareControllerTest
*
* @package OCA\Files_Sharing\Controllers
*/
class ExternalShareControllerTest extends \Test\TestCase {
/** @var IRequest */
private $request;
/** @var \OCA\Files_Sharing\External\Manager */
private $externalManager;
/** @var IClientService */
private $clientService;
public function setUp() {
$this->request = $this->getMockBuilder('\\OCP\\IRequest')
->disableOriginalConstructor()->getMock();
$this->externalManager = $this->getMockBuilder('\\OCA\\Files_Sharing\\External\\Manager')
->disableOriginalConstructor()->getMock();
$this->clientService = $this->getMockBuilder('\\OCP\Http\\Client\\IClientService')
->disableOriginalConstructor()->getMock();
}
/**
* @return ExternalSharesController
*/
public function getExternalShareController() {
return new ExternalSharesController(
'files_sharing',
$this->request,
$this->externalManager,
$this->clientService
);
}
public function testIndex() {
$this->externalManager
->expects($this->once())
->method('getOpenShares')
->will($this->returnValue(['MyDummyArray']));
$this->assertEquals(new JSONResponse(['MyDummyArray']), $this->getExternalShareController()->index());
}
public function testCreate() {
$this->externalManager
->expects($this->once())
->method('acceptShare')
->with(4);
$this->assertEquals(new JSONResponse(), $this->getExternalShareController()->create(4));
}
public function testDestroy() {
$this->externalManager
->expects($this->once())
->method('declineShare')
->with(4);
$this->assertEquals(new JSONResponse(), $this->getExternalShareController()->destroy(4));
}
}

View File

@@ -266,15 +266,15 @@ class EtagPropagation extends TestCase {
\OCP\Share::unshare(
'folder',
$folderId,
\OCP\Share::SHARE_TYPE_USER,
\OCP\Share::SHARE_TYPE_USER,
self::TEST_FILES_SHARING_API_USER2
)
);
$this->assertEtagsForFoldersChanged([
// direct recipient affected
self::TEST_FILES_SHARING_API_USER2,
self::TEST_FILES_SHARING_API_USER2,
// reshare recipient affected
self::TEST_FILES_SHARING_API_USER4,
self::TEST_FILES_SHARING_API_USER4,
]);
$this->assertAllUnchaged();
@@ -287,9 +287,9 @@ class EtagPropagation extends TestCase {
);
$this->assertEtagsForFoldersChanged([
// direct recipient affected
self::TEST_FILES_SHARING_API_USER2,
self::TEST_FILES_SHARING_API_USER2,
// reshare recipient affected
self::TEST_FILES_SHARING_API_USER4,
self::TEST_FILES_SHARING_API_USER4,
]);
$this->assertAllUnchaged();
@@ -398,4 +398,13 @@ class EtagPropagation extends TestCase {
$this->assertAllUnchaged();
}
public function testRecipientUploadInDirectReshare() {
$this->loginAsUser(self::TEST_FILES_SHARING_API_USER2);
Filesystem::file_put_contents('/directReshare/test.txt', 'sad');
$this->assertEtagsNotChanged([self::TEST_FILES_SHARING_API_USER3]);
$this->assertEtagsChanged([self::TEST_FILES_SHARING_API_USER1, self::TEST_FILES_SHARING_API_USER2, self::TEST_FILES_SHARING_API_USER4]);
$this->assertAllUnchaged();
}
}

View File

@@ -0,0 +1,82 @@
<?php
/**
* @author Joas Schilling <nickvergessen@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_Sharing\Tests\External;
use OCA\Files_Sharing\External\Scanner;
use Test\TestCase;
class ScannerTest extends TestCase {
/** @var \OCA\Files_Sharing\External\Scanner */
protected $scanner;
/** @var \OCA\Files_Sharing\External\Storage|\PHPUnit_Framework_MockObject_MockObject */
protected $storage;
/** @var \OC\Files\Cache\Cache|\PHPUnit_Framework_MockObject_MockObject */
protected $cache;
protected function setUp() {
parent::setUp();
$this->storage = $this->getMockBuilder('\OCA\Files_Sharing\External\Storage')
->disableOriginalConstructor()
->getMock();
$this->cache = $this->getMockBuilder('\OC\Files\Cache\Cache')
->disableOriginalConstructor()
->getMock();
$this->storage->expects($this->any())
->method('getCache')
->willReturn($this->cache);
$this->scanner = new Scanner($this->storage);
}
public function testScanAll() {
$this->storage->expects($this->any())
->method('getShareInfo')
->willReturn(['status' => 'success', 'data' => []]);
// FIXME add real tests, we are currently only checking for
// Declaration of OCA\Files_Sharing\External\Scanner::*() should be
// compatible with OC\Files\Cache\Scanner::*()
$this->scanner->scanAll();
$this->assertTrue(true);
}
public function testScan() {
$this->storage->expects($this->any())
->method('getShareInfo')
->willReturn(['status' => 'success', 'data' => []]);
// FIXME add real tests, we are currently only checking for
// Declaration of OCA\Files_Sharing\External\Scanner::*() should be
// compatible with OC\Files\Cache\Scanner::*()
$this->scanner->scan('test', Scanner::SCAN_RECURSIVE);
$this->assertTrue(true);
}
public function testScanFile() {
// FIXME add real tests, we are currently only checking for
// Declaration of OCA\Files_Sharing\External\Scanner::*() should be
// compatible with OC\Files\Cache\Scanner::*()
$this->scanner->scanFile('test', Scanner::SCAN_RECURSIVE);
$this->assertTrue(true);
}
}

View File

@@ -206,6 +206,23 @@ describe('OCA.Sharing.Util tests', function() {
expect(OC.basename(getImageUrl($tr.find('.filename .thumbnail')))).toEqual('folder-shared.svg');
expect($action.find('img').length).toEqual(1);
});
it('do not show static share text when share exists but neither permission nor owner is available', function() {
var $action, $tr;
fileList.setFiles([{
id: 1,
type: 'dir',
name: 'One',
path: '/subdir',
mimetype: 'text/plain',
size: 12,
permissions: OC.PERMISSION_CREATE,
etag: 'abc'
}]);
$tr = fileList.$el.find('tbody tr:first');
expect($tr.find('.action-share').length).toEqual(0);
$action = $tr.find('.action-share-notification');
expect($action.length).toEqual(0);
});
});
describe('Share action', function() {
var showDropDownStub;

View File

@@ -0,0 +1,101 @@
<?php
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Vincent Petry <pvince81@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\Files_sharing\Tests;
use OC\Files\Filesystem;
use OC\Files\View;
use OC\Lock\MemcacheLockingProvider;
use OCP\Lock\ILockingProvider;
class Locking extends TestCase {
/**
* @var \OC_User_Dummy
*/
private $userBackend;
private $ownerUid;
private $recipientUid;
public function setUp() {
parent::setUp();
$this->userBackend = new \OC_User_Dummy();
\OC::$server->getUserManager()->registerBackend($this->userBackend);
$this->ownerUid = $this->getUniqueID('owner_');
$this->recipientUid = $this->getUniqueID('recipient_');
$this->userBackend->createUser($this->ownerUid, '');
$this->userBackend->createUser($this->recipientUid, '');
$this->loginAsUser($this->ownerUid);
Filesystem::mkdir('/foo');
Filesystem::file_put_contents('/foo/bar.txt', 'asd');
$fileId = Filesystem::getFileInfo('/foo/bar.txt')->getId();
\OCP\Share::shareItem('file', $fileId, \OCP\Share::SHARE_TYPE_USER, $this->recipientUid, 31);
$this->loginAsUser($this->recipientUid);
$this->assertTrue(Filesystem::file_exists('bar.txt'));
}
public function tearDown() {
\OC::$server->getUserManager()->removeBackend($this->userBackend);
parent::tearDown();
}
/**
* @expectedException \OCP\Lock\LockedException
*/
public function testLockAsRecipient() {
$this->loginAsUser($this->ownerUid);
Filesystem::initMountPoints($this->recipientUid);
$recipientView = new View('/' . $this->recipientUid . '/files');
$recipientView->lockFile('bar.txt', ILockingProvider::LOCK_EXCLUSIVE);
Filesystem::rename('/foo', '/asd');
}
public function testUnLockAsRecipient() {
$this->loginAsUser($this->ownerUid);
Filesystem::initMountPoints($this->recipientUid);
$recipientView = new View('/' . $this->recipientUid . '/files');
$recipientView->lockFile('bar.txt', ILockingProvider::LOCK_EXCLUSIVE);
$recipientView->unlockFile('bar.txt', ILockingProvider::LOCK_EXCLUSIVE);
$this->assertTrue(Filesystem::rename('/foo', '/asd'));
}
public function testChangeLock() {
Filesystem::initMountPoints($this->recipientUid);
$recipientView = new View('/' . $this->recipientUid . '/files');
$recipientView->lockFile('bar.txt', ILockingProvider::LOCK_SHARED);
$recipientView->changeLock('bar.txt', ILockingProvider::LOCK_EXCLUSIVE);
$recipientView->unlockFile('bar.txt', ILockingProvider::LOCK_EXCLUSIVE);
$this->assertTrue(true);
}
}

View File

@@ -23,7 +23,11 @@
*/
namespace OCA\Files_Sharing\Middleware;
use OCP\AppFramework\Http\NotFoundResponse;
use OCP\Files\NotFoundException;
use OCP\AppFramework\Utility\IControllerMethodReflector;
use OCA\Files_Sharing\Exceptions\S2SException;
use OCP\AppFramework\Http\JSONResponse;
/**
* @package OCA\Files_Sharing\Middleware\SharingCheckMiddleware
@@ -36,29 +40,35 @@ class SharingCheckMiddlewareTest extends \Test\TestCase {
private $appManager;
/** @var SharingCheckMiddleware */
private $sharingCheckMiddleware;
/** @var \OCP\AppFramework\Controller */
private $controllerMock;
/** @var IControllerMethodReflector */
private $reflector;
protected function setUp() {
$this->config = $this->getMockBuilder('\OCP\IConfig')
->disableOriginalConstructor()->getMock();
$this->appManager = $this->getMockBuilder('\OCP\App\IAppManager')
->disableOriginalConstructor()->getMock();
$this->controllerMock = $this->getMockBuilder('\OCP\AppFramework\Controller')
->disableOriginalConstructor()->getMock();
$this->reflector = $this->getMockBuilder('\OCP\AppFramework\Utility\IControllerMethodReflector')
->disableOriginalConstructor()->getMock();
$this->sharingCheckMiddleware = new SharingCheckMiddleware('files_sharing', $this->config, $this->appManager);
$this->sharingCheckMiddleware = new SharingCheckMiddleware(
'files_sharing',
$this->config,
$this->appManager,
$this->reflector);
}
public function testIsSharingEnabledWithEverythingEnabled() {
public function testIsSharingEnabledWithAppEnabled() {
$this->appManager
->expects($this->once())
->method('isEnabledForUser')
->with('files_sharing')
->will($this->returnValue(true));
$this->config
->expects($this->once())
->method('getAppValue')
->with('core', 'shareapi_allow_links', 'yes')
->will($this->returnValue('yes'));
$this->assertTrue(self::invokePrivate($this->sharingCheckMiddleware, 'isSharingEnabled'));
}
@@ -72,7 +82,136 @@ class SharingCheckMiddlewareTest extends \Test\TestCase {
$this->assertFalse(self::invokePrivate($this->sharingCheckMiddleware, 'isSharingEnabled'));
}
public function testIsSharingEnabledWithSharingDisabled() {
public function testIsLinkSharingEnabledWithEverythinEnabled() {
$this->config
->expects($this->at(0))
->method('getAppValue')
->with('core', 'shareapi_enabled', 'yes')
->will($this->returnValue('yes'));
$this->config
->expects($this->at(1))
->method('getAppValue')
->with('core', 'shareapi_allow_links', 'yes')
->will($this->returnValue('yes'));
$this->assertTrue(self::invokePrivate($this->sharingCheckMiddleware, 'isLinkSharingEnabled'));
}
public function testIsLinkSharingEnabledWithLinkSharingDisabled() {
$this->config
->expects($this->at(0))
->method('getAppValue')
->with('core', 'shareapi_enabled', 'yes')
->will($this->returnValue('yes'));
$this->config
->expects($this->at(1))
->method('getAppValue')
->with('core', 'shareapi_allow_links', 'yes')
->will($this->returnValue('no'));
$this->assertFalse(self::invokePrivate($this->sharingCheckMiddleware, 'isLinkSharingEnabled'));
}
public function testIsLinkSharingEnabledWithSharingAPIDisabled() {
$this->config
->expects($this->once())
->method('getAppValue')
->with('core', 'shareapi_enabled', 'yes')
->will($this->returnValue('no'));
$this->assertFalse(self::invokePrivate($this->sharingCheckMiddleware, 'isLinkSharingEnabled'));
}
public function externalSharesChecksDataProvider() {
$data = [];
foreach ([false, true] as $annIn) {
foreach ([false, true] as $annOut) {
foreach ([false, true] as $confIn) {
foreach ([false, true] as $confOut) {
$res = true;
if (!$annIn && !$confIn) {
$res = false;
} elseif (!$annOut && !$confOut) {
$res = false;
}
$d = [
[
['NoIncomingFederatedSharingRequired', $annIn],
['NoOutgoingFederatedSharingRequired', $annOut],
],
[
['files_sharing', 'incoming_server2server_share_enabled', 'yes', $confIn ? 'yes' : 'no'],
['files_sharing', 'outgoing_server2server_share_enabled', 'yes', $confOut ? 'yes' : 'no'],
],
$res
];
$data[] = $d;
}
}
}
}
return $data;
}
/**
* @dataProvider externalSharesChecksDataProvider
*/
public function testExternalSharesChecks($annotations, $config, $expectedResult) {
$this->reflector
->expects($this->atLeastOnce())
->method('hasAnnotation')
->will($this->returnValueMap($annotations));
$this->config
->method('getAppValue')
->will($this->returnValueMap($config));
$this->assertEquals($expectedResult, self::invokePrivate($this->sharingCheckMiddleware, 'externalSharesChecks'));
}
/**
* @dataProvider externalSharesChecksDataProvider
*/
public function testBeforeControllerWithExternalShareControllerWithSharingEnabled($annotations, $config, $noException) {
$this->appManager
->expects($this->once())
->method('isEnabledForUser')
->with('files_sharing')
->will($this->returnValue(true));
$this->reflector
->expects($this->atLeastOnce())
->method('hasAnnotation')
->will($this->returnValueMap($annotations));
$this->config
->method('getAppValue')
->will($this->returnValueMap($config));
$controller = $this->getMockBuilder('\OCA\Files_Sharing\Controllers\ExternalSharesController')
->disableOriginalConstructor()->getMock();
$exceptionThrown = false;
try {
$this->sharingCheckMiddleware->beforeController($controller, 'myMethod');
} catch (\OCA\Files_Sharing\Exceptions\S2SException $exception) {
$exceptionThrown = true;
}
$this->assertNotEquals($noException, $exceptionThrown);
}
public function testBeforeControllerWithShareControllerWithSharingEnabled() {
$this->appManager
->expects($this->once())
->method('isEnabledForUser')
@@ -80,11 +219,69 @@ class SharingCheckMiddlewareTest extends \Test\TestCase {
->will($this->returnValue(true));
$this->config
->expects($this->once())
->expects($this->at(0))
->method('getAppValue')
->with('core', 'shareapi_enabled', 'yes')
->will($this->returnValue('yes'));
$this->config
->expects($this->at(1))
->method('getAppValue')
->with('core', 'shareapi_allow_links', 'yes')
->will($this->returnValue('no'));
->will($this->returnValue('yes'));
$this->assertFalse(self::invokePrivate($this->sharingCheckMiddleware, 'isSharingEnabled'));
$controller = $this->getMockBuilder('\OCA\Files_Sharing\Controllers\ShareController')
->disableOriginalConstructor()->getMock();
$this->sharingCheckMiddleware->beforeController($controller, 'myMethod');
}
/**
* @expectedException \OCP\Files\NotFoundException
* @expectedExceptionMessage Link sharing is disabled
*/
public function testBeforeControllerWithShareControllerWithSharingEnabledAPIDisabled() {
$this->appManager
->expects($this->once())
->method('isEnabledForUser')
->with('files_sharing')
->will($this->returnValue(true));
$controller = $this->getMockBuilder('\OCA\Files_Sharing\Controllers\ShareController')
->disableOriginalConstructor()->getMock();
$this->sharingCheckMiddleware->beforeController($controller, 'myMethod');
}
/**
* @expectedException \OCP\Files\NotFoundException
* @expectedExceptionMessage Sharing is disabled.
*/
public function testBeforeControllerWithSharingDisabled() {
$this->appManager
->expects($this->once())
->method('isEnabledForUser')
->with('files_sharing')
->will($this->returnValue(false));
$this->sharingCheckMiddleware->beforeController($this->controllerMock, 'myMethod');
}
/**
* @expectedException \Exception
* @expectedExceptionMessage My Exception message
*/
public function testAfterExceptionWithRegularException() {
$this->sharingCheckMiddleware->afterException($this->controllerMock, 'myMethod', new \Exception('My Exception message'));
}
public function testAfterExceptionWithNotFoundException() {
$this->assertEquals(new NotFoundResponse(), $this->sharingCheckMiddleware->afterException($this->controllerMock, 'myMethod', new NotFoundException('My Exception message')));
}
public function testAfterExceptionWithS2SException() {
$this->assertEquals(new JSONResponse('My Exception message', 405), $this->sharingCheckMiddleware->afterException($this->controllerMock, 'myMethod', new S2SException('My Exception message')));
}
}

View File

@@ -321,4 +321,134 @@ class Test_Files_Sharing extends OCA\Files_sharing\Tests\TestCase {
);
}
/**
* @dataProvider dataProviderGetUsersSharingFile
*
* @param string $groupName name of group to share with
* @param bool $includeOwner whether to include the owner in the result
* @param bool $includePaths whether to include paths in the result
* @param array $expectedResult expected result of the API call
*/
function testGetUsersSharingFile($groupName, $includeOwner, $includePaths, $expectedResult) {
$fileinfo = $this->view->getFileInfo($this->folder);
$result = \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_GROUP,
$groupName, \OCP\Constants::PERMISSION_READ);
$this->assertTrue($result);
// public share
$result = \OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_LINK,
null, \OCP\Constants::PERMISSION_READ);
$this->assertNotNull($result); // returns the token!
// owner renames after sharing
$this->view->rename($this->folder, $this->folder . '_owner_renamed');
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$user2View = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
$user2View->rename($this->folder, $this->folder . '_renamed');
$ownerPath = $this->folder . '_owner_renamed';
$owner = self::TEST_FILES_SHARING_API_USER1;
$result = \OCP\Share::getUsersSharingFile($ownerPath, $owner, $includeOwner, $includePaths);
// sort users to make sure it matches
if ($includePaths) {
ksort($result);
} else {
sort($result['users']);
}
$this->assertEquals(
$expectedResult,
$result
);
}
function dataProviderGetUsersSharingFile() {
// note: "group" contains user1 (the owner), user2 and user3
// and self::TEST_FILES_SHARING_API_GROUP1 contains only user2
return [
// share with group that contains owner
[
'group',
false,
false,
[
'users' =>
[
// because user1 was in group
self::TEST_FILES_SHARING_API_USER1,
self::TEST_FILES_SHARING_API_USER2,
self::TEST_FILES_SHARING_API_USER3,
],
'public' => true,
'remote' => false,
],
],
// share with group that does not contain owner
[
self::TEST_FILES_SHARING_API_GROUP1,
false,
false,
[
'users' =>
[
self::TEST_FILES_SHARING_API_USER2,
],
'public' => true,
'remote' => false,
],
],
// share with group that does not contain owner, include owner
[
self::TEST_FILES_SHARING_API_GROUP1,
true,
false,
[
'users' =>
[
self::TEST_FILES_SHARING_API_USER1,
self::TEST_FILES_SHARING_API_USER2,
],
'public' => true,
'remote' => false,
],
],
// include paths, with owner
[
'group',
true,
true,
[
self::TEST_FILES_SHARING_API_USER1 => self::TEST_FOLDER_NAME . '_owner_renamed',
self::TEST_FILES_SHARING_API_USER2 => self::TEST_FOLDER_NAME . '_renamed',
self::TEST_FILES_SHARING_API_USER3 => self::TEST_FOLDER_NAME,
],
],
// include paths, group without owner
[
self::TEST_FILES_SHARING_API_GROUP1,
false,
true,
[
self::TEST_FILES_SHARING_API_USER2 => self::TEST_FOLDER_NAME. '_renamed',
],
],
// include paths, include owner, group without owner
[
self::TEST_FILES_SHARING_API_GROUP1,
true,
true,
[
self::TEST_FILES_SHARING_API_USER1 => self::TEST_FOLDER_NAME . '_owner_renamed',
self::TEST_FILES_SHARING_API_USER2 => self::TEST_FOLDER_NAME . '_renamed',
],
],
];
}
}

View File

@@ -441,4 +441,43 @@ class Test_Files_Sharing_Storage extends OCA\Files_sharing\Tests\TestCase {
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$this->view->unlink($this->folder);
}
public function testNameConflict() {
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$view1 = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER1 . '/files');
$view1->mkdir('foo');
$folderInfo1 = $view1->getFileInfo('foo');
self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
$view3 = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER3 . '/files');
$view3->mkdir('foo');
$folderInfo2 = $view3->getFileInfo('foo');
// share a folder with the same name from two different users to the same user
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
\OCP\Share::shareItem('folder', $folderInfo1['fileid'], \OCP\Share::SHARE_TYPE_GROUP,
self::TEST_FILES_SHARING_API_GROUP1, 31);
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
\OCP\Share::shareItem('folder', $folderInfo2['fileid'], \OCP\Share::SHARE_TYPE_GROUP,
self::TEST_FILES_SHARING_API_GROUP1, 31);
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$view2 = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2 . '/files');
$this->assertTrue($view2->file_exists('/foo'));
$this->assertTrue($view2->file_exists('/foo (2)'));
$mount = $view2->getMount('/foo');
$this->assertInstanceOf('\OCA\Files_Sharing\SharedMount', $mount);
/** @var \OC\Files\Storage\Shared $storage */
$storage = $mount->getStorage();
$source = $storage->getFile('');
$this->assertEquals(self::TEST_FILES_SHARING_API_USER1, $source['uid_owner']);
}
}

View File

@@ -40,7 +40,7 @@ class UnshareChildren extends TestCase {
\OCP\Util::connectHook('OC_Filesystem', 'post_delete', '\OCA\Files_Sharing\Hooks', 'unshareChildren');
$this->folder = self::TEST_FOLDER_NAME;
$this->subfolder = '/subfolder_share_api_test';
$this->subfolder = '/subfolder_share_api_test';
$this->subsubfolder = '/subsubfolder_share_api_test';
$this->filename = '/share-api-test';
@@ -49,12 +49,14 @@ class UnshareChildren extends TestCase {
$this->view->mkdir($this->folder);
$this->view->mkdir($this->folder . $this->subfolder);
$this->view->mkdir($this->folder . $this->subfolder . $this->subsubfolder);
$this->view->file_put_contents($this->folder.$this->filename, $this->data);
$this->view->file_put_contents($this->folder . $this->filename, $this->data);
$this->view->file_put_contents($this->folder . $this->subfolder . $this->filename, $this->data);
}
protected function tearDown() {
$this->view->deleteAll($this->folder);
if ($this->view) {
$this->view->deleteAll($this->folder);
}
self::$tempStorage = null;

View File

@@ -18,5 +18,4 @@ To prevent a user from running out of disk space, the ownCloud Deleted files app
<documentation>
<user>user-trashbin</user>
</documentation>
<ocsid>166052</ocsid>
</info>

View File

@@ -1 +1 @@
0.6.2
0.6.3

View File

@@ -26,6 +26,7 @@ namespace OCA\Files_Trashbin;
use OC\Files\Filesystem;
use OC\Files\Storage\Wrapper\Wrapper;
use OCP\IUserManager;
class Storage extends Wrapper {
@@ -41,8 +42,12 @@ class Storage extends Wrapper {
*/
private static $disableTrash = false;
function __construct($parameters) {
/** @var IUserManager */
private $userManager;
function __construct($parameters, IUserManager $userManager = null) {
$this->mountPoint = $parameters['mountPoint'];
$this->userManager = $userManager;
parent::__construct($parameters);
}
@@ -100,6 +105,27 @@ class Storage extends Wrapper {
return $this->doDelete($path, 'rmdir');
}
/**
* check if it is a file located in data/user/files only files in the
* 'files' directory should be moved to the trash
*
* @param $path
* @return bool
*/
protected function shouldMoveToTrash($path){
$normalized = Filesystem::normalizePath($this->mountPoint . '/' . $path);
$parts = explode('/', $normalized);
if (count($parts) < 4) {
return false;
}
if ($this->userManager->userExists($parts[1]) && $parts[2] == 'files') {
return true;
}
return false;
}
/**
* Run the delete operation with the given method
*
@@ -112,6 +138,7 @@ class Storage extends Wrapper {
if (self::$disableTrash
|| !\OC_App::isEnabled('files_trashbin')
|| (pathinfo($path, PATHINFO_EXTENSION) === 'part')
|| $this->shouldMoveToTrash($path) === false
) {
return call_user_func_array([$this->storage, $method], [$path]);
}
@@ -144,7 +171,10 @@ class Storage extends Wrapper {
*/
public static function setupStorage() {
\OC\Files\Filesystem::addStorageWrapper('oc_trashbin', function ($mountPoint, $storage) {
return new \OCA\Files_Trashbin\Storage(array('storage' => $storage, 'mountPoint' => $mountPoint));
return new \OCA\Files_Trashbin\Storage(
array('storage' => $storage, 'mountPoint' => $mountPoint),
\OC::$server->getUserManager()
);
}, 1);
}

View File

@@ -493,4 +493,34 @@ class Storage extends \Test\TestCase {
$results = $this->rootView->getDirectoryContent($this->user . '/files_trashbin/files/');
$this->assertEquals(0, count($results));
}
/**
* @dataProvider dataTestShouldMoveToTrash
*/
public function testShouldMoveToTrash($mountPoint, $path, $userExists, $expected) {
$tmpStorage = $this->getMockBuilder('\OC\Files\Storage\Temporary')
->disableOriginalConstructor()->getMock();
$userManager = $this->getMockBuilder('OCP\IUserManager')
->disableOriginalConstructor()->getMock();
$userManager->expects($this->any())
->method('userExists')->willReturn($userExists);
$storage = new \OCA\Files_Trashbin\Storage(
['mountPoint' => $mountPoint, 'storage' => $tmpStorage],
$userManager
);
$this->assertSame($expected,
$this->invokePrivate($storage, 'shouldMoveToTrash', [$path])
);
}
public function dataTestShouldMoveToTrash() {
return [
['/schiesbn/', '/files/test.txt', true, true],
['/schiesbn/', '/files/test.txt', false, false],
['/schiesbn/', '/test.txt', true, false],
['/schiesbn/', '/test.txt', false, false],
];
}
}

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