Compare commits

...

338 Commits

Author SHA1 Message Date
Frank Karlitschek
e35303f702 5.0.7 2013-06-06 10:13:32 +02:00
blizzz
68960db77e Merge pull request #3584 from owncloud/fix_ldap_port
LDAP: append port when URL is passed in LDAP Host configuration, fixes #...
2013-06-04 01:31:52 -07:00
Arthur Schiwon
03e5982026 LDAP: append port when URL is passed in LDAP Host configuration, fixes #2600 2013-06-03 23:07:32 +02:00
Frank Karlitschek
9046c65af5 5.0.7 RC 2013-06-02 23:02:52 +02:00
Arthur Schiwon
f3620b7c03 LDAP: sqlite compatibility for emptyiing tables 2013-05-31 21:18:39 +02:00
Arthur Schiwon
7b95d031a1 LDAP: fix possible recursion 2013-05-31 20:13:33 +02:00
Arthur Schiwon
78520cdfc7 Backport bfa7157 2013-05-31 20:13:22 +02:00
Florin Peter
1ef101c439 also fix login errors while filesystem is not loaded in app.php 2013-05-31 20:06:43 +02:00
Florin Peter
a1401f686a fix login errors while filesystem is not loaded 2013-05-31 20:06:33 +02:00
Florin Peter
5eded27fa3 added our own file extension .part will not work here if we use file_get_contents so we used our own extension '.etmp' 2013-05-31 12:28:45 +02:00
Florin Peter
7c9b34a416 prevent files_versions from calling file proxy which calls files_encryption and do unnecessary load and file operations 2013-05-31 12:28:40 +02:00
Florin Peter
6e3acd3111 fix share and un-share for single file 2013-05-31 12:28:29 +02:00
Florin Peter
aed15ef72b fixed problems with file_get_contents and file_put_contents this problem was related to text editor with big text files 2013-05-31 12:28:22 +02:00
Florin Peter
5353bcc246 fixes for pgsql 2013-05-31 12:28:12 +02:00
Florin Peter
2e5fcf4d56 changed deprecated class 2013-05-31 12:28:06 +02:00
Florin Peter
4dac837046 fixed typo 2013-05-31 12:28:00 +02:00
Florin Peter
512571c54f fixes if cache returns false 2013-05-31 12:27:55 +02:00
Florin Peter
0fa0e92883 fix $parent/$source typo 2013-05-31 12:27:49 +02:00
Florin Peter
8e80aa3630 backport of #3527 2013-05-31 12:27:38 +02:00
Björn Schießle
15e0fc6b7f fix indention 2013-05-31 12:24:44 +02:00
Björn Schießle
6d667c02fc remove unnecessary variable 2013-05-31 12:24:36 +02:00
Björn Schießle
8e512bdfdf use public API for error handling; improved while condition 2013-05-31 12:24:26 +02:00
Björn Schießle
a5b75d348f for external storages we never reach the path 'files', instead we need to leave the loop if no further parent exists 2013-05-31 12:24:21 +02:00
Björn Schießle
ae2ab015d9 if one public link share was found, we don't have to check it for the other folders 2013-05-31 12:24:15 +02:00
Björn Schießle
a8c3d51a49 check list of users with access to the file from the bottom to the top. This way we avoid calling getFileInfo() on every dir, which creates a lot of overhead, especially for external storages 2013-05-31 12:24:08 +02:00
Florin Peter
f9c9cceb30 fixed if fopen returns false typically on external storage 2013-05-31 12:23:25 +02:00
blizzz
acff4fc4fa Merge pull request #3543 from owncloud/fix_ldap_alternateintname
Fix ldap alternateintname
2013-05-30 07:54:48 -07:00
Arthur Schiwon
deeb1cfd50 Merge branch 'stable5' into fix_ldap_alternateintname 2013-05-30 14:15:38 +02:00
Arthur Schiwon
955eff8d87 LDAP: fix generation of alternate internal name on conflicts. Use also smaller number for better user experience on e.g. *DAV links 2013-05-30 14:14:43 +02:00
Morris Jobke
1b4d2e851d Merge pull request #3526 from owncloud/fix_ldap_doc_url
LDAP: fix help (doc) URL. Old one works, but leads to an outdated versio...
2013-05-30 04:16:10 -07:00
Florin Peter
1c49784f7f backport #3507 2013-05-30 00:40:30 +02:00
Michael Gapczynski
9a25f7b849 Organize conditionals in a better order 2013-05-29 13:25:19 -04:00
Michael Gapczynski
71cdd17df4 Only update metadata that has changed 2013-05-29 13:25:04 -04:00
Michael Gapczynski
3891a4cef9 Style fixes 2013-05-29 17:22:06 +02:00
Robin Appelman
0017753ec5 Cache mimetype icons 2013-05-29 17:22:00 +02:00
Arthur Schiwon
a4ef49c2be LDAP: fix help (doc) URL. Old one works, but leads to an outdated version 2013-05-29 14:07:47 +02:00
zafi
621d18f77d The "lost password" field depends on OC_USER_BACKEND_SET_PASSWORD
so it should only be visible for users with a supporting backend.
2013-05-28 13:17:07 +02:00
Florin Peter
0c5bd4e578 fix for undefined index 2013-05-28 10:56:48 +02:00
Florin Peter
54768402b6 fix for losing private key while being logged in and accessing a public link 2013-05-28 10:56:41 +02:00
Björn Schießle
7316d6f850 Merge pull request #3504 from owncloud/fix_enc_migration
fix migration old encryption -> new encryption
2013-05-27 08:29:58 -07:00
Florin Peter
daf5d47821 backport of #3495 2013-05-27 17:19:48 +02:00
Georg Ehrke
c872042616 fix https://github.com/owncloud/core/issues/3320 2013-05-27 17:07:45 +02:00
Georg Ehrke
0cf6e5693a add event.preventDefault to undelete function 2013-05-27 17:07:39 +02:00
Björn Schießle
9ac29cd122 Merge branch 'stable5' into fix_enc_migration 2013-05-27 14:28:26 +02:00
Florin Peter
55e4e054d6 added users for tests
reformat code to meet coding guidelines
2013-05-27 14:20:24 +02:00
Florin Peter
3cbe6b2d8b improved test
- fixed testPermanentDeleteFile sometimes failed
- speed optimization
- reformat code
2013-05-27 14:20:18 +02:00
Björn Schießle
087b21c913 legacyBlockDecryprt() needs to be public 2013-05-27 13:47:03 +02:00
Björn Schießle
09765ea27c make legacyDecrypt() private als always call legacyBlockDecrypt() from other classes 2013-05-27 12:21:39 +02:00
Björn Schießle
189d251c6a fix migration from old to new encryption 2013-05-27 12:02:27 +02:00
Roland Hager
07fb230cbe Fixing UPDATE error in filecache table when renaming files by calling move(). Add storage id to the where clause to avoid updating entries of other users. 2013-05-25 14:19:11 -04:00
Bart Visscher
faad2d0d69 Add check for Magic Quotes 2013-05-25 14:06:40 -04:00
Arthur Schiwon
c7d8cd9679 Merge branch 'backport_ldap_configurable_username_n_uuid' into stable5 2013-05-25 14:07:38 +02:00
Frank Karlitschek
6c53253ad6 preview of stable5 including the new encryption app 2013-05-25 12:12:07 +02:00
Frank Karlitschek
2018e94b41 increase version and add warning 2013-05-25 12:07:16 +02:00
Björn Schießle
e044260bc1 Merge pull request #3484 from owncloud/files_encryption_stable5
file encryption app backport master -> stable5
2013-05-24 14:09:50 -07:00
Florin Peter
12f5b5ce61 improved trashbin test again 2013-05-24 22:01:27 +02:00
Florin Peter
210ae9e5f7 improved trashbin test 2013-05-24 21:35:18 +02:00
Florin Peter
f164f43590 added files_encryption tests at first position 2013-05-24 20:04:51 +02:00
Florin Peter
9a25c39c36 fixed missing directory creation in files_trashbin 2013-05-24 20:04:21 +02:00
Björn Schießle
397dc3dcde fix first time encryption after app was enabled 2013-05-24 20:02:41 +02:00
Björn Schießle
8c235de826 no use the recoveryPassword var instead of accessing the POST array 2013-05-24 20:00:29 +02:00
Florin Peter
e7734d0c46 Merge branch 'stable5' into files_encryption_stable5 2013-05-24 19:40:23 +02:00
Florin Peter
1a638cd3a8 backport of #3271 2013-05-24 19:37:28 +02:00
Björn Schießle
890b7702ef port css for recovery passwd input to stable5 2013-05-24 18:04:23 +02:00
Björn Schießle
a4018ad4d7 handle recovery password 2013-05-24 17:57:39 +02:00
Björn Schießle
c6dc7993b6 enable files_encryption for testing 2013-05-24 14:59:12 +02:00
Björn Schießle
7b8f64d20f remove unneeded hooks 2013-05-24 14:54:47 +02:00
Björn Schießle
cb12cf8324 increase ownCloud version number to upgrade file cache table 2013-05-24 13:44:05 +02:00
Björn Schießle
3bd0141e6d backport file cache changes from master to stable5, needed for encryption app 2013-05-24 13:40:37 +02:00
Björn Schießle
89546bf90c add post hooks to share API, needed by the encryption app 2013-05-24 13:26:03 +02:00
Björn Schießle
c960cfcd55 add post hooks to share API, needed by the encryption app 2013-05-24 13:15:51 +02:00
Björn Schießle
a99676a73e backport trashbin: enable trashbin to handle encryption keys 2013-05-24 13:04:31 +02:00
Björn Schießle
8fa5f35e4f backport changes to share.php to enable the encryption app to get all users with access to a given file 2013-05-24 12:45:30 +02:00
Björn Schießle
c4b40af602 backport: enable admin to recover encrypted files 2013-05-24 12:42:08 +02:00
Björn Schießle
1c3ced26c1 add new files encryption app 2013-05-24 12:08:40 +02:00
Björn Schießle
33520c2985 move old files_encryption out of the way 2013-05-24 12:05:13 +02:00
Michael Gapczynski
0eb32bfc93 Switch to calling deleteAll via storage to avoid emitting delete hook 2013-05-23 20:43:08 -04:00
Michael Gapczynski
ae98c50b16 Remove user name addition to paths in deleteAll 2013-05-23 20:42:59 -04:00
Michael Gapczynski
c528fbb9bb Add data-dir attribute to home breadcrumb 2013-05-23 20:42:44 -04:00
Michael Gapczynski
0e4d45a56d Fix undefined variable for copying empty folders 2013-05-23 20:42:23 -04:00
Michael Gapczynski
a55a92752a Add support for copying/moving folders between storages, move isIgnoredDir() to Filesystem
Conflicts:
	lib/files/cache/scanner.php
2013-05-23 20:40:13 -04:00
Michael Gapczynski
34fda272d6 RUNTIME_NOSETUPFS no longer exists, using tearDownFS() in public links instead 2013-05-22 18:21:39 -04:00
Robin Appelman
412f0962e7 Have the filecache updater testcase clean the filesystem properly 2013-05-22 15:04:39 -04:00
Jörn Friedrich Dreyer
74e475cf2d cleanup after people who don't test in ie 2013-05-20 13:00:32 +02:00
Robin Appelman
1291f36709 Set storage id for openstack swift backend 2013-05-17 18:26:57 -04:00
Michael Gapczynski
1284179589 Initialize collectionTypes variable as false 2013-05-17 15:29:38 +02:00
Florin Peter
75fd96878a only connect share hooks if installation OC is installed 2013-05-17 10:56:59 +02:00
Thomas Tanghus
f6dac667fd Add Compound property to avoid double escaping values. 2013-05-16 16:59:37 +02:00
Thomas Tanghus
197914480e StringProperty unittest 2013-05-16 16:58:50 +02:00
Thomas Tanghus
3a6181620a Add OC\VObject\StringProperty. Partial fix for owncloud/apps#762 2013-05-16 16:58:28 +02:00
Arthur Schiwon
41aef94c24 LDAP: fix display of numerical display names 2013-05-16 14:48:02 +02:00
Arthur Schiwon
0e3e3d15a1 LDAP: Implement clear mappings functionality 2013-05-16 14:47:52 +02:00
Arthur Schiwon
6573fdc717 LDAP: implement UUID and internal username override 2013-05-16 14:47:00 +02:00
Arthur Schiwon
0e2c3dc89e LDAP: better variable name 2013-05-16 14:46:53 +02:00
Arthur Schiwon
34c8fd5149 LDAP: implement r+w for new settings 2013-05-16 14:46:45 +02:00
Arthur Schiwon
55332fe1bb LDAP: add settings for UUID override 2013-05-16 14:46:39 +02:00
Arthur Schiwon
57339b725e LDAP: prepare settings for internal username attribute and clearing user mappings 2013-05-16 14:46:33 +02:00
Arthur Schiwon
c8d63e3c79 LDAP: Coypright info 2013-05-16 14:46:25 +02:00
Thomas Tanghus
7a1992a170 Merge pull request #3355 from owncloud/filepicker_escape_names
Escape file names and types in filepicker.
2013-05-15 05:08:58 -07:00
Thomas Tanghus
752a316a52 Escape file names and types in filepicker. 2013-05-15 01:31:53 +02:00
Björn Schießle
408aed3175 Merge pull request #3350 from owncloud/fix_history_template
fix history template, print_unescaped() needs to include closing tags
2013-05-14 12:18:16 -07:00
Björn Schießle
1282c33db4 fix history template, print_unescaped() needs to include closing tags 2013-05-14 20:06:53 +02:00
Björn Schießle
256e53ba68 touch() needs to be performed relative to user/files otherwise ownCloud doesn't execute the hooks which means that etags aren't updated properly; backport of https://github.com/owncloud/core/pull/3303 2013-05-14 11:34:40 +02:00
Frank Karlitschek
2020f35c6a 5.0.6 2013-05-14 08:14:24 +02:00
Frank Karlitschek
cc495ed6d8 backport https://github.com/owncloud/core/pull/3329 2013-05-13 03:23:07 +02:00
Lukas Reschke
f2911e76bc Add requesttoken to guest view
Should fix #3321
2013-05-13 14:54:18 +02:00
Frank Karlitschek
726350ea97 5.0.6 RC2 2013-05-12 23:59:31 +02:00
Lukas Reschke
9a53d50e16 Merge pull request #3290 from owncloud/config-data
Move config data to template
2013-05-12 11:41:42 +02:00
Jörn Friedrich Dreyer
bc767f1899 don't emit rename hooks on partial file renames 2013-05-10 15:19:02 +02:00
Jörn Friedrich Dreyer
35b1f40ba4 rename isIgnoredFile to isPartialFile, remove check of blacklisted files in isPartialFile, correct usage of isPartialFile and isFileBlacklisted 2013-05-10 15:18:57 +02:00
Björn Schießle
a23e8833c3 Merge pull request #3282 from owncloud/fix_etag_update
Fix etag update
2013-05-08 13:58:24 -07:00
Björn Schießle
8875bae0c3 don't call correctFolder() in touchHook, it will be called later in the writeUpdate() 2013-05-08 22:57:08 +02:00
Robin Appelman
144977352d Cache: only look for child entires when doing a move operation when moving a folder 2013-05-08 22:35:38 +02:00
Björn Schießle
35da6f25b1 rename a file if it gets restored so that it no longer exists as a version. Otherwise it can happen that the expire() function removes all other versions so that we end up with only one version which is exactly the same as the original file 2013-05-08 16:32:29 +02:00
Björn Schießle
c43ec33ecb update etag for for the touched file 2013-05-08 15:49:45 +02:00
Björn Schießle
08561da5b6 touch file relative to users file folder, otherwise the hooks will be ignored 2013-05-08 15:05:03 +02:00
Bart Visscher
d6fe8f213d Merge pull request #3141 from owncloud/fix_2553
Cache: mount user mountpoints to make sure that $data/$user/ exists before accessi...
2013-05-08 05:05:21 -07:00
Morris Jobke
dd8c1f7759 Merge pull request #3244 from owncloud/allow_set_quota_to_zero
allow to set quota to zero, issue #2696
2013-05-07 01:37:10 -07:00
Björn Schießle
7ff26af107 allow to set quota to zero, issue #2696 2013-05-06 11:43:50 +02:00
blizzz
44fedae69f Merge pull request #3143 from owncloud/ldap_guid_check
LDAP: do not reset UUID attribute setting when guid is detected
2013-05-06 01:16:32 -07:00
Frank Karlitschek
ffb91cdd66 5.0.6 RC 2013-05-05 23:35:20 +02:00
Lukas Reschke
1dfb757593 Merge pull request #3245 from owncloud/use-$view
Use the internal ownCloud view
2013-05-06 18:23:58 +02:00
Michael Gapczynski
c0047b9079 Fix #2816 renaming shared files 2013-05-06 11:40:55 -04:00
Arthur Schiwon
0d5c82cd2a LDAP: cachekey in set method needs to match with that one from get 2013-05-03 16:05:46 +02:00
Bernhard Posselt
e3c7386be4 respect format output 2013-05-03 15:39:51 +02:00
Bernhard Posselt
5db33b47c2 logout before output to not run into header already sent problems 2013-05-03 15:39:45 +02:00
Bernhard Posselt
6c26143516 fix bug that would only return error responses for 3rdparty apps 2013-05-03 15:39:35 +02:00
Robin Appelman
9c605c3fd1 Dont task external storages with creating their own root 2013-05-03 15:11:56 +02:00
Arthur Schiwon
0639634782 LDAP: remove restriction from group names to be in line with core behaviour again 2013-05-03 15:07:10 +02:00
blizzz
7d5b8e85ac Merge pull request #3197 from owncloud/fix_userlist
Fix retrieval of users with multiple backends
2013-05-03 04:48:51 -07:00
Arthur Schiwon
c99b667021 Fix retrieval of users with multiple backends 2013-04-30 19:51:28 +02:00
Lukas Reschke
c08c22aa54 It's a class 2013-04-29 14:28:49 +02:00
Lukas Reschke
cbd216414a Remove uneeded onclick handler 2013-04-29 14:28:43 +02:00
Lukas Reschke
5428086204 Move onclick handler 2013-04-29 14:28:33 +02:00
Robin Appelman
b38a1adf2d Files: Fix XSS when creating dropshadow 2013-04-28 19:33:54 +02:00
Tom Needham
a5978ad544 Correct the api response when both a shipped app and/or a third party app fail 2013-04-28 11:56:31 +01:00
Tom Needham
b24e6f11ba Fix typo 2013-04-28 11:53:30 +01:00
Tom Needham
d642480c55 Code style for ocs/routes.php 2013-04-28 11:53:23 +01:00
Tom Needham
556ea61f8e Change app identifier for core api routes 2013-04-28 11:53:17 +01:00
Tom Needham
3bcd10a97c Use correct variable when checking auth 2013-04-28 11:53:08 +01:00
Arthur Schiwon
54a3038dc0 Cache Test: set datadir to temporary location, otherwise initmountpoints will access to productive location 2013-04-26 22:14:38 +02:00
Arthur Schiwon
a6ece109ba LDAP: do not reset UUID attribute setting when guid is detected 2013-04-26 15:02:05 +02:00
Arthur Schiwon
4c008a8f92 Cache: mount user mountpoints to make sure that // exists before accessing it. Fixes #2553 and #2374 2013-04-26 13:20:12 +02:00
Morris Jobke
2030037301 modify password clone to password type right on submit to prevent the browser remind the content 2013-04-26 11:05:07 +02:00
Morris Jobke
794ed99927 turn off autocompletion for password field
refs #2632
2013-04-26 11:04:54 +02:00
Morris Jobke
65c7746504 Merge pull request #3115 from owncloud/backport-3109-stable5-2
backport #3109 to stable5 - changed *.po and *.pot have been ignored
2013-04-25 01:51:38 -07:00
Jenkins for ownCloud
faa51bd002 backport #3109 to stable5 - changed *.po and *.pot have been ignored 2013-04-24 22:37:41 +02:00
Robin Appelman
d9f10e2c26 Files: fix the order fileactions are computed for a file 2013-04-24 19:58:43 +02:00
Morris Jobke
8d92aaf3b7 fix wrong shared icon description
fix #2928

translation of string "Shared" has to be marked as located in "files" for the translation extractor
2013-04-24 17:51:50 +02:00
Lukas Reschke
9894145f8d Allow loading of external media ressources 2013-04-24 17:20:00 +02:00
Florian Scholz
deba972093 - xframe restriction configurable now 2013-04-24 17:02:58 +02:00
Daniel Molkentin
41dc1fee68 Merge pull request #3100 from owncloud/ensure_index_php
Fix for #3049(cherry picked from commit ff6fb0906b)
2013-04-24 16:23:21 +02:00
Bernhard Posselt
72ea678c0e use variable instead of relative path to file 2013-04-24 16:12:23 +02:00
Bernhard Posselt
ff49824312 check if there is a default/ folder in the theme directory if no theme exists 2013-04-24 16:12:10 +02:00
Lukas Reschke
bb3d39f728 Disallow URLs containing a @ 2013-04-23 21:24:05 +02:00
Robin Appelman
a7f1269f92 Files: also check if the source path is valid when doing a rename or copy operation 2013-04-23 21:13:29 +02:00
Arthur Schiwon
7ae0e38c4f LDAP: reset user/group-config association only after exists-check, may performance in some cases 2013-04-23 19:20:54 +02:00
Thomas Tanghus
b626e514f7 Merge pull request #3076 from owncloud/manually_backport_insertIfNotExist
Backport #2567 OC_DB:insertIfNotExist()
2013-04-22 13:48:55 -07:00
Thomas Tanghus
3e8beddfe3 Backport #2567 2013-04-22 21:12:30 +02:00
Jan-Christoph Borchardt
18d515450a remove unnecessary border from navigation, looked strange with scrollbar and pushed the text over 1px 2013-04-22 16:17:22 +02:00
Jan-Christoph Borchardt
969bcb3ced make textarea inherit ownCloud font instead of using monospace 2013-04-22 16:16:52 +02:00
Bart Visscher
1d255ebf70 No need to strip slashes, json_decode handles that for us 2013-04-19 15:08:46 +02:00
Frank Karlitschek
9aae21db79 5.0.5 2013-04-10 02:14:16 +02:00
Jan-Christoph Borchardt
536117da2a apply navigation hover effect directly to img and span, cleaner code 2013-04-18 10:03:14 +02:00
Brice Maron
29054c27c9 Warn when we do an upgrade 2013-04-17 22:03:05 +02:00
Jan-Christoph Borchardt
207bf4bffe additional comments 2013-04-17 19:44:20 +02:00
Jan-Christoph Borchardt
4e11814a0c fix navigation hover effect, documentation 2013-04-17 19:44:07 +02:00
Thomas Tanghus
32667f8c38 Remove not null constraint. Fix #2976 2013-04-17 19:18:17 +02:00
Thomas Müller
1c06bec262 Merge pull request #2967 from Mirodin/patch-6
Update de_DE.php
2013-04-17 02:29:34 -07:00
Thomas Müller
a82965edf2 Merge pull request #2965 from Mirodin/patch-5
Update de.php
2013-04-17 02:29:02 -07:00
Mirodin
76f12567be Update de_DE.php 2013-04-17 11:54:56 +03:00
Mirodin
d7cbf45d15 Update de.php
Fixed a translation issue
2013-04-17 11:53:17 +03:00
Bart Visscher
05a2f31352 Merge pull request #2960 from owncloud/always_load_file_cache_hooks_first_stable5
always connect file cache updater hooks first
2013-04-17 00:32:45 -07:00
Jörn Friedrich Dreyer
811d649262 always connect file cache updater hooks first 2013-04-17 08:21:33 +02:00
Frank Karlitschek
6e32fc1db7 Merge pull request #2945 from owncloud/improved_quota_calc
Improved free space calculation for trash and versions
2013-04-16 19:55:32 -07:00
Björn Schießle
e718a728c4 adapt free space calculation to the way it is done for the trash bin 2013-04-16 13:52:46 +02:00
Björn Schießle
a065ae5db2 improved free space calculation if no quota is set, discussed in #2936 2013-04-16 13:51:53 +02:00
Bernhard Posselt
623db8549e also show black background on links that are active, fixes the news app that doesnt show the bg for folders correctly 2013-04-15 21:07:50 +02:00
Jan-Christoph Borchardt
16ef7c62dc Merge pull request #2931 from owncloud/info_message_trash_bin
write a info message to the log if a file gets removed from the trash bin automatically
2013-04-15 11:16:43 -07:00
Björn Schießle
0978ebd195 add explenation of the expire function to the apps description 2013-04-15 11:42:50 +02:00
Björn Schießle
1ddfefed3f write a info message to the log if a file gets removed from the trash bin automatically 2013-04-15 10:34:38 +02:00
Arthur Schiwon
16b62c697f allow Storages to join MountPoint initialization 2013-04-15 10:28:14 +02:00
Jan-Christoph Borchardt
f70b1c1b0d add .disabled class so it can be used for simple a buttons as well 2013-04-14 22:07:07 +02:00
raghunayyar
b400c29944 Add span tag while enabling or disbling apps as well. 2013-04-13 20:08:25 +05:30
Lukas Reschke
86d8b831f2 Add a name to the version parameter
Without an additional name it's nearly impossible to write positive security model based rules since the parameter name isn't defined.
2013-04-13 15:49:15 +02:00
Thomas Mueller
5fbb8b374d more accurate safe_mode check - refs #2258 2013-04-13 01:16:45 +02:00
Bernhard Posselt
0a3e87c890 used oc version 5.0.3 2013-04-13 01:15:35 +02:00
Bernhard Posselt
2220802cdd added yet another test for the verion compare check due to mail 2013-04-13 01:15:35 +02:00
Jan-Christoph Borchardt
0ff7aa4436 add styles for disabled input fields 2013-04-12 19:14:09 +02:00
Jan-Christoph Borchardt
5e817584db use proper sans-serif font-stack 2013-04-12 19:10:20 +02:00
Bernhard Posselt
fbcb4b2673 Merge pull request #2899 from owncloud/stable5-backport-buttonfix
dont overwrite background image when hovering over button
2013-04-12 09:44:13 -07:00
Bernhard Posselt
edae196f34 dont overwrite background image when hovering over button 2013-04-12 15:41:37 +02:00
Bernhard Posselt
11dcc29c0c Merge pull request #2867 from owncloud/cleanup_after_delUser
Cleanup database after del user
2013-04-11 05:00:44 -07:00
Björn Schießle
d068325bdb cleanup the trash bin tables in the database after a user was deleted 2013-04-11 12:37:52 +02:00
Björn Schießle
6dc66e14fb remove used space for versions from db is a user was deleted 2013-04-11 12:36:08 +02:00
raghunayyar
30d5c70180 Using max-width instead of width for filename. 2013-04-11 13:55:31 +05:30
raghunayyar
e9c3caeb9b Adds a fixed width to the filename to prevent horizontal scroll. 2013-04-11 13:55:11 +05:30
raghunayyar
9a0344f1d5 The Opacity for the navigation loads fine for icon and App name. 2013-04-11 11:00:35 +05:30
raghunayyar
33b27362ff Long Application Names are ellipsis correctly. 2013-04-11 10:59:46 +05:30
Frank Karlitschek
15c50017cc 5.0.5 RC1 2013-04-09 20:04:37 +02:00
Frank Karlitschek
c43e33cdf5 5.0.4 2013-04-09 18:01:26 +02:00
Robin Appelman
ef1481c7bb Fix touch for creating new files 2013-04-10 14:52:56 +02:00
Robin Appelman
892d85556b Add the quota change listeners to newly added user entries in the user list 2013-04-10 14:50:42 +02:00
Frank Karlitschek
5fb891e20a Merge pull request #2828 from owncloud/trashbin_fixes
Trashbin fixes
2013-04-10 01:07:17 -07:00
Frank Karlitschek
c241985f04 5.0.4 RC 2013-04-09 16:59:03 +02:00
Lukas Reschke
9a4fe09979 Use a more random source... 2013-04-10 00:15:44 +02:00
Bart Visscher
e26cdc4cdd Suppress the notice from the nullbyte check 2013-04-09 22:20:48 +02:00
Björn Schießle
317b00988a size of the trash bin could be incorrect, remove it for all users to enforce a recalculation during next usage. 2013-04-09 15:27:19 +02:00
Thomas Mueller
9159d55639 fixes #2743 - use public OC_User::getDisplayName instead of OC_User::determineDisplayName 2013-04-09 15:23:35 +02:00
Thomas Mueller
06ab314c15 fixes #2125 - the warning is now displayed with a disabled button 2013-04-09 15:18:19 +02:00
Björn Schießle
f26a4e0b80 only add filesize to trashbin size if the file was moved to the trash bin successfully 2013-04-09 15:16:15 +02:00
Robin Appelman
2c3d66c776 Users: fix "Other.." quota option for the default quota 2013-04-09 15:15:08 +02:00
Frank Karlitschek
aef66e06b3 Merge pull request #2818 from owncloud/fix_versioncheck
fix versioning check
2013-04-09 05:35:46 -07:00
kondou
67a84ad487 Fix #2730
Swap OC.dialogs.alert()'s parameters, so Error is shown
as its title.
2013-04-09 14:20:23 +02:00
Frank Karlitschek
440148aa1f fix versioning check 2013-04-09 13:13:52 +02:00
OpenLarry
b35148bbb6 fixes #2679 2013-04-09 13:02:35 +02:00
Lukas Reschke
5ef8762886 Merge pull request #2786 from owncloud/disable-archive-app
manually disable archive app for stable5 to fix upgrade problems
2013-04-09 03:04:46 -07:00
Thomas Mueller
b52666567a fixes #2792 - only touch if writable 2013-04-09 10:52:06 +02:00
Bernhard Posselt
1e580bf04b manually disable archive app for stable5 to fix upgrade problems 2013-04-08 15:53:43 +02:00
Bart Visscher
2a5599b3e0 Merge pull request #2614 from eMerzh/fix_internet_check
Improve internet connection check with proxy
2013-04-06 09:50:40 -07:00
Bernhard Posselt
f82799cf7d Merge pull request #2741 from owncloud/fix_2650
Make FileCache upgrade more robust, fixes #2650
2013-04-05 12:22:59 -07:00
root
e6d286b449 Proper CSS comment
CSS comments don't work like that.
2013-04-05 17:13:17 +02:00
Arthur Schiwon
dc3a7e09af Make FileCache upgrade more robust, fixes #2650 2013-04-05 11:27:08 +02:00
Lukas Reschke
5add001373 Unescape the update hint
Backport of 8000f9db74ef2890cac74a34132c2550e4be6f11, fixes #2676
2013-04-05 00:41:08 +03:00
Bernhard Posselt
5317e7071e Merge pull request #2680 from owncloud/fix_2666
PostgreSQL compatibility, fixes #2666
2013-04-03 13:06:40 -07:00
Arthur Schiwon
f5592cc88e Typo, fixes #2690 2013-04-03 20:06:33 +02:00
Arthur Schiwon
09f11c2679 PostreSQL compatibility, fixes #2666 2013-04-03 13:04:38 +02:00
Frank Karlitschek
db48f5302a 5.0.3 2013-04-03 00:53:09 +02:00
Bernhard Posselt
4cd4bbd489 Merge pull request #2665 from owncloud/backport-2275-app-styles
manually backport #2275 app styles to stable
2013-04-02 14:24:00 -07:00
Bernhard Posselt
7b42c20180 Merge pull request #2595 from owncloud/fix_part_file_ignoring_stable5
Fix part file ignoring stable5
2013-04-02 14:01:17 -07:00
Jan-Christoph Borchardt
835df6c177 manually backport #2275 app styles to stable 2013-04-02 22:20:46 +02:00
root
5268aadb62 Backport PR #2622 2013-04-02 21:13:09 +02:00
Frank Karlitschek
d7dccfb648 5.0.3 RC1 2013-04-02 19:14:24 +02:00
Frank Karlitschek
cc204a608a Merge pull request #2656 from owncloud/fix_2642
fix upgrade error for instances not upgraded from 4.5
2013-04-02 09:34:29 -07:00
Arthur Schiwon
22c8194cc8 fix upgrade error for instances not upgraded from 4.5 2013-04-02 16:25:12 +02:00
Frank Karlitschek
8231f657d9 Merge pull request #2641 from owncloud/fix_2612
Key must use less then 767 bytes long
2013-04-02 02:58:57 -07:00
Arthur Schiwon
4f9f5a41b1 Key must use less then 767 bytes long 2013-04-02 11:29:41 +02:00
Frank Karlitschek
5944ee6ebe 5.0.2 2013-04-02 11:23:47 +02:00
VicDeo
e1b6574ce7 Merge pull request #2625 from owncloud/fix_namespace_in_autoloader_stable5
Fix namespace in autoloader stable5
2013-03-31 06:10:47 -07:00
VicDeo
c16860e648 Remove space before parethesis 2013-03-31 16:51:54 +04:00
Lukas Reschke
d4a492d321 Show a warning in the installer if the used PHP version is vulnerable to the NULL Byte attack 2013-03-31 16:51:29 +04:00
Lukas Reschke
a004266b7c Check if the installed PHP version has a fix for the nullbyte vulnerability 2013-03-31 16:51:12 +04:00
Thomas Mueller
da96d1adb0 some basic unit test for loading classes 2013-03-31 16:50:29 +04:00
VicDeo
ed39e47c9d Remove leading and trailing backslashes in classname. Ref #2310 2013-03-31 16:49:43 +04:00
Thomas Tanghus
b9213cf451 User list: Keep array of available groups. Should fix #873 2013-03-29 20:45:35 +01:00
Brice Maron
f308b0e321 Improve internet connection check with proxy 2013-03-29 15:37:39 +00:00
Thomas Mueller
eeebf21fce fixes #1463 - file size is now displayed correctly in IE8 2013-03-29 13:50:53 +01:00
Thomas Mueller
75d944f96a fixes #1461 2013-03-29 13:50:53 +01:00
Jörn Friedrich Dreyer
9bfdfdf071 supress write hook for .part files 2013-03-28 12:21:00 +01:00
Jörn Friedrich Dreyer
2bb22d3aab ignore files in scanFile instead of scan to catch all occurences.
Conflicts:
	lib/files/cache/scanner.php
2013-03-28 12:21:00 +01:00
blizzz
4742d0eb94 Merge pull request #2602 from owncloud/fix_share_with_displayname
Fix share with displayname
2013-03-27 14:54:16 -07:00
Arthur Schiwon
c901709d53 Whitespaces 2013-03-27 21:18:19 +01:00
Arthur Schiwon
84bc4c175a Share Dialog: show Displayname instead of internal name 2013-03-27 21:17:58 +01:00
blizzz
4d50a21eb4 Merge pull request #2558 from owncloud/fix_cache_upgrade
Fix cache upgrade
2013-03-27 11:10:22 -07:00
blizzz
37971133f1 Merge pull request #2596 from owncloud/fix_files_external_displayname
Files External: show display names instead of internal user names in Set...
2013-03-27 11:06:49 -07:00
blizzz
c962f9db47 Merge pull request #2593 from owncloud/fix_userlist_append_displayname
Users: use DisplayName in the Display Name col when appending users
2013-03-27 10:47:52 -07:00
Jan-Christoph Borchardt
6333036a1a Merge pull request #2599 from owncloud/backport-2515-nav-scrollbar
Backport 2515 nav scrollbar
2013-03-27 09:19:06 -07:00
yannickoo
73758c1f78 Fixed typo 2013-03-27 17:13:06 +01:00
yannickoo
7e9e94d8d7 No Scrolling for more than approximately 10 Applications 2013-03-27 17:13:04 +01:00
Arthur Schiwon
07d0245336 Files External: show display names instead of internal user names in Settings UI 2013-03-27 14:33:35 +01:00
Arthur Schiwon
0bbac66ec5 Users: use DisplayName in the Display Name col when appending users 2013-03-27 14:05:00 +01:00
Arthur Schiwon
4411de0dbf Cache: on equal mtime also for equal size before keeping ETag, at least makes Unit Test happy 2013-03-26 23:42:00 +01:00
Thomas Mueller
871bbbba8a prevent to fire delete ajax a second time.
Before the click on a single file delete icon fired two different handlers - one of them is for multiple deletion only
2013-03-26 22:56:42 +01:00
Arthur Schiwon
4384cf70da Cache: Do not overwrite ETag when file did not change 2013-03-26 16:03:40 +01:00
Thomas Müller
e0cf61dfc8 Merge pull request #2272 from owncloud/fix_json_encoded_pubic_download_oc5
let public link download handle json encoded file lists [oc5]
2013-03-26 01:55:40 -07:00
Björn Schießle
2387fbd9dd Merge pull request #2562 from owncloud/update_mtime_after_sync
listen to touch hook to update the mtime after sync
2013-03-26 01:41:41 -07:00
Arthur Schiwon
0b6b5e807c Only prepare an SQL statement once. 2013-03-25 21:46:50 +01:00
Arthur Schiwon
b2b78228d6 Add PHPDoc 2013-03-25 21:45:55 +01:00
Arthur Schiwon
2e5829445f Adjust to Icewind's fix 2013-03-25 21:45:10 +01:00
Robin Appelman
e63a12a481 Cache: fix property path for getting legacy etag 2013-03-25 21:43:51 +01:00
Robin Appelman
56302ff9cf Port Icewind's fix I 2013-03-25 21:43:49 +01:00
Arthur Schiwon
707de3e644 Add Index to properties table for better performance on upgrade 2013-03-25 17:54:45 +01:00
Arthur Schiwon
19a65f6c3f Change LIMIT in DB query respectively remove where not necessary 2013-03-25 17:54:10 +01:00
Björn Schießle
011ab3a11c listen to touch hook to update the mtime after sync 2013-03-25 16:26:17 +01:00
Arthur Schiwon
ad62d89f2b Remove Debug output 2013-03-25 14:23:46 +01:00
Jörn Friedrich Dreyer
9b84c50f15 Merge pull request #2533 from owncloud/fix_sharing_updater
fix shared updated for rename action
2013-03-25 05:13:57 -07:00
Thomas Müller
01ffa519d5 Fixing author and copyright 2013-03-24 19:17:56 +01:00
Thomas Mueller
fe73b5919d some more test cases & fix on file name generation with index 2013-03-24 19:17:56 +01:00
Thomas Mueller
5ad7eb080e adding extension to slugified physical path 2013-03-24 19:17:55 +01:00
Thomas Müller
2ce8329503 Merge pull request #2531 from Mirodin/patch-5
Update de.php
2013-03-24 11:14:33 -07:00
Thomas Müller
83e5383912 Merge pull request #2532 from Mirodin/patch-6
Update de_DE.php
2013-03-24 11:13:25 -07:00
Bernhard Posselt
660d204cbf Merge pull request #2525 from owncloud/fix_db_queries
add backticks around table names
2013-03-23 05:39:01 -07:00
Bernhard Posselt
d091db4bc7 Merge pull request #2474 from owncloud/fix_2299
skip update if the recipient is the same user as the owner
2013-03-23 05:35:50 -07:00
Bernhard Posselt
d61e820285 Merge pull request #2538 from eMerzh/improve_pbm_detect
Improve detection of installations errors
2013-03-23 05:31:19 -07:00
Brice Maron
85613cc66c Improve detection of installations errors 2013-03-23 12:19:43 +01:00
Arthur Schiwon
0fb9cc3c25 Upgrade FileCache on ownCloud upgrade for all users with files 2013-03-22 23:33:40 +01:00
Björn Schießle
76e5ffaa92 the old path no longer exists after rename, update the parent folder instead 2013-03-22 16:20:40 +01:00
Mirodin
9a26b1e0a6 Update de_DE.php
Fixed some translation issues
2013-03-22 15:33:52 +01:00
Mirodin
bfd69dc8e0 Update de.php
Fixed some translation issues
2013-03-22 15:28:20 +01:00
Arthur Schiwon
0d075df15e Performance: prepare queries only once 2013-03-22 13:36:31 +01:00
Arthur Schiwon
c82f43ee55 Fix lost ETag on Cache Upgrade 2013-03-22 13:23:43 +01:00
Björn Schießle
0eaf141528 add backticks around table names 2013-03-22 12:47:43 +01:00
Arthur Schiwon
ee0dab1b13 LDAP: fix wrong return value 2013-03-20 13:17:40 +01:00
Björn Schießle
98ee292c93 fix indention 2013-03-20 12:58:39 +01:00
Björn Schießle
4ff5658475 skip update if the recipient is the same user as the owner, otherwise we run in a infinite loop for group shares 2013-03-20 12:45:24 +01:00
Thomas Mueller
7de540b8ee using rtrim 2013-03-19 17:00:48 +01:00
Thomas Mueller
9a41453254 fixes #2081 2013-03-19 17:00:35 +01:00
Jörn Friedrich Dreyer
707b319157 Merge pull request #2449 from owncloud/fix_npe
fix npe when createStorage() returns null
2013-03-19 07:48:54 -07:00
Bernhard Posselt
f7911412e0 Merge pull request #2444 from owncloud/fix_ldap_issues
Fix ldap issues
2013-03-19 06:20:33 -07:00
Jörn Friedrich Dreyer
1cb3872df0 fix npe when createStorage() returns null 2013-03-19 14:18:44 +01:00
Arthur Schiwon
432fb55d91 LDAP: specify appid when selecting from appconfig 2013-03-19 13:39:52 +01:00
Arthur Schiwon
98c5d10bb5 LDAP: remove unnecessary func call, was a leftover from earlier refactor 2013-03-19 13:29:09 +01:00
Thomas Tanghus
84a2be1aad Backport #2440 js parameter. 2013-03-19 13:13:11 +01:00
Thomas Tanghus
9e383db75b User list: Avoid dupes and better sorting. Fix #2420 2013-03-19 12:59:32 +01:00
Arthur Schiwon
c12b30f7a2 LDAP: check first whether group exists in this backend before doing other operations 2013-03-19 11:52:35 +01:00
Arthur Schiwon
5bf111e75f LDAP: check whether user exists for before trying to determine displayname 2013-03-19 11:16:57 +01:00
Arthur Schiwon
f42d98edab LDAP: avoid irritating log output 2013-03-19 00:23:59 +01:00
Arthur Schiwon
d392aa81c7 LDAP: user exists check on getHome, otherwise check will be performed with wrong configs on a multi LDAP server setup. 2013-03-19 00:23:35 +01:00
Frank Karlitschek
532e5463db backport https://github.com/owncloud/core/pull/2411 2013-03-17 22:17:24 +01:00
Robin Appelman
cfea3ce2d7 Cache: better rename hook for cache updater 2013-03-17 14:16:13 +01:00
Robin Appelman
2c76ee1c8b Close sessions when doing background jobs 2013-03-17 02:25:21 +01:00
Michael Gapczynski
9a2c1cbcc3 Merge pull request #2384 from owncloud/error-handling-upgrade-backport
Backport add error handling to the file cache upgrade
2013-03-16 13:17:01 -07:00
Michael Gapczynski
e6616ed758 Add error handling to the file cache upgrade 2013-03-16 15:22:27 -04:00
Ceri Davies
b51b41468d Correct emails when folders are shared.
itemType is never "dir"; it's either "file" or "folder".
2013-03-15 12:43:22 +01:00
Frank Karlitschek
6f86802a48 Merge pull request #2348 from owncloud/fix_version_db_query
Fix db query in versions app, add backticks
2013-03-15 03:37:35 -07:00
Björn Schießle
0c6c175d62 remove backticks around table names 2013-03-15 11:24:13 +01:00
Brice Maron
885b81ba23 Add backtick for trash app to prevent pg errors 2013-03-15 11:19:02 +01:00
Björn Schießle
fc86815a2c add backtick for db queries to prevent postgresql errors 2013-03-15 11:06:51 +01:00
Björn Schießle
6ca2abc108 create new version if the same file is uploaded again over the web interface, approved in #2317 2013-03-15 10:47:19 +01:00
Björn Schießle
0fe2f81a0c create new version if the same file is uploaded again over the web interface 2013-03-15 10:44:27 +01:00
Bernhard Posselt
2cd52e52c8 Merge pull request #2294 from owncloud/use_display_name_in_mail
use display name as sender for private link mails
2013-03-14 05:22:45 -07:00
Björn Schießle
d06fec658c use display name as sender for private link mails 2013-03-14 11:48:04 +01:00
Bernhard Posselt
049329588f Merge pull request #2276 from owncloud/fix_sharing_hooks_oc5
listen to the pre delete hook in the sharing app [oc5]
2013-03-13 10:16:14 -07:00
Jörn Friedrich Dreyer
09d3b9ef26 Merge pull request #2278 from owncloud/fix_2267_master
use OC_DB instead of MDB2
2013-03-13 10:09:39 -07:00
Björn Schießle
92ce2bf89b fix for #2267, use OC_DB instead of MDB2 2013-03-13 16:51:41 +01:00
Björn Schießle
ca93f6e1de don't show share action for the Shared folder, approved pull request #2265 2013-03-13 16:26:20 +01:00
Björn Schießle
d166471a46 we need to listen to the pre delete hook, otherwise the file is already gone 2013-03-13 15:36:02 +01:00
Björn Schießle
896c56996e let public link download handle json encoded file lists 2013-03-13 11:40:46 +01:00
Arthur Schiwon
6017ca5ddd LDAP: compatibility with Novell eDirectory UUID 2013-03-12 20:16:09 +01:00
Thomas Mueller
eedc1e76db enable UTF-8 charset on mssql
disable MDB2_PORTABILITY_EMPTY_TO_NULL for mssql to allow insert of empty string to no null fields
2013-03-12 20:01:40 +01:00
Thomas Mueller
510cbc4ff9 write error message to log file in case insert to file cache failed - took hours to find that the insert failed :-( 2013-03-12 20:01:40 +01:00
Thomas Mueller
9b9497bedf fixing various filesystem/storage unit tests on windows
fixing copy operation on mapper
2013-03-12 19:57:56 +01:00
Thomas Mueller
8846edd919 skip archive tests for now 2013-03-12 19:57:42 +01:00
Thomas Mueller
253f7ec932 adding //IGNORE to iconv to prevent nasty php warnings 2013-03-12 19:57:28 +01:00
Thomas Mueller
8bafcd1414 slug generates uniqid in case the file/folder name contains not one single valid character 2013-03-12 19:56:44 +01:00
Thomas Mueller
40bb805b83 indexed slug should be created based on logic path 2013-03-12 19:56:33 +01:00
icewind1991
00030a6c24 Merge pull request #2248 from otetard/bugfix/fix-public-link-file-sharing
Fix file sharing via public link for one particular file.
2013-03-12 11:49:08 -07:00
Olivier Tétard
2afece459a Fix file sharing via public link for one particular file.
Fix OC_Files::get() to not return the first character of the filename
if only one file is requested.
2013-03-12 11:53:41 +01:00
234 changed files with 10556 additions and 3646 deletions

1
.gitignore vendored
View File

@@ -73,3 +73,4 @@ data-autotest
/tests/coverage*
/tests/autoconfig*
/tests/autotest*
/l10n/.tx/

View File

@@ -32,5 +32,8 @@ RewriteRule ^remote/(.*) remote.php [QSA,L]
AddType image/svg+xml svg svgz
AddEncoding gzip svgz
</IfModule>
<IfModule dir_module>
DirectoryIndex index.php index.html
</IfModule>
AddDefaultCharset utf-8
Options -Indexes

View File

@@ -8,7 +8,7 @@ OCP\JSON::callCheck();
// Get data
$dir = stripslashes($_POST["dir"]);
$files = isset($_POST["file"]) ? stripslashes($_POST["file"]) : stripslashes($_POST["files"]);
$files = isset($_POST["file"]) ? $_POST["file"] : $_POST["files"];
$files = json_decode($files);
$filesWithError = '';

View File

@@ -12,3 +12,10 @@ OCP\App::addNavigationEntry( array( "id" => "files_index",
"name" => $l->t("Files") ));
OC_Search::registerProvider('OC_Search_Provider_File');
// cache hooks must be connected before all other apps.
// since 'files' is always loaded first the hooks need to be connected here
\OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Updater', 'writeHook');
\OC_Hook::connect('OC_Filesystem', 'post_touch', '\OC\Files\Cache\Updater', 'touchHook');
\OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Updater', 'deleteHook');
\OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook');

View File

@@ -84,7 +84,7 @@ table td.filename input.filename { width:100%; cursor:text; }
table td.filename a, table td.login, table td.logout, table td.download, table td.upload, table td.create, table td.delete { padding:.2em .5em .5em 0; }
table td.filename .nametext, .uploadtext, .modified { float:left; padding:.3em 0; }
/* TODO fix usability bug (accidental file/folder selection) */
table td.filename .nametext { overflow:hidden; text-overflow:ellipsis; }
table td.filename .nametext { overflow:hidden; text-overflow:ellipsis; max-width:800px; }
table td.filename .uploadtext { font-weight:normal; margin-left:.5em; }
table td.filename form { font-size:.85em; margin-left:3em; margin-right:3em; }

View File

@@ -22,18 +22,18 @@ var FileActions = {
if (FileActions.actions.all) {
actions = $.extend(actions, FileActions.actions.all);
}
if (mime) {
if (FileActions.actions[mime]) {
actions = $.extend(actions, FileActions.actions[mime]);
if (type) {//type is 'dir' or 'file'
if (FileActions.actions[type]) {
actions = $.extend(actions, FileActions.actions[type]);
}
}
if (mime) {
var mimePart = mime.substr(0, mime.indexOf('/'));
if (FileActions.actions[mimePart]) {
actions = $.extend(actions, FileActions.actions[mimePart]);
}
}
if (type) {//type is 'dir' or 'file'
if (FileActions.actions[type]) {
actions = $.extend(actions, FileActions.actions[type]);
if (FileActions.actions[mime]) {
actions = $.extend(actions, FileActions.actions[mime]);
}
}
var filteredActions = {};
@@ -112,7 +112,8 @@ var FileActions = {
addAction(name, action);
}
});
if(actions.Share){
if(actions.Share && !($('#dir').val() === '/' && file === 'Shared')){
// t('files', 'Share')
addAction('Share', actions.Share);
}

View File

@@ -115,6 +115,11 @@ $(document).ready(function() {
return false;
});
// Trigger cancelling of file upload
$('#uploadprogresswrapper .stop').on('click', function() {
Files.cancelUploads();
});
// Show trash bin
$('#trash a').live('click', function() {
window.location=OC.filePath('files_trashbin', '', 'index.php');
@@ -226,14 +231,14 @@ $(document).ready(function() {
OC.Notification.show(t('files','Your download is being prepared. This might take some time if the files are big.'));
// use special download URL if provided, e.g. for public shared files
if ( (downloadURL = document.getElementById("downloadURL")) ) {
window.location=downloadURL.value+"&download&files="+files;
window.location=downloadURL.value+"&download&files="+encodeURIComponent(fileslist);
} else {
window.location=OC.filePath('files', 'ajax', 'download.php') + '?'+ $.param({ dir: dir, files: fileslist });
}
return false;
});
$('.delete').click(function(event) {
$('.delete-selected').click(function(event) {
var files=getSelectedFiles('name');
event.preventDefault();
FileList.do_delete(files);
@@ -407,7 +412,9 @@ $(document).ready(function() {
$('tr').filterAttr('data-file',file.name).data('mime',file.mime).data('id',file.id);
var size = $('tr').filterAttr('data-file',file.name).find('td.filesize').text();
if(size==t('files','Pending')){
$('tr').filterAttr('data-file',file.name).find('td.filesize').text(file.size);
var sizeElement = $('tr').filterAttr('data-file',file.name).find('td.filesize');
sizeElement.text(simpleFileSize(file.size));
sizeElement.attr('title',humanFileSize(file.size));
}
//TODO update file upload size limit
FileList.loadingDone(file.name, file.id);
@@ -438,7 +445,9 @@ $(document).ready(function() {
$('tr').filterAttr('data-file',file.name).data('mime',file.mime).data('id',file.id);
var size = $('tr').filterAttr('data-file',file.name).find('td.filesize').text();
if(size==t('files','Pending')){
$('tr').filterAttr('data-file',file.name).find('td.filesize').text(file.size);
var sizeElement = $('tr').filterAttr('data-file',file.name).find('td.filesize');
sizeElement.text(simpleFileSize(file.size));
sizeElement.attr('title',humanFileSize(file.size));
}
//TODO update file upload size limit
FileList.loadingDone(file.name, file.id);
@@ -459,6 +468,10 @@ $(document).ready(function() {
// TODO: show nice progress bar in file row
},
progressall: function(e, data) {
//IE < 10 does not fire the necessary events for the progress bar.
if($.browser.msie && parseInt($.browser.version) < 10) {
return;
}
var progress = (data.loaded/data.total)*100;
$('#uploadprogressbar').progressbar('value',progress);
},
@@ -477,6 +490,11 @@ $(document).ready(function() {
if(data.dataType != 'iframe ') {
$('#upload input.stop').hide();
}
//IE < 10 does not fire the necessary events for the progress bar.
if($.browser.msie && parseInt($.browser.version) < 10) {
return;
}
$('#uploadprogressbar').progressbar('value',100);
$('#uploadprogressbar').fadeOut();
}
@@ -637,12 +655,19 @@ $(document).ready(function() {
localName=(localName.match(/:\/\/(.[^/]+)/)[1]).replace('www.','');
}
localName = getUniqueName(localName);
$('#uploadprogressbar').progressbar({value:0});
$('#uploadprogressbar').fadeIn();
//IE < 10 does not fire the necessary events for the progress bar.
if($.browser.msie && parseInt($.browser.version) < 10) {
} else {
$('#uploadprogressbar').progressbar({value:0});
$('#uploadprogressbar').fadeIn();
}
var eventSource=new OC.EventSource(OC.filePath('files','ajax','newfile.php'),{dir:$('#dir').val(),source:name,filename:localName});
eventSource.listen('progress',function(progress){
$('#uploadprogressbar').progressbar('value',progress);
if($.browser.msie && parseInt($.browser.version) < 10) {
} else {
$('#uploadprogressbar').progressbar('value',progress);
}
});
eventSource.listen('success',function(data){
var mime=data.mime;
@@ -839,9 +864,9 @@ var createDragShadow = function(event){
var dir=$('#dir').val();
$(selectedFiles).each(function(i,elem){
var newtr = $('<tr data-dir="'+dir+'" data-filename="'+elem.name+'">'
+'<td class="filename">'+elem.name+'</td><td class="size">'+humanFileSize(elem.size)+'</td>'
+'</tr>');
var newtr = $('<tr/>').attr('data-dir', dir).attr('data-filename', elem.name);
newtr.append($('<td/>').addClass('filename').text(elem.name));
newtr.append($('<td/>').addClass('size').text(humanFileSize(elem.size)));
tbody.append(newtr);
if (elem.type === 'dir') {
newtr.find('td.filename').attr('style','background-image:url('+OC.imagePath('core', 'filetypes/folder.png')+')');

View File

@@ -5,6 +5,8 @@
"No file was uploaded" => "لم يتم ترفيع أي من الملفات",
"Missing a temporary folder" => "المجلد المؤقت غير موجود",
"Files" => "الملفات",
"Share" => "شارك",
"Delete permanently" => "حذف بشكل دائم",
"Delete" => "محذوف",
"Close" => "إغلق",
"Name" => "الاسم",

View File

@@ -3,6 +3,7 @@
"Failed to write to disk" => "Възникна проблем при запис в диска",
"Invalid directory." => "Невалидна директория.",
"Files" => "Файлове",
"Share" => "Споделяне",
"Delete permanently" => "Изтриване завинаги",
"Delete" => "Изтриване",
"Rename" => "Преименуване",

View File

@@ -12,6 +12,7 @@
"Failed to write to disk" => "ডিস্কে লিখতে ব্যর্থ",
"Invalid directory." => "ভুল ডিরেক্টরি",
"Files" => "ফাইল",
"Share" => "ভাগাভাগি কর",
"Delete" => "মুছে ফেল",
"Rename" => "পূনঃনামকরণ",
"Pending" => "মুলতুবি",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "No hi ha prou espai disponible",
"Invalid directory." => "Directori no vàlid.",
"Files" => "Fitxers",
"Share" => "Comparteix",
"Delete permanently" => "Esborra permanentment",
"Delete" => "Suprimeix",
"Rename" => "Reanomena",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Nedostatek dostupného úložného prostoru",
"Invalid directory." => "Neplatný adresář",
"Files" => "Soubory",
"Share" => "Sdílet",
"Delete permanently" => "Trvale odstranit",
"Delete" => "Smazat",
"Rename" => "Přejmenovat",

74
apps/files/l10n/cy_GB.php Normal file
View File

@@ -0,0 +1,74 @@
<?php $TRANSLATIONS = array(
"Could not move %s - File with this name already exists" => "Methwyd symud %s - Mae ffeil gyda'r enw hwn eisoes yn bodoli",
"Could not move %s" => "Methwyd symud %s",
"Unable to rename file" => "Methu ailenwi ffeil",
"No file was uploaded. Unknown error" => "Ni lwythwyd ffeil i fyny. Gwall anhysbys.",
"There is no error, the file uploaded with success" => "Does dim gwall, llwythodd y ffeil i fyny'n llwyddiannus",
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Mae'r ffeil lwythwyd i fyny'n fwy na chyfarwyddeb upload_max_filesize yn php.ini:",
"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Mae'r ffeil lwythwyd i fyny'n fwy na chyfarwyddeb MAX_FILE_SIZE bennwyd yn y ffurflen HTML",
"The uploaded file was only partially uploaded" => "Dim ond yn rhannol y llwythwyd y ffeil i fyny",
"No file was uploaded" => "Ni lwythwyd ffeil i fyny",
"Missing a temporary folder" => "Plygell dros dro yn eisiau",
"Failed to write to disk" => "Methwyd ysgrifennu i'r ddisg",
"Not enough storage available" => "Dim digon o le storio ar gael",
"Invalid directory." => "Cyfeiriadur annilys.",
"Files" => "Ffeiliau",
"Share" => "Rhannu",
"Delete permanently" => "Dileu'n barhaol",
"Delete" => "Dileu",
"Rename" => "Ailenwi",
"Pending" => "I ddod",
"{new_name} already exists" => "{new_name} yn bodoli'n barod",
"replace" => "amnewid",
"suggest name" => "awgrymu enw",
"cancel" => "diddymu",
"replaced {new_name} with {old_name}" => "newidiwyd {new_name} yn lle {old_name}",
"undo" => "dadwneud",
"perform delete operation" => "cyflawni gweithred dileu",
"1 file uploading" => "1 ffeil yn llwytho i fyny",
"files uploading" => "ffeiliau'n llwytho i fyny",
"'.' is an invalid file name." => "Mae '.' yn enw ffeil annilys.",
"File name cannot be empty." => "Does dim hawl cael enw ffeil gwag.",
"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Enw annilys, ni chaniateir, '\\', '/', '<', '>', ':', '\"', '|', '?' na '*'.",
"Your storage is full, files can not be updated or synced anymore!" => "Mae eich storfa'n llawn, ni ellir diweddaru a chydweddu ffeiliau mwyach!",
"Your storage is almost full ({usedSpacePercent}%)" => "Mae eich storfa bron a bod yn llawn ({usedSpacePercent}%)",
"Your download is being prepared. This might take some time if the files are big." => "Wrthi'n paratoi i lwytho i lawr. Gall gymryd peth amser os yw'r ffeiliau'n fawr.",
"Unable to upload your file as it is a directory or has 0 bytes" => "Methu llwytho'ch ffeil i fyny gan ei fod yn gyferiadur neu'n cynnwys 0 beit",
"Not enough space available" => "Dim digon o le ar gael",
"Upload cancelled." => "Diddymwyd llwytho i fyny.",
"File upload is in progress. Leaving the page now will cancel the upload." => "Mae ffeiliau'n cael eu llwytho i fyny. Bydd gadael y dudalen hon nawr yn diddymu'r broses.",
"URL cannot be empty." => "Does dim hawl cael URL gwag.",
"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Enw plygell annilys. Mae'r defnydd o 'Shared' yn cael ei gadw gan Owncloud",
"Error" => "Gwall",
"Name" => "Enw",
"Size" => "Maint",
"Modified" => "Addaswyd",
"1 folder" => "1 blygell",
"{count} folders" => "{count} plygell",
"1 file" => "1 ffeil",
"{count} files" => "{count} ffeil",
"Upload" => "Llwytho i fyny",
"File handling" => "Trafod ffeiliau",
"Maximum upload size" => "Maint mwyaf llwytho i fyny",
"max. possible: " => "mwyaf. posib:",
"Needed for multi-file and folder downloads." => "Angen ar gyfer llwytho mwy nag un ffeil neu blygell i lawr yr un pryd.",
"Enable ZIP-download" => "Galluogi llwytho i lawr ZIP",
"0 is unlimited" => "0 yn ddiderfyn",
"Maximum input size for ZIP files" => "Maint mewnbynnu mwyaf ffeiliau ZIP",
"Save" => "Cadw",
"New" => "Newydd",
"Text file" => "Ffeil destun",
"Folder" => "Plygell",
"From link" => "Dolen o",
"Deleted files" => "Ffeiliau ddilewyd",
"Cancel upload" => "Diddymu llwytho i fyny",
"You dont have write permissions here." => "Nid oes gennych hawliau ysgrifennu fan hyn.",
"Nothing in here. Upload something!" => "Does dim byd fan hyn. Llwythwch rhywbeth i fyny!",
"Download" => "Llwytho i lawr",
"Unshare" => "Dad-rannu",
"Upload too large" => "Maint llwytho i fyny'n rhy fawr",
"The files you are trying to upload exceed the maximum size for file uploads on this server." => "Mae'r ffeiliau rydych yn ceisio llwytho i fyny'n fwy na maint mwyaf llwytho ffeiliau i fyny ar y gweinydd hwn.",
"Files are being scanned, please wait." => "Arhoswch, mae ffeiliau'n cael eu sganio.",
"Current scanning" => "Sganio cyfredol",
"Upgrading filesystem cache..." => "Uwchraddio storfa system ffeiliau..."
);

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Der er ikke nok plads til rådlighed",
"Invalid directory." => "Ugyldig mappe.",
"Files" => "Filer",
"Share" => "Del",
"Delete permanently" => "Slet permanent",
"Delete" => "Slet",
"Rename" => "Omdøb",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Nicht genug Speicherplatz verfügbar",
"Invalid directory." => "Ungültiges Verzeichnis.",
"Files" => "Dateien",
"Share" => "Teilen",
"Delete permanently" => "Permanent löschen",
"Delete" => "Löschen",
"Rename" => "Umbenennen",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Nicht genug Speicher vorhanden.",
"Invalid directory." => "Ungültiges Verzeichnis.",
"Files" => "Dateien",
"Share" => "Teilen",
"Delete permanently" => "Entgültig löschen",
"Delete" => "Löschen",
"Rename" => "Umbenennen",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Μη επαρκής διαθέσιμος αποθηκευτικός χώρος",
"Invalid directory." => "Μη έγκυρος φάκελος.",
"Files" => "Αρχεία",
"Share" => "Διαμοιρασμός",
"Delete permanently" => "Μόνιμη διαγραφή",
"Delete" => "Διαγραφή",
"Rename" => "Μετονομασία",

View File

@@ -12,6 +12,7 @@
"Failed to write to disk" => "Malsukcesis skribo al disko",
"Invalid directory." => "Nevalida dosierujo.",
"Files" => "Dosieroj",
"Share" => "Kunhavigi",
"Delete" => "Forigi",
"Rename" => "Alinomigi",
"Pending" => "Traktotaj",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "No hay suficiente espacio disponible",
"Invalid directory." => "Directorio invalido.",
"Files" => "Archivos",
"Share" => "Compartir",
"Delete permanently" => "Eliminar permanentemente",
"Delete" => "Eliminar",
"Rename" => "Renombrar",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "No hay suficiente capacidad de almacenamiento",
"Invalid directory." => "Directorio invalido.",
"Files" => "Archivos",
"Share" => "Compartir",
"Delete permanently" => "Borrar de manera permanente",
"Delete" => "Borrar",
"Rename" => "Cambiar nombre",

View File

@@ -11,6 +11,7 @@
"Not enough storage available" => "Saadaval pole piisavalt ruumi",
"Invalid directory." => "Vigane kaust.",
"Files" => "Failid",
"Share" => "Jaga",
"Delete permanently" => "Kustuta jäädavalt",
"Delete" => "Kustuta",
"Rename" => "ümber",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Ez dago behar aina leku erabilgarri,",
"Invalid directory." => "Baliogabeko karpeta.",
"Files" => "Fitxategiak",
"Share" => "Elkarbanatu",
"Delete permanently" => "Ezabatu betirako",
"Delete" => "Ezabatu",
"Rename" => "Berrizendatu",

View File

@@ -12,6 +12,7 @@
"Failed to write to disk" => "نوشتن بر روی دیسک سخت ناموفق بود",
"Invalid directory." => "فهرست راهنما نامعتبر می باشد.",
"Files" => "فایل ها",
"Share" => "اشتراک‌گذاری",
"Delete permanently" => "حذف قطعی",
"Delete" => "پاک کردن",
"Rename" => "تغییرنام",

View File

@@ -12,6 +12,7 @@
"Not enough storage available" => "Tallennustilaa ei ole riittävästi käytettävissä",
"Invalid directory." => "Virheellinen kansio.",
"Files" => "Tiedostot",
"Share" => "Jaa",
"Delete permanently" => "Poista pysyvästi",
"Delete" => "Poista",
"Rename" => "Nimeä uudelleen",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Plus assez d'espace de stockage disponible",
"Invalid directory." => "Dossier invalide.",
"Files" => "Fichiers",
"Share" => "Partager",
"Delete permanently" => "Supprimer de façon définitive",
"Delete" => "Supprimer",
"Rename" => "Renommer",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Non hai espazo de almacenamento abondo",
"Invalid directory." => "O directorio é incorrecto.",
"Files" => "Ficheiros",
"Share" => "Compartir",
"Delete permanently" => "Eliminar permanentemente",
"Delete" => "Eliminar",
"Rename" => "Renomear",

View File

@@ -8,6 +8,7 @@
"Missing a temporary folder" => "תיקייה זמנית חסרה",
"Failed to write to disk" => "הכתיבה לכונן נכשלה",
"Files" => "קבצים",
"Share" => "שתף",
"Delete permanently" => "מחק לצמיתות",
"Delete" => "מחיקה",
"Rename" => "שינוי שם",

View File

@@ -6,6 +6,7 @@
"Missing a temporary folder" => "Nedostaje privremena mapa",
"Failed to write to disk" => "Neuspjelo pisanje na disk",
"Files" => "Datoteke",
"Share" => "Podijeli",
"Delete" => "Briši",
"Rename" => "Promjeni ime",
"Pending" => "U tijeku",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Nincs elég szabad hely.",
"Invalid directory." => "Érvénytelen mappa.",
"Files" => "Fájlok",
"Share" => "Megosztás",
"Delete permanently" => "Végleges törlés",
"Delete" => "Törlés",
"Rename" => "Átnevezés",

View File

@@ -3,6 +3,7 @@
"No file was uploaded" => "Nulle file esseva incargate",
"Missing a temporary folder" => "Manca un dossier temporari",
"Files" => "Files",
"Share" => "Compartir",
"Delete" => "Deler",
"Close" => "Clauder",
"Name" => "Nomine",

View File

@@ -6,6 +6,8 @@
"Missing a temporary folder" => "Kehilangan folder temporer",
"Failed to write to disk" => "Gagal menulis ke disk",
"Files" => "Berkas",
"Share" => "Bagikan",
"Delete permanently" => "Hapus secara permanen",
"Delete" => "Hapus",
"Pending" => "Menunggu",
"replace" => "mengganti",

View File

@@ -12,6 +12,7 @@
"Failed to write to disk" => "Tókst ekki að skrifa á disk",
"Invalid directory." => "Ógild mappa.",
"Files" => "Skrár",
"Share" => "Deila",
"Delete" => "Eyða",
"Rename" => "Endurskýra",
"Pending" => "Bíður",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Spazio di archiviazione insufficiente",
"Invalid directory." => "Cartella non valida.",
"Files" => "File",
"Share" => "Condividi",
"Delete permanently" => "Elimina definitivamente",
"Delete" => "Elimina",
"Rename" => "Rinomina",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "ストレージに十分な空き容量がありません",
"Invalid directory." => "無効なディレクトリです。",
"Files" => "ファイル",
"Share" => "共有",
"Delete permanently" => "完全に削除する",
"Delete" => "削除",
"Rename" => "名前の変更",

View File

@@ -6,6 +6,8 @@
"Missing a temporary folder" => "დროებითი საქაღალდე არ არსებობს",
"Failed to write to disk" => "შეცდომა დისკზე ჩაწერისას",
"Files" => "ფაილები",
"Share" => "გაზიარება",
"Delete permanently" => "სრულად წაშლა",
"Delete" => "წაშლა",
"Rename" => "გადარქმევა",
"Pending" => "მოცდის რეჟიმში",

View File

@@ -12,6 +12,7 @@
"Failed to write to disk" => "디스크에 쓰지 못했습니다",
"Invalid directory." => "올바르지 않은 디렉터리입니다.",
"Files" => "파일",
"Share" => "공유",
"Delete" => "삭제",
"Rename" => "이름 바꾸기",
"Pending" => "보류 중",

View File

@@ -6,6 +6,7 @@
"Missing a temporary folder" => "Et feelt en temporären Dossier",
"Failed to write to disk" => "Konnt net op den Disk schreiwen",
"Files" => "Dateien",
"Share" => "Deelen",
"Delete" => "Läschen",
"replace" => "ersetzen",
"cancel" => "ofbriechen",

View File

@@ -6,6 +6,7 @@
"Missing a temporary folder" => "Nėra laikinojo katalogo",
"Failed to write to disk" => "Nepavyko įrašyti į diską",
"Files" => "Failai",
"Share" => "Dalintis",
"Delete" => "Ištrinti",
"Rename" => "Pervadinti",
"Pending" => "Laukiantis",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Nav pietiekami daudz vietas",
"Invalid directory." => "Nederīga direktorija.",
"Files" => "Datnes",
"Share" => "Dalīties",
"Delete permanently" => "Dzēst pavisam",
"Delete" => "Dzēst",
"Rename" => "Pārsaukt",

View File

@@ -8,6 +8,7 @@
"Missing a temporary folder" => "Не постои привремена папка",
"Failed to write to disk" => "Неуспеав да запишам на диск",
"Files" => "Датотеки",
"Share" => "Сподели",
"Delete" => "Избриши",
"Rename" => "Преименувај",
"Pending" => "Чека",

View File

@@ -7,6 +7,7 @@
"Missing a temporary folder" => "Folder sementara hilang",
"Failed to write to disk" => "Gagal untuk disimpan",
"Files" => "fail",
"Share" => "Kongsi",
"Delete" => "Padam",
"Pending" => "Dalam proses",
"replace" => "ganti",

View File

@@ -7,6 +7,7 @@
"Missing a temporary folder" => "Mangler en midlertidig mappe",
"Failed to write to disk" => "Klarte ikke å skrive til disk",
"Files" => "Filer",
"Share" => "Del",
"Delete permanently" => "Slett permanent",
"Delete" => "Slett",
"Rename" => "Omdøp",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Niet genoeg opslagruimte beschikbaar",
"Invalid directory." => "Ongeldige directory.",
"Files" => "Bestanden",
"Share" => "Delen",
"Delete permanently" => "Verwijder definitief",
"Delete" => "Verwijder",
"Rename" => "Hernoem",

View File

@@ -6,6 +6,7 @@
"Missing a temporary folder" => "Un dorsièr temporari manca",
"Failed to write to disk" => "L'escriptura sul disc a fracassat",
"Files" => "Fichièrs",
"Share" => "Parteja",
"Delete" => "Escafa",
"Rename" => "Torna nomenar",
"Pending" => "Al esperar",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Za mało dostępnego miejsca",
"Invalid directory." => "Zła ścieżka.",
"Files" => "Pliki",
"Share" => "Udostępnij",
"Delete permanently" => "Trwale usuń",
"Delete" => "Usuń",
"Rename" => "Zmień nazwę",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Espaço de armazenamento insuficiente",
"Invalid directory." => "Diretório inválido.",
"Files" => "Arquivos",
"Share" => "Compartilhar",
"Delete permanently" => "Excluir permanentemente",
"Delete" => "Excluir",
"Rename" => "Renomear",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Não há espaço suficiente em disco",
"Invalid directory." => "Directório Inválido",
"Files" => "Ficheiros",
"Share" => "Partilhar",
"Delete permanently" => "Eliminar permanentemente",
"Delete" => "Apagar",
"Rename" => "Renomear",

View File

@@ -12,6 +12,7 @@
"Failed to write to disk" => "Eroare la scriere pe disc",
"Invalid directory." => "Director invalid.",
"Files" => "Fișiere",
"Share" => "Partajează",
"Delete" => "Șterge",
"Rename" => "Redenumire",
"Pending" => "În așteptare",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Недостаточно доступного места в хранилище",
"Invalid directory." => "Неправильный каталог.",
"Files" => "Файлы",
"Share" => "Открыть доступ",
"Delete permanently" => "Удалено навсегда",
"Delete" => "Удалить",
"Rename" => "Переименовать",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Недостаточно места в хранилище",
"Invalid directory." => "Неверный каталог.",
"Files" => "Файлы",
"Share" => "Сделать общим",
"Delete permanently" => "Удалить навсегда",
"Delete" => "Удалить",
"Rename" => "Переименовать",

View File

@@ -7,6 +7,7 @@
"Missing a temporary folder" => "තාවකාලික ෆොල්ඩරයක් සොයාගත නොහැක",
"Failed to write to disk" => "තැටිගත කිරීම අසාර්ථකයි",
"Files" => "ගොනු",
"Share" => "බෙදා හදා ගන්න",
"Delete" => "මකන්න",
"Rename" => "නැවත නම් කරන්න",
"replace" => "ප්‍රතිස්ථාපනය කරන්න",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Nedostatok dostupného úložného priestoru",
"Invalid directory." => "Neplatný priečinok",
"Files" => "Súbory",
"Share" => "Zdieľať",
"Delete permanently" => "Zmazať trvalo",
"Delete" => "Odstrániť",
"Rename" => "Premenovať",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Na voljo ni dovolj prostora",
"Invalid directory." => "Neveljavna mapa.",
"Files" => "Datoteke",
"Share" => "Souporaba",
"Delete permanently" => "Izbriši trajno",
"Delete" => "Izbriši",
"Rename" => "Preimenuj",

74
apps/files/l10n/sq.php Normal file
View File

@@ -0,0 +1,74 @@
<?php $TRANSLATIONS = array(
"Could not move %s - File with this name already exists" => "%s nuk u spostua - Aty ekziston një skedar me të njëjtin emër",
"Could not move %s" => "%s nuk u spostua",
"Unable to rename file" => "Nuk është i mundur riemërtimi i skedarit",
"No file was uploaded. Unknown error" => "Nuk u ngarkua asnjë skedar. Veprim i gabuar i panjohur",
"There is no error, the file uploaded with success" => "Nuk pati veprime të gabuara, skedari u ngarkua me sukses",
"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Skedari i ngarkuar tejkalon udhëzimin upload_max_filesize tek php.ini:",
"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Skedari i ngarkuar tejkalon udhëzimin MAX_FILE_SIZE të specifikuar në formularin HTML",
"The uploaded file was only partially uploaded" => "Skedari i ngarkuar u ngarkua vetëm pjesërisht",
"No file was uploaded" => "Nuk u ngarkua asnjë skedar",
"Missing a temporary folder" => "Një dosje e përkohshme nuk u gjet",
"Failed to write to disk" => "Ruajtja në disk dështoi",
"Not enough storage available" => "Nuk ka mbetur hapësirë memorizimi e mjaftueshme",
"Invalid directory." => "Dosje e pavlefshme.",
"Files" => "Skedarët",
"Share" => "Nda",
"Delete permanently" => "Elimino përfundimisht",
"Delete" => "Elimino",
"Rename" => "Riemërto",
"Pending" => "Pezulluar",
"{new_name} already exists" => "{new_name} ekziston",
"replace" => "zëvëndëso",
"suggest name" => "sugjero një emër",
"cancel" => "anulo",
"replaced {new_name} with {old_name}" => "U zëvëndësua {new_name} me {old_name}",
"undo" => "anulo",
"perform delete operation" => "ekzekuto operacionin e eliminimit",
"1 file uploading" => "Po ngarkohet 1 skedar",
"files uploading" => "po ngarkoj skedarët",
"'.' is an invalid file name." => "'.' është emër i pavlefshëm.",
"File name cannot be empty." => "Emri i skedarit nuk mund të jetë bosh.",
"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Emër i pavlefshëm, '\\', '/', '<', '>', ':', '\"', '|', '?' dhe '*' nuk lejohen.",
"Your storage is full, files can not be updated or synced anymore!" => "Hapësira juaj e memorizimit është plot, nuk mund të ngarkoni apo sinkronizoni më skedarët.",
"Your storage is almost full ({usedSpacePercent}%)" => "Hapësira juaj e memorizimit është gati plot ({usedSpacePercent}%)",
"Your download is being prepared. This might take some time if the files are big." => "Shkarkimi juaj po përgatitet. Mund të duhet pak kohë nqse skedarët janë të mëdhenj.",
"Unable to upload your file as it is a directory or has 0 bytes" => "Nuk është i mundur ngarkimi i skedarit tuaj sepse është dosje ose ka dimension 0 byte",
"Not enough space available" => "Nuk ka hapësirë memorizimi e mjaftueshme",
"Upload cancelled." => "Ngarkimi u anulua.",
"File upload is in progress. Leaving the page now will cancel the upload." => "Ngarkimi i skedarit është në vazhdim. Nqse ndërroni faqen tani ngarkimi do të anulohet.",
"URL cannot be empty." => "URL-i nuk mund të jetë bosh.",
"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Emri i dosjes është i pavlefshëm. Përdorimi i \"Shared\" është i rezervuar nga Owncloud-i.",
"Error" => "Veprim i gabuar",
"Name" => "Emri",
"Size" => "Dimensioni",
"Modified" => "Modifikuar",
"1 folder" => "1 dosje",
"{count} folders" => "{count} dosje",
"1 file" => "1 skedar",
"{count} files" => "{count} skedarë",
"Upload" => "Ngarko",
"File handling" => "Trajtimi i skedarit",
"Maximum upload size" => "Dimensioni maksimal i ngarkimit",
"max. possible: " => "maks. i mundur:",
"Needed for multi-file and folder downloads." => "Duhet për shkarkimin e dosjeve dhe të skedarëve",
"Enable ZIP-download" => "Aktivizo shkarkimin e ZIP-eve",
"0 is unlimited" => "0 është i pakufizuar",
"Maximum input size for ZIP files" => "Dimensioni maksimal i ngarkimit të skedarëve ZIP",
"Save" => "Ruaj",
"New" => "I ri",
"Text file" => "Skedar teksti",
"Folder" => "Dosje",
"From link" => "Nga lidhja",
"Deleted files" => "Skedarë të eliminuar",
"Cancel upload" => "Anulo ngarkimin",
"You dont have write permissions here." => "Nuk keni të drejta për të shkruar këtu.",
"Nothing in here. Upload something!" => "Këtu nuk ka asgjë. Ngarkoni diçka!",
"Download" => "Shkarko",
"Unshare" => "Hiq ndarjen",
"Upload too large" => "Ngarkimi është shumë i madh",
"The files you are trying to upload exceed the maximum size for file uploads on this server." => "Skedarët që doni të ngarkoni tejkalojnë dimensionet maksimale për ngarkimet në këtë server.",
"Files are being scanned, please wait." => "Skedarët po analizohen, ju lutemi pritni.",
"Current scanning" => "Analizimi aktual",
"Upgrading filesystem cache..." => "Po përmirësoj memorjen e filesystem-it..."
);

View File

@@ -7,6 +7,8 @@
"Missing a temporary folder" => "Недостаје привремена фасцикла",
"Failed to write to disk" => "Не могу да пишем на диск",
"Files" => "Датотеке",
"Share" => "Дели",
"Delete permanently" => "Обриши за стално",
"Delete" => "Обриши",
"Rename" => "Преименуј",
"Pending" => "На чекању",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Inte tillräckligt med lagringsutrymme tillgängligt",
"Invalid directory." => "Felaktig mapp.",
"Files" => "Filer",
"Share" => "Dela",
"Delete permanently" => "Radera permanent",
"Delete" => "Radera",
"Rename" => "Byt namn",

View File

@@ -7,6 +7,7 @@
"Missing a temporary folder" => "ஒரு தற்காலிகமான கோப்புறையை காணவில்லை",
"Failed to write to disk" => "வட்டில் எழுத முடியவில்லை",
"Files" => "கோப்புகள்",
"Share" => "பகிர்வு",
"Delete" => "அழிக்க",
"Rename" => "பெயர்மாற்றம்",
"Pending" => "நிலுவையிலுள்ள",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "เหลือพื้นที่ไม่เพียงสำหรับใช้งาน",
"Invalid directory." => "ไดเร็กทอรี่ไม่ถูกต้อง",
"Files" => "ไฟล์",
"Share" => "แชร์",
"Delete" => "ลบ",
"Rename" => "เปลี่ยนชื่อ",
"Pending" => "อยู่ระหว่างดำเนินการ",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Yeterli disk alanı yok",
"Invalid directory." => "Geçersiz dizin.",
"Files" => "Dosyalar",
"Share" => "Paylaş",
"Delete permanently" => "Kalıcı olarak sil",
"Delete" => "Sil",
"Rename" => "İsim değiştir.",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Місця більше немає",
"Invalid directory." => "Невірний каталог.",
"Files" => "Файли",
"Share" => "Поділитися",
"Delete permanently" => "Видалити назавжди",
"Delete" => "Видалити",
"Rename" => "Перейменувати",

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "Không đủ không gian lưu trữ",
"Invalid directory." => "Thư mục không hợp lệ",
"Files" => "Tập tin",
"Share" => "Chia sẻ",
"Delete permanently" => "Xóa vĩnh vễn",
"Delete" => "Xóa",
"Rename" => "Sửa tên",

View File

@@ -7,6 +7,7 @@
"Missing a temporary folder" => "丢失了一个临时文件夹",
"Failed to write to disk" => "写磁盘失败",
"Files" => "文件",
"Share" => "分享",
"Delete" => "删除",
"Rename" => "重命名",
"Pending" => "Pending",

View File

@@ -12,6 +12,8 @@
"Failed to write to disk" => "写入磁盘失败",
"Invalid directory." => "无效文件夹。",
"Files" => "文件",
"Share" => "分享",
"Delete permanently" => "永久删除",
"Delete" => "删除",
"Rename" => "重命名",
"Pending" => "操作等待中",

12
apps/files/l10n/zh_HK.php Normal file
View File

@@ -0,0 +1,12 @@
<?php $TRANSLATIONS = array(
"Files" => "文件",
"Share" => "分享",
"Delete" => "刪除",
"Error" => "錯誤",
"Name" => "名稱",
"{count} folders" => "{}文件夾",
"Upload" => "上傳",
"Save" => "儲存",
"Download" => "下載",
"Unshare" => "取消分享"
);

View File

@@ -13,6 +13,7 @@
"Not enough storage available" => "儲存空間不足",
"Invalid directory." => "無效的資料夾。",
"Files" => "檔案",
"Share" => "分享",
"Delete permanently" => "永久刪除",
"Delete" => "刪除",
"Rename" => "重新命名",

View File

@@ -32,7 +32,7 @@
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[]'/>
<a href="#" class="svg" onclick="return false;"></a>
<a href="#" class="svg"></a>
</form>
</div>
<?php if ($_['trash'] ): ?>
@@ -44,13 +44,12 @@
<div id="uploadprogressbar"></div>
<input type="button" class="stop" style="display:none"
value="<?php p($l->t('Cancel upload'));?>"
onclick="javascript:Files.cancelUploads();"
/>
</div>
</div>
<div id="file_action_panel"></div>
<?php else:?>
<div class="crumb last"><?php p($l->t('You dont have write permissions here.'))?></div>
<div class="actions"><input type="button" disabled value="<?php p($l->t('You dont have write permissions here.'))?>"></div>
<input type="hidden" name="dir" value="<?php p($_['dir']) ?>" id="dir">
<?php endif;?>
<input type="hidden" name="permissions" value="<?php p($_['permissions']); ?>" id="permissions">
@@ -82,13 +81,13 @@
<?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">
<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">
<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")); ?>" />

View File

@@ -1,5 +1,5 @@
<?php if(count($_["breadcrumb"])):?>
<div class="crumb">
<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>

View File

@@ -0,0 +1,317 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Crypt_Blowfish allows for encryption and decryption on the fly using
* the Blowfish algorithm. Crypt_Blowfish does not require the mcrypt
* PHP extension, it uses only PHP.
* Crypt_Blowfish support encryption/decryption with or without a secret key.
*
*
* PHP versions 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category Encryption
* @package Crypt_Blowfish
* @author Matthew Fonda <mfonda@php.net>
* @copyright 2005 Matthew Fonda
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Blowfish.php,v 1.81 2005/05/30 18:40:36 mfonda Exp $
* @link http://pear.php.net/package/Crypt_Blowfish
*/
require_once 'PEAR.php';
/**
*
* Example usage:
* $bf = new Crypt_Blowfish('some secret key!');
* $encrypted = $bf->encrypt('this is some example plain text');
* $plaintext = $bf->decrypt($encrypted);
* echo "plain text: $plaintext";
*
*
* @category Encryption
* @package Crypt_Blowfish
* @author Matthew Fonda <mfonda@php.net>
* @copyright 2005 Matthew Fonda
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @link http://pear.php.net/package/Crypt_Blowfish
* @version @package_version@
* @access public
*/
class Crypt_Blowfish
{
/**
* P-Array contains 18 32-bit subkeys
*
* @var array
* @access private
*/
var $_P = array();
/**
* Array of four S-Blocks each containing 256 32-bit entries
*
* @var array
* @access private
*/
var $_S = array();
/**
* Mcrypt td resource
*
* @var resource
* @access private
*/
var $_td = null;
/**
* Initialization vector
*
* @var string
* @access private
*/
var $_iv = null;
/**
* Crypt_Blowfish Constructor
* Initializes the Crypt_Blowfish object, and gives a sets
* the secret key
*
* @param string $key
* @access public
*/
function Crypt_Blowfish($key)
{
if (extension_loaded('mcrypt')) {
$this->_td = mcrypt_module_open(MCRYPT_BLOWFISH, '', 'ecb', '');
$this->_iv = mcrypt_create_iv(8, MCRYPT_RAND);
}
$this->setKey($key);
}
/**
* Deprecated isReady method
*
* @return bool
* @access public
* @deprecated
*/
function isReady()
{
return true;
}
/**
* Deprecated init method - init is now a private
* method and has been replaced with _init
*
* @return bool
* @access public
* @deprecated
* @see Crypt_Blowfish::_init()
*/
function init()
{
$this->_init();
}
/**
* Initializes the Crypt_Blowfish object
*
* @access private
*/
function _init()
{
$defaults = new Crypt_Blowfish_DefaultKey();
$this->_P = $defaults->P;
$this->_S = $defaults->S;
}
/**
* Enciphers a single 64 bit block
*
* @param int &$Xl
* @param int &$Xr
* @access private
*/
function _encipher(&$Xl, &$Xr)
{
for ($i = 0; $i < 16; $i++) {
$temp = $Xl ^ $this->_P[$i];
$Xl = ((($this->_S[0][($temp>>24) & 255] +
$this->_S[1][($temp>>16) & 255]) ^
$this->_S[2][($temp>>8) & 255]) +
$this->_S[3][$temp & 255]) ^ $Xr;
$Xr = $temp;
}
$Xr = $Xl ^ $this->_P[16];
$Xl = $temp ^ $this->_P[17];
}
/**
* Deciphers a single 64 bit block
*
* @param int &$Xl
* @param int &$Xr
* @access private
*/
function _decipher(&$Xl, &$Xr)
{
for ($i = 17; $i > 1; $i--) {
$temp = $Xl ^ $this->_P[$i];
$Xl = ((($this->_S[0][($temp>>24) & 255] +
$this->_S[1][($temp>>16) & 255]) ^
$this->_S[2][($temp>>8) & 255]) +
$this->_S[3][$temp & 255]) ^ $Xr;
$Xr = $temp;
}
$Xr = $Xl ^ $this->_P[1];
$Xl = $temp ^ $this->_P[0];
}
/**
* Encrypts a string
*
* @param string $plainText
* @return string Returns cipher text on success, PEAR_Error on failure
* @access public
*/
function encrypt($plainText)
{
if (!is_string($plainText)) {
PEAR::raiseError('Plain text must be a string', 0, PEAR_ERROR_DIE);
}
if (extension_loaded('mcrypt')) {
return mcrypt_generic($this->_td, $plainText);
}
$cipherText = '';
$len = strlen($plainText);
$plainText .= str_repeat(chr(0),(8 - ($len%8))%8);
for ($i = 0; $i < $len; $i += 8) {
list(,$Xl,$Xr) = unpack("N2",substr($plainText,$i,8));
$this->_encipher($Xl, $Xr);
$cipherText .= pack("N2", $Xl, $Xr);
}
return $cipherText;
}
/**
* Decrypts an encrypted string
*
* @param string $cipherText
* @return string Returns plain text on success, PEAR_Error on failure
* @access public
*/
function decrypt($cipherText)
{
if (!is_string($cipherText)) {
PEAR::raiseError('Cipher text must be a string', 1, PEAR_ERROR_DIE);
}
if (extension_loaded('mcrypt')) {
return mdecrypt_generic($this->_td, $cipherText);
}
$plainText = '';
$len = strlen($cipherText);
$cipherText .= str_repeat(chr(0),(8 - ($len%8))%8);
for ($i = 0; $i < $len; $i += 8) {
list(,$Xl,$Xr) = unpack("N2",substr($cipherText,$i,8));
$this->_decipher($Xl, $Xr);
$plainText .= pack("N2", $Xl, $Xr);
}
return $plainText;
}
/**
* Sets the secret key
* The key must be non-zero, and less than or equal to
* 56 characters in length.
*
* @param string $key
* @return bool Returns true on success, PEAR_Error on failure
* @access public
*/
function setKey($key)
{
if (!is_string($key)) {
PEAR::raiseError('Key must be a string', 2, PEAR_ERROR_DIE);
}
$len = strlen($key);
if ($len > 56 || $len == 0) {
PEAR::raiseError('Key must be less than 56 characters and non-zero. Supplied key length: ' . $len, 3, PEAR_ERROR_DIE);
}
if (extension_loaded('mcrypt')) {
mcrypt_generic_init($this->_td, $key, $this->_iv);
return true;
}
require_once 'Blowfish/DefaultKey.php';
$this->_init();
$k = 0;
$data = 0;
$datal = 0;
$datar = 0;
for ($i = 0; $i < 18; $i++) {
$data = 0;
for ($j = 4; $j > 0; $j--) {
$data = $data << 8 | ord($key{$k});
$k = ($k+1) % $len;
}
$this->_P[$i] ^= $data;
}
for ($i = 0; $i <= 16; $i += 2) {
$this->_encipher($datal, $datar);
$this->_P[$i] = $datal;
$this->_P[$i+1] = $datar;
}
for ($i = 0; $i < 256; $i += 2) {
$this->_encipher($datal, $datar);
$this->_S[0][$i] = $datal;
$this->_S[0][$i+1] = $datar;
}
for ($i = 0; $i < 256; $i += 2) {
$this->_encipher($datal, $datar);
$this->_S[1][$i] = $datal;
$this->_S[1][$i+1] = $datar;
}
for ($i = 0; $i < 256; $i += 2) {
$this->_encipher($datal, $datar);
$this->_S[2][$i] = $datal;
$this->_S[2][$i+1] = $datar;
}
for ($i = 0; $i < 256; $i += 2) {
$this->_encipher($datal, $datar);
$this->_S[3][$i] = $datal;
$this->_S[3][$i+1] = $datar;
}
return true;
}
}
?>

View File

@@ -0,0 +1,327 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Crypt_Blowfish allows for encryption and decryption on the fly using
* the Blowfish algorithm. Crypt_Blowfish does not require the mcrypt
* PHP extension, it uses only PHP.
* Crypt_Blowfish support encryption/decryption with or without a secret key.
*
*
* PHP versions 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category Encryption
* @package Crypt_Blowfish
* @author Matthew Fonda <mfonda@php.net>
* @copyright 2005 Matthew Fonda
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: DefaultKey.php,v 1.81 2005/05/30 18:40:37 mfonda Exp $
* @link http://pear.php.net/package/Crypt_Blowfish
*/
/**
* Class containing default key
*
* @category Encryption
* @package Crypt_Blowfish
* @author Matthew Fonda <mfonda@php.net>
* @copyright 2005 Matthew Fonda
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @link http://pear.php.net/package/Crypt_Blowfish
* @version @package_version@
* @access public
*/
class Crypt_Blowfish_DefaultKey
{
var $P = array();
var $S = array();
function Crypt_Blowfish_DefaultKey()
{
$this->P = array(
0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917,
0x9216D5D9, 0x8979FB1B
);
$this->S = array(
array(
0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7,
0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99,
0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16,
0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E,
0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE,
0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013,
0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF,
0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E,
0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60,
0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440,
0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE,
0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A,
0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E,
0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677,
0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193,
0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032,
0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88,
0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239,
0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E,
0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0,
0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3,
0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98,
0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88,
0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE,
0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6,
0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D,
0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B,
0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7,
0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA,
0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463,
0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F,
0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09,
0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3,
0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB,
0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279,
0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,
0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB,
0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82,
0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB,
0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573,
0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0,
0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B,
0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790,
0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8,
0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4,
0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0,
0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7,
0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C,
0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD,
0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1,
0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299,
0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9,
0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477,
0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF,
0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49,
0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF,
0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA,
0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5,
0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41,
0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915,
0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400,
0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915,
0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,
0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A
),
array(
0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623,
0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266,
0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1,
0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E,
0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6,
0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1,
0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E,
0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1,
0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737,
0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8,
0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF,
0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD,
0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701,
0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7,
0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41,
0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331,
0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF,
0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF,
0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E,
0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87,
0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C,
0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2,
0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16,
0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD,
0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B,
0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509,
0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E,
0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3,
0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F,
0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A,
0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4,
0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960,
0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66,
0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28,
0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802,
0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,
0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510,
0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF,
0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14,
0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E,
0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50,
0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7,
0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8,
0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281,
0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99,
0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696,
0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128,
0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73,
0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0,
0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0,
0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105,
0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250,
0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3,
0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285,
0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00,
0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061,
0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB,
0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E,
0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735,
0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC,
0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9,
0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340,
0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,
0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7
),
array(
0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934,
0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068,
0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF,
0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840,
0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45,
0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504,
0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A,
0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB,
0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE,
0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6,
0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42,
0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B,
0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2,
0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB,
0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527,
0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B,
0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33,
0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C,
0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3,
0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC,
0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17,
0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564,
0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B,
0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115,
0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922,
0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728,
0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0,
0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E,
0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37,
0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D,
0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804,
0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B,
0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3,
0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB,
0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D,
0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,
0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350,
0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9,
0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A,
0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE,
0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D,
0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC,
0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F,
0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61,
0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2,
0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9,
0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2,
0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C,
0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E,
0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633,
0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10,
0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169,
0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52,
0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027,
0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5,
0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62,
0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634,
0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76,
0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24,
0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC,
0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4,
0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C,
0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,
0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0
),
array(
0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B,
0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE,
0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B,
0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4,
0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8,
0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6,
0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304,
0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22,
0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4,
0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6,
0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9,
0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59,
0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593,
0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51,
0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28,
0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C,
0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B,
0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28,
0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C,
0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD,
0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A,
0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319,
0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB,
0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F,
0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991,
0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32,
0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680,
0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166,
0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE,
0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB,
0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5,
0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47,
0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370,
0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D,
0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84,
0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,
0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8,
0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD,
0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9,
0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7,
0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38,
0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F,
0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C,
0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525,
0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,
0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442,
0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964,
0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E,
0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8,
0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D,
0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F,
0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299,
0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02,
0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,
0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614,
0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A,
0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6,
0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B,
0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0,
0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060,
0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E,
0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9,
0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,
0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6
)
);
}
}
?>

View File

@@ -0,0 +1,59 @@
<?php
/**
* Copyright (c) 2013, Sam Tuke <samtuke@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*
* @brief Script to handle admin settings for encrypted key recovery
*/
use OCA\Encryption;
\OCP\JSON::checkAdminUser();
\OCP\JSON::checkAppEnabled('files_encryption');
\OCP\JSON::callCheck();
$l = OC_L10N::get('files_encryption');
$return = false;
// Enable recoveryAdmin
$recoveryKeyId = OC_Appconfig::getValue('files_encryption', 'recoveryKeyId');
if (isset($_POST['adminEnableRecovery']) && $_POST['adminEnableRecovery'] === '1') {
$return = \OCA\Encryption\Helper::adminEnableRecovery($recoveryKeyId, $_POST['recoveryPassword']);
// Return success or failure
if ($return) {
\OCP\JSON::success(array('data' => array('message' => $l->t('Recovery key successfully enabled'))));
} else {
\OCP\JSON::error(array(
'data' => array(
'message' => $l->t(
'Could not enable recovery key. Please check your recovery key password!')
)
));
}
// Disable recoveryAdmin
} elseif (
isset($_POST['adminEnableRecovery'])
&& '0' === $_POST['adminEnableRecovery']
) {
$return = \OCA\Encryption\Helper::adminDisableRecovery($_POST['recoveryPassword']);
// Return success or failure
if ($return) {
\OCP\JSON::success(array('data' => array('message' => $l->t('Recovery key successfully disabled'))));
} else {
\OCP\JSON::error(array(
'data' => array(
'message' => $l->t(
'Could not disable recovery key. Please check your recovery key password!')
)
));
}
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* Copyright (c) 2013, Bjoern Schiessle <schiessle@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*
* @brief Script to change recovery key password
*
*/
use OCA\Encryption;
\OCP\JSON::checkAdminUser();
\OCP\JSON::checkAppEnabled('files_encryption');
\OCP\JSON::callCheck();
$l = OC_L10N::get('core');
$return = false;
$oldPassword = $_POST['oldPassword'];
$newPassword = $_POST['newPassword'];
$util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \OCP\User::getUser());
$result = $util->checkRecoveryPassword($oldPassword);
if ($result) {
$keyId = $util->getRecoveryKeyId();
$keyPath = '/owncloud_private_key/' . $keyId . '.private.key';
$view = new \OC\Files\View('/');
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$encryptedRecoveryKey = $view->file_get_contents($keyPath);
$decryptedRecoveryKey = \OCA\Encryption\Crypt::symmetricDecryptFileContent($encryptedRecoveryKey, $oldPassword);
$encryptedRecoveryKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($decryptedRecoveryKey, $newPassword);
$view->file_put_contents($keyPath, $encryptedRecoveryKey);
\OC_FileProxy::$enabled = $proxyStatus;
$return = true;
}
// success or failure
if ($return) {
\OCP\JSON::success(array('data' => array('message' => $l->t('Password successfully changed.'))));
} else {
\OCP\JSON::error(array('data' => array('message' => $l->t('Could not change the password. Maybe the old password was not correct.'))));
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* Copyright (c) 2013, Sam Tuke <samtuke@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*
* @brief Script to handle admin settings for encrypted key recovery
*/
use OCA\Encryption;
\OCP\JSON::checkLoggedIn();
\OCP\JSON::checkAppEnabled('files_encryption');
\OCP\JSON::callCheck();
if (
isset($_POST['userEnableRecovery'])
&& (0 == $_POST['userEnableRecovery'] || '1' === $_POST['userEnableRecovery'])
) {
$userId = \OCP\USER::getUser();
$view = new \OC_FilesystemView('/');
$util = new \OCA\Encryption\Util($view, $userId);
// Save recovery preference to DB
$return = $util->setRecoveryForUser($_POST['userEnableRecovery']);
if ($_POST['userEnableRecovery'] === '1') {
$util->addRecoveryKeys();
} else {
$util->removeRecoveryKeys();
}
} else {
$return = false;
}
// Return success or failure
($return) ? \OCP\JSON::success() : \OCP\JSON::error();

View File

@@ -8,42 +8,50 @@ OC::$CLASSPATH['OCA\Encryption\Stream'] = 'files_encryption/lib/stream.php';
OC::$CLASSPATH['OCA\Encryption\Proxy'] = 'files_encryption/lib/proxy.php';
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';
OC_FileProxy::register( new OCA\Encryption\Proxy() );
OC_FileProxy::register(new OCA\Encryption\Proxy());
// User-related hooks
OCP\Util::connectHook( 'OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login' );
OCP\Util::connectHook( 'OC_User', 'pre_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase' );
// User related hooks
OCA\Encryption\Helper::registerUserHooks();
// Sharing-related hooks
OCP\Util::connectHook( 'OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared' );
OCP\Util::connectHook( 'OCP\Share', 'pre_unshare', 'OCA\Encryption\Hooks', 'preUnshare' );
OCP\Util::connectHook( 'OCP\Share', 'pre_unshareAll', 'OCA\Encryption\Hooks', 'preUnshareAll' );
// Sharing related hooks
OCA\Encryption\Helper::registerShareHooks();
// Webdav-related hooks
OCP\Util::connectHook( 'OC_Webdav_Properties', 'update', 'OCA\Encryption\Hooks', 'updateKeyfile' );
// Filesystem related hooks
OCA\Encryption\Helper::registerFilesystemHooks();
stream_wrapper_register( 'crypt', 'OCA\Encryption\Stream' );
stream_wrapper_register('crypt', 'OCA\Encryption\Stream');
$session = new OCA\Encryption\Session();
// check if we are logged in
if (OCP\User::isLoggedIn()) {
if (
! $session->getPrivateKey( \OCP\USER::getUser() )
&& OCP\User::isLoggedIn()
&& OCA\Encryption\Crypt::mode() == 'server'
) {
// ensure filesystem is loaded
if(!\OC\Files\Filesystem::$loaded) {
\OC_Util::setupFS();
}
// Force the user to log-in again if the encryption key isn't unlocked
// (happens when a user is logged in before the encryption app is
// enabled)
OCP\User::logout();
header( "Location: " . OC::$WEBROOT.'/' );
exit();
$view = new OC_FilesystemView('/');
$session = new \OCA\Encryption\Session($view);
// check if user has a private key
if (
!$session->getPrivateKey(\OCP\USER::getUser())
&& OCA\Encryption\Crypt::mode() === 'server'
) {
// Force the user to log-in again if the encryption key isn't unlocked
// (happens when a user is logged in before the encryption app is
// enabled)
OCP\User::logout();
header("Location: " . OC::$WEBROOT . '/');
exit();
}
}
// Register settings scripts
OCP\App::registerAdmin( 'files_encryption', 'settings' );
OCP\App::registerPersonal( 'files_encryption', 'settings-personal' );
OCP\App::registerAdmin('files_encryption', 'settings-admin');
OCP\App::registerPersonal('files_encryption', 'settings-personal');

View File

@@ -18,6 +18,21 @@
<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>

View File

@@ -2,9 +2,9 @@
<info>
<id>files_encryption</id>
<name>Encryption</name>
<description>Server side encryption of files. Warning: You will lose your data if you enable this App and forget your password. Encryption is not yet compatible with LDAP.</description>
<description>WARNING: This is a preview release of the new ownCloud 5 encryption system. Testing and feedback is very welcome but don't use this in production yet. Encryption is not yet compatible with LDAP.</description>
<licence>AGPL</licence>
<author>Sam Tuke</author>
<author>Sam Tuke, Bjoern Schiessle, Florin Peter</author>
<require>4</require>
<shipped>true</shipped>
<types>

View File

@@ -9,6 +9,57 @@ Encrypted files
[encrypted data string][delimiter][IV][padding]
[anhAAjAmcGXqj1X9g==][00iv00][MSHU5N5gECP7aAg7][xx] (square braces added)
- Directory structure:
- Encrypted user data (catfiles) are stored in the usual /data/user/files dir
- Keyfiles are stored in /data/user/files_encryption/keyfiles
- Sharekey are stored in /data/user/files_encryption/share-files
- File extensions:
- Catfiles have to keep the file extension of the original file, pre-encryption
- Keyfiles use .keyfile
- Sharekeys have .shareKey
Shared files
------------
Shared files have a centrally stored catfile and keyfile, and one sharekey for
each user that shares it.
When sharing is used, a different encryption method is used to encrypt the
keyfile (openssl_seal). Although shared files have a keyfile, its contents
use a different format therefore.
Each time a shared file is edited or deleted, all sharekeys for users sharing
that file must have their sharekeys changed also. The keyfile and catfile
however need only changing in the owners files, as there is only one copy of
these.
Publicly shared files (public links)
------------------------------------
Files shared via public links use a separate system user account called 'ownCloud'. All public files are shared to that user's public key, and the private key is used to access the files when the public link is used in browser.
This means that files shared via public links are accessible only to users who know the shared URL, or to admins who know the 'ownCloud' user password.
Lost password recovery
----------------------
In order to enable users to read their encrypted files in the event of a password loss/reset scenario, administrators can choose to enable a 'recoveryAdmin' account. This is a user that all user files will automatically be shared to of the option is enabled. This allows the recoveryAdmin user to generate new keyfiles for the user. By default the UID of the recoveryAdmin is 'recoveryAdmin'.
OC_FilesystemView
-----------------
files_encryption deals extensively with paths and the filesystem. In order to minimise bugs, it makes calls to filesystem methods in a consistent way: OC_FilesystemView{} objects always use '/' as their root, and specify paths each time particular methods are called. e.g. do this:
$view->file_exists( 'path/to/file' );
Not:
$view->chroot( 'path/to' );
$view->file_exists( 'file' );
Using this convention means that $view objects are more predictable and less likely to break. Problems with paths are the #1 cause of bugs in this app, and consistent $view handling is an important way to prevent them.
Notes
-----
@@ -16,4 +67,11 @@ Notes
- The user passphrase is required in order to set up or upgrade the app. New
keypair generation, and the re-encryption of legacy encrypted files requires
it. Therefore an appinfo/update.php script cannot be used, and upgrade logic
is handled in the login hook listener.
is handled in the login hook listener. Therefore each time the user logs in
their files are scanned to detect unencrypted and legacy encrypted files, and
they are (re)encrypted as necessary. This may present a performance issue; we
need to monitor this.
- When files are saved to ownCloud via WebDAV, a .part file extension is used so
that the file isn't cached before the upload has been completed. .part files
are not compatible with files_encrytion's key management system however, so
we have to always sanitise such paths manually before using them.

View File

@@ -1 +1 @@
0.3
0.4

View File

@@ -0,0 +1,10 @@
/* Copyright (c) 2013, Sam Tuke, <samtuke@owncloud.com>
This file is licensed under the Affero General Public License version 3 or later.
See the COPYING-README file. */
#encryptAllError
, #encryptAllSuccess
, #recoveryEnabledError
, #recoveryEnabledSuccess {
display: none;
}

View File

@@ -23,10 +23,11 @@
namespace OCA\Encryption;
use OC\Files\Filesystem;
/**
* Class for hook specific logic
*/
class Hooks {
// TODO: use passphrase for encrypting private key that is separate to
@@ -36,156 +37,489 @@ class Hooks {
* @brief Startup encryption backend upon user login
* @note This method should never be called for users using client side encryption
*/
public static function login( $params ) {
public static function login($params) {
// Manually initialise Filesystem{} singleton with correct
// fake root path, in order to avoid fatal webdav errors
\OC\Files\Filesystem::init( $params['uid'], $params['uid'] . '/' . 'files' . '/' );
$view = new \OC_FilesystemView( '/' );
// NOTE: disabled because this give errors on webdav!
//\OC\Files\Filesystem::init( $params['uid'], '/' . 'files' . '/' );
$util = new Util( $view, $params['uid'] );
// Check files_encryption infrastructure is ready for action
if ( ! $util->ready() ) {
\OC_Log::write( 'Encryption library', 'User account "' . $params['uid'] . '" is not ready for encryption; configuration started', \OC_Log::DEBUG );
return $util->setupServerSide( $params['password'] );
$view = new \OC_FilesystemView('/');
// ensure filesystem is loaded
if(!\OC\Files\Filesystem::$loaded) {
\OC_Util::setupFS($params['uid']);
}
\OC_FileProxy::$enabled = false;
$encryptedKey = Keymanager::getPrivateKey( $view, $params['uid'] );
\OC_FileProxy::$enabled = true;
$privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] );
$session = new Session();
$session->setPrivateKey( $privateKey, $params['uid'] );
$view1 = new \OC_FilesystemView( '/' . $params['uid'] );
// Set legacy encryption key if it exists, to support
// depreciated encryption system
if (
$view1->file_exists( 'encryption.key' )
&& $encLegacyKey = $view1->file_get_contents( 'encryption.key' )
) {
$plainLegacyKey = Crypt::legacyDecrypt( $encLegacyKey, $params['password'] );
$session->setLegacyKey( $plainLegacyKey );
$util = new Util($view, $params['uid']);
// setup user, if user not ready force relogin
if (Helper::setupUser($util, $params['password']) === false) {
return false;
}
$publicKey = Keymanager::getPublicKey( $view, $params['uid'] );
// Encrypt existing user files:
// This serves to upgrade old versions of the encryption
// app (see appinfo/spec.txt)
if (
$util->encryptAll( $publicKey, '/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password'] )
) {
\OC_Log::write(
'Encryption library', 'Encryption of existing files belonging to "' . $params['uid'] . '" started at login'
, \OC_Log::INFO
);
$encryptedKey = Keymanager::getPrivateKey($view, $params['uid']);
$privateKey = Crypt::symmetricDecryptFileContent($encryptedKey, $params['password']);
$session = new \OCA\Encryption\Session($view);
$session->setPrivateKey($privateKey, $params['uid']);
// Check if first-run file migration has already been performed
$migrationCompleted = $util->getMigrationStatus();
// If migration not yet done
if (!$migrationCompleted) {
$userView = new \OC_FilesystemView('/' . $params['uid']);
// Set legacy encryption key if it exists, to support
// depreciated encryption system
if (
$userView->file_exists('encryption.key')
&& $encLegacyKey = $userView->file_get_contents('encryption.key')
) {
$plainLegacyKey = Crypt::legacyBlockDecrypt($encLegacyKey, $params['password']);
$session->setLegacyKey($plainLegacyKey);
}
// Encrypt existing user files:
// This serves to upgrade old versions of the encryption
// app (see appinfo/spec.txt)
if (
$util->encryptAll('/' . $params['uid'] . '/' . 'files', $session->getLegacyKey(), $params['password'])
) {
\OC_Log::write(
'Encryption library', 'Encryption of existing files belonging to "' . $params['uid'] . '" completed'
, \OC_Log::INFO
);
}
// Register successful migration in DB
$util->setMigrationStatus(1);
}
return true;
}
/**
* @brief setup encryption backend upon user created
* @note This method should never be called for users using client side encryption
*/
public static function postCreateUser($params) {
$view = new \OC_FilesystemView('/');
$util = new Util($view, $params['uid']);
Helper::setupUser($util, $params['password']);
}
/**
* @brief cleanup encryption backend upon user deleted
* @note This method should never be called for users using client side encryption
*/
public static function postDeleteUser($params) {
$view = new \OC_FilesystemView('/');
// cleanup public key
$publicKey = '/public-keys/' . $params['uid'] . '.public.key';
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$view->unlink($publicKey);
\OC_FileProxy::$enabled = $proxyStatus;
}
/**
* @brief Change a user's encryption passphrase
* @param array $params keys: uid, password
*/
public static function setPassphrase( $params ) {
public static function setPassphrase($params) {
// Only attempt to change passphrase if server-side encryption
// is in use (client-side encryption does not have access to
// the necessary keys)
if ( Crypt::mode() == 'server' ) {
$session = new Session();
// Get existing decrypted private key
$privateKey = $session->getPrivateKey();
// Encrypt private key with new user pwd as passphrase
$encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $privateKey, $params['password'] );
// Save private key
Keymanager::setPrivateKey( $encryptedPrivateKey );
// NOTE: Session does not need to be updated as the
// private key has not changed, only the passphrase
// used to decrypt it has changed
}
}
/**
* @brief update the encryption key of the file uploaded by the client
*/
public static function updateKeyfile( $params ) {
if ( Crypt::mode() == 'client' ) {
if ( isset( $params['properties']['key'] ) ) {
$view = new \OC_FilesystemView( '/' );
$userId = \OCP\User::getUser();
Keymanager::setFileKey( $view, $params['path'], $userId, $params['properties']['key'] );
} else {
\OC_Log::write(
'Encryption library', "Client side encryption is enabled but the client doesn't provide a encryption key for the file!"
, \OC_Log::ERROR
);
error_log( "Client side encryption is enabled but the client doesn't provide an encryption key for the file!" );
if (Crypt::mode() === 'server') {
if ($params['uid'] === \OCP\User::getUser()) {
$view = new \OC_FilesystemView('/');
$session = new \OCA\Encryption\Session($view);
// Get existing decrypted private key
$privateKey = $session->getPrivateKey();
// Encrypt private key with new user pwd as passphrase
$encryptedPrivateKey = Crypt::symmetricEncryptFileContent($privateKey, $params['password']);
// Save private key
Keymanager::setPrivateKey($encryptedPrivateKey);
// NOTE: Session does not need to be updated as the
// private key has not changed, only the passphrase
// used to decrypt it has changed
} 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'];
$view = new \OC_FilesystemView('/');
// make sure that the users home is mounted
\OC\Files\Filesystem::initMountPoints($user);
$keypair = Crypt::createKeypair();
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
// Save public key
$view->file_put_contents('/public-keys/' . $user . '.public.key', $keypair['publicKey']);
// Encrypt private key empty passphrase
$encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], $newUserPassword);
// 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;
}
}
}
/**
* @brief
/*
* @brief check if files can be encrypted to every user.
*/
public static function postShared( $params ) {
}
/**
* @brief
* @param $params
*/
public static function preUnshare( $params ) {
// Delete existing catfile
// Generate new catfile and env keys
// Save env keys to user folders
public static function preShared($params) {
$users = array();
$view = new \OC\Files\View('/public-keys/');
switch ($params['shareType']) {
case \OCP\Share::SHARE_TYPE_USER:
$users[] = $params['shareWith'];
break;
case \OCP\Share::SHARE_TYPE_GROUP:
$users = \OC_Group::usersInGroup($params['shareWith']);
break;
}
$error = false;
foreach ($users as $user) {
if (!$view->file_exists($user . '.public.key')) {
$error = true;
break;
}
}
if ($error) // Set flag var 'run' to notify emitting
// script that hook execution failed
{
$params['run']->run = false;
}
// TODO: Make sure files_sharing provides user
// feedback on failed share
}
/**
* @brief
* @brief
*/
public static function preUnshareAll( $params ) {
trigger_error( "preUnshareAll" );
public static function postShared($params) {
// NOTE: $params has keys:
// [itemType] => file
// itemSource -> int, filecache file ID
// [parent] =>
// [itemTarget] => /13
// shareWith -> string, uid of user being shared to
// fileTarget -> path of file being shared
// uidOwner -> owner of the original file being shared
// [shareType] => 0
// [shareWith] => test1
// [uidOwner] => admin
// [permissions] => 17
// [fileSource] => 13
// [fileTarget] => /test8
// [id] => 10
// [token] =>
// [run] => whether emitting script should continue to run
// TODO: Should other kinds of item be encrypted too?
if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
$view = new \OC_FilesystemView('/');
$session = new \OCA\Encryption\Session($view);
$userId = \OCP\User::getUser();
$util = new Util($view, $userId);
$path = $util->fileIdToPath($params['itemSource']);
$share = $util->getParentFromShare($params['id']);
//if parent is set, then this is a re-share action
if ($share['parent'] !== null) {
// get the parent from current share
$parent = $util->getShareParent($params['parent']);
// if parent is file the it is an 1:1 share
if ($parent['item_type'] === 'file') {
// prefix path with Shared
$path = '/Shared' . $parent['file_target'];
} else {
// NOTE: parent is folder but shared was a file!
// we try to rebuild the missing path
// some examples we face here
// user1 share folder1 with user2 folder1 has
// the following structure
// /folder1/subfolder1/subsubfolder1/somefile.txt
// user2 re-share subfolder2 with user3
// user3 re-share somefile.txt user4
// so our path should be
// /Shared/subfolder1/subsubfolder1/somefile.txt
// while user3 is sharing
if ($params['itemType'] === 'file') {
// get target path
$targetPath = $util->fileIdToPath($params['fileSource']);
$targetPathSplit = array_reverse(explode('/', $targetPath));
// init values
$path = '';
$sharedPart = ltrim($parent['file_target'], '/');
// rebuild path
foreach ($targetPathSplit as $pathPart) {
if ($pathPart !== $sharedPart) {
$path = '/' . $pathPart . $path;
} else {
break;
}
}
// prefix path with Shared
$path = '/Shared' . $parent['file_target'] . $path;
} else {
// prefix path with Shared
$path = '/Shared' . $parent['file_target'] . $params['fileTarget'];
}
}
}
$sharingEnabled = \OCP\Share::isEnabled();
// get the path including mount point only if not a shared folder
if(strncmp($path, '/Shared' , strlen('/Shared') !== 0)) {
// get path including the the storage mount point
$path = $util->getPathWithMountPoint($params['itemSource']);
}
// if a folder was shared, get a list of all (sub-)folders
if ($params['itemType'] === 'folder') {
$allFiles = $util->getAllFiles($path);
} else {
$allFiles = array($path);
}
foreach ($allFiles as $path) {
$usersSharing = $util->getSharingUsersArray($sharingEnabled, $path);
$util->setSharedFileKeyfiles($session, $usersSharing, $path);
}
}
}
/**
* @brief
*/
public static function postUnshare($params) {
// NOTE: $params has keys:
// [itemType] => file
// [itemSource] => 13
// [shareType] => 0
// [shareWith] => test1
// [itemParent] =>
if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
$view = new \OC_FilesystemView('/');
$userId = \OCP\User::getUser();
$util = new Util($view, $userId);
$path = $util->fileIdToPath($params['itemSource']);
// check if this is a re-share
if ($params['itemParent']) {
// get the parent from current share
$parent = $util->getShareParent($params['itemParent']);
// get target path
$targetPath = $util->fileIdToPath($params['itemSource']);
$targetPathSplit = array_reverse(explode('/', $targetPath));
// init values
$path = '';
$sharedPart = ltrim($parent['file_target'], '/');
// rebuild path
foreach ($targetPathSplit as $pathPart) {
if ($pathPart !== $sharedPart) {
$path = '/' . $pathPart . $path;
} else {
break;
}
}
// prefix path with Shared
$path = '/Shared' . $parent['file_target'] . $path;
}
// for group shares get a list of the group members
if ($params['shareType'] === \OCP\Share::SHARE_TYPE_GROUP) {
$userIds = \OC_Group::usersInGroup($params['shareWith']);
} else {
if ($params['shareType'] === \OCP\Share::SHARE_TYPE_LINK) {
$userIds = array($util->getPublicShareKeyId());
} else {
$userIds = array($params['shareWith']);
}
}
// get the path including mount point only if not a shared folder
if(strncmp($path, '/Shared' , strlen('/Shared') !== 0)) {
// get path including the the storage mount point
$path = $util->getPathWithMountPoint($params['itemSource']);
}
// if we unshare a folder we need a list of all (sub-)files
if ($params['itemType'] === 'folder') {
$allFiles = $util->getAllFiles( $path );
} else {
$allFiles = array($path);
}
foreach ($allFiles as $path) {
// check if the user still has access to the file, otherwise delete share key
$sharingUsers = $util->getSharingUsersArray(true, $path);
// Unshare every user who no longer has access to the file
$delUsers = array_diff($userIds, $sharingUsers);
// delete share key
Keymanager::delShareKey($view, $delUsers, $path);
}
}
}
/**
* @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
*
* This function is connected to the rename signal of OC_Filesystem and adjust the name and location
* of the stored versions along the actual file
*/
public static function postRename($params) {
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$view = new \OC_FilesystemView('/');
$session = new \OCA\Encryption\Session($view);
$userId = \OCP\User::getUser();
$util = new Util($view, $userId);
// Format paths to be relative to user files dir
$oldKeyfilePath = \OC\Files\Filesystem::normalizePath(
$userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $params['oldpath']);
$newKeyfilePath = \OC\Files\Filesystem::normalizePath(
$userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $params['newpath']);
// add key ext if this is not an folder
if (!$view->is_dir($oldKeyfilePath)) {
$oldKeyfilePath .= '.key';
$newKeyfilePath .= '.key';
// handle share-keys
$localKeyPath = $view->getLocalFile($userId . '/files_encryption/share-keys/' . $params['oldpath']);
$matches = glob(preg_quote($localKeyPath) . '*.shareKey');
foreach ($matches as $src) {
$dst = \OC\Files\Filesystem::normalizePath(str_replace($params['oldpath'], $params['newpath'], $src));
// create destination folder if not exists
if (!file_exists(dirname($dst))) {
mkdir(dirname($dst), 0750, true);
}
rename($src, $dst);
}
} else {
// handle share-keys folders
$oldShareKeyfilePath = \OC\Files\Filesystem::normalizePath(
$userId . '/' . 'files_encryption' . '/' . 'share-keys' . '/' . $params['oldpath']);
$newShareKeyfilePath = \OC\Files\Filesystem::normalizePath(
$userId . '/' . 'files_encryption' . '/' . 'share-keys' . '/' . $params['newpath']);
// create destination folder if not exists
if (!$view->file_exists(dirname($newShareKeyfilePath))) {
$view->mkdir(dirname($newShareKeyfilePath), 0750, true);
}
$view->rename($oldShareKeyfilePath, $newShareKeyfilePath);
}
// Rename keyfile so it isn't orphaned
if ($view->file_exists($oldKeyfilePath)) {
// create destination folder if not exists
if (!$view->file_exists(dirname($newKeyfilePath))) {
$view->mkdir(dirname($newKeyfilePath), 0750, true);
}
$view->rename($oldKeyfilePath, $newKeyfilePath);
}
// build the path to the file
$newPath = '/' . $userId . '/files' . $params['newpath'];
$newPathRelative = $params['newpath'];
if ($util->fixFileSize($newPath)) {
// get sharing app state
$sharingEnabled = \OCP\Share::isEnabled();
// get users
$usersSharing = $util->getSharingUsersArray($sharingEnabled, $newPathRelative);
// update sharing-keys
$util->setSharedFileKeyfiles($session, $usersSharing, $newPathRelative);
}
\OC_FileProxy::$enabled = $proxyStatus;
}
}

View File

@@ -0,0 +1,102 @@
/**
* Copyright (c) 2013, Sam Tuke <samtuke@owncloud.com>, Robin Appelman
* <icewind1991@gmail.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*/
OC.msg={
startSaving:function(selector){
$(selector)
.html( t('settings', 'Saving...') )
.removeClass('success')
.removeClass('error')
.stop(true, true)
.show();
},
finishedSaving:function(selector, data){
if( data.status === "success" ){
$(selector).html( data.data.message )
.addClass('success')
.stop(true, true)
.delay(3000)
.fadeOut(900);
}else{
$(selector).html( data.data.message ).addClass('error');
}
}
};
$(document).ready(function(){
// Trigger ajax on recoveryAdmin status change
var enabledStatus = $('#adminEnableRecovery').val();
$('input:password[name="recoveryPassword"]').keyup(function(event) {
var recoveryPassword = $( '#recoveryPassword' ).val();
var checkedButton = $('input:radio[name="adminEnableRecovery"]:checked').val();
var uncheckedValue = (1+parseInt(checkedButton)) % 2;
if (recoveryPassword != '' ) {
$('input:radio[name="adminEnableRecovery"][value="'+uncheckedValue.toString()+'"]').removeAttr("disabled");
} else {
$('input:radio[name="adminEnableRecovery"][value="'+uncheckedValue.toString()+'"]').attr("disabled", "true");
}
});
$( 'input:radio[name="adminEnableRecovery"]' ).change(
function() {
var recoveryStatus = $( this ).val();
var oldStatus = (1+parseInt(recoveryStatus)) % 2;
var recoveryPassword = $( '#recoveryPassword' ).val();
$.post(
OC.filePath( 'files_encryption', 'ajax', 'adminrecovery.php' )
, { adminEnableRecovery: recoveryStatus, recoveryPassword: recoveryPassword }
, function( result ) {
if (result.status === "error") {
OC.Notification.show(t('admin', result.data.message));
$('input:radio[name="adminEnableRecovery"][value="'+oldStatus.toString()+'"]').attr("checked", "true");
} else {
OC.Notification.hide();
if (recoveryStatus === "0") {
$('button:button[name="submitChangeRecoveryKey"]').attr("disabled", "true");
$('input:password[name="changeRecoveryPassword"]').attr("disabled", "true");
$('input:password[name="changeRecoveryPassword"]').val("");
} else {
$('input:password[name="changeRecoveryPassword"]').removeAttr("disabled");
}
}
}
);
}
);
// change recovery password
$('input:password[name="changeRecoveryPassword"]').keyup(function(event) {
var oldRecoveryPassword = $('input:password[id="oldRecoveryPassword"]').val();
var newRecoveryPassword = $('input:password[id="newRecoveryPassword"]').val();
if (newRecoveryPassword != '' && oldRecoveryPassword != '' ) {
$('button:button[name="submitChangeRecoveryKey"]').removeAttr("disabled");
} else {
$('button:button[name="submitChangeRecoveryKey"]').attr("disabled", "true");
}
});
$('button:button[name="submitChangeRecoveryKey"]').click(function() {
var oldRecoveryPassword = $('input:password[id="oldRecoveryPassword"]').val();
var newRecoveryPassword = $('input:password[id="newRecoveryPassword"]').val();
OC.msg.startSaving('#encryption .msg');
$.post(
OC.filePath( 'files_encryption', 'ajax', 'changeRecoveryPassword.php' )
, { oldPassword: oldRecoveryPassword, newPassword: newRecoveryPassword }
, function( data ) {
if (data.status == "error") {
OC.msg.finishedSaving('#encryption .msg', data);
} else {
OC.msg.finishedSaving('#encryption .msg', data);
}
}
);
});
});

View File

@@ -0,0 +1,60 @@
/**
* Copyright (c) 2013, Sam Tuke <samtuke@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*/
$(document).ready(function(){
// Trigger ajax on recoveryAdmin status change
$( 'input:radio[name="userEnableRecovery"]' ).change(
function() {
// Hide feedback messages in case they're already visible
$('#recoveryEnabledSuccess').hide();
$('#recoveryEnabledError').hide();
var recoveryStatus = $( this ).val();
$.post(
OC.filePath( 'files_encryption', 'ajax', 'userrecovery.php' )
, { userEnableRecovery: recoveryStatus }
, function( data ) {
if ( data.status == "success" ) {
$('#recoveryEnabledSuccess').show();
} else {
$('#recoveryEnabledError').show();
}
}
);
// Ensure page is not reloaded on form submit
return false;
}
);
$("#encryptAll").click(
function(){
// Hide feedback messages in case they're already visible
$('#encryptAllSuccess').hide();
$('#encryptAllError').hide();
var userPassword = $( '#userPassword' ).val();
var encryptAll = $( '#encryptAll' ).val();
$.post(
OC.filePath( 'files_encryption', 'ajax', 'encryptall.php' )
, { encryptAll: encryptAll, userPassword: userPassword }
, function( data ) {
if ( data.status == "success" ) {
$('#encryptAllSuccess').show();
} else {
$('#encryptAllError').show();
}
}
);
// Ensure page is not reloaded on form submit
return false;
}
);
});

View File

@@ -1,19 +0,0 @@
/**
* Copyright (c) 2011, Robin Appelman <icewind1991@gmail.com>
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
*/
$(document).ready(function(){
$('#encryption_blacklist').multiSelect({
oncheck:blackListChange,
onuncheck:blackListChange,
createText:'...'
});
function blackListChange(){
var blackList=$('#encryption_blacklist').val().join(',');
OC.AppConfig.setValue('files_encryption','type_blacklist',blackList);
}
})

View File

@@ -1,4 +1,7 @@
<?php $TRANSLATIONS = array(
"Encryption" => "التشفير",
"File encryption is enabled." => "تشفير الملفات فعال.",
"The following file types will not be encrypted:" => "الملفات الاتية لن يتم تشفيرها:",
"Exclude the following file types from encryption:" => "إستثناء أنواع الملفات الاتية من التشفير: ",
"None" => "لا شيء"
);

View File

@@ -1,7 +1,7 @@
<?php $TRANSLATIONS = array(
"Encryption" => "Encriptatge",
"File encryption is enabled." => "L'encriptació de fitxers està activada.",
"The following file types will not be encrypted:" => "Els tipus de fitxers següents no s'encriptaran:",
"Exclude the following file types from encryption:" => "Exclou els tipus de fitxers següents de l'encriptatge:",
"Encryption" => "Xifrat",
"File encryption is enabled." => "El xifrat de fitxers està activat.",
"The following file types will not be encrypted:" => "Els tipus de fitxers següents no es xifraran:",
"Exclude the following file types from encryption:" => "Exclou els tipus de fitxers següents del xifratge:",
"None" => "Cap"
);

View File

@@ -0,0 +1,7 @@
<?php $TRANSLATIONS = array(
"Encryption" => "Amgryptiad",
"File encryption is enabled." => "Galluogwyd amgryptio ffeiliau.",
"The following file types will not be encrypted:" => "Ni fydd ffeiliau o'r math yma'n cael eu hamgryptio:",
"Exclude the following file types from encryption:" => "Eithrio'r mathau canlynol o ffeiliau rhag cael eu hamgryptio:",
"None" => "Dim"
);

View File

@@ -1,4 +1,7 @@
<?php $TRANSLATIONS = array(
"Encryption" => "رمزگذاری",
"File encryption is enabled." => "رمزنگاری فایلها فعال شد.",
"The following file types will not be encrypted:" => "فایلهای زیر رمزنگاری نخواهند شد:",
"Exclude the following file types from encryption:" => "فایلهای زیر از رمزنگاری نادیده گرفته می شوند:",
"None" => "هیچ‌کدام"
);

View File

@@ -0,0 +1,7 @@
<?php $TRANSLATIONS = array(
"Encryption" => "ენკრიპცია",
"File encryption is enabled." => "ფაილის ენკრიპცია ჩართულია.",
"The following file types will not be encrypted:" => "შემდეგი ფაილური ტიპების ენკრიპცია არ მოხდება:",
"Exclude the following file types from encryption:" => "ამოიღე შემდეგი ფაილის ტიპები ენკრიპციიდან:",
"None" => "არა"
);

View File

@@ -2,6 +2,6 @@
"Encryption" => "Šifriranje",
"File encryption is enabled." => "Šifriranje datotek je omogočeno.",
"The following file types will not be encrypted:" => "Navedene vrste datotek ne bodo šifrirane:",
"Exclude the following file types from encryption:" => "Izloči navedene vrste datotek med šifriranjem:",
"Exclude the following file types from encryption:" => "Ne šifriraj navedenih vrst datotek:",
"None" => "Brez"
);

View File

@@ -0,0 +1,7 @@
<?php $TRANSLATIONS = array(
"Encryption" => "شىفىرلاش",
"File encryption is enabled." => "ھۆججەت شىفىرلاش قوزغىتىلدى.",
"The following file types will not be encrypted:" => "تۆۋەندىكى ھۆججەت تىپلىرى شىفىرلانمايدۇ:",
"Exclude the following file types from encryption:" => "تۆۋەندىكى ھۆججەت تىپلىرى شىفىرلاشنىڭ سىرتىدا:",
"None" => "يوق"
);

View File

@@ -1,4 +1,7 @@
<?php $TRANSLATIONS = array(
"Encryption" => "加密",
"None" => "None"
"File encryption is enabled." => "文件加密已启用.",
"The following file types will not be encrypted:" => "如下的文件类型将不会被加密:",
"Exclude the following file types from encryption:" => "从加密中排除如下的文件类型:",
"None" => ""
);

View File

@@ -0,0 +1,6 @@
<?php $TRANSLATIONS = array(
"Encryption" => "加密",
"File encryption is enabled." => "檔案加密已開啟",
"The following file types will not be encrypted:" => "以下文件類別將不會被加密",
"None" => ""
);

View File

@@ -1,4 +1,7 @@
<?php $TRANSLATIONS = array(
"Encryption" => "加密",
"File encryption is enabled." => "檔案加密已被啟用",
"The following file types will not be encrypted:" => "以下的文件類型不會被加密:",
"Exclude the following file types from encryption:" => "從加密中排除的檔案類型:",
"None" => ""
);

View File

@@ -25,13 +25,8 @@
namespace OCA\Encryption;
require_once 'Crypt_Blowfish/Blowfish.php';
// Todo:
// - Add a setting "Don´t encrypt files larger than xx because of performance"
// - Don't use a password directly as encryption key. but a key which is
// stored on the server and encrypted with the user password. -> change pass
// faster
//require_once '../3rdparty/Crypt_Blowfish/Blowfish.php';
require_once realpath(dirname(__FILE__) . '/../3rdparty/Crypt_Blowfish/Blowfish.php');
/**
* Class for common cryptography functionality
@@ -41,10 +36,10 @@ class Crypt {
/**
* @brief return encryption mode client or server side encryption
* @param string user name (use system wide setting if name=null)
* @param string $user name (use system wide setting if name=null)
* @return string 'client' or 'server'
*/
public static function mode( $user = null ) {
public static function mode($user = null) {
return 'server';
@@ -56,30 +51,33 @@ class Crypt {
*/
public static function createKeypair() {
$res = openssl_pkey_new();
$res = openssl_pkey_new(array('private_key_bits' => 4096));
// Get private key
openssl_pkey_export( $res, $privateKey );
openssl_pkey_export($res, $privateKey);
// Get public key
$publicKey = openssl_pkey_get_details( $res );
$publicKey = openssl_pkey_get_details($res);
$publicKey = $publicKey['key'];
return( array( 'publicKey' => $publicKey, 'privateKey' => $privateKey ) );
return (array(
'publicKey' => $publicKey,
'privateKey' => $privateKey
));
}
/**
* @brief Add arbitrary padding to encrypted data
* @param string $data data to be padded
* @return padded data
* @return string padded data
* @note In order to end up with data exactly 8192 bytes long we must
* add two letters. It is impossible to achieve exactly 8192 length
* blocks with encryption alone, hence padding is added to achieve the
* required length.
*/
public static function addPadding( $data ) {
public static function addPadding($data) {
$padded = $data . 'xx';
@@ -90,13 +88,13 @@ class Crypt {
/**
* @brief Remove arbitrary padding to encrypted data
* @param string $padded padded data to remove padding from
* @return unpadded data on success, false on error
* @return string unpadded data on success, false on error
*/
public static function removePadding( $padded ) {
public static function removePadding($padded) {
if ( substr( $padded, -2 ) == 'xx' ) {
if (substr($padded, -2) === 'xx') {
$data = substr( $padded, 0, -2 );
$data = substr($padded, 0, -2);
return $data;
@@ -111,29 +109,30 @@ class Crypt {
/**
* @brief Check if a file's contents contains an IV and is symmetrically encrypted
* @return true / false
* @param $content
* @return boolean
* @note see also OCA\Encryption\Util->isEncryptedPath()
*/
public static function isCatfile( $content ) {
public static function isCatfileContent($content) {
if ( !$content ) {
if (!$content) {
return false;
}
$noPadding = self::removePadding( $content );
$noPadding = self::removePadding($content);
// Fetch encryption metadata from end of file
$meta = substr( $noPadding, -22 );
$meta = substr($noPadding, -22);
// Fetch IV from end of file
$iv = substr( $meta, -16 );
$iv = substr($meta, -16);
// Fetch identifier from start of metadata
$identifier = substr( $meta, 0, 6 );
$identifier = substr($meta, 0, 6);
if ( $identifier == '00iv00') {
if ($identifier === '00iv00') {
return true;
@@ -150,36 +149,36 @@ class Crypt {
* @param string $path
* @return bool
*/
public static function isEncryptedMeta( $path ) {
public static function isEncryptedMeta($path) {
// TODO: Use DI to get \OC\Files\Filesystem out of here
// Fetch all file metadata from DB
$metadata = \OC\Files\Filesystem::getFileInfo( $path, '' );
$metadata = \OC\Files\Filesystem::getFileInfo($path);
// Return encryption status
return isset( $metadata['encrypted'] ) and ( bool )$metadata['encrypted'];
return isset($metadata['encrypted']) && ( bool )$metadata['encrypted'];
}
/**
* @brief Check if a file is encrypted via legacy system
* @param $data
* @param string $relPath The path of the file, relative to user/data;
* e.g. filename or /Docs/filename, NOT admin/files/filename
* @return true / false
* @return boolean
*/
public static function isLegacyEncryptedContent( $data, $relPath ) {
public static function isLegacyEncryptedContent($data, $relPath) {
// Fetch all file metadata from DB
$metadata = \OC\Files\Filesystem::getFileInfo( $relPath, '' );
$metadata = \OC\Files\Filesystem::getFileInfo($relPath, '');
// If a file is flagged with encryption in DB, but isn't a
// valid content + IV combination, it's probably using the
// legacy encryption system
if (
isset( $metadata['encrypted'] )
and $metadata['encrypted'] === true
and ! self::isCatfile( $data )
if (isset($metadata['encrypted'])
&& $metadata['encrypted'] === true
&& !self::isCatfileContent($data)
) {
return true;
@@ -194,17 +193,20 @@ class Crypt {
/**
* @brief Symmetrically encrypt a string
* @returns encrypted file
* @param $plainContent
* @param $iv
* @param string $passphrase
* @return string encrypted file content
*/
public static function encrypt( $plainContent, $iv, $passphrase = '' ) {
public static function encrypt($plainContent, $iv, $passphrase = '') {
if ( $encryptedContent = openssl_encrypt( $plainContent, 'AES-128-CFB', $passphrase, false, $iv ) ) {
if ($encryptedContent = openssl_encrypt($plainContent, 'AES-128-CFB', $passphrase, false, $iv)) {
return $encryptedContent;
} else {
\OC_Log::write( 'Encryption library', 'Encryption (symmetric) of content failed', \OC_Log::ERROR );
\OCP\Util::writeLog('Encryption library', 'Encryption (symmetric) of content failed', \OCP\Util::ERROR);
return false;
@@ -214,18 +216,21 @@ class Crypt {
/**
* @brief Symmetrically decrypt a string
* @returns decrypted file
* @param $encryptedContent
* @param $iv
* @param $passphrase
* @throws \Exception
* @return string decrypted file content
*/
public static function decrypt( $encryptedContent, $iv, $passphrase ) {
public static function decrypt($encryptedContent, $iv, $passphrase) {
if ( $plainContent = openssl_decrypt( $encryptedContent, 'AES-128-CFB', $passphrase, false, $iv ) ) {
if ($plainContent = openssl_decrypt($encryptedContent, 'AES-128-CFB', $passphrase, false, $iv)) {
return $plainContent;
} else {
throw new \Exception( 'Encryption library: Decryption (symmetric) of content failed' );
throw new \Exception('Encryption library: Decryption (symmetric) of content failed');
}
@@ -237,7 +242,7 @@ class Crypt {
* @param string $iv IV to be concatenated
* @returns string concatenated content
*/
public static function concatIv ( $content, $iv ) {
public static function concatIv($content, $iv) {
$combined = $content . '00iv00' . $iv;
@@ -250,20 +255,20 @@ class Crypt {
* @param string $catFile concatenated data to be split
* @returns array keys: encrypted, iv
*/
public static function splitIv ( $catFile ) {
public static function splitIv($catFile) {
// Fetch encryption metadata from end of file
$meta = substr( $catFile, -22 );
$meta = substr($catFile, -22);
// Fetch IV from end of file
$iv = substr( $meta, -16 );
$iv = substr($meta, -16);
// Remove IV and IV identifier text to expose encrypted content
$encrypted = substr( $catFile, 0, -22 );
$encrypted = substr($catFile, 0, -22);
$split = array(
'encrypted' => $encrypted
, 'iv' => $iv
'encrypted' => $encrypted,
'iv' => $iv
);
return $split;
@@ -272,14 +277,16 @@ class Crypt {
/**
* @brief Symmetrically encrypts a string and returns keyfile content
* @param $plainContent content to be encrypted in keyfile
* @returns encrypted content combined with IV
* @param string $plainContent content to be encrypted in keyfile
* @param string $passphrase
* @return bool|string
* @return string encrypted content combined with IV
* @note IV need not be specified, as it will be stored in the returned keyfile
* and remain accessible therein.
*/
public static function symmetricEncryptFileContent( $plainContent, $passphrase = '' ) {
public static function symmetricEncryptFileContent($plainContent, $passphrase = '') {
if ( !$plainContent ) {
if (!$plainContent) {
return false;
@@ -287,18 +294,18 @@ class Crypt {
$iv = self::generateIv();
if ( $encryptedContent = self::encrypt( $plainContent, $iv, $passphrase ) ) {
if ($encryptedContent = self::encrypt($plainContent, $iv, $passphrase)) {
// Combine content to encrypt with IV identifier and actual IV
$catfile = self::concatIv( $encryptedContent, $iv );
$catfile = self::concatIv($encryptedContent, $iv);
$padded = self::addPadding( $catfile );
$padded = self::addPadding($catfile);
return $padded;
} else {
\OC_Log::write( 'Encryption library', 'Encryption (symmetric) of keyfile content failed', \OC_Log::ERROR );
\OCP\Util::writeLog('Encryption library', 'Encryption (symmetric) of keyfile content failed', \OCP\Util::ERROR);
return false;
@@ -309,31 +316,37 @@ class Crypt {
/**
* @brief Symmetrically decrypts keyfile content
* @param string $source
* @param string $target
* @param string $key the decryption key
* @returns decrypted content
* @param $keyfileContent
* @param string $passphrase
* @throws \Exception
* @return bool|string
* @internal param string $source
* @internal param string $target
* @internal param string $key the decryption key
* @returns string decrypted content
*
* This function decrypts a file
*/
public static function symmetricDecryptFileContent( $keyfileContent, $passphrase = '' ) {
public static function symmetricDecryptFileContent($keyfileContent, $passphrase = '') {
if ( !$keyfileContent ) {
if (!$keyfileContent) {
throw new \Exception( 'Encryption library: no data provided for decryption' );
throw new \Exception('Encryption library: no data provided for decryption');
}
// Remove padding
$noPadding = self::removePadding( $keyfileContent );
$noPadding = self::removePadding($keyfileContent);
// Split into enc data and catfile
$catfile = self::splitIv( $noPadding );
$catfile = self::splitIv($noPadding);
if ( $plainContent = self::decrypt( $catfile['encrypted'], $catfile['iv'], $passphrase ) ) {
if ($plainContent = self::decrypt($catfile['encrypted'], $catfile['iv'], $passphrase)) {
return $plainContent;
} else {
return false;
}
}
@@ -346,15 +359,15 @@ class Crypt {
*
* This function decrypts a file
*/
public static function symmetricEncryptFileContentKeyfile( $plainContent ) {
public static function symmetricEncryptFileContentKeyfile($plainContent) {
$key = self::generateKey();
if( $encryptedContent = self::symmetricEncryptFileContent( $plainContent, $key ) ) {
if ($encryptedContent = self::symmetricEncryptFileContent($plainContent, $key)) {
return array(
'key' => $key
, 'encrypted' => $encryptedContent
'key' => $key,
'encrypted' => $encryptedContent
);
} else {
@@ -368,22 +381,41 @@ class Crypt {
/**
* @brief Create asymmetrically encrypted keyfile content using a generated key
* @param string $plainContent content to be encrypted
* @returns array keys: key, encrypted
* @note symmetricDecryptFileContent() can be used to decrypt files created using this method
*
* This function decrypts a file
* @param array $publicKeys array keys must be the userId of corresponding user
* @returns array keys: keys (array, key = userId), data
* @note symmetricDecryptFileContent() can decrypt files created using this method
*/
public static function multiKeyEncrypt( $plainContent, array $publicKeys ) {
public static function multiKeyEncrypt($plainContent, array $publicKeys) {
// openssl_seal returns false without errors if $plainContent
// is empty, so trigger our own error
if (empty($plainContent)) {
throw new \Exception('Cannot mutliKeyEncrypt empty plain content');
}
// Set empty vars to be set by openssl by reference
$sealed = '';
$envKeys = array();
$shareKeys = array();
$mappedShareKeys = array();
if( openssl_seal( $plainContent, $sealed, $envKeys, $publicKeys ) ) {
if (openssl_seal($plainContent, $sealed, $shareKeys, $publicKeys)) {
$i = 0;
// Ensure each shareKey is labelled with its
// corresponding userId
foreach ($publicKeys as $userId => $publicKey) {
$mappedShareKeys[$userId] = $shareKeys[$i];
$i++;
}
return array(
'keys' => $envKeys
, 'encrypted' => $sealed
'keys' => $mappedShareKeys,
'data' => $sealed
);
} else {
@@ -396,27 +428,31 @@ class Crypt {
/**
* @brief Asymmetrically encrypt a file using multiple public keys
* @param string $plainContent content to be encrypted
* @param $encryptedContent
* @param $shareKey
* @param $privateKey
* @return bool
* @internal param string $plainContent content to be encrypted
* @returns string $plainContent decrypted string
* @note symmetricDecryptFileContent() can be used to decrypt files created using this method
*
* This function decrypts a file
*/
public static function multiKeyDecrypt( $encryptedContent, $envKey, $privateKey ) {
public static function multiKeyDecrypt($encryptedContent, $shareKey, $privateKey) {
if ( !$encryptedContent ) {
if (!$encryptedContent) {
return false;
}
if ( openssl_open( $encryptedContent, $plainContent, $envKey, $privateKey ) ) {
if (openssl_open($encryptedContent, $plainContent, $shareKey, $privateKey)) {
return $plainContent;
} else {
\OC_Log::write( 'Encryption library', 'Decryption (asymmetric) of sealed content failed', \OC_Log::ERROR );
\OCP\Util::writeLog('Encryption library', 'Decryption (asymmetric) of sealed content failed', \OCP\Util::ERROR);
return false;
@@ -425,12 +461,14 @@ class Crypt {
}
/**
* @brief Asymmetrically encrypt a string using a public key
* @returns encrypted file
* @brief Asymetrically encrypt a string using a public key
* @param $plainContent
* @param $publicKey
* @return string encrypted file
*/
public static function keyEncrypt( $plainContent, $publicKey ) {
public static function keyEncrypt($plainContent, $publicKey) {
openssl_public_encrypt( $plainContent, $encryptedContent, $publicKey );
openssl_public_encrypt($plainContent, $encryptedContent, $publicKey);
return $encryptedContent;
@@ -438,110 +476,19 @@ class Crypt {
/**
* @brief Asymetrically decrypt a file using a private key
* @returns decrypted file
* @param $encryptedContent
* @param $privatekey
* @return string decrypted file
*/
public static function keyDecrypt( $encryptedContent, $privatekey ) {
public static function keyDecrypt($encryptedContent, $privatekey) {
openssl_private_decrypt( $encryptedContent, $plainContent, $privatekey );
return $plainContent;
}
/**
* @brief Encrypts content symmetrically and generates keyfile asymmetrically
* @returns array containing catfile and new keyfile.
* keys: data, key
* @note this method is a wrapper for combining other crypt class methods
*/
public static function keyEncryptKeyfile( $plainContent, $publicKey ) {
// Encrypt plain data, generate keyfile & encrypted file
$cryptedData = self::symmetricEncryptFileContentKeyfile( $plainContent );
// Encrypt keyfile
$cryptedKey = self::keyEncrypt( $cryptedData['key'], $publicKey );
return array( 'data' => $cryptedData['encrypted'], 'key' => $cryptedKey );
}
/**
* @brief Takes catfile, keyfile, and private key, and
* performs decryption
* @returns decrypted content
* @note this method is a wrapper for combining other crypt class methods
*/
public static function keyDecryptKeyfile( $catfile, $keyfile, $privateKey ) {
// Decrypt the keyfile with the user's private key
$decryptedKeyfile = self::keyDecrypt( $keyfile, $privateKey );
// Decrypt the catfile symmetrically using the decrypted keyfile
$decryptedData = self::symmetricDecryptFileContent( $catfile, $decryptedKeyfile );
return $decryptedData;
}
/**
* @brief Symmetrically encrypt a file by combining encrypted component data blocks
*/
public static function symmetricBlockEncryptFileContent( $plainContent, $key ) {
$crypted = '';
$remaining = $plainContent;
$testarray = array();
while( strlen( $remaining ) ) {
//echo "\n\n\$block = ".substr( $remaining, 0, 6126 );
// Encrypt a chunk of unencrypted data and add it to the rest
$block = self::symmetricEncryptFileContent( substr( $remaining, 0, 6126 ), $key );
$padded = self::addPadding( $block );
$crypted .= $block;
$testarray[] = $block;
// Remove the data already encrypted from remaining unencrypted data
$remaining = substr( $remaining, 6126 );
$result = @openssl_private_decrypt($encryptedContent, $plainContent, $privatekey);
if ($result) {
return $plainContent;
}
return $crypted;
}
/**
* @brief Symmetrically decrypt a file by combining encrypted component data blocks
*/
public static function symmetricBlockDecryptFileContent( $crypted, $key ) {
$decrypted = '';
$remaining = $crypted;
$testarray = array();
while( strlen( $remaining ) ) {
$testarray[] = substr( $remaining, 0, 8192 );
// Decrypt a chunk of unencrypted data and add it to the rest
$decrypted .= self::symmetricDecryptFileContent( $remaining, $key );
// Remove the data already encrypted from remaining unencrypted data
$remaining = substr( $remaining, 8192 );
}
return $decrypted;
return $result;
}
@@ -551,24 +498,24 @@ class Crypt {
*/
public static function generateIv() {
if ( $random = openssl_random_pseudo_bytes( 12, $strong ) ) {
if ($random = openssl_random_pseudo_bytes(12, $strong)) {
if ( !$strong ) {
if (!$strong) {
// If OpenSSL indicates randomness is insecure, log error
\OC_Log::write( 'Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()', \OC_Log::WARN );
\OCP\Util::writeLog('Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()', \OCP\Util::WARN);
}
// We encode the iv purely for string manipulation
// purposes - it gets decoded before use
$iv = base64_encode( $random );
$iv = base64_encode($random);
return $iv;
} else {
throw new \Exception( 'Generating IV failed' );
throw new \Exception('Generating IV failed');
}
@@ -581,12 +528,12 @@ class Crypt {
public static function generateKey() {
// Generate key
if ( $key = base64_encode( openssl_random_pseudo_bytes( 183, $strong ) ) ) {
if ($key = base64_encode(openssl_random_pseudo_bytes(183, $strong))) {
if ( !$strong ) {
if (!$strong) {
// If OpenSSL indicates randomness is insecure, log error
throw new \Exception ( 'Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()' );
throw new \Exception('Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()');
}
@@ -603,15 +550,15 @@ class Crypt {
/**
* @brief Get the blowfish encryption handeler for a key
* @param $key string (optional)
* @return Crypt_Blowfish blowfish object
* @return \Crypt_Blowfish blowfish object
*
* if the key is left out, the default handeler will be used
*/
public static function getBlowfish( $key = '' ) {
public static function getBlowfish($key = '') {
if ( $key ) {
if ($key) {
return new \Crypt_Blowfish( $key );
return new \Crypt_Blowfish($key);
} else {
@@ -621,13 +568,17 @@ class Crypt {
}
public static function legacyCreateKey( $passphrase ) {
/**
* @param $passphrase
* @return mixed
*/
public static function legacyCreateKey($passphrase) {
// Generate a random integer
$key = mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 );
$key = mt_rand(10000, 99999) . mt_rand(10000, 99999) . mt_rand(10000, 99999) . mt_rand(10000, 99999);
// Encrypt the key with the passphrase
$legacyEncKey = self::legacyEncrypt( $key, $passphrase );
$legacyEncKey = self::legacyEncrypt($key, $passphrase);
return $legacyEncKey;
@@ -635,61 +586,79 @@ class Crypt {
/**
* @brief encrypts content using legacy blowfish system
* @param $content the cleartext message you want to encrypt
* @param $key the encryption key (optional)
* @returns encrypted content
* @param string $content the cleartext message you want to encrypt
* @param string $passphrase
* @returns string encrypted content
*
* This function encrypts an content
*/
public static function legacyEncrypt( $content, $passphrase = '' ) {
public static function legacyEncrypt($content, $passphrase = '') {
$bf = self::getBlowfish( $passphrase );
$bf = self::getBlowfish($passphrase);
return $bf->encrypt( $content );
return $bf->encrypt($content);
}
/**
* @brief decrypts content using legacy blowfish system
* @param $content the cleartext message you want to decrypt
* @param $key the encryption key (optional)
* @returns cleartext content
* @param string $content the cleartext message you want to decrypt
* @param string $passphrase
* @return string cleartext content
*
* This function decrypts an content
*/
public static function legacyDecrypt( $content, $passphrase = '' ) {
private static function legacyDecrypt($content, $passphrase = '') {
$bf = self::getBlowfish( $passphrase );
$bf = self::getBlowfish($passphrase);
$decrypted = $bf->decrypt( $content );
$trimmed = rtrim( $decrypted, "\0" );
return $trimmed;
}
public static function legacyKeyRecryptKeyfile( $legacyEncryptedContent, $legacyPassphrase, $publicKey, $newPassphrase ) {
$decrypted = self::legacyDecrypt( $legacyEncryptedContent, $legacyPassphrase );
$recrypted = self::keyEncryptKeyfile( $decrypted, $publicKey );
return $recrypted;
$decrypted = $bf->decrypt($content);
return $decrypted;
}
/**
* @brief Re-encryptes a legacy blowfish encrypted file using AES with integrated IV
* @param $legacyContent the legacy encrypted content to re-encrypt
* @returns cleartext content
*
* This function decrypts an content
* @param $data
* @param string $key
* @param int $maxLength
* @return string
*/
public static function legacyRecrypt( $legacyContent, $legacyPassphrase, $newPassphrase ) {
public static function legacyBlockDecrypt($data, $key = '', $maxLength = 0) {
// TODO: write me
$result = '';
while (strlen($data)) {
$result .= self::legacyDecrypt(substr($data, 0, 8192), $key);
$data = substr($data, 8192);
}
if ($maxLength > 0) {
return substr($result, 0, $maxLength);
} else {
return rtrim($result, "\0");
}
}
/**
* @param $legacyEncryptedContent
* @param $legacyPassphrase
* @param $publicKeys
* @return array
*/
public static function legacyKeyRecryptKeyfile($legacyEncryptedContent, $legacyPassphrase, $publicKeys) {
$decrypted = self::legacyBlockDecrypt($legacyEncryptedContent, $legacyPassphrase);
// Encrypt plain data, generate keyfile & encrypted file
$cryptedData = self::symmetricEncryptFileContentKeyfile($decrypted);
// Encrypt plain keyfile to multiple sharefiles
$multiEncrypted = Crypt::multiKeyEncrypt($cryptedData['key'], $publicKeys);
return array(
'data' => $cryptedData['encrypted'],
'filekey' => $multiEncrypted['data'],
'sharekeys' => $multiEncrypted['keys']
);
}
}
}

View File

@@ -0,0 +1,203 @@
<?php
/**
* ownCloud
*
* @author Florin Peter
* @copyright 2013 Florin Peter <owncloud@florin-peter.de>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Encryption;
/**
* @brief Class to manage registration of hooks an various helper methods
* @package OCA\Encryption
*/
class Helper {
/**
* @brief register share related hooks
*
*/
public static function registerShareHooks() {
\OCP\Util::connectHook('OCP\Share', 'pre_shared', 'OCA\Encryption\Hooks', 'preShared');
\OCP\Util::connectHook('OCP\Share', 'post_shared', 'OCA\Encryption\Hooks', 'postShared');
\OCP\Util::connectHook('OCP\Share', 'post_unshare', 'OCA\Encryption\Hooks', 'postUnshare');
}
/**
* @brief register user related hooks
*
*/
public static function registerUserHooks() {
\OCP\Util::connectHook('OC_User', 'post_login', 'OCA\Encryption\Hooks', 'login');
\OCP\Util::connectHook('OC_User', 'post_setPassword', 'OCA\Encryption\Hooks', 'setPassphrase');
\OCP\Util::connectHook('OC_User', 'post_createUser', 'OCA\Encryption\Hooks', 'postCreateUser');
\OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OCA\Encryption\Hooks', 'postDeleteUser');
}
/**
* @brief register filesystem related hooks
*
*/
public static function registerFilesystemHooks() {
\OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename');
}
/**
* @brief setup user for files_encryption
*
* @param Util $util
* @param string $password
* @return bool
*/
public static function setupUser($util, $password) {
// Check files_encryption infrastructure is ready for action
if (!$util->ready()) {
\OCP\Util::writeLog('Encryption library', 'User account "' . $util->getUserId()
. '" is not ready for encryption; configuration started', \OCP\Util::DEBUG);
if (!$util->setupServerSide($password)) {
return false;
}
}
return true;
}
/**
* @brief enable recovery
*
* @param $recoveryKeyId
* @param $recoveryPassword
* @internal param \OCA\Encryption\Util $util
* @internal param string $password
* @return bool
*/
public static function adminEnableRecovery($recoveryKeyId, $recoveryPassword) {
$view = new \OC\Files\View('/');
if ($recoveryKeyId === null) {
$recoveryKeyId = 'recovery_' . substr(md5(time()), 0, 8);
\OC_Appconfig::setValue('files_encryption', 'recoveryKeyId', $recoveryKeyId);
}
if (!$view->is_dir('/owncloud_private_key')) {
$view->mkdir('/owncloud_private_key');
}
if (
(!$view->file_exists("/public-keys/" . $recoveryKeyId . ".public.key")
|| !$view->file_exists("/owncloud_private_key/" . $recoveryKeyId . ".private.key"))
) {
$keypair = \OCA\Encryption\Crypt::createKeypair();
\OC_FileProxy::$enabled = false;
// Save public key
if (!$view->is_dir('/public-keys')) {
$view->mkdir('/public-keys');
}
$view->file_put_contents('/public-keys/' . $recoveryKeyId . '.public.key', $keypair['publicKey']);
// Encrypt private key empthy passphrase
$encryptedPrivateKey = \OCA\Encryption\Crypt::symmetricEncryptFileContent($keypair['privateKey'], $recoveryPassword);
// Save private key
$view->file_put_contents('/owncloud_private_key/' . $recoveryKeyId . '.private.key', $encryptedPrivateKey);
// create control file which let us check later on if the entered password was correct.
$encryptedControlData = \OCA\Encryption\Crypt::keyEncrypt("ownCloud", $keypair['publicKey']);
if (!$view->is_dir('/control-file')) {
$view->mkdir('/control-file');
}
$view->file_put_contents('/control-file/controlfile.enc', $encryptedControlData);
\OC_FileProxy::$enabled = true;
// Set recoveryAdmin as enabled
\OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1);
$return = true;
} else { // get recovery key and check the password
$util = new \OCA\Encryption\Util(new \OC_FilesystemView('/'), \OCP\User::getUser());
$return = $util->checkRecoveryPassword($recoveryPassword);
if ($return) {
\OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 1);
}
}
return $return;
}
/**
* @brief disable recovery
*
* @param $recoveryPassword
* @return bool
*/
public static function adminDisableRecovery($recoveryPassword) {
$util = new Util(new \OC_FilesystemView('/'), \OCP\User::getUser());
$return = $util->checkRecoveryPassword($recoveryPassword);
if ($return) {
// Set recoveryAdmin as disabled
\OC_Appconfig::setValue('files_encryption', 'recoveryAdminEnabled', 0);
}
return $return;
}
/**
* @brief checks if access is public/anonymous user
* @return bool
*/
public static function isPublicAccess() {
if (\OCP\USER::getUser() === false
|| (isset($_GET['service']) && $_GET['service'] == 'files'
&& isset($_GET['t']))
) {
return true;
} else {
return false;
}
}
/**
* @brief Format a path to be relative to the /user/files/ directory
* @param string $path the absolute path
* @return string e.g. turns '/admin/files/test.txt' into 'test.txt'
*/
public static function stripUserFilesPath($path) {
$trimmed = ltrim($path, '/');
$split = explode('/', $trimmed);
$sliced = array_slice($split, 2);
$relPath = implode('/', $sliced);
return $relPath;
}
}

View File

@@ -28,19 +28,26 @@ namespace OCA\Encryption;
* @note Where a method requires a view object, it's root must be '/'
*/
class Keymanager {
/**
* @brief retrieve the ENCRYPTED private key from a user
*
* @return string private key or false
*
* @param \OC_FilesystemView $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 ) {
$path = '/' . $user . '/' . 'files_encryption' . '/' . $user.'.private.key';
$key = $view->file_get_contents( $path );
public static function getPrivateKey(\OC_FilesystemView $view, $user) {
$path = '/' . $user . '/' . 'files_encryption' . '/' . $user . '.private.key';
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$key = $view->file_get_contents($path);
\OC_FileProxy::$enabled = $proxyStatus;
return $key;
}
@@ -50,102 +57,152 @@ class Keymanager {
* @param $userId
* @return string public key or false
*/
public static function getPublicKey( \OC_FilesystemView $view, $userId ) {
return $view->file_get_contents( '/public-keys/' . '/' . $userId . '.public.key' );
public static function getPublicKey(\OC_FilesystemView $view, $userId) {
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$result = $view->file_get_contents('/public-keys/' . $userId . '.public.key');
\OC_FileProxy::$enabled = $proxyStatus;
return $result;
}
/**
* @brief retrieve both keys from a user (private and public)
* @brief Retrieve a user's public and private key
* @param \OC_FilesystemView $view
* @param $userId
* @return array keys: privateKey, publicKey
*/
public static function getUserKeys( \OC_FilesystemView $view, $userId ) {
return array(
'publicKey' => self::getPublicKey( $view, $userId )
, 'privateKey' => self::getPrivateKey( $view, $userId )
);
}
/**
* @brief Retrieve public keys of all users with access to a file
* @param string $path Path to file
* @return array of public keys for the given file
* @note Checks that the sharing app is enabled should be performed
* by client code, that isn't checked here
*/
public static function getPublicKeys( \OC_FilesystemView $view, $userId, $filePath ) {
$path = ltrim( $path, '/' );
$filepath = '/' . $userId . '/files/' . $filePath;
// Check if sharing is enabled
if ( OC_App::isEnabled( 'files_sharing' ) ) {
public static function getUserKeys(\OC_FilesystemView $view, $userId) {
return array(
'publicKey' => self::getPublicKey($view, $userId),
'privateKey' => self::getPrivateKey($view, $userId)
);
} else {
// check if it is a file owned by the user and not shared at all
$userview = new \OC_FilesystemView( '/'.$userId.'/files/' );
if ( $userview->file_exists( $path ) ) {
$users[] = $userId;
}
}
$view = new \OC_FilesystemView( '/public-keys/' );
$keylist = array();
$count = 0;
foreach ( $users as $user ) {
$keylist['key'.++$count] = $view->file_get_contents( $user.'.public.key' );
}
return $keylist;
}
/**
* @brief Retrieve public keys for given users
* @param \OC_FilesystemView $view
* @param array $userIds
* @return array of public keys for the specified users
*/
public static function getPublicKeys(\OC_FilesystemView $view, array $userIds) {
$keys = array();
foreach ($userIds as $userId) {
$keys[$userId] = self::getPublicKey($view, $userId);
}
return $keys;
}
/**
* @brief store file encryption key
*
* @param \OC_FilesystemView $view
* @param string $path relative path of the file, including filename
* @param string $key
* @param $userId
* @param $catfile
* @internal param string $key
* @return bool true/false
* @note The keyfile is not encrypted here. Client code must
* @note The keyfile is not encrypted here. Client code must
* asymmetrically encrypt the keyfile before passing it to this method
*/
public static function setFileKey( \OC_FilesystemView $view, $path, $userId, $catfile ) {
$basePath = '/' . $userId . '/files_encryption/keyfiles';
$targetPath = self::keySetPreparation( $view, $path, $basePath, $userId );
if ( $view->is_dir( $basePath . '/' . $targetPath ) ) {
public static function setFileKey(\OC_FilesystemView $view, $path, $userId, $catfile) {
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
//here we need the currently logged in user, while userId can be a different user
$util = new Util($view, \OCP\User::getUser());
list($owner, $filename) = $util->getUidAndFilename($path);
$basePath = '/' . $owner . '/files_encryption/keyfiles';
$targetPath = self::keySetPreparation($view, $filename, $basePath, $owner);
if (!$view->is_dir($basePath . '/' . $targetPath)) {
// create all parent folders
$info = pathinfo($basePath . '/' . $targetPath);
$keyfileFolderName = $view->getLocalFolder($info['dirname']);
if (!file_exists($keyfileFolderName)) {
mkdir($keyfileFolderName, 0750, true);
}
}
// try reusing key file if part file
if (self::isPartialFilePath($targetPath)) {
$result = $view->file_put_contents(
$basePath . '/' . self::fixPartialFilePath($targetPath) . '.key', $catfile);
} else {
// Save the keyfile in parallel directory
return $view->file_put_contents( $basePath . '/' . $targetPath . '.key', $catfile );
$result = $view->file_put_contents($basePath . '/' . $targetPath . '.key', $catfile);
}
\OC_FileProxy::$enabled = $proxyStatus;
return $result;
}
/**
* @brief Remove .path extension from a file path
* @param string $path Path that may identify a .part file
* @return string File path without .part extension
* @note this is needed for reusing keys
*/
public static function fixPartialFilePath($path) {
if (preg_match('/\.part$/', $path) || preg_match('/\.etmp$/', $path)) {
$newLength = strlen($path) - 5;
$fPath = substr($path, 0, $newLength);
return $fPath;
} else {
return $path;
}
}
/**
* @brief Check if a path is a .part file
* @param string $path Path that may identify a .part file
* @return bool
*/
public static function isPartialFilePath($path) {
if (preg_match('/\.part$/', $path) || preg_match('/\.etmp$/', $path)) {
return true;
} else {
return false;
}
}
/**
* @brief retrieve keyfile for an encrypted file
* @param \OC_FilesystemView $view
@@ -156,168 +213,359 @@ class Keymanager {
* @note The keyfile returned is asymmetrically encrypted. Decryption
* of the keyfile must be performed by client code
*/
public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) {
$filePath_f = ltrim( $filePath, '/' );
$catfilePath = '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key';
if ( $view->file_exists( $catfilePath ) ) {
public static function getFileKey(\OC_FilesystemView $view, $userId, $filePath) {
// try reusing key file if part file
if (self::isPartialFilePath($filePath)) {
$result = self::getFileKey($view, $userId, self::fixPartialFilePath($filePath));
if ($result) {
return $result;
}
return $view->file_get_contents( $catfilePath );
} else {
return false;
}
$util = new Util($view, \OCP\User::getUser());
list($owner, $filename) = $util->getUidAndFilename($filePath);
$filePath_f = ltrim($filename, '/');
$keyfilePath = '/' . $owner . '/files_encryption/keyfiles/' . $filePath_f . '.key';
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
if ($view->file_exists($keyfilePath)) {
$result = $view->file_get_contents($keyfilePath);
} else {
$result = false;
}
\OC_FileProxy::$enabled = $proxyStatus;
return $result;
}
/**
* @brief Delete a keyfile
*
* @param OC_FilesystemView $view
* @param \OC_FilesystemView $view
* @param string $userId username
* @param string $path path of the file the key belongs to
* @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, $userId, $path ) {
$trimmed = ltrim( $path, '/' );
$keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed . '.key';
// Unlink doesn't tell us if file was deleted (not found returns
// true), so we perform our own test
if ( $view->file_exists( $keyPath ) ) {
return $view->unlink( $keyPath );
public static function deleteFileKey(\OC_FilesystemView $view, $userId, $path) {
$trimmed = ltrim($path, '/');
$keyPath = '/' . $userId . '/files_encryption/keyfiles/' . $trimmed;
$result = false;
if ($view->is_dir($keyPath)) {
$result = $view->unlink($keyPath);
} else {
\OC_Log::write( 'Encryption library', 'Could not delete keyfile; does not exist: "' . $keyPath, \OC_Log::ERROR );
return false;
if ($view->file_exists($keyPath . '.key')) {
$result = $view->unlink($keyPath . '.key');
}
}
if (!$result) {
\OCP\Util::writeLog('Encryption library',
'Could not delete keyfile; does not exist: "' . $keyPath, \OCP\Util::ERROR);
}
return $result;
}
/**
* @brief store private key from the user
* @param string key
* @param string $key
* @return bool
* @note Encryption of the private key must be performed by client code
* as no encryption takes place here
*/
public static function setPrivateKey( $key ) {
public static function setPrivateKey($key) {
$user = \OCP\User::getUser();
$view = new \OC_FilesystemView( '/' . $user . '/files_encryption' );
$view = new \OC_FilesystemView('/' . $user . '/files_encryption');
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
if ( !$view->file_exists( '' ) )
$view->mkdir( '' );
return $view->file_put_contents( $user . '.private.key', $key );
if (!$view->file_exists(''))
$view->mkdir('');
$result = $view->file_put_contents($user . '.private.key', $key);
\OC_FileProxy::$enabled = $proxyStatus;
return $result;
}
/**
* @brief store private keys from the user
*
* @param string privatekey
* @param string publickey
* @return bool true/false
*/
public static function setUserKeys($privatekey, $publickey) {
return ( self::setPrivateKey( $privatekey ) && self::setPublicKey( $publickey ) );
}
/**
* @brief store public key of the user
*
* @param string key
* @return bool true/false
*/
public static function setPublicKey( $key ) {
$view = new \OC_FilesystemView( '/public-keys' );
\OC_FileProxy::$enabled = false;
if ( !$view->file_exists( '' ) )
$view->mkdir( '' );
return $view->file_put_contents( \OCP\User::getUser() . '.public.key', $key );
}
/**
* @brief store file encryption key
* @brief store share key
*
* @param \OC_FilesystemView $view
* @param string $path relative path of the file, including filename
* @param string $key
* @param null $view
* @param string $dbClassName
* @param $userId
* @param $shareKey
* @internal param string $key
* @internal param string $dbClassName
* @return bool true/false
* @note The keyfile is not encrypted here. Client code must
* asymmetrically encrypt the keyfile before passing it to this method
*/
public static function setShareKey( \OC_FilesystemView $view, $path, $userId, $shareKey ) {
$basePath = '/' . $userId . '/files_encryption/share-keys';
$shareKeyPath = self::keySetPreparation( $view, $path, $basePath, $userId );
return $view->file_put_contents( $basePath . '/' . $shareKeyPath . '.shareKey', $shareKey );
}
/**
* @brief Make preparations to vars and filesystem for saving a keyfile
*/
public static function keySetPreparation( \OC_FilesystemView $view, $path, $basePath, $userId ) {
$targetPath = ltrim( $path, '/' );
$path_parts = pathinfo( $targetPath );
// If the file resides within a subdirectory, create it
if (
isset( $path_parts['dirname'] )
&& ! $view->file_exists( $basePath . '/' . $path_parts['dirname'] )
) {
$view->mkdir( $basePath . '/' . $path_parts['dirname'] );
public static function setShareKey(\OC_FilesystemView $view, $path, $userId, $shareKey) {
// Here we need the currently logged in user, while userId can be a different user
$util = new Util($view, \OCP\User::getUser());
list($owner, $filename) = $util->getUidAndFilename($path);
$basePath = '/' . $owner . '/files_encryption/share-keys';
$shareKeyPath = self::keySetPreparation($view, $filename, $basePath, $owner);
// try reusing key file if part file
if (self::isPartialFilePath($shareKeyPath)) {
$writePath = $basePath . '/' . self::fixPartialFilePath($shareKeyPath) . '.' . $userId . '.shareKey';
} else {
$writePath = $basePath . '/' . $shareKeyPath . '.' . $userId . '.shareKey';
}
return $targetPath;
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$result = $view->file_put_contents($writePath, $shareKey);
\OC_FileProxy::$enabled = $proxyStatus;
if (
is_int($result)
&& $result > 0
) {
return true;
} else {
return false;
}
}
/**
* @brief Fetch the legacy encryption key from user files
* @param string $login used to locate the legacy key
* @param string $passphrase used to decrypt the legacy key
* @return true / false
*
* if the key is left out, the default handler will be used
* @brief store multiple share keys for a single file
* @param \OC_FilesystemView $view
* @param $path
* @param array $shareKeys
* @return bool
*/
public function getLegacyKey() {
$user = \OCP\User::getUser();
$view = new \OC_FilesystemView( '/' . $user );
return $view->file_get_contents( 'encryption.key' );
public static function setShareKeys(\OC_FilesystemView $view, $path, array $shareKeys) {
// $shareKeys must be an array with the following format:
// [userId] => [encrypted key]
$result = true;
foreach ($shareKeys as $userId => $shareKey) {
if (!self::setShareKey($view, $path, $userId, $shareKey)) {
// If any of the keys are not set, flag false
$result = false;
}
}
// Returns false if any of the keys weren't set
return $result;
}
/**
* @brief retrieve shareKey for an encrypted file
* @param \OC_FilesystemView $view
* @param string $userId
* @param string $filePath
* @internal param \OCA\Encryption\file $string name
* @return string file key or false
* @note The sharekey returned is encrypted. Decryption
* of the keyfile must be performed by client code
*/
public static function getShareKey(\OC_FilesystemView $view, $userId, $filePath) {
// try reusing key file if part file
if (self::isPartialFilePath($filePath)) {
$result = self::getShareKey($view, $userId, self::fixPartialFilePath($filePath));
if ($result) {
return $result;
}
}
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
//here we need the currently logged in user, while userId can be a different user
$util = new Util($view, \OCP\User::getUser());
list($owner, $filename) = $util->getUidAndFilename($filePath);
$shareKeyPath = \OC\Files\Filesystem::normalizePath(
'/' . $owner . '/files_encryption/share-keys/' . $filename . '.' . $userId . '.shareKey');
if ($view->file_exists($shareKeyPath)) {
$result = $view->file_get_contents($shareKeyPath);
} else {
$result = false;
}
\OC_FileProxy::$enabled = $proxyStatus;
return $result;
}
/**
* @brief delete all share keys of a given file
* @param \OC_FilesystemView $view
* @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) {
if ($view->is_dir($userId . '/files/' . $filePath)) {
$view->unlink($userId . '/files_encryption/share-keys/' . $filePath);
} else {
$localKeyPath = $view->getLocalFile($userId . '/files_encryption/share-keys/' . $filePath);
$matches = glob(preg_quote($localKeyPath) . '*.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);
}
}
}
}
/**
* @brief Delete a single user's shareKey for a single file
*/
public static function delShareKey(\OC_FilesystemView $view, $userIds, $filePath) {
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
//here we need the currently logged in user, while userId can be a different user
$util = new Util($view, \OCP\User::getUser());
list($owner, $filename) = $util->getUidAndFilename($filePath);
$shareKeyPath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files_encryption/share-keys/' . $filename);
if ($view->is_dir($shareKeyPath)) {
$localPath = \OC\Files\Filesystem::normalizePath($view->getLocalFolder($shareKeyPath));
self::recursiveDelShareKeys($localPath, $userIds);
} else {
foreach ($userIds as $userId) {
if (!$view->unlink($shareKeyPath . '.' . $userId . '.shareKey')) {
\OCP\Util::writeLog('Encryption library',
'Could not delete shareKey; does not exist: "' . $shareKeyPath . '.' . $userId
. '.shareKey"', \OCP\Util::ERROR);
}
}
}
\OC_FileProxy::$enabled = $proxyStatus;
}
/**
* @brief recursively delete share keys from given users
*
* @param string $dir directory
* @param array $userIds user ids for which the share keys should be deleted
*/
private static function recursiveDelShareKeys($dir, $userIds) {
foreach ($userIds as $userId) {
$matches = glob(preg_quote($dir) . '/*' . preg_quote('.' . $userId . '.shareKey'));
}
/** @var $matches array */
foreach ($matches as $ma) {
if (!unlink($ma)) {
\OCP\Util::writeLog('Encryption library',
'Could not delete shareKey; does not exist: "' . $ma . '"', \OCP\Util::ERROR);
}
}
$subdirs = $directories = glob(preg_quote($dir) . '/*', GLOB_ONLYDIR);
foreach ($subdirs as $subdir) {
self::recursiveDelShareKeys($subdir, $userIds);
}
}
/**
* @brief Make preparations to vars and filesystem for saving a keyfile
*/
public static function keySetPreparation(\OC_FilesystemView $view, $path, $basePath, $userId) {
$targetPath = ltrim($path, '/');
$path_parts = pathinfo($targetPath);
// If the file resides within a subdirectory, create it
if (
isset($path_parts['dirname'])
&& !$view->file_exists($basePath . '/' . $path_parts['dirname'])
) {
$sub_dirs = explode(DIRECTORY_SEPARATOR, $basePath . '/' . $path_parts['dirname']);
$dir = '';
foreach ($sub_dirs as $sub_dir) {
$dir .= '/' . $sub_dir;
if (!$view->is_dir($dir)) {
$view->mkdir($dir);
}
}
}
return $targetPath;
}
}

View File

@@ -1,41 +1,45 @@
<?php
/**
* ownCloud
*
* @author Sam Tuke, Robin Appelman
* @copyright 2012 Sam Tuke samtuke@owncloud.com, Robin Appelman
* icewind1991@gmail.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
* ownCloud
*
* @author Sam Tuke, Robin Appelman
* @copyright 2012 Sam Tuke samtuke@owncloud.com, Robin Appelman
* icewind1991@gmail.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/>.
*
*/
/**
* @brief Encryption proxy which handles filesystem operations before and after
* execution and encrypts, and handles keyfiles accordingly. Used for
* webui.
*/
* @brief Encryption proxy which handles filesystem operations before and after
* execution and encrypts, and handles keyfiles accordingly. Used for
* webui.
*/
namespace OCA\Encryption;
/**
* Class Proxy
* @package OCA\Encryption
*/
class Proxy extends \OC_FileProxy {
private static $blackList = null; //mimetypes blacklisted from encryption
private static $enableEncryption = null;
/**
* Check if a file requires encryption
* @param string $path
@@ -43,347 +47,383 @@ class Proxy extends \OC_FileProxy {
*
* Tests if server side encryption is enabled, and file is allowed by blacklists
*/
private static function shouldEncrypt( $path ) {
if ( is_null( self::$enableEncryption ) ) {
if (
\OCP\Config::getAppValue( 'files_encryption', 'enable_encryption', 'true' ) == 'true'
&& Crypt::mode() == 'server'
private static function shouldEncrypt($path) {
if (is_null(self::$enableEncryption)) {
if (
\OCP\Config::getAppValue('files_encryption', 'enable_encryption', 'true') === 'true'
&& Crypt::mode() === 'server'
) {
self::$enableEncryption = true;
} else {
self::$enableEncryption = false;
}
}
if ( !self::$enableEncryption ) {
if (!self::$enableEncryption) {
return false;
}
if ( is_null(self::$blackList ) ) {
self::$blackList = explode(',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', 'jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg' ) );
if (is_null(self::$blackList)) {
self::$blackList = explode(',', \OCP\Config::getAppValue('files_encryption', 'type_blacklist', ''));
}
if ( Crypt::isCatfile( $path ) ) {
if (Crypt::isCatfileContent($path)) {
return true;
}
$extension = substr( $path, strrpos( $path, '.' ) +1 );
if ( array_search( $extension, self::$blackList ) === false ) {
$extension = substr($path, strrpos($path, '.') + 1);
if (array_search($extension, self::$blackList) === false) {
return true;
}
return false;
}
public function preFile_put_contents( $path, &$data ) {
if ( self::shouldEncrypt( $path ) ) {
if ( !is_resource( $data ) ) { //stream put contents should have been converted to fopen
$userId = \OCP\USER::getUser();
$rootView = new \OC_FilesystemView( '/' );
// Set the filesize for userland, before encrypting
$size = strlen( $data );
// Disable encryption proxy to prevent recursive calls
\OC_FileProxy::$enabled = false;
// TODO: Check if file is shared, if so, use multiKeyEncrypt
// Encrypt plain data and fetch key
$encrypted = Crypt::keyEncryptKeyfile( $data, Keymanager::getPublicKey( $rootView, $userId ) );
// Replace plain content with encrypted content by reference
$data = $encrypted['data'];
$filePath = explode( '/', $path );
$filePath = array_slice( $filePath, 3 );
$filePath = '/' . implode( '/', $filePath );
// TODO: make keyfile dir dynamic from app config
$view = new \OC_FilesystemView( '/' );
// Save keyfile for newly encrypted file in parallel directory tree
Keymanager::setFileKey( $view, $filePath, $userId, $encrypted['key'] );
// Update the file cache with file info
\OC\Files\Filesystem::putFileInfo( $path, array( 'encrypted'=>true, 'size' => $size ), '' );
// Re-enable proxy - our work is done
\OC_FileProxy::$enabled = true;
/**
* @param $path
* @param $data
* @return bool
*/
public function preFile_put_contents($path, &$data) {
if (self::shouldEncrypt($path)) {
if (!is_resource($data)) {
// get root view
$view = new \OC_FilesystemView('/');
// get relative path
$relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
if (!isset($relativePath)) {
return true;
}
$handle = fopen('crypt://' . $relativePath . '.etmp', 'w');
if (is_resource($handle)) {
// write data to stream
fwrite($handle, $data);
// close stream
fclose($handle);
// disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
// get encrypted content
$data = $view->file_get_contents($path . '.etmp');
// remove our temp file
$view->unlink($path . '.etmp');
// re-enable proxy - our work is done
\OC_FileProxy::$enabled = $proxyStatus;
}
}
}
return true;
}
/**
* @param string $path Path of file from which has been read
* @param string $data Data that has been read from file
*/
public function postFile_get_contents( $path, $data ) {
// TODO: Use dependency injection to add required args for view and user etc. to this method
public function postFile_get_contents($path, $data) {
$plainData = null;
$view = new \OC_FilesystemView('/');
// get relative path
$relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
// init session
$session = new \OCA\Encryption\Session($view);
// Disable encryption proxy to prevent recursive calls
\OC_FileProxy::$enabled = false;
// If data is a catfile
if (
Crypt::mode() == 'server'
&& Crypt::isCatfile( $data )
if (
Crypt::mode() === 'server'
&& Crypt::isCatfileContent($data)
) {
$split = explode( '/', $path );
$filePath = array_slice( $split, 3 );
$filePath = '/' . implode( '/', $filePath );
//$cached = \OC\Files\Filesystem::getFileInfo( $path, '' );
$view = new \OC_FilesystemView( '' );
$userId = \OCP\USER::getUser();
// TODO: Check if file is shared, if so, use multiKeyDecrypt
$encryptedKeyfile = Keymanager::getFileKey( $view, $userId, $filePath );
$session = new Session();
$decrypted = Crypt::keyDecryptKeyfile( $data, $encryptedKeyfile, $session->getPrivateKey( $split[1] ) );
$handle = fopen('crypt://' . $relativePath, 'r');
if (is_resource($handle)) {
while (($plainDataChunk = fgets($handle, 8192)) !== false) {
$plainData .= $plainDataChunk;
}
}
} elseif (
Crypt::mode() == 'server'
&& isset( $_SESSION['legacyenckey'] )
&& Crypt::isEncryptedMeta( $path )
Crypt::mode() == 'server'
&& isset($_SESSION['legacyenckey'])
&& Crypt::isEncryptedMeta($path)
) {
$decrypted = Crypt::legacyDecrypt( $data, $_SESSION['legacyenckey'] );
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$plainData = Crypt::legacyBlockDecrypt($data, $session->getLegacyKey());
\OC_FileProxy::$enabled = $proxyStatus;
}
\OC_FileProxy::$enabled = true;
if ( ! isset( $decrypted ) ) {
$decrypted = $data;
if (!isset($plainData)) {
$plainData = $data;
}
return $decrypted;
return $plainData;
}
/**
* @brief When a file is deleted, remove its keyfile also
*/
public function preUnlink( $path ) {
// Disable encryption proxy to prevent recursive calls
\OC_FileProxy::$enabled = false;
$view = new \OC_FilesystemView( '/' );
$userId = \OCP\USER::getUser();
// Format path to be relative to user files dir
$trimmed = ltrim( $path, '/' );
$split = explode( '/', $trimmed );
$sliced = array_slice( $split, 2 );
$relPath = implode( '/', $sliced );
if ( $view->is_dir( $path ) ) {
// Dirs must be handled separately as deleteFileKey
// doesn't handle them
$view->unlink( $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/'. $relPath );
} else {
// Delete keyfile so it isn't orphaned
$result = Keymanager::deleteFileKey( $view, $userId, $relPath );
\OC_FileProxy::$enabled = true;
return $result;
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, $owner, $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;
}
/**
* @brief When a file is renamed, rename its keyfile also
* @return bool Result of rename()
* @note This is pre rather than post because using post didn't work
* @param $path
* @return bool
*/
public function preRename( $oldPath, $newPath ) {
// Disable encryption proxy to prevent recursive calls
\OC_FileProxy::$enabled = false;
$view = new \OC_FilesystemView( '/' );
$userId = \OCP\USER::getUser();
// Format paths to be relative to user files dir
$oldTrimmed = ltrim( $oldPath, '/' );
$oldSplit = explode( '/', $oldTrimmed );
$oldSliced = array_slice( $oldSplit, 2 );
$oldRelPath = implode( '/', $oldSliced );
$oldKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $oldRelPath . '.key';
$newTrimmed = ltrim( $newPath, '/' );
$newSplit = explode( '/', $newTrimmed );
$newSliced = array_slice( $newSplit, 2 );
$newRelPath = implode( '/', $newSliced );
$newKeyfilePath = $userId . '/' . 'files_encryption' . '/' . 'keyfiles' . '/' . $newRelPath . '.key';
// Rename keyfile so it isn't orphaned
$result = $view->rename( $oldKeyfilePath, $newKeyfilePath );
\OC_FileProxy::$enabled = true;
return $result;
public function postTouch($path) {
$this->handleFile($path);
return true;
}
public function postFopen( $path, &$result ){
if ( !$result ) {
/**
* @param $path
* @param $result
* @return resource
*/
public function postFopen($path, &$result) {
if (!$result) {
return $result;
}
// Reformat path for use with OC_FSV
$path_split = explode( '/', $path );
$path_f = implode( array_slice( $path_split, 3 ) );
// split the path parts
$pathParts = explode('/', $path);
// get relative path
$relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
// FIXME: handling for /userId/cache used by webdav for chunking. The cache chunks are NOT encrypted
if (isset($pathParts[2]) && $pathParts[2] === 'cache') {
return $result;
}
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$meta = stream_get_meta_data( $result );
$view = new \OC_FilesystemView( '' );
$util = new Util( $view, \OCP\USER::getUser());
$meta = stream_get_meta_data($result);
$view = new \OC_FilesystemView('');
$util = new Util($view, \OCP\USER::getUser());
// If file is already encrypted, decrypt using crypto protocol
if (
Crypt::mode() == 'server'
&& $util->isEncryptedPath( $path )
if (
Crypt::mode() === 'server'
&& $util->isEncryptedPath($path)
) {
// Close the original encrypted file
fclose( $result );
fclose($result);
// Open the file using the crypto stream wrapper
// protocol and let it do the decryption work instead
$result = fopen( 'crypt://' . $path_f, $meta['mode'] );
} elseif (
self::shouldEncrypt( $path )
and $meta ['mode'] != 'r'
and $meta['mode'] != 'rb'
$result = fopen('crypt://' . $relativePath, $meta['mode']);
} elseif (
self::shouldEncrypt($path)
and $meta ['mode'] !== 'r'
and $meta['mode'] !== 'rb'
) {
// If the file is not yet encrypted, but should be
// encrypted when it's saved (it's not read only)
// NOTE: this is the case for new files saved via WebDAV
if (
$view->file_exists( $path )
and $view->filesize( $path ) > 0
) {
$x = $view->file_get_contents( $path );
$tmp = tmpfile();
// // Make a temporary copy of the original file
// \OCP\Files::streamCopy( $result, $tmp );
//
// // Close the original stream, we'll return another one
// fclose( $result );
//
// $view->file_put_contents( $path_f, $tmp );
//
// fclose( $tmp );
}
$result = fopen( 'crypt://'.$path_f, $meta['mode'] );
$result = fopen('crypt://' . $relativePath, $meta['mode']);
}
// Re-enable the proxy
\OC_FileProxy::$enabled = true;
\OC_FileProxy::$enabled = $proxyStatus;
return $result;
}
public function postGetMimeType( $path, $mime ) {
if ( Crypt::isCatfile( $path ) ) {
$mime = \OCP\Files::getMimeType( 'crypt://' . $path, 'w' );
}
return $mime;
}
/**
* @param $path
* @param $data
* @return array
*/
public function postGetFileInfo($path, $data) {
public function postStat( $path, $data ) {
if ( Crypt::isCatfile( $path ) ) {
$cached = \OC\Files\Filesystem::getFileInfo( $path, '' );
$data['size'] = $cached['size'];
// if path is a folder do nothing
if (is_array($data) && array_key_exists('size', $data)) {
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
// get file size
$data['size'] = self::postFileSize($path, $data['size']);
// Re-enable the proxy
\OC_FileProxy::$enabled = $proxyStatus;
}
return $data;
}
public function postFileSize( $path, $size ) {
if ( Crypt::isCatfile( $path ) ) {
$cached = \OC\Files\Filesystem::getFileInfo( $path, '' );
return $cached['size'];
} else {
/**
* @param $path
* @param $size
* @return bool
*/
public function postFileSize($path, $size) {
$view = new \OC_FilesystemView('/');
// if path is a folder do nothing
if ($view->is_dir($path)) {
return $size;
}
// get relative path
$relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
// if path is empty we cannot resolve anything
if (empty($relativePath)) {
return $size;
}
$fileInfo = false;
// get file info from database/cache if not .part file
if (!Keymanager::isPartialFilePath($path)) {
$fileInfo = $view->getFileInfo($path);
}
// if file is encrypted return real file size
if (is_array($fileInfo) && $fileInfo['encrypted'] === true) {
$size = $fileInfo['unencrypted_size'];
} else {
// self healing if file was removed from file cache
if (!is_array($fileInfo)) {
$fileInfo = array();
}
$userId = \OCP\User::getUser();
$util = new Util($view, $userId);
$fixSize = $util->getFileSize($path);
if ($fixSize > 0) {
$size = $fixSize;
$fileInfo['encrypted'] = true;
$fileInfo['unencrypted_size'] = $size;
// put file info if not .part file
if (!Keymanager::isPartialFilePath($relativePath)) {
$view->putFileInfo($path, $fileInfo);
}
}
}
return $size;
}
/**
* @param $path
*/
public function handleFile($path) {
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$view = new \OC_FilesystemView('/');
$session = new \OCA\Encryption\Session($view);
$userId = \OCP\User::getUser();
$util = new Util($view, $userId);
// split the path parts
$pathParts = explode('/', $path);
// get relative path
$relativePath = \OCA\Encryption\Helper::stripUserFilesPath($path);
// only if file is on 'files' folder fix file size and sharing
if (isset($pathParts[2]) && $pathParts[2] === 'files' && $util->fixFileSize($path)) {
// get sharing app state
$sharingEnabled = \OCP\Share::isEnabled();
// get users
$usersSharing = $util->getSharingUsersArray($sharingEnabled, $relativePath);
// update sharing-keys
$util->setSharedFileKeyfiles($session, $usersSharing, $relativePath);
}
\OC_FileProxy::$enabled = $proxyStatus;
}
}

View File

@@ -28,76 +28,170 @@ namespace OCA\Encryption;
class Session {
private $view;
/**
* @brief if session is started, check if ownCloud key pair is set up, if not create it
* @param \OC_FilesystemView $view
*
* @note The ownCloud key pair is used to allow public link sharing even if encryption is enabled
*/
public function __construct($view) {
$this->view = $view;
if (!$this->view->is_dir('owncloud_private_key')) {
$this->view->mkdir('owncloud_private_key');
}
$publicShareKeyId = \OC_Appconfig::getValue('files_encryption', 'publicShareKeyId');
if ($publicShareKeyId === null) {
$publicShareKeyId = 'pubShare_' . substr(md5(time()), 0, 8);
\OC_Appconfig::setValue('files_encryption', 'publicShareKeyId', $publicShareKeyId);
}
if (
!$this->view->file_exists("/public-keys/" . $publicShareKeyId . ".public.key")
|| !$this->view->file_exists("/owncloud_private_key/" . $publicShareKeyId . ".private.key")
) {
$keypair = Crypt::createKeypair();
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
// Save public key
if (!$view->is_dir('/public-keys')) {
$view->mkdir('/public-keys');
}
$this->view->file_put_contents('/public-keys/' . $publicShareKeyId . '.public.key', $keypair['publicKey']);
// Encrypt private key empty passphrase
$encryptedPrivateKey = Crypt::symmetricEncryptFileContent($keypair['privateKey'], '');
// Save private key
$this->view->file_put_contents(
'/owncloud_private_key/' . $publicShareKeyId . '.private.key', $encryptedPrivateKey);
\OC_FileProxy::$enabled = $proxyStatus;
}
if (\OCA\Encryption\Helper::isPublicAccess()) {
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
$encryptedKey = $this->view->file_get_contents(
'/owncloud_private_key/' . $publicShareKeyId . '.private.key');
$privateKey = Crypt::symmetricDecryptFileContent($encryptedKey, '');
$this->setPublicSharePrivateKey($privateKey);
\OC_FileProxy::$enabled = $proxyStatus;
}
}
/**
* @brief Sets user private key to session
* @param string $privateKey
* @return bool
*
* @note this should only be set on login
*/
public function setPrivateKey( $privateKey ) {
public function setPrivateKey($privateKey) {
$_SESSION['privateKey'] = $privateKey;
return true;
}
/**
* @brief Gets user private key from session
* @brief Gets user or public share private key from session
* @returns string $privateKey The user's plaintext private key
*
*/
public function getPrivateKey() {
if (
isset( $_SESSION['privateKey'] )
&& !empty( $_SESSION['privateKey'] )
) {
return $_SESSION['privateKey'];
// return the public share private key if this is a public access
if (\OCA\Encryption\Helper::isPublicAccess()) {
return $this->getPublicSharePrivateKey();
} else {
return false;
if (isset($_SESSION['privateKey']) && !empty($_SESSION['privateKey'])) {
return $_SESSION['privateKey'];
} else {
return false;
}
}
}
/**
* @brief Sets user legacy key to session
* @brief Sets public user private key to session
* @param string $privateKey
* @return bool
*/
public function setPublicSharePrivateKey($privateKey) {
$_SESSION['publicSharePrivateKey'] = $privateKey;
return true;
}
/**
* @brief Gets public share private key from session
* @returns string $privateKey
*
*/
public function setLegacyKey( $legacyKey ) {
if ( $_SESSION['legacyKey'] = $legacyKey ) {
return true;
public function getPublicSharePrivateKey() {
if (isset($_SESSION['publicSharePrivateKey']) && !empty($_SESSION['publicSharePrivateKey'])) {
return $_SESSION['publicSharePrivateKey'];
} else {
return false;
}
}
/**
* @brief Sets user legacy key to session
* @param $legacyKey
* @return bool
*/
public function setLegacyKey($legacyKey) {
$_SESSION['legacyKey'] = $legacyKey;
return true;
}
/**
* @brief Gets user legacy key from session
* @returns string $legacyKey The user's plaintext legacy key
*
*/
public function getLegacyKey() {
if (
isset( $_SESSION['legacyKey'] )
&& !empty( $_SESSION['legacyKey'] )
if (
isset($_SESSION['legacyKey'])
&& !empty($_SESSION['legacyKey'])
) {
return $_SESSION['legacyKey'];
} else {
return false;
}
}
}

View File

@@ -3,7 +3,7 @@
* ownCloud
*
* @author Robin Appelman
* @copyright 2012 Sam Tuke <samtuke@owncloud.com>, 2011 Robin Appelman
* @copyright 2012 Sam Tuke <samtuke@owncloud.com>, 2011 Robin Appelman
* <icewind1991@gmail.com>
*
* This library is free software; you can redistribute it and/or
@@ -32,27 +32,28 @@ namespace OCA\Encryption;
/**
* @brief Provides 'crypt://' stream wrapper protocol.
* @note We use a stream wrapper because it is the most secure way to handle
* @note We use a stream wrapper because it is the most secure way to handle
* decrypted content transfers. There is no safe way to decrypt the entire file
* somewhere on the server, so we have to encrypt and decrypt blocks on the fly.
* @note Paths used with this protocol MUST BE RELATIVE. Use URLs like:
* crypt://filename, or crypt://subdirectory/filename, NOT
* crypt:///home/user/owncloud/data. Otherwise keyfiles will be put in
* [owncloud]/data/user/files_encryption/keyfiles/home/user/owncloud/data and
* crypt://filename, or crypt://subdirectory/filename, NOT
* crypt:///home/user/owncloud/data. Otherwise keyfiles will be put in
* [owncloud]/data/user/files_encryption/keyfiles/home/user/owncloud/data and
* will not be accessible to other methods.
* @note Data read and written must always be 8192 bytes long, as this is the
* buffer size used internally by PHP. The encryption process makes the input
* data longer, and input is chunked into smaller pieces in order to result in
* @note Data read and written must always be 8192 bytes long, as this is the
* buffer size used internally by PHP. The encryption process makes the input
* data longer, and input is chunked into smaller pieces in order to result in
* a 8192 encrypted block size.
* @note When files are deleted via webdav, or when they are updated and the
* previous version deleted, this is handled by OC\Files\View, and thus the
* encryption proxies are used and keyfiles deleted.
*/
class Stream {
private $plainKey;
private $encKeyfiles;
public static $sourceStreams = array();
// TODO: make all below properties private again once unit testing is
// configured correctly
public $rawPath; // The raw path received by stream_open
public $path_f; // The raw path formatted to include username and data dir
private $rawPath; // The raw path relative to the data dir
private $relPath; // rel path to users file dir
private $userId;
private $handle; // Resource returned by fopen
private $path;
@@ -60,226 +61,191 @@ class Stream {
private $meta = array(); // Header / meta for source stream
private $count;
private $writeCache;
public $size;
private $size;
private $unencryptedSize;
private $publicKey;
private $keyfile;
private $encKeyfile;
private static $view; // a fsview object set to user dir
private $rootView; // a fsview object set to '/'
public function stream_open( $path, $mode, $options, &$opened_path ) {
// Get access to filesystem via filesystemview object
if ( !self::$view ) {
self::$view = new \OC_FilesystemView( $this->userId . '/' );
/**
* @param $path
* @param $mode
* @param $options
* @param $opened_path
* @return bool
*/
public function stream_open($path, $mode, $options, &$opened_path) {
if (!isset($this->rootView)) {
$this->rootView = new \OC_FilesystemView('/');
}
// Set rootview object if necessary
if ( ! $this->rootView ) {
$this->rootView = new \OC_FilesystemView( $this->userId . '/' );
$util = new Util($this->rootView, \OCP\USER::getUser());
}
$this->userId = \OCP\User::getUser();
// Get the bare file path
$path = str_replace( 'crypt://', '', $path );
$this->rawPath = $path;
$this->path_f = $this->userId . '/files/' . $path;
if (
dirname( $path ) == 'streams'
and isset( self::$sourceStreams[basename( $path )] )
$this->userId = $util->getUserId();
// Strip identifier text from path, this gives us the path relative to data/<user>/files
$this->relPath = \OC\Files\Filesystem::normalizePath(str_replace('crypt://', '', $path));
// rawPath is relative to the data directory
$this->rawPath = $util->getUserFilesDir() . $this->relPath;
// Disable fileproxies so we can get the file size and open the source file without recursive encryption
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
if (
$mode === 'w'
or $mode === 'w+'
or $mode === 'wb'
or $mode === 'wb+'
) {
// Is this just for unit testing purposes?
$this->handle = self::$sourceStreams[basename( $path )]['stream'];
$this->path = self::$sourceStreams[basename( $path )]['path'];
$this->size = self::$sourceStreams[basename( $path )]['size'];
// We're writing a new file so start write counter with 0 bytes
$this->size = 0;
$this->unencryptedSize = 0;
} else {
if (
$mode == 'w'
or $mode == 'w+'
or $mode == 'wb'
or $mode == 'wb+'
) {
$this->size = $this->rootView->filesize($this->rawPath, $mode);
}
$this->size = 0;
$this->handle = $this->rootView->fopen($this->rawPath, $mode);
} else {
$this->size = self::$view->filesize( $this->path_f, $mode );
//$this->size = filesize( $path );
}
\OC_FileProxy::$enabled = $proxyStatus;
// Disable fileproxies so we can open the source file without recursive encryption
\OC_FileProxy::$enabled = false;
if (!is_resource($this->handle)) {
//$this->handle = fopen( $path, $mode );
$this->handle = self::$view->fopen( $this->path_f, $mode );
\OC_FileProxy::$enabled = true;
\OCP\Util::writeLog('files_encryption', 'failed to open file "' . $this->rawPath . '"', \OCP\Util::ERROR);
if ( !is_resource( $this->handle ) ) {
} else {
\OCP\Util::writeLog( 'files_encryption', 'failed to open '.$path, \OCP\Util::ERROR );
}
$this->meta = stream_get_meta_data($this->handle);
}
if ( is_resource( $this->handle ) ) {
$this->meta = stream_get_meta_data( $this->handle );
}
return is_resource( $this->handle );
return is_resource($this->handle);
}
public function stream_seek( $offset, $whence = SEEK_SET ) {
/**
* @param $offset
* @param int $whence
*/
public function stream_seek($offset, $whence = SEEK_SET) {
$this->flush();
fseek( $this->handle, $offset, $whence );
fseek($this->handle, $offset, $whence);
}
public function stream_tell() {
return ftell($this->handle);
}
public function stream_read( $count ) {
/**
* @param $count
* @return bool|string
* @throws \Exception
*/
public function stream_read($count) {
$this->writeCache = '';
if ( $count != 8192 ) {
if ($count !== 8192) {
// $count will always be 8192 https://bugs.php.net/bug.php?id=21641
// This makes this function a lot simpler, but will break this class if the above 'bug' gets 'fixed'
\OCP\Util::writeLog( 'files_encryption', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', \OCP\Util::FATAL );
\OCP\Util::writeLog('files_encryption', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', \OCP\Util::FATAL);
die();
}
// $pos = ftell( $this->handle );
//
// Get the data from the file handle
$data = fread( $this->handle, 8192 );
if ( strlen( $data ) ) {
$this->getKey();
$result = Crypt::symmetricDecryptFileContent( $data, $this->keyfile );
} else {
$data = fread($this->handle, 8192);
$result = '';
$result = '';
if (strlen($data)) {
if (!$this->getKey()) {
// Error! We don't have a key to decrypt the file with
throw new \Exception(
'Encryption key not found for "' . $this->rawPath . '" during attempted read via stream');
}
// Decrypt data
$result = Crypt::symmetricDecryptFileContent($data, $this->plainKey);
}
// $length = $this->size - $pos;
//
// if ( $length < 8192 ) {
//
// $result = substr( $result, 0, $length );
//
// }
return $result;
}
/**
* @brief Encrypt and pad data ready for writing to disk
* @param string $plainData data to be encrypted
* @param string $key key to use for encryption
* @return encrypted data on success, false on failure
* @return string encrypted data on success, false on failure
*/
public function preWriteEncrypt( $plainData, $key ) {
public function preWriteEncrypt($plainData, $key) {
// Encrypt data to 'catfile', which includes IV
if ( $encrypted = Crypt::symmetricEncryptFileContent( $plainData, $key ) ) {
return $encrypted;
if ($encrypted = Crypt::symmetricEncryptFileContent($plainData, $key)) {
return $encrypted;
} else {
return false;
}
}
/**
* @brief Get the keyfile for the current file, generate one if necessary
* @param bool $generate if true, a new key will be generated if none can be found
* @brief Fetch the plain encryption key for the file and set it as plainKey property
* @internal param bool $generate if true, a new key will be generated if none can be found
* @return bool true on key found and set, false on key not found and new key generated and set
*/
public function getKey() {
// If a keyfile already exists for a file named identically to
// file to be written
if ( self::$view->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->rawPath . '.key' ) ) {
// TODO: add error handling for when file exists but no
// keyfile
// Fetch existing keyfile
$this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->rawPath );
$this->getUser();
$session = new Session();
$privateKey = $session->getPrivateKey( $this->userId );
$this->keyfile = Crypt::keyDecrypt( $this->encKeyfile, $privateKey );
// Check if key is already set
if (isset($this->plainKey) && isset($this->encKeyfile)) {
return true;
}
// Fetch and decrypt keyfile
// Fetch existing keyfile
$this->encKeyfile = Keymanager::getFileKey($this->rootView, $this->userId, $this->relPath);
// If a keyfile already exists
if ($this->encKeyfile) {
$session = new \OCA\Encryption\Session( $this->rootView );
$privateKey = $session->getPrivateKey($this->userId);
$shareKey = Keymanager::getShareKey($this->rootView, $this->userId, $this->relPath);
$this->plainKey = Crypt::multiKeyDecrypt($this->encKeyfile, $shareKey, $privateKey);
return true;
} else {
return false;
}
}
public function getuser() {
// Only get the user again if it isn't already set
if ( empty( $this->userId ) ) {
// TODO: Move this user call out of here - it belongs
// elsewhere
$this->userId = \OCP\User::getUser();
}
// TODO: Add a method for getting the user in case OCP\User::
// getUser() doesn't work (can that scenario ever occur?)
}
/**
* @brief Handle plain data from the stream, and write it in 8192 byte blocks
* @param string $data data to be written to disk
@@ -289,99 +255,55 @@ class Stream {
* @note Padding is added to each encrypted block to ensure that the resulting block is exactly 8192 bytes. This is removed during stream_read
* @note PHP automatically updates the file pointer after writing data to reflect it's length. There is generally no need to update the poitner manually using fseek
*/
public function stream_write( $data ) {
public function stream_write($data) {
// Disable the file proxies so that encryption is not
// automatically attempted when the file is written to disk -
// we are handling that separately here and we don't want to
// get into an infinite loop
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
// Get the length of the unencrypted data that we are handling
$length = strlen( $data );
// So far this round, no data has been written
$written = 0;
// Find out where we are up to in the writing of data to the
$length = strlen($data);
// Find out where we are up to in the writing of data to the
// file
$pointer = ftell( $this->handle );
// Make sure the userId is set
$this->getuser();
// TODO: Check if file is shared, if so, use multiKeyEncrypt and
// save shareKeys in necessary user directories
$pointer = ftell($this->handle);
// Get / generate the keyfile for the file we're handling
// If we're writing a new file (not overwriting an existing
// one), save the newly generated keyfile
if ( ! $this->getKey() ) {
$this->keyfile = Crypt::generateKey();
$this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId );
$this->encKeyfile = Crypt::keyEncrypt( $this->keyfile, $this->publicKey );
$view = new \OC_FilesystemView( '/' );
$userId = \OCP\User::getUser();
// Save the new encrypted file key
Keymanager::setFileKey( $view, $this->rawPath, $userId, $this->encKeyfile );
if (!$this->getKey()) {
$this->plainKey = Crypt::generateKey();
}
// If extra data is left over from the last round, make sure it
// is integrated into the next 6126 / 8192 block
if ( $this->writeCache ) {
if ($this->writeCache) {
// Concat writeCache to start of $data
$data = $this->writeCache . $data;
// Clear the write cache, ready for resuse - it has been
// Clear the write cache, ready for reuse - it has been
// flushed and its old contents processed
$this->writeCache = '';
}
//
// // Make sure we always start on a block start
if ( 0 != ( $pointer % 8192 ) ) {
// if the current position of
// file indicator is not aligned to a 8192 byte block, fix it
// so that it is
// fseek( $this->handle, - ( $pointer % 8192 ), SEEK_CUR );
//
// $pointer = ftell( $this->handle );
//
// $unencryptedNewBlock = fread( $this->handle, 8192 );
//
// fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR );
//
// $block = Crypt::symmetricDecryptFileContent( $unencryptedNewBlock, $this->keyfile );
//
// $x = substr( $block, 0, $currentPos % 8192 );
//
// $data = $x . $data;
//
// fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR );
//
}
// While there still remains some data to be processed & written
while (strlen($data) > 0) {
// Remaining length for this iteration, not of the
// entire file (may be greater than 8192 bytes)
$remainingLength = strlen($data);
// If data remaining to be written is less than the
// size of 1 6126 byte block
if ($remainingLength < 6126) {
// $currentPos = ftell( $this->handle );
// // While there still remains somed data to be processed & written
while( strlen( $data ) > 0 ) {
//
// // Remaining length for this iteration, not of the
// // entire file (may be greater than 8192 bytes)
// $remainingLength = strlen( $data );
//
// // If data remaining to be written is less than the
// // size of 1 6126 byte block
if ( strlen( $data ) < 6126 ) {
// Set writeCache to contents of $data
// The writeCache will be carried over to the
// next write round, and added to the start of
@@ -394,101 +316,167 @@ class Stream {
// Clear $data ready for next round
$data = '';
//
} else {
// Read the chunk from the start of $data
$chunk = substr( $data, 0, 6126 );
$encrypted = $this->preWriteEncrypt( $chunk, $this->keyfile );
$chunk = substr($data, 0, 6126);
$encrypted = $this->preWriteEncrypt($chunk, $this->plainKey);
// Write the data chunk to disk. This will be
// attended to the last data chunk if the file
// being handled totals more than 6126 bytes
fwrite( $this->handle, $encrypted );
$writtenLen = strlen( $encrypted );
//fseek( $this->handle, $writtenLen, SEEK_CUR );
fwrite($this->handle, $encrypted);
// Remove the chunk we just processed from
// Remove the chunk we just processed from
// $data, leaving only unprocessed data in $data
// var, for handling on the next round
$data = substr( $data, 6126 );
$data = substr($data, 6126);
}
}
$this->size = max( $this->size, $pointer + $length );
$this->size = max($this->size, $pointer + $length);
$this->unencryptedSize += $length;
\OC_FileProxy::$enabled = $proxyStatus;
return $length;
}
public function stream_set_option( $option, $arg1, $arg2 ) {
switch($option) {
/**
* @param $option
* @param $arg1
* @param $arg2
*/
public function stream_set_option($option, $arg1, $arg2) {
$return = false;
switch ($option) {
case STREAM_OPTION_BLOCKING:
stream_set_blocking( $this->handle, $arg1 );
$return = stream_set_blocking($this->handle, $arg1);
break;
case STREAM_OPTION_READ_TIMEOUT:
stream_set_timeout( $this->handle, $arg1, $arg2 );
$return = stream_set_timeout($this->handle, $arg1, $arg2);
break;
case STREAM_OPTION_WRITE_BUFFER:
stream_set_write_buffer( $this->handle, $arg1, $arg2 );
$return = stream_set_write_buffer($this->handle, $arg1);
}
return $return;
}
/**
* @return array
*/
public function stream_stat() {
return fstat($this->handle);
}
public function stream_lock( $mode ) {
flock( $this->handle, $mode );
}
public function stream_flush() {
return fflush( $this->handle );
// Not a typo: http://php.net/manual/en/function.fflush.php
/**
* @param $mode
*/
public function stream_lock($mode) {
return flock($this->handle, $mode);
}
/**
* @return bool
*/
public function stream_flush() {
return fflush($this->handle);
// Not a typo: http://php.net/manual/en/function.fflush.php
}
/**
* @return bool
*/
public function stream_eof() {
return feof($this->handle);
}
private function flush() {
if ( $this->writeCache ) {
if ($this->writeCache) {
// Set keyfile property for file in question
$this->getKey();
$encrypted = $this->preWriteEncrypt( $this->writeCache, $this->keyfile );
fwrite( $this->handle, $encrypted );
$encrypted = $this->preWriteEncrypt($this->writeCache, $this->plainKey);
fwrite($this->handle, $encrypted);
$this->writeCache = '';
}
}
/**
* @return bool
*/
public function stream_close() {
$this->flush();
if (
$this->meta['mode']!='r'
and $this->meta['mode']!='rb'
if (
$this->meta['mode'] !== 'r'
and $this->meta['mode'] !== 'rb'
and $this->size > 0
) {
// Disable encryption proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy::$enabled;
\OC_FileProxy::$enabled = false;
\OC\Files\Filesystem::putFileInfo( $this->path, array( 'encrypted' => true, 'size' => $this->size ), '' );
// Fetch user's public key
$this->publicKey = Keymanager::getPublicKey($this->rootView, $this->userId);
// Check if OC sharing api is enabled
$sharingEnabled = \OCP\Share::isEnabled();
$util = new Util($this->rootView, $this->userId);
// Get all users sharing the file includes current user
$uniqueUserIds = $util->getSharingUsersArray($sharingEnabled, $this->relPath, $this->userId);
// Fetch public keys for all sharing users
$publicKeys = Keymanager::getPublicKeys($this->rootView, $uniqueUserIds);
// Encrypt enc key for all sharing users
$this->encKeyfiles = Crypt::multiKeyEncrypt($this->plainKey, $publicKeys);
$view = new \OC_FilesystemView('/');
// Save the new encrypted file key
Keymanager::setFileKey($this->rootView, $this->relPath, $this->userId, $this->encKeyfiles['data']);
// Save the sharekeys
Keymanager::setShareKeys($view, $this->relPath, $this->encKeyfiles['keys']);
// get file info
$fileInfo = $view->getFileInfo($this->rawPath);
if (!is_array($fileInfo)) {
$fileInfo = array();
}
// Re-enable proxy - our work is done
\OC_FileProxy::$enabled = $proxyStatus;
// set encryption data
$fileInfo['encrypted'] = true;
$fileInfo['size'] = $this->size;
$fileInfo['unencrypted_size'] = $this->unencryptedSize;
// set fileinfo
$view->putFileInfo($this->rawPath, $fileInfo);
}
return fclose( $this->handle );
return fclose($this->handle);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
<?php
/**
* Copyright (c) 2011 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
\OC_Util::checkAdminUser();
$tmpl = new OCP\Template('files_encryption', 'settings-admin');
// Check if an adminRecovery account is enabled for recovering files after lost pwd
$view = new OC_FilesystemView('');
$recoveryAdminEnabled = OC_Appconfig::getValue('files_encryption', 'recoveryAdminEnabled');
$tmpl->assign('recoveryEnabled', $recoveryAdminEnabled);
\OCP\Util::addscript('files_encryption', 'settings-admin');
\OCP\Util::addscript('core', 'multiselect');
return $tmpl->fetchPage();

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