Compare commits

...

635 Commits

Author SHA1 Message Date
Frank Karlitschek
508d84dcd8 6.0.4 beta 1 2014-06-17 08:48:46 +02:00
blizzz
659a3d4a37 Merge pull request #8623 from owncloud/fix-8457
LDAP: fix possible infinite loop, that causes hanging wizard, fixes #8457
2014-06-16 17:42:46 +02:00
Lukas Reschke
3d26896431 Merge pull request #9033 from owncloud/validate-dire
Add deprecation notice to load* functions
2014-06-16 16:20:21 +02:00
Vincent Petry
f6c970e214 Merge pull request #9008 from owncloud/repair-parent-stable6
Repair broken parent link in the scanner - stable6
2014-06-16 15:00:22 +02:00
Robin Appelman
84222e30a7 Fix unit test 2014-06-16 13:37:08 +02:00
Lukas Reschke
81fc7cfb21 Add deprecation notice to load* functions
This functions are deprecated and/or removed since ownCloud 7. Additionally a issubdirectory check has been added here to prevent developers to use this function in a potentially insecure way.

Please review @karlitschek and others. Backport to stable5 and master requested.
2014-06-14 11:05:12 +02:00
Morris Jobke
04817fb0f3 Merge pull request #9015 from owncloud/stable6-downloadwithdisabledzip
[stable6] Fix public download link when zip download is disabled
2014-06-13 13:09:41 +02:00
Vincent Petry
bca536eb3d Merge pull request #8988 from owncloud/stable6_fix_encryption
Stable6 fix encryption
2014-06-13 10:31:18 +02:00
Morris Jobke
64534546be Merge pull request #9016 from owncloud/stable6-maxheartbeatinterval
[stable6] Added max heartbeat interval to prevent integer overflow
2014-06-13 00:19:36 +02:00
Vincent Petry
00ec5fc193 Added max heartbeat interval to prevent integer overflow
When using big session timeout values, the interval value might overflow
and cause the setInterval() call to ping the server in a loop without
any delay.

This fix adds a maximum ping interval of 24 hours.
2014-06-12 18:27:21 +02:00
Vincent Petry
8ef1542ad0 Fix public download link when zip download is disabled
When zip download is disabled, the public download action defined in
public.js is overridden by the one in fileactions.js because of the JS
loading order.

This quick fix prevents the override to happen when a download action is
already defined.

There are additional changes that were required to make the download
action icon work when registered from the public page.
2014-06-12 17:29:55 +02:00
Robin Appelman
eeca726d28 remove unused argument 2014-06-12 15:07:05 +02:00
Robin Appelman
e793a87954 add some comments 2014-06-12 15:06:01 +02:00
Robin Appelman
6e0a218d11 Repair broken parent link in the scanner 2014-06-12 15:05:45 +02:00
Jörn Friedrich Dreyer
b2fae8a8b7 Fix copy conflict dialog translation
backport of fileexist template translations
with minor fixes
2014-06-11 20:25:10 +02:00
Bjoern Schiessle
193d237b56 fix rename of encryption keys 2014-06-11 18:38:20 +02:00
Vincent Petry
4bc091965f Merge pull request #8970 from owncloud/cache-change-propagator-stable6
Cache change propagator stable6
2014-06-10 17:17:35 +02:00
Robin Appelman
3ea94a7930 Fix unit tests 2014-06-10 16:32:46 +02:00
Robin Appelman
129bfad204 Fix size calculation during recursive scan 2014-06-10 16:24:08 +02:00
Robin Appelman
4d7e1c568c Fix unit tests 2014-06-10 16:24:00 +02:00
Robin Appelman
f36e354a42 Fix recursive scanning 2014-06-10 16:20:59 +02:00
Robin Appelman
81f6e78c0c propagate changes in the scanner 2014-06-10 16:20:51 +02:00
Robin Appelman
a543f46699 Split of cache writes in the scanner to their own methods 2014-06-10 16:20:48 +02:00
Robin Appelman
2895261102 Add a change propagator class to handle propagating etag and mtime changes 2014-06-10 16:16:46 +02:00
Thomas Müller
2911906586 Merge pull request #8885 from owncloud/flock-stable6
[stable6][WIP] Move Flock basics into stable6
2014-06-06 17:58:08 +02:00
Thomas Müller
909913d581 fix failing unit test 2014-06-06 15:48:02 +02:00
Jan-Christoph Borchardt
edced60ed4 keep long file names in one line to not overflow download button on mobile 2014-06-06 15:35:12 +02:00
Jan-Christoph Borchardt
45d165405f add max-width to directLink input to prevent overflow 2014-06-06 15:34:36 +02:00
Robin Appelman
e98627d6ab Dont backport unit tests for code that isn't backported 2014-06-05 16:48:04 +02:00
Thomas Müller
a4c422a6da added missing LockNotAcquiredException 2014-06-05 16:48:03 +02:00
ringmaster
6ec29711fc Continued flock work.
add actual locking and log changes necessary for debugging.

Simpler log unique id.

Respect locked files, surface correct exception.

Conflicts:
	lib/private/connector/sabre/file.php

Remove unused methods.

Conflicts:
	lib/private/files/storage/local.php

Fix typo

Fix typo

Removed unused vars/declarations, update PHPDoc.

Don't error out on console.

Move Lock to private namespace, add interface. Update PHPDoc.

Restore the reference to this used exception class.

make sure to close the stream at the end of each test

Normalize lock exception messages.

don't ask for fileInfo if we already have one

Conflicts:
	apps/files_encryption/lib/proxy.php

name the storage wrapper to make sure that we don't apply the wrapper multiple times

Conflicts:
	lib/private/util.php

fix unit test after adding the additional parameter to addStorageWrapper()

only lock if unlink is called for a file

Can't use assertInstanceOf on wrapped storage; use assertTrue(instanceOfStorage() instead.

Conflicts:
	tests/lib/files/filesystem.php

Use ->instanceOfStorage() not instanceof for Storage instances.

Conflicts:
	lib/private/helper.php

get the storage from the view

Conflicts:
	apps/files_encryption/tests/webdav.php

workaround to get the unit test going

Conflicts:
	apps/files_encryption/hooks/hooks.php

Added isLocal() method to storage, used for xsendfile

Added isLocal() method to Storage to find out whether the storage is
local or not.
This method is used for the x-sendfile logic to find out whether to add
the headers.

Conflicts:
	lib/private/files.php

Add ->instanceOfStorage to handle instanceof for storage wrappers

Conflicts:
	lib/private/files/storage/common.php
	lib/private/files/storage/wrapper/wrapper.php
	lib/public/files/storage.php

Use instanceOfStorage instead of instanceof

Conflicts:
	lib/private/files.php

Fix storage wrapper being called with null

Pass any methods custom to specific storage implementations to the wrapped storage

remove duplicate declaration of isLocal()

remove file locking - code will continue to live in it's own app
2014-06-05 16:47:37 +02:00
Vincent Petry
49f2955119 Merge pull request #8870 from owncloud/storage-instanceof-stable6
Add storage->instanceOfStorage() - stable6
2014-06-05 11:16:08 +02:00
Robin Appelman
b62ba9808a Pass any methods custom to specific storage implementations to the wrapped storage 2014-06-04 14:30:40 +02:00
Robin Appelman
f814b9a23c Fix storage wrapper being called with null 2014-06-04 14:30:17 +02:00
Robin Appelman
b3c8b574df Use instanceOfStorage instead of instanceof 2014-06-04 14:29:55 +02:00
Robin Appelman
79b953a920 Add ->instanceOfStorage to handle instanceof for storage wrappers 2014-06-04 14:17:52 +02:00
Thomas Müller
d3445d9668 Merge pull request #8847 from owncloud/stable6_backport_8557
Stable6 backport of #8557
2014-06-04 10:26:59 +02:00
Thomas Müller
e5dcec75ba Merge pull request #8850 from owncloud/stable6_backport_8607
[backport] [stable6] Skip filescan but execute hooks
2014-06-04 09:34:39 +02:00
ringmaster
a908e281e7 [backport] [stable6] Skip filescan but execute hooks
Backport of #8607
2014-06-03 10:52:12 -04:00
ringmaster
2910486979 Allow apps to create custom session handlers. 2014-06-03 10:20:42 -04:00
blizzz
58b6b89ec4 Merge pull request #8579 from owncloud/ldap_nail_filter_on_upgrade
LDAP: fix filter can be reset and broken after upgrade from OC 5
2014-06-02 12:02:15 +02:00
Frank Karlitschek
8758b66fc4 Merge pull request #8672 from owncloud/stable6-obfuscatepasswords
[backport] [stable6] Added password obfuscation for external storage config
2014-06-02 11:56:36 +02:00
Thomas Müller
8429dde4d9 Merge pull request #8692 from owncloud/fix_unit_tests_oc6
fix failing unit tests on OC6
2014-05-28 17:44:40 +02:00
Arthur Schiwon
37ef48d9f4 simpler and better readable assignment 2014-05-28 17:24:04 +02:00
Thomas Müller
776d656ea9 Merge pull request #8683 from owncloud/log-upload-error-stable6
Log upload error stable6
2014-05-28 13:07:18 +02:00
Thomas Müller
d17335d7a8 fix expectation - same as in master 2014-05-27 23:44:09 +02:00
Jan-Christoph Borchardt
84b239f123 reduce multiselect max-width from 400 to 200px to not take too much space 2014-05-27 14:32:23 +02:00
Bjoern Schiessle
ab3b713c23 don't expect depreciated OC_FilesystemView 2014-05-23 15:13:59 +02:00
Thomas Müller
1eedab7f6e php upload errors are written to log 2014-05-23 11:45:35 +02:00
Vincent Petry
9a5da34721 Added password obfuscation for external storage config
Added obfuscation for all "password" options from external storages.
Added more ext storage unit tests config.
Added unit tests for reading/writing the configuration.
Added IV for ext storage password encryption
Moved the mounting code for external storage from
OC\Filesystem::initMountPoint to files_external using the post_initMountPoints hook
Fixed ext storage unit test for groups

Squashed backport of 2c561c9c50 from
master.
2014-05-22 12:29:15 +02:00
Bjoern Schiessle
6f29e1c67b only start migration if the encryption was initialized; allow to overwrite keys if no files exists 2014-05-21 17:36:39 +02:00
Arthur Schiwon
516f75fc6b add unit test to make sure the infinite loop never comes back 2014-05-16 18:03:40 +02:00
Arthur Schiwon
9f405339d6 set result entry identifier earlier, i.e. before a continue for the same level can happen. otherwise will always get the same value and we end up in an infinite loop 2014-05-16 18:03:15 +02:00
tomneedham
419e0354d5 Only accept success as 100 like the OCS spec does 2014-05-14 19:24:08 +00:00
Arthur Schiwon
313324a7b4 bump version and don't overwrite values on next update if not necessary 2014-05-14 13:27:23 +02:00
Arthur Schiwon
c18f2943d5 get the correct version number for compare -.- 2014-05-14 12:01:41 +02:00
Vincent Petry
0c355cb1fb Fixed getAbsolutePath case when path is "0"
Make sure to correctly check for string emptiness when the passed path
is "0".

Backport of bab8c1f from master
2014-05-13 21:17:33 +02:00
Arthur Schiwon
68434510bd LDAP: set filter mode to raw, so filters will not be changed and broken after upgrade from oc5, when visiting the LDAP settings and opening filter tabs 2014-05-13 17:47:00 +02:00
Lukas Reschke
1e6b4576c2 Harden issubdirectory()
realpath() may return false in case the directory does not exist since we can not be sure how different PHP versions may behave here we do an additional check whether realpath returned false
2014-05-12 09:10:35 +02:00
Vincent Petry
8c1eff8f52 Merge pull request #8521 from owncloud/stable6-shareextstoragemountpointfix
[stable6] Fix sharing of ext storage mount points
2014-05-09 16:57:53 +02:00
Vincent Petry
37e29169e0 Fix getPathById for Oracle
Added extra code to handle the case of Oracle which saves empty strings
as null values.

Backport of 05dc694 from master
2014-05-09 14:37:26 +02:00
Vincent Petry
b91e3be5de Added unit test for sharing ext storage mount points
Backport of f73a168 from master
2014-05-09 14:37:16 +02:00
Vincent Petry
113cd404c0 Fix sharing of ext storage mount points
When sharing an ext storage mount point, it will now use the name of the
mount point instead of an empty string for the target path.

Backport of 28f0e63 from master
2014-05-09 14:37:07 +02:00
Robin Appelman
d2dbab21fb Fix getPath for storage roots 2014-05-07 21:51:10 +02:00
Vincent Petry
a152f3a50f Added PostgreSQL version warning + log on upgrade
Backport of 3cd09f2, a25b86a, 6bfeb34 from master
2014-05-07 12:15:55 +02:00
Morris Jobke
c341a971f8 fix getUserFolder() of server container 2014-05-05 23:09:06 +02:00
Georg Ehrke
1d2dc9b685 fix issue with spamming logging files when loading cached thumbnail
Conflicts:
	lib/private/preview.php
2014-05-05 16:04:05 +02:00
Bjoern Schiessle
4e1d57e815 always encrypt files to owner 2014-05-05 12:05:36 +02:00
Fabian Henze
76cdd85cd9 Add unit tests for OC_Helper::phpFileSize function 2014-05-03 13:04:10 +02:00
Fabian Henze
6f8a24c2cd Fix setting the max-upload-size for really large values.
php can only parse filesize units up to gigabytes, not terabytes or petabytes.
2014-05-03 13:03:59 +02:00
Frank Karlitschek
835025e569 6.0.3 2014-04-29 02:38:18 +02:00
Lukas Reschke
821ad6ad41 Merge pull request #8389 from owncloud/reset-3rdparty-stable6
Update 3rdparty
2014-04-28 22:25:43 +02:00
Thomas Müller
3fe45b1d4c Update 3rdparty 2014-04-28 20:38:48 +02:00
Thomas Müller
86757cdb45 Merge pull request #8384 from owncloud/kill_office_fallback_stable6
backport b68098ebba to stable6
2014-04-28 20:29:06 +02:00
Volkan Gezer
65ea07fc54 Update outdated comment 2014-04-28 20:24:17 +02:00
Georg Ehrke
a3d93f0ba1 backport b68098ebba to stable6 2014-04-28 15:42:48 +02:00
Lukas Reschke
283a8b9624 Clarify the trusted_domain error page
Backport of https://github.com/owncloud/core/pull/8372
2014-04-27 18:34:35 +02:00
Lukas Reschke
dacacacc4f Revert "Clarify the trusted_domain error page"
This reverts commit 4f9a5c9d3c.
2014-04-27 18:33:50 +02:00
Lukas Reschke
4f9a5c9d3c Clarify the trusted_domain error page
Conflicts:
	lib/base.php
2014-04-27 18:32:28 +02:00
Lukas Reschke
e5def25f40 Add another example to the trusted_domains config
Users often ask in IRC or the forum how to add another domain.
Hopefully they will be able to find it out on their own if we have an example with two domains.
2014-04-26 23:13:48 +02:00
Morris Jobke
2c92ef9e64 Merge pull request #8365 from owncloud/stable6-external-storage-css-fix
fix layout of external storage config table
2014-04-26 10:34:36 +02:00
Morris Jobke
16ae62f246 fix layout of external storage config table
Conflicts:
	apps/files_external/css/settings.css
2014-04-26 00:45:45 +02:00
Frank Karlitschek
53df9c93c4 6.0.3 RC1 2014-04-23 16:49:44 +02:00
blizzz
14c95086a9 Merge pull request #7745 from owncloud/fix_6946_stable6
Group Database backend must not gather user details itself but ask user backends, fixes #6946 in stable6
2014-04-23 16:30:26 +02:00
Lukas Reschke
4696b06060 Merge pull request #8261 from owncloud/stable6-backport-8182
Backport of #8182
2014-04-23 14:37:07 +02:00
Arthur Schiwon
0a9487ec80 fix after rebase 2014-04-23 13:55:21 +02:00
Arthur Schiwon
fcffccf018 keep the constant to not provoke PHP warnings 2014-04-23 13:35:01 +02:00
Arthur Schiwon
72b90816fa trim must not be used in empty in PHP < 5.5 2014-04-23 13:35:00 +02:00
Arthur Schiwon
6aeb5996b6 test for group manager's displayNamesInGroup 2014-04-23 13:35:00 +02:00
Arthur Schiwon
af45da94b3 adjust user manager tests 2014-04-23 13:35:00 +02:00
Arthur Schiwon
f93ab1105f implement getDisplayNames in group manager 2014-04-23 13:35:00 +02:00
Arthur Schiwon
637aa56197 remove now unnecessary test 2014-04-23 13:34:56 +02:00
Arthur Schiwon
649233e54c clean up group backends 2014-04-23 13:34:56 +02:00
Arthur Schiwon
8d00f1ca1f LDAP: getDisplayNamesInGroup is not an option for group backends anymore 2014-04-23 13:34:56 +02:00
Arthur Schiwon
60edf98c15 remove OC_GROUP_BACKEND_GET_DISPLAYNAME option for group backends 2014-04-23 13:34:56 +02:00
Thomas Müller
1041617a4e Merge pull request #8260 from owncloud/stable6-backport-8183-and-co
Backport of #8183 and #8197
2014-04-23 12:04:09 +02:00
ben-denham
a314508543 Backport of #8164
Added improved version of patch by @blizzz in https://github.com/owncloud/core/issues/6651#issuecomment-32261257 to stop filter settings from being reset under a race condition.

Moved LdapFilter into a separate js file in user_ldap.

Changed conditions in user_ldap's ldapFilter.js to use ===, fixed indentation.

fix comparison in determineMode, fixes problems with restoring the filter mode (assisted or manually) on page refresh

Give hint when composing filter failed

fixing some JSHint warnings
2014-04-23 11:21:28 +02:00
Thomas Müller
74241140d2 Update 3rdparty submodule 2014-04-22 23:59:03 +02:00
Lukas Reschke
d3a15b6b07 Check whether the user has permissions to add personal storage backends
Quick’n dirty back port of #8182 - master has a better fix but that
should be good enough…

missing return - OCP\JSON::success does not terminate the PHP process - which is good ;-)

Use error instead of success

Revert "Use error instead of success"

This reverts commit e2d5535a5aa436c3896e46f0b9e8ff1bd5640d4d.

Use error instead of success
2014-04-22 23:20:32 +02:00
blizzz
1403a85950 Merge pull request #8232 from owncloud/fix_8135
LDAP: optimize retrieval of displaynames, fixes #8135
2014-04-22 18:35:47 +02:00
Bernhard Posselt
130f2419f5 Merge pull request #8265 from owncloud/appframework-fix-backports
Appframework fix backports
2014-04-18 22:29:57 +02:00
Bernhard Posselt
a53ec9ebeb merge middleware string registration 2014-04-18 16:17:58 +02:00
Bernhard Posselt
33bdab1618 use references for middleware to fix problems on 5.3 2014-04-18 16:14:46 +02:00
Bernhard Posselt
3405342ab6 merge dicontainer 2014-04-18 16:14:44 +02:00
Bernhard Posselt
980b11f096 default to GET request when no method is set to fix unittests, also set parsed json parameters on the post attribute 2014-04-18 16:13:10 +02:00
Bernhard Posselt
22485fe743 Correctly process request parameters other than GET or POST, dont use globals in the class but inject it 2014-04-18 16:13:01 +02:00
Lukas Reschke
a7bc716b95 Merge pull request #8259 from owncloud/backport-7682-6
Backport #7682
2014-04-18 11:36:59 +02:00
Lukas Reschke
9b36224bd4 Backport of #8197 to stable6
This extends mimetypes.list.php to be a white-list of known secure mime
types as well as offering secure alternatives for know potentially
malicious mime types.
I kept this in the OC_Helper and OC\Files\Type\Detection classes as
each backend has its own way of detecting mime types.

This supersedes #8184 as discussed in owncloud/security-tracker#56
2014-04-18 11:19:47 +02:00
Lukas Reschke
9f1788f202 Backport of #8183 to stable6
Some headers were currently only added to the templates but not to
other components (e.g. SabreDAV / JSON / etc...)
The migration to base.php ensures that the headers are served to all
requests passing base.php
2014-04-18 11:13:47 +02:00
Lukas Reschke
a30040411c Backport of #7682 to stable6 2014-04-18 10:36:04 +02:00
Lukas Reschke
c4d4065dc2 Use JS as content-type due to mimesniffing 2014-04-17 17:15:35 +02:00
Robin Appelman
d4be12ab21 Verify that a file exists before we share it 2014-04-17 12:32:52 +02:00
Arthur Schiwon
02de48e1ba add additional comments, PHPdoc and check whether it's really applicable 2014-04-16 17:16:51 +02:00
Arthur Schiwon
97d6db966c LDAP: cache display names immediately on retrieval, saves tens of unecessary queries to LDAP server in the share dialog for example 2014-04-16 12:56:08 +02:00
Arthur Schiwon
cf2fc58c65 Backport of PR #7815, correct LDAP user count on setup with many users
(occ user:report)

LDAP: make sure cache key for paged result cookie matches when limit or offset is null or 0

LDAP: fix user report i.e. count for LDAP servers with really many users

initialize variable

var count is assigned in the inner loop so it must be checked inside there to be properly used as part of the exit condition of the outer loop

Put inner loop into own method, let's see whether it makes scrutinizer happier
2014-04-16 11:15:16 +02:00
Arthur Schiwon
e1b1ce684d adjust tests accordingly 2014-04-15 19:16:02 +02:00
Arthur Schiwon
793f20d728 Remove limit and offset manipulation when getting users or groups, because it does not work when more than one user or group backend. Fixing it would be too costly performancewise, so we switch back to the model used in OC 5: limit and offset are effective per backend, and not a general constraint 2014-04-15 19:15:55 +02:00
blizzz
15ebb4b8ad Merge pull request #8166 from owncloud/ldap_update_email
Also check for email address on userExists (next to Avatar and Quota)
2014-04-14 10:23:57 +02:00
Arthur Schiwon
80a294b334 LDAP: fetch email from LDAP on userExists check as well (along to Quota and Avatar) 2014-04-11 18:33:58 +02:00
Thomas Müller
6636c14c2a Merge pull request #8150 from owncloud/backport-8138-stable6
To isolate the variable scope used inside the $file it is required in i...
2014-04-11 12:30:18 +02:00
Bernhard Posselt
bf898f90bc Merge pull request #8151 from owncloud/backport-8137-stable6
add requirements to routing
2014-04-10 21:34:57 +02:00
Bernhard Posselt
de7a3861f3 Merge pull request #8119 from Raydiation/stable6
Remove dependency on container, removing service locator antipattern
2014-04-10 19:41:10 +02:00
Vincent Petry
d4951c68f3 Fixed Sabre Node implementation to correctly return timestamps as int
Negative timestamps were returned as string and were confusing other

Sabre API like Sabre_DAV_Property_GetLastModified.

This fix makes sure the timestamp is returned as int when defined.

Backport of 4f11786 from master
2014-04-10 17:46:36 +02:00
Vincent Petry
85e90c33fc Merge pull request #8148 from owncloud/backport-6676-stable6
Disabled internet checking as mentioned when in proxy mode
2014-04-10 17:28:00 +02:00
Bernhard Posselt
22632a227c Update controller.php
Backwards compability fix for faster merge ;)
2014-04-10 16:43:57 +02:00
Bernhard Posselt
fc8004d335 add requirements to routing
Conflicts:
	tests/lib/appframework/routing/RoutingTest.php
2014-04-10 16:25:44 +02:00
Thomas Müller
2149670328 fix code formatting 2014-04-10 16:20:42 +02:00
Thomas Müller
2741eb1fe3 To isolate the variable scope used inside the $file it is required in it's own method - refs #8138 2014-04-10 16:15:04 +02:00
Joan
b09614b61b Disabled internet checking as mentioned when in proxy mode 2014-04-10 15:48:04 +02:00
Morris Jobke
2257ae987f Merge pull request #8123 from owncloud/fix_filename_closing_tag
fix double closing </a> for filenames
2014-04-09 13:41:08 +02:00
Arthur Schiwon
88949d7f94 Backport of PR #7837 to stable6
LDAP Wizard: when determining objectclasses, we realy do not need to look at every entry. Fixes #7530

Conflicts:
	apps/user_ldap/lib/wizard.php

Fix wildcard handling and check even less DNs per filter, enough will be looked at anyway

Use the LDAP wrapper for checking resources, needs for proper testing

fix potential infinite loop when the DN of the first entry was already read.

add tests for cumulativeSearchOnAttribute

make tests work on systems without php5_ldap

define var

add comment to clearify when a skip in the foreach happens
2014-04-09 12:45:36 +02:00
Jörn Friedrich Dreyer
e34d00a958 fix double closing </a> for filenames 2014-04-09 11:23:57 +02:00
Bernhard Posselt
6b15731bfe Remove dependency on container, removing service locator antipattern 2014-04-08 22:48:57 +02:00
Vincent Petry
be30728bc2 Fixed chunking and insufficient storage check
- fixed free space detection based on the already uploaded chunks
- now deleting chunks as soon as it is read out before writing it into
  the part file, which reduces the space needed when assembling part
files

Backport of 4033eba from master
2014-04-07 09:48:07 +02:00
Vincent Petry
d34e1b524a Do not expire chunks while checking for their existence
The expiration should be done by the gc() function on login, not while
isComplete() is calling hasKey() for every chunk.

Backport of ab56f69416 from master
2014-04-04 17:17:53 +02:00
blizzz
3debb33346 Merge pull request #8038 from owncloud/fix_8028
Meanwhile, the quota value is stored human-readable in the DB
2014-04-04 16:34:48 +02:00
Robin Appelman
79635ccb41 Add bindParam to statement wrapper 2014-04-04 15:12:51 +02:00
Robin Appelman
d8097b48ea fix unit tests 2014-04-04 13:07:14 +02:00
Thomas Müller
1116455b3f Merge pull request #8037 from owncloud/fix-7216
authentication apps need to be loaded in any case - fixes #7216
2014-04-03 23:05:41 +02:00
Arthur Schiwon
09802ac217 Meanwhile, the quota value is stored human-readable in the DB 2014-04-03 20:51:05 +02:00
Thomas Müller
984586c20a authentication apps need to be loaded in any case - fixes #7216 2014-04-03 20:47:38 +02:00
Robin Appelman
a591160c32 use a non-recursive chmod on the datadir 2014-04-03 13:42:35 +02:00
Robin Appelman
6dd3215eae Improve phpdoc 2014-04-03 13:27:09 +02:00
Robin Appelman
e96c365054 Implement getPath for shared files 2014-04-03 13:27:01 +02:00
Robin Appelman
2150cac956 Give storages the option to implement the getById behaviour for View->getPath 2014-04-03 13:26:54 +02:00
blizzz
096b4d8b1b Merge pull request #7931 from owncloud/fix_7785_stable6
LDAP: Read email and quota when mapping user, fixes #7785
2014-04-02 19:24:22 +02:00
Volkan Gezer
47e3e73c8f Fix admin-dir_permissions redirection when cannot write warning
is shown.
2014-04-02 14:51:06 +02:00
Arthur Schiwon
519ab3a9c8 more precise php doc 2014-04-02 11:01:29 +02:00
Arthur Schiwon
5df99d3e61 add PHP docs 2014-04-01 21:57:01 +02:00
Jan-Christoph Borchardt
bd5eec7bb7 general styles for the content area 2014-04-01 18:55:37 +02:00
Rodrigo Hjort
2086e80e4d Correction: failure on sharing when user ID was prefixed by zero
Backport of 51b727c from master
2014-04-01 18:42:10 +02:00
Vincent Petry
f84168253b Merge pull request #7976 from owncloud/fix-7973-stable6-2
remove pl_PL - fixes #7973
2014-04-01 18:41:33 +02:00
Thomas Müller
a390bd2e73 Revert "remove Sabre_DAV_Browser_Plugin"
This reverts commit e4104e63d9.
2014-04-01 13:42:58 +02:00
Thomas Müller
456f02b476 remove pl_PL - fixes #7973 2014-03-31 18:10:12 +02:00
Bjoern Schiessle
027de54558 don't write file if opening a stream to encrypt the data fails 2014-03-28 15:00:27 +01:00
Arthur Schiwon
7dd34b1212 LDAP: Read email and quota when mapping user, fixes #7785 2014-03-28 12:18:24 +01:00
Jörn Friedrich Dreyer
24274acd6a don't block php session while download is in progress 2014-03-28 11:41:58 +01:00
Morris Jobke
5099caa55a Merge pull request #7901 from owncloud/fixed_position_ocdialogdim
prevent dimmed ocdialog div from scrolling
2014-03-28 02:43:08 +01:00
Vincent Petry
17e5c03a02 Fix swift touch operation
The touch() operation now uses "UpdateMetadata()" instead of "Update()"
which doesn't clear the object's contents.

This fixes syncing, as the sync client needs to use touch to update the
object's mtime.

Backport of 2a08e35 from master
2014-03-27 18:39:57 +01:00
Vincent Petry
a31b37e733 Fixed mtime reading from OpenStack API
The API seems to return floating point values, which prevents
the hasUpdated() check to work and causes the scanner to rescan
everything every time.

Backport of fa00a18 from master
2014-03-27 17:59:39 +01:00
Jörn Friedrich Dreyer
35e4784202 prevent dimmed ocdialog div from scrolling 2014-03-26 17:48:33 +01:00
Thomas Tanghus
f464620a65 Fix 'Undefined variable: message' in OCP\Util::logException 2014-03-25 18:07:07 +01:00
Arthur Schiwon
2d639b83ab add test for cloning and keeping configuration seperate 2014-03-21 18:03:05 +01:00
Arthur Schiwon
406747ab30 Use array_key_exists instead of isset, because the latter returns false if the assigned value is null 2014-03-21 18:02:59 +01:00
Arthur Schiwon
b41c1d7655 On clone create a new instance of the Configuration
To avide effects on the original instance of Connection when the clone
is modified, for instance on authentication checks.
2014-03-21 18:02:53 +01:00
Vincent Petry
b10b8a470b Fixed warning when browsing Shared folder
The virtual "Shared" folder doesn't have an unencrypted_size field.
This fix adds a check to prevent warnings in the log.

Backport of 022d76c from master
2014-03-21 17:56:56 +01:00
Thomas Müller
23ffdcc314 Merge pull request #7840 from owncloud/fix/7839
fixing wrong html close tags
2014-03-21 12:54:55 +01:00
Vincent Petry
ffdbdf7496 Merge pull request #7834 from owncloud/stable6-quota-usequotaevenwhenfreespaceunknown
[stable6] [backport] Still return quota value when free space is unknown
2014-03-21 12:29:19 +01:00
Thomas Müller
df636371a7 fixing wrong html close tags 2014-03-21 12:15:02 +01:00
Robin McCorkell
ceff4dae61 Fix duplicate ipauniqueid 2014-03-21 11:30:00 +01:00
Robin McCorkell
540d4af8a7 Add FreeIPA UUID compatibility, fixes #7796
Ability to use ipauniqueid for the UUID of a user
2014-03-21 11:29:50 +01:00
Vincent Petry
bb995c53c5 Still return quota value when free space is unknown
Fixed the quota storage wrapper to correctly return the quota value
when the free space is not known (which usually happens when the
disk_free_space function is disabled)

Backport of 66bc0f0 from master
2014-03-21 10:25:43 +01:00
Vincent Petry
eacb4b3f3e Return unencrypted_size of folder when queried
This fixes the "used space" to be based on the unencrypted size, not
encrypted size, to be consistent with how quota/space is handled when
encryption is enabled
2014-03-21 10:23:56 +01:00
Vincent Petry
a70b99ff62 Propagate unencrypted_size up to the file cache root 2014-03-21 10:23:48 +01:00
Vincent Petry
2c2fd5f3a0 Merge pull request #7819 from owncloud/stable6-datafolderexistence
[stable6] [backport] Added .ocdata file to check for data folder validity
2014-03-20 15:28:33 +01:00
Vincent Petry
288c40e2a6 Increase version to trigger upgrade related to .ocdata 2014-03-20 11:51:54 +01:00
Vincent Petry
d85d3a4493 Return 503 when a config/data dir error exists
Backport of b619ff6 from master
2014-03-20 11:51:14 +01:00
Vincent Petry
a1c0c5e1a2 Added .ocdata file to check for data folder validity
In environments where the data folder is mount from another partition,
it is important to check that the data folder we see is actually the
real one. If the mount failed for some reasons, this fix will make
ownCloud temporarily unavailable instead of causing unpredictable
behavior.

Backport of 3c46dcd from master
2014-03-20 11:50:53 +01:00
Robin McCorkell
6ccc8173d3 Fix smb4php to work with home shares
Stat'ing a share with url_stat now checks if the user can run 'ls' in that share rather than checking if the share is listed by the server. This means that OwnCloud can now mount user home shares, which are never listed by the server.
2014-03-18 21:37:14 +01:00
Vincent Petry
2cb342c3b8 Display admin option for public upload with encryption enabled
Now that public upload works with encryption, the admin option to toggle
it must be made visible.

Backport of b75ca9f from master
2014-03-18 13:15:50 +01:00
Vincent Petry
58db31e61e Added warning for trusted_domains after CLI upgrade
If trusted_domains is not set after a CLI upgrade, show a warning in the
output.

Backport of 1a11682 from master
2014-03-17 14:27:19 +01:00
Bjoern Schiessle
30cca2524f finally fix the paths for the OCS Share API 2014-03-13 20:28:08 +01:00
Vincent Petry
53ad7ebfea Merge pull request #7690 from owncloud/backport-7683-stable6
Backport 7683 stable6
2014-03-13 11:41:46 +01:00
Thomas Müller
bff2c20fce Merge pull request #7701 from owncloud/backport-7681-stable6
remove Sabre_DAV_Browser_Plugin
2014-03-13 09:42:28 +01:00
Thomas Müller
e4104e63d9 remove Sabre_DAV_Browser_Plugin 2014-03-12 23:56:28 +01:00
Vincent Petry
bc5145e267 Merge pull request #7698 from owncloud/backport_7631
only enable drag&drop upload if public upload is allowed
2014-03-12 23:51:45 +01:00
Vincent Petry
544495563f Merge pull request #7280 from owncloud/tune_legacy_cache_webdav_properties_prefixing_stable6
Concatenate string in SQL instead of PHP, use doctrine to construct concat expression
2014-03-12 18:55:11 +01:00
Bjoern Schiessle
112a277998 only enable drag&drop upload if public upload is allowed, backport of #7631 2014-03-12 17:50:26 +01:00
Thomas Müller
46657ad8a6 fixing method names 2014-03-12 15:40:54 +01:00
Thomas Müller
14b9eba428 set content-type on ocs exceptions 2014-03-12 15:40:54 +01:00
Frank Karlitschek
6a31fecca3 increase version number 2014-03-11 19:11:07 +01:00
Bjoern Schiessle
3ccbc25dba add 'received_from' info to the share, so that every share can have a different value 2014-03-11 17:16:04 +01:00
Bjoern Schiessle
c3c255b0ca fix path creation for re-shares, issue #7662 2014-03-11 17:15:56 +01:00
Thomas Müller
2e42b0555a Merge pull request #7672 from owncloud/backport-7659-stable6-2
Backport 7659 stable6 2
2014-03-11 16:26:28 +01:00
Thomas Müller
c1c6ce22e8 remove magic handling of recipient lists by exploding the string - this functionality is nowhere used this way and nowhere documented - and broken because only $toaddress will be exploded not $toname 2014-03-11 14:41:36 +01:00
Thomas Müller
a3bc3bbf2d backport #7659 2014-03-11 14:40:51 +01:00
Victor Dubiniuk
37e19534f1 Reset time of last update feed polling 2014-03-11 15:36:08 +03:00
Morris Jobke
d290f44fc7 Merge pull request #7608 from owncloud/stable6-publicpagedownloadall
[stable6] Fixed "select all" + download on public page
2014-03-11 10:29:08 +01:00
Vincent Petry
4966d632ae Disable XML entities when parsing XML 2014-03-10 20:41:40 +01:00
Thomas Müller
a5871c1811 Merge pull request #7653 from owncloud/backport-7646-stable6
we need the file_source to delete a share successfully
2014-03-10 17:55:27 +01:00
Bjoern Schiessle
0f40acb9a8 we need the file_source to delete a share successfully 2014-03-10 16:44:58 +01:00
Thomas Müller
cf2af3ce4d Merge pull request #7633 from owncloud/fix-7582-stable6
Fix 7582 stable6
2014-03-10 15:10:07 +01:00
Thomas Müller
d54f314c93 fixing ident 2014-03-07 20:05:11 +01:00
Thomas Müller
ff078db8cb we first shall check if the current session is valid - otherwise the session-id will be regenerated on login via basic auth 2014-03-07 20:03:51 +01:00
Björn Schießle
acc35849af Merge pull request #7586 from owncloud/dont_create_shared_folder_stable6
[oc6] don't allow to create a file or folder named 'Shared' in the root folder
2014-03-07 10:31:08 +01:00
Frank Karlitschek
c9c91c7e15 Merge pull request #7609 from owncloud/fix-updater-6
Use $installedVersion instead of $currentVersion
2014-03-06 23:19:11 +01:00
Lukas Reschke
ce5f8d72a4 Use $installedVersion instead of $currentVersion
Additionally use 6.00.4 as the internal version has been changed
2014-03-06 22:43:08 +01:00
Vincent Petry
b4c10eea60 Fixed "select all" + download on public page
When a user has lots of files, selecting all and downloading would send
the whole list of files to the server.

This fix makes it use the simpler default download URL in such cases
(the one that was used by the "Download" button that is now removed on
the public page)
2014-03-06 20:32:27 +01:00
Vincent Petry
c358373dfa Merge pull request #7578 from owncloud/introduce-generateUrl-stable6
adding new javascript function OC.generateUrl(url, params)
2014-03-06 17:26:17 +01:00
Frank Karlitschek
95ddadd146 increase the version number 2014-03-06 16:52:44 +01:00
Morris Jobke
91392c5a87 add dprecated warning for OC.Router 2014-03-06 15:17:55 +01:00
Jan-Christoph Borchardt
26b70bce28 fix noise not repeating 2014-03-06 14:55:04 +01:00
Bjoern Schiessle
7f81b14eff don't allow to create a file or folder named 'Shared' in the root folder, also exclude all combinations of lower and upper case letters 2014-03-06 12:09:32 +01:00
Thomas Müller
87d385303f adding new javascript function OC.generateUrl(url, params) 2014-03-06 00:28:11 +01:00
Lukas Reschke
eaf96335ad Merge pull request #7565 from owncloud/stable6-trusteddomainerrorpage
[stable6] Show warning page when accessing server from an untrusted domain
2014-03-05 21:04:11 +01:00
Vincent Petry
d7163c9b5a Fixed X-Forwarded-Host parsing 2014-03-05 20:06:05 +01:00
Vincent Petry
98ff74a70e Added unit tests for serverHost and other related functions 2014-03-05 20:06:04 +01:00
Vincent Petry
f1b948d4dc Added localhost as trusted domain 2014-03-05 18:59:34 +01:00
Vincent Petry
9b6b02af6d Show warning page when accessing server from an untrusted domain
Added early check for the requested domain host and show a warning
page if the domain is not trusted.
2014-03-05 18:59:34 +01:00
Jan-Christoph Borchardt
6b45835ecf add hover/focus states for star icons to hint at action 2014-03-05 15:29:52 +01:00
Bjoern Schiessle
c02c815603 don't create files folder, let ownCloud core handle it 2014-03-05 14:32:25 +01:00
Vincent Petry
5bf9aab464 Fixed configkey casing for PostgreSQL
Backport of fd5dec0 from master
2014-03-04 17:59:48 +01:00
Vincent Petry
722b81627c Merge pull request #7464 from owncloud/enc_fseek_fallback_stable6
Enc fseek fallback stable6
2014-03-04 12:53:08 +01:00
Vincent Petry
7e2659f017 Fix mail template to use p() for colors
Now using p() instead of print_unescaped() for colors.

Backport of 25251d4 from master
2014-03-03 17:43:52 +01:00
Frank Karlitschek
52b3187962 Merge pull request #7510 from owncloud/stable6-theme-mailtemplate
[stable6] Enable theming of the mail template header
2014-03-03 17:21:53 +01:00
Jan-Christoph Borchardt
b3c5aaa1ca make mail notification header color themable 2014-03-03 16:50:05 +01:00
Jan-Christoph Borchardt
ea62d23cb3 compress mail notification logo 2014-03-03 16:50:01 +01:00
Jan-Christoph Borchardt
289f64b191 mail template: remove off-white background color to better blend into mail client 2014-03-03 16:49:54 +01:00
Jan-Christoph Borchardt
5878d27068 remove border from log in input fields, simpler and works better with themes 2014-03-03 16:19:49 +01:00
Frank Karlitschek
071e371803 increasing the internal verison one more 2014-03-03 14:59:34 +01:00
Björn Schießle
ccf2bf74ea Merge pull request #7501 from owncloud/stable6-libxmlfixsubmoduleupdate
Updated submodule for libxml entity fixes
2014-03-03 13:04:05 +01:00
Vincent Petry
9e439305fd Updated submodule for libxml entity fixes 2014-03-03 12:58:18 +01:00
Björn Schießle
dadd67e7bd Merge pull request #7498 from owncloud/stable6-dbschemaxmlentityfix
Allow XML entity loader for MDB2 schema loader
2014-03-03 12:55:38 +01:00
Vincent Petry
762b0d9510 Allow XML entity loader for MDB2 schema loader 2014-03-03 12:15:51 +01:00
Frank Karlitschek
dc0a7428bd 6.0.2 2014-02-28 22:59:59 +01:00
Thomas Müller
7534fae9bc Merge pull request #7462 from owncloud/ldap_proxy_access
Ldap proxy access
2014-02-28 21:51:37 +01:00
Jan-Christoph Borchardt
68a9ceacbb Merge pull request #7472 from owncloud/stable6-icons.css-updates
stable6 icons.css backports
2014-02-28 15:24:56 +01:00
Jan-Christoph Borchardt
8a3a5a2ff1 icons: automatically show delete hover instead of using explicit class 2014-02-28 11:37:00 +01:00
jbtbnl
8995c81103 Remove necessity of icon class
Only the icon specific class is needed
2014-02-28 11:36:51 +01:00
jbtbnl
095f9114dd Add white color variant of checkmark icon 2014-02-28 11:36:39 +01:00
Arthur Schiwon
470a0ad611 remove remaining testing artefact 2014-02-28 10:58:51 +01:00
Bjoern Schiessle
9661001af1 remember original fopen access type in pre-proxy because sometimes they change
during the fopen call, e.g. 'r' becomes 'r+' if we open an URL
2014-02-28 10:38:58 +01:00
Vincent Petry
17f869b2fb Merge pull request #7459 from owncloud/deletestorage-legacy
Also delete legacy storages when deleting a user
2014-02-28 10:30:52 +01:00
Vincent Petry
162ba722f6 Merge pull request #7468 from owncloud/stable6-enc-fixfieldnametypo
[stable6] Fixed wrong field name
2014-02-27 23:52:20 +01:00
Vincent Petry
4756d18a14 Fixed wrong field name
This re-fixes an issue where the unencrypted size isn't updated
correctly when saving a text file in the UI multiple times.

Fixes #7467
2014-02-27 19:50:16 +01:00
Bjoern Schiessle
9cff832282 add test for the stream wrapper to read encrypted files from the system folder /tmp 2014-02-27 18:02:13 +01:00
Bjoern Schiessle
7ced22ccc6 test for isEncryptedPath() 2014-02-27 18:02:05 +01:00
Bjoern Schiessle
6455722f29 extend the encryption stream wrapper to handle local files and add a fall back for file size calculation if the storage doesn't support fseek 2014-02-27 18:01:58 +01:00
Bjoern Schiessle
8b3d99308c implement ftell stream wrapper and fix return value from fseek stream wrapper 2014-02-27 18:01:51 +01:00
Bjoern Schiessle
f87319f834 fall back to getLocalFile if storage doesn't support fseek 2014-02-27 18:01:45 +01:00
Arthur Schiwon
4605c2cc2d intendetion. where did the whitespaces come from? 2014-02-27 16:20:53 +01:00
Arthur Schiwon
49e567a5cc LDAP: let proxy for multiple server access methods from Access 2014-02-27 16:18:03 +01:00
Robin Appelman
7580518bd8 Also delete legacy storages when deleting a user 2014-02-27 14:52:36 +01:00
Jörn Friedrich Dreyer
d93b5af265 Merge pull request #7430 from owncloud/stable6-quote-oldcolumname
[stable6] Also quote old column name during DB migration
2014-02-27 13:12:32 +01:00
Bjoern Schiessle
9a0c78b831 close encryption session after decryption was finished 2014-02-27 11:48:29 +01:00
Jan-Christoph Borchardt
61a37331ce disable autocomplete for shared link password input, fix #7419 2014-02-26 22:21:36 +01:00
Thomas Müller
d265d290c3 Merge pull request #7426 from owncloud/stable6-fixmailnotificationtranslation
[stable6] Backported incorrect translation texts for German
2014-02-26 22:18:42 +01:00
Thomas Müller
aff7594ef3 let's name the column 'select' because this is a keyword on all platforms 2014-02-26 22:14:44 +01:00
Thomas Müller
5e586995a8 adding test for migrations on columns using keywords 2014-02-26 22:14:44 +01:00
Vincent Petry
1d0e45e179 Also quote old column name during DB migration
This fixes alter table commands that didn't quote the old column name
2014-02-26 16:30:38 +01:00
Vincent Petry
cab94eb719 Fix German message for "Enter new" 2014-02-26 15:50:02 +01:00
Vincent Petry
c1cc4df26e Fixed German shared notification message 2014-02-26 15:49:44 +01:00
Bjoern Schiessle
b4f154f9b4 fix path in sharing results if it is a file in the Shared folder 2014-02-26 15:22:20 +01:00
Bjoern Schiessle
ac3f1d6f61 only add "received_from" if a share was found 2014-02-26 14:49:41 +01:00
Morris Jobke
d27f2929d2 Merge pull request #7402 from owncloud/stable6-ie9-navigation
Stable6 IE9 navigation bar width
2014-02-26 13:49:03 +01:00
Vincent Petry
6aee04bba4 Merge pull request #7397 from owncloud/stable6-scrollperformance
Users list scrolling performance / improvements
2014-02-26 13:19:27 +01:00
Thomas Müller
a88b253c78 introduce new theme function to allow full creation of documentation links: buildDocLinkToKey() 2014-02-26 12:52:49 +01:00
Jan-Christoph Borchardt
751c1b0418 manual backport of IE9 navigation bar pull request #6808, fix #7321 2014-02-26 09:19:02 +01:00
Vincent Petry
a0feffb2a7 Added loading spinner to users list on scroll 2014-02-25 19:37:33 +01:00
Vincent Petry
34d17e6168 Improve users list scrolling performance
- fixed JS error when avatar mode is disabled
- added spinner at the bottom of the table
- scroll detection now happens earlier
- single/multiselect init is deferred so that the new rows are first appended
  into the list (more responsive) and initialized afterwards
- disabled users sorting after add (assuming they are always sorted on
  the server side)
2014-02-25 19:37:23 +01:00
Owen Winkler
c30377392b Merge pull request #7394 from owncloud/backport-7344
Allow apps to add/modify config js output via hook.
2014-02-25 10:37:33 -05:00
ringmaster
0d2482a1a9 Allow apps to add/modify config js output via hook. 2014-02-25 09:16:38 -05:00
Vincent Petry
149814d95b Replace deleteAll call with unlink call
The method deleteAll() doesn't officially exist on the Storage class as
it's not defined on the interface, which means it fails on the Quota
storage wrapper and might fail on some external storage classes.
Also, this here is the only use case for that one method.
2014-02-25 15:01:38 +01:00
Frank Karlitschek
16e24dc4c5 Merge branch 'stable6' of https://github.com/owncloud/core into stable6 2014-02-25 13:56:30 +01:00
Frank Karlitschek
dc11b87a1d 6.0.2 RC1 2014-02-25 13:56:06 +01:00
Bjoern Schiessle
c8d34eaf9c add test case if a file gets moved out from the shared folder 2014-02-25 12:42:34 +01:00
Bjoern Schiessle
9183ade655 don't overwrite keys if rename was done by a stream copy 2014-02-25 12:36:06 +01:00
Vincent Petry
678afc4906 Merge pull request #7386 from owncloud/stable6-fixhostnamewithport
Fix case where port is missing
2014-02-25 12:32:41 +01:00
Vincent Petry
6d3b5b24fd Fix case where port is missing 2014-02-25 11:22:53 +01:00
icewind1991
4286eeb531 Merge pull request #7369 from owncloud/stable6-smbmissingfiles
[stable6] Fixed missing files on SMB storage
2014-02-24 13:57:57 +01:00
Vincent Petry
0187537a2e Fixed missing files on SMB storage
Files with attribute "N" weren't parsed out of the file list returned by
smbclient. It seems that these files appear when created on a Linux SMB
mount directly and that have no executable bit.
2014-02-24 09:22:02 +01:00
Vincent Petry
928947f1c3 Added extra checks for ext storage class 2014-02-22 08:13:11 +01:00
Lukas Reschke
fb1ebf13c6 Adjust version for stable6 2014-02-22 08:09:49 +01:00
Lukas Reschke
ed7e9be7cd Add overwritehost config on setup and upgrade 2014-02-22 07:59:39 +01:00
Bjoern Schiessle
e903c8b57b fix test so that it doesn't depend on the array order 2014-02-21 15:53:11 +01:00
Bjoern Schiessle
210832ddf1 fix usersPath and add unit tests 2014-02-21 15:53:03 +01:00
Vincent Petry
96ebefc597 Updated submodule
Includes XML fixes
2014-02-21 15:49:08 +01:00
Bjoern Schiessle
5348e2eb54 fix sharing unit tests 2014-02-21 14:44:09 +01:00
Bjoern Schiessle
f6e6f465f2 add unit test for \OC\URLGenerator::getAbsoluteURL to verify #6935 2014-02-21 13:49:11 +01:00
Thomas Müller
ce87f933a4 Merge pull request #7349 from owncloud/backport-7347
Backport of #7347 to stable6
2014-02-21 11:21:06 +01:00
Arthur Schiwon
a04af7854d LDAP: fix and extend tests 2014-02-21 10:15:09 +01:00
Arthur Schiwon
75c7fd2886 LDAP: improve compilation of filters 2014-02-21 10:15:00 +01:00
Lukas Reschke
92b4d52079 Fix "headers are already sent" introduced with #6519
Backport of #7347
2014-02-21 10:05:05 +01:00
Thomas Tanghus
91b4045791 Test if $url is already prefixed by '/' 2014-02-20 18:19:05 +01:00
Thomas Tanghus
0f87a0248f Add missing slash in URLGenerator::getAbsoluteURL(). Refs. #6840 2014-02-20 18:18:54 +01:00
Arthur Schiwon
3c9421381b LDAP: prevent other configuration from being deleted when deleting the first one which has an empty prefix for historical reasons 2014-02-20 16:25:50 +01:00
nhirokinet
2d946d2766 Update user.php to fix duplicate session-duplicate 2014-02-20 14:31:28 +01:00
NARUKAWA Hiroki
a422f19fac Security Update: session fixation
Previous version is vulnerable to session fixation attack in some situations, guessing non-apache-module-php5 environment. Regeneration of session id should be done here.
2014-02-20 14:31:23 +01:00
Lukas Reschke
ebb1a70abc Check whether the app is set 2014-02-20 11:26:55 +01:00
Lukas Reschke
b9d013e3ce Check whether the Key is set 2014-02-20 11:26:47 +01:00
Lukas Reschke
b044ec0420 An admin should not be able to add remote and public services on its own. This should only be possible programmatically.
This change is due the fact that an admin may not be expected to execute arbitrary code in every environment.
2014-02-20 11:26:41 +01:00
Jörn Friedrich Dreyer
3520529430 Concatenate string in SQL instead of PHP, use doctrine to construct concat expression 2014-02-19 12:06:04 +01:00
Joas Schilling
864f0342af Make google drive client secret and dropbox api secret a password field
Fix issue #5794

Backport of 828985d
2014-02-18 18:33:13 +01:00
Joas Schilling
5a2e99c975 External FTP Storage should request hostname instead of URL
Fix issue #6277

Backport of 658af62
2014-02-18 18:15:19 +01:00
Lukas Reschke
d07f459409 Use the proper content-type
We should use the proper content-type `application/xml` instead of the default `text/html` here.

Backport requested.
2014-02-18 11:45:05 +01:00
Vincent Petry
3d5d6b5ad1 Now using PHP session lifetime as default value for the JS config
This will fix the heartbeat when the session_lifetime config parameter
hasn't been set explicitly.

Backport of f9763e1fc5
2014-02-18 10:53:35 +01:00
Vincent Petry
80dcec773a Merge pull request #7225 from owncloud/enc_improved_error_handling_oc6
[encryption] improved error handling (OC6)
2014-02-17 11:26:21 +01:00
Bjoern Schiessle
43738dacfb don't block login forever if we are stuck in the middle of the initial encryption 2014-02-17 10:24:04 +01:00
Bjoern Schiessle
78b10de7d6 catch errors during decryption
Conflicts:
	apps/files_encryption/tests/util.php
2014-02-17 10:23:48 +01:00
Bjoern Schiessle
37db8a13d4 catch errors during initial encryption 2014-02-17 10:21:16 +01:00
Joas Schilling
eb8b2210cd Send correct path on file upload when using public app
Fix issue #7152
2014-02-14 12:27:34 +01:00
Robin Appelman
118033cac6 Also clean up the filecache table when deleting a storage entry 2014-02-12 14:03:30 +01:00
Robin Appelman
b0ba69ff31 Also remove the user's home storage from the storage table when deleting a user 2014-02-12 14:03:30 +01:00
Thomas Müller
c1241b1691 Load authentication apps to get users from all backends - fixes #7019 2014-02-11 18:42:09 +01:00
Vincent Petry
ad813da7b1 Merge pull request #7157 from owncloud/stable6-xsendfilequotacheck
Fix xsendfile local storage detection with quota
2014-02-11 17:03:55 +01:00
Vincent Petry
b4f04c18db Fix xsendfile local storage detection with quota 2014-02-11 15:04:17 +01:00
blizzz
23985428ea Merge pull request #6778 from owncloud/fix_6430
on filtering the share box users and groups whose name begins with the s...
2014-02-11 10:38:04 +01:00
Bjoern Schiessle
018fed6014 getData() always needs to return an array 2014-02-10 15:16:58 +01:00
Arthur Schiwon
3be50224ff intendation 2014-02-10 14:53:59 +01:00
Arthur Schiwon
0213928735 fix DI 2014-02-10 14:53:59 +01:00
Arthur Schiwon
1cf599d494 Inject logger 2014-02-10 14:53:59 +01:00
Arthur Schiwon
8a4dbdedcf wrong tld 2014-02-10 14:53:59 +01:00
Arthur Schiwon
35b316f93f test for share dialoge sorter 2014-02-10 14:53:59 +01:00
Arthur Schiwon
7e451a24bc sort following entries in alphabetical order 2014-02-10 14:53:59 +01:00
Arthur Schiwon
f8620704d4 move sorter into a class 2014-02-10 14:53:58 +01:00
Arthur Schiwon
c6687e159b respect coding guidelines 2014-02-10 14:53:58 +01:00
Arthur Schiwon
8227bc41cd on filtering the share box users and groups whose name begins with the search term shall appear on top, fixes #6430 2014-02-10 14:53:58 +01:00
Bjoern Schiessle
6f5caaa87a refuse login as long as the initial encryption is running 2014-02-10 14:51:34 +01:00
blizzz
e5dac9fa24 Merge pull request #7124 from owncloud/fix_6541
LDAP: also try MS AD's thumbnailPhoto when looking for an avatar image
2014-02-10 14:44:43 +01:00
Joas Schilling
48bb8aeb01 Only add files to file list when uploading to current directory
Fix Issue #6683
2014-02-10 12:41:45 +01:00
blizzz
fd32501fe0 Merge pull request #7081 from owncloud/fix_6670
LDAP: Wizard cannot determine Base DN in some cases, fixes #6670
2014-02-10 11:27:31 +01:00
Arthur Schiwon
0a475bdab3 LDAP: improve debug message 2014-02-10 10:19:37 +01:00
Arthur Schiwon
3d6ab2b53b LDAP: also try MS AD's thumbnailPhoto when looking for an avatar image 2014-02-10 10:19:37 +01:00
Björn Schießle
5e315495c2 Merge pull request #7130 from owncloud/enc_fix_unit_tests
name users after test
2014-02-07 17:56:21 +01:00
Thomas Müller
b353637e45 Merge pull request #7129 from owncloud/ldap_info_doc
LDAP: add documentation info in info.xml
2014-02-07 17:13:45 +01:00
Thomas Müller
fb6290c87a Merge pull request #7083 from owncloud/backport_6777_stable6
Backport 6777 stable6
2014-02-07 17:08:25 +01:00
Bjoern Schiessle
76cb5a50c0 name users after test 2014-02-07 17:01:02 +01:00
Arthur Schiwon
5c40ef090a LDAP: add documentation info in info.xml 2014-02-07 15:55:35 +01:00
Bjoern Schiessle
9c9b161f51 replace 'size' with 'unencrypted_size' if encryption is enabled 2014-02-07 15:26:21 +01:00
Bjoern Schiessle
9b257ad862 change order of issubdirectory() calls to avoid error messages for non-apps 2014-02-07 14:48:01 +01:00
Thomas Müller
5edc4c95bc Merge branch 'stable6' into backport_6777_stable6
Conflicts:
	apps/files_sharing/css/public.css
	apps/files_sharing/templates/public.php
2014-02-07 14:21:10 +01:00
Vincent Petry
f9bd4c5d24 Fixed searchByMime in shared cache
- searchByMime now correctly returns files recursively search through
  all the dirs
- added unit test for searchByMime

Backport of fa5ddc3 to stable6
2014-02-06 16:23:15 +01:00
Thomas Müller
88a5f7d994 remove css files from rewrite rule - there is no need to rewrite css any more 2014-02-06 15:13:23 +01:00
Jan-Christoph Borchardt
04b4c7c042 remove %webroot from files_sharing app 2014-02-06 14:28:26 +01:00
Jan-Christoph Borchardt
87d06bae85 remove %webroot% from files app 2014-02-06 14:28:17 +01:00
Jan-Christoph Borchardt
c096c6edc3 add icons.css file, first step to get rid of %webroot% 2014-02-06 14:28:08 +01:00
Bjoern Schiessle
713c5c4275 use appstoreenabled config switch 2014-02-05 16:52:18 +01:00
Jan-Christoph Borchardt
e48c7675b9 do not show 'Add app' and 'More apps' for themed ownCloud 2014-02-05 16:52:15 +01:00
Bjoern Schiessle
f824986742 add function to extract filename from sharekey name + tests 2014-02-05 14:32:32 +01:00
Bjoern Schiessle
5e788ae1fa added tests for the delete hooks if the trash bin is disabled 2014-02-05 14:32:13 +01:00
Bjoern Schiessle
78b390da31 don't expect OC_FilesystemView, this is depreciated 2014-02-05 14:31:47 +01:00
Bjoern Schiessle
b3257a315d better error detection and don't use glob() 2014-02-05 14:31:34 +01:00
Bjoern Schiessle
fc1763dc6b move unlink proxy to a hook which handles pre and post conditions 2014-02-05 14:31:13 +01:00
Vincent Petry
7b948b0580 Added session_keepalive setting
When session_keepalive is true (default) the heartbeat will be send as
often as the half of the session timeout value.

Backport of 912da8d to stable6
2014-02-05 13:46:49 +01:00
Jörn Friedrich Dreyer
379ddd88d6 make header scroll up for single shares, more view of content on small screens 2014-02-05 11:39:02 +01:00
Jörn Friedrich Dreyer
23c015ba52 adding class to header div: share-folder or share-file 2014-02-05 11:38:21 +01:00
Jörn Friedrich Dreyer
0f97d9555c adjust file type icon placement for when no preview can be generated 2014-02-05 11:37:23 +01:00
Jörn Friedrich Dreyer
0992a77cfb permanently show download action on mobile, only icon 2014-02-05 11:33:43 +01:00
Jörn Friedrich Dreyer
4b1f93b61c fix horizontal scrollbar appearing when footer is too long, footer wraps now 2014-02-05 11:30:54 +01:00
Jörn Friedrich Dreyer
916122b166 fix multiselect bar being too short on big displays 2014-02-05 11:29:39 +01:00
Jörn Friedrich Dreyer
a3b351738a Instead of 'No preview available for ...' we simple display the mime-type icon 2014-02-05 11:27:46 +01:00
Jörn Friedrich Dreyer
37f8607a88 remove background and width from multiselect bar, fix Download button not showing on mobile 2014-02-05 11:24:34 +01:00
Jörn Friedrich Dreyer
a4895e4df1 focus link text only on click in the input field - closes #6817 2014-02-05 11:17:04 +01:00
Jörn Friedrich Dreyer
a9a92892be remove unused variable 2014-02-05 11:15:04 +01:00
Jörn Friedrich Dreyer
d8770d1284 fix input element closing tag 2014-02-05 11:13:31 +01:00
Jörn Friedrich Dreyer
e3d8758a32 make sure there's enough room for the file actions 2014-02-05 11:12:01 +01:00
Jörn Friedrich Dreyer
5a5496f4e7 restrict zooming on mobile devices for the publicly accessible, optimized pages 2014-02-05 11:10:30 +01:00
Jörn Friedrich Dreyer
b33cfce2fa add icons for file list and picture view toggles 2014-02-05 11:08:34 +01:00
Jörn Friedrich Dreyer
025ab0dabb on mobile, show single shared image at full width without margin 2014-02-05 11:06:42 +01:00
Jörn Friedrich Dreyer
63b078b550 fix public share download button width 2014-02-05 11:02:21 +01:00
Jörn Friedrich Dreyer
fa1288c6b3 tweak color and position of username in public share 2014-02-05 10:59:52 +01:00
Jörn Friedrich Dreyer
9f9466d001 improvements to public files mobile view 2014-02-05 10:57:26 +01:00
Jörn Friedrich Dreyer
249df3864b remove min-width rule to fix mobile views 2014-02-05 10:53:54 +01:00
Jörn Friedrich Dreyer
615f0c4a1c first mobile style rules, hide extra columns in files view and scroll header 2014-02-05 10:52:25 +01:00
Jörn Friedrich Dreyer
a096f19bb2 add download button on single file share page 2014-02-05 10:49:57 +01:00
Arthur Schiwon
a967acee4c Rephrase and clarify log message 2014-02-05 10:33:44 +01:00
Arthur Schiwon
2801edc451 Wizard: enable base DN for editing, if not base DN could have been detected. Also part of fix for #6670 2014-02-05 10:30:56 +01:00
Arthur Schiwon
acebc3f41e Wizard: disable LDAP referrals, fixes #6670 2014-02-05 10:29:09 +01:00
Vincent Petry
9404389d83 Allow getting info or renaming part files through WebDAV
When mounting an ownCloud (backend OC) inside another ownCloud (frontend
OC), the frontend OC will use WebDAV to upload file, which will create
part files. These part files need to be accessible for the frontend OC
to rename them to the actual file name.

This fix leaves the file cache untouched but gives direct access to part
file info when requested.

This means that part file can be accessed only when their path and name
are known. These won't appear in file listtings.

Fixes #6068
2014-02-05 10:11:28 +01:00
Arthur Schiwon
60b75b25f8 throw an info message, when base dn test failed 2014-02-04 19:37:40 +01:00
Arthur Schiwon
608fe55889 LDAP: extend LDAP wrapper search method for sizelimit, improves performance in wizard 2014-02-04 17:56:53 +01:00
Jörn Friedrich Dreyer
37d2c0a4be remove unused js code and css rules 2014-02-04 16:32:39 +01:00
Jörn Friedrich Dreyer
3ccbc984f4 no new menu on public upload 2014-02-04 16:29:59 +01:00
Jörn Friedrich Dreyer
8bd3ce2fe2 fixing preview generation 2014-02-04 16:28:51 +01:00
Jörn Friedrich Dreyer
ebcbf85396 reuse file upload as used within files app - remove public upload button 2014-02-04 16:25:23 +01:00
Bjoern Schiessle
44a6d2a98c add test for password remove method 2014-02-04 14:42:41 +01:00
Bjoern Schiessle
8ee368ddad remove needless element tag 2014-02-03 17:03:30 +01:00
Bjoern Schiessle
34069e00c4 also load error handler if debugging is enabled 2014-02-03 17:00:30 +01:00
Bjoern Schiessle
88542819f0 remove passwords in URLs from all log messages 2014-02-03 17:00:17 +01:00
Vincent Petry
8a66c30895 Fixed image preview in trashbin subdirs 2014-01-31 16:35:23 +01:00
Bjoern Schiessle
e6579a3c0a public upload is also possible with encryption enabled, since OC6 2014-01-29 11:51:50 +01:00
Bjoern Schiessle
9016093b4c use more accurate error codes 2014-01-28 16:46:58 +01:00
Vincent Petry
301e4988a1 Added exception logger plugin for sabre connector
Whenever an exception occurs in the sabre connector code or code called
by it, it will be logged.

This plugin approach is needed because Sabre already catches exceptions
to return them to the client in the XML response, so they don't appear
logged in the web server log.

This will make it much easier to debug syncing issues.

Backport of 11ef12a to stable6
2014-01-28 14:19:13 +01:00
Otto Sabart
e6391d84a1 Add check for apc.enabled option
Sometimes it's not possible to disable APC entirely and some of
apc_functions are disabled. Only thing which is possible is
to disable apc.enable option.
2014-01-27 23:33:39 +03:00
Bjoern Schiessle
4c305ef459 disable button and input field during decryption 2014-01-27 14:23:56 +01:00
Bjoern Schiessle
72e308788f remove the form, it isn't needed here 2014-01-27 14:23:43 +01:00
Bjoern Schiessle
f1dc6e1441 use localised date in notification mails 2014-01-27 14:18:10 +01:00
Bjoern Schiessle
33801c311e only update file cache with the unenecrypted size when the file was written 2014-01-27 10:39:11 +01:00
Jan-Christoph Borchardt
0cd68cfedc prevent autofill for password change settings, prevent leak of existing password, fix #6552 2014-01-26 20:04:24 +01:00
Bjoern Schiessle
e00f483238 add expire date to link share if possible 2014-01-24 16:57:18 +01:00
Bjoern Schiessle
5cc8df3723 increase size of mimetype column 2014-01-24 16:09:22 +01:00
Bjoern Schiessle
08bf128255 added website field 2014-01-24 13:58:51 +01:00
Bjoern Schiessle
3979508dae distinguish app links from doc links 2014-01-24 13:58:43 +01:00
Bjoern Schiessle
a5a2fe9180 show link to app documentation 2014-01-24 13:58:29 +01:00
Bjoern Schiessle
29d63893ff add link to documentation 2014-01-24 13:58:18 +01:00
Vincent Petry
39354eaaf1 Fixed sharing results to include the correct permissions
Passing $includeCollections would return more than one entry which gives
mixed up file permissions.

Added a method getFile() that doesn't set $includeCollections to make
sure we only get one result which is the file itself.

Fixes #6265
2014-01-23 15:31:14 +01:00
Bjoern Schiessle
2e8418b362 fix infinite loop if folder and subfolder has the same name 2014-01-23 13:36:33 +01:00
Bjoern Schiessle
1a93891222 add path relative to the files folder of the currently logged in user to the output of getFolderContent() 2014-01-23 13:36:22 +01:00
Vincent Petry
099ccfa254 Fixed isPreviewAvailable warnings in log
isPreviewAvailable wasn't always set as the files formatting code is
slightly different than the one from the files app.

Fixes #6423

Backport of f4c198b to stable6
2014-01-23 12:32:10 +01:00
Björn Schießle
d41b2c5401 Merge pull request #6891 from owncloud/version_fix_array_order_stable6
Version fix array order stable6
2014-01-22 03:21:50 -08:00
Myles McNamara
5f7bc2cf4d change publicUploadButtonMock to public_upload
Changed jQuery selector for public preview to public_upload to correctly show preview
2014-01-22 11:36:47 +01:00
Myles McNamara
6d330e8a3f change em to px 2014-01-22 11:36:42 +01:00
Myles McNamara
72b680ca2d modify js to move upload wrapper, modify css to match core values 2014-01-22 11:36:38 +01:00
Myles McNamara
5e1c3732e5 remove extra upload controls 2014-01-22 11:36:29 +01:00
Myles McNamara
7251c65996 fix upload button layout 2014-01-22 11:36:24 +01:00
Bjoern Schiessle
fea0ba84c5 fix size calculation 2014-01-22 11:28:09 +01:00
Bjoern Schiessle
cdfc6ff5d5 fix array ordering issue 2014-01-22 11:25:19 +01:00
Björn Schießle
50721da77b Merge pull request #6874 from owncloud/versioning_expire_fixes_stable6
selective backport of the bug fixes from pr #6863
2014-01-22 02:21:55 -08:00
Frank Karlitschek
14cbec6d6b 6.0.1 2014-01-22 09:28:41 +01:00
Thomas Müller
ea334cfa18 fixing comment + adding unit test for checkPasswordProtectedShare 2014-01-21 20:52:16 +01:00
Thomas Müller
c10af30381 in case no share is found for the given token we can return right away 2014-01-21 20:52:16 +01:00
Thomas Müller
4351609df9 adding password protection check to getShareByToken() 2014-01-21 20:52:16 +01:00
Thomas Müller
c430fe6612 Merge pull request #6869 from owncloud/fix-setupfs-only-for-existing-users-stable6
Fix setupfs only for existing users stable6
2014-01-21 10:18:29 -08:00
Tigran Mkrtchyan
3501007074 webdav: return SPACE_UNKNOWN if server do not support quota
Backport of a78dc11732 to stable6
2014-01-21 18:15:14 +01:00
Bjoern Schiessle
603828366f selective backport of the bug fixes from pr #6863 2014-01-21 17:49:56 +01:00
Vincent Petry
e46df97c3a Replaced time() with uniqid() to make sure the file name is unique
The cache isn't cleared properly because unlink() doesn't remove the
cache entry which caused side-effects when reusing the same file name
(which randomly happens when time() returns the same value)

This fix first makes sure the unit tests don't fail any more.
The unlink() case with the cache will be investigated separately.

Backport of f09c19c to stable6
2014-01-21 17:47:46 +01:00
Björn Schießle
180bb9fa9f Merge pull request #6867 from owncloud/protect-versions-preview-stable6
don't use the user id within the versions preview call as it could be us...
2014-01-21 07:46:37 -08:00
Thomas Müller
81f1c04b85 Merge pull request #6456 from owncloud/fix_home_storage_quota_stable6
Fix home storage quota stable6
2014-01-21 07:42:35 -08:00
Thomas Müller
b722ce6cc3 OC_Util::setupFS($user) will create a data dir for the given string - no matter if the user really exists - OCP\JSON::checkUserExists($owner); introduces a ready to use check which will bail out with an JSON error
Conflicts:
	lib/public/json.php
2014-01-21 16:39:31 +01:00
Jörn Friedrich Dreyer
65fa896bc2 add getOwner impementation to Home Storage 2014-01-21 15:18:46 +01:00
Thomas Müller
464b31157e don't use the user id within the versions preview call as it could be used to access previews of another user 2014-01-21 15:18:36 +01:00
Thomas Müller
a9f7764879 Merge pull request #6865 from owncloud/fix_user_ldap_sql_on_oracle_stable6
user workarount to compare CLOB column with CHAR value
2014-01-21 06:15:02 -08:00
Jörn Friedrich Dreyer
047ae7fb23 user workarount to compare CLOB column with CHAR value 2014-01-21 14:03:51 +01:00
Thomas Müller
98db90ba70 Merge pull request #6862 from owncloud/neutral_download_zip_default_name_stable6
use 'download.zip' as default name for zip downloads instead of 'owncloud.zip'
2014-01-21 04:20:02 -08:00
Jörn Friedrich Dreyer
0b11762b1c use 'download.zip' as default name for zip downloads instead of 'owncloud.zip' 2014-01-21 12:43:43 +01:00
Vincent Petry
127ab3cb47 When reading the size of "files" mountpoints need to be excluded
The versions and trashbin app are now passing "includeMountPoints=false"
to "getFileInfo()" to make sure that the calculated total size doesn't
include mount points like Shared or external storage.

This is because the default call (legacy) used to return the size of
mount points as well.

Fixes #6731

Backport of ca57a84 to stable6
2014-01-20 18:29:27 +01:00
Vincent Petry
09cc0c5cc9 Fixed quota wrapper to not wrap failed fopen streams
When calling fopen() on some storage types, these return false instead
of throwing an exception.

This fix makes sure that in case the stream wasn't opened (for example
when a file doesn't exist any more) the stream isn't wrapped.

Also added 'rb' as another case that doesn't need to be wrapped.

Fixes #6832
2014-01-20 14:32:57 +01:00
rnveach
c4c5e34110 added trigger to redo selection text on a directory change 2014-01-20 13:03:40 +01:00
rnveach
89d60a2680 fixed selector string and removed all checkbox if it was selected 2014-01-20 13:03:34 +01:00
Thomas Müller
369ec65d12 Merge pull request #6828 from owncloud/dont_add_queuedtasks_during_upgrade
add needUpgrade() check to addQueuedTask()
2014-01-18 03:46:31 -08:00
Jörn Friedrich Dreyer
40c2f47cd9 add needUpgrade() check to addQueuedTask() 2014-01-17 19:50:37 +01:00
Vincent Petry
bc22799160 Fix array access syntax for older PHP
There was a syntax error when running tests in PHP 5.3.10.
2014-01-17 14:39:49 +01:00
Bjoern Schiessle
4c1510b729 updated description of the files encryption app 2014-01-17 12:56:58 +01:00
Vincent Petry
d44b98d3dd Fix to not destroy draggable when no draggable was set
When a dir has no delete permission, the draggable isn't initialized on
files. This fix makes sure we don't try to destroy a draggable when it
wasn't inited in the first place.

Fixes #6254

Backport of 8135828 to stable6
2014-01-16 17:50:07 +01:00
Frank Karlitschek
a4e842f19a 6.0.1 RC1 2014-01-16 17:09:54 +01:00
Volkan Gezer
aec0f06501 Fix untranslated text when deleting user
This should fix issue #6728
2014-01-16 12:23:34 +01:00
ben-denham
f9e4d0a5e2 updated the unit test for OCP\Share::unshareAll() to verify that shares by all users are removed for an item. 2014-01-16 12:14:53 +01:00
ben-denham
3093c63024 Unshare all will now delete all shares for the item, instead of only for a single owner. 2014-01-16 12:14:37 +01:00
Thomas Müller
b0edbd8ebd Merge pull request #6783 from owncloud/backport-6530-stable6
Backport 6530 stable6
2014-01-15 11:01:47 -08:00
Vincent Petry
5dd20db05f Fixed Dropbox/Google storage async save call
When clicking "Grant access", the settings for Dropbox/Google were saved
through a call that gets cancelled when redirecting to the grant page
(for example in Firefox)

This fix makes sure the "save settings" call finished before redirecting
to the grant page.

Fixes #6176

Backport of e13be94 to stable6
2014-01-15 16:41:54 +01:00
Thomas Müller
0c140d5f6e in order to work properly with encryption ocTransferId is added to the file path - questionable usage of magic string 2014-01-15 16:37:23 +01:00
Thomas Müller
49969825ad Adding a random postfix to the part file. 2014-01-15 16:37:23 +01:00
Bjoern Schiessle
3b21499b34 extended test to also check the status messages 2014-01-15 16:10:31 +01:00
Bjoern Schiessle
3fde29ead4 keep response message 2014-01-15 16:10:22 +01:00
Bjoern Schiessle
afe35ca12d call getFileInfo to enforce a file cache entry for the new version, fix #6286 2014-01-15 16:01:48 +01:00
Bjoern Schiessle
a83e37c799 remove old code 2014-01-15 15:59:04 +01:00
Bjoern Schiessle
3c7541e97c don't try to encrypt/decrypt cache chunks or files in the trash bin 2014-01-15 15:58:56 +01:00
Bjoern Schiessle
3ec3ebb3db copy files to owner trash recursively 2014-01-15 15:58:48 +01:00
Morris Jobke
3e71827bea Merge pull request #6293 from owncloud/stable6-legacy-settings-popup
Stable6 legacy settings popup
2014-01-15 02:12:27 -08:00
Robin Appelman
6adac6a673 Use storage_mtime when determining if we can reuse cached data while scanning
Backport to stable6 of the following commits, in order:
- 203d5d0
- 4113042
- 7e4c80f
- 16b898d
2014-01-15 10:36:32 +01:00
Vincent Petry
88dc71381f Fix calculated folder size to use unencrypted size
The encrypted size was used when calculating folder sizes.
This fix now also sums up the unencrypted size and shows that one when
available.

Backport of 4faba49 to stable6
2014-01-14 16:37:48 +01:00
icewind1991
c6ca9be406 Merge pull request #6612 from owncloud/user-no-change-displayname-stable
Backport: Re-add the config options to remove the ability for users to change their displayname
2014-01-14 07:13:21 -08:00
Bjoern Schiessle
7dddf59942 it is not an urgent error... a DEBUG message is enough at this point 2014-01-14 15:09:26 +01:00
Vincent Petry
8ef32821be Fixed timezone issue with SMB storage
Now forcing smbclient to also run on UTC

Backport of 1eb5ebd to stable6
2014-01-14 15:04:41 +01:00
Thomas Müller
1e9f0409c3 Merge pull request #6408 from owncloud/ldap_fix_tls_detection
LDAP fix TLS detection
2014-01-14 05:01:08 -08:00
Andreas Fischer
bcec9cea78 Merge pull request #6756 from owncloud/remove-ru_RU-stable6
remove ru_RU - it's almost untranslated

* owncloud/remove-ru_RU-stable6:
  remove ru_RU - it's almost untranslated
2014-01-14 00:45:55 +01:00
Björn Schießle
87cfbb3a2b Merge pull request #6753 from owncloud/no_unshare_on_delete
don't unshare on delete
2014-01-13 07:48:22 -08:00
Thomas Müller
3b1396b538 remove ru_RU - it's almost untranslated 2014-01-13 16:44:03 +01:00
Carlos Cerrillo
ce1a1996f7 Fixing Issue #6301 on master branch
Added private var $certPath to store the user root cert

Move logic to determine the $certPath path to the constructor and modify to get the path from OC_User::getHome()

Add curl options to use the certificate to avoid certificate errors with self-signed certicates in the downdload/upload method so we don't get blank files

Only set SSL things when ```$this->secure``` is ```true```

Fix ```createCertificateBundle``` and  ```getCertificates``` methods
from ```OC_Mount_config``` to use ```OC_User::getHome``` to get the
path

Backport of 7c264c88fe,
b245e2e3d8 and
c06844c374 to stable6 (squashed)
2014-01-13 16:38:30 +01:00
st3so
5f2e8f7723 fixing typo in redirection query string
Backport of a2cae551f3 to stable6
2014-01-13 15:58:29 +01:00
Bjoern Schiessle
54cd174f61 don't unshare on delete 2014-01-13 15:25:59 +01:00
Vincent Petry
28be8496a9 Fixed various file name escaping issues in core apps
- Refactored file tr lookup into FileList.findFileEl that uses
  filterAttr to avoid escaping issues in jQuery selectors
- Fixed versions and sharing app to properly escape file names in
  attributes

Backport to stable6 of 1042733
2014-01-12 13:29:54 +01:00
Georg Ehrke
3ae7bfc298 fix preview for reshared file 2014-01-11 11:31:43 +01:00
Vincent Petry
1cbe1896e7 Prevent deleting storage root
Storage mount points are not deletable, so make sure that the unlink
operation and its hooks aren't run in such cases.

Note that some storages might recursively delete their contents when
calling unlink on their root. This fix prevents that as well.

Backport of f642ad3 to stable6
2014-01-10 16:50:26 +01:00
Arthur Schiwon
ebe3872c64 Infowarning about 32bit 2014-01-09 17:00:35 +01:00
Arthur Schiwon
f1ea0bcafc add tests for user counting 2014-01-09 17:00:28 +01:00
Arthur Schiwon
cf8fc2294e if backends have the same class name, sum their users up instead of overwriting 2014-01-09 17:00:21 +01:00
Arthur Schiwon
1636c6dbd8 LDAP: add tests for countUsers 2014-01-09 17:00:14 +01:00
Arthur Schiwon
59ff8388ea remove unnecessary line 2014-01-09 17:00:06 +01:00
Arthur Schiwon
1c58d8b226 LDAP: implement userCount action. This required to (finally) clean up and refactor the search method, which will have a positive performance impact on paged search. 2014-01-09 16:59:58 +01:00
Arthur Schiwon
0f58bd02c1 Add command line tool to show numbers of users and user directories 2014-01-09 16:59:47 +01:00
Arthur Schiwon
4b4901519d Introduce user count action to user management 2014-01-09 16:59:39 +01:00
Vincent Petry
a711d4e39a Removed special handling of part files in shared storage rename
This fixes the issue introduced by the transfer id which itself wasn't
taken into account by the shortcut code for part file in the shared
storage class.

Backport of 8eaa39f to stable6
2014-01-09 15:23:55 +01:00
Thomas Müller
52dc90d5fd Merge pull request #6696 from owncloud/backport-6693-stable6
Backport 6693 stable6
2014-01-09 04:56:26 -08:00
Thomas Müller
9a1cbabdd6 rename user-id to loginname to stay consistent 2014-01-09 12:34:19 +01:00
Thomas Müller
596ab7552e set login name within apache auth backend 2014-01-09 12:34:19 +01:00
Thomas Müller
ea23a09c05 fixing PHPDoc and use cameCase names 2014-01-09 12:34:19 +01:00
Arthur Schiwon
394bd17251 typo, grammar 2014-01-08 19:55:28 +01:00
Thomas Müller
627612c9e0 Merge pull request #6679 from owncloud/backport-6675-stable6
Backport 6675 stable6
2014-01-08 04:33:40 -08:00
Thomas Müller
c6fa2dd8e2 turn off mod_pagespeed 2014-01-08 12:19:30 +01:00
Thomas Müller
8d38228c98 Merge pull request #6678 from owncloud/backport-6660-stable6
Backport 6660 stable6
2014-01-08 02:50:15 -08:00
Thomas Müller
bbba8fd09d trimming all array elements 2014-01-08 10:45:37 +01:00
Thomas Müller
5e928fc988 we shall explode on ',' only 2014-01-08 10:45:37 +01:00
Thomas Müller
7e36763631 reuse existing helper function OC_Helper::is_function_enabled 2014-01-08 10:45:37 +01:00
Vincent Petry
542cf79595 Now also preventing to override "files" dir size with -1
Fixes #6526

Backport of 5be4af9 to stable6
2014-01-08 09:56:00 +01:00
Vincent Petry
2ea3765359 Added isUserAgent() method to request
- added isUserAgent() method to OC_Request which makes it possible to
  test it
- OC_Response::setContentDisposition now uses OC_Request::isUserAgent()
2014-01-07 22:11:39 +01:00
Vincent Petry
b7aaebf94f Added workaround for Android content disposition
Fixes #5807
2014-01-07 22:11:30 +01:00
Vincent Petry
c9cb258616 Moved content disposition code+workarounds to OCP\Response
Added new OC\Response API called setContentDispositionHeader() that
contains the needed workarounds for UTF8 and IE.

Refactored download code to use the new API.

Removed unused trashbin download file.
2014-01-07 22:11:22 +01:00
Thomas Müller
697ad1ca9e Merge pull request #6666 from ogasser/decimal_precision_scale_stable6_bp
DB: Support DECIMAL(precision,scale) syntax in XML
2014-01-07 11:11:32 -08:00
Thomas Müller
6a838718df Merge pull request #6664 from owncloud/fix_empty_mimetypes_stable6
remove duplicate exe mimetype, add correct msi mimetype
2014-01-07 07:31:29 -08:00
Oliver Gasser
6a21922854 DB: Support DECIMAL(precision,scale) syntax in XML
Add support for specifying the precision and scale of a decimal data
type to the XML description language. Added new unit tests and adapted
existing ones.

See owncloud/core#6475

Backported from owncloud/core#6476
2014-01-07 16:07:54 +01:00
Jörn Friedrich Dreyer
c81a05cbb1 remove duplicate exe mimetype, add correct msi mimetype 2014-01-07 15:54:33 +01:00
Robin Appelman
956a4419d8 Fix APCIterator syntax in \OC\Memcache\APCU::clear
see http://www.php.net/manual/en/apciterator.construct.php
2014-01-03 14:31:19 +01:00
Robin Appelman
f356ef90d7 Return SPACE_UNKNOWN if disk_free_space is disabled when getting the free space on a local storage 2014-01-02 17:30:39 +01:00
Robin Appelman
a8fd55d90d Pass config object in testGetHomeNotSupported 2014-01-02 16:58:30 +01:00
Robin Appelman
208037b56a Replace static usage of OC_Config and OC_Preferences with the injected \OC\ConfigAll 2014-01-02 16:58:12 +01:00
Robin Appelman
62887c67ab fix the config option to remove the ability for users to set their displayname 2014-01-02 16:58:05 +01:00
Robin Appelman
9960596f4e fix fallback overwriting result of getHome 2014-01-02 16:57:52 +01:00
Robin Appelman
b5ef21b22d cache the home folder of a User 2014-01-02 16:57:45 +01:00
Robin Appelman
44fb817a4e Also add default to the \OCP\IConfig interface 2014-01-02 16:54:44 +01:00
Robin Appelman
2c54dcda89 add default parameter for AllConfig->get*Value() 2014-01-02 16:54:39 +01:00
Frank Karlitschek
0bb7202ff7 Merge pull request #6562 from syncloud/stable6
Made admin password field required on client side
2013-12-25 03:36:00 -08:00
Vladimir Sapronov
75eaea1dff Made password field required on client side
Fix for case described in https://github.com/syncloud/owncloud-setup/issues/19
2013-12-23 21:39:14 -05:00
Andreas Fischer
93b6c83814 Backport of PR #4378: Don't use xcache in case admin auth is enabled. 2013-12-20 17:15:48 +01:00
Andreas Fischer
d9df271113 Do not use xcache variable cache if cache size is 0.
This is possible because it is possible to only use xcache as an opcode cache
but not a variable cache.
2013-12-20 16:50:18 +01:00
Bjoern Schiessle
13461698e4 tests added 2013-12-19 20:10:42 +01:00
Bjoern Schiessle
eaa5dd0282 we can also have a path user/cache/... 2013-12-19 20:10:29 +01:00
Bjoern Schiessle
672cbc5378 check if the old owner and the old path is available 2013-12-19 19:20:29 +01:00
Bjoern Schiessle
2f568c9766 fix rename of shared files 2013-12-19 19:20:17 +01:00
Vincent Petry
c4c972fd2f Merge pull request #6498 from owncloud/stable6-oracleencryptiontestfix
[stable6] Trying to fix failing encryption tests on Oracle
2013-12-19 06:45:37 -08:00
Thomas Müller
6de259e0ac Merge pull request #6291 from owncloud/ldap_doc_link
LDAP: Adjust help link to documentation
2013-12-19 02:56:34 -08:00
Vincent Petry
1f93b4e842 Removed numRows usage from encryption app
numRows on Oracle always seem to return 0.

This fix removes numRows usage from the encryption and sharing app.

This fixes unit tests and potentially the encryption app itself
(migration status) when running on Oracle
2013-12-18 21:14:26 +01:00
Robin Appelman
4c2d2f4dc9 check if a $_SESSION entry exists before we try to remove it 2013-12-18 14:26:27 +01:00
Robin Appelman
148c16bf70 preserve 3rd party values in in the Session destructor 2013-12-18 14:26:21 +01:00
Vincent Petry
77af1a7127 Fixed JS plural function to be per app
Some apps might not define the same "nplural" value.
To avoid conflicts, the plural function is now generated per app.

Fixes #6427
2013-12-18 12:13:22 +01:00
Bjoern Schiessle
2f0ec8256f reliable detect encrypted files 2013-12-17 18:14:36 +01:00
Frank Karlitschek
913df0c5ed clarifying license 2013-12-17 17:30:57 +01:00
Bjoern Schiessle
c88109a496 always show home breadcrumb in files view 2013-12-17 11:02:02 +01:00
Bjoern Schiessle
8f5dfd0920 always show 'Deleted Files' breadcrumb 2013-12-17 11:01:43 +01:00
Vincent Petry
ae58a385b7 Do not use L10n when logging exceptions
In some specific situations, the L10N bundle isn't loadable yet (for
example when there is an issue with the app_config table). In such case,
we still want to be able to log the real exception.

This fixes errors that say "OC_L10N_String::__toString must not throw
exceptions"
2013-12-17 10:56:02 +01:00
Bjoern Schiessle
3160b23291 update file cache for target file 2013-12-16 17:49:14 +01:00
Bjoern Schiessle
73a0b690e9 only remove encryption keys if a real file gets deleted, skip this method if a file outside of /data/user/files was deleted 2013-12-16 17:49:05 +01:00
Bjoern Schiessle
bdb4890d04 call set password hook because it doesn't get triggered during test execution and fix paths 2013-12-16 17:48:52 +01:00
Bjoern Schiessle
9091dd7833 enable more tests 2013-12-16 17:48:44 +01:00
Thomas Tanghus
a8a35f4d07 Use DEBUG instead of ERROR when favourites not found. Fix #6419 2013-12-16 17:31:03 +01:00
Frank Karlitschek
0d24b22485 6.0.0a 2013-12-14 20:40:17 +01:00
Frank Karlitschek
e8a696cff9 Merge pull request #6389 from owncloud/ignore_comments_on_columns
ignore comments on schema as a quickfix for oc6
2013-12-14 11:31:20 -08:00
Vincent Petry
811ef19ada Removed comments in database schema of encryption app 2013-12-14 11:18:48 +01:00
Jörn Friedrich Dreyer
db696a2dda ignore comments on schema as a quickfix for oc6 2013-12-13 19:21:14 +01:00
Arthur Schiwon
3d81009347 LDAP: only read config from database, if configID is given. Not what we want to do when on-the-fly-testing settings from the admin page 2013-12-13 18:01:42 +01:00
Vincent Petry
0b665700b5 Merge pull request #6406 from owncloud/stable6-no-backgroundjobs-during-upgrade
dont try to register background jobs if we haven't upgraded yet
2013-12-13 08:58:50 -08:00
Arthur Schiwon
1e407482be remove unused variables 2013-12-13 17:52:43 +01:00
Arthur Schiwon
d343c66f85 LDAP: fix TLS detection 2013-12-13 17:52:19 +01:00
Robin Appelman
0a0d89296b dont try to register background jobs if we haven't upgraded yet 2013-12-13 17:13:18 +01:00
blizzz
fede36d515 Merge pull request #6308 from owncloud/fix_webdav_session_login_user_comparison
Fix webdav session login user comparison
2013-12-13 07:56:28 -08:00
Vincent Petry
527a16852e Merge pull request #6367 from owncloud/fix_expiration_date_conversion
rely only on php DateTime to parse the db datetime string
2013-12-13 07:36:30 -08:00
blizzz
aab7c187f2 Merge pull request #6372 from owncloud/ldap_fix_setConfig
LDAP: fix method behind save button on advancend and expert tabs, fixes ...
2013-12-13 07:28:44 -08:00
Vincent Petry
dd7b074dfa Fix webroot for update page
On the update page, config.js was missing which caused oc_webroot to not
be available. That would trigger the faulty oc_webroot fallback that
didn't take URLs like "/owncloud/index.php/files/apps" into account.

This fix adds config.js in the update page and also a fix for the
oc_webroot fallback, in case it is used elsewhere.

Backport of df1a404
2013-12-13 14:36:35 +01:00
Robin Appelman
71e93c2b79 remove unneeded ; in comment 2013-12-13 13:52:39 +01:00
Robin Appelman
ca161e2a96 Add test for having utf8 filenames in the cache 2013-12-13 13:52:32 +01:00
Arthur Schiwon
ab8691d84b adjust test 2013-12-13 12:56:06 +01:00
Thomas Müller
a48cf28e17 Merge pull request #6364 from owncloud/backport-6302-stable6
Send "SET NAMES utf8" to MySQL for PHP below 5.3.6
2013-12-13 00:56:28 -08:00
Thomas Müller
cd7c974fb6 Updated 3rdparty ref 2013-12-13 00:03:20 +01:00
Arthur Schiwon
3b5d032dd5 LDAP: fix method behind save button on advancend and expert tabs, fixes at least Home Folder setinng 2013-12-12 23:09:31 +01:00
Jörn Friedrich Dreyer
f8088ecd29 rely only on php DateTime to parse the db datetime string 2013-12-12 19:09:21 +01:00
Bjoern Schiessle
e83ff69465 toggle select all checkbox 2013-12-12 18:47:31 +01:00
Andreas Fischer
66af605697 Send "SET NAMES utf8" to MySQL for PHP below 5.3.6 2013-12-12 12:26:17 -05:00
Jörn Friedrich Dreyer
71dc81d420 update 3rdparty 2013-12-12 17:59:46 +01:00
blizzz
02c9bb76ff Merge pull request #6350 from owncloud/ldap_dont_autofill
LDAP: the browser shall not autofill userdn and password, usually login ...
2013-12-12 05:14:44 -08:00
Arthur Schiwon
7b388eb4a8 LDAP: the browser shall not autofill userdn and password, usually login credentials are inserted. fixes #6283 2013-12-12 14:04:10 +01:00
Arthur Schiwon
c770089b50 coding style 2013-12-11 14:01:48 +01:00
Arthur Schiwon
afaac05f61 coding style 2013-12-11 13:57:02 +01:00
Arthur Schiwon
aba8199a82 On webdav sesssions, loginname was compared to username which does not need to match necessarily 2013-12-11 13:56:45 +01:00
Arthur Schiwon
0134b1ebfa LDAP: adjust documentation URL for OC 6 2013-12-10 17:45:03 +01:00
Jan-Christoph Borchardt
339e073399 fix shadow size and arrow position 2013-12-10 14:39:23 +01:00
Jan-Christoph Borchardt
4feafda822 fix the legacy popup to make calendar settings look nicer 2013-12-10 14:39:15 +01:00
Andreas Fischer
5ac339b866 Document memcached settings in config.sample.php 2013-12-09 14:35:20 +01:00
Morris Jobke
95c90ddbc4 fix wrong test data in l10n 2013-12-09 10:41:57 +01:00
Morris Jobke
2417c8a49e fix plural translation - fixes #6226 2013-12-09 10:41:51 +01:00
Frank Karlitschek
26d0adf2fe 6.0.0 2013-12-06 21:20:22 +01:00
Frank Karlitschek
734fdbddea RC4 2013-12-06 21:06:42 +01:00
Robin Appelman
33144941a9 add test case for removing background jobs that are throwing exceptions 2013-12-06 20:58:12 +01:00
Robin Appelman
f309920bef Dont use exceptions for the backgroundjob test cases 2013-12-06 20:58:06 +01:00
Robin Appelman
e78a309111 remove background jobs if they are failing 2013-12-06 20:57:58 +01:00
Robin Appelman
46a4ad4f3c Catch exceptions from background jobs and log them 2013-12-06 20:57:52 +01:00
Frank Karlitschek
3842c0d766 Merge pull request #6225 from owncloud/stable6-backgroundscan-reuse-etag
Stable6 backgroundscan reuse etag
2013-12-06 11:55:23 -08:00
Robin Appelman
8369c1f05b get rid of failing test that don't cause additional downloads 2013-12-06 19:19:10 +01:00
Robin Appelman
cadf1c232e extend test case for etag preservation 2013-12-06 19:19:10 +01:00
Robin Appelman
713651738c reuse etags when doing a background scan 2013-12-06 19:19:10 +01:00
Bart Visscher
1475245465 XSendfile and encryption don't work together
The file on disk is encrypted, and not readable on client systems
2013-12-06 19:07:22 +01:00
Bart Visscher
281bbf4bd4 Don't try to encrypt a file when the temp file isn't created 2013-12-06 19:07:11 +01:00
Bart Visscher
a2bbbb1448 Users of getFolderContent are mostly interested in the unecrypted file size 2013-12-06 19:06:42 +01:00
root
87a28957aa correctly propagate the return value of ldap_set_option
otherwise LDAP_OPT_REFERRALS won't be set to 0 and in turn
active directory paging will stop working
(Operations error on ldap_control_paged_result_response)
2013-12-06 18:01:42 +01:00
Bjoern Schiessle
01de6c565a set unencrypted_size to 0 after decryption... so that the unencrypted_size gets re-calculated if encryption was enabled again 2013-12-06 17:08:17 +01:00
Bjoern Schiessle
f3e341edac add a optional parameter to skip check for expired files, this is necessary to find out to whom a file was shared after it was expired. 2013-12-06 14:42:09 +01:00
Bjoern Schiessle
c5d6af3c5a get owner from share item, if we expire a share while the user updates his /Shared folder than the owner is different from the currently logged in user 2013-12-06 14:41:59 +01:00
Bjoern Schiessle
cc1577054d it is not possible to unshare files 2013-12-06 12:36:31 +01:00
Björn Schießle
3e6b18b2d0 Merge pull request #6208 from owncloud/enc_only_create_new_key_if_no_other_key_exists
[Encryption] Only create new key if no other key exists
2013-12-06 03:07:52 -08:00
Nico Kaiser
7eb505e6dd Fix user's displayName being overwritten by (old) cookie 2013-12-05 20:56:41 +01:00
Bjoern Schiessle
91ca1cf985 fix typo 2013-12-05 20:02:41 +01:00
Bjoern Schiessle
f8a4bcdd50 only create new key on password change if a recovery key exists or if the user don't have any private/public keys 2013-12-05 19:41:01 +01:00
Bjoern Schiessle
418d401bf9 show change password form if key couldn't be decrypted 2013-12-05 18:50:52 +01:00
Bjoern Schiessle
d0afd774b7 add method to check if users private/public key exists 2013-12-05 18:49:55 +01:00
Morris Jobke
0af65cae37 fix appearance of error message - .errors is outdated 2013-12-05 16:11:52 +01:00
Frank Karlitschek
4d50fe5f12 ownCloud 6 RC3 2013-12-05 12:02:53 +01:00
Vincent Petry
f24aca61a9 Merge pull request #6180 from owncloud/fix_6143
fixes checkboxes in Advanced Tab don't save unchecked state anymore, #6143
2013-12-04 08:33:12 -08:00
Bjoern Schiessle
d3e2226b38 config switch to disable auto expire for the trash bin 2013-12-04 16:55:07 +01:00
Arthur Schiwon
73fa6259be LDAP Wizard: avoid a manually deactivated LDAP configuration is enabled by just opening the admin page 2013-12-04 14:01:31 +01:00
Morris Jobke
dffc2a8b1c Revert "Adjust files_encryption requirements to the new core requirement (PHP 5.3.8)."
This reverts commit efbf18652c.
2013-12-04 13:26:59 +01:00
Vincent Petry
fd634fdec8 Added unit test for the test() method
This is to make sure that method isn't broken
2013-12-04 13:22:25 +01:00
Arthur Schiwon
328ebaefde LDAP: make unsetting checkboxes from Advanced tab work again, fixes #6143 2013-12-04 13:15:17 +01:00
Thomas Müller
4de8c4e5db Merge pull request #6175 from owncloud/fix_6142
LDAP Wizard: make sure auto-detected suggestions are really applied initially, fixes #6142
2013-12-04 02:54:07 -08:00
Frank Karlitschek
8dc3cb2ffb lower required php version to 5.3.3 2013-12-04 10:51:12 +01:00
Arthur Schiwon
c67ece0f6b LDAP Wizard: don't generate filter when not allowed 2013-12-03 20:50:46 +01:00
Arthur Schiwon
6640e120b7 some equals are more equal than other equals 2013-12-03 20:45:05 +01:00
Thomas Mueller
6f7b394d99 fixing PHPDoc and spelling 2013-12-03 17:49:37 +01:00
Andreas Fischer
91f47645b0 Use getLastError() everywhere. 2013-12-03 17:49:37 +01:00
Andreas Fischer
18903cc8f7 Add getLastError() 2013-12-03 17:49:37 +01:00
Andreas Fischer
7e467484a8 No function as oci_last_error. It's oci_error. 2013-12-03 17:49:37 +01:00
Andreas Fischer
21bf6abd41 There is no property such as dbusername. It's 'dbuser'. 2013-12-03 17:49:37 +01:00
Andreas Fischer
401728b2a2 Correct property name. It's 'dbpassword', with the 'db' prefix. 2013-12-03 17:49:37 +01:00
Andreas Fischer
bfd0dc3314 Correct property name. It's just 'tableprefix', without the 'db' prefix. 2013-12-03 17:49:37 +01:00
Jan-Christoph Borchardt
ad92b12559 fix time input field properly, details 2013-12-03 17:42:03 +01:00
Morris Jobke
4391992b8c fix public page - gallery view issues 2013-12-03 17:20:29 +01:00
Morris Jobke
728e6d735a fix trashbin and pbulic page controls 2013-12-03 17:20:23 +01:00
Morris Jobke
66df8c3bb3 fix and cleanup CSS for public page 2013-12-03 17:20:17 +01:00
Jan-Christoph Borchardt
ca08d21da0 change different shades of grey for public share page to white 2013-12-03 17:20:08 +01:00
Jan-Christoph Borchardt
7d0f458f11 remove app specific code 2013-12-03 17:20:00 +01:00
Jan-Christoph Borchardt
f15aeb3bbc fix details for buttons in header and controls bar 2013-12-03 17:19:53 +01:00
Jan-Christoph Borchardt
9333244925 account for shift of controls bar due to app navigation, do not shift on public page 2013-12-03 17:19:38 +01:00
Vincent Petry
50f5ab8515 Merge pull request #6173 from owncloud/stable6-extstorage-s3fixes
Backport of S3 ext storage fixes to stable6
2013-12-03 08:16:10 -08:00
Arthur Schiwon
4df0d2e7e8 LDAP Wizard: return correct var 2013-12-03 16:37:11 +01:00
Vincent Petry
f2e17a0b68 Fixed placeholder after page reload
The placeholder somehow had too many characters stripping from it...
2013-12-03 15:55:24 +01:00
Vincent Petry
e372971f2b Fixed test function for S3
Fixes #5752
2013-12-03 15:55:15 +01:00
Vincent Petry
3bf30377b8 Fixed Amazon S3 ext storage config UI
Optional parameters are now really optional

Fixes #5861
2013-12-03 15:55:08 +01:00
Arthur Schiwon
67b67b6d66 LDAP Wizard: make sure auto-detected suggestions are really applied initially. Also make initial filter compilation and user counting robust against race conditions. 2013-12-03 13:27:45 +01:00
Arthur Schiwon
b8390f15d4 LDAP: on testing configuration, set active property to true, otherwise inactive connections cannot be tested properly 2013-12-03 13:21:55 +01:00
Robin Appelman
5ac3f9bfa5 check if a directory exists before we try to remove it 2013-12-03 12:45:41 +01:00
Arthur Schiwon
02fe013d2f LDAP: set default value for login filter to empty, otherwise the wizard signals completed configuration too early when it might be not correct, i.e. login won't work 2013-12-03 12:11:43 +01:00
Bjoern Schiessle
5e5e4fe3a4 make it possible to select folders 2013-12-02 22:23:51 +01:00
Arthur Schiwon
d49e4e53fd LDAP Wizard: don't send ldap_tls change back to the interface as the element was removed, for it is detected fully automatically. Resolves an JS error and thus an ever-spinning spinner 2013-12-02 21:11:20 +01:00
Bjoern Schiessle
2d11290121 check explicitely all possible dir values 2013-12-02 16:06:51 +01:00
Bjoern Schiessle
1a197292da set delete all to true if a complete folder was deleted 2013-12-02 16:06:36 +01:00
Bjoern Schiessle
3b59979746 fix delete files from trash bin 2013-12-02 16:06:24 +01:00
Bjoern Schiessle
259d619af3 fix restore from files in sub-folders 2013-12-02 16:06:14 +01:00
344 changed files with 9396 additions and 8526 deletions

View File

@@ -26,7 +26,7 @@ RewriteRule ^.well-known/carddav /remote.php/carddav/ [R]
RewriteRule ^.well-known/caldav /remote.php/caldav/ [R]
RewriteRule ^apps/calendar/caldav.php remote.php/caldav/ [QSA,L]
RewriteRule ^apps/contacts/carddav.php remote.php/carddav/ [QSA,L]
RewriteRule ^apps/([^/]*)/(.*\.(css|php))$ index.php?app=$1&getfile=$2 [QSA,L]
RewriteRule ^apps/([^/]*)/(.*\.(php))$ index.php?app=$1&getfile=$2 [QSA,L]
RewriteRule ^remote/(.*) remote.php [QSA,L]
</IfModule>
<IfModule mod_mime.c>
@@ -38,3 +38,6 @@ DirectoryIndex index.php index.html
</IfModule>
AddDefaultCharset utf-8
Options -Indexes
<IfModule pagespeed_module>
ModPagespeed Off
</IfModule>

View File

@@ -18,7 +18,7 @@ if(\OC\Files\Filesystem::file_exists($target . '/' . $file)) {
exit;
}
if ($dir != '' || $file != 'Shared') {
if ($target != '' || strtolower($file) != 'shared') {
$targetFile = \OC\Files\Filesystem::normalizePath($target . '/' . $file);
$sourceFile = \OC\Files\Filesystem::normalizePath($dir . '/' . $file);
if(\OC\Files\Filesystem::rename($sourceFile, $targetFile)) {

View File

@@ -21,6 +21,7 @@ if (empty($_POST['dirToken'])) {
} else {
// return only read permissions for public upload
$allowedPermissions = OCP\PERMISSION_READ;
$public_directory = !empty($_POST['subdir']) ? $_POST['subdir'] : '/';
$linkItem = OCP\Share::getShareByToken($_POST['dirToken']);
if ($linkItem === false) {
@@ -34,6 +35,7 @@ if (empty($_POST['dirToken'])) {
// resolve reshares
$rootLinkItem = OCP\Share::resolveReShare($linkItem);
OCP\JSON::checkUserExists($rootLinkItem['uid_owner']);
// Setup FS with owner
OC_Util::tearDownFS();
OC_Util::setupFS($rootLinkItem['uid_owner']);
@@ -43,7 +45,7 @@ if (empty($_POST['dirToken'])) {
$dir = sprintf(
"/%s/%s",
$path,
isset($_POST['subdir']) ? $_POST['subdir'] : ''
$public_directory
);
if (!$dir || empty($dir) || $dir === false) {
@@ -77,7 +79,9 @@ foreach ($_FILES['files']['error'] as $error) {
UPLOAD_ERR_NO_TMP_DIR => $l->t('Missing a temporary folder'),
UPLOAD_ERR_CANT_WRITE => $l->t('Failed to write to disk'),
);
OCP\JSON::error(array('data' => array_merge(array('message' => $errors[$error]), $storageStats)));
$errorMessage = $errors[$error];
\OCP\Util::writeLog('files', "Upload error: $error - $errorMessage", \OCP\Util::ERROR);
OCP\JSON::error(array('data' => array_merge(array('message' => $errorMessage), $storageStats)));
exit();
}
}
@@ -110,7 +114,14 @@ if (strpos($dir, '..') === false) {
} else {
$target = \OC\Files\Filesystem::normalizePath(stripslashes($dir).'/'.$files['name'][$i]);
}
$directory = \OC\Files\Filesystem::normalizePath(stripslashes($dir));
if (isset($public_directory)) {
// If we are uploading from the public app,
// we want to send the relative path in the ajax request.
$directory = $public_directory;
}
if ( ! \OC\Files\Filesystem::file_exists($target)
|| (isset($_POST['resolution']) && $_POST['resolution']==='replace')
) {
@@ -136,7 +147,8 @@ if (strpos($dir, '..') === false) {
'originalname' => $files['tmp_name'][$i],
'uploadMaxFilesize' => $maxUploadFileSize,
'maxHumanFilesize' => $maxHumanFileSize,
'permissions' => $meta['permissions'] & $allowedPermissions
'permissions' => $meta['permissions'] & $allowedPermissions,
'directory' => $directory,
);
}
@@ -163,7 +175,8 @@ if (strpos($dir, '..') === false) {
'originalname' => $files['tmp_name'][$i],
'uploadMaxFilesize' => $maxUploadFileSize,
'maxHumanFilesize' => $maxHumanFileSize,
'permissions' => $meta['permissions'] & $allowedPermissions
'permissions' => $meta['permissions'] & $allowedPermissions,
'directory' => $directory,
);
}
}

View File

@@ -52,6 +52,7 @@ $server->addPlugin(new OC_Connector_Sabre_FilesPlugin());
$server->addPlugin(new OC_Connector_Sabre_AbortedUploadDetectionPlugin());
$server->addPlugin(new OC_Connector_Sabre_QuotaPlugin());
$server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin());
$server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav'));
// And off we go!
$server->exec();

View File

@@ -3,17 +3,14 @@
// fix webdav properties,add namespace in front of the property, update for OC4.5
$installedVersion=OCP\Config::getAppValue('files', 'installed_version');
if (version_compare($installedVersion, '1.1.6', '<')) {
$query = OC_DB::prepare( 'SELECT `propertyname`, `propertypath`, `userid` FROM `*PREFIX*properties`' );
$result = $query->execute();
$updateQuery = OC_DB::prepare('UPDATE `*PREFIX*properties`'
.' SET `propertyname` = ?'
.' WHERE `userid` = ?'
.' AND `propertypath` = ?');
while( $row = $result->fetchRow()) {
if ( $row['propertyname'][0] != '{' ) {
$updateQuery->execute(array('{DAV:}' + $row['propertyname'], $row['userid'], $row['propertypath']));
}
}
$concat = OC_DB::getConnection()->getDatabasePlatform()->
getConcatExpression( '\'{DAV:}\'', '`propertyname`' );
$query = OC_DB::prepare('
UPDATE `*PREFIX*properties`
SET `propertyname` = ' . $concat . '
WHERE `propertyname` NOT LIKE \'{%\'
');
$query->execute();
}
//update from OC 3

View File

@@ -57,6 +57,7 @@ class Scan extends Command {
}
protected function execute(InputInterface $input, OutputInterface $output) {
\OC_App::loadApps('authentication');
if ($input->getOption('all')) {
$users = $this->userManager->search('');
} else {

View File

@@ -65,9 +65,14 @@
top: 44px;
width: 100%;
}
#filestable, #controls {
min-width: 680px;
/* make sure there's enough room for the file actions */
#body-user #filestable {
min-width: 750px;
}
#body-user #controls {
min-width: 600px;
}
#filestable tbody tr { background-color:#fff; height:2.5em; }
#filestable tbody tr:hover, tbody tr:active {
background-color: rgb(240,240,240);
@@ -98,7 +103,7 @@ table td {
}
table th#headerName {
position: relative;
width: 100em; /* not really sure why this works better than 100% … table styling */
width: 9999px; /* not really sure why this works better than 100% … table styling */
padding: 0;
}
#headerName-container {
@@ -140,7 +145,7 @@ table.multiselect thead th {
}
table.multiselect #headerName {
position: relative;
width: 100%;
width: 9999px; /* when we use 100%, the styling breaks on mobile … table styling */
}
table td.selection, table th.selection, table td.fileaction { width:2em; text-align:center; }
table td.filename a.name {
@@ -237,7 +242,7 @@ table td.filename form { font-size:.85em; margin-left:3em; margin-right:3em; }
#fileList tr td.filename a.name label {
position: absolute;
width: 100%;
width: 80%;
height: 50px;
}

View File

@@ -18,9 +18,6 @@
margin: -5px -3px;
cursor: pointer;
z-index: 10;
background-image: url('%webroot%/core/img/actions/upload.svg');
background-repeat: no-repeat;
background-position: center;
opacity: .65;
}
.file_upload_target { display:none; }
@@ -119,11 +116,6 @@
.oc-dialog .fileexists .conflict input[type='checkbox'] {
float: left;
}
.oc-dialog .fileexists .toggle {
background-image: url('%webroot%/core/img/actions/triangle-e.png');
width: 16px;
height: 16px;
}
.oc-dialog .fileexists #allfileslabel {
float:right;
}

View File

@@ -24,6 +24,9 @@
// Check if we are a user
OCP\User::checkLoggedIn();
// don't block php session during download
session_write_close();
$filename = $_GET["file"];
if(!\OC\Files\Filesystem::file_exists($filename)) {
@@ -37,12 +40,7 @@ if(!\OC\Files\Filesystem::file_exists($filename)) {
$ftype=\OC\Files\Filesystem::getMimeType( $filename );
header('Content-Type:'.$ftype);
if ( preg_match( "/MSIE/", $_SERVER["HTTP_USER_AGENT"] ) ) {
header( 'Content-Disposition: attachment; filename="' . rawurlencode( basename($filename) ) . '"' );
} else {
header( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode( basename($filename) )
. '; filename="' . rawurlencode( basename($filename) ) . '"' );
}
OCP\Response::setContentDispositionHeader(basename($filename), 'attachment');
OCP\Response::disableCaching();
header('Content-Length: '.\OC\Files\Filesystem::filesize($filename));

View File

@@ -70,7 +70,7 @@ OC.Upload = {
*/
isProcessing:function() {
var count = 0;
jQuery.each(this._uploads,function(i, data) {
if (data.state() === 'pending') {
count++;
@@ -170,7 +170,7 @@ OC.Upload = {
$(document).ready(function() {
if ( $('#file_upload_start').exists() ) {
if ( $('#file_upload_start').exists()&& $('#file_upload_start').is(':visible') ) {
var file_upload_param = {
dropZone: $('#content'), // restrict dropZone to content div
@@ -196,13 +196,13 @@ $(document).ready(function() {
add: function(e, data) {
OC.Upload.log('add', e, data);
var that = $(this);
// we need to collect all data upload objects before starting the upload so we can check their existence
// and set individual conflict actions. unfortunately there is only one variable that we can use to identify
// the selection a data upload is part of, so we have to collect them in data.originalFiles
// turning singleFileUploads off is not an option because we want to gracefully handle server errors like
// already exists
// create a container where we can store the data objects
if ( ! data.originalFiles.selection ) {
// initialize selection and remember number of files to upload
@@ -213,32 +213,40 @@ $(document).ready(function() {
};
}
var selection = data.originalFiles.selection;
// add uploads
if ( selection.uploads.length < selection.filesToUpload ) {
// remember upload
selection.uploads.push(data);
}
//examine file
var file = data.files[0];
try {
// FIXME: not so elegant... need to refactor that method to return a value
Files.isFileNameValid(file.name, FileList.getCurrentDirectory());
}
catch (errorMessage) {
data.textStatus = 'invalidcharacters';
data.errorThrown = errorMessage;
}
if (file.type === '' && file.size === 4096) {
data.textStatus = 'dirorzero';
data.errorThrown = t('files', 'Unable to upload {filename} as it is a directory or has 0 bytes',
{filename: file.name}
);
}
// add size
selection.totalBytes += file.size;
//check max upload size
if (selection.totalBytes > $('#max_upload').val()) {
data.textStatus = 'notenoughspace';
data.errorThrown = t('files', 'Not enough space available');
}
// end upload for whole selection on error
if (data.errorThrown) {
// trigger fileupload fail
@@ -249,12 +257,12 @@ $(document).ready(function() {
// check existing files when all is collected
if ( selection.uploads.length >= selection.filesToUpload ) {
//remove our selection hack:
delete data.originalFiles.selection;
var callbacks = {
onNoConflicts: function (selection) {
$.each(selection.uploads, function(i, upload) {
upload.submit();
@@ -277,7 +285,7 @@ $(document).ready(function() {
};
OC.Upload.checkExistingFiles(selection, callbacks);
}
return true; // continue adding files
@@ -400,7 +408,7 @@ $(document).ready(function() {
});
fileupload.on('fileuploadstop', function(e, data) {
OC.Upload.log('progress handle fileuploadstop', e, data);
$('#uploadprogresswrapper input.stop').fadeOut();
$('#uploadprogressbar').fadeOut();
Files.updateStorageStatistics();
@@ -492,7 +500,7 @@ $(document).ready(function() {
if ($(this).children('p').length === 0) {
return;
}
$('#new .error').tipsy('hide');
$('#new li').each(function(i,element) {
@@ -506,7 +514,7 @@ $(document).ready(function() {
var text=$(this).children('p').text();
$(this).data('text',text);
$(this).children('p').remove();
// add input field
var form = $('<form></form>');
var input = $('<input type="text">');
@@ -523,7 +531,7 @@ $(document).ready(function() {
throw t('files', 'URL cannot be empty');
} else if (type !== 'web' && !Files.isFileNameValid(filename)) {
// Files.isFileNameValid(filename) throws an exception itself
} else if ($('#dir').val() === '/' && filename === 'Shared') {
} else if (FileList.getCurrentDirectory() === '/' && filename.toLowerCase() === 'shared') {
throw t('files', 'In the home folder \'Shared\' is a reserved filename');
} else if (FileList.inList(filename)) {
throw t('files', '{new_name} already exists', {new_name: filename});
@@ -605,7 +613,7 @@ $(document).ready(function() {
if (result.status === 'success') {
var date=new Date();
FileList.addDir(name, 0, date, hidden);
var tr=$('tr[data-file="'+name+'"]');
var tr = FileList.findFileEl(name);
tr.attr('data-id', result.data.id);
} else {
OC.dialogs.alert(result.data.message, t('core', 'Could not create folder'));
@@ -647,7 +655,7 @@ $(document).ready(function() {
$('#uploadprogressbar').fadeOut();
var date = new Date();
FileList.addFile(localName, size, date, false, hidden);
var tr = $('tr[data-file="'+localName+'"]');
var tr = FileList.findFileEl(localName);
tr.data('mime', mime).data('id', id);
tr.attr('data-id', id);
var path = $('#dir').val()+'/'+localName;

View File

@@ -71,7 +71,7 @@ var FileActions = {
FileActions.currentFile = parent;
var actions = FileActions.get(FileActions.getCurrentMimeType(), FileActions.getCurrentType(), FileActions.getCurrentPermissions());
var file = FileActions.getCurrentFile();
if ($('tr[data-file="'+file+'"]').data('renaming')) {
if (FileList.findFileEl(file).data('renaming')) {
return;
}
@@ -103,9 +103,9 @@ var FileActions = {
}
var html = '<a href="#" class="action" data-action="' + name + '">';
if (img) {
html += '<img class ="svg" src="' + img + '" /> ';
html += '<img class ="svg" src="' + img + '" />';
}
html += t('files', name) + '</a>';
html += '<span> ' + t('files', name) + '</span></a>';
var element = $(html);
element.data('action', name);
@@ -163,13 +163,18 @@ var FileActions = {
};
$(document).ready(function () {
var hasDownloadAction = false;
var downloadScope;
if ($('#allowZipDownload').val() == 1) {
var downloadScope = 'all';
downloadScope = 'all';
} else {
var downloadScope = 'file';
downloadScope = 'file';
}
if (typeof disableDownloadActions == 'undefined' || !disableDownloadActions) {
hasDownloadAction = FileActions.actions[downloadScope] && FileActions.actions[downloadScope].Download;
// do not override download action if it exists (might have been registered by an app already)
if ((typeof disableDownloadActions == 'undefined' || !disableDownloadActions) && !hasDownloadAction) {
FileActions.register(downloadScope, 'Download', OC.PERMISSION_READ, function () {
return OC.imagePath('core', 'actions/download');
}, function (filename) {

View File

@@ -6,6 +6,13 @@ var FileList={
$(this).attr('data-file',decodeURIComponent($(this).attr('data-file')));
});
},
/**
* Returns the tr element for a given file name
*/
findFileEl: function(fileName){
// use filterAttr to avoid escaping issues
return $('#fileList tr').filterAttr('data-file', fileName);
},
update:function(fileListHtml) {
var $fileList = $('#fileList');
$fileList.empty().html(fileListHtml);
@@ -20,6 +27,8 @@ var FileList={
Files.setupDragAndDrop();
}
FileList.updateFileSummary();
procesSelection();
$fileList.trigger(jQuery.Event("updated"));
},
createRow:function(type, name, iconurl, linktarget, size, lastModified, permissions) {
@@ -292,8 +301,12 @@ var FileList={
$('#filestable').toggleClass('hidden', show);
},
remove:function(name){
$('tr').filterAttr('data-file',name).find('td.filename').draggable('destroy');
$('tr').filterAttr('data-file',name).remove();
var fileEl = FileList.findFileEl(name);
if (fileEl.data('permissions') & OC.PERMISSION_DELETE) {
// file is only draggable when delete permissions are set
fileEl.find('td.filename').draggable('destroy');
}
fileEl.remove();
FileList.updateFileSummary();
if ( ! $('tr[data-file]').exists() ) {
$('#emptycontent').removeClass('hidden');
@@ -334,7 +347,7 @@ var FileList={
FileList.updateFileSummary();
},
loadingDone:function(name, id) {
var mime, tr = $('tr[data-file="'+name+'"]');
var mime, tr = FileList.findFileEl(name);
tr.data('loading', false);
mime = tr.data('mime');
tr.attr('data-mime', mime);
@@ -347,12 +360,12 @@ var FileList={
}, null, null, tr.attr('data-etag'));
tr.find('td.filename').draggable(dragOptions);
},
isLoading:function(name) {
return $('tr[data-file="'+name+'"]').data('loading');
isLoading:function(file) {
return FileList.findFileEl(file).data('loading');
},
rename:function(oldname) {
var tr, td, input, form;
tr = $('tr[data-file="'+oldname+'"]');
tr = FileList.findFileEl(oldname);
tr.data('renaming',true);
td = tr.children('td.filename');
input = $('<input type="text" class="filename"/>').val(oldname);
@@ -367,15 +380,12 @@ var FileList={
len = input.val().length;
}
input.selectRange(0, len);
var checkInput = function () {
var filename = input.val();
if (filename !== oldname) {
if (!Files.isFileNameValid(filename)) {
// Files.isFileNameValid(filename) throws an exception itself
} else if($('#dir').val() === '/' && filename === 'Shared') {
throw t('files','In the home folder \'Shared\' is a reserved filename');
} else if (FileList.inList(filename)) {
// Files.isFileNameValid(filename) throws an exception itself
Files.isFileNameValid(filename, FileList.getCurrentDirectory());
if (FileList.inList(filename)) {
throw t('files', '{new_name} already exists', {new_name: filename});
}
}
@@ -500,14 +510,16 @@ var FileList={
form.trigger('submit');
});
},
inList:function(filename) {
return $('#fileList tr[data-file="'+filename+'"]').length;
inList:function(file) {
return FileList.findFileEl(file).length;
},
replace:function(oldName, newName, isNewFile) {
// Finish any existing actions
$('tr[data-file="'+oldName+'"]').hide();
$('tr[data-file="'+newName+'"]').hide();
var tr = $('tr[data-file="'+oldName+'"]').clone();
var oldFileEl = FileList.findFileEl(oldName);
var newFileEl = FileList.findFileEl(newName);
oldFileEl.hide();
newFileEl.hide();
var tr = oldFileEl.clone();
tr.attr('data-replace', 'true');
tr.attr('data-file', newName);
var td = tr.children('td.filename');
@@ -559,7 +571,7 @@ var FileList={
files=[files];
}
for (var i=0; i<files.length; i++) {
var deleteAction = $('tr[data-file="'+files[i]+'"]').children("td.date").children(".action.delete");
var deleteAction = FileList.findFileEl(files[i]).children("td.date").children(".action.delete");
deleteAction.removeClass('delete-icon').addClass('progress-icon');
}
// Finish any existing actions
@@ -573,7 +585,7 @@ var FileList={
function(result) {
if (result.status === 'success') {
$.each(files,function(index,file) {
var files = $('tr[data-file="'+file+'"]');
var files = FileList.findFileEl(file);
files.remove();
files.find('input[type="checkbox"]').removeAttr('checked');
files.removeClass('selected');
@@ -595,7 +607,7 @@ var FileList={
OC.Notification.hide();
}, 10000);
$.each(files,function(index,file) {
var deleteAction = $('tr[data-file="' + file + '"] .action.delete');
var deleteAction = FileList.findFileEl(file).find('.action.delete');
deleteAction.removeClass('progress-icon').addClass('delete-icon');
});
}
@@ -737,7 +749,7 @@ var FileList={
},
scrollTo:function(file) {
//scroll to and highlight preselected file
var $scrolltorow = $('tr[data-file="'+file+'"]');
var $scrolltorow = FileList.findFileEl(file);
if ($scrolltorow.exists()) {
$scrolltorow.addClass('searchresult');
$(window).scrollTop($scrolltorow.position().top);
@@ -880,8 +892,8 @@ $(document).ready(function() {
data.context.find('td.filesize').text(humanFileSize(size));
} else {
// only append new file if dragged onto current dir's crumb (last)
if (data.context && data.context.hasClass('crumb') && !data.context.hasClass('last')) {
// only append new file if uploaded into the current folder
if (file.directory !== FileList.getCurrentDirectory()) {
return;
}
@@ -949,7 +961,7 @@ $(document).ready(function() {
$('#notification').on('click', '.undo', function() {
if (FileList.deleteFiles) {
$.each(FileList.deleteFiles,function(index,file) {
$('tr[data-file="'+file+'"]').show();
FileList.findFileEl(file).show();
});
FileList.deleteCanceled=true;
FileList.deleteFiles=null;
@@ -959,10 +971,10 @@ $(document).ready(function() {
FileList.deleteCanceled = false;
FileList.deleteFiles = [FileList.replaceOldName];
} else {
$('tr[data-file="'+FileList.replaceOldName+'"]').show();
FileList.findFileEl(FileList.replaceOldName).show();
}
$('tr[data-replace="true"').remove();
$('tr[data-file="'+FileList.replaceNewName+'"]').show();
FileList.findFileEl(FileList.replaceNewName).show();
FileList.replaceCanceled = true;
FileList.replaceOldName = null;
FileList.replaceNewName = null;
@@ -977,7 +989,8 @@ $(document).ready(function() {
});
});
$('#notification:first-child').on('click', '.suggest', function() {
$('tr[data-file="'+$('#notification > span').attr('data-oldName')+'"]').show();
var file = $('#notification > span').attr('data-oldName');
FileList.findFileEl(file).show();
OC.Notification.hide();
});
$('#notification:first-child').on('click', '.cancel', function() {

View File

@@ -67,10 +67,21 @@ Files={
return fileName;
},
isFileNameValid:function (name) {
if (name === '.') {
throw t('files', '\'.\' is an invalid file name.');
} else if (name.length === 0) {
/**
* Checks whether the given file name is valid.
* @param name file name to check
* @return true if the file name is valid.
* Throws a string exception with an error message if
* the file name is not valid
*/
isFileNameValid: function (name, root) {
var trimmedName = name.trim();
if (trimmedName === '.'
|| trimmedName === '..'
|| (root === '/' && trimmedName.toLowerCase() === 'shared'))
{
throw t('files', '"{name}" is an invalid file name.', {name: name});
} else if (trimmedName.length === 0) {
throw t('files', 'File name cannot be empty.');
}
@@ -282,7 +293,7 @@ $(document).ready(function() {
procesSelection();
} else {
var filename=$(this).parent().parent().attr('data-file');
var tr=$('tr[data-file="'+filename+'"]');
var tr = FileList.findFileEl(filename);
var renaming=tr.data('renaming');
if (!renaming && !FileList.isLoading(filename)) {
FileActions.currentFile = $(this).parent();
@@ -350,7 +361,12 @@ $(document).ready(function() {
// use special download URL if provided, e.g. for public shared files
var downloadURL = document.getElementById("downloadURL");
if ( downloadURL ) {
window.location = downloadURL.value+"&download&files=" + encodeURIComponent(fileslist);
// downloading all in root of public share ? (replacement for old "Download" button)
if ($('#isPublic').val() && dir === '/' && $('#select_all').is(':checked')) {
window.location = downloadURL.value;
} else {
window.location = downloadURL.value+"&download&files=" + encodeURIComponent(fileslist);
}
} else {
window.location = OC.filePath('files', 'ajax', 'download.php') + '?'+ $.param({ dir: dir, files: fileslist });
}
@@ -541,10 +557,12 @@ var folderDropOptions={
if (result) {
if (result.status === 'success') {
//recalculate folder size
var oldSize = $('#fileList tr[data-file="'+target+'"]').data('size');
var newSize = oldSize + $('#fileList tr[data-file="'+file+'"]').data('size');
$('#fileList tr[data-file="'+target+'"]').data('size', newSize);
$('#fileList tr[data-file="'+target+'"]').find('td.filesize').text(humanFileSize(newSize));
var oldFile = FileList.findFileEl(target);
var newFile = FileList.findFileEl(file);
var oldSize = oldFile.data('size');
var newSize = oldSize + newFile.data('size');
oldFile.data('size', newSize);
oldFile.find('td.filesize').text(humanFileSize(newSize));
FileList.remove(file);
procesSelection();
@@ -610,11 +628,12 @@ function procesSelection() {
return el.type==='dir';
});
if (selectedFiles.length === 0 && selectedFolders.length === 0) {
$('#headerName>span.name').text(t('files','Name'));
$('#headerName span.name').text(t('files','Name'));
$('#headerSize').text(t('files','Size'));
$('#modified').text(t('files','Modified'));
$('table').removeClass('multiselect');
$('.selectedActions').hide();
$('#select_all').removeAttr('checked');
}
else {
$('.selectedActions').show();
@@ -717,7 +736,7 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) {
console.warn('Files.lazyLoadPreview(): missing etag argument');
}
if ( $('#publicUploadButtonMock').length ) {
if ( $('#isPublic').length ) {
urlSpec.t = $('#dirToken').val();
previewURL = OC.Router.generate('core_ajax_public_preview', urlSpec);
} else {
@@ -738,7 +757,7 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) {
}
function getUniqueName(name) {
if ($('tr[data-file="'+name+'"]').exists()) {
if (FileList.findFileEl(name).exists()) {
var parts=name.split('.');
var extension = "";
if (parts.length > 1) {

View File

@@ -1,5 +0,0 @@
<?php
$TRANSLATIONS = array(
"Save" => "Zapisz"
);
$PLURAL_FORMS = "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);";

View File

@@ -1,17 +0,0 @@
<?php
$TRANSLATIONS = array(
"Files" => "Файлы",
"Share" => "Сделать общим",
"Rename" => "Переименовать",
"_%n folder_::_%n folders_" => array("","",""),
"_%n file_::_%n files_" => array("","",""),
"_Uploading %n file_::_Uploading %n files_" => array("","",""),
"Error" => "Ошибка",
"Size" => "Размер",
"Upload" => "Загрузка",
"Save" => "Сохранить",
"Cancel upload" => "Отмена загрузки",
"Download" => "Загрузка",
"Delete" => "Удалить"
);
$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);";

View File

@@ -3,8 +3,8 @@
<span class="what">{what}<!-- If you select both versions, the copied file will have a number added to its name. --></span><br/>
<br/>
<table>
<th><label><input class="allnewfiles" type="checkbox" />New Files<span class="count"></span></label></th>
<th><label><input class="allexistingfiles" type="checkbox" />Already existing files<span class="count"></span></label></th>
<th><label><input class="allnewfiles" type="checkbox" />{allnewfiles}<span class="count"></span></label></th>
<th><label><input class="allexistingfiles" type="checkbox" />{allexistingfiles}<span class="count"></span></label></th>
</table>
<div class="conflicts">
<div class="template">

View File

@@ -1,6 +1,7 @@
<div id="controls">
<?php print_unescaped($_['breadcrumb']); ?>
<div class="actions creatable <?php if (!$_['isCreatable']):?>hidden<?php endif; ?>">
<?php if(!isset($_['dirToken'])):?>
<div id="new" class="button">
<a><?php p($l->t('New'));?></a>
<ul>
@@ -12,21 +13,26 @@
data-type='web'><p><?php p($l->t('From link'));?></p></li>
</ul>
</div>
<?php endif;?>
<div id="upload" class="button"
title="<?php p($l->t('Upload') . ' max. '.$_['uploadMaxHumanFilesize']) ?>">
<?php if($_['uploadMaxFilesize'] >= 0):?>
<input type="hidden" name="MAX_FILE_SIZE" id="max_upload"
value="<?php p($_['uploadMaxFilesize']) ?>">
<?php endif;?>
<?php if(isset($_['dirToken'])):?>
<input type="hidden" id="publicUploadRequestToken" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
<input type="hidden" id="dirToken" name="dirToken" value="<?php p($_['dirToken']) ?>" />
<?php endif;?>
<input type="hidden" class="max_human_file_size"
value="(max <?php p($_['uploadMaxHumanFilesize']); ?>)">
<input type="hidden" name="dir" value="<?php p($_['dir']) ?>" id="dir">
<input type="file" id="file_upload_start" name='files[]'
data-url="<?php print_unescaped(OCP\Util::linkTo('files', 'ajax/upload.php')); ?>" />
<a href="#" class="svg"></a>
<a href="#" class="svg icon icon-upload"></a>
</div>
<?php if ($_['trash']): ?>
<input id="trash" type="button" value="<?php p($l->t('Deleted files'));?>" class="button" <?php $_['trashEmpty'] ? p('disabled') : '' ?>></input>
<input id="trash" type="button" value="<?php p($l->t('Deleted files'));?>" class="button" <?php $_['trashEmpty'] ? p('disabled') : '' ?> />
<?php endif; ?>
<div id="uploadprogresswrapper">
<div id="uploadprogressbar"></div>
@@ -44,7 +50,7 @@
<div id="emptycontent" <?php if (!$_['emptyContent']):?>class="hidden"<?php endif; ?>><?php p($l->t('Nothing in here. Upload something!'))?></div>
<input type="hidden" id="disableSharing" data-status="<?php p($_['disableSharing']); ?>"></input>
<input type="hidden" id="disableSharing" data-status="<?php p($_['disableSharing']); ?>" />
<table id="filestable" data-allow-public-upload="<?php p($_['publicUploadEnabled'])?>" data-preview-x="36" data-preview-y="36">
<thead>
@@ -69,20 +75,11 @@
<th <?php if (!$_['fileHeader']):?>class="hidden"<?php endif; ?> id="headerDate">
<span id="modified"><?php p($l->t( 'Modified' )); ?></span>
<?php if ($_['permissions'] & OCP\PERMISSION_DELETE): ?>
<!-- NOTE: Temporary fix to allow unsharing of files in root of Shared folder -->
<?php if ($_['dir'] == '/Shared'): ?>
<span class="selectedActions"><a href="" class="delete-selected">
<?php p($l->t('Unshare'))?>
<img class="svg" alt="<?php p($l->t('Unshare'))?>"
src="<?php print_unescaped(OCP\image_path("core", "actions/delete.svg")); ?>" />
</a></span>
<?php else: ?>
<span class="selectedActions"><a href="" class="delete-selected">
<?php p($l->t('Delete'))?>
<img class="svg" alt="<?php p($l->t('Delete'))?>"
src="<?php print_unescaped(OCP\image_path("core", "actions/delete.svg")); ?>" />
</a></span>
<?php endif; ?>
<span class="selectedActions"><a href="" class="delete-selected">
<?php p($l->t('Delete'))?>
<img class="svg" alt="<?php p($l->t('Delete'))?>"
src="<?php print_unescaped(OCP\image_path("core", "actions/delete.svg")); ?>" />
</a></span>
<?php endif; ?>
</th>
</tr>

View File

@@ -1,10 +1,8 @@
<?php if(count($_["breadcrumb"])):?>
<div class="crumb" data-dir=''>
<a href="<?php print_unescaped($_['baseURL']); ?>">
<img src="<?php print_unescaped(OCP\image_path('core', 'places/home.svg'));?>" class="svg" />
</a>
</div>
<?php endif;?>
<div class="crumb <?php if(!count($_["breadcrumb"])) p('last');?>" data-dir=''>
<a href="<?php print_unescaped($_['baseURL']); ?>">
<img src="<?php print_unescaped(OCP\image_path('core', 'places/home.svg'));?>" class="svg" />
</a>
</div>
<?php for($i=0; $i<count($_["breadcrumb"]); $i++):
$crumb = $_["breadcrumb"][$i];
$dir = \OCP\Util::encodePath($crumb["dir"]); ?>

View File

@@ -18,7 +18,7 @@ $totalsize = 0; ?>
data-size="<?php p($file['size']);?>"
data-etag="<?php p($file['etag']);?>"
data-permissions="<?php p($file['permissions']); ?>">
<?php if($file['isPreviewAvailable']): ?>
<?php if(isset($file['isPreviewAvailable']) and $file['isPreviewAvailable']): ?>
<td class="filename svg preview-icon"
<?php else: ?>
<td class="filename svg"
@@ -34,17 +34,15 @@ $totalsize = 0; ?>
<span class="nametext">
<?php print_unescaped(htmlspecialchars($file['name']));?>
</span>
<span class="uploadtext" currentUploads="0">
</span>
</a>
<?php else: ?>
<a class="name" href="<?php p(rtrim($_['downloadURL'],'/').'/'.trim($directory,'/').'/'.$name); ?>">
<label class="filetext" title="" for="select-<?php p($file['fileid']); ?>"></label>
<span class="nametext"><?php print_unescaped(htmlspecialchars($file['basename']));?><span class='extension'><?php p($file['extension']);?></span></span>
</a>
<?php endif; ?>
<?php if($file['type'] == 'dir'):?>
<span class="uploadtext" currentUploads="0">
</span>
<?php endif;?>
</a>
</td>
<td class="filesize"
style="color:rgb(<?php p($simple_size_color.','.$simple_size_color.','.$simple_size_color) ?>)">

View File

@@ -6,6 +6,7 @@ if (OC::$CLI) {
if (count($argv) === 2) {
$file = $argv[1];
list(, $user) = explode('/', $file);
OCP\JSON::checkUserExists($owner);
OC_Util::setupFS($user);
$view = new \OC\Files\View('');
/**

View File

@@ -13,16 +13,14 @@ use OCA\Encryption\Util;
$loginname = isset($_POST['user']) ? $_POST['user'] : '';
$password = isset($_POST['password']) ? $_POST['password'] : '';
$migrationCompleted = true;
$migrationStatus = Util::MIGRATION_COMPLETED;
if ($loginname !== '' && $password !== '') {
$username = \OCP\User::checkPassword($loginname, $password);
if ($username) {
$util = new Util(new \OC_FilesystemView('/'), $username);
if ($util->getMigrationStatus() !== Util::MIGRATION_COMPLETED) {
$migrationCompleted = false;
}
$migrationStatus = $util->getMigrationStatus();
}
}
\OCP\JSON::success(array('data' => array('migrationCompleted' => $migrationCompleted)));
\OCP\JSON::success(array('data' => array('migrationStatus' => $migrationStatus)));

View File

@@ -10,6 +10,7 @@ OC::$CLASSPATH['OCA\Encryption\Session'] = 'files_encryption/lib/session.php';
OC::$CLASSPATH['OCA\Encryption\Capabilities'] = 'files_encryption/lib/capabilities.php';
OC::$CLASSPATH['OCA\Encryption\Helper'] = 'files_encryption/lib/helper.php';
\OCP\Util::addscript('files_encryption', 'encryption');
\OCP\Util::addscript('files_encryption', 'detect-migration');
if (!OC_Config::getValue('maintenance', false)) {

View File

@@ -18,22 +18,19 @@
<type>text</type>
<notnull>true</notnull>
<length>64</length>
<comments>What client-side / server-side configuration is used</comments>
</field>
<field>
<name>recovery_enabled</name>
<type>integer</type>
<notnull>true</notnull>
<default>0</default>
<comments>Whether encryption key recovery is enabled</comments>
</field>
<field>
<name>migration_status</name>
<type>integer</type>
<notnull>true</notnull>
<default>0</default>
<comments>Whether encryption migration has been performed</comments>
</field>
</declaration>
</table>
</database>
</database>

View File

@@ -2,11 +2,15 @@
<info>
<id>files_encryption</id>
<name>Encryption</name>
<description>The new ownCloud 5 files encryption system. After the app was enabled you need to re-login to initialize your encryption keys.</description>
<description>The ownCloud files encryption system provides server side-encryption. After the app was enabled you need to re-login to initialize your encryption keys.</description>
<licence>AGPL</licence>
<author>Sam Tuke, Bjoern Schiessle, Florin Peter</author>
<require>4</require>
<shipped>true</shipped>
<documentation>
<user>http://doc.owncloud.org/server/6.0/user_manual/files/encryption.html</user>
<admin>http://doc.owncloud.org/server/6.0/admin_manual/configuration/configuration_encryption.html</admin>
</documentation>
<rememberlogin>false</rememberlogin>
<types>
<filesystem/>

View File

@@ -30,6 +30,11 @@ use OC\Files\Filesystem;
*/
class Hooks {
// file for which we want to rename the keys after the rename operation was successful
private static $renamedFiles = array();
// file for which we want to delete the keys after the delete operation was successful
private static $deleteFiles = array();
/**
* @brief Startup encryption backend upon user login
* @note This method should never be called for users using client side encryption
@@ -75,8 +80,14 @@ class Hooks {
// Check if first-run file migration has already been performed
$ready = false;
if ($util->getMigrationStatus() === Util::MIGRATION_OPEN) {
$migrationStatus = $util->getMigrationStatus();
if ($migrationStatus === Util::MIGRATION_OPEN && $session !== false) {
$ready = $util->beginMigration();
} elseif ($migrationStatus === Util::MIGRATION_IN_PROGRESS) {
// refuse login as long as the initial encryption is running
sleep(5);
\OCP\User::logout();
return false;
}
// If migration not yet done
@@ -90,28 +101,32 @@ class Hooks {
$userView->file_exists('encryption.key')
&& $encLegacyKey = $userView->file_get_contents('encryption.key')
) {
$plainLegacyKey = Crypt::legacyDecrypt($encLegacyKey, $params['password']);
$plainLegacyKey = Crypt::legacyDecrypt($encLegacyKey, $params['password']);
$session->setLegacyKey($plainLegacyKey);
$session->setLegacyKey($plainLegacyKey);
}
// Encrypt existing user files:
if (
$util->encryptAll('/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password'])
) {
// Encrypt existing user files
try {
$result = $util->encryptAll('/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password']);
} catch (\Exception $ex) {
\OCP\Util::writeLog('Encryption library', 'Initial encryption failed! Error: ' . $ex->getMessage(), \OCP\Util::FATAL);
$util->resetMigrationStatus();
\OCP\User::logout();
$result = false;
}
if ($result) {
\OC_Log::write(
'Encryption library', 'Encryption of existing files belonging to "' . $params['uid'] . '" completed'
, \OC_Log::INFO
);
// Register successful migration in DB
$util->finishMigration();
}
// Register successful migration in DB
$util->finishMigration();
}
return true;
@@ -179,9 +194,9 @@ class Hooks {
// the necessary keys)
if (Crypt::mode() === 'server') {
if ($params['uid'] === \OCP\User::getUser()) {
$view = new \OC_FilesystemView('/');
$view = new \OC_FilesystemView('/');
if ($params['uid'] === \OCP\User::getUser()) {
$session = new \OCA\Encryption\Session($view);
@@ -202,36 +217,45 @@ class Hooks {
} else { // admin changed the password for a different user, create new keys and reencrypt file keys
$user = $params['uid'];
$recoveryPassword = $params['recoveryPassword'];
$newUserPassword = $params['password'];
$util = new Util($view, $user);
$recoveryPassword = isset($params['recoveryPassword']) ? $params['recoveryPassword'] : null;
$view = new \OC_FilesystemView('/');
// we generate new keys if...
// ...we have a recovery password and the user enabled the recovery key
// ...encryption was activated for the first time (no keys exists)
// ...the user doesn't have any files
if (($util->recoveryEnabledForUser() && $recoveryPassword)
|| !$util->userKeysExists()
|| !$view->file_exists($user . '/files')) {
// make sure that the users home is mounted
\OC\Files\Filesystem::initMountPoints($user);
$newUserPassword = $params['password'];
$keypair = Crypt::createKeypair();
// make sure that the users home is mounted
\OC\Files\Filesystem::initMountPoints($user);
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$keypair = Crypt::createKeypair();
// Save public key
$view->file_put_contents('/public-keys/' . $user . '.public.key', $keypair['publicKey']);
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
// Encrypt private key empty passphrase
$encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $newUserPassword);
// Save public key
$view->file_put_contents('/public-keys/' . $user . '.public.key', $keypair['publicKey']);
// Save private key
$view->file_put_contents(
'/' . $user . '/files_encryption/' . $user . '.private.key', $encryptedPrivateKey);
// Encrypt private key empty passphrase
$encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $newUserPassword);
if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files
$util = new Util($view, $user);
$util->recoverUsersFiles($recoveryPassword);
// Save private key
$view->file_put_contents(
'/' . $user . '/files_encryption/' . $user . '.private.key', $encryptedPrivateKey);
if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files
$util = new Util($view, $user);
$util->recoverUsersFiles($recoveryPassword);
}
\OC_FileProxy::$enabled = $proxyStatus;
}
\OC_FileProxy::$enabled = $proxyStatus;
}
}
}
@@ -474,6 +498,27 @@ class Hooks {
}
}
/**
* @brief mark file as renamed so that we know the original source after the file was renamed
* @param array $params with the old path and the new path
*/
public static function preRename($params) {
$user = \OCP\User::getUser();
$view = new \OC_FilesystemView('/');
$util = new Util($view, $user);
list($ownerOld, $pathOld) = $util->getUidAndFilename($params['oldpath']);
// we only need to rename the keys if the rename happens on the same mountpoint
// otherwise we perform a stream copy, so we get a new set of keys
$mp1 = $view->getMountPoint('/' . $user . '/files/' . $params['oldpath']);
$mp2 = $view->getMountPoint('/' . $user . '/files/' . $params['newpath']);
if ($mp1 === $mp2) {
self::$renamedFiles[$params['oldpath']] = array(
'uid' => $ownerOld,
'path' => $pathOld);
}
}
/**
* @brief after a file is renamed, rename its keyfile and share-keys also fix the file size and fix also the sharing
* @param array with oldpath and newpath
@@ -496,19 +541,32 @@ class Hooks {
$userId = \OCP\User::getUser();
$util = new Util($view, $userId);
// Format paths to be relative to user files dir
if ($util->isSystemWideMountPoint($params['oldpath'])) {
$baseDir = 'files_encryption/';
$oldKeyfilePath = $baseDir . 'keyfiles/' . $params['oldpath'];
if (isset(self::$renamedFiles[$params['oldpath']]['uid']) &&
isset(self::$renamedFiles[$params['oldpath']]['path'])) {
$ownerOld = self::$renamedFiles[$params['oldpath']]['uid'];
$pathOld = self::$renamedFiles[$params['oldpath']]['path'];
} else {
$baseDir = $userId . '/' . 'files_encryption/';
$oldKeyfilePath = $baseDir . 'keyfiles/' . $params['oldpath'];
\OCP\Util::writeLog('Encryption library', "can't get path and owner from the file before it was renamed", \OCP\Util::ERROR);
return false;
}
if ($util->isSystemWideMountPoint($params['newpath'])) {
$newKeyfilePath = $baseDir . 'keyfiles/' . $params['newpath'];
list($ownerNew, $pathNew) = $util->getUidAndFilename($params['newpath']);
// Format paths to be relative to user files dir
if ($util->isSystemWideMountPoint($pathOld)) {
$oldKeyfilePath = 'files_encryption/keyfiles/' . $pathOld;
$oldShareKeyPath = 'files_encryption/share-keys/' . $pathOld;
} else {
$newKeyfilePath = $baseDir . 'keyfiles/' . $params['newpath'];
$oldKeyfilePath = $ownerOld . '/' . 'files_encryption/keyfiles/' . $pathOld;
$oldShareKeyPath = $ownerOld . '/' . 'files_encryption/share-keys/' . $pathOld;
}
if ($util->isSystemWideMountPoint($pathNew)) {
$newKeyfilePath = 'files_encryption/keyfiles/' . $pathNew;
$newShareKeyPath = 'files_encryption/share-keys/' . $pathNew;
} else {
$newKeyfilePath = $ownerNew . '/files_encryption/keyfiles/' . $pathNew;
$newShareKeyPath = $ownerNew . '/files_encryption/share-keys/' . $pathNew;
}
// add key ext if this is not an folder
@@ -517,11 +575,11 @@ class Hooks {
$newKeyfilePath .= '.key';
// handle share-keys
$localKeyPath = $view->getLocalFile($baseDir . 'share-keys/' . $params['oldpath']);
$localKeyPath = $view->getLocalFile($oldShareKeyPath);
$escapedPath = Helper::escapeGlobPattern($localKeyPath);
$matches = glob($escapedPath . '*.shareKey');
foreach ($matches as $src) {
$dst = \OC\Files\Filesystem::normalizePath(str_replace($params['oldpath'], $params['newpath'], $src));
$dst = \OC\Files\Filesystem::normalizePath(str_replace($pathOld, $pathNew, $src));
// create destination folder if not exists
if (!file_exists(dirname($dst))) {
@@ -533,15 +591,13 @@ class Hooks {
} else {
// handle share-keys folders
$oldShareKeyfilePath = $baseDir . 'share-keys/' . $params['oldpath'];
$newShareKeyfilePath = $baseDir . 'share-keys/' . $params['newpath'];
// create destination folder if not exists
if (!$view->file_exists(dirname($newShareKeyfilePath))) {
$view->mkdir(dirname($newShareKeyfilePath), 0750, true);
if (!$view->file_exists(dirname($newShareKeyPath))) {
mkdir($view->getLocalFile($newShareKeyPath), 0750, true);
}
$view->rename($oldShareKeyfilePath, $newShareKeyfilePath);
$view->rename($oldShareKeyPath, $newShareKeyPath);
}
// Rename keyfile so it isn't orphaned
@@ -549,25 +605,24 @@ class Hooks {
// create destination folder if not exists
if (!$view->file_exists(dirname($newKeyfilePath))) {
$view->mkdir(dirname($newKeyfilePath), 0750, true);
mkdir(dirname($view->getLocalFile($newKeyfilePath)), 0750, true);
}
$view->rename($oldKeyfilePath, $newKeyfilePath);
}
// build the path to the file
$newPath = '/' . $userId . '/files' . $params['newpath'];
$newPathRelative = $params['newpath'];
$newPath = '/' . $ownerNew . '/files' . $pathNew;
if ($util->fixFileSize($newPath)) {
// get sharing app state
$sharingEnabled = \OCP\Share::isEnabled();
// get users
$usersSharing = $util->getSharingUsersArray($sharingEnabled, $newPathRelative);
$usersSharing = $util->getSharingUsersArray($sharingEnabled, $pathNew);
// update sharing-keys
$util->setSharedFileKeyfiles($session, $usersSharing, $newPathRelative);
$util->setSharedFileKeyfiles($session, $usersSharing, $pathNew);
}
\OC_FileProxy::$enabled = $proxyStatus;
@@ -600,4 +655,66 @@ class Hooks {
}
}
/**
* @brief if the file was really deleted we remove the encryption keys
* @param array $params
* @return boolean
*/
public static function postDelete($params) {
if (!isset(self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]])) {
return true;
}
$deletedFile = self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]];
$path = $deletedFile['path'];
$user = $deletedFile['uid'];
// we don't need to remember the file any longer
unset(self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]]);
$view = new \OC\Files\View('/');
// return if the file still exists and wasn't deleted correctly
if ($view->file_exists('/' . $user . '/files/' . $path)) {
return true;
}
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
// Delete keyfile & shareKey so it isn't orphaned
if (!Keymanager::deleteFileKey($view, $path, $user)) {
\OCP\Util::writeLog('Encryption library',
'Keyfile or shareKey could not be deleted for file "' . $user.'/files/'.$path . '"', \OCP\Util::ERROR);
}
Keymanager::delAllShareKeys($view, $user, $path);
\OC_FileProxy::$enabled = $proxyStatus;
}
/**
* @brief remember the file which should be deleted and it's owner
* @param array $params
* @return boolean
*/
public static function preDelete($params) {
$path = $params[\OC\Files\Filesystem::signal_param_path];
// skip this method if the trash bin is enabled or if we delete a file
// outside of /data/user/files
if (\OCP\App::isEnabled('files_trashbin')) {
return true;
}
$util = new Util(new \OC_FilesystemView('/'), \OCP\USER::getUser());
list($owner, $ownerPath) = $util->getUidAndFilename($path);
self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]] = array(
'uid' => $owner,
'path' => $ownerPath);
}
}

View File

@@ -17,10 +17,14 @@ $(document).ready(function(){
data: {user: user, password: password},
async: false,
success: function(response) {
if (response.data.migrationCompleted === false) {
if (response.data.migrationStatus === OC.Encryption.MIGRATION_OPEN) {
var message = t('files_encryption', 'Initial encryption started... This can take some time. Please wait.');
$('#messageText').text(message);
$('#message').removeClass('hidden').addClass('update');
} else if (response.data.migrationStatus === OC.Encryption.MIGRATION_IN_PROGRESS) {
var message = t('files_encryption', 'Initial encryption running... Please try again later.');
$('#messageText').text(message);
$('#message').removeClass('hidden').addClass('update');
}
}
});

View File

@@ -0,0 +1,12 @@
/**
* Copyright (c) 2014
* Bjoern Schiessle <schiessle@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*/
OC.Encryption={
MIGRATION_OPEN:0,
MIGRATION_COMPLETED:1,
MIGRATION_IN_PROGRESS:-1,
};

View File

@@ -29,6 +29,8 @@ namespace OCA\Encryption;
*/
class Helper {
private static $tmpFileMapping; // Map tmp files to files in data/user/files
/**
* @brief register share related hooks
*
@@ -59,7 +61,10 @@ class Helper {
*/
public static function registerFilesystemHooks() {
\OCP\Util::connectHook('OC_Filesystem', 'rename', 'OCA\Encryption\Hooks', 'preRename');
\OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename');
\OCP\Util::connectHook('OC_Filesystem', 'post_delete', 'OCA\Encryption\Hooks', 'postDelete');
\OCP\Util::connectHook('OC_Filesystem', 'delete', 'OCA\Encryption\Hooks', 'preDelete');
}
/**
@@ -274,7 +279,7 @@ class Helper {
$split = explode('/', $trimmed);
// it is not a file relative to data/user/files
if (count($split) < 2 || $split[1] !== 'files') {
if (count($split) < 2 || ($split[1] !== 'files' && $split[1] !== 'cache')) {
return false;
}
@@ -370,7 +375,14 @@ class Helper {
* @return bool true if requirements are met
*/
public static function checkRequirements() {
return extension_loaded('openssl');
$result = true;
//openssl extension needs to be loaded
$result &= extension_loaded("openssl");
// we need php >= 5.3.3
$result &= version_compare(phpversion(), '5.3.3', '>=');
return (bool) $result;
}
/**
@@ -416,5 +428,27 @@ class Helper {
public static function escapeGlobPattern($path) {
return preg_replace('/(\*|\?|\[)/', '[$1]', $path);
}
/**
* @brief remember from which file the tmp file (getLocalFile() call) was created
* @param string $tmpFile path of tmp file
* @param string $originalFile path of the original file relative to data/
*/
public static function addTmpFileToMapper($tmpFile, $originalFile) {
self::$tmpFileMapping[$tmpFile] = $originalFile;
}
/**
* @brief get the path of the original file
* @param string $tmpFile path of the tmp file
* @return mixed path of the original file or false
*/
public static function getPathFromTmpFile($tmpFile) {
if (isset(self::$tmpFileMapping[$tmpFile])) {
return self::$tmpFileMapping[$tmpFile];
}
return false;
}
}

View File

@@ -32,12 +32,12 @@ class Keymanager {
/**
* @brief retrieve the ENCRYPTED private key from a user
*
* @param \OC_FilesystemView $view
* @param \OC\Files\View $view
* @param string $user
* @return string private key or false (hopefully)
* @note the key returned by this method must be decrypted before use
*/
public static function getPrivateKey(\OC_FilesystemView $view, $user) {
public static function getPrivateKey($view, $user) {
$path = '/' . $user . '/' . 'files_encryption' . '/' . $user . '.private.key';
$key = false;
@@ -214,15 +214,24 @@ class Keymanager {
*
* @param \OC_FilesystemView $view
* @param string $path path of the file the key belongs to
* @param string $userId the user to whom the file belongs
* @return bool Outcome of unlink operation
* @note $path must be relative to data/user/files. e.g. mydoc.txt NOT
* /data/admin/files/mydoc.txt
*/
public static function deleteFileKey(\OC_FilesystemView $view, $path) {
public static function deleteFileKey($view, $path, $userId=null) {
$trimmed = ltrim($path, '/');
$userId = Helper::getUser($path);
if ($trimmed === '') {
\OCP\Util::writeLog('Encryption library',
'Can\'t delete file-key empty path given!', \OCP\Util::ERROR);
return false;
}
if ($userId === null) {
$userId = Helper::getUser($path);
}
$util = new Util($view, $userId);
if($util->isSystemWideMountPoint($path)) {
@@ -402,7 +411,15 @@ class Keymanager {
* @param string $userId owner of the file
* @param string $filePath path to the file, relative to the owners file dir
*/
public static function delAllShareKeys(\OC_FilesystemView $view, $userId, $filePath) {
public static function delAllShareKeys($view, $userId, $filePath) {
$filePath = ltrim($filePath, '/');
if ($filePath === '') {
\OCP\Util::writeLog('Encryption library',
'Can\'t delete share-keys empty path given!', \OCP\Util::ERROR);
return false;
}
$util = new util($view, $userId);
@@ -413,17 +430,15 @@ class Keymanager {
}
if ($view->is_dir($userId . '/files/' . $filePath)) {
if ($view->is_dir($baseDir . $filePath)) {
$view->unlink($baseDir . $filePath);
} else {
$localKeyPath = $view->getLocalFile($baseDir . $filePath);
$escapedPath = Helper::escapeGlobPattern($localKeyPath);
$matches = glob($escapedPath . '*.shareKey');
foreach ($matches as $ma) {
$result = unlink($ma);
if (!$result) {
\OCP\Util::writeLog('Encryption library',
'Keyfile or shareKey could not be deleted for file "' . $filePath . '"', \OCP\Util::ERROR);
$parentDir = dirname($baseDir . $filePath);
$filename = pathinfo($filePath, PATHINFO_BASENAME);
foreach($view->getDirectoryContent($parentDir) as $content) {
$path = $content['path'];
if (self::getFilenameFromShareKey($content['name']) === $filename) {
$view->unlink('/' . $userId . '/' . $path);
}
}
}
@@ -523,4 +538,20 @@ class Keymanager {
return $targetPath;
}
/**
* @brief extract filename from share key name
* @param string $shareKey (filename.userid.sharekey)
* @return mixed filename or false
*/
protected static function getFilenameFromShareKey($shareKey) {
$parts = explode('.', $shareKey);
$filename = false;
if(count($parts) > 2) {
$filename = implode('.', array_slice($parts, 0, count($parts)-2));
}
return $filename;
}
}

View File

@@ -37,6 +37,8 @@ namespace OCA\Encryption;
class Proxy extends \OC_FileProxy {
private static $blackList = null; //mimetypes blacklisted from encryption
private static $unencryptedSizes = array(); // remember unencrypted size
private static $fopenMode = array(); // remember the fopen mode
/**
* Check if a file requires encryption
@@ -114,11 +116,20 @@ class Proxy extends \OC_FileProxy {
// get encrypted content
$data = $view->file_get_contents($tmpPath);
// store new unenecrypted size so that it can be updated
// in the post proxy
$tmpFileInfo = $view->getFileInfo($tmpPath);
if ( isset($tmpFileInfo['size']) ) {
self::$unencryptedSizes[\OC_Filesystem::normalizePath($path)] = $tmpFileInfo['size'];
}
// remove our temp file
$view->deleteAll('/' . \OCP\User::getUser() . '/cache/' . $cacheFolder);
// re-enable proxy - our work is done
\OC_FileProxy::$enabled = $proxyStatus;
} else {
return false;
}
}
}
@@ -127,6 +138,24 @@ class Proxy extends \OC_FileProxy {
}
/**
* @brief update file cache with the new unencrypted size after file was written
* @param string $path
* @param mixed $result
* @return mixed
*/
public function postFile_put_contents($path, $result) {
$normalizedPath = \OC_Filesystem::normalizePath($path);
if ( isset(self::$unencryptedSizes[$normalizedPath]) ) {
$view = new \OC_FilesystemView('/');
$view->putFileInfo($normalizedPath,
array('encrypted' => true, 'unencrypted_size' => self::$unencryptedSizes[$normalizedPath]));
unset(self::$unencryptedSizes[$normalizedPath]);
}
return $result;
}
/**
* @param string $path Path of file from which has been read
* @param string $data Data that has been read from file
@@ -177,47 +206,6 @@ class Proxy extends \OC_FileProxy {
}
/**
* @brief When a file is deleted, remove its keyfile also
*/
public function preUnlink($path) {
// let the trashbin handle this
if (\OCP\App::isEnabled('files_trashbin')) {
return true;
}
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$view = new \OC_FilesystemView('/');
$userId = \OCP\USER::getUser();
$util = new Util($view, $userId);
// get relative path
$relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
list($owner, $ownerPath) = $util->getUidAndFilename($relativePath);
// Delete keyfile & shareKey so it isn't orphaned
if (!Keymanager::deleteFileKey($view, $ownerPath)) {
\OCP\Util::writeLog('Encryption library',
'Keyfile or shareKey could not be deleted for file "' . $ownerPath . '"', \OCP\Util::ERROR);
}
Keymanager::delAllShareKeys($view, $owner, $ownerPath);
\OC_FileProxy::$enabled = $proxyStatus;
// If we don't return true then file delete will fail; better
// to leave orphaned keyfiles than to disallow file deletion
return true;
}
/**
* @param $path
* @return bool
@@ -228,6 +216,16 @@ class Proxy extends \OC_FileProxy {
return true;
}
/**
* @brief remember initial fopen mode because sometimes it gets changed during the request
* @param string $path path
* @param string $mode type of access
*/
public function preFopen($path, $mode) {
self::$fopenMode[$path] = $mode;
}
/**
* @param $path
* @param $result
@@ -246,8 +244,8 @@ class Proxy extends \OC_FileProxy {
// split the path parts
$pathParts = explode('/', $path);
// FIXME: handling for /userId/cache used by webdav for chunking. The cache chunks are NOT encrypted
if (isset($pathParts[2]) && $pathParts[2] === 'cache') {
// don't try to encrypt/decrypt cache chunks or files in the trash bin
if (isset($pathParts[2]) && ($pathParts[2] === 'cache' || $pathParts[2] === 'files_trashbin')) {
return $result;
}
@@ -255,7 +253,15 @@ class Proxy extends \OC_FileProxy {
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$meta = stream_get_meta_data($result);
// if we remember the mode from the pre proxy we re-use it
// oterwise we fall back to stream_get_meta_data()
if (isset(self::$fopenMode[$path])) {
$mode = self::$fopenMode[$path];
unset(self::$fopenMode[$path]);
} else {
$meta = stream_get_meta_data($result);
$mode = $meta['mode'];
}
$view = new \OC_FilesystemView('');
@@ -273,14 +279,14 @@ class Proxy extends \OC_FileProxy {
// Open the file using the crypto stream wrapper
// protocol and let it do the decryption work instead
$result = fopen('crypt://' . $path, $meta['mode']);
$result = fopen('crypt://' . $path, $mode);
} elseif (
self::shouldEncrypt($path)
and $meta ['mode'] !== 'r'
and $meta['mode'] !== 'rb'
self::shouldEncrypt($path)
and $mode !== 'r'
and $mode !== 'rb'
) {
$result = fopen('crypt://' . $path, $meta['mode']);
$result = fopen('crypt://' . $path, $mode);
}
// Re-enable the proxy
@@ -305,7 +311,7 @@ class Proxy extends \OC_FileProxy {
\OC_FileProxy::$enabled = false;
// get file size
$data['size'] = self::postFileSize($path, $data['size']);
$data['size'] = self::postFileSize($path, $data['size'], $data);
// Re-enable the proxy
\OC_FileProxy::$enabled = $proxyStatus;
@@ -319,7 +325,7 @@ class Proxy extends \OC_FileProxy {
* @param $size
* @return bool
*/
public function postFileSize($path, $size) {
public function postFileSize($path, $size, $fileInfo = null) {
$view = new \OC_FilesystemView('/');
@@ -335,6 +341,13 @@ class Proxy extends \OC_FileProxy {
// if path is a folder do nothing
if ($view->is_dir($path)) {
$proxyState = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$fileInfo = $view->getFileInfo($path);
\OC_FileProxy::$enabled = $proxyState;
if (isset($fileInfo['unencrypted_size']) && $fileInfo['unencrypted_size'] > 0) {
return $fileInfo['unencrypted_size'];
}
return $size;
}
@@ -346,9 +359,8 @@ class Proxy extends \OC_FileProxy {
return $size;
}
$fileInfo = false;
// get file info from database/cache if not .part file
if (!Helper::isPartialFilePath($path)) {
if (empty($fileInfo) && !Helper::isPartialFilePath($path)) {
$proxyState = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$fileInfo = $view->getFileInfo($path);
@@ -356,7 +368,7 @@ class Proxy extends \OC_FileProxy {
}
// if file is encrypted return real file size
if (is_array($fileInfo) && $fileInfo['encrypted'] === true) {
if (isset($fileInfo['encrypted']) && $fileInfo['encrypted'] === true) {
// try to fix unencrypted file size if it doesn't look plausible
if ((int)$fileInfo['size'] > 0 && (int)$fileInfo['unencrypted_size'] === 0 ) {
$fixSize = $util->getFileSize($path);

View File

@@ -132,6 +132,14 @@ class Session {
}
/**
* @brief remove encryption keys and init status from session
*/
public function closeSession() {
\OC::$session->remove('encryptionInitialized');
\OC::$session->remove('privateKey');
}
/**
* @brief Gets status if we already tried to initialize the encryption app

View File

@@ -64,6 +64,9 @@ class Stream {
private $publicKey;
private $encKeyfile;
private $newFile; // helper var, we only need to write the keyfile for new files
private $isLocalTmpFile = false; // do we operate on a local tmp file
private $localTmpFile; // path of local tmp file
/**
* @var \OC\Files\View
*/
@@ -91,13 +94,18 @@ class Stream {
$this->rootView = new \OC_FilesystemView('/');
}
$this->session = new \OCA\Encryption\Session($this->rootView);
$this->privateKey = $this->session->getPrivateKey();
// rawPath is relative to the data directory
$this->rawPath = \OC\Files\Filesystem::normalizePath(str_replace('crypt://', '', $path));
$normalizedPath = \OC\Files\Filesystem::normalizePath(str_replace('crypt://', '', $path));
if ($originalFile = Helper::getPathFromTmpFile($normalizedPath)) {
$this->rawPath = $originalFile;
$this->isLocalTmpFile = true;
$this->localTmpFile = $normalizedPath;
} else {
$this->rawPath = $normalizedPath;
}
$this->userId = Helper::getUser($this->rawPath);
@@ -141,10 +149,14 @@ class Stream {
\OCA\Encryption\Helper::redirectToErrorPage($this->session);
}
$this->size = $this->rootView->filesize($this->rawPath, $mode);
$this->size = $this->rootView->filesize($this->rawPath);
}
$this->handle = $this->rootView->fopen($this->rawPath, $mode);
if ($this->isLocalTmpFile) {
$this->handle = fopen($this->localTmpFile, $mode);
} else {
$this->handle = $this->rootView->fopen($this->rawPath, $mode);
}
\OC_FileProxy::$enabled = $proxyStatus;
@@ -155,6 +167,9 @@ class Stream {
} else {
$this->meta = stream_get_meta_data($this->handle);
// sometimes fopen changes the mode, e.g. for a url "r" convert to "r+"
// but we need to remember the original access type
$this->meta['mode'] = $mode;
}
@@ -163,15 +178,26 @@ class Stream {
}
/**
* @brief Returns the current position of the file pointer
* @return int position of the file pointer
*/
public function stream_tell() {
return ftell($this->handle);
}
/**
* @param $offset
* @param int $whence
* @return bool true if fseek was successful, otherwise false
*/
public function stream_seek($offset, $whence = SEEK_SET) {
$this->flush();
fseek($this->handle, $offset, $whence);
// this wrapper needs to return "true" for success.
// the fseek call itself returns 0 on succeess
return !fseek($this->handle, $offset, $whence);
}
@@ -477,7 +503,7 @@ class Stream {
if ($this->privateKey === false) {
// cleanup
if ($this->meta['mode'] !== 'r' && $this->meta['mode'] !== 'rb') {
if ($this->meta['mode'] !== 'r' && $this->meta['mode'] !== 'rb' && !$this->isLocalTmpFile) {
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
@@ -498,6 +524,7 @@ class Stream {
if (
$this->meta['mode'] !== 'r' &&
$this->meta['mode'] !== 'rb' &&
$this->isLocalTmpFile === false &&
$this->size > 0 &&
$this->unencryptedSize > 0
) {
@@ -518,7 +545,7 @@ class Stream {
$util = new Util($this->rootView, $this->userId);
// Get all users sharing the file includes current user
$uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $this->relPath, $this->userId);
$uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $this->relPath);
$checkedUserIds = $util->filterShareReadyUsers($uniqueUserIds);
// Fetch public keys for all sharing users

View File

@@ -2,9 +2,10 @@
/**
* ownCloud
*
* @author Sam Tuke, Frank Karlitschek
* @author Sam Tuke, Frank Karlitschek, Bjoern Schiessle
* @copyright 2012 Sam Tuke <samtuke@owncloud.com>,
* Frank Karlitschek <frank@owncloud.org>
* Frank Karlitschek <frank@owncloud.org>,
* Bjoern Schiessle <schiessle@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -56,7 +57,7 @@ class Util {
* @param $userId
* @param bool $client
*/
public function __construct(\OC_FilesystemView $view, $userId, $client = false) {
public function __construct($view, $userId, $client = false) {
$this->view = $view;
$this->client = $client;
@@ -101,15 +102,24 @@ class Util {
or !$this->view->file_exists($this->publicKeyPath)
or !$this->view->file_exists($this->privateKeyPath)
) {
return false;
} else {
return true;
}
}
/**
* @brief check if the users private & public key exists
* @return boolean
*/
public function userKeysExists() {
if (
$this->view->file_exists($this->privateKeyPath) &&
$this->view->file_exists($this->publicKeyPath)) {
return true;
} else {
return false;
}
}
/**
@@ -123,7 +133,6 @@ class Util {
// Set directories to check / create
$setUpDirs = array(
$this->userDir,
$this->userFilesDir,
$this->publicKeyDir,
$this->encryptionDir,
$this->keyfilesPath,
@@ -232,11 +241,9 @@ class Util {
if (\OCP\DB::isError($result)) {
\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
} else {
if ($result->numRows() > 0) {
$row = $result->fetchRow();
if (isset($row['recovery_enabled'])) {
$recoveryEnabled[] = $row['recovery_enabled'];
}
$row = $result->fetchRow();
if ($row && isset($row['recovery_enabled'])) {
$recoveryEnabled[] = $row['recovery_enabled'];
}
}
@@ -280,7 +287,7 @@ class Util {
$sql = 'UPDATE `*PREFIX*encryption` SET `recovery_enabled` = ? WHERE `uid` = ?';
$args = array(
$enabled,
$enabled ? '1' : '0',
$this->userId
);
@@ -308,7 +315,8 @@ class Util {
$found = array(
'plain' => array(),
'encrypted' => array(),
'legacy' => array()
'legacy' => array(),
'broken' => array(),
);
}
@@ -319,10 +327,7 @@ class Util {
if(is_resource($handle)) {
while (false !== ($file = readdir($handle))) {
if (
$file !== "."
&& $file !== ".."
) {
if ($file !== "." && $file !== "..") {
$filePath = $directory . '/' . $this->view->getRelativePath('/' . $file);
$relPath = \OCA\Encryption\Helper::stripUserFilesPath($filePath);
@@ -349,15 +354,23 @@ class Util {
// NOTE: This is inefficient;
// scanning every file like this
// will eat server resources :(
if (
Keymanager::getFileKey($this->view, $this, $relPath)
&& $isEncryptedPath
) {
if ($isEncryptedPath) {
$found['encrypted'][] = array(
'name' => $file,
'path' => $filePath
);
$fileKey = Keymanager::getFileKey($this->view, $this, $relPath);
$shareKey = Keymanager::getShareKey($this->view, $this->userId, $this, $relPath);
// if file is encrypted but now file key is available, throw exception
if ($fileKey === false || $shareKey === false) {
\OCP\Util::writeLog('encryption library', 'No keys available to decrypt the file: ' . $filePath, \OCP\Util::ERROR);
$found['broken'][] = array(
'name' => $file,
'path' => $filePath,
);
} else {
$found['encrypted'][] = array(
'name' => $file,
'path' => $filePath,
);
}
// If the file uses old
// encryption system
@@ -455,20 +468,36 @@ class Util {
*/
public function isEncryptedPath($path) {
$relPath = Helper::getPathToRealFile($path);
// Disable encryption proxy so data retrieved is in its
// original form
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
if ($relPath === false) {
$relPath = Helper::stripUserFilesPath($path);
// we only need 24 byte from the last chunk
$data = '';
$handle = $this->view->fopen($path, 'r');
if (is_resource($handle)) {
// suppress fseek warining, we handle the case that fseek doesn't
// work in the else branch
if (@fseek($handle, -24, SEEK_END) === 0) {
$data = fgets($handle);
} else {
// if fseek failed on the storage we create a local copy from the file
// and read this one
fclose($handle);
$localFile = $this->view->getLocalFile($path);
$handle = fopen($localFile, 'r');
if (is_resource($handle) && fseek($handle, -24, SEEK_END) === 0) {
$data = fgets($handle);
}
}
fclose($handle);
}
$fileKey = Keymanager::getFileKey($this->view, $this, $relPath);
if ($fileKey === false) {
return false;
}
return true;
// re-enable proxy
\OC_FileProxy::$enabled = $proxyStatus;
return Crypt::isCatfileContent($data);
}
/**
@@ -514,7 +543,20 @@ class Util {
$lastChunckPos = ($lastChunkNr * 8192);
// seek to end
fseek($stream, $lastChunckPos);
if (@fseek($stream, $lastChunckPos) === -1) {
// storage doesn't support fseek, we need a local copy
fclose($stream);
$localFile = $this->view->getLocalFile($path);
Helper::addTmpFileToMapper($localFile, $path);
$stream = fopen('crypt://' . $localFile, "r");
if (fseek($stream, $lastChunckPos) === -1) {
// if fseek also fails on the local storage, than
// there is nothing we can do
fclose($stream);
\OCP\Util::writeLog('Encryption library', 'couldn\'t determine size of "' . $path, \OCP\Util::ERROR);
return $result;
}
}
// get the content of the last chunk
$lastChunkContent = fread($stream, $lastChunkSize);
@@ -761,7 +803,7 @@ class Util {
\OC\Files\Filesystem::putFileInfo($relPath, array(
'encrypted' => false,
'size' => $size,
'unencrypted_size' => $size,
'unencrypted_size' => 0,
'etag' => $fileInfo['etag']
));
@@ -777,6 +819,12 @@ class Util {
$successful = false;
}
// if there are broken encrypted files than the complete decryption
// was not successful
if (!empty($found['broken'])) {
$successful = false;
}
if ($successful) {
$this->view->deleteAll($this->keyfilesPath);
$this->view->deleteAll($this->shareKeysPath);
@@ -831,32 +879,35 @@ class Util {
// Open enc file handle for binary writing, with same filename as original plain file
$encHandle = fopen('crypt://' . $rawPath . '.part', 'wb');
// Move plain file to a temporary location
$size = stream_copy_to_stream($plainHandle, $encHandle);
if (is_resource($encHandle)) {
// Move plain file to a temporary location
$size = stream_copy_to_stream($plainHandle, $encHandle);
fclose($encHandle);
fclose($plainHandle);
fclose($encHandle);
fclose($plainHandle);
$fakeRoot = $this->view->getRoot();
$this->view->chroot('/' . $this->userId . '/files');
$fakeRoot = $this->view->getRoot();
$this->view->chroot('/' . $this->userId . '/files');
$this->view->rename($relPath . '.part', $relPath);
$this->view->rename($relPath . '.part', $relPath);
// set timestamp
$this->view->touch($relPath, $timestamp);
// set timestamp
$this->view->touch($relPath, $timestamp);
$this->view->chroot($fakeRoot);
$encSize = $this->view->filesize($relPath);
// Add the file to the cache
\OC\Files\Filesystem::putFileInfo($relPath, array(
'encrypted' => true,
'size' => $size,
'unencrypted_size' => $size,
'etag' => $fileInfo['etag']
));
$this->view->chroot($fakeRoot);
$encryptedFiles[] = $relPath;
// Add the file to the cache
\OC\Files\Filesystem::putFileInfo($relPath, array(
'encrypted' => true,
'size' => $encSize,
'unencrypted_size' => $size,
'etag' => $fileInfo['etag']
));
$encryptedFiles[] = $relPath;
}
}
// Encrypt legacy encrypted files
@@ -973,8 +1024,8 @@ class Util {
if (\OCP\DB::isError($result)) {
\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
} else {
if ($result->numRows() > 0) {
$row = $result->fetchRow();
$row = $result->fetchRow();
if ($row) {
$path = substr($row['path'], strlen('files'));
}
}
@@ -1113,8 +1164,10 @@ class Util {
/**
* @brief Find, sanitise and format users sharing a file
* @note This wraps other methods into a portable bundle
* @param boolean $sharingEnabled
* @param string $filePath path relativ to current users files folder
*/
public function getSharingUsersArray($sharingEnabled, $filePath, $currentUserId = false) {
public function getSharingUsersArray($sharingEnabled, $filePath) {
// Check if key recovery is enabled
if (
@@ -1131,12 +1184,14 @@ class Util {
$ownerPath = \OCA\Encryption\Helper::stripPartialFileExtension($ownerPath);
$userIds = array();
// always add owner to the list of users with access to the file
$userIds = array($owner);
if ($sharingEnabled) {
// Find out who, if anyone, is sharing the file
$result = \OCP\Share::getUsersSharingFile($ownerPath, $owner, true);
$userIds = $result['users'];
$result = \OCP\Share::getUsersSharingFile($ownerPath, $owner);
$userIds = \array_merge($userIds, $result['users']);
if ($result['public']) {
$userIds[] = $this->publicShareKeyId;
}
@@ -1152,11 +1207,6 @@ class Util {
$userIds[] = $recoveryKeyId;
}
// add current user if given
if ($currentUserId !== false) {
$userIds[] = $currentUserId;
}
// check if it is a group mount
if (\OCP\App::isEnabled("files_external")) {
$mount = \OC_Mount_Config::getSystemMountPoints();
@@ -1188,27 +1238,49 @@ class Util {
return $result;
}
/**
* @brief set migration status
* @param int $status
* @return boolean
*/
private function setMigrationStatus($status) {
$sql = 'UPDATE `*PREFIX*encryption` SET `migration_status` = ? WHERE `uid` = ?';
$args = array($status, $this->userId);
$query = \OCP\DB::prepare($sql);
$manipulatedRows = $query->execute($args);
if ($manipulatedRows === 1) {
$result = true;
\OCP\Util::writeLog('Encryption library', "Migration status set to " . self::MIGRATION_OPEN, \OCP\Util::INFO);
} else {
$result = false;
\OCP\Util::writeLog('Encryption library', "Could not set migration status to " . self::MIGRATION_OPEN, \OCP\Util::WARN);
}
return $result;
}
/**
* @brief start migration mode to initially encrypt users data
* @return boolean
*/
public function beginMigration() {
$return = false;
$result = $this->setMigrationStatus(self::MIGRATION_IN_PROGRESS);
$sql = 'UPDATE `*PREFIX*encryption` SET `migration_status` = ? WHERE `uid` = ? and `migration_status` = ?';
$args = array(self::MIGRATION_IN_PROGRESS, $this->userId, self::MIGRATION_OPEN);
$query = \OCP\DB::prepare($sql);
$manipulatedRows = $query->execute($args);
if ($manipulatedRows === 1) {
$return = true;
if ($result) {
\OCP\Util::writeLog('Encryption library', "Start migration to encryption mode for " . $this->userId, \OCP\Util::INFO);
} else {
\OCP\Util::writeLog('Encryption library', "Could not activate migration mode for " . $this->userId . ". Probably another process already started the initial encryption", \OCP\Util::WARN);
}
return $return;
return $result;
}
public function resetMigrationStatus() {
return $this->setMigrationStatus(self::MIGRATION_OPEN);
}
/**
@@ -1216,22 +1288,15 @@ class Util {
* @return boolean
*/
public function finishMigration() {
$result = $this->setMigrationStatus(self::MIGRATION_COMPLETED);
$return = false;
$sql = 'UPDATE `*PREFIX*encryption` SET `migration_status` = ? WHERE `uid` = ? and `migration_status` = ?';
$args = array(self::MIGRATION_COMPLETED, $this->userId, self::MIGRATION_IN_PROGRESS);
$query = \OCP\DB::prepare($sql);
$manipulatedRows = $query->execute($args);
if ($manipulatedRows === 1) {
$return = true;
if ($result) {
\OCP\Util::writeLog('Encryption library', "Finish migration successfully for " . $this->userId, \OCP\Util::INFO);
} else {
\OCP\Util::writeLog('Encryption library', "Could not deactivate migration mode for " . $this->userId, \OCP\Util::WARN);
}
return $return;
return $result;
}
/**
@@ -1254,11 +1319,9 @@ class Util {
if (\OCP\DB::isError($result)) {
\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
} else {
if ($result->numRows() > 0) {
$row = $result->fetchRow();
if (isset($row['migration_status'])) {
$migrationStatus[] = $row['migration_status'];
}
$row = $result->fetchRow();
if ($row && isset($row['migration_status'])) {
$migrationStatus[] = $row['migration_status'];
}
}
@@ -1366,59 +1429,32 @@ class Util {
}
}
/**
* @brief go recursively through a dir and collect all files and sub files.
* @param string $dir relative to the users files folder
* @return array with list of files relative to the users files folder
*/
public function getAllFiles($dir) {
$result = array();
$dirList = array($dir);
$content = $this->view->getDirectoryContent(\OC\Files\Filesystem::normalizePath(
$this->userFilesDir . '/' . $dir));
// handling for re shared folders
$pathSplit = explode('/', $dir);
foreach ($content as $c) {
$sharedPart = $pathSplit[sizeof($pathSplit) - 1];
$targetPathSplit = array_reverse(explode('/', $c['path']));
$path = '';
// rebuild path
foreach ($targetPathSplit as $pathPart) {
if ($pathPart !== $sharedPart) {
$path = '/' . $pathPart . $path;
while ($dirList) {
$dir = array_pop($dirList);
$content = $this->view->getDirectoryContent(\OC\Files\Filesystem::normalizePath(
$this->userFilesDir . '/' . $dir));
foreach ($content as $c) {
$usersPath = isset($c['usersPath']) ? $c['usersPath'] : $c['path'];
if ($c['type'] === 'dir') {
$dirList[] = substr($usersPath, strlen("files"));
} else {
break;
$result[] = substr($usersPath, strlen("files"));
}
}
$path = $dir . $path;
if ($c['type'] === 'dir') {
$result = array_merge($result, $this->getAllFiles($path));
} else {
$result[] = $path;
}
}
return $result;
}
/**
@@ -1438,9 +1474,7 @@ class Util {
if (\OCP\DB::isError($result)) {
\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
} else {
if ($result->numRows() > 0) {
$row = $result->fetchRow();
}
$row = $result->fetchRow();
}
return $row;
@@ -1464,9 +1498,7 @@ class Util {
if (\OCP\DB::isError($result)) {
\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
} else {
if ($result->numRows() > 0) {
$row = $result->fetchRow();
}
$row = $result->fetchRow();
}
return $row;
@@ -1485,18 +1517,16 @@ class Util {
$result = $query->execute(array($id));
$source = array();
$source = null;
if (\OCP\DB::isError($result)) {
\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
} else {
if ($result->numRows() > 0) {
$source = $result->fetchRow();
}
$source = $result->fetchRow();
}
$fileOwner = false;
if (isset($source['parent'])) {
if ($source && isset($source['parent'])) {
$parent = $source['parent'];
@@ -1506,16 +1536,14 @@ class Util {
$result = $query->execute(array($parent));
$item = array();
$item = null;
if (\OCP\DB::isError($result)) {
\OCP\Util::writeLog('Encryption library', \OC_DB::getErrorMessage($result), \OCP\Util::ERROR);
} else {
if ($result->numRows() > 0) {
$item = $result->fetchRow();
}
$item = $result->fetchRow();
}
if (isset($item['parent'])) {
if ($item && isset($item['parent'])) {
$parent = $item['parent'];
@@ -1780,4 +1808,12 @@ class Util {
return $session;
}
/*
* @brief remove encryption related keys from the session
*/
public function closeEncryptionSession() {
$session = new \OCA\Encryption\Session($this->view);
$session->closeSession();
}
}

View File

@@ -2,7 +2,7 @@
<fieldset class="personalblock">
<h2><?php p( $l->t( 'Encryption' ) ); ?></h2>
<?php if ( ! $_["privateKeySet"] && $_["initialized"] ): ?>
<?php if ( $_["initialized"] === '1' ): ?>
<p>
<a name="changePKPasswd" />
<label for="changePrivateKeyPasswd">

View File

@@ -155,7 +155,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
*/
function testSymmetricStreamEncryptShortFileContent() {
$filename = 'tmp-' . time() . '.test';
$filename = 'tmp-' . uniqid() . '.test';
$util = new Encryption\Util(new \OC_FilesystemView(), $this->userId);
@@ -214,7 +214,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
function testSymmetricStreamEncryptLongFileContent() {
// Generate a a random filename
$filename = 'tmp-' . time() . '.test';
$filename = 'tmp-' . uniqid() . '.test';
$util = new Encryption\Util(new \OC_FilesystemView(), $this->userId);
@@ -297,7 +297,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
*/
function testSymmetricStreamDecryptShortFileContent() {
$filename = 'tmp-' . time();
$filename = 'tmp-' . uniqid();
// Save long data as encrypted file using stream wrapper
$cryptedFile = file_put_contents('crypt:///'. $this->userId . '/files/' . $filename, $this->dataShort);
@@ -327,7 +327,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
*/
function testSymmetricStreamDecryptLongFileContent() {
$filename = 'tmp-' . time();
$filename = 'tmp-' . uniqid();
// Save long data as encrypted file using stream wrapper
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong);
@@ -418,7 +418,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
*/
function testRenameFile() {
$filename = 'tmp-' . time();
$filename = 'tmp-' . uniqid();
// Save long data as encrypted file using stream wrapper
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong);
@@ -431,7 +431,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
$this->assertEquals($this->dataLong, $decrypt);
$newFilename = 'tmp-new-' . time();
$newFilename = 'tmp-new-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files');
$view->rename($filename, $newFilename);
@@ -449,7 +449,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
*/
function testMoveFileIntoFolder() {
$filename = 'tmp-' . time();
$filename = 'tmp-' . uniqid();
// Save long data as encrypted file using stream wrapper
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong);
@@ -462,8 +462,8 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
$this->assertEquals($this->dataLong, $decrypt);
$newFolder = '/newfolder' . time();
$newFilename = 'tmp-new-' . time();
$newFolder = '/newfolder' . uniqid();
$newFilename = 'tmp-new-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files');
$view->mkdir($newFolder);
$view->rename($filename, $newFolder . '/' . $newFilename);
@@ -484,8 +484,8 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
$view = new \OC\Files\View('/' . $this->userId . '/files');
$filename = '/tmp-' . time();
$folder = '/folder' . time();
$filename = '/tmp-' . uniqid();
$folder = '/folder' . uniqid();
$view->mkdir($folder);
@@ -500,7 +500,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
$this->assertEquals($this->dataLong, $decrypt);
$newFolder = '/newfolder/subfolder' . time();
$newFolder = '/newfolder/subfolder' . uniqid();
$view->mkdir('/newfolder');
$view->rename($folder, $newFolder);
@@ -519,7 +519,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
* @medium
*/
function testChangePassphrase() {
$filename = 'tmp-' . time();
$filename = 'tmp-' . uniqid();
// Save long data as encrypted file using stream wrapper
$cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong);
@@ -557,7 +557,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
*/
function testViewFilePutAndGetContents() {
$filename = '/tmp-' . time();
$filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files');
// Save short data as encrypted file using stream wrapper
@@ -590,7 +590,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
* @large
*/
function testTouchExistingFile() {
$filename = '/tmp-' . time();
$filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files');
// Save short data as encrypted file using stream wrapper
@@ -614,7 +614,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
* @medium
*/
function testTouchFile() {
$filename = '/tmp-' . time();
$filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files');
$view->touch($filename);
@@ -638,7 +638,7 @@ class Test_Encryption_Crypt extends \PHPUnit_Framework_TestCase {
* @medium
*/
function testFopenFile() {
$filename = '/tmp-' . time();
$filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files');
// Save short data as encrypted file using stream wrapper

View File

@@ -8,6 +8,7 @@
require_once __DIR__ . '/../lib/helper.php';
require_once __DIR__ . '/util.php';
use OCA\Encryption;
@@ -16,6 +17,18 @@ use OCA\Encryption;
*/
class Test_Encryption_Helper extends \PHPUnit_Framework_TestCase {
const TEST_ENCRYPTION_HELPER_USER1 = "test-helper-user1";
public static function setUpBeforeClass() {
// create test user
\Test_Encryption_Util::loginHelper(\Test_Encryption_Helper::TEST_ENCRYPTION_HELPER_USER1, true);
}
public static function tearDownAfterClass() {
// cleanup test user
\OC_User::deleteUser(\Test_Encryption_Helper::TEST_ENCRYPTION_HELPER_USER1);
}
/**
* @medium
*/
@@ -64,4 +77,28 @@ class Test_Encryption_Helper extends \PHPUnit_Framework_TestCase {
$this->assertEquals($relativePath, Encryption\Helper::getPathToRealFile($cachePath));
}
function testGetUser() {
$path1 = "/" . self::TEST_ENCRYPTION_HELPER_USER1 . "/files/foo/bar.txt";
$path2 = "/" . self::TEST_ENCRYPTION_HELPER_USER1 . "/cache/foo/bar.txt";
$path3 = "/" . self::TEST_ENCRYPTION_HELPER_USER1 . "/thumbnails/foo";
$path4 ="/" . "/" . self::TEST_ENCRYPTION_HELPER_USER1;
// if we are logged-in every path should return the currently logged-in user
$this->assertEquals(self::TEST_ENCRYPTION_HELPER_USER1, Encryption\Helper::getUser($path3));
// now log out
\Test_Encryption_Util::logoutHelper();
// now we should only get the user from /user/files and user/cache paths
$this->assertEquals(self::TEST_ENCRYPTION_HELPER_USER1, Encryption\Helper::getUser($path1));
$this->assertEquals(self::TEST_ENCRYPTION_HELPER_USER1, Encryption\Helper::getUser($path2));
$this->assertFalse(Encryption\Helper::getUser($path3));
$this->assertFalse(Encryption\Helper::getUser($path4));
// Log-in again
\Test_Encryption_Util::loginHelper(\Test_Encryption_Helper::TEST_ENCRYPTION_HELPER_USER1);
}
}

View File

@@ -0,0 +1,369 @@
<?php
/**
* ownCloud
*
* @author Bjoern Schiessle
* @copyright 2014 Bjoern Schiessle <schiessle@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
require_once __DIR__ . '/../../../lib/base.php';
require_once __DIR__ . '/../lib/crypt.php';
require_once __DIR__ . '/../lib/keymanager.php';
require_once __DIR__ . '/../lib/stream.php';
require_once __DIR__ . '/../lib/util.php';
require_once __DIR__ . '/../appinfo/app.php';
require_once __DIR__ . '/util.php';
use OCA\Encryption;
/**
* Class Test_Encryption_Hooks
* @brief this class provide basic hook app tests
*/
class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
const TEST_ENCRYPTION_HOOKS_USER1 = "test-encryption-hooks-user1";
const TEST_ENCRYPTION_HOOKS_USER2 = "test-encryption-hooks-user2";
/**
* @var \OC_FilesystemView
*/
public $user1View; // view on /data/user1/files
public $user2View; // view on /data/user2/files
public $rootView; // view on /data/user
public $data;
public $filename;
public $folder;
public static function setUpBeforeClass() {
// reset backend
\OC_User::clearBackends();
\OC_User::useBackend('database');
\OC_Hook::clear('OC_Filesystem');
\OC_Hook::clear('OC_User');
// clear share hooks
\OC_Hook::clear('OCP\\Share');
\OC::registerShareHooks();
\OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup');
// Filesystem related hooks
\OCA\Encryption\Helper::registerFilesystemHooks();
// Sharing related hooks
\OCA\Encryption\Helper::registerShareHooks();
// clear and register proxies
\OC_FileProxy::clearProxies();
\OC_FileProxy::register(new OCA\Encryption\Proxy());
// create test user
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1, true);
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2, true);
}
function setUp() {
// set user id
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
// init filesystem view
$this->user1View = new \OC_FilesystemView('/'. \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '/files');
$this->user2View = new \OC_FilesystemView('/'. \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '/files');
$this->rootView = new \OC_FilesystemView('/');
// init short data
$this->data = 'hats';
$this->filename = 'enc_hooks_tests-' . uniqid() . '.txt';
$this->folder = 'enc_hooks_tests_folder-' . uniqid();
}
public static function tearDownAfterClass() {
// cleanup test user
\OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
\OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
}
function testDeleteHooks() {
// remember files_trashbin state
$stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
// we want to tests with app files_trashbin disabled
\OC_App::disable('files_trashbin');
// make sure that the trash bin is disabled
$this->assertFalse(\OC_APP::isEnabled('files_trashbin'));
$this->user1View->file_put_contents($this->filename, $this->data);
// check if all keys are generated
$this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
$this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
\Test_Encryption_Util::logoutHelper();
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
$this->user2View->file_put_contents($this->filename, $this->data);
// check if all keys are generated
$this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/'
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
$this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
// create a dummy file that we can delete something outside of data/user/files
// in this case no share or file keys should be deleted
$this->rootView->file_put_contents(self::TEST_ENCRYPTION_HOOKS_USER2 . "/" . $this->filename, $this->data);
// delete dummy file outside of data/user/files
$this->rootView->unlink(self::TEST_ENCRYPTION_HOOKS_USER2 . "/" . $this->filename);
// all keys should still exist
$this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/'
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
$this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
// delete the file in data/user/files
// now the correspondig share and file keys from user2 should be deleted
$this->user2View->unlink($this->filename);
// check if keys from user2 are really deleted
$this->assertFalse($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/'
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
$this->assertFalse($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
// but user1 keys should still exist
$this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
$this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
if ($stateFilesTrashbin) {
OC_App::enable('files_trashbin');
}
else {
OC_App::disable('files_trashbin');
}
}
function testDeleteHooksForSharedFiles() {
\Test_Encryption_Util::logoutHelper();
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
// remember files_trashbin state
$stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
// we want to tests with app files_trashbin disabled
\OC_App::disable('files_trashbin');
// make sure that the trash bin is disabled
$this->assertFalse(\OC_APP::isEnabled('files_trashbin'));
$this->user1View->file_put_contents($this->filename, $this->data);
// check if all keys are generated
$this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
$this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
// get the file info from previous created file
$fileInfo = $this->user1View->getFileInfo($this->filename);
// check if we have a valid file info
$this->assertTrue(is_array($fileInfo));
// share the file with user2
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_ENCRYPTION_HOOKS_USER2, OCP\PERMISSION_ALL);
// check if new share key exists
$this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
\Test_Encryption_Util::logoutHelper();
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
// user2 has a local file with the same name
$this->user2View->file_put_contents($this->filename, $this->data);
// check if all keys are generated
$this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/'
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
$this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
// delete the Shared file from user1 in data/user2/files/Shared
$this->user2View->unlink('/Shared/' . $this->filename);
// now keys from user1s home should be gone
$this->assertFalse($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
$this->assertFalse($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
$this->assertFalse($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
// but user2 keys should still exist
$this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/'
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
$this->assertTrue($this->rootView->file_exists(
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
// cleanup
$this->user2View->unlink($this->filename);
\Test_Encryption_Util::logoutHelper();
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
// unshare the file
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_ENCRYPTION_HOOKS_USER2);
$this->user1View->unlink($this->filename);
if ($stateFilesTrashbin) {
OC_App::enable('files_trashbin');
}
else {
OC_App::disable('files_trashbin');
}
}
/**
* @brief test rename operation
*/
function testRenameHook() {
// save file with content
$cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->filename, $this->data);
// test that data was successfully written
$this->assertTrue(is_int($cryptedFile));
// check if keys exists
$this->assertTrue($this->rootView->file_exists(
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
. $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
$this->assertTrue($this->rootView->file_exists(
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/'
. $this->filename . '.key'));
// make subfolder and sub-subfolder
$this->rootView->mkdir('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder);
$this->rootView->mkdir('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder . '/' . $this->folder);
$this->assertTrue($this->rootView->is_dir('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder . '/' . $this->folder));
// move the file out of the shared folder
$root = $this->rootView->getRoot();
$this->rootView->chroot('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/');
$this->rootView->rename($this->filename, '/' . $this->folder . '/' . $this->folder . '/' . $this->filename);
$this->rootView->chroot($root);
$this->assertFalse($this->rootView->file_exists('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->filename));
$this->assertTrue($this->rootView->file_exists('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder . '/' . $this->folder . '/' . $this->filename));
// keys should be renamed too
$this->assertFalse($this->rootView->file_exists(
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
. $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
$this->assertFalse($this->rootView->file_exists(
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/'
. $this->filename . '.key'));
$this->assertTrue($this->rootView->file_exists(
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/' . $this->folder . '/' . $this->folder . '/'
. $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
$this->assertTrue($this->rootView->file_exists(
'/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->folder . '/' . $this->folder . '/'
. $this->filename . '.key'));
// cleanup
$this->rootView->unlink('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder);
}
/**
* @brief replacing encryption keys during password change should be allowed
* until the user logged in for the first time
*/
public function testSetPassphrase() {
$view = new \OC\Files\View();
// set user password for the first time
\OCA\Encryption\Hooks::postCreateUser(array('uid' => 'newUser', 'password' => 'newUserPassword'));
$this->assertTrue($view->file_exists('public-keys/newUser.public.key'));
$this->assertTrue($view->file_exists('newUser/files_encryption/newUser.private.key'));
// check if we are able to decrypt the private key
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, 'newUser');
$privateKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, 'newUserPassword');
$this->assertTrue(is_string($privateKey));
// change the password before the user logged-in for the first time,
// we can replace the encryption keys
\OCA\Encryption\Hooks::setPassphrase(array('uid' => 'newUser', 'password' => 'passwordChanged'));
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, 'newUser');
$privateKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, 'passwordChanged');
$this->assertTrue(is_string($privateKey));
// now create a files folder to simulate a already used account
$view->mkdir('/newUser/files');
// change the password after the user logged in, now the password should not change
\OCA\Encryption\Hooks::setPassphrase(array('uid' => 'newUser', 'password' => 'passwordChanged2'));
$encryptedKey = \OCA\Encryption\Keymanager::getPrivateKey($view, 'newUser');
$privateKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, 'passwordChanged2');
$this->assertFalse($privateKey);
$privateKey = \OCA\Encryption\Crypt::decryptPrivateKey($encryptedKey, 'passwordChanged');
$this->assertTrue(is_string($privateKey));
}
}

View File

@@ -136,6 +136,17 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
$this->assertArrayHasKey('key', $sslInfo);
}
/**
* @small
*/
function testGetFilenameFromShareKey() {
$this->assertEquals("file",
\TestProtectedKeymanagerMethods::testGetFilenameFromShareKey("file.user.shareKey"));
$this->assertEquals("file.name.with.dots",
\TestProtectedKeymanagerMethods::testGetFilenameFromShareKey("file.name.with.dots.user.shareKey"));
$this->assertFalse(\TestProtectedKeymanagerMethods::testGetFilenameFromShareKey("file.txt"));
}
/**
* @medium
*/
@@ -143,7 +154,7 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
$key = $this->randomKey;
$file = 'unittest-' . time() . '.txt';
$file = 'unittest-' . uniqid() . '.txt';
$util = new Encryption\Util($this->view, $this->userId);
@@ -196,7 +207,7 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
function testRecursiveDelShareKeys() {
// generate filename
$filename = '/tmp-' . time() . '.txt';
$filename = '/tmp-' . uniqid() . '.txt';
// create folder structure
$this->view->mkdir('/'.Test_Encryption_Keymanager::TEST_USER.'/files/folder1');
@@ -234,3 +245,12 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
\OC_FileProxy::$enabled = $proxyStatus;
}
}
/**
* dummy class to access protected methods of \OCA\Encryption\Keymanager for testing
*/
class TestProtectedKeymanagerMethods extends \OCA\Encryption\Keymanager {
public static function testGetFilenameFromShareKey($sharekey) {
return self::getFilenameFromShareKey($sharekey);
}
}

View File

@@ -44,8 +44,10 @@ class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase {
/**
* @var \OC_FilesystemView
*/
public $view;
public $view; // view in /data/user/files
public $rootView; // view on /data/user
public $data;
public $filename;
public static function setUpBeforeClass() {
// reset backend
@@ -74,9 +76,12 @@ class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase {
// init filesystem view
$this->view = new \OC_FilesystemView('/'. \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 . '/files');
$this->rootView = new \OC_FilesystemView('/'. \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 );
// init short data
$this->data = 'hats';
$this->filename = 'enc_proxy_tests-' . uniqid() . '.txt';
}
public static function tearDownAfterClass() {
@@ -90,21 +95,41 @@ class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase {
*/
function testPostFileSize() {
// generate filename
$filename = 'tmp-' . time() . '.txt';
$this->view->file_put_contents($filename, $this->data);
$this->view->file_put_contents($this->filename, $this->data);
\OC_FileProxy::$enabled = false;
$unencryptedSize = $this->view->filesize($filename);
$unencryptedSize = $this->view->filesize($this->filename);
\OC_FileProxy::$enabled = true;
$encryptedSize = $this->view->filesize($filename);
$encryptedSize = $this->view->filesize($this->filename);
$this->assertTrue($encryptedSize !== $unencryptedSize);
// cleanup
$this->view->unlink($this->filename);
}
function testPostFileSizeWithDirectory() {
$this->view->file_put_contents($this->filename, $this->data);
\OC_FileProxy::$enabled = false;
// get root size, must match the file's unencrypted size
$unencryptedSize = $this->view->filesize('');
\OC_FileProxy::$enabled = true;
$encryptedSize = $this->view->filesize('');
$this->assertTrue($encryptedSize !== $unencryptedSize);
// cleanup
$this->view->unlink($this->filename);
}
}

View File

@@ -127,6 +127,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
\OC_User::deleteUser(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4);
}
/**
* @medium
* @param bool $withTeardown
@@ -194,8 +195,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
// cleanup
$this->view->unlink(
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
$this->view->unlink($this->filename);
$this->view->chroot('/');
// check if share key not exists
$this->assertFalse($this->view->file_exists(
@@ -265,8 +267,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
// cleanup
$this->view->unlink(
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
$this->view->unlink($this->filename);
$this->view->chroot('/');
// check if share key not exists
$this->assertFalse($this->view->file_exists(
@@ -352,7 +355,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
// cleanup
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1);
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files');
$this->view->unlink($this->folder1);
$this->view->chroot('/');
// check if share key not exists
$this->assertFalse($this->view->file_exists(
@@ -482,9 +487,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
// cleanup
$this->view->unlink(
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1 . $this->subfolder
. $this->subsubfolder . '/' . $this->filename);
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files');
$this->view->unlink($this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
$this->view->chroot('/');
// check if share key not exists
$this->assertFalse($this->view->file_exists(
@@ -494,6 +499,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
}
}
function testPublicShareFile() {
// login as admin
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
@@ -559,7 +565,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
. $this->filename . '.' . $publicShareKeyId . '.shareKey'));
// cleanup
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
$this->view->unlink($this->filename);
$this->view->chroot('/');
// check if share key not exists
$this->assertFalse($this->view->file_exists(
@@ -636,7 +644,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4 . '.shareKey'));
// cleanup
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
$this->view->unlink($this->filename);
$this->view->chroot('/');
// check if share key not exists
$this->assertFalse($this->view->file_exists(
@@ -649,9 +659,7 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
* @large
*/
function testRecoveryFile() {
$this->markTestIncomplete(
'No idea what\'s wrong here, this works perfectly in real-world. removeRecoveryKeys(\'/\') L709 removes correctly the keys, but for some reasons afterwards also the top-level folder "share-keys" is gone...'
);
// login as admin
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
@@ -733,8 +741,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
. $this->filename . '.' . $recoveryKeyId . '.shareKey'));
// cleanup
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->folder1);
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
$this->view->unlink($this->filename);
$this->view->unlink($this->folder1);
$this->view->chroot('/');
// check if share key for recovery not exists
$this->assertFalse($this->view->file_exists(
@@ -754,13 +764,13 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
* @large
*/
function testRecoveryForUser() {
$this->markTestIncomplete(
'This test drives Jenkins crazy - "Cannot modify header information - headers already sent" - line 811'
);
// login as admin
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
\OCA\Encryption\Helper::adminEnableRecovery(null, 'test123');
$result = \OCA\Encryption\Helper::adminEnableRecovery(null, 'test123');
$this->assertTrue($result);
$recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId');
// login as user2
@@ -771,6 +781,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
// enable recovery for admin
$this->assertTrue($util->setRecoveryForUser(1));
// add recovery keys for existing files (e.g. the auto-generated welcome.txt)
$util->addRecoveryKeys();
// create folder structure
$this->view->mkdir('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1);
$this->view->mkdir(
@@ -809,6 +822,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
// change password
\OC_User::setPassword(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, 'test', 'test123');
$params = array('uid' => \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2,
'password' => 'test',
'recoveryPassword' => 'test123');
\OCA\Encryption\Hooks::setPassphrase($params);
// login as user2
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, false, 'test');
@@ -823,8 +840,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
$this->assertEquals($this->dataShort, $retrievedCryptedFile2);
// cleanup
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->folder1);
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files' . $this->filename);
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/');
$this->view->unlink($this->folder1);
$this->view->unlink($this->filename);
$this->view->chroot('/');
// check if share key for user and recovery exists
$this->assertFalse($this->view->file_exists(
@@ -842,11 +861,21 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
. $this->subfolder . $this->subsubfolder . '/'
. $this->filename . '.' . $recoveryKeyId . '.shareKey'));
// enable recovery for admin
// disable recovery for admin
$this->assertTrue($util->setRecoveryForUser(0));
\OCA\Encryption\Helper::adminDisableRecovery('test123');
$this->assertEquals(0, \OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled'));
//clean up, reset passwords
\OC_User::setPassword(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, 'test123');
$params = array('uid' => \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2,
'password' => \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2,
'recoveryPassword' => 'test123');
\OCA\Encryption\Hooks::setPassphrase($params);
}
/**
@@ -889,8 +918,8 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
} catch (Exception $e) {
$this->assertEquals(0, strpos($e->getMessage(), "Following users are not set up for encryption"));
}
// login as admin
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
@@ -925,7 +954,70 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
// cleanup
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
$this->view->unlink($this->filename);
$this->view->chroot('/');
}
/**
* @brief test moving a shared file out of the Shared folder
*/
function testRename() {
// login as admin
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1);
// save file with content
$cryptedFile = file_put_contents('crypt:///' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename, $this->dataShort);
// test that data was successfully written
$this->assertTrue(is_int($cryptedFile));
// get the file info from previous created file
$fileInfo = $this->view->getFileInfo(
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
// check if we have a valid file info
$this->assertTrue(is_array($fileInfo));
// share the file
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2, OCP\PERMISSION_ALL);
// check if share key for user2exists
$this->assertTrue($this->view->file_exists(
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/share-keys/'
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
// login as user2
\Test_Encryption_Util::loginHelper(\Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2);
$this->assertTrue($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/Shared/' . $this->filename));
// get file contents
$retrievedCryptedFile = $this->view->file_get_contents(
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/Shared/' . $this->filename);
// check if data is the same as we previously written
$this->assertEquals($this->dataShort, $retrievedCryptedFile);
// move the file out of the shared folder
$this->view->rename('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/Shared/' . $this->filename,
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename);
// check if we can read the moved file
$retrievedRenamedFile = $this->view->file_get_contents(
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename);
// check if data is the same as we previously written
$this->assertEquals($this->dataShort, $retrievedRenamedFile);
// the owners file should be deleted
$this->assertFalse($this->view->file_exists('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename));
// cleanup
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename);
}
}

View File

@@ -99,7 +99,7 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
}
function testStreamOptions() {
$filename = '/tmp-' . time();
$filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files');
// Save short data as encrypted file using stream wrapper
@@ -122,7 +122,7 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
}
function testStreamSetBlocking() {
$filename = '/tmp-' . time();
$filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files');
// Save short data as encrypted file using stream wrapper
@@ -136,6 +136,8 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
// set stream options
$this->assertTrue(stream_set_blocking($handle, 1));
fclose($handle);
// tear down
$view->unlink($filename);
}
@@ -144,7 +146,7 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
* @medium
*/
function testStreamSetTimeout() {
$filename = '/tmp-' . time();
$filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files');
// Save short data as encrypted file using stream wrapper
@@ -158,12 +160,14 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
// set stream options
$this->assertFalse(stream_set_timeout($handle, 1));
fclose($handle);
// tear down
$view->unlink($filename);
}
function testStreamSetWriteBuffer() {
$filename = '/tmp-' . time();
$filename = '/tmp-' . uniqid();
$view = new \OC\Files\View('/' . $this->userId . '/files');
// Save short data as encrypted file using stream wrapper
@@ -177,7 +181,48 @@ class Test_Encryption_Stream extends \PHPUnit_Framework_TestCase {
// set stream options
$this->assertEquals(0, stream_set_write_buffer($handle, 1024));
fclose($handle);
// tear down
$view->unlink($filename);
}
/**
* @medium
* @brief test if stream wrapper can read files outside from the data folder
*/
function testStreamFromLocalFile() {
$filename = '/' . $this->userId . '/files/' . 'tmp-' . time().'.txt';
$tmpFilename = "/tmp/" . time() . ".txt";
// write an encrypted file
$cryptedFile = $this->view->file_put_contents($filename, $this->dataShort);
// Test that data was successfully written
$this->assertTrue(is_int($cryptedFile));
// create a copy outside of the data folder in /tmp
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$encryptedContent = $this->view->file_get_contents($filename);
\OC_FileProxy::$enabled = $proxyStatus;
file_put_contents($tmpFilename, $encryptedContent);
\OCA\Encryption\Helper::addTmpFileToMapper($tmpFilename, $filename);
// try to read the file from /tmp
$handle = fopen("crypt://".$tmpFilename, "r");
$contentFromTmpFile = stream_get_contents($handle);
// check if it was successful
$this->assertEquals($this->dataShort, $contentFromTmpFile);
// clean up
unlink($tmpFilename);
$this->view->unlink($filename);
}
}

View File

@@ -119,7 +119,7 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
function testDeleteFile() {
// generate filename
$filename = 'tmp-' . time() . '.txt';
$filename = 'tmp-' . uniqid() . '.txt';
// save file with content
$cryptedFile = file_put_contents('crypt:///' .\Test_Encryption_Trashbin::TEST_ENCRYPTION_TRASHBIN_USER1. '/files/'. $filename, $this->dataShort);
@@ -223,7 +223,7 @@ class Test_Encryption_Trashbin extends \PHPUnit_Framework_TestCase {
function testPermanentDeleteFile() {
// generate filename
$filename = 'tmp-' . time() . '.txt';
$filename = 'tmp-' . uniqid() . '.txt';
// save file with content
$cryptedFile = file_put_contents('crypt:///' .$this->userId. '/files/' . $filename, $this->dataShort);

View File

@@ -64,6 +64,8 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
function setUp() {
// login user
\Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
\OC_User::setUserId(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
$this->userId = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1;
$this->pass = \Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1;
@@ -132,6 +134,41 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
}
/**
* @medium
* @brief test detection of encrypted files
*/
function testIsEncryptedPath() {
$util = new Encryption\Util($this->view, $this->userId);
self::loginHelper($this->userId);
$unencryptedFile = '/tmpUnencrypted-' . time() . '.txt';
$encryptedFile = '/tmpEncrypted-' . time() . '.txt';
// Disable encryption proxy to write a unencrypted file
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$this->view->file_put_contents($this->userId . '/files/' . $unencryptedFile, $this->dataShort);
// Re-enable proxy - our work is done
\OC_FileProxy::$enabled = $proxyStatus;
// write a encrypted file
$this->view->file_put_contents($this->userId . '/files/' . $encryptedFile, $this->dataShort);
// test if both files are detected correctly
$this->assertFalse($util->isEncryptedPath($this->userId . '/files/' . $unencryptedFile));
$this->assertTrue($util->isEncryptedPath($this->userId . '/files/' . $encryptedFile));
// cleanup
$this->view->unlink($this->userId . '/files/' . $unencryptedFile, $this->dataShort);
$this->view->unlink($this->userId . '/files/' . $encryptedFile, $this->dataShort);
}
/**
* @medium
* @brief test setup of encryption directories
@@ -219,7 +256,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
\OC_User::setUserId(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
$filename = '/tmp-' . time() . '.test';
$filename = '/tmp-' . uniqid() . '.test';
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
@@ -247,7 +284,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
function testGetFileSize() {
\Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
$filename = 'tmp-' . time();
$filename = 'tmp-' . uniqid();
$externalFilename = '/' . $this->userId . '/files/' . $filename;
// Test for 0 byte files
@@ -283,7 +320,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
function testEncryptAll() {
$filename = "/encryptAll" . time() . ".txt";
$filename = "/encryptAll" . uniqid() . ".txt";
$util = new Encryption\Util($this->view, $this->userId);
// disable encryption to upload a unencrypted file
@@ -315,7 +352,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
function testDecryptAll() {
$filename = "/decryptAll" . time() . ".txt";
$filename = "/decryptAll" . uniqid() . ".txt";
$util = new Encryption\Util($this->view, $this->userId);
$this->view->file_put_contents($this->userId . '/files/' . $filename, $this->dataShort);
@@ -323,9 +360,12 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
$fileInfoEncrypted = $this->view->getFileInfo($this->userId . '/files/' . $filename);
$this->assertTrue(is_array($fileInfoEncrypted));
$this->assertEquals($fileInfoEncrypted['encrypted'], 1);
// encrypt all unencrypted files
$util->decryptAll('/' . $this->userId . '/' . 'files');
// decrypt all encrypted files
$result = $util->decryptAll('/' . $this->userId . '/' . 'files');
$this->assertTrue($result);
$fileInfoUnencrypted = $this->view->getFileInfo($this->userId . '/files/' . $filename);
@@ -334,11 +374,83 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
// check if mtime and etags unchanged
$this->assertEquals($fileInfoEncrypted['mtime'], $fileInfoUnencrypted['mtime']);
$this->assertEquals($fileInfoEncrypted['etag'], $fileInfoUnencrypted['etag']);
// file should no longer be encrypted
$this->assertEquals(0, $fileInfoUnencrypted['encrypted']);
$this->view->unlink($this->userId . '/files/' . $filename);
}
function testDescryptAllWithBrokenFiles() {
$file1 = "/decryptAll1" . uniqid() . ".txt";
$file2 = "/decryptAll2" . uniqid() . ".txt";
$util = new Encryption\Util($this->view, $this->userId);
$this->view->file_put_contents($this->userId . '/files/' . $file1, $this->dataShort);
$this->view->file_put_contents($this->userId . '/files/' . $file2, $this->dataShort);
$fileInfoEncrypted1 = $this->view->getFileInfo($this->userId . '/files/' . $file1);
$fileInfoEncrypted2 = $this->view->getFileInfo($this->userId . '/files/' . $file2);
$this->assertTrue(is_array($fileInfoEncrypted1));
$this->assertTrue(is_array($fileInfoEncrypted2));
$this->assertEquals($fileInfoEncrypted1['encrypted'], 1);
$this->assertEquals($fileInfoEncrypted2['encrypted'], 1);
// rename keyfile for file1 so that the decryption for file1 fails
// Expected behaviour: decryptAll() returns false, file2 gets decrypted anyway
$this->view->rename($this->userId . '/files_encryption/keyfiles/' . $file1 . '.key',
$this->userId . '/files_encryption/keyfiles/' . $file1 . '.key.moved');
// decrypt all encrypted files
$result = $util->decryptAll('/' . $this->userId . '/' . 'files');
$this->assertFalse($result);
$fileInfoUnencrypted1 = $this->view->getFileInfo($this->userId . '/files/' . $file1);
$fileInfoUnencrypted2 = $this->view->getFileInfo($this->userId . '/files/' . $file2);
$this->assertTrue(is_array($fileInfoUnencrypted1));
$this->assertTrue(is_array($fileInfoUnencrypted2));
// file1 should be still encrypted; file2 should be decrypted
$this->assertEquals(1, $fileInfoUnencrypted1['encrypted']);
$this->assertEquals(0, $fileInfoUnencrypted2['encrypted']);
// keyfiles and share keys should still exist
$this->assertTrue($this->view->is_dir($this->userId . '/files_encryption/keyfiles/'));
$this->assertTrue($this->view->is_dir($this->userId . '/files_encryption/share-keys/'));
// rename the keyfile for file1 back
$this->view->rename($this->userId . '/files_encryption/keyfiles/' . $file1 . '.key.moved',
$this->userId . '/files_encryption/keyfiles/' . $file1 . '.key');
// try again to decrypt all encrypted files
$result = $util->decryptAll('/' . $this->userId . '/' . 'files');
$this->assertTrue($result);
$fileInfoUnencrypted1 = $this->view->getFileInfo($this->userId . '/files/' . $file1);
$fileInfoUnencrypted2 = $this->view->getFileInfo($this->userId . '/files/' . $file2);
$this->assertTrue(is_array($fileInfoUnencrypted1));
$this->assertTrue(is_array($fileInfoUnencrypted2));
// now both files should be decrypted
$this->assertEquals(0, $fileInfoUnencrypted1['encrypted']);
$this->assertEquals(0, $fileInfoUnencrypted2['encrypted']);
// keyfiles and share keys should be deleted
$this->assertFalse($this->view->is_dir($this->userId . '/files_encryption/keyfiles/'));
$this->assertFalse($this->view->is_dir($this->userId . '/files_encryption/share-keys/'));
$this->view->unlink($this->userId . '/files/' . $file1);
$this->view->unlink($this->userId . '/files/' . $file2);
}
/**
* @large
*/
@@ -416,6 +528,12 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
OCA\Encryption\Hooks::login($params);
}
public static function logoutHelper() {
\OC_Util::tearDownFS();
\OC_User::setUserId('');
\OC\Files\Filesystem::tearDown();
}
/**
* helper function to set migration status to the right value
* to be able to test the migration path

View File

@@ -48,6 +48,8 @@ class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase {
public $dataShort;
public $stateFilesTrashbin;
private $storage;
public static function setUpBeforeClass() {
// reset backend
\OC_User::clearBackends();
@@ -77,8 +79,8 @@ class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase {
$this->pass = \Test_Encryption_Webdav::TEST_ENCRYPTION_WEBDAV_USER1;
// init filesystem view
$this->view = new \OC_FilesystemView('/');
$this->view = new \OC\Files\View('/');
list($this->storage, $intPath) = $this->view->resolvePath('/');
// init short data
$this->dataShort = 'hats';
@@ -113,7 +115,7 @@ class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase {
function testWebdavPUT() {
// generate filename
$filename = '/tmp-' . time() . '.txt';
$filename = '/tmp-' . uniqid() . '.txt';
// set server vars
$_SERVER['REQUEST_METHOD'] = 'OPTIONS';
@@ -196,6 +198,9 @@ class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase {
$_SERVER['HTTP_AUTHORIZATION'] = 'Basic dGVzdC13ZWJkYXYtdXNlcjE6dGVzdC13ZWJkYXYtdXNlcjE=';
$_SERVER['PATH_INFO'] = '/webdav' . $filename;
// at the beginning the file should exist
$this->assertTrue($this->view->file_exists('/' . $this->userId . '/files' . $filename));
// handle webdav request
$content = $this->handleWebdavRequest();

View File

@@ -19,6 +19,11 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# Addition 17/12/2012 Frank Karlitschek (frank@owncloud.org)
# Addition 17/03/2014 Robin McCorkell (rmccorkell@karoshi.org.uk)
# On the official website http://www.phpclasses.org/smb4php the
# license is listed as LGPL so we assume that this is
# dual-licensed GPL/LGPL
###################################################################
define ('SMB4PHP_VERSION', '0.8');
@@ -126,7 +131,7 @@ class smb {
// this put env is necessary to read the output of smbclient correctly
$old_locale = getenv('LC_ALL');
putenv('LC_ALL=en_US.UTF-8');
$output = popen (SMB4PHP_SMBCLIENT." -N {$auth} {$options} {$port} {$options} {$params} 2>/dev/null", 'r');
$output = popen ('TZ=UTC '.SMB4PHP_SMBCLIENT." -N {$auth} {$options} {$port} {$options} {$params} 2>/dev/null", 'r');
$gotInfo = false;
$info = array ();
$info['info']= array ();
@@ -160,7 +165,7 @@ class smb {
$i = ($mode == 'servers') ? array ($name, "server") : array ($name, "workgroup", $master);
break;
case 'files':
list ($attr, $name) = preg_match ("/^(.*)[ ]+([D|A|H|S|R]+)$/", trim ($regs[1]), $regs2)
list ($attr, $name) = preg_match ("/^(.*)[ ]+([D|A|H|S|R|N]+)$/", trim ($regs[1]), $regs2)
? array (trim ($regs2[2]), trim ($regs2[1]))
: array ('', trim ($regs[1]));
list ($his, $im) = array (
@@ -234,17 +239,10 @@ class smb {
trigger_error ("url_stat(): list failed for host '{$pu['host']}'", E_USER_WARNING);
break;
case 'share':
if ($o = smb::look ($pu)) {
$found = FALSE;
$lshare = strtolower ($pu['share']); # fix by Eric Leung
foreach ($o['disk'] as $s) if ($lshare == strtolower($s)) {
$found = TRUE;
$stat = stat ("/tmp");
break;
}
if (! $found)
trigger_error ("url_stat(): disk resource '{$lshare}' not found in '{$pu['host']}'", E_USER_WARNING);
}
if (smb::execute("ls", $pu))
$stat = stat ("/tmp");
else
trigger_error ("url_stat(): disk resource '{$pu['share']}' not found in '{$pu['host']}'", E_USER_WARNING);
break;
case 'path':
if ($o = smb::execute ('dir "'.$pu['path'].'"', $pu)) {

View File

@@ -1,10 +1,15 @@
<?php
OCP\JSON::checkAppEnabled('files_external');
OCP\JSON::checkLoggedIn();
OCP\JSON::callCheck();
if ($_POST['isPersonal'] == 'true') {
OCP\JSON::checkLoggedIn();
// Check whether the user has permissions to add personal storage backends
if(OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') !== 'yes') {
OCP\JSON::error(array('data' => array('message' => 'no permission')));
return;
}
$isPersonal = true;
} else {
OCP\JSON::checkAdminUser();

View File

@@ -24,5 +24,6 @@ if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == '
}
// connecting hooks
OCP\Util::connectHook( 'OC_User', 'post_login', 'OC\Files\Storage\iRODS', 'login' );
OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\OC_Mount_Config', 'initMountPointsHook');
OCP\Util::connectHook('OC_User', 'post_login', 'OC\Files\Storage\iRODS', 'login');

View File

@@ -13,7 +13,7 @@ span.error {
}
td.mountPoint, td.backend { width:10em; }
td.remove>img { visibility:hidden; padding-top:0.8em; }
td.remove>img { visibility:hidden; padding-top:0.5em; }
tr:hover>td.remove>img { visibility:visible; cursor:pointer; }
#addMountPoint>td { border:none; }
#addMountPoint>td.applicable { visibility:hidden; }
@@ -22,3 +22,8 @@ tr:hover>td.remove>img { visibility:visible; cursor:pointer; }
#externalStorage label > input[type="checkbox"] {
margin-right: 3px;
}
#externalStorage td.applicable div.chzn-container {
position: relative;
top: 3px;
}

View File

@@ -23,9 +23,12 @@ $(document).ready(function() {
$(token).val(result.access_token);
$(token_secret).val(result.access_token_secret);
$(configured).val('true');
OC.MountConfig.saveStorage(tr);
$(tr).find('.configuration input').attr('disabled', 'disabled');
$(tr).find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>');
OC.MountConfig.saveStorage(tr, function(status) {
if (status) {
$(tr).find('.configuration input').attr('disabled', 'disabled');
$(tr).find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>');
}
});
} else {
OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Dropbox storage'));
}
@@ -77,7 +80,6 @@ $(document).ready(function() {
var tr = $(this).parent().parent();
var app_key = $(this).parent().find('[data-parameter="app_key"]').val();
var app_secret = $(this).parent().find('[data-parameter="app_secret"]').val();
var statusSpan = $(tr).find('.status span');
if (app_key != '' && app_secret != '') {
var tr = $(this).parent().parent();
var configured = $(this).parent().find('[data-parameter="configured"]');
@@ -88,10 +90,9 @@ $(document).ready(function() {
$(configured).val('false');
$(token).val(result.data.request_token);
$(token_secret).val(result.data.request_token_secret);
OC.MountConfig.saveStorage(tr);
statusSpan.removeClass();
statusSpan.addClass('waiting');
window.location = result.data.url;
OC.MountConfig.saveStorage(tr, function() {
window.location = result.data.url;
});
} else {
OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Dropbox storage'));
}

View File

@@ -32,11 +32,14 @@ $(document).ready(function() {
if (result && result.status == 'success') {
$(token).val(result.data.token);
$(configured).val('true');
OC.MountConfig.saveStorage(tr);
$(tr).find('.configuration input').attr('disabled', 'disabled');
$(tr).find('.configuration').append($('<span/>')
.attr('id', 'access')
.text(t('files_external', 'Access granted')));
OC.MountConfig.saveStorage(tr, function(status) {
if (status) {
$(tr).find('.configuration input').attr('disabled', 'disabled');
$(tr).find('.configuration').append($('<span/>')
.attr('id', 'access')
.text(t('files_external', 'Access granted')));
}
});
} else {
OC.dialogs.alert(result.data.message,
t('files_external', 'Error configuring Google Drive storage')
@@ -99,7 +102,6 @@ $(document).ready(function() {
var configured = $(this).parent().find('[data-parameter="configured"]');
var client_id = $(this).parent().find('[data-parameter="client_id"]').val();
var client_secret = $(this).parent().find('[data-parameter="client_secret"]').val();
var statusSpan = $(tr).find('.status span');
if (client_id != '' && client_secret != '') {
var token = $(this).parent().find('[data-parameter="token"]');
$.post(OC.filePath('files_external', 'ajax', 'google.php'),
@@ -112,10 +114,9 @@ $(document).ready(function() {
if (result && result.status == 'success') {
$(configured).val('false');
$(token).val('false');
OC.MountConfig.saveStorage(tr);
statusSpan.removeClass();
statusSpan.addClass('waiting');
window.location = result.data.url;
OC.MountConfig.saveStorage(tr, function(status) {
window.location = result.data.url;
});
} else {
OC.dialogs.alert(result.data.message,
t('files_external', 'Error configuring Google Drive storage')

View File

@@ -12,7 +12,7 @@ function updateStatus(statusEl, result){
}
OC.MountConfig={
saveStorage:function(tr) {
saveStorage:function(tr, callback) {
var mountPoint = $(tr).find('.mountPoint input').val();
if (mountPoint == '') {
return false;
@@ -84,9 +84,15 @@ OC.MountConfig={
},
success: function(result) {
status = updateStatus(statusSpan, result);
if (callback) {
callback(status);
}
},
error: function(result){
status = updateStatus(statusSpan, result);
if (callback) {
callback(status);
}
}
});
});
@@ -137,9 +143,15 @@ OC.MountConfig={
},
success: function(result) {
status = updateStatus(statusSpan, result);
if (callback) {
callback(status);
}
},
error: function(result){
status = updateStatus(statusSpan, result);
if (callback) {
callback(status);
}
}
});
}

View File

@@ -1,6 +0,0 @@
<?php
$TRANSLATIONS = array(
"Options" => "Опции",
"Delete" => "Удалить"
);
$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);";

View File

@@ -81,9 +81,9 @@ class AmazonS3 extends \OC\Files\Storage\Common {
$scheme = ($params['use_ssl'] === 'false') ? 'http' : 'https';
$this->test = isset($params['test']);
$this->timeout = ( ! isset($params['timeout'])) ? 15 : $params['timeout'];
$params['region'] = ( ! isset($params['region'])) ? 'eu-west-1' : $params['region'];
$params['hostname'] = ( !isset($params['hostname'])) ? 's3.amazonaws.com' : $params['hostname'];
if (!isset($params['port'])) {
$params['region'] = ( ! isset($params['region']) || $params['region'] === '' ) ? 'eu-west-1' : $params['region'];
$params['hostname'] = ( !isset($params['hostname']) || $params['hostname'] === '' ) ? 's3.amazonaws.com' : $params['hostname'];
if (!isset($params['port']) || $params['port'] === '') {
$params['port'] = ($params['use_ssl'] === 'false') ? 80 : 443;
}
$base_url = $scheme.'://'.$params['hostname'].':'.$params['port'].'/';
@@ -507,8 +507,10 @@ class AmazonS3 extends \OC\Files\Storage\Common {
}
public function test() {
$test = $this->s3->get_canonical_user_id();
if (isset($test['id']) && $test['id'] != '') {
$test = $this->connection->getBucketAcl(array(
'Bucket' => $this->bucket,
));
if (isset($test) && !is_null($test->getPath('Owner/ID'))) {
return true;
}
return false;

View File

@@ -4,6 +4,7 @@
*
* @author Michael Gapczynski
* @copyright 2012 Michael Gapczynski mtgap@owncloud.com
* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@@ -19,15 +20,24 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
set_include_path(
get_include_path() . PATH_SEPARATOR .
\OC_App::getAppPath('files_external') . '/3rdparty/phpseclib/phpseclib'
);
/**
* Class to configure the config/mount.php and data/$user/mount.php files
*/
* Class to configure mount.json globally and for users
*/
class OC_Mount_Config {
// TODO: make this class non-static and give it a proper namespace
const MOUNT_TYPE_GLOBAL = 'global';
const MOUNT_TYPE_GROUP = 'group';
const MOUNT_TYPE_USER = 'user';
// whether to skip backend test (for unit tests, as this static class is not mockable)
public static $skipTest = false;
/**
* Get details on each of the external storage backends, used for the mount config UI
* If a custom UI is needed, add the key 'custom' and a javascript file with that name will be loaded
@@ -39,6 +49,7 @@ class OC_Mount_Config {
*/
public static function getBackends() {
// FIXME: do not rely on php key order for the options order in the UI
$backends['\OC\Files\Storage\Local']=array(
'backend' => 'Local',
'configuration' => array(
@@ -50,9 +61,9 @@ class OC_Mount_Config {
'key' => 'Access Key',
'secret' => '*Secret Key',
'bucket' => 'Bucket',
'hostname' => 'Hostname (optional)',
'port' => 'Port (optional)',
'region' => 'Region (optional)',
'hostname' => '&Hostname (optional)',
'port' => '&Port (optional)',
'region' => '&Region (optional)',
'use_ssl' => '!Enable SSL',
'use_path_style' => '!Enable Path Style'));
@@ -61,7 +72,7 @@ class OC_Mount_Config {
'configuration' => array(
'configured' => '#configured',
'app_key' => 'App key',
'app_secret' => 'App secret',
'app_secret' => '*App secret',
'token' => '#token',
'token_secret' => '#token_secret'),
'custom' => 'dropbox');
@@ -69,7 +80,7 @@ class OC_Mount_Config {
if(OC_Mount_Config::checkphpftp()) $backends['\OC\Files\Storage\FTP']=array(
'backend' => 'FTP',
'configuration' => array(
'host' => 'URL',
'host' => 'Hostname',
'user' => 'Username',
'password' => '*Password',
'root' => '&Root',
@@ -80,7 +91,7 @@ class OC_Mount_Config {
'configuration' => array(
'configured' => '#configured',
'client_id' => 'Client ID',
'client_secret' => 'Client secret',
'client_secret' => '*Client secret',
'token' => '#token'),
'custom' => 'google');
@@ -145,6 +156,125 @@ class OC_Mount_Config {
return($backends);
}
/**
* Hook that mounts the given user's visible mount points
* @param array $data
*/
public static function initMountPointsHook($data) {
$mountPoints = self::getAbsoluteMountPoints($data['user']);
foreach ($mountPoints as $mountPoint => $options) {
\OC\Files\Filesystem::mount($options['class'], $options['options'], $mountPoint);
}
}
/**
* Returns the mount points for the given user.
* The mount point is relative to the data directory.
*
* @param string $user user
* @return array of mount point string as key, mountpoint config as value
*/
public static function getAbsoluteMountPoints($user) {
$mountPoints = array();
$datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
$mount_file = \OC_Config::getValue("mount_file", $datadir . "/mount.json");
//move config file to it's new position
if (is_file(\OC::$SERVERROOT . '/config/mount.json')) {
rename(\OC::$SERVERROOT . '/config/mount.json', $mount_file);
}
// Load system mount points
$mountConfig = self::readData(false);
if (isset($mountConfig[self::MOUNT_TYPE_GLOBAL])) {
foreach ($mountConfig[self::MOUNT_TYPE_GLOBAL] as $mountPoint => $options) {
$options['options'] = self::decryptPasswords($options['options']);
$mountPoints[$mountPoint] = $options;
}
}
if (isset($mountConfig[self::MOUNT_TYPE_GROUP])) {
foreach ($mountConfig[self::MOUNT_TYPE_GROUP] as $group => $mounts) {
if (\OC_Group::inGroup($user, $group)) {
foreach ($mounts as $mountPoint => $options) {
$mountPoint = self::setUserVars($user, $mountPoint);
foreach ($options as &$option) {
$option = self::setUserVars($user, $option);
}
$options['options'] = self::decryptPasswords($options['options']);
$mountPoints[$mountPoint] = $options;
}
}
}
}
if (isset($mountConfig[self::MOUNT_TYPE_USER])) {
foreach ($mountConfig[self::MOUNT_TYPE_USER] as $mountUser => $mounts) {
if ($mountUser === 'all' or strtolower($mountUser) === strtolower($user)) {
foreach ($mounts as $mountPoint => $options) {
$mountPoint = self::setUserVars($user, $mountPoint);
foreach ($options as &$option) {
$option = self::setUserVars($user, $option);
}
$options['options'] = self::decryptPasswords($options['options']);
$mountPoints[$mountPoint] = $options;
}
}
}
}
// Load personal mount points
$mountConfig = self::readData(true);
if (isset($mountConfig[self::MOUNT_TYPE_USER][$user])) {
foreach ($mountConfig[self::MOUNT_TYPE_USER][$user] as $mountPoint => $options) {
$options['options'] = self::decryptPasswords($options['options']);
$mountPoints[$mountPoint] = $options;
}
}
return $mountPoints;
}
/**
* fill in the correct values for $user
*
* @param string $user
* @param string $input
* @return string
*/
private static function setUserVars($user, $input) {
return str_replace('$user', $user, $input);
}
/**
* Get details on each of the external storage backends, used for the mount config UI
* Some backends are not available as a personal backend, f.e. Local and such that have
* been disabled by the admin.
*
* If a custom UI is needed, add the key 'custom' and a javascript file with that name will be loaded
* If the configuration parameter should be secret, add a '*' to the beginning of the value
* If the configuration parameter is a boolean, add a '!' to the beginning of the value
* If the configuration parameter is optional, add a '&' to the beginning of the value
* If the configuration parameter is hidden, add a '#' to the beginning of the value
* @return array
*/
public static function getPersonalBackends() {
$backends = self::getBackends();
// Remove local storage and other disabled storages
unset($backends['\OC\Files\Storage\Local']);
$allowed_backends = explode(',', OCP\Config::getAppValue('files_external', 'user_mounting_backends', ''));
foreach ($backends as $backend => $null) {
if (!in_array($backend, $allowed_backends)) {
unset($backends[$backend]);
}
}
return $backends;
}
/**
* Get the system mount points
* The returned array is not in the same format as getUserMountPoints()
@@ -161,6 +291,7 @@ class OC_Mount_Config {
if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
$mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15);
}
$mount['options'] = self::decryptPasswords($mount['options']);
// Remove '/$user/files/' from mount point
$mountPoint = substr($mountPoint, 13);
// Merge the mount point into the current mount points
@@ -186,6 +317,7 @@ class OC_Mount_Config {
if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
$mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15);
}
$mount['options'] = self::decryptPasswords($mount['options']);
// Remove '/$user/files/' from mount point
$mountPoint = substr($mountPoint, 13);
// Merge the mount point into the current mount points
@@ -223,6 +355,7 @@ class OC_Mount_Config {
if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
$mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15);
}
$mount['options'] = self::decryptPasswords($mount['options']);
// Remove '/uid/files/' from mount point
$personal[substr($mountPoint, strlen($uid) + 8)] = array(
'class' => $mount['class'],
@@ -235,15 +368,25 @@ class OC_Mount_Config {
return $personal;
}
/**
* Test connecting using the given backend configuration
* @param string $class backend class name
* @param array $options backend configuration options
* @return bool true if the connection succeeded, false otherwise
*/
private static function getBackendStatus($class, $options) {
if (self::$skipTest) {
return true;
}
foreach ($options as &$option) {
$option = str_replace('$user', OCP\User::getUser(), $option);
$option = self::setUserVars(OCP\User::getUser(), $option);
}
if (class_exists($class)) {
try {
$storage = new $class($options);
return $storage->test();
} catch (Exception $exception) {
\OCP\Util::logException('files_external', $exception);
return false;
}
}
@@ -266,22 +409,34 @@ class OC_Mount_Config {
$mountType,
$applicable,
$isPersonal = false) {
$backends = self::getBackends();
$mountPoint = OC\Files\Filesystem::normalizePath($mountPoint);
if ($mountPoint === '' || $mountPoint === '/' || $mountPoint == '/Shared') {
// can't mount at root or "Shared" folder
return false;
}
if (!isset($backends[$class])) {
// invalid backend
return false;
}
if ($isPersonal) {
// Verify that the mount point applies for the current user
// Prevent non-admin users from mounting local storage
if ($applicable != OCP\User::getUser() || $class == '\OC\Files\Storage\Local') {
if ($applicable !== OCP\User::getUser() || strtolower($class) === '\oc\files\storage\local') {
return false;
}
$mountPoint = '/'.$applicable.'/files/'.ltrim($mountPoint, '/');
} else {
$mountPoint = '/$user/files/'.ltrim($mountPoint, '/');
}
$mount = array($applicable => array($mountPoint => array('class' => $class, 'options' => $classOptions)));
$mount = array($applicable => array(
$mountPoint => array(
'class' => $class,
'options' => self::encryptPasswords($classOptions))
)
);
$mountPoints = self::readData($isPersonal);
// Merge the new mount point into the current mount points
if (isset($mountPoints[$mountType])) {
@@ -381,8 +536,7 @@ class OC_Mount_Config {
* @return array
*/
public static function getCertificates() {
$view = \OCP\Files::getStorage('files_external');
$path=\OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath("").'uploads/';
$path=OC_User::getHome(OC_User::getUser()) . '/files_external/uploads/';
\OCP\Util::writeLog('files_external', 'checking path '.$path, \OCP\Util::INFO);
if ( ! is_dir($path)) {
//path might not exist (e.g. non-standard OC_User::getHome() value)
@@ -404,8 +558,7 @@ class OC_Mount_Config {
* creates certificate bundle
*/
public static function createCertificateBundle() {
$view = \OCP\Files::getStorage("files_external");
$path = \OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath("");
$path=OC_User::getHome(OC_User::getUser()) . '/files_external';
$certs = OC_Mount_Config::getCertificates();
$fh_certs = fopen($path."/rootcerts.crt", 'w');
@@ -475,4 +628,71 @@ class OC_Mount_Config {
return $txt;
}
/**
* Encrypt passwords in the given config options
* @param array $options mount options
* @return array updated options
*/
private static function encryptPasswords($options) {
if (isset($options['password'])) {
$options['password_encrypted'] = self::encryptPassword($options['password']);
// do not unset the password, we want to keep the keys order
// on load... because that's how the UI currently works
$options['password'] = '';
}
return $options;
}
/**
* Decrypt passwords in the given config options
* @param array $options mount options
* @return array updated options
*/
private static function decryptPasswords($options) {
// note: legacy options might still have the unencrypted password in the "password" field
if (isset($options['password_encrypted'])) {
$options['password'] = self::decryptPassword($options['password_encrypted']);
unset($options['password_encrypted']);
}
return $options;
}
/**
* Encrypt a single password
* @param string $password plain text password
* @return encrypted password
*/
private static function encryptPassword($password) {
$cipher = self::getCipher();
$iv = \OCP\Util::generateRandomBytes(16);
$cipher->setIV($iv);
return base64_encode($iv . $cipher->encrypt($password));
}
/**
* Decrypts a single password
* @param string $encryptedPassword encrypted password
* @return plain text password
*/
private static function decryptPassword($encryptedPassword) {
$cipher = self::getCipher();
$binaryPassword = base64_decode($encryptedPassword);
$iv = substr($binaryPassword, 0, 16);
$cipher->setIV($iv);
$binaryPassword = substr($binaryPassword, 16);
return $cipher->decrypt($binaryPassword);
}
/**
* Returns the encryption cipher
*/
private static function getCipher() {
if (!class_exists('Crypt_AES', false)) {
include('Crypt/AES.php');
}
$cipher = new Crypt_AES(CRYPT_AES_MODE_CBC);
$cipher->setKey(\OCP\Config::getSystemValue('passwordsalt'));
return $cipher;
}
}

View File

@@ -37,7 +37,7 @@ class SMB extends \OC\Files\Storage\StreamWrapper{
$this->share = substr($this->share, 0, -1);
}
} else {
throw new \Exception();
throw new \Exception('Invalid configuration');
}
}

View File

@@ -245,6 +245,10 @@ class Swift extends \OC\Files\Storage\Common {
$mtime = $object->extra_headers['X-Object-Meta-Timestamp'];
}
if (!empty($mtime)) {
$mtime = floor($mtime);
}
$stat = array();
$stat['size'] = $object->content_length;
$stat['mtime'] = $mtime;
@@ -364,7 +368,7 @@ class Swift extends \OC\Files\Storage\Common {
'X-Object-Meta-Timestamp' => $mtime
)
);
return $object->Update($settings);
return $object->UpdateMetadata($settings);
} else {
$object = $this->container->DataObject();
if (is_null($mtime)) {

View File

@@ -14,6 +14,7 @@ class DAV extends \OC\Files\Storage\Common{
private $host;
private $secure;
private $root;
private $certPath;
private $ready;
/**
* @var \Sabre_DAV_Client
@@ -40,6 +41,12 @@ class DAV extends \OC\Files\Storage\Common{
} else {
$this->secure = false;
}
if ($this->secure === true) {
$certPath=\OC_User::getHome(\OC_User::getUser()) . '/files_external/rootcerts.crt';
if (file_exists($certPath)) {
$this->certPath=$certPath;
}
}
$this->root=isset($params['root'])?$params['root']:'/';
if ( ! $this->root || $this->root[0]!='/') {
$this->root='/'.$this->root;
@@ -58,20 +65,16 @@ class DAV extends \OC\Files\Storage\Common{
}
$this->ready = true;
$settings = array(
'baseUri' => $this->createBaseUri(),
'userName' => $this->user,
'password' => $this->password,
);
$settings = array(
'baseUri' => $this->createBaseUri(),
'userName' => $this->user,
'password' => $this->password,
);
$this->client = new \Sabre_DAV_Client($settings);
$caview = \OCP\Files::getStorage('files_external');
if ($caview) {
$certPath=\OCP\Config::getSystemValue('datadirectory').$caview->getAbsolutePath("").'rootcerts.crt';
if (file_exists($certPath)) {
$this->client->addTrustedCertificates($certPath);
}
if ($this->secure === true && $this->certPath) {
$this->client->addTrustedCertificates($this->certPath);
}
}
@@ -166,7 +169,14 @@ class DAV extends \OC\Files\Storage\Common{
curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().str_replace(' ', '%20', $path));
curl_setopt($curl, CURLOPT_FILE, $fp);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
if ($this->secure === true) {
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
if($this->certPath){
curl_setopt($curl, CURLOPT_CAINFO, $this->certPath);
}
}
curl_exec ($curl);
curl_close ($curl);
rewind($fp);
@@ -214,7 +224,7 @@ class DAV extends \OC\Files\Storage\Common{
if (isset($response['{DAV:}quota-available-bytes'])) {
return (int)$response['{DAV:}quota-available-bytes'];
} else {
return 0;
return \OC\Files\SPACE_UNKNOWN;
}
} catch(\Exception $e) {
return \OC\Files\SPACE_UNKNOWN;
@@ -254,6 +264,13 @@ class DAV extends \OC\Files\Storage\Common{
curl_setopt($curl, CURLOPT_INFILE, $source); // file pointer
curl_setopt($curl, CURLOPT_INFILESIZE, filesize($path));
curl_setopt($curl, CURLOPT_PUT, true);
if ($this->secure === true) {
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
if($this->certPath){
curl_setopt($curl, CURLOPT_CAINFO, $this->certPath);
}
}
curl_exec ($curl);
curl_close ($curl);
}
@@ -331,3 +348,4 @@ class DAV extends \OC\Files\Storage\Common{
}
}
}

View File

@@ -60,7 +60,7 @@
class="optional"
data-parameter="<?php p($parameter); ?>"
value="<?php p($value); ?>"
placeholder="<?php p(substr($placeholder, 5)); ?>" />
placeholder="<?php p(substr($placeholder, 1)); ?>" />
<?php elseif (strpos($placeholder, '#') !== false): ?>
<input type="hidden"
data-parameter="<?php p($parameter); ?>"

View File

@@ -34,6 +34,90 @@ class Test_Mount_Config_Dummy_Storage {
* Class Test_Mount_Config
*/
class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
private $dataDir;
private $userHome;
private $oldAllowedBackends;
private $allBackends;
const TEST_USER1 = 'user1';
const TEST_USER2 = 'user2';
const TEST_GROUP1 = 'group1';
const TEST_GROUP2 = 'group2';
public function setUp() {
\OC_User::createUser(self::TEST_USER1, self::TEST_USER1);
\OC_User::createUser(self::TEST_USER2, self::TEST_USER2);
\OC_Group::createGroup(self::TEST_GROUP1);
\OC_Group::addToGroup(self::TEST_USER1, self::TEST_GROUP1);
\OC_Group::createGroup(self::TEST_GROUP2);
\OC_Group::addToGroup(self::TEST_USER2, self::TEST_GROUP2);
\OC_User::setUserId(self::TEST_USER1);
$this->userHome = \OC_User::getHome(self::TEST_USER1);
mkdir($this->userHome);
$this->dataDir = \OC_Config::getValue(
'datadirectory',
\OC::$SERVERROOT . '/data/'
);
$this->oldAllowedBackends = OCP\Config::getAppValue(
'files_external',
'user_mounting_backends',
''
);
$this->allBackends = OC_Mount_Config::getBackends();
OCP\Config::setAppValue(
'files_external',
'user_mounting_backends',
implode(',', array_keys($this->allBackends))
);
OC_Mount_Config::$skipTest = true;
}
public function tearDown() {
OC_Mount_Config::$skipTest = false;
\OC_User::deleteUser(self::TEST_USER2);
\OC_User::deleteUser(self::TEST_USER1);
\OC_Group::deleteGroup(self::TEST_GROUP1);
\OC_Group::deleteGroup(self::TEST_GROUP2);
@unlink($this->dataDir . '/mount.json');
OCP\Config::setAppValue(
'files_external',
'user_mounting_backends',
$this->oldAllowedBackends
);
}
/**
* Reads the global config, for checking
*/
private function readGlobalConfig() {
$configFile = $this->dataDir . '/mount.json';
return json_decode(file_get_contents($configFile), true);
}
/**
* Reads the user config, for checking
*/
private function readUserConfig() {
$configFile = $this->userHome . '/mount.json';
return json_decode(file_get_contents($configFile), true);
}
/**
* Write the user config, to simulate existing files
*/
private function writeUserConfig($config) {
$configFile = $this->userHome . '/mount.json';
file_put_contents($configFile, json_encode($config));
}
/**
* Test mount point validation
*/
@@ -42,10 +126,329 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
$mountType = 'user';
$applicable = 'all';
$isPersonal = false;
$this->assertEquals(false, OC_Mount_Config::addMountPoint('', $storageClass, array(), $mountType, $applicable, $isPersonal));
$this->assertEquals(false, OC_Mount_Config::addMountPoint('/', $storageClass, array(), $mountType, $applicable, $isPersonal));
$this->assertEquals(false, OC_Mount_Config::addMountPoint('Shared', $storageClass, array(), $mountType, $applicable, $isPersonal));
$this->assertEquals(false, OC_Mount_Config::addMountPoint('/Shared', $storageClass, array(), $mountType, $applicable, $isPersonal));
$this->assertFalse(OC_Mount_Config::addMountPoint('', $storageClass, array(), $mountType, $applicable, $isPersonal));
$this->assertFalse(OC_Mount_Config::addMountPoint('/', $storageClass, array(), $mountType, $applicable, $isPersonal));
$this->assertFalse(OC_Mount_Config::addMountPoint('Shared', $storageClass, array(), $mountType, $applicable, $isPersonal));
$this->assertFalse(OC_Mount_Config::addMountPoint('/Shared', $storageClass, array(), $mountType, $applicable, $isPersonal));
}
/**
* Test adding a global mount point
*/
public function testAddGlobalMountPoint() {
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
$applicable = 'all';
$isPersonal = false;
$this->assertEquals(true, OC_Mount_Config::addMountPoint('/ext', '\OC\Files\Storage\SFTP', array(), $mountType, $applicable, $isPersonal));
$config = $this->readGlobalConfig();
$this->assertEquals(1, count($config));
$this->assertTrue(isset($config[$mountType]));
$this->assertTrue(isset($config[$mountType][$applicable]));
$this->assertTrue(isset($config[$mountType][$applicable]['/$user/files/ext']));
$this->assertEquals(
'\OC\Files\Storage\SFTP',
$config[$mountType][$applicable]['/$user/files/ext']['class']
);
}
/**
* Test adding a personal mount point
*/
public function testAddMountPointSingleUser() {
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
$applicable = self::TEST_USER1;
$isPersonal = true;
$this->assertEquals(true, OC_Mount_Config::addMountPoint('/ext', '\OC\Files\Storage\SFTP', array(), $mountType, $applicable, $isPersonal));
$config = $this->readUserConfig();
$this->assertEquals(1, count($config));
$this->assertTrue(isset($config[$mountType]));
$this->assertTrue(isset($config[$mountType][$applicable]));
$this->assertTrue(isset($config[$mountType][$applicable]['/' . self::TEST_USER1 . '/files/ext']));
$this->assertEquals(
'\OC\Files\Storage\SFTP',
$config[$mountType][$applicable]['/' . self::TEST_USER1 . '/files/ext']['class']
);
}
/**
* Test adding a mount point with an non-existant backend
*/
public function testAddMountPointUnexistClass() {
$storageClass = 'Unexist_Storage';
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
$applicable = self::TEST_USER1;
$isPersonal = false;
$this->assertFalse(OC_Mount_Config::addMountPoint('/ext', $storageClass, array(), $mountType, $applicable, $isPersonal));
}
/**
* Test reading and writing global config
*/
public function testReadWriteGlobalConfig() {
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
$applicable = 'all';
$isPersonal = false;
$mountConfig = array(
'host' => 'smbhost',
'user' => 'smbuser',
'password' => 'smbpassword',
'share' => 'smbshare',
'root' => 'smbroot'
);
// write config
$this->assertTrue(
OC_Mount_Config::addMountPoint(
'/ext',
'\OC\Files\Storage\SMB',
$mountConfig,
$mountType,
$applicable,
$isPersonal
)
);
// re-read config
$config = OC_Mount_Config::getSystemMountPoints();
$this->assertEquals(1, count($config));
$this->assertTrue(isset($config['ext']));
$this->assertEquals('\OC\Files\Storage\SMB', $config['ext']['class']);
$savedMountConfig = $config['ext']['configuration'];
$this->assertEquals($mountConfig, $savedMountConfig);
// key order needs to be preserved for the UI...
$this->assertEquals(array_keys($mountConfig), array_keys($savedMountConfig));
}
/**
* Test reading and writing config
*/
public function testReadWritePersonalConfig() {
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
$applicable = self::TEST_USER1;
$isPersonal = true;
$mountConfig = array(
'host' => 'smbhost',
'user' => 'smbuser',
'password' => 'smbpassword',
'share' => 'smbshare',
'root' => 'smbroot'
);
// write config
$this->assertTrue(
OC_Mount_Config::addMountPoint(
'/ext',
'\OC\Files\Storage\SMB',
$mountConfig,
$mountType,
$applicable,
$isPersonal
)
);
// re-read config
$config = OC_Mount_Config::getPersonalMountPoints();
$this->assertEquals(1, count($config));
$this->assertTrue(isset($config['ext']));
$this->assertEquals('\OC\Files\Storage\SMB', $config['ext']['class']);
$savedMountConfig = $config['ext']['configuration'];
$this->assertEquals($mountConfig, $savedMountConfig);
// key order needs to be preserved for the UI...
$this->assertEquals(array_keys($mountConfig), array_keys($savedMountConfig));
}
/**
* Test password obfuscation
*/
public function testPasswordObfuscation() {
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
$applicable = self::TEST_USER1;
$isPersonal = true;
$mountConfig = array(
'host' => 'smbhost',
'user' => 'smbuser',
'password' => 'smbpassword',
'share' => 'smbshare',
'root' => 'smbroot'
);
// write config
$this->assertTrue(
OC_Mount_Config::addMountPoint(
'/ext',
'\OC\Files\Storage\SMB',
$mountConfig,
$mountType,
$applicable,
$isPersonal
)
);
// note: password re-reading is covered by testReadWritePersonalConfig
// check that password inside the file is NOT in plain text
$config = $this->readUserConfig();
$savedConfig = $config[$mountType][$applicable]['/' . self::TEST_USER1 . '/files/ext']['options'];
// no more clear text password in file (kept because of key order)
$this->assertEquals('', $savedConfig['password']);
// encrypted password is present
$this->assertNotEquals($mountConfig['password'], $savedConfig['password_encrypted']);
}
/**
* Test read legacy passwords
*/
public function testReadLegacyPassword() {
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
$applicable = self::TEST_USER1;
$isPersonal = true;
$mountConfig = array(
'host' => 'smbhost',
'user' => 'smbuser',
'password' => 'smbpassword',
'share' => 'smbshare',
'root' => 'smbroot'
);
// write config
$this->assertTrue(
OC_Mount_Config::addMountPoint(
'/ext',
'\OC\Files\Storage\SMB',
$mountConfig,
$mountType,
$applicable,
$isPersonal
)
);
$config = $this->readUserConfig();
// simulate non-encrypted password situation
$config[$mountType][$applicable]['/' . self::TEST_USER1 . '/files/ext']['options']['password'] = 'smbpasswd';
$this->writeUserConfig($config);
// re-read config, password was read correctly
$config = OC_Mount_Config::getPersonalMountPoints();
$savedMountConfig = $config['ext']['configuration'];
$this->assertEquals($mountConfig, $savedMountConfig);
}
public function mountDataProvider() {
return array(
// Tests for visible mount points
// system mount point for all users
array(
false,
OC_Mount_Config::MOUNT_TYPE_USER,
'all',
self::TEST_USER1,
true,
),
// system mount point for a specific user
array(
false,
OC_Mount_Config::MOUNT_TYPE_USER,
self::TEST_USER1,
self::TEST_USER1,
true,
),
// system mount point for a specific group
array(
false,
OC_Mount_Config::MOUNT_TYPE_GROUP,
self::TEST_GROUP1,
self::TEST_USER1,
true,
),
// user mount point
array(
true,
OC_Mount_Config::MOUNT_TYPE_USER,
self::TEST_USER1,
self::TEST_USER1,
true,
),
// Tests for non-visible mount points
// system mount point for another user
array(
false,
OC_Mount_Config::MOUNT_TYPE_USER,
self::TEST_USER2,
self::TEST_USER1,
false,
),
// system mount point for a specific group
array(
false,
OC_Mount_Config::MOUNT_TYPE_GROUP,
self::TEST_GROUP2,
self::TEST_USER1,
false,
),
// user mount point
array(
true,
OC_Mount_Config::MOUNT_TYPE_USER,
self::TEST_USER1,
self::TEST_USER2,
false,
),
);
}
/**
* Test mount points used at mount time, making sure
* the configuration is prepared properly.
*
* @dataProvider mountDataProvider
* @param bool $isPersonal true for personal mount point, false for system mount point
* @param string $mountType mount type
* @param string $applicable target user/group or "all"
* @param string $testUser user for which to retrieve the mount points
* @param bool $expectVisible whether to expect the mount point to be visible for $testUser
*/
public function testMount($isPersonal, $mountType, $applicable, $testUser, $expectVisible) {
$mountConfig = array(
'host' => 'someost',
'user' => 'someuser',
'password' => 'somepassword',
'root' => 'someroot'
);
// add mount point as "test" user
$this->assertTrue(
OC_Mount_Config::addMountPoint(
'/ext',
'\OC\Files\Storage\SMB',
$mountConfig,
$mountType,
$applicable,
$isPersonal
)
);
// check mount points in the perspective of user $testUser
\OC_User::setUserId($testUser);
$mountPoints = OC_Mount_Config::getAbsoluteMountPoints($testUser);
if ($expectVisible) {
$this->assertEquals(1, count($mountPoints));
$this->assertTrue(isset($mountPoints['/' . self::TEST_USER1 . '/files/ext']));
$this->assertEquals('\OC\Files\Storage\SMB', $mountPoints['/' . self::TEST_USER1 . '/files/ext']['class']);
$this->assertEquals($mountConfig, $mountPoints['/' . self::TEST_USER1 . '/files/ext']['options']);
}
else {
$this->assertEquals(0, count($mountPoints));
}
}
}

View File

@@ -36,7 +36,10 @@ if(!isset($linkedItem['uid_owner']) || !isset($linkedItem['file_source'])) {
exit;
}
$userId = $linkedItem['uid_owner'];
$rootLinkItem = OCP\Share::resolveReShare($linkedItem);
$userId = $rootLinkItem['uid_owner'];
OCP\JSON::checkUserExists($rootLinkItem['uid_owner']);
\OC_Util::setupFS($userId);
\OC\Files\Filesystem::initMountPoints($userId);
$view = new \OC\Files\View('/' . $userId . '/files');
@@ -86,4 +89,4 @@ try{
} catch (\Exception $e) {
\OC_Response::setStatus(500);
\OC_Log::write('core', $e->getmessage(), \OC_Log::DEBUG);
}
}

View File

@@ -44,6 +44,7 @@ if (version_compare($installedVersion, '0.3', '<')) {
$shareType = OCP\Share::SHARE_TYPE_USER;
$shareWith = $row['uid_shared_with'];
}
OCP\JSON::checkUserExists($row['uid_owner']);
OC_User::setUserId($row['uid_owner']);
//we need to setup the filesystem for the user, otherwise OC_FileSystem::getRoot will fail and break
OC_Util::setupFS($row['uid_owner']);

View File

@@ -11,16 +11,13 @@
margin: 6px;
}
input[type="submit"]{
input[type='submit'] {
width: 45px;
height: 45px;
margin: 6px;
background-image: url('%webroot%/core/img/actions/confirm.svg');
background-repeat: no-repeat;
background-position: center;
}
#body-login input[type="submit"] {
#body-login input[type='submit'] {
position: absolute;
top: 0px;
}

View File

@@ -0,0 +1,49 @@
@media only screen and (max-width: 600px) {
/* make header scroll up for single shares, more view of content on small screens */
#header.share-file {
position: absolute !important;
}
/* hide size and date columns */
table th#headerSize,
table td.filesize,
table th#headerDate,
table td.date {
display: none;
}
/* restrict length of displayed filename to prevent overflow */
table td.filename .nametext {
max-width: 75% !important;
}
/* on mobile, show single shared image at full width without margin */
#imgframe {
width: 100%;
padding: 0;
margin-bottom: 35px;
}
/* some margin for the file type icon */
#imgframe .publicpreview {
margin-top: 32px;
}
/* always show actions on mobile */
#fileList a.action {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)" !important;
filter: alpha(opacity=20) !important;
opacity: .2 !important;
display: inline !important;
}
/* some padding for better clickability */
#fileList a.action img {
padding: 0 6px 0 12px;
}
/* hide text of the actions on mobile */
#fileList a.action span {
display: none;
}
}

View File

@@ -1,9 +1,9 @@
body {
background:#ddd;
height: auto;
}
#header {
background: #1d2d44 url('%webroot%/core/img/noise.png') repeat;
background-color: #1d2d44;
height:32px;
left:0;
line-height:32px;
@@ -14,47 +14,27 @@ body {
padding:7px;
}
#details {
color:#fff;
float: left;
}
#public_upload,
#download {
font-weight:700;
margin: 0 0.4em 0 0;
padding: 0 5px;
height: 32px;
float: left;
}
.header-right #details {
margin-right: 28px;
}
.header-right {
padding: 0;
height: 32px;
}
#public_upload {
margin-left: 0.3em;
#details {
color:#fff;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
filter: alpha(opacity=50);
opacity: .5;
padding-right: 5px;
}
#public_upload img,
#download img {
padding-left:.1em;
padding-right:.3em;
vertical-align:text-bottom;
#controls {
left: 0;
}
#preview {
background:#eee;
border-bottom:1px solid #f8f8f8;
min-height:30em;
text-align:center;
margin:45px auto;
background: #fff;
text-align: center;
margin: 45px auto 0;
}
#noPreview {
@@ -62,11 +42,15 @@ body {
padding-top:5em;
}
footer {
margin-top: 45px;
}
p.info {
color:#777;
text-align:center;
width:22em;
margin:2em auto;
color: #777;
text-align: center;
margin: 0 auto;
padding: 20px 0;
}
p.info a {
@@ -87,9 +71,13 @@ p.info a {
max-width:100%;
}
thead{
background-color: white;
padding-left:0 !important; /* fixes multiselect bar offset on shared page */
/* some margin for the file type icon */
#imgframe .publicpreview {
margin-top: 10%;
}
thead {
padding-left: 0 !important; /* fixes multiselect bar offset on shared page */
}
#data-upload-form {
@@ -103,41 +91,37 @@ thead{
margin: 0;
}
#file_upload_start {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
filter: alpha(opacity=0);
opacity: 0;
z-index: 20;
position: absolute !important;
top: 0;
left: 0;
width: 100% !important;
}
#publicUploadButtonMock {
position:relative;
display:block;
width:100%;
height:32px;
cursor:pointer;
z-index:10;
background-image:url('%webroot%/core/img/actions/upload.svg');
background-repeat:no-repeat;
background-position:7px 8px;
}
#publicUploadButtonMock span {
margin: 0 5px 0 28px;
color: #555;
}
.directDownload,
.directLink {
margin-bottom: 20px;
}
.directLink label {
font-weight: normal;
}
.directLink input {
margin-left: 10px;
width: 300px;
}
/* keep long file names in one line to not overflow download button on mobile */
.directDownload #download {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 90%;
display: inline-block;
margin-left: auto;
margin-right: auto;
}
.directDownload .button img {
vertical-align: text-bottom;
}
.directLink label {
font-weight: normal;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
filter: alpha(opacity=50);
opacity: .5;
}
.directLink input {
margin-left: 5px;
width: 300px;
max-width: 90%;
}
.public_actions {
padding: 4px;
}

View File

@@ -9,39 +9,34 @@ function fileDownloadPath(dir, file) {
$(document).ready(function() {
$('#data-upload-form').tipsy({gravity:'ne', fade:true});
if (typeof FileActions !== 'undefined') {
var mimetype = $('#mimetype').val();
// Show file preview if previewer is available, images are already handled by the template
if (mimetype.substr(0, mimetype.indexOf('/')) != 'image' && $('.publicpreview').length === 0) {
// Trigger default action if not download TODO
var action = FileActions.getDefault(mimetype, 'file', OC.PERMISSION_READ);
if (typeof action === 'undefined') {
$('#noPreview').show();
if (mimetype != 'httpd/unix-directory') {
// NOTE: Remove when a better file previewer solution exists
$('#content').remove();
$('table').remove();
}
} else {
if (typeof action !== 'undefined') {
action($('#filename').val());
}
}
FileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function(filename) {
var tr = $('tr').filterAttr('data-file', filename);
var tr = FileList.findFileEl(filename);
if (tr.length > 0) {
window.location = $(tr).find('a.name').attr('href');
}
});
FileActions.register('file', 'Download', OC.PERMISSION_READ, '', function(filename) {
var tr = $('tr').filterAttr('data-file', filename);
FileActions.register('file', 'Download', OC.PERMISSION_READ, function() {
return OC.imagePath('core', 'actions/download');
}, function(filename) {
var tr = FileList.findFileEl(filename);
if (tr.length > 0) {
window.location = $(tr).find('a.name').attr('href');
}
});
FileActions.register('dir', 'Download', OC.PERMISSION_READ, '', function(filename) {
var tr = $('tr').filterAttr('data-file', filename);
FileActions.register('dir', 'Download', OC.PERMISSION_READ, function() {
return OC.imagePath('core', 'actions/download');
}, function(filename) {
var tr = FileList.findFileEl(filename);
if (tr.length > 0) {
window.location = $(tr).find('a.name').attr('href')+'&download';
}
@@ -58,15 +53,9 @@ $(document).ready(function() {
};
});
// Add Uploadprogress Wrapper to controls bar
$('#controls').append($('#additional_controls div#uploadprogresswrapper'));
// Cancel upload trigger
$('#cancel_upload_button').click(function() {
OC.Upload.cancelUploads();
procesSelection();
$(document).on('click', '#directLink', function() {
$(this).focus();
$(this).select();
});
$('#directLink').focus();
});

View File

@@ -22,7 +22,7 @@ $(document).ready(function() {
} else {
var item = $('#dir').val() + '/' + filename;
}
var tr = $('tr').filterAttr('data-file', filename);
var tr = FileList.findFileEl(filename);
if ($(tr).data('type') == 'dir') {
var itemType = 'folder';
} else {

View File

@@ -1,8 +0,0 @@
<?php
$TRANSLATIONS = array(
"Password" => "Пароль",
"Download" => "Загрузка",
"Upload" => "Загрузка",
"Cancel upload" => "Отмена загрузки"
);
$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);";

View File

@@ -68,7 +68,7 @@ class Api {
public static function getShare($params) {
$s = self::getShareFromId($params['id']);
$params['itemSource'] = $s['item_source'];
$params['itemSource'] = $s['file_source'];
$params['itemType'] = $s['item_type'];
$params['specificShare'] = true;
@@ -98,8 +98,14 @@ class Api {
break;
}
}
} else {
$path = $params['path'];
foreach ($shares as $key => $share) {
$shares[$key]['path'] = $path;
}
}
// include also reshares in the lists. This means that the result
// will contain every user with access to the file.
if (isset($params['reshares']) && $params['reshares'] === true) {
@@ -107,8 +113,10 @@ class Api {
}
if ($receivedFrom) {
$shares['received_from'] = $receivedFrom['uid_owner'];
$shares['received_from_displayname'] = \OCP\User::getDisplayName($receivedFrom['uid_owner']);
foreach ($shares as $key => $share) {
$shares[$key]['received_from'] = $receivedFrom['uid_owner'];
$shares[$key]['received_from_displayname'] = \OCP\User::getDisplayName($receivedFrom['uid_owner']);
}
}
} else {
$shares = null;
@@ -162,7 +170,7 @@ class Api {
$view = new \OC\Files\View('/'.\OCP\User::getUser().'/files');
if(!$view->is_dir($path)) {
return new \OC_OCS_Result(null, 404, "not a directory");
return new \OC_OCS_Result(null, 400, "not a directory");
}
$content = $view->getDirectoryContent($path);
@@ -172,14 +180,16 @@ class Api {
// workaround because folders are named 'dir' in this context
$itemType = $file['type'] === 'file' ? 'file' : 'folder';
$share = \OCP\Share::getItemShared($itemType, $file['fileid']);
$receivedFrom = \OCP\Share::getItemSharedWithBySource($itemType, $file['fileid']);
if ($receivedFrom) {
$share['received_from'] = $receivedFrom['uid_owner'];
$share['received_from_displayname'] = \OCP\User::getDisplayName($receivedFrom['uid_owner']);
}
if ($share) {
$share['filename'] = $file['name'];
$result[] = $share;
if($share) {
$receivedFrom = \OCP\Share::getItemSharedWithBySource($itemType, $file['fileid']);
reset($share);
$key = key($share);
$share[$key]['path'] = self::correctPath($share[$key]['path'], $path);
if ($receivedFrom) {
$share[$key]['received_from'] = $receivedFrom['uid_owner'];
$share[$key]['received_from_displayname'] = \OCP\User::getDisplayName($receivedFrom['uid_owner']);
}
$result = array_merge($result, $share);
}
}
@@ -220,10 +230,8 @@ class Api {
$shareWith = isset($_POST['password']) ? $_POST['password'] : null;
//check public link share
$publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
$encryptionEnabled = \OC_App::isEnabled('files_encryption');
if(isset($_POST['publicUpload']) &&
($encryptionEnabled || $publicUploadEnabled !== 'yes')) {
return new \OC_OCS_Result(null, 404, "public upload disabled by the administrator");
if(isset($_POST['publicUpload']) && $publicUploadEnabled !== 'yes') {
return new \OC_OCS_Result(null, 403, "public upload disabled by the administrator");
}
$publicUpload = isset($_POST['publicUpload']) ? $_POST['publicUpload'] : 'false';
// read, create, update (7) if public upload is enabled or
@@ -231,7 +239,7 @@ class Api {
$permissions = $publicUpload === 'true' ? 7 : 1;
break;
default:
return new \OC_OCS_Result(null, 404, "unknown share type");
return new \OC_OCS_Result(null, 400, "unknown share type");
}
try {
@@ -243,7 +251,7 @@ class Api {
$permissions
);
} catch (\Exception $e) {
return new \OC_OCS_Result(null, 404, $e->getMessage());
return new \OC_OCS_Result(null, 403, $e->getMessage());
}
if ($token) {
@@ -284,9 +292,8 @@ class Api {
public static function updateShare($params) {
$share = self::getShareFromId($params['id']);
$itemSource = isset($share['item_source']) ? $share['item_source'] : null;
if($itemSource === null) {
if(!isset($share['file_source'])) {
return new \OC_OCS_Result(null, 404, "wrong share Id, share doesn't exist.");
}
@@ -321,11 +328,8 @@ class Api {
$permissions = isset($params['_put']['permissions']) ? (int)$params['_put']['permissions'] : null;
$publicUploadStatus = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
$encryptionEnabled = \OC_App::isEnabled('files_encryption');
$publicUploadEnabled = false;
if(!$encryptionEnabled && $publicUploadStatus === 'yes') {
$publicUploadEnabled = true;
}
$publicUploadEnabled = ($publicUploadStatus === 'yes') ? true : false;
// only change permissions for public shares if public upload is enabled
// and we want to set permissions to 1 (read only) or 7 (allow upload)
@@ -363,9 +367,8 @@ class Api {
private static function updatePublicUpload($share, $params) {
$publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
$encryptionEnabled = \OC_App::isEnabled('files_encryption');
if($encryptionEnabled || $publicUploadEnabled !== 'yes') {
return new \OC_OCS_Result(null, 404, "public upload disabled by the administrator");
if($publicUploadEnabled !== 'yes') {
return new \OC_OCS_Result(null, 403, "public upload disabled by the administrator");
}
if ($share['item_type'] !== 'folder' ||
@@ -438,10 +441,10 @@ class Api {
public static function deleteShare($params) {
$share = self::getShareFromId($params['id']);
$itemSource = isset($share['item_source']) ? $share['item_source'] : null;
$fileSource = isset($share['file_source']) ? $share['file_source'] : null;
$itemType = isset($share['item_type']) ? $share['item_type'] : null;;
if($itemSource === null) {
if($fileSource === null) {
return new \OC_OCS_Result(null, 404, "wrong share ID, share doesn't exist.");
}
@@ -455,7 +458,7 @@ class Api {
try {
$return = \OCP\Share::unshare(
$itemType,
$itemSource,
$fileSource,
$shareType,
$shareWith);
} catch (\Exception $e) {
@@ -511,7 +514,7 @@ class Api {
* @return array with: item_source, share_type, share_with, item_type, permissions
*/
private static function getShareFromId($shareID) {
$sql = 'SELECT `item_source`, `share_type`, `share_with`, `item_type`, `permissions` FROM `*PREFIX*share` WHERE `id` = ?';
$sql = 'SELECT `file_source`, `item_source`, `share_type`, `share_with`, `item_type`, `permissions` FROM `*PREFIX*share` WHERE `id` = ?';
$args = array($shareID);
$query = \OCP\DB::prepare($sql);
$result = $query->execute($args);
@@ -528,4 +531,15 @@ class Api {
}
/**
* @brief make sure that the path has the correct root
*
* @param string $path path returned from the share API
* @param string $folder current root folder
* @return string the correct path
*/
protected static function correctPath($path, $folder) {
return \OC_Filesystem::normalizePath('/' . $folder . '/' . basename($path));
}
}

View File

@@ -20,6 +20,7 @@
*/
namespace OC\Files\Cache;
use OCP\Share_Backend_Collection;
/**
@@ -47,7 +48,7 @@ class Shared_Cache extends Cache {
\OC\Files\Filesystem::initMountPoints($source['fileOwner']);
$mount = \OC\Files\Filesystem::getMountByNumericId($source['storage']);
if (is_array($mount)) {
$fullPath = $mount[key($mount)]->getMountPoint().$source['path'];
$fullPath = $mount[key($mount)]->getMountPoint() . $source['path'];
list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($fullPath);
if ($storage) {
$this->files[$target] = $internalPath;
@@ -72,7 +73,7 @@ class Shared_Cache extends Cache {
/**
* get the stored metadata of a file or folder
*
* @param string/int $file
* @param string /int $file
* @return array
*/
public function get($file) {
@@ -92,12 +93,11 @@ class Shared_Cache extends Cache {
} else {
$query = \OC_DB::prepare(
'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`,'
.' `size`, `mtime`, `encrypted`'
.' FROM `*PREFIX*filecache` WHERE `fileid` = ?');
. ' `size`, `mtime`, `encrypted`, `unencrypted_size`'
. ' FROM `*PREFIX*filecache` WHERE `fileid` = ?');
$result = $query->execute(array($file));
$data = $result->fetchRow();
$data['fileid'] = (int)$data['fileid'];
$data['size'] = (int)$data['size'];
$data['mtime'] = (int)$data['mtime'];
$data['storage_mtime'] = (int)$data['storage_mtime'];
$data['encrypted'] = (bool)$data['encrypted'];
@@ -106,6 +106,12 @@ class Shared_Cache extends Cache {
if ($data['storage_mtime'] === 0) {
$data['storage_mtime'] = $data['mtime'];
}
if ($data['encrypted'] or ($data['unencrypted_size'] > 0 and $data['mimetype'] === 'httpd/unix-directory')) {
$data['encrypted_size'] = (int)$data['size'];
$data['size'] = (int)$data['unencrypted_size'];
} else {
$data['size'] = (int)$data['size'];
}
return $data;
}
return false;
@@ -123,11 +129,18 @@ class Shared_Cache extends Cache {
foreach ($files as &$file) {
$file['mimetype'] = $this->getMimetype($file['mimetype']);
$file['mimepart'] = $this->getMimetype($file['mimepart']);
$file['usersPath'] = 'files/Shared/' . ltrim($file['path'], '/');
}
return $files;
} else {
if ($cache = $this->getSourceCache($folder)) {
return $cache->getFolderContents($this->files[$folder]);
$cache = $this->getSourceCache($folder);
if ($cache) {
$sourceFolderContent = $cache->getFolderContents($this->files[$folder]);
foreach ($sourceFolderContent as $key => $c) {
$sourceFolderContent[$key]['usersPath'] = 'files/Shared/' . $folder . '/' . $c['name'];
}
return $sourceFolderContent;
}
}
return false;
@@ -248,19 +261,39 @@ class Shared_Cache extends Cache {
* @return array
*/
public function searchByMime($mimetype) {
if (strpos($mimetype, '/')) {
$where = '`mimetype` = ? AND ';
} else {
$where = '`mimepart` = ? AND ';
$mimepart = null;
if (strpos($mimetype, '/') === false) {
$mimepart = $mimetype;
$mimetype = null;
}
$value = $this->getMimetypeId($mimetype);
return $this->searchWithWhere($where, $value);
// note: searchWithWhere is currently broken as it doesn't
// recurse into subdirs nor returns the correct
// file paths, so using getFolderContents() for now
$result = array();
$exploreDirs = array('');
while (count($exploreDirs) > 0) {
$dir = array_pop($exploreDirs);
$files = $this->getFolderContents($dir);
// no results?
if (!$files) {
continue;
}
foreach ($files as $file) {
if ($file['mimetype'] === 'httpd/unix-directory') {
$exploreDirs[] = ltrim($dir . '/' . $file['name'], '/');
} else if (($mimepart && $file['mimepart'] === $mimepart) || ($mimetype && $file['mimetype'] === $mimetype)) {
// usersPath not reliable
//$file['path'] = $file['usersPath'];
$file['path'] = ltrim($dir . '/' . $file['name'], '/');
$result[] = $file;
}
}
}
return $result;
}
/**
* The maximum number of placeholders that can be used in an SQL query.
* Value MUST be <= 1000 for oracle:
@@ -268,7 +301,7 @@ class Shared_Cache extends Cache {
* FIXME we should get this from doctrine as other DBs allow a lot more placeholders
*/
const MAX_SQL_CHUNK_SIZE = 1000;
/**
* search for files with a custom where clause and value
* the $wherevalue will be array_merge()d with the file id chunks
@@ -282,16 +315,16 @@ class Shared_Cache extends Cache {
$ids = $this->getAll();
$files = array();
// divide into chunks
$chunks = array_chunk($ids, $chunksize);
foreach ($chunks as $chunk) {
$placeholders = join(',', array_fill(0, count($chunk), '?'));
$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
`encrypted`, `unencrypted_size`, `etag`
FROM `*PREFIX*filecache` WHERE ' . $sqlwhere . ' `fileid` IN (' . $placeholders . ')';
$stmt = \OC_DB::prepare($sql);
$result = $stmt->execute(array_merge(array($wherevalue), $chunk));
@@ -302,6 +335,10 @@ class Shared_Cache extends Cache {
}
$row['mimetype'] = $this->getMimetype($row['mimetype']);
$row['mimepart'] = $this->getMimetype($row['mimepart']);
if ($row['encrypted'] or ($row['unencrypted_size'] > 0 and $row['mimetype'] === 'httpd/unix-directory')) {
$row['encrypted_size'] = $row['size'];
$row['size'] = $row['unencrypted_size'];
}
$files[] = $row;
}
}
@@ -356,4 +393,48 @@ class Shared_Cache extends Cache {
return false;
}
/**
* get the path of a file on this storage by it's id
*
* @param int $id
* @param string $pathEnd (optional) used internally for recursive calls
* @return string | null
*/
public function getPathById($id, $pathEnd = '') {
// direct shares are easy
if ($path = $this->getShareById($id)) {
return $path . $pathEnd;
} else {
// if the item is a direct share we try and get the path of the parent and append the name of the item to it
list($parent, $name) = $this->getParentInfo($id);
if ($parent > 0) {
return $this->getPathById($parent, '/' . $name . $pathEnd);
} else {
return null;
}
}
}
private function getShareById($id) {
$item = \OCP\Share::getItemSharedWithBySource('file', $id);
if ($item) {
return trim($item['file_target'], '/');
}
$item = \OCP\Share::getItemSharedWithBySource('folder', $id);
if ($item) {
return trim($item['file_target'], '/');
}
return null;
}
private function getParentInfo($id) {
$sql = 'SELECT `parent`, `name` FROM `*PREFIX*filecache` WHERE `fileid` = ?';
$query = \OC_DB::prepare($sql);
$result = $query->execute(array($id));
if ($row = $result->fetchRow()) {
return array($row['parent'], $row['name']);
} else {
return array(-1, '');
}
}
}

View File

@@ -42,6 +42,19 @@ class Shared_Permissions extends Permissions {
}
}
private function getFile($fileId, $user) {
if ($fileId == -1) {
return \OCP\PERMISSION_READ;
}
$source = \OCP\Share::getItemSharedWithBySource('file', $fileId, \OC_Share_Backend_File::FORMAT_SHARED_STORAGE,
null, false);
if ($source) {
return $source['permissions'];
} else {
return -1;
}
}
/**
* set the permissions of a file
*
@@ -82,7 +95,7 @@ class Shared_Permissions extends Permissions {
if ($parentId === -1) {
return \OCP\Share::getItemsSharedWith('file', \OC_Share_Backend_File::FORMAT_PERMISSIONS);
}
$permissions = $this->get($parentId, $user);
$permissions = $this->getFile($parentId, $user);
$query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `parent` = ?');
$result = $query->execute(array($parentId));
$filePermissions = array();

View File

@@ -31,10 +31,12 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent {
private $path;
public function isValidSource($itemSource, $uidOwner) {
$query = \OC_DB::prepare('SELECT `name` FROM `*PREFIX*filecache` WHERE `fileid` = ?');
$result = $query->execute(array($itemSource));
if ($row = $result->fetchRow()) {
$this->path = $row['name'];
$path = \OC\Files\Filesystem::getPath($itemSource);
if ($path) {
// FIXME: attributes should not be set here,
// keeping this pattern for now to avoid unexpected
// regressions
$this->path = basename($path);
return true;
}
return false;
@@ -91,10 +93,17 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent {
$file['name'] = basename($item['file_target']);
$file['mimetype'] = $item['mimetype'];
$file['mimepart'] = $item['mimepart'];
$file['size'] = $item['size'];
$file['mtime'] = $item['mtime'];
$file['encrypted'] = $item['encrypted'];
$file['etag'] = $item['etag'];
$storage = \OC\Files\Filesystem::getStorage('/');
$cache = $storage->getCache();
if ($item['encrypted'] or ($item['unencrypted_size'] > 0 and $cache->getMimetype($item['mimetype']) === 'httpd/unix-directory')) {
$file['size'] = $item['unencrypted_size'];
$file['encrypted_size'] = $item['size'];
} else {
$file['size'] = $item['size'];
}
$files[] = $file;
}
return $files;
@@ -172,7 +181,7 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent {
$source['fileOwner'] = $fileOwner;
return $source;
}
\OCP\Util::writeLog('files_sharing', 'File source not found for: '.$target, \OCP\Util::ERROR);
\OCP\Util::writeLog('files_sharing', 'File source not found for: '.$target, \OCP\Util::DEBUG);
return false;
}

View File

@@ -279,43 +279,26 @@ class Shared extends \OC\Files\Storage\Common {
if ($this->isDeletable($path)) {
list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
return $storage->unlink($internalPath);
} else if (dirname($path) == '/' || dirname($path) == '.') {
// Unshare the file from the user if in the root of the Shared folder
if ($this->is_dir($path)) {
$itemType = 'folder';
} else {
$itemType = 'file';
}
return \OCP\Share::unshareFromSelf($itemType, $path);
}
}
return false;
}
public function rename($path1, $path2) {
// Check for partial files
if (pathinfo($path1, PATHINFO_EXTENSION) === 'part') {
if ($oldSource = $this->getSourcePath($path1)) {
// Renaming/moving is only allowed within shared folders
$pos1 = strpos($path1, '/', 1);
$pos2 = strpos($path2, '/', 1);
if ($pos1 !== false && $pos2 !== false && ($oldSource = $this->getSourcePath($path1))) {
$newSource = $this->getSourcePath(dirname($path2)) . '/' . basename($path2);
// Within the same folder, we only need UPDATE permissions
if (dirname($path1) == dirname($path2) and $this->isUpdatable($path1)) {
list($storage, $oldInternalPath) = \OC\Files\Filesystem::resolvePath($oldSource);
$newInternalPath = substr($oldInternalPath, 0, -5);
list(, $newInternalPath) = \OC\Files\Filesystem::resolvePath($newSource);
return $storage->rename($oldInternalPath, $newInternalPath);
}
} else {
// Renaming/moving is only allowed within shared folders
$pos1 = strpos($path1, '/', 1);
$pos2 = strpos($path2, '/', 1);
if ($pos1 !== false && $pos2 !== false && ($oldSource = $this->getSourcePath($path1))) {
$newSource = $this->getSourcePath(dirname($path2)) . '/' . basename($path2);
// Within the same folder, we only need UPDATE permissions
if (dirname($path1) == dirname($path2) and $this->isUpdatable($path1)) {
list($storage, $oldInternalPath) = \OC\Files\Filesystem::resolvePath($oldSource);
list(, $newInternalPath) = \OC\Files\Filesystem::resolvePath($newSource);
return $storage->rename($oldInternalPath, $newInternalPath);
// otherwise DELETE and CREATE permissions required
} elseif ($this->isDeletable($path1) && $this->isCreatable(dirname($path2))) {
$rootView = new \OC\Files\View('');
return $rootView->rename($oldSource, $newSource);
}
// otherwise DELETE and CREATE permissions required
} elseif ($this->isDeletable($path1) && $this->isCreatable(dirname($path2))) {
$rootView = new \OC\Files\View('');
return $rootView->rename($oldSource, $newSource);
}
}
return false;

View File

@@ -112,8 +112,12 @@ class Shared_Updater {
*/
static public function shareHook($params) {
if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
$uidOwner = \OCP\User::getUser();
$users = \OCP\Share::getUsersItemShared($params['itemType'], $params['fileSource'], $uidOwner, true);
if (isset($params['uidOwner'])) {
$uidOwner = $params['uidOwner'];
} else {
$uidOwner = \OCP\User::getUser();
}
$users = \OCP\Share::getUsersItemShared($params['itemType'], $params['fileSource'], $uidOwner, true, false);
if (!empty($users)) {
while (!empty($users)) {
$reshareUsers = array();

View File

@@ -35,7 +35,7 @@ function determineIcon($file, $sharingRoot, $sharingToken) {
if (isset($_GET['t'])) {
$token = $_GET['t'];
$linkItem = OCP\Share::getShareByToken($token);
$linkItem = OCP\Share::getShareByToken($token, false);
if (is_array($linkItem) && isset($linkItem['uid_owner'])) {
// seems to be a valid share
$type = $linkItem['item_type'];
@@ -43,10 +43,10 @@ if (isset($_GET['t'])) {
$shareOwner = $linkItem['uid_owner'];
$path = null;
$rootLinkItem = OCP\Share::resolveReShare($linkItem);
$fileOwner = $rootLinkItem['uid_owner'];
if (isset($fileOwner)) {
if (isset($rootLinkItem['uid_owner'])) {
OCP\JSON::checkUserExists($rootLinkItem['uid_owner']);
OC_Util::tearDownFS();
OC_Util::setupFS($fileOwner);
OC_Util::setupFS($rootLinkItem['uid_owner']);
$path = \OC\Files\Filesystem::getPath($linkItem['file_source']);
}
}
@@ -136,6 +136,7 @@ if (isset($path)) {
} else {
OCP\Util::addScript('files', 'file-upload');
OCP\Util::addStyle('files_sharing', 'public');
OCP\Util::addStyle('files_sharing', 'mobile');
OCP\Util::addScript('files_sharing', 'public');
OCP\Util::addScript('files', 'fileactions');
OCP\Util::addScript('files', 'jquery.iframe-transport');
@@ -158,7 +159,6 @@ if (isset($path)) {
if ($linkItem['item_type'] !== 'folder') {
$allowPublicUploadEnabled = false;
}
$tmpl->assign('allowPublicUploadEnabled', $allowPublicUploadEnabled);
$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize);
$tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize));
@@ -188,8 +188,8 @@ if (isset($path)) {
} else {
$i['extension'] = '';
}
$i['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($i['mimetype']);
}
$i['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($i['mimetype']);
$i['directory'] = $getPath;
$i['permissions'] = OCP\PERMISSION_READ;
$i['icon'] = determineIcon($i, $basePath, $token);
@@ -224,7 +224,8 @@ if (isset($path)) {
$folder->assign('fileList', $list->fetchPage());
$folder->assign('breadcrumb', $breadcrumbNav->fetchPage());
$folder->assign('dir', $getPath);
$folder->assign('isCreatable', false);
$folder->assign('isCreatable', $allowPublicUploadEnabled);
$folder->assign('dirToken', $linkItem['token']);
$folder->assign('permissions', OCP\PERMISSION_READ);
$folder->assign('isPublic',true);
$folder->assign('publicUploadEnabled', 'no');

View File

@@ -8,8 +8,11 @@
<?php endif; ?>
<p class="infield">
<label for="password" class="infield"><?php p($l->t('Password')); ?></label>
<input type="password" name="password" id="password" placeholder="" value="" autofocus />
<input type="submit" value="" class="svg" />
<input type="password" name="password" id="password"
placeholder="" value=""
autocomplete="off" autocapitalize="off" autocorrect="off"
autofocus />
<input type="submit" value="" class="svg icon icon-confirm" />
</p>
</fieldset>
</form>

View File

@@ -9,64 +9,14 @@
<input type="hidden" name="sharingToken" value="<?php p($_['sharingToken']) ?>" id="sharingToken">
<input type="hidden" name="filename" value="<?php p($_['filename']) ?>" id="filename">
<input type="hidden" name="mimetype" value="<?php p($_['mimetype']) ?>" id="mimetype">
<header><div id="header">
<header><div id="header" class="icon icon-noise <?php p((isset($_['folder']) ? 'share-folder' : 'share-file')) ?>">
<a href="<?php print_unescaped(link_to('', 'index.php')); ?>" title="" id="owncloud"><img class="svg"
src="<?php print_unescaped(image_path('', 'logo-wide.svg')); ?>" alt="<?php p($theme->getName()); ?>" /></a>
<div id="logo-claim" style="display:none;"><?php p($theme->getLogoClaim()); ?></div>
<div class="header-right">
<?php if (isset($_['folder'])): ?>
<span id="details"><?php p($l->t('%s shared the folder %s with you',
array($_['displayName'], $_['filename']))) ?></span>
<?php else: ?>
<span id="details"><?php p($l->t('%s shared the file %s with you',
array($_['displayName'], $_['filename']))) ?></span>
<?php endif; ?>
<?php if (!isset($_['folder']) || $_['allowZipDownload']): ?>
<a href="<?php p($_['downloadURL']); ?>" class="button" id="download"><img
class="svg" alt="Download" src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>"
/><span><?php p($l->t('Download'))?></span></a>
<?php endif; ?>
<?php if ($_['allowPublicUploadEnabled']):?>
<input type="hidden" id="publicUploadRequestToken" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
<input type="hidden" id="dirToken" name="dirToken" value="<?php p($_['dirToken']) ?>" />
<input type="hidden" id="uploadMaxFilesize" name="uploadMaxFilesize" value="<?php p($_['uploadMaxFilesize']) ?>" />
<input type="hidden" id="uploadMaxHumanFilesize" name="uploadMaxHumanFilesize" value="<?php p($_['uploadMaxHumanFilesize']) ?>" />
<input type="hidden" id="directory_path" name="directory_path" value="<?php p($_['directory_path']) ?>" />
<?php if($_['uploadMaxFilesize'] >= 0):?>
<input type="hidden" name="MAX_FILE_SIZE" id="max_upload"
value="<?php p($_['uploadMaxFilesize']) ?>">
<?php endif;?>
<div id="data-upload-form" class="button" title="<?php p($l->t('Upload') . ' max. '.$_['uploadMaxHumanFilesize']) ?>">
<input id="file_upload_start" type="file" name="files[]" data-url="<?php print_unescaped(OCP\Util::linkTo('files', 'ajax/upload.php')); ?>" multiple>
<a href="#" id="publicUploadButtonMock" class="svg">
<span><?php p($l->t('Upload'))?></span>
</a>
</div>
<span id="details"><?php p($l->t('shared by %s', array($_['displayName']))) ?></span>
</div>
<div id="additional_controls" style="display:none">
<div id="uploadprogresswrapper">
<div id="uploadprogressbar"></div>
<input id="cancel_upload_button" type="button" class="stop" style="display:none"
value="<?php p($l->t('Cancel upload'));?>"
/>
</div>
<?php endif; ?>
</div>
</div></header>
</div></header>
<div id="content">
<div id="preview">
<?php if (isset($_['folder'])): ?>
@@ -82,25 +32,28 @@
<source src="<?php p($_['downloadURL']); ?>" type="<?php p($_['mimetype']); ?>" />
</video>
</div>
<?php elseif (\OC\Preview::isMimeSupported($_['mimetype'])): ?>
<div id="imgframe">
<img src="<?php p(OCP\Util::linkToRoute( 'core_ajax_public_preview', array('x' => 500, 'y' => 500, 'file' => urlencode($_['directory_path']), 't' => $_['dirToken']))); ?>" class="publicpreview"/>
</div>
<?php else: ?>
<ul id="noPreview">
<li class="error">
<?php p($l->t('No preview available for').' '.$_['filename']); ?><br />
<a href="<?php p($_['downloadURL']); ?>" id="download"><img class="svg" alt="Download"
src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>"
/><?php p($l->t('Download'))?></a>
</li>
</ul>
<div id="imgframe">
<?php $size = \OC\Preview::isMimeSupported($_['mimetype']) ? 500 : 128 ?>
<img src="<?php p(OCP\Util::linkToRoute( 'core_ajax_public_preview', array('x' => $size, 'y' => $size, 'file' => urlencode($_['directory_path']), 't' => $_['dirToken']))); ?>" class="publicpreview"/>
</div>
<?php endif; ?>
<div class="directLink"><label for="directLink"><?php p($l->t('Direct link')) ?></label><input id="directLink" type="text" readonly value="<?php p($_['downloadURL']); ?>"></input></div>
<div class="directDownload">
<a href="<?php p($_['downloadURL']); ?>" id="download" 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'])))?>
</a>
</div>
<div class="directLink">
<label for="directLink"><?php p($l->t('Direct link')) ?></label>
<input id="directLink" type="text" readonly value="<?php p($_['downloadURL']); ?>">
</div>
<?php endif; ?>
</div>
<footer>
<p class="info">
<?php print_unescaped($theme->getLongFooter()); ?>
</p>
</footer>
</div>
<footer>
<p class="info">
<?php print_unescaped($theme->getLongFooter()); ?>
</p>
</footer>

View File

@@ -29,23 +29,34 @@ use OCA\Files\Share;
*/
class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
const TEST_FOLDER_NAME = '/folder_share_api_test';
private static $tempStorage;
function setUp() {
parent::setUp();
$this->folder = '/folder_share_api_test';
$this->folder = self::TEST_FOLDER_NAME;
$this->subfolder = '/subfolder_share_api_test';
$this->subsubfolder = '/subsubfolder_share_api_test';
$this->filename = 'share-api-test.txt';
$this->filename = '/share-api-test.txt';
// save file with content
$this->view->file_put_contents($this->filename, $this->data);
$this->view->mkdir($this->folder);
$this->view->file_put_contents($this->folder.'/'.$this->filename, $this->data);
$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->subfolder . $this->filename, $this->data);
}
function tearDown() {
$this->view->unlink($this->filename);
$this->view->deleteAll($this->folder);
self::$tempStorage = null;
parent::tearDown();
}
@@ -286,6 +297,343 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
}
/**
* @brief share a folder, than reshare a file within the shared folder and check if we construct the correct path
* @medium
*/
function testGetShareFromFolderReshares() {
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$fileInfo1 = $this->view->getFileInfo($this->folder);
$fileInfo2 = $this->view->getFileInfo($this->folder.'/'.$this->filename);
$fileInfo3 = $this->view->getFileInfo($this->folder.'/' . $this->subfolder . '/' .$this->filename);
// share root folder to user2
$result = \OCP\Share::shareItem('folder', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31);
// share was successful?
$this->assertTrue($result);
// login as user2
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
// share file in root folder
$result = \OCP\Share::shareItem('file', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null, 1);
// share was successful?
$this->assertTrue(is_string($result));
// share file in subfolder
$result = \OCP\Share::shareItem('file', $fileInfo3['fileid'], \OCP\Share::SHARE_TYPE_LINK, null, 1);
// share was successful?
$this->assertTrue(is_string($result));
$testValues=array(
array('query' => 'Shared/' . $this->folder,
'expectedResult' => '/Shared' . $this->folder . $this->filename),
array('query' => 'Shared/' . $this->folder . $this->subfolder,
'expectedResult' => '/Shared' . $this->folder . $this->subfolder . $this->filename),
);
foreach ($testValues as $value) {
$_GET['path'] = $value['query'];
$_GET['subfiles'] = 'true';
$result = Share\Api::getAllShares(array());
$this->assertTrue($result->succeeded());
// test should return one share within $this->folder
$data = $result->getData();
$this->assertEquals($value['expectedResult'], $data[0]['path']);
}
// cleanup
\OCP\Share::unshare('file', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
\OCP\Share::unshare('file', $fileInfo3['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
\OCP\Share::unshare('folder', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2);
}
/**
* @brief reshare a sub folder and check if we get the correct path
* @medium
*/
function testGetShareFromSubFolderReShares() {
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$fileInfo = $this->view->getFileInfo($this->folder . $this->subfolder);
// share sub-folder to user2
$result = \OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31);
// share was successful?
$this->assertTrue($result);
// login as user2
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
// reshare subfolder
$result = \OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null, 1);
// share was successful?
$this->assertTrue(is_string($result));
$_GET['path'] = '/Shared';
$_GET['subfiles'] = 'true';
$result = Share\Api::getAllShares(array());
$this->assertTrue($result->succeeded());
// test should return one share within $this->folder
$data = $result->getData();
// we should get exactly one result
$this->assertEquals(1, count($data));
$expectedPath = '/Shared' . $this->subfolder;
$this->assertEquals($expectedPath, $data[0]['path']);
// cleanup
$result = \OCP\Share::unshare('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
$this->assertTrue($result);
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$result = \OCP\Share::unshare('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2);
$this->assertTrue($result);
}
/**
* @brief test re-re-share of folder if the path gets constructed correctly
* @medium
*/
function testGetShareFromFolderReReShares() {
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$fileInfo1 = $this->view->getFileInfo($this->folder . $this->subfolder);
$fileInfo2 = $this->view->getFileInfo($this->folder . $this->subfolder . $this->subsubfolder);
// share sub-folder to user2
$result = \OCP\Share::shareItem('folder', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31);
// share was successful?
$this->assertTrue($result);
// login as user2
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
// reshare subsubfolder
$result = \OCP\Share::shareItem('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER3, 31);
// share was successful?
$this->assertTrue($result);
// login as user3
self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
$result = \OCP\Share::shareItem('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null, 1);
// share was successful?
$this->assertTrue(is_string($result));
$_GET['path'] = '/Shared';
$_GET['subfiles'] = 'true';
$result = Share\Api::getAllShares(array());
$this->assertTrue($result->succeeded());
// test should return one share within $this->folder
$data = $result->getData();
// we should get exactly one result
$this->assertEquals(1, count($data));
$expectedPath = '/Shared' . $this->subsubfolder;
$this->assertEquals($expectedPath, $data[0]['path']);
// cleanup
$result = \OCP\Share::unshare('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
$this->assertTrue($result);
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$result = \OCP\Share::unshare('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER3);
$this->assertTrue($result);
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$result = \OCP\Share::unshare('folder', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2);
$this->assertTrue($result);
}
/**
* @brief test multiple shared folder if the path gets constructed correctly
* @medium
*/
function testGetShareMultipleSharedFolder() {
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$fileInfo1 = $this->view->getFileInfo($this->folder);
$fileInfo2 = $this->view->getFileInfo($this->folder . $this->subfolder);
// share sub-folder to user2
$result = \OCP\Share::shareItem('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31);
// share was successful?
$this->assertTrue($result);
// share folder to user2
$result = \OCP\Share::shareItem('folder', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31);
// share was successful?
$this->assertTrue($result);
// login as user2
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$result = \OCP\Share::shareItem('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null, 1);
// share was successful?
$this->assertTrue(is_string($result));
// ask for shared/subfolder
$expectedPath1 = '/Shared' . $this->subfolder;
$_GET['path'] = $expectedPath1;
$result1 = Share\Api::getAllShares(array());
$this->assertTrue($result1->succeeded());
// test should return one share within $this->folder
$data1 = $result1->getData();
$share1 = reset($data1);
// ask for shared/folder/subfolder
$expectedPath2 = '/Shared' . $this->folder . $this->subfolder;
$_GET['path'] = $expectedPath2;
$result2 = Share\Api::getAllShares(array());
$this->assertTrue($result2->succeeded());
// test should return one share within $this->folder
$data2 = $result2->getData();
$share2 = reset($data2);
// validate results
// we should get exactly one result each time
$this->assertEquals(1, count($data1));
$this->assertEquals(1, count($data2));
$this->assertEquals($expectedPath1, $share1['path']);
$this->assertEquals($expectedPath2, $share2['path']);
// cleanup
$result = \OCP\Share::unshare('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
$this->assertTrue($result);
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$result = \OCP\Share::unshare('folder', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2);
$this->assertTrue($result);
$result = \OCP\Share::unshare('folder', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2);
$this->assertTrue($result);
}
/**
* @brief test re-re-share of folder if the path gets constructed correctly
* @medium
*/
function testGetShareFromFileReReShares() {
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$fileInfo1 = $this->view->getFileInfo($this->folder . $this->subfolder);
$fileInfo2 = $this->view->getFileInfo($this->folder. $this->subfolder . $this->filename);
// share sub-folder to user2
$result = \OCP\Share::shareItem('folder', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31);
// share was successful?
$this->assertTrue($result);
// login as user2
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
// reshare subsubfolder
$result = \OCP\Share::shareItem('file', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER3, 31);
// share was successful?
$this->assertTrue($result);
// login as user3
self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
$result = \OCP\Share::shareItem('file', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null, 1);
// share was successful?
$this->assertTrue(is_string($result));
$_GET['path'] = '/Shared';
$_GET['subfiles'] = 'true';
$result = Share\Api::getAllShares(array());
$this->assertTrue($result->succeeded());
// test should return one share within $this->folder
$data = $result->getData();
// we should get exactly one result
$this->assertEquals(1, count($data));
$expectedPath = '/Shared' . $this->filename;
$this->assertEquals($expectedPath, $data[0]['path']);
// cleanup
$result = \OCP\Share::unshare('file', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
$this->assertTrue($result);
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$result = \OCP\Share::unshare('file', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER3);
$this->assertTrue($result);
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$result = \OCP\Share::unshare('folder', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2);
$this->assertTrue($result);
}
/**
* @medium
*/
@@ -491,4 +839,107 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
$this->assertTrue(empty($itemsAfterDelete));
}
/**
* @brief test unshare of a reshared file
*/
function testDeleteReshare() {
// user 1 shares a folder with user2
\Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1);
$fileInfo1 = $this->view->getFileInfo($this->folder);
$fileInfo2 = $this->view->getFileInfo($this->folder.'/'.$this->filename);
$result1 = \OCP\Share::shareItem('folder', $fileInfo1['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31);
$this->assertTrue($result1);
// user2 shares a file from the folder as link
\Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2);
$result2 = \OCP\Share::shareItem('file', $fileInfo2['fileid'], \OCP\Share::SHARE_TYPE_LINK, null, 1);
$this->assertTrue(is_string($result2));
// test if we can unshare the link again
$items = \OCP\Share::getItemShared('file', null);
$this->assertEquals(1, count($items));
$item = reset($items);
$result3 = Share\Api::deleteShare(array('id' => $item['id']));
$this->assertTrue($result3->succeeded());
}
function testCorrectPath() {
$path = "/foo/bar/test.txt";
$folder = "/correct/path";
$expectedResult = "/correct/path/test.txt";
$shareApiDummy = new TestShareApi();
$this->assertSame($expectedResult, $shareApiDummy->correctPathTest($path, $folder));
}
/**
* Post init mount points hook for mounting simulated ext storage
*/
public static function initTestMountPointsHook($data) {
if ($data['user'] === \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1) {
\OC\Files\Filesystem::mount(self::$tempStorage, array(), '/' . \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1 . '/files' . self::TEST_FOLDER_NAME);
}
}
/**
* Tests mounting a folder that is an external storage mount point.
*/
public function testShareStorageMountPoint() {
self::$tempStorage = new \OC\Files\Storage\Temporary(array());
self::$tempStorage->file_put_contents('test.txt', 'abcdef');
self::$tempStorage->getScanner()->scan('');
// needed because the sharing code sometimes switches the user internally and mounts the user's
// storages. In our case the temp storage isn't mounted automatically, so doing it in the post hook
// (similar to how ext storage works)
OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\Test_Files_Sharing_Api', 'initTestMountPointsHook');
// logging in will auto-mount the temp storage for user1 as well
\Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1);
$fileInfo = $this->view->getFileInfo($this->folder);
// user 1 shares the mount point folder with user2
$result = \OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31);
$this->assertTrue($result);
// user2: check that mount point name appears correctly
\Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2);
$view = new \OC\Files\View('/' . \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2 . '/files/Shared');
$this->assertTrue($view->file_exists($this->folder));
$this->assertTrue($view->file_exists($this->folder . '/test.txt'));
\Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1);
\OCP\Share::unshare('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2);
\OC_Hook::clear('OC_Filesystem', 'post_initMountPoints', '\Test_Files_Sharing_Api', 'initTestMountPointsHook');
}
}
/**
* @brief dumnmy class to test protected methods
*/
class TestShareApi extends \OCA\Files\Share\Api {
public function correctPathTest($path, $folder) {
return self::correctPath($path, $folder);
}
}

View File

@@ -43,6 +43,7 @@ abstract class Test_Files_Sharing_Base extends \PHPUnit_Framework_TestCase {
*/
public $view;
public $folder;
public $subfolder;
public static function setUpBeforeClass() {
// reset backend
@@ -132,8 +133,8 @@ abstract class Test_Files_Sharing_Base extends \PHPUnit_Framework_TestCase {
$share = Null;
if ($result && $result->numRows() > 0) {
$share = $result->fetchRow();
if ($result) {
$share = $result->fetchRow();
}
return $share;

View File

@@ -0,0 +1,288 @@
<?php
/**
* ownCloud
*
* @author Vincent Petry, Bjoern Schiessle
* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
* 2014 Bjoern Schiessle <schiessle@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
require_once __DIR__ . '/base.php';
class Test_Files_Sharing_Cache extends Test_Files_Sharing_Base {
/**
* @var OC_FilesystemView
*/
public $user2View;
function setUp() {
parent::setUp();
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$this->user2View = new \OC\Files\View('/'. self::TEST_FILES_SHARING_API_USER2 . '/files');
// prepare user1's dir structure
$this->view->mkdir('container');
$this->view->mkdir('container/shareddir');
$this->view->mkdir('container/shareddir/subdir');
$this->view->mkdir('container/shareddir/emptydir');
$textData = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$this->view->file_put_contents('container/not shared.txt', $textData);
$this->view->file_put_contents('container/shared single file.txt', $textData);
$this->view->file_put_contents('container/shareddir/bar.txt', $textData);
$this->view->file_put_contents('container/shareddir/subdir/another.txt', $textData);
$this->view->file_put_contents('container/shareddir/subdir/another too.txt', $textData);
$this->view->file_put_contents('container/shareddir/subdir/not a text file.xml', '<xml></xml>');
list($this->ownerStorage, $internalPath) = $this->view->resolvePath('');
$this->ownerCache = $this->ownerStorage->getCache();
$this->ownerStorage->getScanner()->scan('');
// share "shareddir" with user2
$fileinfo = $this->view->getFileInfo('container/shareddir');
\OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
self::TEST_FILES_SHARING_API_USER2, 31);
$fileinfo = $this->view->getFileInfo('container/shared single file.txt');
\OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
self::TEST_FILES_SHARING_API_USER2, 31);
// login as user2
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
// retrieve the shared storage
$secondView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2);
list($this->sharedStorage, $internalPath) = $secondView->resolvePath('files/Shared/shareddir');
$this->sharedCache = $this->sharedStorage->getCache();
}
function tearDown() {
$this->sharedCache->clear();
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$fileinfo = $this->view->getFileInfo('container/shareddir');
\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
self::TEST_FILES_SHARING_API_USER2);
$fileinfo = $this->view->getFileInfo('container/shared single file.txt');
\OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
self::TEST_FILES_SHARING_API_USER2);
$this->view->deleteAll('container');
$this->ownerCache->clear();
parent::tearDown();
}
/**
* Test searching by mime type
*/
function testSearchByMime() {
$results = $this->sharedStorage->getCache()->searchByMime('text');
$check = array(
array(
'name' => 'shared single file.txt',
'path' => 'shared single file.txt'
),
array(
'name' => 'bar.txt',
'path' => 'shareddir/bar.txt'
),
array(
'name' => 'another too.txt',
'path' => 'shareddir/subdir/another too.txt'
),
array(
'name' => 'another.txt',
'path' => 'shareddir/subdir/another.txt'
),
);
$this->verifyFiles($check, $results);
$results2 = $this->sharedStorage->getCache()->searchByMime('text/plain');
$this->verifyFiles($check, $results);
}
function testGetFolderContentsInRoot() {
$results = $this->user2View->getDirectoryContent('/Shared/');
$this->verifyFiles(
array(
array(
'name' => 'shareddir',
'path' => '/shareddir',
'mimetype' => 'httpd/unix-directory',
'usersPath' => 'files/Shared/shareddir'
),
array(
'name' => 'shared single file.txt',
'path' => '/shared single file.txt',
'mimetype' => 'text/plain',
'usersPath' => 'files/Shared/shared single file.txt'
),
),
$results
);
}
function testGetFolderContentsInSubdir() {
$results = $this->user2View->getDirectoryContent('/Shared/shareddir');
$this->verifyFiles(
array(
array(
'name' => 'bar.txt',
'path' => 'files/container/shareddir/bar.txt',
'mimetype' => 'text/plain',
'usersPath' => 'files/Shared/shareddir/bar.txt'
),
array(
'name' => 'emptydir',
'path' => 'files/container/shareddir/emptydir',
'mimetype' => 'httpd/unix-directory',
'usersPath' => 'files/Shared/shareddir/emptydir'
),
array(
'name' => 'subdir',
'path' => 'files/container/shareddir/subdir',
'mimetype' => 'httpd/unix-directory',
'usersPath' => 'files/Shared/shareddir/subdir'
),
),
$results
);
}
function testGetFolderContentsWhenSubSubdirShared() {
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$fileinfo = $this->view->getFileInfo('container/shareddir/subdir');
\OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
self::TEST_FILES_SHARING_API_USER3, 31);
self::loginHelper(self::TEST_FILES_SHARING_API_USER3);
$thirdView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER3 . '/files');
$results = $thirdView->getDirectoryContent('/Shared/subdir');
$this->verifyFiles(
array(
array(
'name' => 'another too.txt',
'path' => 'files/container/shareddir/subdir/another too.txt',
'mimetype' => 'text/plain',
'usersPath' => 'files/Shared/subdir/another too.txt'
),
array(
'name' => 'another.txt',
'path' => 'files/container/shareddir/subdir/another.txt',
'mimetype' => 'text/plain',
'usersPath' => 'files/Shared/subdir/another.txt'
),
array(
'name' => 'not a text file.xml',
'path' => 'files/container/shareddir/subdir/not a text file.xml',
'mimetype' => 'application/xml',
'usersPath' => 'files/Shared/subdir/not a text file.xml'
),
),
$results
);
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
self::TEST_FILES_SHARING_API_USER3);
}
/**
* Check if 'results' contains the expected 'examples' only.
*
* @param array $examples array of example files
* @param array $results array of files
*/
private function verifyFiles($examples, $results) {
$this->assertEquals(count($examples), count($results));
foreach ($examples as $example) {
foreach ($results as $key => $result) {
if ($result['name'] === $example['name']) {
$this->verifyKeys($example, $result);
unset($results[$key]);
break;
}
}
}
$this->assertTrue(empty($results));
}
/**
* @brief verify if each value from the result matches the expected result
* @param array $example array with the expected results
* @param array $result array with the results
*/
private function verifyKeys($example, $result) {
foreach ($example as $key => $value) {
$this->assertEquals($value, $result[$key]);
}
}
public function testGetPathByIdDirectShare() {
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
\OC\Files\Filesystem::file_put_contents('test.txt', 'foo');
$info = \OC\Files\Filesystem::getFileInfo('test.txt');
\OCP\Share::shareItem('file', $info['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, \OCP\PERMISSION_ALL);
\OC_Util::tearDownFS();
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$this->assertTrue(\OC\Files\Filesystem::file_exists('/Shared/test.txt'));
list($sharedStorage) = \OC\Files\Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/Shared/test.txt');
/**
* @var \OC\Files\Storage\Shared $sharedStorage
*/
$sharedCache = $sharedStorage->getCache();
$this->assertEquals('test.txt', $sharedCache->getPathById($info['fileid']));
}
public function testGetPathByIdShareSubFolder() {
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
\OC\Files\Filesystem::mkdir('foo');
\OC\Files\Filesystem::mkdir('foo/bar');
\OC\Files\Filesystem::touch('foo/bar/test.txt', 'bar');
$folderInfo = \OC\Files\Filesystem::getFileInfo('foo');
$fileInfo = \OC\Files\Filesystem::getFileInfo('foo/bar/test.txt');
\OCP\Share::shareItem('folder', $folderInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, \OCP\PERMISSION_ALL);
\OC_Util::tearDownFS();
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$this->assertTrue(\OC\Files\Filesystem::file_exists('/Shared/foo'));
list($sharedStorage) = \OC\Files\Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/Shared/foo');
/**
* @var \OC\Files\Storage\Shared $sharedStorage
*/
$sharedCache = $sharedStorage->getCache();
$this->assertEquals('foo', $sharedCache->getPathById($folderInfo['fileid']));
$this->assertEquals('foo/bar/test.txt', $sharedCache->getPathById($fileInfo['fileid']));
}
}

View File

@@ -0,0 +1,110 @@
<?php
/**
* ownCloud
*
* @author Vincent Petry
* @copyright 2013 Vincent Petry <pvince81@owncloud.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
require_once __DIR__ . '/base.php';
class Test_Files_Sharing_Permissions extends Test_Files_Sharing_Base {
function setUp() {
parent::setUp();
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
// prepare user1's dir structure
$textData = "dummy file data\n";
$this->view->mkdir('container');
$this->view->mkdir('container/shareddir');
$this->view->mkdir('container/shareddir/subdir');
$this->view->mkdir('container/shareddirrestricted');
$this->view->mkdir('container/shareddirrestricted/subdir');
$this->view->file_put_contents('container/shareddir/textfile.txt', $textData);
$this->view->file_put_contents('container/shareddirrestricted/textfile1.txt', $textData);
list($this->ownerStorage, $internalPath) = $this->view->resolvePath('');
$this->ownerCache = $this->ownerStorage->getCache();
$this->ownerStorage->getScanner()->scan('');
// share "shareddir" with user2
$fileinfo = $this->view->getFileInfo('container/shareddir');
\OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
self::TEST_FILES_SHARING_API_USER2, 31);
$fileinfo2 = $this->view->getFileInfo('container/shareddirrestricted');
\OCP\Share::shareItem('folder', $fileinfo2['fileid'], \OCP\Share::SHARE_TYPE_USER,
self::TEST_FILES_SHARING_API_USER2, 7);
// login as user2
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
// retrieve the shared storage
$this->secondView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2);
list($this->sharedStorage, $internalPath) = $this->secondView->resolvePath('files/Shared/shareddir');
$this->sharedCache = $this->sharedStorage->getCache();
}
function tearDown() {
$this->sharedCache->clear();
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$fileinfo = $this->view->getFileInfo('container/shareddir');
\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
self::TEST_FILES_SHARING_API_USER2);
$fileinfo2 = $this->view->getFileInfo('container/shareddirrestricted');
\OCP\Share::unshare('folder', $fileinfo2['fileid'], \OCP\Share::SHARE_TYPE_USER,
self::TEST_FILES_SHARING_API_USER2);
$this->view->deleteAll('container');
$this->ownerCache->clear();
parent::tearDown();
}
/**
* Test that the permissions of shared directory are returned correctly
*/
function testGetPermissions() {
$sharedDirPerms = $this->sharedStorage->getPermissions('shareddir');
$this->assertEquals(31, $sharedDirPerms);
$sharedDirPerms = $this->sharedStorage->getPermissions('shareddir/textfile.txt');
$this->assertEquals(31, $sharedDirPerms);
$sharedDirRestrictedPerms = $this->sharedStorage->getPermissions('shareddirrestricted');
$this->assertEquals(7, $sharedDirRestrictedPerms);
$sharedDirRestrictedPerms = $this->sharedStorage->getPermissions('shareddirrestricted/textfile.txt');
$this->assertEquals(7, $sharedDirRestrictedPerms);
}
/**
* Test that the permissions of shared directory are returned correctly
*/
function testGetDirectoryPermissions() {
$contents = $this->secondView->getDirectoryContent('files/Shared/shareddir');
$this->assertEquals('subdir', $contents[0]['name']);
$this->assertEquals(31, $contents[0]['permissions']);
$this->assertEquals('textfile.txt', $contents[1]['name']);
$this->assertEquals(31, $contents[1]['permissions']);
$contents = $this->secondView->getDirectoryContent('files/Shared/shareddirrestricted');
$this->assertEquals('subdir', $contents[0]['name']);
$this->assertEquals(7, $contents[0]['permissions']);
$this->assertEquals('textfile1.txt', $contents[1]['name']);
$this->assertEquals(7, $contents[1]['permissions']);
}
}

View File

@@ -4,14 +4,24 @@ OCP\JSON::checkLoggedIn();
OCP\JSON::callCheck();
// "empty trash" command
$deleteAll = false;
if (isset($_POST['allfiles']) and $_POST['allfiles'] === 'true'){
$user = \OCP\User::getUser();
$list = OCA\Files_Trashbin\Helper::getTrashFiles('/');
$deleteAll = true;
$dirlisting = '0';
$folder = isset($_POST['dir']) ? $_POST['dir'] : '/';
if ($folder === '/' || $folder === '') {
OCA\Files_Trashbin\Trashbin::deleteAll();
$list = array();
} else {
$dirname = dirname($folder);
if ( $dirname !== '/' && $dirname !== '.' ) {
$dirlisting = '1';
} else {
$dirlisting = '0';
}
$list[] = $folder;
}
}
else {
$deleteAll = false;
$files = $_POST['files'];
$dirlisting = $_POST['dirlisting'];
$list = json_decode($files);
@@ -19,19 +29,13 @@ else {
$error = array();
$success = array();
$i = 0;
foreach ($list as $file) {
if ( $dirlisting === '0') {
if ($deleteAll) {
$filename = $file['name'];
$timestamp = $file['timestamp'];
}
else {
$delimiter = strrpos($file, '.d');
$filename = substr($file, 0, $delimiter);
$timestamp = substr($file, $delimiter+2);
}
$file = ltrim($file, '/');
$delimiter = strrpos($file, '.d');
$filename = substr($file, 0, $delimiter);
$timestamp = substr($file, $delimiter+2);
} else {
$filename = $file;
$timestamp = null;

View File

@@ -34,7 +34,17 @@ try{
if ($view->is_dir($file)) {
$mimetype = 'httpd/unix-directory';
} else {
$mimetype = \OC_Helper::getFileNameMimeType(pathinfo($file, PATHINFO_FILENAME));
$pathInfo = pathinfo($file);
$fileName = $pathInfo['basename'];
// if in root dir
if ($pathInfo['dirname'] === '.') {
// cut off the .d* suffix
$i = strrpos($fileName, '.');
if ($i !== false) {
$fileName = substr($fileName, 0, $i);
}
}
$mimetype = \OC_Helper::getFileNameMimeType($fileName);
}
$preview->setMimetype($mimetype);
$preview->setMaxX($maxX);
@@ -45,4 +55,4 @@ try{
}catch(\Exception $e) {
\OC_Response::setStatus(500);
\OC_Log::write('core', $e->getmessage(), \OC_Log::DEBUG);
}
}

View File

@@ -13,6 +13,7 @@ $success = array();
$i = 0;
foreach ($list as $file) {
if ( $dirlisting === '0') {
$file = ltrim($file, '/');
$delimiter = strrpos($file, '.d');
$filename = substr($file, 0, $delimiter);
$timestamp = substr($file, $delimiter+2);

View File

@@ -44,7 +44,7 @@
<notnull>true</notnull>
<length>512</length>
</field>
<field>
<name>type</name>
<type>text</type>
@@ -52,15 +52,15 @@
<notnull>true</notnull>
<length>4</length>
</field>
<field>
<name>mime</name>
<type>text</type>
<default></default>
<notnull>true</notnull>
<length>30</length>
<length>255</length>
</field>
<index>
<name>id_index</name>
<field>
@@ -68,7 +68,7 @@
<sorting>ascending</sorting>
</field>
</index>
<index>
<name>timestamp_index</name>
<field>
@@ -76,7 +76,7 @@
<sorting>ascending</sorting>
</field>
</index>
<index>
<name>user_index</name>
<field>
@@ -84,7 +84,7 @@
<sorting>ascending</sorting>
</field>
</index>
</declaration>
</table>
@@ -110,7 +110,7 @@
<notnull>true</notnull>
<length>50</length>
</field>
</declaration>
</table>

View File

@@ -1 +1 @@
0.4
0.5

View File

@@ -0,0 +1,3 @@
#fileList td a.file, #fileList td a.file span {
cursor: default;
}

View File

@@ -1,51 +0,0 @@
<?php
/**
* ownCloud - trash bin
*
* @author Bjoern Schiessle
* @copyright 2013 Bjoern Schiessle schiessle@owncloud.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
// Check if we are a user
OCP\User::checkLoggedIn();
$filename = $_GET["file"];
$view = new OC_FilesystemView('/'.\OCP\User::getUser().'/files_trashbin/files');
if(!$view->file_exists($filename)) {
header("HTTP/1.0 404 Not Found");
$tmpl = new OCP\Template( '', '404', 'guest' );
$tmpl->assign('file', $filename);
$tmpl->printPage();
exit;
}
$ftype=$view->getMimeType( $filename );
header('Content-Type:'.$ftype);if ( preg_match( "/MSIE/", $_SERVER["HTTP_USER_AGENT"] ) ) {
header( 'Content-Disposition: attachment; filename="' . rawurlencode( basename($filename) ) . '"' );
} else {
header( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode( basename($filename) )
. '; filename="' . rawurlencode( basename($filename) ) . '"' );
}
OCP\Response::disableCaching();
header('Content-Length: '. $view->filesize($filename));
OC_Util::obEnd();
$view->readfile( $filename );

View File

@@ -10,6 +10,7 @@ OCP\Util::addScript('files', 'fileactions');
$tmpl = new OCP\Template('files_trashbin', 'index', 'user');
OCP\Util::addStyle('files', 'files');
OCP\Util::addStyle('files_trashbin', 'trash');
OCP\Util::addScript('files', 'filelist');
// filelist overrides
OCP\Util::addScript('files_trashbin', 'filelist');

View File

@@ -3,12 +3,12 @@ $(document).ready(function() {
if (typeof FileActions !== 'undefined') {
FileActions.register('all', 'Restore', OC.PERMISSION_READ, OC.imagePath('core', 'actions/history'), function(filename) {
var tr = $('tr').filterAttr('data-file', filename);
var deleteAction = $('tr').filterAttr('data-file', filename).children("td.date").children(".action.delete");
var tr = FileList.findFileEl(filename);
var deleteAction = tr.children("td.date").children(".action.delete");
deleteAction.removeClass('delete-icon').addClass('progress-icon');
disableActions();
$.post(OC.filePath('files_trashbin', 'ajax', 'undelete.php'),
{files: JSON.stringify([filename]), dirlisting: tr.attr('data-dirlisting')},
{files: JSON.stringify([$('#dir').val() + '/' + filename]), dirlisting: tr.attr('data-dirlisting')},
function(result) {
for (var i = 0; i < result.data.success.length; i++) {
var row = document.getElementById(result.data.success[i].filename);
@@ -30,12 +30,12 @@ $(document).ready(function() {
return OC.imagePath('core', 'actions/delete');
}, function(filename) {
$('.tipsy').remove();
var tr = $('tr').filterAttr('data-file', filename);
var deleteAction = $('tr').filterAttr('data-file', filename).children("td.date").children(".action.delete");
var tr = FileList.findFileEl(filename);
var deleteAction = tr.children("td.date").children(".action.delete");
deleteAction.removeClass('delete-icon').addClass('progress-icon');
disableActions();
$.post(OC.filePath('files_trashbin', 'ajax', 'delete.php'),
{files: JSON.stringify([filename]), dirlisting: tr.attr('data-dirlisting')},
{files: JSON.stringify([$('#dir').val() + '/' +filename]), dirlisting: tr.attr('data-dirlisting')},
function(result) {
for (var i = 0; i < result.data.success.length; i++) {
var row = document.getElementById(result.data.success[i].filename);
@@ -66,41 +66,6 @@ $(document).ready(function() {
procesSelection();
});
$('#fileList').on('click', 'td.filename a', function(event) {
if (event.shiftKey) {
event.preventDefault();
var last = $(lastChecked).parent().parent().prevAll().length;
var first = $(this).parent().parent().prevAll().length;
var start = Math.min(first, last);
var end = Math.max(first, last);
var rows = $(this).parent().parent().parent().children('tr');
for (var i = start; i < end; i++) {
$(rows).each(function(index) {
if (index == i) {
var checkbox = $(this).children().children('input:checkbox');
$(checkbox).attr('checked', 'checked');
$(checkbox).parent().parent().addClass('selected');
}
});
}
}
var checkbox = $(this).parent().children('input:checkbox');
lastChecked = checkbox;
if ($(checkbox).attr('checked')) {
$(checkbox).removeAttr('checked');
$(checkbox).parent().parent().removeClass('selected');
$('#select_all').removeAttr('checked');
} else {
$(checkbox).attr('checked', 'checked');
$(checkbox).parent().parent().toggleClass('selected');
var selectedCount = $('td.filename input:checkbox:checked').length;
if (selectedCount == $('td.filename input:checkbox').length) {
$('#select_all').attr('checked', 'checked');
}
}
procesSelection();
});
$('.undelete').click('click', function(event) {
event.preventDefault();
var files = getSelectedFiles('file');
@@ -108,7 +73,7 @@ $(document).ready(function() {
var dirlisting = getSelectedFiles('dirlisting')[0];
disableActions();
for (var i = 0; i < files.length; i++) {
var deleteAction = $('tr').filterAttr('data-file', files[i]).children("td.date").children(".action.delete");
var deleteAction = FileList.findFileEl(files[i]).children("td.date").children(".action.delete");
deleteAction.removeClass('delete-icon').addClass('progress-icon');
}
@@ -136,7 +101,8 @@ $(document).ready(function() {
var params = {};
if (allFiles) {
params = {
allfiles: true
allfiles: true,
dir: $('#dir').val()
};
}
else {
@@ -153,7 +119,7 @@ $(document).ready(function() {
}
else {
for (var i = 0; i < files.length; i++) {
var deleteAction = $('tr').filterAttr('data-file', files[i]).children("td.date").children(".action.delete");
var deleteAction = FileList.findFileEl(files[i]).children("td.date").children(".action.delete");
deleteAction.removeClass('delete-icon').addClass('progress-icon');
}
}
@@ -183,13 +149,27 @@ $(document).ready(function() {
});
$('#fileList').on('click', 'td.filename input', function() {
var checkbox = $(this).parent().children('input:checkbox');
$(checkbox).parent().parent().toggleClass('selected');
if ($(checkbox).is(':checked')) {
var selectedCount = $('td.filename input:checkbox:checked').length;
if (selectedCount === $('td.filename input:checkbox').length) {
$('#select_all').prop('checked', true);
}
} else {
$('#select_all').prop('checked',false);
}
procesSelection();
});
$('#fileList').on('click', 'td.filename a', function(event) {
var mime = $(this).parent().parent().data('mime');
if (mime !== 'httpd/unix-directory') {
event.preventDefault();
}
var filename = $(this).parent().parent().attr('data-file');
var tr = $('tr').filterAttr('data-file',filename);
var tr = FileList.findFileEl(filename);
var renaming = tr.data('renaming');
if(!renaming && !FileList.isLoading(filename)){
if(mime.substr(0, 5) === 'text/'){ //no texteditor for now
@@ -229,7 +209,7 @@ function getSelectedFiles(property){
elements.each(function(i,element){
var file={
name:$(element).attr('data-filename'),
file:$(element).attr('data-file'),
file:$('#dir').val() + "/" + $(element).attr('data-file'),
timestamp:$(element).attr('data-timestamp'),
type:$(element).attr('data-type'),
dirlisting:$(element).attr('data-dirlisting')

View File

@@ -1,6 +0,0 @@
<?php
$TRANSLATIONS = array(
"Error" => "Ошибка",
"Delete" => "Удалить"
);
$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);";

View File

@@ -44,8 +44,10 @@ class Helper
}
$files = array();
$id = 0;
foreach ($result as $r) {
$i = array();
$i['id'] = $id++;
$i['name'] = $r['id'];
$i['date'] = \OCP\Util::formatDate($r['timestamp']);
$i['timestamp'] = $r['timestamp'];

View File

@@ -189,7 +189,7 @@ class Trashbin {
if ($rootView->is_dir($owner . '/files_versions/' . $ownerPath)) {
$size += self::calculateSize(new \OC\Files\View('/' . $owner . '/files_versions/' . $ownerPath));
if ($owner !== $user) {
$rootView->copy($owner . '/files_versions/' . $ownerPath, $owner . '/files_trashbin/versions/' . basename($ownerPath) . '.d' . $timestamp);
self::copy_recursive($owner . '/files_versions/' . $ownerPath, $owner . '/files_trashbin/versions/' . basename($ownerPath) . '.d' . $timestamp, $rootView);
}
$rootView->rename($owner . '/files_versions/' . $ownerPath, $user . '/files_trashbin/versions/' . $filename . '.d' . $timestamp);
} else if ($versions = \OCA\Files_Versions\Storage::getVersions($owner, $ownerPath)) {
@@ -247,7 +247,7 @@ class Trashbin {
if ($rootView->is_dir($keyfile)) {
$size += self::calculateSize(new \OC\Files\View($keyfile));
if ($owner !== $user) {
$rootView->copy($keyfile, $owner . '/files_trashbin/keyfiles/' . basename($ownerPath) . '.d' . $timestamp);
self::copy_recursive($keyfile, $owner . '/files_trashbin/keyfiles/' . basename($ownerPath) . '.d' . $timestamp, $rootView);
}
$rootView->rename($keyfile, $user . '/files_trashbin/keyfiles/' . $filename . '.d' . $timestamp);
} else {
@@ -265,7 +265,7 @@ class Trashbin {
if ($rootView->is_dir($sharekeys)) {
$size += self::calculateSize(new \OC\Files\View($sharekeys));
if ($owner !== $user) {
$rootView->copy($sharekeys, $owner . '/files_trashbin/share-keys/' . basename($ownerPath) . '.d' . $timestamp);
self::copy_recursive($sharekeys, $owner . '/files_trashbin/share-keys/' . basename($ownerPath) . '.d' . $timestamp, $rootView);
}
$rootView->rename($sharekeys, $user . '/files_trashbin/share-keys/' . $filename . '.d' . $timestamp);
} else {
@@ -564,6 +564,21 @@ class Trashbin {
return $size;
}
/**
* @brief delete all files from the trash
*/
public static function deleteAll() {
$user = \OCP\User::getUser();
$view = new \OC\Files\View('/' . $user);
$view->deleteAll('files_trashbin');
self::setTrashbinSize($user, 0);
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=?');
$query->execute(array($user));
return true;
}
/**
* @brief delete file from trash bin permanently
*
@@ -719,7 +734,7 @@ class Trashbin {
// calculate available space for trash bin
// subtract size of files and current trash bin size from quota
if ($softQuota) {
$rootInfo = $view->getFileInfo('/files/');
$rootInfo = $view->getFileInfo('/files/', false);
$free = $quota - $rootInfo['size']; // remaining free space for user
if ($free > 0) {
$availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - $trashbinSize; // how much space can be used for versions
@@ -763,8 +778,13 @@ class Trashbin {
*/
private static function expire($trashbinSize, $user) {
// let the admin disable auto expire
$autoExpire = \OC_Config::getValue('trashbin_auto_expire', true);
if ($autoExpire === false) {
return 0;
}
$user = \OCP\User::getUser();
$view = new \OC\Files\View('/' . $user);
$availableSpace = self::calculateFreeSpace($trashbinSize);
$size = 0;

View File

@@ -3,11 +3,11 @@
<img src="<?php print_unescaped(OCP\image_path('core', 'places/home.svg'));?>" class="svg" />
</a>
</div>
<?php if(count($_["breadcrumb"])):?>
<div class="crumb svg"
data-dir='/'>
<div class="crumb svg"
data-dir='/'>
<a href="<?php p($_['baseURL']); ?>"><?php p($l->t("Deleted Files")); ?></a>
</div>
</div>
<?php if(count($_["breadcrumb"])):?>
<?php endif;?>
<?php for($i=0; $i<count($_["breadcrumb"]); $i++):
$crumb = $_["breadcrumb"][$i];

View File

@@ -35,18 +35,21 @@
<?php endif; ?>
<?php endif; ?>
>
<?php if(!isset($_['readonly']) || !$_['readonly']): ?><input type="checkbox" /><?php endif; ?>
<?php if(!isset($_['readonly']) || !$_['readonly']): ?>
<input id="select-<?php p($file['id']); ?>" type="checkbox" />
<label for="select-<?php p($file['id']); ?>"></label>
<?php endif; ?>
<?php if($file['type'] === 'dir'): ?>
<?php if( $_['dirlisting'] ): ?>
<a class="name" href="<?php p($_['baseURL'].'/'.$name); ?>" title="">
<a class="name dir" href="<?php p($_['baseURL'].'/'.$name); ?>" title="">
<?php else: ?>
<a class="name" href="<?php p($_['baseURL'].'/'.$name.'.d'.$file['timestamp']); ?>" title="">
<a class="name dir" href="<?php p($_['baseURL'].'/'.$name.'.d'.$file['timestamp']); ?>" title="">
<?php endif; ?>
<?php else: ?>
<?php if( $_['dirlisting'] ): ?>
<a class="name" href="<?php p($_['downloadURL'].'/'.$name); ?>" title="">
<a class="name file" href="<?php p($_['downloadURL'].'/'.$name); ?>" title="">
<?php else: ?>
<a class="name" href="<?php p($_['downloadURL'].'/'.$name.'.d'.$file['timestamp']);?>" title="">
<a class="name file" href="<?php p($_['downloadURL'].'/'.$name.'.d'.$file['timestamp']);?>" title="">
<?php endif; ?>
<?php endif; ?>
<span class="nametext">

View File

@@ -5,7 +5,8 @@ $source = $_GET['source'];
$start = $_GET['start'];
list ($uid, $filename) = OCA\Files_Versions\Storage::getUidAndFilename($source);
$count = 5; //show the newest revisions
if( ($versions = OCA\Files_Versions\Storage::getVersions($uid, $filename)) ) {
$versions = OCA\Files_Versions\Storage::getVersions($uid, $filename, $source);
if( $versions ) {
$endReached = false;
if (count($versions) <= $start+$count) {

View File

@@ -12,18 +12,11 @@ if(!\OC_App::isEnabled('files_versions')){
}
$file = array_key_exists('file', $_GET) ? (string) urldecode($_GET['file']) : '';
$user = array_key_exists('user', $_GET) ? $_GET['user'] : '';
$maxX = array_key_exists('x', $_GET) ? (int) $_GET['x'] : 44;
$maxY = array_key_exists('y', $_GET) ? (int) $_GET['y'] : 44;
$version = array_key_exists('version', $_GET) ? $_GET['version'] : '';
$scalingUp = array_key_exists('scalingup', $_GET) ? (bool) $_GET['scalingup'] : true;
if($user === '') {
\OC_Response::setStatus(400); //400 Bad Request
\OC_Log::write('versions-preview', 'No user parameter was passed', \OC_Log::DEBUG);
exit;
}
if($file === '' && $version === '') {
\OC_Response::setStatus(400); //400 Bad Request
\OC_Log::write('versions-preview', 'No file parameter was passed', \OC_Log::DEBUG);
@@ -36,7 +29,8 @@ if($maxX === 0 || $maxY === 0) {
exit;
}
try{
try {
list($user, $file) = \OCA\Files_Versions\Storage::getUidAndFilename($file);
$preview = new \OC\Preview($user, 'files_versions', $file.'.v'.$version);
$mimetype = \OC_Helper::getFileNameMimeType($file);
$preview->setMimetype($mimetype);

View File

@@ -36,12 +36,7 @@ $view = new OC\Files\View('/');
$ftype = $view->getMimeType('/'.$uid.'/files/'.$filename);
header('Content-Type:'.$ftype);
if ( preg_match( "/MSIE/", $_SERVER["HTTP_USER_AGENT"] ) ) {
header( 'Content-Disposition: attachment; filename="' . rawurlencode( basename($filename) ) . '"' );
} else {
header( 'Content-Disposition: attachment; filename*=UTF-8\'\'' . rawurlencode( basename($filename) )
. '; filename="' . rawurlencode( basename($filename) ) . '"' );
}
OCP\Response::setContentDispositionHeader(basename($filename), 'attachment');
OCP\Response::disableCaching();
header('Content-Length: '.$view->filesize($versionName));

View File

@@ -77,6 +77,7 @@ function goToVersionPage(url){
function createVersionsDropdown(filename, files) {
var start = 0;
var fileEl;
var html = '<div id="dropdown" class="drop drop-versions" data-file="'+escapeHTML(files)+'">';
html += '<div id="private">';
@@ -86,8 +87,9 @@ function createVersionsDropdown(filename, files) {
html += '<input type="button" value="'+ t('files_versions', 'More versions...') + '" name="show-more-versions" id="show-more-versions" style="display: none;" />';
if (filename) {
$('tr').filterAttr('data-file',filename).addClass('mouseOver');
$(html).appendTo($('tr').filterAttr('data-file',filename).find('td.filename'));
fileEl = FileList.findFileEl(filename);
fileEl.addClass('mouseOver');
$(html).appendTo(fileEl.find('td.filename'));
} else {
$(html).appendTo($('thead .share'));
}
@@ -138,7 +140,7 @@ function createVersionsDropdown(filename, files) {
var preview = '<img class="preview" src="'+revision.preview+'"/>';
var download ='<a href="' + path + "?file=" + files + '&revision=' + revision.version + '">';
var download ='<a href="' + path + "?file=" + encodeURIComponent(files) + '&revision=' + revision.version + '">';
download+='<img';
download+=' src="' + OC.imagePath('core', 'actions/download') + '"';
download+=' name="downloadVersion" />';
@@ -146,8 +148,7 @@ function createVersionsDropdown(filename, files) {
download+='</a>';
var revert='<span class="revertVersion"';
revert+=' id="' + revision.version + '"';
revert+=' value="' + files + '">';
revert+=' id="' + revision.version + '">';
revert+='<img';
revert+=' src="' + OC.imagePath('core', 'actions/history') + '"';
revert+=' name="revertVersion"';
@@ -156,14 +157,13 @@ function createVersionsDropdown(filename, files) {
var version=$('<li/>');
version.attr('value', revision.version);
version.html(preview + download + revert);
// add file here for proper name escaping
version.find('span.revertVersion').attr('value', files);
version.appendTo('#found_versions');
}
$('tr').filterAttr('data-file',filename).addClass('mouseOver');
$('#dropdown').show('blind');
}
$(this).click(

View File

@@ -98,7 +98,6 @@ class Storage {
$files_view = new \OC\Files\View('/'.$uid .'/files');
$users_view = new \OC\Files\View('/'.$uid);
$versions_view = new \OC\Files\View('/'.$uid.'/files_versions');
// check if filename is a directory
if($files_view->is_dir($filename)) {
@@ -132,7 +131,10 @@ class Storage {
\OC_FileProxy::$enabled = false;
// store a new version of a file
$users_view->copy('files'.$filename, 'files_versions'.$filename.'.v'.$users_view->filemtime('files'.$filename));
$mtime = $users_view->filemtime('files'.$filename);
$users_view->copy('files'.$filename, 'files_versions'.$filename.'.v'. $mtime);
// call getFileInfo to enforce a file cache entry for the new version
$users_view->getFileInfo('files_versions'.$filename.'.v'.$mtime);
// reset proxy state
\OC_FileProxy::$enabled = $proxyStatus;
@@ -259,11 +261,12 @@ class Storage {
/**
* @brief get a list of all available versions of a file in descending chronological order
* @param $uid user id from the owner of the file
* @param $filename file to find versions of, relative to the user files dir
* @returns array
* @param string $uid user id from the owner of the file
* @param string $filename file to find versions of, relative to the user files dir
* @param string $userFullPath
* @returns array versions newest first
*/
public static function getVersions($uid, $filename) {
public static function getVersions($uid, $filename, $userFullPath = '') {
$versions = array();
// fetch for old versions
$view = new \OC\Files\View('/' . $uid . '/' . self::VERSIONS_ROOT);
@@ -284,7 +287,11 @@ class Storage {
$versions[$key]['cur'] = 0;
$versions[$key]['version'] = $version;
$versions[$key]['humanReadableTimestamp'] = self::getHumanReadableTimestamp($version);
$versions[$key]['preview'] = \OCP\Util::linkToRoute('core_ajax_versions_preview', array('file' => $filename, 'version' => $version, 'user' => $uid));
if (empty($userFullPath)) {
$versions[$key]['preview'] = '';
} else {
$versions[$key]['preview'] = \OCP\Util::linkToRoute('core_ajax_versions_preview', array('file' => $userFullPath, 'version' => $version));
}
$versions[$key]['path'] = $filename;
$versions[$key]['name'] = $versionedFile;
$versions[$key]['size'] = $file['size'];
@@ -390,12 +397,13 @@ class Storage {
}
}
ksort($versions);
// newest first
krsort($versions);
$result = array();
foreach ($versions as $key => $value) {
$size = $view->filesize($value['path']);
$size = $view->filesize(self::VERSIONS_ROOT.'/'.$value['path'].'.v'.$value['timestamp']);
$filename = $value['path'];
$result['all'][$key]['version'] = $value['timestamp'];
@@ -443,7 +451,7 @@ class Storage {
// subtract size of files and current versions size from quota
if ($softQuota) {
$files_view = new \OC\Files\View('/'.$uid.'/files');
$rootInfo = $files_view->getFileInfo('/');
$rootInfo = $files_view->getFileInfo('/', false);
$free = $quota-$rootInfo['size']; // remaining free space for user
if ( $free > 0 ) {
$availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - ($versionsSize + $offset); // how much space can be used for versions
@@ -506,8 +514,8 @@ class Storage {
* @brief delete old version from a given list of versions
*
* @param array $versionsByFile list of versions ordered by files
* @param array $allVversions all versions accross multiple files
* @param $versionsFileview OC\Files\View on data/user/files_versions
* @param array $allVversions all versions across multiple files
* @param $versionsFileview \OC\Files\View on data/user/files_versions
* @return size of releted versions
*/
private static function delOldVersions($versionsByFile, &$allVersions, $versionsFileview) {
@@ -517,7 +525,6 @@ class Storage {
// delete old versions for every given file
foreach ($versionsByFile as $versions) {
$versions = array_reverse($versions); // newest version first
$interval = 1;
$step = Storage::$max_versions_per_interval[$interval]['step'];
@@ -536,15 +543,16 @@ class Storage {
foreach ($versions as $key => $version) {
$newInterval = true;
while ($newInterval) {
if ($nextInterval == -1 || $version['version'] >= $nextInterval) {
if ($nextInterval == -1 || $prevTimestamp > $nextInterval) {
if ($version['version'] > $nextVersion) {
//distance between two version too small, delete version
$versionsFileview->unlink($version['path'] . '.v' . $version['version']);
\OC_Hook::emit('\OCP\Versions', 'delete', array('path' => $version['path'] . '.v' . $version['version']));
$versionsFileview->unlink($version['path'] . '.v' . $version['version']);
$size += $version['size'];
unset($allVersions[$key]); // update array with all versions
} else {
$nextVersion = $version['version'] - $step;
$prevTimestamp = $version['version'];
}
$newInterval = false; // version checked so we can move to the next one
} else { // time to move on to the next interval
@@ -559,7 +567,6 @@ class Storage {
$newInterval = true; // we changed the interval -> check same version with new interval
}
}
$prevTimestamp = $version['version'];
}
}
return $size;

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